/[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 3364 - (hide annotations) (download)
Tue Nov 14 18:07:25 2017 UTC (6 years, 5 months ago) by schoenebeck
File size: 70291 byte(s)
* Added experimental support for upcoming GTK(MM)4
  (for now up to GTKMM 3.91.2 while still preserving backward compatibility
  down to GTKMM 2).
* Re-merged r2845 to compile now with and without Gtk "Stock ID" API
  (see also r3158).

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

  ViewVC Help
Powered by ViewVC