/[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 1262 by persson, Sun Jul 22 15:07:08 2007 UTC revision 2845 by persson, Sun Sep 20 10:18:22 2015 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>
 #include <gtkmm/stock.h>  
27  #include <gtkmm/spinbutton.h>  #include <gtkmm/spinbutton.h>
28  #include <gtkmm/dialog.h>  #include <gtkmm/dialog.h>
 #include <libintl.h>  
 #include <math.h>  
29    
30  #define _(String) gettext(String)  #include "global.h"
31    #include "Settings.h"
32    
33  RegionChooser::RegionChooser()  #define REGION_BLOCK_HEIGHT             30
34  {  #define KEYBOARD_HEIGHT                 40
     Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();  
35    
36      red = Gdk::Color("#8070ff");  void SortedRegions::update(gig::Instrument* instrument) {
37      grey1 = Gdk::Color("#b0b0b0");      // Usually, the regions in a gig file are ordered after their key
38        // range, but there are files where they are not. The
39        // RegionChooser code needs a sorted list of regions.
40        regions.clear();
41        if (instrument) {
42            for (gig::Region* r = instrument->GetFirstRegion() ;
43                 r ;
44                 r = instrument->GetNextRegion()) {
45                regions.push_back(r);
46            }
47            sort(regions.begin(), regions.end(), *this);
48        }
49    }
50    
51    gig::Region* SortedRegions::first() {
52        region_iterator = regions.begin();
53        return region_iterator == regions.end() ? 0 : *region_iterator;
54    }
55    
56    gig::Region* SortedRegions::next() {
57        ++region_iterator;
58        return region_iterator == regions.end() ? 0 : *region_iterator;
59    }
60    
61    
62    
63    RegionChooser::RegionChooser() :
64        activeKeyColor("red"),
65        red("#8070ff"),
66        grey1("grey69"),
67        white("white"),
68        black("black"),
69        m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),
70        currentActiveKey(-1)
71    {
72        set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT);
73    
     colormap->alloc_color(red);  
     colormap->alloc_color(grey1);  
74      instrument = 0;      instrument = 0;
75      region = 0;      region = 0;
76      resize.active = false;      resize.active = false;
77        move.active = false;
78      cursor_is_resize = false;      cursor_is_resize = false;
79      h1 = 20;      h1 = REGION_BLOCK_HEIGHT;
80      width = 800;  
81        // properties of the virtual keyboard
82        {
83            const char* choices[] = { _("normal"), _("chord"), 0 };
84            static const virt_keyboard_mode_t values[] = {
85                VIRT_KEYBOARD_MODE_NORMAL,
86                VIRT_KEYBOARD_MODE_CHORD
87            };
88            m_VirtKeybModeChoice.set_choices(choices, values);
89            m_VirtKeybModeChoice.set_value(VIRT_KEYBOARD_MODE_NORMAL);
90        }
91        m_VirtKeybVelocityLabelDescr.set_text(_("Note-On Velocity:"));
92        m_VirtKeybVelocityLabel.set_text("-");
93        m_VirtKeybOffVelocityLabelDescr.set_text(_("Note-Off Velocity:"));
94        m_VirtKeybOffVelocityLabel.set_text("-");
95        m_VirtKeybPropsBox.pack_start(m_VirtKeybModeChoice.label, Gtk::PACK_SHRINK);
96        m_VirtKeybPropsBox.pack_start(m_VirtKeybModeChoice.widget, Gtk::PACK_SHRINK);
97        m_VirtKeybPropsBox.pack_start(m_VirtKeybVelocityLabelDescr, Gtk::PACK_SHRINK);
98        m_VirtKeybPropsBox.pack_start(m_VirtKeybVelocityLabel, Gtk::PACK_SHRINK);
99        m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabelDescr, Gtk::PACK_SHRINK);
100        m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);
101        m_VirtKeybPropsBox.set_spacing(10);
102        m_VirtKeybPropsBox.show();
103        for (int i = 0 ; i < 128 ; i++) key_pressed[i] = false;
104    
105      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
106      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties", _("_Properties")),
                                          Gtk::Stock::PROPERTIES),  
