/[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 3364 - (show annotations) (download)
Tue Nov 14 18:07:25 2017 UTC (6 years, 5 months ago) by schoenebeck
File size: 45353 byte(s)
* Added experimental support for upcoming GTK(MM)4
  (for now up to GTKMM 3.91.2 while still preserving backward compatibility
  down to GTKMM 2).
* Re-merged r2845 to compile now with and without Gtk "Stock ID" API
  (see also r3158).

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
300 RegionChooser::~RegionChooser()
301 {
302 }
303
304 void RegionChooser::setModifyAllRegions(bool b) {
305 modifyallregions = b;
306 // redraw required parts
307 queue_draw();
308 }
309
310 void RegionChooser::invalidate_key(int key) {
311 const int h = KEYBOARD_HEIGHT;
312 const int w = get_width() - 1;
313 int x1 = key_to_x(key - 0.5, w);
314 int x2 = key_to_x(key + 1.5, w);
315
316 Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
317 get_window()->invalidate_rect(rect, false);
318 }
319
320 void RegionChooser::on_note_on_event(int key, int velocity) {
321 key_pressed[key] = true;
322 invalidate_key(key);
323 m_VirtKeybVelocityLabel.set_text(ToString(velocity));
324 }
325
326 void RegionChooser::on_note_off_event(int key, int velocity) {
327 key_pressed[key] = false;
328 invalidate_key(key);
329 m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
330 }
331
332
333 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
334 bool RegionChooser::on_expose_event(GdkEventExpose* e) {
335 double clipx1 = e->area.x;
336 double clipx2 = e->area.x + e->area.width;
337 double clipy1 = e->area.y;
338 double clipy2 = e->area.y + e->area.height;
339
340 const Cairo::RefPtr<Cairo::Context>& cr =
341 get_window()->create_cairo_context();
342 #if 0
343 }
344 #endif
345 #else
346 bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
347 double clipx1, clipx2, clipy1, clipy2;
348 cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
349 #endif
350
351 cr->save();
352 cr->set_line_width(1);
353
354 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
355 const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
356 #else
357 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 22)
358 GdkRGBA gdkBgRGBA;
359 gtk_style_context_get_background_color(get_style_context()->gobj(), &gdkBgRGBA);
360 const Gdk::RGBA bg = Glib::wrap(&gdkBgRGBA, true);
361 # else
362 const Gdk::RGBA bg = get_style_context()->get_background_color();
363 # endif
364 #endif
365 Gdk::Cairo::set_source_rgba(cr, bg);
366 cr->paint();
367
368 if (clipy2 > h1) {
369 draw_keyboard(cr, clipx1, clipx2);
370 }
371
372 if (clipy1 < h1 && instrument) {
373 draw_regions(cr, clipx1, clipx2);
374 }
375
376 cr->restore();
377
378 return true;
379 }
380
381 void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
382 int clip_low, int clip_high) {
383 const int h = KEYBOARD_HEIGHT;
384 const int w = get_width() - 1;
385 const int bh = int(h * 0.55);
386
387 Gdk::Cairo::set_source_rgba(cr, black);
388 cr->rectangle(0.5, h1 + 0.5, w, h - 1);
389 cr->stroke();
390
391 int x1 = key_to_x(20.5, w);
392 Gdk::Cairo::set_source_rgba(cr, grey1);
393 cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
394 cr->fill();
395
396 int x2 = key_to_x(109.5, w);
397 Gdk::Cairo::set_source_rgba(cr, white);
398 cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
399 cr->fill();
400
401 Gdk::Cairo::set_source_rgba(cr, grey1);
402 cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);
403 cr->fill();
404
405 Gdk::Cairo::set_source_rgba(cr, black);
406
407 int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
408 int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
409
410 for (int i = clipkey1 ; i < clipkey2 ; i++) {
411 int note = (i + 3) % 12;
412 int x = key_to_x(i, w);
413
414 if (note == 1 || note == 4 || note == 6 ||
415 note == 9 || note == 11) {
416 // black key: short line in the middle, with a rectangle
417 // on top
418 int x2 = key_to_x(i + 0.5, w);
419 cr->move_to(x2 + 0.5, h1 + bh + 0.5);
420 cr->line_to(x2 + 0.5, h1 + h - 1);
421 cr->stroke();
422
423 int x3 = key_to_x(i + 1, w);
424 cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
425 cr->fill();
426 } else if (note == 3 || note == 8) {
427 // C or F: long line to the left
428 cr->move_to(x + 0.5, h1 + 1);
429 cr->line_to(x + 0.5, h1 + h - 1);
430 cr->stroke();
431 }
432
433 if (key_pressed[i]) draw_key(cr, i);
434
435 if (note == 3) draw_digit(cr, i);
436 }
437 }
438
439
440 void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
441 int clip_low, int clip_high) {
442 const int w = get_width() - 1;
443
444 Gdk::Cairo::set_source_rgba(cr, black);
445 gig::Region* next_region;
446 int x3 = -1;
447 for (gig::Region* r = regions.first() ; r ; r = next_region) {
448 next_region = regions.next();
449
450 if (x3 < 0) {
451 x3 = key_to_x(r->KeyRange.low, w);
452 if (x3 >= clip_high) break;
453 }
454 if (!next_region ||
455 r->KeyRange.high + 1 != next_region->KeyRange.low ||
456 r == region || next_region == region) {
457
458 int x2 = key_to_x(r->KeyRange.high + 1, w);
459 if (x2 >= clip_low) {
460 cr->move_to(x3, 0.5);
461 cr->line_to(x2 + 0.5, 0.5);
462 cr->line_to(x2 + 0.5, h1 - 0.5);
463 cr->line_to(x3, h1 - 0.5);
464 cr->stroke();
465
466 if (region == r)
467 Gdk::Cairo::set_source_rgba(cr, blue);
468 else if (modifyallregions)
469 cr->set_source(blueHatchedSurfacePattern);
470 else
471 Gdk::Cairo::set_source_rgba(cr, white);
472
473 cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
474 cr->fill();
475 Gdk::Cairo::set_source_rgba(cr, black);
476 }
477 x3 = -1;
478 }
479 }
480
481 for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
482 int x = key_to_x(r->KeyRange.low, w);
483 int x2 = key_to_x(r->KeyRange.high + 1, w);
484
485 RegionFeatures features = regionFeatures(r);
486
487 const bool bShowLoopSymbol = features.loops > 0;
488 const bool bShowSampleRefSymbol = features.sampleRefs < features.validDimRegs;
489 if (bShowLoopSymbol || bShowSampleRefSymbol) {
490 const int margin = 2;
491 const int wRgn = x2 - x;
492 //printf("x=%d x2=%d wRgn=%d\n", x, x2, wRgn);
493
494 cr->save();
495 cr->set_line_width(1);
496 cr->rectangle(x, 1, wRgn, h1 - 1);
497 cr->clip();
498 if (bShowSampleRefSymbol) {
499 const int wPic = 8;
500 const int hPic = 8;
501 Gdk::Cairo::set_source_pixbuf(
502 cr, (features.sampleRefs) ? yellowDot : redDot,
503 x + (wRgn-wPic)/2.f,
504 (bShowLoopSymbol) ? margin : (h1-hPic)/2.f
505 );
506 cr->paint();
507 }
508 if (bShowLoopSymbol) {
509 const int wPic = 12;
510 const int hPic = 14;
511 Gdk::Cairo::set_source_pixbuf(
512 cr, (features.loops == features.validDimRegs) ? blackLoop : grayLoop,
513 x + (wRgn-wPic)/2.f,
514 (bShowSampleRefSymbol) ? h1 - hPic - margin : (h1-hPic)/2.f
515 );
516 cr->paint();
517 }
518 cr->restore();
519 }
520 }
521
522 for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
523 int x = key_to_x(r->KeyRange.low, w);
524
525 if (x < clip_low) continue;
526 if (x >= clip_high) break;
527
528 cr->move_to(x + 0.5, 1);
529 cr->line_to(x + 0.5, h1 - 1);
530 cr->stroke();
531 }
532
533 // if there is no region yet, show the user some hint text that he may
534 // right click on this area to create a new region
535 if (!regions.first()) {
536 Glib::RefPtr<Pango::Context> context = get_pango_context();
537 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
538 layout->set_alignment(Pango::ALIGN_CENTER);
539 layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
540 layout->set_width(get_width() * Pango::SCALE);
541 //layout->set_height(get_height() * Pango::SCALE);
542 layout->set_spacing(10);
543 Gdk::Cairo::set_source_rgba(cr, blue);
544 // get the text dimensions
545 int text_width, text_height;
546 layout->get_pixel_size(text_width, text_height);
547 cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
548 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
549 pango_cairo_show_layout(cr->cobj(), layout->gobj());
550 #else
551 layout->show_in_cairo_context(cr);
552 #endif
553 }
554 }
555
556 bool RegionChooser::is_black_key(int key) {
557 const int note = (key + 3) % 12;
558 return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
559 }
560
561 void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
562 int key) {
563 const int h = KEYBOARD_HEIGHT;
564 const int w = get_width() - 1;
565 Glib::RefPtr<Pango::Layout> layout =
566 Pango::Layout::create(get_pango_context());
567 char buf[30];
568 sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
569 layout->set_markup(buf);
570 Pango::Rectangle rectangle = layout->get_logical_extents();
571 double text_w = double(rectangle.get_width()) / Pango::SCALE;
572 double text_h = double(rectangle.get_height()) / Pango::SCALE;
573 double x = w * (key + 0.75) / 128.0;
574 Gdk::Cairo::set_source_rgba(cr, black);
575 cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));
576 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
577 pango_cairo_show_layout(cr->cobj(), layout->gobj());
578 #else
579 layout->show_in_cairo_context(cr);
580 #endif
581 }
582
583 void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
584 int key) {
585 const int h = KEYBOARD_HEIGHT;
586 const int w = get_width() - 1;
587 const int bh = int(h * 0.55);
588
589 Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
590
591 int note = (key + 3) % 12;
592 int x = key_to_x(key, w) + 1;
593 int x2 = key_to_x(key + 1.5, w);
594 int x3 = key_to_x(key + 1, w);
595 int x4 = key_to_x(key - 0.5, w);
596 int w1 = x3 - x;
597 switch (note) {
598 case 0: case 5: case 10:
599 cr->rectangle(x, h1 + 1, w1, bh);
600 cr->fill();
601 cr->rectangle(x4 + 1, h1 + bh + 1, x2 - x4 - 1, h - bh - 2);
602 cr->fill();
603 break;
604 case 2: case 7:
605 cr->rectangle(x, h1 + 1, w1, bh);
606 cr->fill();
607 cr->rectangle(x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2);
608 cr->fill();
609 break;
610 case 3: case 8:
611 cr->rectangle(x, h1 + 1, w1, bh);
612 cr->fill();
613 cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
614 cr->fill();
615 break;
616 default:
617 cr->rectangle(x, h1 + 1, w1, bh - 1);
618 cr->fill();
619 break;
620 }
621 Gdk::Cairo::set_source_rgba(cr, black);
622 }
623
624 void RegionChooser::set_instrument(gig::Instrument* instrument)
625 {
626 this->instrument = instrument;
627 regions.update(instrument);
628 region = regions.first();
629 queue_draw();
630 region_selected();
631 dimensionManager.set_region(region);
632 }
633
634 bool RegionChooser::on_button_release_event(GdkEventButton* event)
635 {
636 const int k = x_to_key(event->x, get_width() - 1);
637
638 // handle-note off on virtual keyboard
639 if (event->type == GDK_BUTTON_RELEASE) {
640 int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
641 int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
642 if (velocity <= 0) velocity = 1;
643 switch (m_VirtKeybModeChoice.get_value()) {
644 case VIRT_KEYBOARD_MODE_CHORD:
645 if (event->y >= REGION_BLOCK_HEIGHT)
646 keyboard_key_released_signal.emit(k, velocity);
647 break;
648 case VIRT_KEYBOARD_MODE_NORMAL:
649 default:
650 if (currentActiveKey >= 0 && currentActiveKey <= 127) {
651 keyboard_key_released_signal.emit(currentActiveKey, velocity);
652 currentActiveKey = -1;
653 }
654 break;
655 }
656 }
657
658 if (resize.active) {
659 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
660 get_window()->pointer_ungrab(event->time);
661 #else
662 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
663 Glib::wrap(event->device, true)->ungrab(event->time);
664 # else
665 gdk_device_ungrab(Glib::wrap(event->device, true)->gobj(), event->time);
666 # endif
667 #endif
668 resize.active = false;
669
670 if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
671 get_window()->set_cursor();
672 cursor_is_resize = false;
673 }
674 } else if (move.active) {
675 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
676 get_window()->pointer_ungrab(event->time);
677 #else
678 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
679 Glib::wrap(event->device, true)->ungrab(event->time);
680 # else
681 gdk_device_ungrab(Glib::wrap(event->device, true)->gobj(), event->time);
682 # endif
683 #endif
684 move.active = false;
685
686 if (is_in_resize_zone(event->x, event->y)) {
687 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
688 get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
689 #else
690 get_window()->set_cursor(
691 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
692 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
693 # else
694 Gdk::Cursor::create(
695 Glib::wrap(event->device, true)->get_seat()->get_display(),
696 Gdk::SB_H_DOUBLE_ARROW
697 )
698 # endif
699 );
700 #endif
701 cursor_is_resize = true;
702 }
703 }
704 return true;
705 }
706
707 void RegionChooser::update_after_resize()
708 {
709 if (resize.mode == resize.moving_high_limit) {
710 if (resize.region->KeyRange.high != resize.pos - 1) {
711 instrument_struct_to_be_changed_signal.emit(instrument);
712 resize.region->SetKeyRange(resize.region->KeyRange.low,
713 resize.pos - 1);
714 regions.update(instrument);
715 instrument_changed.emit();
716 instrument_struct_changed_signal.emit(instrument);
717 }
718 } else if (resize.mode == resize.moving_low_limit) {
719 if (resize.region->KeyRange.low != resize.pos) {
720 instrument_struct_to_be_changed_signal.emit(instrument);
721 resize.region->SetKeyRange(resize.pos,
722 resize.region->KeyRange.high);
723 regions.update(instrument);
724 instrument_changed.emit();
725 instrument_struct_changed_signal.emit(instrument);
726 }
727 }
728 }
729
730 void RegionChooser::update_after_move(int pos)
731 {
732 instrument_struct_to_be_changed_signal.emit(instrument);
733 const int range = region->KeyRange.high - region->KeyRange.low;
734 const int diff = pos - int(region->KeyRange.low);
735 region->SetKeyRange(pos, pos + range);
736 if (Settings::singleton()->moveRootNoteWithRegionMoved) {
737 for (int i = 0; i < 256; ++i) {
738 gig::DimensionRegion* dimrgn = region->pDimensionRegions[i];
739 if (!dimrgn || !dimrgn->pSample || !dimrgn->PitchTrack) continue;
740 dimrgn->UnityNote += diff;
741 }
742 }
743 regions.update(instrument);
744 instrument_changed.emit();
745 instrument_struct_changed_signal.emit(instrument);
746 }
747
748 bool RegionChooser::on_button_press_event(GdkEventButton* event)
749 {
750 if (!instrument) return true;
751
752 const int w = get_width() - 1;
753 const int k = x_to_key(event->x, w);
754
755 if (event->type == GDK_BUTTON_PRESS) {
756 if (event->y >= REGION_BLOCK_HEIGHT) {
757 int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
758 int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
759 currentActiveKey = k;
760 keyboard_key_hit_signal.emit(k, velocity);
761 }
762 }
763
764 // left mouse button double click
765 if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
766 if (event->y < REGION_BLOCK_HEIGHT) {
767 // show dimension manager dialog for this region
768 manage_dimensions();
769 }
770 }
771
772 if (event->y >= REGION_BLOCK_HEIGHT) return true;
773 if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
774 gig::Region* r = get_region(k);
775 if (r) {
776 region = r;
777 queue_draw();
778 region_selected();
779 dimensionManager.set_region(region);
780 popup_menu_inside_region->popup(event->button, event->time);
781 } else {
782 new_region_pos = k;
783 popup_menu_outside_region->popup(event->button, event->time);
784 }
785 } else {
786 if (is_in_resize_zone(event->x, event->y)) {
787 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
788 get_window()->pointer_grab(false,
789 Gdk::BUTTON_RELEASE_MASK |
790 Gdk::POINTER_MOTION_MASK |
791 Gdk::POINTER_MOTION_HINT_MASK,
792 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
793 event->time);
794 #else
795 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
796 Glib::wrap(event->device, true)->grab(get_window(),
797 Gdk::OWNERSHIP_NONE,
798 false,
799 Gdk::BUTTON_RELEASE_MASK |
800 Gdk::POINTER_MOTION_MASK |
801 Gdk::POINTER_MOTION_HINT_MASK,
802 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
803 event->time);
804 # else
805 gdk_device_grab(
806 Glib::wrap(event->device, true)->gobj(),
807 get_window()->gobj(),
808 GDK_OWNERSHIP_NONE,
809 false,
810 GdkEventMask(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
811 GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK),
812 Gdk::Cursor::create(
813 Glib::wrap(event->device, true)->get_seat()->get_display(),
814 Gdk::SB_H_DOUBLE_ARROW
815 )->gobj(),
816 event->time
817 );
818 # endif
819 #endif
820 resize.active = true;
821 } else {
822 gig::Region* r = get_region(k);
823 if (r) {
824 region = r;
825 queue_draw();
826 region_selected();
827 dimensionManager.set_region(region);
828
829 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
830 get_window()->pointer_grab(false,
831 Gdk::BUTTON_RELEASE_MASK |
832 Gdk::POINTER_MOTION_MASK |
833 Gdk::POINTER_MOTION_HINT_MASK,
834 Gdk::Cursor(Gdk::FLEUR),
835 event->time);
836 #else
837 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
838 Glib::wrap(event->device, true)->grab(get_window(),
839 Gdk::OWNERSHIP_NONE,
840 false,
841 Gdk::BUTTON_RELEASE_MASK |
842 Gdk::POINTER_MOTION_MASK |
843 Gdk::POINTER_MOTION_HINT_MASK,
844 Gdk::Cursor::create(Gdk::FLEUR),
845 event->time);
846 # else
847 gdk_device_grab(
848 Glib::wrap(event->device, true)->gobj(),
849 get_window()->gobj(),
850 GDK_OWNERSHIP_NONE,
851 false,
852 GdkEventMask(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
853 GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK),
854 Gdk::Cursor::create(
855 Glib::wrap(event->device, true)->get_seat()->get_display(),
856 Gdk::FLEUR
857 )->gobj(),
858 event->time
859 );
860 # endif
861 #endif
862 move.active = true;
863 move.offset = event->x - key_to_x(region->KeyRange.low, w);
864 }
865 }
866 }
867 return true;
868 }
869
870 gig::Region* RegionChooser::get_region(int key)
871 {
872 for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
873 if (key < r->KeyRange.low) return 0;
874 if (key <= r->KeyRange.high) return r;
875 }
876 return 0;
877 }
878
879 void RegionChooser::set_region(gig::Region* region) {
880 this->region = region;
881 queue_draw();
882 region_selected();
883 dimensionManager.set_region(region);
884 }
885
886 void RegionChooser::select_next_region() {
887 if (!instrument) return;
888 if (!region) {
889 for (int i = 0; i < 128; ++i) {
890 ::gig::Region* rgn = instrument->GetRegion(i);
891 if (rgn) {
892 set_region(rgn);
893 return;
894 }
895 }
896 } else {
897 bool currentFound = false;
898 for (int i = 0; i < 128; ++i) {
899 ::gig::Region* rgn = instrument->GetRegion(i);
900 if (!rgn) continue;
901 if (currentFound) {
902 if (rgn != region) {
903 set_region(rgn);
904 return;
905 }
906 } else {
907 if (rgn == region) currentFound = true;
908 }
909 }
910 }
911 }
912
913 void RegionChooser::select_prev_region() {
914 if (!instrument) return;
915 if (!region) {
916 for (int i = 0; i < 128; ++i) {
917 ::gig::Region* rgn = instrument->GetRegion(i);
918 if (rgn) {
919 set_region(rgn);
920 return;
921 }
922 }
923 } else {
924 bool currentFound = false;
925 for (int i = 127; i >= 0; --i) {
926 ::gig::Region* rgn = instrument->GetRegion(i);
927 if (!rgn) continue;
928 if (currentFound) {
929 if (rgn != region) {
930 set_region(rgn);
931 return;
932 }
933 } else {
934 if (rgn == region) currentFound = true;
935 }
936 }
937 }
938 }
939
940 void RegionChooser::motion_resize_region(int x, int y)
941 {
942 const int w = get_width() - 1;
943
944 int k = int(double(x) / w * 128.0 + 0.5);
945
946 if (k < resize.min) k = resize.min;
947 else if (k > resize.max) k = resize.max;
948
949 if (k != resize.pos) {
950 if (resize.mode == resize.undecided) {
951 if (k < resize.pos) {
952 // edit high limit of prev_region
953 resize.max = resize.region->KeyRange.low;
954 resize.region = resize.prev_region;
955 resize.mode = resize.moving_high_limit;
956 } else {
957 // edit low limit of region
958 resize.min = resize.prev_region->KeyRange.high + 1;
959 resize.mode = resize.moving_low_limit;
960 }
961 }
962 resize.pos = k;
963
964 int x1, x2;
965 if (resize.mode == resize.moving_high_limit) {
966 if (resize.region->KeyRange.high < resize.pos - 1) {
967 x1 = resize.region->KeyRange.high;
968 x2 = resize.pos - 1;
969 } else {
970 x1 = resize.pos - 1;
971 x2 = resize.region->KeyRange.high;
972 }
973 } else {
974 if (resize.region->KeyRange.low < resize.pos) {
975 x1 = resize.region->KeyRange.low;
976 x2 = resize.pos;
977 } else {
978 x1 = resize.pos;
979 x2 = resize.region->KeyRange.low;
980 }
981 }
982 x1 = key_to_x(x1, w);
983 x2 = key_to_x(x2 + 1, w) + 1;
984 Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
985
986 update_after_resize();
987
988 //get_window()->invalidate_rect(rect, false);
989 get_window()->invalidate(false); // repaint entire region, otherwise it would create visual artifacts
990 }
991 }
992
993 void RegionChooser::motion_move_region(int x, int y)
994 {
995 const int w = get_width() - 1;
996
997 int l = int(double(x - move.offset) / w * 128.0 + 0.5);
998
999 if (l == region->KeyRange.low) return;
1000 int new_l;
1001 int regionsize = region->KeyRange.high - region->KeyRange.low;
1002 int a = 0;
1003 if (l > region->KeyRange.low) {
1004 for (gig::Region* r = regions.first() ; ; r = regions.next()) {
1005 if (r != region) {
1006 int b = r ? r->KeyRange.low : 128;
1007
1008 // gap: from a to b (not inclusive b)
1009
1010 if (region->KeyRange.high >= b) {
1011 // not found the current gap yet, just continue
1012 } else {
1013
1014 if (a > l) {
1015 // this gap is too far to the right, break
1016 break;
1017 }
1018
1019 int newhigh = std::min(l + regionsize, b - 1);
1020 int newlo = newhigh - regionsize;
1021
1022 if (newlo >= a) {
1023 // yes it fits - it's a candidate
1024 new_l = newlo;
1025 }
1026 }
1027 if (!r) break;
1028 a = r->KeyRange.high + 1;
1029 }
1030 }
1031 } else {
1032 for (gig::Region* r = regions.first() ; ; r = regions.next()) {
1033 if (r != region) {
1034 int b = r ? r->KeyRange.low : 128;
1035
1036 // gap from a to b (not inclusive b)
1037
1038 if (l + regionsize >= b) {
1039 // not found the current gap yet, just continue
1040 } else {
1041
1042 if (a > region->KeyRange.low) {
1043 // this gap is too far to the right, break
1044 break;
1045 }
1046
1047 int newlo = std::max(l, a);
1048 int newhigh = newlo + regionsize;
1049
1050 if (newhigh < b) {
1051 // yes it fits - break as the first one is the best
1052 new_l = newlo;
1053 break;
1054 }
1055 }
1056 if (!r) break;
1057 a = r->KeyRange.high + 1;
1058 }
1059 }
1060 }
1061 if (new_l == region->KeyRange.low) return;
1062
1063 int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
1064 int x2 = key_to_x(std::max(int(region->KeyRange.high),
1065 new_l + regionsize) + 1, w) + 1;
1066
1067 Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
1068 update_after_move(new_l);
1069
1070 get_window()->invalidate_rect(rect, false);
1071 }
1072
1073
1074 bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)
1075 {
1076 Glib::RefPtr<Gdk::Window> window = get_window();
1077 int x, y;
1078 #if HAS_GDKMM_SEAT
1079 x = event->x;
1080 y = event->y;
1081 Gdk::ModifierType state = Gdk::ModifierType(event->state);
1082 #else
1083 Gdk::ModifierType state = Gdk::ModifierType(0);
1084 window->get_pointer(x, y, state);
1085 #endif
1086
1087 // handle virtual MIDI keyboard
1088 if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&
1089 currentActiveKey > 0 &&
1090 event->y >= REGION_BLOCK_HEIGHT &&
1091 event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
1092 {
1093 const int k = x_to_key(event->x, get_width() - 1);
1094 if (k != currentActiveKey) {
1095 int velocity =
1096 (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
1097 int(float(event->y - REGION_BLOCK_HEIGHT) /
1098 float(KEYBOARD_HEIGHT) * 128.0f) + 1;
1099 if (velocity <= 0) velocity = 1;
1100 keyboard_key_released_signal.emit(currentActiveKey, velocity);
1101 currentActiveKey = k;
1102 keyboard_key_hit_signal.emit(k, velocity);
1103 }
1104 }
1105
1106 if (resize.active) {
1107 motion_resize_region(x, y);
1108 } else if (move.active) {
1109 motion_move_region(x, y);
1110 } else {
1111 if (is_in_resize_zone(x, y)) {
1112 if (!cursor_is_resize) {
1113 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1114 window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1115 #else
1116 window->set_cursor(
1117 # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1118 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1119 # else
1120 Gdk::Cursor::create(
1121 Glib::wrap(event->device, true)->get_seat()->get_display(),
1122 Gdk::SB_H_DOUBLE_ARROW
1123 )
1124 # endif
1125 );
1126 #endif
1127 cursor_is_resize = true;
1128 }
1129 } else if (cursor_is_resize) {
1130 window->set_cursor();
1131 cursor_is_resize = false;
1132 }
1133 }
1134
1135 return true;
1136 }
1137
1138 bool RegionChooser::is_in_resize_zone(double x, double y) {
1139 const int w = get_width() - 1;
1140
1141 if (instrument && y >= 0 && y <= h1) {
1142 gig::Region* prev_region = 0;
1143 gig::Region* next_region;
1144 for (gig::Region* r = regions.first(); r ; r = next_region) {
1145 next_region = regions.next();
1146
1147 int lo = key_to_x(r->KeyRange.low, w);
1148 if (x <= lo - 2) break;
1149 if (x < lo + 2) {
1150 resize.region = r;
1151 resize.pos = r->KeyRange.low;
1152 resize.max = r->KeyRange.high;
1153
1154 if (prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low) {
1155 // we don't know yet if it's the high limit of
1156 // prev_region or the low limit of r that's going
1157 // to be edited
1158 resize.mode = resize.undecided;
1159 resize.min = prev_region->KeyRange.low + 1;
1160 resize.prev_region = prev_region;
1161 return resize.min != resize.max;
1162 }
1163
1164 // edit low limit
1165 resize.mode = resize.moving_low_limit;
1166 resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
1167 return resize.min != resize.max;
1168 }
1169 if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
1170 int hi = key_to_x(r->KeyRange.high + 1, w);
1171 if (x <= hi - 2) break;
1172 if (x < hi + 2) {
1173 // edit high limit
1174 resize.region = r;
1175 resize.pos = r->KeyRange.high + 1;
1176 resize.mode = resize.moving_high_limit;
1177 resize.min = r->KeyRange.low + 1;
1178 resize.max = next_region ? next_region->KeyRange.low : 128;
1179 return resize.min != resize.max;
1180 }
1181 }
1182 prev_region = r;
1183 }
1184 }
1185 return false;
1186 }
1187
1188 sigc::signal<void>& RegionChooser::signal_region_selected()
1189 {
1190 return region_selected;
1191 }
1192
1193 sigc::signal<void>& RegionChooser::signal_instrument_changed()
1194 {
1195 return instrument_changed;
1196 }
1197
1198 void RegionChooser::show_region_properties()
1199 {
1200 if (!region) return;
1201 Gtk::Dialog dialog(_("Region Properties"), true /*modal*/);
1202 // add "Keygroup" checkbox
1203 Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));
1204 checkBoxKeygroup.set_active(region->KeyGroup);
1205 #if USE_GTKMM_BOX
1206 dialog.get_content_area()->pack_start(checkBoxKeygroup);
1207 #else
1208 dialog.get_vbox()->pack_start(checkBoxKeygroup);
1209 #endif
1210 checkBoxKeygroup.show();
1211 // add "Keygroup" spinbox
1212 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1213 Gtk::Adjustment adjustment(1, 1, 999);
1214 Gtk::SpinButton spinBox(adjustment);
1215 #else
1216 Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1217 #endif
1218 if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
1219 #if USE_GTKMM_BOX
1220 dialog.get_content_area()->pack_start(spinBox);
1221 #else
1222 dialog.get_vbox()->pack_start(spinBox);
1223 #endif
1224 spinBox.show();
1225 // add OK and CANCEL buttons to the dialog
1226 #if HAS_GTKMM_STOCK
1227 dialog.add_button(Gtk::Stock::OK, 0);
1228 dialog.add_button(Gtk::Stock::CANCEL, 1);
1229 #else
1230 dialog.add_button(_("_OK"), 0);
1231 dialog.add_button(_("_Cancel"), 1);
1232 #endif
1233 dialog.set_position(Gtk::WIN_POS_MOUSE);
1234 #if HAS_GTKMM_SHOW_ALL_CHILDREN
1235 dialog.show_all_children();
1236 #endif
1237 if (!dialog.run()) { // OK selected ...
1238 region->KeyGroup =
1239 (checkBoxKeygroup.get_active()) ? spinBox.get_value_as_int() : 0;
1240 }
1241 }
1242
1243 void RegionChooser::add_region()
1244 {
1245 instrument_struct_to_be_changed_signal.emit(instrument);
1246
1247 region = instrument->AddRegion();
1248 region->SetKeyRange(new_region_pos, new_region_pos);
1249
1250 instrument_struct_changed_signal.emit(instrument);
1251 regions.update(instrument);
1252
1253 queue_draw();
1254 region_selected();
1255 dimensionManager.set_region(region);
1256 instrument_changed();
1257 }
1258
1259 void RegionChooser::delete_region()
1260 {
1261 instrument_struct_to_be_changed_signal.emit(instrument);
1262 instrument->DeleteRegion(region);
1263 instrument_struct_changed_signal.emit(instrument);
1264 regions.update(instrument);
1265
1266 region = 0;
1267 queue_draw();
1268 region_selected();
1269 dimensionManager.set_region(region);
1270 instrument_changed();
1271 }
1272
1273 void RegionChooser::manage_dimensions()
1274 {
1275 gig::Region* region = get_region();
1276 if (!region) return;
1277 dimensionManager.show(region);
1278 }
1279
1280 void RegionChooser::on_dimension_manager_changed() {
1281 region_selected();
1282 instrument_changed();
1283 }
1284
1285 sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_to_be_changed() {
1286 return instrument_struct_to_be_changed_signal;
1287 }
1288
1289 sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_changed() {
1290 return instrument_struct_changed_signal;
1291 }
1292
1293 sigc::signal<void, gig::Region*>& RegionChooser::signal_region_to_be_changed() {
1294 return region_to_be_changed_signal;
1295 }
1296
1297 sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {
1298 return region_changed_signal;
1299 }
1300
1301 sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_hit() {
1302 return keyboard_key_hit_signal;
1303 }
1304
1305 sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_released() {
1306 return keyboard_key_released_signal;
1307 }

  ViewVC Help
Powered by ViewVC