1 /*
2 ** 1998-08-14 - Configure styles, e.g. things such as back- & foreground colors, icons, and
3 ** actions. This might become involved.
4 ** 1998-08-23 - Did lots of work. Now you can actually add and delete styles. Got involved.
5 ** 1998-08-24 - Completed a first version, fixed plenty of bugs too...
6 ** 1998-08-26 - Added fun "Copy" button group for visual properties. Also added a deselect
7 ** signal handler for root style. Oops.
8 ** 1998-08-30 - Now uses the ico_get_all() function to retrieve a list of all icon file names.
9 ** Added three (!) forgotten modified-sets. Damn.
10 ** 1998-09-02 - Added action property configuration, and cleaned up their save/load handling.
11 ** 1998-09-16 - Made some optimizations, mainly in set_preview() (one more signal blocker).
12 ** 1998-09-27 - Now uses the brand new cmdseq_dialog for choosing actions. Works fine.
13 ** 1999-03-05 - Due to new selection handling, we no longer have control over how selected items
14 ** look. That got rid of some code.
15 ** 1999-03-13 - Rewrote the dialog module (from scratch), which lead to some changes here too.
16 ** 1999-05-07 - Now uses the (new) color dialog module. Got rid of lots of crufty code.
17 ** 2000-07-02 - Took a step closer to the rest of the world, by marking strings for translation.
18 */
19
20 #include <ctype.h>
21
22 #include "gentoo.h"
23
24 #include "styles.h"
25 #include "types.h"
26 #include "dirpane.h"
27 #include "dialog.h"
28 #include "dpformat.h"
29 #include "iconutil.h"
30 #include "strutil.h"
31 #include "fileutil.h"
32 #include "miscutil.h"
33 #include "xmlutil.h"
34 #include "guiutil.h"
35 #include "style_dialog.h"
36 #include "cmdseq_dialog.h"
37 #include "color_dialog.h"
38 #include "icon_dialog.h"
39
40 #include "configure.h"
41 #include "cfg_module.h"
42 #include "cfg_paths.h" /* For cpt_get_path(). */
43 #include "cfg_types.h" /* For ctp_get_types(). */
44 #include "cfg_cmdseq.h" /* For ccs_get_current(). */
45
46 #include "cfg_styles.h"
47
48 #define NODE "FileStyles"
49
50 /* ----------------------------------------------------------------------------------------- */
51
52 /* For GtkTreeModel access. */
53 enum {
54 COLUMN_ICON,
55 COLUMN_NAME
56 };
57
58 typedef struct { /* Visual properties notebook page. */
59 GtkWidget *vbox;
60 GtkWidget *preview; /* CList showing preview of style (old-school!). */
61 GtkTreeViewColumn *pre_icon; /* Icon preview. */
62 GtkCellRenderer *pre_icon_r;
63 GtkTreeViewColumn *pre_name; /* Name (text) preview. */
64 GtkCellRenderer *pre_name_r;
65 GtkWidget *override[3]; /* Override check buttons for back- & foreground colors, plus icon. */
66 GtkWidget *edit[3]; /* The "edit" (or "pick") command buttons. */
67 } PVisual;
68
69 typedef struct { /* Action properties notebook page. */
70 GtkWidget *vbox;
71 GtkListStore *store;
72 GtkWidget *view;
73 GtkWidget *editcmd; /* Shortcut to go to the Command editing configuration page. */
74 GtkWidget *adel; /* Delete (or override) command button. */
75 } PAction;
76
77 enum {
78 ACTION_COLUMN_NAME,
79 ACTION_COLUMN_CMDSEQ,
80 ACTION_COLUMN_ACTION,
81 ACTION_COLUMN_WEIGHT,
82
83 ACTION_COLUMN_COUNT
84 };
85
86 typedef struct {
87 GtkWidget *vbox;
88 GuiHandlerGroup *handlers; /* Collects editing widgets, for signal blocking. */
89 GtkWidget *scwin;
90 GtkWidget *tree; /* Main style tree widget. */
91 gulong sig_expand; /* Signal handler for tree item expansion. */
92 gulong sig_collapse; /* Signal handler for tree item collapse. */
93 GtkTreeStore *store;
94
95 GtkWidget *dvbox; /* Vbox holding definition widgets. */
96 GtkWidget *dname; /* Name of selected style. */
97 GtkWidget *dparent; /* Parent of selected style. */
98 GtkWidget *dreparent; /* Button for reparenting dialog. */
99
100 GtkWidget *dpnbook; /* Property notebook. */
101 PVisual dpvisual;
102 PAction dpaction;
103
104 GtkWidget *del; /* The style "Delete" button. */
105
106 MainInfo *min;
107 StyleInfo *si;
108 const gchar *curr_prop; /* Current property, when editing one. */
109 gint curr_arow; /* Action property clist row. */
110 gboolean modified;
111 } P_Styles;
112
113 static P_Styles the_page;
114
115 /* ----------------------------------------------------------------------------------------- */
116
117 /* 1999-05-24 - Set the preview widget(s). */
set_widgets_preview(P_Styles * page,Style * stl)118 static void set_widgets_preview(P_Styles *page, Style *stl)
119 {
120 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(page->dpvisual.preview)));
121 GtkTreeIter iter;
122
123 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
124 {
125 const gchar *iname;
126
127 if((iname = stl_style_property_get_icon(stl, SPN_ICON_UNSEL)) != NULL)
128 {
129 GdkPixbuf *pbuf;
130
131 if((pbuf = ico_icon_get_pixbuf(page->min, iname)) != NULL)
132 gtk_list_store_set(store, &iter, COLUMN_ICON, pbuf, -1);
133 }
134 }
135 dpf_cell_set_style_colors(page->dpvisual.pre_icon_r, stl, FALSE, FALSE);
136 dpf_cell_set_style_colors(page->dpvisual.pre_name_r, stl, TRUE, TRUE);
137 }
138
139 /* 1999-05-24 - Set action list. */
set_widgets_action(P_Styles * page,Style * stl)140 static void set_widgets_action(P_Styles *page, Style *stl)
141 {
142 GList *alist;
143
144 gtk_list_store_clear(page->dpaction.store);
145 if((alist = stl_style_property_get_actions(stl)) != NULL)
146 {
147 const GList *iter;
148 GtkTreeIter titer;
149
150 for(iter = alist; iter != NULL; iter = g_list_next(iter))
151 {
152 const gboolean ovr = stl_style_property_get_override(stl, iter->data);
153 gtk_list_store_insert_with_values(page->dpaction.store, &titer, -1,
154 ACTION_COLUMN_NAME, iter->data,
155 ACTION_COLUMN_CMDSEQ, stl_style_property_get_action(stl, iter->data),
156 ACTION_COLUMN_ACTION, iter->data,
157 ACTION_COLUMN_WEIGHT, ovr ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
158 -1);
159 }
160 g_list_free(alist);
161 }
162 }
163
164 /* 1999-05-24 - Set various editing widgets to display <stl>'s details. */
set_widgets(P_Styles * page,Style * stl)165 static void set_widgets(P_Styles *page, Style *stl)
166 {
167 const gchar *pname, *vpname[] = { SPN_COL_UNSEL_BG, SPN_COL_UNSEL_FG, SPN_ICON_UNSEL };
168 gboolean or;
169 guint i;
170
171 if((page == NULL) || (stl == NULL))
172 return;
173
174 gui_handler_group_block(page->handlers);
175
176 gtk_entry_set_text(GTK_ENTRY(page->dname), stl_style_get_name(stl));
177 if((pname = stl_style_get_name(stl_styleinfo_style_get_parent(page->si, stl))) != NULL)
178 gtk_entry_set_text(GTK_ENTRY(page->dparent), pname);
179 else
180 gtk_entry_set_text(GTK_ENTRY(page->dparent), _("(None)"));
181 gtk_widget_set_sensitive(page->dreparent, pname != NULL);
182
183 set_widgets_preview(page, stl);
184 for(i = 0; i < 3; i++)
185 {
186 or = stl_style_property_get_override(stl, vpname[i]);
187 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->dpvisual.override[i]), or);
188 gtk_widget_set_sensitive(page->dpvisual.override[i], (i < 1) || (pname != NULL));
189 gtk_widget_set_sensitive(page->dpvisual.edit[i], or);
190 }
191 set_widgets_action(page, stl);
192 gtk_widget_set_sensitive(page->dvbox, TRUE);
193 gtk_widget_set_sensitive(page->del, stl_styleinfo_style_root(page->si) != stl);
194
195 gui_handler_group_unblock(page->handlers);
196 }
197
198 /* 1999-05-25 - Reset action editing widgets. */
reset_widgets_action(P_Styles * page)199 static void reset_widgets_action(P_Styles *page)
200 {
201 gtk_widget_set_sensitive(page->dpaction.editcmd, FALSE);
202 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(page->dpaction.adel))), _("Delete Action"));
203 gtk_widget_set_sensitive(page->dpaction.adel, FALSE);
204 }
205
206 /* 1999-05-24 - Reset widgets. Handy when there is no longer a selection. */
reset_widgets(P_Styles * page)207 static void reset_widgets(P_Styles *page)
208 {
209 page->curr_prop = NULL;
210 page->curr_arow = -1;
211 gtk_entry_set_text(GTK_ENTRY(page->dname), "");
212 gtk_entry_set_text(GTK_ENTRY(page->dparent), "");
213 reset_widgets_action(page);
214 gtk_widget_set_sensitive(page->dvbox, FALSE);
215 gtk_widget_set_sensitive(page->del, FALSE);
216 }
217
218 /* ----------------------------------------------------------------------------------------- */
219
style_get_selected(const P_Styles * page,GtkTreeIter * iter)220 static Style * style_get_selected(const P_Styles *page, GtkTreeIter *iter)
221 {
222 GtkTreeIter myiter;
223
224 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->tree)), NULL, &myiter))
225 {
226 if(iter != NULL)
227 *iter = myiter;
228 return stl_styleinfo_get_style_iter(page->si, page->store, &myiter);
229 }
230 return NULL;
231 }
232
233 /* 2009-03-24 - New-style selection tracking. */
evt_style_selection_changed(GtkTreeSelection * sel,gpointer user)234 static void evt_style_selection_changed(GtkTreeSelection *sel, gpointer user)
235 {
236 P_Styles *page = user;
237 Style *style;
238
239 if((style = style_get_selected(page, NULL)) != NULL)
240 {
241 set_widgets(page, style);
242 reset_widgets_action(page);
243 }
244 else
245 reset_widgets(page);
246 }
247
248 /* 2009-02-06 - A row was expanded, update the underlying Style object. */
evt_style_row_expanded(GtkTreeView * view,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)249 static void evt_style_row_expanded(GtkTreeView *view, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data)
250 {
251 GtkTreeModel *m;
252 Style *stl;
253
254 m = gtk_tree_view_get_model(view);
255 gtk_tree_model_get(m, iter, 1, &stl, -1);
256 stl_style_set_expand(stl, TRUE);
257 }
258
259 /* 2009-02-06 - A row was collapsed, update the underlying Style object. */
evt_style_row_collapsed(GtkTreeView * view,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)260 static void evt_style_row_collapsed(GtkTreeView *view, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data)
261 {
262 GtkTreeModel *m;
263 Style *stl;
264
265 m = gtk_tree_view_get_model(view);
266 gtk_tree_model_get(m, iter, 1, &stl, -1);
267 stl_style_set_expand(stl, FALSE);
268 }
269
270 /* 2009-02-06 - This is a gtk_tree_model_foreach() callback, that simply applies the collapsed/
271 ** expanded status to a tree row showing a style. This is a property of the view,
272 ** so it cannot be done from inside the styles module.
273 */
set_expand(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user)274 static gboolean set_expand(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user)
275 {
276 Style *stl;
277
278 gtk_tree_model_get(model, iter, 1, &stl, -1);
279 if(stl_style_get_expand(stl))
280 gtk_tree_view_expand_row(GTK_TREE_VIEW(user), path, FALSE);
281 else
282 gtk_tree_view_collapse_row(GTK_TREE_VIEW(user), path);
283 return FALSE;
284 }
285
286 /* 1999-05-24 - Repopulate the tree. */
populate_tree(P_Styles * page)287 static void populate_tree(P_Styles *page)
288 {
289 if(page->si != NULL)
290 {
291 page->store = stl_styleinfo_build_partial(page->si, NULL);
292 /* Block expand/collapse signals. */
293 g_signal_handler_block(page->tree, page->sig_collapse);
294 g_signal_handler_block(page->tree, page->sig_expand);
295 gtk_tree_view_set_model(GTK_TREE_VIEW(page->tree), GTK_TREE_MODEL(page->store));
296 gtk_tree_model_foreach(GTK_TREE_MODEL(page->store), set_expand, page->tree);
297 g_signal_handler_unblock(page->tree, page->sig_expand);
298 g_signal_handler_unblock(page->tree, page->sig_collapse);
299 }
300 }
301
302 /* ----------------------------------------------------------------------------------------- */
303
304 /* 1999-05-24 - Set a new name for the current style. */
evt_style_name_changed(GtkWidget * wid,gpointer user)305 static void evt_style_name_changed(GtkWidget *wid, gpointer user)
306 {
307 P_Styles *page = user;
308 const gchar *name;
309 Style *style;
310 GtkTreeIter iter;
311
312 if((style = style_get_selected(page, &iter)) != NULL)
313 {
314 if((name = gtk_entry_get_text(GTK_ENTRY(wid))) != NULL)
315 {
316 ctp_replace_style(stl_style_get_name(style), style);
317 stl_styleinfo_set_name_iter(page->si, page->store, &iter, name);
318 page->modified = TRUE;
319 }
320 }
321 }
322
323 /* 1999-05-24 - User clicked the details (magnifying glass) button to set new parent for current style. */
evt_style_parent_clicked(GtkWidget * wid,gpointer user)324 static void evt_style_parent_clicked(GtkWidget *wid, gpointer user)
325 {
326 P_Styles *page = user;
327 Style *style;
328 Style *np;
329
330 if((style = style_get_selected(page, NULL)) != NULL)
331 {
332 if((np = sdl_dialog_sync_new_wait(page->si, style)) != NULL)
333 {
334 stl_styleinfo_style_set_parent(page->si, style, np);
335 populate_tree(page);
336 page->modified = TRUE;
337 }
338 }
339 }
340
341 /* ----------------------------------------------------------------------------------------- */
342
343 /* 1999-05-24 - User toggled one of the visual property override checkbuttons. Update
344 ** the current style accordingly.
345 */
evt_vprop_override_toggled(GtkWidget * wid,gpointer user)346 static void evt_vprop_override_toggled(GtkWidget *wid, gpointer user)
347 {
348 P_Styles *page = user;
349 Style *style;
350 const gchar *pname;
351 gboolean or;
352
353 if((style = style_get_selected(page, NULL)) == NULL)
354 return;
355
356 pname = g_object_get_data(G_OBJECT(wid), "user");
357 or = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wid));
358 if(or)
359 {
360 if(strcmp(pname, SPN_ICON_UNSEL) == 0)
361 stl_style_property_set_icon(style, pname, stl_style_property_get_icon(style, pname));
362 else /* If not an icon, it's a color. */
363 {
364 const GdkColor *def;
365
366 /* FIXME: This assumes only background can be non-overridden in root. */
367 if((def = stl_style_property_get_color(style, pname)) != NULL)
368 stl_style_property_set_color(style, pname, def);
369 }
370 }
371 else
372 stl_style_property_remove(style, pname);
373 set_widgets(page, style);
374 page->modified = TRUE;
375 }
376
377 /* 1999-05-24 - A color property has changed. Update previews and stuff. */
evt_vprop_color_changed(const GdkRGBA * color,gpointer user)378 static void evt_vprop_color_changed(const GdkRGBA *color, gpointer user)
379 {
380 P_Styles *page = user;
381 Style *style;
382 GdkColor color_old;
383
384 if((style = style_get_selected(page, NULL)) == NULL)
385 return;
386
387 gui_color_from_rgba(&color_old, color);
388 stl_style_property_set_color(style, page->curr_prop, &color_old);
389 set_widgets(page, style);
390 }
391
392 /* 1999-05-24 - User hit the "Edit..." (or, for the icon, "Pick...") button below override toggle. */
evt_vprop_edit_clicked(GtkWidget * wid,gpointer user)393 static void evt_vprop_edit_clicked(GtkWidget *wid, gpointer user)
394 {
395 P_Styles *page = user;
396 Style *style;
397
398 if((style = style_get_selected(page, NULL)) == NULL)
399 return;
400
401 page->curr_prop = g_object_get_data(G_OBJECT(wid), "user");
402
403 if(strcmp(page->curr_prop, SPN_ICON_UNSEL) == 0)
404 {
405 const gchar *icon;
406
407 if((icon = idl_dialog_sync_new_wait(page->min, cpt_get_path(PTID_ICON), NULL,
408 stl_style_property_get_icon(style, page->curr_prop),
409 TRUE)) != NULL)
410 {
411 stl_style_property_set_icon(style, page->curr_prop, icon);
412 page->modified = TRUE;
413 set_widgets(page, style);
414 }
415 }
416 else
417 {
418 const GdkColor *col;
419 GdkColor col_old;
420 GdkRGBA initial, *ip = NULL;
421
422 if((col = stl_style_property_get_color(style, page->curr_prop)) != NULL)
423 {
424 col_old = *col;
425 gui_rgba_from_color(&initial, col);
426 ip = &initial;
427 }
428 if(cdl_dialog_sync_new_wait(_("Edit Color"), evt_vprop_color_changed, ip, page) != DLG_POSITIVE)
429 {
430 if(col != NULL)
431 stl_style_property_set_color(style, page->curr_prop, &col_old);
432 }
433 else
434 page->modified = TRUE;
435 set_widgets(page, style);
436 }
437 }
438
439 /* ----------------------------------------------------------------------------------------- */
440
441 /* 2014-12-25 - Set sensitivity of the shortcut button for command-editing. User-defined commands only. */
set_aprop_editcmd_button(const P_Styles * page,Style * style)442 static void set_aprop_editcmd_button(const P_Styles *page, Style *style)
443 {
444 const gchar *action = stl_style_property_get_action(style, page->curr_prop);
445
446 if(action != NULL && *action != '\0' && g_hash_table_contains(ccs_get_current(), action))
447 {
448 gtk_widget_set_sensitive(page->dpaction.editcmd, islower((unsigned char) action[0]));
449 }
450 }
451
452 /* 2009-04-22 - Set the proper label for the Delete Action button. Depends on override. */
set_aprop_delete_button(P_Styles * page,Style * style)453 static gboolean set_aprop_delete_button(P_Styles *page, Style *style)
454 {
455 gboolean unique, ovr;
456
457 unique = stl_style_property_is_unique(style, page->curr_prop);
458 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(page->dpaction.adel))),
459 unique ? _("Delete Action") : _("Revert to Inherited Command"));
460 ovr = stl_style_property_get_override(style, page->curr_prop);
461 gtk_widget_set_sensitive(page->dpaction.adel, ovr);
462
463 return ovr;
464 }
465
466 /* 2009-04-22 - Update widgets when action property selection changes. */
evt_aprop_selection_changed(GtkTreeSelection * sel,gpointer user)467 static void evt_aprop_selection_changed(GtkTreeSelection *sel, gpointer user)
468 {
469 P_Styles *page = user;
470 Style *style;
471 GtkTreeIter myiter;
472
473 if((style = style_get_selected(page, NULL)) == NULL)
474 {
475 gtk_widget_set_sensitive(page->dpaction.editcmd, FALSE);
476 return;
477 }
478 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->dpaction.view)), NULL, &myiter))
479 {
480 gboolean ovr;
481 GtkTreeViewColumn *col;
482 GList *cellrenderers;
483
484 gtk_tree_model_get(GTK_TREE_MODEL(page->dpaction.store), &myiter, ACTION_COLUMN_ACTION, &page->curr_prop, -1);
485 set_aprop_editcmd_button(page, style);
486 ovr = set_aprop_delete_button(page, style);
487 /* Set the name column's editable mode, depending on override. */
488 col = gtk_tree_view_get_column(GTK_TREE_VIEW(page->dpaction.view), 0);
489 cellrenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(col));
490 if(cellrenderers != NULL)
491 {
492 g_object_set(G_OBJECT(cellrenderers->data), "editable", ovr, NULL);
493 g_list_free(cellrenderers);
494 }
495 /* Make name column bold/normal depending on override. */
496 gtk_list_store_set(page->dpaction.store, &myiter, ACTION_COLUMN_WEIGHT, ovr ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, -1);
497 }
498 }
499
500 /* 2009-04-22 - An action property name was edited. If the name changed, to the rename by calling the Styles module. */
evt_aprop_name_edited(GtkCellRendererText * cr,gchar * spath,gchar * new_name,gpointer user)501 static void evt_aprop_name_edited(GtkCellRendererText *cr, gchar *spath, gchar *new_name, gpointer user)
502 {
503 P_Styles *page = user;
504 Style *stl;
505 GtkTreePath *path;
506 gchar *name;
507
508 if((stl = style_get_selected(page, NULL)) == NULL)
509 return;
510
511 if((path = gtk_tree_path_new_from_string(spath)) != NULL)
512 {
513 GtkTreeIter iter;
514
515 if(gtk_tree_model_get_iter(GTK_TREE_MODEL(page->dpaction.store), &iter, path))
516 {
517 gtk_tree_model_get(GTK_TREE_MODEL(page->dpaction.store), &iter,
518 ACTION_COLUMN_NAME, &name,
519 -1);
520 /* Only do the change if the new_name really is new. */
521 if(strcmp(name, new_name) != 0)
522 {
523 if(stl_style_property_rename(stl, name, new_name))
524 set_widgets_action(page, stl);
525 }
526 g_free(name);
527 }
528 gtk_tree_path_free(path);
529 }
530 }
531
532 /* 2009-04-22 - User wants to select a command from a dialog, for the current action property's action. */
evt_aprop_cmdseq_pick_activated(GtkWidget * wid,gpointer user)533 static void evt_aprop_cmdseq_pick_activated(GtkWidget *wid, gpointer user)
534 {
535 P_Styles *page = user;
536 const gchar *cmd;
537
538 if((cmd = csq_dialog_sync_new_wait(page->min, ccs_get_current())) != NULL)
539 {
540 Style *style;
541 GtkTreeIter myiter;
542
543 if((style = style_get_selected(page, NULL)) == NULL)
544 return;
545 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->dpaction.view)), NULL, &myiter))
546 {
547 gtk_tree_model_get(GTK_TREE_MODEL(page->dpaction.store), &myiter, ACTION_COLUMN_ACTION, &page->curr_prop, -1);
548 stl_style_property_set_action(style, page->curr_prop, cmd);
549 gtk_list_store_set(page->dpaction.store, &myiter, ACTION_COLUMN_CMDSEQ, cmd, -1);
550 page->modified = TRUE;
551 }
552 }
553 }
554
555 /* 2009-04-22 - Populate the action name editing entry's popup menu. This gives us a chance to add a menuitem that
556 ** brings up the good old "Select Command" dialog. This used to be done by a magnifying-glass button
557 ** to the right of the entry, but now the entry is *in* the GtkTreeView.
558 */
evt_aprop_cmdseq_populate_popup(GtkEntry * entry,GtkMenu * menu,gpointer user)559 static void evt_aprop_cmdseq_populate_popup(GtkEntry *entry, GtkMenu *menu, gpointer user)
560 {
561 GtkWidget *wid;
562
563 wid = gtk_menu_item_new_with_label(_("Select Command ...")); /* FIXME: Add back (deprecated) icon?! */
564 g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(evt_aprop_cmdseq_pick_activated), user);
565 gtk_menu_shell_append(GTK_MENU_SHELL(menu), wid);
566 gtk_widget_show_all(wid);
567 }
568
569 /* 2009-04-22 - This gets called when an action property name editing is started. This is the time to attach a
570 ** popup-population handler, which gets called if the user right-clicks the entry.
571 */
evt_aprop_cmdseq_edit_started(GtkCellRenderer * renderer,GtkCellEditable * editable,gchar * spath,gpointer user)572 static void evt_aprop_cmdseq_edit_started(GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *spath, gpointer user)
573 {
574 /* Magically know that the editable is a GtkEntry, and attach a menu signal handler. */
575 g_signal_connect(G_OBJECT(editable), "populate_popup", G_CALLBACK(evt_aprop_cmdseq_populate_popup), user);
576 }
577
evt_aprop_cmdseq_edited(GtkCellRendererText * cr,gchar * spath,gchar * new_cmdseq,gpointer user)578 static void evt_aprop_cmdseq_edited(GtkCellRendererText *cr, gchar *spath, gchar *new_cmdseq, gpointer user)
579 {
580 P_Styles *page = user;
581 Style *stl;
582 GtkTreePath *path;
583 const gchar *cmdseq;
584
585 if(page->curr_prop == NULL)
586 return;
587 if((stl = style_get_selected(page, NULL)) == NULL)
588 return;
589 if((path = gtk_tree_path_new_from_string(spath)) == NULL)
590 return;
591 /* Only do the change if the new_cmdseq really is new. */
592 cmdseq = stl_style_property_get_action(stl, page->curr_prop);
593 if(strcmp(cmdseq, new_cmdseq) != 0)
594 {
595 GtkTreeIter iter;
596
597 if(gtk_tree_model_get_iter(GTK_TREE_MODEL(page->dpaction.store), &iter, path))
598 {
599 stl_style_property_set_action(stl, page->curr_prop, new_cmdseq);
600 gtk_list_store_set(page->dpaction.store, &iter, ACTION_COLUMN_CMDSEQ, new_cmdseq, -1);
601 gtk_list_store_set(page->dpaction.store, &iter, ACTION_COLUMN_WEIGHT, PANGO_WEIGHT_BOLD, -1);
602 set_aprop_delete_button(page, stl);
603 page->modified = TRUE;
604 }
605 }
606 gtk_tree_path_free(path);
607 }
608
609 /* 1999-05-25 - Add a new action property. Pops up a dialog asking for the name. */
evt_aprop_add_clicked(GtkWidget * wid,gpointer user)610 static void evt_aprop_add_clicked(GtkWidget *wid, gpointer user)
611 {
612 P_Styles *page = user;
613 Style *style;
614 Dialog *dlg;
615 GtkWidget *hbox, *label, *entry;
616
617 if((style = style_get_selected(page, NULL)) == NULL)
618 return;
619
620 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
621 label = gtk_label_new(_("Name"));
622 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
623 entry = gtk_entry_new();
624 gtk_entry_set_max_length(GTK_ENTRY(entry), STL_PROPERTY_NAME_SIZE - 1);
625 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
626 dlg = dlg_dialog_sync_new(hbox, _("New Action Property"), NULL);
627 gtk_widget_grab_focus(entry);
628 if(dlg_dialog_sync_wait(dlg) == DLG_POSITIVE)
629 {
630 const gchar *name;
631
632 if(((name = gtk_entry_get_text(GTK_ENTRY(entry))) != NULL) && *name != '\0')
633 {
634 stl_style_property_set_action(style, name, _("something"));
635 set_widgets_action(page, style);
636 reset_widgets_action(page);
637 page->modified = TRUE;
638 }
639 }
640 dlg_dialog_sync_destroy(dlg);
641 }
642
643 /* 2014-12-26 - Go to the command editor for the currently chosen command. Convenient? */
evt_editcmd_clicked(GtkWidget * wid,gpointer user)644 static void evt_editcmd_clicked(GtkWidget *wid, gpointer user)
645 {
646 const P_Styles *page = user;
647 const Style *style;
648 const gchar *cmdseq;
649
650 if((style = style_get_selected(page, NULL)) == NULL)
651 return;
652 cmdseq = stl_style_property_get_action(style, page->curr_prop);
653 if(ccs_goto_cmdseq(cmdseq))
654 {
655 cfg_goto_page("Definitions"); /* This won't win any prices for low coupling. */
656 }
657 }
658
659 /* 1999-05-25 - User clicked the "Delete" (or "Revert...") button. Do it. */
evt_aprop_delete_clicked(GtkWidget * wid,gpointer user)660 static void evt_aprop_delete_clicked(GtkWidget *wid, gpointer user)
661 {
662 P_Styles *page = user;
663 Style *style;
664
665 if((style = style_get_selected(page, NULL)) == NULL)
666 return;
667
668 if((page->curr_prop != NULL))
669 {
670 stl_style_property_remove(style, page->curr_prop);
671 set_widgets_action(page, style);
672 reset_widgets_action(page);
673 page->modified = TRUE;
674 }
675 }
676
677 /* ----------------------------------------------------------------------------------------- */
678
679 /* 1999-05-26 - Add a new style. Use the currently selected style, if one exists, as parent.
680 ** If there is no selection, add style with Root as parent.
681 */
evt_style_add_clicked(GtkWidget * wid,gpointer user)682 static void evt_style_add_clicked(GtkWidget *wid, gpointer user)
683 {
684 P_Styles *page = user;
685
686 if(page != NULL)
687 {
688 Style *stl, *parent;
689 GtkTreeIter iter;
690
691 stl = stl_style_new_unique_name(page->si);
692 /* Parent is either current selection, or root. */
693 if((parent = style_get_selected(page, &iter)) == NULL)
694 parent = stl_styleinfo_style_root(page->si);
695 stl_styleinfo_style_add(page->si, parent, stl);
696 stl_style_set_expand(parent, TRUE);
697 populate_tree(page);
698 if(stl_styleinfo_tree_find_style(page->si, page->store, stl, &iter))
699 {
700 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->tree)), &iter);
701 gtk_editable_select_region(GTK_EDITABLE(page->dname), 0, -1);
702 gtk_widget_grab_focus(page->dname);
703 }
704 }
705 }
706
707 /* 1999-05-27 - Delete the currently selected style. If the style has children, the user must
708 ** confirm the operation, since all children will be deleted, too.
709 */
evt_style_del_clicked(GtkWidget * wid,gpointer user)710 static void evt_style_del_clicked(GtkWidget *wid, gpointer user)
711 {
712 P_Styles *page = user;
713 Style *style;
714 gint ok = DLG_POSITIVE;
715
716 if((style = style_get_selected(page, NULL)) == NULL)
717 return;
718
719 if(stl_styleinfo_style_has_children(page->si, style))
720 ok = dlg_dialog_sync_new_simple_wait(_("Deleting this style will also delete\n"
721 "all its children. Are you sure?"), _("Confirm Delete"), _("_Delete|_Cancel"));
722 if(ok == DLG_POSITIVE)
723 {
724 GList *chlist, *iter;
725 Style *stl;
726
727 stl = stl_styleinfo_style_root(page->si);
728 chlist = stl_styleinfo_style_get_children(page->si, style, TRUE);
729 for(iter = chlist; iter != NULL; iter = g_list_next(iter))
730 ctp_replace_style(stl_style_get_name(iter->data), stl);
731 g_list_free(chlist);
732 stl_styleinfo_style_remove(page->si, style);
733 populate_tree(page);
734 reset_widgets(page);
735 }
736 }
737
738 /* ----------------------------------------------------------------------------------------- */
739
740 /* 1999-05-22 - Build the visual property editing widgets. */
build_pvisual(P_Styles * page)741 static void build_pvisual(P_Styles *page)
742 {
743 PVisual *pv = &page->dpvisual;
744 const gchar *vplab[] = { N_("Background Color"), N_("Foreground Color"), N_("Icon") },
745 *vpname[] = { SPN_COL_UNSEL_BG, SPN_COL_UNSEL_FG, SPN_ICON_UNSEL };
746 gchar ptxt[] = N_("(Row Style Preview Text)");
747 GtkListStore *store;
748 GtkTreeIter iter;
749 GtkWidget *hbox, *frame, *vbox, *label;
750 guint i;
751
752 pv->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
753 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
754 label = gtk_label_new(_("Preview"));
755 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
756 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
757 gtk_list_store_insert_with_values(store, &iter, -1, COLUMN_NAME, _(ptxt), -1);
758 pv->preview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
759 pv->pre_icon_r = gtk_cell_renderer_pixbuf_new();
760 pv->pre_icon = gtk_tree_view_column_new_with_attributes("(title)", pv->pre_icon_r, "pixbuf", COLUMN_ICON, NULL);
761 gtk_tree_view_append_column(GTK_TREE_VIEW(pv->preview), pv->pre_icon);
762 pv->pre_name_r = gtk_cell_renderer_text_new();
763 pv->pre_name = gtk_tree_view_column_new_with_attributes("(title)", pv->pre_name_r, "text", COLUMN_NAME, NULL);
764 gtk_tree_view_append_column(GTK_TREE_VIEW(pv->preview), pv->pre_name);
765 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pv->preview), FALSE);
766 gtk_widget_set_name(pv->preview, "cstPreview");
767 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(pv->preview)), GTK_SELECTION_SINGLE); /* Or none, like before? */
768 gtk_box_pack_start(GTK_BOX(hbox), pv->preview, TRUE, TRUE, 0);
769 gtk_box_pack_start(GTK_BOX(pv->vbox), hbox, FALSE, FALSE, 2);
770
771 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
772 for(i = 0; i < 3; i++)
773 {
774 frame = gtk_frame_new(_(vplab[i]));
775 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
776 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
777 pv->override[i] = gtk_check_button_new_with_label(_("Override Parent's?"));
778 g_object_set_data(G_OBJECT(pv->override[i]), "user", (gpointer) vpname[i]);
779 g_signal_connect(G_OBJECT(pv->override[i]), "toggled", G_CALLBACK(evt_vprop_override_toggled), page);
780 gtk_box_pack_start(GTK_BOX(vbox), pv->override[i], FALSE, FALSE, 0);
781 pv->edit[i] = gtk_button_new_with_label(i < 2 ? _("Edit...") : _("Pick..."));
782 g_object_set_data(G_OBJECT(pv->edit[i]), "user", (gpointer) vpname[i]);
783 g_signal_connect(G_OBJECT(pv->edit[i]), "clicked", G_CALLBACK(evt_vprop_edit_clicked), page);
784 gtk_box_pack_start(GTK_BOX(vbox), pv->edit[i], FALSE, FALSE, 0);
785 gtk_container_add(GTK_CONTAINER(frame), vbox);
786 gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 5);
787 }
788 gtk_box_pack_start(GTK_BOX(pv->vbox), hbox, FALSE, FALSE, 0);
789 }
790
791 /* 1999-05-22 - Build action property editing widgetry. */
build_paction(P_Styles * page)792 static void build_paction(P_Styles *page)
793 {
794 PAction *pa = &page->dpaction;
795 GtkWidget *hbox, *btn, *scwin;
796 GtkCellRenderer *cr;
797 GtkTreeViewColumn *vc;
798
799 pa->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
800 pa->store = gtk_list_store_new(ACTION_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
801 pa->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pa->store));
802 cr = gtk_cell_renderer_text_new();
803 g_object_set(G_OBJECT(cr), "editable", TRUE, NULL);
804 g_signal_connect(G_OBJECT(cr), "edited", G_CALLBACK(evt_aprop_name_edited), page);
805 vc = gtk_tree_view_column_new_with_attributes("(Name)", cr, "text", ACTION_COLUMN_NAME, "weight", ACTION_COLUMN_WEIGHT, NULL);
806 gtk_tree_view_append_column(GTK_TREE_VIEW(pa->view), vc);
807 cr = gtk_cell_renderer_text_new();
808 g_object_set(G_OBJECT(cr), "editable", TRUE, NULL);
809 g_signal_connect(G_OBJECT(cr), "editing_started", G_CALLBACK(evt_aprop_cmdseq_edit_started), page);
810 g_signal_connect(G_OBJECT(cr), "edited", G_CALLBACK(evt_aprop_cmdseq_edited), page);
811 vc = gtk_tree_view_column_new_with_attributes("(CmdSeq)", cr, "text", ACTION_COLUMN_CMDSEQ, NULL);
812 gtk_tree_view_append_column(GTK_TREE_VIEW(pa->view), vc);
813 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pa->view), FALSE);
814 g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(pa->view))), "changed", G_CALLBACK(evt_aprop_selection_changed), page);
815 scwin = gtk_scrolled_window_new(NULL, NULL);
816 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
817 gtk_widget_set_size_request(scwin, -1, 100);
818 gtk_container_add(GTK_CONTAINER(scwin), pa->view);
819 gtk_box_pack_start(GTK_BOX(pa->vbox), scwin, TRUE, TRUE, 0);
820
821 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
822 gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
823 btn = gtk_button_new_with_label(_("Add Action..."));
824 g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(evt_aprop_add_clicked), page);
825 gtk_box_pack_start(GTK_BOX(hbox), btn, TRUE, TRUE, 5);
826 pa->editcmd = gtk_button_new_with_label(_("Edit Command"));
827 g_signal_connect(G_OBJECT(pa->editcmd), "clicked", G_CALLBACK(evt_editcmd_clicked), page);
828 gtk_box_pack_start(GTK_BOX(hbox), pa->editcmd, TRUE, TRUE, 5);
829 pa->adel = gtk_button_new_with_label(_("Delete Action"));
830 g_signal_connect(G_OBJECT(pa->adel), "clicked", G_CALLBACK(evt_aprop_delete_clicked), page);
831 gtk_box_pack_start(GTK_BOX(hbox), pa->adel, TRUE, TRUE, 5);
832 gtk_box_pack_start(GTK_BOX(pa->vbox), hbox, FALSE, FALSE, 5);
833 }
834
835 /* 1999-05-22 - Build style configuration GUI page. */
cst_init(MainInfo * min,gchar ** name)836 static GtkWidget * cst_init(MainInfo *min, gchar **name)
837 {
838 P_Styles *page = &the_page;
839 GtkWidget *grid, *label, *frame, *hbox, *btn;
840 GtkCellRenderer *cr;
841 GtkTreeViewColumn *vc;
842
843 page->min = min;
844 page->si = NULL;
845 page->modified = FALSE;
846 page->store = NULL;
847
848 page->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
849 page->handlers = gui_handler_group_new();
850
851 page->scwin = gtk_scrolled_window_new(FALSE, FALSE);
852 page->tree = gtk_tree_view_new();
853 cr = gtk_cell_renderer_text_new();
854 vc = gtk_tree_view_column_new_with_attributes("(Styles)", cr, "text", 0, NULL);
855 gtk_tree_view_append_column(GTK_TREE_VIEW(page->tree), vc);
856 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(page->tree), FALSE);
857 g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(page->tree))), "changed", G_CALLBACK(evt_style_selection_changed), page);
858 page->sig_expand = g_signal_connect(G_OBJECT(page->tree), "row_expanded", G_CALLBACK(evt_style_row_expanded), page);
859 page->sig_collapse = g_signal_connect(G_OBJECT(page->tree), "row_collapsed", G_CALLBACK(evt_style_row_collapsed), page);
860 gtk_container_add(GTK_CONTAINER(page->scwin), page->tree);
861 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(page->scwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
862 gtk_box_pack_start(GTK_BOX(page->vbox), page->scwin, TRUE, TRUE, 0);
863
864 page->dvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
865
866 grid = gtk_grid_new();
867 label = gtk_label_new(_("Name"));
868 gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
869 page->dname = gtk_entry_new();
870 gtk_entry_set_max_length(GTK_ENTRY(page->dname), STL_STYLE_NAME_SIZE - 1);
871 gui_handler_group_connect(page->handlers, G_OBJECT(page->dname), "changed", G_CALLBACK(evt_style_name_changed), page);
872 gtk_grid_attach(GTK_GRID(grid), page->dname, 1, 0, 2, 1);
873 label = gtk_label_new(_("Parent"));
874 gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
875 page->dparent = gtk_entry_new();
876 gtk_widget_set_hexpand(page->dparent, TRUE);
877 gtk_widget_set_halign(page->dparent, GTK_ALIGN_FILL);
878 gtk_entry_set_max_length(GTK_ENTRY(page->dparent), STL_STYLE_NAME_SIZE - 1);
879 gtk_editable_set_editable(GTK_EDITABLE(page->dparent), FALSE);
880 gtk_grid_attach(GTK_GRID(grid), page->dparent, 1, 1, 1, 1);
881 page->dreparent = gui_details_button_new();
882 g_signal_connect(G_OBJECT(page->dreparent), "clicked", G_CALLBACK(evt_style_parent_clicked), page);
883 gtk_grid_attach(GTK_GRID(grid), page->dreparent, 2, 1, 1, 1);
884 gtk_box_pack_start(GTK_BOX(page->dvbox), grid, FALSE, FALSE, 0);
885
886 frame = gtk_frame_new(_("Inherited Properties"));
887 page->dpnbook = gtk_notebook_new();
888 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(page->dpnbook), GTK_POS_LEFT);
889 build_pvisual(page);
890 gtk_notebook_append_page(GTK_NOTEBOOK(page->dpnbook), page->dpvisual.vbox, gtk_label_new(_("Visual")));
891 build_paction(page);
892 gtk_notebook_append_page(GTK_NOTEBOOK(page->dpnbook), page->dpaction.vbox, gtk_label_new(_("Actions")));
893 gtk_container_add(GTK_CONTAINER(frame), page->dpnbook);
894
895 gtk_box_pack_start(GTK_BOX(page->dvbox), frame, FALSE, FALSE, 5);
896 gtk_box_pack_start(GTK_BOX(page->vbox), page->dvbox, FALSE, FALSE, 0);
897
898 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
899 btn = gtk_button_new_with_label(_("Add"));
900 g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(evt_style_add_clicked), page);
901 gtk_box_pack_start(GTK_BOX(hbox), btn, TRUE, TRUE, 5);
902 page->del = gtk_button_new_with_label(_("Delete"));
903 g_signal_connect(G_OBJECT(page->del), "clicked", G_CALLBACK(evt_style_del_clicked), page);
904 gtk_box_pack_start(GTK_BOX(hbox), page->del, TRUE, TRUE, 5);
905 gtk_box_pack_start(GTK_BOX(page->vbox), hbox, FALSE, FALSE, 5);
906
907 gtk_widget_show_all(page->vbox);
908
909 cfg_tree_level_begin(_("File Recognition"));
910 cfg_tree_level_append(_("Styles"), page->vbox);
911
912 return NULL;
913 }
914
915 /* ----------------------------------------------------------------------------------------- */
916
917 /* 1999-05-12 - Update style display. */
cst_update(MainInfo * min)918 static void cst_update(MainInfo *min)
919 {
920 P_Styles *page = &the_page;
921
922 page->si = stl_styleinfo_copy(min->cfg.style);
923 populate_tree(page);
924 reset_widgets(page);
925 }
926
927 /* ----------------------------------------------------------------------------------------- */
928
929 /* 1999-05-27 - Accept changes, if any. Causes a call to the relink function in types config.
930 ** 1999-06-13 - Fixed a rather sneaky problem: if the style for a _type_ changed, it would point
931 ** into the editing copies here. If the editing copies went away because of the
932 ** 'modified' flag being FALSE, those types were left with dangling style pointers.
933 ** The fix was simple.
934 */
cst_accept(MainInfo * min)935 static void cst_accept(MainInfo *min)
936 {
937 P_Styles *page = &the_page;
938
939 if(page->modified)
940 {
941 ctp_relink_styles(min->cfg.style, page->si);
942 stl_styleinfo_destroy(min->cfg.style);
943 min->cfg.style = page->si;
944 page->si = NULL;
945 page->modified = FALSE;
946 cfg_set_flags(CFLG_RESCAN_LEFT | CFLG_RESCAN_RIGHT);
947 }
948 else /* Make sure the types link to the existing styles. */
949 ctp_relink_styles(page->si, min->cfg.style);
950 }
951
952 /* ----------------------------------------------------------------------------------------- */
953
954 /* 1999-05-27 - Save the current style configuration. Thanks to the styles module, this
955 ** is really not complicated. :)
956 */
cst_save(MainInfo * min,FILE * out)957 static gint cst_save(MainInfo *min, FILE *out)
958 {
959 stl_styleinfo_save(min, min->cfg.style, out, NODE);
960
961 return TRUE;
962 }
963
964 /* 1998-08-24 - Load style configuration info from given XML tree. */
cst_load(MainInfo * min,const XmlNode * node)965 static void cst_load(MainInfo *min, const XmlNode *node)
966 {
967 /* Free the built-in first. */
968 stl_styleinfo_destroy(min->cfg.style);
969 min->cfg.style = stl_styleinfo_load(node);
970 }
971
972 /* ----------------------------------------------------------------------------------------- */
973
974 /* 1999-05-27 - When the config window closes, free the editing copies since they're bulky. */
cst_hide(MainInfo * min)975 static void cst_hide(MainInfo *min)
976 {
977 P_Styles *page = &the_page;
978
979 stl_styleinfo_destroy(page->si);
980 page->si = NULL;
981 populate_tree(page); /* This will destroy the tree widget and *not* create a new one, since there's no si. */
982 reset_widgets(page);
983 }
984
985 /* ----------------------------------------------------------------------------------------- */
986
cst_describe(MainInfo * min)987 const CfgModule * cst_describe(MainInfo *min)
988 {
989 static const CfgModule desc = { NODE, cst_init, cst_update, cst_accept, cst_save, cst_load, cst_hide };
990
991 return &desc;
992 }
993
994 /* ----------------------------------------------------------------------------------------- */
995
996 /* 1999-05-27 - Get the most current style info, namely the editing version. */
cst_get_styleinfo(void)997 StyleInfo * cst_get_styleinfo(void)
998 {
999 return the_page.si;
1000 }
1001