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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2462 by schoenebeck, Wed Sep 4 20:23:05 2013 UTC revision 3460 by persson, Sat Feb 2 07:48:50 2019 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2011 Andreas Persson   * Copyright (C) 2006-2019 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include "global.h"
21    #include "compat.h"
22    #include "Settings.h"
23    #include <gtkmm/box.h>
24  #include "dimregionchooser.h"  #include "dimregionchooser.h"
25  #include <cairomm/context.h>  #include <cairomm/context.h>
26    #include <cairomm/surface.h>
27  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
28  #include <gdkmm/general.h>  #include <gdkmm/general.h>
29    #if HAS_GDKMM_SEAT
30    # include <gdkmm/seat.h>
31    #endif
32    #include <glibmm/stringutils.h>
33    #if HAS_GTKMM_STOCK
34    # include <gtkmm/stock.h>
35    #endif
36    #include <glibmm/ustring.h>
37    #include <gtkmm/messagedialog.h>
38    #include <assert.h>
39    
40    #include "gfx/builtinpix.h"
41    
42    //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        if (!dr) {
46            *isValidZone = false;
47            return dimCase;
48        }
49    
50  #include "global.h"      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            return DimensionCase();
63        }
64    
65  DimRegionChooser::DimRegionChooser() :      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
66      red("#8070ff"),          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                return DimensionCase();
74            }
75        }
76    
77        *isValidZone = true;
78        return dimCase;
79    }
80    
81    DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
82        red("#ff476e"),
83        blue("#4796ff"),
84      black("black"),      black("black"),
85      white("white")      white("white")
86  {  {
87        // make sure blue hatched pattern pixmap is loaded
88        loadBuiltInPix();
89    
90        // create blue hatched pattern 1
91        {
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    #if HAS_CAIROMM_CPP11_ENUMS
115                this->blueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
116    #else
117                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
118    #endif
119            );
120            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
121    #if HAS_CAIROMM_CPP11_ENUMS
122            this->blueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
123    #else
124            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
125    #endif
126        }
127    
128        // 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    #if HAS_CAIROMM_CPP11_ENUMS
153                this->blueHatchedPattern2ARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
154    #else
155                this->blueHatchedPattern2ARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
156    #endif
157            );
158            this->blueHatchedSurfacePattern2 = Cairo::SurfacePattern::create(imageSurface);
159    #if HAS_CAIROMM_CPP11_ENUMS
160            this->blueHatchedSurfacePattern2->set_extend(Cairo::Pattern::Extend::REPEAT);
161    #else
162            this->blueHatchedSurfacePattern2->set_extend(Cairo::EXTEND_REPEAT);
163    #endif
164        }
165    
166        // 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    #if HAS_CAIROMM_CPP11_ENUMS
191                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
192    #else
193                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
194    #endif
195            );
196            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
197    #if HAS_CAIROMM_CPP11_ENUMS
198            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
199    #else
200            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
201    #endif
202        }
203    
204      instrument = 0;      instrument = 0;
205      region = 0;      region = 0;
206      dimregno = -1;      maindimregno = -1;
207        maindimtype = gig::dimension_none; // initialize with invalid dimension type
208      focus_line = 0;      focus_line = 0;
209      resize.active = false;      resize.active = false;
210      cursor_is_resize = false;      cursor_is_resize = false;
211      h = 20;      h = 24;
212        multiSelectKeyDown = false;
213        primaryKeyDown = false;
214        shiftKeyDown = false;
215        modifybothchannels = modifyalldimregs = modifybothchannels = false;
216      set_can_focus();      set_can_focus();
217    
218        const Glib::ustring txtUseCheckBoxAllRegions =
219            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
220    
221        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        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
233        actionGroup->add(
234            actionSplitDimZone,
235            sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
236        );
237        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
238        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
239        actionGroup->add(
240            actionDeleteDimZone,
241            sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
242        );
243    #endif
244    
245    #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        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    #endif // USE_GTKMM_BUILDER
290    
291    
292    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 24)
293    # warning GTKMM4 event registration code missing for dimregionchooser!
294        //add_events(Gdk::EventMask::BUTTON_PRESS_MASK);
295    #else
296      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
297                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
298    #endif
299    
     for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;  
