summaryrefslogtreecommitdiff
path: root/gtk2_ardour/lineset.h
blob: 2f9a61d03983f85161eec665e652470846c12d73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
    Copyright (C) 2007 Paul Davis
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __gnome_canvas_lineset_h__
#define __gnome_canvas_lineset_h__

#include <stdint.h>
#include <libgnomecanvasmm/item.h>

namespace Gnome {
namespace Canvas {

class LineSetClass : public Glib::Class {
public:
	const Glib::Class& init();
	static void class_init_function(void* g_class, void* class_data);
};

/** A canvas item that displays a set of vertical or horizontal lines,
 * spanning the entire size of the item.
 */
class LineSet : public Item {
public:
	enum Orientation {
		Vertical,
		Horizontal
	};

	LineSet(Group& parent, Orientation);
	virtual ~LineSet();

	Glib::PropertyProxy<double> property_x1() { return x1.get_proxy(); }
	Glib::PropertyProxy<double> property_y1() { return y1.get_proxy(); }
	Glib::PropertyProxy<double> property_x2() { return x2.get_proxy(); }
	Glib::PropertyProxy<double> property_y2() { return y2.get_proxy(); }

	/* Note: every line operation takes a coord parameter, as an index to
	 * the line it modifies. The index will identify a line if it is between
	 * line.coord and line.coord + line.width.
	 */

	/** Move a line to a new position.
	 * For this to work (to move the desired line) it is important that
	 * lines have unique coordinates. This also applies to every line
	 * accessing functions below
	 */
	void move_line(double coord, double dest);

	/** Change the width of a line.
	 * Only allow if the new width doesn't overlap the next line (see below)
	 */
	void change_line_width(double coord, double width);

	/** Change the color of a line.
	 */
	void change_line_color(double coord, uint32_t color);

	/** Add a line to draw.
	 * width is an offset, so that coord + width specifies the end of the line.
	 * lines should not overlap, as no layering information is provided.
	 * however, line_coord[i] + line_width[i] == line_coord[i+1] is
	 * be legal, as the coordinates are real numbers and represents
	 * real world coordinates. Two real world object sharing coordinates for start
	 * and end are not overlapping.
	 */
	void add_line(double coord, double width, uint32_t color);

	/** Remove the line at coord
	 */
	void remove_line(double coord);

	/** Remove all lines in a coordinate range
	 */
	void remove_lines(double c1, double c2);

	/** Remove all lines with a coordinate lower than coord
	 */
	void remove_until(double coord);

	/** Remove all lines with a coordinate equal to or higher than coord.
	 */
	void remove_from(double coord);

	/** Remove all lines.
	 */
	void clear();

	/** Add a set of lines in the given range.
	 * For every line visible in the provided coordinate range, call add_line().
	 * This is called when the area between c1 and c2 becomes visible, when
	 * previously outside any possible view.
	 * The number of calls to this function should be kept at a minimum.
	 */
	virtual void request_lines(double c1, double c2);

	/** Instead of overriding the update_lines function one can connect to this
	 * and add lines externally instead.
	 * If add_lines() is overrided, this signal will not be emitted.
	 */
	sigc::signal<void, LineSet&, double, double> signal_request_lines;

	/* overridden from Gnome::Canvas::Item */
	void update_vfunc(double* affine, ArtSVP* clip_path, int flags);
	void realize_vfunc();
	void unrealize_vfunc();
	void map_vfunc();
	void unmap_vfunc();
	void draw_vfunc(const Glib::RefPtr<Gdk::Drawable>& drawable, int x, int y, int width, int height);
	void render_vfunc(GnomeCanvasBuf* buf);
	double point_vfunc(double x, double y, int cx, int cy, GnomeCanvasItem** actual_item);
	void bounds_vfunc(double* x1, double* y1, double* x2, double* y2);
	bool on_event(GdkEvent* p1);

	/* debug */
	void print_lines();

protected:
	struct Line {
		Line(double c, double w, uint32_t color);
		Line(double c);

		void set_color(uint32_t color);

		double coord;
		double width;
		unsigned char r;
		unsigned char g;
		unsigned char b;
		unsigned char a;
	};

	static inline void paint_vert(GnomeCanvasBuf* buf, LineSet::Line& line, int x1, int y1, int x2, int y2);
	static inline void paint_horiz(GnomeCanvasBuf* buf, LineSet::Line& line, int x1, int y1, int x2, int y2);

	static bool line_compare(const Line& a, const Line& b);

	typedef std::list<Line> Lines;
	void bounds_need_update();
	void region_needs_update(double coord1, double coord2);
	bool update_bounds();
	void update_lines(bool need_redraw);
	void redraw_request (ArtDRect const &);

	Lines::iterator line_at(double coord);

	/** Stores last accessed line so adjacent lines are found faster */
	Lines::iterator cached_pos;

	static LineSetClass lineset_class;
	Orientation orientation;
	Lines lines;

	/* properties */
	Glib::Property<double> x1;
	Glib::Property<double> y1;
	Glib::Property<double> x2;
	Glib::Property<double> y2;

	/** Cached bounding box in canvas coordinates */
	ArtIRect bbox;

private:
	LineSet();
	LineSet(const LineSet&);

	bool in_update;

	/* a range that needs update update1 > update2 ==> no update needed */
	double update_region1;
	double update_region2;
	bool bounds_changed;

	double covered1;
	double covered2;
};

} /* namespace Canvas */
} /* namespace Gnome */

#endif /* __gnome_canvas_lineset_h__ */