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 version 3.8.4 --- ANY OTHER VERSION
13 IS UNLIKELY TO WORK --- I know that 3.18.x does not! If your
14 distro doesn't have this version, you will need to download it and
19 2. Build and install the lastest pspp master HEAD, with the
20 "--with-gui-tools" option passed to configure. Thus:
22 ./configure --with-gui-tools
26 This installs the pspp specific libraries and widgets that glade needs.
28 For this step, you must build inside the pspp source directory, and
29 you must install to the default directory. DO NOT build from
30 outside the source, and do not pass a --prefix to configure.
33 Having done the above, you should be able to edit an existing dialog
36 glade-3 src/ui/gui/descriptives.ui
38 You will probably get a lot of Gtk-Warnings/Criticals most of them
42 If this works, now you are in a position to start ....
44 There are two basic steps. Firstly, you need to define the layout of
45 the dialog. This is done using glade, which you have installed as
46 described above. The second step is to define the behaviour of the
47 dialog. For this, you need to define a new object deriving from
52 Example: Adding a new dialog: foobar
53 -------------------------------------
59 Start glade and create a new GtkBuilder file, thus:
60 glade-3 src/ui/gui/foobar.ui
62 All dialogs need a top level window. For Psppire, this must be an
63 instance of PsppireDialog.
64 On the left hand side of the Glade window, you will see a category
65 headed "Psppire". Click on the first item in that category and a new
66 (empty) dialog will be created.
68 Most dialogs have a vertical button box on the right hand side, so
69 click on the "Vertical Button Box" icon. Then on the right hand panel
70 of the new dialog. You will be prompted to enter the number of items
71 in the button box. For this example, chooose 5.
73 Note, that by default, the dialog box was created with an "internal
74 child" GtkVbox whose "Number of items" property is 2. Change this
75 to 4. You should see the extra empty panels appear.
77 Typically a dialog box needs a DictionaryTreeview in the left hand
78 panel. But we normally put that inside a scrolled window, which in
79 turn is inside a Frame.
81 Under the "Containers" category there is a "Frame" item. Click on
82 this. Then on the leftmost panel of the dialog box. The new GtkFrame
83 widget should appear. Again in the "Containers" category click on
84 "Scrolled Window" and then in the frame you have just created.
85 This will put a new GtkScrolledWindow inside the GtkFrame.
87 Now click on the "Dictionary Treeview" widget (unde the "Psppire"
88 category, and put that inside the Scrolled window.
90 You should now have a half complete dialog looking something like
93 +---------------+-----------------+----------------+-----------------+
94 |Frame1 | | | +--------------+|
95 |+-------------+| | | | OK ||
96 || || | | +--------------+|
98 || || | | +--------------+|
100 || || | | +--------------+|
102 || || | | +--------------+|
103 || || | | | Cancel ||
104 || || | | +--------------+|
106 || || | | +--------------+|
108 || || | | +--------------+|
110 || || | | +--------------+|
112 |+-------------+| | | +--------------+|
113 +---------------+-----------------+----------------+-----------------+
115 In the second panel from the left, we might want a selector button.
116 However, we don't want to to fill the entire panel.
117 So we put it in inside a GtkAlignment. From the "Containers" category
118 click "Alignment". and then the panel. Such a widget is of course
119 not visible, but you will note its presence from the widget hierarchy
120 in the top right hand corner of the glade window.
121 Now, from the "Psppire" category, click on "Selector Button" and put
122 it inside the new GtkAlignment. It will appear to occupy the entire
123 panel. To fix this, select the GtkAlignment and change its Horizontal
124 Scale and Vertical Scale properties to zero.
126 If all is well, the dialog box now looks like this:
129 +---------------+-----------------+----------------+-----------------+
130 |Frame1 | | | +--------------+|
131 |+-------------+| | | | OK ||
132 || || | | +--------------+|
134 || || | | +--------------+|
136 || || | | +--------------+|
138 || || |\ | | +--------------+|
139 || || | \ | | | Cancel ||
140 || || | / | | +--------------+|
142 || || | | +--------------+|
144 || || | | +--------------+|
146 || || | | +--------------+|
148 |+-------------+| | | +--------------+|
149 +---------------+-----------------+----------------+-----------------+
152 However you will notice that upon resizing the dialog, the selector
153 button's panel expands with it, which is probably not what we want.
154 To fix this, select the GtkAlignment which we created above, and set
155 its "Expand" packing-property to false.
158 We final panel might require a PsppireVarView widget, again inside a
159 GtkScrolled window (and possibly a GtkFrame). Create this, in a
160 similar way to which you did the PsppireDictionaryTreeview above.
162 Now you have a fully populated dialog box. It might need tweaking
163 which we can do later. But we are now in a position to display our
167 Displaying the Dialog box in Psppire
168 ....................................
171 1. Define a new PsppireDialogAction Class
173 Create a new object class derived from PsppireDialogAction (note that
174 PsppireDialogAction itself derives from GtkAction). It's probably
175 best if you use an existing example as a template. The minimum you
180 #include "psppire-dialog-action-foobar.h"
181 #include "psppire-var-view.h"
182 #include "psppire-dialog.h"
183 #include "builder-wrapper.h"
185 static void psppire_dialog_action_foobar_init (PsppireDialogActionFoobar *act);
186 static void psppire_dialog_action_foobar_class_init (PsppireDialogActionFoobarClass *class);
188 G_DEFINE_TYPE (PsppireDialogActionFoobar, psppire_dialog_action_foobar, PSPPIRE_TYPE_DIALOG_ACTION);
191 dialog_state_valid (gpointer data)
193 PsppireDialogActionFoobar *ud = PSPPIRE_DIALOG_ACTION_FOOBAR (data);
195 // This function is a predicate to determine if the dialog box has
196 // been set to a state where is is appropriate to click OK /
199 // If it returns FALSE, the OK and PASTE buttons are insensitive
206 refresh (PsppireDialogAction *rd_)
208 PsppireDialogActionFoobar *uv = PSPPIRE_DIALOG_ACTION_FOOBAR (rd_);
210 // This function is called when the Reset Button is clicked.
211 // It sets the dialog to its default state
215 // This function is called when the menuitem is activated.
216 // It is what pops up the dialog
218 psppire_dialog_action_foobar_activate (GtkAction *a)
220 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
221 PsppireDialogActionFoobar *act = PSPPIRE_DIALOG_ACTION_FOOBAR (a);
223 // These three lines are (almost) always required
224 GtkBuilder *xml = builder_new ("foobar.ui");
225 pda->dialog = get_widget_assert (xml, "foobar-dialog");
226 pda->source = get_widget_assert (xml, "dict-view");
228 // ... here you can load any widgets that your dialog uses
229 act->this_widget = get_widget_assert (xml, "this_widget");
230 act->that_widget = get_widget_assert (xml, "that_widget");
232 // ... you will most probably need to have these here
233 psppire_dialog_action_set_valid_predicate (pda, dialog_state_valid);
234 psppire_dialog_action_set_refresh (pda, refresh);
237 // Everything below this line is necessary.
238 g_object_unref (xml);
240 if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_foobar_parent_class)->activate)
241 PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_foobar_parent_class)->activate (pda);
245 // Most often this function will not need any changes
247 psppire_dialog_action_foobar_class_init (PsppireDialogActionFoobarClass *class)
249 GtkActionClass *action_class = GTK_ACTION_CLASS (class);
251 action_class->activate = psppire_dialog_action_foobar_activate;
252 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
257 psppire_dialog_action_foobar_init (PsppireDialogActionFoobar *act)
259 // often, this function can be empty
265 generate_syntax (PsppireDialogAction *act)
267 PsppireDialogActionFoobar *uvd = PSPPIRE_DIALOG_ACTION_FOOBAR (act);
270 GString *str = g_string_new ("FOOBAR ");
272 // ... this function generates the syntax to be interpreted by
275 g_string_append (str, ".\n");
277 g_string_free (str, FALSE);
282 2. Declare the new PsppireDialogAction Class
284 You will also need to define the corresponding .h header file. Best
285 to copy and search replace on an existing one.
288 3. Adding the entry point for the dialog.
290 Edit src/ui/gui/data-editor.ui It is possible to do this with Glade,
291 but frankly is easier with a text editor. Something like the
292 following is typical.
296 <object class="PsppireDialogActionFoobar" id="some-menu_foobar">
297 <property name="manager">uimanager1</property>
298 <property name="name">some-menu_foobar</property>
299 <property name="label" translatable="yes">_Foobar</property>
300 <property name="stock-id">somemenu-foobar</property>
305 4. Announce the new object to GtkBuilder.
307 Add the new PsppireDialogAction's get_type function to to
308 src/ui/gui/widgets.c Just have a look there and follow the pattern.
309 This is necessary to that GtkBuilder knows about the new object class.
311 5. Putting it all together.
313 Don't forget to put any new files you've created in
314 src/ui/gui/automake.mk and to rerun make ; make install
318 That's about it, I think. Did I forget anything?