/[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 2169 by persson, Sun Mar 6 07:51:04 2011 UTC revision 3460 by persson, Sat Feb 2 07:48:50 2019 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2011 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 <sstream>  #include <assert.h>
26    
27  #include <cairomm/context.h>  #include <cairomm/context.h>
28  #include <gdkmm/general.h>  #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>
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    struct RegionFeatures {
47        int sampleRefs;
48        int loops;
49        int validDimRegs;
50    
51        RegionFeatures() {
52            sampleRefs = loops = validDimRegs = 0;
53        }
54    };
55    
56  #define REGION_BLOCK_HEIGHT             20  static RegionFeatures regionFeatures(gig::Region* rgn) {
57  #define KEYBOARD_HEIGHT                 40      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 55  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    
# Line 63  gig::Region* SortedRegions::next() { Line 96  gig::Region* SortedRegions::next() {
96    
97  RegionChooser::RegionChooser() :  RegionChooser::RegionChooser() :
98      activeKeyColor("red"),      activeKeyColor("red"),
99      red("#8070ff"),      blue("#4796ff"),
100      grey1("grey69"),      grey1("grey69"),
101      white("white"),      white("white"),
102      black("black"),      black("black"),
103      m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),      m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),
104      currentActiveKey(-1)      currentActiveKey(-1),
105        modifyallregions(false)
106  {  {
107      set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT);      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    
149      instrument = 0;      instrument = 0;
150      region = 0;      region = 0;
151      resize.active = false;      resize.active = false;
# Line 81  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 101  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 113  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 134  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 154  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_key(key, 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_key(key, black);      invalidate_key(key);
     } else {  
         draw_key(key, key >= 21 && key <= 108 ? white : grey1);  
     }  
