1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 25 module gio.MenuModel; 26 27 private import gio.MenuAttributeIter; 28 private import gio.MenuLinkIter; 29 private import glib.Str; 30 private import glib.Variant; 31 private import glib.VariantType; 32 private import gobject.ObjectG; 33 private import gobject.Signals; 34 public import gtkc.gdktypes; 35 private import gtkc.gio; 36 public import gtkc.giotypes; 37 private import std.algorithm; 38 39 40 /** 41 * #GMenuModel represents the contents of a menu -- an ordered list of 42 * menu items. The items are associated with actions, which can be 43 * activated through them. Items can be grouped in sections, and may 44 * have submenus associated with them. Both items and sections usually 45 * have some representation data, such as labels or icons. The type of 46 * the associated action (ie whether it is stateful, and what kind of 47 * state it has) can influence the representation of the item. 48 * 49 * The conceptual model of menus in #GMenuModel is hierarchical: 50 * sections and submenus are again represented by #GMenuModels. 51 * Menus themselves do not define their own roles. Rather, the role 52 * of a particular #GMenuModel is defined by the item that references 53 * it (or, in the case of the 'root' menu, is defined by the context 54 * in which it is used). 55 * 56 * As an example, consider the visible portions of this menu: 57 * 58 * ## An example menu # {#menu-example} 59 * 60 * ![](menu-example.png) 61 * 62 * There are 8 "menus" visible in the screenshot: one menubar, two 63 * submenus and 5 sections: 64 * 65 * - the toplevel menubar (containing 4 items) 66 * - the View submenu (containing 3 sections) 67 * - the first section of the View submenu (containing 2 items) 68 * - the second section of the View submenu (containing 1 item) 69 * - the final section of the View submenu (containing 1 item) 70 * - the Highlight Mode submenu (containing 2 sections) 71 * - the Sources section (containing 2 items) 72 * - the Markup section (containing 2 items) 73 * 74 * The [example][menu-model] illustrates the conceptual connection between 75 * these 8 menus. Each large block in the figure represents a menu and the 76 * smaller blocks within the large block represent items in that menu. Some 77 * items contain references to other menus. 78 * 79 * ## A menu example # {#menu-model} 80 * 81 * ![](menu-model.png) 82 * 83 * Notice that the separators visible in the [example][menu-example] 84 * appear nowhere in the [menu model][menu-model]. This is because 85 * separators are not explicitly represented in the menu model. Instead, 86 * a separator is inserted between any two non-empty sections of a menu. 87 * Section items can have labels just like any other item. In that case, 88 * a display system may show a section header instead of a separator. 89 * 90 * The motivation for this abstract model of application controls is 91 * that modern user interfaces tend to make these controls available 92 * outside the application. Examples include global menus, jumplists, 93 * dash boards, etc. To support such uses, it is necessary to 'export' 94 * information about actions and their representation in menus, which 95 * is exactly what the [GActionGroup exporter][gio-GActionGroup-exporter] 96 * and the [GMenuModel exporter][gio-GMenuModel-exporter] do for 97 * #GActionGroup and #GMenuModel. The client-side counterparts to 98 * make use of the exported information are #GDBusActionGroup and 99 * #GDBusMenuModel. 100 * 101 * The API of #GMenuModel is very generic, with iterators for the 102 * attributes and links of an item, see g_menu_model_iterate_item_attributes() 103 * and g_menu_model_iterate_item_links(). The 'standard' attributes and 104 * link types have predefined names: %G_MENU_ATTRIBUTE_LABEL, 105 * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, %G_MENU_LINK_SECTION 106 * and %G_MENU_LINK_SUBMENU. 107 * 108 * Items in a #GMenuModel represent active controls if they refer to 109 * an action that can get activated when the user interacts with the 110 * menu item. The reference to the action is encoded by the string id 111 * in the %G_MENU_ATTRIBUTE_ACTION attribute. An action id uniquely 112 * identifies an action in an action group. Which action group(s) provide 113 * actions depends on the context in which the menu model is used. 114 * E.g. when the model is exported as the application menu of a 115 * #GtkApplication, actions can be application-wide or window-specific 116 * (and thus come from two different action groups). By convention, the 117 * application-wide actions have names that start with "app.", while the 118 * names of window-specific actions start with "win.". 119 * 120 * While a wide variety of stateful actions is possible, the following 121 * is the minimum that is expected to be supported by all users of exported 122 * menu information: 123 * - an action with no parameter type and no state 124 * - an action with no parameter type and boolean state 125 * - an action with string parameter type and string state 126 * 127 * ## Stateless 128 * 129 * A stateless action typically corresponds to an ordinary menu item. 130 * 131 * Selecting such a menu item will activate the action (with no parameter). 132 * 133 * ## Boolean State 134 * 135 * An action with a boolean state will most typically be used with a "toggle" 136 * or "switch" menu item. The state can be set directly, but activating the 137 * action (with no parameter) results in the state being toggled. 138 * 139 * Selecting a toggle menu item will activate the action. The menu item should 140 * be rendered as "checked" when the state is true. 141 * 142 * ## String Parameter and State 143 * 144 * Actions with string parameters and state will most typically be used to 145 * represent an enumerated choice over the items available for a group of 146 * radio menu items. Activating the action with a string parameter is 147 * equivalent to setting that parameter as the state. 148 * 149 * Radio menu items, in addition to being associated with the action, will 150 * have a target value. Selecting that menu item will result in activation 151 * of the action with the target value as the parameter. The menu item should 152 * be rendered as "selected" when the state of the action is equal to the 153 * target value of the menu item. 154 * 155 * Since: 2.32 156 */ 157 public class MenuModel : ObjectG 158 { 159 /** the main Gtk struct */ 160 protected GMenuModel* gMenuModel; 161 162 /** Get the main Gtk struct */ 163 public GMenuModel* getMenuModelStruct() 164 { 165 return gMenuModel; 166 } 167 168 /** the main Gtk struct as a void* */ 169 protected override void* getStruct() 170 { 171 return cast(void*)gMenuModel; 172 } 173 174 protected override void setStruct(GObject* obj) 175 { 176 gMenuModel = cast(GMenuModel*)obj; 177 super.setStruct(obj); 178 } 179 180 /** 181 * Sets our main struct and passes it to the parent class. 182 */ 183 public this (GMenuModel* gMenuModel, bool ownedRef = false) 184 { 185 this.gMenuModel = gMenuModel; 186 super(cast(GObject*)gMenuModel, ownedRef); 187 } 188 189 190 /** */ 191 public static GType getType() 192 { 193 return g_menu_model_get_type(); 194 } 195 196 /** 197 * Queries the item at position @item_index in @model for the attribute 198 * specified by @attribute. 199 * 200 * If @expected_type is non-%NULL then it specifies the expected type of 201 * the attribute. If it is %NULL then any type will be accepted. 202 * 203 * If the attribute exists and matches @expected_type (or if the 204 * expected type is unspecified) then the value is returned. 205 * 206 * If the attribute does not exist, or does not match the expected type 207 * then %NULL is returned. 208 * 209 * Params: 210 * itemIndex = the index of the item 211 * attribute = the attribute to query 212 * expectedType = the expected type of the attribute, or 213 * %NULL 214 * 215 * Return: the value of the attribute 216 * 217 * Since: 2.32 218 */ 219 public Variant getItemAttributeValue(int itemIndex, string attribute, VariantType expectedType) 220 { 221 auto p = g_menu_model_get_item_attribute_value(gMenuModel, itemIndex, Str.toStringz(attribute), (expectedType is null) ? null : expectedType.getVariantTypeStruct()); 222 223 if(p is null) 224 { 225 return null; 226 } 227 228 return new Variant(cast(GVariant*) p, true); 229 } 230 231 /** 232 * Queries the item at position @item_index in @model for the link 233 * specified by @link. 234 * 235 * If the link exists, the linked #GMenuModel is returned. If the link 236 * does not exist, %NULL is returned. 237 * 238 * Params: 239 * itemIndex = the index of the item 240 * link = the link to query 241 * 242 * Return: the linked #GMenuModel, or %NULL 243 * 244 * Since: 2.32 245 */ 246 public MenuModel getItemLink(int itemIndex, string link) 247 { 248 auto p = g_menu_model_get_item_link(gMenuModel, itemIndex, Str.toStringz(link)); 249 250 if(p is null) 251 { 252 return null; 253 } 254 255 return ObjectG.getDObject!(MenuModel)(cast(GMenuModel*) p, true); 256 } 257 258 /** 259 * Query the number of items in @model. 260 * 261 * Return: the number of items 262 * 263 * Since: 2.32 264 */ 265 public int getNItems() 266 { 267 return g_menu_model_get_n_items(gMenuModel); 268 } 269 270 /** 271 * Queries if @model is mutable. 272 * 273 * An immutable #GMenuModel will never emit the #GMenuModel::items-changed 274 * signal. Consumers of the model may make optimisations accordingly. 275 * 276 * Return: %TRUE if the model is mutable (ie: "items-changed" may be 277 * emitted). 278 * 279 * Since: 2.32 280 */ 281 public bool isMutable() 282 { 283 return g_menu_model_is_mutable(gMenuModel) != 0; 284 } 285 286 /** 287 * Requests emission of the #GMenuModel::items-changed signal on @model. 288 * 289 * This function should never be called except by #GMenuModel 290 * subclasses. Any other calls to this function will very likely lead 291 * to a violation of the interface of the model. 292 * 293 * The implementation should update its internal representation of the 294 * menu before emitting the signal. The implementation should further 295 * expect to receive queries about the new state of the menu (and 296 * particularly added menu items) while signal handlers are running. 297 * 298 * The implementation must dispatch this call directly from a mainloop 299 * entry and not in response to calls -- particularly those from the 300 * #GMenuModel API. Said another way: the menu must not change while 301 * user code is running without returning to the mainloop. 302 * 303 * Params: 304 * position = the position of the change 305 * removed = the number of items removed 306 * added = the number of items added 307 * 308 * Since: 2.32 309 */ 310 public void itemsChanged(int position, int removed, int added) 311 { 312 g_menu_model_items_changed(gMenuModel, position, removed, added); 313 } 314 315 /** 316 * Creates a #GMenuAttributeIter to iterate over the attributes of 317 * the item at position @item_index in @model. 318 * 319 * You must free the iterator with g_object_unref() when you are done. 320 * 321 * Params: 322 * itemIndex = the index of the item 323 * 324 * Return: a new #GMenuAttributeIter 325 * 326 * Since: 2.32 327 */ 328 public MenuAttributeIter iterateItemAttributes(int itemIndex) 329 { 330 auto p = g_menu_model_iterate_item_attributes(gMenuModel, itemIndex); 331 332 if(p is null) 333 { 334 return null; 335 } 336 337 return ObjectG.getDObject!(MenuAttributeIter)(cast(GMenuAttributeIter*) p, true); 338 } 339 340 /** 341 * Creates a #GMenuLinkIter to iterate over the links of the item at 342 * position @item_index in @model. 343 * 344 * You must free the iterator with g_object_unref() when you are done. 345 * 346 * Params: 347 * itemIndex = the index of the item 348 * 349 * Return: a new #GMenuLinkIter 350 * 351 * Since: 2.32 352 */ 353 public MenuLinkIter iterateItemLinks(int itemIndex) 354 { 355 auto p = g_menu_model_iterate_item_links(gMenuModel, itemIndex); 356 357 if(p is null) 358 { 359 return null; 360 } 361 362 return ObjectG.getDObject!(MenuLinkIter)(cast(GMenuLinkIter*) p, true); 363 } 364 365 protected class OnItemsChangedDelegateWrapper 366 { 367 void delegate(int, int, int, MenuModel) dlg; 368 gulong handlerId; 369 ConnectFlags flags; 370 this(void delegate(int, int, int, MenuModel) dlg, gulong handlerId, ConnectFlags flags) 371 { 372 this.dlg = dlg; 373 this.handlerId = handlerId; 374 this.flags = flags; 375 } 376 } 377 protected OnItemsChangedDelegateWrapper[] onItemsChangedListeners; 378 379 /** 380 * Emitted when a change has occured to the menu. 381 * 382 * The only changes that can occur to a menu is that items are removed 383 * or added. Items may not change (except by being removed and added 384 * back in the same location). This signal is capable of describing 385 * both of those changes (at the same time). 386 * 387 * The signal means that starting at the index @position, @removed 388 * items were removed and @added items were added in their place. If 389 * @removed is zero then only items were added. If @added is zero 390 * then only items were removed. 391 * 392 * As an example, if the menu contains items a, b, c, d (in that 393 * order) and the signal (2, 1, 3) occurs then the new composition of 394 * the menu will be a, b, _, _, _, d (with each _ representing some 395 * new item). 396 * 397 * Signal handlers may query the model (particularly the added items) 398 * and expect to see the results of the modification that is being 399 * reported. The signal is emitted after the modification. 400 * 401 * Params: 402 * position = the position of the change 403 * removed = the number of items removed 404 * added = the number of items added 405 */ 406 gulong addOnItemsChanged(void delegate(int, int, int, MenuModel) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 407 { 408 onItemsChangedListeners ~= new OnItemsChangedDelegateWrapper(dlg, 0, connectFlags); 409 onItemsChangedListeners[onItemsChangedListeners.length - 1].handlerId = Signals.connectData( 410 this, 411 "items-changed", 412 cast(GCallback)&callBackItemsChanged, 413 cast(void*)onItemsChangedListeners[onItemsChangedListeners.length - 1], 414 cast(GClosureNotify)&callBackItemsChangedDestroy, 415 connectFlags); 416 return onItemsChangedListeners[onItemsChangedListeners.length - 1].handlerId; 417 } 418 419 extern(C) static void callBackItemsChanged(GMenuModel* menumodelStruct, int position, int removed, int added,OnItemsChangedDelegateWrapper wrapper) 420 { 421 wrapper.dlg(position, removed, added, wrapper.outer); 422 } 423 424 extern(C) static void callBackItemsChangedDestroy(OnItemsChangedDelegateWrapper wrapper, GClosure* closure) 425 { 426 wrapper.outer.internalRemoveOnItemsChanged(wrapper); 427 } 428 429 protected void internalRemoveOnItemsChanged(OnItemsChangedDelegateWrapper source) 430 { 431 foreach(index, wrapper; onItemsChangedListeners) 432 { 433 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 434 { 435 onItemsChangedListeners[index] = null; 436 onItemsChangedListeners = std.algorithm.remove(onItemsChangedListeners, index); 437 break; 438 } 439 } 440 } 441 442 }