source: trunk/third/gtkhtml3/src/htmlengine-edit-fontstyle.c @ 21116

Revision 21116, 15.2 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21115, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/* This file is part of the GtkHTML library
3
4   Copyright (C) 2000 Helix Code, Inc.
5   
6   This library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Library General Public
8   License as published by the Free Software Foundation; either
9   version 2 of the License, or (at your option) any later version.
10   
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Library General Public License for more details.
15   
16   You should have received a copy of the GNU Library General Public License
17   along with this library; see the file COPYING.LIB.  If not, write to
18   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   Boston, MA 02111-1307, USA.
20*/
21
22#include <config.h>
23#include "gtkhtmldebug.h"
24#include "htmlclue.h"
25#include "htmlcolor.h"
26#include "htmlcolorset.h"
27#include "htmlengine-edit.h"
28#include "htmlengine-edit-fontstyle.h"
29#include "htmlengine-edit-movement.h"
30#include "htmlengine-edit-selection-updater.h"
31#include "htmlinterval.h"
32#include "htmltext.h"
33#include "htmlselection.h"
34#include "htmlsettings.h"
35#include "htmlundo.h"
36
37/* #define PARANOID_DEBUG */
38static HTMLObject * html_engine_text_style_object (HTMLEngine *e, gint *offset);
39
40
41static GtkHTMLFontStyle
42get_font_style_from_selection (HTMLEngine *engine)
43{
44        GtkHTMLFontStyle style;
45        GtkHTMLFontStyle conflicts;
46        gboolean first;
47        HTMLPoint p;
48        gint offset;
49
50        g_return_val_if_fail (engine->clue != NULL, GTK_HTML_FONT_STYLE_DEFAULT);
51        g_return_val_if_fail (html_engine_is_selection_active (engine), GTK_HTML_FONT_STYLE_DEFAULT);
52
53        /* printf ("%s mark %p,%d cursor %p,%d\n",
54                __FUNCTION__,
55                engine->mark, engine->mark->position,
56                engine->cursor, engine->cursor->position); */
57
58
59        style = GTK_HTML_FONT_STYLE_DEFAULT;
60        conflicts = GTK_HTML_FONT_STYLE_DEFAULT;
61        first = TRUE;
62
63        p = engine->selection->from;
64        offset = p.offset;
65
66        while (1) {
67                if (html_object_is_text (p.object) && p.offset != html_object_get_length (p.object)) {
68                        gint index = 0;
69                        if (first) {
70                                gint index = g_utf8_offset_to_pointer (HTML_TEXT (p.object)->text, offset) - HTML_TEXT (p.object)->text;
71                                style = html_text_get_fontstyle_at_index (HTML_TEXT (p.object), index);
72                                first = FALSE;
73                        }
74                        conflicts |= html_text_get_style_conflicts (HTML_TEXT (p.object), style, index,
75                                                                    p.object == engine->selection->to.object
76                                                                    ? engine->selection->to.offset : HTML_TEXT (p.object)->text_bytes);
77                }
78
79                if (html_point_cursor_object_eq (&p, &engine->selection->to))
80                        break;
81
82                html_point_next_cursor (&p);
83                offset = 0;
84
85                if (p.object == NULL) {
86                        g_warning ("Unable to find style for end of selection");
87                        return style;
88                }
89        }
90
91        return style & ~conflicts;
92}
93
94static HTMLColor *
95get_color_from_selection (HTMLEngine *engine)
96{
97        HTMLColor *color = NULL;
98        HTMLPoint p;
99
100        g_return_val_if_fail (engine->clue != NULL, NULL);
101        g_return_val_if_fail (html_engine_is_selection_active (engine), NULL);
102
103        p = engine->selection->from;
104        while (1) {
105                if (html_object_is_text (p.object)  && p.offset != html_object_get_length (p.object)) {
106                        color = html_text_get_color (HTML_TEXT (p.object), engine,
107                                                     p.object == engine->selection->from.object
108                                                     ? g_utf8_offset_to_pointer (HTML_TEXT (p.object)->text, p.offset) - HTML_TEXT (p.object)->text : 0);
109                        break;
110                }
111
112                if (html_point_cursor_object_eq (&p, &engine->selection->to))
113                        break;
114                html_point_next_cursor (&p);
115
116                if (p.object == NULL) {
117                        g_warning ("Unable to find color for end of selection");
118                        return color;
119                }
120        }
121
122        return color;
123}
124
125GtkHTMLFontStyle
126html_engine_get_document_font_style (HTMLEngine *engine)
127{
128        g_return_val_if_fail (engine != NULL, GTK_HTML_FONT_STYLE_DEFAULT);
129        g_return_val_if_fail (HTML_IS_ENGINE (engine), GTK_HTML_FONT_STYLE_DEFAULT);
130        g_return_val_if_fail (engine->editable, GTK_HTML_FONT_STYLE_DEFAULT);
131
132        if (html_engine_is_selection_active (engine))
133                return get_font_style_from_selection (engine);
134        else {
135                HTMLObject *curr = engine->cursor->object;
136                gint offset;
137
138                if (curr == NULL)
139                        return GTK_HTML_FONT_STYLE_DEFAULT;
140                else if (! html_object_is_text (curr))
141                        return GTK_HTML_FONT_STYLE_DEFAULT;
142                else {
143                        HTMLObject *obj;
144
145                        obj = html_engine_text_style_object (engine, &offset);
146                        return obj
147                                ? html_text_get_fontstyle_at_index (HTML_TEXT (obj), g_utf8_offset_to_pointer (HTML_TEXT (obj)->text, offset) - HTML_TEXT (obj)->text)
148                                : GTK_HTML_FONT_STYLE_DEFAULT;
149                }
150        }
151}
152
153HTMLColor *
154html_engine_get_document_color (HTMLEngine *engine)
155{
156        g_return_val_if_fail (engine != NULL, NULL);
157        g_return_val_if_fail (HTML_IS_ENGINE (engine), NULL);
158        g_return_val_if_fail (engine->editable, NULL);
159
160        if (html_engine_is_selection_active (engine))
161                return get_color_from_selection (engine);
162        else {
163                HTMLObject *curr = engine->cursor->object;
164
165                if (curr == NULL)
166                        return NULL;
167                else if (! html_object_is_text (curr))
168                        return NULL;
169                else {
170                        HTMLObject *obj;
171                        gint offset;
172
173                        obj = html_engine_text_style_object (engine, &offset);
174                        return obj
175                                ? html_text_get_color_at_index (HTML_TEXT (obj), engine, g_utf8_offset_to_pointer (HTML_TEXT (obj)->text, offset) - HTML_TEXT (obj)->text)
176                                : html_colorset_get_color (engine->settings->color_set, HTMLTextColor);
177                }
178        }
179}
180
181GtkHTMLFontStyle
182html_engine_get_font_style (HTMLEngine *engine)
183{
184        return (engine->insertion_font_style == GTK_HTML_FONT_STYLE_DEFAULT)
185                ? html_engine_get_document_font_style (engine)
186                : engine->insertion_font_style;
187}
188
189HTMLColor *
190html_engine_get_color (HTMLEngine *engine)
191{
192        return engine->insertion_color;
193}
194
195/**
196 * html_engine_update_insertion_font_style:
197 * @engine: An HTMLEngine
198 *
199 * Update @engine's current insertion font style according to the
200 * current selection and cursor position.
201 *
202 * Return value:
203 **/
204gboolean
205html_engine_update_insertion_font_style (HTMLEngine *engine)
206{
207        GtkHTMLFontStyle new_style;
208
209        new_style = html_engine_get_document_font_style (engine);
210
211        if (new_style != engine->insertion_font_style) {
212                engine->insertion_font_style = new_style;
213                return TRUE;
214        }
215
216        return FALSE;
217}
218
219/**
220 * html_engine_update_insertion_style:
221 * @engine: An HTMLEngine
222 *
223 * Update @engine's current insertion font style/color according to the
224 * current selection and cursor position.
225 *
226 * Return value:
227 **/
228gboolean
229html_engine_update_insertion_color (HTMLEngine *engine)
230{
231        HTMLColor *new_color;
232
233        new_color = html_engine_get_document_color (engine);
234
235        if (new_color && !html_color_equal (new_color, engine->insertion_color)) {
236                html_color_unref (engine->insertion_color);
237                engine->insertion_color = new_color;
238                html_color_ref (engine->insertion_color);
239                return TRUE;
240        }
241
242        return FALSE;
243}
244
245/**
246 * html_engine_set_font_style:
247 * @engine: An HTMLEngine
248 * @style: An HTMLFontStyle
249 *
250 * Set the current font style for `engine'.  This has the same semantics as the
251 * bold, italics etc. buttons in a word processor, i.e.:
252 *
253 * - If there is a selection, the selection gets the specified style.
254 *
255 * - If there is no selection, the style gets "attached" to the cursor.  So
256 *   inserting text after this will cause text to have this style.
257 *
258 * Instead of specifying an "absolute" style, we specify it as a "difference"
259 * from the current one, through an AND mask and an OR mask.
260 *
261 **/
262struct tmp_font {
263        GtkHTMLFontStyle and_mask;
264        GtkHTMLFontStyle or_mask;
265};
266
267static void
268object_set_font_style (HTMLObject *o, HTMLEngine *e, gpointer data)
269{
270        if (html_object_is_text (o)) {
271                struct tmp_font *tf = (struct tmp_font *) data;
272
273                html_text_unset_style (HTML_TEXT (o), ~tf->and_mask);
274                html_text_set_style (HTML_TEXT (o), tf->or_mask, e);
275        }
276}
277
278struct _HTMLEmptyParaSetStyle {
279        HTMLUndoData data;
280
281        GtkHTMLFontStyle and_mask;
282        GtkHTMLFontStyle or_mask;
283};
284typedef struct _HTMLEmptyParaSetStyle HTMLEmptyParaSetStyle;
285
286static void set_empty_flow_style (HTMLEngine *e, GtkHTMLFontStyle and_mask, GtkHTMLFontStyle or_mask, HTMLUndoDirection dir);
287
288static void
289set_empty_flow_style_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirection dir, guint position_after)
290{
291        HTMLEmptyParaSetStyle *undo = (HTMLEmptyParaSetStyle *) undo_data;
292
293        set_empty_flow_style (e, undo->and_mask, undo->or_mask, html_undo_direction_reverse (dir));
294}
295
296static void
297set_empty_flow_style (HTMLEngine *e, GtkHTMLFontStyle and_mask, GtkHTMLFontStyle or_mask, HTMLUndoDirection dir)
298{
299        HTMLEmptyParaSetStyle *undo;
300        GtkHTMLFontStyle old_or_mask;
301
302        g_return_if_fail (html_object_is_text (e->cursor->object));
303
304        old_or_mask = HTML_TEXT (e->cursor->object)->font_style & ~and_mask;
305        HTML_TEXT (e->cursor->object)->font_style &= and_mask;
306        HTML_TEXT (e->cursor->object)->font_style |= or_mask;
307
308        undo = g_new (HTMLEmptyParaSetStyle, 1);
309        html_undo_data_init (HTML_UNDO_DATA (undo));
310        undo->and_mask = and_mask;
311        undo->or_mask = old_or_mask;
312        undo->data.destroy = NULL;
313        html_undo_add_action (e->undo,
314                              html_undo_action_new ("Set empty paragraph text style", set_empty_flow_style_undo_action,
315                                                    HTML_UNDO_DATA (undo), html_cursor_get_position (e->cursor),
316                                                    html_cursor_get_position (e->cursor)), dir);
317}
318
319gboolean
320html_engine_set_font_style (HTMLEngine *e,
321                            GtkHTMLFontStyle and_mask,
322                            GtkHTMLFontStyle or_mask)
323{
324        gboolean rv;
325        GtkHTMLFontStyle old = e->insertion_font_style;
326
327        g_return_val_if_fail (e != NULL, FALSE);
328        g_return_val_if_fail (HTML_IS_ENGINE (e), FALSE);
329        g_return_val_if_fail (e->editable, FALSE);
330
331        /* printf ("and %d or %d\n", and_mask, or_mask); */
332        e->insertion_font_style &= and_mask;
333        e->insertion_font_style |= or_mask;
334
335        if (html_engine_is_selection_active (e)) {
336                struct tmp_font *tf = g_new (struct tmp_font, 1);
337                tf->and_mask = and_mask;
338                tf->or_mask  = or_mask;
339                html_engine_cut_and_paste (e, "Set font style", "Unset font style", object_set_font_style, tf);
340                g_free (tf);
341                rv = TRUE;
342        } else {
343                if (e->cursor->object->parent && html_clueflow_is_empty (HTML_CLUEFLOW (e->cursor->object->parent))) {
344                        set_empty_flow_style (e, and_mask, or_mask, HTML_UNDO_UNDO);
345                }
346                rv = (old == e->insertion_font_style) ? FALSE : TRUE;
347        }
348        return rv;
349}
350
351gboolean
352html_engine_toggle_font_style (HTMLEngine *engine, GtkHTMLFontStyle style)
353{
354        GtkHTMLFontStyle cur_style;
355
356        cur_style = html_engine_get_font_style (engine);
357
358        if (cur_style & style)
359                return html_engine_set_font_style (engine, GTK_HTML_FONT_STYLE_MAX & ~style, 0);
360        else
361                return html_engine_set_font_style (engine, GTK_HTML_FONT_STYLE_MAX, style);
362}
363
364static GtkHTMLFontStyle
365inc_dec_size (GtkHTMLFontStyle style, gboolean inc)
366{
367        GtkHTMLFontStyle size;
368
369        if (style == GTK_HTML_FONT_STYLE_DEFAULT)
370                style = GTK_HTML_FONT_STYLE_SIZE_3;
371
372        size = style & GTK_HTML_FONT_STYLE_SIZE_MASK;
373        if (inc && size < GTK_HTML_FONT_STYLE_SIZE_7)
374                size++;
375        else if (!inc && size > GTK_HTML_FONT_STYLE_SIZE_1)
376                size--;
377
378        style &= ~GTK_HTML_FONT_STYLE_SIZE_MASK;
379        style |= size;
380
381        return style;
382}
383
384static void
385inc_dec_size_cb (HTMLObject *o, HTMLEngine *e, gpointer data)
386{
387        if (html_object_is_text (o)) {
388                html_text_set_font_style (HTML_TEXT (o), e, inc_dec_size (HTML_TEXT (o)->font_style, GPOINTER_TO_INT (data)));
389                if (o->prev)
390                        html_object_merge (o->prev, o, e, NULL, NULL, NULL);
391        }
392}
393
394void
395html_engine_font_size_inc_dec (HTMLEngine *e, gboolean inc)
396{
397        if (html_engine_is_selection_active (e))
398                html_engine_cut_and_paste (e,
399                                           inc ? "Increase font size" : "Decrease font size",
400                                           inc ? "Decrease font size" : "Increase font size",
401                                           inc_dec_size_cb, GINT_TO_POINTER (inc));
402        else
403                e->insertion_font_style = inc_dec_size (e->insertion_font_style, inc);
404}
405
406static void
407set_color (HTMLObject *o, HTMLEngine *e, gpointer data)
408{
409        if (html_object_is_text (o)) {
410                HTMLObject *prev;
411
412                html_text_set_color (HTML_TEXT (o), (HTMLColor *) data);
413
414                if (o->parent) {
415                        prev = html_object_prev_not_slave (o);
416                        if (prev) {
417                                html_object_merge (prev, o, e, NULL, NULL, NULL);
418                        }
419                }
420        }
421}
422
423gboolean
424html_engine_set_color (HTMLEngine *e, HTMLColor *color)
425{
426        gboolean rv = TRUE;
427
428        if (!color)
429                color = html_colorset_get_color (e->settings->color_set, HTMLTextColor);
430
431        if (html_engine_is_selection_active (e))
432                html_engine_cut_and_paste (e, "Set color", "Unset color", set_color, color);
433        else {
434                if (gdk_color_equal (&e->insertion_color->color, &color->color))
435                        rv = FALSE;
436        }
437        html_color_unref (e->insertion_color);
438
439        e->insertion_color = color;
440        html_color_ref (e->insertion_color);
441
442        return rv;
443}
444
445/* URL/Target
446
447   get actual url/target
448*/
449
450const gchar *
451html_engine_get_url (HTMLEngine *e)
452{
453        return e->insertion_url;
454}
455
456const gchar *
457html_engine_get_target (HTMLEngine *e)
458{
459        return e->insertion_target;
460}
461
462void
463html_engine_set_url (HTMLEngine *e, const gchar *url)
464{
465        if (e->insertion_url)
466                g_free (e->insertion_url);
467        e->insertion_url = g_strdup (url);
468}
469
470void
471html_engine_set_target (HTMLEngine *e, const gchar *target)
472{
473        if (e->insertion_target)
474                g_free (e->insertion_target);
475        e->insertion_target = g_strdup (target);
476}
477
478/* get url/target from document */
479
480static const gchar *
481get_url_or_target_from_selection (HTMLEngine *e, gboolean get_url)
482{
483        const gchar *str = NULL;
484        HTMLPoint p;
485
486        g_return_val_if_fail (e->clue != NULL, NULL);
487        g_return_val_if_fail (html_engine_is_selection_active (e), NULL);
488
489        p = e->selection->from;
490        while (1) {
491                str = get_url ? html_object_get_url (p.object, p.offset) : html_object_get_target (p.object, p.offset);
492                if (str || html_point_cursor_object_eq (&p, &e->selection->to))
493                        break;
494                html_point_next_cursor (&p);
495               
496                if (p.object == NULL) {
497                        g_warning ("Unable to find url by end of selection");
498                        return str;
499                }
500        }
501
502        return str;
503}
504
505static HTMLObject *
506html_engine_text_style_object (HTMLEngine *e, gint *offset)
507{
508        if (HTML_IS_TEXT (e->cursor->object)
509            || (e->cursor->offset && e->cursor->offset != html_object_get_length (e->cursor->object))) {
510                if (offset)
511                        *offset = e->cursor->offset;
512                return e->cursor->object;
513        }
514
515        if (e->cursor->offset) {
516                HTMLObject *next;
517
518                next = html_object_next_not_slave (e->cursor->object);
519                if (next && HTML_IS_TEXT (next)) {
520                        if (offset)
521                                *offset = 0;
522                        return next;
523                }
524        } else {
525                HTMLObject *prev;
526
527                prev = html_object_prev_not_slave (e->cursor->object);
528                if (prev && HTML_IS_TEXT (prev)) {
529                        if (offset)
530                                *offset = html_object_get_length (prev);
531                        return prev;
532                }
533        }
534
535        return NULL;
536}
537
538const gchar *
539html_engine_get_document_url (HTMLEngine *e)
540{
541        if (html_engine_is_selection_active (e))
542                return get_url_or_target_from_selection (e, TRUE);
543        else {
544                HTMLObject *obj;
545                gint offset;
546
547                obj = html_engine_text_style_object (e, &offset);
548                return obj ? html_object_get_url (obj, offset) : NULL;
549        }
550}
551
552const gchar *
553html_engine_get_document_target (HTMLEngine *e)
554{
555        if (html_engine_is_selection_active (e))
556                return get_url_or_target_from_selection (e, FALSE);
557        else {
558                HTMLObject *obj;
559                gint offset;
560
561                obj = html_engine_text_style_object (e, &offset);
562                return obj ? html_object_get_target (obj, offset) : NULL;
563        }
564}
565
566gboolean
567html_engine_update_insertion_url_and_target (HTMLEngine *engine)
568{
569        const gchar *url, *target;
570        gboolean retval = FALSE;
571
572        url    = html_engine_get_document_url    (engine);
573        target = html_engine_get_document_target (engine);
574
575        if (url != engine->insertion_url) {
576                html_engine_set_url (engine, url);
577                retval = TRUE;
578        }
579
580        if (target != engine->insertion_target) {
581                html_engine_set_target (engine, target);
582                retval = TRUE;
583        }
584
585        return retval;
586}
Note: See TracBrowser for help on using the repository browser.