/[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 1656 by schoenebeck, Sat Feb 2 08:18:19 2008 UTC revision 3123 by schoenebeck, Tue Apr 25 20:45:54 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2008 Andreas Persson   * Copyright (C) 2006-2017 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include <gtkmm/box.h>
21  #include "dimregionchooser.h"  #include "dimregionchooser.h"
22    #include <cairomm/context.h>
23  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
24    #include <gdkmm/general.h>
25    #include <glibmm/stringutils.h>
26    #include <glibmm/ustring.h>
27    #include <gtkmm/messagedialog.h>
28    #include <assert.h>
29    
30    #include "global.h"
31    
32    //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
33    static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
34        DimensionCase dimCase;
35        if (!dr) {
36            *isValidZone = false;
37            return dimCase;
38        }
39    
40        gig::Region* rgn = (gig::Region*) dr->GetParent();
41    
42        // find the dimension region index of the passed dimension region
43        int drIndex;
44        for (drIndex = 0; drIndex < 256; ++drIndex)
45            if (rgn->pDimensionRegions[drIndex] == dr)
46                break;
47    
48        // not found in region, something's horribly wrong
49        if (drIndex == 256) {
50            fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
51            *isValidZone = false;
52            return DimensionCase();
53        }
54    
55        for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
56            const int bits = rgn->pDimensionDefinitions[d].bits;
57            dimCase[rgn->pDimensionDefinitions[d].dimension] =
58                (drIndex >> baseBits) & ((1 << bits) - 1);
59            baseBits += bits;
60            // there are also DimensionRegion objects of unused zones, skip them
61            if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
62                *isValidZone = false;
63                return DimensionCase();
64            }
65        }
66    
67        *isValidZone = true;
68        return dimCase;
69    }
70    
71  DimRegionChooser::DimRegionChooser()  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
72        red("#8070ff"),
73        black("black"),
74        white("white")
75  {  {
     // get_window() would return 0 because the Gdk::Window has not yet been realized  
     // So we can only allocate the colors here - the rest will happen in on_realize().  
     Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();  
   
     black = Gdk::Color("black");  
     white = Gdk::Color("white");  
     red = Gdk::Color("#8070ff");  
     blue = Gdk::Color("blue");  
     green = Gdk::Color("green");  
   
     colormap->alloc_color(black);  
     colormap->alloc_color(white);  
     colormap->alloc_color(red);  
     colormap->alloc_color(blue);  
     colormap->alloc_color(green);  
76      instrument = 0;      instrument = 0;
77      region = 0;      region = 0;
78      dimregno = -1;      maindimregno = -1;
79        maindimtype = gig::dimension_none; // initialize with invalid dimension type
80      focus_line = 0;      focus_line = 0;
81      resize.active = false;      resize.active = false;
82      cursor_is_resize = false;      cursor_is_resize = false;
83      h = 20;      h = 24;
84      set_flags(Gtk::CAN_FOCUS);      multiSelectKeyDown = false;
85        modifybothchannels = modifyalldimregs = modifybothchannels = false;
86        set_can_focus();
87    
88        const Glib::ustring txtUseCheckBoxAllRegions =
89            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
90    
91        actionGroup = Gtk::ActionGroup::create();
92        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
93        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
94        actionGroup->add(
95            actionSplitDimZone,
96            sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
97        );
98        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
99        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
100        actionGroup->add(
101            actionDeleteDimZone,
102            sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
103        );
104    
105        uiManager = Gtk::UIManager::create();
106        uiManager->insert_action_group(actionGroup);
107        Glib::ustring ui_info =
108            "<ui>"
109            "  <popup name='PopupMenuInsideDimRegion'>"
110            "    <menuitem action='SplitDimZone'/>"
111            "    <menuitem action='DeleteDimZone'/>"
112            "  </popup>"
113    //         "  <popup name='PopupMenuOutsideDimRegion'>"
114    //         "    <menuitem action='Add'/>"
115    //         "  </popup>"
116            "</ui>";
117        uiManager->add_ui_from_string(ui_info);
118    
119        popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
120            uiManager->get_widget("/PopupMenuInsideDimRegion"));
121    //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
122    //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));
123    
124      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
125                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
126    
127      for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;      labels_changed = true;
128    
129        set_tooltip_text(_(
130            "Right click here for options on altering dimension zones. Press and "
131            "hold CTRL key for selecting multiple dimension zones simultaniously."
132        ));
133        
134        window.signal_key_press_event().connect(
135            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
136        );
137        window.signal_key_release_event().connect(
138            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
139        );
140  }  }
141    
142  DimRegionChooser::~DimRegionChooser()  DimRegionChooser::~DimRegionChooser()
143  {  {
144  }  }
145    
146  void DimRegionChooser::on_realize()  void DimRegionChooser::setModifyBothChannels(bool b) {
147  {      modifybothchannels = b;
148      // We need to call the base on_realize()  }
     Gtk::DrawingArea::on_realize();  
149    
150      // Now we can allocate any additional resources we need  void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
151      Glib::RefPtr<Gdk::Window> window = get_window();      modifyalldimregs = b;
152      gc = Gdk::GC::create(window);  }
153    
154    void DimRegionChooser::setModifyAllRegions(bool b) {
155        modifyallregions = b;
156    
157        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
158        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
159  }  }
160    
161  bool DimRegionChooser::on_expose_event(GdkEventExpose* event)  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
162    bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
163    {
164        double clipx1 = e->area.x;
165        double clipx2 = e->area.x + e->area.width;
166        double clipy1 = e->area.y;
167        double clipy2 = e->area.y + e->area.height;
168    
169        const Cairo::RefPtr<Cairo::Context>& cr =
170            get_window()->create_cairo_context();
171    #else
172    bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
173  {  {
174        double clipx1, clipx2, clipy1, clipy2;
175        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
176    #endif
177    
178      if (!region) return true;      if (!region) return true;
179    
180      // This is where we draw on the window      // This is where we draw on the window
181      int w = get_width();      int w = get_width();
     Glib::RefPtr<Gdk::Window> window = get_window();  
182      Glib::RefPtr<Pango::Context> context = get_pango_context();      Glib::RefPtr<Pango::Context> context = get_pango_context();
183    
184      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
185        cr->set_line_width(1);
186    
     window->clear();  
   
     // draw labels on the left (reflecting the dimension type)  
187      int y = 0;      int y = 0;
188      double maxwidth = 0;      if (labels_changed || label_width - 10 > clipx1) {
189      for (int i = 0 ; i < region->Dimensions ; i++) {          // draw labels on the left (reflecting the dimension type)
190          int nbZones = region->pDimensionDefinitions[i].zones;          double maxwidth = 0;
191          if (nbZones) {          for (int i = 0 ; i < region->Dimensions ; i++) {
192              const char* dstr;              int nbZones = region->pDimensionDefinitions[i].zones;
193              char dstrbuf[10];              if (nbZones) {
194              switch (region->pDimensionDefinitions[i].dimension) {                  const char* dstr;
195              case gig::dimension_none: dstr="none"; break;                  char dstrbuf[10];
196              case gig::dimension_samplechannel: dstr="samplechannel"; break;                  switch (region->pDimensionDefinitions[i].dimension) {
197              case gig::dimension_layer: dstr="layer"; break;                  case gig::dimension_none: dstr=_("none"); break;
198              case gig::dimension_velocity: dstr="velocity"; break;                  case gig::dimension_samplechannel: dstr=_("samplechannel");
199              case gig::dimension_channelaftertouch: dstr="channelaftertouch"; break;                      break;
200              case gig::dimension_releasetrigger: dstr="releasetrigger"; break;                  case gig::dimension_layer: dstr=_("layer"); break;
201              case gig::dimension_keyboard: dstr="keyswitching"; break;                  case gig::dimension_velocity: dstr=_("velocity"); break;
202              case gig::dimension_roundrobin: dstr="roundrobin"; break;                  case gig::dimension_channelaftertouch:
203              case gig::dimension_random: dstr="random"; break;                      dstr=_("channelaftertouch"); break;
204              case gig::dimension_smartmidi: dstr="smartmidi"; break;                  case gig::dimension_releasetrigger:
205              case gig::dimension_roundrobinkeyboard: dstr="roundrobinkeyboard"; break;                      dstr=_("releasetrigger"); break;
206              case gig::dimension_modwheel: dstr="modwheel"; break;                  case gig::dimension_keyboard: dstr=_("keyswitching"); break;
207              case gig::dimension_breath: dstr="breath"; break;                  case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
208              case gig::dimension_foot: dstr="foot"; break;                  case gig::dimension_random: dstr=_("random"); break;
209              case gig::dimension_portamentotime: dstr="portamentotime"; break;                  case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
210              case gig::dimension_effect1: dstr="effect1"; break;                  case gig::dimension_roundrobinkeyboard:
211              case gig::dimension_effect2: dstr="effect2"; break;                      dstr=_("roundrobinkeyboard"); break;
212              case gig::dimension_genpurpose1: dstr="genpurpose1"; break;                  case gig::dimension_modwheel: dstr=_("modwheel"); break;
213              case gig::dimension_genpurpose2: dstr="genpurpose2"; break;                  case gig::dimension_breath: dstr=_("breath"); break;
214              case gig::dimension_genpurpose3: dstr="genpurpose3"; break;                  case gig::dimension_foot: dstr=_("foot"); break;
215              case gig::dimension_genpurpose4: dstr="genpurpose4"; break;                  case gig::dimension_portamentotime:
216              case gig::dimension_sustainpedal: dstr="sustainpedal"; break;                      dstr=_("portamentotime"); break;
217              case gig::dimension_portamento: dstr="portamento"; break;                  case gig::dimension_effect1: dstr=_("effect1"); break;
218              case gig::dimension_sostenutopedal: dstr="sostenutopedal"; break;                  case gig::dimension_effect2: dstr=_("effect2"); break;
219              case gig::dimension_softpedal: dstr="softpedal"; break;                  case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
220              case gig::dimension_genpurpose5: dstr="genpurpose5"; break;                  case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
221              case gig::dimension_genpurpose6: dstr="genpurpose6"; break;                  case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
222              case gig::dimension_genpurpose7: dstr="genpurpose7"; break;                  case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
223              case gig::dimension_genpurpose8: dstr="genpurpose8"; break;                  case gig::dimension_sustainpedal:
224              case gig::dimension_effect1depth: dstr="effect1depth"; break;                      dstr=_("sustainpedal"); break;
225              case gig::dimension_effect2depth: dstr="effect2depth"; break;                  case gig::dimension_portamento: dstr=_("portamento"); break;
226              case gig::dimension_effect3depth: dstr="effect3depth"; break;                  case gig::dimension_sostenutopedal:
227              case gig::dimension_effect4depth: dstr="effect4depth"; break;                      dstr=_("sostenutopedal"); break;
228              case gig::dimension_effect5depth: dstr="effect5depth"; break;                  case gig::dimension_softpedal: dstr=_("softpedal"); break;
229              default:                  case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
230                  sprintf(dstrbuf, "%d",                  case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
231                          region->pDimensionDefinitions[i].dimension);                  case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
232                  dstr = dstrbuf;                  case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
233                  break;                  case gig::dimension_effect1depth:
234              }                      dstr=_("effect1depth"); break;
235              layout->set_text(dstr);                  case gig::dimension_effect2depth:
236                        dstr=_("effect2depth"); break;
237              Pango::Rectangle rectangle = layout->get_logical_extents();                  case gig::dimension_effect3depth:
238              double text_w = double(rectangle.get_width()) / Pango::SCALE;                      dstr=_("effect3depth"); break;
239              if (text_w > maxwidth) maxwidth = text_w;                  case gig::dimension_effect4depth:
240              double text_h = double(rectangle.get_height()) / Pango::SCALE;                      dstr=_("effect4depth"); break;
241              Glib::RefPtr<const Gdk::GC> fg = get_style()->get_fg_gc(get_state());                  case gig::dimension_effect5depth:
242              window->draw_layout(fg, 4, int(y + (h - text_h) / 2 + 0.5), layout);                      dstr=_("effect5depth"); break;
243                    default:
244                        sprintf(dstrbuf, "%d",
245                                region->pDimensionDefinitions[i].dimension);
246                        dstr = dstrbuf;
247                        break;
248                    }
249                    layout->set_text(dstr);
250    
251                    Pango::Rectangle rectangle = layout->get_logical_extents();
252                    double text_w = double(rectangle.get_width()) / Pango::SCALE;
253                    if (text_w > maxwidth) maxwidth = text_w;
254    
255                    if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
256                        double text_h = double(rectangle.get_height()) /
257                            Pango::SCALE;
258    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
259                        const Gdk::Color fg = get_style()->get_fg(get_state());
260    #else
261                        const Gdk::RGBA fg =
262                            get_style_context()->get_color(get_state_flags());
263    #endif
264                        Gdk::Cairo::set_source_rgba(cr, fg);
265                        cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
266    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
267                        pango_cairo_show_layout(cr->cobj(), layout->gobj());
268    #else
269                        layout->show_in_cairo_context(cr);
270    #endif
271                    }
272                }
273                y += h;
274          }          }
275          y += h;          label_width = int(maxwidth + 10);
276            labels_changed = false;
277      }      }
278        if (label_width >= clipx2) return true;
279    
280      // draw dimensions' zones areas      // draw dimensions' zones areas
281      y = 0;      y = 0;
282      int bitpos = 0;      int bitpos = 0;
     label_width = int(maxwidth + 10);  
283      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
284          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
285          if (nbZones) {          if (nbZones) {
286              // 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));  
287    
288              // draw dimension's zone borders              if (y >= clipy2) break;
289              if (customsplits) {              if (y + h > clipy1) {
290                  window->draw_line(black, label_width, y + 1, label_width, y + h - 2);                  // draw focus rectangle around dimension's label and zones
291                  for (int j = 0 ; j < nbZones ; j++) {                  if (has_focus() && focus_line == i) {
292                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
293                      int upperLimit = d->DimensionUpperLimits[i];                      Gdk::Rectangle farea(0, y, 150, h);
294                      if (!upperLimit) upperLimit = d->VelocityUpperLimit;                      get_style()->paint_focus(get_window(), get_state(), farea,
295                      int v = upperLimit + 1;                                               *this, "",
296                      int x = int((w - label_width - 1) * v / 128.0 + 0.5);                                               0, y, label_width, h);
297                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);  #else
298                        get_style_context()->render_focus(cr,
299                                                          0, y, label_width, h);
300    #endif
301                  }                  }
302              } else {  
303                  for (int j = 0 ; j <= nbZones ; j++) {                  // draw top and bottom lines of dimension's zones
304                      int x = int((w - label_width - 1) * j / double(nbZones) + 0.5);                  Gdk::Cairo::set_source_rgba(cr, black);
305                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);                  cr->move_to(label_width, y + 0.5);
306                    cr->line_to(w, y + 0.5);
307                    cr->move_to(w, y + h - 0.5);
308                    cr->line_to(label_width, y + h - 0.5);
309                    cr->stroke();
310    
311                    // erase whole dimension's zones area
312                    Gdk::Cairo::set_source_rgba(cr, white);
313                    cr->rectangle(label_width + 1, y + 1,
314                                  (w - label_width - 2), h - 2);
315                    cr->fill();
316    
317                    int c = 0;
318                    if (maindimregno >= 0) {
319                        int mask =
320                            ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
321                              bitpos);
322                        c = maindimregno & mask; // mask away this dimension
323                  }                  }
324              }                  bool customsplits =
325                        ((region->pDimensionDefinitions[i].split_type ==
326                          gig::split_type_normal &&
327                          region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
328                         (region->pDimensionDefinitions[i].dimension ==
329                          gig::dimension_velocity &&
330                          region->pDimensionRegions[c]->VelocityUpperLimit));
331    
332              // draw fill for currently selected zone                  // draw dimension zones
333              if (dimregno >= 0) {                  Gdk::Cairo::set_source_rgba(cr, black);
                 gc->set_foreground(red);  
                 int dr = (dimregno >> bitpos) & ((1 << region->pDimensionDefinitions[i].bits) - 1);  
334                  if (customsplits) {                  if (customsplits) {
335                      int x1 = 0;                      cr->move_to(label_width + 0.5, y + 1);
336                        cr->line_to(label_width + 0.5, y + h - 1);
337                        int prevX = label_width;
338                        int prevUpperLimit = -1;
339    
340                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
341                          gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                          // draw dimension zone's borders for custom splits
342                            gig::DimensionRegion* d =
343                                region->pDimensionRegions[c + (j << bitpos)];
344                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
345                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;
346                          int v = upperLimit + 1;                          int v = upperLimit + 1;
347                          int x2 = int((w - label_width - 1) * v / 128.0 + 0.5);                          int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
348                          if (j == dr && x1 < x2) {                              label_width;
349                              window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          if (x >= clipx2) break;
350                                                     (x2 - x1) - 1, h - 2);                          if (x < clipx1) continue;
351                              break;                          Gdk::Cairo::set_source_rgba(cr, black);
352                            cr->move_to(x + 0.5, y + 1);
353                            cr->line_to(x + 0.5, y + h - 1);
354                            cr->stroke();
355    
356                            // draw fill for zone
357                            bool isSelectedZone = this->dimzones[dimension].count(j);
358                            Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
359                            cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
360                            cr->fill();
361    
362                            // draw text showing the beginning of the dimension zone
363                            // as numeric value to the user
364                            {
365                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
366                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
367                                Gdk::Cairo::set_source_rgba(cr, black);
368                                // get the text dimensions
369                                int text_width, text_height;
370                                layout->get_pixel_size(text_width, text_height);
371                                // move text to the left end of the dimension zone
372                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
373    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
374                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
375    #else
376                                layout->show_in_cairo_context(cr);
377    #endif
378                            }
379                            // draw text showing the end of the dimension zone
380                            // as numeric value to the user
381                            {
382                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
383                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
384                                Gdk::Cairo::set_source_rgba(cr, black);
385                                // get the text dimensions
386                                int text_width, text_height;
387                                layout->get_pixel_size(text_width, text_height);
388                                // move text to the left end of the dimension zone
389                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
390    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
391                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
392    #else
393                                layout->show_in_cairo_context(cr);
394    #endif
395                          }                          }
396                          x1 = x2;  
397                            prevX = x;
398                            prevUpperLimit = upperLimit;
399                      }                      }
400                  } else {                  } else {
401                      if (dr < nbZones) {                      int prevX = 0;
402                          int x1 = int((w - label_width - 1) * dr / double(nbZones) + 0.5);                      for (int j = 0 ; j <= nbZones ; j++) {
403                          int x2 = int((w - label_width - 1) * (dr + 1) / double(nbZones) + 0.5);                          // draw dimension zone's borders for normal splits
404                          window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          int x = int((w - label_width - 1) * j /
405                                                 (x2 - x1) - 1, h - 2);                                      double(nbZones) + 0.5) + label_width;
406                      }                          if (x >= clipx2) break;
407                            if (x < clipx1) continue;
408                            Gdk::Cairo::set_source_rgba(cr, black);
409                            cr->move_to(x + 0.5, y + 1);
410                            cr->line_to(x + 0.5, y + h - 1);
411                            cr->stroke();
412    
413                            if (j != 0) {
414                                // draw fill for zone
415                                bool isSelectedZone = this->dimzones[dimension].count(j-1);
416                                Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
417                                cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
418                                cr->fill();
419    
420                                // draw text showing the beginning of the dimension zone
421                                // as numeric value to the user
422                                {
423                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
424                                    layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
425                                    Gdk::Cairo::set_source_rgba(cr, black);
426                                    // get the text dimensions
427                                    int text_width, text_height;
428                                    layout->get_pixel_size(text_width, text_height);
429                                    // move text to the left end of the dimension zone
430                                    cr->move_to(prevX + 3, y + (h - text_height) / 2);
431    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
432                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
433    #else
434                                    layout->show_in_cairo_context(cr);
435    #endif
436                                }
437                                // draw text showing the end of the dimension zone
438                                // as numeric value to the user
439                                {
440                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
441                                    layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
442                                    Gdk::Cairo::set_source_rgba(cr, black);
443                                    // get the text dimensions
444                                    int text_width, text_height;
445                                    layout->get_pixel_size(text_width, text_height);
446                                    // move text to the left end of the dimension zone
447                                    cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
448    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
449                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
450    #else
451                                    layout->show_in_cairo_context(cr);
452    #endif
453                                }
454                            }
455                            prevX = x;
456                        }      
457                  }                  }
458              }              }
   
