/[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 1303 by persson, Sun Aug 26 09:29:52 2007 UTC revision 3460 by persson, Sat Feb 2 07:48:50 2019 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006, 2007 Andreas Persson   * Copyright (C) 2006-2019 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include "global.h"
21    #include "compat.h"
22    #include "Settings.h"
23    #include <gtkmm/box.h>
24  #include "dimregionchooser.h"  #include "dimregionchooser.h"
25    #include <cairomm/context.h>
26    #include <cairomm/surface.h>
27  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
28    #include <gdkmm/general.h>
29    #if HAS_GDKMM_SEAT
30    # include <gdkmm/seat.h>
31    #endif
32    #include <glibmm/stringutils.h>
33    #if HAS_GTKMM_STOCK
34    # include <gtkmm/stock.h>
35    #endif
36    #include <glibmm/ustring.h>
37    #include <gtkmm/messagedialog.h>
38    #include <assert.h>
39    
40    #include "gfx/builtinpix.h"
41    
42    //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
43    static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
44        DimensionCase dimCase;
45        if (!dr) {
46            *isValidZone = false;
47            return dimCase;
48        }
49    
50        gig::Region* rgn = (gig::Region*) dr->GetParent();
51    
52        // find the dimension region index of the passed dimension region
53        int drIndex;
54        for (drIndex = 0; drIndex < 256; ++drIndex)
55            if (rgn->pDimensionRegions[drIndex] == dr)
56                break;
57    
58        // not found in region, something's horribly wrong
59        if (drIndex == 256) {
60            fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
61            *isValidZone = false;
62            return DimensionCase();
63        }
64    
65        for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
66            const int bits = rgn->pDimensionDefinitions[d].bits;
67            dimCase[rgn->pDimensionDefinitions[d].dimension] =
68                (drIndex >> baseBits) & ((1 << bits) - 1);
69            baseBits += bits;
70            // there are also DimensionRegion objects of unused zones, skip them
71            if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
72                *isValidZone = false;
73                return DimensionCase();
74            }
75        }
76    
77  DimRegionChooser::DimRegionChooser()      *isValidZone = true;
78        return dimCase;
79    }
80    
81    DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
82        red("#ff476e"),
83        blue("#4796ff"),
84        black("black"),
85        white("white")
86  {  {
87      // get_window() would return 0 because the Gdk::Window has not yet been realized      // make sure blue hatched pattern pixmap is loaded
88      // So we can only allocate the colors here - the rest will happen in on_realize().      loadBuiltInPix();
89      Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();  
90        // create blue hatched pattern 1
91      black = Gdk::Color("black");      {
92      white = Gdk::Color("white");          const int width = blueHatchedPattern->get_width();
93      red = Gdk::Color("#8070ff");          const int height = blueHatchedPattern->get_height();
94      blue = Gdk::Color("blue");          const int stride = blueHatchedPattern->get_rowstride();
95      green = Gdk::Color("green");  
96            // manually convert from RGBA to ARGB
97      colormap->alloc_color(black);          this->blueHatchedPatternARGB = blueHatchedPattern->copy();
98      colormap->alloc_color(white);          const int pixelSize = stride / width;
99      colormap->alloc_color(red);          const int totalPixels = width * height;
100      colormap->alloc_color(blue);          assert(pixelSize == 4);
101      colormap->alloc_color(green);          unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
102            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
103                const unsigned char r = ptr[0];
104                const unsigned char g = ptr[1];
105                const unsigned char b = ptr[2];
106                const unsigned char a = ptr[3];
107                ptr[0] = b;
108                ptr[1] = g;
109                ptr[2] = r;
110                ptr[3] = a;
111            }
112    
113            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
114    #if HAS_CAIROMM_CPP11_ENUMS
115                this->blueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
116    #else
117                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
118    #endif
119            );
120            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
121    #if HAS_CAIROMM_CPP11_ENUMS
122            this->blueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
123    #else
124            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
125    #endif
126        }
127    
128        // create blue hatched pattern 2
129        {
130            const int width = blueHatchedPattern2->get_width();
131            const int height = blueHatchedPattern2->get_height();
132            const int stride = blueHatchedPattern2->get_rowstride();
133    
134            // manually convert from RGBA to ARGB
135            this->blueHatchedPattern2ARGB = blueHatchedPattern2->copy();
136            const int pixelSize = stride / width;
137            const int totalPixels = width * height;
138            assert(pixelSize == 4);
139            unsigned char* ptr = this->blueHatchedPattern2ARGB->get_pixels();
140            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
141                const unsigned char r = ptr[0];
142                const unsigned char g = ptr[1];
143                const unsigned char b = ptr[2];
144                const unsigned char a = ptr[3];
145                ptr[0] = b;
146                ptr[1] = g;
147                ptr[2] = r;
148                ptr[3] = a;
149            }
150    
151            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
152    #if HAS_CAIROMM_CPP11_ENUMS
153                this->blueHatchedPattern2ARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
154    #else
155                this->blueHatchedPattern2ARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
156    #endif
157            );
158            this->blueHatchedSurfacePattern2 = Cairo::SurfacePattern::create(imageSurface);
159    #if HAS_CAIROMM_CPP11_ENUMS
160            this->blueHatchedSurfacePattern2->set_extend(Cairo::Pattern::Extend::REPEAT);
161    #else
162            this->blueHatchedSurfacePattern2->set_extend(Cairo::EXTEND_REPEAT);
163    #endif
164        }
165    
166        // create gray blue hatched pattern
167        {
168            const int width = grayBlueHatchedPattern->get_width();
169            const int height = grayBlueHatchedPattern->get_height();
170            const int stride = grayBlueHatchedPattern->get_rowstride();
171    
172            // manually convert from RGBA to ARGB
173            this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
174            const int pixelSize = stride / width;
175            const int totalPixels = width * height;
176            assert(pixelSize == 4);
177            unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
178            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
179                const unsigned char r = ptr[0];
180                const unsigned char g = ptr[1];
181                const unsigned char b = ptr[2];
182                const unsigned char a = ptr[3];
183                ptr[0] = b;
184                ptr[1] = g;
185                ptr[2] = r;
186                ptr[3] = a;
187            }
188    
189            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
190    #if HAS_CAIROMM_CPP11_ENUMS
191                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
192    #else
193                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
194    #endif
195            );
196            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
197    #if HAS_CAIROMM_CPP11_ENUMS
198            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
199    #else
200            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
201    #endif
202        }
203    
204      instrument = 0;      instrument = 0;
205      region = 0;      region = 0;
206      dimregno = -1;      maindimregno = -1;
207        maindimtype = gig::dimension_none; // initialize with invalid dimension type
208      focus_line = 0;      focus_line = 0;
209      resize.active = false;      resize.active = false;
210      cursor_is_resize = false;      cursor_is_resize = false;
211      h = 20;      h = 24;
212      w = 800;      multiSelectKeyDown = false;
213      set_flags(Gtk::CAN_FOCUS);      primaryKeyDown = false;
214        shiftKeyDown = false;
215        modifybothchannels = modifyalldimregs = modifybothchannels = false;
216        set_can_focus();
217    
218        const Glib::ustring txtUseCheckBoxAllRegions =
219            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
220    
221        actionGroup = ActionGroup::create();
222    #if USE_GLIB_ACTION
223        actionSplitDimZone = actionGroup->add_action(
224            "SplitDimZone", sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
225        );
226        actionDeleteDimZone = actionGroup->add_action(
227             "DeleteDimZone", sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
228         );
229        insert_action_group("PopupMenuInsideDimRegion", actionGroup);
230    #else
231        actionSplitDimZone = Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
232        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
233        actionGroup->add(
234            actionSplitDimZone,
235            sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
236        );
237        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
238        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
239        actionGroup->add(
240            actionDeleteDimZone,
241            sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
242        );
243    #endif
244    
245    #if USE_GTKMM_BUILDER
246        uiManager = Gtk::Builder::create();
247        Glib::ustring ui_info =
248            "<interface>"
249            "  <menu id='menu-PopupMenuInsideDimRegion'>"
250            "    <section>"
251            "      <item id='item-split'>"
252            "        <attribute name='label' translatable='yes'>Split Dimensions Zone</attribute>"
253            "        <attribute name='action'>PopupMenuInsideDimRegion.SplitDimZone</attribute>"
254            "      </item>"
255            "      <item id='item-delete'>"
256            "        <attribute name='label' translatable='yes'>Delete Dimension Zone</attribute>"
257            "        <attribute name='action'>PopupMenuInsideDimRegion.DeleteDimZone</attribute>"
258            "      </item>"
259            "    </section>"
260            "  </menu>"
261            "</interface>";
262        uiManager->add_from_string(ui_info);
263    
264        popup_menu_inside_dimregion = new Gtk::Menu(
265            Glib::RefPtr<Gio::Menu>::cast_dynamic(
266                uiManager->get_object("menu-PopupMenuInsideDimRegion")
267            )
268        );
269    #else
270        uiManager = Gtk::UIManager::create();
271        uiManager->insert_action_group(actionGroup);
272        Glib::ustring ui_info =
273            "<ui>"
274            "  <popup name='PopupMenuInsideDimRegion'>"
275            "    <menuitem action='SplitDimZone'/>"
276            "    <menuitem action='DeleteDimZone'/>"
277            "  </popup>"
278    //         "  <popup name='PopupMenuOutsideDimRegion'>"
279    //         "    <menuitem action='Add'/>"
280    //         "  </popup>"
281            "</ui>";
282        uiManager->add_ui_from_string(ui_info);
283    
284        popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
285            uiManager->get_widget("/PopupMenuInsideDimRegion"));
286    //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
287    //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));
288    
289    #endif // USE_GTKMM_BUILDER
290    
291    
292    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 24)
293    # warning GTKMM4 event registration code missing for dimregionchooser!
294        //add_events(Gdk::EventMask::BUTTON_PRESS_MASK);
295    #else
296      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
297                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
298    #endif
299    
300        labels_changed = true;
301    
302      for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;      set_tooltip_text(_(
303            "Right click here for options on altering dimension zones. Press and "
304            "hold CTRL key for selecting multiple dimension zones simultaniously."
305        ));
306    
307        Settings::singleton()->showTooltips.get_proxy().signal_changed().connect(
308            sigc::mem_fun(*this, &DimRegionChooser::on_show_tooltips_changed)
309        );
310        on_show_tooltips_changed();
311        
312        window.signal_key_press_event().connect(
313            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
314        );
315        window.signal_key_release_event().connect(
316            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
317        );
318  }  }
319    
320  DimRegionChooser::~DimRegionChooser()  DimRegionChooser::~DimRegionChooser()
321  {  {
322  }  }
323    
324  void DimRegionChooser::on_realize()  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      // We need to call the base on_realize()      DimensionCase dimCase;
369      Gtk::DrawingArea::on_realize();      dimCase[dimension] = zone;
370    
371      // Now we can allocate any additional resources we need      std::vector<gig::DimensionRegion*> dimregs =
372      Glib::RefPtr<Gdk::Window> window = get_window();          dimensionRegionsMatching(dimCase, region, true);
373      gc = Gdk::GC::create(window);  
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  bool DimRegionChooser::on_expose_event(GdkEventExpose* event)  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
423    bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
424    {
425        double clipx1 = e->area.x;
426        double clipx2 = e->area.x + e->area.width;
427        double clipy1 = e->area.y;
428        double clipy2 = e->area.y + e->area.height;
429    
430        const Cairo::RefPtr<Cairo::Context>& cr =
431            get_window()->create_cairo_context();
432    #else
433    bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
434  {  {
435        double clipx1, clipx2, clipy1, clipy2;
436        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
437    #endif
438    
439      if (!region) return true;      if (!region) return true;
440    
441      // This is where we draw on the window      // This is where we draw on the window
442      Glib::RefPtr<Gdk::Window> window = get_window();      int w = get_width();
443      Glib::RefPtr<Pango::Context> context = get_pango_context();      Glib::RefPtr<Pango::Context> context = get_pango_context();
444    
445      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
446        cr->set_line_width(1);
447    
     window->clear();  
   
     // draw labels on the left (reflecting the dimension type)  
448      int y = 0;      int y = 0;
449      double maxwidth = 0;      if (labels_changed || label_width - 10 > clipx1) {
450      for (int i = 0 ; i < region->Dimensions ; i++) {          // draw labels on the left (reflecting the dimension type)
451          int nbZones = region->pDimensionDefinitions[i].zones;          double maxwidth = 0;
452          if (nbZones) {          for (int i = 0 ; i < region->Dimensions ; i++) {
453              const char* dstr;              int nbZones = region->pDimensionDefinitions[i].zones;
454              char dstrbuf[10];              if (nbZones) {
455              switch (region->pDimensionDefinitions[i].dimension) {                  const char* dstr;
456              case gig::dimension_none: dstr="none"; break;                  char dstrbuf[10];
457              case gig::dimension_samplechannel: dstr="samplechannel"; break;                  switch (region->pDimensionDefinitions[i].dimension) {
458              case gig::dimension_layer: dstr="layer"; break;                  case gig::dimension_none: dstr=_("none"); break;
459              case gig::dimension_velocity: dstr="velocity"; break;                  case gig::dimension_samplechannel: dstr=_("samplechannel");
460              case gig::dimension_channelaftertouch: dstr="channelaftertouch"; break;                      break;
461              case gig::dimension_releasetrigger: dstr="releasetrigger"; break;                  case gig::dimension_layer: dstr=_("layer"); break;
462              case gig::dimension_keyboard: dstr="keyboard"; break;                  case gig::dimension_velocity: dstr=_("velocity"); break;
463              case gig::dimension_roundrobin: dstr="roundrobin"; break;                  case gig::dimension_channelaftertouch:
464              case gig::dimension_random: dstr="random"; break;                      dstr=_("channelaftertouch"); break;
465              case gig::dimension_smartmidi: dstr="smartmidi"; break;                  case gig::dimension_releasetrigger:
466              case gig::dimension_roundrobinkeyboard: dstr="roundrobinkeyboard"; break;                      dstr=_("releasetrigger"); break;
467              case gig::dimension_modwheel: dstr="modwheel"; break;                  case gig::dimension_keyboard: dstr=_("keyswitching"); break;
468              case gig::dimension_breath: dstr="breath"; break;                  case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
469              case gig::dimension_foot: dstr="foot"; break;                  case gig::dimension_random: dstr=_("random"); break;
470              case gig::dimension_portamentotime: dstr="portamentotime"; break;                  case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
471              case gig::dimension_effect1: dstr="effect1"; break;                  case gig::dimension_roundrobinkeyboard:
472              case gig::dimension_effect2: dstr="effect2"; break;                      dstr=_("roundrobinkeyboard"); break;
473              case gig::dimension_genpurpose1: dstr="genpurpose1"; break;                  case gig::dimension_modwheel: dstr=_("modwheel"); break;
474              case gig::dimension_genpurpose2: dstr="genpurpose2"; break;                  case gig::dimension_breath: dstr=_("breath"); break;
475              case gig::dimension_genpurpose3: dstr="genpurpose3"; break;                  case gig::dimension_foot: dstr=_("foot"); break;
476              case gig::dimension_genpurpose4: dstr="genpurpose4"; break;                  case gig::dimension_portamentotime:
477              case gig::dimension_sustainpedal: dstr="sustainpedal"; break;                      dstr=_("portamentotime"); break;
478              case gig::dimension_portamento: dstr="portamento"; break;                  case gig::dimension_effect1: dstr=_("effect1"); break;
479              case gig::dimension_sostenutopedal: dstr="sostenutopedal"; break;                  case gig::dimension_effect2: dstr=_("effect2"); break;
480              case gig::dimension_softpedal: dstr="softpedal"; break;                  case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
481              case gig::dimension_genpurpose5: dstr="genpurpose5"; break;                  case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
482              case gig::dimension_genpurpose6: dstr="genpurpose6"; break;                  case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
483              case gig::dimension_genpurpose7: dstr="genpurpose7"; break;                  case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
484              case gig::dimension_genpurpose8: dstr="genpurpose8"; break;                  case gig::dimension_sustainpedal:
485              case gig::dimension_effect1depth: dstr="effect1depth"; break;                      dstr=_("sustainpedal"); break;
486              case gig::dimension_effect2depth: dstr="effect2depth"; break;                  case gig::dimension_portamento: dstr=_("portamento"); break;
487              case gig::dimension_effect3depth: dstr="effect3depth"; break;                  case gig::dimension_sostenutopedal:
488              case gig::dimension_effect4depth: dstr="effect4depth"; break;                      dstr=_("sostenutopedal"); break;
489              case gig::dimension_effect5depth: dstr="effect5depth"; break;                  case gig::dimension_softpedal: dstr=_("softpedal"); break;
490              default:                  case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
491                  sprintf(dstrbuf, "%d",                  case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
492                          region->pDimensionDefinitions[i].dimension);                  case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
493                  dstr = dstrbuf;                  case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
494                  break;                  case gig::dimension_effect1depth:
495              }                      dstr=_("effect1depth"); break;
496              layout->set_text(dstr);                  case gig::dimension_effect2depth:
497                        dstr=_("effect2depth"); break;
498              Pango::Rectangle rectangle = layout->get_logical_extents();                  case gig::dimension_effect3depth:
499              double text_w = double(rectangle.get_width()) / Pango::SCALE;                      dstr=_("effect3depth"); break;
500              if (text_w > maxwidth) maxwidth = text_w;                  case gig::dimension_effect4depth:
501              double text_h = double(rectangle.get_height()) / Pango::SCALE;                      dstr=_("effect4depth"); break;
502              Glib::RefPtr<const Gdk::GC> fg = get_style()->get_fg_gc(get_state());                  case gig::dimension_effect5depth:
503              window->draw_layout(fg, 4, int(y + (h - text_h) / 2 + 0.5), layout);                      dstr=_("effect5depth"); break;
504                    default:
505                        sprintf(dstrbuf, "%d",
506                                region->pDimensionDefinitions[i].dimension);
507                        dstr = dstrbuf;
508                        break;
509                    }
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();
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;
524                    if (text_w > maxwidth) maxwidth = text_w;
525    
526                    if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
527                        double text_h = double(rectangle.get_height()) /
528                            Pango::SCALE;
529    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
530                        const Gdk::Color fg = get_style()->get_fg(get_state());
531    #else
532                        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());
537    # endif
538    #endif
539                        Gdk::Cairo::set_source_rgba(cr, fg);
540                        cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
541    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
542                        pango_cairo_show_layout(cr->cobj(), layout->gobj());
543    #else
544                        layout->show_in_cairo_context(cr);
545    #endif
546                    }
547                }
548                y += h;
549          }          }
550          y += h;          label_width = int(maxwidth + 10);
551            labels_changed = false;
552      }      }
553        if (label_width >= clipx2) return true;
554    
555      // draw dimensions' zones areas      // draw dimensions' zones areas
556      y = 0;      y = 0;
557      int bitpos = 0;      int bitpos = 0;
     label_width = int(maxwidth + 10);  
558      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
559          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
560          if (nbZones) {          if (nbZones) {
561              // draw focus rectangle around dimension's label and zones              const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
             if (has_focus() && focus_line == i) {  
                 Gdk::Rectangle farea(0, y, 150, 20);  
                 get_style()->paint_focus(window, get_state(), farea, *this, "",  
                                          0, y, label_width, 20);  
             }  
   
             Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();  
             // draw top and bottom lines of dimension's zones  
             window->draw_line(black, label_width, y, w - 1, y);  
             window->draw_line(black, w - 1, y + h - 1, label_width, y + h - 1);  
             // erase whole dimension's zones area  
             window->draw_rectangle(get_style()->get_white_gc(), true,  
                                    label_width + 1, y + 1, (w - label_width - 2), h - 2);  
   
             int c = 0;  
             if (dimregno >= 0) {  
                 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);  
                 c = dimregno & mask; // mask away this dimension  
             }  
             bool customsplits =  
                 ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&  
                  region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||  
                 (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&  
                  region->pDimensionRegions[c]->VelocityUpperLimit));  
562    
563              // draw dimension's zone borders              if (y >= clipy2) break;
564              if (customsplits) {              if (y + h > clipy1) {
565                  window->draw_line(black, label_width, y + 1, label_width, y + h - 2);                  // draw focus rectangle around dimension's label and zones
566                  for (int j = 0 ; j < nbZones ; j++) {                  if (has_focus() && focus_line == i) {
567                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
568                      int upperLimit = d->DimensionUpperLimits[i];                      Gdk::Rectangle farea(0, y, 150, h);
569                      if (!upperLimit) upperLimit = d->VelocityUpperLimit;                      get_style()->paint_focus(get_window(), get_state(), farea,
570                      int v = upperLimit + 1;                                               *this, "",
571                      int x = int((w - label_width - 1) * v / 128.0 + 0.5);                                               0, y, label_width, h);
572                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);  #else
573                        get_style_context()->render_focus(cr,
574                                                          0, y, label_width, h);
575    #endif
576                  }                  }
577              } else {  
578                  for (int j = 0 ; j <= nbZones ; j++) {                  // draw top and bottom lines of dimension's zones
579                      int x = int((w - label_width - 1) * j / double(nbZones) + 0.5);                  Gdk::Cairo::set_source_rgba(cr, black);
580                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);                  cr->move_to(label_width, y + 0.5);
581                    cr->line_to(w, y + 0.5);
582                    cr->move_to(w, y + h - 0.5);
583                    cr->line_to(label_width, y + h - 0.5);
584                    cr->stroke();
585    
586                    // erase whole dimension's zones area
587                    Gdk::Cairo::set_source_rgba(cr, white);
588                    cr->rectangle(label_width + 1, y + 1,
589                                  (w - label_width - 2), h - 2);
590                    cr->fill();
591    
592                    int c = 0;
593                    if (maindimregno >= 0) {
594                        int mask =
595                            ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
596                              bitpos);
597                        c = maindimregno & mask; // mask away this dimension
598                  }                  }
599              }                  bool customsplits =
600                        ((region->pDimensionDefinitions[i].split_type ==
601                          gig::split_type_normal &&
602                          region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
603                         (region->pDimensionDefinitions[i].dimension ==
604                          gig::dimension_velocity &&
605                          region->pDimensionRegions[c]->VelocityUpperLimit));
606    
607              // draw fill for currently selected zone                  // draw dimension zones
608              if (dimregno >= 0) {                  Gdk::Cairo::set_source_rgba(cr, black);
                 gc->set_foreground(red);  
                 int dr = (dimregno >> bitpos) & ((1 << region->pDimensionDefinitions[i].bits) - 1);  
609                  if (customsplits) {                  if (customsplits) {
610                      int x1 = 0;                      cr->move_to(label_width + 0.5, y + 1);
611                        cr->line_to(label_width + 0.5, y + h - 1);
612                        int prevX = label_width;
613                        int prevUpperLimit = -1;
614    
615                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
616                          gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                          // draw dimension zone's borders for custom splits
617                            gig::DimensionRegion* d =
618                                region->pDimensionRegions[c + (j << bitpos)];
619                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
620                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;
621                          int v = upperLimit + 1;                          int v = upperLimit + 1;
622                          int x2 = int((w - label_width - 1) * v / 128.0 + 0.5);                          int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
623                          if (j == dr && x1 < x2) {                              label_width;
624                              window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          if (x >= clipx2) break;
625                                                     (x2 - x1) - 1, h - 2);                          if (x < clipx1) continue;
626                              break;                          Gdk::Cairo::set_source_rgba(cr, black);
627                            cr->move_to(x + 0.5, y + 1);
628                            cr->line_to(x + 0.5, y + h - 1);
629                            cr->stroke();
630    
631                            // draw fill for zone
632                            bool isSelectedZone = this->dimzones[dimension].count(j);
633                            bool isMainSelection =
634                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
635                                this->maindimcase[dimension] == j;
636                            bool isCheckBoxSelected =
637                                modifyalldimregs ||
638                                (modifybothchannels &&
639                                    dimension == gig::dimension_samplechannel);
640                            if (isMainSelection)
641                                Gdk::Cairo::set_source_rgba(cr, blue);
642                            else if (isSelectedZone)
643                                cr->set_source(blueHatchedSurfacePattern2);
644                            else if (isCheckBoxSelected)
645                                cr->set_source(blueHatchedSurfacePattern);
646                            else
647                                Gdk::Cairo::set_source_rgba(cr, white);
648    
649                            const int wZone = x - prevX - 1;
650    
651                            cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
652                            cr->fill();
653    
654                            // draw icons
655                            drawIconsFor(dimension, j, cr, prevX, y, wZone, h);
656    
657                            // draw text showing the beginning of the dimension zone
658                            // as numeric value to the user
659                            {
660                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
661                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
662                                Gdk::Cairo::set_source_rgba(cr, black);
663                                // get the text dimensions
664                                int text_width, text_height;
665                                layout->get_pixel_size(text_width, text_height);
666                                // move text to the left end of the dimension zone
667                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
668    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
669                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
670    #else
671                                layout->show_in_cairo_context(cr);
672    #endif
673                          }                          }
674                          x1 = x2;                          // draw text showing the end of the dimension zone
675                            // as numeric value to the user
676                            {
677                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
678                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
679                                Gdk::Cairo::set_source_rgba(cr, black);
680                                // get the text dimensions
681                                int text_width, text_height;
682                                layout->get_pixel_size(text_width, text_height);
683                                // move text to the left end of the dimension zone
684                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
685    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
686                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
687    #else
688                                layout->show_in_cairo_context(cr);
689    #endif
690                            }
691    
692                            prevX = x;
693                            prevUpperLimit = upperLimit;
694                      }                      }
695                  } else {                  } else {
696                      if (dr < nbZones) {                      int prevX = 0;
697                          int x1 = int((w - label_width - 1) * dr / double(nbZones) + 0.5);                      for (int j = 0 ; j <= nbZones ; j++) {
698                          int x2 = int((w - label_width - 1) * (dr + 1) / double(nbZones) + 0.5);                          // draw dimension zone's borders for normal splits
699                          window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          int x = int((w - label_width - 1) * j /
700                                                 (x2 - x1) - 1, h - 2);                                      double(nbZones) + 0.5) + label_width;
701                      }                          if (x >= clipx2) break;
702                            if (x < clipx1) continue;
703                            Gdk::Cairo::set_source_rgba(cr, black);
704                            cr->move_to(x + 0.5, y + 1);
705                            cr->line_to(x + 0.5, y + h - 1);
706                            cr->stroke();
707    
708                            if (j != 0) {
709                                const int wZone = x - prevX - 1;
710    
711                                // draw fill for zone
712                                bool isSelectedZone = this->dimzones[dimension].count(j-1);
713                                bool isMainSelection =
714                                    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();
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
735                                // as numeric value to the user
736                                {
737                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
738                                    layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
739                                    Gdk::Cairo::set_source_rgba(cr, black);
740                                    // get the text dimensions
741                                    int text_width, text_height;
742                                    layout->get_pixel_size(text_width, text_height);
743                                    // move text to the left end of the dimension zone
744                                    cr->move_to(prevX + 3, y + (h - text_height) / 2);
745    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
746                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
747    #else
748                                    layout->show_in_cairo_context(cr);
749    #endif
750                                }
751                                // draw text showing the end of the dimension zone
752                                // as numeric value to the user
753                                {
754                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
755                                    layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
756                                    Gdk::Cairo::set_source_rgba(cr, black);
757                                    // get the text dimensions
758                                    int text_width, text_height;
759                                    layout->get_pixel_size(text_width, text_height);
760                                    // move text to the left end of the dimension zone
761                                    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
763                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
764    #else
765                                    layout->show_in_cairo_context(cr);
766    #endif
767                                }
768                            }
769                            prevX = x;
770                        }      
771                  }                  }
772              }              }
   
