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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1623 - (hide annotations) (download)
Fri Jan 4 19:42:45 2008 UTC (16 years, 3 months ago) by persson
File size: 26015 byte(s)
* gig files where regions are not internally ordered are now handled
* the resize mouse pointer is not shown anymore for regions that can't
  be resized
* the region and dimregion chooser widgets are now resizable
* bugfix: sometimes you could not delete more than one dimension
* filter headers are now also greyed out when the filter is inactive

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

  ViewVC Help
Powered by ViewVC