|
| 1 | +/* |
| 2 | +* Copyright (c) 2025 (https://github.com/phase1geo/Minder) |
| 3 | +* |
| 4 | +* This program is free software; you can redistribute it and/or |
| 5 | +* modify it under the terms of the GNU General Public |
| 6 | +* License as published by the Free Software Foundation; either |
| 7 | +* version 2 of the License, or (at your option) any later version. |
| 8 | +* |
| 9 | +* This program is distributed in the hope that it will be useful, |
| 10 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | +* General Public License for more details. |
| 13 | +* |
| 14 | +* You should have received a copy of the GNU General Public |
| 15 | +* License along with this program; if not, write to the |
| 16 | +* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 17 | +* Boston, MA 02110-1301 USA |
| 18 | +* |
| 19 | +* Authored by: Trevor Williams <[email protected]> |
| 20 | +*/ |
| 21 | + |
| 22 | +public class BaseMenu { |
| 23 | + |
| 24 | + private Gtk.Application _app; |
| 25 | + private OutlineTable _ot; |
| 26 | + private string _group_name; |
| 27 | + private SimpleActionGroup _group; |
| 28 | + private Gtk.PopoverMenu _popover; |
| 29 | + private GLib.Menu _menu; |
| 30 | + |
| 31 | + public OutlineTable ot { |
| 32 | + get { |
| 33 | + return( _ot ); |
| 34 | + } |
| 35 | + } |
| 36 | + protected GLib.Menu menu { |
| 37 | + get { |
| 38 | + return( _menu ); |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + //------------------------------------------------------------- |
| 43 | + // Default constructor |
| 44 | + public BaseMenu( Gtk.Application app, OutlineTable ot, string group ) { |
| 45 | + |
| 46 | + _ot = ot; |
| 47 | + _app = app; |
| 48 | + _group_name = group; |
| 49 | + |
| 50 | + // Handle any updates to shortcuts in the menu |
| 51 | + ot.win.shortcuts.shortcut_changed.connect( handle_shortcut_change ); |
| 52 | + |
| 53 | + // Create and add the action group to the mindmap canvas |
| 54 | + _group = new SimpleActionGroup(); |
| 55 | + _ot.insert_action_group( _group_name, _group ); |
| 56 | + |
| 57 | + // Create the main menu |
| 58 | + _menu = new GLib.Menu(); |
| 59 | + |
| 60 | + // Create the popover for the menu |
| 61 | + _popover = new Gtk.PopoverMenu.from_model( _menu ); |
| 62 | + _popover.set_parent( ot ); |
| 63 | + _popover.closed.connect( on_popdown ); |
| 64 | + |
| 65 | + } |
| 66 | + |
| 67 | + //------------------------------------------------------------- |
| 68 | + // Called when the menu is just about to be shown. Use this |
| 69 | + // to set the enabled values of menu items. |
| 70 | + protected virtual void on_popup() {} |
| 71 | + |
| 72 | + //------------------------------------------------------------- |
| 73 | + // Called when the menu is being hidden. |
| 74 | + protected virtual void on_popdown() {} |
| 75 | + |
| 76 | + //------------------------------------------------------------- |
| 77 | + // Shows the menu at the given location. |
| 78 | + public void show( double x, double y ) { |
| 79 | + |
| 80 | + // Set the menu state |
| 81 | + on_popup(); |
| 82 | + |
| 83 | + // Display the popover at the given location |
| 84 | + Gdk.Rectangle rect = {(int)x, (int)y, 1, 1}; |
| 85 | + _popover.pointing_to = rect; |
| 86 | + _popover.popup(); |
| 87 | + |
| 88 | + } |
| 89 | + |
| 90 | + //------------------------------------------------------------- |
| 91 | + // Hides the menu. |
| 92 | + public void hide() { |
| 93 | + _popover.popdown(); |
| 94 | + } |
| 95 | + |
| 96 | + //------------------------------------------------------------- |
| 97 | + // Returns the detailed action name for the given command. |
| 98 | + private string detailed_name( KeyCommand command ) { |
| 99 | + return( "%s.%s".printf( _group_name, command.to_string() ) ); |
| 100 | + } |
| 101 | + |
| 102 | + //------------------------------------------------------------- |
| 103 | + // Appends a command with the given command to the specified menu. |
| 104 | + protected void append_menu_item( GLib.Menu menu, KeyCommand command, string label, bool grab_canvas = true ) { |
| 105 | + |
| 106 | + menu.append( label, detailed_name( command ) ); |
| 107 | + |
| 108 | + // Create action to execute |
| 109 | + var action = new SimpleAction( command.to_string(), null ); |
| 110 | + action.activate.connect((v) => { |
| 111 | + var func = command.get_func(); |
| 112 | + func( _ot ); |
| 113 | + if( grab_canvas ) { |
| 114 | + _ot.grab_focus(); |
| 115 | + } |
| 116 | + }); |
| 117 | + _group.add_action( action ); |
| 118 | + |
| 119 | + var shortcut = _ot.win.shortcuts.get_shortcut( command ); |
| 120 | + if( shortcut != null ) { |
| 121 | + _app.set_accels_for_action( detailed_name( command ), { shortcut.get_accelerator() } ); |
| 122 | + } |
| 123 | + |
| 124 | + } |
| 125 | + |
| 126 | + //------------------------------------------------------------- |
| 127 | + // Changes the menu label to the given string for the given command. |
| 128 | + protected void change_menu_item_label( GLib.Menu menu, KeyCommand command, string label ) { |
| 129 | + var detailed_action = detailed_name( command ); |
| 130 | + for( int i=0; i<menu.get_n_items(); i++ ) { |
| 131 | + var variant = menu.get_item_attribute_value( i, GLib.Menu.ATTRIBUTE_ACTION, null ); |
| 132 | + if( (variant != null) && (variant.get_string() == detailed_action) ) { |
| 133 | + menu.remove( i ); |
| 134 | + menu.insert( i, label, detailed_name( command ) ); |
| 135 | + return; |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + //------------------------------------------------------------- |
| 141 | + // Sets the action enable for the given command to the given value. |
| 142 | + protected void set_enabled( KeyCommand command, bool enable ) { |
| 143 | + var action = _group.lookup_action( command.to_string() ); |
| 144 | + if( action != null ) { |
| 145 | + (action as SimpleAction).set_enabled( enable ); |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + //------------------------------------------------------------- |
| 150 | + // Handles any changes to the shortcuts manager and updates the |
| 151 | + // affected accelerator. |
| 152 | + private void handle_shortcut_change( KeyCommand command, Shortcut? shortcut ) { |
| 153 | + var action = _group.lookup_action( command.to_string() ); |
| 154 | + if( action != null ) { |
| 155 | + if( shortcut == null ) { |
| 156 | + shortcut_removed( command ); |
| 157 | + } else { |
| 158 | + shortcut_added( shortcut ); |
| 159 | + } |
| 160 | + } |
| 161 | + } |
| 162 | + |
| 163 | + //------------------------------------------------------------- |
| 164 | + // Removes the accelerator for the given shortcut command. |
| 165 | + private void shortcut_removed( KeyCommand command ) { |
| 166 | + _app.set_accels_for_action( detailed_name( command ), {} ); |
| 167 | + } |
| 168 | + |
| 169 | + //------------------------------------------------------------- |
| 170 | + // Adds the accelerator for the given shortcut. |
| 171 | + private void shortcut_added( Shortcut shortcut ) { |
| 172 | + _app.set_accels_for_action( detailed_name( shortcut.command ), { shortcut.get_accelerator() } ); |
| 173 | + |
| 174 | + } |
| 175 | + |
| 176 | +} |
0 commit comments