/[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 1898 by persson, Sun May 10 09:35:56 2009 UTC revision 3460 by persson, Sat Feb 2 07:48:50 2019 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2009 Andreas Persson   * Copyright (C) 2006-2019 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include "compat.h"
21    #include "global.h"
22  #include "regionchooser.h"  #include "regionchooser.h"
23    
24  #include <algorithm>  #include <algorithm>
25    #include <assert.h>
26    
27    #include <cairomm/context.h>
28    #include <gdkmm/general.h>
29    #if HAS_GDKMM_SEAT
30    # include <gdkmm/seat.h>
31    #endif
32  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
33  #include <gtkmm/stock.h>  #if HAS_GTKMM_STOCK
34    # include <gtkmm/stock.h>
35    #endif
36    #include <gdkmm/pixbuf.h>
37  #include <gtkmm/spinbutton.h>  #include <gtkmm/spinbutton.h>
38  #include <gtkmm/dialog.h>  #include <gtkmm/dialog.h>
 #include <math.h>  
 #include <sstream>  
39    
40  #include "global.h"  #include "Settings.h"
41    #include "gfx/builtinpix.h"
42    
43    #define REGION_BLOCK_HEIGHT             30
44    #define KEYBOARD_HEIGHT                 40
45    
46  #define REGION_BLOCK_HEIGHT             20  struct RegionFeatures {
47  #define KEYBOARD_HEIGHT                 40      int sampleRefs;
48        int loops;
49        int validDimRegs;
50    
51        RegionFeatures() {
52            sampleRefs = loops = validDimRegs = 0;
53        }
54    };
55    
56    static RegionFeatures regionFeatures(gig::Region* rgn) {
57        RegionFeatures f;
58        for (int i = 0; i < rgn->DimensionRegions; ++i) {
59            gig::DimensionRegion* dr = rgn->pDimensionRegions[i];
60            DimensionCase c = dimensionCaseOf(dr);
61            if (!isUsedCase(c, rgn)) continue;
62            f.validDimRegs++;
63            if (dr->pSample) f.sampleRefs++;
64            // the user doesn't care about loop if there is no valid sample reference
65            if (dr->pSample && dr->SampleLoops) f.loops++;
66        }
67        return f;
68    }
69    
70  void SortedRegions::update(gig::Instrument* instrument) {  void SortedRegions::update(gig::Instrument* instrument) {
71      // 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 37  void SortedRegions::update(gig::Instrume Line 73  void SortedRegions::update(gig::Instrume
73      // RegionChooser code needs a sorted list of regions.      // RegionChooser code needs a sorted list of regions.
74      regions.clear();      regions.clear();
75      if (instrument) {      if (instrument) {
76          for (gig::Region *r = instrument->GetFirstRegion() ;          for (gig::Region* r = instrument->GetFirstRegion() ;
77               r ;               r ;
78               r = instrument->GetNextRegion()) {               r = instrument->GetNextRegion()) {
79              regions.push_back(r);              regions.push_back(r);
# Line 52  gig::Region* SortedRegions::first() { Line 88  gig::Region* SortedRegions::first() {
88  }  }
89    
90  gig::Region* SortedRegions::next() {  gig::Region* SortedRegions::next() {
91      region_iterator++;      ++region_iterator;
92      return region_iterator == regions.end() ? 0 : *region_iterator;      return region_iterator == regions.end() ? 0 : *region_iterator;
93  }  }
94    
95    
96    
97  RegionChooser::RegionChooser() :  RegionChooser::RegionChooser() :
98        activeKeyColor("red"),
99        blue("#4796ff"),
100        grey1("grey69"),
101        white("white"),
102        black("black"),
103      m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),      m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),
104      currentActiveKey(-1)      currentActiveKey(-1),
105        modifyallregions(false)
106  {  {
107      Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();      set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT);
108    
109        loadBuiltInPix();
110    
111        // create blue hatched pattern
112        {
113            const int width = blueHatchedPattern->get_width();
114            const int height = blueHatchedPattern->get_height();
115            const int stride = blueHatchedPattern->get_rowstride();
116    
117            // manually convert from RGBA to ARGB
118            this->blueHatchedPatternARGB = blueHatchedPattern->copy();
119            const int pixelSize = stride / width;
120            const int totalPixels = width * height;
121            assert(pixelSize == 4);
122            unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
123            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
124                const unsigned char r = ptr[0];
125                const unsigned char g = ptr[1];
126                const unsigned char b = ptr[2];
127                const unsigned char a = ptr[3];
128                ptr[0] = b;
129                ptr[1] = g;
130                ptr[2] = r;
131                ptr[3] = a;
132            }
133    
134            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
135    #if HAS_CAIROMM_CPP11_ENUMS
136                this->blueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
137    #else
138                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
139    #endif
140            );
141            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
142    #if HAS_CAIROMM_CPP11_ENUMS
143            this->blueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
144    #else
145            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
146    #endif
147        }
148    
     red = Gdk::Color("#8070ff");  
     grey1 = Gdk::Color("#b0b0b0");  
     activeKeyColor = Gdk::Color("#ff0000");  
     white = Gdk::Color("#ffffff");  
     black = Gdk::Color("#000000");  
   
     colormap->alloc_color(red);  
     colormap->alloc_color(grey1);  
     colormap->alloc_color(activeKeyColor);  
     colormap->alloc_color(white);  
     colormap->alloc_color(black);  
149      instrument = 0;      instrument = 0;
150      region = 0;      region = 0;
151      resize.active = false;      resize.active = false;
# Line 84  RegionChooser::RegionChooser() : Line 155  RegionChooser::RegionChooser() :
155    
156      // properties of the virtual keyboard      // properties of the virtual keyboard
157      {      {
158          const char* choices[] = { _("normal"), _("chord"), NULL };          const char* choices[] = { _("normal"), _("chord"), 0 };
159          static const virt_keyboard_mode_t values[] = {          static const virt_keyboard_mode_t values[] = {
160              VIRT_KEYBOARD_MODE_NORMAL,              VIRT_KEYBOARD_MODE_NORMAL,
161              VIRT_KEYBOARD_MODE_CHORD              VIRT_KEYBOARD_MODE_CHORD
# Line 104  RegionChooser::RegionChooser() : Line 175  RegionChooser::RegionChooser() :
175      m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);      m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);
176      m_VirtKeybPropsBox.set_spacing(10);      m_VirtKeybPropsBox.set_spacing(10);
177      m_VirtKeybPropsBox.show();      m_VirtKeybPropsBox.show();
178        for (int i = 0 ; i < 128 ; i++) key_pressed[i] = false;
179    
180      actionGroup = Gtk::ActionGroup::create();      actionGroup = ActionGroup::create();
181    #if USE_GLIB_ACTION
182        actionGroup->add_action(
183            "Properties", sigc::mem_fun(*this, &RegionChooser::show_region_properties)
184        );
185        actionGroup->add_action(
186            "Remove", sigc::mem_fun(*this, &RegionChooser::delete_region)
187        );
188        actionGroup->add_action(
189            "Add", sigc::mem_fun(*this, &RegionChooser::add_region)
190        );
191        actionGroup->add_action(
192            "Dimensions", sigc::mem_fun(*this, &RegionChooser::manage_dimensions)
193        );
194        insert_action_group("PopupMenuInsideRegion", actionGroup);
195    #else
196      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties",
197                                           Gtk::Stock::PROPERTIES),                                           Gtk::Stock::PROPERTIES),
198                       sigc::mem_fun(*this,                       sigc::mem_fun(*this,
# Line 116  RegionChooser::RegionChooser() : Line 203  RegionChooser::RegionChooser() :
203                       sigc::mem_fun(*this, &RegionChooser::add_region));                       sigc::mem_fun(*this, &RegionChooser::add_region));
204      actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),      actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),
205                       sigc::mem_fun(*this, &RegionChooser::manage_dimensions));                       sigc::mem_fun(*this, &RegionChooser::manage_dimensions));
206    #endif
207    
208    #if USE_GTKMM_BUILDER
209        uiManager = Gtk::Builder::create();
210        Glib::ustring ui_info =
211            "<interface>"
212            "  <menu id='menu-PopupMenuInsideRegion'>"
213            "    <section>"
214            "      <item>"
215            "        <attribute name='label' translatable='yes'>Properties</attribute>"
216            "        <attribute name='action'>PopupMenuInsideRegion.Properties</attribute>"
217            "      </item>"
218            "      <item>"
219            "        <attribute name='label' translatable='yes'>Dimensions</attribute>"
220            "        <attribute name='action'>PopupMenuInsideRegion.Dimensions</attribute>"
221            "      </item>"
222            "      <item>"
223            "        <attribute name='label' translatable='yes'>Remove</attribute>"
224            "        <attribute name='action'>PopupMenuInsideRegion.Remove</attribute>"
225            "      </item>"
226            "    </section>"
227            "  </menu>"
228            "  <menu id='menu-PopupMenuOutsideRegion'>"
229            "    <section>"
230            "      <item>"
231            "        <attribute name='label' translatable='yes'>Add</attribute>"
232            "        <attribute name='action'>PopupMenuInsideRegion.Add</attribute>"
233            "      </item>"
234            "    </section>"
235            "  </menu>"
236            "</interface>";
237        uiManager->add_from_string(ui_info);
238        
239        popup_menu_inside_region = new Gtk::Menu(
240             Glib::RefPtr<Gio::Menu>::cast_dynamic(
241                 uiManager->get_object("menu-PopupMenuInsideRegion")
242             )
243        );
244        popup_menu_outside_region = new Gtk::Menu(
245             Glib::RefPtr<Gio::Menu>::cast_dynamic(
246                 uiManager->get_object("menu-PopupMenuOutsideRegion")
247             )
248        );
249    #else
250      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
251      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
252      Glib::ustring ui_info =      Glib::ustring ui_info =
# Line 137  RegionChooser::RegionChooser() : Line 267  RegionChooser::RegionChooser() :
267      popup_menu_outside_region = dynamic_cast<Gtk::Menu*>(      popup_menu_outside_region = dynamic_cast<Gtk::Menu*>(
268          uiManager->get_widget("/PopupMenuOutsideRegion"));          uiManager->get_widget("/PopupMenuOutsideRegion"));
269    
270    #endif // USE_GTKMM_BUILDER
271    
272    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 24)
273    # warning GTKMM4 event registration code missing for regionchooser!
274        //add_events(Gdk::EventMask::BUTTON_PRESS_MASK);
275    #else
276      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
277                 Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK);
278    #endif
279    
280      dimensionManager.region_to_be_changed_signal.connect(      dimensionManager.region_to_be_changed_signal.connect(
281          region_to_be_changed_signal.make_slot()          region_to_be_changed_signal.make_slot()
# Line 157  RegionChooser::RegionChooser() : Line 294  RegionChooser::RegionChooser() :
294      keyboard_key_released_signal.connect(      keyboard_key_released_signal.connect(
295          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)
296      );      );
297        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."));
298    
299        Settings::singleton()->showTooltips.get_proxy().signal_changed().connect(
300            sigc::mem_fun(*this, &RegionChooser::on_show_tooltips_changed)
301        );
302    
303        on_show_tooltips_changed();
304  }  }
305    
306  RegionChooser::~RegionChooser()  RegionChooser::~RegionChooser()
307  {  {
308  }  }
309    
310  template<class T> inline std::string ToString(T o) {  void RegionChooser::on_show_tooltips_changed() {
311      std::stringstream ss;      const bool b = Settings::singleton()->showTooltips;
312      ss << o;  
313      return ss.str();      set_has_tooltip(b);
314    }
315    
316    void RegionChooser::setModifyAllRegions(bool b) {
317        modifyallregions = b;
318        // redraw required parts
319        queue_draw();
320    }
321    
322    void RegionChooser::invalidate_key(int key) {
323        const int h = KEYBOARD_HEIGHT;
324        const int w = get_width() - 1;
325        int x1 = key_to_x(key - 0.5, w);
326        int x2 = key_to_x(key + 1.5, w);
327    
328        Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
329        get_window()->invalidate_rect(rect, false);
330  }  }
331    
332  void RegionChooser::on_note_on_event(int key, int velocity) {  void RegionChooser::on_note_on_event(int key, int velocity) {
333      draw_region(key, key+1, activeKeyColor);      key_pressed[key] = true;
334        invalidate_key(key);
335      m_VirtKeybVelocityLabel.set_text(ToString(velocity));      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
336  }  }
337    
338  void RegionChooser::on_note_off_event(int key, int velocity) {  void RegionChooser::on_note_off_event(int key, int velocity) {
339      if (is_black_key(key)) {      key_pressed[key] = false;
340          draw_region(key, key+1, black);      invalidate_key(key);
     } else {  
         draw_region(key, key+1, key >= 21 && key <= 108 ? white : grey1);  
     }  
341      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
342  }  }
343    
 void RegionChooser::on_realize()  
 {  
     // We need to call the base on_realize()  
     Gtk::DrawingArea::on_realize();  
344    
345      // Now we can allocate any additional resources we need  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
346      Glib::RefPtr<Gdk::Window> window = get_window();  bool RegionChooser::on_expose_event(GdkEventExpose* e) {
347      gc = Gdk::GC::create(window);      double clipx1 = e->area.x;
348      window->clear();      double clipx2 = e->area.x + e->area.width;
349        double clipy1 = e->area.y;
350        double clipy2 = e->area.y + e->area.height;
351    
352        const Cairo::RefPtr<Cairo::Context>& cr =
353            get_window()->create_cairo_context();
354    #if 0
355    }
356    #endif
357    #else
358    bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
359        double clipx1, clipx2, clipy1, clipy2;
360        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
361    #endif
362    
363        cr->save();
364        cr->set_line_width(1);
365    
366    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
367        const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
368    #else
369    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 24)
370        GdkRGBA gdkBgRGBA;
371        gtk_style_context_get_background_color(get_style_context()->gobj(), &gdkBgRGBA);
372        const Gdk::RGBA bg = Glib::wrap(&gdkBgRGBA, true);
373    # else
374        const Gdk::RGBA bg = get_style_context()->get_background_color();
375    # endif
376    #endif
377        Gdk::Cairo::set_source_rgba(cr, bg);
378        cr->paint();
379    
380        if (clipy2 > h1) {
381            draw_keyboard(cr, clipx1, clipx2);
382        }
383    
384        if (clipy1 < h1 && instrument) {
385            draw_regions(cr, clipx1, clipx2);
386        }
387    
388        cr->restore();
389    
390        return true;
391  }  }
392    
393  bool RegionChooser::on_expose_event(GdkEventExpose* event)  void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
394  {                                    int clip_low, int clip_high) {
     Glib::RefPtr<Gdk::Window> window = get_window();  
     window->clear();  
395      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
396      const int w = get_width() - 1;      const int w = get_width() - 1;
397      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
398    
399      Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();      Gdk::Cairo::set_source_rgba(cr, black);
400      Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
401        cr->stroke();
402    
403        int x1 = key_to_x(20.5, w);
404        Gdk::Cairo::set_source_rgba(cr, grey1);
405        cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
406        cr->fill();
407    
408        int x2 = key_to_x(109.5, w);
409        Gdk::Cairo::set_source_rgba(cr, white);
410        cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
411        cr->fill();
412    
413        Gdk::Cairo::set_source_rgba(cr, grey1);
414        cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);
415        cr->fill();
416    
417      window->draw_rectangle(black, false, 0, h1, w, h - 1);      Gdk::Cairo::set_source_rgba(cr, black);
     gc->set_foreground(grey1);  
     int x1 = int(w * 20.5 / 128.0 + 0.5);  
     int x2 = int(w * 109.5 / 128.0 + 0.5);  
     window->draw_rectangle(gc, true, 1, h1 + 1,  
                            x1 - 1, h - 2);  
     window->draw_rectangle(white, true, x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);  
     window->draw_rectangle(gc, true, x2 + 1, h1 + 1,  
                            w - x2 - 1, h - 2);  
     for (int i = 0 ; i < 128 ; i++) {  
         int note = (i + 3) % 12;  
         int x = int(w * i / 128.0 + 0.5);  
418    
419          if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) {      int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
420              int x2 = int(w * (i + 0.5) / 128.0 + 0.5);      int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
421              window->draw_line(black, x2, h1 + bh, x2, h1 + h);  
422        for (int i = clipkey1 ; i < clipkey2 ; i++) {
423            int note = (i + 3) % 12;
424            int x = key_to_x(i, w);
425    
426              int x3 = int(w * (i + 1) / 128.0 + 0.5);          if (note == 1 || note == 4 || note == 6 ||
427              window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh);              note == 9 || note == 11) {
428                // black key: short line in the middle, with a rectangle
429                // on top
430                int x2 = key_to_x(i + 0.5, w);
431                cr->move_to(x2 + 0.5, h1 + bh + 0.5);
432                cr->line_to(x2 + 0.5, h1 + h - 1);
433                cr->stroke();
434    
435                int x3 = key_to_x(i + 1, w);
436                cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
437                cr->fill();
438          } else if (note == 3 || note == 8) {          } else if (note == 3 || note == 8) {
439              window->draw_line(black, x, h1 + 1, x, h1 + h);              // C or F: long line to the left
440                cr->move_to(x + 0.5, h1 + 1);
441                cr->line_to(x + 0.5, h1 + h - 1);
442                cr->stroke();
443          }          }
444          if (note == 3) draw_digit(i);  
445            if (key_pressed[i]) draw_key(cr, i);
446    
447            if (note == 3) draw_digit(cr, i);
448      }      }
449    }
450    
     if (instrument) {  
         int i = 0;  
         gig::Region *next_region;  
         int x3 = -1;  
         for (gig::Region *r = regions.first() ; r ; r = next_region) {  
451    
452              if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);  void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
453              next_region = regions.next();                                   int clip_low, int clip_high) {
454              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {      const int w = get_width() - 1;
455                  int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);  
456                  window->draw_line(black, x3, 0, x2, 0);      Gdk::Cairo::set_source_rgba(cr, black);
457                  window->draw_line(black, x3, h1 - 1, x2, h1 - 1);      gig::Region* next_region;
458                  window->draw_line(black, x2, 1, x2, h1 - 2);      int x3 = -1;
459                  window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);      for (gig::Region* r = regions.first() ; r ; r = next_region) {
460                  x3 = -1;          next_region = regions.next();
461              }  
462              i++;          if (x3 < 0) {
463          }              x3 = key_to_x(r->KeyRange.low, w);
464                if (x3 >= clip_high) break;
465          for (gig::Region *r = regions.first() ; r ; r = regions.next()) {          }
466              int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);          if (!next_region ||
467              window->draw_line(black, x, 1, x, h1 - 2);              r->KeyRange.high + 1 != next_region->KeyRange.low ||
468          }              r == region || next_region == region) {
469    
470          if (region) {              int x2 = key_to_x(r->KeyRange.high + 1, w);
471              int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);              if (x2 >= clip_low) {
472              int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);                  cr->move_to(x3, 0.5);
473              gc->set_foreground(red);                  cr->line_to(x2 + 0.5, 0.5);
474              window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);                  cr->line_to(x2 + 0.5, h1 - 0.5);
475                    cr->line_to(x3, h1 - 0.5);
476                    cr->stroke();
477    
478                    if (region == r)
479                        Gdk::Cairo::set_source_rgba(cr, blue);
480                    else if (modifyallregions)
481                        cr->set_source(blueHatchedSurfacePattern);
482                    else
483                        Gdk::Cairo::set_source_rgba(cr, white);
484    
485                    cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
486                    cr->fill();
487                    Gdk::Cairo::set_source_rgba(cr, black);
488                }
489                x3 = -1;
490          }          }
491      }      }
     return true;  
 }  
