/[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 1261 by persson, Thu Jul 5 17:12:20 2007 UTC revision 3089 by schoenebeck, Sun Jan 15 19:18:39 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        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()  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        actionGroup = Gtk::ActionGroup::create();
96        actionGroup->add(
97            Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),
98            sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
99        );
100        actionGroup->add(
101            Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),
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++) {      labels_changed = true;
128          dimvalue_from[i] = 0;  
129          dimvalue_to[i] = 1;      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    
158  bool DimRegionChooser::on_expose_event(GdkEventExpose* event)  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
159    bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
160  {  {
161        double clipx1 = e->area.x;
162        double clipx2 = e->area.x + e->area.width;
163        double clipy1 = e->area.y;
164        double clipy2 = e->area.y + e->area.height;
165    
166        const Cairo::RefPtr<Cairo::Context>& cr =
167            get_window()->create_cairo_context();
168    #else
169    bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
170    {
171        double clipx1, clipx2, clipy1, clipy2;
172        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
173    #endif
174    
175      if (!region) return true;      if (!region) return true;
176    
177      // This is where we draw on the window      // This is where we draw on the window
178      Glib::RefPtr<Gdk::Window> window = get_window();      int w = get_width();
179      Glib::RefPtr<Pango::Context> context = get_pango_context();      Glib::RefPtr<Pango::Context> context = get_pango_context();
180    
181      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
182        cr->set_line_width(1);
183    
     window->clear();  
   
     // draw labels on the left (reflecting the dimension type)  
184      int y = 0;      int y = 0;
185      double maxwidth = 0;      if (labels_changed || label_width - 10 > clipx1) {
186      for (int i = 0 ; i < region->Dimensions ; i++) {          // draw labels on the left (reflecting the dimension type)
187          int nbZones = region->pDimensionDefinitions[i].zones;          double maxwidth = 0;
188          if (nbZones) {          for (int i = 0 ; i < region->Dimensions ; i++) {
189              const char* dstr;              int nbZones = region->pDimensionDefinitions[i].zones;
190              char dstrbuf[10];              if (nbZones) {
191              switch (region->pDimensionDefinitions[i].dimension) {                  const char* dstr;
192              case gig::dimension_none: dstr="none"; break;                  char dstrbuf[10];
193              case gig::dimension_samplechannel: dstr="samplechannel"; break;                  switch (region->pDimensionDefinitions[i].dimension) {
194              case gig::dimension_layer: dstr="layer"; break;                  case gig::dimension_none: dstr=_("none"); break;
195              case gig::dimension_velocity: dstr="velocity"; break;                  case gig::dimension_samplechannel: dstr=_("samplechannel");
196              case gig::dimension_channelaftertouch: dstr="channelaftertouch"; break;                      break;
197              case gig::dimension_releasetrigger: dstr="releasetrigger"; break;                  case gig::dimension_layer: dstr=_("layer"); break;
198              case gig::dimension_keyboard: dstr="keyboard"; break;                  case gig::dimension_velocity: dstr=_("velocity"); break;
199              case gig::dimension_roundrobin: dstr="roundrobin"; break;                  case gig::dimension_channelaftertouch:
200              case gig::dimension_random: dstr="random"; break;                      dstr=_("channelaftertouch"); break;
201              case gig::dimension_smartmidi: dstr="smartmidi"; break;                  case gig::dimension_releasetrigger:
202              case gig::dimension_roundrobinkeyboard: dstr="roundrobinkeyboard"; break;                      dstr=_("releasetrigger"); break;
203              case gig::dimension_modwheel: dstr="modwheel"; break;                  case gig::dimension_keyboard: dstr=_("keyswitching"); break;
204              case gig::dimension_breath: dstr="breath"; break;                  case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
205              case gig::dimension_foot: dstr="foot"; break;                  case gig::dimension_random: dstr=_("random"); break;
206              case gig::dimension_portamentotime: dstr="portamentotime"; break;                  case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
207              case gig::dimension_effect1: dstr="effect1"; break;                  case gig::dimension_roundrobinkeyboard:
208              case gig::dimension_effect2: dstr="effect2"; break;                      dstr=_("roundrobinkeyboard"); break;
209              case gig::dimension_genpurpose1: dstr="genpurpose1"; break;                  case gig::dimension_modwheel: dstr=_("modwheel"); break;
210              case gig::dimension_genpurpose2: dstr="genpurpose2"; break;                  case gig::dimension_breath: dstr=_("breath"); break;
211              case gig::dimension_genpurpose3: dstr="genpurpose3"; break;                  case gig::dimension_foot: dstr=_("foot"); break;
212              case gig::dimension_genpurpose4: dstr="genpurpose4"; break;                  case gig::dimension_portamentotime:
213              case gig::dimension_sustainpedal: dstr="sustainpedal"; break;                      dstr=_("portamentotime"); break;
214              case gig::dimension_portamento: dstr="portamento"; break;                  case gig::dimension_effect1: dstr=_("effect1"); break;
215              case gig::dimension_sostenutopedal: dstr="sostenutopedal"; break;                  case gig::dimension_effect2: dstr=_("effect2"); break;
216              case gig::dimension_softpedal: dstr="softpedal"; break;                  case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
217              case gig::dimension_genpurpose5: dstr="genpurpose5"; break;                  case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
218              case gig::dimension_genpurpose6: dstr="genpurpose6"; break;                  case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
219              case gig::dimension_genpurpose7: dstr="genpurpose7"; break;                  case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
220              case gig::dimension_genpurpose8: dstr="genpurpose8"; break;                  case gig::dimension_sustainpedal:
221              case gig::dimension_effect1depth: dstr="effect1depth"; break;                      dstr=_("sustainpedal"); break;
222              case gig::dimension_effect2depth: dstr="effect2depth"; break;                  case gig::dimension_portamento: dstr=_("portamento"); break;
223              case gig::dimension_effect3depth: dstr="effect3depth"; break;                  case gig::dimension_sostenutopedal:
224              case gig::dimension_effect4depth: dstr="effect4depth"; break;                      dstr=_("sostenutopedal"); break;
225              case gig::dimension_effect5depth: dstr="effect5depth"; break;                  case gig::dimension_softpedal: dstr=_("softpedal"); break;
226              default:                  case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
227                  sprintf(dstrbuf, "%d",                  case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
228                          region->pDimensionDefinitions[i].dimension);                  case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
229                  dstr = dstrbuf;                  case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
230                  break;                  case gig::dimension_effect1depth:
231              }                      dstr=_("effect1depth"); break;
232              layout->set_text(dstr);                  case gig::dimension_effect2depth:
233                        dstr=_("effect2depth"); break;
234              Pango::Rectangle rectangle = layout->get_logical_extents();                  case gig::dimension_effect3depth:
235              double text_w = double(rectangle.get_width()) / Pango::SCALE;                      dstr=_("effect3depth"); break;
236              if (text_w > maxwidth) maxwidth = text_w;                  case gig::dimension_effect4depth:
237              double text_h = double(rectangle.get_height()) / Pango::SCALE;                      dstr=_("effect4depth"); break;
238              Glib::RefPtr<const Gdk::GC> fg = get_style()->get_fg_gc(get_state());                  case gig::dimension_effect5depth:
239              window->draw_layout(fg, 4, int(y + (h - text_h) / 2 + 0.5), layout);                      dstr=_("effect5depth"); break;
240                    default:
241                        sprintf(dstrbuf, "%d",
242                                region->pDimensionDefinitions[i].dimension);
243                        dstr = dstrbuf;
244                        break;
245                    }
246                    layout->set_text(dstr);
247    
248                    Pango::Rectangle rectangle = layout->get_logical_extents();
249                    double text_w = double(rectangle.get_width()) / Pango::SCALE;
250                    if (text_w > maxwidth) maxwidth = text_w;
251    
252                    if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
253                        double text_h = double(rectangle.get_height()) /
254                            Pango::SCALE;
255    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
256                        const Gdk::Color fg = get_style()->get_fg(get_state());
257    #else
258                        const Gdk::RGBA fg =
259                            get_style_context()->get_color(get_state_flags());
260    #endif
261                        Gdk::Cairo::set_source_rgba(cr, fg);
262                        cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
263    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
264                        pango_cairo_show_layout(cr->cobj(), layout->gobj());
265    #else
266                        layout->show_in_cairo_context(cr);
267    #endif
268                    }
269                }
270                y += h;
271          }          }
272          y += h;          label_width = int(maxwidth + 10);
273            labels_changed = false;
274      }      }
275        if (label_width >= clipx2) return true;
276    
277      // draw dimensions' zones areas      // draw dimensions' zones areas
278      y = 0;      y = 0;
279      int bitpos = 0;      int bitpos = 0;
     label_width = int(maxwidth + 10);  
280      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
281          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
282          if (nbZones) {          if (nbZones) {
283              // 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));  
284    
285              // draw dimension's zone borders              if (y >= clipy2) break;
286              if (customsplits) {              if (y + h > clipy1) {
287                  window->draw_line(black, label_width, y + 1, label_width, y + h - 2);                  // draw focus rectangle around dimension's label and zones
288                  for (int j = 0 ; j < nbZones ; j++) {                  if (has_focus() && focus_line == i) {
289                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
290                      int upperLimit = d->DimensionUpperLimits[i];                      Gdk::Rectangle farea(0, y, 150, h);
291                      if (!upperLimit) upperLimit = d->VelocityUpperLimit;                      get_style()->paint_focus(get_window(), get_state(), farea,
292                      int v = upperLimit + 1;                                               *this, "",
293                      int x = int((w - label_width - 1) * v / 128.0 + 0.5);                                               0, y, label_width, h);
294                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);  #else
295                        get_style_context()->render_focus(cr,
296                                                          0, y, label_width, h);
297    #endif
298                  }                  }
299              } else {  
300                  for (int j = 0 ; j <= nbZones ; j++) {                  // draw top and bottom lines of dimension's zones
301                      int x = int((w - label_width - 1) * j / double(nbZones) + 0.5);                  Gdk::Cairo::set_source_rgba(cr, black);
302                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);                  cr->move_to(label_width, y + 0.5);
303                    cr->line_to(w, y + 0.5);
304                    cr->move_to(w, y + h - 0.5);
305                    cr->line_to(label_width, y + h - 0.5);
306                    cr->stroke();
307    
308                    // erase whole dimension's zones area
309                    Gdk::Cairo::set_source_rgba(cr, white);
310                    cr->rectangle(label_width + 1, y + 1,
311                                  (w - label_width - 2), h - 2);
312                    cr->fill();
313    
314                    int c = 0;
315                    if (maindimregno >= 0) {
316                        int mask =
317                            ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
318                              bitpos);
319                        c = maindimregno & mask; // mask away this dimension
320                  }                  }
321              }                  bool customsplits =
322                        ((region->pDimensionDefinitions[i].split_type ==
323                          gig::split_type_normal &&
324                          region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
325                         (region->pDimensionDefinitions[i].dimension ==
326                          gig::dimension_velocity &&
327                          region->pDimensionRegions[c]->VelocityUpperLimit));
328    
329              // draw fill for currently selected zone                  // draw dimension zones
330              if (dimregno >= 0) {                  Gdk::Cairo::set_source_rgba(cr, black);
                 gc->set_foreground(red);  
                 int dr = (dimregno >> bitpos) & ((1 << region->pDimensionDefinitions[i].bits) - 1);  
331                  if (customsplits) {                  if (customsplits) {
332                      int x1 = 0;                      cr->move_to(label_width + 0.5, y + 1);
333                        cr->line_to(label_width + 0.5, y + h - 1);
334                        int prevX = label_width;
335                        int prevUpperLimit = -1;
336    
337                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
338                          gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                          // draw dimension zone's borders for custom splits
339                            gig::DimensionRegion* d =
340                                region->pDimensionRegions[c + (j << bitpos)];
341                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
342                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;
343                          int v = upperLimit + 1;                          int v = upperLimit + 1;
344                          int x2 = int((w - label_width - 1) * v / 128.0 + 0.5);                          int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
345                          if (j == dr && x1 < x2) {                              label_width;
346                              window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          if (x >= clipx2) break;
347                                                     (x2 - x1) - 1, h - 2);                          if (x < clipx1) continue;
348                              break;                          Gdk::Cairo::set_source_rgba(cr, black);
349                            cr->move_to(x + 0.5, y + 1);
350                            cr->line_to(x + 0.5, y + h - 1);
351                            cr->stroke();
352    
353                            // draw fill for zone
354                            bool isSelectedZone = this->dimzones[dimension].count(j);
355                            Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
356                            cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
357                            cr->fill();
358    
359                            // draw text showing the beginning of the dimension zone
360                            // as numeric value to the user
361                            {
362                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
363                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
364                                Gdk::Cairo::set_source_rgba(cr, black);
365                                // get the text dimensions
366                                int text_width, text_height;
367                                layout->get_pixel_size(text_width, text_height);
368                                // move text to the left end of the dimension zone
369                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
370    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
371                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
372    #else
373                                layout->show_in_cairo_context(cr);
374    #endif
375                            }
376                            // draw text showing the end of the dimension zone
377                            // as numeric value to the user
378                            {
379                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
380                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
381                                Gdk::Cairo::set_source_rgba(cr, black);
382                                // get the text dimensions
383                                int text_width, text_height;
384                                layout->get_pixel_size(text_width, text_height);
385                                // move text to the left end of the dimension zone
386                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
387    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
388                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
389    #else
390                                layout->show_in_cairo_context(cr);
391    #endif
392                          }                          }
393                          x1 = x2;  
394                            prevX = x;
395                            prevUpperLimit = upperLimit;
396                      }                      }
397                  } else {                  } else {
398                      if (dr < nbZones) {                      int prevX = 0;
399                          int x1 = int((w - label_width - 1) * dr / double(nbZones) + 0.5);                      for (int j = 0 ; j <= nbZones ; j++) {
400                          int x2 = int((w - label_width - 1) * (dr + 1) / double(nbZones) + 0.5);                          // draw dimension zone's borders for normal splits
401                          window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          int x = int((w - label_width - 1) * j /
402                                                 (x2 - x1) - 1, h - 2);                                      double(nbZones) + 0.5) + label_width;
403                      }                          if (x >= clipx2) break;
404                            if (x < clipx1) continue;
405                            Gdk::Cairo::set_source_rgba(cr, black);
406                            cr->move_to(x + 0.5, y + 1);
407                            cr->line_to(x + 0.5, y + h - 1);
408                            cr->stroke();
409    
410                            if (j != 0) {
411                                // draw fill for zone
412                                bool isSelectedZone = this->dimzones[dimension].count(j-1);
413                                Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
414                                cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
415                                cr->fill();
416    
417                                // draw text showing the beginning of the dimension zone
418                                // as numeric value to the user
419                                {
420                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
421                                    layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
422                                    Gdk::Cairo::set_source_rgba(cr, black);
423                                    // get the text dimensions
424                                    int text_width, text_height;
425                                    layout->get_pixel_size(text_width, text_height);
426                                    // move text to the left end of the dimension zone
427                                    cr->move_to(prevX + 3, y + (h - text_height) / 2);
428    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
429                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
430    #else
431                                    layout->show_in_cairo_context(cr);
432    #endif
433                                }
434                                // draw text showing the end of the dimension zone
435                                // as numeric value to the user
436                                {
437                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
438                                    layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
439                                    Gdk::Cairo::set_source_rgba(cr, black);
440                                    // get the text dimensions
441                                    int text_width, text_height;
442                                    layout->get_pixel_size(text_width, text_height);
443                                    // move text to the left end of the dimension zone
444                                    cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
445    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
446                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
447    #else
448                                    layout->show_in_cairo_context(cr);
449    #endif
450                                }
451                            }
452                            prevX = x;
453                        }      
454                  }                  }
455              }              }
   
