/[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 2844 by persson, Sun Sep 20 08:49:40 2015 UTC revision 3364 by schoenebeck, Tue Nov 14 18:07:25 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2015 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 <gtkmm/box.h>  #include <gtkmm/box.h>
23  #include "dimregionchooser.h"  #include "dimregionchooser.h"
24  #include <cairomm/context.h>  #include <cairomm/context.h>
25    #include <cairomm/surface.h>
26  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
27  #include <gdkmm/general.h>  #include <gdkmm/general.h>
28    #if HAS_GDKMM_SEAT
29    # include <gdkmm/seat.h>
30    #endif
31  #include <glibmm/stringutils.h>  #include <glibmm/stringutils.h>
32  #include <gtkmm/stock.h>  #if HAS_GTKMM_STOCK
33    # include <gtkmm/stock.h>
34    #endif
35  #include <glibmm/ustring.h>  #include <glibmm/ustring.h>
36  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
37    #include <assert.h>
38    
39  #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  
40    
41  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!
42      std::map<gig::dimension_t,int> dimCase;  static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
43        DimensionCase dimCase;
44      if (!dr) {      if (!dr) {
45          *isValidZone = false;          *isValidZone = false;
46          return dimCase;          return dimCase;
# Line 57  static std::map<gig::dimension_t,int> ca Line 58  static std::map<gig::dimension_t,int> ca
58      if (drIndex == 256) {      if (drIndex == 256) {
59          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
60          *isValidZone = false;          *isValidZone = false;
61          return std::map<gig::dimension_t,int>();          return DimensionCase();
62      }      }
63    
64      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
# Line 68  static std::map<gig::dimension_t,int> ca Line 69  static std::map<gig::dimension_t,int> ca
69          // there are also DimensionRegion objects of unused zones, skip them          // there are also DimensionRegion objects of unused zones, skip them
70          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
71              *isValidZone = false;              *isValidZone = false;
72              return std::map<gig::dimension_t,int>();              return DimensionCase();
73          }          }
74      }      }
75    
# Line 77  static std::map<gig::dimension_t,int> ca Line 78  static std::map<gig::dimension_t,int> ca
78  }  }
79    
80  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
81      red("#8070ff"),      red("#ff476e"),
82        blue("#4796ff"),
83      black("black"),      black("black"),
84      white("white")      white("white")
85  {  {
86        // make sure blue hatched pattern pixmap is loaded
87        loadBuiltInPix();
88    
89        // create blue hatched pattern 1
90        {
91            const int width = blueHatchedPattern->get_width();
92            const int height = blueHatchedPattern->get_height();
93            const int stride = blueHatchedPattern->get_rowstride();
94    
95            // manually convert from RGBA to ARGB
96            this->blueHatchedPatternARGB = blueHatchedPattern->copy();
97            const int pixelSize = stride / width;
98            const int totalPixels = width * height;
99            assert(pixelSize == 4);
100            unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
101            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
102                const unsigned char r = ptr[0];
103                const unsigned char g = ptr[1];
104                const unsigned char b = ptr[2];
105                const unsigned char a = ptr[3];
106                ptr[0] = b;
107                ptr[1] = g;
108                ptr[2] = r;
109                ptr[3] = a;
110            }
111    
112            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
113    #if HAS_CAIROMM_CPP11_ENUMS
114                this->blueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
115    #else
116                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
117    #endif
118            );
119            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
120    #if HAS_CAIROMM_CPP11_ENUMS
121            this->blueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
122    #else
123            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
124    #endif
125        }
126    
127        // create blue hatched pattern 2
128        {
129            const int width = blueHatchedPattern2->get_width();
130            const int height = blueHatchedPattern2->get_height();
131            const int stride = blueHatchedPattern2->get_rowstride();
132    
133            // manually convert from RGBA to ARGB
134            this->blueHatchedPattern2ARGB = blueHatchedPattern2->copy();
135            const int pixelSize = stride / width;
136            const int totalPixels = width * height;
137            assert(pixelSize == 4);
138            unsigned char* ptr = this->blueHatchedPattern2ARGB->get_pixels();
139            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
140                const unsigned char r = ptr[0];
141                const unsigned char g = ptr[1];
142                const unsigned char b = ptr[2];
143                const unsigned char a = ptr[3];
144                ptr[0] = b;
145                ptr[1] = g;
146                ptr[2] = r;
147                ptr[3] = a;
148            }
149    
150            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
151    #if HAS_CAIROMM_CPP11_ENUMS
152                this->blueHatchedPattern2ARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
153    #else
154                this->blueHatchedPattern2ARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
155    #endif
156            );
157            this->blueHatchedSurfacePattern2 = Cairo::SurfacePattern::create(imageSurface);
158    #if HAS_CAIROMM_CPP11_ENUMS
159            this->blueHatchedSurfacePattern2->set_extend(Cairo::Pattern::Extend::REPEAT);
160    #else
161            this->blueHatchedSurfacePattern2->set_extend(Cairo::EXTEND_REPEAT);
162    #endif
163        }
164    
165        // create gray blue hatched pattern
166        {
167            const int width = grayBlueHatchedPattern->get_width();
168            const int height = grayBlueHatchedPattern->get_height();
169            const int stride = grayBlueHatchedPattern->get_rowstride();
170    
171            // manually convert from RGBA to ARGB
172            this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
173            const int pixelSize = stride / width;
174            const int totalPixels = width * height;
175            assert(pixelSize == 4);
176            unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
177            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
178                const unsigned char r = ptr[0];
179                const unsigned char g = ptr[1];
180                const unsigned char b = ptr[2];
181                const unsigned char a = ptr[3];
182                ptr[0] = b;
183                ptr[1] = g;
184                ptr[2] = r;
185                ptr[3] = a;
186            }
187    
188            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
189    #if HAS_CAIROMM_CPP11_ENUMS
190                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
191    #else
192                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
193    #endif
194            );
195            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
196    #if HAS_CAIROMM_CPP11_ENUMS
197            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
198    #else
199            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
200    #endif
201        }
202    
203      instrument = 0;      instrument = 0;
204      region = 0;      region = 0;
205      maindimregno = -1;      maindimregno = -1;
206        maindimtype = gig::dimension_none; // initialize with invalid dimension type
207      focus_line = 0;      focus_line = 0;
208      resize.active = false;      resize.active = false;
209      cursor_is_resize = false;      cursor_is_resize = false;
210      h = 24;      h = 24;
211      multiSelectKeyDown = false;      multiSelectKeyDown = false;
212        primaryKeyDown = false;
213        shiftKeyDown = false;
214        modifybothchannels = modifyalldimregs = modifybothchannels = false;
215      set_can_focus();      set_can_focus();
216    
217      actionGroup = Gtk::ActionGroup::create();      const Glib::ustring txtUseCheckBoxAllRegions =
218            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
219    
220        actionGroup = ActionGroup::create();
221    #if USE_GLIB_ACTION
222        actionSplitDimZone = actionGroup->add_action(
223            "SplitDimZone", sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
224        );
225        actionDeleteDimZone = actionGroup->add_action(
226             "DeleteDimZone", sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
227         );
228        insert_action_group("PopupMenuInsideDimRegion", actionGroup);
229    #else
230        actionSplitDimZone = Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
231        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
232      actionGroup->add(      actionGroup->add(
233          Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),          actionSplitDimZone,
234          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
235      );      );
236        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
237        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
238      actionGroup->add(      actionGroup->add(
239          Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),          actionDeleteDimZone,
240          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
241      );      );
242    #endif
243    
244    #if USE_GTKMM_BUILDER
245        uiManager = Gtk::Builder::create();
246        Glib::ustring ui_info =
247            "<interface>"
248            "  <menu id='menu-PopupMenuInsideDimRegion'>"
249            "    <section>"
250            "      <item id='item-split'>"
251            "        <attribute name='label' translatable='yes'>Split Dimensions Zone</attribute>"
252            "        <attribute name='action'>PopupMenuInsideDimRegion.SplitDimZone</attribute>"
253            "      </item>"
254            "      <item id='item-delete'>"
255            "        <attribute name='label' translatable='yes'>Delete Dimension Zone</attribute>"
256            "        <attribute name='action'>PopupMenuInsideDimRegion.DeleteDimZone</attribute>"
257            "      </item>"
258            "    </section>"
259            "  </menu>"
260            "</interface>";
261        uiManager->add_from_string(ui_info);
262    
263        popup_menu_inside_dimregion = new Gtk::Menu(
264            Glib::RefPtr<Gio::Menu>::cast_dynamic(
265                uiManager->get_object("menu-PopupMenuInsideDimRegion")
266            )
267        );
268    #else
269      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
270      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
271      Glib::ustring ui_info =      Glib::ustring ui_info =
# Line 120  DimRegionChooser::DimRegionChooser(Gtk:: Line 285  DimRegionChooser::DimRegionChooser(Gtk::
285  //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(  //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
286  //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));  //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));
287    
288    #endif // USE_GTKMM_BUILDER
289    
290    
291    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 22)
292    # warning GTKMM4 event registration code missing for dimregionchooser!
293        //add_events(Gdk::EventMask::BUTTON_PRESS_MASK);
294    #else
295      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
296                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
297    #endif
298    
299      labels_changed = true;      labels_changed = true;
300    
# Line 142  DimRegionChooser::~DimRegionChooser() Line 315  DimRegionChooser::~DimRegionChooser()
315  {  {
316  }  }
317    
318    void DimRegionChooser::setModifyBothChannels(bool b) {
319        modifybothchannels = b;
320        // redraw required parts
321        queue_draw();
322    }
323    
324    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
325        modifyalldimregs = b;
326        // redraw required parts
327        queue_draw();
328    }
329    
330    void DimRegionChooser::setModifyAllRegions(bool b) {
331        modifyallregions = b;
332    
333    #if USE_GTKMM_BUILDER
334        auto menuItemSplit = Glib::RefPtr<Gio::MenuItem>::cast_dynamic(
335            uiManager->get_object("item-split")
336        );
337        auto menuItemDelete = Glib::RefPtr<Gio::MenuItem>::cast_dynamic(
338            uiManager->get_object("item-delete")
339        );
340        menuItemDelete->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
341        menuItemSplit->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
342    #else
343        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
344        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
345    #endif
346    
347        // redraw required parts
348        queue_draw();
349    }
350    
351    void DimRegionChooser::drawIconsFor(
352        gig::dimension_t dimension, uint zone,
353        const Cairo::RefPtr<Cairo::Context>& cr,
354        int x, int y, int w, int h)
355    {
356        DimensionCase dimCase;
357        dimCase[dimension] = zone;
358    
359        std::vector<gig::DimensionRegion*> dimregs =
360            dimensionRegionsMatching(dimCase, region, true);
361    
362        if (dimregs.empty()) return;
363    
364        int iSampleRefs = 0;
365        int iLoops = 0;
366    
367        for (uint i = 0; i < dimregs.size(); ++i) {
368            if (dimregs[i]->pSample) iSampleRefs++;
369            if (dimregs[i]->SampleLoops) iLoops++;
370        }
371    
372        bool bShowLoopSymbol = (iLoops > 0);
373        bool bShowSampleRefSymbol = (iSampleRefs < dimregs.size());
374    
375        if (bShowLoopSymbol || bShowSampleRefSymbol) {
376            const int margin = 1;
377    
378            cr->save();
379            cr->set_line_width(1);
380            cr->rectangle(x, y + margin, w, h - 2*margin);
381            cr->clip();
382            if (bShowSampleRefSymbol) {
383                const int wPic = 8;
384                const int hPic = 8;
385                Gdk::Cairo::set_source_pixbuf(
386                    cr, (iSampleRefs) ? yellowDot : redDot,
387                    x + (w-wPic)/2.f,
388                    y + (
389                        (bShowLoopSymbol) ? margin : (h-hPic)/2.f
390                    )
391                );
392                cr->paint();
393            }
394            if (bShowLoopSymbol) {
395                const int wPic = 12;
396                const int hPic = 14;
397                Gdk::Cairo::set_source_pixbuf(
398                    cr, (iLoops == dimregs.size()) ? blackLoop : grayLoop,
399                    x + (w-wPic)/2.f,
400                    y + (
401                        (bShowSampleRefSymbol) ? h - hPic - margin : (h-hPic)/2.f
402                    )
403                );
404                cr->paint();
405            }
406            cr->restore();
407        }
408    }
409    
410  #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
411  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
412  {  {
# Line 230  bool DimRegionChooser::on_draw(const Cai Line 495  bool DimRegionChooser::on_draw(const Cai
495                      dstr = dstrbuf;                      dstr = dstrbuf;
496                      break;                      break;
497                  }                  }
                 layout->set_text(dstr);  
