/[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 1261 by persson, Thu Jul 5 17:12:20 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        loadBuiltInPix();
97    
     black = Gdk::Color("black");  
     white = Gdk::Color("white");  
     red = Gdk::Color("#8070ff");  
     blue = Gdk::Color("#c098ff");  
     green = Gdk::Color("#a088ff");  
     grey1 = Gdk::Color("red");  
   
     colormap->alloc_color(black);  
     colormap->alloc_color(white);  
     colormap->alloc_color(red);  
     colormap->alloc_color(blue);  
     colormap->alloc_color(green);  
     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;
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 86  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      // Now we can allocate any additional resources we need      Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
194      Glib::RefPtr<Gdk::Window> window = get_window();      get_window()->invalidate_rect(rect, false);
     gc = Gdk::GC::create(window);  
     window->clear();  
195  }  }
196    
197  bool RegionChooser::on_expose_event(GdkEventExpose* event)  void RegionChooser::on_note_on_event(int key, int velocity) {
198  {      key_pressed[key] = true;
199      Glib::RefPtr<Gdk::Window> window = get_window();      invalidate_key(key);
200      window->clear();      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
201      const int h = 40;  }
202      const int w = width - 1;  
203    void RegionChooser::on_note_off_event(int key, int velocity) {
204        key_pressed[key] = false;
205        invalidate_key(key);
206        m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
207    }
208    
209    
210    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
211    bool RegionChooser::on_expose_event(GdkEventExpose* e) {
212        double clipx1 = e->area.x;
213        double clipx2 = e->area.x + e->area.width;
214        double clipy1 = e->area.y;
215        double clipy2 = e->area.y + e->area.height;
216    
217        const Cairo::RefPtr<Cairo::Context>& cr =
218            get_window()->create_cairo_context();
219    #if 0
220    }
221    #endif
222    #else
223    bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
224        double clipx1, clipx2, clipy1, clipy2;
225        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
226    #endif
227    
228        cr->save();
229        cr->set_line_width(1);
230    
231    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
232        const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
233    #else
234        const Gdk::RGBA bg = get_style_context()->get_background_color();
235    #endif
236        Gdk::Cairo::set_source_rgba(cr, bg);
237        cr->paint();
238    
239        if (clipy2 > h1) {
240            draw_keyboard(cr, clipx1, clipx2);
241        }
242    
243        if (clipy1 < h1 && instrument) {
244            draw_regions(cr, clipx1, clipx2);
245        }
246    
247        cr->restore();
248    
249        return true;
250    }
251    
252    void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
253                                      int clip_low, int clip_high) {
254        const int h = KEYBOARD_HEIGHT;
255        const int w = get_width() - 1;
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      window->draw_rectangle(black, false, 0, h1, w, h - 1);      Gdk::Cairo::set_source_rgba(cr, black);
277      window->draw_rectangle(white, true, 1, h1 + 1, w - 1, h - 2);  
278      for (int i = 0 ; i < 128 ; i++) {      int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
279          int note = (i + 3) % 12;      int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
         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                cr->line_to(x + 0.5, h1 + h - 1);
301                cr->stroke();
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 *nextRegion;  
         int x3 = -1;  
         for (gig::Region *r = instrument->GetFirstRegion() ;  
              r ;  
              r = nextRegion) {  
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              nextRegion = instrument->GetNextRegion();                                   int clip_low, int clip_high) {
313              if (!nextRegion || r->KeyRange.high + 1 != nextRegion->KeyRange.low) {      const int w = get_width() - 1;
314                  int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);  
315                  window->draw_line(black, x3, 0, x2, 0);      Gdk::Cairo::set_source_rgba(cr, black);
316                  window->draw_line(black, x3, h1 - 1, x2, h1 - 1);      gig::Region* next_region;
317                  window->draw_line(black, x2, 1, x2, h1 - 2);      int x3 = -1;
318                  window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);      for (gig::Region* r = regions.first() ; r ; r = next_region) {
319                  x3 = -1;          next_region = regions.next();
320    
321            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              i++;              x3 = -1;
343          }          }
344        }
345    
346          for (gig::Region *r = instrument->GetFirstRegion() ;      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
347               r ;          int x = key_to_x(r->KeyRange.low, w);
348               r = instrument->GetNextRegion()) {          int x2 = key_to_x(r->KeyRange.high + 1, w);
349              int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);  
350              window->draw_line(black, x, 1, x, 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        }
386    
387          if (region) {      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
388              int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);          int x = key_to_x(r->KeyRange.low, w);
389              int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);  
390              gc->set_foreground(red);          if (x < clip_low) continue;
391              window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);          if (x >= clip_high) break;
392          }  
393            cr->move_to(x + 0.5, 1);
394            cr->line_to(x + 0.5, h1 - 1);
395            cr->stroke();
396      }      }
     return true;  
 }  
