/[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 2151 by persson, Sun Nov 21 12:38:41 2010 UTC revision 2536 by schoenebeck, Mon Apr 21 17:49:17 2014 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2010 Andreas Persson   * Copyright (C) 2006-2014 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 20  Line 20 
20  #include "regionchooser.h"  #include "regionchooser.h"
21    
22  #include <algorithm>  #include <algorithm>
 #include <cmath>  
 #include <sstream>  
23    
24  #include <cairomm/context.h>  #include <cairomm/context.h>
25  #include <gdkmm/general.h>  #include <gdkmm/general.h>
# Line 32  Line 30 
30    
31  #include "global.h"  #include "global.h"
32    
33  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 10) || GTKMM_MAJOR_VERSION < 2  #define REGION_BLOCK_HEIGHT             20
34    #define KEYBOARD_HEIGHT                 40
 #define create_cairo_context()                                          \  
     gobj() ? Cairo::RefPtr<Cairo::Context>(                             \  
         new Cairo::Context(gdk_cairo_create(get_window()->gobj()))) :   \  
     Cairo::RefPtr<Cairo::Context>()  
   
 namespace Gdk {  
     namespace Cairo {  
         void set_source_color(const ::Cairo::RefPtr< ::Cairo::Context >& cr,  
                               const Gdk::Color& color) {  
             gdk_cairo_set_source_color(cr->cobj(),  
                                        const_cast<GdkColor*>(color.gobj()));  
         }  
     }  
 }  
 #endif  
   
 #define REGION_BLOCK_HEIGHT             20  
 #define KEYBOARD_HEIGHT                 40  
35    
36  void SortedRegions::update(gig::Instrument* instrument) {  void SortedRegions::update(gig::Instrument* instrument) {
37      // Usually, the regions in a gig file are ordered after their key      // Usually, the regions in a gig file are ordered after their key
# Line 81  gig::Region* SortedRegions::next() { Line 61  gig::Region* SortedRegions::next() {
61    
62    
63  RegionChooser::RegionChooser() :  RegionChooser::RegionChooser() :
64        activeKeyColor("red"),
65        red("#8070ff"),
66        grey1("grey69"),
67        white("white"),
68        black("black"),
69      m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),      m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),
70      currentActiveKey(-1)      currentActiveKey(-1)
71  {  {
72      red = Gdk::Color("#8070ff");      set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT);
     grey1 = Gdk::Color("#b0b0b0");  
     activeKeyColor = Gdk::Color("#ff0000");  
     white = Gdk::Color("#ffffff");  
     black = Gdk::Color("#000000");  
73    
74      instrument = 0;      instrument = 0;
75      region = 0;      region = 0;
# Line 99  RegionChooser::RegionChooser() : Line 80  RegionChooser::RegionChooser() :
80    
81      // properties of the virtual keyboard      // properties of the virtual keyboard
82      {      {
83          const char* choices[] = { _("normal"), _("chord"), NULL };          const char* choices[] = { _("normal"), _("chord"), 0 };
84          static const virt_keyboard_mode_t values[] = {          static const virt_keyboard_mode_t values[] = {
85              VIRT_KEYBOARD_MODE_NORMAL,              VIRT_KEYBOARD_MODE_NORMAL,
86              VIRT_KEYBOARD_MODE_CHORD              VIRT_KEYBOARD_MODE_CHORD
# Line 119  RegionChooser::RegionChooser() : Line 100  RegionChooser::RegionChooser() :
100      m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);      m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);
101      m_VirtKeybPropsBox.set_spacing(10);      m_VirtKeybPropsBox.set_spacing(10);
102      m_VirtKeybPropsBox.show();      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",
# Line 172  RegionChooser::RegionChooser() : Line 154  RegionChooser::RegionChooser() :
154      keyboard_key_released_signal.connect(      keyboard_key_released_signal.connect(
155          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)
156      );      );
157        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."));
158  }  }
159    
160  RegionChooser::~RegionChooser()  RegionChooser::~RegionChooser()
161  {  {
162  }  }
163    
164  template<class T> inline std::string ToString(T o) {  void RegionChooser::invalidate_key(int key) {
165      std::stringstream ss;      const int h = KEYBOARD_HEIGHT;
166      ss << o;      const int w = get_width() - 1;
167      return ss.str();      int x1 = key_to_x(key - 0.5, w);
168        int x2 = key_to_x(key + 1.5, w);
169    
170        Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
171        get_window()->invalidate_rect(rect, false);
172  }  }
173    
174  void RegionChooser::on_note_on_event(int key, int velocity) {  void RegionChooser::on_note_on_event(int key, int velocity) {
175      draw_key(key, activeKeyColor);      key_pressed[key] = true;
176        invalidate_key(key);
177      m_VirtKeybVelocityLabel.set_text(ToString(velocity));      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
178  }  }
179    
180  void RegionChooser::on_note_off_event(int key, int velocity) {  void RegionChooser::on_note_off_event(int key, int velocity) {
181      if (is_black_key(key)) {      key_pressed[key] = false;
182          draw_key(key, black);      invalidate_key(key);
     } else {  
         draw_key(key, key >= 21 && key <= 108 ? white : grey1);  
     }  
183      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
184  }  }
185    
186    
187  bool RegionChooser::on_expose_event(GdkEventExpose* event)  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
188  {  bool RegionChooser::on_expose_event(GdkEventExpose* e) {
189      Glib::RefPtr<Gdk::Window> window = get_window();      double clipx1 = e->area.x;
190      if (window) {      double clipx2 = e->area.x + e->area.width;
191          Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();      double clipy1 = e->area.y;
192          if (event) {      double clipy2 = e->area.y + e->area.height;
193              cr->rectangle(event->area.x, event->area.y,  
194                            event->area.width, event->area.height);      const Cairo::RefPtr<Cairo::Context>& cr =
195              cr->clip();          get_window()->create_cairo_context();
196          }  #if 0
197          const int h = KEYBOARD_HEIGHT;  }
198          const int w = get_width() - 1;  #endif
199          const int bh = int(h * 0.55);  #else
200    bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
201          cr->save();      double clipx1, clipx2, clipy1, clipy2;
202          cr->set_line_width(1);      cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
203    #endif
         const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);  
         Gdk::Cairo::set_source_color(cr, bg);  
         cr->paint();  
204    
205          Gdk::Cairo::set_source_color(cr, black);      cr->save();
206          cr->rectangle(0.5, h1 + 0.5, w, h - 1);      cr->set_line_width(1);
         cr->stroke();  
207    
208          int x1 = int(w * 20.5 / 128.0 + 0.5);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
209          int x2 = int(w * 109.5 / 128.0 + 0.5);      const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
210    #else
211        const Gdk::RGBA bg = get_style_context()->get_background_color();
212    #endif
213        Gdk::Cairo::set_source_rgba(cr, bg);
214        cr->paint();
215    
216          Gdk::Cairo::set_source_color(cr, grey1);      if (clipy2 > h1) {
217          cr->rectangle(1, h1 + 1, x1 - 1, h - 2);          draw_keyboard(cr, clipx1, clipx2);
218          cr->fill();      }
219    
220          Gdk::Cairo::set_source_color(cr, white);      if (clipy1 < h1 && instrument) {
221          cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);          draw_regions(cr, clipx1, clipx2);
222          cr->fill();      }
223    
224          Gdk::Cairo::set_source_color(cr, grey1);      cr->restore();
         cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);  
         cr->fill();  