498    
499                    // Since bold font yields in larger label width, we first always
500                    // set the bold text variant, retrieve its dimensions (as worst
501                    // case dimensions of the label) ...
502                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
503                  Pango::Rectangle rectangle = layout->get_logical_extents();                  Pango::Rectangle rectangle = layout->get_logical_extents();
504                    // ... and then reset the label to regular font style in case
505                    // the line is not selected. Otherwise the right hand side
506                    // actual dimension zones would jump around on selection change.
507                    bool isSelectedLine = (focus_line == i);
508                    if (!isSelectedLine)
509                        layout->set_markup(dstr);
510    
511                  double text_w = double(rectangle.get_width()) / Pango::SCALE;                  double text_w = double(rectangle.get_width()) / Pango::SCALE;
512                  if (text_w > maxwidth) maxwidth = text_w;                  if (text_w > maxwidth) maxwidth = text_w;
513    
# Line 243  bool DimRegionChooser::on_draw(const Cai Line 518  bool DimRegionChooser::on_draw(const Cai
518                      const Gdk::Color fg = get_style()->get_fg(get_state());                      const Gdk::Color fg = get_style()->get_fg(get_state());
519  #else  #else
520                      const Gdk::RGBA fg =                      const Gdk::RGBA fg =
521    # if GTKMM_MAJOR_VERSION >= 3
522                            get_style_context()->get_color();
523    # else
524                          get_style_context()->get_color(get_state_flags());                          get_style_context()->get_color(get_state_flags());
525    # endif
526  #endif  #endif
527                      Gdk::Cairo::set_source_rgba(cr, fg);                      Gdk::Cairo::set_source_rgba(cr, fg);
528                      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 339  bool DimRegionChooser::on_draw(const Cai Line 618  bool DimRegionChooser::on_draw(const Cai
618    
619                          // draw fill for zone                          // draw fill for zone
620                          bool isSelectedZone = this->dimzones[dimension].count(j);                          bool isSelectedZone = this->dimzones[dimension].count(j);
621                          Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                          bool isMainSelection =
622                          cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                              this->maindimcase.find(dimension) != this->maindimcase.end() &&
623                                this->maindimcase[dimension] == j;
624                            bool isCheckBoxSelected =
625                                modifyalldimregs ||
626                                (modifybothchannels &&
627                                    dimension == gig::dimension_samplechannel);
628                            if (isMainSelection)
629                                Gdk::Cairo::set_source_rgba(cr, blue);
630                            else if (isSelectedZone)
631                                cr->set_source(blueHatchedSurfacePattern2);
632                            else if (isCheckBoxSelected)
633                                cr->set_source(blueHatchedSurfacePattern);
634                            else
635                                Gdk::Cairo::set_source_rgba(cr, white);
636    
637                            const int wZone = x - prevX - 1;
638    
639                            cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
640                          cr->fill();                          cr->fill();
641    
642                            // draw icons
643                            drawIconsFor(dimension, j, cr, prevX, y, wZone, h);
644    
645                          // draw text showing the beginning of the dimension zone                          // draw text showing the beginning of the dimension zone
646                          // as numeric value to the user                          // as numeric value to the user
647                          {                          {
# Line 395  bool DimRegionChooser::on_draw(const Cai Line 694  bool DimRegionChooser::on_draw(const Cai
694                          cr->stroke();                          cr->stroke();
695    
696                          if (j != 0) {                          if (j != 0) {
697                                const int wZone = x - prevX - 1;
698    
699                              // draw fill for zone                              // draw fill for zone
700                              bool isSelectedZone = this->dimzones[dimension].count(j-1);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
701                              Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                              bool isMainSelection =
702                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
703                                    this->maindimcase[dimension] == (j-1);
704                                bool isCheckBoxSelected =
705                                    modifyalldimregs ||
706                                    (modifybothchannels &&
707                                        dimension == gig::dimension_samplechannel);
708                                if (isMainSelection)
709                                    Gdk::Cairo::set_source_rgba(cr, blue);
710                                else if (isSelectedZone)
711                                    cr->set_source(blueHatchedSurfacePattern2);
712                                else if (isCheckBoxSelected)
713                                    cr->set_source(blueHatchedSurfacePattern);
714                                else
715                                    Gdk::Cairo::set_source_rgba(cr, white);
716                                cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
717                              cr->fill();                              cr->fill();
718    
719                                // draw icons
720                                drawIconsFor(dimension, j - 1, cr, prevX, y, wZone, h);
721    
722                              // draw text showing the beginning of the dimension zone                              // draw text showing the beginning of the dimension zone
723                              // as numeric value to the user                              // as numeric value to the user
724                              {                              {
# Line 508  void DimRegionChooser::get_dimregions(co Line 826  void DimRegionChooser::get_dimregions(co
826    
827  void DimRegionChooser::update_after_resize()  void DimRegionChooser::update_after_resize()
828  {  {
829      if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const uint8_t upperLimit = resize.pos - 1;
830        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
831    
832          int bitpos = 0;      int bitpos = 0;
833          for (int j = 0 ; j < resize.dimension ; j++) {      for (int j = 0 ; j < resize.dimension ; j++) {
834              bitpos += region->pDimensionDefinitions[j].bits;          bitpos += region->pDimensionDefinitions[j].bits;
835          }      }
836    
837        const int stereobitpos =
838            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
839    
840        // the velocity dimension must be handled differently than all other
841        // dimension types, because
842        // 1. it is currently the only dimension type which allows different zone
843        //    sizes for different cases
844        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
845        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
846          int mask =          int mask =
847              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
848          int c = maindimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
# Line 539  void DimRegionChooser::update_after_resi Line 868  void DimRegionChooser::update_after_resi
868              }              }
869          }          }
870    
871          gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];          int index = c + (resize.zone << bitpos);
872            gig::DimensionRegion* d = region->pDimensionRegions[index];
873          // update both v2 and v3 values          // update both v2 and v3 values
874          d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;          d->DimensionUpperLimits[resize.dimension] = upperLimit;
875          d->VelocityUpperLimit = resize.pos - 1;          d->VelocityUpperLimit = upperLimit;
876            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
877                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
878                d->DimensionUpperLimits[resize.dimension] = upperLimit;
879                d->VelocityUpperLimit = upperLimit;
880            }
881    
882            if (modifyalldimregs) {
883                gig::Region* rgn = NULL;
884                for (int key = 0; key < 128; ++key) {
885                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
886                    rgn = instr->GetRegion(key);
887                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
888                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
889                    if (!dimdef) continue;
890                    if (dimdef->zones != resize.dimensionDef.zones) continue;
891                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
892                    assert(iDim >= 0 && iDim < rgn->Dimensions);
893    
894                    // the dimension layout might be completely different in this
895                    // region, so we have to recalculate bitpos etc for this region
896                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
897                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
898                    const int selection = resize.zone << bitpos;
899    
900                    // primitive and inefficient loop implementation, however due to
901                    // this circumstance the loop code is much simpler, and its lack
902                    // of runtime efficiency should not be notable in practice
903                    for (int idr = 0; idr < 256; ++idr) {
904                        const int index = (idr & stencil) | selection;
905                        assert(index >= 0 && index < 256);
906                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
907                        if (!dr) continue;
908                        dr->DimensionUpperLimits[iDim] = upperLimit;
909                        d->VelocityUpperLimit = upperLimit;
910                    }
911                }
912            } else if (modifyallregions) { // implies modifyalldimregs is false ...
913                // resolve the precise case we need to modify for all other regions
914                DimensionCase dimCase = dimensionCaseOf(d);
915                // apply the velocity upper limit change to that resolved dim case
916                // of all regions ...
917                gig::Region* rgn = NULL;
918                for (int key = 0; key < 128; ++key) {
919                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
920                    rgn = instr->GetRegion(key);
921                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
922                    if (!dimdef) continue;
923                    if (dimdef->zones != resize.dimensionDef.zones) continue;
924                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
925                    assert(iDim >= 0 && iDim < rgn->Dimensions);
926    
927                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
928                    for (int i = 0; i < dimrgns.size(); ++i) {
929                        gig::DimensionRegion* dr = dimrgns[i];
930                        dr->DimensionUpperLimits[iDim] = upperLimit;
931                        dr->VelocityUpperLimit = upperLimit;
932                    }
933                }
934            }
935      } else {      } else {
936          for (int i = 0 ; i < region->DimensionRegions ; ) {          for (int i = 0 ; i < region->DimensionRegions ; ) {
   
937              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
938                  // the dimension didn't previously have custom                  // the dimension didn't previously have custom
939                  // limits, so we have to set default limits for                  // limits, so we have to set default limits for
940                  // all the dimension regions                  // all the dimension regions
                 int bitpos = 0;  
                 for (int j = 0 ; j < resize.dimension ; j++) {  
                     bitpos += region->pDimensionDefinitions[j].bits;  
                 }  
941                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
942    
943                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
# Line 562  void DimRegionChooser::update_after_resi Line 945  void DimRegionChooser::update_after_resi
945                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
946                  }                  }
947              }              }
948              gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];              int index = i + (resize.zone << bitpos);
949              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              gig::DimensionRegion* d = region->pDimensionRegions[index];
950                d->DimensionUpperLimits[resize.dimension] = upperLimit;
951    #if 0       // the following is currently not necessary, because ATM the gig format uses for all dimension types except of the veleocity dimension the same zone sizes for all cases
952                if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
953                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
954                    d->DimensionUpperLimits[resize.dimension] = upperLimit;
955                }
956    #endif
957              int bitpos = 0;              int bitpos = 0;
958              int j;              int j;
959              for (j = 0 ; j < region->Dimensions ; j++) {              for (j = 0 ; j < region->Dimensions ; j++) {
# Line 578  void DimRegionChooser::update_after_resi Line 967  void DimRegionChooser::update_after_resi
967              if (j == region->Dimensions) break;              if (j == region->Dimensions) break;
968              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
969          }          }
970    
971            if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
972                gig::Region* rgn = NULL;
973                for (int key = 0; key < 128; ++key) {
974                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
975                    rgn = instr->GetRegion(key);
976                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
977                    if (!dimdef) continue;
978                    if (dimdef->zones != resize.dimensionDef.zones) continue;
979                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
980                    assert(iDim >= 0 && iDim < rgn->Dimensions);
981    
982                    // the dimension layout might be completely different in this
983                    // region, so we have to recalculate bitpos etc for this region
984                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
985                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
986                    const int selection = resize.zone << bitpos;
987    
988                    // this loop implementation is less efficient than the above's
989                    // loop implementation (which skips unnecessary dimension regions)
990                    // however this code is much simpler, and its lack of runtime
991                    // efficiency should not be notable in practice
992                    for (int idr = 0; idr < 256; ++idr) {
993                        const int index = (idr & stencil) | selection;
994                        assert(index >= 0 && index < 256);
995                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
996                        if (!dr) continue;
997                        dr->DimensionUpperLimits[iDim] = upperLimit;
998                    }
999                }
1000            }
1001      }      }
1002  }  }
1003    
# Line 587  bool DimRegionChooser::on_button_release Line 1007  bool DimRegionChooser::on_button_release
1007  #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
1008          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
1009  #else  #else
1010    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1011          Glib::wrap(event->device, true)->ungrab(event->time);          Glib::wrap(event->device, true)->ungrab(event->time);
1012    # else
1013            gdk_device_ungrab(Glib::wrap(event->device, true)->gobj(), event->time);
1014    # endif
1015  #endif  #endif
1016          resize.active = false;          resize.active = false;
1017    
# Line 616  bool DimRegionChooser::on_button_press_e Line 1040  bool DimRegionChooser::on_button_press_e
1040                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
1041                                         event->time);                                         event->time);
1042  #else  #else
1043    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1044              Glib::wrap(event->device, true)->grab(get_window(),              Glib::wrap(event->device, true)->grab(get_window(),
1045                                                    Gdk::OWNERSHIP_NONE,                                                    Gdk::OWNERSHIP_NONE,
1046                                                    false,                                                    false,
# Line 624  bool DimRegionChooser::on_button_press_e Line 1049  bool DimRegionChooser::on_button_press_e
1049                                                    Gdk::POINTER_MOTION_HINT_MASK,                                                    Gdk::POINTER_MOTION_HINT_MASK,
1050                                                    Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),                                                    Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
1051                                                    event->time);                                                    event->time);
1052    # else
1053                gdk_device_grab(
1054                    Glib::wrap(event->device, true)->gobj(),
1055                    get_window()->gobj(),
1056                    GDK_OWNERSHIP_NONE,
1057                    false,
1058                    GdkEventMask(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
1059                                 GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK),
1060                    Gdk::Cursor::create(
1061                        Glib::wrap(event->device, true)->get_seat()->get_display(),
1062                        Gdk::SB_H_DOUBLE_ARROW
1063                    )->gobj(),
1064                    event->time
1065                );
1066    # endif
1067  #endif  #endif
1068              resize.active = true;              resize.active = true;
1069          } else {          } else {
# Line 716  bool DimRegionChooser::on_motion_notify_ Line 1156  bool DimRegionChooser::on_motion_notify_
1156  {  {
1157      Glib::RefPtr<Gdk::Window> window = get_window();      Glib::RefPtr<Gdk::Window> window = get_window();
1158      int x, y;      int x, y;
1159    #if HAS_GDKMM_SEAT
1160        x = event->x;
1161        y = event->y;
1162        Gdk::ModifierType state = Gdk::ModifierType(event->state);
1163    #else
1164      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
1165      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
1166    #endif
1167    
1168      if (resize.active) {      if (resize.active) {
1169          int w = get_width();          int w = get_width();
# Line 753  bool DimRegionChooser::on_motion_notify_ Line 1199  bool DimRegionChooser::on_motion_notify_
1199  #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
1200                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1201  #else  #else
1202                  window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(
1203    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1204                        Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1205    # else
1206                        Gdk::Cursor::create(
1207                            Glib::wrap(event->device, true)->get_seat()->get_display(),
1208                            Gdk::SB_H_DOUBLE_ARROW
1209                        )
1210    # endif
1211                    );
1212  #endif  #endif
1213                  cursor_is_resize = true;                  cursor_is_resize = true;
1214              }              }
# Line 806  bool DimRegionChooser::is_in_resize_zone Line 1261  bool DimRegionChooser::is_in_resize_zone
1261                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1262                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1263                      resize.dimension = dim;                      resize.dimension = dim;
1264                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1265                        resize.zone = iZone;
1266                      resize.pos = limit;                      resize.pos = limit;
1267                      resize.min = prev_limit;                      resize.min = prev_limit;
1268    
# Line 892  bool DimRegionChooser::on_focus(Gtk::Dir Line 1348  bool DimRegionChooser::on_focus(Gtk::Dir
1348  void DimRegionChooser::split_dimension_zone() {      void DimRegionChooser::split_dimension_zone() {    
1349      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1350      try {      try {
1351          region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1352                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1353            } else {
1354                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1355                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1356                assert(pMaindimdef != NULL);
1357                // retain structure by value since the original region will be
1358                // modified in the loop below as well
1359                gig::dimension_def_t maindimdef = *pMaindimdef;
1360                std::vector<gig::Region*> ignoredAll;
1361                std::vector<gig::Region*> ignoredMinor;
1362                std::vector<gig::Region*> ignoredCritical;
1363                gig::Region* rgn = NULL;
1364                for (int key = 0; key < 128; ++key) {
1365                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1366                    rgn = instr->GetRegion(key);
1367    
1368                    // ignore all regions which do not exactly match the dimension
1369                    // layout of the selected region where this operation was emitted
1370                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1371                    if (!dimdef) {
1372                        ignoredAll.push_back(rgn);
1373                        ignoredMinor.push_back(rgn);
1374                        continue;
1375                    }
1376                    if (dimdef->zones != maindimdef.zones) {
1377                        ignoredAll.push_back(rgn);
1378                        ignoredCritical.push_back(rgn);
1379                        continue;
1380                    }
1381    
1382                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1383                }
1384                if (!ignoredAll.empty()) {
1385                    Glib::ustring txt;
1386                    if (ignoredCritical.empty())
1387                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1388                    else if (ignoredMinor.empty())
1389                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1390                    else
1391                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1392                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1393                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1394                    Gtk::MessageDialog msg(txt, false, type);
1395                    msg.run();
1396                }
1397            }
1398      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1399          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1400          msg.run();          msg.run();
# Line 907  void DimRegionChooser::split_dimension_z Line 1409  void DimRegionChooser::split_dimension_z
1409  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1410      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1411      try {      try {
1412          region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1413                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1414            } else {
1415                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1416                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1417                assert(pMaindimdef != NULL);
1418                // retain structure by value since the original region will be
1419                // modified in the loop below as well
1420                gig::dimension_def_t maindimdef = *pMaindimdef;
1421                std::vector<gig::Region*> ignoredAll;
1422                std::vector<gig::Region*> ignoredMinor;
1423                std::vector<gig::Region*> ignoredCritical;
1424                gig::Region* rgn = NULL;
1425                for (int key = 0; key < 128; ++key) {
1426                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1427                    rgn = instr->GetRegion(key);
1428    
1429                    // ignore all regions which do not exactly match the dimension
1430                    // layout of the selected region where this operation was emitted
1431                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1432                    if (!dimdef) {
1433                        ignoredAll.push_back(rgn);
1434                        ignoredMinor.push_back(rgn);
1435                        continue;
1436                    }
1437                    if (dimdef->zones != maindimdef.zones) {
1438                        ignoredAll.push_back(rgn);
1439                        ignoredCritical.push_back(rgn);
1440                        continue;
1441                    }
1442    
1443                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1444                }
1445                if (!ignoredAll.empty()) {
1446                    Glib::ustring txt;
1447                    if (ignoredCritical.empty())
1448                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1449                    else if (ignoredMinor.empty())
1450                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1451                    else
1452                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1453                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1454                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1455                    Gtk::MessageDialog msg(txt, false, type);
1456                    msg.run();
1457                }
1458            }
1459      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1460          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1461          msg.run();          msg.run();
# Line 919  void DimRegionChooser::delete_dimension_ Line 1467  void DimRegionChooser::delete_dimension_
1467      refresh_all();      refresh_all();
1468  }  }
1469    
1470    // Cmd key on Mac, Ctrl key on all other OSs
1471    static const guint primaryKeyL =
1472        #if defined(__APPLE__)
1473        GDK_KEY_Meta_L;
1474        #else
1475        GDK_KEY_Control_L;
1476        #endif
1477    
1478    static const guint primaryKeyR =
1479        #if defined(__APPLE__)
1480        GDK_KEY_Meta_R;
1481        #else
1482        GDK_KEY_Control_R;
1483        #endif
1484    
1485    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
1486    bool DimRegionChooser::onKeyPressed(Gdk::EventKey& _key) {
1487        GdkEventKey* key = _key.gobj();
1488    #else
1489  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1490      //printf("key down\n");  #endif
1491        //printf("key down 0x%x\n", key->keyval);
1492      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)
1493          multiSelectKeyDown = true;          multiSelectKeyDown = true;
1494        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1495            primaryKeyDown = true;
1496        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1497            shiftKeyDown = true;
1498    
1499        //FIXME: hmm, for some reason GDKMM does not fire arrow key down events, so we are doing those handlers in the key up handler instead for now
1500        /*if (key->keyval == GDK_KEY_Left)
1501            select_prev_dimzone();
1502        if (key->keyval == GDK_KEY_Right)
1503            select_next_dimzone();
1504        if (key->keyval == GDK_KEY_Up)
1505            select_prev_dimension();
1506        if (key->keyval == GDK_KEY_Down)
1507            select_next_dimension();*/
1508      return false;      return false;
1509  }  }
1510    
1511    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
1512    bool DimRegionChooser::onKeyReleased(Gdk::EventKey& _key) {
1513        GdkEventKey* key = _key.gobj();
1514    #else
1515  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1516      //printf("key up\n");  #endif
1517        //printf("key up 0x%x\n", key->keyval);
1518      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)
1519          multiSelectKeyDown = false;          multiSelectKeyDown = false;
1520        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1521            primaryKeyDown = false;
1522        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1523            shiftKeyDown = false;
1524    
1525        if (!has_focus()) return false;
1526    
1527        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1528        // (which is supposed to switch between regions)
1529        if (primaryKeyDown) return false;
1530    
1531        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1532        // mainwindow
1533        if (shiftKeyDown) return false;
1534    
1535        if (key->keyval == GDK_KEY_Left)
1536            select_prev_dimzone();
1537        if (key->keyval == GDK_KEY_Right)
1538            select_next_dimzone();
1539        if (key->keyval == GDK_KEY_Up)
1540            select_prev_dimension();
1541        if (key->keyval == GDK_KEY_Down)
1542            select_next_dimension();
1543    
1544      return false;      return false;
1545  }  }
1546    
# Line 950  void DimRegionChooser::resetSelectedZone Line 1561  void DimRegionChooser::resetSelectedZone
1561      gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];      gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1562    
1563      bool isValidZone;      bool isValidZone;
1564      this->maindimcase = caseOfDimRegion(dimrgn, &isValidZone);      this->maindimcase = dimensionCaseOf(dimrgn);
     if (!isValidZone) {  
         queue_draw(); // redraw required parts  
         return;  
     }  
