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