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

Contents of /gigedit/trunk/src/gigedit/dimregionchooser.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3147 - (show annotations) (download)
Wed May 3 21:23:16 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 61749 byte(s)
* Dimension Region Chooser: Mark all zones auto selected by check box trio
  with gray hatched pattern.
* Bumped version (1.0.0.svn33).

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 <gtkmm/box.h>
21 #include "dimregionchooser.h"
22 #include <cairomm/context.h>
23 #include <cairomm/surface.h>
24 #include <gdkmm/cursor.h>
25 #include <gdkmm/general.h>
26 #include <glibmm/stringutils.h>
27 #include <glibmm/ustring.h>
28 #include <gtkmm/messagedialog.h>
29 #include <assert.h>
30
31 #include "global.h"
32 #include "gfx/builtinpix.h"
33
34 //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
35 static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
36 DimensionCase dimCase;
37 if (!dr) {
38 *isValidZone = false;
39 return dimCase;
40 }
41
42 gig::Region* rgn = (gig::Region*) dr->GetParent();
43
44 // find the dimension region index of the passed dimension region
45 int drIndex;
46 for (drIndex = 0; drIndex < 256; ++drIndex)
47 if (rgn->pDimensionRegions[drIndex] == dr)
48 break;
49
50 // not found in region, something's horribly wrong
51 if (drIndex == 256) {
52 fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
53 *isValidZone = false;
54 return DimensionCase();
55 }
56
57 for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
58 const int bits = rgn->pDimensionDefinitions[d].bits;
59 dimCase[rgn->pDimensionDefinitions[d].dimension] =
60 (drIndex >> baseBits) & ((1 << bits) - 1);
61 baseBits += bits;
62 // there are also DimensionRegion objects of unused zones, skip them
63 if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
64 *isValidZone = false;
65 return DimensionCase();
66 }
67 }
68
69 *isValidZone = true;
70 return dimCase;
71 }
72
73 DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
74 red("#ff476e"),
75 blue("#4796ff"),
76 black("black"),
77 white("white")
78 {
79 // make sure blue hatched pattern pixmap is loaded
80 loadBuiltInPix();
81
82 // create blue hatched pattern
83 {
84 const int width = blueHatchedPattern->get_width();
85 const int height = blueHatchedPattern->get_height();
86 const int stride = blueHatchedPattern->get_rowstride();
87
88 // manually convert from RGBA to ARGB
89 this->blueHatchedPatternARGB = blueHatchedPattern->copy();
90 const int pixelSize = stride / width;
91 const int totalPixels = width * height;
92 assert(pixelSize == 4);
93 unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
94 for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
95 const unsigned char r = ptr[0];
96 const unsigned char g = ptr[1];
97 const unsigned char b = ptr[2];
98 const unsigned char a = ptr[3];
99 ptr[0] = b;
100 ptr[1] = g;
101 ptr[2] = r;
102 ptr[3] = a;
103 }
104
105 Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
106 this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
107 );
108 this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
109 this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
110 }
111
112 // create gray blue hatched pattern
113 {
114 const int width = grayBlueHatchedPattern->get_width();
115 const int height = grayBlueHatchedPattern->get_height();
116 const int stride = grayBlueHatchedPattern->get_rowstride();
117
118 // manually convert from RGBA to ARGB
119 this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
120 const int pixelSize = stride / width;
121 const int totalPixels = width * height;
122 assert(pixelSize == 4);
123 unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
124 for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
125 const unsigned char r = ptr[0];
126 const unsigned char g = ptr[1];
127 const unsigned char b = ptr[2];
128 const unsigned char a = ptr[3];
129 ptr[0] = b;
130 ptr[1] = g;
131 ptr[2] = r;
132 ptr[3] = a;
133 }
134
135 Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
136 this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
137 );
138 this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
139 this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
140 }
141
142 instrument = 0;
143 region = 0;
144 maindimregno = -1;
145 maindimtype = gig::dimension_none; // initialize with invalid dimension type
146 focus_line = 0;
147 resize.active = false;
148 cursor_is_resize = false;
149 h = 24;
150 multiSelectKeyDown = false;
151 primaryKeyDown = false;
152 shiftKeyDown = false;
153 modifybothchannels = modifyalldimregs = modifybothchannels = false;
154 set_can_focus();
155
156 const Glib::ustring txtUseCheckBoxAllRegions =
157 _("Use checkbox 'all regions' to control whether this should apply to all regions.");
158
159 actionGroup = Gtk::ActionGroup::create();
160 actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
161 actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
162 actionGroup->add(
163 actionSplitDimZone,
164 sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
165 );
166 actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
167 actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
168 actionGroup->add(
169 actionDeleteDimZone,
170 sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
171 );
172
173 uiManager = Gtk::UIManager::create();
174 uiManager->insert_action_group(actionGroup);
175 Glib::ustring ui_info =
176 "<ui>"
177 " <popup name='PopupMenuInsideDimRegion'>"
178 " <menuitem action='SplitDimZone'/>"
179 " <menuitem action='DeleteDimZone'/>"
180 " </popup>"
181 // " <popup name='PopupMenuOutsideDimRegion'>"
182 // " <menuitem action='Add'/>"
183 // " </popup>"
184 "</ui>";
185 uiManager->add_ui_from_string(ui_info);
186
187 popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
188 uiManager->get_widget("/PopupMenuInsideDimRegion"));
189 // popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
190 // uiManager->get_widget("/PopupMenuOutsideDimRegion"));
191
192 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
193 Gdk::POINTER_MOTION_HINT_MASK);
194
195 labels_changed = true;
196
197 set_tooltip_text(_(
198 "Right click here for options on altering dimension zones. Press and "
199 "hold CTRL key for selecting multiple dimension zones simultaniously."
200 ));
201
202 window.signal_key_press_event().connect(
203 sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
204 );
205 window.signal_key_release_event().connect(
206 sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
207 );
208 }
209
210 DimRegionChooser::~DimRegionChooser()
211 {
212 }
213
214 void DimRegionChooser::setModifyBothChannels(bool b) {
215 modifybothchannels = b;
216 // redraw required parts
217 queue_draw();
218 }
219
220 void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
221 modifyalldimregs = b;
222 // redraw required parts
223 queue_draw();
224 }
225
226 void DimRegionChooser::setModifyAllRegions(bool b) {
227 modifyallregions = b;
228
229 actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
230 actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
231
232 // redraw required parts
233 queue_draw();
234 }
235
236 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
237 bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
238 {
239 double clipx1 = e->area.x;
240 double clipx2 = e->area.x + e->area.width;
241 double clipy1 = e->area.y;
242 double clipy2 = e->area.y + e->area.height;
243
244 const Cairo::RefPtr<Cairo::Context>& cr =
245 get_window()->create_cairo_context();
246 #else
247 bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
248 {
249 double clipx1, clipx2, clipy1, clipy2;
250 cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
251 #endif
252
253 if (!region) return true;
254
255 // This is where we draw on the window
256 int w = get_width();
257 Glib::RefPtr<Pango::Context> context = get_pango_context();
258
259 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
260 cr->set_line_width(1);
261
262 int y = 0;
263 if (labels_changed || label_width - 10 > clipx1) {
264 // draw labels on the left (reflecting the dimension type)
265 double maxwidth = 0;
266 for (int i = 0 ; i < region->Dimensions ; i++) {
267 int nbZones = region->pDimensionDefinitions[i].zones;
268 if (nbZones) {
269 const char* dstr;
270 char dstrbuf[10];
271 switch (region->pDimensionDefinitions[i].dimension) {
272 case gig::dimension_none: dstr=_("none"); break;
273 case gig::dimension_samplechannel: dstr=_("samplechannel");
274 break;
275 case gig::dimension_layer: dstr=_("layer"); break;
276 case gig::dimension_velocity: dstr=_("velocity"); break;
277 case gig::dimension_channelaftertouch:
278 dstr=_("channelaftertouch"); break;
279 case gig::dimension_releasetrigger:
280 dstr=_("releasetrigger"); break;
281 case gig::dimension_keyboard: dstr=_("keyswitching"); break;
282 case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
283 case gig::dimension_random: dstr=_("random"); break;
284 case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
285 case gig::dimension_roundrobinkeyboard:
286 dstr=_("roundrobinkeyboard"); break;
287 case gig::dimension_modwheel: dstr=_("modwheel"); break;
288 case gig::dimension_breath: dstr=_("breath"); break;
289 case gig::dimension_foot: dstr=_("foot"); break;
290 case gig::dimension_portamentotime:
291 dstr=_("portamentotime"); break;
292 case gig::dimension_effect1: dstr=_("effect1"); break;
293 case gig::dimension_effect2: dstr=_("effect2"); break;
294 case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
295 case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
296 case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
297 case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
298 case gig::dimension_sustainpedal:
299 dstr=_("sustainpedal"); break;
300 case gig::dimension_portamento: dstr=_("portamento"); break;
301 case gig::dimension_sostenutopedal:
302 dstr=_("sostenutopedal"); break;
303 case gig::dimension_softpedal: dstr=_("softpedal"); break;
304 case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
305 case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
306 case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
307 case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
308 case gig::dimension_effect1depth:
309 dstr=_("effect1depth"); break;
310 case gig::dimension_effect2depth:
311 dstr=_("effect2depth"); break;
312 case gig::dimension_effect3depth:
313 dstr=_("effect3depth"); break;
314 case gig::dimension_effect4depth:
315 dstr=_("effect4depth"); break;
316 case gig::dimension_effect5depth:
317 dstr=_("effect5depth"); break;
318 default:
319 sprintf(dstrbuf, "%d",
320 region->pDimensionDefinitions[i].dimension);
321 dstr = dstrbuf;
322 break;
323 }
324
325 // Since bold font yields in larger label width, we first always
326 // set the bold text variant, retrieve its dimensions (as worst
327 // case dimensions of the label) ...
328 layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
329 Pango::Rectangle rectangle = layout->get_logical_extents();
330 // ... and then reset the label to regular font style in case
331 // the line is not selected. Otherwise the right hand side
332 // actual dimension zones would jump around on selection change.
333 bool isSelectedLine = (focus_line == i);
334 if (!isSelectedLine)
335 layout->set_markup(dstr);
336
337 double text_w = double(rectangle.get_width()) / Pango::SCALE;
338 if (text_w > maxwidth) maxwidth = text_w;
339
340 if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
341 double text_h = double(rectangle.get_height()) /
342 Pango::SCALE;
343 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
344 const Gdk::Color fg = get_style()->get_fg(get_state());
345 #else
346 const Gdk::RGBA fg =
347 get_style_context()->get_color(get_state_flags());
348 #endif
349 Gdk::Cairo::set_source_rgba(cr, fg);
350 cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
351 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
352 pango_cairo_show_layout(cr->cobj(), layout->gobj());
353 #else
354 layout->show_in_cairo_context(cr);
355 #endif
356 }
357 }
358 y += h;
359 }
360 label_width = int(maxwidth + 10);
361 labels_changed = false;
362 }
363 if (label_width >= clipx2) return true;
364
365 // draw dimensions' zones areas
366 y = 0;
367 int bitpos = 0;
368 for (int i = 0 ; i < region->Dimensions ; i++) {
369 int nbZones = region->pDimensionDefinitions[i].zones;
370 if (nbZones) {
371 const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
372
373 if (y >= clipy2) break;
374 if (y + h > clipy1) {
375 // draw focus rectangle around dimension's label and zones
376 if (has_focus() && focus_line == i) {
377 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
378 Gdk::Rectangle farea(0, y, 150, h);
379 get_style()->paint_focus(get_window(), get_state(), farea,
380 *this, "",
381 0, y, label_width, h);
382 #else
383 get_style_context()->render_focus(cr,
384 0, y, label_width, h);
385 #endif
386 }
387
388 // draw top and bottom lines of dimension's zones
389 Gdk::Cairo::set_source_rgba(cr, black);
390 cr->move_to(label_width, y + 0.5);
391 cr->line_to(w, y + 0.5);
392 cr->move_to(w, y + h - 0.5);
393 cr->line_to(label_width, y + h - 0.5);
394 cr->stroke();
395
396 // erase whole dimension's zones area
397 Gdk::Cairo::set_source_rgba(cr, white);
398 cr->rectangle(label_width + 1, y + 1,
399 (w - label_width - 2), h - 2);
400 cr->fill();
401
402 int c = 0;
403 if (maindimregno >= 0) {
404 int mask =
405 ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
406 bitpos);
407 c = maindimregno & mask; // mask away this dimension
408 }
409 bool customsplits =
410 ((region->pDimensionDefinitions[i].split_type ==
411 gig::split_type_normal &&
412 region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
413 (region->pDimensionDefinitions[i].dimension ==
414 gig::dimension_velocity &&
415 region->pDimensionRegions[c]->VelocityUpperLimit));
416
417 // draw dimension zones
418 Gdk::Cairo::set_source_rgba(cr, black);
419 if (customsplits) {
420 cr->move_to(label_width + 0.5, y + 1);
421 cr->line_to(label_width + 0.5, y + h - 1);
422 int prevX = label_width;
423 int prevUpperLimit = -1;
424
425 for (int j = 0 ; j < nbZones ; j++) {
426 // draw dimension zone's borders for custom splits
427 gig::DimensionRegion* d =
428 region->pDimensionRegions[c + (j << bitpos)];
429 int upperLimit = d->DimensionUpperLimits[i];
430 if (!upperLimit) upperLimit = d->VelocityUpperLimit;
431 int v = upperLimit + 1;
432 int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
433 label_width;
434 if (x >= clipx2) break;
435 if (x < clipx1) continue;
436 Gdk::Cairo::set_source_rgba(cr, black);
437 cr->move_to(x + 0.5, y + 1);
438 cr->line_to(x + 0.5, y + h - 1);
439 cr->stroke();
440
441 // draw fill for zone
442 bool isSelectedZone = this->dimzones[dimension].count(j);
443 bool isMainSelection =
444 this->maindimcase.find(dimension) != this->maindimcase.end() &&
445 this->maindimcase[dimension] == j;
446 bool isCheckBoxSelected =
447 modifyalldimregs ||
448 (modifybothchannels &&
449 dimension == gig::dimension_samplechannel);
450 if (isMainSelection)
451 Gdk::Cairo::set_source_rgba(cr, blue);
452 else if (isSelectedZone)
453 cr->set_source(blueHatchedSurfacePattern);
454 else if (isCheckBoxSelected)
455 cr->set_source(grayBlueHatchedSurfacePattern);
456 else
457 Gdk::Cairo::set_source_rgba(cr, white);
458
459 cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
460 cr->fill();
461
462 // draw text showing the beginning of the dimension zone
463 // as numeric value to the user
464 {
465 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
466 layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
467 Gdk::Cairo::set_source_rgba(cr, black);
468 // get the text dimensions
469 int text_width, text_height;
470 layout->get_pixel_size(text_width, text_height);
471 // move text to the left end of the dimension zone
472 cr->move_to(prevX + 3, y + (h - text_height) / 2);
473 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
474 pango_cairo_show_layout(cr->cobj(), layout->gobj());
475 #else
476 layout->show_in_cairo_context(cr);
477 #endif
478 }
479 // draw text showing the end of the dimension zone
480 // as numeric value to the user
481 {
482 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
483 layout->set_text(Glib::Ascii::dtostr(upperLimit));
484 Gdk::Cairo::set_source_rgba(cr, black);
485 // get the text dimensions
486 int text_width, text_height;
487 layout->get_pixel_size(text_width, text_height);
488 // move text to the left end of the dimension zone
489 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
490 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
491 pango_cairo_show_layout(cr->cobj(), layout->gobj());
492 #else
493 layout->show_in_cairo_context(cr);
494 #endif
495 }
496
497 prevX = x;
498 prevUpperLimit = upperLimit;
499 }
500 } else {
501 int prevX = 0;
502 for (int j = 0 ; j <= nbZones ; j++) {
503 // draw dimension zone's borders for normal splits
504 int x = int((w - label_width - 1) * j /
505 double(nbZones) + 0.5) + label_width;
506 if (x >= clipx2) break;
507 if (x < clipx1) continue;
508 Gdk::Cairo::set_source_rgba(cr, black);
509 cr->move_to(x + 0.5, y + 1);
510 cr->line_to(x + 0.5, y + h - 1);
511 cr->stroke();
512
513 if (j != 0) {
514 // draw fill for zone
515 bool isSelectedZone = this->dimzones[dimension].count(j-1);
516 bool isMainSelection =
517 this->maindimcase.find(dimension) != this->maindimcase.end() &&
518 this->maindimcase[dimension] == (j-1);
519 bool isCheckBoxSelected =
520 modifyalldimregs ||
521 (modifybothchannels &&
522 dimension == gig::dimension_samplechannel);
523 if (isMainSelection)
524 Gdk::Cairo::set_source_rgba(cr, blue);
525 else if (isSelectedZone)
526 cr->set_source(blueHatchedSurfacePattern);
527 else if (isCheckBoxSelected)
528 cr->set_source(grayBlueHatchedSurfacePattern);
529 else
530 Gdk::Cairo::set_source_rgba(cr, white);
531 cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
532 cr->fill();
533
534 // draw text showing the beginning of the dimension zone
535 // as numeric value to the user
536 {
537 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
538 layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
539 Gdk::Cairo::set_source_rgba(cr, black);
540 // get the text dimensions
541 int text_width, text_height;
542 layout->get_pixel_size(text_width, text_height);
543 // move text to the left end of the dimension zone
544 cr->move_to(prevX + 3, y + (h - text_height) / 2);
545 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
546 pango_cairo_show_layout(cr->cobj(), layout->gobj());
547 #else
548 layout->show_in_cairo_context(cr);
549 #endif
550 }
551 // draw text showing the end of the dimension zone
552 // as numeric value to the user
553 {
554 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
555 layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
556 Gdk::Cairo::set_source_rgba(cr, black);
557 // get the text dimensions
558 int text_width, text_height;
559 layout->get_pixel_size(text_width, text_height);
560 // move text to the left end of the dimension zone
561 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
562 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
563 pango_cairo_show_layout(cr->cobj(), layout->gobj());
564 #else
565 layout->show_in_cairo_context(cr);
566 #endif
567 }
568 }
569 prevX = x;
570 }
571 }
572 }
573 y += h;
574 }
575 bitpos += region->pDimensionDefinitions[i].bits;
576 }
577
578 return true;
579 }
580
581 void DimRegionChooser::set_region(gig::Region* region)
582 {
583 this->region = region;
584 maindimregno = 0;
585 nbDimensions = 0;
586 if (region) {
587 int bitcount = 0;
588 for (int dim = 0 ; dim < region->Dimensions ; dim++) {
589 if (region->pDimensionDefinitions[dim].bits == 0) continue;
590 nbDimensions++;
591
592 int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
593 region->pDimensionDefinitions[dim].zones - 1);
594 maindimregno |= (z << bitcount);
595 bitcount += region->pDimensionDefinitions[dim].bits;
596 }
597 }
598 dimregion_selected();
599 set_size_request(800, region ? nbDimensions * h : 0);
600
601 labels_changed = true;
602 queue_resize();
603 queue_draw();
604 }
605
606 void DimRegionChooser::refresh_all() {
607 set_region(region);
608 }
609
610 void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
611 std::set<gig::DimensionRegion*>& dimregs) const
612 {
613 for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
614 gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
615 if (!dimRgn) continue;
616 bool isValidZone;
617 std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
618 if (!isValidZone) continue;
619 for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
620 it != dimCase.end(); ++it)
621 {
622 if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
623
624 std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
625 this->dimzones.find(it->first);
626 if (itSelectedDimension != this->dimzones.end() &&
627 itSelectedDimension->second.count(it->second)) continue; // is selected
628
629 goto notSelected;
630 }
631
632 dimregs.insert(dimRgn);
633
634 notSelected:
635 ;
636 }
637 }
638
639 void DimRegionChooser::update_after_resize()
640 {
641 const uint8_t upperLimit = resize.pos - 1;
642 gig::Instrument* instr = (gig::Instrument*)region->GetParent();
643
644 int bitpos = 0;
645 for (int j = 0 ; j < resize.dimension ; j++) {
646 bitpos += region->pDimensionDefinitions[j].bits;
647 }
648
649 const int stereobitpos =
650 (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
651
652 // the velocity dimension must be handled differently than all other
653 // dimension types, because
654 // 1. it is currently the only dimension type which allows different zone
655 // sizes for different cases
656 // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
657 if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
658 int mask =
659 ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
660 int c = maindimregno & mask; // mask away this dimension
661
662 if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
663 // the velocity dimension didn't previously have
664 // custom v3 splits, so we initialize all splits with
665 // default values
666 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
667 for (int j = 0 ; j < nbZones ; j++) {
668 gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
669 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
670 }
671 }
672 if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
673 // the velocity dimension didn't previously have
674 // custom v2 splits, so we initialize all splits with
675 // default values
676 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
677 for (int j = 0 ; j < nbZones ; j++) {
678 gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
679 d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
680 }
681 }
682
683 int index = c + (resize.zone << bitpos);
684 gig::DimensionRegion* d = region->pDimensionRegions[index];
685 // update both v2 and v3 values
686 d->DimensionUpperLimits[resize.dimension] = upperLimit;
687 d->VelocityUpperLimit = upperLimit;
688 if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
689 gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
690 d->DimensionUpperLimits[resize.dimension] = upperLimit;
691 d->VelocityUpperLimit = upperLimit;
692 }
693
694 if (modifyalldimregs) {
695 gig::Region* rgn = NULL;
696 for (int key = 0; key < 128; ++key) {
697 if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
698 rgn = instr->GetRegion(key);
699 if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
700 gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
701 if (!dimdef) continue;
702 if (dimdef->zones != resize.dimensionDef.zones) continue;
703 const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
704 assert(iDim >= 0 && iDim < rgn->Dimensions);
705
706 // the dimension layout might be completely different in this
707 // region, so we have to recalculate bitpos etc for this region
708 const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
709 const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
710 const int selection = resize.zone << bitpos;
711
712 // primitive and inefficient loop implementation, however due to
713 // this circumstance the loop code is much simpler, and its lack
714 // of runtime efficiency should not be notable in practice
715 for (int idr = 0; idr < 256; ++idr) {
716 const int index = (idr & stencil) | selection;
717 assert(index >= 0 && index < 256);
718 gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
719 if (!dr) continue;
720 dr->DimensionUpperLimits[iDim] = upperLimit;
721 d->VelocityUpperLimit = upperLimit;
722 }
723 }
724 } else if (modifyallregions) { // implies modifyalldimregs is false ...
725 // resolve the precise case we need to modify for all other regions
726 DimensionCase dimCase = dimensionCaseOf(d);
727 // apply the velocity upper limit change to that resolved dim case
728 // of all regions ...
729 gig::Region* rgn = NULL;
730 for (int key = 0; key < 128; ++key) {
731 if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
732 rgn = instr->GetRegion(key);
733 gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
734 if (!dimdef) continue;
735 if (dimdef->zones != resize.dimensionDef.zones) continue;
736 const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
737 assert(iDim >= 0 && iDim < rgn->Dimensions);
738
739 std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
740 for (int i = 0; i < dimrgns.size(); ++i) {
741 gig::DimensionRegion* dr = dimrgns[i];
742 dr->DimensionUpperLimits[iDim] = upperLimit;
743 dr->VelocityUpperLimit = upperLimit;
744 }
745 }
746 }
747 } else {
748 for (int i = 0 ; i < region->DimensionRegions ; ) {
749 if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
750 // the dimension didn't previously have custom
751 // limits, so we have to set default limits for
752 // all the dimension regions
753 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
754
755 for (int j = 0 ; j < nbZones ; j++) {
756 gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
757 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
758 }
759 }
760 int index = i + (resize.zone << bitpos);
761 gig::DimensionRegion* d = region->pDimensionRegions[index];
762 d->DimensionUpperLimits[resize.dimension] = upperLimit;
763 #if 0 // the following is currently not necessary, because ATM the gig format uses for all dimension types except of the veleocity dimension the same zone sizes for all cases
764 if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
765 gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
766 d->DimensionUpperLimits[resize.dimension] = upperLimit;
767 }
768 #endif
769 int bitpos = 0;
770 int j;
771 for (j = 0 ; j < region->Dimensions ; j++) {
772 if (j != resize.dimension) {
773 int maxzones = 1 << region->pDimensionDefinitions[j].bits;
774 int dimj = (i >> bitpos) & (maxzones - 1);
775 if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
776 }
777 bitpos += region->pDimensionDefinitions[j].bits;
778 }
779 if (j == region->Dimensions) break;
780 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
781 }
782
783 if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
784 gig::Region* rgn = NULL;
785 for (int key = 0; key < 128; ++key) {
786 if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
787 rgn = instr->GetRegion(key);
788 gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
789 if (!dimdef) continue;
790 if (dimdef->zones != resize.dimensionDef.zones) continue;
791 const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
792 assert(iDim >= 0 && iDim < rgn->Dimensions);
793
794 // the dimension layout might be completely different in this
795 // region, so we have to recalculate bitpos etc for this region
796 const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
797 const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
798 const int selection = resize.zone << bitpos;
799
800 // this loop implementation is less efficient than the above's
801 // loop implementation (which skips unnecessary dimension regions)
802 // however this code is much simpler, and its lack of runtime
803 // efficiency should not be notable in practice
804 for (int idr = 0; idr < 256; ++idr) {
805 const int index = (idr & stencil) | selection;
806 assert(index >= 0 && index < 256);
807 gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
808 if (!dr) continue;
809 dr->DimensionUpperLimits[iDim] = upperLimit;
810 }
811 }
812 }
813 }
814 }
815
816 bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
817 {
818 if (resize.active) {
819 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
820 get_window()->pointer_ungrab(event->time);
821 #else
822 Glib::wrap(event->device, true)->ungrab(event->time);
823 #endif
824 resize.active = false;
825
826 region_changed();
827
828 if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
829 get_window()->set_cursor();
830 cursor_is_resize = false;
831 }
832 }
833 return true;
834 }
835
836 bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
837 {
838 int w = get_width();
839 if (region && event->y < nbDimensions * h &&
840 event->x >= label_width && event->x < w) {
841
842 if (is_in_resize_zone(event->x, event->y)) {
843 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
844 get_window()->pointer_grab(false,
845 Gdk::BUTTON_RELEASE_MASK |
846 Gdk::POINTER_MOTION_MASK |
847 Gdk::POINTER_MOTION_HINT_MASK,
848 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
849 event->time);
850 #else
851 Glib::wrap(event->device, true)->grab(get_window(),
852 Gdk::OWNERSHIP_NONE,
853 false,
854 Gdk::BUTTON_RELEASE_MASK |
855 Gdk::POINTER_MOTION_MASK |
856 Gdk::POINTER_MOTION_HINT_MASK,
857 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
858 event->time);
859 #endif
860 resize.active = true;
861 } else {
862 int ydim = int(event->y / h);
863 int dim;
864 for (dim = 0 ; dim < region->Dimensions ; dim++) {
865 if (region->pDimensionDefinitions[dim].bits == 0) continue;
866 if (ydim == 0) break;
867 ydim--;
868 }
869 int nbZones = region->pDimensionDefinitions[dim].zones;
870
871 int z = -1;
872 int bitpos = 0;
873 for (int i = 0 ; i < dim ; i++) {
874 bitpos += region->pDimensionDefinitions[i].bits;
875 }
876
877 int i = dim;
878 if (maindimregno < 0) maindimregno = 0;
879 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
880 int c = this->maindimregno & mask; // mask away this dimension
881
882 bool customsplits =
883 ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
884 region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
885 (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
886 region->pDimensionRegions[c]->VelocityUpperLimit));
887 if (customsplits) {
888 int val = int((event->x - label_width) * 128 / (w - label_width - 1));
889
890 if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
891 for (z = 0 ; z < nbZones ; z++) {
892 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
893 if (val <= d->DimensionUpperLimits[i]) break;
894 }
895 } else {
896 for (z = 0 ; z < nbZones ; z++) {
897 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
898 if (val <= d->VelocityUpperLimit) break;
899 }
900 }
901 } else {
902 z = int((event->x - label_width) * nbZones / (w - label_width - 1));
903 }
904
905 printf("dim=%d z=%d dimensionsource=%d split_type=%d zones=%d zone_size=%f\n", dim, z,
906 region->pDimensionDefinitions[dim].dimension,
907 region->pDimensionDefinitions[dim].split_type,
908 region->pDimensionDefinitions[dim].zones,
909 region->pDimensionDefinitions[dim].zone_size);
910 this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
911 this->maindimregno = c | (z << bitpos);
912 this->maindimtype = region->pDimensionDefinitions[dim].dimension;
913
914 if (multiSelectKeyDown) {
915 if (dimzones[this->maindimtype].count(z)) {
916 if (dimzones[this->maindimtype].size() > 1) {
917 dimzones[this->maindimtype].erase(z);
918 }
919 } else {
920 dimzones[this->maindimtype].insert(z);
921 }
922 } else {
923 this->dimzones.clear();
924 for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
925 it != this->maindimcase.end(); ++it)
926 {
927 this->dimzones[it->first].insert(it->second);
928 }
929 }
930
931 focus_line = dim;
932 if (has_focus()) queue_draw();
933 else grab_focus();
934 dimregion_selected();
935
936 if (event->button == 3) {
937 printf("dimregion right click\n");
938 popup_menu_inside_dimregion->popup(event->button, event->time);
939 }
940
941 queue_draw();
942 }
943 }
944 return true;
945 }
946
947 bool DimRegionChooser::on_motion_notify_event(GdkEventMotion* event)
948 {
949 Glib::RefPtr<Gdk::Window> window = get_window();
950 int x, y;
951 Gdk::ModifierType state = Gdk::ModifierType(0);
952 window->get_pointer(x, y, state);
953
954 if (resize.active) {
955 int w = get_width();
956 int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
957
958 if (k < resize.min) k = resize.min;
959 else if (k > resize.max) k = resize.max;
960
961 if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
962
963 if (k != resize.pos) {
964 int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
965 int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
966 int y = resize.dimension * h;
967 int x1, x2;
968 if (k > resize.pos) {
969 x1 = prevx;
970 x2 = x;
971 } else {
972 x1 = x;
973 x2 = prevx;
974 }
975 Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
976
977 resize.pos = k;
978 update_after_resize();
979 get_window()->invalidate_rect(rect, false); // not sufficient ...
980 queue_draw(); // ... so do a complete redraw instead.
981 }
982 } else {
983 if (is_in_resize_zone(x, y)) {
984 if (!cursor_is_resize) {
985 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
986 window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
987 #else
988 window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
989 #endif
990 cursor_is_resize = true;
991 }
992 } else if (cursor_is_resize) {
993 window->set_cursor();
994 cursor_is_resize = false;
995 }
996 }
997 return true;
998 }
999
1000 bool DimRegionChooser::is_in_resize_zone(double x, double y)
1001 {
1002 int w = get_width();
1003 if (region && y < nbDimensions * h && x >= label_width && x < w) {
1004 int ydim = int(y / h);
1005 int dim;
1006 int bitpos = 0;
1007 for (dim = 0 ; dim < region->Dimensions ; dim++) {
1008 if (region->pDimensionDefinitions[dim].bits == 0) continue;
1009 if (ydim == 0) break;
1010 ydim--;
1011 bitpos += region->pDimensionDefinitions[dim].bits;
1012 }
1013 int nbZones = region->pDimensionDefinitions[dim].zones;
1014
1015 int c = 0;
1016 if (maindimregno >= 0) {
1017 int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1018 c = maindimregno & mask; // mask away this dimension
1019 }
1020 const bool customsplits =
1021 ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
1022 region->pDimensionRegions[c]->DimensionUpperLimits[dim]) ||
1023 (region->pDimensionDefinitions[dim].dimension == gig::dimension_velocity &&
1024 region->pDimensionRegions[c]->VelocityUpperLimit));
1025
1026 // dimensions of split_type_bit cannot be resized
1027 if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
1028 int prev_limit = 0;
1029 for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
1030 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1031 const int upperLimit =
1032 (customsplits) ?
1033 (d->DimensionUpperLimits[dim]) ?
1034 d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
1035 : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
1036 int limit = upperLimit + 1;
1037 int limitx = int((w - label_width - 1) * limit / 128.0 + 0.5) + label_width;
1038 if (x <= limitx - 2) break;
1039 if (x <= limitx + 2) {
1040 resize.dimension = dim;
1041 resize.dimensionDef = region->pDimensionDefinitions[dim];
1042 resize.zone = iZone;
1043 resize.pos = limit;
1044 resize.min = prev_limit;
1045
1046 int dr = (maindimregno >> bitpos) &
1047 ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1048 resize.selected = dr == iZone ? resize.left :
1049 dr == iZone + 1 ? resize.right : resize.none;
1050
1051 iZone++;
1052 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1053
1054 const int upperLimit =
1055 (customsplits) ?
1056 (d->DimensionUpperLimits[dim]) ?
1057 d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
1058 : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
1059
1060 int limit = upperLimit + 1;
1061 resize.max = limit;
1062 return true;
1063 }
1064 prev_limit = limit;
1065 }
1066 }
1067 }
1068 return false;
1069 }
1070
1071 sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
1072 {
1073 return dimregion_selected;
1074 }
1075
1076 sigc::signal<void>& DimRegionChooser::signal_region_changed()
1077 {
1078 return region_changed;
1079 }
1080
1081 bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1082 {
1083 // TODO: check that region exists etc, that is, that it's possible
1084 // to set focus
1085 if (direction == Gtk::DIR_TAB_FORWARD ||
1086 direction == Gtk::DIR_DOWN) {
1087 if (!has_focus()) {
1088 focus_line = 0;
1089 grab_focus();
1090 return true;
1091 } else {
1092 if (focus_line + 1 < region->Dimensions) {
1093 focus_line++;
1094 queue_draw();
1095 return true;
1096 } else {
1097 return false;
1098 }
1099 }
1100 } else if (direction == Gtk::DIR_TAB_BACKWARD ||
1101 direction == Gtk::DIR_UP) {
1102 if (!has_focus()) {
1103 focus_line = region->Dimensions - 1;
1104 grab_focus();
1105 return true;
1106 } else {
1107 if (focus_line > 0) {
1108 focus_line--;
1109 queue_draw();
1110 return true;
1111 } else {
1112 return false;
1113 }
1114 }
1115 } else if (!has_focus()) {
1116 // TODO: check that focus_line exists
1117 grab_focus();
1118 return true;
1119 } else {
1120 // TODO: increase or decrease value
1121 }
1122 return false;
1123 }
1124
1125 void DimRegionChooser::split_dimension_zone() {
1126 printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1127 try {
1128 if (!modifyallregions) {
1129 region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1130 } else {
1131 gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1132 gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1133 assert(pMaindimdef != NULL);
1134 // retain structure by value since the original region will be
1135 // modified in the loop below as well
1136 gig::dimension_def_t maindimdef = *pMaindimdef;
1137 std::vector<gig::Region*> ignoredAll;
1138 std::vector<gig::Region*> ignoredMinor;
1139 std::vector<gig::Region*> ignoredCritical;
1140 gig::Region* rgn = NULL;
1141 for (int key = 0; key < 128; ++key) {
1142 if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1143 rgn = instr->GetRegion(key);
1144
1145 // ignore all regions which do not exactly match the dimension
1146 // layout of the selected region where this operation was emitted
1147 gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1148 if (!dimdef) {
1149 ignoredAll.push_back(rgn);
1150 ignoredMinor.push_back(rgn);
1151 continue;
1152 }
1153 if (dimdef->zones != maindimdef.zones) {
1154 ignoredAll.push_back(rgn);
1155 ignoredCritical.push_back(rgn);
1156 continue;
1157 }
1158
1159 rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1160 }
1161 if (!ignoredAll.empty()) {
1162 Glib::ustring txt;
1163 if (ignoredCritical.empty())
1164 txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1165 else if (ignoredMinor.empty())
1166 txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1167 else
1168 txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1169 ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1170 Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1171 Gtk::MessageDialog msg(txt, false, type);
1172 msg.run();
1173 }
1174 }
1175 } catch (RIFF::Exception e) {
1176 Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1177 msg.run();
1178 } catch (...) {
1179 Glib::ustring txt = _("An unknown exception occurred!");
1180 Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1181 msg.run();
1182 }
1183 refresh_all();
1184 }
1185
1186 void DimRegionChooser::delete_dimension_zone() {
1187 printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1188 try {
1189 if (!modifyallregions) {
1190 region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1191 } else {
1192 gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1193 gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1194 assert(pMaindimdef != NULL);
1195 // retain structure by value since the original region will be
1196 // modified in the loop below as well
1197 gig::dimension_def_t maindimdef = *pMaindimdef;
1198 std::vector<gig::Region*> ignoredAll;
1199 std::vector<gig::Region*> ignoredMinor;
1200 std::vector<gig::Region*> ignoredCritical;
1201 gig::Region* rgn = NULL;
1202 for (int key = 0; key < 128; ++key) {
1203 if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1204 rgn = instr->GetRegion(key);
1205
1206 // ignore all regions which do not exactly match the dimension
1207 // layout of the selected region where this operation was emitted
1208 gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1209 if (!dimdef) {
1210 ignoredAll.push_back(rgn);
1211 ignoredMinor.push_back(rgn);
1212 continue;
1213 }
1214 if (dimdef->zones != maindimdef.zones) {
1215 ignoredAll.push_back(rgn);
1216 ignoredCritical.push_back(rgn);
1217 continue;
1218 }
1219
1220 rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1221 }
1222 if (!ignoredAll.empty()) {
1223 Glib::ustring txt;
1224 if (ignoredCritical.empty())
1225 txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1226 else if (ignoredMinor.empty())
1227 txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1228 else
1229 txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1230 ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1231 Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1232 Gtk::MessageDialog msg(txt, false, type);
1233 msg.run();
1234 }
1235 }
1236 } catch (RIFF::Exception e) {
1237 Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1238 msg.run();
1239 } catch (...) {
1240 Glib::ustring txt = _("An unknown exception occurred!");
1241 Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1242 msg.run();
1243 }
1244 refresh_all();
1245 }
1246
1247 // Cmd key on Mac, Ctrl key on all other OSs
1248 static const guint primaryKeyL =
1249 #if defined(__APPLE__)
1250 GDK_KEY_Meta_L;
1251 #else
1252 GDK_KEY_Control_L;
1253 #endif
1254
1255 static const guint primaryKeyR =
1256 #if defined(__APPLE__)
1257 GDK_KEY_Meta_R;
1258 #else
1259 GDK_KEY_Control_R;
1260 #endif
1261
1262 bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1263 //printf("key down 0x%x\n", key->keyval);
1264 if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1265 multiSelectKeyDown = true;
1266 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1267 primaryKeyDown = true;
1268 if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1269 shiftKeyDown = true;
1270
1271 //FIXME: hmm, for some reason GDKMM does not fire arrow key down events, so we are doing those handlers in the key up handler instead for now
1272 /*if (key->keyval == GDK_KEY_Left)
1273 select_prev_dimzone();
1274 if (key->keyval == GDK_KEY_Right)
1275 select_next_dimzone();
1276 if (key->keyval == GDK_KEY_Up)
1277 select_prev_dimension();
1278 if (key->keyval == GDK_KEY_Down)
1279 select_next_dimension();*/
1280 return false;
1281 }
1282
1283 bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1284 //printf("key up 0x%x\n", key->keyval);
1285 if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1286 multiSelectKeyDown = false;
1287 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1288 primaryKeyDown = false;
1289 if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1290 shiftKeyDown = false;
1291
1292 if (!has_focus()) return false;
1293
1294 // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1295 // (which is supposed to switch between regions)
1296 if (primaryKeyDown) return false;
1297
1298 // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1299 // mainwindow
1300 if (shiftKeyDown) return false;
1301
1302 if (key->keyval == GDK_KEY_Left)
1303 select_prev_dimzone();
1304 if (key->keyval == GDK_KEY_Right)
1305 select_next_dimzone();
1306 if (key->keyval == GDK_KEY_Up)
1307 select_prev_dimension();
1308 if (key->keyval == GDK_KEY_Down)
1309 select_next_dimension();
1310
1311 return false;
1312 }
1313
1314 void DimRegionChooser::resetSelectedZones() {
1315 this->dimzones.clear();
1316 if (!region) {
1317 queue_draw(); // redraw required parts
1318 return;
1319 }
1320 if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1321 queue_draw(); // redraw required parts
1322 return;
1323 }
1324 if (!region->pDimensionRegions[maindimregno]) {
1325 queue_draw(); // redraw required parts
1326 return;
1327 }
1328 gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1329
1330 bool isValidZone;
1331 this->maindimcase = dimensionCaseOf(dimrgn);
1332
1333 for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1334 it != this->maindimcase.end(); ++it)
1335 {
1336 this->dimzones[it->first].insert(it->second);
1337 }
1338
1339 // redraw required parts
1340 queue_draw();
1341 }
1342
1343 bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1344 if (!region) return false; //.selection failed
1345
1346 for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1347 if (region->pDimensionRegions[dr] == dimrgn) {
1348 // reset dim region zone selection to the requested specific dim region case
1349 maindimregno = dr;
1350 resetSelectedZones();
1351
1352 // emit signal that dimregion selection has changed, for external entities
1353 dimregion_selected();
1354
1355 return true; // selection success
1356 }
1357 }
1358
1359 return false; //.selection failed
1360 }
1361
1362 void DimRegionChooser::select_next_dimzone(bool add) {
1363 select_dimzone_by_dir(+1, add);
1364 }
1365
1366 void DimRegionChooser::select_prev_dimzone(bool add) {
1367 select_dimzone_by_dir(-1, add);
1368 }
1369
1370 void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1371 if (!region) return;
1372 if (!region->Dimensions) return;
1373 if (focus_line < 0) focus_line = 0;
1374 if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1375
1376 maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1377 if (maindimtype == gig::dimension_none) {
1378 printf("maindimtype -> none\n");
1379 return;
1380 }
1381
1382 if (maindimcase.empty()) {
1383 maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1384 if (maindimcase.empty()) {
1385 printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1386 return;
1387 }
1388 }
1389
1390 int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1391 if (z < 0) z = 0;
1392 if (z >= region->pDimensionDefinitions[focus_line].zones)
1393 z = region->pDimensionDefinitions[focus_line].zones - 1;
1394
1395 maindimcase[maindimtype] = z;
1396
1397 ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1398 if (!dr) {
1399 printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1400 return;
1401 }
1402
1403 maindimregno = getDimensionRegionIndex(dr);
1404
1405 if (!add) {
1406 // reset selected dimregion zones
1407 dimzones.clear();
1408 }
1409 for (DimensionCase::const_iterator it = maindimcase.begin();
1410 it != maindimcase.end(); ++it)
1411 {
1412 dimzones[it->first].insert(it->second);
1413 }
1414
1415 dimregion_selected();
1416
1417 // disabled: would overwrite dimregno with wrong value
1418 //refresh_all();
1419 // so requesting just a raw repaint instead:
1420 queue_draw();
1421 }
1422
1423 void DimRegionChooser::select_next_dimension() {
1424 if (!region) return;
1425 focus_line++;
1426 if (focus_line >= region->Dimensions)
1427 focus_line = region->Dimensions - 1;
1428 this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1429 queue_draw();
1430 }
1431
1432 void DimRegionChooser::select_prev_dimension() {
1433 if (!region) return;
1434 focus_line--;
1435 if (focus_line < 0)
1436 focus_line = 0;
1437 this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1438 queue_draw();
1439 }
1440
1441 gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1442 if (!region) return NULL;
1443 return region->pDimensionRegions[maindimregno];
1444 }

  ViewVC Help
Powered by ViewVC