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

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

  ViewVC Help
Powered by ViewVC