/[svn]/gigedit/trunk/src/gigedit/regionchooser.cpp
ViewVC logotype

Diff of /gigedit/trunk/src/gigedit/regionchooser.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2151 by persson, Sun Nov 21 12:38:41 2010 UTC revision 3148 by schoenebeck, Thu May 4 11:47:45 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2010 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 20  Line 20 
20  #include "regionchooser.h"  #include "regionchooser.h"
21    
22  #include <algorithm>  #include <algorithm>
23  #include <cmath>  #include <assert.h>
 #include <sstream>  
24    
25  #include <cairomm/context.h>  #include <cairomm/context.h>
26  #include <gdkmm/general.h>  #include <gdkmm/general.h>
27  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
28  #include <gtkmm/stock.h>  #include <gdkmm/pixbuf.h>
29  #include <gtkmm/spinbutton.h>  #include <gtkmm/spinbutton.h>
30  #include <gtkmm/dialog.h>  #include <gtkmm/dialog.h>
31    
32  #include "global.h"  #include "global.h"
33    #include "Settings.h"
34    #include "gfx/builtinpix.h"
35    
36  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 10) || GTKMM_MAJOR_VERSION < 2  #define REGION_BLOCK_HEIGHT             30
37    #define KEYBOARD_HEIGHT                 40
38    
39  #define create_cairo_context()                                          \  struct RegionFeatures {
40      gobj() ? Cairo::RefPtr<Cairo::Context>(                             \      int sampleRefs;
41          new Cairo::Context(gdk_cairo_create(get_window()->gobj()))) :   \      int loops;
     Cairo::RefPtr<Cairo::Context>()  
42    
43  namespace Gdk {      RegionFeatures() {
44      namespace Cairo {          sampleRefs = loops = 0;
         void set_source_color(const ::Cairo::RefPtr< ::Cairo::Context >& cr,  
                               const Gdk::Color& color) {  
             gdk_cairo_set_source_color(cr->cobj(),  
                                        const_cast<GdkColor*>(color.gobj()));  
         }  
45      }      }
46  }  };
 #endif  