107                       sigc::mem_fun(*this,                       sigc::mem_fun(*this,
108                                     &RegionChooser::show_region_properties));                                     &RegionChooser::show_region_properties));
109      actionGroup->add(Gtk::Action::create("Remove", Gtk::Stock::REMOVE),      actionGroup->add(Gtk::Action::create("Remove", _("_Remove")),
110                       sigc::mem_fun(*this, &RegionChooser::delete_region));                       sigc::mem_fun(*this, &RegionChooser::delete_region));
111      actionGroup->add(Gtk::Action::create("Add", Gtk::Stock::ADD),      actionGroup->add(Gtk::Action::create("Add", _("_Add")),
112                       sigc::mem_fun(*this, &RegionChooser::add_region));                       sigc::mem_fun(*this, &RegionChooser::add_region));
113      actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),      actionGroup->add(Gtk::Action::create("Dimensions", _("Dimensions...")),
114                       sigc::mem_fun(*this, &RegionChooser::manage_dimensions));                       sigc::mem_fun(*this, &RegionChooser::manage_dimensions));
# Line 78  RegionChooser::RegionChooser() Line 136  RegionChooser::RegionChooser()
136      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
137                 Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK);
138    
139      dimensionManager.articulation_changed_signal.connect(      dimensionManager.region_to_be_changed_signal.connect(
140          sigc::mem_fun(*this, &RegionChooser::on_dimension_manager_changed)          region_to_be_changed_signal.make_slot()
141        );
142        dimensionManager.region_changed_signal.connect(
143            region_changed_signal.make_slot()
144        );
145        dimensionManager.region_changed_signal.connect(
146            sigc::hide(
147                sigc::mem_fun(*this, &RegionChooser::on_dimension_manager_changed)
148            )
149        );
150        keyboard_key_hit_signal.connect(
151            sigc::mem_fun(*this, &RegionChooser::on_note_on_event)
152      );      );
153        keyboard_key_released_signal.connect(
154            sigc::mem_fun(*this, &RegionChooser::on_note_off_event)
155        );
156        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."));
157  }  }
158    
159  RegionChooser::~RegionChooser()  RegionChooser::~RegionChooser()
160  {  {
161  }  }
162    
163  void RegionChooser::on_realize()  void RegionChooser::invalidate_key(int key) {
164  {      const int h = KEYBOARD_HEIGHT;
165      // We need to call the base on_realize()      const int w = get_width() - 1;
166      Gtk::DrawingArea::on_realize();      int x1 = key_to_x(key - 0.5, w);
167        int x2 = key_to_x(key + 1.5, w);
168    
169      // Now we can allocate any additional resources we need      Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
170      Glib::RefPtr<Gdk::Window> window = get_window();      get_window()->invalidate_rect(rect, false);
     gc = Gdk::GC::create(window);  
     window->clear();  
171  }  }
172    
173  bool RegionChooser::on_expose_event(GdkEventExpose* event)  void RegionChooser::on_note_on_event(int key, int velocity) {
174  {      key_pressed[key] = true;
175      Glib::RefPtr<Gdk::Window> window = get_window();      invalidate_key(key);
176      window->clear();      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
177      const int h = 40;  }
     const int w = width - 1;  
     const int bh = int(h * 0.55);  
   
     Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();  
     Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();  
178    
179      Glib::RefPtr<Pango::Context> context = get_pango_context();  void RegionChooser::on_note_off_event(int key, int velocity) {
180      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);      key_pressed[key] = false;
181        invalidate_key(key);
182        m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
183    }
184    
     window->draw_rectangle(black, false, 0, h1, w, h - 1);  
     gc->set_foreground(grey1);  
     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);  
185    
186          if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) {  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
187              int x2 = int(w * (i + 0.5) / 128.0 + 0.5);  bool RegionChooser::on_expose_event(GdkEventExpose* e) {
188              window->draw_line(black, x2, h1 + bh, x2, h1 + h);      double clipx1 = e->area.x;
189        double clipx2 = e->area.x + e->area.width;
190        double clipy1 = e->area.y;
191        double clipy2 = e->area.y + e->area.height;
192    
193              int x3 = int(w * (i + 1) / 128.0 + 0.5);      const Cairo::RefPtr<Cairo::Context>& cr =
194              window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh);          get_window()->create_cairo_context();
195          } else if (note == 3 || note == 8) {  #if 0
196              window->draw_line(black, x, h1 + 1, x, h1 + h);  }
197          }  #endif
198          if (note == 3) {  #else
199              char buf[30];  bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
200              sprintf(buf, "<span size=\"x-small\">%d</span>", octave);      double clipx1, clipx2, clipy1, clipy2;
201              layout->set_markup(buf);      cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
202              Pango::Rectangle rectangle = layout->get_logical_extents();  #endif
             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++;  
         }  
     }  
203    
204      if (instrument) {      cr->save();
205          int i = 0;      cr->set_line_width(1);
         gig::Region *next_region;  
         int x3 = -1;  
         for (gig::Region *r = instrument->GetFirstRegion() ;  
              r ;  
              r = next_region) {  
206    
207              if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
208              next_region = instrument->GetNextRegion();      const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
209              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {  #else
210                  int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);      const Gdk::RGBA bg = get_style_context()->get_background_color();
211                  window->draw_line(black, x3, 0, x2, 0);  #endif
212                  window->draw_line(black, x3, h1 - 1, x2, h1 - 1);      Gdk::Cairo::set_source_rgba(cr, bg);
213                  window->draw_line(black, x2, 1, x2, h1 - 2);      cr->paint();
                 window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);  
                 x3 = -1;  
             }  
             i++;  
         }  
214    
215          for (gig::Region *r = instrument->GetFirstRegion() ;      if (clipy2 > h1) {
216               r ;          draw_keyboard(cr, clipx1, clipx2);
217               r = instrument->GetNextRegion()) {      }
             int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);  
             window->draw_line(black, x, 1, x, h1 - 2);  
         }  
218    
219          if (region) {      if (clipy1 < h1 && instrument) {
220              int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);          draw_regions(cr, clipx1, clipx2);
             int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);  
             gc->set_foreground(red);  
             window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);  
         }  
