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

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

  ViewVC Help
Powered by ViewVC