1 /*
2  * Copyright 2006 Richard Wilson <info@tinct.net>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <oslib/osspriteop.h>
23 #include <oslib/wimp.h>
24 #include <oslib/wimpspriteop.h>
25 
26 #include "utils/config.h"
27 #include "utils/nsoption.h"
28 #include "utils/log.h"
29 #include "utils/messages.h"
30 
31 #include "riscos/gui.h"
32 #include "riscos/configure/configure.h"
33 #include "riscos/configure.h"
34 #include "riscos/dialog.h"
35 #include "riscos/menus.h"
36 #include "riscos/theme.h"
37 #include "riscos/toolbar.h"
38 #include "riscos/url_complete.h"
39 #include "riscos/wimp.h"
40 #include "riscos/wimp_event.h"
41 #include "riscos/wimputils.h"
42 
43 
44 #define THEME_PANE_AREA 0
45 #define THEME_DEFAULT_BUTTON 2
46 #define THEME_CANCEL_BUTTON 3
47 #define THEME_OK_BUTTON 4
48 
49 struct toolbar_display {
50 	struct toolbar *toolbar;
51 	struct theme_descriptor *descriptor;
52 	int icon_number;
53 	struct toolbar_display *next;
54 };
55 
56 static wimp_window theme_pane_definition = {
57 	{0, 0, 16, 16},
58 	0,
59 	0,
60 	wimp_TOP,
61 	wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_VSCROLL | wimp_WINDOW_AUTO_REDRAW,
62 	wimp_COLOUR_BLACK,
63 	wimp_COLOUR_LIGHT_GREY,
64 	wimp_COLOUR_LIGHT_GREY,
65 	wimp_COLOUR_VERY_LIGHT_GREY,
66 	wimp_COLOUR_DARK_GREY,
67 	wimp_COLOUR_MID_LIGHT_GREY,
68 	wimp_COLOUR_CREAM,
69 	0,
70 	{0, -16384, 16384, 0},
71 	wimp_ICON_TEXT | wimp_ICON_HCENTRED | wimp_ICON_VCENTRED,
72 	wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT,
73 	wimpspriteop_AREA,
74 	1,
75 	1,
76 	{""},
77 	0,
78 	{}
79 };
80 
81 
82 static wimp_w theme_pane;
83 static struct theme_descriptor *theme_list = NULL;
84 static struct toolbar_display *toolbars = NULL;
85 static char theme_radio_validation[] = "Sradiooff,radioon";
86 static char theme_null_validation[] = "";
87 static char theme_line_validation[] = "R2";
88 
89 static bool ro_gui_options_theme_ok(wimp_w w);
90 static bool ro_gui_options_theme_click(wimp_pointer *pointer);
91 static void ro_gui_options_theme_load(void);
92 static void ro_gui_options_theme_free(void);
93 
ro_gui_options_theme_initialise(wimp_w w)94 bool ro_gui_options_theme_initialise(wimp_w w)
95 {
96 	wimp_window_state state;
97 	wimp_icon_state icon_state;
98 	os_error *error;
99 	struct theme_descriptor *theme_choice;
100 	struct toolbar_display *toolbar;
101 
102 	/* only allow one instance for now*/
103 	if (theme_pane)
104 		return false;
105 	error = xwimp_create_window(&theme_pane_definition, &theme_pane);
106 	if (error) {
107 		NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
108 		      error->errnum, error->errmess);
109 		return false;
110 	}
111 	state.w = w;
112 	error = xwimp_get_window_state(&state);
113 	if (error) {
114 		NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
115 		      error->errnum, error->errmess);
116 		return false;
117 	}
118 	icon_state.w = w;
119 	icon_state.i = THEME_PANE_AREA;
120 	error = xwimp_get_icon_state(&icon_state);
121 	if (error) {
122 		NSLOG(netsurf, INFO, "xwimp_get_icon_state: 0x%x: %s",
123 		      error->errnum, error->errmess);
124 		return false;
125 	}
126 	state.w = theme_pane;
127 	state.visible.x1 = state.visible.x0 + icon_state.icon.extent.x1 - 16 -
128 			ro_get_vscroll_width(theme_pane);
129 	state.visible.x0 += icon_state.icon.extent.x0 + 16;
130 	state.visible.y0 = state.visible.y1 + icon_state.icon.extent.y0 + 16;
131 	state.visible.y1 += icon_state.icon.extent.y1 - 28;
132 	NSLOG(netsurf, INFO, "Y0 = %i, y1 = %i", icon_state.icon.extent.y0,
133 	      icon_state.icon.extent.y1);
134 	error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), w,
135 			wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
136 					<< wimp_CHILD_XORIGIN_SHIFT |
137 			wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
138 					<< wimp_CHILD_YORIGIN_SHIFT |
139 			wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
140 					<< wimp_CHILD_LS_EDGE_SHIFT |
141 			wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
142 					<< wimp_CHILD_BS_EDGE_SHIFT |
143 			wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
144 					<< wimp_CHILD_RS_EDGE_SHIFT |
145 			wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT
146 					<< wimp_CHILD_TS_EDGE_SHIFT);
147 	if (error) {
148 		NSLOG(netsurf, INFO, "xwimp_open_window_nested: 0x%x: %s",
149 		      error->errnum, error->errmess);
150 		return false;
151 	}
152 
153   	/* load themes */
154 	ro_gui_options_theme_load();
155 
156 	/* set the current selection */
157 	theme_choice = ro_gui_theme_find(nsoption_charp(theme));
158 	if (!theme_choice)
159 		theme_choice = ro_gui_theme_find("Aletheia");
160 	for (toolbar = toolbars; toolbar; toolbar = toolbar->next)
161 		ro_gui_set_icon_selected_state(theme_pane, toolbar->icon_number,
162 				(toolbar->descriptor == theme_choice));
163 	ro_gui_wimp_event_memorise(theme_pane);
164 	ro_gui_wimp_event_set_help_prefix(theme_pane, "HelpThemePConfig");
165 
166 	ro_gui_wimp_event_register_mouse_click(w, ro_gui_options_theme_click);
167 	ro_gui_wimp_event_register_cancel(w, THEME_CANCEL_BUTTON);
168 	ro_gui_wimp_event_register_ok(w, THEME_OK_BUTTON,
169 			ro_gui_options_theme_ok);
170 	ro_gui_wimp_event_set_help_prefix(w, "HelpThemeConfig");
171 	ro_gui_wimp_event_memorise(w);
172 
173 	return true;
174 }
175 
ro_gui_options_theme_finalise(wimp_w w)176 void ro_gui_options_theme_finalise(wimp_w w)
177 {
178 	ro_gui_options_theme_free();
179 	if (theme_pane) {
180 		os_error *error;
181 		ro_gui_wimp_event_finalise(theme_pane);
182 		error = xwimp_delete_window(theme_pane);
183 		if (error) {
184 			NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x: %s",
185 			      error->errnum, error->errmess);
186 			ro_warn_user("WimpError", error->errmess);
187 		}
188 		theme_pane = 0;
189 	}
190 	ro_gui_wimp_event_finalise(w);
191 }
192 
ro_gui_options_theme_ok(wimp_w w)193 bool ro_gui_options_theme_ok(wimp_w w)
194 {
195 	struct toolbar_display *toolbar;
196 	struct theme_descriptor *theme_new = NULL;
197 
198 	/* find the current selection */
199 	for (toolbar = toolbars; toolbar; toolbar = toolbar->next) {
200 		if (ro_gui_get_icon_selected_state(theme_pane, toolbar->icon_number)) {
201 			theme_new = toolbar->descriptor;
202 		  	break;
203 		}
204 	}
205 
206 	/* set the options */
207 	if (theme_new) {
208 		nsoption_set_charp(theme, strdup(theme_new->leafname));
209 		ro_gui_theme_apply(theme_new);
210 	} else {
211 		nsoption_set_charp(theme, NULL);
212         }
213 	ro_gui_save_options();
214 
215 	/* store the pane status */
216 	ro_gui_wimp_event_memorise(theme_pane);
217 	return true;
218 }
219 
ro_gui_options_theme_click(wimp_pointer * pointer)220 bool ro_gui_options_theme_click(wimp_pointer *pointer)
221 {
222 	struct theme_descriptor *theme_default;
223 	struct toolbar_display *toolbar;
224 
225 	switch (pointer->i) {
226 		case THEME_DEFAULT_BUTTON:
227 			theme_default = ro_gui_theme_find("Aletheia");
228 			for (toolbar = toolbars; toolbar; toolbar = toolbar->next)
229 				ro_gui_set_icon_selected_state(theme_pane,
230 						toolbar->icon_number,
231 						(toolbar->descriptor == theme_default));
232 			break;
233 		case THEME_CANCEL_BUTTON:
234 			ro_gui_wimp_event_restore(theme_pane);
235 			break;
236 		case THEME_OK_BUTTON:
237 			ro_gui_wimp_event_memorise(theme_pane);
238 			break;
239 	}
240 	return false;
241 }
242 
ro_gui_options_theme_load(void)243 void ro_gui_options_theme_load(void)
244 {
245 	os_error *error;
246 	os_box extent = { 0, 0, 0, 0 };
247 	struct theme_descriptor *descriptor;
248 	struct toolbar_display *link;
249 	struct toolbar_display *toolbar_display;
250 	struct toolbar *toolbar;
251 	wimp_icon_create new_icon;
252 	wimp_window_state state;
253 	int parent_width, nested_y, min_extent, base_extent;
254 	int *radio_icons, *radio_set;
255 	int theme_count;
256 
257 	/* delete our old list and get/open a new one */
258 	ro_gui_options_theme_free();
259 	theme_list = ro_gui_theme_get_available();
260 	ro_gui_theme_open(theme_list, true);
261 
262 	/* create toolbars for each theme */
263 	theme_count = 0;
264 	descriptor = theme_list;
265 	while (descriptor != NULL) {
266 		/* try to create a toolbar */
267 		toolbar = ro_toolbar_create(descriptor, NULL,
268 				THEME_STYLE_BROWSER_TOOLBAR,
269 				TOOLBAR_FLAGS_DISPLAY, NULL, NULL, NULL);
270 		if (toolbar != NULL) {
271 			ro_toolbar_add_buttons(toolbar, brower_toolbar_buttons,
272 					       nsoption_charp(toolbar_browser));
273 			ro_toolbar_add_url(toolbar);
274 			ro_toolbar_add_throbber(toolbar);
275 			ro_toolbar_rebuild(toolbar);
276 			toolbar_display = calloc(sizeof(struct toolbar_display), 1);
277 			if (!toolbar_display) {
278 				NSLOG(netsurf, INFO, "No memory for calloc()");
279 				ro_warn_user("NoMemory", 0);
280 				return;
281 			}
282 			toolbar_display->toolbar = toolbar;
283 			toolbar_display->descriptor = descriptor;
284 			if (!toolbars) {
285 				toolbars = toolbar_display;
286 			} else {
287 				link = toolbars;
288 				while (link->next) link = link->next;
289 				link->next = toolbar_display;
290 			}
291 			theme_count++;
292 		}
293 		descriptor = descriptor->next;
294 	}
295 
296 	/* nest the toolbars */
297 	state.w = theme_pane;
298 	error = xwimp_get_window_state(&state);
299 	if (error) {
300 		NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
301 		      error->errnum, error->errmess);
302 		ro_warn_user("WimpError", error->errmess);
303 		return;
304 	}
305 
306 	parent_width = state.visible.x1 - state.visible.x0;
307 	min_extent = state.visible.y0 - state.visible.y1;
308 	nested_y = 0;
309 	base_extent = state.visible.y1 - state.yscroll;
310 	extent.x1 = parent_width;
311 	link = toolbars;
312 	new_icon.w = theme_pane;
313 	new_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
314 			wimp_ICON_VCENTRED |
315 			(wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
316 			(wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT);
317 	while (link) {
318 		/* update the toolbar */
319 		int item_height = 44 + 44 + 16;
320 		if (link->next) item_height += 16;
321 		ro_toolbar_process(link->toolbar, parent_width, false);
322 		extent.y0 = nested_y -
323 				ro_toolbar_height(link->toolbar) -
324 				item_height;
325 		if (link->next) extent.y0 -= 16;
326 		if (extent.y0 > min_extent) extent.y0 = min_extent;
327 		xwimp_set_extent(theme_pane, &extent);
328 
329 		/* create the descriptor icons and separator line */
330 		new_icon.icon.extent.x0 = 8;
331 		new_icon.icon.extent.x1 = parent_width - 8;
332 		new_icon.icon.flags &= ~wimp_ICON_BORDER;
333 		new_icon.icon.flags |= wimp_ICON_SPRITE;
334 		new_icon.icon.extent.y1 = nested_y -
335 				ro_toolbar_height(link->toolbar) - 8;
336 		new_icon.icon.extent.y0 = nested_y -
337 				ro_toolbar_height(link->toolbar) - 52;
338 		new_icon.icon.data.indirected_text_and_sprite.text =
339 			(char *)&link->descriptor->name;
340 		new_icon.icon.data.indirected_text_and_sprite.size =
341 			strlen(link->descriptor->name) + 1;
342 		new_icon.icon.data.indirected_text_and_sprite.validation =
343 				theme_radio_validation;
344 		new_icon.icon.flags |= (wimp_BUTTON_RADIO <<
345 				wimp_ICON_BUTTON_TYPE_SHIFT);
346 		xwimp_create_icon(&new_icon, &link->icon_number);
347 		new_icon.icon.flags &= ~wimp_ICON_SPRITE;
348 		new_icon.icon.extent.x0 = 52;
349 		new_icon.icon.extent.y1 -= 44;
350 		new_icon.icon.extent.y0 -= 44;
351 		new_icon.icon.data.indirected_text.text =
352 			(char *)&link->descriptor->author;
353 		new_icon.icon.data.indirected_text.size =
354 			strlen(link->descriptor->author) + 1;
355 		new_icon.icon.data.indirected_text.validation =
356 				theme_null_validation;
357 		new_icon.icon.flags &= ~(wimp_BUTTON_RADIO <<
358 				wimp_ICON_BUTTON_TYPE_SHIFT);
359 		xwimp_create_icon(&new_icon, 0);
360 		if (link->next) {
361 			new_icon.icon.flags |= wimp_ICON_BORDER;
362 			new_icon.icon.extent.x0 = -8;
363 			new_icon.icon.extent.x1 = parent_width + 8;
364 			new_icon.icon.extent.y1 -= 52;
365 			new_icon.icon.extent.y0 = new_icon.icon.extent.y1 - 8;
366 			new_icon.icon.data.indirected_text.text =
367 					theme_null_validation;
368 			new_icon.icon.data.indirected_text.validation =
369 					theme_line_validation;
370 			new_icon.icon.data.indirected_text.size = 1;
371 			xwimp_create_icon(&new_icon, 0);
372 		}
373 
374 		/* nest the toolbar window */
375 		state.w = ro_toolbar_get_window(link->toolbar);
376 		state.yscroll = 0;
377 		state.visible.y1 = nested_y + base_extent;
378 		state.visible.y0 = state.visible.y1 -
379 				ro_toolbar_height(link->toolbar) + 2;
380 		xwimp_open_window_nested(PTR_WIMP_OPEN(&state), theme_pane,
381 				wimp_CHILD_LINKS_PARENT_WORK_AREA
382 						<< wimp_CHILD_BS_EDGE_SHIFT |
383 				wimp_CHILD_LINKS_PARENT_WORK_AREA
384 						<< wimp_CHILD_TS_EDGE_SHIFT);
385 
386 		/* continue processing */
387 		nested_y -= ro_toolbar_height(link->toolbar) +
388 				item_height;
389 		link = link->next;
390 	}
391 
392 	/* set the icons as radios */
393 	radio_icons = (int *)calloc(theme_count + 1, sizeof(int));
394 	radio_set = radio_icons;
395 	for (link = toolbars; link; link = link->next)
396 		*radio_set++ = link->icon_number;
397 	*radio_set = -1;
398 	ro_gui_wimp_event_register_radio(theme_pane, radio_icons);
399 
400 	/* update our display */
401 	xwimp_force_redraw(theme_pane, 0, -16384, 16384, 16384);
402 }
403 
ro_gui_options_theme_free(void)404 void ro_gui_options_theme_free(void)
405 {
406 	struct toolbar_display *toolbar;
407 	struct toolbar_display *next_toolbar;
408 
409 	/* free all our toolbars */
410 	next_toolbar = toolbars;
411 	while ((toolbar = next_toolbar) != NULL) {
412 		next_toolbar = toolbar->next;
413 		xwimp_delete_icon(theme_pane, toolbar->icon_number);
414 		xwimp_delete_icon(theme_pane, toolbar->icon_number + 1);
415 		if (next_toolbar)
416 			xwimp_delete_icon(theme_pane,
417 					toolbar->icon_number + 2);
418 		ro_toolbar_destroy(toolbar->toolbar);
419 		free(toolbar);
420 	}
421 	toolbars = NULL;
422 
423 	/* close all our themes */
424 	if (theme_list)
425 		ro_gui_theme_close(theme_list, true);
426 	theme_list = NULL;
427 }
428