221      }      }
222    
223        cr->restore();
224    
225      return true;      return true;
226  }  }
227    
228    void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
229                                      int clip_low, int clip_high) {
230        const int h = KEYBOARD_HEIGHT;
231        const int w = get_width() - 1;
232        const int bh = int(h * 0.55);
233    
234  void RegionChooser::on_size_request(GtkRequisition* requisition)      Gdk::Cairo::set_source_rgba(cr, black);
235  {      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
236      *requisition = GtkRequisition();      cr->stroke();
237      requisition->height = 40 + 20;  
238      requisition->width = 500;      int x1 = key_to_x(20.5, w);
239        Gdk::Cairo::set_source_rgba(cr, grey1);
240        cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
241        cr->fill();
242    
243        int x2 = key_to_x(109.5, w);
244        Gdk::Cairo::set_source_rgba(cr, white);
245        cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
246        cr->fill();
247    
248        Gdk::Cairo::set_source_rgba(cr, grey1);
249        cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);
250        cr->fill();
251    
252        Gdk::Cairo::set_source_rgba(cr, black);
253    
254        int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
255        int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
256    
257        for (int i = clipkey1 ; i < clipkey2 ; i++) {
258            int note = (i + 3) % 12;
259            int x = key_to_x(i, w);
260    
261            if (note == 1 || note == 4 || note == 6 ||
262                note == 9 || note == 11) {
263                // black key: short line in the middle, with a rectangle
264                // on top
265                int x2 = key_to_x(i + 0.5, w);
266                cr->move_to(x2 + 0.5, h1 + bh + 0.5);
267                cr->line_to(x2 + 0.5, h1 + h - 1);
268                cr->stroke();
269    
270                int x3 = key_to_x(i + 1, w);
271                cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
272                cr->fill();
273            } else if (note == 3 || note == 8) {
274                // C or F: long line to the left
275                cr->move_to(x + 0.5, h1 + 1);
276                cr->line_to(x + 0.5, h1 + h - 1);
277                cr->stroke();
278            }
279    
280            if (key_pressed[i]) draw_key(cr, i);
281    
282            if (note == 3) draw_digit(cr, i);
283        }
284  }  }
285    
286    
287  // not used  void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
288  void RegionChooser::draw_region(int from, int to, const Gdk::Color& color)                                   int clip_low, int clip_high) {
289  {      const int w = get_width() - 1;
290      const int h = 40;  
291      const int w = width;      Gdk::Cairo::set_source_rgba(cr, black);
292        gig::Region* next_region;
293        int x3 = -1;
294        for (gig::Region* r = regions.first() ; r ; r = next_region) {
295            next_region = regions.next();
296    
297            if (x3 < 0) {
298                x3 = key_to_x(r->KeyRange.low, w);
299                if (x3 >= clip_high) break;
300            }
301            if (!next_region ||
302                r->KeyRange.high + 1 != next_region->KeyRange.low ||
303                r == region || next_region == region) {
304    
305                int x2 = key_to_x(r->KeyRange.high + 1, w);
306                if (x2 >= clip_low) {
307                    cr->move_to(x3, 0.5);
308                    cr->line_to(x2 + 0.5, 0.5);
309                    cr->line_to(x2 + 0.5, h1 - 0.5);
310                    cr->line_to(x3, h1 - 0.5);
311                    cr->stroke();
312    
313                    Gdk::Cairo::set_source_rgba(cr, region == r ? red : white);
314                    cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
315                    cr->fill();
316                    Gdk::Cairo::set_source_rgba(cr, black);
317                }
318                x3 = -1;
319            }
320        }
321    
322        for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
323            int x = key_to_x(r->KeyRange.low, w);
324    
325            if (x < clip_low) continue;
326            if (x >= clip_high) break;
327    
328            cr->move_to(x + 0.5, 1);
329            cr->line_to(x + 0.5, h1 - 1);
330            cr->stroke();
331        }
332    
333        // if there is no region yet, show the user some hint text that he may
334        // right click on this area to create a new region
335        if (!regions.first()) {
336            Glib::RefPtr<Pango::Context> context = get_pango_context();
337            Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
338            layout->set_alignment(Pango::ALIGN_CENTER);
339            layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
340            layout->set_width(get_width() * Pango::SCALE);
341            //layout->set_height(get_height() * Pango::SCALE);
342            layout->set_spacing(10);
343            Gdk::Cairo::set_source_rgba(cr, red);        
344            // get the text dimensions
345            int text_width, text_height;
346            layout->get_pixel_size(text_width, text_height);
347            cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
348    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
349            pango_cairo_show_layout(cr->cobj(), layout->gobj());
350    #else
351            layout->show_in_cairo_context(cr);
352    #endif
353        }
354    }
355    
356    bool RegionChooser::is_black_key(int key) {
357        const int note = (key + 3) % 12;
358        return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
359    }
360    
361    void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
362                                   int key) {
363        const int h = KEYBOARD_HEIGHT;
364        const int w = get_width() - 1;
365        Glib::RefPtr<Pango::Layout> layout =
366            Pango::Layout::create(get_pango_context());
367        char buf[30];
368        sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
369        layout->set_markup(buf);
370        Pango::Rectangle rectangle = layout->get_logical_extents();
371        double text_w = double(rectangle.get_width()) / Pango::SCALE;
372        double text_h = double(rectangle.get_height()) / Pango::SCALE;
373        double x = w * (key + 0.75) / 128.0;
374        Gdk::Cairo::set_source_rgba(cr, black);
375        cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));
376    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
377        pango_cairo_show_layout(cr->cobj(), layout->gobj());
378    #else
379        layout->show_in_cairo_context(cr);
380    #endif
381    }
382    
383    void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
384                                 int key) {
385        const int h = KEYBOARD_HEIGHT;
386        const int w = get_width() - 1;
387      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
388    
389      Glib::RefPtr<Gdk::Window> window = get_window();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     gc->set_foreground(color);  
390    
391      for (int i = from ; i < to ; i++) {      int note = (key + 3) % 12;
392          int note = (i + 3) % 12;      int x = key_to_x(key, w) + 1;
393          int x = int(w * i / 128.0 + 0.5) + 1;      int x2 = key_to_x(key + 1.5, w);
394          int x2 = int(w * (i + 1.5) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
395          int x3 = int(w * (i + 1) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
396          int x4 = int(w * (i - 0.5) / 128 + 0.5) + 1;      int w1 = x3 - x;
397          int w1 = x3 - x;      switch (note) {
398          switch (note) {      case 0: case 5: case 10:
399          case 0: case 5: case 10:          cr->rectangle(x, h1 + 1, w1, bh);
400              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);          cr->fill();
401              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);
402              break;          cr->fill();
403          case 2: case 7:          break;
404              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);      case 2: case 7:
405              window->draw_rectangle(gc, true, x4, h1 + bh + 1, x3 - x4, h - bh - 2);          cr->rectangle(x, h1 + 1, w1, bh);
406              break;          cr->fill();
407          case 3: case 8:          cr->rectangle(x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2);
408              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);          cr->fill();
409              window->draw_rectangle(gc, true, x, h1 + bh + 1, x2 - x, h - bh - 2);          break;
410              break;      case 3: case 8:
411          default:          cr->rectangle(x, h1 + 1, w1, bh);
412              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh - 1);          cr->fill();
413              break;          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
414          }          cr->fill();
415            break;
416        default:
417            cr->rectangle(x, h1 + 1, w1, bh - 1);
418            cr->fill();
419            break;
420      }      }
421        Gdk::Cairo::set_source_rgba(cr, black);
422  }  }
423    
424  void RegionChooser::set_instrument(gig::Instrument* instrument)  void RegionChooser::set_instrument(gig::Instrument* instrument)
425  {  {
426      this->instrument = instrument;      this->instrument = instrument;
427      region = instrument ? instrument->GetFirstRegion() : 0;      regions.update(instrument);
428        region = regions.first();
429      queue_draw();      queue_draw();
430      region_selected();      region_selected();
431        dimensionManager.set_region(region);
432  }  }
433    
434  bool RegionChooser::on_button_release_event(GdkEventButton* event)  bool RegionChooser::on_button_release_event(GdkEventButton* event)
435  {  {
436        const int k = x_to_key(event->x, get_width() - 1);
437    
438        // handle-note off on virtual keyboard
439        if (event->type == GDK_BUTTON_RELEASE) {
440            int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
441                           int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
442            if (velocity <= 0) velocity = 1;
443            switch (m_VirtKeybModeChoice.get_value()) {
444                case VIRT_KEYBOARD_MODE_CHORD:
445                    if (event->y >= REGION_BLOCK_HEIGHT)
446                        keyboard_key_released_signal.emit(k, velocity);
447                    break;
448                case VIRT_KEYBOARD_MODE_NORMAL:
449                default:
450                    if (currentActiveKey >= 0 && currentActiveKey <= 127) {
451                        keyboard_key_released_signal.emit(currentActiveKey, velocity);
452                        currentActiveKey = -1;
453                    }
454                    break;
455            }
456        }
457    
458      if (resize.active) {      if (resize.active) {
459    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
460          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
461    #else
462            Glib::wrap(event->device, true)->ungrab(event->time);
463    #endif
464          resize.active = false;          resize.active = false;
465    
         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();  
             }  
         }  
   
466          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
467              get_window()->set_cursor();              get_window()->set_cursor();
468              cursor_is_resize = false;              cursor_is_resize = false;
469          }          }
470      } else if (move.active) {      } else if (move.active) {
471    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
472          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
473    #else
474            Glib::wrap(event->device, true)->ungrab(event->time);
475    #endif
476          move.active = false;          move.active = false;
477    
         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);  
             }  
         }  
   
