/[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 1623 by persson, Fri Jan 4 19:42:45 2008 UTC revision 3131 by schoenebeck, Thu Apr 27 17:28:01 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2008 Andreas Persson   * Copyright (C) 2006-2015 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 18  Line 18 
18   */   */
19    
20  #include "regionchooser.h"  #include "regionchooser.h"
21    
22  #include <algorithm>  #include <algorithm>
23    
24    #include <cairomm/context.h>
25    #include <gdkmm/general.h>
26  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
27  #include <gtkmm/stock.h>  #include <gdkmm/pixbuf.h>
28  #include <gtkmm/spinbutton.h>  #include <gtkmm/spinbutton.h>
29  #include <gtkmm/dialog.h>  #include <gtkmm/dialog.h>
 #include <math.h>  
30    
31  #include "global.h"  #include "global.h"
32    #include "Settings.h"
33    #include "gfx/builtinpix.h"
34    
35    #define REGION_BLOCK_HEIGHT             30
36    #define KEYBOARD_HEIGHT                 40
37    
38    struct RegionFeatures {
39        int sampleRefs;
40        int loops;
41    
42        RegionFeatures() {
43            sampleRefs = loops = 0;
44        }
45    };
46    
47    static RegionFeatures regionFeatures(gig::Region* rgn) {
48        RegionFeatures f;
49        for (int i = 0; i < rgn->DimensionRegions; ++i) {
50            gig::DimensionRegion* dr = rgn->pDimensionRegions[i];
51            if (dr->pSample) f.sampleRefs++;
52            // the user doesn't care about loop if there is no valid sample reference
53            if (dr->pSample && dr->SampleLoops) f.loops++;
54        }
55        return f;
56    }
57    
58  void SortedRegions::update(gig::Instrument* instrument) {  void SortedRegions::update(gig::Instrument* instrument) {
59      // 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 33  void SortedRegions::update(gig::Instrume Line 61  void SortedRegions::update(gig::Instrume
61      // RegionChooser code needs a sorted list of regions.      // RegionChooser code needs a sorted list of regions.
62      regions.clear();      regions.clear();
63      if (instrument) {      if (instrument) {
64          for (gig::Region *r = instrument->GetFirstRegion() ;          for (gig::Region* r = instrument->GetFirstRegion() ;
65               r ;               r ;
66               r = instrument->GetNextRegion()) {               r = instrument->GetNextRegion()) {
67              regions.push_back(r);              regions.push_back(r);
# Line 48  gig::Region* SortedRegions::first() { Line 76  gig::Region* SortedRegions::first() {
76  }  }
77    
78  gig::Region* SortedRegions::next() {  gig::Region* SortedRegions::next() {
79      region_iterator++;      ++region_iterator;
80      return region_iterator == regions.end() ? 0 : *region_iterator;      return region_iterator == regions.end() ? 0 : *region_iterator;
81  }  }
82    
83    
84    
85  RegionChooser::RegionChooser()  RegionChooser::RegionChooser() :
86        activeKeyColor("red"),
87        blue("#4796ff"),
88        grey1("grey69"),
89        white("white"),
90        black("black"),
91        m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),
92        currentActiveKey(-1)
93  {  {
94      Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();      set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT);
95    
96      red = Gdk::Color("#8070ff");      loadBuiltInPix();
     grey1 = Gdk::Color("#b0b0b0");  
97    
     colormap->alloc_color(red);  
     colormap->alloc_color(grey1);  
98      instrument = 0;      instrument = 0;
99      region = 0;      region = 0;
100      resize.active = false;      resize.active = false;
101      move.active = false;      move.active = false;
102      cursor_is_resize = false;      cursor_is_resize = false;
103      h1 = 20;      h1 = REGION_BLOCK_HEIGHT;
104    
105        // properties of the virtual keyboard
106        {
107            const char* choices[] = { _("normal"), _("chord"), 0 };
108            static const virt_keyboard_mode_t values[] = {
109                VIRT_KEYBOARD_MODE_NORMAL,
110                VIRT_KEYBOARD_MODE_CHORD
111            };
112            m_VirtKeybModeChoice.set_choices(choices, values);
113            m_VirtKeybModeChoice.set_value(VIRT_KEYBOARD_MODE_NORMAL);
114        }
115        m_VirtKeybVelocityLabelDescr.set_text(_("Note-On Velocity:"));
116        m_VirtKeybVelocityLabel.set_text("-");
117        m_VirtKeybOffVelocityLabelDescr.set_text(_("Note-Off Velocity:"));
118        m_VirtKeybOffVelocityLabel.set_text("-");
119        m_VirtKeybPropsBox.pack_start(m_VirtKeybModeChoice.label, Gtk::PACK_SHRINK);
120        m_VirtKeybPropsBox.pack_start(m_VirtKeybModeChoice.widget, Gtk::PACK_SHRINK);
121        m_VirtKeybPropsBox.pack_start(m_VirtKeybVelocityLabelDescr, Gtk::PACK_SHRINK);
122        m_VirtKeybPropsBox.pack_start(m_VirtKeybVelocityLabel, Gtk::PACK_SHRINK);
123        m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabelDescr, Gtk::PACK_SHRINK);
124        m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);
125        m_VirtKeybPropsBox.set_spacing(10);
126        m_VirtKeybPropsBox.show();
127        for (int i = 0 ; i < 128 ; i++) key_pressed[i] = false;
128    
129      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
130      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties", _("_Properties")),
                                          Gtk::Stock::PROPERTIES),  
131                       sigc::mem_fun(*this,                       sigc::mem_fun(*this,
132                                     &RegionChooser::show_region_properties));                                     &RegionChooser::show_region_properties));
133      actionGroup->add(Gtk::Action::create("Remove", Gtk::Stock::REMOVE),      actionGroup->add(Gtk::Action::create("Remove", _("_Remove")),
134                       sigc::mem_fun(*this, &RegionChooser::delete_region));                       sigc::mem_fun(*this, &RegionChooser::delete_region));
135      actionGroup->add(Gtk::Action::create("Add", Gtk::Stock::ADD),      actionGroup->add(Gtk::Action::create("Add", _("_Add")),
136                       sigc::mem_fun(*this, &RegionChooser::add_region));                       sigc::mem_fun(*this, &RegionChooser::add_region));
137      actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),      actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),
138                       sigc::mem_fun(*this, &RegionChooser::manage_dimensions));                       sigc::mem_fun(*this, &RegionChooser::manage_dimensions));
# Line 116  RegionChooser::RegionChooser() Line 171  RegionChooser::RegionChooser()
171              sigc::mem_fun(*this, &RegionChooser::on_dimension_manager_changed)              sigc::mem_fun(*this, &RegionChooser::on_dimension_manager_changed)
172          )          )
173      );      );
174        keyboard_key_hit_signal.connect(
175            sigc::mem_fun(*this, &RegionChooser::on_note_on_event)
176        );
177        keyboard_key_released_signal.connect(
178            sigc::mem_fun(*this, &RegionChooser::on_note_off_event)
179        );
180        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."));
181  }  }
182    
183  RegionChooser::~RegionChooser()  RegionChooser::~RegionChooser()
184  {  {
185  }  }
186    
187  void RegionChooser::on_realize()  void RegionChooser::invalidate_key(int key) {
188  {      const int h = KEYBOARD_HEIGHT;
189      // We need to call the base on_realize()      const int w = get_width() - 1;
190      Gtk::DrawingArea::on_realize();      int x1 = key_to_x(key - 0.5, w);
191        int x2 = key_to_x(key + 1.5, w);
192    
193      // Now we can allocate any additional resources we need      Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
194      Glib::RefPtr<Gdk::Window> window = get_window();      get_window()->invalidate_rect(rect, false);
     gc = Gdk::GC::create(window);  
     window->clear();  
195  }  }
196    
197  bool RegionChooser::on_expose_event(GdkEventExpose* event)  void RegionChooser::on_note_on_event(int key, int velocity) {
198  {      key_pressed[key] = true;
199      Glib::RefPtr<Gdk::Window> window = get_window();      invalidate_key(key);
200      window->clear();      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
201      const int h = 40;  }
202    
203    void RegionChooser::on_note_off_event(int key, int velocity) {
204        key_pressed[key] = false;
205        invalidate_key(key);
206        m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
207    }
208    
209    
210    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
211    bool RegionChooser::on_expose_event(GdkEventExpose* e) {
212        double clipx1 = e->area.x;
213        double clipx2 = e->area.x + e->area.width;
214        double clipy1 = e->area.y;
215        double clipy2 = e->area.y + e->area.height;
216    
217        const Cairo::RefPtr<Cairo::Context>& cr =
218            get_window()->create_cairo_context();
219    #if 0
220    }
221    #endif
222    #else
223    bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
224        double clipx1, clipx2, clipy1, clipy2;
225        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
226    #endif
227    
228        cr->save();
229        cr->set_line_width(1);
230    
231    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
232        const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
233    #else
234        const Gdk::RGBA bg = get_style_context()->get_background_color();
235    #endif
236        Gdk::Cairo::set_source_rgba(cr, bg);
237        cr->paint();
238    
239        if (clipy2 > h1) {
240            draw_keyboard(cr, clipx1, clipx2);
241        }
242    
243        if (clipy1 < h1 && instrument) {
244            draw_regions(cr, clipx1, clipx2);
245        }
246    
247        cr->restore();
248    
249        return true;
250    }
251    
252    void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
253                                      int clip_low, int clip_high) {
254        const int h = KEYBOARD_HEIGHT;
255      const int w = get_width() - 1;      const int w = get_width() - 1;
256      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
257    
258      Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();      Gdk::Cairo::set_source_rgba(cr, black);
259      Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
260        cr->stroke();
261    
262        int x1 = key_to_x(20.5, w);
263        Gdk::Cairo::set_source_rgba(cr, grey1);
264        cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
265        cr->fill();
266    
267        int x2 = key_to_x(109.5, w);
268        Gdk::Cairo::set_source_rgba(cr, white);
269        cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
270        cr->fill();
271    
272        Gdk::Cairo::set_source_rgba(cr, grey1);
273        cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);
274        cr->fill();
275    
276      Glib::RefPtr<Pango::Context> context = get_pango_context();      Gdk::Cairo::set_source_rgba(cr, black);
     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);  