300      labels_changed = true;      labels_changed = true;
301    
302        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    
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        
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  }  }
319    
320  DimRegionChooser::~DimRegionChooser()  DimRegionChooser::~DimRegionChooser()
321  {  {
322  }  }
323    
324    void DimRegionChooser::on_show_tooltips_changed() {
325        const bool b = Settings::singleton()->showTooltips;
326    
327        set_has_tooltip(b);
328    }
329    
330    void DimRegionChooser::setModifyBothChannels(bool b) {
331        modifybothchannels = b;
332        // redraw required parts
333        queue_draw();
334    }
335    
336    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
337        modifyalldimregs = b;
338        // redraw required parts
339        queue_draw();
340    }
341    
342    void DimRegionChooser::setModifyAllRegions(bool b) {
343        modifyallregions = b;
344    
345    #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        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    #endif
358    
359        // redraw required parts
360        queue_draw();
361    }
362    
363    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            dimensionRegionsMatching(dimCase, region, true);
373    
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  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
423  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
424  {  {
# Line 58  bool DimRegionChooser::on_expose_event(G Line 429  bool DimRegionChooser::on_expose_event(G
429    
430      const Cairo::RefPtr<Cairo::Context>& cr =      const Cairo::RefPtr<Cairo::Context>& cr =
431          get_window()->create_cairo_context();          get_window()->create_cairo_context();
 #if 0  
 }  
 #endif  
432  #else  #else
433  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
434  {  {
# Line 139  bool DimRegionChooser::on_draw(const Cai Line 507  bool DimRegionChooser::on_draw(const Cai
507                      dstr = dstrbuf;                      dstr = dstrbuf;
508                      break;                      break;
509                  }                  }
                 layout->set_text(dstr);  
510    
511                    // 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                  Pango::Rectangle rectangle = layout->get_logical_extents();                  Pango::Rectangle rectangle = layout->get_logical_extents();
516                    // ... 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                  double text_w = double(rectangle.get_width()) / Pango::SCALE;                  double text_w = double(rectangle.get_width()) / Pango::SCALE;
524                  if (text_w > maxwidth) maxwidth = text_w;                  if (text_w > maxwidth) maxwidth = text_w;
525    
# Line 152  bool DimRegionChooser::on_draw(const Cai Line 530  bool DimRegionChooser::on_draw(const Cai
530                      const Gdk::Color fg = get_style()->get_fg(get_state());                      const Gdk::Color fg = get_style()->get_fg(get_state());
531  #else  #else
532                      const Gdk::RGBA fg =                      const Gdk::RGBA fg =
533    # if GTKMM_MAJOR_VERSION >= 3
534                            get_style_context()->get_color();
535    # else
536                          get_style_context()->get_color(get_state_flags());                          get_style_context()->get_color(get_state_flags());
537    # endif
538  #endif  #endif
539                      Gdk::Cairo::set_source_rgba(cr, fg);                      Gdk::Cairo::set_source_rgba(cr, fg);
540                      cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));                      cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
# Line 176  bool DimRegionChooser::on_draw(const Cai Line 558  bool DimRegionChooser::on_draw(const Cai
558      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
559          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
560          if (nbZones) {          if (nbZones) {
561                const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
562    
563              if (y >= clipy2) break;              if (y >= clipy2) break;
564              if (y + h > clipy1) {              if (y + h > clipy1) {
565                  // draw focus rectangle around dimension's label and zones                  // draw focus rectangle around dimension's label and zones
566                  if (has_focus() && focus_line == i) {                  if (has_focus() && focus_line == i) {
567  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
568                      Gdk::Rectangle farea(0, y, 150, 20);                      Gdk::Rectangle farea(0, y, 150, h);
569                      get_style()->paint_focus(get_window(), get_state(), farea,                      get_style()->paint_focus(get_window(), get_state(), farea,
570                                               *this, "",                                               *this, "",
571                                               0, y, label_width, 20);                                               0, y, label_width, h);
572  #else  #else
573                      get_style_context()->render_focus(cr,                      get_style_context()->render_focus(cr,
574                                                        0, y, label_width, 20);                                                        0, y, label_width, h);
575  #endif  #endif
576                  }                  }
577    
# Line 206  bool DimRegionChooser::on_draw(const Cai Line 590  bool DimRegionChooser::on_draw(const Cai
590                  cr->fill();                  cr->fill();
591    
592                  int c = 0;                  int c = 0;
593                  if (dimregno >= 0) {                  if (maindimregno >= 0) {
594                      int mask =                      int mask =
595                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
596                            bitpos);                            bitpos);
597                      c = dimregno & mask; // mask away this dimension                      c = maindimregno & mask; // mask away this dimension
598                  }                  }
599                  bool customsplits =                  bool customsplits =
600                      ((region->pDimensionDefinitions[i].split_type ==                      ((region->pDimensionDefinitions[i].split_type ==
# Line 220  bool DimRegionChooser::on_draw(const Cai Line 604  bool DimRegionChooser::on_draw(const Cai
604                        gig::dimension_velocity &&                        gig::dimension_velocity &&
605                        region->pDimensionRegions[c]->VelocityUpperLimit));                        region->pDimensionRegions[c]->VelocityUpperLimit));
606    
607                  // draw dimension's zone borders                  // draw dimension zones
608                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
609                  if (customsplits) {                  if (customsplits) {
610                      cr->move_to(label_width + 0.5, y + 1);                      cr->move_to(label_width + 0.5, y + 1);
611                      cr->line_to(label_width + 0.5, y + h - 1);                      cr->line_to(label_width + 0.5, y + h - 1);
612                        int prevX = label_width;
613                        int prevUpperLimit = -1;
614    
615                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
616                            // draw dimension zone's borders for custom splits
617                          gig::DimensionRegion* d =                          gig::DimensionRegion* d =
618                              region->pDimensionRegions[c + (j << bitpos)];                              region->pDimensionRegions[c + (j << bitpos)];
619                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
# Line 236  bool DimRegionChooser::on_draw(const Cai Line 623  bool DimRegionChooser::on_draw(const Cai
623                              label_width;                              label_width;
624                          if (x >= clipx2) break;                          if (x >= clipx2) break;
625                          if (x < clipx1) continue;                          if (x < clipx1) continue;
626                            Gdk::Cairo::set_source_rgba(cr, black);
627                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
628                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
629                            cr->stroke();
630    
631                            // draw fill for zone
632                            bool isSelectedZone = this->dimzones[dimension].count(j);
633                            bool isMainSelection =
634                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
635                                this->maindimcase[dimension] == j;
636                            bool isCheckBoxSelected =
637                                modifyalldimregs ||
638                                (modifybothchannels &&
639                                    dimension == gig::dimension_samplechannel);
640                            if (isMainSelection)
641                                Gdk::Cairo::set_source_rgba(cr, blue);
642                            else if (isSelectedZone)
643                                cr->set_source(blueHatchedSurfacePattern2);
644                            else if (isCheckBoxSelected)
645                                cr->set_source(blueHatchedSurfacePattern);
646                            else
647                                Gdk::Cairo::set_source_rgba(cr, white);
648    
649                            const int wZone = x - prevX - 1;
650    
651                            cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
652                            cr->fill();
653    
654                            // draw icons
655                            drawIconsFor(dimension, j, cr, prevX, y, wZone, h);
656    
657                            // 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                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
662                                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                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
668    #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                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
685    #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                      }                      }
695                  } else {                  } else {
696                        int prevX = 0;
697                      for (int j = 0 ; j <= nbZones ; j++) {                      for (int j = 0 ; j <= nbZones ; j++) {
698                            // draw dimension zone's borders for normal splits
699                          int x = int((w - label_width - 1) * j /                          int x = int((w - label_width - 1) * j /
700                                      double(nbZones) + 0.5) + label_width;                                      double(nbZones) + 0.5) + label_width;
701                          if (x >= clipx2) break;                          if (x >= clipx2) break;
702                          if (x < clipx1) continue;                          if (x < clipx1) continue;
703                            Gdk::Cairo::set_source_rgba(cr, black);
704                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
705                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
706                      }                          cr->stroke();
                 }  
                 cr->stroke();  
707    
708                  // draw fill for currently selected zone                          if (j != 0) {
709                  if (dimregno >= 0) {                              const int wZone = x - prevX - 1;
710                      Gdk::Cairo::set_source_rgba(cr, red);  
711                      int dr = (dimregno >> bitpos) &                              // draw fill for zone
712                          ((1 << region->pDimensionDefinitions[i].bits) - 1);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
713                                                    bool isMainSelection =
714                      int x1 = -1, x2 = -1;                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
715                      if (customsplits) {                                  this->maindimcase[dimension] == (j-1);
716                          x1 = label_width;                              bool isCheckBoxSelected =
717                          for (int j = 0 ; j < nbZones && x1 + 1 < clipx2 ; j++) {                                  modifyalldimregs ||
718                              gig::DimensionRegion* d =                                  (modifybothchannels &&
719                                  region->pDimensionRegions[c + (j << bitpos)];                                      dimension == gig::dimension_samplechannel);
720                              int upperLimit = d->DimensionUpperLimits[i];                              if (isMainSelection)
721                              if (!upperLimit) {                                  Gdk::Cairo::set_source_rgba(cr, blue);
722                                  upperLimit = d->VelocityUpperLimit;                              else if (isSelectedZone)
723                              }                                  cr->set_source(blueHatchedSurfacePattern2);
724                              int v = upperLimit + 1;                              else if (isCheckBoxSelected)
725                              x2 = int((w - label_width - 1) * v / 128.0 +                                  cr->set_source(blueHatchedSurfacePattern);
726                                       0.5) + label_width;                              else
727                              if (j == dr && x1 < x2) {                                  Gdk::Cairo::set_source_rgba(cr, white);
728                                  cr->rectangle(x1 + 1, y + 1,                              cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
                                               (x2 - x1) - 1, h - 2);  
                                 cr->fill();  
                                 break;  
                             }  
                             x1 = x2;  
                         }  
                     } else {  
                         if (dr < nbZones) {  
                             x1 = int((w - label_width - 1) * dr /  
                                      double(nbZones) + 0.5);  
                             x2 = int((w - label_width - 1) * (dr + 1) /  
                                      double(nbZones) + 0.5);  
                             cr->rectangle(label_width + x1 + 1, y + 1,  
                                           (x2 - x1) - 1, h - 2);  
729                              cr->fill();                              cr->fill();
                         }  
                     }  
730    
731                      // draw text showing the beginning of the dimension zone                              // draw icons
732                      // as numeric value to the user                              drawIconsFor(dimension, j - 1, cr, prevX, y, wZone, h);
733                      if (x1 >= 0) {  
734                          Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                              // draw text showing the beginning of the dimension zone
735                          int v = roundf(float(x1 - label_width) / float(w - label_width) * 127.f);                              // as numeric value to the user
736                          if (dr > 0) v++;                              {
737                          layout->set_text(Glib::Ascii::dtostr(v));                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
738                          Gdk::Cairo::set_source_rgba(cr, black);                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
739                          Pango::Rectangle rect = layout->get_logical_extents();                                  Gdk::Cairo::set_source_rgba(cr, black);
740                                                            // get the text dimensions
741                          int text_width, text_height;                                  int text_width, text_height;
742                          // get the text dimensions                                  layout->get_pixel_size(text_width, text_height);
743                          layout->get_pixel_size(text_width, text_height);                                  // move text to the left end of the dimension zone
744                          // move text to the right end of the dimension zone                                  cr->move_to(prevX + 3, y + (h - text_height) / 2);
                         cr->move_to(x1 + 1, y + 1);  
745  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
746                          pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
747  #else  #else
748                          layout->show_in_cairo_context(cr);                                  layout->show_in_cairo_context(cr);
749  #endif  #endif
750                      }                              }
751                      // draw text showing the end of the dimension zone                              // draw text showing the end of the dimension zone
752                      // as numeric value to the user                              // as numeric value to the user
753                      if (x2 >= 0) {                              {
754                          Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
755                          const int v = roundf(float(x2 - label_width) / float(w - label_width) * 127.f);                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
756                          layout->set_text(Glib::Ascii::dtostr(v));                                  Gdk::Cairo::set_source_rgba(cr, black);
757                          Gdk::Cairo::set_source_rgba(cr, black);                                  // get the text dimensions
758                          Pango::Rectangle rect = layout->get_logical_extents();                                  int text_width, text_height;
759                                                            layout->get_pixel_size(text_width, text_height);
760                          int text_width, text_height;                                  // move text to the left end of the dimension zone
761                          // get the text dimensions                                  cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
                         layout->get_pixel_size(text_width, text_height);  
                         // move text to the right end of the dimension zone  
                         cr->move_to(x2 - text_width - 1, y + 1);  
762  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
763                          pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
764  #else  #else
765                          layout->show_in_cairo_context(cr);                                  layout->show_in_cairo_context(cr);
766  #endif  #endif
767                      }                              }
768                            }
769                            prevX = x;
770                        }      
771                  }                  }
772              }              }
   