478          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
479    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
480              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
481    #else
482                get_window()->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
483    #endif
484              cursor_is_resize = true;              cursor_is_resize = true;
485          }          }
486      }      }
487      return true;      return true;
488  }  }
489    
490    void RegionChooser::update_after_resize()
491    {
492        if (resize.mode == resize.moving_high_limit) {
493            if (resize.region->KeyRange.high != resize.pos - 1) {
494                instrument_struct_to_be_changed_signal.emit(instrument);
495                resize.region->SetKeyRange(resize.region->KeyRange.low,
496                                           resize.pos - 1);
497                regions.update(instrument);
498                instrument_changed.emit();
499                instrument_struct_changed_signal.emit(instrument);
500            }
501        } else if (resize.mode == resize.moving_low_limit) {
502            if (resize.region->KeyRange.low != resize.pos) {
503                instrument_struct_to_be_changed_signal.emit(instrument);
504                resize.region->SetKeyRange(resize.pos,
505                                           resize.region->KeyRange.high);
506                regions.update(instrument);
507                instrument_changed.emit();
508                instrument_struct_changed_signal.emit(instrument);
509            }
510        }
511    }
512    
513    void RegionChooser::update_after_move(int pos)
514    {
515        instrument_struct_to_be_changed_signal.emit(instrument);
516        const int range = region->KeyRange.high - region->KeyRange.low;
517        const int diff  = pos - int(region->KeyRange.low);
518        region->SetKeyRange(pos, pos + range);
519        if (Settings::singleton()->moveRootNoteWithRegionMoved) {
520            for (int i = 0; i < 256; ++i) {
521                gig::DimensionRegion* dimrgn = region->pDimensionRegions[i];
522                if (!dimrgn || !dimrgn->pSample || !dimrgn->PitchTrack) continue;
523                dimrgn->UnityNote += diff;
524            }
525        }
526        regions.update(instrument);
527        instrument_changed.emit();
528        instrument_struct_changed_signal.emit(instrument);
529    }
530    
531  bool RegionChooser::on_button_press_event(GdkEventButton* event)  bool RegionChooser::on_button_press_event(GdkEventButton* event)
532  {  {
533      if (!instrument) return true;      if (!instrument) return true;
534    
535      int k = int(event->x / (width - 1) * 128.0);      const int w = get_width() - 1;
536        const int k = x_to_key(event->x, w);
537    
538        if (event->type == GDK_BUTTON_PRESS) {
539            if (event->y >= REGION_BLOCK_HEIGHT) {
540                int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
541                               int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
542                currentActiveKey = k;
543                keyboard_key_hit_signal.emit(k, velocity);
544            }
545        }
546    
547        // left mouse button double click
548        if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
549            if (event->y < REGION_BLOCK_HEIGHT) {
550                // show dimension manager dialog for this region
551                manage_dimensions();
552            }
553        }
554    
555        if (event->y >= REGION_BLOCK_HEIGHT) return true;
556      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
557          gig::Region* r = get_region(k);          gig::Region* r = get_region(k);
558          if (r) {          if (r) {
559              region = r;              region = r;
560              queue_draw();              queue_draw();
561              region_selected();              region_selected();
562                dimensionManager.set_region(region);
563              popup_menu_inside_region->popup(event->button, event->time);              popup_menu_inside_region->popup(event->button, event->time);
564          } else {          } else {
565              new_region_pos = k;              new_region_pos = k;
# Line 313  bool RegionChooser::on_button_press_even Line 567  bool RegionChooser::on_button_press_even
567          }          }
568      } else {      } else {
569          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
570    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
571              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
572                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
573                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
574                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
575                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW), event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
576                                           event->time);
577    #else
578                Glib::wrap(event->device, true)->grab(get_window(),
579                                                      Gdk::OWNERSHIP_NONE,
580                                                      false,
581                                                      Gdk::BUTTON_RELEASE_MASK |
582                                                      Gdk::POINTER_MOTION_MASK |
583                                                      Gdk::POINTER_MOTION_HINT_MASK,
584                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
585                                                      event->time);
586    #endif
587              resize.active = true;              resize.active = true;
588          } else {          } else {
589              gig::Region* r = get_region(k);              gig::Region* r = get_region(k);
# Line 325  bool RegionChooser::on_button_press_even Line 591  bool RegionChooser::on_button_press_even
591                  region = r;                  region = r;
592                  queue_draw();                  queue_draw();
593                  region_selected();                  region_selected();
594                    dimensionManager.set_region(region);
595    
596    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
597                  get_window()->pointer_grab(false,                  get_window()->pointer_grab(false,
598                                             Gdk::BUTTON_RELEASE_MASK |                                             Gdk::BUTTON_RELEASE_MASK |
599                                             Gdk::POINTER_MOTION_MASK |                                             Gdk::POINTER_MOTION_MASK |
600                                             Gdk::POINTER_MOTION_HINT_MASK,                                             Gdk::POINTER_MOTION_HINT_MASK,
601                                             Gdk::Cursor(Gdk::FLEUR), event->time);                                             Gdk::Cursor(Gdk::FLEUR),
602                                               event->time);
603    #else
604                    Glib::wrap(event->device, true)->grab(get_window(),
605                                                          Gdk::OWNERSHIP_NONE,
606                                                          false,
607                                                          Gdk::BUTTON_RELEASE_MASK |
608                                                          Gdk::POINTER_MOTION_MASK |
609                                                          Gdk::POINTER_MOTION_HINT_MASK,
610                                                          Gdk::Cursor::create(Gdk::FLEUR),
611                                                          event->time);
612    #endif
613                  move.active = true;                  move.active = true;
614                  move.from_x = event->x;                  move.offset = event->x - key_to_x(region->KeyRange.low, w);
                 move.pos = 0;  
615              }              }
616          }          }
617      }      }
# Line 342  bool RegionChooser::on_button_press_even Line 620  bool RegionChooser::on_button_press_even
620    
621  gig::Region* RegionChooser::get_region(int key)  gig::Region* RegionChooser::get_region(int key)
622  {  {
623      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();  
   
624          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
625          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;  
626      }      }
627      return 0;      return 0;
628  }  }
629    
630    void RegionChooser::set_region(gig::Region* region) {
631        this->region = region;
632        queue_draw();
633        region_selected();
634        dimensionManager.set_region(region);
635    }
636    
637  void RegionChooser::motion_resize_region(int x, int y)  void RegionChooser::motion_resize_region(int x, int y)
638  {  {
639      const int w = width - 1;      const int w = get_width() - 1;
     Glib::RefPtr<Gdk::Window> window = get_window();  
640    
641      int k = int(double(x) / w * 128.0 + 0.5);      int k = int(double(x) / w * 128.0 + 0.5);
642    
# Line 382  void RegionChooser::motion_resize_region Line 656  void RegionChooser::motion_resize_region
656                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
657              }              }
658          }          }
659          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);  
660    
661            int x1, x2;
662          if (resize.mode == resize.moving_high_limit) {          if (resize.mode == resize.moving_high_limit) {
663              if (k > resize.pos) {              if (resize.region->KeyRange.high < resize.pos - 1) {
664                  window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);                  x1 = resize.region->KeyRange.high;
665                  window->draw_line(black, prevx, 0, x, 0);                  x2 = resize.pos - 1;
                 window->draw_line(black, prevx, h1 - 1, x, h1 - 1);  
666              } else {              } else {
667                  int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);                  x1 = resize.pos - 1;
668                  window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);                  x2 = resize.region->KeyRange.high;
669              }              }
670          } else {          } else {
671              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
672                  window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);                  x1 = resize.region->KeyRange.low;
673                  window->draw_line(black, x, 0, prevx, 0);                  x2 = resize.pos;
                 window->draw_line(black, x, h1 - 1, prevx, h1 - 1);  