277    
278      window->draw_rectangle(black, false, 0, h1, w, h - 1);      int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
279      gc->set_foreground(grey1);      int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
     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);  
     int octave = -1;  
     for (int i = 0 ; i < 128 ; i++) {  
         int note = (i + 3) % 12;  
         int x = int(w * i / 128.0 + 0.5);  
280    
281          if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) {      for (int i = clipkey1 ; i < clipkey2 ; i++) {
282              int x2 = int(w * (i + 0.5) / 128.0 + 0.5);          int note = (i + 3) % 12;
283              window->draw_line(black, x2, h1 + bh, x2, h1 + h);          int x = key_to_x(i, w);
284    
285              int x3 = int(w * (i + 1) / 128.0 + 0.5);          if (note == 1 || note == 4 || note == 6 ||
286              window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh);              note == 9 || note == 11) {
287                // black key: short line in the middle, with a rectangle
288                // on top
289                int x2 = key_to_x(i + 0.5, w);
290                cr->move_to(x2 + 0.5, h1 + bh + 0.5);
291                cr->line_to(x2 + 0.5, h1 + h - 1);
292                cr->stroke();
293    
294                int x3 = key_to_x(i + 1, w);
295                cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
296                cr->fill();
297          } else if (note == 3 || note == 8) {          } else if (note == 3 || note == 8) {
298              window->draw_line(black, x, h1 + 1, x, h1 + h);              // C or F: long line to the left
299          }              cr->move_to(x + 0.5, h1 + 1);
300          if (note == 3) {              cr->line_to(x + 0.5, h1 + h - 1);
301              char buf[30];              cr->stroke();
             sprintf(buf, "<span size=\"8000\">%d</span>", octave);  
             layout->set_markup(buf);  
             Pango::Rectangle rectangle = layout->get_logical_extents();  
             double text_w = double(rectangle.get_width()) / Pango::SCALE;  
             double text_h = double(rectangle.get_height()) / Pango::SCALE;  
             double x2 = w * (i + 0.75) / 128.0;  
             window->draw_layout(black, int(x2 - text_w / 2 + 1),  
                                 int(h1 + h - text_h + 0.5), layout);  
             octave++;  
302          }          }
303    
304            if (key_pressed[i]) draw_key(cr, i);
305    
306            if (note == 3) draw_digit(cr, i);
307      }      }
308    }
309    
     if (instrument) {  
         int i = 0;  
         gig::Region *next_region;  
         int x3 = -1;  
         for (gig::Region *r = regions.first() ; r ; r = next_region) {  
310    
311              if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);  void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
312              next_region = regions.next();                                   int clip_low, int clip_high) {
313              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {      const int w = get_width() - 1;
314                  int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);  
315                  window->draw_line(black, x3, 0, x2, 0);      Gdk::Cairo::set_source_rgba(cr, black);
316                  window->draw_line(black, x3, h1 - 1, x2, h1 - 1);      gig::Region* next_region;
317                  window->draw_line(black, x2, 1, x2, h1 - 2);      int x3 = -1;
318                  window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);      for (gig::Region* r = regions.first() ; r ; r = next_region) {
319                  x3 = -1;          next_region = regions.next();
320              }  
321              i++;          if (x3 < 0) {
322          }              x3 = key_to_x(r->KeyRange.low, w);
323                if (x3 >= clip_high) break;
324          for (gig::Region *r = regions.first() ; r ; r = regions.next()) {          }
325              int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);          if (!next_region ||
326              window->draw_line(black, x, 1, x, h1 - 2);              r->KeyRange.high + 1 != next_region->KeyRange.low ||
327          }              r == region || next_region == region) {
328    
329          if (region) {              int x2 = key_to_x(r->KeyRange.high + 1, w);
330              int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);              if (x2 >= clip_low) {
331              int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);                  cr->move_to(x3, 0.5);
332              gc->set_foreground(red);                  cr->line_to(x2 + 0.5, 0.5);
333              window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);                  cr->line_to(x2 + 0.5, h1 - 0.5);
334                    cr->line_to(x3, h1 - 0.5);
335                    cr->stroke();
336    
337                    Gdk::Cairo::set_source_rgba(cr, region == r ? blue : white);
338                    cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
339                    cr->fill();
340                    Gdk::Cairo::set_source_rgba(cr, black);
341                }
342                x3 = -1;
343          }          }
344      }      }
     return true;  
 }  