459              y += h;              y += h;
460          }          }
461          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 228  bool DimRegionChooser::on_expose_event(G Line 464  bool DimRegionChooser::on_expose_event(G
464      return true;      return true;
465  }  }
466    
 void DimRegionChooser::on_size_request(GtkRequisition* requisition)  
 {  
     *requisition = GtkRequisition();  
     requisition->height = region ? nbDimensions * 20 : 0;  
     requisition->width = 800;  
 }  
   
467  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
468  {  {
469      this->region = region;      this->region = region;
470      dimregno = 0;      maindimregno = 0;
471      nbDimensions = 0;      nbDimensions = 0;
472      if (region) {      if (region) {
473          int bitcount = 0;          int bitcount = 0;
# Line 246  void DimRegionChooser::set_region(gig::R Line 475  void DimRegionChooser::set_region(gig::R
475              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
476              nbDimensions++;              nbDimensions++;
477    
478              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
479                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
480              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
481              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
482          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
483      }      }
484      dimregion_selected();      dimregion_selected();
485        set_size_request(800, region ? nbDimensions * h : 0);
486    
487        labels_changed = true;
488      queue_resize();      queue_resize();
489        queue_draw();
490  }  }
491    
492    void DimRegionChooser::refresh_all() {
493        set_region(region);
494    }
495    
496  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
497                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
498  {  {
499      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
500      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
501      int stereo_bit = 0;          if (!dimRgn) continue;
502      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
503          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
504          if (stereo &&          if (!isValidZone) continue;
505              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
506              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
507          } else {          {
508              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
509                               region->pDimensionDefinitions[dim].zones - 1);  
510              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
511                    this->dimzones.find(it->first);
512                if (itSelectedDimension != this->dimzones.end() &&
513                    itSelectedDimension->second.count(it->second)) continue; // is selected
514    
515                goto notSelected;
516          }          }
517          bitcount += region->pDimensionDefinitions[dim].bits;  
518            dimregs.insert(dimRgn);
519    
520            notSelected:
521            ;
522      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
523  }  }
524    
525    void DimRegionChooser::update_after_resize()
 bool DimRegionChooser::on_button_release_event(GdkEventButton* event)  