674              } else {              } else {
675                  int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);                  x1 = resize.pos;
676                  window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);                  x2 = resize.region->KeyRange.low;
677              }              }
678          }          }
679          window->draw_line(black, x, 1, x, h1 - 2);          x1 = key_to_x(x1, w);
680          resize.pos = k;          x2 = key_to_x(x2 + 1, w) + 1;
681            Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
682    
683            update_after_resize();
684    
685            get_window()->invalidate_rect(rect, false);
686      }      }
687  }  }
688    
689  void RegionChooser::motion_move_region(int x, int y)  void RegionChooser::motion_move_region(int x, int y)
690  {  {
691      const int w = width - 1;      const int w = get_width() - 1;
     Glib::RefPtr<Gdk::Window> window = get_window();  
692    
693      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);
694      if (k == move.pos) return;  
695      int new_k;      if (l == region->KeyRange.low) return;
696      bool new_touch_left;      int new_l;
697      bool new_touch_right;      int regionsize = region->KeyRange.high - region->KeyRange.low;
698      int a = 0;      int a = 0;
699      if (k > move.pos) {      if (l > region->KeyRange.low) {
700          for (gig::Region* r = instrument->GetFirstRegion() ; ;          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
              r = instrument->GetNextRegion()) {  
701              if (r != region) {              if (r != region) {
702                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
703    
704                  // gap: from a to b (not inclusive b)                  // gap: from a to b (not inclusive b)
705    
706                  if (region->KeyRange.high + move.pos >= b) {                  if (region->KeyRange.high >= b) {
707                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
708                  } else {                  } else {
709    
710                      if (a > region->KeyRange.low + k) {                      if (a > l) {
711                          // this gap is too far to the right, break                          // this gap is too far to the right, break
712                          break;                          break;
713                      }                      }
714    
715                      int newhigh = std::min(region->KeyRange.high + k, b - 1);                      int newhigh = std::min(l + regionsize, b - 1);
716                      int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);                      int newlo = newhigh - regionsize;
717    
718                      if (newlo >= a) {                      if (newlo >= a) {
719                          // yes it fits - it's a candidate                          // yes it fits - it's a candidate
720                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
721                      }                      }
722                  }                  }
723                  if (!r) break;                  if (!r) break;
# Line 459  void RegionChooser::motion_move_region(i Line 725  void RegionChooser::motion_move_region(i
725              }              }
726          }          }
727      } else {      } else {
728          for (gig::Region* r = instrument->GetFirstRegion() ; ;          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
              r = instrument->GetNextRegion()) {  
729              if (r != region) {              if (r != region) {
730                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
731    
732                  // gap from a to b (not inclusive b)                  // gap from a to b (not inclusive b)
733    
734                  if (region->KeyRange.high + k >= b) {                  if (l + regionsize >= b) {
735                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
736                  } else {                  } else {
737    
738                      if (a > region->KeyRange.low + move.pos) {                      if (a > region->KeyRange.low) {
739                          // this gap is too far to the right, break                          // this gap is too far to the right, break
740                          break;                          break;
741                      }                      }
742    
743                      int newlo = std::max(region->KeyRange.low + k, a);                      int newlo = std::max(l, a);
744                      int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);                      int newhigh = newlo + regionsize;
745    
746                      if (newhigh < b) {                      if (newhigh < b) {
747                          // yes it fits - break as the first one is the best                          // yes it fits - break as the first one is the best
748                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
749                          break;                          break;
750                      }                      }
751                  }                  }
# Line 491  void RegionChooser::motion_move_region(i Line 754  void RegionChooser::motion_move_region(i
754              }              }
755          }          }
756      }      }
757      k = new_k;      if (new_l == region->KeyRange.low) return;
     if (k == move.pos) return;  
   
     Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);  
     int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);  
     x = int(w * (k + region->KeyRange.low) / 128.0 + 0.5);  
     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);  
