a5d051613929a90e6036f29414c00010e5a1998e
[ardour.git] / gtk2_ardour / lineset.h
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 #ifndef __gnome_canvas_lineset_h__
19 #define __gnome_canvas_lineset_h__
20
21 #include <libgnomecanvasmm/item.h>
22
23 namespace Gnome {
24 namespace Canvas {
25
26 class LinesetClass : public Glib::Class {
27 public:
28         const Glib::Class& init();
29         static void class_init_function(void* g_class, void* class_data);
30 };
31
32 /**
33  * A canvas item that displays a list of lines vertically or horizontally,
34  * spanning the entire size of the item.
35  */
36 class Lineset : public Item {
37 public:
38         enum Orientation {
39                 Vertical,
40                 Horizontal
41         };
42
43         Lineset(Group& parent, Orientation);
44         virtual ~Lineset();
45
46         Glib::PropertyProxy<double> property_x1() { return x1.get_proxy(); }
47         Glib::PropertyProxy<double> property_y1() { return y1.get_proxy(); }
48         Glib::PropertyProxy<double> property_x2() { return x2.get_proxy(); }
49         Glib::PropertyProxy<double> property_y2() { return y2.get_proxy(); }
50
51         /*
52          * Note: every line operation takes a coord parameter, as an index to
53          * the line it modifies. The index will identify a line if it is between
54          * line.coord and line.coord + line.width.
55          */
56
57         /**
58          * Move a line to a new position
59          * for this to work (to move the desired line) it is important that
60          * lines have unique coordinates. This also applies to every line
61          * accessing functions below
62          */
63         void move_line(double coord, double dest);
64
65         /**
66          * Change the width of a line. Only allow it if the new width doesn't
67          * overlap the next line (see below)
68          */
69         void change_line_width(double coord, double width);
70
71         /**
72          * Change the color of a line
73          */
74         void change_line_color(double coord, uint32_t color);
75
76         /**
77          * this function adds a line to draw.
78          * width is an offset, so that coord + width specifies the end of the line.
79          * lines should not overlap, as no layering information is provided.
80          * however, line_coord[i] + line_width[i] == line_coord[i+1] is
81          * be legal, as the coordinates are real numbers and represents
82          * real world coordinates. Two real world object sharing coordinates for start
83          * and end are not overlapping.
84          */
85         void add_line(double coord, double width, uint32_t color);
86
87         /**
88          * remove the line at coord
89          */
90         void remove_line(double coord);
91         
92         /**
93          * remove all lines in a coordinate range
94          */
95         void remove_lines(double c1, double c2);
96
97         /**
98          * remove all lines with a coordinate lower than coord
99          */
100         void remove_until(double coord);
101         
102         /**
103          * remove all lines with a coordinate equal to or higher than coord
104          */
105         void remove_from(double coord);
106
107         /**
108          * remove all lines
109          */
110         void clear();
111
112         /**
113          * this is a request of information on lines in a coordinate range.
114          * for every line visible in the provided coordinate range,
115          * call add_line() on it.
116          * This is called when the area between c1 and c2 becomes visible, when
117          * previously outside any possible view. So the number of calls to this
118          * function will be kept at a minimum.
119          */
120         virtual void request_lines(double c1, double c2);
121
122         /**
123          * instead of overriding the update_lines function one can connect to this
124          * and add lines externally instead. If add_lines() is overrided, this
125          * signal will not be emitted.
126          */
127         sigc::signal<void, Lineset&, double, double> signal_request_lines;
128
129         /* overrided from Gnome::Canvas::Item */
130         void update_vfunc(double* affine, ArtSVP* clip_path, int flags);
131         void realize_vfunc();
132         void unrealize_vfunc();
133         void map_vfunc();
134         void unmap_vfunc();
135         void draw_vfunc(const Glib::RefPtr<Gdk::Drawable>& drawable, int x, int y, int width, int height);
136         void render_vfunc(GnomeCanvasBuf* buf);
137         double point_vfunc(double x, double y, int cx, int cy, GnomeCanvasItem** actual_item);
138         void bounds_vfunc(double* x1, double* y1, double* x2, double* y2);
139         bool on_event(GdkEvent* p1);
140
141         /* debug */
142         void print_lines();
143         
144 protected:
145         struct Line {
146                 Line(double c, double w, uint32_t color);
147                 Line(double c);
148
149                 void set_color(uint32_t color);
150
151                 double coord;
152                 double width;
153                 unsigned char r;
154                 unsigned char g;
155                 unsigned char b;
156                 unsigned char a;
157         };
158
159         static inline void paint_vert(GnomeCanvasBuf* buf, Lineset::Line& line, int x1, int y1, int x2, int y2);
160         static inline void paint_horiz(GnomeCanvasBuf* buf, Lineset::Line& line, int x1, int y1, int x2, int y2);
161
162         static bool line_compare(const Line& a, const Line& b);
163
164         typedef std::list<Line> Lines;
165         void bounds_need_update();
166         void region_needs_update(double coord1, double coord2);
167         bool update_bounds();
168         void update_lines(bool need_redraw);
169         void redraw_request(ArtIRect&);
170         void redraw_request(ArtDRect&);
171
172         Lines::iterator line_at(double coord);
173
174         /* store that last accessed line so adjacent lines are found faster */
175         Lines::iterator cached_pos;
176
177         static LinesetClass lineset_class;
178         Orientation orientation;
179         Lines lines;
180
181         /* properties */
182         Glib::Property<double> x1;
183         Glib::Property<double> y1;
184         Glib::Property<double> x2;
185         Glib::Property<double> y2;
186
187         /* cached bounding box in canvas coordinates*/
188         ArtIRect bbox;
189
190 private:
191         Lineset();
192         Lineset(const Lineset&);
193
194         bool in_update;
195
196         /* a range that needs update update1 > update2 ==> no update needed */
197         double update_region1;
198         double update_region2;
199         bool bounds_changed;
200
201         double covered1;
202         double covered2;
203 };
204
205 } /* namespace Canvas */
206 } /* namespace Gnome */
207
208 #endif /* __gnome_canvas_lineset_h__ */