Skip to content

Commit

Permalink
Merge pull request #2317 from picoe/dropdowntoolitem
Browse files Browse the repository at this point in the history
Add DropDownToolItem
  • Loading branch information
cwensley committed Sep 21, 2022
2 parents 4c4d823 + 56c893b commit a5cad53
Show file tree
Hide file tree
Showing 21 changed files with 696 additions and 33 deletions.
150 changes: 150 additions & 0 deletions src/Eto.Gtk/Forms/ToolBar/DropDownToolItemHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using System;
using Eto.Drawing;
using Eto.Forms;
using Gdk;

namespace Eto.GtkSharp.Forms.ToolBar
{

public class DropDownToolItemHandler : ToolItemHandler<Gtk.ToggleToolButton, DropDownToolItem>, DropDownToolItem.IHandler
{
// GTK3 MenuToolButton looks kind of horrible with a huge visually separate drop button, and forces
// the main button and drop button to function separately. So, use a normal ToolButton with a Menu, but
// add a drop arrow to the button text.

private Gtk.Menu dropMenu;
bool showDropArrow = true;

public DropDownToolItemHandler()
{
dropMenu = new Gtk.Menu();
}

#region IToolBarButton Members


#endregion

public override void CreateControl(ToolBarHandler handler, int index)
{
Gtk.Toolbar tb = handler.Control;

Control = new Gtk.ToggleToolButton();
Control.IconWidget = GtkImage;
Control.IsImportant = true;
Control.Sensitive = Enabled;
Control.TooltipText = this.ToolTip;
Control.ShowAll();
Control.NoShowAll = true;
Control.Visible = Visible;
//control.CanFocus = false; // why is this disabled and not true???
tb.Insert(Control, index);
Control.Clicked += HandleClicked;
dropMenu.Hidden += HandleMenuClosed;
SetText();
}

protected override void SetText()
{
if (Control != null)
Control.Label = ShowDropArrow ? Text + "" : Text;
}

/// <summary>
/// Gets or sets whether the drop arrow is shown on the button.
/// </summary>
public bool ShowDropArrow
{
get => showDropArrow;
set
{
if (showDropArrow != value)
{
showDropArrow = value;
SetText();
}
}
}

#if GTKCORE
private void HandleClicked(object sender, EventArgs e)
{
if (!Control.Active)
return;

dropMenu.PopupAtWidget(Control, Gravity.SouthWest, Gravity.NorthWest, null);
Connector.HandleClicked(sender, e);
}
#else
private void HandleClicked(object sender, EventArgs e)
{
if (!Control.Active)
return;

var buttonRect = Control.Allocation;
var pt = new PointF(buttonRect.Left, buttonRect.Bottom);
var parentWindow = (Widget.Parent as Eto.Forms.ToolBar).Parent as Eto.Forms.Window;
showLocation = parentWindow.PointToScreen(pt);
dropMenu.Popup(null, null, PopupMenuPosition, 3u, Gtk.Global.CurrentEventTime);

Connector.HandleClicked(sender, e);
}

PointF showLocation;

void PopupMenuPosition(Gtk.Menu menu, out int x, out int y, out bool push_in)
{
x = (int)showLocation.X;
y = (int)showLocation.Y;
push_in = false;
}
#endif

private void HandleMenuClosed(Object sender, EventArgs e)
{
Control.Active = false;
}

protected new DropDownToolItemConnector Connector { get { return (DropDownToolItemConnector)base.Connector; } }

protected override WeakConnector CreateConnector()
{
return new DropDownToolItemConnector();
}

protected class DropDownToolItemConnector : WeakConnector
{
public new DropDownToolItemHandler Handler { get { return (DropDownToolItemHandler)base.Handler; } }

public void HandleClicked(object sender, EventArgs e)
{
Handler.Widget.OnClick(e);
}
}

public void AddMenu(int index, MenuItem item)
{
dropMenu.Insert((Gtk.Widget)item.ControlObject, index);
var handler = item.Handler as Menu.IMenuHandler;
//SetChildAccelGroup(item);
}

public void RemoveMenu(MenuItem item)
{
dropMenu.Remove((Gtk.Widget)item.ControlObject);
/*
var handler = item.Handler as Menu.IMenuHandler;
if (handler != null)
handler.SetAccelGroup(null);
*/
}

public void Clear()
{
foreach (Gtk.Widget w in dropMenu.Children)
{
dropMenu.Remove(w);
}
}
}
}
42 changes: 39 additions & 3 deletions src/Eto.Gtk/Forms/ToolBar/ToolItemHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,56 @@ public interface IToolBarItemHandler
}

