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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3703 - (hide annotations) (download)
Wed Jan 8 15:49:24 2020 UTC (4 years, 3 months ago) by schoenebeck
File size: 71083 byte(s)
* Fix: dimregion edit actions were ignored if user did not click (ever) on
  any dimension zone yet.

* Bumped version (1.1.1.svn10).

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

  ViewVC Help
Powered by ViewVC