1 /*
2 * gtkatlantic - the gtk+ monopd client, enjoy network monopoly games
3 *
4 *
5 * Copyright © 2002-2015 Sylvain Rochet
6 *
7 * gtkatlantic is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <gtk/gtk.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <gtk/gtk.h>
31
32 #include <dirent.h>
33
34 #include "global.h"
35 #include "theme.h"
36 #include "parser.h"
37 #include "interface.h"
38 #include "callback.h"
39
40
41 /* refresh themes database */
theme_build_database()42 void theme_build_database() {
43
44 DIR *d;
45 struct dirent *dir;
46 gchar *path, *path2;
47 guint32 i;
48
49 /* first free all the database */
50 for(i = 0; i < MAX_THEMES; i++) {
51
52 if(!data->theme[i].open) continue;
53 theme_del_entry(i);
54 }
55
56 /* user home theme */
57 if (global->path_home) {
58 path = g_strconcat(global->path_home, "/themes", NULL);
59 d = opendir (path);
60
61 if(d) {
62
63 while (1) {
64
65 dir = readdir(d);
66 if(!dir) break;
67
68 if(dir->d_name[0] == '.') continue;
69
70 path2 = g_strconcat(path, "/", dir->d_name, "/", NULL);
71 theme_add_entry(path2);
72 g_free(path2);
73 }
74 closedir (d);
75 }
76 g_free(path);
77 }
78
79 /* global theme */
80 d = opendir (PACKAGE_DATA_DIR "/themes");
81 if (d) {
82
83 while (1) {
84
85 dir = readdir(d);
86 if(!dir) break;
87
88 if(dir->d_name[0] == '.') continue;
89
90 path2 = g_strconcat(PACKAGE_DATA_DIR "/themes/", dir->d_name, "/", NULL);
91 theme_add_entry(path2);
92 g_free(path2);
93 }
94 closedir (d);
95 }
96 }
97
98
theme_get_valid_slot(guint32 * themeslot)99 gboolean theme_get_valid_slot(guint32 *themeslot) {
100
101 guint32 i;
102
103 if(!data) return(FALSE);
104
105 for(i = 0; i < MAX_THEMES; i++)
106 if(!data->theme[i].open) {
107
108 *themeslot = i;
109 return(TRUE);
110 }
111
112 return(FALSE);
113 }
114
115
theme_del_entry(guint32 slot)116 void theme_del_entry(guint32 slot) {
117
118 if(!data->theme[slot].open) return;
119
120 g_free(data->theme[slot].path);
121 g_free(data->theme[slot].path_preview);
122 g_free(data->theme[slot].path_conf);
123
124 g_free(data->theme[slot].name);
125 g_free(data->theme[slot].type);
126 g_free(data->theme[slot].version);
127 g_free(data->theme[slot].author);
128 g_free(data->theme[slot].email);
129
130 data->theme[slot].open = FALSE;
131 }
132
133
theme_add_entry(gchar * path)134 void theme_add_entry(gchar *path) {
135
136 guint32 slot, area = 0;
137 gchar *path2, str[512], *ident;
138 struct stat s;
139 FILE *file;
140 char *ret;
141
142 gchar *name = 0, *type = 0, *version = 0, *author = 0, *email = 0, *preview = 0;
143
144 /* get properties of this theme, name, author, preview file, ... */
145 path2 = g_strconcat(path, "theme.conf", NULL);
146
147 /* detect invalid theme */
148 if(stat(path2, &s) < 0) {
149
150 g_free(path2);
151 return;
152 }
153
154 /* parse general group */
155 file = fopen(path2, "r");
156 if (!file) return;
157
158 for (ret = fgets(str, 512, file); ret && !feof(file); ret = fgets(str, 512, file)) {
159
160 if (str[0] == '[') {
161
162 if(! strncmp(str, "[general]", 9) ) area = THEME_FILE_SECTION_GENERAL;
163 else area = 0;
164 }
165
166 else if(area == THEME_FILE_SECTION_GENERAL) {
167
168 ident = parser_get_identifier(str);
169 if(!ident) continue;
170
171 if(! strcmp(ident, "theme") ) {
172
173 name = parser_get_data(str, "name");
174 type = parser_get_data(str, "type");
175 version = parser_get_data(str, "version");
176
177 } else if(! strcmp(ident, "author") ) {
178
179 author = parser_get_data(str, "name");
180 email = parser_get_data(str, "email");
181
182 } else if(! strcmp(ident, "misc") ) {
183
184 preview = parser_get_data(str, "preview");
185 }
186
187 g_free(ident);
188 }
189 }
190 fclose(file);
191
192
193 /* giving up if theme provide no name or no type */
194 if(!name || !type) return;
195
196
197 /* fill the theme database */
198 if(! theme_get_valid_slot(&slot) ) return;
199
200 data->theme[slot].path = g_strdup(path);
201 data->theme[slot].path_preview = g_strconcat(path, preview, NULL);
202 g_free(preview);
203 data->theme[slot].path_conf = g_strconcat(path, "theme.conf", NULL);
204
205 data->theme[slot].open = TRUE;
206 data->theme[slot].name = name;
207 data->theme[slot].type = type;
208 data->theme[slot].version = version;
209 data->theme[slot].author = author;
210 data->theme[slot].email = email;
211 }
212
213
theme_build_selection_win()214 void theme_build_selection_win() {
215
216 GtkWidget *ThemeWin;
217 GtkWidget *VBox;
218 GtkWidget *HBox;
219 GtkWidget *VBoxLeft;
220 GtkWidget *ScrollThemeList;
221 GtkWidget *ThemeCList;
222 GtkWidget *HBoxButtons;
223 GtkWidget *Button;
224 GtkWidget *VBoxInfo;
225 GtkWidget *GridInfo;
226 GtkWidget *Label;
227 GtkWidget *PreviewFrame;
228
229 GtkWidget *tmp;
230 gchar *str;
231 GtkTreeSelection *select;
232 GtkCellRenderer *renderer;
233 GtkTreeViewColumn *column;
234 GtkListStore *store;
235
236 if(global->ThemeWin) return;
237
238 global->ThemeWin = ThemeWin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
239 gtk_window_set_title(GTK_WINDOW(ThemeWin), "GtkAtlantic: Theme Selection");
240 g_signal_connect(G_OBJECT(ThemeWin), "delete_event", G_CALLBACK(CallBack_ThemeWin_Delete), NULL);
241 g_signal_connect(G_OBJECT(ThemeWin), "destroy", G_CALLBACK(CallBack_ThemeWin_Destroyed), NULL);
242
243 VBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
244 gtk_container_set_border_width(GTK_CONTAINER(VBox), 5);
245 gtk_container_add(GTK_CONTAINER(ThemeWin), VBox);
246
247 HBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
248 gtk_box_pack_start(GTK_BOX(VBox), HBox, TRUE, TRUE, 0);
249
250 VBoxLeft = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
251 gtk_box_pack_start(GTK_BOX(HBox), VBoxLeft, TRUE, TRUE, 0);
252
253 /* theme list */
254 ScrollThemeList = gtk_scrolled_window_new(NULL, NULL);
255 gtk_widget_set_size_request(ScrollThemeList, 140, -1);
256 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrollThemeList), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
257 gtk_box_pack_start(GTK_BOX(VBoxLeft), ScrollThemeList, TRUE, TRUE, 0);
258
259 ThemeCList = gtk_tree_view_new();
260 g_object_set_data(G_OBJECT(ThemeWin), "theme_list", ThemeCList);
261 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ThemeCList), FALSE);
262 gtk_container_add(GTK_CONTAINER(ScrollThemeList), ThemeCList);
263 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(ThemeCList));
264 gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
265 g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(Callback_ThemeList_Select), NULL);
266
267 renderer = gtk_cell_renderer_text_new();
268 column = gtk_tree_view_column_new_with_attributes("Theme", renderer, "text", THEMELIST_COLUMN_NAME, NULL);
269 gtk_tree_view_append_column(GTK_TREE_VIEW(ThemeCList), column);
270
271 store = gtk_list_store_new(TRADEPLAYERLIST_COLUMN_NUM, G_TYPE_STRING, G_TYPE_INT);
272 gtk_tree_view_set_model(GTK_TREE_VIEW(ThemeCList), GTK_TREE_MODEL(store));
273 g_object_unref(store);
274
275 /* hbox for buttons */
276 HBoxButtons = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
277 gtk_box_pack_start(GTK_BOX(VBoxLeft), HBoxButtons, FALSE, FALSE, 0);
278
279 Button = gtk_button_new_with_label("Apply");
280 g_signal_connect(G_OBJECT(Button), "clicked", G_CALLBACK(CallBack_Theme_Apply), NULL);
281 gtk_box_pack_start(GTK_BOX(HBoxButtons), Button, TRUE, TRUE, 0);
282
283 Button = gtk_button_new_with_label("Cancel");
284 g_signal_connect(G_OBJECT(Button), "clicked", G_CALLBACK(CallBack_ThemeWin_Delete), NULL);
285 gtk_box_pack_start(GTK_BOX(HBoxButtons), Button, TRUE, TRUE, 0);
286
287 /* vbox for themes */
288 VBoxInfo = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
289 gtk_box_pack_start(GTK_BOX(HBox), VBoxInfo, TRUE, TRUE, 0);
290
291 /* table which contain theme infos */
292 GridInfo = gtk_grid_new();
293 gtk_grid_set_column_spacing(GTK_GRID(GridInfo), 5);
294 gtk_grid_set_row_spacing(GTK_GRID(GridInfo), 2);
295 gtk_box_pack_start(GTK_BOX(VBoxInfo), GridInfo, FALSE, FALSE, 0);
296
297 Label = gtk_label_new("Name:");
298 gtk_widget_set_halign(Label, GTK_ALIGN_START);
299 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
300 gtk_grid_attach(GTK_GRID(GridInfo), Label, 0, 0, 1, 1);
301
302 Label = gtk_label_new("");
303 gtk_widget_set_halign(Label, GTK_ALIGN_START);
304 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
305 g_object_set_data(G_OBJECT(ThemeWin), "theme_name", Label);
306 gtk_grid_attach(GTK_GRID(GridInfo), Label, 1, 0, 1, 1);
307
308 Label = gtk_label_new("Type:");
309 gtk_widget_set_halign(Label, GTK_ALIGN_START);
310 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
311 gtk_grid_attach(GTK_GRID(GridInfo), Label, 0, 1, 1, 1);
312
313 Label = gtk_label_new("");
314 gtk_widget_set_halign(Label, GTK_ALIGN_START);
315 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
316 g_object_set_data(G_OBJECT(ThemeWin), "theme_type", Label);
317 gtk_grid_attach(GTK_GRID(GridInfo), Label, 1, 1, 1, 1);
318
319 Label = gtk_label_new("Version:");
320 gtk_widget_set_halign(Label, GTK_ALIGN_START);
321 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
322 gtk_grid_attach(GTK_GRID(GridInfo), Label, 0, 2, 1, 1);
323
324 Label = gtk_label_new("");
325 gtk_widget_set_halign(Label, GTK_ALIGN_START);
326 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
327 g_object_set_data(G_OBJECT(ThemeWin), "theme_version", Label);
328 gtk_grid_attach(GTK_GRID(GridInfo), Label, 1, 2, 1, 1);
329
330 Label = gtk_label_new("Author:");
331 gtk_widget_set_halign(Label, GTK_ALIGN_START);
332 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
333 gtk_grid_attach(GTK_GRID(GridInfo), Label, 0, 3, 1, 1);
334
335 Label = gtk_label_new("");
336 gtk_widget_set_halign(Label, GTK_ALIGN_START);
337 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
338 g_object_set_data(G_OBJECT(ThemeWin), "theme_author", Label);
339 gtk_grid_attach(GTK_GRID(GridInfo), Label, 1, 3, 1, 1);
340
341 Label = gtk_label_new("Email:");
342 gtk_widget_set_halign(Label, GTK_ALIGN_START);
343 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
344 gtk_grid_attach(GTK_GRID(GridInfo), Label, 0, 4, 1, 1);
345
346 Label = gtk_label_new("");
347 gtk_widget_set_halign(Label, GTK_ALIGN_START);
348 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
349 g_object_set_data(G_OBJECT(ThemeWin), "theme_email", Label);
350 gtk_grid_attach(GTK_GRID(GridInfo), Label, 1, 4, 1, 1);
351
352 Label = gtk_label_new("Location:");
353 gtk_widget_set_halign(Label, GTK_ALIGN_START);
354 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
355 gtk_grid_attach(GTK_GRID(GridInfo), Label, 0, 5, 1, 1);
356
357 Label = gtk_label_new("");
358 gtk_widget_set_halign(Label, GTK_ALIGN_START);
359 gtk_widget_set_valign(Label, GTK_ALIGN_CENTER);
360 g_object_set_data(G_OBJECT(ThemeWin), "theme_location", Label);
361 gtk_grid_attach(GTK_GRID(GridInfo), Label, 1, 5, 1, 1);
362
363 /* preview */
364 PreviewFrame = gtk_frame_new("Preview");
365 gtk_box_pack_start(GTK_BOX(VBoxInfo), PreviewFrame, TRUE, TRUE, 0);
366 gtk_widget_set_size_request(PreviewFrame, 400, 245);
367 g_object_set_data(G_OBJECT(ThemeWin), "theme_preview_container", PreviewFrame);
368
369 tmp = gtk_label_new("No preview available");
370 gtk_widget_set_halign(tmp, GTK_ALIGN_CENTER);
371 gtk_widget_set_valign(tmp, GTK_ALIGN_CENTER);
372 g_object_set_data(G_OBJECT(ThemeWin), "theme_preview_data", tmp);
373 gtk_container_add(GTK_CONTAINER(PreviewFrame), tmp);
374
375 str = g_strdup_printf("%d", -1);
376 g_object_set_data_full(G_OBJECT(global->ThemeWin), "theme_preview_selected", str, g_free);
377
378 gtk_widget_show_all(ThemeWin);
379 }
380
381
theme_fill_selection_list()382 void theme_fill_selection_list() {
383
384 guint32 i;
385 GtkWidget *ThemeList;
386 GtkListStore *store;
387
388 ThemeList = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_list");
389
390 /* build theme list */
391 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ThemeList)));
392 gtk_list_store_clear(store);
393
394 for(i = 0 ; i < MAX_THEMES ; i++) {
395 GtkTreeIter iter;
396
397 if (!data->theme[i].open) {
398 continue;
399 }
400
401 gtk_list_store_append(store, &iter);
402 gtk_list_store_set(store, &iter,
403 THEMELIST_COLUMN_NAME, data->theme[i].name,
404 THEMELIST_COLUMN_ID, i,
405 -1);
406 }
407 }
408
409
theme_preview_free()410 void theme_preview_free() {
411 GtkWidget *Preview;
412
413 /* free all preview data */
414 Preview = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_preview_data");
415 gtk_widget_destroy(Preview);
416 g_object_set_data(G_OBJECT(global->ThemeWin), "theme_preview_data", NULL);
417 }
418
419
theme_display(gint32 themeid)420 void theme_display(gint32 themeid) {
421
422 GtkWidget *Label;
423 GtkWidget *Frame;
424 GtkWidget *Preview;
425 GdkPixbuf *pixbuf = NULL;
426 gchar *tmp;
427
428 if(! data->theme[themeid].open) return;
429
430 Label = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_name");
431 gtk_label_set_text(GTK_LABEL(Label), data->theme[themeid].name);
432
433 Label = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_type");
434 gtk_label_set_text(GTK_LABEL(Label), data->theme[themeid].type);
435
436 Label = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_version");
437 gtk_label_set_text(GTK_LABEL(Label), data->theme[themeid].version);
438
439 Label = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_author");
440 gtk_label_set_text(GTK_LABEL(Label), data->theme[themeid].author);
441
442 Label = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_email");
443 gtk_label_set_text(GTK_LABEL(Label), data->theme[themeid].email);
444
445 Label = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_location");
446 gtk_label_set_text(GTK_LABEL(Label), data->theme[themeid].path);
447
448 tmp = g_strdup_printf("%d", themeid);
449 g_object_set_data_full(G_OBJECT(global->ThemeWin), "theme_preview_selected", tmp, g_free);
450
451 /* free all preview data */
452 theme_preview_free();
453
454 Frame = g_object_get_data(G_OBJECT(global->ThemeWin), "theme_preview_container");
455
456 /* put new preview data */
457 if(! (pixbuf = theme_preview_read(themeid)) ) {
458
459 Preview = gtk_label_new("No preview available");
460 g_object_set_data(G_OBJECT(global->ThemeWin), "theme_preview_data", Preview);
461 gtk_container_add(GTK_CONTAINER(Frame), Preview);
462 gtk_widget_show_all(Frame);
463 return;
464 }
465
466 /* put preview image */
467 Preview = gtk_image_new_from_pixbuf(pixbuf);
468 gtk_widget_set_halign(Preview, GTK_ALIGN_CENTER);
469 gtk_widget_set_valign(Preview, GTK_ALIGN_CENTER);
470 g_object_set_data(G_OBJECT(global->ThemeWin), "theme_preview_data", Preview);
471 gtk_container_add(GTK_CONTAINER(Frame), Preview);
472 gtk_widget_show_all(Frame);
473 g_object_unref(pixbuf);
474 }
475
476
theme_preview_read(gint32 themeid)477 GdkPixbuf *theme_preview_read(gint32 themeid) {
478 gchar *path = data->theme[themeid].path_preview;
479 GdkPixbuf *pixbuf = NULL;
480 GError *err = NULL;
481
482 if (!data->theme[themeid].open) return NULL;
483 if (path == NULL) return NULL;
484
485 /* load preview image */
486 pixbuf = gdk_pixbuf_new_from_file(path, &err);
487 if (!pixbuf) {
488 fprintf(stderr, "error while loading %s: %s\n", path, err ? err->message : "(unknown)");
489 g_error_free(err);
490 }
491 return pixbuf;
492 }
493
494
theme_load(gint32 themeid)495 void theme_load(gint32 themeid) {
496
497 printf("%d\n", themeid);
498 return;
499 }
500