526  {  {
527      if (resize.active) {      const uint8_t upperLimit = resize.pos - 1;
528          get_window()->pointer_ungrab(event->time);      gig::Instrument* instr = (gig::Instrument*)region->GetParent();
529          resize.active = false;  
530        int bitpos = 0;
531        for (int j = 0 ; j < resize.dimension ; j++) {
532            bitpos += region->pDimensionDefinitions[j].bits;
533        }
534    
535          if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const int stereobitpos =
536            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
537    
538              int bitpos = 0;      // the velocity dimension must be handled differently than all other
539              for (int j = 0 ; j < resize.dimension ; j++) {      // dimension types, because
540                  bitpos += region->pDimensionDefinitions[j].bits;      // 1. it is currently the only dimension type which allows different zone
541        //    sizes for different cases
542        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
543        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
544            int mask =
545                ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
546            int c = maindimregno & mask; // mask away this dimension
547    
548            if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
549                // the velocity dimension didn't previously have
550                // custom v3 splits, so we initialize all splits with
551                // default values
552                int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
553                for (int j = 0 ; j < nbZones ; j++) {
554                    gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
555                    d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
556              }              }
557              int mask =          }
558                  ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);          if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
559              int c = dimregno & mask; // mask away this dimension              // the velocity dimension didn't previously have
560                // custom v2 splits, so we initialize all splits with
561              if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {              // default values
562                  // the velocity dimension didn't previously have              int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
563                  // custom v3 splits, so we initialize all splits with              for (int j = 0 ; j < nbZones ; j++) {
564                  // default values                  gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
565                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
566                  for (int j = 0 ; j < nbZones ; j++) {              }
567                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];          }
568                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);  
569            int index = c + (resize.zone << bitpos);
570            gig::DimensionRegion* d = region->pDimensionRegions[index];
571            // update both v2 and v3 values
572            d->DimensionUpperLimits[resize.dimension] = upperLimit;
573            d->VelocityUpperLimit = upperLimit;
574            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
575                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
576                d->DimensionUpperLimits[resize.dimension] = upperLimit;
577                d->VelocityUpperLimit = upperLimit;
578            }
579    
580            if (modifyalldimregs) {
581                gig::Region* rgn = NULL;
582                for (int key = 0; key < 128; ++key) {
583                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
584                    rgn = instr->GetRegion(key);
585                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
586                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
587                    if (!dimdef) continue;
588                    if (dimdef->zones != resize.dimensionDef.zones) continue;
589                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
590                    assert(iDim >= 0 && iDim < rgn->Dimensions);
591    
592                    // the dimension layout might be completely different in this
593                    // region, so we have to recalculate bitpos etc for this region
594                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
595                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
596                    const int selection = resize.zone << bitpos;
597    
598                    // primitive and inefficient loop implementation, however due to
599                    // this circumstance the loop code is much simpler, and its lack
600                    // of runtime efficiency should not be notable in practice
601                    for (int idr = 0; idr < 256; ++idr) {
602                        const int index = (idr & stencil) | selection;
603                        assert(index >= 0 && index < 256);
604                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
605                        if (!dr) continue;
606                        dr->DimensionUpperLimits[iDim] = upperLimit;
607                        d->VelocityUpperLimit = upperLimit;
608                  }                  }
609              }              }
610              if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {          } else if (modifyallregions) { // implies modifyalldimregs is false ...
611                  // the velocity dimension didn't previously have              // resolve the precise case we need to modify for all other regions
612                  // custom v2 splits, so we initialize all splits with              DimensionCase dimCase = dimensionCaseOf(d);
613                  // default values              // apply the velocity upper limit change to that resolved dim case
614                // of all regions ...
615                gig::Region* rgn = NULL;
616                for (int key = 0; key < 128; ++key) {
617                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
618                    rgn = instr->GetRegion(key);
619                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
620                    if (!dimdef) continue;
621                    if (dimdef->zones != resize.dimensionDef.zones) continue;
622                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
623                    assert(iDim >= 0 && iDim < rgn->Dimensions);
624    
625                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
626                    for (int i = 0; i < dimrgns.size(); ++i) {
627                        gig::DimensionRegion* dr = dimrgns[i];
628                        dr->DimensionUpperLimits[iDim] = upperLimit;
629                        dr->VelocityUpperLimit = upperLimit;
630                    }
631                }
632            }
633        } else {
634            for (int i = 0 ; i < region->DimensionRegions ; ) {
635                if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
636                    // the dimension didn't previously have custom
637                    // limits, so we have to set default limits for
638                    // all the dimension regions
639                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
640    
641                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
642                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
643                      d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
644                  }                  }
645              }              }
646                int index = i + (resize.zone << bitpos);
647              gig::DimensionRegion *d = region->pDimensionRegions[c + resize.offset];              gig::DimensionRegion* d = region->pDimensionRegions[index];
648              // update both v2 and v3 values              d->DimensionUpperLimits[resize.dimension] = upperLimit;
649              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
650              d->VelocityUpperLimit = resize.pos - 1;              if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
651                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
652          } else {                  d->DimensionUpperLimits[resize.dimension] = upperLimit;
653              for (int i = 0 ; i < region->DimensionRegions ; ) {              }
654    #endif
655                  if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              int bitpos = 0;
656                      // the dimension didn't previously have custom              int j;
657                      // limits, so we have to set default limits for              for (j = 0 ; j < region->Dimensions ; j++) {
658                      // all the dimension regions                  if (j != resize.dimension) {
659                      int bitpos = 0;                      int maxzones = 1 << region->pDimensionDefinitions[j].bits;
660                      for (int j = 0 ; j < resize.dimension ; j++) {                      int dimj = (i >> bitpos) & (maxzones - 1);
661                          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);  
                     }  