1565    
1566      for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();      for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1567           it != this->maindimcase.end(); ++it)           it != this->maindimcase.end(); ++it)
# Line 985  bool DimRegionChooser::select_dimregion( Line 1592  bool DimRegionChooser::select_dimregion(
1592      return false; //.selection failed      return false; //.selection failed
1593  }  }
1594    
1595    void DimRegionChooser::select_next_dimzone(bool add) {
1596        select_dimzone_by_dir(+1, add);
1597    }
1598    
1599    void DimRegionChooser::select_prev_dimzone(bool add) {
1600        select_dimzone_by_dir(-1, add);
1601    }
1602    
1603    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1604        if (!region) return;
1605        if (!region->Dimensions) return;
1606        if (focus_line < 0) focus_line = 0;
1607        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1608    
1609        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1610        if (maindimtype == gig::dimension_none) {
1611            printf("maindimtype -> none\n");
1612            return;
1613        }
1614    
1615        // commented out: re-evaluate maindimcase, since it might not been reset from a previous instrument which causes errors if it got different dimension types
1616        //if (maindimcase.empty()) {
1617            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1618            if (maindimcase.empty()) {
1619                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1620                return;
1621            }
1622        //}
1623    
1624        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1625        if (z < 0) z = 0;
1626        if (z >= region->pDimensionDefinitions[focus_line].zones)
1627            z = region->pDimensionDefinitions[focus_line].zones - 1;
1628    
1629        maindimcase[maindimtype] = z;
1630    
1631        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1632        if (!dr) {
1633            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1634            return;
1635        }
1636    
1637        maindimregno = getDimensionRegionIndex(dr);
1638    
1639        if (!add) {
1640            // reset selected dimregion zones
1641            dimzones.clear();
1642        }
1643        for (DimensionCase::const_iterator it = maindimcase.begin();
1644             it != maindimcase.end(); ++it)
1645        {
1646            dimzones[it->first].insert(it->second);
1647        }
1648    
1649        dimregion_selected();
1650    
1651        // disabled: would overwrite dimregno with wrong value
1652        //refresh_all();
1653        // so requesting just a raw repaint instead:
1654        queue_draw();
1655    }
1656    
1657    void DimRegionChooser::select_next_dimension() {
1658        if (!region) return;
1659        focus_line++;
1660        if (focus_line >= region->Dimensions)
1661            focus_line = region->Dimensions - 1;
1662        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1663        queue_draw();
1664    }
1665    
1666    void DimRegionChooser::select_prev_dimension() {
1667        if (!region) return;
1668        focus_line--;
1669        if (focus_line < 0)
1670            focus_line = 0;
1671        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1672        queue_draw();
1673    }
1674    
1675  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1676      if (!region) return NULL;      if (!region) return NULL;
1677      return region->pDimensionRegions[maindimregno];      return region->pDimensionRegions[maindimregno];

Legend:
Removed from v.2844  
changed lines
  Added in v.3364

  ViewVC Help
Powered by ViewVC