492    
493        for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
494            int x = key_to_x(r->KeyRange.low, w);
495            int x2 = key_to_x(r->KeyRange.high + 1, w);
496    
497            RegionFeatures features = regionFeatures(r);
498    
499            const bool bShowLoopSymbol = features.loops > 0;
500            const bool bShowSampleRefSymbol = features.sampleRefs < features.validDimRegs;
501            if (bShowLoopSymbol || bShowSampleRefSymbol) {
502                const int margin = 2;
503                const int wRgn = x2 - x;
504                //printf("x=%d x2=%d wRgn=%d\n", x, x2, wRgn);
505    
506                cr->save();
507                cr->set_line_width(1);
508                cr->rectangle(x, 1, wRgn, h1 - 1);
509                cr->clip();
510                if (bShowSampleRefSymbol) {
511                    const int wPic = 8;
512                    const int hPic = 8;
513                    Gdk::Cairo::set_source_pixbuf(
514                        cr, (features.sampleRefs) ? yellowDot : redDot,
515                        x + (wRgn-wPic)/2.f,
516                        (bShowLoopSymbol) ? margin : (h1-hPic)/2.f
517                    );
518                    cr->paint();
519                }
520                if (bShowLoopSymbol) {
521                    const int wPic = 12;
522                    const int hPic = 14;
523                    Gdk::Cairo::set_source_pixbuf(
524                        cr, (features.loops == features.validDimRegs) ? blackLoop : grayLoop,
525                        x + (wRgn-wPic)/2.f,
526                        (bShowSampleRefSymbol) ? h1 - hPic - margin : (h1-hPic)/2.f
527                    );
528                    cr->paint();
529                }
530                cr->restore();
531            }
532        }
533    
534  void RegionChooser::on_size_request(GtkRequisition* requisition)      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
535  {          int x = key_to_x(r->KeyRange.low, w);
536      *requisition = GtkRequisition();  
537      requisition->height = KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT;          if (x < clip_low) continue;
538      requisition->width = 500;          if (x >= clip_high) break;
539    
540            cr->move_to(x + 0.5, 1);
541            cr->line_to(x + 0.5, h1 - 1);
542            cr->stroke();
543        }
544    
545        // if there is no region yet, show the user some hint text that he may
546        // right click on this area to create a new region
547        if (!regions.first()) {
548            Glib::RefPtr<Pango::Context> context = get_pango_context();
549            Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
550            layout->set_alignment(Pango::ALIGN_CENTER);
551            layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
552            layout->set_width(get_width() * Pango::SCALE);
553            //layout->set_height(get_height() * Pango::SCALE);
554            layout->set_spacing(10);
555            Gdk::Cairo::set_source_rgba(cr, blue);
556            // get the text dimensions
557            int text_width, text_height;
558            layout->get_pixel_size(text_width, text_height);
559            cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
560    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
561            pango_cairo_show_layout(cr->cobj(), layout->gobj());
562    #else
563            layout->show_in_cairo_context(cr);
564    #endif
565        }
566  }  }
567    
568  bool RegionChooser::is_black_key(int key) {  bool RegionChooser::is_black_key(int key) {
# Line 277  bool RegionChooser::is_black_key(int key Line 570  bool RegionChooser::is_black_key(int key
570      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
571  }  }
572    
573  void RegionChooser::draw_digit(int key) {  void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
574                                   int key) {
575      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
576      const int w = get_width() - 1;      const int w = get_width() - 1;
577      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(get_pango_context());      Glib::RefPtr<Pango::Layout> layout =
578            Pango::Layout::create(get_pango_context());
579      char buf[30];      char buf[30];
580      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
581      layout->set_markup(buf);      layout->set_markup(buf);
# Line 288  void RegionChooser::draw_digit(int key) Line 583  void RegionChooser::draw_digit(int key)
583      double text_w = double(rectangle.get_width()) / Pango::SCALE;      double text_w = double(rectangle.get_width()) / Pango::SCALE;
584      double text_h = double(rectangle.get_height()) / Pango::SCALE;      double text_h = double(rectangle.get_height()) / Pango::SCALE;
585      double x = w * (key + 0.75) / 128.0;      double x = w * (key + 0.75) / 128.0;
586      get_window()->draw_layout(get_style()->get_black_gc(), int(x - text_w / 2 + 1),      Gdk::Cairo::set_source_rgba(cr, black);
587                                int(h1 + h - text_h + 0.5), layout);      cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));
588    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
589        pango_cairo_show_layout(cr->cobj(), layout->gobj());
590    #else
591        layout->show_in_cairo_context(cr);
592    #endif
593  }  }
594    
595  void RegionChooser::draw_region(int from, int to, const Gdk::Color& color)  void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
596  {                               int key) {
597      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
598      const int w = get_width() - 1;      const int w = get_width() - 1;
599      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
600    
601      Glib::RefPtr<Gdk::Window> window = get_window();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     gc->set_foreground(color);  
602    
603      for (int i = from ; i < to ; i++) {      int note = (key + 3) % 12;
604          int note = (i + 3) % 12;      int x = key_to_x(key, w) + 1;
605          int x = int(w * i / 128.0 + 0.5) + 1;      int x2 = key_to_x(key + 1.5, w);
606          int x2 = int(w * (i + 1.5) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
607          int x3 = int(w * (i + 1) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
608          int x4 = int(w * (i - 0.5) / 128.0 + 0.5);      int w1 = x3 - x;
609          int w1 = x3 - x;      switch (note) {
610          switch (note) {      case 0: case 5: case 10:
611          case 0: case 5: case 10:          cr->rectangle(x, h1 + 1, w1, bh);
612              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);          cr->fill();
613              window->draw_rectangle(gc, true, x4 + 1, h1 + bh + 1, x2 - x4 - 1, h - bh - 2);          cr->rectangle(x4 + 1, h1 + bh + 1, x2 - x4 - 1, h - bh - 2);
614              break;          cr->fill();
615          case 2: case 7:          break;
616              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);      case 2: case 7:
617              window->draw_rectangle(gc, true, x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2);          cr->rectangle(x, h1 + 1, w1, bh);
618              break;          cr->fill();
619          case 3: case 8:          cr->rectangle(x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2);
620              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);          cr->fill();
621              window->draw_rectangle(gc, true, x, h1 + bh + 1, x2 - x, h - bh - 2);          break;
622              if (note == 3) draw_digit(i);      case 3: case 8:
623              break;          cr->rectangle(x, h1 + 1, w1, bh);
624          default:          cr->fill();
625              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh - 1);          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
626              break;          cr->fill();
627          }          break;
628        default:
629            cr->rectangle(x, h1 + 1, w1, bh - 1);
630            cr->fill();
631            break;
632      }      }
633        Gdk::Cairo::set_source_rgba(cr, black);
634  }  }
635    
636  void RegionChooser::set_instrument(gig::Instrument* instrument)  void RegionChooser::set_instrument(gig::Instrument* instrument)
# Line 341  void RegionChooser::set_instrument(gig:: Line 645  void RegionChooser::set_instrument(gig::
645    
646  bool RegionChooser::on_button_release_event(GdkEventButton* event)  bool RegionChooser::on_button_release_event(GdkEventButton* event)
647  {  {
648      const int k = int(event->x / (get_width() - 1) * 128.0);      const int k = x_to_key(event->x, get_width() - 1);
649    
650      // handle-note off on virtual keyboard      // handle-note off on virtual keyboard
651      if (event->type == GDK_BUTTON_RELEASE) {      if (event->type == GDK_BUTTON_RELEASE) {
# Line 364  bool RegionChooser::on_button_release_ev Line 668  bool RegionChooser::on_button_release_ev
668      }      }
669    
670      if (resize.active) {      if (resize.active) {
671    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
672          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
673    #else
674    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
675            Glib::wrap(event->device, true)->ungrab(event->time);
676    # else
677            Glib::wrap(event->device, true)->get_seat()->ungrab();
678    # endif
679    #endif
680          resize.active = false;          resize.active = false;
681    
         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);  
             }  
         }  
   
682          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
683              get_window()->set_cursor();              get_window()->set_cursor();
684              cursor_is_resize = false;              cursor_is_resize = false;
685          }          }
686      } else if (move.active) {      } else if (move.active) {
687    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
688          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
689    #else
690    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
691            Glib::wrap(event->device, true)->ungrab(event->time);
692    # else
693            Glib::wrap(event->device, true)->get_seat()->ungrab();
694    # endif
695    #endif
696          move.active = false;          move.active = false;
697    
698          if (move.pos) {          if (is_in_resize_zone(event->x, event->y)) {
699              instrument_struct_to_be_changed_signal.emit(instrument);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
700              region->SetKeyRange(              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
701                  region->KeyRange.low  + move.pos,  #else
702                  region->KeyRange.high + move.pos              get_window()->set_cursor(
703    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
704                    Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
705    # else
706                    Gdk::Cursor::create(
707                        Glib::wrap(event->device, true)->get_seat()->get_display(),
708                        Gdk::SB_H_DOUBLE_ARROW
709                    )
710    # endif
711              );              );
712    #endif
713                cursor_is_resize = true;
714            }
715        }
716        return true;
717    }
718    
719    void RegionChooser::update_after_resize()
720    {
721        if (resize.mode == resize.moving_high_limit) {
722            if (resize.region->KeyRange.high != resize.pos - 1) {
723                instrument_struct_to_be_changed_signal.emit(instrument);
724                resize.region->SetKeyRange(resize.region->KeyRange.low,
725                                           resize.pos - 1);
726              regions.update(instrument);              regions.update(instrument);
727              instrument_changed.emit();              instrument_changed.emit();
728              instrument_struct_changed_signal.emit(instrument);              instrument_struct_changed_signal.emit(instrument);
729          }          }
730        } else if (resize.mode == resize.moving_low_limit) {
731            if (resize.region->KeyRange.low != resize.pos) {
732                instrument_struct_to_be_changed_signal.emit(instrument);
733                resize.region->SetKeyRange(resize.pos,
734                                           resize.region->KeyRange.high);
735                regions.update(instrument);
736                instrument_changed.emit();
737                instrument_struct_changed_signal.emit(instrument);
738            }
739        }
740    }
741    
742          if (is_in_resize_zone(event->x, event->y)) {  void RegionChooser::update_after_move(int pos)
743              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));  {
744              cursor_is_resize = true;      instrument_struct_to_be_changed_signal.emit(instrument);
745        const int range = region->KeyRange.high - region->KeyRange.low;
746        const int diff  = pos - int(region->KeyRange.low);
747        region->SetKeyRange(pos, pos + range);
748        if (Settings::singleton()->moveRootNoteWithRegionMoved) {
749            for (int i = 0; i < 256; ++i) {
750                gig::DimensionRegion* dimrgn = region->pDimensionRegions[i];
751                if (!dimrgn || !dimrgn->pSample || !dimrgn->PitchTrack) continue;
752                dimrgn->UnityNote += diff;
753          }          }
754      }      }
755      return true;      regions.update(instrument);
756        instrument_changed.emit();
757        instrument_struct_changed_signal.emit(instrument);
758  }  }
759    
760  bool RegionChooser::on_button_press_event(GdkEventButton* event)  bool RegionChooser::on_button_press_event(GdkEventButton* event)
761  {  {
762      if (!instrument) return true;      if (!instrument) return true;
763    
764      const int k = int(event->x / (get_width() - 1) * 128.0);      const int w = get_width() - 1;
765        const int k = x_to_key(event->x, w);
766    
767      if (event->type == GDK_BUTTON_PRESS) {      if (event->type == GDK_BUTTON_PRESS) {
768          if (event->y >= REGION_BLOCK_HEIGHT) {          if (event->y >= REGION_BLOCK_HEIGHT) {
# Line 433  bool RegionChooser::on_button_press_even Line 773  bool RegionChooser::on_button_press_even
773          }          }
774      }      }
775    
776        // left mouse button double click
777        if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
778            if (event->y < REGION_BLOCK_HEIGHT) {
779                // show dimension manager dialog for this region
780                manage_dimensions();
781            }
782        }
783    
784      if (event->y >= REGION_BLOCK_HEIGHT) return true;      if (event->y >= REGION_BLOCK_HEIGHT) return true;
785      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
786          gig::Region* r = get_region(k);          gig::Region* r = get_region(k);
# Line 448  bool RegionChooser::on_button_press_even Line 796  bool RegionChooser::on_button_press_even
796          }          }
797      } else {      } else {
798          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
799    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
800              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
801                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
802                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
803                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
804                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW), event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
805                                           event->time);
806    #else
807    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
808                Glib::wrap(event->device, true)->grab(get_window(),
809                                                      Gdk::OWNERSHIP_NONE,
810                                                      false,
811                                                      Gdk::BUTTON_RELEASE_MASK |
812                                                      Gdk::POINTER_MOTION_MASK |
813                                                      Gdk::POINTER_MOTION_HINT_MASK,
814                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
815                                                      event->time);
816    # else
817                Glib::wrap(event->device, true)->get_seat()->grab(
818                    get_window(),
819                    Gdk::SeatCapabilities::SEAT_CAPABILITY_ALL_POINTING,
820                    false,
821                    Gdk::Cursor::create(
822                        Glib::wrap(event->device, true)->get_seat()->get_display(),
823                        Gdk::SB_H_DOUBLE_ARROW
824                    ),
825                    reinterpret_cast<GdkEvent*>(event)
826                );
827    # endif
828    #endif
829              resize.active = true;              resize.active = true;
830          } else {          } else {
831              gig::Region* r = get_region(k);              gig::Region* r = get_region(k);
# Line 462  bool RegionChooser::on_button_press_even Line 835  bool RegionChooser::on_button_press_even
835                  region_selected();                  region_selected();
836                  dimensionManager.set_region(region);                  dimensionManager.set_region(region);
837    
838    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
839                  get_window()->pointer_grab(false,                  get_window()->pointer_grab(false,
840                                             Gdk::BUTTON_RELEASE_MASK |                                             Gdk::BUTTON_RELEASE_MASK |
841                                             Gdk::POINTER_MOTION_MASK |                                             Gdk::POINTER_MOTION_MASK |
842                                             Gdk::POINTER_MOTION_HINT_MASK,                                             Gdk::POINTER_MOTION_HINT_MASK,
843                                             Gdk::Cursor(Gdk::FLEUR), event->time);                                             Gdk::Cursor(Gdk::FLEUR),
844                                               event->time);
845    #else
846    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
847                Glib::wrap(event->device, true)->grab(get_window(),
848                                                      Gdk::OWNERSHIP_NONE,
849                                                      false,
850                                                      Gdk::BUTTON_RELEASE_MASK |
851                                                      Gdk::POINTER_MOTION_MASK |
852                                                      Gdk::POINTER_MOTION_HINT_MASK,
853                                                      Gdk::Cursor::create(Gdk::FLEUR),
854                                                      event->time);
855    # else
856                Glib::wrap(event->device, true)->get_seat()->grab(
857                    get_window(),
858                    Gdk::SeatCapabilities::SEAT_CAPABILITY_ALL_POINTING,
859                    false,
860                    Gdk::Cursor::create(
861                        Glib::wrap(event->device, true)->get_seat()->get_display(),
862                        Gdk::FLEUR
863                    ),
864                    reinterpret_cast<GdkEvent*>(event)
865                );
866    # endif
867    #endif
868                  move.active = true;                  move.active = true;
869                  move.from_x = event->x;                  move.offset = event->x - key_to_x(region->KeyRange.low, w);
                 move.pos = 0;  
870              }              }
871          }          }
872      }      }
# Line 478  bool RegionChooser::on_button_press_even Line 875  bool RegionChooser::on_button_press_even
875    
876  gig::Region* RegionChooser::get_region(int key)  gig::Region* RegionChooser::get_region(int key)
877  {  {
878      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();  
   
879          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
880          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;  
881      }      }
882      return 0;      return 0;
883  }  }
884    
885    void RegionChooser::set_region(gig::Region* region) {
886        this->region = region;
887        queue_draw();
888        region_selected();
889        dimensionManager.set_region(region);
890    }
891    
892    void RegionChooser::select_next_region() {
893        if (!instrument) return;
894        if (!region) {
895            for (int i = 0; i < 128; ++i) {
896                ::gig::Region* rgn = instrument->GetRegion(i);
897                if (rgn) {
898                    set_region(rgn);
899                    return;
900                }
901            }
902        } else {
903            bool currentFound = false;
904            for (int i = 0; i < 128; ++i) {
905                ::gig::Region* rgn = instrument->GetRegion(i);
906                if (!rgn) continue;
907                if (currentFound) {
908                    if (rgn != region) {
909                        set_region(rgn);
910                        return;
911                    }
912                } else {
913                    if (rgn == region) currentFound = true;
914                }
915            }
916        }
917    }
918    
919    void RegionChooser::select_prev_region() {
920        if (!instrument) return;
921        if (!region) {
922            for (int i = 0; i < 128; ++i) {
923                ::gig::Region* rgn = instrument->GetRegion(i);
924                if (rgn) {
925                    set_region(rgn);
926                    return;
927                }
928            }
929        } else {
930            bool currentFound = false;
931            for (int i = 127; i >= 0; --i) {
932                ::gig::Region* rgn = instrument->GetRegion(i);
933                if (!rgn) continue;
934                if (currentFound) {
935                    if (rgn != region) {
936                        set_region(rgn);
937                        return;
938                    }
939                } else {
940                    if (rgn == region) currentFound = true;
941                }
942            }
943        }
944    }
945    
946  void RegionChooser::motion_resize_region(int x, int y)  void RegionChooser::motion_resize_region(int x, int y)
947  {  {
948      const int w = get_width() - 1;      const int w = get_width() - 1;
     Glib::RefPtr<Gdk::Window> window = get_window();  
949    
950      int k = int(double(x) / w * 128.0 + 0.5);      int k = int(double(x) / w * 128.0 + 0.5);
951    
# Line 517  void RegionChooser::motion_resize_region Line 965  void RegionChooser::motion_resize_region
965                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
966              }              }
967          }          }
968          Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();          resize.pos = k;
         Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();  
         if (region == resize.region) {  
             gc->set_foreground(red);  
             white = gc;  
         }  
         Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);  
         int prevx = int(w * resize.pos / 128.0 + 0.5);  
         x = int(w * k / 128.0 + 0.5);  