225    
226          Gdk::Cairo::set_source_color(cr, black);      return true;
227          for (int i = 0 ; i < 128 ; i++) {  }
             int note = (i + 3) % 12;  
             int x = int(w * i / 128.0 + 0.5);  
   
             if (note == 1 || note == 4 || note == 6 ||  
                 note == 9 || note == 11) {  
                 int x2 = int(w * (i + 0.5) / 128.0 + 0.5);  
                 cr->move_to(x2 + 0.5, h1 + bh + 0.5);  
                 cr->line_to(x2 + 0.5, h1 + h - 1);  
                 cr->stroke();  
228    
229                  int x3 = int(w * (i + 1) / 128.0 + 0.5);  void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
230                  cr->rectangle(x, h1 + 1, x3 - x + 1, bh);                                    int clip_low, int clip_high) {
231                  cr->fill();      const int h = KEYBOARD_HEIGHT;
232              } else if (note == 3 || note == 8) {      const int w = get_width() - 1;
233                  cr->move_to(x + 0.5, h1 + 1);      const int bh = int(h * 0.55);
                 cr->line_to(x + 0.5, h1 + h - 1);  
                 cr->stroke();  
234    
235                  if (note == 3) draw_digit(i);      Gdk::Cairo::set_source_rgba(cr, black);
236              }      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
237        cr->stroke();
238    
239        int x1 = key_to_x(20.5, w);
240        Gdk::Cairo::set_source_rgba(cr, grey1);
241        cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
242        cr->fill();
243    
244        int x2 = key_to_x(109.5, w);
245        Gdk::Cairo::set_source_rgba(cr, white);
246        cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
247        cr->fill();
248    
249        Gdk::Cairo::set_source_rgba(cr, grey1);
250        cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);
251        cr->fill();
252    
253        Gdk::Cairo::set_source_rgba(cr, black);
254    
255        int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
256        int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
257    
258        for (int i = clipkey1 ; i < clipkey2 ; i++) {
259            int note = (i + 3) % 12;
260            int x = key_to_x(i, w);
261    
262            if (note == 1 || note == 4 || note == 6 ||
263                note == 9 || note == 11) {
264                // black key: short line in the middle, with a rectangle
265                // on top
266                int x2 = key_to_x(i + 0.5, w);
267                cr->move_to(x2 + 0.5, h1 + bh + 0.5);
268                cr->line_to(x2 + 0.5, h1 + h - 1);
269                cr->stroke();
270    
271                int x3 = key_to_x(i + 1, w);
272                cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
273                cr->fill();
274            } else if (note == 3 || note == 8) {
275                // C or F: long line to the left
276                cr->move_to(x + 0.5, h1 + 1);
277                cr->line_to(x + 0.5, h1 + h - 1);
278                cr->stroke();
279          }          }
280    
281          if (instrument) {          if (key_pressed[i]) draw_key(cr, i);
282              int i = 0;  
283              gig::Region* next_region;          if (note == 3) draw_digit(cr, i);
284              int x3 = -1;      }
285              for (gig::Region* r = regions.first() ; r ; r = next_region) {  }
   
                 if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);  
                 next_region = regions.next();  
                 if (!next_region ||  
                     r->KeyRange.high + 1 != next_region->KeyRange.low) {  
                     int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);  
                     cr->move_to(x3, 0.5);  
                     cr->line_to(x2 + 0.5, 0.5);  
                     cr->line_to(x2 + 0.5, h1 - 0.5);  
                     cr->line_to(x3, h1 - 0.5);  
                     cr->stroke();  
   
                     Gdk::Cairo::set_source_color(cr, white);  
                     cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);  
                     cr->fill();  
                     Gdk::Cairo::set_source_color(cr, black);  
