/[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 3123 - (show annotations) (download)
Tue Apr 25 20:45:54 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 55472 byte(s)
* Implemented fast navigation through regions by keyboard accelerator
  Ctrl+Left and Ctrl+Right (on Mac: Cmd+Left and Cmd+Right).
* Implemented fast navigation through dimension region zones of currently
  selected region by keyboard accelerator Alt+Left, Alt+Right, Alt+Up,
  Alt+Down, as well as simply using the arrow keys alone if the dimension
  region chooser got focus (i.e. when it was selected by mouse previously).
* Bumped version (1.0.0.svn29).

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

  ViewVC Help
Powered by ViewVC