47    
48  #define REGION_BLOCK_HEIGHT             20  static RegionFeatures regionFeatures(gig::Region* rgn) {
49  #define KEYBOARD_HEIGHT                 40      RegionFeatures f;
50        for (int i = 0; i < rgn->DimensionRegions; ++i) {
51            gig::DimensionRegion* dr = rgn->pDimensionRegions[i];
52            if (dr->pSample) f.sampleRefs++;
53            // the user doesn't care about loop if there is no valid sample reference
54            if (dr->pSample && dr->SampleLoops) f.loops++;
55        }
56        return f;
57    }
58    
59  void SortedRegions::update(gig::Instrument* instrument) {  void SortedRegions::update(gig::Instrument* instrument) {
60      // Usually, the regions in a gig file are ordered after their key      // Usually, the regions in a gig file are ordered after their key
# Line 74  gig::Region* SortedRegions::first() { Line 77  gig::Region* SortedRegions::first() {
77  }  }
78    
79  gig::Region* SortedRegions::next() {  gig::Region* SortedRegions::next() {
80      region_iterator++;      ++region_iterator;
81      return region_iterator == regions.end() ? 0 : *region_iterator;      return region_iterator == regions.end() ? 0 : *region_iterator;
82  }  }
83    
84    
85    
86  RegionChooser::RegionChooser() :  RegionChooser::RegionChooser() :
87        activeKeyColor("red"),
88        blue("#4796ff"),
89        grey1("grey69"),
90        white("white"),
91        black("black"),
92      m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),      m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),
93      currentActiveKey(-1)      currentActiveKey(-1),
94        modifyallregions(false)
95  {  {
96      red = Gdk::Color("#8070ff");      set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT);
97      grey1 = Gdk::Color("#b0b0b0");  
98      activeKeyColor = Gdk::Color("#ff0000");      loadBuiltInPix();
99      white = Gdk::Color("#ffffff");  
100      black = Gdk::Color("#000000");      // create gray blue hatched pattern
101        {
102            const int width = grayBlueHatchedPattern->get_width();
103            const int height = grayBlueHatchedPattern->get_height();
104            const int stride = grayBlueHatchedPattern->get_rowstride();
105    
106            // manually convert from RGBA to ARGB
107            this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
108            const int pixelSize = stride / width;
109            const int totalPixels = width * height;
110            assert(pixelSize == 4);
111            unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
112            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
113                const unsigned char r = ptr[0];
114                const unsigned char g = ptr[1];
115                const unsigned char b = ptr[2];
116                const unsigned char a = ptr[3];
117                ptr[0] = b;
118                ptr[1] = g;
119                ptr[2] = r;
120                ptr[3] = a;
121            }
122    
123            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
124                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
125            );
126            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
127            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
128        }
129    
130      instrument = 0;      instrument = 0;
131      region = 0;      region = 0;
# Line 99  RegionChooser::RegionChooser() : Line 136  RegionChooser::RegionChooser() :
136    
137      // properties of the virtual keyboard      // properties of the virtual keyboard
138      {      {
139          const char* choices[] = { _("normal"), _("chord"), NULL };          const char* choices[] = { _("normal"), _("chord"), 0 };
140          static const virt_keyboard_mode_t values[] = {          static const virt_keyboard_mode_t values[] = {
141              VIRT_KEYBOARD_MODE_NORMAL,              VIRT_KEYBOARD_MODE_NORMAL,
142              VIRT_KEYBOARD_MODE_CHORD              VIRT_KEYBOARD_MODE_CHORD
# Line 119  RegionChooser::RegionChooser() : Line 156  RegionChooser::RegionChooser() :
156      m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);      m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);
157      m_VirtKeybPropsBox.set_spacing(10);      m_VirtKeybPropsBox.set_spacing(10);
158      m_VirtKeybPropsBox.show();      m_VirtKeybPropsBox.show();
159        for (int i = 0 ; i < 128 ; i++) key_pressed[i] = false;
160    
161      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
162      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties", _("_Properties")),
                                          Gtk::Stock::PROPERTIES),  
163                       sigc::mem_fun(*this,                       sigc::mem_fun(*this,
164                                     &RegionChooser::show_region_properties));                                     &RegionChooser::show_region_properties));
165      actionGroup->add(Gtk::Action::create("Remove", Gtk::Stock::REMOVE),      actionGroup->add(Gtk::Action::create("Remove", _("_Remove")),
166                       sigc::mem_fun(*this, &RegionChooser::delete_region));                       sigc::mem_fun(*this, &RegionChooser::delete_region));
167      actionGroup->add(Gtk::Action::create("Add", Gtk::Stock::ADD),      actionGroup->add(Gtk::Action::create("Add", _("_Add")),
168                       sigc::mem_fun(*this, &RegionChooser::add_region));                       sigc::mem_fun(*this, &RegionChooser::add_region));
169      actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),      actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),
170                       sigc::mem_fun(*this, &RegionChooser::manage_dimensions));                       sigc::mem_fun(*this, &RegionChooser::manage_dimensions));
# Line 172  RegionChooser::RegionChooser() : Line 209  RegionChooser::RegionChooser() :
209      keyboard_key_released_signal.connect(      keyboard_key_released_signal.connect(
210          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)
211      );      );
212        set_tooltip_text(_("Right click here for adding new region. Use mouse pointer for moving (dragging) or resizing existing regions (by pointing at region's boundary). Right click on an existing region for more actions."));
213  }  }
214    
215  RegionChooser::~RegionChooser()  RegionChooser::~RegionChooser()
216  {  {
217  }  }
218    
219  template<class T> inline std::string ToString(T o) {  void RegionChooser::setModifyAllRegions(bool b) {
220      std::stringstream ss;      modifyallregions = b;
221      ss << o;      // redraw required parts
222      return ss.str();      queue_draw();
223    }
224    
225    void RegionChooser::invalidate_key(int key) {
226        const int h = KEYBOARD_HEIGHT;
227        const int w = get_width() - 1;
228        int x1 = key_to_x(key - 0.5, w);
229        int x2 = key_to_x(key + 1.5, w);
230    
231        Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
232        get_window()->invalidate_rect(rect, false);
233  }  }
234    
235  void RegionChooser::on_note_on_event(int key, int velocity) {  void RegionChooser::on_note_on_event(int key, int velocity) {
236      draw_key(key, activeKeyColor);      key_pressed[key] = true;
237        invalidate_key(key);
238      m_VirtKeybVelocityLabel.set_text(ToString(velocity));      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
239  }  }
240    
241  void RegionChooser::on_note_off_event(int key, int velocity) {  void RegionChooser::on_note_off_event(int key, int velocity) {
242      if (is_black_key(key)) {      key_pressed[key] = false;
243          draw_key(key, black);      invalidate_key(key);
     } else {  
         draw_key(key, key >= 21 && key <= 108 ? white : grey1);  
     }  
244      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
245  }  }
246    
247    
248  bool RegionChooser::on_expose_event(GdkEventExpose* event)  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
249  {  bool RegionChooser::on_expose_event(GdkEventExpose* e) {
250      Glib::RefPtr<Gdk::Window> window = get_window();      double clipx1 = e->area.x;
251      if (window) {      double clipx2 = e->area.x + e->area.width;
252          Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();      double clipy1 = e->area.y;
253          if (event) {      double clipy2 = e->area.y + e->area.height;
254              cr->rectangle(event->area.x, event->area.y,  
255                            event->area.width, event->area.height);      const Cairo::RefPtr<Cairo::Context>& cr =
256              cr->clip();          get_window()->create_cairo_context();
257          }  #if 0
258          const int h = KEYBOARD_HEIGHT;  }
259          const int w = get_width() - 1;  #endif
260          const int bh = int(h * 0.55);  #else
261    bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
262          cr->save();      double clipx1, clipx2, clipy1, clipy2;
263          cr->set_line_width(1);      cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
264    #endif
         const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);  
         Gdk::Cairo::set_source_color(cr, bg);  
         cr->paint();  
265    
266          Gdk::Cairo::set_source_color(cr, black);      cr->save();
267          cr->rectangle(0.5, h1 + 0.5, w, h - 1);      cr->set_line_width(1);
         cr->stroke();  
268    
269          int x1 = int(w * 20.5 / 128.0 + 0.5);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
270          int x2 = int(w * 109.5 / 128.0 + 0.5);      const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
271    #else
272        const Gdk::RGBA bg = get_style_context()->get_background_color();
273    #endif
274        Gdk::Cairo::set_source_rgba(cr, bg);
275        cr->paint();
276    
277          Gdk::Cairo::set_source_color(cr, grey1);      if (clipy2 > h1) {
278          cr->rectangle(1, h1 + 1, x1 - 1, h - 2);          draw_keyboard(cr, clipx1, clipx2);
279          cr->fill();      }
280    
281          Gdk::Cairo::set_source_color(cr, white);      if (clipy1 < h1 && instrument) {
282          cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);          draw_regions(cr, clipx1, clipx2);
283          cr->fill();      }
284    
285          Gdk::Cairo::set_source_color(cr, grey1);      cr->restore();
         cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);  
         cr->fill();  