662                  }                  }
663                  gig::DimensionRegion *d = region->pDimensionRegions[i + resize.offset];                  bitpos += region->pDimensionDefinitions[j].bits;
664                  d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              }
665                if (j == region->Dimensions) break;
666                i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
667            }
668    
669                  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
670                  int j;              gig::Region* rgn = NULL;
671                  for (j = 0 ; j < region->Dimensions ; j++) {              for (int key = 0; key < 128; ++key) {
672                      if (j != resize.dimension) {                  if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
673                          int maxzones = 1 << region->pDimensionDefinitions[j].bits;                  rgn = instr->GetRegion(key);
674                          int dimj = (i >> bitpos) & (maxzones - 1);                  gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
675                          if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;                  if (!dimdef) continue;
676                      }                  if (dimdef->zones != resize.dimensionDef.zones) continue;
677                      bitpos += region->pDimensionDefinitions[j].bits;                  const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
678                    assert(iDim >= 0 && iDim < rgn->Dimensions);
679    
680                    // the dimension layout might be completely different in this
681                    // region, so we have to recalculate bitpos etc for this region
682                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
683                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
684                    const int selection = resize.zone << bitpos;
685    
686                    // this loop implementation is less efficient than the above's
687                    // loop implementation (which skips unnecessary dimension regions)
688                    // however this code is much simpler, and its lack of runtime
689                    // efficiency should not be notable in practice
690                    for (int idr = 0; idr < 256; ++idr) {
691                        const int index = (idr & stencil) | selection;
692                        assert(index >= 0 && index < 256);
693                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
694                        if (!dr) continue;
695                        dr->DimensionUpperLimits[iDim] = upperLimit;
696                  }                  }
                 if (j == region->Dimensions) break;  
                 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);  