758    
759          window->draw_line(black, x, 0, std::min(x2, prevx - 1), 0);      int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
760          window->draw_line(black, x, h1 - 1, std::min(x2, prevx - 1), h1 - 1);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
761                                   new_l + regionsize) + 1, w) + 1;
762    
763          window->draw_rectangle(gc, true, x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
764      }      update_after_move(new_l);
765    
766      move.pos = k;      get_window()->invalidate_rect(rect, false);
     move.touch_left = new_touch_left;  
     move.touch_right = new_touch_right;  
767  }  }
768    
769    
# Line 538  bool RegionChooser::on_motion_notify_eve Line 774  bool RegionChooser::on_motion_notify_eve
774      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
775      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
776    
777        // handle virtual MIDI keyboard
778        if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&
779            currentActiveKey > 0 &&
780            event->y >= REGION_BLOCK_HEIGHT &&
781            event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
782        {
783            const int k = x_to_key(event->x, get_width() - 1);
784            if (k != currentActiveKey) {
785                int velocity =
786                    (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
787                    int(float(event->y - REGION_BLOCK_HEIGHT) /
788                        float(KEYBOARD_HEIGHT) * 128.0f) + 1;
789                if (velocity <= 0) velocity = 1;
790                keyboard_key_released_signal.emit(currentActiveKey, velocity);
791                currentActiveKey = k;
792                keyboard_key_hit_signal.emit(k, velocity);
793            }
794        }
795    
796      if (resize.active) {      if (resize.active) {
797          motion_resize_region(x, y);          motion_resize_region(x, y);
798      } else if (move.active) {      } else if (move.active) {
# Line 545  bool RegionChooser::on_motion_notify_eve Line 800  bool RegionChooser::on_motion_notify_eve
800      } else {      } else {
801          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
802              if (!cursor_is_resize) {              if (!cursor_is_resize) {
803    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
804                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
805    #else
806                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
807    #endif
808                  cursor_is_resize = true;                  cursor_is_resize = true;
809              }              }
810          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 558  bool RegionChooser::on_motion_notify_eve Line 817  bool RegionChooser::on_motion_notify_eve
817  }  }
818    
819  bool RegionChooser::is_in_resize_zone(double x, double y) {  bool RegionChooser::is_in_resize_zone(double x, double y) {
820      const int w = width - 1;      const int w = get_width() - 1;
821    
822      if (instrument && y >= 0 && y <= h1) {      if (instrument && y >= 0 && y <= h1) {
823          gig::Region* prev_region = 0;          gig::Region* prev_region = 0;
824          gig::Region* next_region;          gig::Region* next_region;
825          for (gig::Region* r = instrument->GetFirstRegion() ; r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
826              next_region = instrument->GetNextRegion();              next_region = regions.next();
827    
828              int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);              int lo = key_to_x(r->KeyRange.low, w);
829              if (x <= lo - 2) break;              if (x <= lo - 2) break;
830              if (x < lo + 2) {              if (x < lo + 2) {
831                  resize.region = r;                  resize.region = r;
# Line 580  bool RegionChooser::is_in_resize_zone(do Line 839  bool RegionChooser::is_in_resize_zone(do
839                      resize.mode = resize.undecided;                      resize.mode = resize.undecided;
840                      resize.min = prev_region->KeyRange.low + 1;                      resize.min = prev_region->KeyRange.low + 1;
841                      resize.prev_region = prev_region;                      resize.prev_region = prev_region;
842                      return true;                      return resize.min != resize.max;
843                  }                  }
844    
845                  // edit low limit                  // edit low limit
846                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
847                  resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;                  resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
848                  return true;                  return resize.min != resize.max;
849              }              }
850              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
851                  int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);                  int hi = key_to_x(r->KeyRange.high + 1, w);
852                  if (x <= hi - 2) break;                  if (x <= hi - 2) break;
853                  if (x < hi + 2) {                  if (x < hi + 2) {
854                      // edit high limit                      // edit high limit
# Line 598  bool RegionChooser::is_in_resize_zone(do Line 857  bool RegionChooser::is_in_resize_zone(do
857                      resize.mode = resize.moving_high_limit;                      resize.mode = resize.moving_high_limit;
858                      resize.min = r->KeyRange.low + 1;                      resize.min = r->KeyRange.low + 1;
859                      resize.max = next_region ? next_region->KeyRange.low : 128;                      resize.max = next_region ? next_region->KeyRange.low : 128;
860                      return true;                      return resize.min != resize.max;
861                  }                  }
862              }              }
863              prev_region = r;              prev_region = r;
# Line 607  bool RegionChooser::is_in_resize_zone(do Line 866  bool RegionChooser::is_in_resize_zone(do
866      return false;      return false;
867  }  }
868    
869  sigc::signal<void> RegionChooser::signal_region_selected()  sigc::signal<void>& RegionChooser::signal_region_selected()
870  {  {
871      return region_selected;      return region_selected;
872  }  }
873    
874  sigc::signal<void> RegionChooser::signal_instrument_changed()  sigc::signal<void>& RegionChooser::signal_instrument_changed()
875  {  {
876      return instrument_changed;      return instrument_changed;
877  }  }
# Line 620  sigc::signal<void> RegionChooser::signal Line 879  sigc::signal<void> RegionChooser::signal
879  void RegionChooser::show_region_properties()  void RegionChooser::show_region_properties()
880  {  {
881      if (!region) return;      if (!region) return;
882      Gtk::Dialog dialog("Region Properties", true /*modal*/);      Gtk::Dialog dialog(_("Region Properties"), true /*modal*/);
883      // add "Keygroup" checkbox      // add "Keygroup" checkbox
884      Gtk::CheckButton checkBoxKeygroup("Member of a Keygroup (Exclusive Group)");      Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));
885      checkBoxKeygroup.set_active(region->KeyGroup);      checkBoxKeygroup.set_active(region->KeyGroup);
886      dialog.get_vbox()->pack_start(checkBoxKeygroup);      dialog.get_vbox()->pack_start(checkBoxKeygroup);
887      checkBoxKeygroup.show();      checkBoxKeygroup.show();
888      // add "Keygroup" spinbox      // add "Keygroup" spinbox
889      Gtk::Adjustment adjustment(1, 1, pow(2,32));  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
890        Gtk::Adjustment adjustment(1, 1, 999);
891      Gtk::SpinButton spinBox(adjustment);      Gtk::SpinButton spinBox(adjustment);
892    #else
893        Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
894    #endif
895      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
896      dialog.get_vbox()->pack_start(spinBox);      dialog.get_vbox()->pack_start(spinBox);
897      spinBox.show();      spinBox.show();
898      // add OK and CANCEL buttons to the dialog      // add OK and CANCEL buttons to the dialog
899      dialog.add_button(Gtk::Stock::OK, 0);      dialog.add_button(_("_OK"), 0);
900      dialog.add_button(Gtk::Stock::CANCEL, 1);      dialog.add_button(_("_Cancel"), 1);
901      dialog.show_all_children();      dialog.show_all_children();
902      if (!dialog.run()) { // OK selected ...      if (!dialog.run()) { // OK selected ...
903          region->KeyGroup =          region->KeyGroup =
# Line 644  void RegionChooser::show_region_properti Line 907  void RegionChooser::show_region_properti
907    
908  void RegionChooser::add_region()  void RegionChooser::add_region()
909  {  {
910      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;  
     }  
911    
912      region = instrument->AddRegion();      region = instrument->AddRegion();
913      region->KeyRange.low = region->KeyRange.high = new_region_pos;      region->SetKeyRange(new_region_pos, new_region_pos);
914    
915        instrument_struct_changed_signal.emit(instrument);
916        regions.update(instrument);
917    
     instrument->MoveRegion(region, r);  
918      queue_draw();      queue_draw();
919      region_selected();      region_selected();
920        dimensionManager.set_region(region);
921      instrument_changed();      instrument_changed();
922  }  }
923    
924  void RegionChooser::delete_region()  void RegionChooser::delete_region()
925  {  {
926        instrument_struct_to_be_changed_signal.emit(instrument);
927      instrument->DeleteRegion(region);      instrument->DeleteRegion(region);
928        instrument_struct_changed_signal.emit(instrument);
929        regions.update(instrument);
930    
931      region = 0;      region = 0;
932      queue_draw();      queue_draw();
933      region_selected();      region_selected();
934        dimensionManager.set_region(region);
935      instrument_changed();      instrument_changed();
936  }  }
937    
# Line 678  void RegionChooser::on_dimension_manager Line 946  void RegionChooser::on_dimension_manager
946      region_selected();      region_selected();
947      instrument_changed();      instrument_changed();
948  }  }
949    
950    sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_to_be_changed() {
951        return instrument_struct_to_be_changed_signal;
952    }
953    
954    sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_changed() {
955        return instrument_struct_changed_signal;
956    }
957    
958    sigc::signal<void, gig::Region*>& RegionChooser::signal_region_to_be_changed() {
959        return region_to_be_changed_signal;
960    }
961    
962    sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {
963        return region_changed_signal;
964    }
965    
966    sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_hit() {
967        return keyboard_key_hit_signal;
968    }
969    
970    sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_released() {
971        return keyboard_key_released_signal;
972    }

Legend:
Removed from v.1262  
changed lines
  Added in v.2845

  ViewVC Help
Powered by ViewVC