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

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

  ViewVC Help
Powered by ViewVC