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