456              y += h;              y += h;
457          }          }
458          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 231  bool DimRegionChooser::on_expose_event(G Line 461  bool DimRegionChooser::on_expose_event(G
461      return true;      return true;
462  }  }
463    
 void DimRegionChooser::on_size_request(GtkRequisition* requisition)  
 {  
     printf("DimRegionChooser::on_size_request\n");  
     *requisition = GtkRequisition();  
     requisition->height = region ? nbDimensions * 20 : 0;  
     requisition->width = 800;  
 }  
   
464  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
465  {  {
466      this->region = region;      this->region = region;
467      dimregno = 0;      maindimregno = 0;
468      nbDimensions = 0;      nbDimensions = 0;
469      if (region) {      if (region) {
470          int bitcount = 0;          int bitcount = 0;
# Line 250  void DimRegionChooser::set_region(gig::R Line 472  void DimRegionChooser::set_region(gig::R
472              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
473              nbDimensions++;              nbDimensions++;
474    
475              int from = dimvalue_from[region->pDimensionDefinitions[dim].dimension];              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
476              int to = dimvalue_to[region->pDimensionDefinitions[dim].dimension];                               region->pDimensionDefinitions[dim].zones - 1);
477              int z;              maindimregno |= (z << bitcount);
             switch (region->pDimensionDefinitions[dim].split_type) {  
             case gig::split_type_normal:  
                 z = int((to + from) / 2.0 / region->pDimensionDefinitions[dim].zone_size);  
                 break;  
             case gig::split_type_bit:  
                 z = std::min(from, region->pDimensionDefinitions[dim].zones - 1);  
                 break;  
             }  
             int mask =  
                 ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) <<  
                   bitcount);  
             dimregno &= mask;  
             dimregno |= (z << bitcount);  
478              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
479          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
480      }      }
481      dimregion_selected();      dimregion_selected();
482        set_size_request(800, region ? nbDimensions * h : 0);
483    
484        labels_changed = true;
485      queue_resize();      queue_resize();
486        queue_draw();
487  }  }
488    
489  bool DimRegionChooser::on_button_release_event(GdkEventButton* event)  void DimRegionChooser::refresh_all() {
490        set_region(region);
491    }
492    
493    void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
494                                          std::set<gig::DimensionRegion*>& dimregs) const
495  {  {
496      if (resize.active) {      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
497          get_window()->pointer_ungrab(event->time);          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
498          resize.active = false;          if (!dimRgn) continue;
499            bool isValidZone;
500            std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
501            if (!isValidZone) continue;
502            for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
503                 it != dimCase.end(); ++it)
504            {
505                if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
506    
507                std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
508                    this->dimzones.find(it->first);
509                if (itSelectedDimension != this->dimzones.end() &&
510                    itSelectedDimension->second.count(it->second)) continue; // is selected
511    
512          if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {              goto notSelected;
513            }
514    
515              int bitpos = 0;          dimregs.insert(dimRgn);
516              for (int j = 0 ; j < resize.dimension ; j++) {  
517                  bitpos += region->pDimensionDefinitions[j].bits;          notSelected:
518            ;
519        }
520    }
521    
522    void DimRegionChooser::update_after_resize()
523    {
524        const uint8_t upperLimit = resize.pos - 1;
525        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
526    
527        int bitpos = 0;
528        for (int j = 0 ; j < resize.dimension ; j++) {
529            bitpos += region->pDimensionDefinitions[j].bits;
530        }
531    
532        const int stereobitpos =
533            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
534    
535        // the velocity dimension must be handled differently than all other
536        // dimension types, because
537        // 1. it is currently the only dimension type which allows different zone
538        //    sizes for different cases
539        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
540        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
541            int mask =
542                ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
543            int c = maindimregno & mask; // mask away this dimension
544    
545            if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
546                // the velocity dimension didn't previously have
547                // custom v3 splits, so we initialize all splits with
548                // default values
549                int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
550                for (int j = 0 ; j < nbZones ; j++) {
551                    gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
552                    d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
553              }              }
554              int mask =          }
555                  ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);          if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
556              int c = dimregno & mask; // mask away this dimension              // the velocity dimension didn't previously have
557                // custom v2 splits, so we initialize all splits with
558              if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {              // default values
559                  // the velocity dimension didn't previously have              int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
560                  // custom v3 splits, so we initialize all splits with              for (int j = 0 ; j < nbZones ; j++) {
561                  // default values                  gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
562                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
563                  for (int j = 0 ; j < nbZones ; j++) {              }
564                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];          }
565                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);  
566            int index = c + (resize.zone << bitpos);
567            gig::DimensionRegion* d = region->pDimensionRegions[index];
568            // update both v2 and v3 values
569            d->DimensionUpperLimits[resize.dimension] = upperLimit;
570            d->VelocityUpperLimit = upperLimit;
571            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
572                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
573                d->DimensionUpperLimits[resize.dimension] = upperLimit;
574                d->VelocityUpperLimit = upperLimit;
575            }
576    
577            if (modifyalldimregs) {
578                gig::Region* rgn = NULL;
579                for (int key = 0; key < 128; ++key) {
580                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
581                    rgn = instr->GetRegion(key);
582                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
583                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
584                    if (!dimdef) continue;
585                    if (dimdef->zones != resize.dimensionDef.zones) continue;
586                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
587                    assert(iDim >= 0 && iDim < rgn->Dimensions);
588    
589                    // the dimension layout might be completely different in this
590                    // region, so we have to recalculate bitpos etc for this region
591                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
592                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
593                    const int selection = resize.zone << bitpos;
594    
595                    // primitive and inefficient loop implementation, however due to
596                    // this circumstance the loop code is much simpler, and its lack
597                    // of runtime efficiency should not be notable in practice
598                    for (int idr = 0; idr < 256; ++idr) {
599                        const int index = (idr & stencil) | selection;
600                        assert(index >= 0 && index < 256);
601                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
602                        if (!dr) continue;
603                        dr->DimensionUpperLimits[iDim] = upperLimit;
604                        d->VelocityUpperLimit = upperLimit;
605                  }                  }
606              }              }
607              if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {          } else if (modifyallregions) { // implies modifyalldimregs is false ...
608                  // the velocity dimension didn't previously have              // resolve the precise case we need to modify for all other regions
609                  // custom v2 splits, so we initialize all splits with              DimensionCase dimCase = dimensionCaseOf(d);
610                  // default values              // apply the velocity upper limit change to that resolved dim case
611                // of all regions ...
612                gig::Region* rgn = NULL;
613                for (int key = 0; key < 128; ++key) {
614                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
615                    rgn = instr->GetRegion(key);
616                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
617                    if (!dimdef) continue;
618                    if (dimdef->zones != resize.dimensionDef.zones) continue;
619                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
620                    assert(iDim >= 0 && iDim < rgn->Dimensions);
621    
622                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
623                    for (int i = 0; i < dimrgns.size(); ++i) {
624                        gig::DimensionRegion* dr = dimrgns[i];
625                        dr->DimensionUpperLimits[iDim] = upperLimit;
626                        dr->VelocityUpperLimit = upperLimit;
627                    }
628                }
629            }
630        } else {
631            for (int i = 0 ; i < region->DimensionRegions ; ) {
632                if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
633                    // the dimension didn't previously have custom
634                    // limits, so we have to set default limits for
635                    // all the dimension regions
636                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
637    
638                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
639                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
640                      d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
641                  }                  }
642              }              }
643                int index = i + (resize.zone << bitpos);
644              gig::DimensionRegion *d = region->pDimensionRegions[c + resize.offset];              gig::DimensionRegion* d = region->pDimensionRegions[index];
645              // update both v2 and v3 values              d->DimensionUpperLimits[resize.dimension] = upperLimit;
646              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
647              d->VelocityUpperLimit = resize.pos - 1;              if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
648                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
649          } else {                  d->DimensionUpperLimits[resize.dimension] = upperLimit;
650              for (int i = 0 ; i < region->DimensionRegions ; ) {              }
651    #endif
652                  if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              int bitpos = 0;
653                      // the dimension didn't previously have custom              int j;
654                      // limits, so we have to set default limits for              for (j = 0 ; j < region->Dimensions ; j++) {
655                      // all the dimension regions                  if (j != resize.dimension) {
656                      int bitpos = 0;                      int maxzones = 1 << region->pDimensionDefinitions[j].bits;
657                      for (int j = 0 ; j < resize.dimension ; j++) {                      int dimj = (i >> bitpos) & (maxzones - 1);
658                          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);  
                     }  