286    
287          Gdk::Cairo::set_source_color(cr, black);      return true;
288          for (int i = 0 ; i < 128 ; i++) {  }
             int note = (i + 3) % 12;  
             int x = int(w * i / 128.0 + 0.5);  
   
             if (note == 1 || note == 4 || note == 6 ||  
                 note == 9 || note == 11) {  
                 int x2 = int(w * (i + 0.5) / 128.0 + 0.5);  
                 cr->move_to(x2 + 0.5, h1 + bh + 0.5);  
                 cr->line_to(x2 + 0.5, h1 + h - 1);  
                 cr->stroke();  
289    
290                  int x3 = int(w * (i + 1) / 128.0 + 0.5);  void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
291                  cr->rectangle(x, h1 + 1, x3 - x + 1, bh);                                    int clip_low, int clip_high) {
292                  cr->fill();      const int h = KEYBOARD_HEIGHT;
293              } else if (note == 3 || note == 8) {      const int w = get_width() - 1;
294                  cr->move_to(x + 0.5, h1 + 1);      const int bh = int(h * 0.55);
                 cr->line_to(x + 0.5, h1 + h - 1);  
                 cr->stroke();  
295    
296                  if (note == 3) draw_digit(i);      Gdk::Cairo::set_source_rgba(cr, black);
297              }      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
298        cr->stroke();
299    
300        int x1 = key_to_x(20.5, w);
301        Gdk::Cairo::set_source_rgba(cr, grey1);
302        cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
303        cr->fill();
304    
305        int x2 = key_to_x(109.5, w);
306        Gdk::Cairo::set_source_rgba(cr, white);
307        cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
308        cr->fill();
309    
310        Gdk::Cairo::set_source_rgba(cr, grey1);
311        cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);
312        cr->fill();
313    
314        Gdk::Cairo::set_source_rgba(cr, black);
315    
316        int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
317        int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
318    
319        for (int i = clipkey1 ; i < clipkey2 ; i++) {
320            int note = (i + 3) % 12;
321            int x = key_to_x(i, w);
322    
323            if (note == 1 || note == 4 || note == 6 ||
324                note == 9 || note == 11) {
325                // black key: short line in the middle, with a rectangle
326                // on top
327                int x2 = key_to_x(i + 0.5, w);
328                cr->move_to(x2 + 0.5, h1 + bh + 0.5);
329                cr->line_to(x2 + 0.5, h1 + h - 1);
330                cr->stroke();
331    
332                int x3 = key_to_x(i + 1, w);
333                cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
334                cr->fill();
335            } else if (note == 3 || note == 8) {
336                // C or F: long line to the left
337                cr->move_to(x + 0.5, h1 + 1);
338                cr->line_to(x + 0.5, h1 + h - 1);
339                cr->stroke();
340          }          }
341    
342          if (instrument) {          if (key_pressed[i]) draw_key(cr, i);
343              int i = 0;  
344              gig::Region* next_region;          if (note == 3) draw_digit(cr, i);
345              int x3 = -1;      }
346              for (gig::Region* r = regions.first() ; r ; r = next_region) {  }
   
                 if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);  
                 next_region = regions.next();  
                 if (!next_region ||  
                     r->KeyRange.high + 1 != next_region->KeyRange.low) {  
                     int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);  
                     cr->move_to(x3, 0.5);  
                     cr->line_to(x2 + 0.5, 0.5);  
                     cr->line_to(x2 + 0.5, h1 - 0.5);  
                     cr->line_to(x3, h1 - 0.5);  
                     cr->stroke();  
   
                     Gdk::Cairo::set_source_color(cr, white);  
                     cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);  
                     cr->fill();  
                     Gdk::Cairo::set_source_color(cr, black);  
347    
                     x3 = -1;  
                 }  
                 i++;  
             }  
