incomplete merge of master into windows (requires upcoming changes to master to be...
[ardour.git] / gtk2_ardour / lineset.cc
1 /*
2     Copyright (C) 2007 Paul Davis
3     This program is free software; you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation; either version 2 of the License, or
6     (at your option) any later version.
7
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12
13     You should have received a copy of the GNU General Public License
14     along with this program; if not, write to the Free Software
15     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
17
18 #include "lineset.h"
19 #include "rgb_macros.h"
20
21 #include <libgnomecanvas/libgnomecanvas.h>
22 #include <libgnomecanvasmm/group.h>
23 #include <libgnomecanvasmm/canvas.h>
24
25 #include <algorithm>
26 #include <cmath>
27 #include <iostream>
28
29 using namespace std;
30
31 namespace Gnome {
32 namespace Canvas {
33
34 LineSetClass LineSet::lineset_class;
35
36 //static const char* overlap_error_str = "LineSet error: Line overlap";
37
38 LineSet::Line::Line(double c, double w, uint32_t color)
39         : coord(c)
40         , width(w)
41 {
42         UINT_TO_RGBA (color, &r, &g, &b, &a);
43 }
44
45 /* Constructor for dummy lines that are used only with the coordinate */
46 LineSet::Line::Line(double c)
47         : coord(c)
48 {
49 }
50
51 void
52 LineSet::Line::set_color(uint32_t color)
53 {
54         UINT_TO_RGBA (color, &r, &g, &b, &a);
55 }
56
57 const Glib::Class&
58 LineSetClass::init()
59 {
60         if (!gtype_) {
61                 class_init_func_ = &LineSetClass::class_init_function;
62                 register_derived_type(Item::get_type());
63         }
64
65         return *this;
66 }
67
68 void
69 LineSetClass::class_init_function(void* /*g_class*/, void* /*class_data*/)
70 {
71 }
72
73 LineSet::LineSet(Group& parent, Orientation o)
74         : Glib::ObjectBase("GnomeCanvasLineSet")
75         , Item(Glib::ConstructParams(lineset_class.init()))
76         , cached_pos(lines.end())
77         , orientation(o)
78         , x1(*this, "x1", 0.0)
79         , y1(*this, "y1", 0.0)
80         , x2(*this, "x2", 0.0)
81         , y2(*this, "y2", 0.0)
82         , in_update(false)
83         , update_region1(1.0)
84         , update_region2(0.0)
85         , bounds_changed(false)
86         , covered1(1.0) // covered1 > covered2 ==> nothing's covered
87         , covered2(0.0)
88 {
89
90         item_construct(parent);
91
92         property_x1().signal_changed().connect(sigc::mem_fun(*this, &LineSet::bounds_need_update));
93         property_y1().signal_changed().connect(sigc::mem_fun(*this, &LineSet::bounds_need_update));
94         property_x2().signal_changed().connect(sigc::mem_fun(*this, &LineSet::bounds_need_update));
95         property_y2().signal_changed().connect(sigc::mem_fun(*this, &LineSet::bounds_need_update));
96 }
97
98 LineSet::~LineSet()
99 {
100 }
101
102 bool
103 LineSet::line_compare(const Line& a, const Line& b)
104 {
105         return a.coord < b.coord;
106 }
107
108 void
109 LineSet::print_lines()
110 {
111         for (Lines::iterator it = lines.begin(); it != lines.end(); ++it) {
112                 cerr << "   " << it->coord << " " << it->width << " " << (int)it->r << " " << (int)it->g << " " << (int)it->b << " " << (int)it->a << endl;
113         }
114 }
115
116 void
117 LineSet::move_line(double coord, double dest)
118 {
119         if (coord == dest) {
120                 return;
121         }
122
123         Lines::iterator it = line_at(coord);
124
125         if (it != lines.end()) {
126
127                 double width = it->width;
128                 it->coord = dest;
129
130                 Lines::iterator ins = lower_bound(lines.begin(), lines.end(), *it, line_compare);
131
132                 lines.insert(ins, *it);
133                 lines.erase(it);
134
135                 if (coord > dest) {
136                         region_needs_update(dest, coord + width);
137                 } else {
138                         region_needs_update(coord, dest + width);
139                 }
140         }
141 }
142
143 void
144 LineSet::change_line_width(double coord, double width)
145 {
146         Lines::iterator it = line_at(coord);
147
148         if (it != lines.end()) {
149                 Line& l = *it;
150                 ++it;
151
152                 if (it != lines.end()) {
153                         if (l.coord + width > it->coord) {
154                                 //cerr << overlap_error_str << endl;
155                                 return;
156                         }
157                 }
158
159                 l.width = width;
160                 region_needs_update(coord, coord + width);
161         }
162 }
163
164 void
165 LineSet::change_line_color(double coord, uint32_t color)
166 {
167         Lines::iterator it = line_at(coord);
168
169         if (it != lines.end()) {
170                 it->set_color(color);
171                 region_needs_update(it->coord, it->coord + it->width);
172         }
173 }
174
175 void
176 LineSet::add_line(double coord, double width, uint32_t color)
177 {
178         Line l(coord, width, color);
179
180         Lines::iterator it = std::lower_bound(lines.begin(), lines.end(), l, line_compare);
181
182         /* overlap checking */
183         if (it != lines.end()) {
184                 if (l.coord + l.width > it->coord) {
185                         //cerr << overlap_error_str << endl;
186                         return;
187                 }
188         }
189         if (it != lines.begin()) {
190                 --it;
191                 if (l.coord < it->coord + it->width) {
192                         //cerr << overlap_error_str << endl;
193                         return;
194                 }
195                 ++it;
196         }
197
198         lines.insert(it, l);
199         region_needs_update(coord, coord + width);
200 }
201
202 void
203 LineSet::remove_line(double coord)
204 {
205         Lines::iterator it = line_at(coord);
206
207         if (it != lines.end()) {
208                 double start = it->coord;
209                 double end = start + it->width;
210
211                 lines.erase(it);
212
213                 region_needs_update(start, end);
214         }
215 }
216
217 void
218 LineSet::remove_lines(double c1, double c2)
219 {
220         if (!lines.empty()) {
221                 region_needs_update(c1, c2);
222         }
223 }
224
225 void
226 LineSet::remove_until(double coord)
227 {
228         if (!lines.empty()) {
229                 double first = lines.front().coord;
230
231                 // code
232
233                 region_needs_update(first, coord);
234         }
235 }
236
237 void
238 LineSet::remove_from(double coord)
239 {
240         if (!lines.empty()) {
241                 double last = lines.back().coord + lines.back().width;
242
243                 // code
244
245                 region_needs_update(coord, last);
246         }
247 }
248
249 void
250 LineSet::clear()
251 {
252         if (!lines.empty()) {
253                 double coord1 = lines.front().coord;
254                 double coord2 = lines.back().coord + lines.back().width;
255
256                 lines.clear();
257                 region_needs_update(coord1, coord2);
258         }
259 }
260
261 /*
262  * this function is optimized to work faster if we access elements that are adjacent to each other.
263  * so if a large number of lines are modified, it is wise to modify them in sorted order.
264  */
265 LineSet::Lines::iterator
266 LineSet::line_at(double coord)
267 {
268         if (cached_pos != lines.end()) {
269                 if (coord < cached_pos->coord) {
270                         /* backward search */
271                         while (--cached_pos != lines.end()) {
272                                 if (cached_pos->coord <= coord) {
273                                         if (cached_pos->coord + cached_pos->width < coord) {
274                                                 /* coord is between two lines */
275                                                 return lines.end();
276                                         } else {
277                                                 return cached_pos;
278                                         }
279                                 }
280                         }
281                 } else {
282                         /* forward search */
283                         while (cached_pos != lines.end()) {
284                                 if (cached_pos->coord > coord) {
285                                         /* we searched past the line that we want, so now see
286                                            if the previous line includes the coordinate */
287                                         --cached_pos;
288                                         if (cached_pos->coord + cached_pos->width >= coord) {
289                                                 return cached_pos;
290                                         } else {
291                                                 return lines.end();
292                                         }
293                                 }
294                                 ++cached_pos;
295                         }
296                 }
297         } else {
298                 /* initialize the cached position */
299                 Line dummy(coord);
300
301                 cached_pos = lower_bound(lines.begin(), lines.end(), dummy, line_compare);
302
303                 /* The iterator found should point to the element after the one we want. */
304                 --cached_pos;
305
306                 if (cached_pos != lines.end()) {
307                         if (cached_pos->coord <= coord) {
308                                 if (cached_pos->coord + cached_pos->width >= coord) {
309                                         return cached_pos;
310                                 } else {
311                                         return lines.end();
312                                 }
313                         } else {
314                                 return lines.end();
315                         }
316                 } else {
317                         return lines.end();
318                 }
319         }
320
321         return lines.end();
322 }
323
324 void
325 LineSet::redraw_request (ArtDRect const & r)
326 {
327         int x0, y0, x1, y1;
328         Canvas& cv = *get_canvas();
329
330         //cerr << "redraw request: " << r.x0 << " " << r.y0 << " " << r.x1 << " " << r.y1 << endl;
331
332         double fx0 = r.x0;
333         if (fx0 > INT_MAX) {
334                 fx0 = INT_MAX;
335         }
336
337         double fx1 = r.x1;
338         if (fx1 > INT_MAX) {
339                 fx1 = INT_MAX;
340         }
341
342         cv.w2c (fx0, r.y0, x0, y0);
343         cv.w2c (fx1, r.y1, x1, y1);
344
345         cv.request_redraw(x0, y0, x1, y1);
346 }
347
348 void
349 LineSet::update_lines(bool need_redraw)
350 {
351         //cerr << "update_lines need_redraw=" << need_redraw << endl;
352         if (!need_redraw) {
353                 update_region1 = 1.0;
354                 update_region2 = 0.0;
355                 return;
356         }
357
358         if (update_region2 > update_region1) {
359                 ArtDRect redraw;
360                 LineSet::bounds_vfunc(&redraw.x0, &redraw.y0, &redraw.x1, &redraw.y1);
361                 i2w(redraw.x0, redraw.y0);
362                 i2w(redraw.x1, redraw.y1);
363
364                 if (orientation == Vertical) {
365                         redraw.x1 = redraw.x0 + update_region2;
366                         redraw.x0 += update_region1;
367                 } else {
368                         redraw.y1 = redraw.y0 + update_region2;
369                         redraw.y0 += update_region1;
370                 }
371                 redraw_request(redraw);
372                 update_region1 = 1.0;
373                 update_region2 = 0.0;
374         }
375
376         // if we need to calculate what becomes visible, use some of this
377         //cv.c2w (0, 0, world_v[X1], world_v[Y1]);
378         //cv.c2w (cv.get_width(), cv.get_height(), world_v[X2], world_v[Y2]);
379 }
380
381 /*
382  * return false if a full redraw request has been made.
383  * return true if nothing or only parts of the rect area has been requested for redraw
384  */
385 bool
386 LineSet::update_bounds()
387 {
388         GnomeCanvasItem* item = GNOME_CANVAS_ITEM(gobj());
389         ArtDRect old_b;
390         ArtDRect new_b;
391         ArtDRect redraw;
392         Canvas& cv = *get_canvas();
393
394         /* store the old bounding box */
395         old_b.x0 = item->x1;
396         old_b.y0 = item->y1;
397         old_b.x1 = item->x2;
398         old_b.y1 = item->y2;
399         LineSet::bounds_vfunc(&new_b.x0, &new_b.y0, &new_b.x1, &new_b.y1);
400
401         i2w(new_b.x0, new_b.y0);
402         i2w(new_b.x1, new_b.y1);
403
404         item->x1 = new_b.x0;
405         item->y1 = new_b.y0;
406         item->x2 = new_b.x1;
407         item->y2 = new_b.y1;
408
409         /* Update bounding box used in rendering function */
410
411         double fx0 = new_b.x0;
412         if (fx0 > INT_MAX) {
413                 fx0 = INT_MAX;
414         }
415
416         double fx1 = new_b.x1;
417         if (fx1 > INT_MAX) {
418                 fx1 = INT_MAX;
419         }
420
421         cv.w2c (fx0, new_b.y0, bbox.x0, bbox.y0);
422         cv.w2c (fx1, new_b.y1, bbox.x1, bbox.y1);
423
424         /*
425          * if the first primary axis property (x1 for Vertical, y1 for Horizontal) changed, we must redraw everything,
426          * because lines are positioned relative to this coordinate. Please excuse the confusion resulting from
427          * gnome canvas coordinate numbering (1, 2) and libart's (0, 1).
428          */
429         if (orientation == Vertical) {
430                 if (new_b.x0 == old_b.x0) {
431                         /* No need to update everything */
432                         if (new_b.y0 != old_b.y0) {
433                                 redraw.x0 = old_b.x0;
434                                 redraw.y0 = min(old_b.y0, new_b.y0);
435                                 redraw.x1 = old_b.x1;
436                                 redraw.y1 = max(old_b.y0, new_b.y0);
437                                 redraw_request(redraw);
438                         }
439                         if (new_b.y1 != old_b.y1) {
440                                 redraw.x0 = old_b.x0;
441                                 redraw.y0 = min(old_b.y1, new_b.y1);
442                                 redraw.x1 = old_b.x1;
443                                 redraw.y1 = max(old_b.y1, new_b.y1);
444                                 redraw_request(redraw);
445                         }
446
447                         if (new_b.x1 > old_b.x1) {
448                                 // we have a larger area ==> possibly more lines
449                                 request_lines(old_b.x1, new_b.x1);
450                                 redraw.x0 = old_b.x1;
451                                 redraw.y0 = min(old_b.y0, new_b.y0);
452                                 redraw.x1 = new_b.x1;
453                                 redraw.y1 = max(old_b.y1, new_b.y1);
454                                 redraw_request(redraw);
455                         } else if (new_b.x1 < old_b.x1) {
456                                 remove_lines(new_b.x1, old_b.x1);
457                                 redraw.x0 = new_b.x1;
458                                 redraw.y0 = min(old_b.y0, new_b.y0);
459                                 redraw.x1 = old_b.x1;
460                                 redraw.y1 = max(old_b.y1, new_b.y1);
461                                 redraw_request(redraw);
462                         }
463                         return true;
464                 } else {
465                         /* update everything */
466                         //cerr << "update everything" << endl;
467                         art_drect_union(&redraw, &old_b, &new_b);
468                         redraw_request(redraw);
469                         return false;
470                 }
471         } else {
472                 if (new_b.y0 == old_b.y0) {
473                         /* No need to update everything */
474                         if (new_b.x0 != old_b.x0) {
475                                 redraw.y0 = old_b.y0;
476                                 redraw.x0 = min(old_b.x0, new_b.x0);
477                                 redraw.y1 = old_b.y1;
478                                 redraw.x1 = max(old_b.x0, new_b.x0);
479                                 redraw_request(redraw);
480                         }
481                         if (new_b.x1 != old_b.x1) {
482                                 redraw.y0 = old_b.y0;
483                                 redraw.x0 = min(old_b.x1, new_b.x1);
484                                 redraw.y1 = old_b.y1;
485                                 redraw.x1 = max(old_b.x1, new_b.x1);
486                                 redraw_request(redraw);
487                         }
488
489                         if (new_b.y1 > old_b.y1) {
490                                 // we have a larger area ==> possibly more lines
491                                 request_lines(old_b.y1, new_b.y1);
492                                 redraw.y0 = old_b.y1;
493                                 redraw.x0 = min(old_b.x0, new_b.x0);
494                                 redraw.y1 = new_b.y1;
495                                 redraw.x1 = max(old_b.x1, new_b.x1);
496                                 redraw_request(redraw);
497                         } else if (new_b.y1 < old_b.y1) {
498                                 remove_lines(new_b.y1, old_b.y1);
499                                 redraw.y0 = new_b.y1;
500                                 redraw.x0 = min(old_b.x0, new_b.x0);
501                                 redraw.y1 = old_b.y1;
502                                 redraw.x1 = max(old_b.x1, new_b.x1);
503                                 redraw_request(redraw);
504                         }
505                         return true;
506                 } else {
507                         /* update everything */
508                         art_drect_union(&redraw, &old_b, &new_b);
509                         redraw_request(redraw);
510                         return false;
511                 }
512         }
513 }
514
515 /*
516  * what to do here?
517  * 1. find out if any line data has been modified since last update.
518  * N. find out if the item moved. if it moved, the old bbox and the new bbox need to be updated.
519  */
520 void
521 LineSet::update_vfunc(double* /*affine*/, ArtSVP* /*clip_path*/, int /*flags*/)
522 {
523         GnomeCanvasItem* item = GNOME_CANVAS_ITEM(gobj());
524         bool lines_need_redraw = true;
525
526         /*
527          * need to call gnome_canvas_item_update here, to unset the need_update flag.
528          * but a call to Gnome::Canvas::Item::update_vfunc results in infinite recursion.
529          * that function is declared in gnome_canvas.c so no way to call it directly:
530          * Item::update_vfunc(affine, clip_path, flags);
531          * So just copy the code from that function. This has to be a bug or
532          * something I haven't figured out.
533          */
534         GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_UPDATE);
535         GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_AFFINE);
536         GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_CLIP);
537         GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_VIS);
538
539         //cerr << "update {" << endl;
540         in_update = true;
541
542         // ahh. We must update bounds no matter what. If the group position changed,
543         // there is no way that we are notified of that.
544
545         //if (bounds_changed) {
546         lines_need_redraw = update_bounds();
547         bounds_changed = false;
548                 //}
549
550         update_lines(lines_need_redraw);
551
552         in_update = false;
553         //cerr << "}" << endl;
554 }
555
556 void
557 LineSet::draw_vfunc(const Glib::RefPtr<Gdk::Drawable>& /*drawable*/, int /*x*/, int /*y*/, int /*width*/, int /*height*/)
558 {
559         cerr << "please don't use the GnomeCanvasLineSet item in a non-aa Canvas" << endl;
560         abort();
561 }
562
563 inline void
564 LineSet::paint_vert(GnomeCanvasBuf* buf, LineSet::Line& line, int x1, int y1, int x2, int y2)
565 {
566         if (line.width == 1.0) {
567                 PAINT_VERTA(buf, line.r, line.g, line.b, line.a, x1, y1, y2);
568         } else {
569                 PAINT_BOX(buf, line.r, line.g, line.b, line.a, x1, y1, x2, y2);
570         }
571 }
572
573 inline void
574 LineSet::paint_horiz(GnomeCanvasBuf* buf, LineSet::Line& line, int x1, int y1, int x2, int y2)
575 {
576         if (line.width == 1.0) {
577                 PAINT_HORIZA(buf, line.r, line.g, line.b, line.a, x1, x2, y1);
578         } else {
579                 PAINT_BOX(buf, line.r, line.g, line.b, line.a, x1, y1, x2, y2);
580         }
581 }
582
583 void
584 LineSet::render_vfunc(GnomeCanvasBuf* buf)
585 {
586         ArtIRect rect;
587         int pos0, pos1, offset;
588
589         if (buf->is_bg) {
590                 gnome_canvas_buf_ensure_buf (buf);
591                 buf->is_bg = FALSE;
592         }
593
594         /* get the rect that we are rendering to */
595         art_irect_intersect(&rect, &bbox, &buf->rect);
596
597 #if 0
598         /* DEBUG render bounding box for this region. should result in the full
599            bounding box when all rendering regions are finished */
600         PAINT_BOX(buf, 0xaa, 0xaa, 0xff, 0xbb, rect.x0, rect.y0, rect.x1, rect.y1);
601 #endif
602
603 #if 0
604         /* harlequin debugging, shows the rect that is actually drawn, distinct from
605            rects from other render cycles */
606         gint r, g, b, a;
607         r = random() % 0xff;
608         g = random() % 0xff;
609         b = random() % 0xff;
610         PAINT_BOX(buf, r, g, b, 0x33, rect.x0, rect.y0, rect.x1, rect.y1);
611 #endif
612
613         if (lines.empty()) {
614                 return;
615         }
616
617         Lines::iterator it = lines.begin();
618         Lines::iterator end = --lines.end();
619
620         /**
621          * The first and the last line in this render have to be handled separately from those in between, because those lines
622          * may be cut off at the ends.
623          */
624
625         if (orientation == Vertical) {
626                 offset = bbox.x0;
627
628                 // skip parts of lines that are to the right of the buffer, and paint the last line visible
629                 for (; end != lines.end(); --end) {
630                         pos0 = ((int) floor(end->coord)) + offset;
631
632                         if (pos0 < rect.x1) {
633                                 pos1 = min((pos0 + (int) floor(end->width)), rect.x1);
634                                 if (pos0 < rect.x0 && pos1 < rect.x0) {
635                                         return;
636                                 }
637
638                                 paint_vert(buf, *end, pos0, rect.y0, pos1, rect.y1);
639                                 break;
640                         }
641                 }
642
643                 if (end == lines.end()) {
644                         return;
645                 }
646
647                 // skip parts of lines that are to the left of the buffer
648                 for (; it != end; ++it) {
649                         pos0 = ((int) floor(it->coord)) + offset;
650                         pos1 = pos0 + ((int) floor(it->width));
651
652                         if (pos1 > rect.x0) {
653                                 pos0 = max(pos0, rect.x0);
654                                 paint_vert(buf, *it, pos0, rect.y0, pos1, rect.y1);
655                                 ++it;
656                                 break;
657                         }
658                 }
659
660                 // render what's between the first and last lines
661                 for (; it != end; ++it) {
662                         pos0 = ((int) floor(it->coord)) + offset;
663                         pos1 = pos0 + ((int) floor(it->width));
664
665                         paint_vert(buf, *it, pos0, rect.y0, pos1, rect.y1);
666                 }
667         } else {
668                 offset = bbox.y0;
669
670                 // skip parts of lines that are to the right of the buffer, and paint the last line visible
671                 for (; end != lines.end(); --end) {
672                         pos0 = ((int) floor(end->coord)) + offset;
673
674                         if (pos0 < rect.y1) {
675                                 pos1 = min((pos0 + (int) floor(end->width)), rect.y1);
676                                 if (pos0 < rect.y0 && pos1 < rect.y0) {
677                                         return;
678                                 }
679
680                                 paint_horiz(buf, *end, rect.x0, pos0, rect.x1, pos1);
681                                 break;
682                         }
683                 }
684
685                 if (end == lines.end()) {
686                         return;
687                 }
688
689                 // skip parts of lines that are to the left of the buffer
690                 for (; it != end; ++it) {
691                         pos0 = ((int) floor(it->coord)) + offset;
692                         pos1 = pos0 + ((int) floor(it->width));
693
694                         if (pos1 > rect.y0) {
695                                 pos0 = max(pos0, rect.y0);
696                                 paint_horiz(buf, *it, rect.x0, pos0, rect.x1, pos1);
697                                 ++it;
698                                 break;
699                         }
700                 }
701
702                 // render what's between the first and last lines
703                 for (; it != end; ++it) {
704                         pos0 = ((int) floor(it->coord)) + offset;
705                         pos1 = pos0 + ((int) floor(it->width));
706                         paint_horiz(buf, *it, rect.x0, pos0, rect.x1, pos1);
707                 }
708         }
709 }
710
711 void
712 LineSet::bounds_vfunc(double* _x1, double* _y1, double* _x2, double* _y2)
713 {
714         *_x1 = x1;
715         *_y1 = y1;
716         *_x2 = x2 + 1;
717         *_y2 = y2 + 1;
718 }
719
720
721 double
722 LineSet::point_vfunc(double x, double y, int /*cx*/, int /*cy*/, GnomeCanvasItem** actual_item)
723 {
724         double x1, y1, x2, y2;
725         double dx, dy;
726
727         LineSet::bounds_vfunc(&x1, &y1, &x2, &y2);
728
729         *actual_item = gobj();
730
731         if (x < x1) {
732                 dx = x1 - x;
733         } else if (x > x2) {
734                 dx = x - x2;
735         } else {
736                 dx = 0.0;
737         }
738
739         if (y < y1) {
740                 dy = y1 - y;
741         } else if (y > y2) {
742                 dy = y - y2;
743         } else {
744                 if (dx == 0.0) {
745                         // point is inside
746                         return 0.0;
747                 } else {
748                         dy = 0.0;
749                 }
750         }
751
752         return sqrt (dx * dx + dy * dy);
753 }
754
755 /* If not overrided emit the signal */
756 void
757 LineSet::request_lines(double c1, double c2)
758 {
759         signal_request_lines(*this, c1, c2);
760 }
761
762 void
763 LineSet::bounds_need_update()
764 {
765         bounds_changed = true;
766
767         if (!in_update) {
768                 request_update();
769         }
770 }
771
772 void
773 LineSet::region_needs_update(double coord1, double coord2)
774 {
775         if (update_region1 > update_region2) {
776                 update_region1 = coord1;
777                 update_region2 = coord2;
778         } else {
779                 update_region1 = min(update_region1, coord1);
780                 update_region2 = max(update_region2, coord2);
781         }
782
783         if (!in_update) {
784                 request_update();
785         }
786 }
787
788 /*
789  * These have been defined to avoid endless recursion with gnomecanvasmm.
790  * Don't know why this happens
791  */
792 bool LineSet::on_event(GdkEvent* /*p1*/)
793 {
794         return false;
795 }
796
797 void LineSet::realize_vfunc() { }
798 void LineSet::unrealize_vfunc() { }
799 void LineSet::map_vfunc() { }
800 void LineSet::unmap_vfunc() { }
801
802 } /* namespace Canvas */
803 } /* namespace Gnome */