659                  }                  }
660                  gig::DimensionRegion *d = region->pDimensionRegions[i + resize.offset];                  bitpos += region->pDimensionDefinitions[j].bits;
661                  d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              }
662                if (j == region->Dimensions) break;
663                i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
664            }
665    
666                  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
667                  int j;              gig::Region* rgn = NULL;
668                  for (j = 0 ; j < region->Dimensions ; j++) {              for (int key = 0; key < 128; ++key) {
669                      if (j != resize.dimension) {                  if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
670                          int maxzones = 1 << region->pDimensionDefinitions[j].bits;                  rgn = instr->GetRegion(key);
671                          int dimj = (i >> bitpos) & (maxzones - 1);                  gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
672                          if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;                  if (!dimdef) continue;
673                      }                  if (dimdef->zones != resize.dimensionDef.zones) continue;
674                      bitpos += region->pDimensionDefinitions[j].bits;                  const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
675                    assert(iDim >= 0 && iDim < rgn->Dimensions);
676    
677                    // the dimension layout might be completely different in this
678                    // region, so we have to recalculate bitpos etc for this region
679                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
680                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
681                    const int selection = resize.zone << bitpos;
682    
683                    // this loop implementation is less efficient than the above's
684                    // loop implementation (which skips unnecessary dimension regions)
685                    // however this code is much simpler, and its lack of runtime
686                    // efficiency should not be notable in practice
687                    for (int idr = 0; idr < 256; ++idr) {
688                        const int index = (idr & stencil) | selection;
689                        assert(index >= 0 && index < 256);
690                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
691                        if (!dr) continue;
692                        dr->DimensionUpperLimits[iDim] = upperLimit;
693                  }                  }
                 if (j == region->Dimensions) break;  
                 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);  