969    
970            int x1, x2;
971          if (resize.mode == resize.moving_high_limit) {          if (resize.mode == resize.moving_high_limit) {
972              if (k > resize.pos) {              if (resize.region->KeyRange.high < resize.pos - 1) {
973                  window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);                  x1 = resize.region->KeyRange.high;
974                  window->draw_line(black, prevx, 0, x, 0);                  x2 = resize.pos - 1;
                 window->draw_line(black, prevx, h1 - 1, x, h1 - 1);  
975              } else {              } else {
976                  int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);                  x1 = resize.pos - 1;
977                  window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);                  x2 = resize.region->KeyRange.high;
978              }              }
979          } else {          } else {
980              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
981                  window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);                  x1 = resize.region->KeyRange.low;
982                  window->draw_line(black, x, 0, prevx, 0);                  x2 = resize.pos;
                 window->draw_line(black, x, h1 - 1, prevx, h1 - 1);  
983              } else {              } else {
984                  int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);                  x1 = resize.pos;
985                  window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);                  x2 = resize.region->KeyRange.low;
986              }              }
987          }          }
988          window->draw_line(black, x, 1, x, h1 - 2);          x1 = key_to_x(x1, w);
989          resize.pos = k;          x2 = key_to_x(x2 + 1, w) + 1;
990            Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
991    
992            update_after_resize();
993    
994            //get_window()->invalidate_rect(rect, false);
995            get_window()->invalidate(false); // repaint entire region, otherwise it would create visual artifacts
996      }      }
997  }  }
998    
999  void RegionChooser::motion_move_region(int x, int y)  void RegionChooser::motion_move_region(int x, int y)
1000  {  {
1001      const int w = get_width() - 1;      const int w = get_width() - 1;
     Glib::RefPtr<Gdk::Window> window = get_window();  
1002    
1003      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);
1004      if (k == move.pos) return;  
1005      int new_k;      if (l == region->KeyRange.low) return;
1006      bool new_touch_left;      int new_l;
1007      bool new_touch_right;      int regionsize = region->KeyRange.high - region->KeyRange.low;
1008      int a = 0;      int a = 0;
1009      if (k > move.pos) {      if (l > region->KeyRange.low) {
1010          for (gig::Region* r = regions.first() ; ; r = regions.next()) {          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
1011              if (r != region) {              if (r != region) {
1012                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
1013    
1014                  // gap: from a to b (not inclusive b)                  // gap: from a to b (not inclusive b)
1015    
1016                  if (region->KeyRange.high + move.pos >= b) {                  if (region->KeyRange.high >= b) {
1017                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
1018                  } else {                  } else {
1019    
1020                      if (a > region->KeyRange.low + k) {                      if (a > l) {
1021                          // this gap is too far to the right, break                          // this gap is too far to the right, break
1022                          break;                          break;
1023                      }                      }
1024    
1025                      int newhigh = std::min(region->KeyRange.high + k, b - 1);                      int newhigh = std::min(l + regionsize, b - 1);
1026                      int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);                      int newlo = newhigh - regionsize;
1027    
1028                      if (newlo >= a) {                      if (newlo >= a) {
1029                          // yes it fits - it's a candidate                          // yes it fits - it's a candidate
1030                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
1031                      }                      }
1032                  }                  }
1033                  if (!r) break;                  if (!r) break;
# Line 599  void RegionChooser::motion_move_region(i Line 1041  void RegionChooser::motion_move_region(i
1041    
1042                  // gap from a to b (not inclusive b)                  // gap from a to b (not inclusive b)
1043    
1044                  if (region->KeyRange.high + k >= b) {                  if (l + regionsize >= b) {
1045                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
1046                  } else {                  } else {
1047    
1048                      if (a > region->KeyRange.low + move.pos) {                      if (a > region->KeyRange.low) {
1049                          // this gap is too far to the right, break                          // this gap is too far to the right, break
1050                          break;                          break;
1051                      }                      }
1052    
1053                      int newlo = std::max(region->KeyRange.low + k, a);                      int newlo = std::max(l, a);
1054                      int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);                      int newhigh = newlo + regionsize;
1055    
1056                      if (newhigh < b) {                      if (newhigh < b) {
1057                          // yes it fits - break as the first one is the best                          // yes it fits - break as the first one is the best
1058                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
1059                          break;                          break;
1060                      }                      }
1061                  }                  }
# Line 624  void RegionChooser::motion_move_region(i Line 1064  void RegionChooser::motion_move_region(i
1064              }              }
1065          }          }
1066      }      }
1067      k = new_k;      if (new_l == region->KeyRange.low) return;
     if (k == move.pos) return;  