348    
349              for (gig::Region* r = regions.first() ; r ; r = regions.next()) {  void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
350                  int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);                                   int clip_low, int clip_high) {
351                  cr->move_to(x + 0.5, 1);      const int w = get_width() - 1;
352                  cr->line_to(x + 0.5, h1 - 1);  
353        Gdk::Cairo::set_source_rgba(cr, black);
354        gig::Region* next_region;
355        int x3 = -1;
356        for (gig::Region* r = regions.first() ; r ; r = next_region) {
357            next_region = regions.next();
358    
359            if (x3 < 0) {
360                x3 = key_to_x(r->KeyRange.low, w);
361                if (x3 >= clip_high) break;
362            }
363            if (!next_region ||
364                r->KeyRange.high + 1 != next_region->KeyRange.low ||
365                r == region || next_region == region) {
366    
367                int x2 = key_to_x(r->KeyRange.high + 1, w);
368                if (x2 >= clip_low) {
369                    cr->move_to(x3, 0.5);
370                    cr->line_to(x2 + 0.5, 0.5);
371                    cr->line_to(x2 + 0.5, h1 - 0.5);
372                    cr->line_to(x3, h1 - 0.5);
373                  cr->stroke();                  cr->stroke();
             }  
374    
375              if (region) {                  if (region == r)
376                  int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);                      Gdk::Cairo::set_source_rgba(cr, blue);
377                  int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);                  else if (modifyallregions)
378                  Gdk::Cairo::set_source_color(cr, red);                      cr->set_source(grayBlueHatchedSurfacePattern);
379                  cr->rectangle(x1 + 1, 1, x2 - x1 - 1, h1 - 2);                  else
380                        Gdk::Cairo::set_source_rgba(cr, white);
381    
382                    cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
383                  cr->fill();                  cr->fill();
384                    Gdk::Cairo::set_source_rgba(cr, black);
385              }              }
386                x3 = -1;
387          }          }
388        }
389    
390          cr->restore();      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
391            int x = key_to_x(r->KeyRange.low, w);
392            int x2 = key_to_x(r->KeyRange.high + 1, w);
393    
394            RegionFeatures features = regionFeatures(r);
395    
396            const bool bShowLoopSymbol = features.loops > 0;
397            const bool bShowSampleRefSymbol = features.sampleRefs < r->DimensionRegions;
398            if (bShowLoopSymbol || bShowSampleRefSymbol) {
399                const int margin = 2;
400                const int wRgn = x2 - x;
401                //printf("x=%d x2=%d wRgn=%d\n", x, x2, wRgn);
402    
403                cr->save();
404                cr->set_line_width(1);
405                cr->rectangle(x, 1, wRgn, h1 - 1);
406                cr->clip();
407                if (bShowSampleRefSymbol) {
408                    const int wPic = 8;
409                    const int hPic = 8;
410                    Gdk::Cairo::set_source_pixbuf(
411                        cr, (features.sampleRefs) ? yellowDot : redDot,
412                        x + (wRgn-wPic)/2.f,
413                        (bShowLoopSymbol) ? margin : (h1-hPic)/2.f
414                    );
415                    cr->paint();
416                }
417                if (bShowLoopSymbol) {
418                    const int wPic = 12;
419                    const int hPic = 14;
420                    Gdk::Cairo::set_source_pixbuf(
421                        cr, (features.loops == r->DimensionRegions) ? blackLoop : grayLoop,
422                        x + (wRgn-wPic)/2.f,
423                        (bShowSampleRefSymbol) ? h1 - hPic - margin : (h1-hPic)/2.f
424                    );
425                    cr->paint();
426                }
427                cr->restore();
428            }
429      }      }
430    
431      return true;      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
432  }          int x = key_to_x(r->KeyRange.low, w);
433    
434            if (x < clip_low) continue;
435            if (x >= clip_high) break;
436    
437  void RegionChooser::on_size_request(GtkRequisition* requisition)          cr->move_to(x + 0.5, 1);
438  {          cr->line_to(x + 0.5, h1 - 1);
439      *requisition = GtkRequisition();          cr->stroke();
440      requisition->height = KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT;      }
441      requisition->width = 500;  
442        // if there is no region yet, show the user some hint text that he may
443        // right click on this area to create a new region
444        if (!regions.first()) {
445            Glib::RefPtr<Pango::Context> context = get_pango_context();
446            Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
447            layout->set_alignment(Pango::ALIGN_CENTER);
448            layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
449            layout->set_width(get_width() * Pango::SCALE);
450            //layout->set_height(get_height() * Pango::SCALE);
451            layout->set_spacing(10);
452            Gdk::Cairo::set_source_rgba(cr, blue);
453            // get the text dimensions
454            int text_width, text_height;
455            layout->get_pixel_size(text_width, text_height);
456            cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
457    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
458            pango_cairo_show_layout(cr->cobj(), layout->gobj());
459    #else
460            layout->show_in_cairo_context(cr);
461    #endif
462        }
463  }  }
464    
465  bool RegionChooser::is_black_key(int key) {  bool RegionChooser::is_black_key(int key) {
# Line 325  bool RegionChooser::is_black_key(int key Line 467  bool RegionChooser::is_black_key(int key
467      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
468  }  }
469    
470  void RegionChooser::draw_digit(int key) {  void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
471                                   int key) {
472      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
473      const int w = get_width() - 1;      const int w = get_width() - 1;
474      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(get_pango_context());      Glib::RefPtr<Pango::Layout> layout =
475            Pango::Layout::create(get_pango_context());
476      char buf[30];      char buf[30];
477      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
478      layout->set_markup(buf);      layout->set_markup(buf);
# Line 336  void RegionChooser::draw_digit(int key) Line 480  void RegionChooser::draw_digit(int key)
480      double text_w = double(rectangle.get_width()) / Pango::SCALE;      double text_w = double(rectangle.get_width()) / Pango::SCALE;
481      double text_h = double(rectangle.get_height()) / Pango::SCALE;      double text_h = double(rectangle.get_height()) / Pango::SCALE;
482      double x = w * (key + 0.75) / 128.0;      double x = w * (key + 0.75) / 128.0;
483      Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();      Gdk::Cairo::set_source_rgba(cr, black);
     Gdk::Cairo::set_source_color(cr, black);  
484      cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));      cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));
485  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
486      pango_cairo_show_layout(cr->cobj(), layout->gobj());      pango_cairo_show_layout(cr->cobj(), layout->gobj());
# Line 346  void RegionChooser::draw_digit(int key) Line 489  void RegionChooser::draw_digit(int key)
489  #endif  #endif
490  }  }
491    
492  void RegionChooser::draw_key(int key, const Gdk::Color& color)  void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
493  {                               int key) {
494      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
495      const int w = get_width() - 1;      const int w = get_width() - 1;
496      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
497    
498      Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     Gdk::Cairo::set_source_color(cr, color);  
499    
500      int note = (key + 3) % 12;      int note = (key + 3) % 12;
501      int x = int(w * key / 128.0 + 0.5) + 1;      int x = key_to_x(key, w) + 1;
502      int x2 = int(w * (key + 1.5) / 128.0 + 0.5);      int x2 = key_to_x(key + 1.5, w);
503      int x3 = int(w * (key + 1) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
504      int x4 = int(w * (key - 0.5) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
505      int w1 = x3 - x;      int w1 = x3 - x;
506      switch (note) {      switch (note) {
507      case 0: case 5: case 10:      case 0: case 5: case 10:
# Line 379  void RegionChooser::draw_key(int key, co Line 521  void RegionChooser::draw_key(int key, co
521          cr->fill();          cr->fill();
522          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
523          cr->fill();          cr->fill();
         if (note == 3) draw_digit(key);  
524          break;          break;
525      default:      default:
526          cr->rectangle(x, h1 + 1, w1, bh - 1);          cr->rectangle(x, h1 + 1, w1, bh - 1);
527          cr->fill();          cr->fill();
528          break;          break;
529      }      }
530        Gdk::Cairo::set_source_rgba(cr, black);
531  }  }
532    
533  void RegionChooser::set_instrument(gig::Instrument* instrument)  void RegionChooser::set_instrument(gig::Instrument* instrument)
# Line 400  void RegionChooser::set_instrument(gig:: Line 542  void RegionChooser::set_instrument(gig::
542    
543  bool RegionChooser::on_button_release_event(GdkEventButton* event)  bool RegionChooser::on_button_release_event(GdkEventButton* event)
544  {  {
545      const int k = int(event->x / (get_width() - 1) * 128.0);      const int k = x_to_key(event->x, get_width() - 1);
546    
547      // handle-note off on virtual keyboard      // handle-note off on virtual keyboard
548      if (event->type == GDK_BUTTON_RELEASE) {      if (event->type == GDK_BUTTON_RELEASE) {
# Line 423  bool RegionChooser::on_button_release_ev Line 565  bool RegionChooser::on_button_release_ev
565      }      }
566    
567      if (resize.active) {      if (resize.active) {
568    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
569          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
570    #else
571            Glib::wrap(event->device, true)->ungrab(event->time);
572    #endif
573          resize.active = false;          resize.active = false;
574    
         if (resize.mode == resize.moving_high_limit) {  
             if (resize.region->KeyRange.high != resize.pos - 1) {  
                 instrument_struct_to_be_changed_signal.emit(instrument);  
                 resize.region->SetKeyRange(  
                     resize.region->KeyRange.low, // low  
                     resize.pos - 1 // high  
                 );  
                 regions.update(instrument);  
                 instrument_changed.emit();  
                 instrument_struct_changed_signal.emit(instrument);  
             }  
         } else if (resize.mode == resize.moving_low_limit) {  
             if (resize.region->KeyRange.low != resize.pos) {  
                 instrument_struct_to_be_changed_signal.emit(instrument);  
                 resize.region->SetKeyRange(  
                     resize.pos, // low  
                     resize.region->KeyRange.high // high  
                 );  
                 regions.update(instrument);  
                 instrument_changed.emit();  
                 instrument_struct_changed_signal.emit(instrument);  
             }  
         }  
   
575          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
576              get_window()->set_cursor();              get_window()->set_cursor();
577              cursor_is_resize = false;              cursor_is_resize = false;
578          }          }
579      } else if (move.active) {      } else if (move.active) {
580    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
581          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
582    #else
583            Glib::wrap(event->device, true)->ungrab(event->time);
584    #endif
585          move.active = false;          move.active = false;
586    
587          if (move.pos) {          if (is_in_resize_zone(event->x, event->y)) {
588    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
589                get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
590    #else
591                get_window()->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
592    #endif
593                cursor_is_resize = true;
594            }
595        }
596        return true;
597    }
598    
599    void RegionChooser::update_after_resize()
600    {
601        if (resize.mode == resize.moving_high_limit) {
602            if (resize.region->KeyRange.high != resize.pos - 1) {
603                instrument_struct_to_be_changed_signal.emit(instrument);
604                resize.region->SetKeyRange(resize.region->KeyRange.low,
605                                           resize.pos - 1);
606                regions.update(instrument);
607                instrument_changed.emit();
608                instrument_struct_changed_signal.emit(instrument);
609            }
610        } else if (resize.mode == resize.moving_low_limit) {
611            if (resize.region->KeyRange.low != resize.pos) {
612              instrument_struct_to_be_changed_signal.emit(instrument);              instrument_struct_to_be_changed_signal.emit(instrument);
613              region->SetKeyRange(              resize.region->SetKeyRange(resize.pos,
614                  region->KeyRange.low  + move.pos,                                         resize.region->KeyRange.high);
                 region->KeyRange.high + move.pos  
             );  
615              regions.update(instrument);              regions.update(instrument);
616              instrument_changed.emit();              instrument_changed.emit();
617              instrument_struct_changed_signal.emit(instrument);              instrument_struct_changed_signal.emit(instrument);
618          }          }
619        }
620    }
621    
622          if (is_in_resize_zone(event->x, event->y)) {  void RegionChooser::update_after_move(int pos)
623              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));  {
624              cursor_is_resize = true;      instrument_struct_to_be_changed_signal.emit(instrument);
625        const int range = region->KeyRange.high - region->KeyRange.low;
626        const int diff  = pos - int(region->KeyRange.low);
627        region->SetKeyRange(pos, pos + range);
628        if (Settings::singleton()->moveRootNoteWithRegionMoved) {
629            for (int i = 0; i < 256; ++i) {
630                gig::DimensionRegion* dimrgn = region->pDimensionRegions[i];
631                if (!dimrgn || !dimrgn->pSample || !dimrgn->PitchTrack) continue;
632                dimrgn->UnityNote += diff;
633          }          }
634      }      }
635      return true;      regions.update(instrument);
636        instrument_changed.emit();
637        instrument_struct_changed_signal.emit(instrument);
638  }  }
639    
640  bool RegionChooser::on_button_press_event(GdkEventButton* event)  bool RegionChooser::on_button_press_event(GdkEventButton* event)
641  {  {
642      if (!instrument) return true;      if (!instrument) return true;
643    
644      const int k = int(event->x / (get_width() - 1) * 128.0);      const int w = get_width() - 1;
645        const int k = x_to_key(event->x, w);
646    
647      if (event->type == GDK_BUTTON_PRESS) {      if (event->type == GDK_BUTTON_PRESS) {
648          if (event->y >= REGION_BLOCK_HEIGHT) {          if (event->y >= REGION_BLOCK_HEIGHT) {
# Line 492  bool RegionChooser::on_button_press_even Line 653  bool RegionChooser::on_button_press_even
653          }          }
654      }      }
655    
656        // left mouse button double click
657        if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
658            if (event->y < REGION_BLOCK_HEIGHT) {
659                // show dimension manager dialog for this region
660                manage_dimensions();
661            }
662        }
663    
664      if (event->y >= REGION_BLOCK_HEIGHT) return true;      if (event->y >= REGION_BLOCK_HEIGHT) return true;
665      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
666          gig::Region* r = get_region(k);          gig::Region* r = get_region(k);
# Line 507  bool RegionChooser::on_button_press_even Line 676  bool RegionChooser::on_button_press_even
676          }          }
677      } else {      } else {
678          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
679    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
680              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
681                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
682                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
683                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
684                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW), event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
685                                           event->time);
686    #else
687                Glib::wrap(event->device, true)->grab(get_window(),
688                                                      Gdk::OWNERSHIP_NONE,
689                                                      false,
690                                                      Gdk::BUTTON_RELEASE_MASK |
691                                                      Gdk::POINTER_MOTION_MASK |
692                                                      Gdk::POINTER_MOTION_HINT_MASK,
693                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
694                                                      event->time);
695    #endif
696              resize.active = true;              resize.active = true;
697          } else {          } else {
698              gig::Region* r = get_region(k);              gig::Region* r = get_region(k);
# Line 521  bool RegionChooser::on_button_press_even Line 702  bool RegionChooser::on_button_press_even
702                  region_selected();                  region_selected();
703                  dimensionManager.set_region(region);                  dimensionManager.set_region(region);
704    
705    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
706                  get_window()->pointer_grab(false,                  get_window()->pointer_grab(false,
707                                             Gdk::BUTTON_RELEASE_MASK |                                             Gdk::BUTTON_RELEASE_MASK |
708                                             Gdk::POINTER_MOTION_MASK |                                             Gdk::POINTER_MOTION_MASK |
709                                             Gdk::POINTER_MOTION_HINT_MASK,                                             Gdk::POINTER_MOTION_HINT_MASK,
710                                             Gdk::Cursor(Gdk::FLEUR), event->time);                                             Gdk::Cursor(Gdk::FLEUR),
711                                               event->time);
712    #else
713                    Glib::wrap(event->device, true)->grab(get_window(),
714                                                          Gdk::OWNERSHIP_NONE,
715                                                          false,
716                                                          Gdk::BUTTON_RELEASE_MASK |
717                                                          Gdk::POINTER_MOTION_MASK |
718                                                          Gdk::POINTER_MOTION_HINT_MASK,
719                                                          Gdk::Cursor::create(Gdk::FLEUR),
720                                                          event->time);
721    #endif
722                  move.active = true;                  move.active = true;
723                  move.from_x = event->x;                  move.offset = event->x - key_to_x(region->KeyRange.low, w);
                 move.pos = 0;  
724              }              }
725          }          }
726      }      }
# Line 537  bool RegionChooser::on_button_press_even Line 729  bool RegionChooser::on_button_press_even
729    
730  gig::Region* RegionChooser::get_region(int key)  gig::Region* RegionChooser::get_region(int key)
731  {  {
732      gig::Region* prev_region = 0;      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
     gig::Region* next_region;  
     for (gig::Region* r = regions.first() ; r ; r = next_region) {  
         next_region = regions.next();  
   
733          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
734          if (key <= r->KeyRange.high) {          if (key <= r->KeyRange.high) return r;
             move.touch_left = prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low;  
             move.touch_right = next_region && r->KeyRange.high + 1 == next_region->KeyRange.low;  
             return r;  
         }  
         prev_region = r;  
735      }      }
736      return 0;      return 0;
737  }  }
738    
739    void RegionChooser::set_region(gig::Region* region) {
740        this->region = region;
741        queue_draw();
742        region_selected();
743        dimensionManager.set_region(region);
744    }
745    
746    void RegionChooser::select_next_region() {
747        if (!instrument) return;
748        if (!region) {
749            for (int i = 0; i < 128; ++i) {
750                ::gig::Region* rgn = instrument->GetRegion(i);
751                if (rgn) {
752                    set_region(rgn);
753                    return;
754                }
755            }
756        } else {
757            bool currentFound = false;
758            for (int i = 0; i < 128; ++i) {
759                ::gig::Region* rgn = instrument->GetRegion(i);
760                if (!rgn) continue;
761                if (currentFound) {
762                    if (rgn != region) {
763                        set_region(rgn);
764                        return;
765                    }
766                } else {
767                    if (rgn == region) currentFound = true;
768                }
769            }
770        }
771    }
772    
773    void RegionChooser::select_prev_region() {
774        if (!instrument) return;
775        if (!region) {
776            for (int i = 0; i < 128; ++i) {
777                ::gig::Region* rgn = instrument->GetRegion(i);
778                if (rgn) {
779                    set_region(rgn);
780                    return;
781                }
782            }
783        } else {
784            bool currentFound = false;
785            for (int i = 127; i >= 0; --i) {
786                ::gig::Region* rgn = instrument->GetRegion(i);
787                if (!rgn) continue;
788                if (currentFound) {
789                    if (rgn != region) {
790                        set_region(rgn);
791                        return;
792                    }
793                } else {
794                    if (rgn == region) currentFound = true;
795                }
796            }
797        }
798    }
799    
800  void RegionChooser::motion_resize_region(int x, int y)  void RegionChooser::motion_resize_region(int x, int y)
801  {  {
802      const int w = get_width() - 1;      const int w = get_width() - 1;
# Line 563  void RegionChooser::motion_resize_region Line 807  void RegionChooser::motion_resize_region
807      else if (k > resize.max) k = resize.max;      else if (k > resize.max) k = resize.max;
808    
809      if (k != resize.pos) {      if (k != resize.pos) {
         Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
         cr->set_line_width(1);  
   
810          if (resize.mode == resize.undecided) {          if (resize.mode == resize.undecided) {
811              if (k < resize.pos) {              if (k < resize.pos) {
812                  // edit high limit of prev_region                  // edit high limit of prev_region
# Line 578  void RegionChooser::motion_resize_region Line 819  void RegionChooser::motion_resize_region
819                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
820              }              }
821          }          }
822          const Gdk::Color white =          resize.pos = k;
             region == resize.region ? red : get_style()->get_white();  
         const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);  
   
         int prevx = int(w * resize.pos / 128.0 + 0.5);  
         x = int(w * k / 128.0 + 0.5);  
823    
824            int x1, x2;
825          if (resize.mode == resize.moving_high_limit) {          if (resize.mode == resize.moving_high_limit) {
826              if (k > resize.pos) {              if (resize.region->KeyRange.high < resize.pos - 1) {
827                  Gdk::Cairo::set_source_color(cr, white);                  x1 = resize.region->KeyRange.high;
828                  cr->rectangle(prevx, 1, x - prevx, h1 - 2);                  x2 = resize.pos - 1;
                 cr->fill();  
   
                 Gdk::Cairo::set_source_color(cr, black);  
                 cr->move_to(prevx, 0.5);  
                 cr->line_to(x + 1, 0.5);  
                 cr->move_to(prevx, h1 - 0.5);  
                 cr->line_to(x + 1, h1 - 0.5);  
                 cr->stroke();  
829              } else {              } else {
830                  int xx = (resize.pos == resize.max &&                  x1 = resize.pos - 1;
831                            resize.max != 128) ? 1 : 0;                  x2 = resize.region->KeyRange.high;
                 Gdk::Cairo::set_source_color(cr, bg);  
                 cr->rectangle(x + 1, 0, prevx - x - xx, h1);  
                 cr->fill();  
832              }              }
833          } else {          } else {
834              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
835                  Gdk::Cairo::set_source_color(cr, white);                  x1 = resize.region->KeyRange.low;
836                  cr->rectangle(x + 1, 1, prevx - x, h1 - 2);                  x2 = resize.pos;
                 cr->fill();  
   
                 Gdk::Cairo::set_source_color(cr, black);  
                 cr->move_to(x, 0.5);  
                 cr->line_to(prevx, 0.5);  
                 cr->move_to(x, h1 - 0.5);  
                 cr->line_to(prevx, h1 - 0.5);  
                 cr->stroke();  
837              } else {              } else {
838                  int xx = (resize.pos == resize.min &&                  x1 = resize.pos;
839                            resize.min != 0) ? 1 : 0;                  x2 = resize.region->KeyRange.low;
                 Gdk::Cairo::set_source_color(cr, bg);  
                 cr->rectangle(prevx + xx, 0, x - prevx - xx, h1);  
                 cr->fill();  
840              }              }
841          }          }
842          Gdk::Cairo::set_source_color(cr, black);          x1 = key_to_x(x1, w);
843          cr->move_to(x + 0.5, 1);          x2 = key_to_x(x2 + 1, w) + 1;
844          cr->line_to(x + 0.5, h1 - 1);          Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
845          cr->stroke();  
846          resize.pos = k;          update_after_resize();
847    
848            //get_window()->invalidate_rect(rect, false);
849            get_window()->invalidate(false); // repaint entire region, otherwise it would create visual artifacts
850      }      }
851  }  }
852    
853  void RegionChooser::motion_move_region(int x, int y)  void RegionChooser::motion_move_region(int x, int y)
854  {  {
855      const int w = get_width() - 1;      const int w = get_width() - 1;
     Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
     cr->set_line_width(1);  
856    
857      int k = int(double(x - move.from_x) / w * 128.0 + 0.5);      int l = int(double(x - move.offset) / w * 128.0 + 0.5);
858      if (k == move.pos) return;  
859      int new_k;      if (l == region->KeyRange.low) return;
860      bool new_touch_left;      int new_l;
861      bool new_touch_right;      int regionsize = region->KeyRange.high - region->KeyRange.low;
862      int a = 0;      int a = 0;
863      if (k > move.pos) {      if (l > region->KeyRange.low) {
864          for (gig::Region* r = regions.first() ; ; r = regions.next()) {          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
865              if (r != region) {              if (r != region) {
866                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
867    
868                  // gap: from a to b (not inclusive b)                  // gap: from a to b (not inclusive b)
869    
870                  if (region->KeyRange.high + move.pos >= b) {                  if (region->KeyRange.high >= b) {
871                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
872                  } else {                  } else {
873    
874                      if (a > region->KeyRange.low + k) {                      if (a > l) {
875                          // this gap is too far to the right, break                          // this gap is too far to the right, break
876                          break;                          break;
877                      }                      }
878    
879                      int newhigh = std::min(region->KeyRange.high + k, b - 1);                      int newhigh = std::min(l + regionsize, b - 1);
880                      int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);                      int newlo = newhigh - regionsize;
881    
882                      if (newlo >= a) {                      if (newlo >= a) {
883                          // yes it fits - it's a candidate                          // yes it fits - it's a candidate
884                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
885                      }                      }
886                  }                  }
887                  if (!r) break;                  if (!r) break;
# Line 681  void RegionChooser::motion_move_region(i Line 895  void RegionChooser::motion_move_region(i
895    
896                  // gap from a to b (not inclusive b)                  // gap from a to b (not inclusive b)
897    
898                  if (region->KeyRange.high + k >= b) {                  if (l + regionsize >= b) {
899                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
900                  } else {                  } else {
901    
902                      if (a > region->KeyRange.low + move.pos) {                      if (a > region->KeyRange.low) {
903                          // this gap is too far to the right, break                          // this gap is too far to the right, break
904                          break;                          break;
905                      }                      }
906    
907                      int newlo = std::max(region->KeyRange.low + k, a);                      int newlo = std::max(l, a);
908                      int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);                      int newhigh = newlo + regionsize;
909    
910                      if (newhigh < b) {                      if (newhigh < b) {
911                          // yes it fits - break as the first one is the best                          // yes it fits - break as the first one is the best
912                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
913                          break;                          break;
914                      }                      }
915                  }                  }
# Line 706  void RegionChooser::motion_move_region(i Line 918  void RegionChooser::motion_move_region(i
918              }              }
919          }          }
920      }      }
921      k = new_k;      if (new_l == region->KeyRange.low) return;
     if (k == move.pos) return;  