697              }              }
698          }          }
699        }
700    }
701    
702    bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
703    {
704        if (resize.active) {
705    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
706            get_window()->pointer_ungrab(event->time);
707    #else
708            Glib::wrap(event->device, true)->ungrab(event->time);
709    #endif
710            resize.active = false;
711    
712          region_changed();          region_changed();
713    
714          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 377  bool DimRegionChooser::on_button_press_e Line 726  bool DimRegionChooser::on_button_press_e
726          event->x >= label_width && event->x < w) {          event->x >= label_width && event->x < w) {
727    
728          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
729              Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
730              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
731                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
732                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
733                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
734                                         double_arrow, event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
735                                           event->time);
736    #else
737                Glib::wrap(event->device, true)->grab(get_window(),
738                                                      Gdk::OWNERSHIP_NONE,
739                                                      false,
740                                                      Gdk::BUTTON_RELEASE_MASK |
741                                                      Gdk::POINTER_MOTION_MASK |
742                                                      Gdk::POINTER_MOTION_HINT_MASK,
743                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
744                                                      event->time);
745    #endif
746              resize.active = true;              resize.active = true;
747          } else {          } else {
748              int ydim = int(event->y / h);              int ydim = int(event->y / h);
# Line 401  bool DimRegionChooser::on_button_press_e Line 761  bool DimRegionChooser::on_button_press_e
761              }              }
762    
763              int i = dim;              int i = dim;
764              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
765              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
766              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
767    
768              bool customsplits =              bool customsplits =
769                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 415  bool DimRegionChooser::on_button_press_e Line 775  bool DimRegionChooser::on_button_press_e
775    
776                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
777                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
778                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
779                          if (val <= d->DimensionUpperLimits[i]) break;                          if (val <= d->DimensionUpperLimits[i]) break;
780                      }                      }
781                  } else {                  } else {
782                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
783                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
784                          if (val <= d->VelocityUpperLimit) break;                          if (val <= d->VelocityUpperLimit) break;
785                      }                      }
786                  }                  }
# Line 433  bool DimRegionChooser::on_button_press_e Line 793  bool DimRegionChooser::on_button_press_e
793                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
794                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
795                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
796              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
797                this->maindimregno = c | (z << bitpos);
798              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
799    
800                if (multiSelectKeyDown) {
801                    if (dimzones[this->maindimtype].count(z)) {
802                        if (dimzones[this->maindimtype].size() > 1) {
803                            dimzones[this->maindimtype].erase(z);
804                        }
805                    } else {
806                        dimzones[this->maindimtype].insert(z);
807                    }
808                } else {
809                    this->dimzones.clear();
810                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
811                         it != this->maindimcase.end(); ++it)
812                    {
813                        this->dimzones[it->first].insert(it->second);
814                    }
815                }
816    
817              focus_line = dim;              focus_line = dim;
818              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
819              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
820              dimregion_selected();              dimregion_selected();
821    
822                if (event->button == 3) {
823                    printf("dimregion right click\n");
824                    popup_menu_inside_dimregion->popup(event->button, event->time);
825                }
826    
827                queue_draw();
828          }          }
829      }      }
830      return true;      return true;
# Line 464  bool DimRegionChooser::on_motion_notify_ Line 847  bool DimRegionChooser::on_motion_notify_
847          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
848    
849          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();  
   