345    
346        for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
347            int x = key_to_x(r->KeyRange.low, w);
348            int x2 = key_to_x(r->KeyRange.high + 1, w);
349    
350            RegionFeatures features = regionFeatures(r);
351    
352            const bool bShowLoopSymbol = features.loops > 0;
353            const bool bShowSampleRefSymbol = features.sampleRefs < r->DimensionRegions;
354            if (bShowLoopSymbol || bShowSampleRefSymbol) {
355                const int margin = 2;
356                const int wRgn = x2 - x;
357                //printf("x=%d x2=%d wRgn=%d\n", x, x2, wRgn);
358    
359                cr->save();
360                cr->set_line_width(1);
361                cr->rectangle(x, 1, wRgn, h1 - 1);
362                cr->clip();
363                if (bShowSampleRefSymbol) {
364                    const int wPic = 8;
365                    const int hPic = 8;
366                    Gdk::Cairo::set_source_pixbuf(
367                        cr, (features.sampleRefs) ? yellowDot : redDot,
368                        x + (wRgn-wPic)/2.f,
369                        (bShowLoopSymbol) ? margin : (h1-hPic)/2.f
370                    );
371                    cr->paint();
372                }
373                if (bShowLoopSymbol) {
374                    const int wPic = 12;
375                    const int hPic = 14;
376                    Gdk::Cairo::set_source_pixbuf(
377                        cr, (features.loops == r->DimensionRegions) ? blackLoop : grayLoop,
378                        x + (wRgn-wPic)/2.f,
379                        (bShowSampleRefSymbol) ? h1 - hPic - margin : (h1-hPic)/2.f
380                    );
381                    cr->paint();
382                }
383                cr->restore();
384            }
385        }
386    
387  void RegionChooser::on_size_request(GtkRequisition* requisition)      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
388  {          int x = key_to_x(r->KeyRange.low, w);
389      *requisition = GtkRequisition();  
390      requisition->height = 40 + 20;          if (x < clip_low) continue;
391      requisition->width = 500;          if (x >= clip_high) break;
392    
393            cr->move_to(x + 0.5, 1);
394            cr->line_to(x + 0.5, h1 - 1);
395            cr->stroke();
396        }
397    
398        // if there is no region yet, show the user some hint text that he may
399        // right click on this area to create a new region
400        if (!regions.first()) {
401            Glib::RefPtr<Pango::Context> context = get_pango_context();
402            Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
403            layout->set_alignment(Pango::ALIGN_CENTER);
404            layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
405            layout->set_width(get_width() * Pango::SCALE);
406            //layout->set_height(get_height() * Pango::SCALE);
407            layout->set_spacing(10);
408            Gdk::Cairo::set_source_rgba(cr, blue);
409            // get the text dimensions
410            int text_width, text_height;
411            layout->get_pixel_size(text_width, text_height);
412            cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
413    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
414            pango_cairo_show_layout(cr->cobj(), layout->gobj());
415    #else
416            layout->show_in_cairo_context(cr);
417    #endif
418        }
419  }  }
420    
421    bool RegionChooser::is_black_key(int key) {
422        const int note = (key + 3) % 12;
423        return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
424    }
425    
426  // not used  void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
427  void RegionChooser::draw_region(int from, int to, const Gdk::Color& color)                                 int key) {
428  {      const int h = KEYBOARD_HEIGHT;
429      const int h = 40;      const int w = get_width() - 1;
430      const int w = get_width();      Glib::RefPtr<Pango::Layout> layout =
431            Pango::Layout::create(get_pango_context());
432        char buf[30];
433        sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
434        layout->set_markup(buf);
435        Pango::Rectangle rectangle = layout->get_logical_extents();
436        double text_w = double(rectangle.get_width()) / Pango::SCALE;
437        double text_h = double(rectangle.get_height()) / Pango::SCALE;
438        double x = w * (key + 0.75) / 128.0;
439        Gdk::Cairo::set_source_rgba(cr, black);
440        cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));
441    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
442        pango_cairo_show_layout(cr->cobj(), layout->gobj());
443    #else
444        layout->show_in_cairo_context(cr);
445    #endif
446    }
447    
448    void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
449                                 int key) {
450        const int h = KEYBOARD_HEIGHT;
451        const int w = get_width() - 1;
452      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
453    
454      Glib::RefPtr<Gdk::Window> window = get_window();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     gc->set_foreground(color);  
455    
456      for (int i = from ; i < to ; i++) {      int note = (key + 3) % 12;
457          int note = (i + 3) % 12;      int x = key_to_x(key, w) + 1;
458          int x = int(w * i / 128.0 + 0.5) + 1;      int x2 = key_to_x(key + 1.5, w);
459          int x2 = int(w * (i + 1.5) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
460          int x3 = int(w * (i + 1) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
461          int x4 = int(w * (i - 0.5) / 128 + 0.5) + 1;      int w1 = x3 - x;
462          int w1 = x3 - x;      switch (note) {
463          switch (note) {      case 0: case 5: case 10:
464          case 0: case 5: case 10:          cr->rectangle(x, h1 + 1, w1, bh);
465              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);          cr->fill();
466              window->draw_rectangle(gc, true, x4, h1 + bh + 1, x2 - x4, h - bh - 2);          cr->rectangle(x4 + 1, h1 + bh + 1, x2 - x4 - 1, h - bh - 2);
467              break;          cr->fill();
468          case 2: case 7:          break;
469              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);      case 2: case 7:
470              window->draw_rectangle(gc, true, x4, h1 + bh + 1, x3 - x4, h - bh - 2);          cr->rectangle(x, h1 + 1, w1, bh);
471              break;          cr->fill();
472          case 3: case 8:          cr->rectangle(x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2);
473              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);          cr->fill();
474              window->draw_rectangle(gc, true, x, h1 + bh + 1, x2 - x, h - bh - 2);          break;
475              break;      case 3: case 8:
476          default:          cr->rectangle(x, h1 + 1, w1, bh);
477              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh - 1);          cr->fill();
478              break;          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
479          }          cr->fill();
480            break;
481        default:
482            cr->rectangle(x, h1 + 1, w1, bh - 1);
483            cr->fill();
484            break;
485      }      }
486        Gdk::Cairo::set_source_rgba(cr, black);
487  }  }
488    
489  void RegionChooser::set_instrument(gig::Instrument* instrument)  void RegionChooser::set_instrument(gig::Instrument* instrument)
# Line 271  void RegionChooser::set_instrument(gig:: Line 493  void RegionChooser::set_instrument(gig::
493      region = regions.first();      region = regions.first();
494      queue_draw();      queue_draw();
495      region_selected();      region_selected();
496        dimensionManager.set_region(region);
497  }  }
498    
499  bool RegionChooser::on_button_release_event(GdkEventButton* event)  bool RegionChooser::on_button_release_event(GdkEventButton* event)
500  {  {
501        const int k = x_to_key(event->x, get_width() - 1);
502    
503        // handle-note off on virtual keyboard
504        if (event->type == GDK_BUTTON_RELEASE) {
505            int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
506                           int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
507            if (velocity <= 0) velocity = 1;
508            switch (m_VirtKeybModeChoice.get_value()) {
509                case VIRT_KEYBOARD_MODE_CHORD:
510                    if (event->y >= REGION_BLOCK_HEIGHT)
511                        keyboard_key_released_signal.emit(k, velocity);
512                    break;
513                case VIRT_KEYBOARD_MODE_NORMAL:
514                default:
515                    if (currentActiveKey >= 0 && currentActiveKey <= 127) {
516                        keyboard_key_released_signal.emit(currentActiveKey, velocity);
517                        currentActiveKey = -1;
518                    }
519                    break;
520            }
521        }
522    
523      if (resize.active) {      if (resize.active) {
524    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
525          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
526    #else
527            Glib::wrap(event->device, true)->ungrab(event->time);
528    #endif
529          resize.active = false;          resize.active = false;
530    
         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);  
             }  
         }  
   
531          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
532              get_window()->set_cursor();              get_window()->set_cursor();
533              cursor_is_resize = false;              cursor_is_resize = false;
534          }          }
535      } else if (move.active) {      } else if (move.active) {
536    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
537          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
538    #else
539            Glib::wrap(event->device, true)->ungrab(event->time);
540    #endif
541          move.active = false;          move.active = false;
542    
543          if (move.pos) {          if (is_in_resize_zone(event->x, event->y)) {
544    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
545                get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
546    #else
547                get_window()->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
548    #endif
549                cursor_is_resize = true;
550            }
551        }
552        return true;
553    }
554    
555    void RegionChooser::update_after_resize()
556    {
557        if (resize.mode == resize.moving_high_limit) {
558            if (resize.region->KeyRange.high != resize.pos - 1) {
559                instrument_struct_to_be_changed_signal.emit(instrument);
560                resize.region->SetKeyRange(resize.region->KeyRange.low,
561                                           resize.pos - 1);
562                regions.update(instrument);
563                instrument_changed.emit();
564                instrument_struct_changed_signal.emit(instrument);
565            }
566        } else if (resize.mode == resize.moving_low_limit) {
567            if (resize.region->KeyRange.low != resize.pos) {
568              instrument_struct_to_be_changed_signal.emit(instrument);              instrument_struct_to_be_changed_signal.emit(instrument);
569              region->SetKeyRange(              resize.region->SetKeyRange(resize.pos,
570                  region->KeyRange.low  + move.pos,                                         resize.region->KeyRange.high);
                 region->KeyRange.high + move.pos  
             );  
571              regions.update(instrument);              regions.update(instrument);
572              instrument_changed.emit();              instrument_changed.emit();
573              instrument_struct_changed_signal.emit(instrument);              instrument_struct_changed_signal.emit(instrument);
574          }          }
575        }
576    }
577    
578          if (is_in_resize_zone(event->x, event->y)) {  void RegionChooser::update_after_move(int pos)
579              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));  {
580              cursor_is_resize = true;      instrument_struct_to_be_changed_signal.emit(instrument);
581        const int range = region->KeyRange.high - region->KeyRange.low;
582        const int diff  = pos - int(region->KeyRange.low);
583        region->SetKeyRange(pos, pos + range);
584        if (Settings::singleton()->moveRootNoteWithRegionMoved) {
585            for (int i = 0; i < 256; ++i) {
586                gig::DimensionRegion* dimrgn = region->pDimensionRegions[i];
587                if (!dimrgn || !dimrgn->pSample || !dimrgn->PitchTrack) continue;
588                dimrgn->UnityNote += diff;
589          }          }
590      }      }
591      return true;      regions.update(instrument);
592        instrument_changed.emit();
593        instrument_struct_changed_signal.emit(instrument);
594  }  }
595    
596  bool RegionChooser::on_button_press_event(GdkEventButton* event)  bool RegionChooser::on_button_press_event(GdkEventButton* event)
597  {  {
598      if (!instrument) return true;      if (!instrument) return true;
599    
600      int k = int(event->x / (get_width() - 1) * 128.0);      const int w = get_width() - 1;
601        const int k = x_to_key(event->x, w);
602    
603        if (event->type == GDK_BUTTON_PRESS) {
604            if (event->y >= REGION_BLOCK_HEIGHT) {
605                int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
606                               int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
607                currentActiveKey = k;
608                keyboard_key_hit_signal.emit(k, velocity);
609            }
610        }
611    
612        // left mouse button double click
613        if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
614            if (event->y < REGION_BLOCK_HEIGHT) {
615                // show dimension manager dialog for this region
616                manage_dimensions();
617            }
618        }
619    
620        if (event->y >= REGION_BLOCK_HEIGHT) return true;
621      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
622          gig::Region* r = get_region(k);          gig::Region* r = get_region(k);
623          if (r) {          if (r) {
624              region = r;              region = r;
625              queue_draw();              queue_draw();
626              region_selected();              region_selected();
627                dimensionManager.set_region(region);
628              popup_menu_inside_region->popup(event->button, event->time);              popup_menu_inside_region->popup(event->button, event->time);
629          } else {          } else {
630              new_region_pos = k;              new_region_pos = k;
# Line 349  bool RegionChooser::on_button_press_even Line 632  bool RegionChooser::on_button_press_even
632          }          }
633      } else {      } else {
634          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
635    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
636              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
637                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
638                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
639                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
640                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW), event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
641                                           event->time);
642    #else
643                Glib::wrap(event->device, true)->grab(get_window(),
644                                                      Gdk::OWNERSHIP_NONE,
645                                                      false,
646                                                      Gdk::BUTTON_RELEASE_MASK |
647                                                      Gdk::POINTER_MOTION_MASK |
648                                                      Gdk::POINTER_MOTION_HINT_MASK,
649                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
650                                                      event->time);
651    #endif
652              resize.active = true;              resize.active = true;
653          } else {          } else {
654              gig::Region* r = get_region(k);              gig::Region* r = get_region(k);
# Line 361  bool RegionChooser::on_button_press_even Line 656  bool RegionChooser::on_button_press_even
656                  region = r;                  region = r;
657                  queue_draw();                  queue_draw();
658                  region_selected();                  region_selected();
659                    dimensionManager.set_region(region);
660    
661    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
662                  get_window()->pointer_grab(false,                  get_window()->pointer_grab(false,
663                                             Gdk::BUTTON_RELEASE_MASK |                                             Gdk::BUTTON_RELEASE_MASK |
664                                             Gdk::POINTER_MOTION_MASK |                                             Gdk::POINTER_MOTION_MASK |
665                                             Gdk::POINTER_MOTION_HINT_MASK,                                             Gdk::POINTER_MOTION_HINT_MASK,
666                                             Gdk::Cursor(Gdk::FLEUR), event->time);                                             Gdk::Cursor(Gdk::FLEUR),
667                                               event->time);
668    #else
669                    Glib::wrap(event->device, true)->grab(get_window(),
670                                                          Gdk::OWNERSHIP_NONE,
671                                                          false,
672                                                          Gdk::BUTTON_RELEASE_MASK |
673                                                          Gdk::POINTER_MOTION_MASK |
674                                                          Gdk::POINTER_MOTION_HINT_MASK,
675                                                          Gdk::Cursor::create(Gdk::FLEUR),
676                                                          event->time);
677    #endif
678                  move.active = true;                  move.active = true;
679                  move.from_x = event->x;                  move.offset = event->x - key_to_x(region->KeyRange.low, w);
                 move.pos = 0;  
680              }              }
681          }          }
682      }      }
# Line 378  bool RegionChooser::on_button_press_even Line 685  bool RegionChooser::on_button_press_even
685    
686  gig::Region* RegionChooser::get_region(int key)  gig::Region* RegionChooser::get_region(int key)
687  {  {
688      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();  
   
689          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
690          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;  
691      }      }
692      return 0;      return 0;
693  }  }
694    
695    void RegionChooser::set_region(gig::Region* region) {
696        this->region = region;
697        queue_draw();
698        region_selected();
699        dimensionManager.set_region(region);
700    }
701    
702    void RegionChooser::select_next_region() {
703        if (!instrument) return;
704        if (!region) {
705            for (int i = 0; i < 128; ++i) {
706                ::gig::Region* rgn = instrument->GetRegion(i);
707                if (rgn) {
708                    set_region(rgn);
709                    return;
710                }
711            }
712        } else {
713            bool currentFound = false;
714            for (int i = 0; i < 128; ++i) {
715                ::gig::Region* rgn = instrument->GetRegion(i);
716                if (!rgn) continue;
717                if (currentFound) {
718                    if (rgn != region) {
719                        set_region(rgn);
720                        return;
721                    }
722                } else {
723                    if (rgn == region) currentFound = true;
724                }
725            }
726        }
727    }
728    
729    void RegionChooser::select_prev_region() {
730        if (!instrument) return;
731        if (!region) {
732            for (int i = 0; i < 128; ++i) {
733                ::gig::Region* rgn = instrument->GetRegion(i);
734                if (rgn) {
735                    set_region(rgn);
736                    return;
737                }
738            }
739        } else {
740            bool currentFound = false;
741            for (int i = 127; i >= 0; --i) {
742                ::gig::Region* rgn = instrument->GetRegion(i);
743                if (!rgn) continue;
744                if (currentFound) {
745                    if (rgn != region) {
746                        set_region(rgn);
747                        return;
748                    }
749                } else {
750                    if (rgn == region) currentFound = true;
751                }
752            }
753        }
754    }
755    
756  void RegionChooser::motion_resize_region(int x, int y)  void RegionChooser::motion_resize_region(int x, int y)
757  {  {
758      const int w = get_width() - 1;      const int w = get_width() - 1;
     Glib::RefPtr<Gdk::Window> window = get_window();  
759    
760      int k = int(double(x) / w * 128.0 + 0.5);      int k = int(double(x) / w * 128.0 + 0.5);
761    
# Line 417  void RegionChooser::motion_resize_region Line 775  void RegionChooser::motion_resize_region
775                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
776              }              }
777          }          }
778          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);  
779    
780            int x1, x2;
781          if (resize.mode == resize.moving_high_limit) {          if (resize.mode == resize.moving_high_limit) {
782              if (k > resize.pos) {              if (resize.region->KeyRange.high < resize.pos - 1) {
783                  window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);                  x1 = resize.region->KeyRange.high;
784                  window->draw_line(black, prevx, 0, x, 0);                  x2 = resize.pos - 1;
                 window->draw_line(black, prevx, h1 - 1, x, h1 - 1);  
785              } else {              } else {
786                  int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);                  x1 = resize.pos - 1;
787                  window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);                  x2 = resize.region->KeyRange.high;
788              }              }
789          } else {          } else {
790              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
791                  window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);                  x1 = resize.region->KeyRange.low;
792                  window->draw_line(black, x, 0, prevx, 0);                  x2 = resize.pos;
                 window->draw_line(black, x, h1 - 1, prevx, h1 - 1);  
