/[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 3158 - (show annotations) (download)
Mon May 8 18:05:35 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 61774 byte(s)
* Reverted major parts of r2845 concerning deprected Gtk StockIDs
  (StockIDs still available with Gtk 3, no replacement API available,
  and these changes caused useful icons to vanish with Gtk 2).
* Bumped version (1.0.0.svn39).

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

  ViewVC Help
Powered by ViewVC