1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
---|
2 | /* |
---|
3 | Copyright (C) 1997 Martin Jones (mjones@kde.org) |
---|
4 | (C) 1997 Torben Weis (weis@kde.org) |
---|
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 "htmlcluealigned.h" |
---|
24 | #include "htmlcluev.h" |
---|
25 | #include "htmlengine.h" |
---|
26 | #include "htmlpainter.h" |
---|
27 | |
---|
28 | |
---|
29 | HTMLClueVClass html_cluev_class; |
---|
30 | |
---|
31 | static HTMLClueClass *parent_class = NULL; |
---|
32 | |
---|
33 | |
---|
34 | /* FIXME this must be rewritten as the multiple type casts make my head spin. |
---|
35 | The types in `HTMLClueAligned' are chosen wrong. */ |
---|
36 | static void |
---|
37 | remove_aligned_by_parent ( HTMLClueV *cluev, |
---|
38 | HTMLObject *p ) |
---|
39 | { |
---|
40 | HTMLClueAligned *tmp; |
---|
41 | HTMLObject *obj; |
---|
42 | |
---|
43 | tmp = 0; |
---|
44 | obj = cluev->align_left_list; |
---|
45 | |
---|
46 | while ( obj ) { |
---|
47 | if ( obj->parent == p ) { |
---|
48 | if ( tmp ) { |
---|
49 | tmp->next_aligned = HTML_CLUEALIGNED (obj)->next_aligned; |
---|
50 | tmp = HTML_CLUEALIGNED (obj); |
---|
51 | } else { |
---|
52 | cluev->align_left_list |
---|
53 | = HTML_OBJECT (HTML_CLUEALIGNED (obj)->next_aligned); |
---|
54 | tmp = 0; |
---|
55 | } |
---|
56 | } else { |
---|
57 | tmp = HTML_CLUEALIGNED (obj); |
---|
58 | } |
---|
59 | |
---|
60 | obj = HTML_OBJECT (HTML_CLUEALIGNED (obj)->next_aligned); |
---|
61 | } |
---|
62 | |
---|
63 | tmp = 0; |
---|
64 | obj = cluev->align_right_list; |
---|
65 | |
---|
66 | while ( obj ) { |
---|
67 | if ( obj->parent == p ) { |
---|
68 | if ( tmp ) { |
---|
69 | tmp->next_aligned = HTML_CLUEALIGNED (obj)->next_aligned; |
---|
70 | tmp = HTML_CLUEALIGNED (obj); |
---|
71 | } else { |
---|
72 | cluev->align_right_list |
---|
73 | = HTML_OBJECT (HTML_CLUEALIGNED (obj)->next_aligned); |
---|
74 | tmp = 0; |
---|
75 | } |
---|
76 | } else { |
---|
77 | tmp = HTML_CLUEALIGNED (obj); |
---|
78 | } |
---|
79 | |
---|
80 | obj = HTML_OBJECT (HTML_CLUEALIGNED (obj)->next_aligned); |
---|
81 | } |
---|
82 | } |
---|
83 | |
---|
84 | static HTMLObject * |
---|
85 | cluev_next_aligned (HTMLObject *aclue) |
---|
86 | { |
---|
87 | return HTML_OBJECT (HTML_CLUEALIGNED (aclue)->next_aligned); |
---|
88 | } |
---|
89 | |
---|
90 | static gint |
---|
91 | get_lmargin (HTMLObject *o, HTMLPainter *painter) |
---|
92 | { |
---|
93 | return HTML_CLUEV (o)->padding * html_painter_get_pixel_size (painter) |
---|
94 | + (o->parent ? html_object_get_left_margin (o->parent, painter, o->y, TRUE) : 0); |
---|
95 | } |
---|
96 | |
---|
97 | static void |
---|
98 | add_clear_area_behind (GList **changed_objs, HTMLObject *o, gint x, gint y, gint w, gint h) |
---|
99 | { |
---|
100 | HTMLObjectClearRectangle *cr; |
---|
101 | |
---|
102 | cr = g_new (HTMLObjectClearRectangle, 1); |
---|
103 | |
---|
104 | cr->object = o; |
---|
105 | cr->x = x; |
---|
106 | cr->y = y; |
---|
107 | cr->width = w; |
---|
108 | cr->height = h; |
---|
109 | |
---|
110 | *changed_objs = g_list_prepend (*changed_objs, cr); |
---|
111 | /* NULL meens: clear rectangle follows */ |
---|
112 | *changed_objs = g_list_prepend (*changed_objs, NULL); |
---|
113 | } |
---|
114 | |
---|
115 | static gboolean |
---|
116 | do_layout (HTMLObject *o, HTMLPainter *painter, gboolean calc_size, GList **changed_objs) |
---|
117 | { |
---|
118 | HTMLClueV *cluev; |
---|
119 | HTMLClue *clue; |
---|
120 | HTMLObject *obj; |
---|
121 | HTMLObject *aclue; |
---|
122 | GList *local_changed_objs; |
---|
123 | gint lmargin; |
---|
124 | gboolean changed; |
---|
125 | gint old_width, old_ascent, old_descent; |
---|
126 | gint new_x; |
---|
127 | gint pixel_size; |
---|
128 | gint padding; |
---|
129 | gint padding2; |
---|
130 | gboolean first_change; |
---|
131 | gint first_y_off = 0; |
---|
132 | |
---|
133 | /* printf ("HTMLClueV::do_layout\n"); */ |
---|
134 | |
---|
135 | cluev = HTML_CLUEV (o); |
---|
136 | clue = HTML_CLUE (o); |
---|
137 | |
---|
138 | pixel_size = html_painter_get_pixel_size (painter); |
---|
139 | padding = pixel_size * cluev->padding; |
---|
140 | padding2 = 2 * padding; |
---|
141 | |
---|
142 | old_width = o->width; |
---|
143 | old_ascent = o->ascent; |
---|
144 | old_descent = o->descent; |
---|
145 | |
---|
146 | changed = FALSE; |
---|
147 | first_change = TRUE; |
---|
148 | local_changed_objs = NULL; |
---|
149 | |
---|
150 | lmargin = get_lmargin (o, painter); |
---|
151 | |
---|
152 | /* If we have already called calc_size for the children, then just |
---|
153 | continue from the last object done in previous call. */ |
---|
154 | |
---|
155 | if (clue->curr != NULL) { |
---|
156 | if (clue->curr->prev) |
---|
157 | o->ascent = clue->curr->prev->y + clue->curr->prev->descent; |
---|
158 | else |
---|
159 | o->ascent = padding; |
---|
160 | remove_aligned_by_parent (cluev, clue->curr); |
---|
161 | } else { |
---|
162 | o->width = 0; |
---|
163 | o->ascent = padding; |
---|
164 | o->descent = 0; |
---|
165 | clue->curr = clue->head; |
---|
166 | } |
---|
167 | |
---|
168 | while (clue->curr != NULL) { |
---|
169 | gint old_y, old_y_off, new_y_off; |
---|
170 | /* Set an initial ypos so that the alignment stuff knows where |
---|
171 | the top of this object is */ |
---|
172 | old_y = clue->curr->y; |
---|
173 | old_y_off = clue->curr->y - clue->curr->ascent; |
---|
174 | clue->curr->y = o->ascent; |
---|
175 | |
---|
176 | switch (html_object_get_clear (clue->curr)) { |
---|
177 | case HTML_CLEAR_ALL: { |
---|
178 | gint y; |
---|
179 | |
---|
180 | do { |
---|
181 | y = clue->curr->y; |
---|
182 | clue->curr->y = html_clue_get_left_clear (clue, clue->curr->y); |
---|
183 | clue->curr->y = html_clue_get_right_clear (clue, clue->curr->y); |
---|
184 | } while (clue->curr->y != y); |
---|
185 | break; |
---|
186 | } |
---|
187 | case HTML_CLEAR_LEFT: |
---|
188 | clue->curr->y = html_clue_get_left_clear (clue, clue->curr->y); |
---|
189 | break; |
---|
190 | case HTML_CLEAR_RIGHT: |
---|
191 | clue->curr->y = html_clue_get_right_clear (clue, clue->curr->y); |
---|
192 | break; |
---|
193 | case HTML_CLEAR_NONE: |
---|
194 | break; |
---|
195 | } |
---|
196 | |
---|
197 | o->ascent = clue->curr->y; |
---|
198 | lmargin = get_lmargin (o, painter); |
---|
199 | |
---|
200 | |
---|
201 | if (calc_size) |
---|
202 | changed |= html_object_calc_size (clue->curr, painter, changed_objs); |
---|
203 | |
---|
204 | if (o->width < clue->curr->width + padding2) |
---|
205 | o->width = clue->curr->width + padding2; |
---|
206 | o->ascent += clue->curr->ascent + clue->curr->descent; |
---|
207 | |
---|
208 | new_y_off = o->ascent - clue->curr->descent - clue->curr->ascent; |
---|
209 | if (clue->curr->x != lmargin || old_y_off != new_y_off) { |
---|
210 | if (changed_objs) { |
---|
211 | /* printf ("y: %d ", o->ascent - clue->curr->descent); */ |
---|
212 | if (first_change) { |
---|
213 | first_change = FALSE; |
---|
214 | /* if it's new one (y == 0) clear from new y_off, else from old one or new one, |
---|
215 | which one is higher */ |
---|
216 | first_y_off = old_y && old_y_off < new_y_off ? old_y_off : new_y_off; |
---|
217 | /* printf ("\nfirst_y_off: %d x %d --> %d\n", old_y_off, new_y_off, first_y_off); */ |
---|
218 | } |
---|
219 | html_object_add_to_changed (&local_changed_objs, clue->curr); |
---|
220 | } |
---|
221 | } |
---|
222 | clue->curr->x = lmargin; |
---|
223 | clue->curr->y = o->ascent - clue->curr->descent; |
---|
224 | |
---|
225 | clue->curr = clue->curr->next; |
---|
226 | } |
---|
227 | |
---|
228 | o->ascent += padding; |
---|
229 | |
---|
230 | /* Remember the last object so that we can start from here next time |
---|
231 | we are called. */ |
---|
232 | clue->curr = clue->tail; |
---|
233 | |
---|
234 | if (o->max_width != 0 && o->width < o->max_width) |
---|
235 | o->width = o->max_width; |
---|
236 | |
---|
237 | if (clue->halign == HTML_HALIGN_CENTER) { |
---|
238 | for (obj = clue->head; obj != 0; obj = obj->next) { |
---|
239 | new_x = lmargin + (o->width - obj->width - padding2) / 2; |
---|
240 | if (obj->x != new_x) { |
---|
241 | obj->x = new_x; |
---|
242 | changed = TRUE; |
---|
243 | } |
---|
244 | } |
---|
245 | } else if (clue->halign == HTML_HALIGN_RIGHT) { |
---|
246 | for (obj = clue->head; obj != 0; obj = obj->next) { |
---|
247 | new_x = lmargin + (o->width - obj->width - padding2); |
---|
248 | if (obj->x != new_x) { |
---|
249 | obj->x = new_x; |
---|
250 | changed = TRUE; |
---|
251 | } |
---|
252 | } |
---|
253 | } |
---|
254 | |
---|
255 | for (aclue = cluev->align_left_list; aclue != NULL; aclue = cluev_next_aligned (aclue)) { |
---|
256 | if (aclue->y + aclue->parent->y - aclue->parent->ascent > o->ascent) |
---|
257 | o->ascent = aclue->y + aclue->parent->y - aclue->parent->ascent; |
---|
258 | } |
---|
259 | |
---|
260 | for (aclue = cluev->align_right_list; aclue != NULL; aclue = cluev_next_aligned (aclue)) { |
---|
261 | if (aclue->y + aclue->parent->y - aclue->parent->ascent > o->ascent) |
---|
262 | o->ascent = aclue->y + aclue->parent->y - aclue->parent->ascent; |
---|
263 | } |
---|
264 | |
---|
265 | if (! changed |
---|
266 | && (o->ascent != old_ascent || o->descent != old_descent || o->width != old_width)) |
---|
267 | changed = TRUE; |
---|
268 | |
---|
269 | if (changed_objs && local_changed_objs) { |
---|
270 | if (!first_change && o->width > o->max_width) { |
---|
271 | add_clear_area_behind (changed_objs, o, o->max_width, first_y_off, |
---|
272 | o->width - o->max_width, o->ascent + o->descent - first_y_off); |
---|
273 | } |
---|
274 | *changed_objs = g_list_concat (local_changed_objs, *changed_objs); |
---|
275 | } |
---|
276 | |
---|
277 | return changed; |
---|
278 | } |
---|
279 | |
---|
280 | |
---|
281 | /* HTMLObject methods. */ |
---|
282 | |
---|
283 | static void |
---|
284 | copy (HTMLObject *self, |
---|
285 | HTMLObject *dest) |
---|
286 | { |
---|
287 | (* HTML_OBJECT_CLASS (parent_class)->copy) (self, dest); |
---|
288 | |
---|
289 | HTML_CLUEV (dest)->padding = HTML_CLUEV (self)->padding; |
---|
290 | |
---|
291 | HTML_CLUEV (dest)->align_left_list = NULL; |
---|
292 | HTML_CLUEV (dest)->align_right_list = NULL; |
---|
293 | } |
---|
294 | |
---|
295 | static gboolean |
---|
296 | calc_size (HTMLObject *o, HTMLPainter *painter, GList **changed_objs) |
---|
297 | { |
---|
298 | return do_layout (o, painter, TRUE, changed_objs); |
---|
299 | } |
---|
300 | |
---|
301 | static gint |
---|
302 | calc_min_width (HTMLObject *o, |
---|
303 | HTMLPainter *painter) |
---|
304 | { |
---|
305 | return (* HTML_OBJECT_CLASS (parent_class)->calc_min_width) (o, painter) |
---|
306 | + 2 * html_painter_get_pixel_size (painter) * HTML_CLUEV (o)->padding; |
---|
307 | } |
---|
308 | |
---|
309 | static gint |
---|
310 | calc_preferred_width (HTMLObject *o, |
---|
311 | HTMLPainter *painter) |
---|
312 | { |
---|
313 | return (* HTML_OBJECT_CLASS (parent_class)->calc_preferred_width) (o, painter) |
---|
314 | + 2 * html_painter_get_pixel_size (painter) * HTML_CLUEV (o)->padding; |
---|
315 | } |
---|
316 | |
---|
317 | static void |
---|
318 | set_max_width (HTMLObject *o, HTMLPainter *painter, gint max_width) |
---|
319 | { |
---|
320 | HTMLObject *obj; |
---|
321 | |
---|
322 | o->max_width = max_width; |
---|
323 | max_width -= 2 * HTML_CLUEV (o)->padding * html_painter_get_pixel_size (painter); |
---|
324 | for (obj = HTML_CLUE (o)->head; obj != NULL; obj = obj->next) |
---|
325 | html_object_set_max_width (obj, painter, max_width); |
---|
326 | } |
---|
327 | |
---|
328 | static void |
---|
329 | reset (HTMLObject *clue) |
---|
330 | { |
---|
331 | HTMLClueV *cluev; |
---|
332 | |
---|
333 | cluev = HTML_CLUEV (clue); |
---|
334 | |
---|
335 | HTML_OBJECT_CLASS (&html_clue_class)->reset (clue); |
---|
336 | |
---|
337 | cluev->align_left_list = NULL; |
---|
338 | cluev->align_right_list = NULL; |
---|
339 | } |
---|
340 | |
---|
341 | static void |
---|
342 | draw (HTMLObject *o, |
---|
343 | HTMLPainter *p, |
---|
344 | gint x, gint y, |
---|
345 | gint width, gint height, |
---|
346 | gint tx, gint ty) |
---|
347 | { |
---|
348 | HTMLObject *aclue; |
---|
349 | |
---|
350 | HTML_OBJECT_CLASS (&html_clue_class)->draw (o, |
---|
351 | p, |
---|
352 | x, y , |
---|
353 | width, height, |
---|
354 | tx, ty); |
---|
355 | |
---|
356 | if (y + height < o->y - o->ascent || y > o->y + o->descent) |
---|
357 | return; |
---|
358 | |
---|
359 | tx += o->x; |
---|
360 | ty += o->y - o->ascent; |
---|
361 | |
---|
362 | for ( aclue = HTML_CLUEV (o)->align_left_list; |
---|
363 | aclue != NULL; |
---|
364 | aclue = cluev_next_aligned (aclue) ) { |
---|
365 | html_object_draw (aclue, |
---|
366 | p, |
---|
367 | x - o->x - aclue->parent->x, |
---|
368 | y - (o->y - o->ascent) - (aclue->parent->y - aclue->parent->ascent), |
---|
369 | width - aclue->parent->x, height, |
---|
370 | tx + aclue->parent->x, |
---|
371 | ty + aclue->parent->y - aclue->parent->ascent); |
---|
372 | } |
---|
373 | |
---|
374 | for (aclue = HTML_CLUEV (o)->align_right_list; |
---|
375 | aclue != NULL; |
---|
376 | aclue = cluev_next_aligned (aclue)) { |
---|
377 | html_object_draw (aclue, |
---|
378 | p, |
---|
379 | x - o->x - aclue->parent->x, |
---|
380 | y - (o->y - o->ascent) - (aclue->parent->y - aclue->parent->ascent), |
---|
381 | width - aclue->parent->x, height, |
---|
382 | tx + aclue->parent->x, |
---|
383 | ty + aclue->parent->y - aclue->parent->ascent); |
---|
384 | } |
---|
385 | } |
---|
386 | |
---|
387 | static HTMLObject * |
---|
388 | check_point (HTMLObject *self, |
---|
389 | HTMLPainter *painter, |
---|
390 | gint x, gint y, |
---|
391 | guint *offset_return, |
---|
392 | gboolean for_cursor) |
---|
393 | { |
---|
394 | HTMLObject *p; |
---|
395 | HTMLObject *obj; |
---|
396 | HTMLClueAligned *clue; |
---|
397 | |
---|
398 | if (x < self->x || x >= self->x + self->width |
---|
399 | || y < self->y - self->ascent || y >= self->y + self->descent) |
---|
400 | return NULL; |
---|
401 | |
---|
402 | x = x - self->x; |
---|
403 | y = y - self->y + self->ascent; |
---|
404 | |
---|
405 | for (clue = HTML_CLUEALIGNED (HTML_CLUEV (self)->align_left_list); |
---|
406 | clue != NULL; |
---|
407 | clue = clue->next_aligned) { |
---|
408 | HTMLObject *parent; |
---|
409 | |
---|
410 | parent = HTML_OBJECT (clue)->parent; |
---|
411 | obj = html_object_check_point (HTML_OBJECT (clue), |
---|
412 | painter, |
---|
413 | x - HTML_OBJECT (clue)->parent->x, |
---|
414 | y - HTML_OBJECT (clue)->parent->y + HTML_OBJECT (clue)->parent->ascent, |
---|
415 | offset_return, |
---|
416 | for_cursor); |
---|
417 | if (obj != NULL) { |
---|
418 | return obj; |
---|
419 | } |
---|
420 | } |
---|
421 | |
---|
422 | for (clue = HTML_CLUEALIGNED (HTML_CLUEV (self)->align_right_list); |
---|
423 | clue != NULL; |
---|
424 | clue = clue->next_aligned) { |
---|
425 | HTMLObject *parent; |
---|
426 | |
---|
427 | parent = HTML_OBJECT (clue)->parent; |
---|
428 | obj = html_object_check_point (HTML_OBJECT (clue), |
---|
429 | painter, |
---|
430 | x - HTML_OBJECT (clue)->parent->x, |
---|
431 | y - HTML_OBJECT (clue)->parent->y + HTML_OBJECT (clue)->parent->ascent, |
---|
432 | offset_return, |
---|
433 | for_cursor); |
---|
434 | if (obj != NULL) { |
---|
435 | return obj; |
---|
436 | } |
---|
437 | } |
---|
438 | |
---|
439 | for (p = HTML_CLUE (self)->head; p != 0; p = p->next) { |
---|
440 | gint x1, y1; |
---|
441 | |
---|
442 | if (! for_cursor) { |
---|
443 | x1 = x; |
---|
444 | y1 = y; |
---|
445 | } else { |
---|
446 | if (x >= p->x + p->width) { |
---|
447 | x1 = MAX (0, p->x + p->width - 1); |
---|
448 | } else if (x < p->x) { |
---|
449 | x1 = p->x; |
---|
450 | } else { |
---|
451 | x1 = x; |
---|
452 | } |
---|
453 | |
---|
454 | if (p->next == NULL && y > p->y + p->descent - 1) { |
---|
455 | x1 = MAX (0, p->x + p->width - 1); |
---|
456 | y1 = p->y + p->descent - 1; |
---|
457 | } else if (p->prev == NULL && y < p->y - p->ascent) { |
---|
458 | y1 = p->y - p->ascent; |
---|
459 | } else { |
---|
460 | y1 = y; |
---|
461 | } |
---|
462 | } |
---|
463 | |
---|
464 | obj = html_object_check_point (p, painter, x1, y1, offset_return, for_cursor); |
---|
465 | if (obj != NULL) |
---|
466 | return obj; |
---|
467 | } |
---|
468 | |
---|
469 | return NULL; |
---|
470 | } |
---|
471 | |
---|
472 | static gboolean |
---|
473 | relayout (HTMLObject *self, |
---|
474 | HTMLEngine *engine, |
---|
475 | HTMLObject *child) |
---|
476 | { |
---|
477 | gint prev_width, prev_ascent, prev_descent; |
---|
478 | gboolean changed; |
---|
479 | |
---|
480 | if (html_engine_frozen (engine)) |
---|
481 | return FALSE; |
---|
482 | |
---|
483 | if (child == NULL) |
---|
484 | child = HTML_CLUE (self)->head; |
---|
485 | html_object_calc_size (child, engine->painter, FALSE); |
---|
486 | |
---|
487 | HTML_CLUE (self)->curr = NULL; |
---|
488 | |
---|
489 | prev_width = self->width; |
---|
490 | prev_ascent = self->ascent; |
---|
491 | prev_descent = self->descent; |
---|
492 | |
---|
493 | changed = do_layout (self, engine->painter, FALSE, FALSE); |
---|
494 | if (changed) |
---|
495 | html_engine_queue_draw (engine, self); |
---|
496 | |
---|
497 | if (prev_width == self->width |
---|
498 | && prev_ascent == self->ascent |
---|
499 | && prev_descent == self->descent) |
---|
500 | return FALSE; |
---|
501 | |
---|
502 | if (self->parent == NULL) { |
---|
503 | /* FIXME resize the widget, e.g. scrollbars and such. */ |
---|
504 | html_engine_queue_draw (engine, self); |
---|
505 | |
---|
506 | /* FIXME extreme ugliness. */ |
---|
507 | self->x = 0; |
---|
508 | self->y = self->ascent; |
---|
509 | } else { |
---|
510 | /* Relayout our parent starting from us. */ |
---|
511 | if (! html_object_relayout (self->parent, engine, self)) |
---|
512 | html_engine_queue_draw (engine, self); |
---|
513 | } |
---|
514 | |
---|
515 | /* If the object has shrunk, we have to clean the areas around |
---|
516 | it so that we don't leave garbage on the screen. FIXME: |
---|
517 | this wastes some time if there is an object on the right of |
---|
518 | or under this one. */ |
---|
519 | |
---|
520 | if (prev_ascent + prev_descent > self->ascent + self->descent) |
---|
521 | html_engine_queue_clear (engine, |
---|
522 | self->x, |
---|
523 | self->y + self->descent, |
---|
524 | self->width, |
---|
525 | (prev_ascent + prev_descent |
---|
526 | - (self->ascent + self->descent))); |
---|
527 | |
---|
528 | if (prev_width > self->width) |
---|
529 | html_engine_queue_clear (engine, |
---|
530 | self->x + self->width, |
---|
531 | self->y - self->ascent, |
---|
532 | prev_width - self->width, |
---|
533 | self->ascent + self->descent); |
---|
534 | |
---|
535 | return TRUE; |
---|
536 | } |
---|
537 | |
---|
538 | static gint |
---|
539 | get_left_margin (HTMLObject *self, HTMLPainter *painter, gint y, gboolean with_aligned) |
---|
540 | { |
---|
541 | HTMLObject *aclue; |
---|
542 | HTMLClueV *cluev; |
---|
543 | gint margin; |
---|
544 | |
---|
545 | cluev = HTML_CLUEV (self); |
---|
546 | margin = 0; |
---|
547 | |
---|
548 | if (with_aligned) |
---|
549 | for (aclue = cluev->align_left_list; |
---|
550 | aclue != NULL; |
---|
551 | aclue = cluev_next_aligned (aclue)) { |
---|
552 | if ((aclue->y - aclue->ascent + aclue->parent->y - aclue->parent->ascent |
---|
553 | <= y) |
---|
554 | && (aclue->y + aclue->parent->y - aclue->parent->ascent |
---|
555 | > y)) |
---|
556 | margin = aclue->x + aclue->width; |
---|
557 | } |
---|
558 | |
---|
559 | return margin; |
---|
560 | } |
---|
561 | |
---|
562 | static gint |
---|
563 | get_right_margin (HTMLObject *self, HTMLPainter *painter, gint y, gboolean with_aligned) |
---|
564 | { |
---|
565 | HTMLClueV *cluev; |
---|
566 | /* FIXME: Should be HTMLAligned */ |
---|
567 | HTMLObject *aclue; |
---|
568 | gint margin; |
---|
569 | |
---|
570 | cluev = HTML_CLUEV (self); |
---|
571 | margin = self->max_width - 2 * cluev->padding * html_painter_get_pixel_size (painter); |
---|
572 | |
---|
573 | if (with_aligned) |
---|
574 | for (aclue = cluev->align_right_list; |
---|
575 | aclue != NULL; |
---|
576 | aclue = cluev_next_aligned (aclue)) { |
---|
577 | if ((aclue->y - aclue->ascent + aclue->parent->y - aclue->parent->ascent) <= y |
---|
578 | && aclue->y + aclue->parent->y - aclue->parent->ascent > y) |
---|
579 | margin = aclue->x; |
---|
580 | } |
---|
581 | |
---|
582 | return margin; |
---|
583 | } |
---|
584 | |
---|
585 | |
---|
586 | /* HTMLClue methods. */ |
---|
587 | |
---|
588 | static void |
---|
589 | find_free_area (HTMLClue *clue, HTMLPainter *painter, gint y, gint width, gint height, |
---|
590 | gint indent, gint *y_pos, gint *_lmargin, gint *_rmargin) |
---|
591 | { |
---|
592 | HTMLClueV *cluev = HTML_CLUEV (clue); |
---|
593 | gint try_y = y; |
---|
594 | gint lmargin; |
---|
595 | gint rmargin; |
---|
596 | gint lm, rm; |
---|
597 | HTMLObject *aclue; |
---|
598 | gint next_y, top_y, base_y=0; |
---|
599 | |
---|
600 | next_y = 0; |
---|
601 | while (1) { |
---|
602 | lmargin = indent; |
---|
603 | rmargin = HTML_OBJECT (clue)->max_width - 2 * cluev->padding * html_painter_get_pixel_size (painter); |
---|
604 | |
---|
605 | for (aclue = cluev->align_left_list; aclue != 0; aclue = cluev_next_aligned (aclue)) { |
---|
606 | base_y = (aclue->y + aclue->parent->y |
---|
607 | - aclue->parent->ascent); |
---|
608 | top_y = base_y - aclue->ascent; |
---|
609 | |
---|
610 | if ((top_y < try_y + height) && (base_y > try_y)) { |
---|
611 | lm = aclue->x + aclue->width; |
---|
612 | if (lm > lmargin) |
---|
613 | lmargin = lm; |
---|
614 | |
---|
615 | if ((next_y == 0) || (base_y < next_y)) { |
---|
616 | next_y = base_y; |
---|
617 | |
---|
618 | } |
---|
619 | } |
---|
620 | } |
---|
621 | |
---|
622 | for (aclue = cluev->align_right_list; aclue != 0; aclue = cluev_next_aligned (aclue)) { |
---|
623 | base_y = (aclue->y + aclue->parent->y |
---|
624 | - aclue->parent->ascent); |
---|
625 | top_y = base_y - aclue->ascent; |
---|
626 | |
---|
627 | if ((top_y < try_y + height) && (base_y > try_y)) { |
---|
628 | rm = aclue->x; |
---|
629 | if (rm < rmargin) |
---|
630 | rmargin = rm; |
---|
631 | |
---|
632 | if ((next_y == 0) || (base_y < next_y)) { |
---|
633 | next_y = base_y; |
---|
634 | } |
---|
635 | } |
---|
636 | } |
---|
637 | |
---|
638 | if (lmargin == indent |
---|
639 | && rmargin == MAX (HTML_OBJECT (clue)->max_width, HTML_OBJECT (clue)->width)) |
---|
640 | break; |
---|
641 | |
---|
642 | if ((rmargin - lmargin) >= width) |
---|
643 | break; |
---|
644 | |
---|
645 | if (try_y == next_y) |
---|
646 | break; |
---|
647 | |
---|
648 | try_y = next_y; |
---|
649 | } |
---|
650 | |
---|
651 | *y_pos = MAX (y, try_y); |
---|
652 | |
---|
653 | *_rmargin = rmargin; |
---|
654 | *_lmargin = lmargin; |
---|
655 | } |
---|
656 | |
---|
657 | static gboolean |
---|
658 | appended (HTMLClue *clue, HTMLClue *aclue) |
---|
659 | { |
---|
660 | /* Returns whether aclue is already in the alignList */ |
---|
661 | HTMLClueAligned *aligned; |
---|
662 | |
---|
663 | if (aclue->halign == HTML_HALIGN_LEFT) { |
---|
664 | aligned = HTML_CLUEALIGNED (HTML_CLUEV (clue)->align_left_list); |
---|
665 | } |
---|
666 | else { |
---|
667 | aligned = HTML_CLUEALIGNED (HTML_CLUEV (clue)->align_right_list); |
---|
668 | } |
---|
669 | |
---|
670 | while (aligned) { |
---|
671 | if (aligned == HTML_CLUEALIGNED (aclue)) |
---|
672 | return TRUE; |
---|
673 | aligned = HTML_CLUEALIGNED (aligned->next_aligned); |
---|
674 | } |
---|
675 | return FALSE; |
---|
676 | } |
---|
677 | |
---|
678 | static void |
---|
679 | append_left_aligned (HTMLClue *clue, HTMLPainter *painter, HTMLClue *aclue, gint *lmargin, gint *rmargin, gint indent) |
---|
680 | { |
---|
681 | gint y_pos, y_inc; |
---|
682 | |
---|
683 | html_clue_find_free_area (clue, painter, |
---|
684 | HTML_OBJECT (aclue)->parent->y, |
---|
685 | HTML_OBJECT (aclue)->width, |
---|
686 | HTML_OBJECT (aclue)->ascent + HTML_OBJECT (aclue)->descent, |
---|
687 | indent, &y_pos, lmargin, rmargin); |
---|
688 | |
---|
689 | /* Set position */ |
---|
690 | y_inc = y_pos - HTML_OBJECT (aclue)->parent->y; |
---|
691 | |
---|
692 | HTML_OBJECT (aclue)->x = *lmargin; |
---|
693 | HTML_OBJECT (aclue)->y = HTML_OBJECT (aclue)->parent->ascent + HTML_OBJECT (aclue)->ascent + y_inc; |
---|
694 | |
---|
695 | /* Insert clue in align list */ |
---|
696 | if (!HTML_CLUEV (clue)->align_left_list) { |
---|
697 | HTML_CLUEV (clue)->align_left_list = HTML_OBJECT (aclue); |
---|
698 | HTML_CLUEALIGNED (aclue)->next_aligned = NULL; |
---|
699 | } else { |
---|
700 | HTMLClueAligned *obj = HTML_CLUEALIGNED (HTML_CLUEV (clue)->align_left_list); |
---|
701 | while (obj->next_aligned) { |
---|
702 | if (obj == HTML_CLUEALIGNED (aclue)) |
---|
703 | return; |
---|
704 | obj = obj->next_aligned; |
---|
705 | } |
---|
706 | if (obj == HTML_CLUEALIGNED (aclue)) |
---|
707 | return; |
---|
708 | |
---|
709 | obj->next_aligned = HTML_CLUEALIGNED (aclue); |
---|
710 | HTML_CLUEALIGNED (aclue)->next_aligned = NULL; |
---|
711 | } |
---|
712 | |
---|
713 | *lmargin += HTML_OBJECT (aclue)->width; |
---|
714 | } |
---|
715 | |
---|
716 | static void |
---|
717 | append_right_aligned (HTMLClue *clue, HTMLPainter *painter, HTMLClue *aclue, gint *lmargin, gint *rmargin, gint indent) |
---|
718 | { |
---|
719 | gint y_pos, y_inc; |
---|
720 | |
---|
721 | html_clue_find_free_area (clue, painter, HTML_OBJECT (aclue)->parent->y, |
---|
722 | HTML_OBJECT (aclue)->width, |
---|
723 | HTML_OBJECT (aclue)->ascent + HTML_OBJECT (aclue)->descent, indent, |
---|
724 | &y_pos, lmargin, rmargin); |
---|
725 | |
---|
726 | *rmargin -= HTML_OBJECT (aclue)->width; |
---|
727 | |
---|
728 | /* Set position */ |
---|
729 | y_inc = y_pos - HTML_OBJECT (aclue)->parent->y; |
---|
730 | |
---|
731 | HTML_OBJECT (aclue)->x = *rmargin; |
---|
732 | HTML_OBJECT (aclue)->y = HTML_OBJECT (aclue)->parent->ascent + HTML_OBJECT (aclue)->ascent + y_inc; |
---|
733 | |
---|
734 | /* Insert clue in align list */ |
---|
735 | if (!HTML_CLUEV (clue)->align_right_list) { |
---|
736 | HTML_CLUEV (clue)->align_right_list = HTML_OBJECT (aclue); |
---|
737 | HTML_CLUEALIGNED (aclue)->next_aligned = NULL; |
---|
738 | } else { |
---|
739 | HTMLClueAligned *obj = HTML_CLUEALIGNED (HTML_CLUEV (clue)->align_right_list); |
---|
740 | while (obj->next_aligned) { |
---|
741 | if (obj == HTML_CLUEALIGNED (aclue)) |
---|
742 | return; |
---|
743 | obj = obj->next_aligned; |
---|
744 | } |
---|
745 | if (obj == HTML_CLUEALIGNED (aclue)) |
---|
746 | return; |
---|
747 | |
---|
748 | obj->next_aligned = HTML_CLUEALIGNED (aclue); |
---|
749 | HTML_CLUEALIGNED (aclue)->next_aligned = NULL; |
---|
750 | } |
---|
751 | } |
---|
752 | |
---|
753 | static gint |
---|
754 | get_left_clear (HTMLClue *self, |
---|
755 | gint y) |
---|
756 | { |
---|
757 | HTMLObject *p; |
---|
758 | gint top_y, base_y; |
---|
759 | |
---|
760 | /* XXX we assume the parent's size has already been calculated here. */ |
---|
761 | |
---|
762 | for (p = HTML_CLUEV (self)->align_left_list; |
---|
763 | p != NULL; |
---|
764 | p = HTML_OBJECT (HTML_CLUEALIGNED (p)->next_aligned)) { |
---|
765 | base_y = p->y + p->parent->y - p->parent->ascent; |
---|
766 | top_y = base_y - p->ascent; |
---|
767 | |
---|
768 | if (top_y <= y && y < base_y + p->descent) |
---|
769 | y = base_y + p->descent; |
---|
770 | } |
---|
771 | |
---|
772 | return y; |
---|
773 | } |
---|
774 | |
---|
775 | static gint |
---|
776 | get_right_clear (HTMLClue *self, |
---|
777 | gint y) |
---|
778 | { |
---|
779 | HTMLObject *p; |
---|
780 | gint top_y, base_y; |
---|
781 | |
---|
782 | /* XXX we assume the parent's size has already been calculated here. */ |
---|
783 | |
---|
784 | for (p = HTML_CLUEV (self)->align_right_list; |
---|
785 | p != NULL; |
---|
786 | p = HTML_OBJECT (HTML_CLUEALIGNED (p)->next_aligned)) { |
---|
787 | base_y = p->y + p->parent->y - p->parent->ascent; |
---|
788 | top_y = base_y - p->ascent; |
---|
789 | |
---|
790 | if (top_y <= y && y < base_y + p->descent) |
---|
791 | y = base_y + p->descent; |
---|
792 | } |
---|
793 | |
---|
794 | return y; |
---|
795 | } |
---|
796 | |
---|
797 | |
---|
798 | void |
---|
799 | html_cluev_type_init (void) |
---|
800 | { |
---|
801 | html_cluev_class_init (&html_cluev_class, HTML_TYPE_CLUEV, sizeof (HTMLClueV)); |
---|
802 | } |
---|
803 | |
---|
804 | void |
---|
805 | html_cluev_class_init (HTMLClueVClass *klass, |
---|
806 | HTMLType type, |
---|
807 | guint size) |
---|
808 | { |
---|
809 | HTMLObjectClass *object_class; |
---|
810 | HTMLClueClass *clue_class; |
---|
811 | |
---|
812 | object_class = HTML_OBJECT_CLASS (klass); |
---|
813 | clue_class = HTML_CLUE_CLASS (klass); |
---|
814 | |
---|
815 | html_clue_class_init (clue_class, type, size); |
---|
816 | |
---|
817 | object_class->copy = copy; |
---|
818 | object_class->calc_size = calc_size; |
---|
819 | object_class->calc_min_width = calc_min_width; |
---|
820 | object_class->calc_preferred_width = calc_preferred_width; |
---|
821 | object_class->relayout = relayout; |
---|
822 | object_class->set_max_width = set_max_width; |
---|
823 | object_class->reset = reset; |
---|
824 | object_class->draw = draw; |
---|
825 | object_class->check_point = check_point; |
---|
826 | object_class->get_left_margin = get_left_margin; |
---|
827 | object_class->get_right_margin = get_right_margin; |
---|
828 | |
---|
829 | clue_class->get_left_clear = get_left_clear; |
---|
830 | clue_class->get_right_clear = get_right_clear; |
---|
831 | clue_class->find_free_area = find_free_area; |
---|
832 | clue_class->appended = appended; |
---|
833 | clue_class->append_left_aligned = append_left_aligned; |
---|
834 | clue_class->append_right_aligned = append_right_aligned; |
---|
835 | |
---|
836 | parent_class = &html_clue_class; |
---|
837 | } |
---|
838 | |
---|
839 | void |
---|
840 | html_cluev_init (HTMLClueV *cluev, |
---|
841 | HTMLClueVClass *klass, |
---|
842 | gint x, gint y, |
---|
843 | gint percent) |
---|
844 | { |
---|
845 | HTMLObject *object; |
---|
846 | HTMLClue *clue; |
---|
847 | |
---|
848 | object = HTML_OBJECT (cluev); |
---|
849 | clue = HTML_CLUE (cluev); |
---|
850 | |
---|
851 | html_clue_init (clue, HTML_CLUE_CLASS (klass)); |
---|
852 | |
---|
853 | object->x = x; |
---|
854 | object->y = y; |
---|
855 | object->percent = percent; |
---|
856 | |
---|
857 | clue->valign = HTML_VALIGN_BOTTOM; |
---|
858 | clue->halign = HTML_HALIGN_LEFT; |
---|
859 | clue->head = clue->tail = clue->curr = 0; |
---|
860 | |
---|
861 | cluev->align_left_list = 0; |
---|
862 | cluev->align_right_list = 0; |
---|
863 | cluev->padding = 0; |
---|
864 | } |
---|
865 | |
---|
866 | HTMLObject * |
---|
867 | html_cluev_new (gint x, gint y, gint percent) |
---|
868 | { |
---|
869 | HTMLClueV *cluev; |
---|
870 | |
---|
871 | cluev = g_new (HTMLClueV, 1); |
---|
872 | html_cluev_init (cluev, &html_cluev_class, x, y, percent); |
---|
873 | |
---|
874 | return HTML_OBJECT (cluev); |
---|
875 | } |
---|