793              } else {              } else {
794                  int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);                  x1 = resize.pos;
795                  window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);                  x2 = resize.region->KeyRange.low;
796              }              }
797          }          }
798          window->draw_line(black, x, 1, x, h1 - 2);          x1 = key_to_x(x1, w);
799          resize.pos = k;          x2 = key_to_x(x2 + 1, w) + 1;
800            Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
801    
802            update_after_resize();
803    
804            //get_window()->invalidate_rect(rect, false);
805            get_window()->invalidate(false); // repaint entire region, otherwise it would create visual artifacts
806      }      }
807  }  }
808    
809  void RegionChooser::motion_move_region(int x, int y)  void RegionChooser::motion_move_region(int x, int y)
810  {  {
811      const int w = get_width() - 1;      const int w = get_width() - 1;
     Glib::RefPtr<Gdk::Window> window = get_window();  
812    
813      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);
814      if (k == move.pos) return;  
815      int new_k;      if (l == region->KeyRange.low) return;
816      bool new_touch_left;      int new_l;
817      bool new_touch_right;      int regionsize = region->KeyRange.high - region->KeyRange.low;
818      int a = 0;      int a = 0;
819      if (k > move.pos) {      if (l > region->KeyRange.low) {
820          for (gig::Region* r = regions.first() ; ; r = regions.next()) {          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
821              if (r != region) {              if (r != region) {
822                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
823    
824                  // gap: from a to b (not inclusive b)                  // gap: from a to b (not inclusive b)
825    
826                  if (region->KeyRange.high + move.pos >= b) {                  if (region->KeyRange.high >= b) {
827                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
828                  } else {                  } else {
829    
830                      if (a > region->KeyRange.low + k) {                      if (a > l) {
831                          // this gap is too far to the right, break                          // this gap is too far to the right, break
832                          break;                          break;
833                      }                      }
834    
835                      int newhigh = std::min(region->KeyRange.high + k, b - 1);                      int newhigh = std::min(l + regionsize, b - 1);
836                      int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);                      int newlo = newhigh - regionsize;
837    
838                      if (newlo >= a) {                      if (newlo >= a) {
839                          // yes it fits - it's a candidate                          // yes it fits - it's a candidate
840                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
841                      }                      }
842                  }                  }
843                  if (!r) break;                  if (!r) break;
# Line 499  void RegionChooser::motion_move_region(i Line 851  void RegionChooser::motion_move_region(i
851    
852                  // gap from a to b (not inclusive b)                  // gap from a to b (not inclusive b)
853    
854                  if (region->KeyRange.high + k >= b) {                  if (l + regionsize >= b) {
855                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
856                  } else {                  } else {
857    
858                      if (a > region->KeyRange.low + move.pos) {                      if (a > region->KeyRange.low) {
859                          // this gap is too far to the right, break                          // this gap is too far to the right, break
860                          break;                          break;
861                      }                      }
862    
863                      int newlo = std::max(region->KeyRange.low + k, a);                      int newlo = std::max(l, a);
864                      int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);                      int newhigh = newlo + regionsize;
865    
866                      if (newhigh < b) {                      if (newhigh < b) {
867                          // yes it fits - break as the first one is the best                          // yes it fits - break as the first one is the best
868                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
869                          break;                          break;
870                      }                      }
871                  }                  }
# Line 524  void RegionChooser::motion_move_region(i Line 874  void RegionChooser::motion_move_region(i
874              }              }
875          }          }
876      }      }
877      k = new_k;      if (new_l == region->KeyRange.low) return;
     if (k == move.pos) return;  
