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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1658 - (show annotations) (download)
Sat Feb 2 08:52:48 2008 UTC (16 years, 2 months ago) by persson
File size: 26715 byte(s)
* fixed the inaccurate drawing of pressed keys

1 /*
2 * Copyright (C) 2006-2008 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 <algorithm>
22 #include <gdkmm/cursor.h>
23 #include <gtkmm/stock.h>
24 #include <gtkmm/spinbutton.h>
25 #include <gtkmm/dialog.h>
26 #include <math.h>
27
28 #include "global.h"
29
30 void SortedRegions::update(gig::Instrument* instrument) {
31 // Usually, the regions in a gig file are ordered after their key
32 // range, but there are files where they are not. The
33 // RegionChooser code needs a sorted list of regions.
34 regions.clear();
35 if (instrument) {
36 for (gig::Region *r = instrument->GetFirstRegion() ;
37 r ;
38 r = instrument->GetNextRegion()) {
39 regions.push_back(r);
40 }
41 sort(regions.begin(), regions.end(), *this);
42 }
43 }
44
45 gig::Region* SortedRegions::first() {
46 region_iterator = regions.begin();
47 return region_iterator == regions.end() ? 0 : *region_iterator;
48 }
49
50 gig::Region* SortedRegions::next() {
51 region_iterator++;
52 return region_iterator == regions.end() ? 0 : *region_iterator;
53 }
54
55
56
57 RegionChooser::RegionChooser()
58 {
59 Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();
60
61 red = Gdk::Color("#8070ff");
62 grey1 = Gdk::Color("#b0b0b0");
63 activeKeyColor = Gdk::Color("#ff0000");
64 white = Gdk::Color("#ffffff");
65 black = Gdk::Color("#000000");
66
67 colormap->alloc_color(red);
68 colormap->alloc_color(grey1);
69 colormap->alloc_color(activeKeyColor);
70 colormap->alloc_color(white);
71 colormap->alloc_color(black);
72 instrument = 0;
73 region = 0;
74 resize.active = false;
75 move.active = false;
76 cursor_is_resize = false;
77 h1 = 20;
78
79 actionGroup = Gtk::ActionGroup::create();
80 actionGroup->add(Gtk::Action::create("Properties",
81 Gtk::Stock::PROPERTIES),
82 sigc::mem_fun(*this,
83 &RegionChooser::show_region_properties));
84 actionGroup->add(Gtk::Action::create("Remove", Gtk::Stock::REMOVE),
85 sigc::mem_fun(*this, &RegionChooser::delete_region));
86 actionGroup->add(Gtk::Action::create("Add", Gtk::Stock::ADD),
87 sigc::mem_fun(*this, &RegionChooser::add_region));
88 actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),
89 sigc::mem_fun(*this, &RegionChooser::manage_dimensions));
90
91 uiManager = Gtk::UIManager::create();
92 uiManager->insert_action_group(actionGroup);
93 Glib::ustring ui_info =
94 "<ui>"
95 " <popup name='PopupMenuInsideRegion'>"
96 " <menuitem action='Properties'/>"
97 " <menuitem action='Dimensions'/>"
98 " <menuitem action='Remove'/>"
99 " </popup>"
100 " <popup name='PopupMenuOutsideRegion'>"
101 " <menuitem action='Add'/>"
102 " </popup>"
103 "</ui>";
104 uiManager->add_ui_from_string(ui_info);
105
106 popup_menu_inside_region = dynamic_cast<Gtk::Menu*>(
107 uiManager->get_widget("/PopupMenuInsideRegion"));
108 popup_menu_outside_region = dynamic_cast<Gtk::Menu*>(
109 uiManager->get_widget("/PopupMenuOutsideRegion"));
110
111 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
112 Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK);
113
114 dimensionManager.region_to_be_changed_signal.connect(
115 region_to_be_changed_signal.make_slot()
116 );
117 dimensionManager.region_changed_signal.connect(
118 region_changed_signal.make_slot()
119 );
120 dimensionManager.region_changed_signal.connect(
121 sigc::hide(
122 sigc::mem_fun(*this, &RegionChooser::on_dimension_manager_changed)
123 )
124 );
125 }
126
127 RegionChooser::~RegionChooser()
128 {
129 }
130
131 void RegionChooser::on_note_on_event(int key, int velocity) {
132 draw_region(key, key+1, activeKeyColor);
133 }
134
135 void RegionChooser::on_note_off_event(int key, int velocity) {
136 if (is_black_key(key))
137 draw_region(key, key+1, black);
138 else
139 draw_region(key, key+1, white);
140 }
141
142 void RegionChooser::on_realize()
143 {
144 // We need to call the base on_realize()
145 Gtk::DrawingArea::on_realize();
146
147 // Now we can allocate any additional resources we need
148 Glib::RefPtr<Gdk::Window> window = get_window();
149 gc = Gdk::GC::create(window);
150 window->clear();
151 }
152
153 bool RegionChooser::on_expose_event(GdkEventExpose* event)
154 {
155 Glib::RefPtr<Gdk::Window> window = get_window();
156 window->clear();
157 const int h = 40;
158 const int w = get_width() - 1;
159 const int bh = int(h * 0.55);
160
161 Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
162 Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();
163
164 window->draw_rectangle(black, false, 0, h1, w, h - 1);
165 gc->set_foreground(grey1);
166 int x1 = int(w * 20.5 / 128.0 + 0.5);
167 int x2 = int(w * 109.5 / 128.0 + 0.5);
168 window->draw_rectangle(gc, true, 1, h1 + 1,
169 x1 - 1, h - 2);
170 window->draw_rectangle(white, true, x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
171 window->draw_rectangle(gc, true, x2 + 1, h1 + 1,
172 w - x2 - 1, h - 2);
173 for (int i = 0 ; i < 128 ; i++) {
174 int note = (i + 3) % 12;
175 int x = int(w * i / 128.0 + 0.5);
176
177 if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) {
178 int x2 = int(w * (i + 0.5) / 128.0 + 0.5);
179 window->draw_line(black, x2, h1 + bh, x2, h1 + h);
180
181 int x3 = int(w * (i + 1) / 128.0 + 0.5);
182 window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh);
183 } else if (note == 3 || note == 8) {
184 window->draw_line(black, x, h1 + 1, x, h1 + h);
185 }
186 if (note == 3) draw_digit(i);
187 }
188
189 if (instrument) {
190 int i = 0;
191 gig::Region *next_region;
192 int x3 = -1;
193 for (gig::Region *r = regions.first() ; r ; r = next_region) {
194
195 if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);
196 next_region = regions.next();
197 if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
198 int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
199 window->draw_line(black, x3, 0, x2, 0);
200 window->draw_line(black, x3, h1 - 1, x2, h1 - 1);
201 window->draw_line(black, x2, 1, x2, h1 - 2);
202 window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);
203 x3 = -1;
204 }
205 i++;
206 }
207
208 for (gig::Region *r = regions.first() ; r ; r = regions.next()) {
209 int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);
210 window->draw_line(black, x, 1, x, h1 - 2);
211 }
212
213 if (region) {
214 int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);
215 int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);
216 gc->set_foreground(red);
217 window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);
218 }
219 }
220 return true;
221 }
222
223
224 void RegionChooser::on_size_request(GtkRequisition* requisition)
225 {
226 *requisition = GtkRequisition();
227 requisition->height = 40 + 20;
228 requisition->width = 500;
229 }
230
231 bool RegionChooser::is_black_key(int key) {
232 const int note = (key + 3) % 12;
233 return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
234 }
235
236 void RegionChooser::draw_digit(int key) {
237 const int h = 40;
238 const int w = get_width() - 1;
239 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(get_pango_context());
240 char buf[30];
241 sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
242 layout->set_markup(buf);
243 Pango::Rectangle rectangle = layout->get_logical_extents();
244 double text_w = double(rectangle.get_width()) / Pango::SCALE;
245 double text_h = double(rectangle.get_height()) / Pango::SCALE;
246 double x = w * (key + 0.75) / 128.0;
247 get_window()->draw_layout(get_style()->get_black_gc(), int(x - text_w / 2 + 1),
248 int(h1 + h - text_h + 0.5), layout);
249 }
250
251 void RegionChooser::draw_region(int from, int to, const Gdk::Color& color)
252 {
253 const int h = 40;
254 const int w = get_width() - 1;
255 const int bh = int(h * 0.55);
256
257 Glib::RefPtr<Gdk::Window> window = get_window();
258 gc->set_foreground(color);
259
260 for (int i = from ; i < to ; i++) {
261 int note = (i + 3) % 12;
262 int x = int(w * i / 128.0 + 0.5) + 1;
263 int x2 = int(w * (i + 1.5) / 128.0 + 0.5);
264 int x3 = int(w * (i + 1) / 128.0 + 0.5);
265 int x4 = int(w * (i - 0.5) / 128.0 + 0.5);
266 int w1 = x3 - x;
267 switch (note) {
268 case 0: case 5: case 10:
269 window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
270 window->draw_rectangle(gc, true, x4 + 1, h1 + bh + 1, x2 - x4 - 1, h - bh - 2);
271 break;
272 case 2: case 7:
273 window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
274 window->draw_rectangle(gc, true, x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2);
275 break;
276 case 3: case 8:
277 window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
278 window->draw_rectangle(gc, true, x, h1 + bh + 1, x2 - x, h - bh - 2);
279 if (note == 3) draw_digit(i);
280 break;
281 default:
282 window->draw_rectangle(gc, true, x, h1 + 1, w1, bh - 1);
283 break;
284 }
285 }
286 }
287
288 void RegionChooser::set_instrument(gig::Instrument* instrument)
289 {
290 this->instrument = instrument;
291 regions.update(instrument);
292 region = regions.first();
293 queue_draw();
294 region_selected();
295 }
296
297 bool RegionChooser::on_button_release_event(GdkEventButton* event)
298 {
299 if (resize.active) {
300 get_window()->pointer_ungrab(event->time);
301 resize.active = false;
302
303 if (resize.mode == resize.moving_high_limit) {
304 if (resize.region->KeyRange.high != resize.pos - 1) {
305 instrument_struct_to_be_changed_signal.emit(instrument);
306 resize.region->SetKeyRange(
307 resize.region->KeyRange.low, // low
308 resize.pos - 1 // high
309 );
310 regions.update(instrument);
311 instrument_changed.emit();
312 instrument_struct_changed_signal.emit(instrument);
313 }
314 } else if (resize.mode == resize.moving_low_limit) {
315 if (resize.region->KeyRange.low != resize.pos) {
316 instrument_struct_to_be_changed_signal.emit(instrument);
317 resize.region->SetKeyRange(
318 resize.pos, // low
319 resize.region->KeyRange.high // high
320 );
321 regions.update(instrument);
322 instrument_changed.emit();
323 instrument_struct_changed_signal.emit(instrument);
324 }
325 }
326
327 if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
328 get_window()->set_cursor();
329 cursor_is_resize = false;
330 }
331 } else if (move.active) {
332 get_window()->pointer_ungrab(event->time);
333 move.active = false;
334
335 if (move.pos) {
336 instrument_struct_to_be_changed_signal.emit(instrument);
337 region->SetKeyRange(
338 region->KeyRange.low + move.pos,
339 region->KeyRange.high + move.pos
340 );
341 regions.update(instrument);
342 instrument_changed.emit();
343 instrument_struct_changed_signal.emit(instrument);
344 }
345
346 if (is_in_resize_zone(event->x, event->y)) {
347 get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
348 cursor_is_resize = true;
349 }
350 }
351 return true;
352 }
353
354 bool RegionChooser::on_button_press_event(GdkEventButton* event)
355 {
356 if (!instrument) return true;
357
358 int k = int(event->x / (get_width() - 1) * 128.0);
359
360 if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
361 gig::Region* r = get_region(k);
362 if (r) {
363 region = r;
364 queue_draw();
365 region_selected();
366 popup_menu_inside_region->popup(event->button, event->time);
367 } else {
368 new_region_pos = k;
369 popup_menu_outside_region->popup(event->button, event->time);
370 }
371 } else {
372 if (is_in_resize_zone(event->x, event->y)) {
373 get_window()->pointer_grab(false,
374 Gdk::BUTTON_RELEASE_MASK |
375 Gdk::POINTER_MOTION_MASK |
376 Gdk::POINTER_MOTION_HINT_MASK,
377 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW), event->time);
378 resize.active = true;
379 } else {
380 gig::Region* r = get_region(k);
381 if (r) {
382 region = r;
383 queue_draw();
384 region_selected();
385
386 get_window()->pointer_grab(false,
387 Gdk::BUTTON_RELEASE_MASK |
388 Gdk::POINTER_MOTION_MASK |
389 Gdk::POINTER_MOTION_HINT_MASK,
390 Gdk::Cursor(Gdk::FLEUR), event->time);
391 move.active = true;
392 move.from_x = event->x;
393 move.pos = 0;
394 }
395 }
396 }
397 return true;
398 }
399
400 gig::Region* RegionChooser::get_region(int key)
401 {
402 gig::Region* prev_region = 0;
403 gig::Region* next_region;
404 for (gig::Region *r = regions.first() ; r ; r = next_region) {
405 next_region = regions.next();
406
407 if (key < r->KeyRange.low) return 0;
408 if (key <= r->KeyRange.high) {
409 move.touch_left = prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low;
410 move.touch_right = next_region && r->KeyRange.high + 1 == next_region->KeyRange.low;
411 return r;
412 }
413 prev_region = r;
414 }
415 return 0;
416 }
417
418 void RegionChooser::motion_resize_region(int x, int y)
419 {
420 const int w = get_width() - 1;
421 Glib::RefPtr<Gdk::Window> window = get_window();
422
423 int k = int(double(x) / w * 128.0 + 0.5);
424
425 if (k < resize.min) k = resize.min;
426 else if (k > resize.max) k = resize.max;
427
428 if (k != resize.pos) {
429 if (resize.mode == resize.undecided) {
430 if (k < resize.pos) {
431 // edit high limit of prev_region
432 resize.max = resize.region->KeyRange.low;
433 resize.region = resize.prev_region;
434 resize.mode = resize.moving_high_limit;
435 } else {
436 // edit low limit of region
437 resize.min = resize.prev_region->KeyRange.high + 1;
438 resize.mode = resize.moving_low_limit;
439 }
440 }
441 Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
442 Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();
443 if (region == resize.region) {
444 gc->set_foreground(red);
445 white = gc;
446 }
447 Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);
448 int prevx = int(w * resize.pos / 128.0 + 0.5);
449 x = int(w * k / 128.0 + 0.5);
450
451 if (resize.mode == resize.moving_high_limit) {
452 if (k > resize.pos) {
453 window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);
454 window->draw_line(black, prevx, 0, x, 0);
455 window->draw_line(black, prevx, h1 - 1, x, h1 - 1);
456 } else {
457 int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);
458 window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);
459 }
460 } else {
461 if (k < resize.pos) {
462 window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);
463 window->draw_line(black, x, 0, prevx, 0);
464 window->draw_line(black, x, h1 - 1, prevx, h1 - 1);
465 } else {
466 int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);
467 window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);
468 }
469 }
470 window->draw_line(black, x, 1, x, h1 - 2);
471 resize.pos = k;
472 }
473 }
474
475 void RegionChooser::motion_move_region(int x, int y)
476 {
477 const int w = get_width() - 1;
478 Glib::RefPtr<Gdk::Window> window = get_window();
479
480 int k = int(double(x - move.from_x) / w * 128.0 + 0.5);
481 if (k == move.pos) return;
482 int new_k;
483 bool new_touch_left;
484 bool new_touch_right;
485 int a = 0;
486 if (k > move.pos) {
487 for (gig::Region* r = regions.first() ; ; r = regions.next()) {
488 if (r != region) {
489 int b = r ? r->KeyRange.low : 128;
490
491 // gap: from a to b (not inclusive b)
492
493 if (region->KeyRange.high + move.pos >= b) {
494 // not found the current gap yet, just continue
495 } else {
496
497 if (a > region->KeyRange.low + k) {
498 // this gap is too far to the right, break
499 break;
500 }
501
502 int newhigh = std::min(region->KeyRange.high + k, b - 1);
503 int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);
504
505 if (newlo >= a) {
506 // yes it fits - it's a candidate
507 new_k = newlo - region->KeyRange.low;
508 new_touch_left = a > 0 && a == newlo;
509 new_touch_right = b < 128 && newhigh + 1 == b;
510 }
511 }
512 if (!r) break;
513 a = r->KeyRange.high + 1;
514 }
515 }
516 } else {
517 for (gig::Region* r = regions.first() ; ; r = regions.next()) {
518 if (r != region) {
519 int b = r ? r->KeyRange.low : 128;
520
521 // gap from a to b (not inclusive b)
522
523 if (region->KeyRange.high + k >= b) {
524 // not found the current gap yet, just continue
525 } else {
526
527 if (a > region->KeyRange.low + move.pos) {
528 // this gap is too far to the right, break
529 break;
530 }
531
532 int newlo = std::max(region->KeyRange.low + k, a);
533 int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);
534
535 if (newhigh < b) {
536 // yes it fits - break as the first one is the best
537 new_k = newlo - region->KeyRange.low;
538 new_touch_left = a > 0 && a == newlo;
539 new_touch_right = b < 128 && newhigh + 1 == b;
540 break;
541 }
542 }
543 if (!r) break;
544 a = r->KeyRange.high + 1;
545 }
546 }
547 }
548 k = new_k;
549 if (k == move.pos) return;
550
551 Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);
552 int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);
553 x = int(w * (k + region->KeyRange.low) / 128.0 + 0.5);
554 int prevx2 = int(w * (move.pos + region->KeyRange.high + 1) / 128.0 + 0.5);
555 int x2 = int(w * (k + region->KeyRange.high + 1) / 128.0 + 0.5);
556 Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
557 gc->set_foreground(red);
558
559 if (!new_touch_left) window->draw_line(black, x, 1, x, h1 - 2);
560 if (!new_touch_right) window->draw_line(black, x2, 1, x2, h1 - 2);
561
562 if (k > move.pos) {
563 window->draw_rectangle(bg, true, prevx + (move.touch_left ? 1 : 0), 0,
564 std::min(x, prevx2 + 1 - (move.touch_right ? 1 : 0)) -
565 (prevx + (move.touch_left ? 1 : 0)), h1);
566
567 window->draw_line(black, std::max(x, prevx2 + 1), 0, x2, 0);
568 window->draw_line(black, std::max(x, prevx2 + 1), h1 - 1, x2, h1 - 1);
569 window->draw_rectangle(gc, true, std::max(x + 1, prevx2), 1,
570 x2 - std::max(x + 1, prevx2), h1 - 2);
571 } else {
572 window->draw_rectangle(bg, true, std::max(x2 + 1, prevx + (move.touch_left ? 1 : 0)), 0,
573 prevx2 + 1 - (move.touch_right ? 1 : 0) -
574 std::max(x2 + 1, prevx + (move.touch_left ? 1 : 0)), h1);
575
576 window->draw_line(black, x, 0, std::min(x2, prevx - 1), 0);
577 window->draw_line(black, x, h1 - 1, std::min(x2, prevx - 1), h1 - 1);
578
579 window->draw_rectangle(gc, true, x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);
580 }
581
582 move.pos = k;
583 move.touch_left = new_touch_left;
584 move.touch_right = new_touch_right;
585 }
586
587
588 bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)
589 {
590 Glib::RefPtr<Gdk::Window> window = get_window();
591 int x, y;
592 Gdk::ModifierType state = Gdk::ModifierType(0);
593 window->get_pointer(x, y, state);
594
595 if (resize.active) {
596 motion_resize_region(x, y);
597 } else if (move.active) {
598 motion_move_region(x, y);
599 } else {
600 if (is_in_resize_zone(x, y)) {
601 if (!cursor_is_resize) {
602 window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
603 cursor_is_resize = true;
604 }
605 } else if (cursor_is_resize) {
606 window->set_cursor();
607 cursor_is_resize = false;
608 }
609 }
610
611 return true;
612 }
613
614 bool RegionChooser::is_in_resize_zone(double x, double y) {
615 const int w = get_width() - 1;
616
617 if (instrument && y >= 0 && y <= h1) {
618 gig::Region* prev_region = 0;
619 gig::Region* next_region;
620 for (gig::Region* r = regions.first(); r ; r = next_region) {
621 next_region = regions.next();
622
623 int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);
624 if (x <= lo - 2) break;
625 if (x < lo + 2) {
626 resize.region = r;
627 resize.pos = r->KeyRange.low;
628 resize.max = r->KeyRange.high;
629
630 if (prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low) {
631 // we don't know yet if it's the high limit of
632 // prev_region or the low limit of r that's going
633 // to be edited
634 resize.mode = resize.undecided;
635 resize.min = prev_region->KeyRange.low + 1;
636 resize.prev_region = prev_region;
637 return resize.min != resize.max;
638 }
639
640 // edit low limit
641 resize.mode = resize.moving_low_limit;
642 resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
643 return resize.min != resize.max;
644 }
645 if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
646 int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
647 if (x <= hi - 2) break;
648 if (x < hi + 2) {
649 // edit high limit
650 resize.region = r;
651 resize.pos = r->KeyRange.high + 1;
652 resize.mode = resize.moving_high_limit;
653 resize.min = r->KeyRange.low + 1;
654 resize.max = next_region ? next_region->KeyRange.low : 128;
655 return resize.min != resize.max;
656 }
657 }
658 prev_region = r;
659 }
660 }
661 return false;
662 }
663
664 sigc::signal<void>& RegionChooser::signal_region_selected()
665 {
666 return region_selected;
667 }
668
669 sigc::signal<void>& RegionChooser::signal_instrument_changed()
670 {
671 return instrument_changed;
672 }
673
674 void RegionChooser::show_region_properties()
675 {
676 if (!region) return;
677 Gtk::Dialog dialog("Region Properties", true /*modal*/);
678 // add "Keygroup" checkbox
679 Gtk::CheckButton checkBoxKeygroup("Member of a Keygroup (Exclusive Group)");
680 checkBoxKeygroup.set_active(region->KeyGroup);
681 dialog.get_vbox()->pack_start(checkBoxKeygroup);
682 checkBoxKeygroup.show();
683 // add "Keygroup" spinbox
684 Gtk::Adjustment adjustment(1, 1, pow(2,32));
685 Gtk::SpinButton spinBox(adjustment);
686 if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
687 dialog.get_vbox()->pack_start(spinBox);
688 spinBox.show();
689 // add OK and CANCEL buttons to the dialog
690 dialog.add_button(Gtk::Stock::OK, 0);
691 dialog.add_button(Gtk::Stock::CANCEL, 1);
692 dialog.show_all_children();
693 if (!dialog.run()) { // OK selected ...
694 region->KeyGroup =
695 (checkBoxKeygroup.get_active()) ? spinBox.get_value_as_int() : 0;
696 }
697 }
698
699 void RegionChooser::add_region()
700 {
701 instrument_struct_to_be_changed_signal.emit(instrument);
702
703 region = instrument->AddRegion();
704 region->SetKeyRange(new_region_pos, new_region_pos);
705
706 instrument_struct_changed_signal.emit(instrument);
707 regions.update(instrument);
708
709 queue_draw();
710 region_selected();
711 instrument_changed();
712 }
713
714 void RegionChooser::delete_region()
715 {
716 instrument_struct_to_be_changed_signal.emit(instrument);
717 instrument->DeleteRegion(region);
718 instrument_struct_changed_signal.emit(instrument);
719 regions.update(instrument);
720
721 region = 0;
722 queue_draw();
723 region_selected();
724 instrument_changed();
725 }
726
727 void RegionChooser::manage_dimensions()
728 {
729 gig::Region* region = get_region();
730 if (!region) return;
731 dimensionManager.show(region);
732 }
733
734 void RegionChooser::on_dimension_manager_changed() {
735 region_selected();
736 instrument_changed();
737 }
738
739 sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_to_be_changed() {
740 return instrument_struct_to_be_changed_signal;
741 }
742
743 sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_changed() {
744 return instrument_struct_changed_signal;
745 }
746
747 sigc::signal<void, gig::Region*>& RegionChooser::signal_region_to_be_changed() {
748 return region_to_be_changed_signal;
749 }
750
751 sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {
752 return region_changed_signal;
753 }

  ViewVC Help
Powered by ViewVC