773              y += h;              y += h;
774          }          }
775          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 228  bool DimRegionChooser::on_expose_event(G Line 778  bool DimRegionChooser::on_expose_event(G
778      return true;      return true;
779  }  }
780    
 void DimRegionChooser::on_size_request(GtkRequisition* requisition)  
 {  
     printf("DimRegionChooser::on_size_request\n");  
     *requisition = GtkRequisition();  
     requisition->height = region ? nbDimensions * 20 : 0;  
     requisition->width = 800;  
 }  
   
781  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
782  {  {
783      this->region = region;      this->region = region;
784      dimregno = 0;      maindimregno = 0;
785      nbDimensions = 0;      nbDimensions = 0;
786      if (region) {      if (region) {
787          int bitcount = 0;          int bitcount = 0;
# Line 247  void DimRegionChooser::set_region(gig::R Line 789  void DimRegionChooser::set_region(gig::R
789              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
790              nbDimensions++;              nbDimensions++;
791    
792              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
793                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
794              int mask =              maindimregno |= (z << bitcount);
                 ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) <<  
                   bitcount);  
             dimregno &= mask;  
             dimregno |= (z << bitcount);  
795              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
796          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
797      }      }
798      dimregion_selected();      dimregion_selected();
799        set_size_request(800, region ? nbDimensions * h : 0);
800    
801        labels_changed = true;
802      queue_resize();      queue_resize();
803        queue_draw();
804  }  }
805    
806  bool DimRegionChooser::on_button_release_event(GdkEventButton* event)  void DimRegionChooser::refresh_all() {
807        set_region(region);
808    }
809    
810    void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
811                                          std::set<gig::DimensionRegion*>& dimregs) const
812  {  {
813      if (resize.active) {      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
814          get_window()->pointer_ungrab(event->time);          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
815          resize.active = false;          if (!dimRgn) continue;
816            bool isValidZone;
817            std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
818            if (!isValidZone) continue;
819            for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
820                 it != dimCase.end(); ++it)
821            {
822                if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
823    
824                std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
825                    this->dimzones.find(it->first);
826                if (itSelectedDimension != this->dimzones.end() &&
827                    itSelectedDimension->second.count(it->second)) continue; // is selected
828    
829          if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {              goto notSelected;
830            }
831    
832              int bitpos = 0;          dimregs.insert(dimRgn);
833              for (int j = 0 ; j < resize.dimension ; j++) {  
834                  bitpos += region->pDimensionDefinitions[j].bits;          notSelected:
835            ;
836        }
837    }
838    
839    void DimRegionChooser::update_after_resize()
840    {
841        const uint8_t upperLimit = resize.pos - 1;
842        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
843    
844        int bitpos = 0;
845        for (int j = 0 ; j < resize.dimension ; j++) {
846            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 =
859                ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
860            int c = maindimregno & mask; // mask away this dimension
861    
862            if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
863                // the velocity dimension didn't previously have
864                // custom v3 splits, so we initialize all splits with
865                // default values
866                int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
867                for (int j = 0 ; j < nbZones ; j++) {
868                    gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
869                    d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
870              }              }
871              int mask =          }
872                  ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);          if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
873              int c = dimregno & mask; // mask away this dimension              // the velocity dimension didn't previously have
874                // custom v2 splits, so we initialize all splits with
875              if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {              // default values
876                  // the velocity dimension didn't previously have              int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
877                  // custom v3 splits, so we initialize all splits with              for (int j = 0 ; j < nbZones ; j++) {
878                  // default values                  gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
879                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
880                  for (int j = 0 ; j < nbZones ; j++) {              }
881                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];          }
882                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);  
883            int index = c + (resize.zone << bitpos);
884            gig::DimensionRegion* d = region->pDimensionRegions[index];
885            // update both v2 and v3 values
886            d->DimensionUpperLimits[resize.dimension] = upperLimit;
887            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              if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {          }
947                  // the velocity dimension didn't previously have      } else {
948                  // custom v2 splits, so we initialize all splits with          for (int i = 0 ; i < region->DimensionRegions ; ) {
949                  // default values              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
950                    // the dimension didn't previously have custom
951                    // limits, so we have to set default limits for
952                    // all the dimension regions
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++) {
956                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
957                      d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
958                  }                  }
959              }              }
960                int index = i + (resize.zone << bitpos);
961              gig::DimensionRegion *d = region->pDimensionRegions[c + resize.offset];              gig::DimensionRegion* d = region->pDimensionRegions[index];
962              // update both v2 and v3 values              d->DimensionUpperLimits[resize.dimension] = upperLimit;
963              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;  #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              d->VelocityUpperLimit = resize.pos - 1;              if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
965                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
966          } else {                  d->DimensionUpperLimits[resize.dimension] = upperLimit;
967              for (int i = 0 ; i < region->DimensionRegions ; ) {              }
968    #endif
969                  if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              int bitpos = 0;
970                      // the dimension didn't previously have custom              int j;
971                      // limits, so we have to set default limits for              for (j = 0 ; j < region->Dimensions ; j++) {
972                      // all the dimension regions                  if (j != resize.dimension) {
973                      int bitpos = 0;                      int maxzones = 1 << region->pDimensionDefinitions[j].bits;
974                      for (int j = 0 ; j < resize.dimension ; j++) {                      int dimj = (i >> bitpos) & (maxzones - 1);
975                          bitpos += region->pDimensionDefinitions[j].bits;                      if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
                     }  
                     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;  
   
                     for (int j = 0 ; j < nbZones ; j++) {  
                         gig::DimensionRegion *d = region->pDimensionRegions[i + (j << bitpos)];  
                         d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);  
                     }  