286    
                     x3 = -1;  
                 }  
                 i++;  
             }  
287    
288              for (gig::Region* r = regions.first() ; r ; r = regions.next()) {  void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
289                  int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);                                   int clip_low, int clip_high) {
290                  cr->move_to(x + 0.5, 1);      const int w = get_width() - 1;
291                  cr->line_to(x + 0.5, h1 - 1);  
292        Gdk::Cairo::set_source_rgba(cr, black);
293        gig::Region* next_region;
294        int x3 = -1;
295        for (gig::Region* r = regions.first() ; r ; r = next_region) {
296            next_region = regions.next();
297    
298            if (x3 < 0) {
299                x3 = key_to_x(r->KeyRange.low, w);
300                if (x3 >= clip_high) break;
301            }
302            if (!next_region ||
303                r->KeyRange.high + 1 != next_region->KeyRange.low ||
304                r == region || next_region == region) {
305    
306                int x2 = key_to_x(r->KeyRange.high + 1, w);
307                if (x2 >= clip_low) {
308                    cr->move_to(x3, 0.5);
309                    cr->line_to(x2 + 0.5, 0.5);
310                    cr->line_to(x2 + 0.5, h1 - 0.5);
311                    cr->line_to(x3, h1 - 0.5);
312                  cr->stroke();                  cr->stroke();
             }  
313    
314              if (region) {                  Gdk::Cairo::set_source_rgba(cr, region == r ? red : white);
315                  int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);                  cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
                 int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);  
                 Gdk::Cairo::set_source_color(cr, red);  
                 cr->rectangle(x1 + 1, 1, x2 - x1 - 1, h1 - 2);  
316                  cr->fill();                  cr->fill();
317                    Gdk::Cairo::set_source_rgba(cr, black);
318              }              }
319                x3 = -1;
320          }          }
   
         cr->restore();  