public abstract class ToolItemHandler<TControl, TWidget> : WidgetHandler<TControl, TWidget>, ToolItem.IHandler, IToolBarItemHandler
where TControl: Gtk.Widget
where TControl: Gtk.ToolItem
where TWidget: ToolItem
{
bool enabled = true;
bool visible = true;
string text;
string toolTip;
Image image;

protected Gtk.Image GtkImage { get; set; }

public abstract void CreateControl(ToolBarHandler handler, int index);

public string Text { get; set; }
public string Text
{
get => text;
set
{
if (text != value)
{
text = value;
SetText();
}
}
}

public virtual string ToolTip
{
get => toolTip;
set
{
if (toolTip != value)
{
toolTip = value;
SetToolTip();
}
}
}

protected virtual void SetText()
{
if (Control is Gtk.ToolButton button)
button.Label = Text;
}

public string ToolTip { get; set; }
protected virtual void SetToolTip()
{
if (Control is Gtk.ToolButton button)
button.TooltipText = ToolTip;
}

public Image Image
{
Expand Down
1 change: 1 addition & 0 deletions src/Eto.Gtk/Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ public static void AddTo(Eto.Platform p)
p.Add<RadioToolItem.IHandler>(() => new RadioToolItemHandler());
p.Add<SeparatorToolItem.IHandler>(() => new SeparatorToolItemHandler());
p.Add<ButtonToolItem.IHandler>(() => new ButtonToolItemHandler());
p.Add<DropDownToolItem.IHandler>(() => new DropDownToolItemHandler());
p.Add<ToolBar.IHandler>(() => new ToolBarHandler());

// Forms
Expand Down
1 change: 1 addition & 0 deletions src/Eto.Mac/Eto.Mac64.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ You do not need to use any of the classes of this assembly (unless customizing t
<Using Include="System.Double" Alias="nfloat" />
<Using Include="System.Int64" Alias="nint" />
<Using Include="System.UInt64" Alias="nuint" />
<Using Include="System.IntPtr" Alias="NativeHandle" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Eto.Mac/Eto.XamMac2.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<Using Include="CoreFoundation" />
<Using Include="ImageIO" />
<Using Include="CoreText" />
<Using Include="System.IntPtr" Alias="NativeHandle" />
</ItemGroup>

<PropertyGroup>
Expand Down
6 changes: 3 additions & 3 deletions src/Eto.Mac/Forms/Controls/SegmentedButtonHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -391,9 +391,9 @@ public void InsertItem(int index, SegmentedItem item)
static readonly IntPtr selSetShowsMenuIndicator = Selector.GetHandle("setShowsMenuIndicator:forSegment:");

// 10.13+
static readonly bool supportsTooltip = ObjCExtensions.InstancesRespondToSelector<NSSegmentedCell>(selSetToolTipForSegment);
static readonly bool supportsMenuIndicator = ObjCExtensions.InstancesRespondToSelector<NSSegmentedControl>(selSetShowsMenuIndicator);

internal static readonly bool supportsTooltip = ObjCExtensions.InstancesRespondToSelector<NSSegmentedCell>(selSetToolTipForSegment);
internal static readonly bool supportsMenuIndicator = ObjCExtensions.InstancesRespondToSelector<NSSegmentedControl>(selSetShowsMenuIndicator);
public void SetItem(int index, SegmentedItem item)
{
Control.SetLabel(item.Text ?? string.Empty, index);
Expand Down
9 changes: 9 additions & 0 deletions src/Eto.Mac/Forms/Menu/MenuHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ public interface IMenuHandler
public class EtoMenu : NSMenu
{
public bool WorksWhenModal { get; set; }

public EtoMenu()
{
}

public EtoMenu(NativeHandle handle)
: base(handle)
{
}
}

static class MenuHandler
Expand Down
85 changes: 85 additions & 0 deletions src/Eto.Mac/Forms/ToolBar/DropDownToolItemHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System;
using Eto.Drawing;
using Eto.Forms;

namespace Eto.Mac.Forms.ToolBar
{
public class DropDownToolItemHandler : ToolItemHandler<NSMenuToolbarItem, DropDownToolItem>, DropDownToolItem.IHandler
{
NSMenu menu;

protected override bool UseButtonStyle => false;
protected override bool UseAction => false;

#if MACOS || XAMMAC2
static readonly IntPtr selInitWithItemIdentifier_Handle = Selector.GetHandle("initWithItemIdentifier:");

// constructor with identifier isn't available in the version of macOS workload we need yet..
class EtoMenuToolbarItem : NSMenuToolbarItem
{
public EtoMenuToolbarItem()
{
}

[Export ("initWithItemIdentifier:")]
public EtoMenuToolbarItem (string itemIdentifier)
: base (NSObjectFlag.Empty)
{
NSApplication.EnsureUIThread ();
if (itemIdentifier == null)
throw new ArgumentNullException ("itemIdentifier");
#if USE_CFSTRING
var nsitemIdentifier = CFString.CreateNative(itemIdentifier);
#else
var nsitemIdentifier = NSString.CreateNative(itemIdentifier);
#endif

if (IsDirectBinding) {
Handle = Messaging.IntPtr_objc_msgSend_IntPtr (this.Handle, selInitWithItemIdentifier_Handle, nsitemIdentifier);
} else {
Handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr (this.SuperHandle, selInitWithItemIdentifier_Handle, nsitemIdentifier);
}
NSString.ReleaseNative (nsitemIdentifier);

}
}

protected override NSMenuToolbarItem CreateControl() => new EtoMenuToolbarItem(Identifier);
#else
protected override NSMenuToolbarItem CreateControl() => new NSMenuToolbarItem(Identifier);
#endif

public bool ShowDropArrow
{
get => Control.ShowsIndicator;
set => Control.ShowsIndicator = value;
}

protected override void Initialize()
{
base.Initialize();
Control.ShowsIndicator = true;
menu = new NSMenu();
menu.AutoEnablesItems = true;
menu.ShowsStateColumn = true;
Control.Menu = menu;
// first item is never shown, it's the "title" of the pull down?? weird.
menu.InsertItem(new NSMenuItem(string.Empty), 0);
}

public void AddMenu(int index, MenuItem item)
{
menu.InsertItem((NSMenuItem)item.ControlObject, index + 1);
}

public void RemoveMenu(MenuItem item)
{
menu.RemoveItem((NSMenuItem)item.ControlObject);
}

public void Clear()
{
menu.RemoveAllItems();
}
}
}
Loading

0 comments on commit a5cad53

Please sign in to comment.