/[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 3409 - (show annotations) (download)
Tue Jan 23 16:30:56 2018 UTC (6 years, 2 months ago) by schoenebeck
File size: 45676 byte(s)
* Added new main menu item "View" -> "Tooltips for Beginners" which allows
  to disable tooltips intended for newbies only (default: on).
* Bumped version (1.1.0.svn3).

1 /*
2 * Copyright (C) 2006-2017 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 "compat.h"
21 #include "global.h"
22 #include "regionchooser.h"
23
24 #include <algorithm>
25 #include <assert.h>
26
27 #include <cairomm/context.h>
28 #include <gdkmm/general.h>
29 #if HAS_GDKMM_SEAT
30 # include <gdkmm/seat.h>
31 #endif
32 #include <gdkmm/cursor.h>
33 #if HAS_GTKMM_STOCK
34 # include <gtkmm/stock.h>
35 #endif
36 #include <gdkmm/pixbuf.h>
37 #include <gtkmm/spinbutton.h>
38 #include <gtkmm/dialog.h>
39
40 #include "Settings.h"
41 #include "gfx/builtinpix.h"
42
43 #define REGION_BLOCK_HEIGHT 30
44 #define KEYBOARD_HEIGHT 40
45
46 struct RegionFeatures {
47 int sampleRefs;
48 int loops;
49 int validDimRegs;
50
51 RegionFeatures() {
52 sampleRefs = loops = validDimRegs = 0;
53 }
54 };
55
56 static RegionFeatures regionFeatures(gig::Region* rgn) {
57 RegionFeatures f;
58 for (int i = 0; i < rgn->DimensionRegions; ++i) {
59 gig::DimensionRegion* dr = rgn->pDimensionRegions[i];
60 DimensionCase c = dimensionCaseOf(dr);
61 if (!isUsedCase(c, rgn)) continue;
62 f.validDimRegs++;
63 if (dr->pSample) f.sampleRefs++;
64 // the user doesn't care about loop if there is no valid sample reference
65 if (dr->pSample && dr->SampleLoops) f.loops++;
66 }
67 return f;
68 }
69
70 void SortedRegions::update(gig::Instrument* instrument) {
71 // Usually, the regions in a gig file are ordered after their key
72 // range, but there are files where they are not. The
73 // RegionChooser code needs a sorted list of regions.
74 regions.clear();
75 if (instrument) {
76 for (gig::Region* r = instrument->GetFirstRegion() ;
77 r ;
78 r = instrument->GetNextRegion()) {
79 regions.push_back(r);
80 }
81 sort(regions.begin(), regions.end(), *this);
82 }
83 }
84
85 gig::Region* SortedRegions::first() {
86 region_iterator = regions.begin();
87 return region_iterator == regions.end() ? 0 : *region_iterator;
88 }
89
90 gig::Region* SortedRegions::next() {
91 ++region_iterator;
92 return region_iterator == regions.end() ? 0 : *region_iterator;
93 }
94
95
96
97 RegionChooser::RegionChooser() :
98 activeKeyColor("red"),
99 blue("#4796ff"),
100 grey1("grey69"),
101 white("white"),
102 black("black"),
103 m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),
104 currentActiveKey(-1),
105 modifyallregions(false)
106 {
107 set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT);
108
109 loadBuiltInPix();
110
111 // create blue hatched pattern
112 {
113 const int width = blueHatchedPattern->get_width();
114 const int height = blueHatchedPattern->get_height();
115 const int stride = blueHatchedPattern->get_rowstride();
116
117 // manually convert from RGBA to ARGB
118 this->blueHatchedPatternARGB = blueHatchedPattern->copy();
119 const int pixelSize = stride / width;
120 const int totalPixels = width * height;
121 assert(pixelSize == 4);
122 unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
123 for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
124 const unsigned char r = ptr[0];
125 const unsigned char g = ptr[1];
126 const unsigned char b = ptr[2];
127 const unsigned char a = ptr[3];
128 ptr[0] = b;
129 ptr[1] = g;
130 ptr[2] = r;
131 ptr[3] = a;
132 }
133
134 Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
135 #if HAS_CAIROMM_CPP11_ENUMS
136 this->blueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
137 #else
138 this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
139 #endif
140 );
141 this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
142 #if HAS_CAIROMM_CPP11_ENUMS
143 this->blueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
144 #else
145 this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
146 #endif
147 }
148
149 instrument = 0;
150 region = 0;
151 resize.active = false;
152 move.active = false;
153 cursor_is_resize = false;
154 h1 = REGION_BLOCK_HEIGHT;
155
156 // properties of the virtual keyboard
157 {
158 const char* choices[] = { _("normal"), _("chord"), 0 };
159 static const virt_keyboard_mode_t values[] = {
160 VIRT_KEYBOARD_MODE_NORMAL,
161 VIRT_KEYBOARD_MODE_CHORD
162 };
163 m_VirtKeybModeChoice.set_choices(choices, values);
164 m_VirtKeybModeChoice.set_value(VIRT_KEYBOARD_MODE_NORMAL);
165 }
166 m_VirtKeybVelocityLabelDescr.set_text(_("Note-On Velocity:"));
167 m_VirtKeybVelocityLabel.set_text("-");
168 m_VirtKeybOffVelocityLabelDescr.set_text(_("Note-Off Velocity:"));
169 m_VirtKeybOffVelocityLabel.set_text("-");
170 m_VirtKeybPropsBox.pack_start(m_VirtKeybModeChoice.label, Gtk::PACK_SHRINK);
171 m_VirtKeybPropsBox.pack_start(m_VirtKeybModeChoice.widget, Gtk::PACK_SHRINK);
172 m_VirtKeybPropsBox.pack_start(m_VirtKeybVelocityLabelDescr, Gtk::PACK_SHRINK);
173 m_VirtKeybPropsBox.pack_start(m_VirtKeybVelocityLabel, Gtk::PACK_SHRINK);
174 m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabelDescr, Gtk::PACK_SHRINK);
175 m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);
176 m_VirtKeybPropsBox.set_spacing(10);
177 m_VirtKeybPropsBox.show();
178 for (int i = 0 ; i < 128 ; i++) key_pressed[i] = false;
179
180 actionGroup = ActionGroup::create();
181 #if USE_GLIB_ACTION
182 actionGroup->add_action(
183 "Properties", sigc::mem_fun(*this, &RegionChooser::show_region_properties)
184 );
185 actionGroup->add_action(
186 "Remove", sigc::mem_fun(*this, &RegionChooser::delete_region)
187 );
188 actionGroup->add_action(
189 "Add", sigc::mem_fun(*this, &RegionChooser::add_region)
190 );
191 actionGroup->add_action(
192 "Dimensions", sigc::mem_fun(*this, &RegionChooser::manage_dimensions)
193 );
194 insert_action_group("PopupMenuInsideRegion", actionGroup);
195 #else
196 actionGroup->add(Gtk::Action::create("Properties",
197 Gtk::Stock::PROPERTIES),
198 sigc::mem_fun(*this,
199 &RegionChooser::show_region_properties));
200 actionGroup->add(Gtk::Action::create("Remove", Gtk::Stock::REMOVE),
201 sigc::mem_fun(*this, &RegionChooser::delete_region));
202 actionGroup->add(Gtk::Action::create("Add", Gtk::Stock::ADD),
203 sigc::mem_fun(*this, &RegionChooser::add_region));
204 actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),
205 sigc::mem_fun(*this, &RegionChooser::manage_dimensions));
206 #endif
207
208 #if USE_GTKMM_BUILDER
209 uiManager = Gtk::Builder::create();
210 Glib::ustring ui_info =
211 "<interface>"
212 " <menu id='menu-PopupMenuInsideRegion'>"
213 " <section>"
214 " <item>"
215 " <attribute name='label' translatable='yes'>Properties</attribute>"
216 " <attribute name='action'>PopupMenuInsideRegion.Properties</attribute>"
217 " </item>"
218 " <item>"
219 " <attribute name='label' translatable='yes'>Dimensions</attribute>"
220 " <attribute name='action'>PopupMenuInsideRegion.Dimensions</attribute>"
221 " </item>"
222 " <item>"
223 " <attribute name='label' translatable='yes'>Remove</attribute>"
224 " <attribute name='action'>PopupMenuInsideRegion.Remove</attribute>"
225 " </item>"
226 " </section>"
227 " </menu>"
228 " <menu id='menu-PopupMenuOutsideRegion'>"
229 " <section>"
230 " <item>"
231 " <attribute name='label' translatable='yes'>Add</attribute>"
232 " <attribute name='action'>PopupMenuInsideRegion.Add</attribute>"
233 " </item>"
234 " </section>"
235 " </menu>"
236 "</interface>";
237 uiManager->add_from_string(ui_info);
238
239 popup_menu_inside_region = new Gtk::Menu(
240 Glib::RefPtr<Gio::Menu>::cast_dynamic(
241 uiManager->get_object("menu-PopupMenuInsideRegion")
242 )
243 );
244 popup_menu_outside_region = new Gtk::Menu(
245 Glib::RefPtr<Gio::Menu>::cast_dynamic(
246 uiManager->get_object("menu-PopupMenuOutsideRegion")
247 )
248 );
249 #else
250 uiManager = Gtk::UIManager::create();
251 uiManager->insert_action_group(actionGroup);
252 Glib::ustring ui_info =
253 "<ui>"
254 " <popup name='PopupMenuInsideRegion'>"
255 " <menuitem action='Properties'/>"
256 " <menuitem action='Dimensions'/>"
257 " <menuitem action='Remove'/>"
258 " </popup>"
259 " <popup name='PopupMenuOutsideRegion'>"
260 " <menuitem action='Add'/>"
261 " </popup>"
262 "</ui>";
263 uiManager->add_ui_from_string(ui_info);
264
265 popup_menu_inside_region = dynamic_cast<Gtk::Menu*>(
266 uiManager->get_widget("/PopupMenuInsideRegion"));
267 popup_menu_outside_region = dynamic_cast<Gtk::Menu*>(
268 uiManager->get_widget("/PopupMenuOutsideRegion"));
269
270 #endif // USE_GTKMM_BUILDER
271
272 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 22)
273 # warning GTKMM4 event registration code missing for regionchooser!
274 //add_events(Gdk::EventMask::BUTTON_PRESS_MASK);
275 #else
276 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
277 Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK);
278 #endif
279
280 dimensionManager.region_to_be_changed_signal.connect(
281 region_to_be_changed_signal.make_slot()
282 );
283 dimensionManager.region_changed_signal.connect(
284 region_changed_signal.make_slot()
285 );
286 dimensionManager.region_changed_signal.connect(
287 sigc::hide(
288 sigc::mem_fun(*this, &RegionChooser::on_dimension_manager_changed)
289 )
290 );
291 keyboard_key_hit_signal.connect(
292 sigc::mem_fun(*this, &RegionChooser::on_note_on_event)
293 );
294 keyboard_key_released_signal.connect(
295 sigc::mem_fun(*this, &RegionChooser::on_note_off_event)
296 );
297 set_tooltip_text(_("Right click here for adding new region. Use mouse pointer for moving (dragging) or resizing existing regions (by pointing at region's boundary). Right click on an existing region for more actions."));
298
299 Settings::singleton()->showTooltips.get_proxy().signal_changed().connect(
300 sigc::mem_fun(*this, &RegionChooser::on_show_tooltips_changed)
301 );
302
303 on_show_tooltips_changed();
304 }
305
306 RegionChooser::~RegionChooser()
307 {
308 }
309
310 void RegionChooser::on_show_tooltips_changed() {
311 const bool b = Settings::singleton()->showTooltips;
312
313 set_has_tooltip(b);
314 }
315
316 void RegionChooser::setModifyAllRegions(bool b) {
317 modifyallregions = b;
318 // redraw required parts
319 queue_draw();
320 }
321
322 void RegionChooser::invalidate_key(int key) {
323 const int h = KEYBOARD_HEIGHT;
324 const int w = get_width() - 1;
325 int x1 = key_to_x(key - 0.5, w);
326 int x2 = key_to_x(key + 1.5, w);
327
328 Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
329 get_window()->invalidate_rect(rect, false);
330 }
331
332 void RegionChooser::on_note_on_event(int key, int velocity) {
333 key_pressed[key] = true;
334 invalidate_key(key);
335 m_VirtKeybVelocityLabel.set_text(ToString(velocity));
336 }
337
338 void RegionChooser::on_note_off_event(int key, int velocity) {
339 key_pressed[key] = false;
340 invalidate_key(key);
341 m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
342 }
343
344
345 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
346 bool RegionChooser::on_expose_event(GdkEventExpose* e) {
347 double clipx1 = e->area.x;
348 double clipx2 = e->area.x + e->area.width;
349 double clipy1 = e->area.y;
350 double clipy2 = e->area.y + e->area.height;
351
352 const Cairo::RefPtr<Cairo::Context>& cr =
353 get_window()->create_cairo_context();
354 #if 0
355 }
356 #endif
357 #else
358 bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
359 double clipx1, clipx2, clipy1, clipy2;
360 cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
361 #endif
362
363 cr->save();
364 cr->set_line_width(1);
365
366 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
367 const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
368 #else
369 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 22)
370 GdkRGBA gdkBgRGBA;
371 gtk_style_context_get_background_color(get_style_context()->gobj(), &gdkBgRGBA);
372 const Gdk::RGBA bg = Glib::wrap(&gdkBgRGBA, true);
373 # else
374 const Gdk::RGBA bg = get_style_context()->get_background_color();
375 # endif
376 #endif
377 Gdk::Cairo::set_source_rgba(cr, bg);
378 cr->paint();
379
380 if (clipy2 > h1) {
381 draw_keyboard(cr, clipx1, clipx2);
382 }
383
384 if (clipy1 < h1 && instrument) {
385 draw_regions(cr, clipx1, clipx2);
386 }
387
388 cr->restore();
389
390 return true;
391 }
392
393 void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
394 int clip_low, int clip_high) {
395 const int h = KEYBOARD_HEIGHT;
396 const int w = get_width() - 1;
397 const int bh = int(h * 0.55);
398
399 Gdk::Cairo::set_source_rgba(cr, black);
400 cr->rectangle(0.5, h1 + 0.5, w, h - 1);
401 cr->stroke();
402
403 int x1 = key_to_x(20.5, w);
404 Gdk::Cairo::set_source_rgba(cr, grey1);
405 cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
406 cr->fill();
407
408 int x2 = key_to_x(109.5, w);
409 Gdk::Cairo::set_source_rgba(cr, white);
410 cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
411 cr->fill();
412
413 Gdk::Cairo::set_source_rgba(cr, grey1);
414 cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);
415 cr->fill();
416
417 Gdk::Cairo::set_source_rgba(cr, black);
418
419 int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
420 int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
421
422 for (int i = clipkey1 ; i < clipkey2 ; i++) {
423 int note = (i + 3) % 12;
424 int x = key_to_x(i, w);
425
426 if (note == 1 || note == 4 || note == 6 ||
427 note == 9 || note == 11) {
428 // black key: short line in the middle, with a rectangle
429 // on top
430 int x2 = key_to_x(i + 0.5, w);
431 cr->move_to(x2 + 0.5, h1 + bh + 0.5);
432 cr->line_to(x2 + 0.5, h1 + h - 1);
433 cr->stroke();
434
435 int x3 = key_to_x(i + 1, w);
436 cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
437 cr->fill();
438 } else if (note == 3 || note == 8) {
439 // C or F: long line to the left
440 cr->move_to(x + 0.5, h1 + 1);
441 cr->line_to(x + 0.5, h1 + h - 1);
442 cr->stroke();
443 }
444
445 if (key_pressed[i]) draw_key(cr, i);
446
447 if (note == 3) draw_digit(cr, i);
448 }
449 }
450
451
452 void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
453 int clip_low, int clip_high) {
454 const int w = get_width() - 1;
455
456 Gdk::Cairo::set_source_rgba(cr, black);
457 gig::Region* next_region;
458 int x3 = -1;
459 for (gig::Region* r = regions.first() ; r ; r = next_region) {
460 next_region = regions.next();
461
462 if (x3 < 0) {
463 x3 = key_to_x(r->KeyRange.low, w);
464 if (x3 >= clip_high) break;
465 }
466 if (!next_region ||
467 r->KeyRange.high + 1 != next_region->KeyRange.low ||
468 r == region || next_region == region) {
469
470 int x2 = key_to_x(r->KeyRange.high + 1, w);
471 if (x2 >= clip_low) {
472 cr->move_to(x3, 0.5);
473 cr->line_to(x2 + 0.5, 0.5);
474 cr->line_to(x2 + 0.5, h1 - 0.5);
475 cr->line_to(x3, h1 - 0.5);
476 cr->stroke();
477
478 if (region == r)
479 Gdk::Cairo::set_source_rgba(cr, blue);
480 else if (modifyallregions)
481 cr->set_source(blueHatchedSurfacePattern);
482 else
483 Gdk::Cairo::set_source_rgba(cr, white);
484
485 cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
486 cr->fill();
487 Gdk::Cairo::set_source_rgba(cr, black);
488 }
489 x3 = -1;
490 }
491 }
492
493 for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
494 int x = key_to_x(r->KeyRange.low, w);
495 int x2 = key_to_x(r->KeyRange.high + 1, w);
496
497 RegionFeatures features = regionFeatures(r);
498
499 const bool bShowLoopSymbol = features.loops > 0;
500 const bool bShowSampleRefSymbol = features.sampleRefs < features.validDimRegs;
501 if (bShowLoopSymbol || bShowSampleRefSymbol) {
502 const int margin = 2;
503 const int wRgn = x2 - x;
504 //printf("x=%d x2=%d wRgn=%d\n", x, x2, wRgn);
505
506 cr->save();
507 cr->set_line_width(1);
508 cr->rectangle(x, 1, wRgn, h1 - 1);
509 cr->clip();
510 if (bShowSampleRefSymbol) {
511 const int wPic = 8;
512 const int hPic = 8;
513 Gdk::Cairo::set_source_pixbuf(
514 cr, (features.sampleRefs) ? yellowDot : redDot,
515 x + (wRgn-wPic)/2.f,
516 (bShowLoopSymbol) ? margin : (h1-hPic)/2.f
517 );
518 cr->paint();
519 }
520 if (bShowLoopSymbol) {
521 const int wPic = 12;
522 const int hPic = 14;
523 Gdk::Cairo::set_source_pixbuf(
524 cr, (features.loops == features.validDimRegs) ? blackLoop : grayLoop,
525 x + (wRgn-wPic)/2.f,
526 (bShowSampleRefSymbol) ? h1 - hPic - margin : (h1-hPic)/2.f
527 );
528 cr->paint();
529 }
530 cr->restore();
531 }
532 }
533
534 for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
535 int x = key_to_x(r->KeyRange.low, w);
536
537 if (x < clip_low) continue;
538 if (x >= clip_high) break;
539
540 cr->move_to(x + 0.5, 1);
541 cr->line_to(x + 0.5, h1 - 1);
542 cr->stroke();
543 }
544
545 // if there is no region yet, show the user some hint text that he may
546 // right click on this area to create a new region
547 if (!regions.first()) {
548 Glib::RefPtr<Pango::Context> context = get_pango_context();
549 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
550 layout->set_alignment(Pango::ALIGN_CENTER);
551 layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
552 layout->set_width(get_width() * Pango::SCALE);
553 //layout->set_height(get_height() * Pango::SCALE);
554 layout->set_spacing(10);
555 Gdk::Cairo::set_source_rgba(cr, blue);
556 // get the text dimensions
557 int text_width, text_height;
558 layout->get_pixel_size(text_width, text_height);
559 cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
560 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
561 pango_cairo_show_layout(cr->cobj(), layout->gobj());
562 #else
563 layout->show_in_cairo_context(cr);
564 #endif
565 }
566 }
567
568 bool RegionChooser::is_black_key(int key) {
569 const int note = (key + 3) % 12;
570 return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
571 }
572
573 void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
574 int key) {
575 const int h = KEYBOARD_HEIGHT;
576 const int w = get_width() - 1;
577 Glib::RefPtr<Pango::Layout> layout =
578 Pango::Layout::create(get_pango_context());
579 char buf[30];
580 sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
581 layout->set_markup(buf);
582 Pango::Rectangle rectangle = layout->get_logical_extents();
583 double text_w = double(rectangle.get_width()) / Pango::SCALE;
584 double text_h = double(rectangle.get_height()) / Pango::SCALE;
585 double x = w * (key + 0.75) / 128.0;
586 Gdk::Cairo::set_source_rgba(cr, black);
587 cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));
588 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
589 pango_cairo_show_layout(cr->cobj(), layout->gobj());
590 #else
591 layout->show_in_cairo_context(cr);
592 #endif
593 }
594
595 void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
596 int key) {
597 const int h = KEYBOARD_HEIGHT;
598 const int w = get_width() - 1;
599 const int bh = int(h * 0.55);
600
601 Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
602
603 int note = (key + 3) % 12;
604 int x = key_to_x(key, w) + 1;
605 int x2 = key_to_x(key + 1.5, w);
606 int x3 = key_to_x(key + 1, w);
607 int x4 = key_to_x(key - 0.5, w);
608 int w1 = x3 - x;
609 switch (note) {
610 case 0: case 5: case 10:
611 cr->rectangle(x, h1 + 1, w1, bh);
612 cr->fill();
613 cr->rectangle(x4 + 1, h1 + bh + 1, x2 - x4 - 1, h - bh - 2);
614 cr->fill();
615 break;
616 case 2: case 7:
617 cr->rectangle(x, h1 + 1, w1, bh);
618 cr->fill();
619 cr->rectangle(x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2);
620 cr->fill();
621 break;
622 case 3: case 8:
623 cr->rectangle(x, h1 + 1, w1, bh);
624 cr->fill();
625 cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
626 cr->fill();
627 break;
628 default:
629 cr->rectangle(x, h1 + 1, w1, bh - 1);
630 cr->fill();
631 break;
632 }
633 Gdk::Cairo::set_source_rgba(cr, black);
634 }
635
636 void RegionChooser::set_instrument(gig::Instrument* instrument)
637 {
638 this->instrument = instrument;
639 regions.update(instrument);
640 region = regions.first();
641 queue_draw();
642 region_selected();
643 dimensionManager.set_region(region);
644 }
645
646 bool RegionChooser::on_button_release_event(GdkEventButton* event)
647 {
648 const int k = x_to_key(event->x, get_width() - 1);
649
650 // handle-note off on virtual keyboard
651 if (event->type == GDK_BUTTON_RELEASE) {
652 int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
653 int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
654 if (velocity <= 0) velocity = 1;
655 switch (m_VirtKeybModeChoice.get_value()) {
656 case VIRT_KEYBOARD_MODE_CHORD:
657 if (event->y >= REGION_BLOCK_HEIGHT)
658 keyboard_key_released_signal.emit(k, velocity);
659 break;
660 case VIRT_KEYBOARD_MODE_NORMAL:
661 default:
662 if (currentActiveKey >= 0 && currentActiveKey <= 127) {
663 keyboard_key_released_signal.emit(currentActiveKey, velocity);
664 currentActiveKey = -1;
665 }
666 break;
667 }
668 }
669
670 if (resize.active) {
671 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
672 get_window()->pointer_ungrab(event->time);
673 #else
674 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
675 Glib::wrap(event->device, true)->ungrab(event->time);
676 # else
677 gdk_device_ungrab(Glib::wrap(event->device, true)->gobj(), event->time);
678 # endif
679 #endif
680 resize.active = false;
681
682 if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
683 get_window()->set_cursor();
684 cursor_is_resize = false;
685 }
686 } else if (move.active) {
687 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
688 get_window()->pointer_ungrab(event->time);
689 #else
690 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
691 Glib::wrap(event->device, true)->ungrab(event->time);
692 # else
693 gdk_device_ungrab(Glib::wrap(event->device, true)->gobj(), event->time);
694 # endif
695 #endif
696 move.active = false;
697
698 if (is_in_resize_zone(event->x, event->y)) {
699 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
700 get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
701 #else
702 get_window()->set_cursor(
703 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
704 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
705 # else
706 Gdk::Cursor::create(
707 Glib::wrap(event->device, true)->get_seat()->get_display(),
708 Gdk::SB_H_DOUBLE_ARROW
709 )
710 # endif
711 );
712 #endif
713 cursor_is_resize = true;
714 }
715 }
716 return true;
717 }
718
719 void RegionChooser::update_after_resize()
720 {
721 if (resize.mode == resize.moving_high_limit) {
722 if (resize.region->KeyRange.high != resize.pos - 1) {
723 instrument_struct_to_be_changed_signal.emit(instrument);
724 resize.region->SetKeyRange(resize.region->KeyRange.low,
725 resize.pos - 1);
726 regions.update(instrument);
727 instrument_changed.emit();
728 instrument_struct_changed_signal.emit(instrument);
729 }
730 } else if (resize.mode == resize.moving_low_limit) {
731 if (resize.region->KeyRange.low != resize.pos) {
732 instrument_struct_to_be_changed_signal.emit(instrument);
733 resize.region->SetKeyRange(resize.pos,
734 resize.region->KeyRange.high);
735 regions.update(instrument);
736 instrument_changed.emit();
737 instrument_struct_changed_signal.emit(instrument);
738 }
739 }
740 }
741
742 void RegionChooser::update_after_move(int pos)
743 {
744 instrument_struct_to_be_changed_signal.emit(instrument);
745 const int range = region->KeyRange.high - region->KeyRange.low;
746 const int diff = pos - int(region->KeyRange.low);
747 region->SetKeyRange(pos, pos + range);
748 if (Settings::singleton()->moveRootNoteWithRegionMoved) {
749 for (int i = 0; i < 256; ++i) {
750 gig::DimensionRegion* dimrgn = region->pDimensionRegions[i];
751 if (!dimrgn || !dimrgn->pSample || !dimrgn->PitchTrack) continue;
752 dimrgn->UnityNote += diff;
753 }
754 }
755 regions.update(instrument);
756 instrument_changed.emit();
757 instrument_struct_changed_signal.emit(instrument);
758 }
759
760 bool RegionChooser::on_button_press_event(GdkEventButton* event)
761 {
762 if (!instrument) return true;
763
764 const int w = get_width() - 1;
765 const int k = x_to_key(event->x, w);
766
767 if (event->type == GDK_BUTTON_PRESS) {
768 if (event->y >= REGION_BLOCK_HEIGHT) {
769 int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
770 int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
771 currentActiveKey = k;
772 keyboard_key_hit_signal.emit(k, velocity);
773 }
774 }
775
776 // left mouse button double click
777 if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
778 if (event->y < REGION_BLOCK_HEIGHT) {
779 // show dimension manager dialog for this region
780 manage_dimensions();
781 }
782 }
783
784 if (event->y >= REGION_BLOCK_HEIGHT) return true;
785 if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
786 gig::Region* r = get_region(k);
787 if (r) {
788 region = r;
789 queue_draw();
790 region_selected();
791 dimensionManager.set_region(region);
792 popup_menu_inside_region->popup(event->button, event->time);
793 } else {
794 new_region_pos = k;
795 popup_menu_outside_region->popup(event->button, event->time);
796 }
797 } else {
798 if (is_in_resize_zone(event->x, event->y)) {
799 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
800 get_window()->pointer_grab(false,
801 Gdk::BUTTON_RELEASE_MASK |
802 Gdk::POINTER_MOTION_MASK |
803 Gdk::POINTER_MOTION_HINT_MASK,
804 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
805 event->time);
806 #else
807 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
808 Glib::wrap(event->device, true)->grab(get_window(),
809 Gdk::OWNERSHIP_NONE,
810 false,
811 Gdk::BUTTON_RELEASE_MASK |
812 Gdk::POINTER_MOTION_MASK |
813 Gdk::POINTER_MOTION_HINT_MASK,
814 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
815 event->time);
816 # else
817 gdk_device_grab(
818 Glib::wrap(event->device, true)->gobj(),
819 get_window()->gobj(),
820 GDK_OWNERSHIP_NONE,
821 false,
822 GdkEventMask(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
823 GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK),
824 Gdk::Cursor::create(
825 Glib::wrap(event->device, true)->get_seat()->get_display(),
826 Gdk::SB_H_DOUBLE_ARROW
827 )->gobj(),
828 event->time
829 );
830 # endif
831 #endif
832 resize.active = true;
833 } else {
834 gig::Region* r = get_region(k);
835 if (r) {
836 region = r;
837 queue_draw();
838 region_selected();
839 dimensionManager.set_region(region);
840
841 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
842 get_window()->pointer_grab(false,
843 Gdk::BUTTON_RELEASE_MASK |
844 Gdk::POINTER_MOTION_MASK |
845 Gdk::POINTER_MOTION_HINT_MASK,
846 Gdk::Cursor(Gdk::FLEUR),
847 event->time);
848 #else
849 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
850 Glib::wrap(event->device, true)->grab(get_window(),
851 Gdk::OWNERSHIP_NONE,
852 false,
853 Gdk::BUTTON_RELEASE_MASK |
854 Gdk::POINTER_MOTION_MASK |
855 Gdk::POINTER_MOTION_HINT_MASK,
856 Gdk::Cursor::create(Gdk::FLEUR),
857 event->time);
858 # else
859 gdk_device_grab(
860 Glib::wrap(event->device, true)->gobj(),
861 get_window()->gobj(),
862 GDK_OWNERSHIP_NONE,
863 false,
864 GdkEventMask(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
865 GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK),
866 Gdk::Cursor::create(
867 Glib::wrap(event->device, true)->get_seat()->get_display(),
868 Gdk::FLEUR
869 )->gobj(),
870 event->time
871 );
872 # endif
873 #endif
874 move.active = true;
875 move.offset = event->x - key_to_x(region->KeyRange.low, w);
876 }
877 }
878 }
879 return true;
880 }
881
882 gig::Region* RegionChooser::get_region(int key)
883 {
884 for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
885 if (key < r->KeyRange.low) return 0;
886 if (key <= r->KeyRange.high) return r;
887 }
888 return 0;
889 }
890
891 void RegionChooser::set_region(gig::Region* region) {
892 this->region = region;
893 queue_draw();
894 region_selected();
895 dimensionManager.set_region(region);
896 }
897
898 void RegionChooser::select_next_region() {
899 if (!instrument) return;
900 if (!region) {
901 for (int i = 0; i < 128; ++i) {
902 ::gig::Region* rgn = instrument->GetRegion(i);
903 if (rgn) {
904 set_region(rgn);
905 return;
906 }
907 }
908 } else {
909 bool currentFound = false;
910 for (int i = 0; i < 128; ++i) {
911 ::gig::Region* rgn = instrument->GetRegion(i);
912 if (!rgn) continue;
913 if (currentFound) {
914 if (rgn != region) {
915 set_region(rgn);
916 return;
917 }
918 } else {
919 if (rgn == region) currentFound = true;
920 }
921 }
922 }
923 }
924
925 void RegionChooser::select_prev_region() {
926 if (!instrument) return;
927 if (!region) {
928 for (int i = 0; i < 128; ++i) {
929 ::gig::Region* rgn = instrument->GetRegion(i);
930 if (rgn) {
931 set_region(rgn);
932 return;
933 }
934 }
935 } else {
936 bool currentFound = false;
937 for (int i = 127; i >= 0; --i) {
938 ::gig::Region* rgn = instrument->GetRegion(i);
939 if (!rgn) continue;
940 if (currentFound) {
941 if (rgn != region) {
942 set_region(rgn);
943 return;
944 }
945 } else {
946 if (rgn == region) currentFound = true;
947 }
948 }
949 }
950 }
951
952 void RegionChooser::motion_resize_region(int x, int y)
953 {
954 const int w = get_width() - 1;
955
956 int k = int(double(x) / w * 128.0 + 0.5);
957
958 if (k < resize.min) k = resize.min;
959 else if (k > resize.max) k = resize.max;
960
961 if (k != resize.pos) {
962 if (resize.mode == resize.undecided) {
963 if (k < resize.pos) {
964 // edit high limit of prev_region
965 resize.max = resize.region->KeyRange.low;
966 resize.region = resize.prev_region;
967 resize.mode = resize.moving_high_limit;
968 } else {
969 // edit low limit of region
970 resize.min = resize.prev_region->KeyRange.high + 1;
971 resize.mode = resize.moving_low_limit;
972 }
973 }
974 resize.pos = k;
975
976 int x1, x2;
977 if (resize.mode == resize.moving_high_limit) {
978 if (resize.region->KeyRange.high < resize.pos - 1) {
979 x1 = resize.region->KeyRange.high;
980 x2 = resize.pos - 1;
981 } else {
982 x1 = resize.pos - 1;
983 x2 = resize.region->KeyRange.high;
984 }
985 } else {
986 if (resize.region->KeyRange.low < resize.pos) {
987 x1 = resize.region->KeyRange.low;
988 x2 = resize.pos;
989 } else {
990 x1 = resize.pos;
991 x2 = resize.region->KeyRange.low;
992 }
993 }
994 x1 = key_to_x(x1, w);
995 x2 = key_to_x(x2 + 1, w) + 1;
996 Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
997
998 update_after_resize();
999
1000 //get_window()->invalidate_rect(rect, false);
1001 get_window()->invalidate(false); // repaint entire region, otherwise it would create visual artifacts
1002 }
1003 }
1004
1005 void RegionChooser::motion_move_region(int x, int y)
1006 {
1007 const int w = get_width() - 1;
1008
1009 int l = int(double(x - move.offset) / w * 128.0 + 0.5);
1010
1011 if (l == region->KeyRange.low) return;
1012 int new_l;
1013 int regionsize = region->KeyRange.high - region->KeyRange.low;
1014 int a = 0;
1015 if (l > region->KeyRange.low) {
1016 for (gig::Region* r = regions.first() ; ; r = regions.next()) {
1017 if (r != region) {
1018 int b = r ? r->KeyRange.low : 128;
1019
1020 // gap: from a to b (not inclusive b)
1021
1022 if (region->KeyRange.high >= b) {
1023 // not found the current gap yet, just continue
1024 } else {
1025
1026 if (a > l) {
1027 // this gap is too far to the right, break
1028 break;
1029 }
1030
1031 int newhigh = std::min(l + regionsize, b - 1);
1032 int newlo = newhigh - regionsize;
1033
1034 if (newlo >= a) {
1035 // yes it fits - it's a candidate
1036 new_l = newlo;
1037 }
1038 }
1039 if (!r) break;
1040 a = r->KeyRange.high + 1;
1041 }
1042 }
1043 } else {
1044 for (gig::Region* r = regions.first() ; ; r = regions.next()) {
1045 if (r != region) {
1046 int b = r ? r->KeyRange.low : 128;
1047
1048 // gap from a to b (not inclusive b)
1049
1050 if (l + regionsize >= b) {
1051 // not found the current gap yet, just continue
1052 } else {
1053
1054 if (a > region->KeyRange.low) {
1055 // this gap is too far to the right, break
1056 break;
1057 }
1058
1059 int newlo = std::max(l, a);
1060 int newhigh = newlo + regionsize;
1061
1062 if (newhigh < b) {
1063 // yes it fits - break as the first one is the best
1064 new_l = newlo;
1065 break;
1066 }
1067 }
1068 if (!r) break;
1069 a = r->KeyRange.high + 1;
1070 }
1071 }
1072 }
1073 if (new_l == region->KeyRange.low) return;
1074
1075 int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
1076 int x2 = key_to_x(std::max(int(region->KeyRange.high),
1077 new_l + regionsize) + 1, w) + 1;
1078
1079 Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
1080 update_after_move(new_l);
1081
1082 get_window()->invalidate_rect(rect, false);
1083 }
1084
1085
1086 bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)
1087 {
1088 Glib::RefPtr<Gdk::Window> window = get_window();
1089 int x, y;
1090 #if HAS_GDKMM_SEAT
1091 x = event->x;
1092 y = event->y;
1093 Gdk::ModifierType state = Gdk::ModifierType(event->state);
1094 #else
1095 Gdk::ModifierType state = Gdk::ModifierType(0);
1096 window->get_pointer(x, y, state);
1097 #endif
1098
1099 // handle virtual MIDI keyboard
1100 if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&
1101 currentActiveKey > 0 &&
1102 event->y >= REGION_BLOCK_HEIGHT &&
1103 event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
1104 {
1105 const int k = x_to_key(event->x, get_width() - 1);
1106 if (k != currentActiveKey) {
1107 int velocity =
1108 (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
1109 int(float(event->y - REGION_BLOCK_HEIGHT) /
1110 float(KEYBOARD_HEIGHT) * 128.0f) + 1;
1111 if (velocity <= 0) velocity = 1;
1112 keyboard_key_released_signal.emit(currentActiveKey, velocity);
1113 currentActiveKey = k;
1114 keyboard_key_hit_signal.emit(k, velocity);
1115 }
1116 }
1117
1118 if (resize.active) {
1119 motion_resize_region(x, y);
1120 } else if (move.active) {
1121 motion_move_region(x, y);
1122 } else {
1123 if (is_in_resize_zone(x, y)) {
1124 if (!cursor_is_resize) {
1125 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1126 window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1127 #else
1128 window->set_cursor(
1129 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1130 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1131 # else
1132 Gdk::Cursor::create(
1133 Glib::wrap(event->device, true)->get_seat()->get_display(),
1134 Gdk::SB_H_DOUBLE_ARROW
1135 )
1136 # endif
1137 );
1138 #endif
1139 cursor_is_resize = true;
1140 }
1141 } else if (cursor_is_resize) {
1142 window->set_cursor();
1143 cursor_is_resize = false;
1144 }
1145 }
1146
1147 return true;
1148 }
1149
1150 bool RegionChooser::is_in_resize_zone(double x, double y) {
1151 const int w = get_width() - 1;
1152
1153 if (instrument && y >= 0 && y <= h1) {
1154 gig::Region* prev_region = 0;
1155 gig::Region* next_region;
1156 for (gig::Region* r = regions.first(); r ; r = next_region) {
1157 next_region = regions.next();
1158
1159 int lo = key_to_x(r->KeyRange.low, w);
1160 if (x <= lo - 2) break;
1161 if (x < lo + 2) {
1162 resize.region = r;
1163 resize.pos = r->KeyRange.low;
1164 resize.max = r->KeyRange.high;
1165
1166 if (prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low) {
1167 // we don't know yet if it's the high limit of
1168 // prev_region or the low limit of r that's going
1169 // to be edited
1170 resize.mode = resize.undecided;
1171 resize.min = prev_region->KeyRange.low + 1;
1172 resize.prev_region = prev_region;
1173 return resize.min != resize.max;
1174 }
1175
1176 // edit low limit
1177 resize.mode = resize.moving_low_limit;
1178 resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
1179 return resize.min != resize.max;
1180 }
1181 if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
1182 int hi = key_to_x(r->KeyRange.high + 1, w);
1183 if (x <= hi - 2) break;
1184 if (x < hi + 2) {
1185 // edit high limit
1186 resize.region = r;
1187 resize.pos = r->KeyRange.high + 1;
1188 resize.mode = resize.moving_high_limit;
1189 resize.min = r->KeyRange.low + 1;
1190 resize.max = next_region ? next_region->KeyRange.low : 128;
1191 return resize.min != resize.max;
1192 }
1193 }
1194 prev_region = r;
1195 }
1196 }
1197 return false;
1198 }
1199
1200 sigc::signal<void>& RegionChooser::signal_region_selected()
1201 {
1202 return region_selected;
1203 }
1204
1205 sigc::signal<void>& RegionChooser::signal_instrument_changed()
1206 {
1207 return instrument_changed;
1208 }
1209
1210 void RegionChooser::show_region_properties()
1211 {
1212 if (!region) return;
1213 Gtk::Dialog dialog(_("Region Properties"), true /*modal*/);
1214 // add "Keygroup" checkbox
1215 Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));
1216 checkBoxKeygroup.set_active(region->KeyGroup);
1217 #if USE_GTKMM_BOX
1218 dialog.get_content_area()->pack_start(checkBoxKeygroup);
1219 #else
1220 dialog.get_vbox()->pack_start(checkBoxKeygroup);
1221 #endif
1222 checkBoxKeygroup.show();
1223 // add "Keygroup" spinbox
1224 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1225 Gtk::Adjustment adjustment(1, 1, 999);
1226 Gtk::SpinButton spinBox(adjustment);
1227 #else
1228 Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1229 #endif
1230 if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
1231 #if USE_GTKMM_BOX
1232 dialog.get_content_area()->pack_start(spinBox);
1233 #else
1234 dialog.get_vbox()->pack_start(spinBox);
1235 #endif
1236 spinBox.show();
1237 // add OK and CANCEL buttons to the dialog
1238 #if HAS_GTKMM_STOCK
1239 dialog.add_button(Gtk::Stock::OK, 0);
1240 dialog.add_button(Gtk::Stock::CANCEL, 1);
1241 #else
1242 dialog.add_button(_("_OK"), 0);
1243 dialog.add_button(_("_Cancel"), 1);
1244 #endif
1245 dialog.set_position(Gtk::WIN_POS_MOUSE);
1246 #if HAS_GTKMM_SHOW_ALL_CHILDREN
1247 dialog.show_all_children();
1248 #endif
1249 if (!dialog.run()) { // OK selected ...
1250 region->KeyGroup =
1251 (checkBoxKeygroup.get_active()) ? spinBox.get_value_as_int() : 0;
1252 }
1253 }
1254
1255 void RegionChooser::add_region()
1256 {
1257 instrument_struct_to_be_changed_signal.emit(instrument);
1258
1259 region = instrument->AddRegion();
1260 region->SetKeyRange(new_region_pos, new_region_pos);
1261
1262 instrument_struct_changed_signal.emit(instrument);
1263 regions.update(instrument);
1264
1265 queue_draw();
1266 region_selected();
1267 dimensionManager.set_region(region);
1268 instrument_changed();
1269 }
1270
1271 void RegionChooser::delete_region()
1272 {
1273 instrument_struct_to_be_changed_signal.emit(instrument);
1274 instrument->DeleteRegion(region);
1275 instrument_struct_changed_signal.emit(instrument);
1276 regions.update(instrument);
1277
1278 region = 0;
1279 queue_draw();
1280 region_selected();
1281 dimensionManager.set_region(region);
1282 instrument_changed();
1283 }
1284
1285 void RegionChooser::manage_dimensions()
1286 {
1287 gig::Region* region = get_region();
1288 if (!region) return;
1289 dimensionManager.show(region);
1290 }
1291
1292 void RegionChooser::on_dimension_manager_changed() {
1293 region_selected();
1294 instrument_changed();
1295 }
1296
1297 sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_to_be_changed() {
1298 return instrument_struct_to_be_changed_signal;
1299 }
1300
1301 sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_changed() {
1302 return instrument_struct_changed_signal;
1303 }
1304
1305 sigc::signal<void, gig::Region*>& RegionChooser::signal_region_to_be_changed() {
1306 return region_to_be_changed_signal;
1307 }
1308
1309 sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {
1310 return region_changed_signal;
1311 }
1312
1313 sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_hit() {
1314 return keyboard_key_hit_signal;
1315 }
1316
1317 sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_released() {
1318 return keyboard_key_released_signal;
1319 }

  ViewVC Help
Powered by ViewVC