321      }      }
322    
323      return true;      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
324  }          int x = key_to_x(r->KeyRange.low, w);
325    
326            if (x < clip_low) continue;
327            if (x >= clip_high) break;
328    
329  void RegionChooser::on_size_request(GtkRequisition* requisition)          cr->move_to(x + 0.5, 1);
330  {          cr->line_to(x + 0.5, h1 - 1);
331      *requisition = GtkRequisition();          cr->stroke();
332      requisition->height = KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT;      }
333      requisition->width = 500;  
334        // if there is no region yet, show the user some hint text that he may
335        // right click on this area to create a new region
336        if (!regions.first()) {
337            Glib::RefPtr<Pango::Context> context = get_pango_context();
338            Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
339            layout->set_alignment(Pango::ALIGN_CENTER);
340            layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
341            layout->set_width(get_width() * Pango::SCALE);
342            Gdk::Cairo::set_source_rgba(cr, red);
343    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
344            pango_cairo_show_layout(cr->cobj(), layout->gobj());
345    #else
346            layout->show_in_cairo_context(cr);
347    #endif
348        }
349  }  }
350    
351  bool RegionChooser::is_black_key(int key) {  bool RegionChooser::is_black_key(int key) {
# Line 325  bool RegionChooser::is_black_key(int key Line 353  bool RegionChooser::is_black_key(int key
353      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
354  }  }
355    
356  void RegionChooser::draw_digit(int key) {  void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
357                                   int key) {
358      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
359      const int w = get_width() - 1;      const int w = get_width() - 1;
360      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(get_pango_context());      Glib::RefPtr<Pango::Layout> layout =
361            Pango::Layout::create(get_pango_context());
362      char buf[30];      char buf[30];
363      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
364      layout->set_markup(buf);      layout->set_markup(buf);
# Line 336  void RegionChooser::draw_digit(int key) Line 366  void RegionChooser::draw_digit(int key)
366      double text_w = double(rectangle.get_width()) / Pango::SCALE;      double text_w = double(rectangle.get_width()) / Pango::SCALE;
367      double text_h = double(rectangle.get_height()) / Pango::SCALE;      double text_h = double(rectangle.get_height()) / Pango::SCALE;
368      double x = w * (key + 0.75) / 128.0;      double x = w * (key + 0.75) / 128.0;
369      Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();      Gdk::Cairo::set_source_rgba(cr, black);
     Gdk::Cairo::set_source_color(cr, black);  
370      cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));      cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));
371  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
372      pango_cairo_show_layout(cr->cobj(), layout->gobj());      pango_cairo_show_layout(cr->cobj(), layout->gobj());
# Line 346  void RegionChooser::draw_digit(int key) Line 375  void RegionChooser::draw_digit(int key)
375  #endif  #endif
376  }  }
377    
378  void RegionChooser::draw_key(int key, const Gdk::Color& color)  void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
379  {                               int key) {
380      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
381      const int w = get_width() - 1;      const int w = get_width() - 1;
382      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
383    
384      Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     Gdk::Cairo::set_source_color(cr, color);  
385    
386      int note = (key + 3) % 12;      int note = (key + 3) % 12;
387      int x = int(w * key / 128.0 + 0.5) + 1;      int x = key_to_x(key, w) + 1;
388      int x2 = int(w * (key + 1.5) / 128.0 + 0.5);      int x2 = key_to_x(key + 1.5, w);
389      int x3 = int(w * (key + 1) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
390      int x4 = int(w * (key - 0.5) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
391      int w1 = x3 - x;      int w1 = x3 - x;
392      switch (note) {      switch (note) {
393      case 0: case 5: case 10:      case 0: case 5: case 10:
# Line 379  void RegionChooser::draw_key(int key, co Line 407  void RegionChooser::draw_key(int key, co
407          cr->fill();          cr->fill();
408          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
409          cr->fill();          cr->fill();
         if (note == 3) draw_digit(key);  
410          break;          break;
411      default:      default:
412          cr->rectangle(x, h1 + 1, w1, bh - 1);          cr->rectangle(x, h1 + 1, w1, bh - 1);
413          cr->fill();          cr->fill();
414          break;          break;
415      }      }
416        Gdk::Cairo::set_source_rgba(cr, black);
417  }  }
418    
419  void RegionChooser::set_instrument(gig::Instrument* instrument)  void RegionChooser::set_instrument(gig::Instrument* instrument)
# Line 400  void RegionChooser::set_instrument(gig:: Line 428  void RegionChooser::set_instrument(gig::
428    
429  bool RegionChooser::on_button_release_event(GdkEventButton* event)  bool RegionChooser::on_button_release_event(GdkEventButton* event)
430  {  {
431      const int k = int(event->x / (get_width() - 1) * 128.0);      const int k = x_to_key(event->x, get_width() - 1);
432    
433      // handle-note off on virtual keyboard      // handle-note off on virtual keyboard
434      if (event->type == GDK_BUTTON_RELEASE) {      if (event->type == GDK_BUTTON_RELEASE) {
# Line 423  bool RegionChooser::on_button_release_ev Line 451  bool RegionChooser::on_button_release_ev
451      }      }
452    
453      if (resize.active) {      if (resize.active) {
454    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
455          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
456    #else
457            Glib::wrap(event->device, true)->ungrab(event->time);
458    #endif
459          resize.active = false;          resize.active = false;
460    
         if (resize.mode == resize.moving_high_limit) {  
             if (resize.region->KeyRange.high != resize.pos - 1) {  
                 instrument_struct_to_be_changed_signal.emit(instrument);  
                 resize.region->SetKeyRange(  
                     resize.region->KeyRange.low, // low  
                     resize.pos - 1 // high  
                 );  
                 regions.update(instrument);  
                 instrument_changed.emit();  
                 instrument_struct_changed_signal.emit(instrument);  
             }  
         } else if (resize.mode == resize.moving_low_limit) {  
             if (resize.region->KeyRange.low != resize.pos) {  
                 instrument_struct_to_be_changed_signal.emit(instrument);  
                 resize.region->SetKeyRange(  
                     resize.pos, // low  
                     resize.region->KeyRange.high // high  
                 );  
                 regions.update(instrument);  
                 instrument_changed.emit();  
                 instrument_struct_changed_signal.emit(instrument);  
             }  
         }  
   
461          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
462              get_window()->set_cursor();              get_window()->set_cursor();
463              cursor_is_resize = false;              cursor_is_resize = false;
464          }          }
465      } else if (move.active) {      } else if (move.active) {
466    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
467          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
468    #else
469            Glib::wrap(event->device, true)->ungrab(event->time);
470    #endif
471          move.active = false;          move.active = false;
472    
473          if (move.pos) {          if (is_in_resize_zone(event->x, event->y)) {
474    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
475                get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
476    #else
477                get_window()->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
478    #endif
479                cursor_is_resize = true;
480            }
481        }
482        return true;
483    }
484    
485    void RegionChooser::update_after_resize()
486    {
487        if (resize.mode == resize.moving_high_limit) {
488            if (resize.region->KeyRange.high != resize.pos - 1) {
489              instrument_struct_to_be_changed_signal.emit(instrument);              instrument_struct_to_be_changed_signal.emit(instrument);
490              region->SetKeyRange(              resize.region->SetKeyRange(resize.region->KeyRange.low,
491                  region->KeyRange.low  + move.pos,                                         resize.pos - 1);
                 region->KeyRange.high + move.pos  
             );  
492              regions.update(instrument);              regions.update(instrument);
493              instrument_changed.emit();              instrument_changed.emit();
494              instrument_struct_changed_signal.emit(instrument);              instrument_struct_changed_signal.emit(instrument);
495          }          }
496        } else if (resize.mode == resize.moving_low_limit) {
497          if (is_in_resize_zone(event->x, event->y)) {          if (resize.region->KeyRange.low != resize.pos) {
498              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));              instrument_struct_to_be_changed_signal.emit(instrument);
499              cursor_is_resize = true;              resize.region->SetKeyRange(resize.pos,
500                                           resize.region->KeyRange.high);
501                regions.update(instrument);
502                instrument_changed.emit();
503                instrument_struct_changed_signal.emit(instrument);
504          }          }
505      }      }
506      return true;  }
507    
508    void RegionChooser::update_after_move(int pos)
509    {
510        instrument_struct_to_be_changed_signal.emit(instrument);
511        region->SetKeyRange(pos, pos + region->KeyRange.high -
512                            region->KeyRange.low);
513        regions.update(instrument);
514        instrument_changed.emit();
515        instrument_struct_changed_signal.emit(instrument);
516  }  }
517    
518  bool RegionChooser::on_button_press_event(GdkEventButton* event)  bool RegionChooser::on_button_press_event(GdkEventButton* event)
519  {  {
520      if (!instrument) return true;      if (!instrument) return true;
521    
522      const int k = int(event->x / (get_width() - 1) * 128.0);      const int w = get_width() - 1;
523        const int k = x_to_key(event->x, w);
524    
525      if (event->type == GDK_BUTTON_PRESS) {      if (event->type == GDK_BUTTON_PRESS) {
526          if (event->y >= REGION_BLOCK_HEIGHT) {          if (event->y >= REGION_BLOCK_HEIGHT) {
# Line 507  bool RegionChooser::on_button_press_even Line 546  bool RegionChooser::on_button_press_even
546          }          }
547      } else {      } else {
548          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
549    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
550              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
551                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
552                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
553                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
554                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW), event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
555                                           event->time);
556    #else
557                Glib::wrap(event->device, true)->grab(get_window(),
558                                                      Gdk::OWNERSHIP_NONE,
559                                                      false,
560                                                      Gdk::BUTTON_RELEASE_MASK |
561                                                      Gdk::POINTER_MOTION_MASK |
562                                                      Gdk::POINTER_MOTION_HINT_MASK,
563                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
564                                                      event->time);
565    #endif
566              resize.active = true;              resize.active = true;
567          } else {          } else {
568              gig::Region* r = get_region(k);              gig::Region* r = get_region(k);
# Line 521  bool RegionChooser::on_button_press_even Line 572  bool RegionChooser::on_button_press_even
572                  region_selected();                  region_selected();
573                  dimensionManager.set_region(region);                  dimensionManager.set_region(region);
574    
575    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
576                  get_window()->pointer_grab(false,                  get_window()->pointer_grab(false,
577                                             Gdk::BUTTON_RELEASE_MASK |                                             Gdk::BUTTON_RELEASE_MASK |
578                                             Gdk::POINTER_MOTION_MASK |                                             Gdk::POINTER_MOTION_MASK |
579                                             Gdk::POINTER_MOTION_HINT_MASK,                                             Gdk::POINTER_MOTION_HINT_MASK,
580                                             Gdk::Cursor(Gdk::FLEUR), event->time);                                             Gdk::Cursor(Gdk::FLEUR),
581                                               event->time);
582    #else
583                    Glib::wrap(event->device, true)->grab(get_window(),
584                                                          Gdk::OWNERSHIP_NONE,
585                                                          false,
586                                                          Gdk::BUTTON_RELEASE_MASK |
587                                                          Gdk::POINTER_MOTION_MASK |
588                                                          Gdk::POINTER_MOTION_HINT_MASK,
589                                                          Gdk::Cursor::create(Gdk::FLEUR),
590                                                          event->time);
591    #endif
592                  move.active = true;                  move.active = true;
593                  move.from_x = event->x;                  move.offset = event->x - key_to_x(region->KeyRange.low, w);
                 move.pos = 0;  
594              }              }
595          }          }
596      }      }
# Line 537  bool RegionChooser::on_button_press_even Line 599  bool RegionChooser::on_button_press_even
599    
600  gig::Region* RegionChooser::get_region(int key)  gig::Region* RegionChooser::get_region(int key)
601  {  {
602      gig::Region* prev_region = 0;      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
     gig::Region* next_region;  
     for (gig::Region* r = regions.first() ; r ; r = next_region) {  
         next_region = regions.next();  
   
603          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
604          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;  
605      }      }
606      return 0;      return 0;
607  }  }
# Line 563  void RegionChooser::motion_resize_region Line 616  void RegionChooser::motion_resize_region
616      else if (k > resize.max) k = resize.max;      else if (k > resize.max) k = resize.max;
617    
618      if (k != resize.pos) {      if (k != resize.pos) {
         Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
         cr->set_line_width(1);  
   
619          if (resize.mode == resize.undecided) {          if (resize.mode == resize.undecided) {
620              if (k < resize.pos) {              if (k < resize.pos) {
621                  // edit high limit of prev_region                  // edit high limit of prev_region
# Line 578  void RegionChooser::motion_resize_region Line 628  void RegionChooser::motion_resize_region
628                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
629              }              }
630          }          }
631          const Gdk::Color white =          resize.pos = k;
             region == resize.region ? red : get_style()->get_white();  
         const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);  
   
         int prevx = int(w * resize.pos / 128.0 + 0.5);  
         x = int(w * k / 128.0 + 0.5);  
632    
633            int x1, x2;
634          if (resize.mode == resize.moving_high_limit) {          if (resize.mode == resize.moving_high_limit) {
635              if (k > resize.pos) {              if (resize.region->KeyRange.high < resize.pos - 1) {
636                  Gdk::Cairo::set_source_color(cr, white);                  x1 = resize.region->KeyRange.high;
637                  cr->rectangle(prevx, 1, x - prevx, h1 - 2);                  x2 = resize.pos - 1;
                 cr->fill();  
   
                 Gdk::Cairo::set_source_color(cr, black);  
                 cr->move_to(prevx, 0.5);  
                 cr->line_to(x + 1, 0.5);  
                 cr->move_to(prevx, h1 - 0.5);  
                 cr->line_to(x + 1, h1 - 0.5);  
                 cr->stroke();  
638              } else {              } else {
639                  int xx = (resize.pos == resize.max &&                  x1 = resize.pos - 1;
640                            resize.max != 128) ? 1 : 0;                  x2 = resize.region->KeyRange.high;
                 Gdk::Cairo::set_source_color(cr, bg);  
                 cr->rectangle(x + 1, 0, prevx - x - xx, h1);  
                 cr->fill();  
641              }              }
642          } else {          } else {
643              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
644                  Gdk::Cairo::set_source_color(cr, white);                  x1 = resize.region->KeyRange.low;
645                  cr->rectangle(x + 1, 1, prevx - x, h1 - 2);                  x2 = resize.pos;
                 cr->fill();  
   
                 Gdk::Cairo::set_source_color(cr, black);  
                 cr->move_to(x, 0.5);  
                 cr->line_to(prevx, 0.5);  
                 cr->move_to(x, h1 - 0.5);  
                 cr->line_to(prevx, h1 - 0.5);  
                 cr->stroke();  
646              } else {              } else {
647                  int xx = (resize.pos == resize.min &&                  x1 = resize.pos;
648                            resize.min != 0) ? 1 : 0;                  x2 = resize.region->KeyRange.low;
                 Gdk::Cairo::set_source_color(cr, bg);  
                 cr->rectangle(prevx + xx, 0, x - prevx - xx, h1);  
                 cr->fill();  
649              }              }
650          }          }
651          Gdk::Cairo::set_source_color(cr, black);          x1 = key_to_x(x1, w);
652          cr->move_to(x + 0.5, 1);          x2 = key_to_x(x2 + 1, w) + 1;
653          cr->line_to(x + 0.5, h1 - 1);          Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
654          cr->stroke();  
655          resize.pos = k;          update_after_resize();
656    
657            get_window()->invalidate_rect(rect, false);
658      }      }
659  }  }
660    
661  void RegionChooser::motion_move_region(int x, int y)  void RegionChooser::motion_move_region(int x, int y)
662  {  {
663      const int w = get_width() - 1;      const int w = get_width() - 1;
     Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
     cr->set_line_width(1);  
664    
665      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);
666      if (k == move.pos) return;  
667      int new_k;      if (l == region->KeyRange.low) return;
668      bool new_touch_left;      int new_l;
669      bool new_touch_right;      int regionsize = region->KeyRange.high - region->KeyRange.low;
670      int a = 0;      int a = 0;
671      if (k > move.pos) {      if (l > region->KeyRange.low) {
672          for (gig::Region* r = regions.first() ; ; r = regions.next()) {          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
673              if (r != region) {              if (r != region) {
674                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
675    
676                  // gap: from a to b (not inclusive b)                  // gap: from a to b (not inclusive b)
677    
678                  if (region->KeyRange.high + move.pos >= b) {                  if (region->KeyRange.high >= b) {
679                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
680                  } else {                  } else {
681    
682                      if (a > region->KeyRange.low + k) {                      if (a > l) {
683                          // this gap is too far to the right, break                          // this gap is too far to the right, break
684                          break;                          break;
685                      }                      }
686    
687                      int newhigh = std::min(region->KeyRange.high + k, b - 1);                      int newhigh = std::min(l + regionsize, b - 1);
688                      int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);                      int newlo = newhigh - regionsize;
689    
690                      if (newlo >= a) {                      if (newlo >= a) {
691                          // yes it fits - it's a candidate                          // yes it fits - it's a candidate
692                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
693                      }                      }
694                  }                  }
695                  if (!r) break;                  if (!r) break;
# Line 681  void RegionChooser::motion_move_region(i Line 703  void RegionChooser::motion_move_region(i
703    
704                  // gap from a to b (not inclusive b)                  // gap from a to b (not inclusive b)
705    
706                  if (region->KeyRange.high + k >= b) {                  if (l + regionsize >= 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 + move.pos) {                      if (a > region->KeyRange.low) {
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 newlo = std::max(region->KeyRange.low + k, a);                      int newlo = std::max(l, a);
716                      int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);                      int newhigh = newlo + regionsize;
717    
718                      if (newhigh < b) {                      if (newhigh < b) {
719                          // yes it fits - break as the first one is the best                          // yes it fits - break as the first one is the best
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                          break;                          break;
722                      }                      }
723                  }                  }
# Line 706  void RegionChooser::motion_move_region(i Line 726  void RegionChooser::motion_move_region(i
726              }              }
727          }          }
728      }      }
729      k = new_k;      if (new_l == region->KeyRange.low) return;
     if (k == move.pos) return;  
