/[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 3409 by schoenebeck, Tue Jan 23 16:30:56 2018 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2014 Andreas Persson   * Copyright (C) 2006-2017 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 > 22)
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            gdk_device_ungrab(Glib::wrap(event->device, true)->gobj(), event->time);
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                gdk_device_grab(
1066                    Glib::wrap(event->device, true)->gobj(),
1067                    get_window()->gobj(),
1068                    GDK_OWNERSHIP_NONE,
1069                    false,
1070                    GdkEventMask(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
1071                                 GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK),
1072                    Gdk::Cursor::create(
1073                        Glib::wrap(event->device, true)->get_seat()->get_display(),
1074                        Gdk::SB_H_DOUBLE_ARROW
1075                    )->gobj(),
1076                    event->time
1077                );
1078    # endif
1079  #endif  #endif
1080              resize.active = true;              resize.active = true;
1081          } else {          } else {
# Line 719  bool DimRegionChooser::on_motion_notify_ Line 1168  bool DimRegionChooser::on_motion_notify_
1168  {  {
1169      Glib::RefPtr<Gdk::Window> window = get_window();      Glib::RefPtr<Gdk::Window> window = get_window();
1170      int x, y;      int x, y;
1171    #if HAS_GDKMM_SEAT
1172        x = event->x;
1173        y = event->y;
1174        Gdk::ModifierType state = Gdk::ModifierType(event->state);
1175    #else
1176      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
1177      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
1178    #endif
1179    
1180      if (resize.active) {      if (resize.active) {
1181          int w = get_width();          int w = get_width();
# Line 756  bool DimRegionChooser::on_motion_notify_ Line 1211  bool DimRegionChooser::on_motion_notify_
1211  #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
1212                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1213  #else  #else
1214                  window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(
1215    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1216                        Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1217    # else
1218                        Gdk::Cursor::create(
1219                            Glib::wrap(event->device, true)->get_seat()->get_display(),
1220                            Gdk::SB_H_DOUBLE_ARROW
1221                        )
1222    # endif
1223                    );
1224  #endif  #endif
1225                  cursor_is_resize = true;                  cursor_is_resize = true;
1226              }              }
# Line 809  bool DimRegionChooser::is_in_resize_zone Line 1273  bool DimRegionChooser::is_in_resize_zone
1273                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1274                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1275                      resize.dimension = dim;                      resize.dimension = dim;
1276                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1277                        resize.zone = iZone;
1278                      resize.pos = limit;                      resize.pos = limit;
1279                      resize.min = prev_limit;                      resize.min = prev_limit;
1280    
# Line 850  sigc::signal<void>& DimRegionChooser::si Line 1315  sigc::signal<void>& DimRegionChooser::si
1315    
1316  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1317  {  {
1318      // 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
1319      // fokus.      // to set focus
1320      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1321          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1322          if (!has_focus()) {          if (!has_focus()) {
# Line 883  bool DimRegionChooser::on_focus(Gtk::Dir Line 1348  bool DimRegionChooser::on_focus(Gtk::Dir
1348              }              }
1349          }          }
1350      } else if (!has_focus()) {      } else if (!has_focus()) {
1351          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1352          grab_focus();          grab_focus();
1353          return true;          return true;
1354      } else {      } else {
1355          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1356      }      }
1357        return false;
1358  }  }
1359    
1360  void DimRegionChooser::split_dimension_zone() {      void DimRegionChooser::split_dimension_zone() {    
1361      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1362      try {      try {
1363          region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1364                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1365            } else {
1366                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1367                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1368                assert(pMaindimdef != NULL);
1369                // retain structure by value since the original region will be
1370                // modified in the loop below as well
1371                gig::dimension_def_t maindimdef = *pMaindimdef;
1372                std::vector<gig::Region*> ignoredAll;
1373                std::vector<gig::Region*> ignoredMinor;
1374                std::vector<gig::Region*> ignoredCritical;
1375                gig::Region* rgn = NULL;
1376                for (int key = 0; key < 128; ++key) {
1377                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1378                    rgn = instr->GetRegion(key);
1379    
1380                    // ignore all regions which do not exactly match the dimension
1381                    // layout of the selected region where this operation was emitted
1382                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1383                    if (!dimdef) {
1384                        ignoredAll.push_back(rgn);
1385                        ignoredMinor.push_back(rgn);
1386                        continue;
1387                    }
1388                    if (dimdef->zones != maindimdef.zones) {
1389                        ignoredAll.push_back(rgn);
1390                        ignoredCritical.push_back(rgn);
1391                        continue;
1392                    }
1393    
1394                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1395                }
1396                if (!ignoredAll.empty()) {
1397                    Glib::ustring txt;
1398                    if (ignoredCritical.empty())
1399                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1400                    else if (ignoredMinor.empty())
1401                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1402                    else
1403                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1404                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1405                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1406                    Gtk::MessageDialog msg(txt, false, type);
1407                    msg.run();
1408                }
1409            }
1410      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1411          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1412          msg.run();          msg.run();
# Line 909  void DimRegionChooser::split_dimension_z Line 1421  void DimRegionChooser::split_dimension_z
1421  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1422      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1423      try {      try {
1424          region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1425                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1426            } else {
1427                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1428                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1429                assert(pMaindimdef != NULL);
1430                // retain structure by value since the original region will be
1431                // modified in the loop below as well
1432                gig::dimension_def_t maindimdef = *pMaindimdef;
1433                std::vector<gig::Region*> ignoredAll;
1434                std::vector<gig::Region*> ignoredMinor;
1435                std::vector<gig::Region*> ignoredCritical;
1436                gig::Region* rgn = NULL;
1437                for (int key = 0; key < 128; ++key) {
1438                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1439                    rgn = instr->GetRegion(key);
1440    
1441                    // ignore all regions which do not exactly match the dimension
1442                    // layout of the selected region where this operation was emitted
1443                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1444                    if (!dimdef) {
1445                        ignoredAll.push_back(rgn);
1446                        ignoredMinor.push_back(rgn);
1447                        continue;
1448                    }
1449                    if (dimdef->zones != maindimdef.zones) {
1450                        ignoredAll.push_back(rgn);
1451                        ignoredCritical.push_back(rgn);
1452                        continue;
1453                    }
1454    
1455                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1456                }
1457                if (!ignoredAll.empty()) {
1458                    Glib::ustring txt;
1459                    if (ignoredCritical.empty())
1460                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1461                    else if (ignoredMinor.empty())
1462                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1463                    else
1464                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1465                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1466                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1467                    Gtk::MessageDialog msg(txt, false, type);
1468                    msg.run();
1469                }
1470            }
1471      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1472          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1473          msg.run();          msg.run();
# Line 921  void DimRegionChooser::delete_dimension_ Line 1479  void DimRegionChooser::delete_dimension_
1479      refresh_all();      refresh_all();
1480  }  }
1481    
1482    // Cmd key on Mac, Ctrl key on all other OSs
1483    static const guint primaryKeyL =
1484        #if defined(__APPLE__)
1485        GDK_KEY_Meta_L;
1486        #else
1487        GDK_KEY_Control_L;
1488        #endif
1489    
1490    static const guint primaryKeyR =
1491        #if defined(__APPLE__)
1492        GDK_KEY_Meta_R;
1493        #else
1494        GDK_KEY_Control_R;
1495        #endif
1496    
1497    #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
1498    bool DimRegionChooser::onKeyPressed(Gdk::EventKey& _key) {
1499        GdkEventKey* key = _key.gobj();
1500    #else
1501  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1502      //printf("key down\n");  #endif
1503        //printf("key down 0x%x\n", key->keyval);
1504      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)
1505          multiSelectKeyDown = true;          multiSelectKeyDown = true;
1506        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1507            primaryKeyDown = true;
1508        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1509            shiftKeyDown = true;
1510    
1511        //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
1512        /*if (key->keyval == GDK_KEY_Left)
1513            select_prev_dimzone();
1514        if (key->keyval == GDK_KEY_Right)
1515            select_next_dimzone();
1516        if (key->keyval == GDK_KEY_Up)
1517            select_prev_dimension();
1518        if (key->keyval == GDK_KEY_Down)
1519            select_next_dimension();*/
1520        return false;
1521  }  }
1522    
1523    #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
1524    bool DimRegionChooser::onKeyReleased(Gdk::EventKey& _key) {
1525        GdkEventKey* key = _key.gobj();
1526    #else
1527  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1528      //printf("key up\n");  #endif
1529        //printf("key up 0x%x\n", key->keyval);
1530      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)
1531          multiSelectKeyDown = false;          multiSelectKeyDown = false;
1532        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1533            primaryKeyDown = false;
1534        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1535            shiftKeyDown = false;
1536    
1537        if (!has_focus()) return false;
1538    
1539        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1540        // (which is supposed to switch between regions)
1541        if (primaryKeyDown) return false;
1542    
1543        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1544        // mainwindow
1545        if (shiftKeyDown) return false;
1546    
1547        if (key->keyval == GDK_KEY_Left)
1548            select_prev_dimzone();
1549        if (key->keyval == GDK_KEY_Right)
1550            select_next_dimzone();
1551        if (key->keyval == GDK_KEY_Up)
1552            select_prev_dimension();
1553        if (key->keyval == GDK_KEY_Down)
1554            select_next_dimension();
1555    
1556        return false;
1557    }
1558    
1559    void DimRegionChooser::resetSelectedZones() {
1560        this->dimzones.clear();
1561        if (!region) {
1562            queue_draw(); // redraw required parts
1563            return;
1564        }
1565        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1566            queue_draw(); // redraw required parts
1567            return;
1568        }
1569        if (!region->pDimensionRegions[maindimregno]) {
1570            queue_draw(); // redraw required parts
1571            return;
1572        }
1573        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1574    
1575        bool isValidZone;
1576        this->maindimcase = dimensionCaseOf(dimrgn);
1577    
1578        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1579             it != this->maindimcase.end(); ++it)
1580        {
1581            this->dimzones[it->first].insert(it->second);
1582        }
1583    
1584        // redraw required parts
1585        queue_draw();
1586    }
1587    
1588    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1589        if (!region) return false; //.selection failed
1590    
1591        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1592            if (region->pDimensionRegions[dr] == dimrgn) {
1593                // reset dim region zone selection to the requested specific dim region case
1594                maindimregno = dr;
1595                resetSelectedZones();
1596    
1597                // emit signal that dimregion selection has changed, for external entities
1598                dimregion_selected();
1599    
1600                return true; // selection success
1601            }
1602        }
1603    
1604        return false; //.selection failed
1605    }
1606    
1607    void DimRegionChooser::select_next_dimzone(bool add) {
1608        select_dimzone_by_dir(+1, add);
1609    }
1610    
1611    void DimRegionChooser::select_prev_dimzone(bool add) {
1612        select_dimzone_by_dir(-1, add);
1613    }
1614    
1615    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1616        if (!region) return;
1617        if (!region->Dimensions) return;
1618        if (focus_line < 0) focus_line = 0;
1619        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1620    
1621        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1622        if (maindimtype == gig::dimension_none) {
1623            printf("maindimtype -> none\n");
1624            return;
1625        }
1626    
1627        // commented out: re-evaluate maindimcase, since it might not been reset from a previous instrument which causes errors if it got different dimension types
1628        //if (maindimcase.empty()) {
1629            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1630            if (maindimcase.empty()) {
1631                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1632                return;
1633            }
1634        //}
1635    
1636        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1637        if (z < 0) z = 0;
1638        if (z >= region->pDimensionDefinitions[focus_line].zones)
1639            z = region->pDimensionDefinitions[focus_line].zones - 1;
1640    
1641        maindimcase[maindimtype] = z;
1642    
1643        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1644        if (!dr) {
1645            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1646            return;
1647        }
1648    
1649        maindimregno = getDimensionRegionIndex(dr);
1650    
1651        if (!add) {
1652            // reset selected dimregion zones
1653            dimzones.clear();
1654        }
1655        for (DimensionCase::const_iterator it = maindimcase.begin();
1656             it != maindimcase.end(); ++it)
1657        {
1658            dimzones[it->first].insert(it->second);
1659        }
1660    
1661        dimregion_selected();
1662    
1663        // disabled: would overwrite dimregno with wrong value
1664        //refresh_all();
1665        // so requesting just a raw repaint instead:
1666        queue_draw();
1667    }
1668    
1669    void DimRegionChooser::select_next_dimension() {
1670        if (!region) return;
1671        focus_line++;
1672        if (focus_line >= region->Dimensions)
1673            focus_line = region->Dimensions - 1;
1674        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1675        queue_draw();
1676    }
1677    
1678    void DimRegionChooser::select_prev_dimension() {
1679        if (!region) return;
1680        focus_line--;
1681        if (focus_line < 0)
1682            focus_line = 0;
1683        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1684        queue_draw();
1685  }  }
1686    
1687  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {

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

  ViewVC Help
Powered by ViewVC