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 gtk.Dialog; 26 27 private import gdk.Screen; 28 private import glib.ConstructionException; 29 private import glib.Str; 30 private import gobject.ObjectG; 31 private import gobject.Signals; 32 private import gtk.Button; 33 private import gtk.HButtonBox; 34 private import gtk.VBox; 35 private import gtk.Widget; 36 private import gtk.Window; 37 public import gtkc.gdktypes; 38 private import gtkc.gtk; 39 public import gtkc.gtktypes; 40 private import std.algorithm; 41 42 43 /** 44 * Dialog boxes are a convenient way to prompt the user for a small amount 45 * of input, e.g. to display a message, ask a question, or anything else 46 * that does not require extensive effort on the user’s part. 47 * 48 * GTK+ treats a dialog as a window split vertically. The top section is a 49 * #GtkVBox, and is where widgets such as a #GtkLabel or a #GtkEntry should 50 * be packed. The bottom area is known as the 51 * “action area”. This is generally used for 52 * packing buttons into the dialog which may perform functions such as 53 * cancel, ok, or apply. 54 * 55 * #GtkDialog boxes are created with a call to gtk_dialog_new() or 56 * gtk_dialog_new_with_buttons(). gtk_dialog_new_with_buttons() is 57 * recommended; it allows you to set the dialog title, some convenient 58 * flags, and add simple buttons. 59 * 60 * If “dialog” is a newly created dialog, the two primary areas of the 61 * window can be accessed through gtk_dialog_get_content_area() and 62 * gtk_dialog_get_action_area(), as can be seen from the example below. 63 * 64 * A “modal” dialog (that is, one which freezes the rest of the application 65 * from user input), can be created by calling gtk_window_set_modal() on the 66 * dialog. Use the GTK_WINDOW() macro to cast the widget returned from 67 * gtk_dialog_new() into a #GtkWindow. When using gtk_dialog_new_with_buttons() 68 * you can also pass the #GTK_DIALOG_MODAL flag to make a dialog modal. 69 * 70 * If you add buttons to #GtkDialog using gtk_dialog_new_with_buttons(), 71 * gtk_dialog_add_button(), gtk_dialog_add_buttons(), or 72 * gtk_dialog_add_action_widget(), clicking the button will emit a signal 73 * called #GtkDialog::response with a response ID that you specified. GTK+ 74 * will never assign a meaning to positive response IDs; these are entirely 75 * user-defined. But for convenience, you can use the response IDs in the 76 * #GtkResponseType enumeration (these all have values less than zero). If 77 * a dialog receives a delete event, the #GtkDialog::response signal will 78 * be emitted with a response ID of #GTK_RESPONSE_DELETE_EVENT. 79 * 80 * If you want to block waiting for a dialog to return before returning 81 * control flow to your code, you can call gtk_dialog_run(). This function 82 * enters a recursive main loop and waits for the user to respond to the 83 * dialog, returning the response ID corresponding to the button the user 84 * clicked. 85 * 86 * For the simple dialog in the following example, in reality you’d probably 87 * use #GtkMessageDialog to save yourself some effort. But you’d need to 88 * create the dialog contents manually if you had more than a simple message 89 * in the dialog. 90 * 91 * An example for simple GtkDialog usage: 92 * |[<!-- language="C" --> 93 * // Function to open a dialog box with a message 94 * void 95 * quick_message (GtkWindow *parent, gchar *message) 96 * { 97 * GtkWidget *dialog, *label, *content_area; 98 * GtkDialogFlags flags; 99 * 100 * // Create the widgets 101 * flags = GTK_DIALOG_DESTROY_WITH_PARENT; 102 * dialog = gtk_dialog_new_with_buttons ("Message", 103 * parent, 104 * flags, 105 * _("_OK"), 106 * GTK_RESPONSE_NONE, 107 * NULL); 108 * content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); 109 * label = gtk_label_new (message); 110 * 111 * // Ensure that the dialog box is destroyed when the user responds 112 * 113 * g_signal_connect_swapped (dialog, 114 * "response", 115 * G_CALLBACK (gtk_widget_destroy), 116 * dialog); 117 * 118 * // Add the label, and show everything we’ve added 119 * 120 * gtk_container_add (GTK_CONTAINER (content_area), label); 121 * gtk_widget_show_all (dialog); 122 * } 123 * ]| 124 * 125 * # GtkDialog as GtkBuildable 126 * 127 * The GtkDialog implementation of the #GtkBuildable interface exposes the 128 * @vbox and @action_area as internal children with the names “vbox” and 129 * “action_area”. 130 * 131 * GtkDialog supports a custom <action-widgets> element, which can contain 132 * multiple <action-widget> elements. The “response” attribute specifies a 133 * numeric response, and the content of the element is the id of widget 134 * (which should be a child of the dialogs @action_area). To mark a response 135 * as default, set the “default“ attribute of the <action-widget> element 136 * to true. 137 * 138 * GtkDialog supports adding action widgets by specifying “action“ as 139 * the “type“ attribute of a <child> element. The widget will be added 140 * either to the action area or the headerbar of the dialog, depending 141 * on the “use-header-bar“ property. The response id has to be associated 142 * with the action widget using the <action-widgets> element. 143 * 144 * An example of a #GtkDialog UI definition fragment: 145 * |[ 146 * <object class="GtkDialog" id="dialog1"> 147 * <child type="action"> 148 * <object class="GtkButton" id="button_cancel"/> 149 * </child> 150 * <child type="action"> 151 * <object class="GtkButton" id="button_ok"> 152 * <property name="can-default">True</property> 153 * </object> 154 * </child> 155 * <action-widgets> 156 * <action-widget response="cancel">button_cancel</action-widget> 157 * <action-widget response="ok" default="true">button_ok</action-widget> 158 * </action-widgets> 159 * </object> 160 * ]| 161 */ 162 public class Dialog : Window 163 { 164 /** the main Gtk struct */ 165 protected GtkDialog* gtkDialog; 166 167 /** Get the main Gtk struct */ 168 public GtkDialog* getDialogStruct() 169 { 170 return gtkDialog; 171 } 172 173 /** the main Gtk struct as a void* */ 174 protected override void* getStruct() 175 { 176 return cast(void*)gtkDialog; 177 } 178 179 protected override void setStruct(GObject* obj) 180 { 181 gtkDialog = cast(GtkDialog*)obj; 182 super.setStruct(obj); 183 } 184 185 /** 186 * Sets our main struct and passes it to the parent class. 187 */ 188 public this (GtkDialog* gtkDialog, bool ownedRef = false) 189 { 190 this.gtkDialog = gtkDialog; 191 super(cast(GtkWindow*)gtkDialog, ownedRef); 192 } 193 194 /** 195 * Both title and parent can be null. 196 */ 197 this(string title, Window parent, GtkDialogFlags flags, string[] buttonsText, ResponseType[] responses) 198 { 199 auto p = gtk_dialog_new_with_buttons(Str.toStringz(title), (parent is null) ? null : parent.getWindowStruct(), flags, Str.toStringz(buttonsText[0]), responses[0], null); 200 if(p is null) 201 { 202 throw new ConstructionException("null returned by gtk_dialog_new_with_buttons"); 203 } 204 205 this(cast(GtkDialog*)p); 206 207 addButtons(buttonsText[1 .. $], responses[1 .. $]); 208 } 209 210 /** ditto */ 211 this(string title, Window parent, GtkDialogFlags flags, StockID[] stockIDs, ResponseType[] responses) 212 { 213 auto p = gtk_dialog_new_with_buttons(Str.toStringz(title), (parent is null) ? null : parent.getWindowStruct(), flags, Str.toStringz(stockIDs[0]), responses[0], null); 214 if(p is null) 215 { 216 throw new ConstructionException("null returned by gtk_dialog_new_with_buttons"); 217 } 218 219 this(cast(GtkDialog*)p); 220 221 addButtons(stockIDs[1 .. $], responses[1 .. $]); 222 } 223 224 /** */ 225 public Button addButton(StockID stockID, int responseId) 226 { 227 auto p = gtk_dialog_add_button(gtkDialog, Str.toStringz(stockID), responseId); 228 229 if ( p is null ) 230 { 231 return null; 232 } 233 234 return new Button(cast(GtkButton*)p); 235 } 236 237 /** */ 238 public void addButtons(string[] buttonsText, ResponseType[] responses) 239 { 240 for ( int i=0 ; i<buttonsText.length && i<responses.length ; i++) 241 { 242 addButton(buttonsText[i], responses[i]); 243 } 244 } 245 246 /** */ 247 public void addButtons(StockID[] stockIDs, ResponseType[] responses) 248 { 249 for ( int i=0 ; i<stockIDs.length && i<responses.length ; i++) 250 { 251 addButton(stockIDs[i], responses[i]); 252 } 253 } 254 255 //Return the corect class instead of Widget 256 /** 257 * Returns the action area of dialog. 258 * Since: 2.14 259 * Returns: the action area. 260 */ 261 public HButtonBox getActionArea() 262 { 263 auto p = gtk_dialog_get_action_area(gtkDialog); 264 if(p is null) 265 { 266 return null; 267 } 268 return new HButtonBox(cast(GtkHButtonBox*) p); 269 } 270 271 //Return the corect class instead of Widget 272 /** 273 * Returns the content area of dialog. 274 * Since: 2.14 275 * Returns: the content area GtkVBox. 276 */ 277 public VBox getContentArea() 278 { 279 auto p = gtk_dialog_get_content_area(gtkDialog); 280 if(p is null) 281 { 282 return null; 283 } 284 return new VBox(cast(GtkVBox*) p); 285 } 286 287 /** 288 */ 289 290 /** */ 291 public static GType getType() 292 { 293 return gtk_dialog_get_type(); 294 } 295 296 /** 297 * Creates a new dialog box. 298 * 299 * Widgets should not be packed into this #GtkWindow 300 * directly, but into the @vbox and @action_area, as described above. 301 * 302 * Return: the new dialog as a #GtkWidget 303 * 304 * Throws: ConstructionException GTK+ fails to create the object. 305 */ 306 public this() 307 { 308 auto p = gtk_dialog_new(); 309 310 if(p is null) 311 { 312 throw new ConstructionException("null returned by new"); 313 } 314 315 this(cast(GtkDialog*) p); 316 } 317 318 /** 319 * Adds an activatable widget to the action area of a #GtkDialog, 320 * connecting a signal handler that will emit the #GtkDialog::response 321 * signal on the dialog when the widget is activated. The widget is 322 * appended to the end of the dialog’s action area. If you want to add a 323 * non-activatable widget, simply pack it into the @action_area field 324 * of the #GtkDialog struct. 325 * 326 * Params: 327 * child = an activatable widget 328 * responseId = response ID for @child 329 */ 330 public void addActionWidget(Widget child, int responseId) 331 { 332 gtk_dialog_add_action_widget(gtkDialog, (child is null) ? null : child.getWidgetStruct(), responseId); 333 } 334 335 /** 336 * Adds a button with the given text and sets things up so that 337 * clicking the button will emit the #GtkDialog::response signal with 338 * the given @response_id. The button is appended to the end of the 339 * dialog’s action area. The button widget is returned, but usually 340 * you don’t need it. 341 * 342 * Params: 343 * buttonText = text of button 344 * responseId = response ID for the button 345 * 346 * Return: the #GtkButton widget that was added 347 */ 348 public Widget addButton(string buttonText, int responseId) 349 { 350 auto p = gtk_dialog_add_button(gtkDialog, Str.toStringz(buttonText), responseId); 351 352 if(p is null) 353 { 354 return null; 355 } 356 357 return ObjectG.getDObject!(Widget)(cast(GtkWidget*) p); 358 } 359 360 /** 361 * Returns the header bar of @dialog. Note that the 362 * headerbar is only used by the dialog if the 363 * #GtkDialog:use-header-bar property is %TRUE. 364 * 365 * Return: the header bar 366 * 367 * Since: 3.12 368 */ 369 public Widget getHeaderBar() 370 { 371 auto p = gtk_dialog_get_header_bar(gtkDialog); 372 373 if(p is null) 374 { 375 return null; 376 } 377 378 return ObjectG.getDObject!(Widget)(cast(GtkWidget*) p); 379 } 380 381 /** 382 * Gets the response id of a widget in the action area 383 * of a dialog. 384 * 385 * Params: 386 * widget = a widget in the action area of @dialog 387 * 388 * Return: the response id of @widget, or %GTK_RESPONSE_NONE 389 * if @widget doesn’t have a response id set. 390 * 391 * Since: 2.8 392 */ 393 public int getResponseForWidget(Widget widget) 394 { 395 return gtk_dialog_get_response_for_widget(gtkDialog, (widget is null) ? null : widget.getWidgetStruct()); 396 } 397 398 /** 399 * Gets the widget button that uses the given response ID in the action area 400 * of a dialog. 401 * 402 * Params: 403 * responseId = the response ID used by the @dialog widget 404 * 405 * Return: the @widget button that uses the given 406 * @response_id, or %NULL. 407 * 408 * Since: 2.20 409 */ 410 public Widget getWidgetForResponse(int responseId) 411 { 412 auto p = gtk_dialog_get_widget_for_response(gtkDialog, responseId); 413 414 if(p is null) 415 { 416 return null; 417 } 418 419 return ObjectG.getDObject!(Widget)(cast(GtkWidget*) p); 420 } 421 422 /** 423 * Emits the #GtkDialog::response signal with the given response ID. 424 * Used to indicate that the user has responded to the dialog in some way; 425 * typically either you or gtk_dialog_run() will be monitoring the 426 * ::response signal and take appropriate action. 427 * 428 * Params: 429 * responseId = response ID 430 */ 431 public void response(int responseId) 432 { 433 gtk_dialog_response(gtkDialog, responseId); 434 } 435 436 /** 437 * Blocks in a recursive main loop until the @dialog either emits the 438 * #GtkDialog::response signal, or is destroyed. If the dialog is 439 * destroyed during the call to gtk_dialog_run(), gtk_dialog_run() returns 440 * #GTK_RESPONSE_NONE. Otherwise, it returns the response ID from the 441 * ::response signal emission. 442 * 443 * Before entering the recursive main loop, gtk_dialog_run() calls 444 * gtk_widget_show() on the dialog for you. Note that you still 445 * need to show any children of the dialog yourself. 446 * 447 * During gtk_dialog_run(), the default behavior of #GtkWidget::delete-event 448 * is disabled; if the dialog receives ::delete_event, it will not be 449 * destroyed as windows usually are, and gtk_dialog_run() will return 450 * #GTK_RESPONSE_DELETE_EVENT. Also, during gtk_dialog_run() the dialog 451 * will be modal. You can force gtk_dialog_run() to return at any time by 452 * calling gtk_dialog_response() to emit the ::response signal. Destroying 453 * the dialog during gtk_dialog_run() is a very bad idea, because your 454 * post-run code won’t know whether the dialog was destroyed or not. 455 * 456 * After gtk_dialog_run() returns, you are responsible for hiding or 457 * destroying the dialog if you wish to do so. 458 * 459 * Typical usage of this function might be: 460 * |[<!-- language="C" --> 461 * gint result = gtk_dialog_run (GTK_DIALOG (dialog)); 462 * switch (result) 463 * { 464 * case GTK_RESPONSE_ACCEPT: 465 * do_application_specific_something (); 466 * break; 467 * default: 468 * do_nothing_since_dialog_was_cancelled (); 469 * break; 470 * } 471 * gtk_widget_destroy (dialog); 472 * ]| 473 * 474 * Note that even though the recursive main loop gives the effect of a 475 * modal dialog (it prevents the user from interacting with other 476 * windows in the same window group while the dialog is run), callbacks 477 * such as timeouts, IO channel watches, DND drops, etc, will 478 * be triggered during a gtk_dialog_run() call. 479 * 480 * Return: response ID 481 */ 482 public int run() 483 { 484 return gtk_dialog_run(gtkDialog); 485 } 486 487 /** 488 * Sets an alternative button order. If the 489 * #GtkSettings:gtk-alternative-button-order setting is set to %TRUE, 490 * the dialog buttons are reordered according to the order of the 491 * response ids in @new_order. 492 * 493 * See gtk_dialog_set_alternative_button_order() for more information. 494 * 495 * This function is for use by language bindings. 496 * 497 * Deprecated: Deprecated 498 * 499 * Params: 500 * nParams = the number of response ids in @new_order 501 * newOrder = an array of response ids of 502 * @dialog’s buttons 503 * 504 * Since: 2.6 505 */ 506 public void setAlternativeButtonOrder(int[] newOrder) 507 { 508 gtk_dialog_set_alternative_button_order_from_array(gtkDialog, cast(int)newOrder.length, newOrder.ptr); 509 } 510 511 /** 512 * Sets the last widget in the dialog’s action area with the given @response_id 513 * as the default widget for the dialog. Pressing “Enter” normally activates 514 * the default widget. 515 * 516 * Params: 517 * responseId = a response ID 518 */ 519 public void setDefaultResponse(int responseId) 520 { 521 gtk_dialog_set_default_response(gtkDialog, responseId); 522 } 523 524 /** 525 * Calls `gtk_widget_set_sensitive (widget, @setting)` 526 * for each widget in the dialog’s action area with the given @response_id. 527 * A convenient way to sensitize/desensitize dialog buttons. 528 * 529 * Params: 530 * responseId = a response ID 531 * setting = %TRUE for sensitive 532 */ 533 public void setResponseSensitive(int responseId, bool setting) 534 { 535 gtk_dialog_set_response_sensitive(gtkDialog, responseId, setting); 536 } 537 538 protected class OnCloseDelegateWrapper 539 { 540 void delegate(Dialog) dlg; 541 gulong handlerId; 542 ConnectFlags flags; 543 this(void delegate(Dialog) dlg, gulong handlerId, ConnectFlags flags) 544 { 545 this.dlg = dlg; 546 this.handlerId = handlerId; 547 this.flags = flags; 548 } 549 } 550 protected OnCloseDelegateWrapper[] onCloseListeners; 551 552 /** 553 * The ::close signal is a 554 * [keybinding signal][GtkBindingSignal] 555 * which gets emitted when the user uses a keybinding to close 556 * the dialog. 557 * 558 * The default binding for this signal is the Escape key. 559 */ 560 gulong addOnClose(void delegate(Dialog) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 561 { 562 onCloseListeners ~= new OnCloseDelegateWrapper(dlg, 0, connectFlags); 563 onCloseListeners[onCloseListeners.length - 1].handlerId = Signals.connectData( 564 this, 565 "close", 566 cast(GCallback)&callBackClose, 567 cast(void*)onCloseListeners[onCloseListeners.length - 1], 568 cast(GClosureNotify)&callBackCloseDestroy, 569 connectFlags); 570 return onCloseListeners[onCloseListeners.length - 1].handlerId; 571 } 572 573 extern(C) static void callBackClose(GtkDialog* dialogStruct,OnCloseDelegateWrapper wrapper) 574 { 575 wrapper.dlg(wrapper.outer); 576 } 577 578 extern(C) static void callBackCloseDestroy(OnCloseDelegateWrapper wrapper, GClosure* closure) 579 { 580 wrapper.outer.internalRemoveOnClose(wrapper); 581 } 582 583 protected void internalRemoveOnClose(OnCloseDelegateWrapper source) 584 { 585 foreach(index, wrapper; onCloseListeners) 586 { 587 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 588 { 589 onCloseListeners[index] = null; 590 onCloseListeners = std.algorithm.remove(onCloseListeners, index); 591 break; 592 } 593 } 594 } 595 596 597 protected class OnResponseDelegateWrapper 598 { 599 void delegate(int, Dialog) dlg; 600 gulong handlerId; 601 ConnectFlags flags; 602 this(void delegate(int, Dialog) dlg, gulong handlerId, ConnectFlags flags) 603 { 604 this.dlg = dlg; 605 this.handlerId = handlerId; 606 this.flags = flags; 607 } 608 } 609 protected OnResponseDelegateWrapper[] onResponseListeners; 610 611 /** 612 * Emitted when an action widget is clicked, the dialog receives a 613 * delete event, or the application programmer calls gtk_dialog_response(). 614 * On a delete event, the response ID is #GTK_RESPONSE_DELETE_EVENT. 615 * Otherwise, it depends on which action widget was clicked. 616 * 617 * Params: 618 * responseId = the response ID 619 */ 620 gulong addOnResponse(void delegate(int, Dialog) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 621 { 622 onResponseListeners ~= new OnResponseDelegateWrapper(dlg, 0, connectFlags); 623 onResponseListeners[onResponseListeners.length - 1].handlerId = Signals.connectData( 624 this, 625 "response", 626 cast(GCallback)&callBackResponse, 627 cast(void*)onResponseListeners[onResponseListeners.length - 1], 628 cast(GClosureNotify)&callBackResponseDestroy, 629 connectFlags); 630 return onResponseListeners[onResponseListeners.length - 1].handlerId; 631 } 632 633 extern(C) static void callBackResponse(GtkDialog* dialogStruct, int responseId,OnResponseDelegateWrapper wrapper) 634 { 635 wrapper.dlg(responseId, wrapper.outer); 636 } 637 638 extern(C) static void callBackResponseDestroy(OnResponseDelegateWrapper wrapper, GClosure* closure) 639 { 640 wrapper.outer.internalRemoveOnResponse(wrapper); 641 } 642 643 protected void internalRemoveOnResponse(OnResponseDelegateWrapper source) 644 { 645 foreach(index, wrapper; onResponseListeners) 646 { 647 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 648 { 649 onResponseListeners[index] = null; 650 onResponseListeners = std.algorithm.remove(onResponseListeners, index); 651 break; 652 } 653 } 654 } 655 656 657 /** 658 * Returns %TRUE if dialogs are expected to use an alternative 659 * button order on the screen @screen. See 660 * gtk_dialog_set_alternative_button_order() for more details 661 * about alternative button order. 662 * 663 * If you need to use this function, you should probably connect 664 * to the ::notify:gtk-alternative-button-order signal on the 665 * #GtkSettings object associated to @screen, in order to be 666 * notified if the button order setting changes. 667 * 668 * Deprecated: Deprecated 669 * 670 * Params: 671 * screen = a #GdkScreen, or %NULL to use the default screen 672 * 673 * Return: Whether the alternative button order should be used 674 * 675 * Since: 2.6 676 */ 677 public static bool alternativeDialogButtonOrder(Screen screen) 678 { 679 return gtk_alternative_dialog_button_order((screen is null) ? null : screen.getScreenStruct()) != 0; 680 } 681 }