773              y += h;              y += h;
774          }          }
775          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 345  bool DimRegionChooser::on_draw(const Cai Line 781  bool DimRegionChooser::on_draw(const Cai
781  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
782  {  {
783      this->region = region;      this->region = region;
784      dimregno = 0;      maindimregno = 0;
785      nbDimensions = 0;      nbDimensions = 0;
786      if (region) {      if (region) {
787          int bitcount = 0;          int bitcount = 0;
# Line 353  void DimRegionChooser::set_region(gig::R Line 789  void DimRegionChooser::set_region(gig::R
789              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
790              nbDimensions++;              nbDimensions++;
791    
792              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
793                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
794              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
795              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
796          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
797      }      }
798      dimregion_selected();      dimregion_selected();
799      set_size_request(800, region ? nbDimensions * 20 : 0);      set_size_request(800, region ? nbDimensions * h : 0);
800    
801      labels_changed = true;      labels_changed = true;
802      queue_resize();      queue_resize();
803        queue_draw();
804  }  }
805    
806    void DimRegionChooser::refresh_all() {
807        set_region(region);
808    }
809    
810  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
811                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
812  {  {
813      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
814      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
815      int stereo_bit = 0;          if (!dimRgn) continue;
816      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
817          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
818          if (stereo &&          if (!isValidZone) continue;
819              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
820              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
821          } else {          {
822              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
823                               region->pDimensionDefinitions[dim].zones - 1);  
824              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
825                    this->dimzones.find(it->first);
826                if (itSelectedDimension != this->dimzones.end() &&
827                    itSelectedDimension->second.count(it->second)) continue; // is selected
828    
829                goto notSelected;
830          }          }
831          bitcount += region->pDimensionDefinitions[dim].bits;  
832            dimregs.insert(dimRgn);
833    
834            notSelected:
835            ;
836      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
837  }  }
838    
839  void DimRegionChooser::update_after_resize()  void DimRegionChooser::update_after_resize()
840  {  {
841      if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const uint8_t upperLimit = resize.pos - 1;
842        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
843    
844          int bitpos = 0;      int bitpos = 0;
845          for (int j = 0 ; j < resize.dimension ; j++) {      for (int j = 0 ; j < resize.dimension ; j++) {
846              bitpos += region->pDimensionDefinitions[j].bits;          bitpos += region->pDimensionDefinitions[j].bits;
847          }      }
848    
849        const int stereobitpos =
850            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
851    
852        // the velocity dimension must be handled differently than all other
853        // dimension types, because
854        // 1. it is currently the only dimension type which allows different zone
855        //    sizes for different cases
856        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
857        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
858          int mask =          int mask =
859              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
860          int c = dimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
861    
862          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
863              // the velocity dimension didn't previously have              // the velocity dimension didn't previously have
# Line 425  void DimRegionChooser::update_after_resi Line 880  void DimRegionChooser::update_after_resi
880              }              }
881          }          }
882    
883          gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];          int index = c + (resize.zone << bitpos);
884            gig::DimensionRegion* d = region->pDimensionRegions[index];
885          // update both v2 and v3 values          // update both v2 and v3 values
886          d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;          d->DimensionUpperLimits[resize.dimension] = upperLimit;
887          d->VelocityUpperLimit = resize.pos - 1;          d->VelocityUpperLimit = upperLimit;
888            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
889                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
890                d->DimensionUpperLimits[resize.dimension] = upperLimit;
891                d->VelocityUpperLimit = upperLimit;
892            }
893    
894            if (modifyalldimregs) {
895                gig::Region* rgn = NULL;
896                for (int key = 0; key < 128; ++key) {
897                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
898                    rgn = instr->GetRegion(key);
899                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
900                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
901                    if (!dimdef) continue;
902                    if (dimdef->zones != resize.dimensionDef.zones) continue;
903                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
904                    assert(iDim >= 0 && iDim < rgn->Dimensions);
905    
906                    // the dimension layout might be completely different in this
907                    // region, so we have to recalculate bitpos etc for this region
908                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
909                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
910                    const int selection = resize.zone << bitpos;
911    
912                    // primitive and inefficient loop implementation, however due to
913                    // this circumstance the loop code is much simpler, and its lack
914                    // of runtime efficiency should not be notable in practice
915                    for (int idr = 0; idr < 256; ++idr) {
916                        const int index = (idr & stencil) | selection;
917                        assert(index >= 0 && index < 256);
918                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
919                        if (!dr) continue;
920                        dr->DimensionUpperLimits[iDim] = upperLimit;
921                        d->VelocityUpperLimit = upperLimit;
922                    }
923                }
924            } else if (modifyallregions) { // implies modifyalldimregs is false ...
925                // resolve the precise case we need to modify for all other regions
926                DimensionCase dimCase = dimensionCaseOf(d);
927                // apply the velocity upper limit change to that resolved dim case
928                // of all regions ...
929                gig::Region* rgn = NULL;
930                for (int key = 0; key < 128; ++key) {
931                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
932                    rgn = instr->GetRegion(key);
933                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
934                    if (!dimdef) continue;
935                    if (dimdef->zones != resize.dimensionDef.zones) continue;
936                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
937                    assert(iDim >= 0 && iDim < rgn->Dimensions);
938    
939                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
940                    for (int i = 0; i < dimrgns.size(); ++i) {
941                        gig::DimensionRegion* dr = dimrgns[i];
942                        dr->DimensionUpperLimits[iDim] = upperLimit;
943                        dr->VelocityUpperLimit = upperLimit;
944                    }
945                }
946            }
947      } else {      } else {
948          for (int i = 0 ; i < region->DimensionRegions ; ) {          for (int i = 0 ; i < region->DimensionRegions ; ) {
   
949              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
950                  // the dimension didn't previously have custom                  // the dimension didn't previously have custom
951                  // limits, so we have to set default limits for                  // limits, so we have to set default limits for
952                  // all the dimension regions                  // all the dimension regions
                 int bitpos = 0;  
                 for (int j = 0 ; j < resize.dimension ; j++) {  
                     bitpos += region->pDimensionDefinitions[j].bits;  
                 }  
953                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
954    
955                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
# Line 448  void DimRegionChooser::update_after_resi Line 957  void DimRegionChooser::update_after_resi
957                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
958                  }                  }
959              }              }
960              gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];              int index = i + (resize.zone << bitpos);
961              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              gig::DimensionRegion* d = region->pDimensionRegions[index];
962                d->DimensionUpperLimits[resize.dimension] = upperLimit;
963    #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
964                if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
965                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
966                    d->DimensionUpperLimits[resize.dimension] = upperLimit;
967                }
968    #endif
969              int bitpos = 0;              int bitpos = 0;
970              int j;              int j;
971              for (j = 0 ; j < region->Dimensions ; j++) {              for (j = 0 ; j < region->Dimensions ; j++) {
# Line 464  void DimRegionChooser::update_after_resi Line 979  void DimRegionChooser::update_after_resi
979              if (j == region->Dimensions) break;              if (j == region->Dimensions) break;
980              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
981          }          }
982    
983            if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
984                gig::Region* rgn = NULL;
985                for (int key = 0; key < 128; ++key) {
986                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
987                    rgn = instr->GetRegion(key);
988                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
989                    if (!dimdef) continue;
990                    if (dimdef->zones != resize.dimensionDef.zones) continue;
991                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
992                    assert(iDim >= 0 && iDim < rgn->Dimensions);
993    
994                    // the dimension layout might be completely different in this
995                    // region, so we have to recalculate bitpos etc for this region
996                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
997                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
998                    const int selection = resize.zone << bitpos;
999    
1000                    // this loop implementation is less efficient than the above's
1001                    // loop implementation (which skips unnecessary dimension regions)
1002                    // however this code is much simpler, and its lack of runtime
1003                    // efficiency should not be notable in practice
1004                    for (int idr = 0; idr < 256; ++idr) {
1005                        const int index = (idr & stencil) | selection;
1006                        assert(index >= 0 && index < 256);
1007                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
1008                        if (!dr) continue;
1009                        dr->DimensionUpperLimits[iDim] = upperLimit;
1010                    }
1011                }
1012            }
1013      }      }
1014  }  }
1015    
# Line 473  bool DimRegionChooser::on_button_release Line 1019  bool DimRegionChooser::on_button_release
1019  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1020          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
1021  #else  #else
1022    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1023          Glib::wrap(event->device, true)->ungrab(event->time);          Glib::wrap(event->device, true)->ungrab(event->time);
1024    # else
1025            Glib::wrap(event->device, true)->get_seat()->ungrab();
1026    # endif
1027  #endif  #endif
1028          resize.active = false;          resize.active = false;
1029    
# Line 502  bool DimRegionChooser::on_button_press_e Line 1052  bool DimRegionChooser::on_button_press_e
1052                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
1053                                         event->time);                                         event->time);
1054  #else  #else
1055    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1056              Glib::wrap(event->device, true)->grab(get_window(),              Glib::wrap(event->device, true)->grab(get_window(),
1057                                                    Gdk::OWNERSHIP_NONE,                                                    Gdk::OWNERSHIP_NONE,
1058                                                    false,                                                    false,
# Line 510  bool DimRegionChooser::on_button_press_e Line 1061  bool DimRegionChooser::on_button_press_e
1061                                                    Gdk::POINTER_MOTION_HINT_MASK,                                                    Gdk::POINTER_MOTION_HINT_MASK,
1062                                                    Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),                                                    Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
1063                                                    event->time);                                                    event->time);
1064    # else
1065                Glib::wrap(event->device, true)->get_seat()->grab(
1066                    get_window(),
1067                    Gdk::SeatCapabilities::SEAT_CAPABILITY_ALL_POINTING,
1068                    false,
1069                    Gdk::Cursor::create(
1070                        Glib::wrap(event->device, true)->get_seat()->get_display(),
1071                        Gdk::SB_H_DOUBLE_ARROW
1072                    ),
1073                    reinterpret_cast<GdkEvent*>(event)
1074                );
1075    # endif
1076  #endif  #endif
1077              resize.active = true;              resize.active = true;
1078          } else {          } else {
# Line 529  bool DimRegionChooser::on_button_press_e Line 1092  bool DimRegionChooser::on_button_press_e
1092              }              }
1093    
1094              int i = dim;              int i = dim;
1095              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
1096              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
1097              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
1098    
1099              bool customsplits =              bool customsplits =
1100                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 561  bool DimRegionChooser::on_button_press_e Line 1124  bool DimRegionChooser::on_button_press_e
1124                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
1125                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
1126                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
1127              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
1128                this->maindimregno = c | (z << bitpos);
1129              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
1130    
1131                if (multiSelectKeyDown) {
1132                    if (dimzones[this->maindimtype].count(z)) {
1133                        if (dimzones[this->maindimtype].size() > 1) {
1134                            dimzones[this->maindimtype].erase(z);
1135                        }
1136                    } else {
1137                        dimzones[this->maindimtype].insert(z);
1138                    }
1139                } else {
1140                    this->dimzones.clear();
1141                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1142                         it != this->maindimcase.end(); ++it)
1143                    {
1144                        this->dimzones[it->first].insert(it->second);
1145                    }
1146                }
1147    
1148              focus_line = dim;              focus_line = dim;
1149              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
1150              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
1151              dimregion_selected();              dimregion_selected();
1152    
1153                if (event->button == 3) {
1154                    printf("dimregion right click\n");
1155                    popup_menu_inside_dimregion->popup(event->button, event->time);
1156                }
1157    
1158                queue_draw();
1159          }          }
1160      }      }
1161      return true;      return true;
# Line 579  bool DimRegionChooser::on_motion_notify_ Line 1165  bool DimRegionChooser::on_motion_notify_
1165  {  {
1166      Glib::RefPtr<Gdk::Window> window = get_window();      Glib::RefPtr<Gdk::Window> window = get_window();
1167      int x, y;      int x, y;
1168    #if HAS_GDKMM_SEAT
1169        x = event->x;
1170        y = event->y;
1171        Gdk::ModifierType state = Gdk::ModifierType(event->state);
1172    #else
1173      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
1174      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
1175    #endif
1176    
1177      if (resize.active) {      if (resize.active) {
1178          int w = get_width();          int w = get_width();
# Line 607  bool DimRegionChooser::on_motion_notify_ Line 1199  bool DimRegionChooser::on_motion_notify_
1199    
1200              resize.pos = k;              resize.pos = k;
1201              update_after_resize();              update_after_resize();
1202              get_window()->invalidate_rect(rect, false);              get_window()->invalidate_rect(rect, false); // not sufficient ...
1203                queue_draw(); // ... so do a complete redraw instead.
1204          }          }
1205      } else {      } else {
1206          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
# Line 615  bool DimRegionChooser::on_motion_notify_ Line 1208  bool DimRegionChooser::on_motion_notify_
1208  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1209                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1210  #else  #else
1211                  window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(
1212    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1213                        Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1214    # else
1215                        Gdk::Cursor::create(
1216                            Glib::wrap(event->device, true)->get_seat()->get_display(),
1217                            Gdk::SB_H_DOUBLE_ARROW
1218                        )
1219    # endif
1220                    );
1221  #endif  #endif
1222                  cursor_is_resize = true;                  cursor_is_resize = true;
1223              }              }
# Line 643  bool DimRegionChooser::is_in_resize_zone Line 1245  bool DimRegionChooser::is_in_resize_zone
1245          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
1246    
1247          int c = 0;          int c = 0;
1248          if (dimregno >= 0) {          if (maindimregno >= 0) {
1249              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1250              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
1251          }          }
1252          const bool customsplits =          const bool customsplits =
1253              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 668  bool DimRegionChooser::is_in_resize_zone Line 1270  bool DimRegionChooser::is_in_resize_zone
1270                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1271                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1272                      resize.dimension = dim;                      resize.dimension = dim;
1273                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1274                        resize.zone = iZone;
1275                      resize.pos = limit;                      resize.pos = limit;
1276                      resize.min = prev_limit;                      resize.min = prev_limit;
1277    
1278                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
1279                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1280                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1281                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
# Line 709  sigc::signal<void>& DimRegionChooser::si Line 1312  sigc::signal<void>& DimRegionChooser::si
1312    
1313  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1314  {  {
1315      // TODO: kolla att region finns osv, dvs att det går att sätta      // TODO: check that region exists etc, that is, that it's possible
1316      // fokus.      // to set focus
1317      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1318          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1319          if (!has_focus()) {          if (!has_focus()) {
# Line 742  bool DimRegionChooser::on_focus(Gtk::Dir Line 1345  bool DimRegionChooser::on_focus(Gtk::Dir
1345              }              }
1346          }          }
1347      } else if (!has_focus()) {      } else if (!has_focus()) {
1348          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1349          grab_focus();          grab_focus();
1350          return true;          return true;
1351      } else {      } else {
1352          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1353        }
1354        return false;
1355    }
1356    
1357    void DimRegionChooser::split_dimension_zone() {    
1358        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1359        try {
1360            if (!modifyallregions) {
1361                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1362            } else {
1363                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1364                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1365                assert(pMaindimdef != NULL);
1366                // retain structure by value since the original region will be
1367                // modified in the loop below as well
1368                gig::dimension_def_t maindimdef = *pMaindimdef;
1369                std::vector<gig::Region*> ignoredAll;
1370                std::vector<gig::Region*> ignoredMinor;
1371                std::vector<gig::Region*> ignoredCritical;
1372                gig::Region* rgn = NULL;
1373                for (int key = 0; key < 128; ++key) {
1374                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1375                    rgn = instr->GetRegion(key);
1376    
1377                    // ignore all regions which do not exactly match the dimension
1378                    // layout of the selected region where this operation was emitted
1379                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1380                    if (!dimdef) {
1381                        ignoredAll.push_back(rgn);
1382                        ignoredMinor.push_back(rgn);
1383                        continue;
1384                    }
1385                    if (dimdef->zones != maindimdef.zones) {
1386                        ignoredAll.push_back(rgn);
1387                        ignoredCritical.push_back(rgn);
1388                        continue;
1389                    }
1390    
1391                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1392                }
1393                if (!ignoredAll.empty()) {
1394                    Glib::ustring txt;
1395                    if (ignoredCritical.empty())
1396                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1397                    else if (ignoredMinor.empty())
1398                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1399                    else
1400                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1401                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1402                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1403                    Gtk::MessageDialog msg(txt, false, type);
1404                    msg.run();
1405                }
1406            }
1407        } catch (RIFF::Exception e) {
1408            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1409            msg.run();
1410        } catch (...) {
1411            Glib::ustring txt = _("An unknown exception occurred!");
1412            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1413            msg.run();
1414      }      }
1415        refresh_all();
1416    }
1417    
1418    void DimRegionChooser::delete_dimension_zone() {
1419        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1420        try {
1421            if (!modifyallregions) {
1422                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1423            } else {
1424                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1425                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1426                assert(pMaindimdef != NULL);
1427                // retain structure by value since the original region will be
1428                // modified in the loop below as well
1429                gig::dimension_def_t maindimdef = *pMaindimdef;
1430                std::vector<gig::Region*> ignoredAll;
1431                std::vector<gig::Region*> ignoredMinor;
1432                std::vector<gig::Region*> ignoredCritical;
1433                gig::Region* rgn = NULL;
1434                for (int key = 0; key < 128; ++key) {
1435                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1436                    rgn = instr->GetRegion(key);
1437    
1438                    // ignore all regions which do not exactly match the dimension
1439                    // layout of the selected region where this operation was emitted
1440                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1441                    if (!dimdef) {
1442                        ignoredAll.push_back(rgn);
1443                        ignoredMinor.push_back(rgn);
1444                        continue;
1445                    }
1446                    if (dimdef->zones != maindimdef.zones) {
1447                        ignoredAll.push_back(rgn);
1448                        ignoredCritical.push_back(rgn);
1449                        continue;
1450                    }
1451    
1452                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1453                }
1454                if (!ignoredAll.empty()) {
1455                    Glib::ustring txt;
1456                    if (ignoredCritical.empty())
1457                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1458                    else if (ignoredMinor.empty())
1459                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1460                    else
1461                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1462                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1463                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1464                    Gtk::MessageDialog msg(txt, false, type);
1465                    msg.run();
1466                }
1467            }
1468        } catch (RIFF::Exception e) {
1469            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1470            msg.run();
1471        } catch (...) {
1472            Glib::ustring txt = _("An unknown exception occurred!");
1473            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1474            msg.run();
1475        }
1476        refresh_all();
1477    }
1478    
1479    // Cmd key on Mac, Ctrl key on all other OSs
1480    static const guint primaryKeyL =
1481        #if defined(__APPLE__)
1482        GDK_KEY_Meta_L;
1483        #else
1484        GDK_KEY_Control_L;
1485        #endif
1486    
1487    static const guint primaryKeyR =
1488        #if defined(__APPLE__)
1489        GDK_KEY_Meta_R;
1490        #else
1491        GDK_KEY_Control_R;
1492        #endif
1493    
1494    #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
1495    bool DimRegionChooser::onKeyPressed(Gdk::EventKey& _key) {
1496        GdkEventKey* key = _key.gobj();
1497    #else
1498    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1499    #endif
1500        //printf("key down 0x%x\n", key->keyval);
1501        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1502            multiSelectKeyDown = true;
1503        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1504            primaryKeyDown = true;
1505        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1506            shiftKeyDown = true;
1507    
1508        //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
1509        /*if (key->keyval == GDK_KEY_Left)
1510            select_prev_dimzone();
1511        if (key->keyval == GDK_KEY_Right)
1512            select_next_dimzone();
1513        if (key->keyval == GDK_KEY_Up)
1514            select_prev_dimension();
1515        if (key->keyval == GDK_KEY_Down)
1516            select_next_dimension();*/
1517        return false;
1518    }
1519    
1520    #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
1521    bool DimRegionChooser::onKeyReleased(Gdk::EventKey& _key) {
1522        GdkEventKey* key = _key.gobj();
1523    #else
1524    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1525    #endif
1526        //printf("key up 0x%x\n", key->keyval);
1527        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1528            multiSelectKeyDown = false;
1529        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1530            primaryKeyDown = false;
1531        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1532            shiftKeyDown = false;
1533    
1534        if (!has_focus()) return false;
1535    
1536        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1537        // (which is supposed to switch between regions)
1538        if (primaryKeyDown) return false;
1539    
1540        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1541        // mainwindow
1542        if (shiftKeyDown) return false;
1543    
1544        if (key->keyval == GDK_KEY_Left)
1545            select_prev_dimzone();
1546        if (key->keyval == GDK_KEY_Right)
1547            select_next_dimzone();
1548        if (key->keyval == GDK_KEY_Up)
1549            select_prev_dimension();
1550        if (key->keyval == GDK_KEY_Down)
1551            select_next_dimension();
1552    
1553        return false;
1554    }
1555    
1556    void DimRegionChooser::resetSelectedZones() {
1557        this->dimzones.clear();
1558        if (!region) {
1559            queue_draw(); // redraw required parts
1560            return;
1561        }
1562        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1563            queue_draw(); // redraw required parts
1564            return;
1565        }
1566        if (!region->pDimensionRegions[maindimregno]) {
1567            queue_draw(); // redraw required parts
1568            return;
1569        }
1570        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1571    
1572        bool isValidZone;
1573        this->maindimcase = dimensionCaseOf(dimrgn);
1574    
1575        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1576             it != this->maindimcase.end(); ++it)
1577        {
1578            this->dimzones[it->first].insert(it->second);
1579        }
1580    
1581        // redraw required parts
1582        queue_draw();
1583    }
1584    
1585    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1586        if (!region) return false; //.selection failed
1587    
1588        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1589            if (region->pDimensionRegions[dr] == dimrgn) {
1590                // reset dim region zone selection to the requested specific dim region case
1591                maindimregno = dr;
1592                resetSelectedZones();
1593    
1594                // emit signal that dimregion selection has changed, for external entities
1595                dimregion_selected();
1596    
1597                return true; // selection success
1598            }
1599        }
1600    
1601        return false; //.selection failed
1602    }
1603    
1604    void DimRegionChooser::select_next_dimzone(bool add) {
1605        select_dimzone_by_dir(+1, add);
1606    }
1607    
1608    void DimRegionChooser::select_prev_dimzone(bool add) {
1609        select_dimzone_by_dir(-1, add);
1610    }
1611    
1612    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1613        if (!region) return;
1614        if (!region->Dimensions) return;
1615        if (focus_line < 0) focus_line = 0;
1616        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1617    
1618        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1619        if (maindimtype == gig::dimension_none) {
1620            printf("maindimtype -> none\n");
1621            return;
1622        }
1623    
1624        // commented out: re-evaluate maindimcase, since it might not been reset from a previous instrument which causes errors if it got different dimension types
1625        //if (maindimcase.empty()) {
1626            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1627            if (maindimcase.empty()) {
1628                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1629                return;
1630            }
1631        //}
1632    
1633        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1634        if (z < 0) z = 0;
1635        if (z >= region->pDimensionDefinitions[focus_line].zones)
1636            z = region->pDimensionDefinitions[focus_line].zones - 1;
1637    
1638        maindimcase[maindimtype] = z;
1639    
1640        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1641        if (!dr) {
1642            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1643            return;
1644        }
1645    
1646        maindimregno = getDimensionRegionIndex(dr);
1647    
1648        if (!add) {
1649            // reset selected dimregion zones
1650            dimzones.clear();
1651        }
1652        for (DimensionCase::const_iterator it = maindimcase.begin();
1653             it != maindimcase.end(); ++it)
1654        {
1655            dimzones[it->first].insert(it->second);
1656        }
1657    
1658        dimregion_selected();
1659    
1660        // disabled: would overwrite dimregno with wrong value
1661        //refresh_all();
1662        // so requesting just a raw repaint instead:
1663        queue_draw();
1664    }
1665    
1666    void DimRegionChooser::select_next_dimension() {
1667        if (!region) return;
1668        focus_line++;
1669        if (focus_line >= region->Dimensions)
1670            focus_line = region->Dimensions - 1;
1671        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1672        queue_draw();
1673    }
1674    
1675    void DimRegionChooser::select_prev_dimension() {
1676        if (!region) return;
1677        focus_line--;
1678        if (focus_line < 0)
1679            focus_line = 0;
1680        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1681        queue_draw();
1682    }
1683    
1684    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1685        if (!region) return NULL;
1686        return region->pDimensionRegions[maindimregno];
1687  }  }

Legend:
Removed from v.2462  
changed lines
  Added in v.3460

  ViewVC Help
Powered by ViewVC