1 /* Bluefish HTML Editor
2 * html2.c - menu/toolbar callbacks, inserting functions, and other cool stuff
3 * otherwise html.c is getting so long ;-)
4 *
5 * Copyright (C) 1999-2012 Olivier Sessink
6 *
7 * This program 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 3 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. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /* #define DEBUG */
22
23 #include <gtk/gtk.h>
24 #include <string.h> /* strlen() */
25 #include <stdlib.h> /* strtol() */
26
27 #include "htmlbar.h"
28 #include "htmlbar_stock_icons.h"
29 #include "html2.h"
30 #include "cap.h"
31 #include "../bf_lib.h" /* string_is_color(), strip_any_whitespace()*/
32 #include "../dialog_utils.h"
33 #include "../document.h"
34 #include "../gtk_easy.h"
35 #include "../stringlist.h"
36
glist_with_html_tags(gint use_html5)37 static GList *glist_with_html_tags(gint use_html5) {
38 GList *tmplist = NULL;
39
40 tmplist = g_list_prepend(tmplist, "var");
41 tmplist = g_list_prepend(tmplist, "ul");
42 tmplist = g_list_prepend(tmplist, "tr");
43 tmplist = g_list_prepend(tmplist, "title");
44 tmplist = g_list_prepend(tmplist, "thead");
45 tmplist = g_list_prepend(tmplist, "th");
46 tmplist = g_list_prepend(tmplist, "tfoot");
47 tmplist = g_list_prepend(tmplist, "textarea");
48 tmplist = g_list_prepend(tmplist, "td");
49 tmplist = g_list_prepend(tmplist, "tbody");
50 tmplist = g_list_prepend(tmplist, "table");
51 tmplist = g_list_prepend(tmplist, "sup");
52 tmplist = g_list_prepend(tmplist, "sub");
53 tmplist = g_list_prepend(tmplist, "style");
54 tmplist = g_list_prepend(tmplist, "strong");
55 tmplist = g_list_prepend(tmplist, "span");
56 tmplist = g_list_prepend(tmplist, "small");
57 tmplist = g_list_prepend(tmplist, "select");
58 tmplist = g_list_prepend(tmplist, "script");
59 tmplist = g_list_prepend(tmplist, "samp");
60 tmplist = g_list_prepend(tmplist, "q");
61 tmplist = g_list_prepend(tmplist, "pre");
62 tmplist = g_list_prepend(tmplist, "param");
63 tmplist = g_list_prepend(tmplist, "p");
64 tmplist = g_list_prepend(tmplist, "option");
65 tmplist = g_list_prepend(tmplist, "optgroup");
66 tmplist = g_list_prepend(tmplist, "ol");
67 tmplist = g_list_prepend(tmplist, "object");
68 tmplist = g_list_prepend(tmplist, "noscript");
69 tmplist = g_list_prepend(tmplist, "meta");
70 tmplist = g_list_prepend(tmplist, "map");
71 tmplist = g_list_prepend(tmplist, "link");
72 tmplist = g_list_prepend(tmplist, "li");
73 tmplist = g_list_prepend(tmplist, "legend");
74 tmplist = g_list_prepend(tmplist, "label");
75 tmplist = g_list_prepend(tmplist, "kbd");
76 tmplist = g_list_prepend(tmplist, "ins");
77 tmplist = g_list_prepend(tmplist, "input");
78 tmplist = g_list_prepend(tmplist, "img");
79 tmplist = g_list_prepend(tmplist, "iframe");
80 tmplist = g_list_prepend(tmplist, "i");
81 tmplist = g_list_prepend(tmplist, "html");
82 tmplist = g_list_prepend(tmplist, "hr");
83 tmplist = g_list_prepend(tmplist, "head");
84 tmplist = g_list_prepend(tmplist, "h6");
85 tmplist = g_list_prepend(tmplist, "h5");
86 tmplist = g_list_prepend(tmplist, "h4");
87 tmplist = g_list_prepend(tmplist, "h3");
88 tmplist = g_list_prepend(tmplist, "h2");
89 tmplist = g_list_prepend(tmplist, "h1");
90 tmplist = g_list_prepend(tmplist, "form");
91 tmplist = g_list_prepend(tmplist, "fieldset");
92 tmplist = g_list_prepend(tmplist, "em");
93 tmplist = g_list_prepend(tmplist, "dt");
94 tmplist = g_list_prepend(tmplist, "dl");
95 tmplist = g_list_prepend(tmplist, "div");
96 tmplist = g_list_prepend(tmplist, "dfn");
97 tmplist = g_list_prepend(tmplist, "del");
98 tmplist = g_list_prepend(tmplist, "dd");
99 tmplist = g_list_prepend(tmplist, "colgroup");
100 tmplist = g_list_prepend(tmplist, "col");
101 tmplist = g_list_prepend(tmplist, "code");
102 tmplist = g_list_prepend(tmplist, "cite");
103 tmplist = g_list_prepend(tmplist, "caption");
104 tmplist = g_list_prepend(tmplist, "button");
105 tmplist = g_list_prepend(tmplist, "br");
106 tmplist = g_list_prepend(tmplist, "body");
107 tmplist = g_list_prepend(tmplist, "blockquote");
108 tmplist = g_list_prepend(tmplist, "bdo");
109 tmplist = g_list_prepend(tmplist, "base");
110 tmplist = g_list_prepend(tmplist, "b");
111 tmplist = g_list_prepend(tmplist, "area");
112 tmplist = g_list_prepend(tmplist, "address");
113 tmplist = g_list_prepend(tmplist, "abbr");
114 tmplist = g_list_prepend(tmplist, "a");
115 tmplist = g_list_prepend(tmplist, "");
116 if (use_html5) {
117 tmplist = g_list_prepend(tmplist, "wbr");
118 tmplist = g_list_prepend(tmplist, "video");
119 tmplist = g_list_prepend(tmplist, "u");
120 tmplist = g_list_prepend(tmplist, "track");
121 tmplist = g_list_prepend(tmplist, "time");
122 tmplist = g_list_prepend(tmplist, "summary");
123 tmplist = g_list_prepend(tmplist, "source");
124 tmplist = g_list_prepend(tmplist, "section");
125 tmplist = g_list_prepend(tmplist, "s");
126 tmplist = g_list_prepend(tmplist, "ruby");
127 tmplist = g_list_prepend(tmplist, "rt");
128 tmplist = g_list_prepend(tmplist, "rp");
129 tmplist = g_list_prepend(tmplist, "progress");
130 tmplist = g_list_prepend(tmplist, "output");
131 tmplist = g_list_prepend(tmplist, "nav");
132 tmplist = g_list_prepend(tmplist, "meter");
133 tmplist = g_list_prepend(tmplist, "menu");
134 tmplist = g_list_prepend(tmplist, "mark");
135 tmplist = g_list_prepend(tmplist, "keygen");
136 tmplist = g_list_prepend(tmplist, "hgroup");
137 tmplist = g_list_prepend(tmplist, "header");
138 tmplist = g_list_prepend(tmplist, "footer");
139 tmplist = g_list_prepend(tmplist, "figure");
140 tmplist = g_list_prepend(tmplist, "figcaption");
141 tmplist = g_list_prepend(tmplist, "embed");
142 tmplist = g_list_prepend(tmplist, "details");
143 tmplist = g_list_prepend(tmplist, "datalist");
144 tmplist = g_list_prepend(tmplist, "command");
145 tmplist = g_list_prepend(tmplist, "canvas");
146 tmplist = g_list_prepend(tmplist, "bdi");
147 tmplist = g_list_prepend(tmplist, "audio");
148 tmplist = g_list_prepend(tmplist, "aside");
149 tmplist = g_list_prepend(tmplist, "article");
150 }
151 else {
152 tmplist = g_list_prepend(tmplist, "tt");
153 tmplist = g_list_prepend(tmplist, "noframes");
154 tmplist = g_list_prepend(tmplist, "frameset");
155 tmplist = g_list_prepend(tmplist, "frame");
156 tmplist = g_list_prepend(tmplist, "big");
157 tmplist = g_list_prepend(tmplist, "acronym");
158 }
159 return tmplist;
160 }
161
162 typedef enum {entry, textbox, wizard} Tdest_type;
163 typedef enum {onestyle, multistyle} Tcs3_style;
164 typedef enum {but_none, but_file, but_style, but_color} Textra_button;
165 typedef struct {
166 Tdest_type dest_type;
167 GtkWidget *entry;
168 Tdocument *doc;
169 gint doc_start;
170 gint doc_end;
171 } Tcs3_destination;
172
173 typedef struct {
174 GtkWidget *win;
175 Tcs3_destination dest;
176 Tcs3_style styletype;
177 /*GtkWidget *clist;*/
178 GtkListStore *lstore;
179 GtkWidget *lview;
180 gint selected_row;
181 gboolean grab;
182 GtkWidget *selector;
183 GtkWidget *html5;
184 GtkWidget *property;
185 GtkWidget *value;
186 GtkWidget *rule_add_but;
187 GtkWidget *rule_update_but;
188 GtkWidget *extra_but;
189 } Tcs3_diag;
190
191 typedef struct {
192 GtkWidget *win;
193 GtkWidget *selector;
194 GtkWidget *html5;
195 GtkWidget *property;
196 GtkWidget *value;
197 GtkWidget *extra_but;
198 gint whichrow;
199 Tcs3_diag *diag;
200 } Tcs3_pd_diag;
201
202 typedef struct {
203 gchar *property; /* the name of the property */
204 gchar **possibilities; /* a list of possibilities */
205 gint force_pos; /* force the possibility to be one of the options in possibilities */
206 Textra_button buttype;
207 } Tcs3_arr;
208
209 static gchar *cs3_colors[] = {"aqua", "black", "blue", "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive", "orange", "purple", "red", "silver", "teal", "white", "yellow", NULL};
210 static gchar *cs3_repeat[] = {"repeat", "repeat-x", "repeat-y", "no-repeat", NULL};
211 static gchar *cs3_fonts[] = {"arial, helvetica, sans-serif", "roman, 'times new roman', times, serif", "courier, fixed, monospace", "western, fantasy", "Zapf-Chancery, cursive", "serif", "sans-serif", "cursive", "fantasy", "monospace", NULL};
212 //static gchar *cs3_font_size_adjustments[] = {"0.58", "none", "inherit", NULL};
213 //static gchar *cs3_font_stretches[] = {"normal","wider","narrower","ultra-condensed","extra-condensed","condensed","semi-condensed","semi-expanded","expanded","extra-expanded","ultra-expanded", NULL};
214 static gchar *cs3_font_styles[] = {"normal", "italic", "oblique", NULL};
215 static gchar *cs3_font_variants[] = {"normal", "small-caps", NULL};
216 static gchar *cs3_font_weights[] = {"normal", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", NULL};
217 static gchar *cs3_background_attachments[] = {"scroll", "fixed", NULL};
218 static gchar *cs3_background_positions[] = {"top", "center", "bottom", "left", "center", "right", "10% 10%", NULL}; /* more 2 add */
219 static gchar *cs3_text_decorations[] = {"none", "underline", "overline", "line-through", "blink", NULL};
220 static gchar *cs3_text_transforms[] = {"none", "capitalize", "uppercase", "lowercase", NULL};
221 static gchar *cs3_text_aligns[] = {"left", "right", "center", "justify", NULL};
222 static gchar *cs3_border_styles[] = {"none", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset", NULL};
223 static gchar *cs3_floats[] = {"left", "right", "none", NULL};
224 static gchar *cs3_positions[] = {"static", "relative", "absolute", "fixed", NULL};
225 static gchar *cs3_clears[] = {"left", "right", "none", "both", NULL};
226 static gchar *cs3_displays[] = {"block", "inline", "list-item", "run-in", "compact", "marker", "table", "inline-table", "table-row-group", "table-header-group", "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "none",NULL};
227 static gchar *cs3_whitespaces[] = {"normal", "pre", "nowrap", NULL};
228 static gchar *cs3_list_style_types[] = {"disc", "circle", "square", "decimal", "lower-roman", "upper-roman", "lower-alpha", "upper-alpha", "none", NULL};
229 static gchar *cs3_list_style_positions[] = {"inside", "outside", NULL};
230 static gchar *cs3_zindices[] = {"auto", NULL};
231 static gchar *cs3_directions[] = {"ltr", "rtl", NULL};
232 static gchar *cs3_unicodebidis[] = {"normal", "embed", "bidi-override", NULL};
233 static gchar *cs3_vertical_aligns[] = {"baseline", "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom", NULL};
234 static gchar *cs3_overflows[] = {"visible", "hidden", "scroll", "auto", NULL};
235 static gchar *cs3_visibilities[] = {"visible", "hidden", "collapse", NULL};
236 static gchar *cs3_none[] = {"none", NULL};
237 static gchar *cs3_caption_sides[] = {"top", "bottom", "left", "right", NULL};
238 static gchar *cs3_table_layouts[] = {"auto", "fixed", NULL};
239 static gchar *cs3_border_collapses[] = {"collapse", "separate", NULL};
240 static gchar *cs3_empty_cells[] = {"show", "hide", NULL};
241 static gchar *cs3_content[] = {"normal", "none", "url()", "counter()", "counters()", "attr()",
242 "open-quote","close-quote", "no-open-quote", "no-close-quote", "inherit", NULL};
243 static gchar *cs3_cursor[] = {"url()", "auto", "crosshair", "default", "help", "move",
244 "pointer ", "progress", "text", "wait", "e-resize", "ne-resize", "nw-resize", "n-resize",
245 "se-resize", "sw-resize", "s-resize", "w-resize", NULL};
246 static gchar *cs3_width[] = {"thin", "medium", "thick", NULL};
247
248 static Tcs3_arr cs3_arr[] = {
249 {"font-family", cs3_fonts, 0, but_none},
250 //{"font-stretch", cs3_font_stretches, 0, but_none},
251 // None of the major browsers support the font-stretch property.
252 {"font-style", cs3_font_styles, 1, but_none},
253 {"font-variant", cs3_font_variants, 1, but_none},
254 {"font-weight", cs3_font_weights, 1, but_none},
255 {"font-size", NULL, 0, but_none},
256 // {"font-size-adjust", cs3_font_size_adjustments, 0, but_none},
257 // Gecko only
258 {"font", NULL, 0, but_none},
259 {"color", cs3_colors, 0, but_color},
260 {"background-color", cs3_colors, 0, but_color},
261 {"background-image", NULL, 0, but_file},// <uri> | none | inherit url("images/bg.png")
262 {"background-repeat", cs3_repeat, 0, but_none},
263 {"background-attachment",cs3_background_attachments , 1, but_none},
264 {"background-position",cs3_background_positions , 0, but_none},
265 {"background", NULL, 0, but_none},
266 {"word-spacing", NULL, 0, but_none},
267 {"letter-spacing", NULL, 0, but_none},
268 {"text-decoration", cs3_text_decorations, 1, but_none},
269 {"text-transform", cs3_text_transforms, 1, but_none},
270 {"text-align", cs3_text_aligns, 1, but_none},
271 {"text-indent", NULL, 0, but_none},
272 {"text-shadow", cs3_none, 0, but_none},
273 {"line-height", NULL, 0, but_none},
274 {"margin-top", NULL, 0, but_none},
275 {"margin-right", NULL, 0, but_none},
276 {"margin-bottom", NULL, 0, but_none},
277 {"margin-left", NULL, 0, but_none},
278 {"margin", NULL, 0, but_none},
279 {"padding-top", NULL, 0, but_none},
280 {"padding-right", NULL, 0, but_none},
281 {"padding-bottom", NULL, 0, but_none},
282 {"padding-left", NULL, 0, but_none},
283 {"padding", NULL, 0, but_none},
284 {"border-top-width", NULL, 0, but_none},
285 {"border-right-width", NULL, 0, but_none},
286 {"border-bottom-width", NULL, 0, but_none},
287 {"border-left-width", NULL, 0, but_none},
288 {"border-width", NULL, 0, but_none},
289 {"border-top-color", cs3_colors, 0, but_color},
290 {"border-right-color", cs3_colors, 0, but_color},
291 {"border-bottom-color", cs3_colors, 0, but_color},
292 {"border-left-color", cs3_colors, 0, but_color},
293 {"border-color", cs3_colors, 0, but_color},
294 {"border-top-style", cs3_border_styles, 1, but_none},
295 {"border-right-style", cs3_border_styles, 1, but_none},
296 {"border-bottom-style", cs3_border_styles, 1, but_none},
297 {"border-left-style", cs3_border_styles, 1, but_none},
298 {"border-style", cs3_border_styles, 1, but_none},
299 {"border-top", NULL, 0, but_none},
300 {"border-right", NULL, 0, but_none},
301 {"border-bottom", NULL, 0, but_none},
302 {"border-left", NULL, 0, but_none},
303 {"border", NULL, 0, but_none},
304 {"width", NULL, 0, but_none},
305 {"height", NULL, 0, but_none},
306 {"float", cs3_floats, 1, but_none},
307 {"position", cs3_positions, 1, but_none},
308 {"top", NULL, 0, but_none},
309 {"right", NULL, 0, but_none},
310 {"bottom", NULL, 0, but_none},
311 {"left", NULL, 0, but_none},
312 {"clear", cs3_clears, 1, but_none},
313 {"display", cs3_displays, 1, but_none},
314 {"direction", cs3_directions, 1, but_none},
315 {"unicode-bidi", cs3_unicodebidis, 1, but_none},
316 {"z-index", cs3_zindices, 0, but_none},
317 {"min-width", NULL, 0, but_none},
318 {"max-width", NULL, 0, but_none},
319 {"min-height", NULL, 0, but_none},
320 {"max-height", NULL, 0, but_none},
321 {"line-height", NULL, 0, but_none},
322 {"white-space", cs3_whitespaces, 1, but_none},
323 {"list-style", NULL, 0, but_none},
324 {"list-style-type", cs3_list_style_types, 1, but_none},
325 {"list-style-image", NULL, 0, but_none},
326 {"list-style-position", cs3_list_style_positions, 1, but_none},
327 {"vertical-align", cs3_vertical_aligns, 0, but_none},
328 {"overflow", cs3_overflows, 0, but_none},
329 {"clip", cs3_zindices, 0, but_none},
330 {"visibility", cs3_visibilities, 0, but_none},
331 {"caption-side", cs3_caption_sides, 1, but_none},
332 {"table-layout", cs3_table_layouts, 1, but_none},
333 {"border-collapse", cs3_border_collapses, 1, but_none},
334 {"border-spacing", NULL, 0, but_none},
335 {"empty-cells", cs3_empty_cells, 1, but_none},
336 {"content", cs3_content, 0, but_none},
337 {"counter-increment", NULL, 0, but_none},
338 {"counter-reset", NULL, 0, but_none},
339 {"cursor", cs3_cursor, 0, but_none},
340 {"opacity", NULL, 0, but_none},
341 {"outline", NULL, 0, but_none},
342 {"outline-color", cs3_colors, 0, but_color},
343 {"outline-style", cs3_border_styles, 0, but_none},
344 {"outline-width", cs3_width, 0, but_none},
345 {"quotes", NULL, 0, but_none},
346 {NULL, NULL, 0, but_none}
347 };
348
349
cs3_arr_from_property(gchar * prop)350 static Tcs3_arr *cs3_arr_from_property(gchar *prop) {
351 Tcs3_arr tmp;
352 gint count=0;
353
354 if (!prop) {
355 return NULL;
356 }
357 tmp = cs3_arr[count];
358 while (tmp.property) {
359 if (strcmp(tmp.property, prop) ==0) {
360 return &cs3_arr[count];
361 }
362 count++;
363 tmp = cs3_arr[count];
364 }
365 return NULL;
366 }
367
368 /* the list should be freed, the contents of the list should NOT */
pointer_arr2glist(gchar ** arr)369 static GList *pointer_arr2glist(gchar **arr) {
370 gchar **tmp;
371 GList *retlist = NULL;
372
373 if (!arr) {
374 return NULL;
375 }
376 tmp = arr;
377 while (*tmp) {
378 retlist = g_list_append(retlist, *tmp);
379 tmp++;
380 }
381 return retlist;
382 }
383
cs3d_destroy_lcb(GtkWidget * widget,Tcs3_diag * diag)384 static void cs3d_destroy_lcb(GtkWidget * widget, Tcs3_diag *diag) {
385 window_destroy(diag->win);
386 g_slice_free(Tcs3_diag, diag);
387 }
388
cs3d_cancel_clicked_lcb(GtkWidget * widget,Tcs3_diag * diag)389 static void cs3d_cancel_clicked_lcb(GtkWidget * widget, Tcs3_diag *diag) {
390 cs3d_destroy_lcb(NULL, diag);
391 }
392
cs3d_ok_clicked_lcb(GtkWidget * widget,Tcs3_diag * diag)393 static void cs3d_ok_clicked_lcb(GtkWidget * widget, Tcs3_diag *diag) {
394 Tcs3_destination dest = diag->dest;
395 GtkTreeIter iter;
396 GString *retstr;
397 retstr = g_string_new("");
398
399 if (diag->styletype == onestyle) {
400 gboolean retval = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(diag->lstore), &iter);
401 while (retval) {
402 gchar *text[3];
403 gtk_tree_model_get(GTK_TREE_MODEL(diag->lstore), &iter, 1, &text[1], 2, &text[2], -1);
404 retstr = g_string_append(retstr, text[1]);
405 retstr = g_string_append(retstr, ": ");
406 retstr = g_string_append(retstr, text[2]);
407 retstr = g_string_append(retstr, "; ");
408 retval = gtk_tree_model_iter_next(GTK_TREE_MODEL(diag->lstore), &iter);
409 }
410 } else { /* multistyle */
411 gchar *prev_selector = NULL;
412 gboolean retval = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(diag->lstore), &iter);
413 while (retval) {
414 gchar *text[3];
415 gtk_tree_model_get(GTK_TREE_MODEL(diag->lstore), &iter, 0, &text[0], 1, &text[1], 2, &text[2], -1);
416 if (!prev_selector) {
417 prev_selector = g_strdup(text[0]);
418 retstr = g_string_append(retstr, text[0]);
419 retstr = g_string_append(retstr, " {\n");
420 } else if (g_strcmp0(prev_selector, text[0]) != 0 ) {
421 retstr = g_string_append(retstr, "}\n");
422 retstr = g_string_append(retstr, text[0]);
423 retstr = g_string_append(retstr, " {\n");
424 g_free(prev_selector);
425 prev_selector = g_strdup(text[0]);
426 }
427 retstr = g_string_append(retstr, "\t");
428 retstr = g_string_append(retstr, text[1]);
429 retstr = g_string_append(retstr, ": ");
430 retstr = g_string_append(retstr, text[2]);
431 retstr = g_string_append(retstr, ";\n");
432 retval = gtk_tree_model_iter_next(GTK_TREE_MODEL(diag->lstore), &iter);
433 }
434 g_free(prev_selector);
435 /* only append '}\n' in case there is content */
436 if (retstr->len > 0) {
437 retstr = g_string_append(retstr, "}\n");
438 }
439 }
440
441 if (retstr->len > 0) {
442 if (dest.dest_type == entry) {
443 DEBUG_MSG("cs3d_ok_clicked_lcb, entry? %p\n", dest.entry);
444 if (dest.entry && GTK_IS_WIDGET(dest.entry)) {
445 DEBUG_MSG("cs3d_ok_clicked_lcb, entry!\n");
446 gtk_entry_set_text(GTK_ENTRY(dest.entry), retstr->str);
447 }
448 } else if (dest.dest_type == textbox) {
449 if (dest.doc) {
450 DEBUG_MSG("cs3d_ok_clicked_lcb, textbox!\n");
451 if (dest.doc_start != -1 || dest.doc_end != -1) {
452 doc_replace_text(dest.doc, retstr->str, dest.doc_start, dest.doc_end);
453 } else {
454 doc_insert_two_strings(dest.doc, retstr->str, NULL);
455 }
456 }
457 } else if (dest.dest_type == wizard) {
458 GtkTextBuffer *buf;
459 buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(dest.entry));
460 gtk_text_buffer_set_text(buf, retstr->str, -1);
461 } else {
462 #ifdef DEVELOPMENT
463 g_print("cs3d_ok_clicked_lcb, an unknown dest type, this should never happen!\n");
464 #endif
465 }
466 }
467 g_string_free(retstr, TRUE);
468 cs3d_destroy_lcb(NULL, diag);
469 }
470
cs3d_selection_changed_cb(GtkTreeSelection * selection,gpointer data)471 static void cs3d_selection_changed_cb(GtkTreeSelection *selection, gpointer data)
472 {
473 Tcs3_diag *diag = data;
474 GtkTreeIter iter;
475 GtkTreeModel *model;
476 gchar *text[3] = {NULL, NULL, NULL};
477 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
478 gint *indices;
479 GtkTreePath *path;
480 gtk_tree_model_get(model, &iter, 0, &text[0], 1, &text[1], 2, &text[2], -1);
481
482 /* now set the diag->selected_row !!!!!!!!!!!!!!!!!!! */
483 path = gtk_tree_model_get_path(model, &iter);
484 indices = gtk_tree_path_get_indices(path);
485 DEBUG_MSG("cs3d_selection_changed_cb, selected row=%d\n",indices[0]);
486 diag->selected_row = indices[0];
487 gtk_tree_path_free(path);
488 }
489 if (diag->styletype == multistyle) {
490 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(diag->selector))), text[0]?text[0]:"");
491 }
492 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(diag->property))), text[1]?text[1]:"");
493 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(diag->value))), text[2]?text[2]:"");
494
495
496 }
497
add_to_row(Tcs3_diag * diag,gint whichrow)498 static void add_to_row(Tcs3_diag *diag, gint whichrow) {
499 gchar *text[3] = {NULL, NULL, NULL};
500 gboolean correct=TRUE;
501 gint count=1;
502 if (diag->styletype == multistyle) {
503 text[0] = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(diag->selector))), 0, -1);
504 count=0;
505 }
506 text[1] = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(diag->property))), 0, -1);
507 text[2] = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(diag->value))), 0, -1);
508
509 while (count < 3) {
510 if (strlen(text[count]) == 0) {
511 DEBUG_MSG("add_to_row, %s:%s:%s: %d %s is incorrect, will not add\n",text[0],text[1], text[2], count, text[count]);
512 correct = FALSE;
513 break;
514 }
515 count++;
516 }
517 if (correct) {
518 GtkTreeIter iter;
519 if (whichrow == -1) {
520 gtk_list_store_append(GTK_LIST_STORE(diag->lstore),&iter);
521 } else {
522 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(diag->lstore),&iter,NULL,whichrow);
523 }
524 gtk_list_store_set(GTK_LIST_STORE(diag->lstore), &iter, 0, text[0], 1, text[1], 2, text[2], -1);
525 }
526 g_free(text[0]);
527 g_free(text[1]);
528 g_free(text[2]);
529 }
530
cs3d_add_clicked_lcb(GtkWidget * widget,Tcs3_diag * diag)531 static void cs3d_add_clicked_lcb(GtkWidget * widget, Tcs3_diag *diag) {
532 add_to_row(diag, -1);
533 }
534
cs3d_del_clicked_lcb(GtkWidget * widget,Tcs3_diag * diag)535 static void cs3d_del_clicked_lcb(GtkWidget * widget, Tcs3_diag *diag) {
536 if (diag->selected_row != -1) {
537 GtkTreeIter iter;
538 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(diag->lstore),&iter,NULL,diag->selected_row);
539 gtk_list_store_remove(GTK_LIST_STORE(diag->lstore),&iter);
540 /*gtk_clist_remove(GTK_CLIST(diag->clist), diag->selected_row);*/
541 diag->selected_row = -1;
542 }
543 }
544
cs3d_update_clicked_lcb(GtkWidget * widget,Tcs3_diag * diag)545 static void cs3d_update_clicked_lcb(GtkWidget * widget, Tcs3_diag *diag) {
546 if (diag->selected_row != -1) {
547 DEBUG_MSG("cs3d_update_clicked_lcb, updating row=%d\n", diag->selected_row);
548 add_to_row(diag, diag->selected_row);
549 }
550 }
551
cs3d_html5_clicked_lcb(GtkWidget * widget,Tcs3_diag * diag)552 static void cs3d_html5_clicked_lcb(GtkWidget * widget, Tcs3_diag *diag) {
553 GList *tmplist, *list;
554 list = glist_with_html_tags(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(diag->html5)));
555 #if GTK_CHECK_VERSION(3,0,0)
556 gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(diag->selector));
557 #else
558 GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(diag->selector)));
559 gtk_list_store_clear(store);
560 #endif
561 for (tmplist=g_list_first(list);tmplist;tmplist=g_list_next(tmplist)) {
562 if (tmplist->data) {
563 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(diag->selector),tmplist->data);
564 }
565 }
566 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(diag->selector))), "");
567 g_list_free(list);
568 g_list_free(tmplist);
569 tmplist = NULL;
570 }
571
cs3d_prop_activate_lcb(GtkWidget * widget,Tcs3_diag * diag)572 static void cs3d_prop_activate_lcb(GtkWidget * widget, Tcs3_diag *diag) {
573 Tcs3_arr *tmp;
574 gchar *tmpstr;
575
576 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(diag->value))), "");
577 #if GTK_CHECK_VERSION(3,0,0)
578 gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(diag->value));
579 #else
580 GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(diag->value)));
581 gtk_list_store_clear(store);
582 #endif
583 tmpstr = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(diag->property))), 0, -1);
584 tmp = cs3_arr_from_property(tmpstr);
585 g_free(tmpstr);
586 if (tmp) {
587 GList *list, *tmplist;
588 list = pointer_arr2glist(tmp->possibilities);
589 if (list) {
590 gchar *tmpstr2=NULL;
591 if (!tmp->force_pos) {
592 tmpstr2 = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(diag->value))), 0, -1);
593 }
594
595 for (tmplist=g_list_first(list);tmplist;tmplist=g_list_next(tmplist)) {
596 if (tmplist->data) {
597 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(diag->value),tmplist->data);
598 }
599 }
600 g_list_free(list);
601 if (tmpstr2) {
602 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(diag->value))), tmpstr2);
603 g_free(tmpstr2);
604 }
605 switch(tmp->buttype) {
606 case but_color:
607 gtk_widget_set_sensitive(diag->extra_but, TRUE);
608 break;
609 default:
610 gtk_widget_set_sensitive(diag->extra_but, FALSE);
611 break;
612 }
613 } else {
614 gtk_widget_set_sensitive(diag->extra_but, FALSE);
615 }
616 gtk_editable_set_editable(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(diag->value))), !tmp->force_pos);
617 } else {
618 gtk_widget_set_sensitive(diag->extra_but, FALSE);
619 }
620 }
621
css_diag(Tcs3_destination dest,Tcs3_style style,GtkWidget * transient_win,gboolean grab)622 static Tcs3_diag *css_diag(Tcs3_destination dest, Tcs3_style style, GtkWidget *transient_win, gboolean grab) {
623
624 Tcs3_diag *diag;
625 GtkWidget *scrolwin, *table, *but, *vbox, *hbox, *vbox2;
626 GList *tmplist = NULL;
627 Tcs3_arr tmp;
628 gint count=0;
629 GtkTreeSelection *selection;
630 GtkCellRenderer *renderer;
631 GtkTreeViewColumn *column;
632
633 diag = g_slice_new(Tcs3_diag);
634 diag->win = window_full2(_("Cascading Style Sheet Builder"), GTK_WIN_POS_CENTER_ON_PARENT,
635 12, G_CALLBACK(cs3d_destroy_lcb), diag, TRUE, transient_win);
636 gtk_window_set_role(GTK_WINDOW(diag->win), "css");
637 diag->dest = dest;
638 diag->styletype = style;
639 diag->grab = grab;
640 diag->selected_row = -1;
641
642 vbox = gtk_vbox_new(FALSE, 0);
643 gtk_container_add(GTK_CONTAINER(diag->win),vbox);
644
645 table = gtk_table_new(3, 6, TRUE);
646 gtk_table_set_row_spacings(GTK_TABLE(table), 12);
647 gtk_table_set_col_spacings(GTK_TABLE(table), 12);
648 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
649 tmplist = NULL;
650
651 if (diag->styletype == multistyle) {
652 tmplist = glist_with_html_tags(0);
653 diag->selector = combobox_with_popdown("", tmplist,1);
654 dialog_mnemonic_label_in_table(_("_Selector(s):"), diag->selector, table, 0, 1, 0, 1);
655 gtk_table_attach_defaults(GTK_TABLE(table), diag->selector, 1 ,5 , 0, 1);
656 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(diag->selector), 5);
657 gtk_combo_box_set_add_tearoffs(GTK_COMBO_BOX(diag->selector), 1);
658
659 diag->html5 = gtk_check_button_new_with_mnemonic("_html 5");
660 gtk_table_attach_defaults(GTK_TABLE(table), diag->html5, 5,6, 0,1);
661 g_signal_connect(diag->html5, "clicked", G_CALLBACK(cs3d_html5_clicked_lcb), diag);
662
663 g_list_free(tmplist);
664 tmplist = NULL;
665 }
666
667 tmp = cs3_arr[count];
668 while (tmp.property) {
669 tmplist = g_list_append(tmplist, tmp.property);
670 count++;
671 tmp = cs3_arr[count];
672 }
673 diag->property = combobox_with_popdown("", tmplist,1);
674 g_list_free(tmplist);
675 tmplist = NULL;
676 g_signal_connect(gtk_bin_get_child(GTK_BIN(diag->property)), "activate", G_CALLBACK(cs3d_prop_activate_lcb), diag);
677 g_signal_connect(gtk_bin_get_child(GTK_BIN(diag->property)), "changed", G_CALLBACK(cs3d_prop_activate_lcb), diag);
678
679 diag->value = combobox_with_popdown("", tmplist,1);
680 dialog_mnemonic_label_in_table(_("_Property:"), diag->property, table, 0, 1, 1, 2);
681 gtk_table_attach_defaults(GTK_TABLE(table), diag->property, 1, 5, 1, 2);
682 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(diag->property), 4);
683 gtk_combo_box_set_add_tearoffs(GTK_COMBO_BOX(diag->property), 1);
684 dialog_mnemonic_label_in_table(_("_Value:"), diag->value, table, 0, 1, 2, 3);
685 gtk_table_attach_defaults(GTK_TABLE(table), diag->value, 1, 4, 2, 3);
686
687
688 gtk_widget_realize(diag->win);
689
690
691 diag->extra_but = color_but_new(GTK_WIDGET(gtk_bin_get_child(GTK_BIN(diag->value))), diag->win);
692 gtk_table_attach(GTK_TABLE(table), diag->extra_but, 4, 5, 2, 3, GTK_EXPAND, GTK_EXPAND, 0, 0);
693
694 /* the list widget and the buttons are in a horizontal box */
695 hbox = gtk_hbox_new(FALSE, 12);
696 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 18);
697
698 diag->lstore = gtk_list_store_new(3, G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING);
699 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(diag->lstore),0,GTK_SORT_ASCENDING);
700 diag->lview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(diag->lstore));
701 g_object_unref(G_OBJECT(diag->lstore));
702 if (diag->styletype == multistyle) {
703 renderer = gtk_cell_renderer_text_new();
704 column = gtk_tree_view_column_new_with_attributes (_("Selector(s)"),renderer,"text", 0,NULL);
705 gtk_tree_view_append_column(GTK_TREE_VIEW(diag->lview), column);
706 }
707 renderer = gtk_cell_renderer_text_new();
708 column = gtk_tree_view_column_new_with_attributes (_("Property"),renderer,"text", 1,NULL);
709 gtk_tree_view_append_column(GTK_TREE_VIEW(diag->lview), column);
710 renderer = gtk_cell_renderer_text_new();
711 column = gtk_tree_view_column_new_with_attributes (_("Value"),renderer,"text", 2,NULL);
712 gtk_tree_view_append_column(GTK_TREE_VIEW(diag->lview), column);
713 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(diag->lview));
714 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
715 g_signal_connect(G_OBJECT(selection), "changed",G_CALLBACK(cs3d_selection_changed_cb),diag);
716 scrolwin = gtk_scrolled_window_new(NULL, NULL);
717 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
718 gtk_widget_set_size_request(scrolwin, 400, 300);
719 gtk_box_pack_start(GTK_BOX(hbox), scrolwin, TRUE, TRUE, 0);
720 gtk_container_add(GTK_CONTAINER(scrolwin), diag->lview);
721 /*if (diag->styletype == multistyle) {
722 gchar *titles[] = {_("Selector"), _("Property"), _("Value"), NULL};
723 diag->clist = gtk_clist_new_with_titles(3, titles);
724 } else {
725 gchar *titles[] = {_("Property"), _("Value"), NULL};
726 diag->clist = gtk_clist_new_with_titles(2, titles);
727 }
728 gtk_clist_set_sort_column(GTK_CLIST(diag->clist), 0);
729 gtk_clist_set_auto_sort(GTK_CLIST(diag->clist), TRUE);
730
731 g_signal_connect(diag->clist, "select_row", G_CALLBACK(cs3d_select_row_lcb), diag);
732 g_signal_connect(diag->clist, "unselect_row", G_CALLBACK(cs3d_unselect_row_lcb), diag);
733 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolwin), diag->lview);
734 */
735
736 vbox2 = gtk_vbox_new(FALSE, 6);
737 gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0);
738
739 but = gtk_button_new_with_mnemonic(_(" _Add "));
740 g_signal_connect(but, "clicked", G_CALLBACK(cs3d_add_clicked_lcb), diag);
741 gtk_box_pack_start(GTK_BOX(vbox2), but, FALSE, FALSE, 0);
742
743 but = gtk_button_new_with_mnemonic(_(" _Update "));
744 g_signal_connect(but, "clicked", G_CALLBACK(cs3d_update_clicked_lcb), diag);
745 gtk_box_pack_start(GTK_BOX(vbox2), but, FALSE, FALSE, 0);
746
747 but = gtk_button_new_with_mnemonic(_(" _Delete "));
748 g_signal_connect(but, "clicked", G_CALLBACK(cs3d_del_clicked_lcb), diag);
749 gtk_box_pack_start(GTK_BOX(vbox2), but, FALSE, FALSE, 0);
750
751 /* the ok and cancel button are in a horizontal box below */
752 hbox = gtk_hbox_new(FALSE, 0);
753 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 12);
754 #if GTK_CHECK_VERSION(3,0,0)
755 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
756 #else
757 hbox = gtk_hbutton_box_new();
758 #endif
759 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
760 gtk_box_set_spacing(GTK_BOX(hbox), 12);
761
762 but = bf_stock_cancel_button(G_CALLBACK(cs3d_cancel_clicked_lcb), diag);
763 gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, FALSE, 0);
764 but = bf_stock_ok_button(G_CALLBACK(cs3d_ok_clicked_lcb), diag);
765 gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, FALSE, 0);
766 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
767
768 gtk_widget_show_all(diag->win);
769
770 cs3d_prop_activate_lcb(NULL, diag);
771
772 if (diag->grab) {
773 gtk_grab_add(diag->win);
774 }
775 return diag;
776 }
777
778 typedef enum {property, value, end} Tcs3_prevtype_onestyle;
779 typedef enum {mselector, mproperty, mvalue, mend, mselectorend} Tcs3_prevtype_multistyle;
780
781 /* static void css_parse(Tcs3_diag *diag, gchar *data)
782 * the buffer 'data' should contain a css stylesheet
783 * the comments are removed from this buffer by this function
784 * so if you don't want this, make a copy of the stylesheet
785 * before you pass it on to this function
786 */
css_parse(Tcs3_diag * diag,gchar * data)787 static void css_parse(Tcs3_diag *diag, gchar *data) {
788 gchar *tmp = data;
789 gint count = 0, parsable_css = 1;
790
791 if (!data) {
792 DEBUG_MSG("css_parse, no data!\n");
793 return;
794 }
795
796 if (diag->styletype == onestyle) {
797 gint prev_end = 0;
798 Tcs3_prevtype_onestyle prevtype = end;
799 gchar *text[3] = {NULL, NULL, NULL};
800
801 DEBUG_MSG("css_parse, onestyle\n");
802 while (tmp[count] && parsable_css) {
803 switch (tmp[count]) {
804 case ':':
805 if (prevtype == end) {
806 text[0] = g_strndup(&tmp[prev_end], count - prev_end);
807 strip_any_whitespace(text[0]);
808 prev_end = count+1;
809 prevtype = property;
810 }
811 break;
812 case ';':
813 if (prevtype == property) {
814 text[1] = g_strndup(&tmp[prev_end], count - prev_end);
815 strip_any_whitespace(text[1]);
816 prev_end = count+1;
817 prevtype = value;
818 }
819 break;
820 case '*':
821 if ((count > 0)&& (tmp[count-1] == '/')) {
822 gint count2 = count, cont=1, movelen;
823 DEBUG_MSG("css_parse, found the start of a comment on %d\n", count);
824 while (tmp[++count2] && cont) {
825 if (tmp[count2] == '/' && tmp[count2-1] == '*') {
826 cont=0;
827 }
828 }
829 DEBUG_MSG("css_parse, before move, tmp='%s'\n", tmp);
830 movelen = strlen(&tmp[count2]);
831 memmove(&tmp[count-1], &tmp[count2], movelen);
832 tmp[count-1 + movelen] = '\0';
833 DEBUG_MSG("css_parse, after move, tmp='%s'\n", tmp);
834 }
835 break;
836 case '<':
837 case '>':
838 parsable_css = 0;
839 DEBUG_MSG("css_parse, this is not a valid stylesheet\n");
840 break;
841
842 default:
843 /* do nothing */
844 break;
845 }
846 if (prevtype == value) {
847 GtkTreeIter iter;
848 gtk_list_store_append(diag->lstore, &iter);
849 gtk_list_store_set(diag->lstore,&iter,1, text[0],2,text[1],-1);
850 /*gtk_clist_append(GTK_CLIST(diag->clist), text);*/
851 g_free(text[0]);
852 g_free(text[1]);
853 prevtype = end;
854 }
855 count++;
856 }
857
858
859 } else { /* multistyle */
860 gint prev_end = 0, i;
861 Tcs3_prevtype_multistyle prevtype = mselectorend;
862 gchar *text[4] = {NULL, NULL, NULL, NULL};
863
864 DEBUG_MSG("css_parse, multistylestyle\n");
865
866 while (tmp[count] && parsable_css) {
867 switch (tmp[count]) {
868 case '}': /* found end of block */
869 if (prevtype != mselectorend) {
870 prevtype = mselectorend;
871 prev_end = count+1;
872 g_free(text[0]);
873 text[0]=NULL;
874 }
875 break;
876 case '{': /* found selector */
877 if (prevtype == mselectorend) {
878 text[0] = g_strndup(&tmp[prev_end], count - prev_end);
879 strip_any_whitespace(text[0]);
880 prev_end = count+1;
881 prevtype = mselector;
882 }
883 break;
884 case ':':
885 if (prevtype == mselector || prevtype == mend) {
886 text[1] = g_strndup(&tmp[prev_end], count - prev_end);
887 strip_any_whitespace(text[1]);
888 prev_end = count+1;
889 prevtype = mproperty;
890 }
891 break;
892 case ';':
893 if (prevtype == mproperty) {
894 text[2] = g_strndup(&tmp[prev_end], count - prev_end);
895 strip_any_whitespace(text[2]);
896 prev_end = count+1;
897 prevtype = mvalue;
898 }
899 break;
900 case '*':
901 if ((count > 0)&& (tmp[count-1] == '/')) {
902 gint count2 = count, cont=1, movelen;
903 DEBUG_MSG("css_parse, found the start of a comment on %d\n", count);
904 while (tmp[++count2] && cont) {
905 if (tmp[count2] == '/' && tmp[count2-1] == '*') {
906 cont=0;
907 }
908 }
909 DEBUG_MSG("css_parse, before move, tmp='%s'\n", tmp);
910 movelen = strlen(&tmp[count2]);
911 memmove(&tmp[count-1], &tmp[count2], movelen);
912 tmp[count-1 + movelen] = '\0';
913 DEBUG_MSG("css_parse, after move, tmp='%s'\n", tmp);
914 }
915 break;
916 case '<':
917 case '>':
918 parsable_css = 0;
919 DEBUG_MSG("css_parse, this is not a valid stylesheet\n");
920 break;
921 default:
922 /* do nothing */
923 break;
924 }
925 if (prevtype == mvalue) {
926 GtkTreeIter iter;
927 gtk_list_store_append(diag->lstore, &iter);
928 gtk_list_store_set(diag->lstore,&iter,0,text[0],1, text[1],2,text[2],-1);
929
930 /*gtk_clist_append(GTK_CLIST(diag->clist), text);*/
931 g_free(text[1]);
932 text[1] = NULL;
933 g_free(text[2]);
934 text[2] = NULL;
935 prevtype = mend;
936 }
937 count++;
938 }
939 for (i=0;i<4;i++) {
940 if (text[i]){
941 g_free(text[i]);
942 }
943 }
944 }
945 /*gtk_clist_sort(GTK_CLIST(diag->clist));*/
946 DEBUG_MSG("css_parse, finished\n");
947 }
948
new_css_dialog(GtkWidget * wid,Tbfwin * bfwin)949 void new_css_dialog(GtkWidget *wid, Tbfwin *bfwin) {
950 Tcs3_destination dest;
951 Tcs3_diag *diag;
952 gint sel_start, sel_end;
953 gboolean has_selection;
954
955 dest.dest_type = textbox;
956 dest.entry = NULL;
957 dest.doc = bfwin->current_document;
958 if (!doc_get_selection(dest.doc, &sel_start, &sel_end)) {
959 dest.doc_start = -1;
960 dest.doc_end = -1;
961 has_selection = FALSE;
962 } else {
963 has_selection = TRUE;
964 dest.doc_start = sel_start;
965 dest.doc_end = sel_end;
966 }
967 if (dest.doc_start > dest.doc_end) {
968 gint swap = dest.doc_start;
969 dest.doc_start = dest.doc_end;
970 dest.doc_end = swap;
971 }
972
973 diag = css_diag(dest, multistyle, bfwin->main_window, FALSE);
974 if (has_selection) {
975 gchar *data;
976
977 data = doc_get_chars(dest.doc, sel_start, sel_end);
978 DEBUG_MSG("new_css_dialog, data=%p\n", data);
979 css_parse(diag, data);
980 g_free(data);
981 }
982 }
983
style_but_clicked_lcb(GtkWidget * widget,GtkWidget * which_entry)984 static void style_but_clicked_lcb(GtkWidget * widget, GtkWidget * which_entry)
985 {
986 Tcs3_destination dest;
987 Tcs3_diag *diag;
988 gchar *data;
989 GtkWidget *win;
990
991 dest.dest_type = entry;
992 dest.entry = which_entry;
993 dest.doc = NULL;
994
995 win = gtk_widget_get_toplevel(which_entry);
996 diag = css_diag(dest, onestyle, win, TRUE);
997 data = gtk_editable_get_chars(GTK_EDITABLE(which_entry), 0, -1);
998 css_parse(diag, data);
999 g_free(data);
1000 }
1001
style_but_new(GtkWidget * which_entry,GtkWidget * win)1002 GtkWidget *style_but_new(GtkWidget * which_entry, GtkWidget * win)
1003 {
1004 GtkWidget *style_but, *hbox;
1005
1006 style_but = gtk_button_new();
1007 hbox = gtk_hbox_new(FALSE, 0);
1008 gtk_box_pack_start(GTK_BOX(hbox), gtk_image_new_from_stock(BF_STOCK_CSS_SMALL, GTK_ICON_SIZE_BUTTON),FALSE, FALSE, 3);
1009 gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new_with_mnemonic(_("_Style...")), TRUE, TRUE, 3);
1010 gtk_container_add(GTK_CONTAINER(style_but), hbox);
1011 g_signal_connect(style_but, "clicked", G_CALLBACK(style_but_clicked_lcb), which_entry);
1012 gtk_widget_show_all(style_but);
1013 return style_but;
1014 }
1015
style_but_for_wizard_clicked_lcb(GtkWidget * widget,GtkWidget * textview)1016 static void style_but_for_wizard_clicked_lcb(GtkWidget * widget, GtkWidget * textview)
1017 {
1018 Tcs3_destination dest;
1019 Tcs3_diag *diag;
1020 gchar *data;
1021 GtkWidget *win;
1022
1023 dest.dest_type = wizard;
1024 dest.entry = textview;
1025 dest.doc = NULL;
1026
1027 win = gtk_widget_get_toplevel(textview);
1028 diag = css_diag(dest, multistyle, win, TRUE);
1029 {
1030 GtkTextBuffer *buf;
1031 GtkTextIter itstart, itend;
1032 buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
1033 gtk_text_buffer_get_bounds(buf,&itstart,&itend);
1034 data = gtk_text_buffer_get_text(buf, &itstart, &itend, FALSE);
1035 css_parse(diag, data);
1036 g_free(data);
1037 }
1038 }
1039
style_but_new_for_wizard(GtkWidget * textview)1040 GtkWidget *style_but_new_for_wizard(GtkWidget * textview) {
1041 GtkWidget *style_but, *hbox;
1042
1043 style_but = gtk_button_new();
1044 hbox = gtk_hbox_new(FALSE, 0);
1045 gtk_box_pack_start(GTK_BOX(hbox), gtk_image_new_from_stock(BF_STOCK_CSS_SMALL, GTK_ICON_SIZE_BUTTON),FALSE, FALSE, 6);
1046 gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new_with_mnemonic(_("_Style...")), TRUE, TRUE, 6);
1047 gtk_container_add(GTK_CONTAINER(style_but), hbox);
1048 g_signal_connect(style_but, "clicked", G_CALLBACK(style_but_for_wizard_clicked_lcb), textview);
1049 gtk_widget_show_all(style_but);
1050 return style_but;
1051 }
1052
1053 /*****************/
1054 /* colorbut code */
1055 /*****************/
1056
1057 typedef struct {
1058 GtkWidget *win;
1059 GtkWidget *hexentry;
1060 GtkWidget *websafe;
1061 GtkWidget *csel;
1062 gint hex_changed_id;
1063 gint csel_changed_id;
1064 /* the dialog is dual functional: it can be called directly from the text, and it can be called by return_color
1065 if called by return_color it is in the modal state */
1066 gint is_modal;
1067 /* for the modal state */
1068 gchar *returnval;
1069
1070 /* for the non-modal state */
1071 gint startpos;
1072 gint endpos;
1073 Tbfwin *bfwin;
1074 } Tcolsel;
1075
colsel_destroy_lcb(GtkWidget * widget,Tcolsel * csd)1076 static void colsel_destroy_lcb(GtkWidget *widget, Tcolsel *csd) {
1077 DEBUG_MSG("colsel_destroy_lcb, started for csd=%p\n",csd);
1078 g_free(csd->returnval);
1079 g_free(csd);
1080 }
1081
colsel_ok_clicked_lcb(GtkWidget * widget,Tcolsel * csd)1082 static void colsel_ok_clicked_lcb(GtkWidget *widget, Tcolsel *csd) {
1083 gchar *tmpstr;
1084 GdkColor gcolor;
1085 /* only on a OK click we do the setcolor thing */
1086 gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(csd->csel), &gcolor);
1087
1088 tmpstr = gdk_color_to_hexstring(&gcolor, FALSE);
1089 if (csd->bfwin) {
1090 csd->bfwin->session->colorlist = add_to_stringlist(csd->bfwin->session->colorlist, tmpstr);
1091 }
1092
1093 if (csd->is_modal) {
1094 g_free(csd->returnval);
1095 csd->returnval = tmpstr;
1096 gtk_main_quit();
1097 } else {
1098 if (string_is_color(tmpstr)) {
1099 if (csd->startpos || csd->endpos) {
1100 DEBUG_MSG("colsel_ok_clicked_lcb, replacing with %s\n", tmpstr);
1101 doc_replace_text(csd->bfwin->current_document, tmpstr, csd->startpos, csd->endpos);
1102 } else {
1103 DEBUG_MSG("colsel_ok_clicked_lcb, inserting %s\n", tmpstr);
1104 doc_insert_two_strings(csd->bfwin->current_document,tmpstr, NULL);
1105 }
1106 }
1107 g_free(tmpstr);
1108 window_destroy(csd->win);
1109 }
1110 }
1111
colsel_cancel_clicked_lcb(GtkWidget * widget,Tcolsel * csd)1112 static void colsel_cancel_clicked_lcb(GtkWidget *widget, Tcolsel *csd) {
1113 window_destroy(csd->win);
1114 }
1115
colsel_dialog(Tbfwin * bfwin,const gchar * setcolor,gint modal,gint startpos,gint endpos)1116 static Tcolsel *colsel_dialog(Tbfwin *bfwin,const gchar *setcolor, gint modal, gint startpos, gint endpos) {
1117 Tcolsel *csd;
1118 GtkWidget *vbox, *hbox, *but;
1119 GdkColor gcolor;
1120 const gchar *this_color=setcolor;
1121 csd = g_new0(Tcolsel, 1);
1122 /* warning: bfwin might be NULL if this dialog is started by return_color() */
1123 csd->bfwin = bfwin;
1124 csd->is_modal = modal;
1125 csd->startpos = startpos;
1126 csd->endpos = endpos;
1127 csd->returnval = setcolor ? g_strdup(setcolor) : g_strdup("");
1128
1129 DEBUG_MSG("colsel_dialog, malloced at %p, setcolor=%s\n", csd, setcolor);
1130 csd->win = window_full2(_("Bluefish: Select color"), GTK_WIN_POS_CENTER, 12, G_CALLBACK(colsel_destroy_lcb), csd, TRUE, bfwin?bfwin->main_window:NULL);
1131 vbox = gtk_vbox_new(FALSE, 0);
1132 gtk_container_add(GTK_CONTAINER(csd->win), vbox);
1133 csd->csel = gtk_color_selection_new();
1134 gtk_color_selection_set_has_opacity_control(GTK_COLOR_SELECTION(csd->csel), FALSE);
1135 if (this_color) {
1136 if (gdk_color_parse(this_color, &gcolor)) {
1137 gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(csd->csel), &gcolor);
1138 } else {
1139 this_color=NULL;
1140 }
1141 }
1142 gtk_color_selection_set_has_palette(GTK_COLOR_SELECTION(csd->csel), TRUE);
1143 gtk_box_pack_start(GTK_BOX(vbox), csd->csel, TRUE, TRUE, 0);
1144
1145 hbox = gtk_hbox_new(FALSE, 0);
1146 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 12);
1147 #if GTK_CHECK_VERSION(3,0,0)
1148 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
1149 #else
1150 hbox = gtk_hbutton_box_new();
1151 #endif
1152 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
1153 gtk_box_set_spacing(GTK_BOX(hbox), 12);
1154 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
1155
1156 but = bf_stock_cancel_button(G_CALLBACK(colsel_cancel_clicked_lcb), csd);
1157 gtk_box_pack_start(GTK_BOX(hbox), but, TRUE, TRUE, 0);
1158 but = bf_stock_ok_button(G_CALLBACK(colsel_ok_clicked_lcb), csd);
1159 gtk_window_set_default(GTK_WINDOW(csd->win), but);
1160 gtk_box_pack_start(GTK_BOX(hbox), but, TRUE, TRUE, 0);
1161
1162 if (bfwin && bfwin->session->colorlist) {
1163 GtkSettings* gtksettings;
1164 /* Note that this function can only be called when the GtkWidget is attached to a toplevel, since the settings object is specific to a particular GdkScreen. */
1165 gtksettings = gtk_widget_get_settings(GTK_WIDGET(csd->csel));
1166 if (gtksettings) {
1167 gchar *strings;
1168 DEBUG_MSG("pallette list=%d\n",g_list_length(bfwin->session->colorlist));
1169 bfwin->session->colorlist = limit_stringlist(bfwin->session->colorlist, 20, TRUE);
1170 DEBUG_MSG("pallette list=%d\n",g_list_length(bfwin->session->colorlist));
1171 strings = stringlist_to_string(bfwin->session->colorlist, ":");
1172 strings[strlen(strings)-1] = '\0';
1173 /* this property may contain max 20 colors, otherwise gtk will crash */
1174 g_object_set(G_OBJECT(gtksettings), "gtk-color-palette", strings, NULL);
1175 g_free(strings);
1176 }
1177 /* DEBUG_MSG("colsel_dialog, setting palette from %s\n", strings);
1178 if (gtk_color_selection_palette_from_string(strings, &gcolorarr, &num)) {
1179 DEBUG_MSG("num=%d, gcolorarr=%p\n",num,gcolorarr);
1180 } else {
1181 DEBUG_MSG("hmm, failed to parse our string :(\n");
1182 } */
1183 }
1184
1185 gtk_widget_show_all(csd->win);
1186
1187 DEBUG_MSG("colsel_dialog, finished\n");
1188 return csd;
1189 }
1190
edit_color_dialog(Tdocument * doc,gchar * color,gint startpos,gint endpos)1191 void edit_color_dialog(Tdocument *doc, gchar *color, gint startpos, gint endpos) {
1192 colsel_dialog(doc->bfwin, color, FALSE, startpos, endpos);
1193 }
1194
sel_colour_cb(GtkWidget * widget,Tbfwin * bfwin)1195 void sel_colour_cb(GtkWidget *widget, Tbfwin *bfwin) {
1196 gchar *tmpstr=NULL;
1197 gint startpos=0;
1198 gint endpos=0;
1199
1200 if (doc_get_selection(bfwin->current_document,&startpos , &endpos)) {
1201 DEBUG_MSG("sel_colour_cb, selection found\n");
1202 if (startpos > endpos) {
1203 gint tmpint;
1204 tmpint = startpos;
1205 startpos = endpos;
1206 endpos = tmpint;
1207 }
1208 if ((endpos - startpos) == 7) {
1209 tmpstr = doc_get_chars(bfwin->current_document,startpos,endpos);
1210 if (!string_is_color(tmpstr)) {
1211 startpos = endpos = 0;
1212 }
1213 DEBUG_MSG("sel_colour_cb, tmpstr = %s (startpos=%d, endpos=%d)\n", tmpstr, startpos, endpos);
1214 } else {
1215 DEBUG_MSG("sel_colour_cb, startpos=%d, endpos=%d\n", startpos, endpos);
1216 startpos = endpos = 0;
1217 }
1218 } else {
1219 DEBUG_MSG("sel_colour_cb, NO selection found\n");
1220 }
1221
1222 colsel_dialog(bfwin, tmpstr, 0, startpos, endpos);
1223 if (tmpstr)
1224 g_free(tmpstr);
1225 }
1226
return_color(gchar * start_value)1227 gchar *return_color(gchar *start_value) {
1228 Tcolsel *csd;
1229 gchar *return_text;
1230
1231 csd = colsel_dialog(NULL,start_value, 1, 0, 0);
1232 DEBUG_MSG("return color, started\n");
1233 gtk_grab_add(csd->win);
1234 gtk_main();
1235
1236 return_text = g_strdup(csd->returnval);
1237 window_destroy(csd->win);
1238 DEBUG_MSG("return_color, the new gtk_main stopped, return_text=%s, %p\n", return_text, return_text);
1239 return return_text;
1240 }
1241
color_but_clicked(GtkWidget * widget,GtkWidget * entry)1242 static void color_but_clicked(GtkWidget * widget, GtkWidget * entry)
1243 {
1244 gchar *tmpstring, *tmpstr2;
1245
1246 DEBUG_MSG("color_but_clicked, before return_color\n");
1247 tmpstr2 = gtk_editable_get_chars(GTK_EDITABLE(entry),0 ,-1);
1248 tmpstring = return_color(tmpstr2);
1249 DEBUG_MSG("color_but_clicked, return_color=%s\n", tmpstring);
1250 gtk_entry_set_text(GTK_ENTRY(entry), tmpstring);
1251 g_free(tmpstring);
1252 g_free(tmpstr2);
1253
1254 }
1255
color_but_new(GtkWidget * which_entry,GtkWidget * win)1256 GtkWidget *color_but_new(GtkWidget * which_entry, GtkWidget * win)
1257 {
1258 GtkWidget *color_but;
1259
1260 color_but = gtk_button_new_from_stock(GTK_STOCK_SELECT_COLOR);
1261 g_signal_connect(color_but, "clicked", G_CALLBACK(color_but_clicked), which_entry);
1262 gtk_widget_show(color_but);
1263 return color_but;
1264 }
1265