1068    
1069      Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);      int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
1070      int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
1071      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);  
     Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();  
     gc->set_foreground(red);  
   
     if (!new_touch_left) window->draw_line(black, x, 1, x, h1 - 2);  
     if (!new_touch_right) window->draw_line(black, x2, 1, x2, h1 - 2);  
   
     if (k > move.pos) {  
         window->draw_rectangle(bg, true, prevx + (move.touch_left ? 1 : 0), 0,  
                                std::min(x, prevx2 + 1 - (move.touch_right ? 1 : 0)) -  
                                (prevx + (move.touch_left ? 1 : 0)), h1);  
   
         window->draw_line(black, std::max(x, prevx2 + 1), 0, x2, 0);  
         window->draw_line(black, std::max(x, prevx2 + 1), h1 - 1, x2, h1 - 1);  
         window->draw_rectangle(gc, true, std::max(x + 1, prevx2), 1,  
                                x2 - std::max(x + 1, prevx2), h1 - 2);  
     } else {  
         window->draw_rectangle(bg, true, 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);  
   
         window->draw_line(black, x, 0, std::min(x2, prevx - 1), 0);  
         window->draw_line(black, x, h1 - 1, std::min(x2, prevx - 1), h1 - 1);  
1072    
1073          window->draw_rectangle(gc, true, x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
1074      }      update_after_move(new_l);
1075    
1076      move.pos = k;      get_window()->invalidate_rect(rect, false);
     move.touch_left = new_touch_left;  
     move.touch_right = new_touch_right;  
1077  }  }
1078    
1079    
# Line 668  bool RegionChooser::on_motion_notify_eve Line 1081  bool RegionChooser::on_motion_notify_eve
1081  {  {
1082      Glib::RefPtr<Gdk::Window> window = get_window();      Glib::RefPtr<Gdk::Window> window = get_window();
1083      int x, y;      int x, y;
1084    #if HAS_GDKMM_SEAT
1085        x = event->x;
1086        y = event->y;
1087        Gdk::ModifierType state = Gdk::ModifierType(event->state);
1088    #else
1089      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
1090      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
1091    #endif
1092    
1093      // handle virtual MIDI keyboard      // handle virtual MIDI keyboard
1094      if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&      if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&
# Line 677  bool RegionChooser::on_motion_notify_eve Line 1096  bool RegionChooser::on_motion_notify_eve
1096          event->y >= REGION_BLOCK_HEIGHT &&          event->y >= REGION_BLOCK_HEIGHT &&
1097          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
1098      {      {
1099          const int k = int(event->x / (get_width() - 1) * 128.0);          const int k = x_to_key(event->x, get_width() - 1);
1100          if (k != currentActiveKey) {          if (k != currentActiveKey) {
1101              int velocity =              int velocity =
1102                  (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :                  (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
# Line 697  bool RegionChooser::on_motion_notify_eve Line 1116  bool RegionChooser::on_motion_notify_eve
1116      } else {      } else {
1117          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
1118              if (!cursor_is_resize) {              if (!cursor_is_resize) {
1119    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1120                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1121    #else
1122                    window->set_cursor(
1123    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1124                        Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1125    # else
1126                        Gdk::Cursor::create(
1127                            Glib::wrap(event->device, true)->get_seat()->get_display(),
1128                            Gdk::SB_H_DOUBLE_ARROW
1129                        )
1130    # endif
1131                    );
1132    #endif
1133                  cursor_is_resize = true;                  cursor_is_resize = true;
1134              }              }
1135          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 718  bool RegionChooser::is_in_resize_zone(do Line 1150  bool RegionChooser::is_in_resize_zone(do
1150          for (gig::Region* r = regions.first(); r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
1151              next_region = regions.next();              next_region = regions.next();
1152    
1153              int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);              int lo = key_to_x(r->KeyRange.low, w);
1154              if (x <= lo - 2) break;              if (x <= lo - 2) break;
1155              if (x < lo + 2) {              if (x < lo + 2) {
1156                  resize.region = r;                  resize.region = r;
# Line 741  bool RegionChooser::is_in_resize_zone(do Line 1173  bool RegionChooser::is_in_resize_zone(do
1173                  return resize.min != resize.max;                  return resize.min != resize.max;
1174              }              }
1175              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
1176                  int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);                  int hi = key_to_x(r->KeyRange.high + 1, w);
1177                  if (x <= hi - 2) break;                  if (x <= hi - 2) break;
1178                  if (x < hi + 2) {                  if (x < hi + 2) {
1179                      // edit high limit                      // edit high limit
# Line 776  void RegionChooser::show_region_properti Line 1208  void RegionChooser::show_region_properti
1208      // add "Keygroup" checkbox      // add "Keygroup" checkbox
1209      Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));      Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));
1210      checkBoxKeygroup.set_active(region->KeyGroup);      checkBoxKeygroup.set_active(region->KeyGroup);
1211    #if USE_GTKMM_BOX
1212        dialog.get_content_area()->pack_start(checkBoxKeygroup);
1213    #else
1214      dialog.get_vbox()->pack_start(checkBoxKeygroup);      dialog.get_vbox()->pack_start(checkBoxKeygroup);
1215    #endif
1216      checkBoxKeygroup.show();      checkBoxKeygroup.show();
1217      // add "Keygroup" spinbox      // add "Keygroup" spinbox
1218      Gtk::Adjustment adjustment(1, 1, pow(2,32));  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1219        Gtk::Adjustment adjustment(1, 1, 999);
1220      Gtk::SpinButton spinBox(adjustment);      Gtk::SpinButton spinBox(adjustment);
1221    #else
1222        Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1223    #endif
1224      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
1225    #if USE_GTKMM_BOX
1226        dialog.get_content_area()->pack_start(spinBox);
1227    #else
1228      dialog.get_vbox()->pack_start(spinBox);      dialog.get_vbox()->pack_start(spinBox);
1229    #endif
1230      spinBox.show();      spinBox.show();
1231      // add OK and CANCEL buttons to the dialog      // add OK and CANCEL buttons to the dialog
1232    #if HAS_GTKMM_STOCK
1233      dialog.add_button(Gtk::Stock::OK, 0);      dialog.add_button(Gtk::Stock::OK, 0);
1234      dialog.add_button(Gtk::Stock::CANCEL, 1);      dialog.add_button(Gtk::Stock::CANCEL, 1);
1235    #else
1236        dialog.add_button(_("_OK"), 0);
1237        dialog.add_button(_("_Cancel"), 1);
1238    #endif
1239        dialog.set_position(Gtk::WIN_POS_MOUSE);
1240    #if HAS_GTKMM_SHOW_ALL_CHILDREN
1241      dialog.show_all_children();      dialog.show_all_children();
1242    #endif
1243      if (!dialog.run()) { // OK selected ...      if (!dialog.run()) { // OK selected ...
1244          region->KeyGroup =          region->KeyGroup =
1245              (checkBoxKeygroup.get_active()) ? spinBox.get_value_as_int() : 0;              (checkBoxKeygroup.get_active()) ? spinBox.get_value_as_int() : 0;

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

  ViewVC Help
Powered by ViewVC