878    
879      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);
880      int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
881      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);  
882    
883          window->draw_rectangle(gc, true, x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
884      }      update_after_move(new_l);
885    
886      move.pos = k;      get_window()->invalidate_rect(rect, false);
     move.touch_left = new_touch_left;  
     move.touch_right = new_touch_right;  
887  }  }
888    
889    
# Line 571  bool RegionChooser::on_motion_notify_eve Line 894  bool RegionChooser::on_motion_notify_eve
894      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
895      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
896    
897        // handle virtual MIDI keyboard
898        if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&
899            currentActiveKey > 0 &&
900            event->y >= REGION_BLOCK_HEIGHT &&
901            event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
902        {
903            const int k = x_to_key(event->x, get_width() - 1);
904            if (k != currentActiveKey) {
905                int velocity =
906                    (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
907                    int(float(event->y - REGION_BLOCK_HEIGHT) /
908                        float(KEYBOARD_HEIGHT) * 128.0f) + 1;
909                if (velocity <= 0) velocity = 1;
910                keyboard_key_released_signal.emit(currentActiveKey, velocity);
911                currentActiveKey = k;
912                keyboard_key_hit_signal.emit(k, velocity);
913            }
914        }
915    
916      if (resize.active) {      if (resize.active) {
917          motion_resize_region(x, y);          motion_resize_region(x, y);
918      } else if (move.active) {      } else if (move.active) {
# Line 578  bool RegionChooser::on_motion_notify_eve Line 920  bool RegionChooser::on_motion_notify_eve
920      } else {      } else {
921          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
922              if (!cursor_is_resize) {              if (!cursor_is_resize) {
923    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
924                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
925    #else
926                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
927    #endif
928                  cursor_is_resize = true;                  cursor_is_resize = true;
929              }              }
930          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 599  bool RegionChooser::is_in_resize_zone(do Line 945  bool RegionChooser::is_in_resize_zone(do
945          for (gig::Region* r = regions.first(); r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
946              next_region = regions.next();              next_region = regions.next();
947    
948              int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);              int lo = key_to_x(r->KeyRange.low, w);
949              if (x <= lo - 2) break;              if (x <= lo - 2) break;
950              if (x < lo + 2) {              if (x < lo + 2) {
951                  resize.region = r;                  resize.region = r;
# Line 622  bool RegionChooser::is_in_resize_zone(do Line 968  bool RegionChooser::is_in_resize_zone(do
968                  return resize.min != resize.max;                  return resize.min != resize.max;
969              }              }
970              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
971                  int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);                  int hi = key_to_x(r->KeyRange.high + 1, w);
972                  if (x <= hi - 2) break;                  if (x <= hi - 2) break;
973                  if (x < hi + 2) {                  if (x < hi + 2) {
974                      // edit high limit                      // edit high limit
# Line 653  sigc::signal<void>& RegionChooser::signa Line 999  sigc::signal<void>& RegionChooser::signa
999  void RegionChooser::show_region_properties()  void RegionChooser::show_region_properties()
1000  {  {
1001      if (!region) return;      if (!region) return;
1002      Gtk::Dialog dialog("Region Properties", true /*modal*/);      Gtk::Dialog dialog(_("Region Properties"), true /*modal*/);
1003      // add "Keygroup" checkbox      // add "Keygroup" checkbox
1004      Gtk::CheckButton checkBoxKeygroup("Member of a Keygroup (Exclusive Group)");      Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));
1005      checkBoxKeygroup.set_active(region->KeyGroup);      checkBoxKeygroup.set_active(region->KeyGroup);
1006      dialog.get_vbox()->pack_start(checkBoxKeygroup);      dialog.get_vbox()->pack_start(checkBoxKeygroup);
1007      checkBoxKeygroup.show();      checkBoxKeygroup.show();
1008      // add "Keygroup" spinbox      // add "Keygroup" spinbox
1009      Gtk::Adjustment adjustment(1, 1, pow(2,32));  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1010        Gtk::Adjustment adjustment(1, 1, 999);
1011      Gtk::SpinButton spinBox(adjustment);      Gtk::SpinButton spinBox(adjustment);
1012    #else
1013        Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1014    #endif
1015      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
1016      dialog.get_vbox()->pack_start(spinBox);      dialog.get_vbox()->pack_start(spinBox);
1017      spinBox.show();      spinBox.show();
1018      // add OK and CANCEL buttons to the dialog      // add OK and CANCEL buttons to the dialog
1019      dialog.add_button(Gtk::Stock::OK, 0);      dialog.add_button(_("_OK"), 0);
1020      dialog.add_button(Gtk::Stock::CANCEL, 1);      dialog.add_button(_("_Cancel"), 1);
1021      dialog.show_all_children();      dialog.show_all_children();
1022      if (!dialog.run()) { // OK selected ...      if (!dialog.run()) { // OK selected ...
1023          region->KeyGroup =          region->KeyGroup =
# Line 687  void RegionChooser::add_region() Line 1037  void RegionChooser::add_region()
1037    
1038      queue_draw();      queue_draw();
1039      region_selected();      region_selected();
1040        dimensionManager.set_region(region);
1041      instrument_changed();      instrument_changed();
1042  }  }
1043    
# Line 700  void RegionChooser::delete_region() Line 1051  void RegionChooser::delete_region()
1051      region = 0;      region = 0;
1052      queue_draw();      queue_draw();
1053      region_selected();      region_selected();
1054        dimensionManager.set_region(region);
1055      instrument_changed();      instrument_changed();
1056  }  }
1057    
# Line 730  sigc::signal<void, gig::Region*>& Region Line 1082  sigc::signal<void, gig::Region*>& Region
1082  sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {  sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {
1083      return region_changed_signal;      return region_changed_signal;
1084  }  }
1085    
1086    sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_hit() {
1087        return keyboard_key_hit_signal;
1088    }
1089    
1090    sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_released() {
1091        return keyboard_key_released_signal;
1092    }

Legend:
Removed from v.1623  
changed lines
  Added in v.3131

  ViewVC Help
Powered by ViewVC