1----------------------------------------------------------------------- 2-- GtkAda - Ada95 binding for Gtk+/Gnome -- 3-- -- 4-- Copyright (C) 2001-2013, AdaCore -- 5-- -- 6-- This library is free software; you can redistribute it and/or -- 7-- modify it under the terms of the GNU General Public -- 8-- License as published by the Free Software Foundation; either -- 9-- version 2 of the License, or (at your option) any later version. -- 10-- -- 11-- This library is distributed in the hope that it will be useful, -- 12-- but WITHOUT ANY WARRANTY; without even the implied warranty of -- 13-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- 14-- General Public License for more details. -- 15-- -- 16-- You should have received a copy of the GNU General Public -- 17-- License along with this library; if not, write to the -- 18-- Free Software Foundation, Inc., 59 Temple Place - Suite 330, -- 19-- Boston, MA 02111-1307, USA. -- 20-- -- 21-- As a special exception, if other files instantiate generics from -- 22-- this unit, or you link this unit with other files to produce an -- 23-- executable, this unit does not by itself cause the resulting -- 24-- executable to be covered by the GNU General Public License. This -- 25-- exception does not however invalidate any other reasons why the -- 26-- executable file might be covered by the GNU Public License. -- 27----------------------------------------------------------------------- 28 29-- <description> 30-- This widget organizes its children into resizable panes. Within each 31-- pane, multiple children can be put, and they will be accessible through 32-- a notebook. 33-- </description> 34-- <group>Layout containers</group> 35 36with Ada.Tags; 37with GNAT.Strings; 38with Glib; use Glib; 39with Glib.Main; 40with Glib.Xml_Int; 41with Gdk.Color; 42with Gdk.Cursor; 43with Gdk.Event; 44with Gdk.Pixbuf; 45with Gdk.Rectangle; 46with Gtk.Accel_Group; 47with Gtk.Box; 48with Gtk.Enums; 49with Gtk.Event_Box; 50with Gtk.Handlers; 51with Gtk.Label; 52with Gtk.Menu; 53with Gtk.Menu_Item; 54with Gtk.Notebook; 55with Gtk.Style; 56with Gtk.Check_Menu_Item; 57with Gtk.Radio_Menu_Item; 58with Gtk.Widget; 59with Gtk.Window; 60with Gtkada.Handlers; 61with Gtkada.Multi_Paned; 62with Pango.Font; 63with Pango.Layout; 64 65package Gtkada.MDI is 66 67 type MDI_Window_Record is new Gtk.Widget.Gtk_Widget_Record with private; 68 type MDI_Window is access all MDI_Window_Record'Class; 69 -- Although this widget is implemented as a gtk_layout, you shouldn't 70 -- use the standard Gtk_Layout functions like Put and Move yourself. 71 72 type MDI_Child_Record is new Gtk.Event_Box.Gtk_Event_Box_Record 73 with private; 74 type MDI_Child is access all MDI_Child_Record'Class; 75 pragma No_Strict_Aliasing (MDI_Child); 76 -- A child of the MDI, that encapsulates the widgets you have put in the 77 -- MDI window. 78 -- You can easily convert from this to the initial widget using the 79 -- functions Find_MDI_Child and Get_Widget. 80 81 type MDI_Child_Array is array (Natural range <>) of MDI_Child; 82 No_Children : constant MDI_Child_Array := (1 .. 0 => null); 83 84 type State_Type is (Normal, Floating, Invisible); 85 -- This type indicates the state of an item in the MDI: 86 -- - Normal: the item can be manipulated (moved and resized) by the user. 87 -- It is found either in the middle notebook (maximized items), or 88 -- in the layout. 89 -- - Floating: the item has its own toplevel window, and is thus managed 90 -- by the window manager. 91 -- - Invisible: the child was part of a previously displayed perspective, 92 -- but is no longer in the current perspective. We still keep it to 93 -- reuse it when switching back to the previous perspective. 94 95 procedure Gtk_New 96 (MDI : out MDI_Window; 97 Group : access Gtk.Accel_Group.Gtk_Accel_Group_Record'Class; 98 Independent_Perspectives : Boolean := False); 99 -- Create a new MDI window. 100 -- Note that it is recommended that you modify the style (Set_Background 101 -- in State_Normal) to have a different color. 102 -- You should call Setup_Toplevel_Window once you have added the MDI to a 103 -- toplevel widget, so that focus is correctly handled when the toplevel 104 -- window gains the focus 105 -- When Independent_Perspectives is True, switching perspectives will not 106 -- preserve any window. Otherwise, the windows that are in the central 107 -- area will be preserved in the new perspective. 108 109 procedure Initialize 110 (MDI : access MDI_Window_Record'Class; 111 Group : access Gtk.Accel_Group.Gtk_Accel_Group_Record'Class; 112 Independent_Perspectives : Boolean := False); 113 -- Internal initialization function. 114 -- See the section "Creating your own widgets" in the documentation. 115 116 procedure Setup_Toplevel_Window 117 (MDI : access MDI_Window_Record; 118 Parent : access Gtk.Window.Gtk_Window_Record'Class); 119 -- Setup Parent to properly handle focus when the window manager changes 120 -- the window that currently has the focus. 121 -- Parent must be the toplevel window that contains the MDI. 122 123 type Show_Tabs_Policy_Enum is (Always, Never, Automatic); 124 type Title_Bars_Policy is (Always, Never, Central_Only); 125 126 procedure Configure 127 (MDI : access MDI_Window_Record; 128 Opaque_Resize : Boolean := False; 129 Close_Floating_Is_Unfloat : Boolean := True; 130 Title_Font : Pango.Font.Pango_Font_Description := null; 131 Background_Color : Gdk.Color.Gdk_Color := Gdk.Color.Null_Color; 132 Title_Bar_Color : Gdk.Color.Gdk_Color := Gdk.Color.Null_Color; 133 Focus_Title_Color : Gdk.Color.Gdk_Color := Gdk.Color.Null_Color; 134 Draw_Title_Bars : Title_Bars_Policy := Always; 135 Tabs_Position : Gtk.Enums.Gtk_Position_Type := Gtk.Enums.Pos_Bottom; 136 Show_Tabs_Policy : Show_Tabs_Policy_Enum := Automatic); 137 -- Change the setup of the MDI. 138 -- Close_Floating_Is_Unfloat, if True, means that closing a floating child 139 -- will put it back in the MDI instead of destroying it (unless its flag 140 -- Always_Destroy_Float is set). 141 -- Title_Font is the font used in the title bars (if null, "sans 8" 142 -- is used). 143 -- The colors, when Null_Color, will not change the current setup. 144 -- If Draw_Title_Bars is False, then no extra title bar will be displayed 145 -- for the MDI children when they are maximized. This saves space on the 146 -- screen. However, the notebook tabs will be highlighted with 147 -- Title_Bar_Color in exchange. 148 -- Tabs_Position indicates where the notebook tabs should be put. 149 -- Show_Tabs_Policy indicates when the notebook tabs should be displayed. 150 151 function Independent_Perspectives 152 (MDI : access MDI_Window_Record) return Boolean; 153 -- Whether the MDI is using independent perspectives 154 155 ------------- 156 -- Windows -- 157 ------------- 158 159 type Child_Flags is mod 2 ** 5; 160 Destroy_Button : constant Child_Flags := 2 ** 2; 161 Float_As_Transient : constant Child_Flags := 2 ** 3; 162 Always_Destroy_Float : constant Child_Flags := 2 ** 4; 163 All_Buttons : constant Child_Flags := Destroy_Button; 164 -- Special flags to set up the widgets: 165 -- The first is the buttons that should be displayed in the title 166 -- bar of the MDI children. 167 -- If Float_As_Transient is set, then the child will be set up as a 168 -- transient window when floating: on most window managers, it will stay on 169 -- top of the MDI, but the window will have less decorations in its title 170 -- bar, in particular no destroy button. In such a case, <Esc> will close 171 -- the window, or unfloat it depending on the MDI's setup, as is the case 172 -- for all dialogs in GtkAda. The MDI's setup will be ignored (and the 173 -- child always destroyed when Esc is pressed) if Always_Destroy_Float is 174 -- true. 175 176 type Child_Group is new Positive; 177 Group_Default : constant Child_Group := 1; 178 Group_Any : constant Child_Group := Child_Group'Last; 179 -- This type can be used to help group windows by type within the MDI. 180 -- Group_Default as a special status when computing the initial position 181 -- for a window. But you can create your own groups as needed, so that for 182 -- instance editors tend to be grouped with other editors, graphs with 183 -- other graphs,... depending on your application. 184 -- The group has an impact when the last window from a notebook is closed: 185 -- If the window belongs to Group_Default, and it is the last of its group, 186 -- then the space currently occupied by that window is not reclaimed, and 187 -- therefore an empty area will exist in the MDI. The idea is that for 188 -- instance editors typically play a special role in an integrated 189 -- development environment, and the users like to have them in the center 190 -- of the window. When closing the last editor, they do not want the side 191 -- windows (browsers, consoles,...) to take up that space that should 192 -- really only be used for editors. 193 -- To get such a behavior, editors should belong to Group_Default, and all 194 -- other windows to custom groups. 195 -- 196 -- Do not use Group_Any, it is used internally with special meanings. 197 198 procedure Gtk_New 199 (Child : out MDI_Child; 200 Widget : access Gtk.Widget.Gtk_Widget_Record'Class; 201 Flags : Child_Flags := All_Buttons; 202 Group : Child_Group := Group_Default; 203 Focus_Widget : Gtk.Widget.Gtk_Widget := null); 204 -- Create a new MDI child that contains widget. 205 -- Widget mustn't be of type Gtk_Window. 206 -- 207 -- You shouldn't access Widget directly afterwards, but should manipulate 208 -- Child only. However, as a special exception, you can still pass Widget 209 -- as a parameter to the subprograms in this package to manipulate it (e.g. 210 -- in Raise_Child, ...) 211 -- 212 -- Note: You might have to call Set_Size_Request on Widget to set its 213 -- initial size. This won't prevent it from being resized by the user. 214 -- 215 -- If Focus_Widget is not null, this is the widget that gets the keyboard 216 -- focus when the child is selected. 217 218 procedure Initialize 219 (Child : access MDI_Child_Record'Class; 220 Widget : access Gtk.Widget.Gtk_Widget_Record'Class; 221 Flags : Child_Flags := All_Buttons; 222 Group : Child_Group := Group_Default; 223 Focus_Widget : Gtk.Widget.Gtk_Widget := null); 224 -- Internal initialization function. 225 -- See the section "Creating your own widgets" in the documentation. 226 227 type Child_Position is 228 (Position_Automatic, 229 Position_Bottom, 230 Position_Top, 231 Position_Left, 232 Position_Right); 233 subtype Side_Position is Child_Position 234 range Position_Bottom .. Position_Right; 235 -- The initial position of windows within the MDI. 236 -- In all cases, the initial location for a window is computed with the 237 -- following algorithm. This algorithm is designed with the notion of 238 -- groups of windows in mind, so that some windows (typically editors) have 239 -- a special status. 240 -- - If another window with the same Group is already in the MDI, the 241 -- new window is put on top of it. 242 -- - Otherwise, if Position_Automatic, if an empty area exists within 243 -- the MDI, the new window is put in that area. 244 -- - Else if the Position is Bottom .. Right, the new window is put 245 -- below all others (resp. to the top, left or right) 246 -- - Else the window is put on top of the currently selected window 247 248 procedure Put 249 (MDI : access MDI_Window_Record; 250 Child : access MDI_Child_Record'Class; 251 Initial_Position : Child_Position := Position_Automatic); 252 -- Add a new child to the MDI window, and return its embedding widget. 253 -- Calling Put does not give the focus to the newly inserted widget. 254 -- To do that, you should call Set_Focus_Child. 255 256 procedure Set_Size 257 (MDI : access MDI_Window_Record; 258 Child : access MDI_Child_Record'Class; 259 Width : Glib.Gint; 260 Height : Glib.Gint; 261 Fixed_Size : Boolean := False); 262 -- Forces a new size for a child. If Width or Height is left to -1, the 263 -- matching size will be computed from the child's requisition. If they are 264 -- left to 0, the corresponding length is left to its current value. 265 -- If Fixed_Size is True, then the widget will not be resized when the MDI 266 -- itself is resized (unless the user has first moved one of the handles to 267 -- manually resize it). Otherwise, it will grow proportionally with the 268 -- rest of the MDI. 269 270 procedure Close 271 (MDI : access MDI_Window_Record; 272 Child : access Gtk.Widget.Gtk_Widget_Record'Class; 273 Force : Boolean := False); 274 -- Close the child that contains Child, and remove its window from the 275 -- MDI. See also Close_Child if you need to close a MDI_Child itself. 276 -- This first checks through a delete_event callback whether the child 277 -- accepts to be closed. 278 -- "delete_event" is not sent, and the child is automatically closed, if 279 -- Force is set to True. 280 281 procedure Set_Title 282 (Child : access MDI_Child_Record; 283 Title : UTF8_String; 284 Short_Title : UTF8_String := ""); 285 -- Set the title for a child. Title is the title put in titlebar of 286 -- the children, whereas Short_Title is the name of the notebook tab when 287 -- children are maximized. By default, it is the same as Title. 288 -- 289 -- The default title is the empty string. 290 -- This title will be the one used for the window when the child is set to 291 -- floating state. 292 293 function Get_MDI (Child : access MDI_Child_Record) return MDI_Window; 294 -- Return the MDI to which Child is associated. In Child is a floating 295 -- child, it might not be in the MDI window itself. 296 297 function Get_Title (Child : access MDI_Child_Record) return UTF8_String; 298 -- Return the title for a specific child 299 300 function Get_Short_Title 301 (Child : access MDI_Child_Record) return UTF8_String; 302 -- Return the name of the notebook tab used when children are maximized. 303 304 function Has_Title_Bar (Child : access MDI_Child_Record) return Boolean; 305 -- Whether a title bar is currently displayed for Child 306 307 function Get_State (Child : access MDI_Child_Record) return State_Type; 308 -- Return the current state of the child 309 310 procedure Set_Icon 311 (Child : access MDI_Child_Record; 312 Icon : Gdk.Pixbuf.Gdk_Pixbuf); 313 -- Associate an icon with Child. This icon is visible in the title bar, the 314 -- notebook tabs, the Window menu and the interactive selection dialog. 315 -- The icon is updated dynamically on the screen. 316 317 function Get_Icon 318 (Child : access MDI_Child_Record) return Gdk.Pixbuf.Gdk_Pixbuf; 319 -- Returns the icon associated with Child 320 321 --------------------------- 322 -- Drag and Drop support -- 323 --------------------------- 324 325 function Dnd_Data 326 (Child : access MDI_Child_Record; Copy : Boolean) return MDI_Child; 327 -- When a drag-and-drop operation took place to move a child from one 328 -- position to the next, this function is called to know what child should 329 -- be moved. 330 -- As a result, the implementor can choose whether a copy of the child 331 -- should be returned (creating a new view for an editor for instance), or 332 -- if the child itself should be moved (the default). 333 -- The returned MDI_Child must have been added to the MDI before it is 334 -- returned. 335 -- Copy is set to true if a copy operation was requested, to False if a 336 -- simple move operation was requested. It can be ignored if Child doesn't 337 -- know how to create a copy of itself for instance. 338 339 procedure Set_Dnd_Message 340 (MDI : access MDI_Window_Record; 341 Message : String); 342 -- Override the message that is displayed in the popup window while 343 -- performing a drag. By default, this message mentions: 344 -- "... will be (preserved|hidden) when changing perspective" 345 -- "Use shift to create a new view for editors" 346 -- so might not be suitable for all applications. 347 -- Through this function you can override the message. If you insert the 348 -- special sequence "(#)" in the message, it will be replaced either with 349 -- "preserved" or "hidden" depending on where the drop occurs (the central 350 -- area or the perspectives). It could also be replaced by an empty string 351 -- if the MDI was configured with independent perspectives. 352 -- You can use markup like "<b>...</b>" to put keywords in bold. 353 -- 354 -- Passing an empty string for Message will restore the default message. 355 356 procedure Child_Drag_Begin 357 (Child : access MDI_Child_Record'Class; 358 Event : Gdk.Event.Gdk_Event); 359 -- Starts a drag-and-drop operation for the child, so that it can be put in 360 -- some other place on the desktop. This should only be called when a 361 -- handler for the "button_press_event" signal, passing the event itself in 362 -- parameter. 363 -- The Child is immediately raised and gains the focus. 364 365 procedure Cancel_Child_Drag (Child : access MDI_Child_Record'Class); 366 -- Cancel a drag operation started by Child_Drag_Begin. 367 -- It doesn't call Child_Drag_Finished. 368 369 procedure Child_Drag_Finished (Child : access MDI_Child_Record); 370 -- Called when a drag operation is either aborted or completed. It should 371 -- be overriden if special cleanup should be done. 372 373 ----------- 374 -- Menus -- 375 ----------- 376 377 type Tab_Contextual_Menu_Factory is access procedure 378 (Child : access MDI_Child_Record'Class; 379 Menu : access Gtk.Menu.Gtk_Menu_Record'Class); 380 381 procedure Set_Tab_Contextual_Menu_Factory 382 (MDI : access MDI_Window_Record; 383 Factory : Tab_Contextual_Menu_Factory); 384 -- Set (or unset if Factory is null) the callback to create the contextual 385 -- menu entries when the user clicks on a notebook tab. 386 -- Factory should add entries to Menu (which already contains the default 387 -- entries, but you can remove them if needed). 388 389 ------------------------ 390 -- Selecting children -- 391 ------------------------ 392 393 procedure Highlight_Child 394 (Child : access MDI_Child_Record; Highlight : Boolean := True); 395 -- Highlight the child until it is selected by the user. 396 -- The color of its menu label and of the text in the notebook tabs is 397 -- changed. 398 -- Nothing is done if the child is already fully visible (either in the 399 -- active page in one of the notebooks, or the child that has the selection 400 -- in the layout). 401 -- This is meant to be used as a graphical note to the user that the child 402 -- has been updated and the user should look at it. 403 404 function Get_Focus_Child 405 (MDI : access MDI_Window_Record) return MDI_Child; 406 -- Return the child that currently has the MDI focus. 407 -- null is returned if no child has the focus. 408 409 procedure Set_Focus_Child 410 (MDI : access MDI_Window_Record; 411 Containing : access Gtk.Widget.Gtk_Widget_Record'Class); 412 -- Give the focus to the child containing Containing. This will not 413 -- Grab_Focus for the child in all cases, since you might want to give the 414 -- focus to some specific part of your widget (an entry field,...) in some 415 -- cases. 416 417 procedure Set_Focus_Child (Child : access MDI_Child_Record); 418 -- Make Child the active widget, and raise it at the top. 419 420 procedure Check_Interactive_Selection_Dialog 421 (MDI : access MDI_Window_Record; 422 Event : Gdk.Event.Gdk_Event; 423 Move_To_Next : Boolean; 424 Only_Group : Child_Group := Group_Any); 425 -- Open the interactive dialog for selecting windows. 426 -- This dialog should be open as a result of a key press event. 427 -- Move_To_Next indicates whether we want to select the next child (True) 428 -- or the previous child (False). 429 -- This dialog will be closed only when the key that opened it is fully 430 -- released. For instance, if the dialog was opened as a result of 431 -- pressing Ctrl-Tab, the dialog will only be closed when Ctrl itself is 432 -- released. 433 -- You can call this procedure even if a dialog is currently open. This 434 -- simply forces a move to the next or previous child. In fact, it is 435 -- your responsability to call this procedure when the user presses 436 -- the keys to move between children. 437 -- 438 -- If Event is null, then no dialog is displayed. Instead, the next or 439 -- previous visible child is immediately selected. In such a mode, windows 440 -- that are not on top of their respective notebook are ignored. This can 441 -- be used to emulate Emacs's behavior for goto-other-window. 442 -- 443 -- If Only_Group is specified, then only the windows from that group will 444 -- be shown in the dialog. 445 446 -- This function is not internal to the MDI since connecting to the 447 -- key_press_event and key_release_event should be done in the gtk_window 448 -- that contains the MDI. Otherwise, some events are intercepted by gtk+, 449 -- for instance the key_release_events, and the key_press_events for some 450 -- specified keys. 451 -- It also gives the choice to the application of whether this feature is 452 -- wanted or not. 453 454 ----------------------------------------- 455 -- MDI_Child and encapsulated children -- 456 ----------------------------------------- 457 458 function Get_Widget 459 (Child : access MDI_Child_Record) return Gtk.Widget.Gtk_Widget; 460 -- Return the widget that Child encapsulates. This is the widget you 461 -- initially Put() in MDI. 462 463 function Find_MDI_Child 464 (MDI : access MDI_Window_Record; 465 Widget : access Gtk.Widget.Gtk_Widget_Record'Class) return MDI_Child; 466 -- Return the MDI_Child that encapsulates Widget. 467 -- Widget must be the exact same one you gave in argument to Put. 468 -- If the child is currently not visible in the perspective (for instance 469 -- it was created for another perspective, but is not present in the 470 -- current one), it is inserted automatically back in the MDI. 471 472 function Find_MDI_Child_From_Widget 473 (Widget : access Gtk.Widget.Gtk_Widget_Record'Class) return MDI_Child; 474 -- Return the MDI child that encapsulate the parent of Widget. 475 -- As opposed to Find_MDI_Child, Widget can be anywhere within the 476 -- widget tree. This function properly handles floating children 477 -- If the child is currently not visible in the perspective (for instance 478 -- it was created for another perspective, but is not present in the 479 -- current one), it is inserted automatically back in the MDI. 480 481 function Find_MDI_Child_By_Tag 482 (MDI : access MDI_Window_Record; 483 Tag : Ada.Tags.Tag; 484 Visible_Only : Boolean := False) return MDI_Child; 485 -- Return the first child matching Tag 486 -- If the child is currently not visible in the perspective (for instance 487 -- it was created for another perspective, but is not present in the 488 -- current one), it is inserted automatically back in the MDI. 489 -- If Visible_Only is True, an invisible child is not returned. This is 490 -- useful to check whether a child is currently visible. 491 492 function Find_MDI_Child_By_Name 493 (MDI : access MDI_Window_Record; 494 Name : String) return MDI_Child; 495 -- Return the first child matching Name. 496 -- If the child is currently not visible in the perspective (for instance 497 -- it was created for another perspective, but is not present in the 498 -- current one), it is inserted automatically back in the MDI. 499 500 type Child_Iterator is private; 501 502 function First_Child 503 (MDI : access MDI_Window_Record; 504 Group_By_Notebook : Boolean := False; 505 Visible_Only : Boolean := True) return Child_Iterator; 506 -- Return an access to the first child of the MDI. 507 -- 508 -- If Group_By_Notebook is True, then the children are reported one after 509 -- the other, but all the widget from the same notebook are reported in the 510 -- same order as the notebook pages. Floating children do not belong to a 511 -- notebook, and are also reported together. To find out to which notebook 512 -- a child belongs, use Get_Notebook below. 513 -- 514 -- If Group_By_Notebook is False, it is garanteed that the first child is 515 -- the one that currently has the focus in the MDI. The children are 516 -- returned in the order in which they last had the focus. 517 -- 518 -- If Visible_Only is true, then only those children currently visible in 519 -- the perspective are returned. The children that were part of a former 520 -- perspective are not returned. 521 522 procedure Next (Iterator : in out Child_Iterator); 523 -- Move to the next child in the MDI 524 525 function Get_Notebook 526 (Iterator : Child_Iterator) return Gtk.Notebook.Gtk_Notebook; 527 -- Return the notebook to which the current child belongs. null is returned 528 -- for floating children 529 530 function Get (Iterator : Child_Iterator) return MDI_Child; 531 -- Return the child pointed to by Iterator. 532 -- If Iterator is no longer valid, null is returned. 533 534 ----------------------------------- 535 -- Floating and closing children -- 536 ----------------------------------- 537 538 procedure Float_Child 539 (Child : access MDI_Child_Record'Class; Float : Boolean); 540 -- Change the floating state of a child 541 542 function Is_Floating 543 (Child : access MDI_Child_Record'Class) return Boolean; 544 -- Return True if Child is currently in a separate window 545 546 procedure Close_Child 547 (Child : access MDI_Child_Record'Class; 548 Force : Boolean := False); 549 -- Same as Close, but applies directly to a MDI_Child. 550 551 procedure Set_All_Floating_Mode 552 (MDI : access MDI_Window_Record; All_Floating : Boolean); 553 -- If All_Floating is set to true, the MDI will have a size of 0x0, and all 554 -- children are set to floating. This can be used if you wish to let the 555 -- window manager handle the windows. If All_Floating is True, children 556 -- can no longer be maximized. 557 558 procedure Use_Short_Titles_For_Floats 559 (MDI : access MDI_Window_Record; Short_Titles : Boolean); 560 -- If Short_Titles is set to true, only short titles will ever be used 561 -- either in the title bars (in notebooks) or as the title for floating 562 -- windows. 563 564 --------------------------- 565 -- Reorganizing children -- 566 --------------------------- 567 568 procedure Raise_Child 569 (Child : access MDI_Child_Record'Class; Give_Focus : Boolean := True); 570 -- Put Child in the foreground. 571 -- Note that this does not give the focus to this child, unless 572 -- Give_Focus is set to True. If Child and the current focus child are in 573 -- the same notebook, Child will always gain the focus, so that the focus 574 -- is not left on an invisible window. 575 576 function Is_Raised (Child : access MDI_Child_Record'Class) return Boolean; 577 -- Whether the child is currently raised, ie fully visible to the user 578 579 procedure Lower_Child (Child : access MDI_Child_Record'Class); 580 -- Put Child in the background. 581 -- If the children are maximized, this selected the next page from the 582 -- notebook. 583 584 type Split_Mode is 585 (Before, Before_Reuse, 586 After, After_Reuse, 587 Any_Side_Reuse); 588 -- How a child should be split: 589 -- If "Before", the child is put above or to the left of its current 590 -- position. A new window is created to containing it. If the "_Reuse" 591 -- version is used, and a window already exist at that position, the child 592 -- will be put in it instead of creating a new one. 593 -- Any_Side_Reuse indicates that the child will be put on either side, 594 -- depending on where a window already exists. If there is no window on the 595 -- side, a new one is created. 596 597 procedure Split 598 (MDI : access MDI_Window_Record; 599 Orientation : Gtk.Enums.Gtk_Orientation; 600 Child : MDI_Child := null; 601 Mode : Split_Mode := Before; 602 Width, Height : Glib.Gint := 0); 603 -- Split the notebook containing Child (by default, the current focus 604 -- child). 605 -- Mode indicates in which direction the splitting should occur. If you 606 -- are splitting a child in the central area, splitting will never reuse 607 -- a window outside of the central area. 608 -- Width and Height indicate the desired geometry for the splitted area, 609 -- 0 indicate a 50/50 split. 610 611 ---------------------- 612 -- Desktop Handling -- 613 ---------------------- 614 -- The MDI provides a way to save desktops, i.e the list of children 615 -- currently open in the MDI and their location. It can then restore the 616 -- desktop at some later point. 617 -- 618 -- Desktops require support from the widgets that are put in the MDI. They 619 -- need to register a function to save them and a function to recreate 620 -- them. Using Ada streams for this didn't prove workable since some 621 -- children might need extra parameters not available to them through 622 -- streams. This is why the following subprograms are in a generic package, 623 -- so that you can pass whatever parameter(s) is needed in your 624 -- application. 625 -- 626 -- Desktops are saved and restored in XML trees. 627 -- 628 -- If you need your application to load a "default desktop" when the user 629 -- hasn't defined one, it is recommended that you distribute an actual 630 -- file containing this desktop. You could also create the XML tree in 631 -- memory yourself, and thus hard-code the default desktop if need be. 632 633 generic 634 type User_Data is private; 635 -- Generic type of parameter that is passed to all the children's save 636 -- and restore functions. 637 638 -- This package needs to be instantiated at library level 639 640 package Desktop is 641 642 type Menu_Registration_Procedure is access procedure 643 (User : User_Data; 644 Item_Name : String; 645 Accel_Path : String); 646 -- Function used to register in the application a static menu 647 -- created by the MDI. 648 649 function Create_Menu 650 (MDI : access MDI_Window_Record'Class; 651 Accel_Path_Prefix : String := "<gtkada>"; 652 User : User_Data; 653 Registration : Menu_Registration_Procedure := null) 654 return Gtk.Menu.Gtk_Menu; 655 -- Create a dynamic menu that can then be inserted into a menu bar. This 656 -- menu is dynamic, ie its content will changed based on the focus 657 -- child. 658 -- If this function is called several times, the same menu is returned 659 -- every time. Accel_Path_Prefix must be the same for every call. 660 -- Accel_Path_Prefix is used so that the key shortcuts associated with 661 -- these menu items can be changed dynamically by the user (see 662 -- gtk-accel_map.ads). The prefix must start with "<" and end with ">". 663 -- User is used for the callbacks on perspective changes, and passed to 664 -- Load_Perspective 665 -- If Registration is specified, call it for 666 667 type Save_Desktop_Function is access function 668 (Widget : access Gtk.Widget.Gtk_Widget_Record'Class; 669 User : User_Data) return Glib.Xml_Int.Node_Ptr; 670 -- A general function that dumps the parameters of a widget into an XML 671 -- tree. 672 -- 673 -- Note: you should register one such function for all the widget types 674 -- you will put in the MDI and that need to be saved when a desktop is 675 -- saved. The MDI will call all the registered functions one after the 676 -- other. Therefore, your function should return null if Widget is not 677 -- of a type that is it can handle. 678 679 type Load_Desktop_Function is access function 680 (MDI : MDI_Window; Node : Glib.Xml_Int.Node_Ptr; User : User_Data) 681 return MDI_Child; 682 -- A general function that loads a widget from an XML tree. 683 -- 684 -- As for Save_Desktop_Function, this function should return null if it 685 -- doesn't know how to handle Node or if Node doesn't describe a widget 686 -- type that it can handle. 687 -- 688 -- This function returns an MDI_Widget that has been put in the MDI. 689 690 procedure Register_Desktop_Functions 691 (Save : Save_Desktop_Function; 692 Load : Load_Desktop_Function); 693 -- Register a set of functions to save and load desktops for some 694 -- specific widget types. This can be called multiple times. 695 -- Neither Save nor Load can be null. 696 697 function Restore_Desktop 698 (MDI : access MDI_Window_Record'Class; 699 Perspectives : Glib.Xml_Int.Node_Ptr; 700 From_Tree : Glib.Xml_Int.Node_Ptr; 701 User : User_Data) return Boolean; 702 -- Restore the contents of the MDI from its saved XML tree. 703 -- Perspectives is the list of perspectives. It is cloned as needed, so 704 -- the caller is still responsible for freeing it. The first perspective 705 -- is loaded. 706 -- From_Tree is the part of the desktop that describes the editor area. 707 -- User is passed as a parameter to all of the Load_Desktop_Function 708 -- registered by the widgets. 709 -- Return False if the desktop couldn't be loaded 710 -- It also restores the size and position of the toplevel window that 711 -- contains the MDI 712 713 procedure Load_Perspective 714 (MDI : access MDI_Window_Record'Class; 715 Name : String; 716 User : User_Data); 717 -- Replace the current perspective by another one. This preserves the 718 -- editor area. 719 -- If the perspective does not exist, nothing is done, unless no 720 -- perspective is currently loaded (in which case we load the first 721 -- on in the list). 722 723 procedure Create_Perspective 724 (MDI : access MDI_Window_Record'Class; 725 Name : String; 726 User : User_Data); 727 -- Create a new perspective with the current desktop layout. If another 728 -- perspective with the same name exists, it is replaced. 729 730 procedure Define_Perspective 731 (MDI : access MDI_Window_Record'Class; 732 XML : Glib.Xml_Int.Node_Ptr; 733 User : User_Data); 734 -- Define a new perspective (in the same format as returned by 735 -- Save_Desktop, the central area is under control of the user so you 736 -- cannot change it). 737 -- If such a perspective already exists, nothing is done (since the user 738 -- might have modified it already). 739 -- XML's root node is the <perspective> node, including its "name" 740 -- attribute. 741 -- XML must be freed by the caller. 742 743 procedure Save_Desktop 744 (MDI : access MDI_Window_Record'Class; 745 User : User_Data; 746 Perspectives : out Glib.Xml_Int.Node_Ptr; 747 Central : out Glib.Xml_Int.Node_Ptr); 748 -- Return XML representations of the perspectives and central area. Both 749 -- nodes need to be freed by the caller, and can be saved in a file (to 750 -- be passed to Restore_Desktop later on). 751 -- This function calls each of the registered function for the children 752 -- of the MDI. 753 -- It also saves the size and position of the toplevel window that 754 -- contains the MDI 755 756 function Get_XML_Content 757 (MDI : access MDI_Window_Record'Class; 758 Tag : String) return Glib.Xml_Int.Node_Ptr; 759 -- Return the first XML subtree starting with 'Tag'. This allows a 760 -- module to retrieve its content after the 'Load_Desktop' call. 761 762 procedure Free_Registered_Desktop_Functions; 763 -- Free the memory allocated for the registered functions. 764 765 private 766 type Register_Node_Record; 767 type Register_Node is access Register_Node_Record; 768 type Register_Node_Record is record 769 Save : Save_Desktop_Function; 770 Load : Load_Desktop_Function; 771 Next : Register_Node; 772 end record; 773 774 type Perspective_Menu_Item_Record 775 is new Gtk.Radio_Menu_Item.Gtk_Radio_Menu_Item_Record 776 with record 777 MDI : MDI_Window; 778 Name : Natural; 779 User : User_Data; 780 end record; 781 type Perspective_Menu_Item 782 is access all Perspective_Menu_Item_Record'Class; 783 784 procedure Change_Perspective 785 (Item : access Gtk.Widget.Gtk_Widget_Record'Class); 786 CP_Access : constant 787 Gtkada.Handlers.Widget_Callback.Marshallers.Marshaller := 788 Gtkada.Handlers.Widget_Callback.To_Marshaller 789 (Change_Perspective'Access); 790 -- Internal, but needed so that we can have a 'Access on a callback 791 792 procedure Create_Perspective_CB 793 (Item : access Gtk.Widget.Gtk_Widget_Record'Class); 794 CreateP_Access : constant 795 Gtkada.Handlers.Widget_Callback.Marshallers.Marshaller := 796 Gtkada.Handlers.Widget_Callback.To_Marshaller 797 (Create_Perspective_CB'Access); 798 799 Registers : Register_Node; 800 -- Global variable that contains the list of functions that have been 801 -- registered. 802 end Desktop; 803 804 function Desktop_Was_Loaded (MDI : access MDI_Window_Record) return Boolean; 805 -- Return True if a desktop was loaded, False if the MDI is only the result 806 -- of calls to Gtk_New and Put. 807 808 function List_Of_Perspectives 809 (MDI : access MDI_Window_Record) 810 return GNAT.Strings.String_List_Access; 811 -- Return the list of perspectives known to the MDI. The caller must not 812 -- free the list 813 814 function Current_Perspective 815 (MDI : access MDI_Window_Record'Class) return String; 816 -- Return the name of the currently displayed perspective 817 818 ------------- 819 -- Signals -- 820 ------------- 821 822 -- <signals> 823 -- The following new signals are defined for this widget: 824 -- 825 -- - "child_selected" 826 -- procedure Handler 827 -- (MDI : access MDI_Window_Record'Class; Child : System.Address); 828 -- 829 -- This signal is emitted when a new child has gained the focus. Convert 830 -- Child to a MDI_Child by calling Gtk.Arguments.To_Object. This can be 831 -- used to change some global information at the MDI level. You should 832 -- connect to "selected" (see below) instead if you want to change some 833 -- information at the child level. 834 -- Child might be null if no child has the focus anymore 835 -- 836 -- - "float_child" 837 -- procedure Handler 838 -- (MDI : access MDI_Window_Record'Class; Child : System.Address); 839 -- 840 -- A child was set as floating in the MDI. A similar signal is emitted on 841 -- the child itself. 842 -- 843 -- - "child_title_changed" 844 -- procedure Handler 845 -- (MDI : access MDI_Window_Record'Class; Child : System.Address); 846 -- 847 -- Emitted when the title of a child is changed. This signal is not 848 -- emitted if Set_Title is called for a child that hasn't been put in the 849 -- MDI yet. 850 -- 851 -- - "child_added" 852 -- procedure Handler 853 -- (MDI : access MDI_Window_Record'Class; Child : System.Address); 854 -- Emitted when a new child is added. You cannot use the "add" signal 855 -- since in fact the children are added to notebooks that are part of 856 -- the MDI, and thus "add" is only emitted when a new notebook is 857 -- created. 858 -- 859 -- - "child_removed" 860 -- procedure Handler 861 -- (MDI : access MDI_Window_Record'Class; Child : System.Address); 862 -- Emitted when a new child is removed. You cannot use the "remove" 863 -- signal since in fact the children are removed from notebooks that are 864 -- part of the MDI, and thus "remove" is only emitted when a new 865 -- notebook is destroyed. 866 -- When this signal is emitted, Child no longer contains a widget, and 867 -- is no longer part of the children, although you can still access its 868 -- titles. 869 -- 870 -- - "child_icon_changed" 871 -- procedure Handler 872 -- (MDI : access MDI_Window_Record'Class; Child : System.Address); 873 -- Emitted when the icon for Child has changed 874 -- 875 -- - "children_reorganized" 876 -- procedure Handler (MDI : access MDI_Window_Record'Class); 877 -- Emitted when the children have been reorganized: either a split 878 -- occurred, or a window was dropped into another position 879 -- 880 -- - "perspective_changed" 881 -- procedure Handler (MDI : access MDI_Window_Record'Class); 882 -- Called when the user has selected a new perspective. One use is to 883 -- save the new desktop to a file. 884 -- 885 -- </signals> 886 -- 887 -- <signals> 888 -- The following new signals are defined for the MDI_Child_Record object: 889 -- 890 -- - "delete_event" 891 -- function Handler (Child : access Gtk_Widget_Record'Class) 892 -- return Boolean; 893 -- 894 -- This signal is emitted for each item in the MDI window before it is 895 -- actually deleted. The child is destroyed only if the handler returns 896 -- False. 897 -- Note that the Child passed in argument is exactly the one you passed 898 -- to Put to insert it in the MDI window. 899 -- Note that this is also the signal to use to prevent top level 900 -- Gtk_Window from being destroyed. 901 -- 902 -- - "selected" 903 -- procedure Handler (Child : access MDI_Child_Record'Class); 904 -- 905 -- This is emitted when the child is selected, ie gains the 906 -- MDI focus. You should probably also connect to the "grab_focus" signal 907 -- to be informed when the child gets the keyboard focus. This can be 908 -- used to transfer the focus to some specific part of the 909 -- widget. Connecting to "grab_focus" should be done with the After 910 -- parameter set to True. 911 -- 912 -- - "float_child" 913 -- procedure Handler (Child : access MDI_Child_Record'Class); 914 -- 915 -- Emitted when a child is set as floating 916 -- 917 -- - "unfloat_child" 918 -- procedure Handler (Child : access MDI_Child_Record'Class); 919 -- 920 -- Emitted when a child is put back in the main MDI window 921 -- 922 -- - "child_state_changed" 923 -- procedure Handler (Child : access MDI_Child_Record'Class); 924 -- 925 -- Emitted when the state of the child has changed. See the function 926 -- Get_State. In particular, this signal can be detected when a child is 927 -- removed from the current perspective (the new state is "invisible"), 928 -- and when it is put back (the new state is "normal" or "floating"). 929 -- 930 -- </signals> 931 932 Signal_Child_Selected : constant Signal_Name := "child_selected"; 933 Signal_Float_Child : constant Signal_Name := "float_child"; 934 Signal_Child_Title_Changed : constant Signal_Name := "child_title_changed"; 935 Signal_Child_Added : constant Signal_Name := "child_added"; 936 Signal_Child_Removed : constant Signal_Name := "child_removed"; 937 Signal_Child_Icon_Changed : constant Signal_Name := "child_icon_changed"; 938 Signal_Delete_Event : constant Signal_Name := "delete_event"; 939 Signal_Selected : constant Signal_Name := "selected"; 940 Signal_Unfloat_Child : constant Signal_Name := "unfloat_child"; 941 Signal_Perspective_Changed : constant Signal_Name := "perspective_changed"; 942 Signal_Children_Reorganized : constant Signal_Name := 943 "children_reorganized"; 944 Signal_Child_State_Changed : constant Signal_Name := "child_state_changed"; 945 946private 947 type String_Access is access all UTF8_String; 948 949 type MDI_Child_Record is new Gtk.Event_Box.Gtk_Event_Box_Record with record 950 Initial : Gtk.Widget.Gtk_Widget; 951 -- The widget we use to build this child. 952 953 Main_Box : Gtk.Box.Gtk_Box; 954 -- The main container. 955 956 State : State_Type := Normal; 957 958 Group : Child_Group := Group_Default; 959 960 Title : String_Access; 961 Short_Title : String_Access; 962 -- Title of the item, as it appears in the title bar. 963 -- These are UTF8-Encoded 964 965 XML_Node_Name : String_Access; 966 -- The name of the XML node when this child is saved in a desktop (if 967 -- we know it). This is used to reuse a child when switching 968 -- perspectives. 969 970 MDI : MDI_Window; 971 -- The MDI to which the child belongs. We cannot get this information 972 -- directly from Get_Parent since some children are actually floating 973 -- and do not belong to the MDI anymore. 974 975 Menu_Item : Gtk.Radio_Menu_Item.Gtk_Radio_Menu_Item; 976 -- The item in the dynamic menu that represents this child. 977 978 Flags : Child_Flags; 979 980 Focus_Widget : Gtk.Widget.Gtk_Widget; 981 -- The widget which should actually get the keyboard focus 982 983 Icon : Gdk.Pixbuf.Gdk_Pixbuf; 984 985 Title_Box : Gtk.Box.Gtk_Box; 986 -- Box that contains the title. It will be resized whenever the title 987 -- font changes. 988 989 Tab_Label : Gtk.Label.Gtk_Label; 990 -- label used when child is in a notebook, null if not in a notebook 991 end record; 992 993 type Child_Iterator (Group_By_Notebook : Boolean := False) is record 994 Visible_Only : Boolean; 995 996 case Group_By_Notebook is 997 when False => 998 Iter : Gtk.Widget.Widget_List.Glist; 999 1000 when True => 1001 MDI : MDI_Window; 1002 1003 -- While iterating children 1004 Paned_Iter : Gtkada.Multi_Paned.Child_Iterator; 1005 1006 -- Whether we have already visited the children of the central 1007 -- area. This is True while iterating them, False afterward 1008 In_Central : Boolean; 1009 1010 -- While iterating the pages of a specific notebook (notebook is 1011 -- set to null when returning floating children) 1012 Notebook : Gtk.Notebook.Gtk_Notebook; 1013 Notebook_Page : Glib.Gint; 1014 1015 -- While iterating the floating children 1016 Floating_Iter : Gtk.Widget.Widget_List.Glist; 1017 end case; 1018 end record; 1019 1020 type Drag_Status is (No_Drag, In_Pre_Drag, In_Drag); 1021 1022 type MDI_Window_Record is new Gtkada.Multi_Paned.Gtkada_Multi_Paned_Record 1023 with record 1024 Items : Gtk.Widget.Widget_List.Glist := Gtk.Widget.Widget_List.Null_List; 1025 -- The list of all MDI children. This includes children in the editor 1026 -- area, even though they are technically in a separate multi_paned. 1027 -- Warning: this list might contain items which are in fact invisible in 1028 -- the MDI (in fact that are not even children of the MDI), if they 1029 -- existed in a previous perspective but no longer in the current one. 1030 1031 Desktop_Was_Loaded : Boolean := False; 1032 -- True if a desktop was loaded 1033 1034 Loading_Desktop : Boolean := False; 1035 -- Whether we are currently loading the desktop. This impacts a number 1036 -- of focus and sizing parameters, so that the desktop can be restored 1037 -- as accurately as possible. 1038 1039 Delay_Before_Focus_Id : Glib.Main.G_Source_Id := Glib.Main.No_Source_Id; 1040 Delay_Before_Focus : Glib.Guint := 700; 1041 -- Delay in ms before a floating window gains the GPS focus, after the 1042 -- "focus_in" event. In all floating mode, this ensures that when the 1043 -- user is passing briefly over floating windows they do not gain the 1044 -- focus, thus potentially leaving the focus to the window that had it 1045 -- at the beginning of the move. 1046 -- Set to 0 to remove any delay. 1047 1048 Focus_Child : MDI_Child := null; 1049 -- The child that currently has the focus. Some default actions will 1050 -- apply to this child only. 1051 1052 Dnd_Message : String_Access; 1053 -- The message displayed during a dnd operation (see Set_Dnd_Message) 1054 1055 Accel_Path_Prefix : String_Access; 1056 -- The Accel path used for the dynamic menu 1057 1058 Menu : Gtk.Menu.Gtk_Menu; 1059 Float_Menu_Item : Gtk.Check_Menu_Item.Gtk_Check_Menu_Item; 1060 Float_Menu_Item_Id : Gtk.Handlers.Handler_Id; 1061 Close_Menu_Item : Gtk.Menu_Item.Gtk_Menu_Item; 1062 -- The dynamic menu used to provide access to the most common 1063 -- functions of MDI. 1064 1065 Tab_Factory : Tab_Contextual_Menu_Factory; 1066 -- Build the contextual menu when right-clicking on tabs 1067 1068 Title_Layout : Pango.Layout.Pango_Layout; 1069 -- Layout used to draw titles in the MDI children 1070 1071 Title_Bar_Height : Glib.Gint; 1072 -- Height of the title bar for all the children 1073 1074 Close_Floating_Is_Unfloat : Boolean; 1075 -- True if destroying a floating window will put the child back in the 1076 -- MDI instead of destroying it. False if the child should be destroyed 1077 -- (provided it accepts so in its delete_event handler). 1078 1079 Highlight_Style : Gtk.Style.Gtk_Style; 1080 -- Style to use to highlight the tabs and menus for the highlighted 1081 -- children. 1082 1083 Background_Color : Gdk.Color.Gdk_Color := Gdk.Color.Null_Color; 1084 Title_Bar_Color : Gdk.Color.Gdk_Color := Gdk.Color.Null_Color; 1085 Focus_Title_Color : Gdk.Color.Gdk_Color := Gdk.Color.Null_Color; 1086 Default_Title_Color : Gdk.Color.Gdk_Color := Gdk.Color.Null_Color; 1087 1088 Cursor_Cross : Gdk.Cursor.Gdk_Cursor; 1089 Cursor_Fleur : Gdk.Cursor.Gdk_Cursor; 1090 -- Cached cursors 1091 1092 Draw_Title_Bars : Title_Bars_Policy := Always; 1093 Tabs_Position : Gtk.Enums.Gtk_Position_Type := Gtk.Enums.Pos_Bottom; 1094 Show_Tabs_Policy : Show_Tabs_Policy_Enum := Automatic; 1095 1096 Selection_Dialog : Gtk.Widget.Gtk_Widget; 1097 -- The interactive dialog for selecting new children. 1098 1099 Dnd_Window : Gtk.Window.Gtk_Window; 1100 Dnd_Window_Label : Gtk.Label.Gtk_Label; 1101 -- The small window displayed while a drag-and-drop operation is 1102 -- taking place. 1103 1104 Group : Gtk.Accel_Group.Gtk_Accel_Group; 1105 1106 All_Floating_Mode : Boolean := False; 1107 -- Set to true if all windows should be set to floating 1108 1109 Independent_Perspectives : Boolean := False; 1110 -- See documentation for Configure. 1111 1112 Use_Short_Titles_For_Floats : Boolean := False; 1113 -- Set to true if all floating children should use their short titles 1114 1115 -- Handling of Dnd 1116 Drag_Start_X, Drag_Start_Y : Gint; 1117 In_Drag : Drag_Status := No_Drag; 1118 Dnd_Rectangle : Gdk.Rectangle.Gdk_Rectangle; -- Highlighted area 1119 Dnd_Target : Gdk.Gdk_Window; -- The current target for DND 1120 Dnd_Target_Window : Gtk.Window.Gtk_Window; -- The overlay window 1121 1122 -- Loaded perspectives 1123 Perspective_Menu_Item : Gtk.Menu_Item.Gtk_Menu_Item; 1124 Perspectives : Glib.Xml_Int.Node_Ptr; 1125 View_Contents : Glib.Xml_Int.Node_Ptr; 1126 Perspective_Names : GNAT.Strings.String_List_Access; 1127 Central : Gtkada.Multi_Paned.Gtkada_Multi_Paned; 1128 1129 Current_Perspective : Glib.Xml_Int.Node_Ptr; 1130 -- pointer into Perspectives 1131 end record; 1132 1133 pragma Inline (Get_Widget); 1134 pragma Inline (Get_Focus_Child); 1135 pragma Inline (Get); 1136 pragma Inline (Next); 1137 pragma Inline (First_Child); 1138 1139end Gtkada.MDI; 1140