/[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 2626 by schoenebeck, Thu Jun 12 15:12:00 2014 UTC revision 3460 by persson, Sat Feb 2 07:48:50 2019 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2014 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>  #include <glibmm/stringutils.h>
33  #include <gtkmm/stock.h>  #if HAS_GTKMM_STOCK
34    # include <gtkmm/stock.h>
35    #endif
36  #include <glibmm/ustring.h>  #include <glibmm/ustring.h>
37  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
38    #include <assert.h>
39    
40  #include "global.h"  #include "gfx/builtinpix.h"
   
 // taken from gdk/gdkkeysyms.h  
 // (define on demand, to avoid unnecessary dev lib package build dependency)  
 #ifndef GDK_KEY_Control_L  
 # define GDK_KEY_Control_L 0xffe3  
 #endif  
 #ifndef GDK_KEY_Control_R  
 # define GDK_KEY_Control_R 0xffe4  
 #endif  
41    
42  static std::map<gig::dimension_t,int> caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {  //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
43      std::map<gig::dimension_t,int> dimCase;  static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
44        DimensionCase dimCase;
45      if (!dr) {      if (!dr) {
46          *isValidZone = false;          *isValidZone = false;
47          return dimCase;          return dimCase;
# Line 56  static std::map<gig::dimension_t,int> ca Line 59  static std::map<gig::dimension_t,int> ca
59      if (drIndex == 256) {      if (drIndex == 256) {
60          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
61          *isValidZone = false;          *isValidZone = false;
62          return std::map<gig::dimension_t,int>();          return DimensionCase();
63      }      }
64    
65      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
# Line 67  static std::map<gig::dimension_t,int> ca Line 70  static std::map<gig::dimension_t,int> ca
70          // there are also DimensionRegion objects of unused zones, skip them          // there are also DimensionRegion objects of unused zones, skip them
71          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
72              *isValidZone = false;              *isValidZone = false;
73              return std::map<gig::dimension_t,int>();              return DimensionCase();
74          }          }
75      }      }
76    
# Line 76  static std::map<gig::dimension_t,int> ca Line 79  static std::map<gig::dimension_t,int> ca
79  }  }
80    
81  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
82      red("#8070ff"),      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      maindimregno = -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;      multiSelectKeyDown = false;
213        primaryKeyDown = false;
214        shiftKeyDown = false;
215        modifybothchannels = modifyalldimregs = modifybothchannels = false;
216      set_can_focus();      set_can_focus();
217    
218      actionGroup = Gtk::ActionGroup::create();      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(      actionGroup->add(
234          Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),          actionSplitDimZone,
235          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)          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(      actionGroup->add(
240          Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),          actionDeleteDimZone,
241          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)          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();      uiManager = Gtk::UIManager::create();
271      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
272      Glib::ustring ui_info =      Glib::ustring ui_info =
# Line 119  DimRegionChooser::DimRegionChooser(Gtk:: Line 286  DimRegionChooser::DimRegionChooser(Gtk::
286  //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(  //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
287  //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));  //         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    
300      labels_changed = true;      labels_changed = true;
301    
# Line 128  DimRegionChooser::DimRegionChooser(Gtk:: Line 303  DimRegionChooser::DimRegionChooser(Gtk::
303          "Right click here for options on altering dimension zones. Press and "          "Right click here for options on altering dimension zones. Press and "
304          "hold CTRL key for selecting multiple dimension zones simultaniously."          "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(      window.signal_key_press_event().connect(
313          sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)          sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
# Line 141  DimRegionChooser::~DimRegionChooser() Line 321  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 229  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 242  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 273  bool DimRegionChooser::on_draw(const Cai Line 565  bool DimRegionChooser::on_draw(const Cai
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 318  bool DimRegionChooser::on_draw(const Cai Line 610  bool DimRegionChooser::on_draw(const Cai
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;                      int prevX = label_width;
613                      int prevUpperLimit = 0;                      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                          // draw dimension zone's borders for custom splits
# Line 338  bool DimRegionChooser::on_draw(const Cai Line 630  bool DimRegionChooser::on_draw(const Cai
630    
631                          // draw fill for zone                          // draw fill for zone
632                          bool isSelectedZone = this->dimzones[dimension].count(j);                          bool isSelectedZone = this->dimzones[dimension].count(j);
633                          Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                          bool isMainSelection =
634                          cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                              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();                          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                          // draw text showing the beginning of the dimension zone
658                          // as numeric value to the user                          // as numeric value to the user
659                          {                          {
660                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
661                              layout->set_text(Glib::Ascii::dtostr(prevUpperLimit));                              layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
662                              Gdk::Cairo::set_source_rgba(cr, black);                              Gdk::Cairo::set_source_rgba(cr, black);
                             Pango::Rectangle rect = layout->get_logical_extents();  
663                              // get the text dimensions                              // get the text dimensions
664                              int text_width, text_height;                              int text_width, text_height;
665                              layout->get_pixel_size(text_width, text_height);                              layout->get_pixel_size(text_width, text_height);
666                              // move text to the left end of the dimension zone                              // move text to the left end of the dimension zone
667                              cr->move_to(prevX + 3, y + 1);                              cr->move_to(prevX + 3, y + (h - text_height) / 2);
668  #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
669                              pango_cairo_show_layout(cr->cobj(), layout->gobj());                              pango_cairo_show_layout(cr->cobj(), layout->gobj());
670  #else  #else
# Line 366  bool DimRegionChooser::on_draw(const Cai Line 677  bool DimRegionChooser::on_draw(const Cai
677                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
678                              layout->set_text(Glib::Ascii::dtostr(upperLimit));                              layout->set_text(Glib::Ascii::dtostr(upperLimit));
679                              Gdk::Cairo::set_source_rgba(cr, black);                              Gdk::Cairo::set_source_rgba(cr, black);
                             Pango::Rectangle rect = layout->get_logical_extents();  
680                              // get the text dimensions                              // get the text dimensions
681                              int text_width, text_height;                              int text_width, text_height;
682                              layout->get_pixel_size(text_width, text_height);                              layout->get_pixel_size(text_width, text_height);
683                              // move text to the left end of the dimension zone                              // move text to the left end of the dimension zone
684                              cr->move_to(x - 3 - text_width, y + 1);                              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  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
686                              pango_cairo_show_layout(cr->cobj(), layout->gobj());                              pango_cairo_show_layout(cr->cobj(), layout->gobj());
687  #else  #else
# Line 396  bool DimRegionChooser::on_draw(const Cai Line 706  bool DimRegionChooser::on_draw(const Cai
706                          cr->stroke();                          cr->stroke();
707    
708                          if (j != 0) {                          if (j != 0) {
709                                const int wZone = x - prevX - 1;
710    
711                              // draw fill for zone                              // draw fill for zone
712                              bool isSelectedZone = this->dimzones[dimension].count(j-1);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
713                              Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                              bool isMainSelection =
714                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
715                                    this->maindimcase[dimension] == (j-1);
716                                bool isCheckBoxSelected =
717                                    modifyalldimregs ||
718                                    (modifybothchannels &&
719                                        dimension == gig::dimension_samplechannel);
720                                if (isMainSelection)
721                                    Gdk::Cairo::set_source_rgba(cr, blue);
722                                else if (isSelectedZone)
723                                    cr->set_source(blueHatchedSurfacePattern2);
724                                else if (isCheckBoxSelected)
725                                    cr->set_source(blueHatchedSurfacePattern);
726                                else
727                                    Gdk::Cairo::set_source_rgba(cr, white);
728                                cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
729                              cr->fill();                              cr->fill();
730    
731                                // draw icons
732                                drawIconsFor(dimension, j - 1, cr, prevX, y, wZone, h);
733    
734                              // draw text showing the beginning of the dimension zone                              // draw text showing the beginning of the dimension zone
735                              // as numeric value to the user                              // as numeric value to the user
736                              {                              {
737                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
738                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
739                                  Gdk::Cairo::set_source_rgba(cr, black);                                  Gdk::Cairo::set_source_rgba(cr, black);
                                 Pango::Rectangle rect = layout->get_logical_extents();  
740                                  // get the text dimensions                                  // get the text dimensions
741                                  int text_width, text_height;                                  int text_width, text_height;
742                                  layout->get_pixel_size(text_width, text_height);                                  layout->get_pixel_size(text_width, text_height);
743                                  // move text to the left end of the dimension zone                                  // move text to the left end of the dimension zone
744                                  cr->move_to(prevX + 3, y + 1);                                  cr->move_to(prevX + 3, y + (h - text_height) / 2);
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
# Line 426  bool DimRegionChooser::on_draw(const Cai Line 754  bool DimRegionChooser::on_draw(const Cai
754                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
755                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
756                                  Gdk::Cairo::set_source_rgba(cr, black);                                  Gdk::Cairo::set_source_rgba(cr, black);
                                 Pango::Rectangle rect = layout->get_logical_extents();  
757                                  // get the text dimensions                                  // get the text dimensions
758                                  int text_width, text_height;                                  int text_width, text_height;
759                                  layout->get_pixel_size(text_width, text_height);                                  layout->get_pixel_size(text_width, text_height);
760                                  // move text to the left end of the dimension zone                                  // move text to the left end of the dimension zone
761                                  cr->move_to(x - 3 - text_width, y + 1);                                  cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
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
# Line 469  void DimRegionChooser::set_region(gig::R Line 796  void DimRegionChooser::set_region(gig::R
796          }          }
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();
# Line 511  void DimRegionChooser::get_dimregions(co Line 838  void DimRegionChooser::get_dimregions(co
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 = maindimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
# Line 542  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 565  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 581  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 590  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 619  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 627  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 719  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 756  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 809  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    
# Line 850  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 883  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() {      void DimRegionChooser::split_dimension_zone() {    
1358      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1359      try {      try {
1360          region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);          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) {      } catch (RIFF::Exception e) {
1408          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1409          msg.run();          msg.run();
# Line 909  void DimRegionChooser::split_dimension_z Line 1418  void DimRegionChooser::split_dimension_z
1418  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1419      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1420      try {      try {
1421          region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);          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) {      } catch (RIFF::Exception e) {
1469          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1470          msg.run();          msg.run();
# Line 921  void DimRegionChooser::delete_dimension_ Line 1476  void DimRegionChooser::delete_dimension_
1476      refresh_all();      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) {  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1499      //printf("key down\n");  #endif
1500        //printf("key down 0x%x\n", key->keyval);
1501      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1502          multiSelectKeyDown = true;          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) {  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1525      //printf("key up\n");  #endif
1526        //printf("key up 0x%x\n", key->keyval);
1527      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1528          multiSelectKeyDown = false;          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 {  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {

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

  ViewVC Help
Powered by ViewVC