397    
398        // if there is no region yet, show the user some hint text that he may
399        // right click on this area to create a new region
400        if (!regions.first()) {
401            Glib::RefPtr<Pango::Context> context = get_pango_context();
402            Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
403            layout->set_alignment(Pango::ALIGN_CENTER);
404            layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
405            layout->set_width(get_width() * Pango::SCALE);
406            //layout->set_height(get_height() * Pango::SCALE);
407            layout->set_spacing(10);
408            Gdk::Cairo::set_source_rgba(cr, blue);
409            // get the text dimensions
410            int text_width, text_height;
411            layout->get_pixel_size(text_width, text_height);
412            cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
413    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
414            pango_cairo_show_layout(cr->cobj(), layout->gobj());
415    #else
416            layout->show_in_cairo_context(cr);
417    #endif
418        }
419    }
420    
421  void RegionChooser::on_size_request(GtkRequisition* requisition)  bool RegionChooser::is_black_key(int key) {
422  {      const int note = (key + 3) % 12;
423      *requisition = GtkRequisition();      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
     requisition->height = 40 + 20;  
     requisition->width = 500;  
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  // not used  void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
449  void RegionChooser::draw_region(int from, int to, const Gdk::Color& color)                               int key) {
450  {      const int h = KEYBOARD_HEIGHT;
451      const int h = 40;      const int w = get_width() - 1;
     const int w = width;  
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) {
536    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
537            get_window()->pointer_ungrab(event->time);
538    #else
539            Glib::wrap(event->device, true)->ungrab(event->time);
540    #endif
541            move.active = false;
542    
543            if (is_in_resize_zone(event->x, event->y)) {
544    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
545                get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
546    #else
547                get_window()->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
548    #endif
549                cursor_is_resize = true;
550            }
551      }      }
552      return true;      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 271  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              Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #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                                         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 284  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,
663                                               Gdk::BUTTON_RELEASE_MASK |
664                                               Gdk::POINTER_MOTION_MASK |
665                                               Gdk::POINTER_MOTION_HINT_MASK,
666                                               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;
679                    move.offset = event->x - key_to_x(region->KeyRange.low, w);
680              }              }
681          }          }
682      }      }
# Line 292  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      for (gig::Region *r = instrument->GetFirstRegion() ; r ;      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
          r = instrument->GetNextRegion()) {  
689          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
690          if (key <= r->KeyRange.high) return r;          if (key <= r->KeyRange.high) return r;
691      }      }
692      return 0;      return 0;
693  }  }
694    
695  bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)  void RegionChooser::set_region(gig::Region* region) {
696  {      this->region = region;
697      const int w = width - 1;      queue_draw();
698      Glib::RefPtr<Gdk::Window> window = get_window();      region_selected();
699      int x, y;      dimensionManager.set_region(region);
700      Gdk::ModifierType state = Gdk::ModifierType(0);  }
     window->get_pointer(x, y, state);  
     if (resize.active) {  
         int k = int(double(x) / w * 128.0 + 0.5);  
701    
702          if (k < resize.min) k = resize.min;  void RegionChooser::select_next_region() {
703          else if (k > resize.max) k = resize.max;      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          if (k != resize.pos) {  void RegionChooser::select_prev_region() {
730              if (resize.mode == resize.undecided) {      if (!instrument) return;
731                  if (k < resize.pos) {      if (!region) {
732                      // edit high limit of prev_region          for (int i = 0; i < 128; ++i) {
733                      resize.max = resize.region->KeyRange.low;              ::gig::Region* rgn = instrument->GetRegion(i);
734                      resize.region = resize.prev_region;              if (rgn) {
735                      resize.mode = resize.moving_high_limit;                  set_region(rgn);
736                  } else {                  return;
737                      // edit low limit of region              }
738                      resize.min = resize.prev_region->KeyRange.high + 1;          }
739                      resize.mode = resize.moving_low_limit;      } 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              Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();          }
753              Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();      }
754              if (region == resize.region) {  }
755                  gc->set_foreground(red);  
756                  white = gc;  void RegionChooser::motion_resize_region(int x, int y)
757              }  {
758              Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);      const int w = get_width() - 1;
759              int prevx = int(w * resize.pos / 128.0 + 0.5);  
760              x = int(w * k / 128.0 + 0.5);      int k = int(double(x) / w * 128.0 + 0.5);
761    
762              if (resize.mode == resize.moving_high_limit) {      if (k < resize.min) k = resize.min;
763                  if (k > resize.pos) {      else if (k > resize.max) k = resize.max;
764                      window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);  
765                      window->draw_line(black, prevx, 0, x, 0);      if (k != resize.pos) {
766                      window->draw_line(black, prevx, h1 - 1, x, h1 - 1);          if (resize.mode == resize.undecided) {
767                if (k < resize.pos) {
768                    // edit high limit of prev_region
769                    resize.max = resize.region->KeyRange.low;
770                    resize.region = resize.prev_region;
771                    resize.mode = resize.moving_high_limit;
772                } else {
773                    // edit low limit of region
774                    resize.min = resize.prev_region->KeyRange.high + 1;
775                    resize.mode = resize.moving_low_limit;
776                }
777            }
778            resize.pos = k;
779    
780            int x1, x2;
781            if (resize.mode == resize.moving_high_limit) {
782                if (resize.region->KeyRange.high < resize.pos - 1) {
783                    x1 = resize.region->KeyRange.high;
784                    x2 = resize.pos - 1;
785                } else {
786                    x1 = resize.pos - 1;
787                    x2 = resize.region->KeyRange.high;
788                }
789            } else {
790                if (resize.region->KeyRange.low < resize.pos) {
791                    x1 = resize.region->KeyRange.low;
792                    x2 = resize.pos;
793                } else {
794                    x1 = resize.pos;
795                    x2 = resize.region->KeyRange.low;
796                }
797            }
798            x1 = key_to_x(x1, w);
799            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)
810    {
811        const int w = get_width() - 1;
812    
813        int l = int(double(x - move.offset) / w * 128.0 + 0.5);
814    
815        if (l == region->KeyRange.low) return;
816        int new_l;
817        int regionsize = region->KeyRange.high - region->KeyRange.low;
818        int a = 0;
819        if (l > region->KeyRange.low) {
820            for (gig::Region* r = regions.first() ; ; r = regions.next()) {
821                if (r != region) {
822                    int b = r ? r->KeyRange.low : 128;
823    
824                    // gap: from a to b (not inclusive b)
825    
826                    if (region->KeyRange.high >= b) {
827                        // not found the current gap yet, just continue
828                  } else {                  } else {
829                      int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);  
830                      window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);                      if (a > l) {
831                            // this gap is too far to the right, break
832                            break;
833                        }
834    
835                        int newhigh = std::min(l + regionsize, b - 1);
836                        int newlo = newhigh - regionsize;
837    
838                        if (newlo >= a) {
839                            // yes it fits - it's a candidate
840                            new_l = newlo;
841                        }
842                  }                  }
843              } else {                  if (!r) break;
844                  if (k < resize.pos) {                  a = r->KeyRange.high + 1;
845                      window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);              }
846                      window->draw_line(black, x, 0, prevx, 0);          }
847                      window->draw_line(black, x, h1 - 1, prevx, h1 - 1);      } else {
848            for (gig::Region* r = regions.first() ; ; r = regions.next()) {
849                if (r != region) {
850                    int b = r ? r->KeyRange.low : 128;
851    
852                    // gap from a to b (not inclusive b)
853    
854                    if (l + regionsize >= b) {
855                        // not found the current gap yet, just continue
856                  } else {                  } else {
857                      int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);  
858                      window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);                      if (a > region->KeyRange.low) {
859                            // this gap is too far to the right, break
860                            break;
861                        }
862    
863                        int newlo = std::max(l, a);
864                        int newhigh = newlo + regionsize;
865    
866                        if (newhigh < b) {
867                            // yes it fits - break as the first one is the best
868                            new_l = newlo;
869                            break;
870                        }
871                  }                  }
872                    if (!r) break;
873                    a = r->KeyRange.high + 1;
874              }              }
             window->draw_line(black, x, 1, x, h1 - 2);  
             resize.pos = k;  
875          }          }
876        }
877        if (new_l == region->KeyRange.low) return;
878    
879        int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
880        int x2 = key_to_x(std::max(int(region->KeyRange.high),
881                                   new_l + regionsize) + 1, w) + 1;
882    
883        Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
884        update_after_move(new_l);
885    
886        get_window()->invalidate_rect(rect, false);
887    }
888    
889    
890    bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)
891    {
892        Glib::RefPtr<Gdk::Window> window = get_window();
893        int x, y;
894        Gdk::ModifierType state = Gdk::ModifierType(0);
895        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) {
917            motion_resize_region(x, y);
918        } else if (move.active) {
919            motion_move_region(x, y);
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                  Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
924                  window->set_cursor(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 375  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 397  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 415  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 424  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 437  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 461  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 495  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.1261  
changed lines
  Added in v.3131

  ViewVC Help
Powered by ViewVC