/[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 3132 - (show annotations) (download)
Thu Apr 27 17:31:50 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 59368 byte(s)
- Fixed compile error.

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

  ViewVC Help
Powered by ViewVC