694              }              }
695          }          }
696        }
697    }
698    
699    bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
700    {
701        if (resize.active) {
702    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
703            get_window()->pointer_ungrab(event->time);
704    #else
705            Glib::wrap(event->device, true)->ungrab(event->time);
706    #endif
707            resize.active = false;
708    
709          region_changed();          region_changed();
710    
711          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 365  bool DimRegionChooser::on_button_release Line 718  bool DimRegionChooser::on_button_release
718    
719  bool DimRegionChooser::on_button_press_event(GdkEventButton* event)  bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
720  {  {
721        int w = get_width();
722      if (region && event->y < nbDimensions * h &&      if (region && event->y < nbDimensions * h &&
723          event->x >= label_width && event->x < w) {          event->x >= label_width && event->x < w) {
724    
725          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
726              Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
727              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
728                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
729                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
730                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
731                                         double_arrow, event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
732                                           event->time);
733    #else
734                Glib::wrap(event->device, true)->grab(get_window(),
735                                                      Gdk::OWNERSHIP_NONE,
736                                                      false,
737                                                      Gdk::BUTTON_RELEASE_MASK |
738                                                      Gdk::POINTER_MOTION_MASK |
739                                                      Gdk::POINTER_MOTION_HINT_MASK,
740                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
741                                                      event->time);
742    #endif
743              resize.active = true;              resize.active = true;
744          } else {          } else {
745              int ydim = int(event->y / h);              int ydim = int(event->y / h);
# Line 393  bool DimRegionChooser::on_button_press_e Line 758  bool DimRegionChooser::on_button_press_e
758              }              }
759    
760              int i = dim;              int i = dim;
761              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
762              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
763              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
764    
765              bool customsplits =              bool customsplits =
766                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 407  bool DimRegionChooser::on_button_press_e Line 772  bool DimRegionChooser::on_button_press_e
772    
773                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
774                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
775                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
776                          if (val <= d->DimensionUpperLimits[i]) break;                          if (val <= d->DimensionUpperLimits[i]) break;
777                      }                      }
778                  } else {                  } else {
779                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
780                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
781                          if (val <= d->VelocityUpperLimit) break;                          if (val <= d->VelocityUpperLimit) break;
782                      }                      }
783                  }                  }
# Line 425  bool DimRegionChooser::on_button_press_e Line 790  bool DimRegionChooser::on_button_press_e
790                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
791                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
792                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
793  #if 0              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
794              switch (region->pDimensionDefinitions[dim].split_type) {              this->maindimregno = c | (z << bitpos);
795              case gig::split_type_normal:              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
796                  dimvalue_from[region->pDimensionDefinitions[dim].dimension] =  
797                      int(z * region->pDimensionDefinitions[dim].zone_size);              if (multiSelectKeyDown) {
798                  dimvalue_to[region->pDimensionDefinitions[dim].dimension] =                  if (dimzones[this->maindimtype].count(z)) {
799                      int((z + 1) * region->pDimensionDefinitions[dim].zone_size) - 1;                      if (dimzones[this->maindimtype].size() > 1) {
800                  break;                          dimzones[this->maindimtype].erase(z);
801              case gig::split_type_bit:                      }
802                  dimvalue_from[region->pDimensionDefinitions[dim].dimension] = z;                  } else {
803                  dimvalue_to[region->pDimensionDefinitions[dim].dimension] = z + 1;                      dimzones[this->maindimtype].insert(z);
804                  break;                  }
805                } else {
806                    this->dimzones.clear();
807                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
808                         it != this->maindimcase.end(); ++it)
809                    {
810                        this->dimzones[it->first].insert(it->second);
811                    }
812              }              }
 #endif  
   
             dimregno = c | (z << bitpos);  
