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

Revision 21116, 10.4 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 <gtk/gtkmain.h>
24#include "gtkhtml.h"
25#include "gtkhtml-private.h"
26#include "htmlcursor.h"
27#include "htmlengine.h"
28#include "htmlengine-edit-cursor.h"
29#include "htmlengine-edit-table.h"
30#include "htmlengine-edit-tablecell.h"
31#include "htmlimage.h"
32#include "htmlobject.h"
33#include "htmltable.h"
34#include "htmlembedded.h"
35
36#define BLINK_TIMEOUT 500
37
38static GdkColor table_stipple_active_on      = { 0, 0,      0,      0xffff };
39static GdkColor table_stipple_active_off     = { 0, 0xffff, 0xffff, 0xffff };
40static GdkColor table_stipple_non_active_on  = { 0, 0xaaaa, 0xaaaa, 0xaaaa };
41static GdkColor table_stipple_non_active_off = { 0, 0xffff, 0xffff, 0xffff };
42
43static GdkColor cell_stipple_active_on      = { 0, 0x7fff, 0x7fff, 0 };
44static GdkColor cell_stipple_active_off     = { 0, 0xffff, 0xffff, 0xffff };
45static GdkColor cell_stipple_non_active_on  = { 0, 0x7aaa, 0x7aaa, 0x7aaa };
46static GdkColor cell_stipple_non_active_off = { 0, 0xffff, 0xffff, 0xffff };
47
48static GdkColor image_stipple_active_on      = { 0, 0xffff, 0,      0 };
49static GdkColor image_stipple_active_off     = { 0, 0xffff, 0xffff, 0xffff };
50
51void
52html_engine_hide_cursor  (HTMLEngine *engine)
53{
54        HTMLEngine *e = engine;
55
56        g_return_if_fail (engine != NULL);
57        g_return_if_fail (HTML_IS_ENGINE (engine));
58
59        if ((engine->editable || engine->caret_mode) && engine->cursor_hide_count == 0) {
60                if (!engine->editable) {
61                        e = html_object_engine(engine->cursor->object, NULL);
62                        if (e) {
63                                e->caret_mode = engine->caret_mode;
64                                html_cursor_copy(e->cursor, engine->cursor);
65                        } else  e = engine;
66                }
67                html_engine_draw_cursor_in_area (e, 0, 0, -1, -1);
68        }
69
70        engine->cursor_hide_count++;
71}
72
73void
74html_engine_show_cursor  (HTMLEngine *engine)
75{
76        HTMLEngine * e = engine;
77
78        g_return_if_fail (engine != NULL);
79        g_return_if_fail (HTML_IS_ENGINE (engine));
80        g_return_if_fail (engine->cursor != NULL);
81
82        if (engine->cursor_hide_count > 0) {
83                engine->cursor_hide_count--;
84                if ((engine->editable || engine->caret_mode) && engine->cursor_hide_count == 0) {
85                        if (!engine->editable) {
86                                e = html_object_engine(engine->cursor->object, NULL);
87                                if (e) {
88                                        e->caret_mode = engine->caret_mode;
89                                        html_cursor_copy(e->cursor, engine->cursor);
90                                } else e = engine;
91                        }
92                        html_engine_draw_cursor_in_area (e, 0, 0, -1, -1);
93                }
94        }
95}
96
97static gboolean
98clip_cursor (HTMLEngine *engine, gint x, gint y, gint width, gint height, gint *x1, gint *y1, gint *x2, gint *y2)
99{
100        if (*x1 > x + width || *y1 > y + height || *x2 < x || *y2 < y)
101                return FALSE;
102
103        *x1 = CLAMP (*x1, x, x + width);
104        *x2 = CLAMP (*x2, x, x + width);
105        *y1 = CLAMP (*y1, y, y + height);
106        *y2 = CLAMP (*y2, y, y + height);
107
108        return TRUE;
109}
110
111static void
112draw_cursor_rectangle (HTMLEngine *e, gint x1, gint y1, gint x2, gint y2,
113                       GdkColor *on_color, GdkColor *off_color,
114                       gint offset)
115{
116        GdkGC *gc;
117        GdkColor color;
118        gint8 dashes [2] = { 1, 3 };
119
120        if (x1 > x2 || y1 > y2)
121                return;
122
123        gc = gdk_gc_new (e->window);
124        color = *on_color;
125        gdk_rgb_find_color (gdk_drawable_get_colormap (e->window), &color);
126        gdk_gc_set_foreground (gc, &color);
127        color = *off_color;
128        gdk_rgb_find_color (gdk_drawable_get_colormap (e->window), &color);
129        gdk_gc_set_background (gc, &color);
130        gdk_gc_set_line_attributes (gc, 1, GDK_LINE_DOUBLE_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND);
131        gdk_gc_set_dashes (gc, offset, dashes, 2);
132        gdk_draw_rectangle (e->window, gc, 0, x1, y1, x2 - x1, y2 - y1);
133        g_object_unref (gc);
134}
135
136static gint cursor_enabled = TRUE;
137
138static inline void
139refresh_under_cursor (HTMLEngine *e, HTMLCursorRectangle *cr, gboolean *enabled)
140{
141        if (cr->x1 > cr->x2 || cr->y1 > cr->y2)
142                return;
143
144        *enabled = cursor_enabled = FALSE;
145        html_engine_draw (e, cr->x1, cr->y1,
146                          cr->x2 - cr->x1 + 1, cr->y2 - cr->y1 + 1);
147        *enabled = cursor_enabled = TRUE;
148}
149
150#define COLORS(x) animate ? &x ## _stipple_active_on  : &x ## _stipple_non_active_on, \
151                  animate ? &x ## _stipple_active_off : &x ## _stipple_non_active_off
152
153static void
154html_engine_draw_image_cursor (HTMLEngine *e)
155{
156        HTMLCursorRectangle *cr;
157        HTMLObject *io;
158        static gboolean enabled = TRUE;
159
160        if (!enabled)
161                return;
162
163        cr    = &e->cursor_image;
164        io    = e->cursor->object;
165
166        if (io && HTML_IS_IMAGE (e->cursor->object)) {
167                HTMLImage *image;
168                static gint offset = 3;
169
170                image = HTML_IMAGE (io);
171                if (io != cr->object) {
172                        if (cr->object)
173                                refresh_under_cursor (e, cr, &enabled);
174                        cr->object = io;
175                }
176
177                html_object_calc_abs_position (io, &cr->x1, &cr->y1);
178                cr->x2 = cr->x1 + io->width - 1;
179                cr->y2 = cr->y1 + io->descent - 1;
180                cr->y1 -= io->ascent;
181
182                draw_cursor_rectangle (e, cr->x1, cr->y1, cr->x2, cr->y2,
183                                       &image_stipple_active_on, &image_stipple_active_off, offset);
184                if (!offset)
185                        offset = 3;
186                else
187                        offset--;
188        } else
189                if (cr->object) {
190                        refresh_under_cursor (e, cr, &enabled);
191                        cr->object = NULL;
192                }
193}
194
195void
196html_engine_draw_cell_cursor (HTMLEngine *e)
197{
198        HTMLCursorRectangle *cr;
199        HTMLTableCell *cell;
200        HTMLObject    *co;
201        static gboolean enabled = TRUE;
202
203        if (!enabled)
204                return;
205
206        cr   = &e->cursor_cell;
207        cell = html_engine_get_table_cell (e);
208        co   = HTML_OBJECT (cell);
209
210        if (cell) {
211                static gint offset = 0;
212                gboolean animate;
213
214                if (co != cr->object) {
215                        if (cr->object)
216                                refresh_under_cursor (e, cr, &enabled);
217                        cr->object = co;
218                }
219
220                html_object_calc_abs_position (co, &cr->x1, &cr->y2);
221                cr->x2  = cr->x1 + co->width - 1;
222                cr->y2 -= 2;
223                cr->y1  = cr->y2 - (co->ascent + co->descent - 2);
224
225                animate = !HTML_IS_IMAGE (e->cursor->object);
226                if (animate) {
227                        offset++;
228                        offset %= 4;
229                }
230                draw_cursor_rectangle (e, cr->x1, cr->y1, cr->x2, cr->y2, COLORS (cell), offset);
231        } else
232                if (cr->object) {
233                        refresh_under_cursor (e, cr, &enabled);
234                        cr->object = NULL;
235                }
236}
237
238void
239html_engine_draw_table_cursor (HTMLEngine *e)
240{
241        HTMLCursorRectangle *cr;
242        HTMLTable *table;
243        HTMLObject *to;
244        static gboolean enabled = TRUE;
245
246        if (!enabled)
247                return;
248
249        cr    = &e->cursor_table;
250        table = html_engine_get_table (e);
251        to    = HTML_OBJECT (table);
252
253        if (table) {
254                static gint offset = 0;
255                gboolean animate;
256
257                if (to != cr->object) {
258                        if (cr->object)
259                                refresh_under_cursor (e, cr, &enabled);
260                        cr->object = to;
261                }
262
263                html_object_calc_abs_position (to, &cr->x1, &cr->y2);
264                cr->x2 = cr->x1 + to->width - 1;
265                cr->y2 --;
266                cr->y1 = cr->y2 - (to->ascent + to->descent - 1);
267
268                animate = HTML_IS_TABLE (e->cursor->object) && !html_engine_get_table_cell (e);
269                if (animate) {
270                        offset++;
271                        offset %= 4;
272                }
273                draw_cursor_rectangle (e, cr->x1, cr->y1, cr->x2, cr->y2, COLORS (table), offset);
274        } else
275                if (cr->object) {
276                        refresh_under_cursor (e, cr, &enabled);
277                        cr->object = NULL;
278                }
279}
280
281void
282html_engine_draw_cursor_in_area (HTMLEngine *engine,
283                                 gint x, gint y,
284                                 gint width, gint height)
285{
286        HTMLObject *obj;
287        guint offset;
288        gint x1, y1, x2, y2;
289        GdkRectangle pos;
290
291        if ((engine->editable || engine->caret_mode) && (engine->cursor_hide_count <= 0 && !engine->thaw_idle_id)) {
292                html_engine_draw_table_cursor (engine);
293                html_engine_draw_cell_cursor (engine);
294                html_engine_draw_image_cursor (engine);
295        }
296
297        if (!cursor_enabled || engine->cursor_hide_count > 0 || !(engine->editable || engine->caret_mode) || engine->thaw_idle_id)
298                return;
299
300        obj = engine->cursor->object;
301        if (obj == NULL)
302                return;
303
304        offset = engine->cursor->offset;
305
306        if (width < 0 || height < 0) {
307                width = html_engine_get_doc_width (engine);
308                height = html_engine_get_doc_height (engine);
309                x = 0;
310                y = 0;
311        }
312
313       
314        html_object_get_cursor (obj, engine->painter, offset, &x1, &y1, &x2, &y2);
315        while (obj) {
316                if (html_object_is_frame(obj)) {
317                        x1 -= HTML_EMBEDDED(obj)->abs_x;
318                        x2 -= HTML_EMBEDDED(obj)->abs_x;
319                        y1 -= HTML_EMBEDDED(obj)->abs_y;
320                        y2 -= HTML_EMBEDDED(obj)->abs_y;
321                        break;
322                }
323                obj = obj->parent;
324        }
325       
326        pos.x = x1;
327        pos.y = y1;
328        pos.width = x2 - x1;
329        pos.height = y2 - y1;
330        gtk_im_context_set_cursor_location (GTK_HTML (engine->widget)->priv->im_context, &pos);
331
332        if (clip_cursor (engine, x, y, width, height, &x1, &y1, &x2, &y2)) {
333                gdk_draw_line (engine->window, engine->invert_gc, x1, y1, x2, y2);
334        }
335}
336
337
338/* Blinking cursor implementation.  */
339
340static gint
341blink_timeout_cb (gpointer data)
342{
343        HTMLEngine *engine;
344
345        g_return_val_if_fail (HTML_IS_ENGINE (data), FALSE);
346        engine = HTML_ENGINE (data);
347
348        engine->blinking_status = ! engine->blinking_status;
349
350        if (engine->blinking_status)
351                html_engine_show_cursor (engine);
352        else
353                html_engine_hide_cursor (engine);
354
355        return TRUE;
356}
357
358void
359html_engine_setup_blinking_cursor (HTMLEngine *engine)
360{
361        g_return_if_fail (engine != NULL);
362        g_return_if_fail (HTML_IS_ENGINE (engine));
363        g_return_if_fail (engine->blinking_timer_id == 0);
364
365        html_engine_show_cursor (engine);
366        engine->blinking_status = FALSE;
367
368        blink_timeout_cb (engine);
369        engine->blinking_timer_id = gtk_timeout_add (BLINK_TIMEOUT, blink_timeout_cb, engine);
370}
371
372void
373html_engine_stop_blinking_cursor (HTMLEngine *engine)
374{
375        g_return_if_fail (engine != NULL);
376        g_return_if_fail (HTML_IS_ENGINE (engine));
377        g_return_if_fail (engine->blinking_timer_id != 0);
378
379        if (engine->blinking_status) {
380                html_engine_hide_cursor (engine);
381                engine->blinking_status = FALSE;
382        }
383
384        gtk_timeout_remove (engine->blinking_timer_id);
385        engine->blinking_timer_id = 0;
386}
387
388void
389html_engine_reset_blinking_cursor (HTMLEngine *engine)
390{
391        g_return_if_fail (engine != NULL);
392        g_return_if_fail (HTML_IS_ENGINE (engine));
393        g_return_if_fail (engine->blinking_timer_id != 0);
394
395        if (engine->blinking_status)
396                return;
397
398        html_engine_show_cursor (engine);
399        engine->blinking_status = TRUE;
400        gtk_timeout_remove (engine->blinking_timer_id);
401        engine->blinking_timer_id = gtk_timeout_add (BLINK_TIMEOUT, blink_timeout_cb, engine);
402}
Note: See TracBrowser for help on using the repository browser.