2009 Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page i of 50 i
Table of Contents 1 Preamble....................................................................................................... 1 2 Introduction .................................................................................................. 1 2.1 Why Verbose Code? .............................................................................. 1 2.2 On Being Methodical ............................................................................. 2 3 Getting GtkAda ............................................................................................. 2 3.1 Glade ..................................................................................................... 2 3.2 GtkAda Documentation ......................................................................... 2 4 Preparations.................................................................................................. 2 4.1 The Mud Map ........................................................................................ 2 4.1.1 Connotative Identifiers .................................................................. 2 4.1.2 Base Boxes ..................................................................................... 3 4.1.3 HBoxes and VBoxes ........................................................................ 3 5 The Cardinal Rule .......................................................................................... 4 6 Other Packages Required .............................................................................. 4 6.1 Mainline ................................................................................................ 5 6.1.1 Set_Locale ..................................................................................... 5 6.1.2 Init ................................................................................................. 5 6.1.3 Show_All ........................................................................................ 5 6.1.4 Main .............................................................................................. 5 6.1.5 The Pragma .................................................................................... 5 6.2 Portability Package ................................................................................ 5 6.3 Callbacks Package .................................................................................. 6 6.3.1 Item Types Requiring Callbacks ...................................................... 6 6.4 Handler Packages .................................................................................. 7 6.5 Toplevel Widget Package ...................................................................... 7 7 Playing with LEGO Blocks ............................................................................... 7 7.1 Setting up the Window .......................................................................... 7 7.1.1 Setting Window Characteristics ...................................................... 7 7.1.2 Sneak a Preview ............................................................................. 9 7.2 Boxes in the Window ............................................................................. 9 7.2.1 Create Window_Base_HBox ........................................................... 9 7.2.2 Create Window_VBox .................................................................... 9 7.2.3 Set the Boxes in the Window ......................................................... 9 7.3 Install a Menu Bar .................................................................................. 9 7.3.1 Menu_Base_Box ............................................................................ 9 7.3.2 Menu_Bar ...................................................................................... 9 Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page ii of 50 ii
7.3.3 Create the File Menu.................................................................. 10 7.3.4 The New Tab .............................................................................. 10 7.3.5 Sneak a Preview ........................................................................... 11 7.4 Install Textedit Screen ........................................................................ 11 7.4.1 Scrolled_Window ......................................................................... 11 7.4.2 Setting Screen Characteristics ...................................................... 11 7.5 Install an Horizontal Separator ............................................................. 11 7.5.1 Sneak a Preview ........................................................................... 11 7.6 Create the Keyboard ............................................................................ 12 7.6.1 Create the Boxes for the Keyboard ............................................... 12 7.6.2 Create and Install BigButton........................................................ 12 7.6.3 Create and Install the Vertical Separator ...................................... 12 7.6.4 Create and Install the Three Small Buttons ................................... 12 8 It is Done ..................................................................................................... 13 8.1 Removing the Command Screen .......................................................... 13 9 Gadget: Exploded Diagram .......................................................................... 14 10 Code ........................................................................................................... 15 10.1 Mainline Gadget.adb ....................................................................... 15 10.2 Portability Package .............................................................................. 16 10.2.1 Specification Gadget_Intl.ads ................................................... 16 10.2.2 Implementation Gadget_Intl.adb ............................................. 16 10.3 Callbacks Package ................................................................................ 17 10.3.1 Specification Gadget_Package.Callbacks.ads ............................ 17 10.4.1 Specification Callbacks_Gadget.ads ......................................... 21 10.5 Development Package ......................................................................... 22 10.5.1 Specification Gadget_Pkg.ads .................................................. 22 10.5.2 Implementation Gadget_Pkg.adb ............................................ 25 11 Reference List ............................................................................................. 47
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 1 of 50 1
Gadget: Building a Compound Widget with GtkAda Rick Duley Perth, Western Australia
Under Australian Law (The Copyright Act of 1968 and Amendments) this work is copyright to the author by fact of its creation and commission to a storage medium. Proprietary rights are hereby waived provided the work is used for educational purposes, AND that the work is presented in full and unmodified, AND that this copyright remains attached and unmodified, All moral rights under the Australian Copyright Amendment (Moral Rights) Act of 2000 are reserved.
1 Preamble The author would like to acknowledge the gallant and patient assistance of the people from AdaCore, the Gnat Academic Program, the GtkAda Mailing List, and others without which he would not have made it this far. This document is humbly presented in the hope that its availability will lessen those peoples future torment. Thanks folks! 2 Introduction This article is intended to save GtkAda Newbies from some of the pain they might experience in learning how to use the system. It traces the construction of a compound widget in verbose code format with comments on the actions of parameters, what they do and what the options are. Gadget will not actually do anything except allow text to be entered into the text window. This is merely an exercise in making the composite widget appear the way it is planned. It is almost certainly not perfect merely an attempt to help. For resolution of matters not dealt with here go to http://libre.adacore.com/libre/tools/gt kada/ and register with the GtkAda Mailing list. (Go to the bottom of the page and the paragraph beginning, Note that the . 2.1 Why Verbose Code? GtkAda from AdaCore comes with an automated developer called Glade (ref: paragraph 3.1 on page 2). This lets a programmer create an interface by sight, then it creates the code to suit. One of the problems with Newbies learning GtkAda by working with Glade is that Glade code does not specify the origin of the widgets and things it uses. Glade religiously implements the use clause. Consequently, beginners do not learn to work with the GtkAda Reference Manual. Because of that they get to know that the code works, but they do not get to know how it works. Verbose style programming changes this because the relevant package is named at each procedure or function call. Furthermore, many of the procedures and functions implemented are inherited from ancestor widgets. Programmers must learn to trace the ancestry of the current widget to find the appropriate operation. Verbose style programming means a lot of typing, but, in the end, it is quicker for a beginner. Programmers tend to think more carefully about each step. Therefore, they avoid unending confusion. Time spent typing is more than compensated for with time saved debugging. Meticulously naming formal parameters and assigning values to them forces Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 2 of 50 2
programmer to think carefully about those values as well. Another error which is frequent when assigning parameter values by association is that of getting the actual parameters in the wrong order. This glitch can be one of the hardest to find. This virtually never happens in verbose programming, and if it does it doesnt matter 2.2 On Being Methodical All programming is methodical in nature graphics programming especially so. Consider the exploded construction diagram on page 14. Dont Panic! For the moment, note only that it starts with the base widget (the window itself) and progressively, working to the right, adds further widgets. In turn, each of these widgets is created, its characteristics are defined, and it is added to the widget to its left. (There are other things that go on but they are not important just yet,) Keep this idea of being methodical in mind. It is the basis of the whole process. 3 Getting GtkAda For a great start contact gap- contact@adacore.com and get registered with the GNAT Academic Program run by AdaCore. Then you can download the GAP Package which includes a quality Integrated Development Environment, complete with compiler and support packages including Win32 and GtkAda. The best advice is to download and install the lot using the default installation settings. 3.1 Glade The GtkAda package includes the executable for Glade, an interactive GUI-builder package. I unashamedly used this package to learn many of the rudiments of GtkAda programming. However, the true power and range of the GtkAda package is only realised by manually coding it. Learning some of the skills required to do that is the object of this exercise. 3.2 GtkAda Documentation Full HTML documentation is included in the GtkAda package. If you have used all the default settings it can be found at c:\GtkAda\share\doc\gtkada\. I refer to these documents all the time so I have shortcuts to them on my desktop. Information on the functions of widgets and the meanings of formal parameters presented here is largely taken from these documents. 4 Preparations Building a compound widget with GtkAda is like building something with LEGO blocks. You simply take the pieces and plug them together. This, however, is not a childs game. Working with GtkAda requires planning. The programmer must know exactly what is to be built before coding starts. Anything other than forethought and planning in fine detail is a recipe for frustration and futility. Be warned! 4.1 The Mud Map Programmers should draw what Australians call a Mud Map before doing anything else. A Mud Map, strictly speaking, is a sketch scraped in the dirt with a finger or a stick. Its just something to get a rough idea. Draw that sort of a sketch of the layout to be achieved including all the visible and invisible widgets to be included in the compound widget. Leave nothing out, and name all the parts in a logical, distinctive and connotative manner. Such a mud map for Gadget is shown in Figure 1. Remember, an exploded diagram of Gadget is shown on page 14 and that may make the design more clear. 4.1.1 Connotative Identifiers Make sure the names of the widgets are distinctive and self-explanatory at the time you draw your Mud Map, and use them when you program. Call the widgets anything you wish, but make sure the name describes what the widget or variable does. Do not accept the identifiers I used as any ultimate. This idea of the use of connotative identifiers is one of the foundation principles of Ada Programming which is what you will be doing in this exercise. The Style Manual still offers these suggestions: Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 3 of 50 3
choose names that are as self- documenting as possible; use names given by the application; do not use obscure jargon; avoid using the same name to declare different kinds of identifiers; do not use an abbreviation of a long word when a shorter synonym exists; use a consistent abbreviation strategy; do not use ambiguous abbreviations; to justify its use, an abbreviation must save many characters over the full word; use abbreviations that are well- accepted in the application domain; and maintain a list of accepted abbreviations, and use only abbreviations on that list. (Software Productivity Consortium, 1995) 4.1.2 Base Boxes Surround each individual widget below the Top-level widget, including multiple- cell boxes, in a single-cell box. It is a little complicated but it does ensure that the visible widgets (e.g. buttons, screens, and separators) will appear as you expect them to appear. 4.1.3 HBoxes and VBoxes As you can see, The_Gadget uses two VBoxes and one HBox. If you have played with Glade you will know that
Figure 1: Gadget Mud Map Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 4 of 50 4
you can specify the number of cells in a box. When you are coding manually you do not have, or need, that option. Programmers arrange things so that each item added will appear below the one before (in VBoxes) or to the right of the one before (for HBoxes). Gadget uses only HBoxes and VBoxes. More specific control of layout is available through use of ButtonBoxes but that is complexity and sophistication not warranted here. 5 The Cardinal Rule As St Paul put it, "Let all things be done decently and in order."--1 Corinthians 14:40. Take a look at the exploded diagram of Gadget shown on page 14. The General Plan of Attack is: 1. Create Gadget_Record, Window_Base_HBox, and Window_VBox. 2. Install Window_VBox in Window_Base_HBox, then install Window_Base_HBox in Gadget_Record (the window). This completes the foundation of the compound widget. 3. Create Menu_Base_HBox and Menu. 4. Install Menu in Menu_Base_HBox then install Menu_Base_HBox into Window_VBox. This will be in the first, i.e. top, cell of Window_VBox. 5. Create File_Menu and File_Dropdown. 6. Attach File_Dropdown to File_Menu then install File_Menu into Menu. 7. Create the submenus with Callbacks and File_Separator and install them in the File_Dropdown. 8. CreateScreen_Frame_HBox, Screen_Frame, Screen_Base_HBox, Scroll, and Screen; Screen_Buffer is created with Screen. 9. Install Screen_Frame into Screen_Frame_HBox; install (Scroll Bar fitted) Screen into Screen_HBox; install Screen_Base_HBox into Screen_Frame; install Screen_Frame_HBox into Window_VBox. This will be the second cell of Window_VBox. 10. Create H_Sep_HBox and H_Sep. 11. Install H_Sep into H_Sep_HBox; install H_Sep_HBox into Window_VBox. This will be the third cell Window_VBox. 12. Create Buttons_Base_HBox and Buttons_HBox. 13. Install Buttons_HBox in Buttons_Base_HBox then install Buttons_Base_HBox in Window_VBox. This completes the foundation of the keyboard. 14. Create Big_Button_Base_HBox and Big_Button. 15. Install Big_Button in Big_Button_Base_HBox then Big_Button_Base_HBox in Buttons_HBox. This will be in the left-hand cell of Buttons_HBox. 16. Create V_Sep_Base_HBox and V_Sep. 17. Install V_Sep into V_Sep_Base_HBox then V_Sep_Base_HBox into Buttons_HBox. 18. Create Three_Buttons_Base_HBox and Three_Buttons_VBox. 19. Install Three_Buttons_VBox into Three_Buttons_Base_HBox then install Three_Buttons_Base_HBox into Buttons_HBox. This completes the foundation for the three buttons. 20. Create B1_Base_HBox and B1 with its callbacks. 21. Install B1 into B1_Base_HBox then install B1_Base_HBox into Three_Buttons_VBox. 22. Repeat steps 20 and 21 for B2. 23. Repeat steps 20 and 21 for B3. 6 Other Packages Required Anyone who has used Glade knows that doing a Build in Glade produces a number of packages specifications and bodies and a Mainline. Set these up before starting to cut code. Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 5 of 50 5
Beginner Programmers are always keen to get down to cutting code. Older heads get set up first. Follow their example. I use the naming conventions used by Glade. There is no law about that, but whatever you do, be consistent. 6.1 Mainline Name: <program name>.adb This file contains the code to create and initialise the top-level widget. In the case of the Gadget project this is a Window. See Figure 2 for the standard code as it applies to this project. 6.1.1 Set_Locale This routine collects local settings, such as time, from the host system. Always include this because it means that your widget can then be used on another system, which is, after all, what you want,. 6.1.2 Init This routine sets up the internal structure of the interface. It exits with an error message if something goes wrong like the computer is not connected to a VDU. 6.1.3 Show_All Gadget_Pkg inherits this routine from Gtk.Widget. It displays The_Gadget and all of its children. This is the routine that makes your GUI appear on the screen. 6.1.4 Main This procedure starts the operating loop and ends only when the operating loop is exited. 6.1.5 The Pragma Here the pragma is shown commented out. Put it in when you write the mainline and uncomment it when you are finished developing. On a PC, this pragma removes the command screen from behind the GUI. However, the command screen is useful during development, a matter dealt with later. 6.2 Portability Package Name: <program name>_Intl.ads/adb Graphical User Interfaces are not much use if they will only run on the machine
Figure 2: Gadget.adb the Mainline
Figure 3: Gadget_Intl.adb Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 6 of 50 6
on which they were written. Surely, the object of the exercise is to write the whizz-bang program and have people all over the world using it. Obviously, then, the program has to be able to adapt to its environment to things like changes of time zone. The Portability Package handles these problems. In the GtkAda Reference Manual entry for Gtkada.Intl we find, This package provides support for string internationalization using the libintl library. To provide internationalization in your application, you must install a number of files along with your application, and modify your code to highlight the strings to translate. This translation is based on the gettext() library. Checking gettext() we read, Depending on the specific implementation of gettext, the following environment variables may be set to change the default settings of locale parameters: - LANG Specifies locale name. - LC_MESSAGES Specifies messaging locale, and if present overrides LANG for messages. - TEXTDOMAIN Specifies the text domain name, which is identical to the message object filename without .mo suffix. - TEXTDOMAINDIR Specifies the pathname to the message database, and if present replaces the default. See Figure 3. Now you know everything. 6.3 Callbacks Package Name: <program name>_Pkg- Callbacks.ads/adb This file contains the code to create the callback procedures needed for the project. This is where the Mud Map becomes useful. Interactive widget types shown on the Map all need callback packages. 6.3.1 Item Types Requiring Callbacks From the Mud Map we can see that there are the widgets which will send messages to the program for implementation: Screen Menu Selection Button Note Carefully: Every time you attach a callback to a widget it will need a handler. Write the handler when you attach the callback. This will save you from confusion later on. It is a matter of disciplined coding procedure. Figure 4 shows the callback required for the New tab on the menu with the procedure in stubbed form. If Gadget was supposed to do anything, there would be code in place of the null. During development, a command window (all black and old fashioned) appears behind Gadget. This can be put to testing use in the callback procedures by using Ada.Text_Io to write to messages. See, for instance, Figure 10 on page 11. When Big Button is clicked a message will appear on the command window. This shows that the callback system is working properly. Before the application is distributed, a pragma is used to remove the command window (see paragraph 6.1.5 on page 5).
Figure 4: Gadget_Pkg.Callbacks.adb - stubbed function
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 7 of 50 7
6.4 Handler Packages Name: Callbacks_<program name>.ads It is all very well having callback routines but they will not do anything unless there is an appropriate Handler package to deal with them. A callback handler needed in Gadget is shown in Figure 5. Since this package only instantiates new packages there is no package body. The sequence is: Instantiate handler package; Write the handler procedure; Attach the handler. Note: the pragma. This simply ensures that the library code for the Gtk.Handlers is elaborated before being called. Good practice. 6.5 Top-level Widget Package Name: <widget name>_pkg.ads/adb See Figure 6. This is where you build your composite widget. Read on. 7 Playing with LEGO Blocks Building a compound widget with GtkAda is like building something with LEGO blocks. You simply take the pieces and plug them together. (See paragraph 4 on page 2.) Sounds simple, doesnt it. Well, it is if you do it systematically. If you rush in, youll find out why they say fools do that. 7.1 Setting up the Window The first thing to do is to pick a top- level widget in the case of Gadget, use a window. Figure 6 shows the minimum code for the top-level package specification for Gadget. This would merely specify an empty window. Other widgets are added to the record. Of course, you will need a package body containing implementations for Gtk_New and Initialize. See Gtk_New line 17 in Gadget_Pkg.adb (page 25). This is the procedure called by the mainline to create a new widget. In this case it creates a new Gadget_Record which is a child of Gtk.Window.Gtk_Window_Record and inherits all the functionality of a Gtk.Window.Gtk_Window_Record. Then it sends New_Gadget to the initialisation procedure where all the other bits are added. See Initialize in line 25 in Gadget_Pkg.adb. Here we get particular about the characteristics and contents of the window. In Gadget there are several things to set. 7.1.1 Setting Window Characteristics Note: Gtk.Enums is a package that contains types used by GtkAda widgets. Programmers should familiarise themselves with these as they give good indication of the range of characteristics programmers can specify. 7.1.1.1 Gtk.Window.Initialize The first call initialises the window which will contain all the other widgets as they are created. See line 38 in Gadget_Pkg.adb. It is not necessary to name and give value to the formal parameter The_Type in this case since the value we want is the default value. This value ensures that the window will be visible when
Figure 5: Callbacks_Gadget.ads Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 8 of 50 8
created, i.e. not hidden behind other windows that may be open at the time. 7.1.1.2 Set_Icon_From_File To an Ada programmer, using a function to perform an external operation (see line 45 in Gadget_Pkg.adb) is something of an anachronism. This is a practice traceable to C and on back to the beginnings of High-level Programming Languages. This practice has the immediate disadvantage that the function returns an (unneeded) value which must be stored somewhere. Such a Boolean value would once have been used to prove that the operation was successful, but since it is not needed here it is assigned to the variable Icon declared back at line 46; then forgotten about. Warning: sending an ICO file to this function causes problems. Use BMP, GIF, PNG etc. In Gadget the GIF format was used to take advantage of its transparency capability. 7.1.1.3 Set_Title As you would expect, this procedure puts whatever name you like in the top border of the window. See line 51 in Gadget_Pkg.adb. It and the other Sets are part of Gadget_Pkg inherited from Gtk.Window. 7.1.1.4 Set_Position The parameter Position is set to Gtk.Enums.Win_Pos_None at line 57 in Gadget_Pkg.adb. which means that the window can appear just about anywhere on the screen i.e. there is no defined position at which it has to appear. There are a variety of available set positions including appearing where the cursor is. 7.1.1.5 Set_Modal Setting the window to Modal => TRUE (line 62) means that it will take the input from the keyboard and the mouse while the window is fully visible. It will ignore them when the window is hidden at all. 7.1.1.6 Set_Resizable Just what you would expect. 7.1.1.7 Connecting the Callback In paragraph 6.3.1 on page 6 the statement was made, Every time you attach a callback to a widget it will need a handler. Well, here a special callback must be attached to the window (line 71). In the top, right-hand corner of most main windows is a little button marked X. This button usually ends the program that created it as well as closing down its own window. Here, we connect that button to its handler (On_X_Button_Destroy in line 43 of Gadget_Pkg-Callbacks.adb). Note carefully: do not forget this step. In the first place, you will not be able to get rid of your window, and, in the second place your application will continue to run and you will not be able to rebuild your program.
Figure 6: Gadget_Pkg.ads
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 9 of 50 9
7.1.2 Sneak a Preview Before you can see what you have done you must build your application using the Mainline (page 5). Figure 7 shows what you will get if you build your mainline at this stage. There is a window with a name and an icon and perilous little else. 7.2 Boxes in the Window Note Carefully: A window can only have one child widget. If more than one widget is to appear in the window then they have to be in some container (containers can have multiple children). There are two types of box in Gadget; HBox and VBox. As pointed out in paragraph 4.1.2 on page 3 it is best to ensure that each widget, including frames and multi-cell boxes, is contained in a single-cell box. 7.2.1 Create Window_Base_HBox See line 93 in Gadget_Pkg.adb. 7.2.1.1 Homogeneous 'Homogeneous => TRUE' means the cells in this box will all be the same size. There is, in fact only one cell in this box so the parameter could have been left at the default value false. 7.2.1.2 Spacing 'Spacing => 0' is the default value and means that there is no space between the box and its contents. 7.2.2 Create Window_VBox This box will sit inside Window_Base_HBox See line 104 in Gadget_Pkg.adb. Window_VBox will hold the Menu in the top cell and all the other widgets in successively lower cells. 7.2.2.1 Homogeneous Homogeneous => false means that the cells can be different sizes. This is the default value and could be omitted. 7.2.2.2 Spacing Spacing => 2 means there will be a two-pixel gap between the box and its contents. 7.2.3 Set the Boxes in the Window Once again, it is a matter of doing things in order. Window_VBox into Window_Base_HBox See line 114 in Gadget_Pkg.adb. Window_Base_HBox into The_Gadget The_Gadget is the window itself. See line 122 in Gadget_Pkg.adb. 7.2.3.1 Sneak a Preview This looks no different to Figure 7 because the boxes are not visible. So, build something to put in the Window_VBox. 7.3 Install a Menu Bar Take these things in order. 7.3.1 Menu_Base_Box Make a single-cell box to hold the menu. See line 135 in Gadget_Pkg.adb. Homogeneous and Spacing have both been discussed previously. 7.3.2 Menu_Bar Construct the menu bar to go into Menu_Base_Box 7.3.2.1 Gtk_New This procedure creates the menu bar itself blank. . See line 140 in Gadget_Pkg.adb.
Figure 7: Gadget - Just a Named Window
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 10 of 50 10
7.3.2.2 Set_Pack_Direction This procedure stipulates the linear relationship of the sub-menus in the menu bar. The choices are Left-to- Right, Right-To-Left, Top-To-Bottom or Bottom-To-Top. See line 144 in Gadget_Pkg.adb. 7.3.2.3 Pack_Start This routine is called twice; once to insert Menu_Bar in Menu_Base_Box then again to install Menu_Base_Box in Window_VBox. See lines 149 and 156 in Gadget_Pkg.adb. Pack_Start is called for both HBoxes and VBoxes so the GtkAda Reference Manual tells us the call means: Add a new child to the beginning of the box (ie left or top part). It is added to the right (resp. the bottom) of the previous child added to the beginning of the box. Note that a child added to the beginning of the box will always remain on the left (resp. top) of all the children added to the end of the box. In this case, size of the box in question is, in fact, defined by the number of items in the menu. Successive words along the menu line will be added from left to right and the box expands to suit. 7.3.3 Create the File Menu Menu_Bar is just a bar at this stage and it needs dropdown menus to make it useful. 7.3.3.1 New_With_Mnemonic. Firstly, call Gtk_New_With_Mnemonic. See line 171 in Gadget_Pkg.adb. The label is created with an underscore indicating the mnemonic for the menu item (i.e. pressing the ALT key and the underscored letter activates the menu item). 7.3.3.2 Gtk_New This procedure creates a new dropdown menu for the menu bar. See line 176 in Gadget_Pkg.adb. Now attach File_Dropdown to File_Menu and then File_Menu to Menu itself. Note Carefully: because each parent is a different type of widget the routines are different and come from different packages. This is a prime example of the need to keep one hand on the Reference Manual and the other on the keyboard. Programmers must use the attachment routine for the appropriate Widget. 7.3.4 The New Tab Now there is a dropdown from the menu but there is nothing on it. See the lines starting at 193 in Gadget_Pkg.adb for the creation of the New tab. 7.3.4.1 Gtk_New_From_Stock This procedure creates a new stock item (a tab for the dropdown menu) which, typically, has an icon next to the action name. Many of the commonly required menu items and buttons, with appropriate icons, are available ex stock. This saves a lot of time and coding in the creation of the widget followed by the design and attachment of the icon. It also means that the software created has a consistent look. To find a list of the available Stock Items, and assuming default addresses for your installation, got to C:\GtkAda\include\gtkada\gtk- stock.ads. 7.3.4.2 Image_Menu_Item_ Callback.Connect This procedure connects the new tab to its callback handler by advising the callback marshaller which callback subroutine to use. 7.3.4.3 Append This procedure attaches the 'New' tab to the dropdown menu. It is inherited from 'Gtk.Menu_Shell'. 7.3.4.4 Create the Other Menu Tabs and the Separator The above sequence is repeated (more or less) for the rest of the tabs on the dropdown menu. See code starting at line 215 in Gadget_Pkg.adb.
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 11 of 50 11
7.3.5 Sneak a Preview Figure 8 shows the result of building the mainline at this stage a Gadget with a dropdown menu. 7.4 Install Text-edit Screen For Gadget use Gtk.Text_View. Check the Mud Map on page 3. In the second cell of Window_VBox sits a single-cell HBox named Screen_Frame_HBox. In Screen_Frame_HBox sits a Gtk_Frame named Screen_Frame and inside that again sits a single-cell HBox named Screen_Base_Box. Finally, inside Screen_Base_Box sits the widget that does the work, a Gtk.Text_View named Screen. When Screen is created several characteristics such as size and border width are set. Creating the Boxes and Screen is largely familiar territory and will be simple to follow. See code starting at line 327 in Gadget_Pkg.adb. There is one new concept. 7.4.1 Scrolled_Window It may be that the user enters too much text into the editing area. Creating Scroll ensures that, in that case, scroll bars will appear when they are needed. They are not displayed when the area is blank. The Scrollbars are created at line 368 in Gadget_Pkg.adb. Scrollbar adjustments can be set (see Gtk.Adjustment in the Reference Manual) but that sort of thing is for the brave, or for those who have plenty of time to experiment. Using the null values makes the process automatic. Another automation is setting when the scrollbars appear. The options (see Gtk.Enums) are Policy_Always, Policy_Automatic, Policy_Never. 7.4.2 Setting Screen Characteristics A variety of characteristics can be set. These specify the way in which the editing area appears and interacts with the user. Starting at line 389 in Gadget_Pkg.adb we have: Set_Size_Request Set_Left_Margin & Set_Right_Margin Set_Wrap_Mode (Note: Because entered text will now word- wrap, the horizontal scroll bar will not appear.) Set_Accepts_Tab 7.5 Install an Horizontal Separator This is an Ornament. It serves no practical purpose but visually separates Screen from the buttons below. Referring to the Mud Map reveals that the third cell of Window_VBox sits a single-cell HBox named H_Sep_Box which, in turn, holds the Separator named H_Sep. Creation and installation procedures used are familiar territory. See line 434 in Gadget_Pkg.adb. 7.5.1 Sneak a Preview Figure 9 shows Gadget to date. Now we need some buttons to press.
Figure 8: Gadget with Menu
Figure 9: Gadget with Text Screen, Scrollbar, and Horizontal Separator Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 12 of 50 12
7.6 Create the Keyboard This is where it might seem a bit complicated. However, it is said that the way to eat an elephant is to chew on one mouthful at a time. In coding the Keyboard, as usual, take little bits at a time. 7.6.1 Create the Boxes for the Keyboard Simple. See lines starting at 469 in Gadget_Pkg.adb 7.6.2 Create and Install Big- Button The only new thing here (starting at line 499) is the introduction of Ada.Characters.Latin_1. This allows use of a carriage return character (CR) so that the title of the button appears in two lines. All else is familiar. Note the trick here with the label. Normally, the text on the button is added at its creation (line 505) but here a null entry is used. This is because the text is to appear in two lines rather than the default one. Create a label (line 508) with the two words separated by a CR (carriage return relates to the days of the typewriter and indicates the end of one line and the start of a new one) character. This text is then justified center (line 514) and the label added to the button (line 519). If the text is not specifically justified to the centre, the default will be justified to the left. 7.6.2.1 Debugging Trick That black screen with white characters, the Command Screen, that has been appearing behind Gadget now comes in useful. Figure 10 shows the coding of a callback procedure for the situation when Big_Button is clicked. This will make the message, Big Button was Clicked appear in the command screen. Then the programmer knows that the handler procedure is connected properly and is being run by the appropriate handler package. In other words it works. That code line will be replaced when Big_Button has a job. 7.6.2.2 Connect Callbacks Note Carefully: Dont forget to have an appropriate handler package in Callbacks_Gadget.ads and to write the handlers in Gadget_Pkg.Callbacks.ads/adb. 7.6.2.3 Tooltip Add a line explaining the function of the Button for the user. This line will appear when the cursor is over the button. See line 530 in Gadget_Pkg.adb. Tip_Private contains more information. Although that information can be displayed, in most cases, Tip_Private should simply keep its default empty value. 7.6.3 Create and Install the Vertical Separator Simple. This is the same process as for the horizontal separator. See line 560 in Gadget_Pkg.adb 7.6.4 Create and Install the Three Small Buttons Absolutely nothing new here just repetition. This is where the programmer learns the value of Cut- And-Paste. See lines starting at 592 in Gadget_Pkg.adb 7.6.4.1 Connect Callbacks Note Carefully: Dont forget to have an appropriate handler package in Callbacks_Gadget.ads and to write the handlers in Gadget_Pkg.Callbacks.ads/adb.
Figure 10: Text Message Test for Big Button
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 13 of 50 13
8 It is Done The_Gadget is complete (Figure 11). It doesnt actually do much, but it looks the way it was planned. There is just on small thing getting rid of the command screen. 8.1 Removing the Command Screen Refer to paragraph 6.1.5 and Figure 2 on page 5. All has been explained.
Figure 11: The_Gadget Completed Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 14 of 50 14
9 Gadget: Exploded Diagram
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 15 of 50 15
10 Code Disclaimer: This work is provided as is and without any express or implied warranties including, without limitation, the implied warranties or merchantability and fitness for a particular purpose.
10.1 Mainline Gadget.adb
1 with Gtk.Main; 2 with Gadget_Pkg; 3 with Callbacks_Gadget; 4 procedure Gadget is 5 6 pragma Linker_Options ("-mwindows"); 7 8 The_Gadget : Gadget_Pkg.Gadget_Access; 9 begin -- Gadget 10 Gtk.Main.Set_Locale; 11 Gtk.Main.Init; 12 Gadget_Pkg.Gtk_New (The_Gadget); 13 Gadget_Pkg.Show_All (The_Gadget); 14 Gtk.Main.Main; 15 end Gadget;
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 16 of 50 16
1 package Gadget_Intl is 2 3 function Local_Format (Input : String) return String; 4 -- This function converts the hard-coded text input into a string in a 5 -- format appropriate to the local host. It utilises Gtkada.Intl.Dgettext 6 -- to perform the conversion. 7 8 end Gadget_Intl; 10.2.2 Implementation Gadget_Intl.adb
1 with Gtkada.Intl; 2 package body Gadget_Intl is 3 -- This function converts the hard-coded text input into a string in a 4 -- format appropriate to the local host. It utilises Gtkada.Intl.Dgettext 5 -- to perform the conversion. 6 function Local_Format (Input : String) return String is 7 begin 8 return Gtkada.Intl.Dgettext (Domain => "Gadget", 9 Msg => Input); 10 end Local_Format; 11 end Gadget_Intl;
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 17 of 50 17
1 with Gtk.Image_Menu_Item; 2 3 package Gadget_Pkg.Callbacks is 4 5 procedure On_X_Button_Destroy 6 (Object : access Gtk.Window.Gtk_Window_Record'Class); 7 -- On_X_Button_Destroy is a callback to destroy the main window and end 8 -- the program run when the [X] button at top right of the window is clicked. 9 10 procedure On_New_Tab_Activate 11 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class); 12 -- New_Tab is an available selection on the 'File' dropdown menu. This 13 -- procedure takes the appropriate action when 'New' is clicked. 14 15 procedure On_Open_Tab_Activate 16 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class); 17 -- Open_Tab is an available selection on the 'File' dropdown menu. This 18 -- procedure takes the appropriate action when 'Open' is clicked. 19 20 procedure On_Save_Tab_Activate 21 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class); 22 -- Save_Tab is an available selection on the 'File' dropdown menu. This 23 -- procedure takes the appropriate action when 'Save' is clicked. 24 25 procedure On_Save_As_Tab_Activate 26 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class); 27 -- Save_As_Tab is an available selection on the 'File' dropdown menu. This 28 -- procedure takes the appropriate action when 'Save As' is clicked. 29 30 procedure On_Quit_Tab_Activate Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 18 of 50 18
31 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class); 32 -- Quit_Tab is an available selection on the 'File' dropdown menu. This 33 -- procedure takes the appropriate action when 'Quit' is clicked. 34 35 procedure On_Big_Button_Clicked 36 (Object : access Gtk.Button.Gtk_Button_Record'Class); 37 -- This procedure takes the appropriate action when 'Big Button' is clicked. 38 39 procedure On_B1_Clicked 40 (Object : access Gtk.Button.Gtk_Button_Record'Class); 41 -- This procedure takes the appropriate action when 'B1' is clicked. 42 43 procedure On_B2_Clicked 44 (Object : access Gtk.Button.Gtk_Button_Record'Class); 45 -- This procedure takes the appropriate action when 'B2' is clicked. 46 47 procedure On_B3_Clicked 48 (Object : access Gtk.Button.Gtk_Button_Record'Class); 49 -- This procedure takes the appropriate action when 'B3' is clicked. 50 end Gadget_Pkg.Callbacks; 10.3.2 Implementation Gadget_Pkg.Callbacks.adb
1 with Gtk.Main; 2 3 package body Gadget_Pkg.Callbacks is 4 5 -- On_X_Button_Destroy is a callback to destroy the main window and end 6 -- the program run when the [X] button at top right of the window is clicked. 7 procedure On_X_Button_Destroy 8 (Object : access Gtk.Window.Gtk_Window_Record'Class) is 9 begin -- On_X_Button_Destroy 10 Gtk.Main.Main_Quit; 11 end On_X_Button_Destroy; Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 19 of 50 19
12 13 -- New_Tab is an available selection on the 'File' dropdown menu. This 14 -- procedure takes the appropriate action when 'New' is clicked. 15 procedure On_New_Tab_Activate 16 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class) is 17 begin -- On_New_Tab_Activate 18 null; 19 end On_New_Tab_Activate; 20 21 -- Open_Tab is an available selection on the 'File' dropdown menu. This 22 -- procedure takes the appropriate action when 'Open' is clicked. 23 procedure On_Open_Tab_Activate 24 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class) is 25 begin -- On_Open_Tab_Activate 26 null; 27 end On_Open_Tab_Activate; 28 29 -- Save_Tab is an available selection on the 'File' dropdown menu. This 30 -- procedure takes the appropriate action when 'Save' is clicked. 31 procedure On_Save_Tab_Activate 32 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class) is 33 begin -- On_Save_Tab_Activate 34 null; 35 end On_Save_Tab_Activate; 36 37 -- Save_As_Tab is an available selection on the 'File' dropdown menu. This 38 -- procedure takes the appropriate action when 'Save' is clicked. 39 procedure On_Save_As_Tab_Activate 40 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class) is 41 begin -- On_Save_As_Tab_Activate 42 null; 43 end On_Save_As_Tab_Activate; 44 45 -- Quit_Tab is an available selection on the 'File' dropdown menu. This Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 20 of 50 20
46 -- procedure takes the appropriate action when 'Quit' is clicked. 47 procedure On_Quit_Tab_Activate 48 (Object : access Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record'Class) is 49 begin -- On_Quit_Tab_Activate 50 -- Exit the Main loop. 51 Gtk.Main.Main_Quit; 52 end On_Quit_Tab_Activate; 53 54 -- This procedure takes the appropriate action when 'Big Button' is clicked. 55 procedure On_Big_Button_Clicked 56 (Object : access Gtk.Button.Gtk_Button_Record'Class) is 57 begin -- On_Big_Button_Clicked 58 null; 59 end On_Big_Button_Clicked; 60 61 -- This procedure takes the appropriate action when 'B1' is clicked. 62 procedure On_B1_Clicked 63 (Object : access Gtk.Button.Gtk_Button_Record'Class) is 64 begin -- On_B1_Clicked 65 null; 66 end On_B1_Clicked; 67 68 -- This procedure takes the appropriate action when 'B2' is clicked. 69 procedure On_B2_Clicked 70 (Object : access Gtk.Button.Gtk_Button_Record'Class) is 71 begin -- On_B2_Clicked 72 null; 73 end On_B2_Clicked; 74 75 -- This procedure takes the appropriate action when 'B3' is clicked. 76 procedure On_B3_Clicked 77 (Object : access Gtk.Button.Gtk_Button_Record'Class) is 78 begin -- On_B3_Clicked 79 null; Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 21 of 50 21
80 end On_B3_Clicked; 81 end Gadget_Pkg.Callbacks; 10.4 Handler Packages 10.4.1 Specification Callbacks_Gadget.ads
1 with Gtk.Handlers; 2 with Gtk.Widget; 3 with Gtk.Window; 4 with Gtk.Image_Menu_Item; 5 with Gtk.Button; 6 7 pragma Elaborate_All (Gtk.Handlers); 8 9 package Callbacks_Gadget is 10 11 package Window_Callback_Pkg is new 12 Gtk.Handlers.Callback (Gtk.Window.Gtk_Window_Record); 13 -- This instantiation creates a new package to handle 14 -- Gtk_Window_Record. 15 16 package Image_Menu_Item_Callback_Pkg is new 17 Gtk.Handlers.Callback (Gtk.Image_Menu_Item.Gtk_Image_Menu_Item_Record); 18 -- This instantiation creates a new package to handle 19 -- Gtk_Image_Menu_Item_Record. 20 21 package Button_Callback_Pkg is new 22 Gtk.Handlers.Callback (Gtk.Button.Gtk_Button_Record); 23 -- This instantiation creates a new package to handle 24 -- Gtk_Button_Record. 25 end Callbacks_Gadget; Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 22 of 50 22
10.5 Development Package 10.5.1 Specification Gadget_Pkg.ads
1 with Gtk.Window; use Gtk.Window; 2 with Glib.Error; 3 with Gtk.Box; 4 with Gtk.Menu; 5 with Gtk.Menu_Bar; 6 with Gtk.Menu_Item; 7 with Gtk.Image_Menu_Item; 8 with Gtk.Separator_Menu_Item; 9 with Gtk.Frame; 10 with Gtk.Scrolled_Window; 11 with Gtk.Text_View; 12 with Gtk.Text_Buffer; 13 with Gtk.Separator; 14 with Gtk.Button; 15 with Gtk.Label; 16 with Gtk.Tooltips; 17 18 package Gadget_Pkg is 19 type Gadget_Record is new Gtk.Window.Gtk_Window_Record with record 20 21 Window_Base_HBox : Gtk.Box.Gtk_Hbox; 22 Window_VBox : Gtk.Box.Gtk_VBox; -- this will have 4 cells 23 24 Menu_Base_HBox : Gtk.Box.Gtk_HBox; 25 Menu : Gtk.Menu_Bar.Gtk_Menu_Bar; 26 27 File_Menu : Gtk.Menu_Item.Gtk_Menu_Item; 28 File_Dropdown : Gtk.Menu.Gtk_Menu; 29 30 New_Tab : Gtk.Image_Menu_Item.Gtk_Image_Menu_Item; Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 23 of 50 23
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 24 of 50 24
65 -- Top Cell 66 B1_HBox : Gtk.Box.Gtk_HBox; 67 B1 : Gtk.Button.Gtk_Button; 68 B1_Tooltip : Gtk.Tooltips.Gtk_Tooltips; 69 70 -- Middle Cell 71 B2_HBox : Gtk.Box.Gtk_HBox; 72 B2 : Gtk.Button.Gtk_Button; 73 B2_Tooltip : Gtk.Tooltips.Gtk_Tooltips; 74 75 -- Bottom Cell 76 B3_Hbox : Gtk.Box.Gtk_HBox; 77 B3 : Gtk.Button.Gtk_Button; 78 B3_Tooltip : Gtk.Tooltips.Gtk_Tooltips; 79 end record; 80 type Gadget_Access is access all Gadget_Record'Class; 81 82 83 procedure Gtk_New (New_Gadget : out Gadget_Access); 84 -- Gtk_New creates the new widget and passes it to Initialize, 85 86 procedure Initialize (The_Gadget : access Gadget_Record'Class); 87 -- Initialize creates, initialises, installs, shows etc. all the widgets 88 -- which make up the interface. 89 end Gadget_Pkg;
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 25 of 50 25
10.5.2 Implementation Gadget_Pkg.adb
1 with Gtk.Enums; 2 3 with Ada.Characters.Latin_1; 4 5 with Gadget_Intl; 6 with Gadget_Pkg.Callbacks; 7 with Callbacks_Gadget; 8 package body Gadget_Pkg is 9 10 Icon : Boolean; 11 12 -- This is the procedure called by the mainline to create a new widget. 13 -- In this case it creates a new Gadget_Record which is a child of 14 -- Gtk.Window.Gtk_Window_Record and inherits all the functionality of 15 -- a Gtk.Window.Gtk_Window_Record. 16 -- Then it sends New_Gadget to the initialisation procedure. 17 procedure Gtk_New (New_Gadget : out Gadget_Access) is 18 begin -- Gtk_New 19 New_Gadget := new Gadget_Record; 20 Initialize (The_Gadget => New_Gadget); 21 end Gtk_New; 22 23 24 25 procedure Initialize (The_Gadget : access Gadget_Record'Class) is 26 begin -- Initialize 27 28 ---------------------------------------------------------------- 29 -- CREATE THE WINDOW WHICH WILL CONTAIN ALL THE OTHER WIDGETS -- 30 ---------------------------------------------------------------- 31 32 -- This procedure call initialises the window which will contain all the Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 26 of 50 26
33 -- other widgets as they are created. 34 -- It is not necessary to name and give value to the formal parameter 35 -- The_Type in this case since the value we want is the default value. 36 -- This value ensures that the window will be visible when created, i.e. 37 -- not hidden behind other windows that may be open at the time. 38 Gtk.Window.Initialize 39 (Window => The_Gadget, 40 The_Type => Gtk.Enums.Window_Toplevel); 41 42 -- Give the window a specified icon. 43 -- Using a function to do this is probably a throwback to the 44 -- primordial days of Gtk's 'C' ancestry. 45 Icon := Set_Icon_From_File (Window => The_Gadget, 46 Filename => "Gadget.gif"); 47 48 -- Give the created window a name. 49 -- This subroutine, and some below it, are part of Gadget_Pkg inherited 50 -- from Gtk.Window. 51 Set_Title (Window => The_Gadget, 52 Title => Gadget_Intl.Local_Format 53 (Input =>"Shiny New Gadget")); 54 55 -- Display the window anywhere. 56 Set_Position (Window => The_Gadget, 57 Position => Gtk.Enums.Win_Pos_None); 58 59 -- Setting the window to Modal means that it will take the input from the 60 -- keyboard and the mouse while the window is fully visible. It will 61 -- ignore them when the window is hidden at all. 62 Set_Modal (Window => The_Gadget, 63 Modal => TRUE); 64 65 -- Make sure the window can be resized. 66 Set_Resizable (Window => The_Gadget, Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 27 of 50 27
67 Resizable => TRUE); 68 69 -- Make sure the window can be destroyed and the program stopped when 70 -- the [X] button on the main window is clicked. 71 Callbacks_Gadget.Window_Callback_Pkg.Connect 72 (Widget => The_Gadget, 73 Name => "destroy", 74 Marsh => Callbacks_Gadget.Window_Callback_Pkg.To_Marshaller 75 (Gadget_Pkg.Callbacks.On_X_Button_Destroy'Access)); 76 77 78 79 ------------------------------------------ 80 -- CREATE THE BOXES TO HOLD THE WIDGETS -- 81 ------------------------------------------ 82 83 -- Create the Base Box for all the widgets in the window. It is created 84 -- as an HBox which means that, as each successive widget is added to it 85 -- the will show in sequence one lower than the other. 86 -- 'Homogeneous(TRUE)' means the cells in this box will all be the 87 -- same size. There is, in fact only one cell in this box. 88 -- 'Spacing(0)' is the default value and means that there is no space 89 -- between the box and its contents. Although it is default value it 90 -- must be specified because the value of Homogeneous has been specified 91 -- non-default. 92 -- Window_HBase_Box will sit inside The_Gadget (the window). 93 Gtk.Box.Gtk_New_HBox (Box => The_Gadget.Window_Base_HBox, 94 Homogeneous => TRUE, 95 Spacing => 0); 96 97 -- Create the VBox to hold the Menu in the top cell and all the other 98 -- widgets in the bottom cell. 99 -- Homogeneous(false) means that the cells can be different sizes. This 100 -- is the default value and could be omitted. Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 28 of 50 28
101 -- Spacing(2) means there will be a two-pixel gap between the box and its 102 -- contents. 103 -- Window_VBox will sit inside Window_Base_Box. 104 Gtk.Box.Gtk_New_VBox (Box => The_Gadget.Window_VBox, 105 Homogeneous => false, 106 Spacing => 2); 107 108 109 ----------------------- 110 -- INSTALL THE BOXES -- 111 ----------------------- 112 113 -- Install Window_VBox in Window_Base_HBox. 114 Gtk.Box.Pack_Start 115 (In_Box => The_Gadget.Window_Base_HBox, 116 Child => The_Gadget.Window_VBox, 117 Expand => TRUE, 118 Fill => TRUE, 119 Padding => 0); 120 121 -- Install Window_Base_HBox in The_Gadget. 122 Gadget_Pkg.Add (Container => The_Gadget, 123 Widget => The_Gadget.Window_Base_HBox); 124 125 126 127 ----------------------------------------- 128 ----------------------------------------- 129 ---- NOW WE CREATE AND INSTALL ----- 130 ---- MENU_BAR AT THE TOP OF GADGET ----- 131 ----------------------------------------- 132 ----------------------------------------- 133 134 -- Create Menu_Base_HBox to hold Menu. Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 29 of 50 29
135 Gtk.Box.Gtk_New_HBox (Box => The_Gadget.Menu_Base_HBox, 136 Homogeneous => TRUE, 137 Spacing => 0); 138 139 -- Create Menu to sit in Gadget_Menu_Box. 140 Gtk.Menu_Bar.Gtk_New (Menu_Bar => The_Gadget.Menu); 141 142 -- Set the direction in which the items in the menu bar are aligned. 143 -- In this bar the items will appear aligned Left to Right. 144 Gtk.Menu_Bar.Set_Pack_Direction 145 (Menubar => The_Gadget.Menu, 146 Pack_Dir => Gtk.Enums.Pack_Direction_LTR); 147 148 -- Install Menu_Bar in Menu_Base_Box. 149 Gtk.Box.Pack_Start (In_Box => The_Gadget.Menu_Base_HBox, 150 Child => The_Gadget.Menu, 151 Expand => TRUE, 152 Fill => TRUE, 153 Padding => 2); 154 155 -- Install Menu_Base_Box in Window_VBox. 156 Gtk.Box.Pack_Start (In_Box => The_Gadget.Window_VBox, 157 Child => The_Gadget.Menu_Base_HBox, 158 Expand => false, 159 Fill => TRUE, 160 Padding => 0); 161 162 163 164 ---------------------------------------------------------- 165 -- CREATE THE 'FILE' MENU AND ATTACH IT TO THE MENU_BAR -- 166 ---------------------------------------------------------- 167 168 -- The underscore before the name means that the 'F' in File will be Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 30 of 50 30
169 -- underlined indicating that the dropdown can be called from the 170 -- keyboard using ALT+F. 171 Gtk.Menu_Item.Gtk_New_With_Mnemonic 172 (Menu_Item => The_Gadget.File_Menu, 173 Label => Gadget_Intl.Local_Format(Input => "_File")); 174 175 -- Create a new dropdown file for the menu bar. 176 Gtk.Menu.Gtk_New (Widget => The_Gadget.File_Dropdown); 177 178 -- Attach the File_Dropdown to File_Menu. 179 Gtk.Menu_Item.Set_Submenu (Menu_Item => The_Gadget.File_Menu, 180 Submenu => The_Gadget.File_Dropdown); 181 182 -- Attach File_Menu to Menu_Bar. 183 Gtk.Menu_Bar.Append (Menu_Shell => The_Gadget.Menu, 184 Child => The_Gadget.File_Menu); 185 186 187 188 -------------------- 189 -- CREATE NEW_TAB -- 190 -------------------- 191 192 -- Create New_Tab to go on File_Dropdown. 193 Gtk.Image_Menu_Item.Gtk_New_From_Stock (Widget => The_Gadget.New_Tab, 194 Stock_Id => "gtk-new"); 195 196 -- Connect New_Tab to its callback procedure. 197 Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.Connect 198 (Widget => The_Gadget.New_Tab, 199 Name => "activate", 200 Marsh => Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.To_Marshaller 201 (Gadget_Pkg.Callbacks.On_New_Tab_Activate'Access)); 202 Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 31 of 50 31
203 -- Attach New_Tab to File_Dropdown. 204 -- The procedure 'Append' is inherited from 'Gtk.Menu_Shell'. 205 Gtk.Menu.Append (Menu_Shell => The_Gadget.File_Dropdown, 206 Child => The_Gadget.New_Tab); 207 208 209 210 ------------------------------------------------------- 211 -- REPEAT THE PROCESS FOR 'OPEN_TAB' ON THE DROPDOWN -- 212 ------------------------------------------------------- 213 214 -- Create Open_Tab to go on File_Dropdown. 215 Gtk.Image_Menu_Item.Gtk_New_From_Stock (Widget => The_Gadget.Open_Tab, 216 Stock_Id => "gtk-open"); 217 218 -- connect Open_Tab to its callback procedure. 219 Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.Connect 220 (Widget => The_Gadget.Open_Tab, 221 Name => "activate", 222 Marsh => Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.To_Marshaller 223 (Gadget_Pkg.Callbacks.On_Open_Tab_Activate'Access)); 224 225 -- Attach Open_Tab to File_Dropdown. 226 -- The procedure 'Append' is inherited from 'Gtk.Menu_Shell'. 227 Gtk.Menu.Append (Menu_Shell => The_Gadget.File_Dropdown, 228 Child => The_Gadget.Open_Tab); 229 230 231 232 ------------------------------------------------------- 234 -- REPEAT THE PROCESS FOR 'SAVE_TAB' ON THE DROPDOWN -- 235 ------------------------------------------------------- 236 Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 32 of 50 32
237 -- Create Save_Tab to go on File_Dropdown. 238 Gtk.Image_Menu_Item.Gtk_New_From_Stock 239 (Widget => The_Gadget.Save_Tab, 240 Stock_Id => "gtk-save"); 241 242 -- connect Save_Tab to its callback procedure. 243 Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.Connect 244 (Widget => The_Gadget.Save_Tab, 245 Name => "activate", 246 Marsh => Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.To_Marshaller 247 (Gadget_Pkg.Callbacks.On_Save_Tab_Activate'Access)); 248 249 -- Attach Save_Tab tab to File_Dropdown. 250 -- The procedure 'Append' is inherited from 'Gtk.Menu_Shell'. 251 Gtk.Menu.Append (Menu_Shell => The_Gadget.File_Dropdown, 252 Child => The_Gadget.Save_Tab); 253 254 255 256 ------------------------------------------------------------- 257 -- REPEAT THE PROCESS FOR A 'SAVE_AS' ITEM ON THE DROPDOWN -- 258 ------------------------------------------------------------- 259 260 -- Create Save_As_Tab to go on File_Dropdown. 261 Gtk.Image_Menu_Item.Gtk_New_From_Stock 262 (Widget => The_Gadget.Save_As_Tab, 263 Stock_Id => "gtk-save-as"); 264 265 -- Connect Save_As_Tab to its callback procedure. 266 Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.Connect 267 (Widget => The_Gadget.Save_As_Tab, 268 Name => "activate", 269 Marsh => Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.To_Marshaller 270 (Gadget_Pkg.Callbacks.On_Save_As_Tab_Activate'Access)); Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 33 of 50 33
271 272 -- Attach the 'Save As' tab to File_Dropdown. 273 -- The procedure 'Append' is inherited from 'Gtk.Menu_Shell'. 274 Gtk.Menu.Append (Menu_Shell => The_Gadget.File_Dropdown, 275 Child => The_Gadget.Save_As_Tab); 276 277 278 279 ------------------------------------- 280 -- PUT A SEPARATOR ON THE DROPDOWN -- 281 ------------------------------------- 282 283 -- Creste File_Separator. 284 Gtk.Separator_Menu_Item.Gtk_New (Widget => The_Gadget.File_Separator); 285 286 -- Install File_Separator on File_Dropdown. 287 Gtk.Menu.Append (Menu_Shell => The_Gadget.File_Dropdown, 288 Child => The_Gadget.File_Separator); 289 290 291 292 -------------------------------------------------------------- 293 -- REPEAT THE TAB PROCESS FOR A 'QUIT' ITEM ON THE DROPDOWN -- 294 -------------------------------------------------------------- 295 296 -- Create Quit_Tab to go on File_Dropdown. 297 Gtk.Image_Menu_Item.Gtk_New_From_Stock 298 (Widget => The_Gadget.Quit_Tab, 299 Stock_Id => "gtk-quit"); 300 301 -- connect that new item to its callback procedure. 302 Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.Connect 303 (Widget => The_Gadget.Quit_Tab, 304 Name => "activate", Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 34 of 50 34
305 Marsh => Callbacks_Gadget.Image_Menu_Item_Callback_Pkg.To_Marshaller 306 (Gadget_Pkg.Callbacks.On_Quit_Tab_Activate'Access)); 307 308 -- Attach Quit_Tab to File_Dropdown. 309 -- The procedure 'Append' is inherited from 'Gtk.Menu_Shell'. 310 Gtk.Menu.Append (Menu_Shell => The_Gadget.File_Dropdown, 311 Child => The_Gadget.Quit_Tab); 312 313 314 315 ----------------------------------- 316 ----------------------------------- 317 ---- NOW WE CREATE AND INSTALL ---- 318 ---- THE EDITING SCREEN ---- 319 ----------------------------------- 320 ----------------------------------- 321 322 ----------------------------------------- 323 -- CREATE AND INSTALL THE SCREEN_FRAME -- 324 ----------------------------------------- 325 326 -- Create Screen_Frame_HBox to hold Screen_Frame. 327 Gtk.Box.Gtk_New_HBox (Box => The_Gadget.Screen_Frame_HBox, 328 Homogeneous => TRUE, 329 Spacing => 0); 330 331 -- Create Screen_Frame. 332 Gtk.Frame.Gtk_New (Frame => The_Gadget.Screen_Frame, 333 Label => "Add Text"); 334 335 -- Specify the border width of Screen_Frame. 336 -- Set_Border_Width inherited from Gtk.Container. 337 Gtk.Frame.Set_Border_Width (Container => The_Gadget.Screen_Frame, 338 Border_Width => 4); Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 35 of 50 35
339 340 -- Specify what the frame looks like. 341 Gtk.Frame.Set_Shadow_Type (Frame => The_Gadget.Screen_Frame, 342 The_Type => Gtk.Enums.Shadow_In); 343 344 -- Install Screen_Frame in Screen_Frame_HBox. 345 Gtk.Box.Pack_Start (In_Box => The_Gadget.Screen_Frame_Hbox, 346 Child => The_Gadget.Screen_Frame); 347 348 -- Install Screen_Frame_HBox in Window_VBox where it will appear below 349 -- Menu_Bar. 350 Gtk.Box.Pack_Start (In_Box => The_Gadget.Window_VBox, 351 Child => The_Gadget.Screen_Frame_HBox, 352 Expand => TRUE, 353 Fill => TRUE, 354 Padding => 0); 355 356 357 358 ----------------------------------------------- 359 -- CREATE AND INSTALL SCREEN WITH SCROLLBARS -- 360 ----------------------------------------------- 361 362 -- Create the HBox to hold Screen. 363 Gtk.Box.Gtk_New_HBox (Box => The_Gadget.Screen_Base_Box, 364 Homogeneous => TRUE, 365 Spacing => 3); 366 367 -- Create the Scrollbars for Screen. 368 Gtk.Scrolled_Window.Gtk_New (Scrolled_Window => The_Gadget.Scroll, 369 Hadjustment => null, 370 Vadjustment => null); 371 372 -- Specify the way Scroll looks. Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 36 of 50 36
373 Gtk.Scrolled_Window.Set_Shadow_Type 374 (Scrolled_Window => The_Gadget.Scroll, 375 Shadow_Type => Gtk.Enums.Shadow_Out); 376 377 -- Specify the way Scroll operates. 378 Gtk.Scrolled_Window.Set_Policy 379 (Scrolled_Window => The_Gadget.Scroll, 380 H_Scrollbar_Policy => Gtk.Enums.Policy_Automatic, 381 V_Scrollbar_Policy => Gtk.Enums.Policy_Automatic); 382 383 -- Create Screen. 384 Gtk.Text_View.Gtk_New (Widget => The_Gadget.Screen, 385 Buffer => The_Gadget.Screen_Buffer); 386 387 -- Set minimum size of The_Gadget.Screen. 388 -- Inherited from Gtk.Widget. 389 Gtk.Text_View.Set_Size_Request (Widget => The_Gadget.Screen, 390 Width => 300, 391 Height => 200); 392 393 -- Set margins of The_Gadget.Screen. 394 Gtk.Text_View.Set_Left_Margin (Text_View => The_Gadget.Screen, 395 Left_Margin => 5); 396 Gtk.Text_View.Set_Right_Margin (Text_View => The_Gadget.Screen, 397 Right_Margin => 5); 398 399 -- Set The_Gadget.Screen. to word wrap. 400 Gtk.Text_View.Set_Wrap_Mode (Text_View => The_Gadget.Screen, 401 Wrap_Mode => Gtk.Enums.Wrap_Word); 402 403 -- Activate the TAB button for The_Gadget.Screen.. 404 Gtk.Text_View.Set_Accepts_Tab (Text_View => The_Gadget.Screen, 405 Accepts_Tab => TRUE); 406 Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 37 of 50 37
407 -- Install Screen in Scroll. 408 -- 'Add' inherited from Gtk.Container. 409 Gtk.Scrolled_Window.Add (Container => The_Gadget.Scroll, 410 Widget => The_Gadget.Screen); 411 412 -- Install Scroll in Screen_Base_Box. 413 Gtk.Box.Pack_Start (In_Box => The_Gadget.Screen_Base_Box, 414 Child => The_Gadget.Scroll, 415 Expand => TRUE, 416 Fill => TRUE, 417 Padding => 5); 418 419 -- Install the Screen_Base_Box in the Screen_Frame. 420 -- 'Add' is inherited from Gtk.Container. 421 Gtk.Frame.Add (Container => The_Gadget.Screen_Frame, 422 Widget => The_Gadget.Screen_Base_Box); 423 424 425 426 ----------------------------------- 427 ----------------------------------- 428 ---- NOW WE CREATE AND INSTALL ---- 429 ---- THE HORIZONTAL SEPARATOR ---- 430 ----------------------------------- 431 ----------------------------------- 432 433 -- Create H_Sep_Base_HBox to hold H_Sep. 434 Gtk.Box.Gtk_New_HBox (Box => The_Gadget.H_Sep_Base_HBox, 435 Homogeneous => TRUE, 436 Spacing => 0); 437 438 -- Create the Separator. 439 Gtk.Separator.Gtk_New_Hseparator (Separator => The_Gadget.H_Sep); 440 Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 38 of 50 38
441 -- Install H_Sep in H_Sep_Base_HBox. 442 Gtk.Box.Pack_Start (In_Box => The_Gadget.H_Sep_Base_HBox, 443 Child => The_Gadget.H_Sep, 444 Expand => TRUE, 445 Fill => TRUE, 446 Padding => 0); 447 448 -- Install H_Sep_Base_HBox in Window_VBox. 449 Gtk.Box.Pack_Start (In_Box => The_Gadget.Window_VBox, 450 Child => The_Gadget.H_Sep_Base_HBox, 451 Expand => false, 452 Fill => TRUE, 453 Padding => 0); 454 455 456 457 ------------------------------ 458 ------------------------------ 459 ---- NOW WE CREATE AND ---- 460 ---- INSTALL THE KEYBOARD ---- 461 ------------------------------ 462 ------------------------------ 463 464 --------------------------------------- 465 -- CREATE THE BOXES FOR THE KEYBOARD -- 466 --------------------------------------- 467 468 -- Create Buttons_Base_Box. 469 Gtk.Box.Gtk_New_HBox (Box => The_Gadget.Buttons_Base_Box, 470 Homogeneous => TRUE, 471 Spacing => 0); 472 473 -- Install Buttons_Base_Box in Window_VBox. 474 Gtk.Box.Pack_Start (In_Box => The_Gadget.Window_VBox, Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 39 of 50 39
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 46 of 50 46
715 -- Connect B3 to its callback procedure. 716 Callbacks_Gadget.Button_Callback_Pkg.Connect 717 (Widget => The_Gadget.B3, 718 Name => "clicked", 719 Marsh => Callbacks_Gadget.Button_Callback_Pkg.To_Marshaller 720 (Gadget_Pkg.Callbacks.On_B3_Clicked'Access)); 721 722 -- Create a tooltip to tell the user what B3 is. 723 Gtk.Tooltips.Gtk_New (Widget => The_Gadget.B3_Tooltip); 724 Gtk.Tooltips.Set_Tip (Tooltips => The_Gadget.B3_Tooltip, 726 Widget => The_Gadget.B3, 727 Tip_Text => Gadget_Intl.Local_Format 728 (Input => "This is B3"), 729 Tip_Private => Gadget_Intl.Local_Format 730 (Input => "")); 731 -- Install B3 in B3_HBox. 733 Gtk.Box.Pack_Start (In_Box => The_Gadget.B3_HBox, 734 Child => The_Gadget.B3, 735 Expand => TRUE, 736 Fill => TRUE, 737 Padding => 3); 738 739 -- Install B3_HBox in Three_Buttons_VBox. 740 Gtk.Box.Pack_Start (In_Box => The_Gadget.Three_Buttons_VBox, 741 Child => The_Gadget.B3_HBox, 742 Expand => TRUE, 743 Fill => TRUE, 744 Padding => 3); 745 end Initialize; 746 747 end Gadget_Pkg;
Gadget: Building a Compound Widget with GtkAda
DOCUMENT CURRENT ONLY WHEN PRINTED c:\documents and settings\rick\desktop\gadget.docx Printed on Wednesday, 2 February 2011 Page 47 of 50 47
11 Reference List Software Productivity Consortium (1995). Ada 95 Quality and Style: Guidelines for Professional Programmers. Department of Defense Ada Joint Program Office.