813    
814              focus_line = dim;              focus_line = dim;
815              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
816              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
817              dimregion_selected();              dimregion_selected();
818    
819                if (event->button == 3) {
820                    printf("dimregion right click\n");
821                    popup_menu_inside_dimregion->popup(event->button, event->time);
822                }
823    
824                queue_draw();
825          }          }
826      }      }
827      return true;      return true;
# Line 460  bool DimRegionChooser::on_motion_notify_ Line 835  bool DimRegionChooser::on_motion_notify_
835      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
836    
837      if (resize.active) {      if (resize.active) {
838            int w = get_width();
839          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);
840    
841          if (k < resize.min) k = resize.min;          if (k < resize.min) k = resize.min;
# Line 468  bool DimRegionChooser::on_motion_notify_ Line 844  bool DimRegionChooser::on_motion_notify_
844          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
845    
846          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();  
   
847              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;
848              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;
849              int y = resize.dimension * h;              int y = resize.dimension * h;
850                int x1, x2;
851              if (resize.selected == resize.none) {              if (k > resize.pos) {
852                  if (resize.pos != resize.min && resize.pos != resize.max) {                  x1 = prevx;
853                      window->draw_line(white, prevx, y + 1, prevx, y + h - 2);                  x2 = x;
                 }  
854              } else {              } else {
855                  gc->set_foreground(red);                  x1 = x;
856                    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);  
                 }  
857              }              }
858              window->draw_line(black, x, y + 1, x, y + h - 2);              Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
859    
860              resize.pos = k;              resize.pos = k;
861                update_after_resize();
862                get_window()->invalidate_rect(rect, false); // not sufficient ...
863                queue_draw(); // ... so do a complete redraw instead.
864          }          }
865      } else {      } else {
866          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
867              if (!cursor_is_resize) {              if (!cursor_is_resize) {
868                  Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
869                  window->set_cursor(double_arrow);                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
870    #else
871                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
872    #endif
873                  cursor_is_resize = true;                  cursor_is_resize = true;
874              }              }
875          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 522  bool DimRegionChooser::on_motion_notify_ Line 882  bool DimRegionChooser::on_motion_notify_
882    
883  bool DimRegionChooser::is_in_resize_zone(double x, double y)  bool DimRegionChooser::is_in_resize_zone(double x, double y)
884  {  {
885        int w = get_width();
886      if (region && y < nbDimensions * h && x >= label_width && x < w) {      if (region && y < nbDimensions * h && x >= label_width && x < w) {
887          int ydim = int(y / h);          int ydim = int(y / h);
888          int dim;          int dim;
# Line 535  bool DimRegionChooser::is_in_resize_zone Line 896  bool DimRegionChooser::is_in_resize_zone
896          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
897    
898          int c = 0;          int c = 0;
899          if (dimregno >= 0) {          if (maindimregno >= 0) {
900              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
901              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
902          }          }
903          const bool customsplits =          const bool customsplits =
904              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 549  bool DimRegionChooser::is_in_resize_zone Line 910  bool DimRegionChooser::is_in_resize_zone
910          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
911              int prev_limit = 0;              int prev_limit = 0;
912              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
913                  gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                  gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
914                  const int upperLimit =                  const int upperLimit =
915                      (customsplits) ?                      (customsplits) ?
916                          (d->DimensionUpperLimits[dim]) ?                          (d->DimensionUpperLimits[dim]) ?
# Line 560  bool DimRegionChooser::is_in_resize_zone Line 921  bool DimRegionChooser::is_in_resize_zone
921                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
922                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
923                      resize.dimension = dim;                      resize.dimension = dim;
924                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
925                        resize.zone = iZone;
926                      resize.pos = limit;                      resize.pos = limit;
927                      resize.min = prev_limit;                      resize.min = prev_limit;
928    
929                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
930                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
931                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
932                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
933    
934                      iZone++;                      iZone++;
935                      gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
936    
937                      const int upperLimit =                      const int upperLimit =
938                          (customsplits) ?                          (customsplits) ?
# Line 589  bool DimRegionChooser::is_in_resize_zone Line 951  bool DimRegionChooser::is_in_resize_zone
951      return false;      return false;
952  }  }
953    
954  sigc::signal<void> DimRegionChooser::signal_dimregion_selected()  sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
955  {  {
956      return dimregion_selected;      return dimregion_selected;
957  }  }
958    
959  sigc::signal<void> DimRegionChooser::signal_region_changed()  sigc::signal<void>& DimRegionChooser::signal_region_changed()
960  {  {
961      return region_changed;      return region_changed;
962  }  }
963    
964  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
965  {  {
966      // 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
967      // fokus.      // to set focus
968      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
969          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
970          if (!has_focus()) {          if (!has_focus()) {
# Line 634  bool DimRegionChooser::on_focus(Gtk::Dir Line 996  bool DimRegionChooser::on_focus(Gtk::Dir
996              }              }
997          }          }
998      } else if (!has_focus()) {      } else if (!has_focus()) {
999          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1000          grab_focus();          grab_focus();
1001          return true;          return true;
1002      } else {      } else {
1003          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1004        }
1005        return false;
1006    }
1007    
1008    void DimRegionChooser::split_dimension_zone() {    
1009        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1010        try {
1011            region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1012        } catch (RIFF::Exception e) {
1013            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1014            msg.run();
1015        } catch (...) {
1016            Glib::ustring txt = _("An unknown exception occurred!");
1017            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1018            msg.run();
1019        }
1020        refresh_all();
1021    }
1022    
1023    void DimRegionChooser::delete_dimension_zone() {
1024        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1025        try {
1026            region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1027        } catch (RIFF::Exception e) {
1028            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1029            msg.run();
1030        } catch (...) {
1031            Glib::ustring txt = _("An unknown exception occurred!");
1032            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1033            msg.run();
1034      }      }
1035        refresh_all();
1036    }
1037    
1038    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1039        //printf("key down\n");
1040        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1041            multiSelectKeyDown = true;
1042        return false;
1043    }
1044    
1045    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1046        //printf("key up\n");
1047        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1048            multiSelectKeyDown = false;
1049        return false;
1050    }
1051    
1052    void DimRegionChooser::resetSelectedZones() {
1053        this->dimzones.clear();
1054        if (!region) {
1055            queue_draw(); // redraw required parts
1056            return;
1057        }
1058        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1059            queue_draw(); // redraw required parts
1060            return;
1061        }
1062        if (!region->pDimensionRegions[maindimregno]) {
1063            queue_draw(); // redraw required parts
1064            return;
1065        }
1066        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1067    
1068        bool isValidZone;
1069        this->maindimcase = caseOfDimRegion(dimrgn, &isValidZone);
1070        if (!isValidZone) {
1071            queue_draw(); // redraw required parts
1072            return;
1073        }
1074    
1075        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1076             it != this->maindimcase.end(); ++it)
1077        {
1078            this->dimzones[it->first].insert(it->second);
1079        }
1080    
1081        // redraw required parts
1082        queue_draw();
1083    }
1084    
1085    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1086        if (!region) return false; //.selection failed
1087    
1088        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1089            if (region->pDimensionRegions[dr] == dimrgn) {
1090                // reset dim region zone selection to the requested specific dim region case
1091                maindimregno = dr;
1092                resetSelectedZones();
1093    
1094                // emit signal that dimregion selection has changed, for external entities
1095                dimregion_selected();
1096    
1097                return true; // selection success
1098            }
1099        }
1100    
1101        return false; //.selection failed
1102    }
1103    
1104    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1105        if (!region) return NULL;
1106        return region->pDimensionRegions[maindimregno];
1107  }  }

Legend:
Removed from v.1261  
changed lines
  Added in v.3089

  ViewVC Help
Powered by ViewVC