976                  }                  }
977                  gig::DimensionRegion *d = region->pDimensionRegions[i + resize.offset];                  bitpos += region->pDimensionDefinitions[j].bits;
978                  d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              }
979                if (j == region->Dimensions) break;
980                i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
981            }
982    
983                  int bitpos = 0;          if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
984                  int j;              gig::Region* rgn = NULL;
985                  for (j = 0 ; j < region->Dimensions ; j++) {              for (int key = 0; key < 128; ++key) {
986                      if (j != resize.dimension) {                  if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
987                          int maxzones = 1 << region->pDimensionDefinitions[j].bits;                  rgn = instr->GetRegion(key);
988                          int dimj = (i >> bitpos) & (maxzones - 1);                  gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
989                          if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;                  if (!dimdef) continue;
990                      }                  if (dimdef->zones != resize.dimensionDef.zones) continue;
991                      bitpos += region->pDimensionDefinitions[j].bits;                  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                  }                  }
                 if (j == region->Dimensions) break;  
                 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);  
1011              }              }
1012          }          }
1013        }
1014    }
1015    
1016    bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
1017    {
1018        if (resize.active) {
1019    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1020            get_window()->pointer_ungrab(event->time);
1021    #else
1022    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1023            Glib::wrap(event->device, true)->ungrab(event->time);
1024    # else
1025            Glib::wrap(event->device, true)->get_seat()->ungrab();
1026    # endif
1027    #endif
1028            resize.active = false;
1029    
1030          region_changed();          region_changed();
1031    
1032          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
# Line 353  bool DimRegionChooser::on_button_release Line 1039  bool DimRegionChooser::on_button_release
1039    
1040  bool DimRegionChooser::on_button_press_event(GdkEventButton* event)  bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
1041  {  {
1042        int w = get_width();
1043      if (region && event->y < nbDimensions * h &&      if (region && event->y < nbDimensions * h &&
1044          event->x >= label_width && event->x < w) {          event->x >= label_width && event->x < w) {
1045    
1046          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
1047              Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1048              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
1049                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
1050                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
1051                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
1052                                         double_arrow, event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
1053                                           event->time);
1054    #else
1055    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1056                Glib::wrap(event->device, true)->grab(get_window(),
1057                                                      Gdk::OWNERSHIP_NONE,
1058                                                      false,
1059                                                      Gdk::BUTTON_RELEASE_MASK |
1060                                                      Gdk::POINTER_MOTION_MASK |
1061                                                      Gdk::POINTER_MOTION_HINT_MASK,
1062                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
1063                                                      event->time);
1064    # else
1065                Glib::wrap(event->device, true)->get_seat()->grab(
1066                    get_window(),
1067                    Gdk::SeatCapabilities::SEAT_CAPABILITY_ALL_POINTING,
1068                    false,
1069                    Gdk::Cursor::create(
1070                        Glib::wrap(event->device, true)->get_seat()->get_display(),
1071                        Gdk::SB_H_DOUBLE_ARROW
1072                    ),
1073                    reinterpret_cast<GdkEvent*>(event)
1074                );
1075    # endif
1076    #endif
1077              resize.active = true;              resize.active = true;
1078          } else {          } else {
1079              int ydim = int(event->y / h);              int ydim = int(event->y / h);
# Line 381  bool DimRegionChooser::on_button_press_e Line 1092  bool DimRegionChooser::on_button_press_e
1092              }              }
1093    
1094              int i = dim;              int i = dim;
1095              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
1096              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
1097              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
1098    
1099              bool customsplits =              bool customsplits =
1100                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 395  bool DimRegionChooser::on_button_press_e Line 1106  bool DimRegionChooser::on_button_press_e
1106    
1107                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
1108                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
1109                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
1110                          if (val <= d->DimensionUpperLimits[i]) break;                          if (val <= d->DimensionUpperLimits[i]) break;
1111                      }                      }
1112                  } else {                  } else {
1113                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
1114                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
1115                          if (val <= d->VelocityUpperLimit) break;                          if (val <= d->VelocityUpperLimit) break;
1116                      }                      }
1117                  }                  }
# Line 413  bool DimRegionChooser::on_button_press_e Line 1124  bool DimRegionChooser::on_button_press_e
1124                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
1125                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
1126                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
1127              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
1128                this->maindimregno = c | (z << bitpos);
1129              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
1130    
1131                if (multiSelectKeyDown) {
1132                    if (dimzones[this->maindimtype].count(z)) {
1133                        if (dimzones[this->maindimtype].size() > 1) {
1134                            dimzones[this->maindimtype].erase(z);
1135                        }
1136                    } else {
1137                        dimzones[this->maindimtype].insert(z);
1138                    }
1139                } else {
1140                    this->dimzones.clear();
1141                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1142                         it != this->maindimcase.end(); ++it)
1143                    {
1144                        this->dimzones[it->first].insert(it->second);
1145                    }
1146                }
1147    
1148              focus_line = dim;              focus_line = dim;
1149              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
1150              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
1151              dimregion_selected();              dimregion_selected();
1152    
1153                if (event->button == 3) {
1154                    printf("dimregion right click\n");
1155                    popup_menu_inside_dimregion->popup(event->button, event->time);
1156                }
1157    
1158                queue_draw();
1159          }          }
1160      }      }
1161      return true;      return true;
# Line 431  bool DimRegionChooser::on_motion_notify_ Line 1165  bool DimRegionChooser::on_motion_notify_
1165  {  {
1166      Glib::RefPtr<Gdk::Window> window = get_window();      Glib::RefPtr<Gdk::Window> window = get_window();
1167      int x, y;      int x, y;
1168    #if HAS_GDKMM_SEAT
1169        x = event->x;
1170        y = event->y;
1171        Gdk::ModifierType state = Gdk::ModifierType(event->state);
1172    #else
1173      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
1174      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
1175    #endif
1176    
1177      if (resize.active) {      if (resize.active) {
1178            int w = get_width();
1179          int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);          int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
1180    
1181          if (k < resize.min) k = resize.min;          if (k < resize.min) k = resize.min;
# Line 443  bool DimRegionChooser::on_motion_notify_ Line 1184  bool DimRegionChooser::on_motion_notify_
1184          if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden          if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
1185    
1186          if (k != resize.pos) {          if (k != resize.pos) {
             Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();  
             Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();  
   
1187              int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;              int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
1188              int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;              int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
1189              int y = resize.dimension * h;              int y = resize.dimension * h;
1190                int x1, x2;
1191              if (resize.selected == resize.none) {              if (k > resize.pos) {
1192                  if (resize.pos != resize.min && resize.pos != resize.max) {                  x1 = prevx;
1193                      window->draw_line(white, prevx, y + 1, prevx, y + h - 2);                  x2 = x;
                 }  
1194              } else {              } else {
1195                  gc->set_foreground(red);                  x1 = x;
1196                    x2 = prevx;
                 Glib::RefPtr<const Gdk::GC> left;  
                 Glib::RefPtr<const Gdk::GC> right;  
                 if (resize.selected == resize.left) {  
                     left = gc;  
                     right = white;  
                 } else {  
                     left = white;  
                     right = gc;  
                 }  
   
                 if (k > resize.pos) {  
                     int xx = resize.pos == resize.min ? 1 : 0;  
                     window->draw_rectangle(left, true,  
                                            prevx + xx, y + 1, x - prevx - xx, h - 2);  
                 } else {  
                     int xx = resize.pos == resize.max ? 0 : 1;  
                     window->draw_rectangle(right, true,  
                                            x, y + 1, prevx - x + xx, h - 2);  
                 }  
1197              }              }
1198              window->draw_line(black, x, y + 1, x, y + h - 2);              Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
1199    
1200              resize.pos = k;              resize.pos = k;
1201                update_after_resize();
1202                get_window()->invalidate_rect(rect, false); // not sufficient ...
1203                queue_draw(); // ... so do a complete redraw instead.
1204          }          }
1205      } else {      } else {
1206          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
1207              if (!cursor_is_resize) {              if (!cursor_is_resize) {
1208                  Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1209                  window->set_cursor(double_arrow);                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1210    #else
1211                    window->set_cursor(
1212    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1213                        Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1214    # else
1215                        Gdk::Cursor::create(
1216                            Glib::wrap(event->device, true)->get_seat()->get_display(),
1217                            Gdk::SB_H_DOUBLE_ARROW
1218                        )
1219    # endif
1220                    );
1221    #endif
1222                  cursor_is_resize = true;                  cursor_is_resize = true;
1223              }              }
1224          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 497  bool DimRegionChooser::on_motion_notify_ Line 1231  bool DimRegionChooser::on_motion_notify_
1231    
1232  bool DimRegionChooser::is_in_resize_zone(double x, double y)  bool DimRegionChooser::is_in_resize_zone(double x, double y)
1233  {  {
1234        int w = get_width();
1235      if (region && y < nbDimensions * h && x >= label_width && x < w) {      if (region && y < nbDimensions * h && x >= label_width && x < w) {
1236          int ydim = int(y / h);          int ydim = int(y / h);
1237          int dim;          int dim;
# Line 510  bool DimRegionChooser::is_in_resize_zone Line 1245  bool DimRegionChooser::is_in_resize_zone
1245          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
1246    
1247          int c = 0;          int c = 0;
1248          if (dimregno >= 0) {          if (maindimregno >= 0) {
1249              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1250              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
1251          }          }
1252          const bool customsplits =          const bool customsplits =
1253              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 524  bool DimRegionChooser::is_in_resize_zone Line 1259  bool DimRegionChooser::is_in_resize_zone
1259          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
1260              int prev_limit = 0;              int prev_limit = 0;
1261              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
1262                  gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                  gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1263                  const int upperLimit =                  const int upperLimit =
1264                      (customsplits) ?                      (customsplits) ?
1265                          (d->DimensionUpperLimits[dim]) ?                          (d->DimensionUpperLimits[dim]) ?
# Line 535  bool DimRegionChooser::is_in_resize_zone Line 1270  bool DimRegionChooser::is_in_resize_zone
1270                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1271                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1272                      resize.dimension = dim;                      resize.dimension = dim;
1273                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1274                        resize.zone = iZone;
1275                      resize.pos = limit;                      resize.pos = limit;
1276                      resize.min = prev_limit;                      resize.min = prev_limit;
1277    
1278                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
1279                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1280                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1281                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
1282    
1283                      iZone++;                      iZone++;
1284                      gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1285    
1286                      const int upperLimit =                      const int upperLimit =
1287                          (customsplits) ?                          (customsplits) ?
# Line 564  bool DimRegionChooser::is_in_resize_zone Line 1300  bool DimRegionChooser::is_in_resize_zone
1300      return false;      return false;
1301  }  }
1302    
1303  sigc::signal<void> DimRegionChooser::signal_dimregion_selected()  sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
1304  {  {
1305      return dimregion_selected;      return dimregion_selected;
1306  }  }
1307    
1308  sigc::signal<void> DimRegionChooser::signal_region_changed()  sigc::signal<void>& DimRegionChooser::signal_region_changed()
1309  {  {
1310      return region_changed;      return region_changed;
1311  }  }
1312    
1313  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1314  {  {
1315      // TODO: kolla att region finns osv, dvs att det går att sätta      // TODO: check that region exists etc, that is, that it's possible
1316      // fokus.      // to set focus
1317      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1318          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1319          if (!has_focus()) {          if (!has_focus()) {
# Line 609  bool DimRegionChooser::on_focus(Gtk::Dir Line 1345  bool DimRegionChooser::on_focus(Gtk::Dir
1345              }              }
1346          }          }
1347      } else if (!has_focus()) {      } else if (!has_focus()) {
1348          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1349          grab_focus();          grab_focus();
1350          return true;          return true;
1351      } else {      } else {
1352          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1353        }
1354        return false;
1355    }
1356    
1357    void DimRegionChooser::split_dimension_zone() {    
1358        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1359        try {
1360            if (!modifyallregions) {
1361                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1362            } else {
1363                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1364                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1365                assert(pMaindimdef != NULL);
1366                // retain structure by value since the original region will be
1367                // modified in the loop below as well
1368                gig::dimension_def_t maindimdef = *pMaindimdef;
1369                std::vector<gig::Region*> ignoredAll;
1370                std::vector<gig::Region*> ignoredMinor;
1371                std::vector<gig::Region*> ignoredCritical;
1372                gig::Region* rgn = NULL;
1373                for (int key = 0; key < 128; ++key) {
1374                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1375                    rgn = instr->GetRegion(key);
1376    
1377                    // ignore all regions which do not exactly match the dimension
1378                    // layout of the selected region where this operation was emitted
1379                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1380                    if (!dimdef) {
1381                        ignoredAll.push_back(rgn);
1382                        ignoredMinor.push_back(rgn);
1383                        continue;
1384                    }
1385                    if (dimdef->zones != maindimdef.zones) {
1386                        ignoredAll.push_back(rgn);
1387                        ignoredCritical.push_back(rgn);
1388                        continue;
1389                    }
1390    
1391                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1392                }
1393                if (!ignoredAll.empty()) {
1394                    Glib::ustring txt;
1395                    if (ignoredCritical.empty())
1396                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1397                    else if (ignoredMinor.empty())
1398                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1399                    else
1400                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1401                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1402                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1403                    Gtk::MessageDialog msg(txt, false, type);
1404                    msg.run();
1405                }
1406            }
1407        } catch (RIFF::Exception e) {
1408            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1409            msg.run();
1410        } catch (...) {
1411            Glib::ustring txt = _("An unknown exception occurred!");
1412            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1413            msg.run();
1414      }      }
1415        refresh_all();
1416    }
1417    
1418    void DimRegionChooser::delete_dimension_zone() {
1419        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1420        try {
1421            if (!modifyallregions) {
1422                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1423            } else {
1424                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1425                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1426                assert(pMaindimdef != NULL);
1427                // retain structure by value since the original region will be
1428                // modified in the loop below as well
1429                gig::dimension_def_t maindimdef = *pMaindimdef;
1430                std::vector<gig::Region*> ignoredAll;
1431                std::vector<gig::Region*> ignoredMinor;
1432                std::vector<gig::Region*> ignoredCritical;
1433                gig::Region* rgn = NULL;
1434                for (int key = 0; key < 128; ++key) {
1435                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1436                    rgn = instr->GetRegion(key);
1437    
1438                    // ignore all regions which do not exactly match the dimension
1439                    // layout of the selected region where this operation was emitted
1440                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1441                    if (!dimdef) {
1442                        ignoredAll.push_back(rgn);
1443                        ignoredMinor.push_back(rgn);
1444                        continue;
1445                    }
1446                    if (dimdef->zones != maindimdef.zones) {
1447                        ignoredAll.push_back(rgn);
1448                        ignoredCritical.push_back(rgn);
1449                        continue;
1450                    }
1451    
1452                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1453                }
1454                if (!ignoredAll.empty()) {
1455                    Glib::ustring txt;
1456                    if (ignoredCritical.empty())
1457                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1458                    else if (ignoredMinor.empty())
1459                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1460                    else
1461                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1462                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1463                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1464                    Gtk::MessageDialog msg(txt, false, type);
1465                    msg.run();
1466                }
1467            }
1468        } catch (RIFF::Exception e) {
1469            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1470            msg.run();
1471        } catch (...) {
1472            Glib::ustring txt = _("An unknown exception occurred!");
1473            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1474            msg.run();
1475        }
1476        refresh_all();
1477    }
1478    
1479    // Cmd key on Mac, Ctrl key on all other OSs
1480    static const guint primaryKeyL =
1481        #if defined(__APPLE__)
1482        GDK_KEY_Meta_L;
1483        #else
1484        GDK_KEY_Control_L;
1485        #endif
1486    
1487    static const guint primaryKeyR =
1488        #if defined(__APPLE__)
1489        GDK_KEY_Meta_R;
1490        #else
1491        GDK_KEY_Control_R;
1492        #endif
1493    
1494    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
1495    bool DimRegionChooser::onKeyPressed(Gdk::EventKey& _key) {
1496        GdkEventKey* key = _key.gobj();
1497    #else
1498    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1499    #endif
1500        //printf("key down 0x%x\n", key->keyval);
1501        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1502            multiSelectKeyDown = true;
1503        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1504            primaryKeyDown = true;
1505        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1506            shiftKeyDown = true;
1507    
1508        //FIXME: hmm, for some reason GDKMM does not fire arrow key down events, so we are doing those handlers in the key up handler instead for now
1509        /*if (key->keyval == GDK_KEY_Left)
1510            select_prev_dimzone();
1511        if (key->keyval == GDK_KEY_Right)
1512            select_next_dimzone();
1513        if (key->keyval == GDK_KEY_Up)
1514            select_prev_dimension();
1515        if (key->keyval == GDK_KEY_Down)
1516            select_next_dimension();*/
1517        return false;
1518    }
1519    
1520    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
1521    bool DimRegionChooser::onKeyReleased(Gdk::EventKey& _key) {
1522        GdkEventKey* key = _key.gobj();
1523    #else
1524    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1525    #endif
1526        //printf("key up 0x%x\n", key->keyval);
1527        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1528            multiSelectKeyDown = false;
1529        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1530            primaryKeyDown = false;
1531        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1532            shiftKeyDown = false;
1533    
1534        if (!has_focus()) return false;
1535    
1536        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1537        // (which is supposed to switch between regions)
1538        if (primaryKeyDown) return false;
1539    
1540        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1541        // mainwindow
1542        if (shiftKeyDown) return false;
1543    
1544        if (key->keyval == GDK_KEY_Left)
1545            select_prev_dimzone();
1546        if (key->keyval == GDK_KEY_Right)
1547            select_next_dimzone();
1548        if (key->keyval == GDK_KEY_Up)
1549            select_prev_dimension();
1550        if (key->keyval == GDK_KEY_Down)
1551            select_next_dimension();
1552    
1553        return false;
1554    }
1555    
1556    void DimRegionChooser::resetSelectedZones() {
1557        this->dimzones.clear();
1558        if (!region) {
1559            queue_draw(); // redraw required parts
1560            return;
1561        }
1562        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1563            queue_draw(); // redraw required parts
1564            return;
1565        }
1566        if (!region->pDimensionRegions[maindimregno]) {
1567            queue_draw(); // redraw required parts
1568            return;
1569        }
1570        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1571    
1572        bool isValidZone;
1573        this->maindimcase = dimensionCaseOf(dimrgn);
1574    
1575        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1576             it != this->maindimcase.end(); ++it)
1577        {
1578            this->dimzones[it->first].insert(it->second);
1579        }
1580    
1581        // redraw required parts
1582        queue_draw();
1583    }
1584    
1585    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1586        if (!region) return false; //.selection failed
1587    
1588        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1589            if (region->pDimensionRegions[dr] == dimrgn) {
1590                // reset dim region zone selection to the requested specific dim region case
1591                maindimregno = dr;
1592                resetSelectedZones();
1593    
1594                // emit signal that dimregion selection has changed, for external entities
1595                dimregion_selected();
1596    
1597                return true; // selection success
1598            }
1599        }
1600    
1601        return false; //.selection failed
1602    }
1603    
1604    void DimRegionChooser::select_next_dimzone(bool add) {
1605        select_dimzone_by_dir(+1, add);
1606    }
1607    
1608    void DimRegionChooser::select_prev_dimzone(bool add) {
1609        select_dimzone_by_dir(-1, add);
1610    }
1611    
1612    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1613        if (!region) return;
1614        if (!region->Dimensions) return;
1615        if (focus_line < 0) focus_line = 0;
1616        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1617    
1618        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1619        if (maindimtype == gig::dimension_none) {
1620            printf("maindimtype -> none\n");
1621            return;
1622        }
1623    
1624        // commented out: re-evaluate maindimcase, since it might not been reset from a previous instrument which causes errors if it got different dimension types
1625        //if (maindimcase.empty()) {
1626            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1627            if (maindimcase.empty()) {
1628                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1629                return;
1630            }
1631        //}
1632    
1633        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1634        if (z < 0) z = 0;
1635        if (z >= region->pDimensionDefinitions[focus_line].zones)
1636            z = region->pDimensionDefinitions[focus_line].zones - 1;
1637    
1638        maindimcase[maindimtype] = z;
1639    
1640        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1641        if (!dr) {
1642            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1643            return;
1644        }
1645    
1646        maindimregno = getDimensionRegionIndex(dr);
1647    
1648        if (!add) {
1649            // reset selected dimregion zones
1650            dimzones.clear();
1651        }
1652        for (DimensionCase::const_iterator it = maindimcase.begin();
1653             it != maindimcase.end(); ++it)
1654        {
1655            dimzones[it->first].insert(it->second);
1656        }
1657    
1658        dimregion_selected();
1659    
1660        // disabled: would overwrite dimregno with wrong value
1661        //refresh_all();
1662        // so requesting just a raw repaint instead:
1663        queue_draw();
1664    }
1665    
1666    void DimRegionChooser::select_next_dimension() {
1667        if (!region) return;
1668        focus_line++;
1669        if (focus_line >= region->Dimensions)
1670            focus_line = region->Dimensions - 1;
1671        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1672        queue_draw();
1673    }
1674    
1675    void DimRegionChooser::select_prev_dimension() {
1676        if (!region) return;
1677        focus_line--;
1678        if (focus_line < 0)
1679            focus_line = 0;
1680        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1681        queue_draw();
1682    }
1683    
1684    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1685        if (!region) return NULL;
1686        return region->pDimensionRegions[maindimregno];
1687  }  }

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

  ViewVC Help
Powered by ViewVC