730    
731      const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);      int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
732      int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
733      x = int(w * (k + region->KeyRange.low) / 128.0 + 0.5);                                 new_l + regionsize) + 1, w) + 1;
     int prevx2 = int(w * (move.pos + region->KeyRange.high + 1) / 128.0 + 0.5);  
     int x2 = int(w * (k + region->KeyRange.high + 1) / 128.0 + 0.5);  
     const Gdk::Color black = get_style()->get_black();  
734    
735      if (!new_touch_left) {      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
736          Gdk::Cairo::set_source_color(cr, black);      update_after_move(new_l);
         cr->move_to(x + 0.5, 1);  
         cr->line_to(x + 0.5, h1 - 1);  
         cr->stroke();  
     }  
     if (!new_touch_right) {  
         Gdk::Cairo::set_source_color(cr, black);  
         cr->move_to(x2 + 0.5, 1);  
         cr->line_to(x2 + 0.5, h1 - 1);  
         cr->stroke();  
     }  
   
     if (k > move.pos) {  
         Gdk::Cairo::set_source_color(cr, bg);  
         cr->rectangle(prevx + (move.touch_left ? 1 : 0), 0,  
                       std::min(x, prevx2 + 1 - (move.touch_right ? 1 : 0)) -  
                       (prevx + (move.touch_left ? 1 : 0)), h1);  
         cr->fill();  
   
         Gdk::Cairo::set_source_color(cr, black);  
         cr->move_to(std::max(x, prevx2 + 1), 0.5);  
         cr->line_to(x2 + 1, 0.5);  
         cr->move_to(std::max(x, prevx2 + 1), h1 - 0.5);  
         cr->line_to(x2 + 1, h1 - 0.5);  
         cr->stroke();  
   
         Gdk::Cairo::set_source_color(cr, red);  
         cr->rectangle(std::max(x + 1, prevx2), 1,  
                       x2 - std::max(x + 1, prevx2), h1 - 2);  
         cr->fill();  
     } else {  
         Gdk::Cairo::set_source_color(cr, bg);  
         cr->rectangle(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);  
         cr->fill();  
737    
738          Gdk::Cairo::set_source_color(cr, black);      get_window()->invalidate_rect(rect, false);
         cr->move_to(x, 0.5);  
         cr->line_to(std::min(x2, prevx - 1) + 1, 0.5);  
         cr->move_to(x, h1 - 0.5);  
         cr->line_to(std::min(x2, prevx - 1) + 1, h1 - 0.5);  
         cr->stroke();  
   
         Gdk::Cairo::set_source_color(cr, red);  
         cr->rectangle(x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);  
         cr->fill();  
     }  
   
     move.pos = k;  
     move.touch_left = new_touch_left;  
     move.touch_right = new_touch_right;  