922    
923      const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);      int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
924      int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
925      x = int(w * (k + region->KeyRange.low) / 128.0 + 0.5);                                 new_l + regionsize) + 1, w) + 1;
     int prevx2 = int(w * (move.pos + region->KeyRange.high + 1) / 128.0 + 0.5);  
     int x2 = int(w * (k + region->KeyRange.high + 1) / 128.0 + 0.5);  
     const Gdk::Color black = get_style()->get_black();  
   
     if (!new_touch_left) {  
         Gdk::Cairo::set_source_color(cr, black);  
         cr->move_to(x + 0.5, 1);  
         cr->line_to(x + 0.5, h1 - 1);  
         cr->stroke();  
     }  
     if (!new_touch_right) {  
         Gdk::Cairo::set_source_color(cr, black);  
         cr->move_to(x2 + 0.5, 1);  
         cr->line_to(x2 + 0.5, h1 - 1);  
         cr->stroke();  
     }  
   
     if (k > move.pos) {  
         Gdk::Cairo::set_source_color(cr, bg);  
         cr->rectangle(prevx + (move.touch_left ? 1 : 0), 0,  
                       std::min(x, prevx2 + 1 - (move.touch_right ? 1 : 0)) -  
                       (prevx + (move.touch_left ? 1 : 0)), h1);  
         cr->fill();  
   
         Gdk::Cairo::set_source_color(cr, black);  
         cr->move_to(std::max(x, prevx2 + 1), 0.5);  
         cr->line_to(x2 + 1, 0.5);  
         cr->move_to(std::max(x, prevx2 + 1), h1 - 0.5);  
         cr->line_to(x2 + 1, h1 - 0.5);  
         cr->stroke();  
926    
927          Gdk::Cairo::set_source_color(cr, red);      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
928          cr->rectangle(std::max(x + 1, prevx2), 1,      update_after_move(new_l);
                       x2 - std::max(x + 1, prevx2), h1 - 2);  
         cr->fill();  
     } else {  
         Gdk::Cairo::set_source_color(cr, bg);  
         cr->rectangle(std::max(x2 + 1, prevx + (move.touch_left ? 1 : 0)), 0,  
                       prevx2 + 1 - (move.touch_right ? 1 : 0) -  
                       std::max(x2 + 1, prevx + (move.touch_left ? 1 : 0)), h1);  
         cr->fill();  
   
         Gdk::Cairo::set_source_color(cr, black);  
         cr->move_to(x, 0.5);  
         cr->line_to(std::min(x2, prevx - 1) + 1, 0.5);  
         cr->move_to(x, h1 - 0.5);  
         cr->line_to(std::min(x2, prevx - 1) + 1, h1 - 0.5);  
         cr->stroke();  
   
         Gdk::Cairo::set_source_color(cr, red);  
         cr->rectangle(x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);  
         cr->fill();  
     }  
