Skip to content

Commit

Permalink
Merge pull request #714 from mono/mac-nsview-based-tables
Browse files Browse the repository at this point in the history
[Mac] NSView based tables
  • Loading branch information
sevoku committed Jan 26, 2018
2 parents c5e86c1 + bdb5f1c commit 2ef8261
Show file tree
Hide file tree
Showing 19 changed files with 1,283 additions and 496 deletions.
149 changes: 111 additions & 38 deletions Xwt.XamMac/Xwt.Mac.CellViews/CanvasTableCell.cs
Expand Up @@ -30,19 +30,15 @@

namespace Xwt.Mac
{
class CanvasTableCell: NSCell, ICellRenderer
class CanvasTableCell: NSView, ICellRenderer
{
bool visible = true;
NSTrackingArea trackingArea;

public CanvasTableCell (IntPtr p): base (p)
{
}
public CompositeCell CellContainer { get; set; }

public CanvasTableCell ()
{
}
public CellViewBackend Backend { get; set; }

public CompositeCell CellContainer { get; set; }
public NSView CellView { get { return this; } }

public void CopyFrom (object other)
{
Expand All @@ -52,46 +48,123 @@ public void CopyFrom (object other)

public void Fill ()
{
visible = Frontend.Visible;
Hidden = !Frontend.Visible;
}

ICanvasCellViewFrontend Frontend {
get { return (ICanvasCellViewFrontend) Backend.Frontend; }
}

public CellViewBackend Backend { get; set; }

public override CGSize FittingSize {
get {
var size = CGSize.Empty;
Frontend.ApplicationContext.InvokeUserCode (delegate {
var s = Frontend.GetRequiredSize ();
size = new CGSize ((nfloat)s.Width, (nfloat)s.Height);
});
return size;
}
}

public override CGSize CellSizeForBounds (CGRect bounds)
public override void DrawRect (CGRect dirtyRect)
{
if (!visible)
return CGSize.Empty;
var size = new CGSize ();
Backend.Load (this);
Frontend.ApplicationContext.InvokeUserCode (delegate {
var s = Frontend.GetRequiredSize ();
size = new CGSize ((nfloat)s.Width, (nfloat)s.Height);
});
if (size.Width > bounds.Width)
size.Width = bounds.Width;
if (size.Height > bounds.Height)
size.Height = bounds.Height;
return size;
}

public override void DrawInteriorWithFrame (CGRect cellFrame, NSView inView)
{
if (!visible)
return;
CGContext ctx = NSGraphicsContext.CurrentContext.GraphicsPort;

var backend = new CGContextBackend {
Context = ctx,
InverseViewTransform = ctx.GetCTM ().Invert ()
};
Frontend.ApplicationContext.InvokeUserCode (delegate {
Frontend.Draw (backend, new Rectangle (cellFrame.X, cellFrame.Y, cellFrame.Width, cellFrame.Height));
CGContext ctx = NSGraphicsContext.CurrentContext.GraphicsPort;

var backend = new CGContextBackend {
Context = ctx,
InverseViewTransform = ctx.GetCTM ().Invert ()
};
var bounds = Backend.CellBounds;
backend.Context.ClipToRect (dirtyRect);
backend.Context.TranslateCTM ((nfloat)(-bounds.X), (nfloat)(-bounds.Y));
Frontend.Draw (backend, new Rectangle (bounds.X, bounds.Y, bounds.Width, bounds.Height));
});
}

public override void UpdateTrackingAreas ()
{
if (trackingArea != null) {
RemoveTrackingArea (trackingArea);
trackingArea.Dispose ();
}
var options = NSTrackingAreaOptions.MouseMoved | NSTrackingAreaOptions.ActiveInKeyWindow | NSTrackingAreaOptions.MouseEnteredAndExited;
trackingArea = new NSTrackingArea (Bounds, options, this, null);
AddTrackingArea (trackingArea);
}

public override void RightMouseDown (NSEvent theEvent)
{
if (!this.HandleMouseDown (theEvent))
base.RightMouseDown (theEvent);
}

public override void RightMouseUp (NSEvent theEvent)
{
if (!this.HandleMouseUp (theEvent))
base.RightMouseUp (theEvent);
}

public override void MouseDown (NSEvent theEvent)
{
if (!this.HandleMouseDown (theEvent))
base.MouseDown (theEvent);
}

public override void MouseUp (NSEvent theEvent)
{
if (!this.HandleMouseUp (theEvent))
base.MouseUp (theEvent);
}

public override void OtherMouseDown (NSEvent theEvent)
{
if (!this.HandleMouseDown (theEvent))
base.OtherMouseDown (theEvent);
}

public override void OtherMouseUp (NSEvent theEvent)
{
if (!this.HandleMouseUp (theEvent))
base.OtherMouseUp (theEvent);
}

public override void MouseEntered (NSEvent theEvent)
{
this.HandleMouseEntered (theEvent);
base.MouseEntered (theEvent);
}

public override void MouseExited (NSEvent theEvent)
{
this.HandleMouseExited (theEvent);
base.MouseExited (theEvent);
}

public override void MouseMoved (NSEvent theEvent)
{
if (!this.HandleMouseMoved (theEvent))
base.MouseMoved (theEvent);
}

public override void MouseDragged (NSEvent theEvent)
{
if (!this.HandleMouseMoved (theEvent))
base.MouseDragged (theEvent);
}

public override void KeyDown (NSEvent theEvent)
{
if (!this.HandleKeyDown (theEvent))
base.KeyDown (theEvent);
}

public override void KeyUp (NSEvent theEvent)
{
if (!this.HandleKeyUp (theEvent))
base.KeyUp (theEvent);
}
}
}

131 changes: 124 additions & 7 deletions Xwt.XamMac/Xwt.Mac.CellViews/CellUtil.cs
Expand Up @@ -27,21 +27,29 @@
using System;
using System.Collections.Generic;
using AppKit;
using CoreGraphics;
using Xwt.Backends;

namespace Xwt.Mac
{
static class CellUtil
{
public static NSCell CreateCell (ApplicationContext context, NSTableView table, ICellSource source, ICollection<CellView> cells, int column)
public static CompositeCell CreateCellView (ApplicationContext context, NSTableView table, ICellSource source, ICollection<CellView> cells, int column)
{
CompositeCell c = new CompositeCell (context, Orientation.Horizontal, source);
CompositeCell c = new CompositeCell (context, source);
foreach (var cell in cells)
c.AddCell ((ICellRenderer) CreateCell (table, c, cell, column));
c.AddCell ((ICellRenderer) CreateCellView (table, cell, column));
return c;
}

public static void UpdateCellView (CompositeCell cellView, NSTableView table, ICollection<CellView> cells, int column)
{
cellView.ClearCells ();
foreach (var cell in cells)
cellView.AddCell ((ICellRenderer) CreateCellView (table, cell, column));
}

static NSCell CreateCell (NSTableView table, CompositeCell source, CellView cell, int column)
static NSView CreateCellView (NSTableView table, CellView cell, int column)
{
ICellRenderer cr = null;

Expand All @@ -57,10 +65,119 @@ static NSCell CreateCell (NSTableView table, CompositeCell source, CellView cell
cr = new RadioButtonTableCell ();
else
throw new NotImplementedException ();
cr.Backend = new CellViewBackend (table, column);
ICellViewFrontend fr = cell;
fr.AttachBackend (null, cr.Backend);
return (NSCell)cr;
CellViewBackend backend = null;
try {
//FIXME: although the cell views are based on XwtComponent, they don't implement
// the dynamic registration based backend creation and there is no way to
// identify whether the frontend has already a valid backend.
backend = cell.GetBackend () as CellViewBackend;
} catch (InvalidOperationException) { }

if (backend == null) {
cr.Backend = new CellViewBackend (table, column);
fr.AttachBackend (null, cr.Backend);
} else
cr.Backend = backend;
return (NSView)cr;
}

public static bool HandleMouseDown (this ICellRenderer cell, NSEvent theEvent)
{
if (cell.Backend.GetIsEventEnabled (WidgetEvent.ButtonPressed)) {
CGPoint p = cell.CellView.ConvertPointFromEvent (theEvent);
if (cell.CellView.Bounds.Contains (p)) {
cell.Backend.Load (cell);
cell.CellContainer.SetCurrentEventRow ();
ButtonEventArgs args = new ButtonEventArgs {
X = p.X,
Y = p.Y,
Button = theEvent.GetPointerButton(),
MultiplePress = (int)theEvent.ClickCount
};
cell.Backend.Context.InvokeUserCode (() => cell.Backend.EventSink.OnButtonPressed (args));
return args.Handled;
}
}
return false;
}

public static bool HandleMouseUp (this ICellRenderer cell, NSEvent theEvent)
{
if (cell.Backend.GetIsEventEnabled (WidgetEvent.ButtonReleased)) {
CGPoint p = cell.CellView.ConvertPointFromEvent (theEvent);
if (cell.CellView.Bounds.Contains (p)) {
cell.Backend.Load (cell);
cell.CellContainer.SetCurrentEventRow ();
ButtonEventArgs args = new ButtonEventArgs {
X = p.X,
Y = p.Y,
Button = theEvent.GetPointerButton (),
MultiplePress = (int)theEvent.ClickCount
};
cell.Backend.Context.InvokeUserCode (() => cell.Backend.EventSink.OnButtonReleased (args));
return args.Handled;
}
}
return false;
}

public static void HandleMouseEntered (this ICellRenderer cell, NSEvent theEvent)
{
if (cell.Backend.GetIsEventEnabled (WidgetEvent.MouseEntered)) {
cell.Backend.Load (cell);
cell.CellContainer.SetCurrentEventRow ();
cell.Backend.Context.InvokeUserCode (cell.Backend.EventSink.OnMouseEntered);
}
}

public static void HandleMouseExited (this ICellRenderer cell, NSEvent theEvent)
{
if (cell.Backend.GetIsEventEnabled (WidgetEvent.MouseExited)) {
cell.Backend.Load (cell);
cell.CellContainer.SetCurrentEventRow ();
cell.Backend.Context.InvokeUserCode (cell.Backend.EventSink.OnMouseExited);
}
}

public static bool HandleMouseMoved (this ICellRenderer cell, NSEvent theEvent)
{
if (cell.Backend.GetIsEventEnabled (WidgetEvent.MouseMoved)) {
CGPoint p = cell.CellView.ConvertPointFromEvent (theEvent);
if (cell.CellView.Bounds.Contains (p)) {
cell.Backend.Load (cell);
cell.CellContainer.SetCurrentEventRow ();
var offset = cell.Backend.CellBounds.Location;
MouseMovedEventArgs args = new MouseMovedEventArgs ((long)TimeSpan.FromSeconds (theEvent.Timestamp).TotalMilliseconds, p.X + offset.X, p.Y + offset.Y);
cell.Backend.Context.InvokeUserCode (() => cell.Backend.EventSink.OnMouseMoved (args));
return args.Handled;
}
}
return false;
}

public static bool HandleKeyDown (this ICellRenderer cell, NSEvent theEvent)
{
if (cell.Backend.GetIsEventEnabled (WidgetEvent.KeyPressed)) {
cell.Backend.Load (cell);
cell.CellContainer.SetCurrentEventRow ();
var keyArgs = theEvent.ToXwtKeyEventArgs ();
cell.Backend.Context.InvokeUserCode (() => cell.Backend.EventSink.OnKeyPressed (keyArgs));
return keyArgs.Handled;
}
return false;
}

public static bool HandleKeyUp (this ICellRenderer cell, NSEvent theEvent)
{
if (cell.Backend.GetIsEventEnabled (WidgetEvent.KeyReleased)) {
cell.Backend.Load (cell);
cell.CellContainer.SetCurrentEventRow ();
var keyArgs = theEvent.ToXwtKeyEventArgs ();
cell.Backend.Context.InvokeUserCode (() => cell.Backend.EventSink.OnKeyReleased (keyArgs));
return keyArgs.Handled;
}
return false;
}
}
}
Expand Down

0 comments on commit 2ef8261

Please sign in to comment.