/[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 3460 - (show annotations) (download)
Sat Feb 2 07:48:50 2019 UTC (5 years, 2 months ago) by persson
File size: 45340 byte(s)
* Use GDK Seat API if available to grab pointer
* Improve version checks for pangomm
* Fix the instrument list tooltip handling so it doesn't generate GTK
  assertion error messages
* Use English quotation marks in tooltips instead of German
* Use multiple columns in controller value popups, as tall popup menus
  work really badly in some GTK environments

1 /*
2 * Copyright (C) 2006-2019 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 > 24)
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 > 24)
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 Glib::wrap(event->device, true)->get_seat()->ungrab();
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 Glib::wrap(event->device, true)->get_seat()->ungrab();
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 Glib::wrap(event->device, true)->get_seat()->grab(
818 get_window(),
819 Gdk::SeatCapabilities::SEAT_CAPABILITY_ALL_POINTING,
820 false,
821 Gdk::Cursor::create(
822 Glib::wrap(event->device, true)->get_seat()->get_display(),
823 Gdk::SB_H_DOUBLE_ARROW
824 ),
825 reinterpret_cast<GdkEvent*>(event)
826 );
827 # endif
828 #endif
829 resize.active = true;
830 } else {
831 gig::Region* r = get_region(k);
832 if (r) {
833 region = r;
834 queue_draw();
835 region_selected();
836 dimensionManager.set_region(region);
837
838 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
839 get_window()->pointer_grab(false,
840 Gdk::BUTTON_RELEASE_MASK |
841 Gdk::POINTER_MOTION_MASK |
842 Gdk::POINTER_MOTION_HINT_MASK,
843 Gdk::Cursor(Gdk::FLEUR),
844 event->time);
845 #else
846 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
847 Glib::wrap(event->device, true)->grab(get_window(),
848 Gdk::OWNERSHIP_NONE,
849 false,
850 Gdk::BUTTON_RELEASE_MASK |
851 Gdk::POINTER_MOTION_MASK |
852 Gdk::POINTER_MOTION_HINT_MASK,
853 Gdk::Cursor::create(Gdk::FLEUR),
854 event->time);
855 # else
856 Glib::wrap(event->device, true)->get_seat()->grab(
857 get_window(),
858 Gdk::SeatCapabilities::SEAT_CAPABILITY_ALL_POINTING,
859 false,
860 Gdk::Cursor::create(
861 Glib::wrap(event->device, true)->get_seat()->get_display(),
862 Gdk::FLEUR
863 ),
864 reinterpret_cast<GdkEvent*>(event)
865 );
866 # endif
867 #endif
868 move.active = true;
869 move.offset = event->x - key_to_x(region->KeyRange.low, w);
870 }
871 }
872 }
873 return true;
874 }
875
876 gig::Region* RegionChooser::get_region(int key)
877 {
878 for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
879 if (key < r->KeyRange.low) return 0;
880 if (key <= r->KeyRange.high) return r;
881 }
882 return 0;
883 }
884
885 void RegionChooser::set_region(gig::Region* region) {
886 this->region = region;
887 queue_draw();
888 region_selected();
889 dimensionManager.set_region(region);
890 }
891
892 void RegionChooser::select_next_region() {
893 if (!instrument) return;
894 if (!region) {
895 for (int i = 0; i < 128; ++i) {
896 ::gig::Region* rgn = instrument->GetRegion(i);
897 if (rgn) {
898 set_region(rgn);
899 return;
900 }
901 }
902 } else {
903 bool currentFound = false;
904 for (int i = 0; i < 128; ++i) {
905 ::gig::Region* rgn = instrument->GetRegion(i);
906 if (!rgn) continue;
907 if (currentFound) {
908 if (rgn != region) {
909 set_region(rgn);
910 return;
911 }
912 } else {
913 if (rgn == region) currentFound = true;
914 }
915 }
916 }
917 }
918
919 void RegionChooser::select_prev_region() {
920 if (!instrument) return;
921 if (!region) {
922 for (int i = 0; i < 128; ++i) {
923 ::gig::Region* rgn = instrument->GetRegion(i);
924 if (rgn) {
925 set_region(rgn);
926 return;
927 }
928 }
929 } else {
930 bool currentFound = false;
931 for (int i = 127; i >= 0; --i) {
932 ::gig::Region* rgn = instrument->GetRegion(i);
933 if (!rgn) continue;
934 if (currentFound) {
935 if (rgn != region) {
936 set_region(rgn);
937 return;
938 }
939 } else {
940 if (rgn == region) currentFound = true;
941 }
942 }
943 }
944 }
945
946 void RegionChooser::motion_resize_region(int x, int y)
947 {
948 const int w = get_width() - 1;
949
950 int k = int(double(x) / w * 128.0 + 0.5);
951
952 if (k < resize.min) k = resize.min;
953 else if (k > resize.max) k = resize.max;
954
955 if (k != resize.pos) {
956 if (resize.mode == resize.undecided) {
957 if (k < resize.pos) {
958 // edit high limit of prev_region
959 resize.max = resize.region->KeyRange.low;
960 resize.region = resize.prev_region;
961 resize.mode = resize.moving_high_limit;
962 } else {
963 // edit low limit of region
964 resize.min = resize.prev_region->KeyRange.high + 1;
965 resize.mode = resize.moving_low_limit;
966 }
967 }
968 resize.pos = k;
969
970 int x1, x2;
971 if (resize.mode == resize.moving_high_limit) {
972 if (resize.region->KeyRange.high < resize.pos - 1) {
973 x1 = resize.region->KeyRange.high;
974 x2 = resize.pos - 1;
975 } else {
976 x1 = resize.pos - 1;
977 x2 = resize.region->KeyRange.high;
978 }
979 } else {
980 if (resize.region->KeyRange.low < resize.pos) {
981 x1 = resize.region->KeyRange.low;
982 x2 = resize.pos;
983 } else {
984 x1 = resize.pos;
985 x2 = resize.region->KeyRange.low;
986 }
987 }
988 x1 = key_to_x(x1, w);
989 x2 = key_to_x(x2 + 1, w) + 1;
990 Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
991
992 update_after_resize();
993
994 //get_window()->invalidate_rect(rect, false);
995 get_window()->invalidate(false); // repaint entire region, otherwise it would create visual artifacts
996 }
997 }
998
999 void RegionChooser::motion_move_region(int x, int y)
1000 {
1001 const int w = get_width() - 1;
1002
1003 int l = int(double(x - move.offset) / w * 128.0 + 0.5);
1004
1005 if (l == region->KeyRange.low) return;
1006 int new_l;
1007 int regionsize = region->KeyRange.high - region->KeyRange.low;
1008 int a = 0;
1009 if (l > region->KeyRange.low) {
1010 for (gig::Region* r = regions.first() ; ; r = regions.next()) {
1011 if (r != region) {
1012 int b = r ? r->KeyRange.low : 128;
1013
1014 // gap: from a to b (not inclusive b)
1015
1016 if (region->KeyRange.high >= b) {
1017 // not found the current gap yet, just continue
1018 } else {
1019
1020 if (a > l) {
1021 // this gap is too far to the right, break
1022 break;
1023 }
1024
1025 int newhigh = std::min(l + regionsize, b - 1);
1026 int newlo = newhigh - regionsize;
1027
1028 if (newlo >= a) {
1029 // yes it fits - it's a candidate
1030 new_l = newlo;
1031 }
1032 }
1033 if (!r) break;
1034 a = r->KeyRange.high + 1;
1035 }
1036 }
1037 } else {
1038 for (gig::Region* r = regions.first() ; ; r = regions.next()) {
1039 if (r != region) {
1040 int b = r ? r->KeyRange.low : 128;
1041
1042 // gap from a to b (not inclusive b)
1043
1044 if (l + regionsize >= b) {
1045 // not found the current gap yet, just continue
1046 } else {
1047
1048 if (a > region->KeyRange.low) {
1049 // this gap is too far to the right, break
1050 break;
1051 }
1052
1053 int newlo = std::max(l, a);
1054 int newhigh = newlo + regionsize;
1055
1056 if (newhigh < b) {
1057 // yes it fits - break as the first one is the best
1058 new_l = newlo;
1059 break;
1060 }
1061 }
1062 if (!r) break;
1063 a = r->KeyRange.high + 1;
1064 }
1065 }
1066 }
1067 if (new_l == region->KeyRange.low) return;
1068
1069 int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
1070 int x2 = key_to_x(std::max(int(region->KeyRange.high),
1071 new_l + regionsize) + 1, w) + 1;
1072
1073 Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
1074 update_after_move(new_l);
1075
1076 get_window()->invalidate_rect(rect, false);
1077 }
1078
1079
1080 bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)
1081 {
1082 Glib::RefPtr<Gdk::Window> window = get_window();
1083 int x, y;
1084 #if HAS_GDKMM_SEAT
1085 x = event->x;
1086 y = event->y;
1087 Gdk::ModifierType state = Gdk::ModifierType(event->state);
1088 #else
1089 Gdk::ModifierType state = Gdk::ModifierType(0);
1090 window->get_pointer(x, y, state);
1091 #endif
1092
1093 // handle virtual MIDI keyboard
1094 if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&
1095 currentActiveKey > 0 &&
1096 event->y >= REGION_BLOCK_HEIGHT &&
1097 event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
1098 {
1099 const int k = x_to_key(event->x, get_width() - 1);
1100 if (k != currentActiveKey) {
1101 int velocity =
1102 (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
1103 int(float(event->y - REGION_BLOCK_HEIGHT) /
1104 float(KEYBOARD_HEIGHT) * 128.0f) + 1;
1105 if (velocity <= 0) velocity = 1;
1106 keyboard_key_released_signal.emit(currentActiveKey, velocity);
1107 currentActiveKey = k;
1108 keyboard_key_hit_signal.emit(k, velocity);
1109 }
1110 }
1111
1112 if (resize.active) {
1113 motion_resize_region(x, y);
1114 } else if (move.active) {
1115 motion_move_region(x, y);
1116 } else {
1117 if (is_in_resize_zone(x, y)) {
1118 if (!cursor_is_resize) {
1119 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1120 window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1121 #else
1122 window->set_cursor(
1123 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1124 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1125 # else
1126 Gdk::Cursor::create(
1127 Glib::wrap(event->device, true)->get_seat()->get_display(),
1128 Gdk::SB_H_DOUBLE_ARROW
1129 )
1130 # endif
1131 );
1132 #endif
1133 cursor_is_resize = true;
1134 }
1135 } else if (cursor_is_resize) {
1136 window->set_cursor();
1137 cursor_is_resize = false;
1138 }
1139 }
1140
1141 return true;
1142 }
1143
1144 bool RegionChooser::is_in_resize_zone(double x, double y) {
1145 const int w = get_width() - 1;
1146
1147 if (instrument && y >= 0 && y <= h1) {
1148 gig::Region* prev_region = 0;
1149 gig::Region* next_region;
1150 for (gig::Region* r = regions.first(); r ; r = next_region) {
1151 next_region = regions.next();
1152
1153 int lo = key_to_x(r->KeyRange.low, w);
1154 if (x <= lo - 2) break;
1155 if (x < lo + 2) {
1156 resize.region = r;
1157 resize.pos = r->KeyRange.low;
1158 resize.max = r->KeyRange.high;
1159
1160 if (prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low) {
1161 // we don't know yet if it's the high limit of
1162 // prev_region or the low limit of r that's going
1163 // to be edited
1164 resize.mode = resize.undecided;
1165 resize.min = prev_region->KeyRange.low + 1;
1166 resize.prev_region = prev_region;
1167 return resize.min != resize.max;
1168 }
1169
1170 // edit low limit
1171 resize.mode = resize.moving_low_limit;
1172 resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
1173 return resize.min != resize.max;
1174 }
1175 if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
1176 int hi = key_to_x(r->KeyRange.high + 1, w);
1177 if (x <= hi - 2) break;
1178 if (x < hi + 2) {
1179 // edit high limit
1180 resize.region = r;
1181 resize.pos = r->KeyRange.high + 1;
1182 resize.mode = resize.moving_high_limit;
1183 resize.min = r->KeyRange.low + 1;
1184 resize.max = next_region ? next_region->KeyRange.low : 128;
1185 return resize.min != resize.max;
1186 }
1187 }
1188 prev_region = r;
1189 }
1190 }
1191 return false;
1192 }
1193
1194 sigc::signal<void>& RegionChooser::signal_region_selected()
1195 {
1196 return region_selected;
1197 }
1198
1199 sigc::signal<void>& RegionChooser::signal_instrument_changed()
1200 {
1201 return instrument_changed;
1202 }
1203
1204 void RegionChooser::show_region_properties()
1205 {
1206 if (!region) return;
1207 Gtk::Dialog dialog(_("Region Properties"), true /*modal*/);
1208 // add "Keygroup" checkbox
1209 Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));
1210 checkBoxKeygroup.set_active(region->KeyGroup);
1211 #if USE_GTKMM_BOX
1212 dialog.get_content_area()->pack_start(checkBoxKeygroup);
1213 #else
1214 dialog.get_vbox()->pack_start(checkBoxKeygroup);
1215 #endif
1216 checkBoxKeygroup.show();
1217 // add "Keygroup" spinbox
1218 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1219 Gtk::Adjustment adjustment(1, 1, 999);
1220 Gtk::SpinButton spinBox(adjustment);
1221 #else
1222 Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1223 #endif
1224 if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
1225 #if USE_GTKMM_BOX
1226 dialog.get_content_area()->pack_start(spinBox);
1227 #else
1228 dialog.get_vbox()->pack_start(spinBox);
1229 #endif
1230 spinBox.show();
1231 // add OK and CANCEL buttons to the dialog
1232 #if HAS_GTKMM_STOCK
1233 dialog.add_button(Gtk::Stock::OK, 0);
1234 dialog.add_button(Gtk::Stock::CANCEL, 1);
1235 #else
1236 dialog.add_button(_("_OK"), 0);
1237 dialog.add_button(_("_Cancel"), 1);
1238 #endif
1239 dialog.set_position(Gtk::WIN_POS_MOUSE);
1240 #if HAS_GTKMM_SHOW_ALL_CHILDREN
1241 dialog.show_all_children();
1242 #endif
1243 if (!dialog.run()) { // OK selected ...
1244 region->KeyGroup =
1245 (checkBoxKeygroup.get_active()) ? spinBox.get_value_as_int() : 0;
1246 }
1247 }
1248
1249 void RegionChooser::add_region()
1250 {
1251 instrument_struct_to_be_changed_signal.emit(instrument);
1252
1253 region = instrument->AddRegion();
1254 region->SetKeyRange(new_region_pos, new_region_pos);
1255
1256 instrument_struct_changed_signal.emit(instrument);
1257 regions.update(instrument);
1258
1259 queue_draw();
1260 region_selected();
1261 dimensionManager.set_region(region);
1262 instrument_changed();
1263 }
1264
1265 void RegionChooser::delete_region()
1266 {
1267 instrument_struct_to_be_changed_signal.emit(instrument);
1268 instrument->DeleteRegion(region);
1269 instrument_struct_changed_signal.emit(instrument);
1270 regions.update(instrument);
1271
1272 region = 0;
1273 queue_draw();
1274 region_selected();
1275 dimensionManager.set_region(region);
1276 instrument_changed();
1277 }
1278
1279 void RegionChooser::manage_dimensions()
1280 {
1281 gig::Region* region = get_region();
1282 if (!region) return;
1283 dimensionManager.show(region);
1284 }
1285
1286 void RegionChooser::on_dimension_manager_changed() {
1287 region_selected();
1288 instrument_changed();
1289 }
1290
1291 sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_to_be_changed() {
1292 return instrument_struct_to_be_changed_signal;
1293 }
1294
1295 sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_changed() {
1296 return instrument_struct_changed_signal;
1297 }
1298
1299 sigc::signal<void, gig::Region*>& RegionChooser::signal_region_to_be_changed() {
1300 return region_to_be_changed_signal;
1301 }
1302
1303 sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {
1304 return region_changed_signal;
1305 }
1306
1307 sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_hit() {
1308 return keyboard_key_hit_signal;
1309 }
1310
1311 sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_released() {
1312 return keyboard_key_released_signal;
1313 }

  ViewVC Help
Powered by ViewVC