341      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
342  }  }
343    
344    
345  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
346  bool RegionChooser::on_expose_event(GdkEventExpose* e)  bool RegionChooser::on_expose_event(GdkEventExpose* e) {
347  {      double clipx1 = e->area.x;
348      return on_draw(get_window()->create_cairo_context());      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  #endif
357    #else
358  bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
359  {      double clipx1, clipx2, clipy1, clipy2;
360      const int h = KEYBOARD_HEIGHT;      cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
361      const int w = get_width() - 1;  #endif
     const int bh = int(h * 0.55);  
362    
363      cr->save();      cr->save();
364      cr->set_line_width(1);      cr->set_line_width(1);
# Line 199  bool RegionChooser::on_draw(const Cairo: Line 366  bool RegionChooser::on_draw(const Cairo:
366  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #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);      const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
368  #else  #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();      const Gdk::RGBA bg = get_style_context()->get_background_color();
375    # endif
376  #endif  #endif
377      Gdk::Cairo::set_source_rgba(cr, bg);      Gdk::Cairo::set_source_rgba(cr, bg);
378      cr->paint();      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    void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
394                                      int clip_low, int clip_high) {
395        const int h = KEYBOARD_HEIGHT;
396        const int w = get_width() - 1;
397        const int bh = int(h * 0.55);
398    
399      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
400      cr->rectangle(0.5, h1 + 0.5, w, h - 1);      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
401      cr->stroke();      cr->stroke();
402    
403      int x1 = int(w * 20.5 / 128.0 + 0.5);      int x1 = key_to_x(20.5, w);
     int x2 = int(w * 109.5 / 128.0 + 0.5);  
   
404      Gdk::Cairo::set_source_rgba(cr, grey1);      Gdk::Cairo::set_source_rgba(cr, grey1);
405      cr->rectangle(1, h1 + 1, x1 - 1, h - 2);      cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
406      cr->fill();      cr->fill();
407    
408        int x2 = key_to_x(109.5, w);
409      Gdk::Cairo::set_source_rgba(cr, white);      Gdk::Cairo::set_source_rgba(cr, white);
410      cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);      cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
411      cr->fill();      cr->fill();
# Line 224  bool RegionChooser::on_draw(const Cairo: Line 415  bool RegionChooser::on_draw(const Cairo:
415      cr->fill();      cr->fill();
416    
417      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
418      for (int i = 0 ; i < 128 ; i++) {  
419        int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
420        int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
421    
422        for (int i = clipkey1 ; i < clipkey2 ; i++) {
423          int note = (i + 3) % 12;          int note = (i + 3) % 12;
424          int x = int(w * i / 128.0 + 0.5);          int x = key_to_x(i, w);
425    
426          if (note == 1 || note == 4 || note == 6 ||          if (note == 1 || note == 4 || note == 6 ||
427              note == 9 || note == 11) {              note == 9 || note == 11) {
428              int x2 = int(w * (i + 0.5) / 128.0 + 0.5);              // 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);              cr->move_to(x2 + 0.5, h1 + bh + 0.5);
432              cr->line_to(x2 + 0.5, h1 + h - 1);              cr->line_to(x2 + 0.5, h1 + h - 1);
433              cr->stroke();              cr->stroke();
434    
435              int x3 = int(w * (i + 1) / 128.0 + 0.5);              int x3 = key_to_x(i + 1, w);
436              cr->rectangle(x, h1 + 1, x3 - x + 1, bh);              cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
437              cr->fill();              cr->fill();
438          } else if (note == 3 || note == 8) {          } else if (note == 3 || note == 8) {
439                // C or F: long line to the left
440              cr->move_to(x + 0.5, h1 + 1);              cr->move_to(x + 0.5, h1 + 1);
441              cr->line_to(x + 0.5, h1 + h - 1);              cr->line_to(x + 0.5, h1 + h - 1);
442              cr->stroke();              cr->stroke();
   
             if (note == 3) draw_digit(i);  
443          }          }
444    
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 ||      const int w = get_width() - 1;
455                  r->KeyRange.high + 1 != next_region->KeyRange.low) {  
456                  int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);      Gdk::Cairo::set_source_rgba(cr, black);
457        gig::Region* next_region;
458        int x3 = -1;
459        for (gig::Region* r = regions.first() ; r ; r = next_region) {
460            next_region = regions.next();
461    
462            if (x3 < 0) {
463                x3 = key_to_x(r->KeyRange.low, w);
464                if (x3 >= clip_high) break;
465            }
466            if (!next_region ||
467                r->KeyRange.high + 1 != next_region->KeyRange.low ||
468                r == region || next_region == region) {
469    
470                int x2 = key_to_x(r->KeyRange.high + 1, w);
471                if (x2 >= clip_low) {
472                  cr->move_to(x3, 0.5);                  cr->move_to(x3, 0.5);
473                  cr->line_to(x2 + 0.5, 0.5);                  cr->line_to(x2 + 0.5, 0.5);
474                  cr->line_to(x2 + 0.5, h1 - 0.5);                  cr->line_to(x2 + 0.5, h1 - 0.5);
475                  cr->line_to(x3, h1 - 0.5);                  cr->line_to(x3, h1 - 0.5);
476                  cr->stroke();                  cr->stroke();
477    
478                  Gdk::Cairo::set_source_rgba(cr, white);                  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);                  cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
486                  cr->fill();                  cr->fill();
487                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
   
                 x3 = -1;  
488              }              }
489              i++;              x3 = -1;
         }  
   
         for (gig::Region* r = regions.first() ; r ; r = regions.next()) {  
             int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);  
             cr->move_to(x + 0.5, 1);  
             cr->line_to(x + 0.5, h1 - 1);  
             cr->stroke();  
490          }          }
491        }
492    
493          if (region) {      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
494              int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);          int x = key_to_x(r->KeyRange.low, w);
495              int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);          int x2 = key_to_x(r->KeyRange.high + 1, w);
496              Gdk::Cairo::set_source_rgba(cr, red);  
497              cr->rectangle(x1 + 1, 1, x2 - x1 - 1, h1 - 2);          RegionFeatures features = regionFeatures(r);
498              cr->fill();  
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      cr->restore();      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
535            int x = key_to_x(r->KeyRange.low, w);
536    
537      return true;          if (x < clip_low) continue;
538  }          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) {
569      const int note = (key + 3) % 12;      const int note = (key + 3) % 12;
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 312  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;
     Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
586      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
587      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));
588  #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
# Line 322  void RegionChooser::draw_digit(int key) Line 592  void RegionChooser::draw_digit(int key)
592  #endif  #endif
593  }  }
594    
595  void RegionChooser::draw_key(int key, const Gdk::RGBA& 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      Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     Gdk::Cairo::set_source_rgba(cr, color);  
602    
603      int note = (key + 3) % 12;      int note = (key + 3) % 12;
604      int x = int(w * key / 128.0 + 0.5) + 1;      int x = key_to_x(key, w) + 1;
605      int x2 = int(w * (key + 1.5) / 128.0 + 0.5);      int x2 = key_to_x(key + 1.5, w);
606      int x3 = int(w * (key + 1) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
607      int x4 = int(w * (key - 0.5) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
608      int w1 = x3 - x;      int w1 = x3 - x;
609      switch (note) {      switch (note) {
610      case 0: case 5: case 10:      case 0: case 5: case 10:
# Line 355  void RegionChooser::draw_key(int key, co Line 624  void RegionChooser::draw_key(int key, co
624          cr->fill();          cr->fill();
625          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
626          cr->fill();          cr->fill();
         if (note == 3) draw_digit(key);  
627          break;          break;
628      default:      default:
629          cr->rectangle(x, h1 + 1, w1, bh - 1);          cr->rectangle(x, h1 + 1, w1, bh - 1);
630          cr->fill();          cr->fill();
631          break;          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 376  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 402  bool RegionChooser::on_button_release_ev Line 671  bool RegionChooser::on_button_release_ev
671  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #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  #else
674    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
675          Glib::wrap(event->device, true)->ungrab(event->time);          Glib::wrap(event->device, true)->ungrab(event->time);
676    # else
677            Glib::wrap(event->device, true)->get_seat()->ungrab();
678    # endif
679  #endif  #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;
# Line 438  bool RegionChooser::on_button_release_ev Line 687  bool RegionChooser::on_button_release_ev
687  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #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  #else
690    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
691          Glib::wrap(event->device, true)->ungrab(event->time);          Glib::wrap(event->device, true)->ungrab(event->time);
692    # else
693            Glib::wrap(event->device, true)->get_seat()->ungrab();
694    # endif
695  #endif  #endif
696          move.active = false;          move.active = false;
697    
         if (move.pos) {  
             instrument_struct_to_be_changed_signal.emit(instrument);  
             region->SetKeyRange(  
                 region->KeyRange.low  + move.pos,  
                 region->KeyRange.high + move.pos  
             );  
             regions.update(instrument);  
             instrument_changed.emit();  
             instrument_struct_changed_signal.emit(instrument);  
         }  
   
698          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
699  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
700              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
701  #else  #else
702              get_window()->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));              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  #endif
713              cursor_is_resize = true;              cursor_is_resize = true;
714          }          }
# Line 465  bool RegionChooser::on_button_release_ev Line 716  bool RegionChooser::on_button_release_ev
716      return true;      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);
727                instrument_changed.emit();
728                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    void RegionChooser::update_after_move(int pos)
743    {
744        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        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 480  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 503  bool RegionChooser::on_button_press_even Line 804  bool RegionChooser::on_button_press_even
804                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
805                                         event->time);                                         event->time);
806  #else  #else
807    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
808              Glib::wrap(event->device, true)->grab(get_window(),              Glib::wrap(event->device, true)->grab(get_window(),
809                                                    Gdk::OWNERSHIP_NONE,                                                    Gdk::OWNERSHIP_NONE,
810                                                    false,                                                    false,
# Line 511  bool RegionChooser::on_button_press_even Line 813  bool RegionChooser::on_button_press_even
813                                                    Gdk::POINTER_MOTION_HINT_MASK,                                                    Gdk::POINTER_MOTION_HINT_MASK,
814                                                    Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),                                                    Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
815                                                    event->time);                                                    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  #endif
829              resize.active = true;              resize.active = true;
830          } else {          } else {
# Line 529  bool RegionChooser::on_button_press_even Line 843  bool RegionChooser::on_button_press_even
843                                             Gdk::Cursor(Gdk::FLEUR),                                             Gdk::Cursor(Gdk::FLEUR),
844                                             event->time);                                             event->time);
845  #else  #else
846                  Glib::wrap(event->device, true)->grab(get_window(),  # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
847                                                        Gdk::OWNERSHIP_NONE,              Glib::wrap(event->device, true)->grab(get_window(),
848                                                        false,                                                    Gdk::OWNERSHIP_NONE,
849                                                        Gdk::BUTTON_RELEASE_MASK |                                                    false,
850                                                        Gdk::POINTER_MOTION_MASK |                                                    Gdk::BUTTON_RELEASE_MASK |
851                                                        Gdk::POINTER_MOTION_HINT_MASK,                                                    Gdk::POINTER_MOTION_MASK |
852                                                        Gdk::Cursor::create(Gdk::FLEUR),                                                    Gdk::POINTER_MOTION_HINT_MASK,
853                                                        event->time);                                                    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  #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 549  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;
# Line 575  void RegionChooser::motion_resize_region Line 953  void RegionChooser::motion_resize_region
953      else if (k > resize.max) k = resize.max;      else if (k > resize.max) k = resize.max;
954    
955      if (k != resize.pos) {      if (k != resize.pos) {
         Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
         cr->set_line_width(1);  
   
956          if (resize.mode == resize.undecided) {          if (resize.mode == resize.undecided) {
957              if (k < resize.pos) {              if (k < resize.pos) {
958                  // edit high limit of prev_region                  // edit high limit of prev_region
# Line 590  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          const Gdk::RGBA white = region == resize.region ? red : this->white;          resize.pos = k;
 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  
         const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);  
 #else  
         const Gdk::RGBA bg = get_style_context()->get_background_color();  
 #endif  
   
         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                  Gdk::Cairo::set_source_rgba(cr, white);                  x1 = resize.region->KeyRange.high;
974                  cr->rectangle(prevx, 1, x - prevx, h1 - 2);                  x2 = resize.pos - 1;
                 cr->fill();  
   
                 Gdk::Cairo::set_source_rgba(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();  
975              } else {              } else {
976                  int xx = (resize.pos == resize.max &&                  x1 = resize.pos - 1;
977                            resize.max != 128) ? 1 : 0;                  x2 = resize.region->KeyRange.high;
                 Gdk::Cairo::set_source_rgba(cr, bg);  
                 cr->rectangle(x + 1, 0, prevx - x - xx, h1);  
                 cr->fill();  
978              }              }
979          } else {          } else {
980              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
981                  Gdk::Cairo::set_source_rgba(cr, white);                  x1 = resize.region->KeyRange.low;
982                  cr->rectangle(x + 1, 1, prevx - x, h1 - 2);                  x2 = resize.pos;
                 cr->fill();  
   
                 Gdk::Cairo::set_source_rgba(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();  
983              } else {              } else {
984                  int xx = (resize.pos == resize.min &&                  x1 = resize.pos;
985                            resize.min != 0) ? 1 : 0;                  x2 = resize.region->KeyRange.low;
                 Gdk::Cairo::set_source_rgba(cr, bg);  
                 cr->rectangle(prevx + xx, 0, x - prevx - xx, h1);  
                 cr->fill();  
986              }              }
987          }          }
988          Gdk::Cairo::set_source_rgba(cr, black);          x1 = key_to_x(x1, w);
989          cr->move_to(x + 0.5, 1);          x2 = key_to_x(x2 + 1, w) + 1;
990          cr->line_to(x + 0.5, h1 - 1);          Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
991          cr->stroke();  
992          resize.pos = k;          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;
     Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
     cr->set_line_width(1);  
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 696  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 721  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;  
   
 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  
     const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);  
 #else  
     const Gdk::RGBA bg = get_style_context()->get_background_color();  
 #endif  
   
     int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);  
     x = int(w * (k + region->KeyRange.low) / 128.0 + 0.5);  
     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);  
   
     if (!new_touch_left) {  
         Gdk::Cairo::set_source_rgba(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_rgba(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_rgba(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();  
1068    
1069          Gdk::Cairo::set_source_rgba(cr, black);      int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
1070          cr->move_to(std::max(x, prevx2 + 1), 0.5);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
1071          cr->line_to(x2 + 1, 0.5);                                 new_l + regionsize) + 1, w) + 1;
         cr->move_to(std::max(x, prevx2 + 1), h1 - 0.5);  
         cr->line_to(x2 + 1, h1 - 0.5);  
         cr->stroke();  
1072    
1073          Gdk::Cairo::set_source_rgba(cr, red);      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
1074          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_rgba(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();  
1075    
1076          Gdk::Cairo::set_source_rgba(cr, black);      get_window()->invalidate_rect(rect, false);
         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_rgba(cr, red);  
         cr->rectangle(x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);  
         cr->fill();  
     }  
   
     move.pos = k;  
     move.touch_left = new_touch_left;  
     move.touch_right = new_touch_right;  
1077  }  }
1078    
1079    
# Line 795  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 804  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 827  bool RegionChooser::on_motion_notify_eve Line 1119  bool RegionChooser::on_motion_notify_eve
1119  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #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  #else
1122                  window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));                  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  #endif
1133                  cursor_is_resize = true;                  cursor_is_resize = true;
1134              }              }
# Line 849  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 872  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 907  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  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
# Line 917  void RegionChooser::show_region_properti Line 1222  void RegionChooser::show_region_properti
1222      Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));      Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1223  #endif  #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.2169  
changed lines
  Added in v.3460

  ViewVC Help
Powered by ViewVC