/[svn]/gigedit/trunk/src/regionchooser.cpp
ViewVC logotype

Contents of /gigedit/trunk/src/regionchooser.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1090 - (show annotations) (download)
Sat Mar 10 17:08:15 2007 UTC (17 years ago) by persson
File size: 12932 byte(s)
* implemented resizing of regions

1 /*
2 * Copyright (C) 2006, 2007 Andreas Persson
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with program; see the file COPYING. If not, write to the Free
16 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include "regionchooser.h"
21 #include <gdkmm/cursor.h>
22
23 RegionChooser::RegionChooser()
24 {
25 Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();
26
27 black = Gdk::Color("black");
28 white = Gdk::Color("white");
29 red = Gdk::Color("#8070ff");
30 blue = Gdk::Color("#c098ff");
31 green = Gdk::Color("#a088ff");
32 grey1 = Gdk::Color("red");
33
34 colormap->alloc_color(black);
35 colormap->alloc_color(white);
36 colormap->alloc_color(red);
37 colormap->alloc_color(blue);
38 colormap->alloc_color(green);
39 colormap->alloc_color(grey1);
40 instrument = 0;
41 region = 0;
42 resize.active = false;
43 cursor_is_resize = false;
44 h1 = 20;
45 width = 800;
46
47 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
48 Gdk::POINTER_MOTION_HINT_MASK);
49 }
50
51 RegionChooser::~RegionChooser()
52 {
53 }
54
55 void RegionChooser::on_realize()
56 {
57 // We need to call the base on_realize()
58 Gtk::DrawingArea::on_realize();
59
60 // Now we can allocate any additional resources we need
61 Glib::RefPtr<Gdk::Window> window = get_window();
62 gc = Gdk::GC::create(window);
63 window->clear();
64 }
65
66 bool RegionChooser::on_expose_event(GdkEventExpose* event)
67 {
68 Glib::RefPtr<Gdk::Window> window = get_window();
69 window->clear();
70 const int h = 40;
71 const int w = width - 1;
72 const int bh = int(h * 0.55);
73
74 Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
75 Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();
76
77 window->draw_rectangle(black, false, 0, h1, w, h - 1);
78 window->draw_rectangle(white, true, 1, h1 + 1, w - 1, h - 2);
79 for (int i = 0 ; i < 128 ; i++) {
80 int note = (i + 3) % 12;
81 int x = int(w * i / 128.0 + 0.5);
82
83 if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) {
84 int x2 = int(w * (i + 0.5) / 128.0 + 0.5);
85 window->draw_line(black, x2, h1 + bh, x2, h1 + h);
86
87 int x3 = int(w * (i + 1) / 128.0 + 0.5);
88 window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh);
89 } else if (note == 3 || note == 8) {
90 window->draw_line(black, x, h1 + 1, x, h1 + h);
91 }
92 }
93
94 if (instrument) {
95 int i = 0;
96 gig::Region *nextRegion;
97 int x3 = -1;
98 for (gig::Region *r = instrument->GetFirstRegion() ;
99 r ;
100 r = nextRegion) {
101
102 if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);
103 nextRegion = instrument->GetNextRegion();
104 if (!nextRegion || r->KeyRange.high + 1 != nextRegion->KeyRange.low) {
105 int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
106 window->draw_line(black, x3, 0, x2, 0);
107 window->draw_line(black, x3, h1 - 1, x2, h1 - 1);
108 window->draw_line(black, x2, 1, x2, h1 - 2);
109 window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);
110 x3 = -1;
111 }
112 i++;
113 }
114
115 for (gig::Region *r = instrument->GetFirstRegion() ;
116 r ;
117 r = instrument->GetNextRegion()) {
118 int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);
119 window->draw_line(black, x, 1, x, h1 - 2);
120 }
121
122 if (region) {
123 int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);
124 int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);
125 gc->set_foreground(red);
126 window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);
127 }
128 }
129 return true;
130 }
131
132
133 void RegionChooser::on_size_request(GtkRequisition* requisition)
134 {
135 *requisition = GtkRequisition();
136 requisition->height = 40 + 20;
137 requisition->width = 500;
138 }
139
140
141 // not used
142 void RegionChooser::draw_region(int from, int to, const Gdk::Color& color)
143 {
144 const int h = 40;
145 const int w = width;
146 const int bh = int(h * 0.55);
147
148 Glib::RefPtr<Gdk::Window> window = get_window();
149 gc->set_foreground(color);
150
151 for (int i = from ; i < to ; i++) {
152 int note = (i + 3) % 12;
153 int x = int(w * i / 128.0 + 0.5) + 1;
154 int x2 = int(w * (i + 1.5) / 128.0 + 0.5);
155 int x3 = int(w * (i + 1) / 128.0 + 0.5);
156 int x4 = int(w * (i - 0.5) / 128 + 0.5) + 1;
157 int w1 = x3 - x;
158 switch (note) {
159 case 0: case 5: case 10:
160 window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
161 window->draw_rectangle(gc, true, x4, h1 + bh + 1, x2 - x4, h - bh - 2);
162 break;
163 case 2: case 7:
164 window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
165 window->draw_rectangle(gc, true, x4, h1 + bh + 1, x3 - x4, h - bh - 2);
166 break;
167 case 3: case 8:
168 window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
169 window->draw_rectangle(gc, true, x, h1 + bh + 1, x2 - x, h - bh - 2);
170 break;
171 default:
172 window->draw_rectangle(gc, true, x, h1 + 1, w1, bh - 1);
173 break;
174 }
175 }
176 }
177
178 void RegionChooser::set_instrument(gig::Instrument* instrument)
179 {
180 this->instrument = instrument;
181 region = instrument->GetFirstRegion();
182 queue_draw();
183 sel_changed_signal.emit();
184 }
185
186 void RegionChooser::set_region(gig::Region* region)
187 {
188 this->region = region;
189 queue_draw();
190 }
191
192 bool RegionChooser::on_button_release_event(GdkEventButton* event)
193 {
194 if (resize.active) {
195 get_window()->pointer_ungrab(event->time);
196 resize.active = false;
197
198 if (resize.mode == resize.moving_high_limit) {
199 resize.region->KeyRange.high = resize.pos - 1;
200 } else if (resize.mode == resize.moving_low_limit) {
201 resize.region->KeyRange.low = resize.pos;
202 }
203
204 if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
205 get_window()->set_cursor();
206 cursor_is_resize = false;
207 }
208 }
209 return true;
210 }
211
212 bool RegionChooser::on_button_press_event(GdkEventButton* event)
213 {
214 if (instrument) {
215 if (is_in_resize_zone(event->x, event->y)) {
216 Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);
217 get_window()->pointer_grab(false,
218 Gdk::BUTTON_RELEASE_MASK |
219 Gdk::POINTER_MOTION_MASK |
220 Gdk::POINTER_MOTION_HINT_MASK,
221 double_arrow, event->time);
222 resize.active = true;
223 } else {
224 const int w = width - 1;
225 int i = 0;
226 for (gig::Region *r = instrument->GetFirstRegion() ; r ;
227 r = instrument->GetNextRegion()) {
228
229 int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);
230 int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
231 if (event->x >= x && event->x < x2) {
232 region = r;
233 break;
234 }
235 i++;
236 }
237 queue_draw();
238 sel_changed_signal.emit();
239 }
240 }
241 }
242
243 bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)
244 {
245 const int w = width - 1;
246 Glib::RefPtr<Gdk::Window> window = get_window();
247 int x, y;
248 Gdk::ModifierType state = Gdk::ModifierType(0);
249 window->get_pointer(x, y, state);
250 if (resize.active) {
251 int k = int(double(x) / w * 128.0 + 0.5);
252
253 if (k < resize.min) k = resize.min;
254 else if (k > resize.max) k = resize.max;
255
256 if (k != resize.pos) {
257 if (resize.mode == resize.undecided) {
258 if (k < resize.pos) {
259 // edit high limit of prev_region
260 resize.max = resize.region->KeyRange.low;
261 resize.region = resize.prev_region;
262 resize.mode = resize.moving_high_limit;
263 } else {
264 // edit low limit of region
265 resize.min = resize.prev_region->KeyRange.high + 1;
266 resize.mode = resize.moving_low_limit;
267 }
268 }
269 Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
270 Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();
271 if (region == resize.region) {
272 gc->set_foreground(red);
273 white = gc;
274 }
275 Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);
276 int prevx = int(w * resize.pos / 128.0 + 0.5);
277 x = int(w * k / 128.0 + 0.5);
278
279 if (resize.mode == resize.moving_high_limit) {
280 if (k > resize.pos) {
281 window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);
282 window->draw_line(black, prevx, 0, x, 0);
283 window->draw_line(black, prevx, h1 - 1, x, h1 - 1);
284 } else {
285 int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);
286 window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);
287 }
288 } else {
289 if (k < resize.pos) {
290 window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);
291 window->draw_line(black, x, 0, prevx, 0);
292 window->draw_line(black, x, h1 - 1, prevx, h1 - 1);
293 } else {
294 int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);
295 window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);
296 }
297 }
298 window->draw_line(black, x, 1, x, h1 - 2);
299 resize.pos = k;
300 }
301 } else {
302 if (is_in_resize_zone(x, y)) {
303 if (!cursor_is_resize) {
304 Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);
305 window->set_cursor(double_arrow);
306 cursor_is_resize = true;
307 }
308 } else if (cursor_is_resize) {
309 window->set_cursor();
310 cursor_is_resize = false;
311 }
312 }
313
314 return true;
315 }
316
317 bool RegionChooser::is_in_resize_zone(double x, double y) {
318 const int w = width - 1;
319
320 if (instrument && y >= 0 && y <= h1) {
321 gig::Region* prev_region = 0;
322 gig::Region* next_region;
323 for (gig::Region* r = instrument->GetFirstRegion() ; r ; r = next_region) {
324 next_region = instrument->GetNextRegion();
325
326 int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);
327 if (x <= lo - 2) break;
328 if (x < lo + 2) {
329 resize.region = r;
330 resize.pos = r->KeyRange.low;
331 resize.max = r->KeyRange.high;
332
333 if (prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low) {
334 // we don't know yet if it's the high limit of
335 // prev_region or the low limit of r that's going
336 // to be edited
337 resize.mode = resize.undecided;
338 resize.min = prev_region->KeyRange.low + 1;
339 resize.prev_region = prev_region;
340 return true;
341 }
342
343 // edit low limit
344 resize.mode = resize.moving_low_limit;
345 resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
346 return true;
347 }
348 if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
349 int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
350 if (x <= hi - 2) break;
351 if (x < hi + 2) {
352 // edit high limit
353 resize.region = r;
354 resize.pos = r->KeyRange.high + 1;
355 resize.mode = resize.moving_high_limit;
356 resize.min = r->KeyRange.low + 1;
357 resize.max = next_region ? next_region->KeyRange.low : 128;
358 return true;
359 }
360 }
361 prev_region = r;
362 }
363 }
364 return false;
365 }
366
367 sigc::signal<void> RegionChooser::signal_sel_changed()
368 {
369 return sel_changed_signal;
370 }

  ViewVC Help
Powered by ViewVC