1 This is a mini howto, describing the steps to add a new dialog box
2 to psppire. This is document is only tested for the master branch.
3 Gtk3 is uncharted territory ....
6 How to add a new dialog to Psppire
7 ==================================
12 1. You will need to install Glade (but see the important note
13 about which version at the end of this document!
17 2. Build and install the lastest pspp master HEAD, with the
18 "--with-gui-tools" option passed to configure. Thus:
20 ./configure --with-gui-tools
24 This installs the pspp specific libraries and widgets that glade needs.
26 For this step, you must build inside the pspp source directory, and
27 you must install to the default directory. DO NOT build from
28 outside the source, and do not pass a --prefix to configure.
31 Having done the above, you should be able to edit an existing dialog
34 glade src/ui/gui/descriptives.ui
36 You will probably get a lot of Gtk-Warnings/Criticals most of them
40 If this works, now you are in a position to start ....
42 There are two basic steps. Firstly, you need to define the layout of
43 the dialog. This is done using glade, which you have installed as
44 described above. The second step is to define the behaviour of the
45 dialog. For this, you need to define a new object deriving from
50 Example: Adding a new dialog: foobar
51 -------------------------------------
57 Start glade and create a new GtkBuilder file, thus:
58 glade-3 src/ui/gui/foobar.ui
60 All dialogs need a top level window. For Psppire, this must be an
61 instance of PsppireDialog.
62 On the left hand side of the Glade window, you will see a category
63 headed "Psppire". Click on the first item in that category and a new
64 (empty) dialog will be created.
66 Most dialogs have a vertical button box on the right hand side, so
67 click on the "Vertical Button Box" icon. Then on the right hand panel
68 of the new dialog. You will be prompted to enter the number of items
69 in the button box. For this example, chooose 5.
71 Note, that by default, the dialog box was created with an "internal
72 child" GtkVbox whose "Number of items" property is 2. Change this
73 to 4. You should see the extra empty panels appear.
75 Typically a dialog box needs a DictionaryTreeview in the left hand
76 panel. But we normally put that inside a scrolled window, which in
77 turn is inside a Frame.
79 Under the "Containers" category there is a "Frame" item. Click on
80 this. Then on the leftmost panel of the dialog box. The new GtkFrame
81 widget should appear. Again in the "Containers" category click on
82 "Scrolled Window" and then in the frame you have just created.
83 This will put a new GtkScrolledWindow inside the GtkFrame.
85 Now click on the "Dictionary Treeview" widget (unde the "Psppire"
86 category, and put that inside the Scrolled window.
88 You should now have a half complete dialog looking something like
91 +---------------+-----------------+----------------+-----------------+
92 |Frame1 | | | +--------------+|
93 |+-------------+| | | | OK ||
94 || || | | +--------------+|
96 || || | | +--------------+|
98 || || | | +--------------+|
100 || || | | +--------------+|
101 || || | | | Cancel ||
102 || || | | +--------------+|
104 || || | | +--------------+|
106 || || | | +--------------+|
108 || || | | +--------------+|
110 |+-------------+| | | +--------------+|
111 +---------------+-----------------+----------------+-----------------+
113 In the second panel from the left, we might want a selector button.
114 However, we don't want to to fill the entire panel.
115 So we put it in inside a GtkAlignment. From the "Containers" category
116 click "Alignment". and then the panel. Such a widget is of course
117 not visible, but you will note its presence from the widget hierarchy
118 in the top right hand corner of the glade window.
119 Now, from the "Psppire" category, click on "Selector Button" and put
120 it inside the new GtkAlignment. It will appear to occupy the entire
121 panel. To fix this, select the GtkAlignment and change its Horizontal
122 Scale and Vertical Scale properties to zero.
124 If all is well, the dialog box now looks like this:
127 +---------------+-----------------+----------------+-----------------+
128 |Frame1 | | | +--------------+|
129 |+-------------+| | | | OK ||
130 || || | | +--------------+|
132 || || | | +--------------+|
134 || || | | +--------------+|
136 || || |\ | | +--------------+|
137 || || | \ | | | Cancel ||
138 || || | / | | +--------------+|
140 || || | | +--------------+|
142 || || | | +--------------+|
144 || || | | +--------------+|
146 |+-------------+| | | +--------------+|
147 +---------------+-----------------+----------------+-----------------+
150 However you will notice that upon resizing the dialog, the selector
151 button's panel expands with it, which is probably not what we want.
152 To fix this, select the GtkAlignment which we created above, and set
153 its "Expand" packing-property to false.
156 We final panel might require a PsppireVarView widget, again inside a
157 GtkScrolled window (and possibly a GtkFrame). Create this, in a
158 similar way to which you did the PsppireDictionaryTreeview above.
160 Now you have a fully populated dialog box. It might need tweaking
161 which we can do later. But we are now in a position to display our
165 Displaying the Dialog box in Psppire
166 ....................................
169 1. Define a new PsppireDialogAction Class
171 Create a new object class derived from PsppireDialogAction (note that
172 PsppireDialogAction itself implements GAction). It's probably
173 best if you use an existing example as a template. The minimum you
178 #include "psppire-dialog-action-foobar.h"
179 #include "psppire-var-view.h"
180 #include "psppire-dialog.h"
181 #include "builder-wrapper.h"
183 static void psppire_dialog_action_foobar_init (PsppireDialogActionFoobar *act);
184 static void psppire_dialog_action_foobar_class_init (PsppireDialogActionFoobarClass *class);
186 G_DEFINE_TYPE (PsppireDialogActionFoobar, psppire_dialog_action_foobar, PSPPIRE_TYPE_DIALOG_ACTION);
189 dialog_state_valid (gpointer data)
191 PsppireDialogActionFoobar *ud = PSPPIRE_DIALOG_ACTION_FOOBAR (data);
193 // This function is a predicate to determine if the dialog box has
194 // been set to a state where is is appropriate to click OK /
197 // If it returns FALSE, the OK and PASTE buttons are insensitive
204 refresh (PsppireDialogAction *rd_)
206 PsppireDialogActionFoobar *uv = PSPPIRE_DIALOG_ACTION_FOOBAR (rd_);
208 // This function is called when the Reset Button is clicked.
209 // It sets the dialog to its default state
213 // This function is called when the menuitem is activated.
214 // It is what pops up the dialog
216 psppire_dialog_action_foobar_activate (GAction *a)
218 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
219 PsppireDialogActionFoobar *act = PSPPIRE_DIALOG_ACTION_FOOBAR (a);
221 // These three lines are (almost) always required
222 GtkBuilder *xml = builder_new ("foobar.ui");
223 pda->dialog = get_widget_assert (xml, "foobar-dialog");
224 pda->source = get_widget_assert (xml, "dict-view");
226 // ... here you can load any widgets that your dialog uses
227 act->this_widget = get_widget_assert (xml, "this_widget");
228 act->that_widget = get_widget_assert (xml, "that_widget");
230 // ... you will most probably need to have these here
231 psppire_dialog_action_set_valid_predicate (pda, dialog_state_valid);
232 psppire_dialog_action_set_refresh (pda, refresh);
235 // Everything below this line is necessary.
236 g_object_unref (xml);
238 if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_foobar_parent_class)->activate)
239 PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_foobar_parent_class)->activate (pda);
243 // Most often this function will not need any changes
245 psppire_dialog_action_foobar_class_init (PsppireDialogActionFoobarClass *class)
247 GActionClass *action_class = GTK_ACTION_CLASS (class);
249 action_class->activate = psppire_dialog_action_foobar_activate;
250 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
255 psppire_dialog_action_foobar_init (PsppireDialogActionFoobar *act)
257 // often, this function can be empty
263 generate_syntax (PsppireDialogAction *act)
265 PsppireDialogActionFoobar *uvd = PSPPIRE_DIALOG_ACTION_FOOBAR (act);
268 GString *str = g_string_new ("FOOBAR ");
270 // ... this function generates the syntax to be interpreted by
273 g_string_append (str, ".\n");
275 g_string_free (str, FALSE);
280 2. Declare the new PsppireDialogAction Class
282 You will also need to define the corresponding .h header file. Best
283 to copy and search replace on an existing one.
286 3. Adding the entry point for the dialog.
288 Edit src/ui/gui/data-editor.ui It is possible to do this with Glade,
289 but frankly is easier with a text editor. Something like the
290 following is typical.
294 <object class="PsppireDialogActionFoobar" id="some-menu_foobar">
295 <property name="manager">uimanager1</property>
296 <property name="name">some-menu_foobar</property>
297 <property name="label" translatable="yes">_Foobar</property>
298 <property name="stock-id">somemenu-foobar</property>
303 4. Announce the new object to GtkBuilder.
305 Add the new PsppireDialogAction's get_type function to to
306 src/ui/gui/widgets.c Just have a look there and follow the pattern.
307 This is necessary to that GtkBuilder knows about the new object class.
309 5. Putting it all together.
311 Don't forget to put any new files you've created in
312 src/ui/gui/automake.mk and to rerun make ; make install
316 Note! Currently (as of commit fe7682b3c3d36cf9ba3e867588e5b808af833262 )
317 psppire is in a transitional phase. Our .ui files come in two mutually
318 incompatible varieties. The older variety can be identified by a
321 <requires lib="psppire" version="2054.17080"/>
322 <!-- interface-requires gtk+ 2.12 -->
323 <!-- interface-naming-policy project-wide -->
325 To edit these files you will need to install Glade version 3.8.4 ---
326 ANY OTHER VERSION IS UNLIKELY TO WORK --- I know that 3.18.x does
327 not! If your distro doesn't have this version, you will need to
328 download it and build it from source.
331 The newer ones contain the string:
333 <!-- Generated with glade 3.18.3 -->
335 <requires lib="gtk+" version="3.12"/>
337 Like the string suggests Glade version 3.18.x or later will probably
338 be ok for these files.
340 Hopefully the older style .ui files will gradually be converted to new
344 That's about it, I think. Did I forget anything?