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

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

  ViewVC Help
Powered by ViewVC