739  }  }
740    
741    
# Line 785  bool RegionChooser::on_motion_notify_eve Line 752  bool RegionChooser::on_motion_notify_eve
752          event->y >= REGION_BLOCK_HEIGHT &&          event->y >= REGION_BLOCK_HEIGHT &&
753          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
754      {      {
755          const int k = int(event->x / (get_width() - 1) * 128.0);          const int k = x_to_key(event->x, get_width() - 1);
756          if (k != currentActiveKey) {          if (k != currentActiveKey) {
757              int velocity =              int velocity =
758                  (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :                  (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
# Line 805  bool RegionChooser::on_motion_notify_eve Line 772  bool RegionChooser::on_motion_notify_eve
772      } else {      } else {
773          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
774              if (!cursor_is_resize) {              if (!cursor_is_resize) {
775    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
776                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
777    #else
778                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
779    #endif
780                  cursor_is_resize = true;                  cursor_is_resize = true;
781              }              }
782          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 826  bool RegionChooser::is_in_resize_zone(do Line 797  bool RegionChooser::is_in_resize_zone(do
797          for (gig::Region* r = regions.first(); r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
798              next_region = regions.next();              next_region = regions.next();
799    
800              int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);              int lo = key_to_x(r->KeyRange.low, w);
801              if (x <= lo - 2) break;              if (x <= lo - 2) break;
802              if (x < lo + 2) {              if (x < lo + 2) {
803                  resize.region = r;                  resize.region = r;
# Line 849  bool RegionChooser::is_in_resize_zone(do Line 820  bool RegionChooser::is_in_resize_zone(do
820                  return resize.min != resize.max;                  return resize.min != resize.max;
821              }              }
822              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
823                  int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);                  int hi = key_to_x(r->KeyRange.high + 1, w);
824                  if (x <= hi - 2) break;                  if (x <= hi - 2) break;
825                  if (x < hi + 2) {                  if (x < hi + 2) {
826                      // edit high limit                      // edit high limit
# Line 887  void RegionChooser::show_region_properti Line 858  void RegionChooser::show_region_properti
858      dialog.get_vbox()->pack_start(checkBoxKeygroup);      dialog.get_vbox()->pack_start(checkBoxKeygroup);
859      checkBoxKeygroup.show();      checkBoxKeygroup.show();
860      // add "Keygroup" spinbox      // add "Keygroup" spinbox
861      Gtk::Adjustment adjustment(1, 1, pow(2,32));  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
862        Gtk::Adjustment adjustment(1, 1, 999);
863      Gtk::SpinButton spinBox(adjustment);      Gtk::SpinButton spinBox(adjustment);
864    #else
865        Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
866    #endif
867      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
868      dialog.get_vbox()->pack_start(spinBox);      dialog.get_vbox()->pack_start(spinBox);
869      spinBox.show();      spinBox.show();

Legend:
Removed from v.2151  
changed lines
  Added in v.2536

  ViewVC Help
Powered by ViewVC