929    
930      move.pos = k;      get_window()->invalidate_rect(rect, false);
     move.touch_left = new_touch_left;  
     move.touch_right = new_touch_right;  
931  }  }
932    
933    
# Line 785  bool RegionChooser::on_motion_notify_eve Line 944  bool RegionChooser::on_motion_notify_eve
944          event->y >= REGION_BLOCK_HEIGHT &&          event->y >= REGION_BLOCK_HEIGHT &&
945          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
946      {      {
947          const int k = int(event->x / (get_width() - 1) * 128.0);          const int k = x_to_key(event->x, get_width() - 1);
948          if (k != currentActiveKey) {          if (k != currentActiveKey) {
949              int velocity =              int velocity =
950                  (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :                  (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
# Line 805  bool RegionChooser::on_motion_notify_eve Line 964  bool RegionChooser::on_motion_notify_eve
964      } else {      } else {
965          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
966              if (!cursor_is_resize) {              if (!cursor_is_resize) {
967    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
968                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
969    #else
970                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
971    #endif
972                  cursor_is_resize = true;                  cursor_is_resize = true;
973              }              }
974          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 826  bool RegionChooser::is_in_resize_zone(do Line 989  bool RegionChooser::is_in_resize_zone(do
989          for (gig::Region* r = regions.first(); r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
990              next_region = regions.next();              next_region = regions.next();
991    
992              int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);              int lo = key_to_x(r->KeyRange.low, w);
993              if (x <= lo - 2) break;              if (x <= lo - 2) break;
994              if (x < lo + 2) {              if (x < lo + 2) {
995                  resize.region = r;                  resize.region = r;
# Line 849  bool RegionChooser::is_in_resize_zone(do Line 1012  bool RegionChooser::is_in_resize_zone(do
1012                  return resize.min != resize.max;                  return resize.min != resize.max;
1013              }              }
1014              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
1015                  int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);                  int hi = key_to_x(r->KeyRange.high + 1, w);
1016                  if (x <= hi - 2) break;                  if (x <= hi - 2) break;
1017                  if (x < hi + 2) {                  if (x < hi + 2) {
1018                      // edit high limit                      // edit high limit
# Line 887  void RegionChooser::show_region_properti Line 1050  void RegionChooser::show_region_properti
1050      dialog.get_vbox()->pack_start(checkBoxKeygroup);      dialog.get_vbox()->pack_start(checkBoxKeygroup);
1051      checkBoxKeygroup.show();      checkBoxKeygroup.show();
1052      // add "Keygroup" spinbox      // add "Keygroup" spinbox
1053      Gtk::Adjustment adjustment(1, 1, pow(2,32));  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1054        Gtk::Adjustment adjustment(1, 1, 999);
1055      Gtk::SpinButton spinBox(adjustment);      Gtk::SpinButton spinBox(adjustment);
1056    #else
1057        Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1058    #endif
1059      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
1060      dialog.get_vbox()->pack_start(spinBox);      dialog.get_vbox()->pack_start(spinBox);
1061      spinBox.show();      spinBox.show();
1062      // add OK and CANCEL buttons to the dialog      // add OK and CANCEL buttons to the dialog
1063      dialog.add_button(Gtk::Stock::OK, 0);      dialog.add_button(_("_OK"), 0);
1064      dialog.add_button(Gtk::Stock::CANCEL, 1);      dialog.add_button(_("_Cancel"), 1);
1065      dialog.show_all_children();      dialog.show_all_children();
1066      if (!dialog.run()) { // OK selected ...      if (!dialog.run()) { // OK selected ...
1067          region->KeyGroup =          region->KeyGroup =

Legend:
Removed from v.2151  
changed lines
  Added in v.3148

  ViewVC Help
Powered by ViewVC