/[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 1660 - (show annotations) (download)
Sun Feb 3 00:19:55 2008 UTC (16 years, 1 month ago) by schoenebeck
File size: 28208 byte(s)
* call it virtually baby: the keyboard finally can trigger notes on
  sampler side (only in live-mode of course)
* added a red cross on top of the detached-mode icon to make
  it more obvious

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

  ViewVC Help
Powered by ViewVC