850              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;
851              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;
852              int y = resize.dimension * h;              int y = resize.dimension * h;
853                int x1, x2;
854              if (resize.selected == resize.none) {              if (k > resize.pos) {
855                  if (resize.pos != resize.min && resize.pos != resize.max) {                  x1 = prevx;
856                      window->draw_line(white, prevx, y + 1, prevx, y + h - 2);                  x2 = x;
                 }  
857              } else {              } else {
858                  gc->set_foreground(red);                  x1 = x;
859                    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);  
                 }  
860              }              }
861              window->draw_line(black, x, y + 1, x, y + h - 2);              Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
862    
863              resize.pos = k;              resize.pos = k;
864                update_after_resize();
865                get_window()->invalidate_rect(rect, false); // not sufficient ...
866                queue_draw(); // ... so do a complete redraw instead.
867          }          }
868      } else {      } else {
869          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
870              if (!cursor_is_resize) {              if (!cursor_is_resize) {
871                  Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
872                  window->set_cursor(double_arrow);                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
873    #else
874                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
875    #endif
876                  cursor_is_resize = true;                  cursor_is_resize = true;
877              }              }
878          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 532  bool DimRegionChooser::is_in_resize_zone Line 899  bool DimRegionChooser::is_in_resize_zone
899          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
900    
901          int c = 0;          int c = 0;
902          if (dimregno >= 0) {          if (maindimregno >= 0) {
903              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
904              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
905          }          }
906          const bool customsplits =          const bool customsplits =
907              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 546  bool DimRegionChooser::is_in_resize_zone Line 913  bool DimRegionChooser::is_in_resize_zone
913          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
914              int prev_limit = 0;              int prev_limit = 0;
915              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
916                  gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                  gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
917                  const int upperLimit =                  const int upperLimit =
918                      (customsplits) ?                      (customsplits) ?
919                          (d->DimensionUpperLimits[dim]) ?                          (d->DimensionUpperLimits[dim]) ?
# Line 557  bool DimRegionChooser::is_in_resize_zone Line 924  bool DimRegionChooser::is_in_resize_zone
924                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
925                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
926                      resize.dimension = dim;                      resize.dimension = dim;
927                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
928                        resize.zone = iZone;
929                      resize.pos = limit;                      resize.pos = limit;
930                      resize.min = prev_limit;                      resize.min = prev_limit;
931    
932                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
933                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
934                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
935                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
936    
937                      iZone++;                      iZone++;
938                      gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
939    
940                      const int upperLimit =                      const int upperLimit =
941                          (customsplits) ?                          (customsplits) ?
# Line 598  sigc::signal<void>& DimRegionChooser::si Line 966  sigc::signal<void>& DimRegionChooser::si
966    
967  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
968  {  {
969      // 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
970      // fokus.      // to set focus
971      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
972          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
973          if (!has_focus()) {          if (!has_focus()) {
# Line 631  bool DimRegionChooser::on_focus(Gtk::Dir Line 999  bool DimRegionChooser::on_focus(Gtk::Dir
999              }              }
1000          }          }
1001      } else if (!has_focus()) {      } else if (!has_focus()) {
1002          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1003          grab_focus();          grab_focus();
1004          return true;          return true;
1005      } else {      } else {
1006          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1007        }
1008        return false;
1009    }
1010    
1011    void DimRegionChooser::split_dimension_zone() {    
1012        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1013        try {
1014            if (!modifyallregions) {
1015                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1016            } else {
1017                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1018                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1019                assert(pMaindimdef != NULL);
1020                // retain structure by value since the original region will be
1021                // modified in the loop below as well
1022                gig::dimension_def_t maindimdef = *pMaindimdef;
1023                std::vector<gig::Region*> ignoredAll;
1024                std::vector<gig::Region*> ignoredMinor;
1025                std::vector<gig::Region*> ignoredCritical;
1026                gig::Region* rgn = NULL;
1027                for (int key = 0; key < 128; ++key) {
1028                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1029                    rgn = instr->GetRegion(key);
1030    
1031                    // ignore all regions which do not exactly match the dimension
1032                    // layout of the selected region where this operation was emitted
1033                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1034                    if (!dimdef) {
1035                        ignoredAll.push_back(rgn);
1036                        ignoredMinor.push_back(rgn);
1037                        continue;
1038                    }
1039                    if (dimdef->zones != maindimdef.zones) {
1040                        ignoredAll.push_back(rgn);
1041                        ignoredCritical.push_back(rgn);
1042                        continue;
1043                    }
1044    
1045                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1046                }
1047                if (!ignoredAll.empty()) {
1048                    Glib::ustring txt;
1049                    if (ignoredCritical.empty())
1050                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1051                    else if (ignoredMinor.empty())
1052                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1053                    else
1054                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1055                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1056                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1057                    Gtk::MessageDialog msg(txt, false, type);
1058                    msg.run();
1059                }
1060            }
1061        } catch (RIFF::Exception e) {
1062            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1063            msg.run();
1064        } catch (...) {
1065            Glib::ustring txt = _("An unknown exception occurred!");
1066            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1067            msg.run();
1068      }      }
1069        refresh_all();
1070    }
1071    
1072    void DimRegionChooser::delete_dimension_zone() {
1073        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1074        try {
1075            if (!modifyallregions) {
1076                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1077            } else {
1078                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1079                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1080                assert(pMaindimdef != NULL);
1081                // retain structure by value since the original region will be
1082                // modified in the loop below as well
1083                gig::dimension_def_t maindimdef = *pMaindimdef;
1084                std::vector<gig::Region*> ignoredAll;
1085                std::vector<gig::Region*> ignoredMinor;
1086                std::vector<gig::Region*> ignoredCritical;
1087                gig::Region* rgn = NULL;
1088                for (int key = 0; key < 128; ++key) {
1089                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1090                    rgn = instr->GetRegion(key);
1091    
1092                    // ignore all regions which do not exactly match the dimension
1093                    // layout of the selected region where this operation was emitted
1094                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1095                    if (!dimdef) {
1096                        ignoredAll.push_back(rgn);
1097                        ignoredMinor.push_back(rgn);
1098                        continue;
1099                    }
1100                    if (dimdef->zones != maindimdef.zones) {
1101                        ignoredAll.push_back(rgn);
1102                        ignoredCritical.push_back(rgn);
1103                        continue;
1104                    }
1105    
1106                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1107                }
1108                if (!ignoredAll.empty()) {
1109                    Glib::ustring txt;
1110                    if (ignoredCritical.empty())
1111                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1112                    else if (ignoredMinor.empty())
1113                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1114                    else
1115                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1116                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1117                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1118                    Gtk::MessageDialog msg(txt, false, type);
1119                    msg.run();
1120                }
1121            }
1122        } catch (RIFF::Exception e) {
1123            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1124            msg.run();
1125        } catch (...) {
1126            Glib::ustring txt = _("An unknown exception occurred!");
1127            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1128            msg.run();
1129        }
1130        refresh_all();
1131    }
1132    
1133    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1134        //printf("key down 0x%x\n", key->keyval);
1135        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1136            multiSelectKeyDown = true;
1137        //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
1138        /*if (key->keyval == GDK_KEY_Left)
1139            select_prev_dimzone();
1140        if (key->keyval == GDK_KEY_Right)
1141            select_next_dimzone();
1142        if (key->keyval == GDK_KEY_Up)
1143            select_prev_dimension();
1144        if (key->keyval == GDK_KEY_Down)
1145            select_next_dimension();*/
1146        return false;
1147    }
1148    
1149    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1150        //printf("key up 0x%x\n", key->keyval);
1151        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1152            multiSelectKeyDown = false;
1153    
1154        if (!has_focus()) return false;
1155    
1156        if (key->keyval == GDK_KEY_Left)
1157            select_prev_dimzone();
1158        if (key->keyval == GDK_KEY_Right)
1159            select_next_dimzone();
1160        if (key->keyval == GDK_KEY_Up)
1161            select_prev_dimension();
1162        if (key->keyval == GDK_KEY_Down)
1163            select_next_dimension();
1164    
1165        return false;
1166    }
1167    
1168    void DimRegionChooser::resetSelectedZones() {
1169        this->dimzones.clear();
1170        if (!region) {
1171            queue_draw(); // redraw required parts
1172            return;
1173        }
1174        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1175            queue_draw(); // redraw required parts
1176            return;
1177        }
1178        if (!region->pDimensionRegions[maindimregno]) {
1179            queue_draw(); // redraw required parts
1180            return;
1181        }
1182        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1183    
1184        bool isValidZone;
1185        this->maindimcase = dimensionCaseOf(dimrgn);
1186    
1187        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1188             it != this->maindimcase.end(); ++it)
1189        {
1190            this->dimzones[it->first].insert(it->second);
1191        }
1192    
1193        // redraw required parts
1194        queue_draw();
1195    }
1196    
1197    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1198        if (!region) return false; //.selection failed
1199    
1200        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1201            if (region->pDimensionRegions[dr] == dimrgn) {
1202                // reset dim region zone selection to the requested specific dim region case
1203                maindimregno = dr;
1204                resetSelectedZones();
1205    
1206                // emit signal that dimregion selection has changed, for external entities
1207                dimregion_selected();
1208    
1209                return true; // selection success
1210            }
1211        }
1212    
1213        return false; //.selection failed
1214    }
1215    
1216    void DimRegionChooser::select_next_dimzone() {
1217        select_dimzone_by_dir(+1);
1218    }
1219    
1220    void DimRegionChooser::select_prev_dimzone() {
1221        select_dimzone_by_dir(-1);
1222    }
1223    
1224    void DimRegionChooser::select_dimzone_by_dir(int dir) {
1225        if (!region) return;
1226        if (!region->Dimensions) return;
1227        if (focus_line < 0) focus_line = 0;
1228        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1229    
1230        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1231        if (maindimtype == gig::dimension_none) {
1232            printf("maindimtype -> none\n");
1233            return;
1234        }
1235    
1236        if (maindimcase.empty()) {
1237            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1238            if (maindimcase.empty()) {
1239                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1240                return;
1241            }
1242        }
1243    
1244        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1245        if (z < 0) z = 0;
1246        if (z >= region->pDimensionDefinitions[focus_line].zones)
1247            z = region->pDimensionDefinitions[focus_line].zones - 1;
1248    
1249        maindimcase[maindimtype] = z;
1250    
1251        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1252        if (!dr) {
1253            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1254            return;
1255        }
1256    
1257        maindimregno = getDimensionRegionIndex(dr);
1258    
1259        // reset selected dimregion zones
1260        dimzones.clear();
1261        for (DimensionCase::const_iterator it = maindimcase.begin();
1262             it != maindimcase.end(); ++it)
1263        {
1264            dimzones[it->first].insert(it->second);
1265        }
1266    
1267        dimregion_selected();
1268    
1269        // disabled: would overwrite dimregno with wrong value
1270        //refresh_all();
1271        // so requesting just a raw repaint instead:
1272        queue_draw();
1273    }
1274    
1275    void DimRegionChooser::select_next_dimension() {
1276        if (!region) return;
1277        focus_line++;
1278        if (focus_line >= region->Dimensions)
1279            focus_line = region->Dimensions - 1;
1280        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1281        queue_draw();
1282    }
1283    
1284    void DimRegionChooser::select_prev_dimension() {
1285        if (!region) return;
1286        focus_line--;
1287        if (focus_line < 0)
1288            focus_line = 0;
1289        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1290        queue_draw();
1291    }
1292    
1293    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1294        if (!region) return NULL;
1295        return region->pDimensionRegions[maindimregno];
1296  }  }

Legend:
Removed from v.1656  
changed lines
  Added in v.3123

  ViewVC Help
Powered by ViewVC