/[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 2169 by persson, Sun Mar 6 07:51:04 2011 UTC revision 2773 by schoenebeck, Fri Jun 12 17:57:52 2015 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2011 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 20  Line 20 
20  #include "regionchooser.h"  #include "regionchooser.h"
21    
22  #include <algorithm>  #include <algorithm>
 #include <sstream>  
23    
24  #include <cairomm/context.h>  #include <cairomm/context.h>
25  #include <gdkmm/general.h>  #include <gdkmm/general.h>
# Line 30  Line 29 
29  #include <gtkmm/dialog.h>  #include <gtkmm/dialog.h>
30    
31  #include "global.h"  #include "global.h"
32    #include "Settings.h"
33    
34  #define REGION_BLOCK_HEIGHT             20  #define REGION_BLOCK_HEIGHT             30
35  #define KEYBOARD_HEIGHT                 40  #define KEYBOARD_HEIGHT                 40
36    
37  void SortedRegions::update(gig::Instrument* instrument) {  void SortedRegions::update(gig::Instrument* instrument) {
38      // 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  RegionChooser::RegionChooser() : Line 81  RegionChooser::RegionChooser() :
81    
82      // properties of the virtual keyboard      // properties of the virtual keyboard
83      {      {
84          const char* choices[] = { _("normal"), _("chord"), NULL };          const char* choices[] = { _("normal"), _("chord"), 0 };
85          static const virt_keyboard_mode_t values[] = {          static const virt_keyboard_mode_t values[] = {
86              VIRT_KEYBOARD_MODE_NORMAL,              VIRT_KEYBOARD_MODE_NORMAL,
87              VIRT_KEYBOARD_MODE_CHORD              VIRT_KEYBOARD_MODE_CHORD
# Line 101  RegionChooser::RegionChooser() : Line 101  RegionChooser::RegionChooser() :
101      m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);      m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);
102      m_VirtKeybPropsBox.set_spacing(10);      m_VirtKeybPropsBox.set_spacing(10);
103      m_VirtKeybPropsBox.show();      m_VirtKeybPropsBox.show();
104        for (int i = 0 ; i < 128 ; i++) key_pressed[i] = false;
105    
106      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
107      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties",
# Line 154  RegionChooser::RegionChooser() : Line 155  RegionChooser::RegionChooser() :
155      keyboard_key_released_signal.connect(      keyboard_key_released_signal.connect(
156          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)
157      );      );
158        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."));
159  }  }
160    
161  RegionChooser::~RegionChooser()  RegionChooser::~RegionChooser()
162  {  {
163  }  }
164    
165  template<class T> inline std::string ToString(T o) {  void RegionChooser::invalidate_key(int key) {
166      std::stringstream ss;      const int h = KEYBOARD_HEIGHT;
167      ss << o;      const int w = get_width() - 1;
168      return ss.str();      int x1 = key_to_x(key - 0.5, w);
169        int x2 = key_to_x(key + 1.5, w);
170    
171        Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
172        get_window()->invalidate_rect(rect, false);
173  }  }
174    
175  void RegionChooser::on_note_on_event(int key, int velocity) {  void RegionChooser::on_note_on_event(int key, int velocity) {
176      draw_key(key, activeKeyColor);      key_pressed[key] = true;
177        invalidate_key(key);
178      m_VirtKeybVelocityLabel.set_text(ToString(velocity));      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
179  }  }
180    
181  void RegionChooser::on_note_off_event(int key, int velocity) {  void RegionChooser::on_note_off_event(int key, int velocity) {
182      if (is_black_key(key)) {      key_pressed[key] = false;
183          draw_key(key, black);      invalidate_key(key);
     } else {  
         draw_key(key, key >= 21 && key <= 108 ? white : grey1);  
     }  
184      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
185  }  }
186    
187    
188  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
189  bool RegionChooser::on_expose_event(GdkEventExpose* e)  bool RegionChooser::on_expose_event(GdkEventExpose* e) {
190  {      double clipx1 = e->area.x;
191      return on_draw(get_window()->create_cairo_context());      double clipx2 = e->area.x + e->area.width;
192        double clipy1 = e->area.y;
193        double clipy2 = e->area.y + e->area.height;
194    
195        const Cairo::RefPtr<Cairo::Context>& cr =
196            get_window()->create_cairo_context();
197    #if 0
198  }  }
199  #endif  #endif
200    #else
201  bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
202  {      double clipx1, clipx2, clipy1, clipy2;
203      const int h = KEYBOARD_HEIGHT;      cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
204      const int w = get_width() - 1;  #endif
     const int bh = int(h * 0.55);  
205    
206      cr->save();      cr->save();
207      cr->set_line_width(1);      cr->set_line_width(1);
# Line 204  bool RegionChooser::on_draw(const Cairo: Line 214  bool RegionChooser::on_draw(const Cairo:
214      Gdk::Cairo::set_source_rgba(cr, bg);      Gdk::Cairo::set_source_rgba(cr, bg);
215      cr->paint();      cr->paint();
216    
217        if (clipy2 > h1) {
218            draw_keyboard(cr, clipx1, clipx2);
219        }
220    
221        if (clipy1 < h1 && instrument) {
222            draw_regions(cr, clipx1, clipx2);
223        }
224    
225        cr->restore();
226    
227        return true;
228    }
229    
230    void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
231                                      int clip_low, int clip_high) {
232        const int h = KEYBOARD_HEIGHT;
233        const int w = get_width() - 1;
234        const int bh = int(h * 0.55);
235    
236      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
237      cr->rectangle(0.5, h1 + 0.5, w, h - 1);      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
238      cr->stroke();      cr->stroke();
239    
240      int x1 = int(w * 20.5 / 128.0 + 0.5);      int x1 = key_to_x(20.5, w);
     int x2 = int(w * 109.5 / 128.0 + 0.5);  
   
241      Gdk::Cairo::set_source_rgba(cr, grey1);      Gdk::Cairo::set_source_rgba(cr, grey1);
242      cr->rectangle(1, h1 + 1, x1 - 1, h - 2);      cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
243      cr->fill();      cr->fill();
244    
245        int x2 = key_to_x(109.5, w);
246      Gdk::Cairo::set_source_rgba(cr, white);      Gdk::Cairo::set_source_rgba(cr, white);
247      cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);      cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
248      cr->fill();      cr->fill();
# Line 224  bool RegionChooser::on_draw(const Cairo: Line 252  bool RegionChooser::on_draw(const Cairo:
252      cr->fill();      cr->fill();
253    
254      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
255      for (int i = 0 ; i < 128 ; i++) {  
256        int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
257        int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128);
258    
259        for (int i = clipkey1 ; i < clipkey2 ; i++) {
260          int note = (i + 3) % 12;          int note = (i + 3) % 12;
261          int x = int(w * i / 128.0 + 0.5);          int x = key_to_x(i, w);
262    
263          if (note == 1 || note == 4 || note == 6 ||          if (note == 1 || note == 4 || note == 6 ||
264              note == 9 || note == 11) {              note == 9 || note == 11) {
265              int x2 = int(w * (i + 0.5) / 128.0 + 0.5);              // black key: short line in the middle, with a rectangle
266                // on top
267                int x2 = key_to_x(i + 0.5, w);
268              cr->move_to(x2 + 0.5, h1 + bh + 0.5);              cr->move_to(x2 + 0.5, h1 + bh + 0.5);
269              cr->line_to(x2 + 0.5, h1 + h - 1);              cr->line_to(x2 + 0.5, h1 + h - 1);
270              cr->stroke();              cr->stroke();
271    
272              int x3 = int(w * (i + 1) / 128.0 + 0.5);              int x3 = key_to_x(i + 1, w);
273              cr->rectangle(x, h1 + 1, x3 - x + 1, bh);              cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
274              cr->fill();              cr->fill();
275          } else if (note == 3 || note == 8) {          } else if (note == 3 || note == 8) {
276                // C or F: long line to the left
277              cr->move_to(x + 0.5, h1 + 1);              cr->move_to(x + 0.5, h1 + 1);
278              cr->line_to(x + 0.5, h1 + h - 1);              cr->line_to(x + 0.5, h1 + h - 1);
279              cr->stroke();              cr->stroke();
   
             if (note == 3) draw_digit(i);  
280          }          }
281    
282            if (key_pressed[i]) draw_key(cr, i);
283    
284            if (note == 3) draw_digit(cr, i);
285      }      }
286    }
287    
     if (instrument) {  
         int i = 0;  
         gig::Region* next_region;  
         int x3 = -1;  
         for (gig::Region* r = regions.first() ; r ; r = next_region) {  
288    
289              if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);  void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
290              next_region = regions.next();                                   int clip_low, int clip_high) {
291              if (!next_region ||      const int w = get_width() - 1;
292                  r->KeyRange.high + 1 != next_region->KeyRange.low) {  
293                  int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);      Gdk::Cairo::set_source_rgba(cr, black);
294        gig::Region* next_region;
295        int x3 = -1;
296        for (gig::Region* r = regions.first() ; r ; r = next_region) {
297            next_region = regions.next();
298    
299            if (x3 < 0) {
300                x3 = key_to_x(r->KeyRange.low, w);
301                if (x3 >= clip_high) break;
302            }
303            if (!next_region ||
304                r->KeyRange.high + 1 != next_region->KeyRange.low ||
305                r == region || next_region == region) {
306    
307                int x2 = key_to_x(r->KeyRange.high + 1, w);
308                if (x2 >= clip_low) {
309                  cr->move_to(x3, 0.5);                  cr->move_to(x3, 0.5);
310                  cr->line_to(x2 + 0.5, 0.5);                  cr->line_to(x2 + 0.5, 0.5);
311                  cr->line_to(x2 + 0.5, h1 - 0.5);                  cr->line_to(x2 + 0.5, h1 - 0.5);
312                  cr->line_to(x3, h1 - 0.5);                  cr->line_to(x3, h1 - 0.5);
313                  cr->stroke();                  cr->stroke();
314    
315                  Gdk::Cairo::set_source_rgba(cr, white);                  Gdk::Cairo::set_source_rgba(cr, region == r ? red : white);
316                  cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);                  cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
317                  cr->fill();                  cr->fill();
318                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
   
                 x3 = -1;  
319              }              }
320              i++;              x3 = -1;
321          }          }
322        }
323    
324          for (gig::Region* r = regions.first() ; r ; r = regions.next()) {      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
325              int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);          int x = key_to_x(r->KeyRange.low, w);
             cr->move_to(x + 0.5, 1);  
             cr->line_to(x + 0.5, h1 - 1);  
             cr->stroke();  
         }  
326    
327          if (region) {          if (x < clip_low) continue;
328              int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);          if (x >= clip_high) break;
             int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);  
             Gdk::Cairo::set_source_rgba(cr, red);  
             cr->rectangle(x1 + 1, 1, x2 - x1 - 1, h1 - 2);  
             cr->fill();  
         }  
     }  
329    
330      cr->restore();          cr->move_to(x + 0.5, 1);
331            cr->line_to(x + 0.5, h1 - 1);
332            cr->stroke();
333        }
334    
335      return true;      // if there is no region yet, show the user some hint text that he may
336        // right click on this area to create a new region
337        if (!regions.first()) {
338            Glib::RefPtr<Pango::Context> context = get_pango_context();
339            Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
340            layout->set_alignment(Pango::ALIGN_CENTER);
341            layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
342            layout->set_width(get_width() * Pango::SCALE);
343            //layout->set_height(get_height() * Pango::SCALE);
344            layout->set_spacing(10);
345            Gdk::Cairo::set_source_rgba(cr, red);        
346            // get the text dimensions
347            Pango::Rectangle rect = layout->get_logical_extents();
348            int text_width, text_height;
349            layout->get_pixel_size(text_width, text_height);
350            cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
351    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
352            pango_cairo_show_layout(cr->cobj(), layout->gobj());
353    #else
354            layout->show_in_cairo_context(cr);
355    #endif
356        }
357  }  }
358    
   
359  bool RegionChooser::is_black_key(int key) {  bool RegionChooser::is_black_key(int key) {
360      const int note = (key + 3) % 12;      const int note = (key + 3) % 12;
361      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
362  }  }
363    
364  void RegionChooser::draw_digit(int key) {  void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
365                                   int key) {
366      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
367      const int w = get_width() - 1;      const int w = get_width() - 1;
368      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(get_pango_context());      Glib::RefPtr<Pango::Layout> layout =
369            Pango::Layout::create(get_pango_context());
370      char buf[30];      char buf[30];
371      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
372      layout->set_markup(buf);      layout->set_markup(buf);
# Line 312  void RegionChooser::draw_digit(int key) Line 374  void RegionChooser::draw_digit(int key)
374      double text_w = double(rectangle.get_width()) / Pango::SCALE;      double text_w = double(rectangle.get_width()) / Pango::SCALE;
375      double text_h = double(rectangle.get_height()) / Pango::SCALE;      double text_h = double(rectangle.get_height()) / Pango::SCALE;
376      double x = w * (key + 0.75) / 128.0;      double x = w * (key + 0.75) / 128.0;
     Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
377      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
378      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));
379  #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
# Line 322  void RegionChooser::draw_digit(int key) Line 383  void RegionChooser::draw_digit(int key)
383  #endif  #endif
384  }  }
385    
386  void RegionChooser::draw_key(int key, const Gdk::RGBA& color)  void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
387  {                               int key) {
388      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
389      const int w = get_width() - 1;      const int w = get_width() - 1;
390      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
391    
392      Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     Gdk::Cairo::set_source_rgba(cr, color);  
393    
394      int note = (key + 3) % 12;      int note = (key + 3) % 12;
395      int x = int(w * key / 128.0 + 0.5) + 1;      int x = key_to_x(key, w) + 1;
396      int x2 = int(w * (key + 1.5) / 128.0 + 0.5);      int x2 = key_to_x(key + 1.5, w);
397      int x3 = int(w * (key + 1) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
398      int x4 = int(w * (key - 0.5) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
399      int w1 = x3 - x;      int w1 = x3 - x;
400      switch (note) {      switch (note) {
401      case 0: case 5: case 10:      case 0: case 5: case 10:
# Line 355  void RegionChooser::draw_key(int key, co Line 415  void RegionChooser::draw_key(int key, co
415          cr->fill();          cr->fill();
416          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
417          cr->fill();          cr->fill();
         if (note == 3) draw_digit(key);  
418          break;          break;
419      default:      default:
420          cr->rectangle(x, h1 + 1, w1, bh - 1);          cr->rectangle(x, h1 + 1, w1, bh - 1);
421          cr->fill();          cr->fill();
422          break;          break;
423      }      }
424        Gdk::Cairo::set_source_rgba(cr, black);
425  }  }
426    
427  void RegionChooser::set_instrument(gig::Instrument* instrument)  void RegionChooser::set_instrument(gig::Instrument* instrument)
# Line 376  void RegionChooser::set_instrument(gig:: Line 436  void RegionChooser::set_instrument(gig::
436    
437  bool RegionChooser::on_button_release_event(GdkEventButton* event)  bool RegionChooser::on_button_release_event(GdkEventButton* event)
438  {  {
439      const int k = int(event->x / (get_width() - 1) * 128.0);      const int k = x_to_key(event->x, get_width() - 1);
440    
441      // handle-note off on virtual keyboard      // handle-note off on virtual keyboard
442      if (event->type == GDK_BUTTON_RELEASE) {      if (event->type == GDK_BUTTON_RELEASE) {
# Line 406  bool RegionChooser::on_button_release_ev Line 466  bool RegionChooser::on_button_release_ev
466  #endif  #endif
467          resize.active = false;          resize.active = false;
468    
         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);  
             }  
         }  
   
469          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
470              get_window()->set_cursor();              get_window()->set_cursor();
471              cursor_is_resize = false;              cursor_is_resize = false;
# Line 442  bool RegionChooser::on_button_release_ev Line 478  bool RegionChooser::on_button_release_ev
478  #endif  #endif
479          move.active = false;          move.active = false;
480    
         if (move.pos) {  
             instrument_struct_to_be_changed_signal.emit(instrument);  
             region->SetKeyRange(  
                 region->KeyRange.low  + move.pos,  
                 region->KeyRange.high + move.pos  
             );  
             regions.update(instrument);  
             instrument_changed.emit();  
             instrument_struct_changed_signal.emit(instrument);  
         }  
   
481          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
482  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
483              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
# Line 465  bool RegionChooser::on_button_release_ev Line 490  bool RegionChooser::on_button_release_ev
490      return true;      return true;
491  }  }
492    
493    void RegionChooser::update_after_resize()
494    {
495        if (resize.mode == resize.moving_high_limit) {
496            if (resize.region->KeyRange.high != resize.pos - 1) {
497                instrument_struct_to_be_changed_signal.emit(instrument);
498                resize.region->SetKeyRange(resize.region->KeyRange.low,
499                                           resize.pos - 1);
500                regions.update(instrument);
501                instrument_changed.emit();
502                instrument_struct_changed_signal.emit(instrument);
503            }
504        } else if (resize.mode == resize.moving_low_limit) {
505            if (resize.region->KeyRange.low != resize.pos) {
506                instrument_struct_to_be_changed_signal.emit(instrument);
507                resize.region->SetKeyRange(resize.pos,
508                                           resize.region->KeyRange.high);
509                regions.update(instrument);
510                instrument_changed.emit();
511                instrument_struct_changed_signal.emit(instrument);
512            }
513        }
514    }
515    
516    void RegionChooser::update_after_move(int pos)
517    {
518        instrument_struct_to_be_changed_signal.emit(instrument);
519        const int range = region->KeyRange.high - region->KeyRange.low;
520        const int diff  = pos - int(region->KeyRange.low);
521        region->SetKeyRange(pos, pos + range);
522        if (Settings::singleton()->moveRootNoteWithRegionMoved) {
523            for (int i = 0; i < 256; ++i) {
524                gig::DimensionRegion* dimrgn = region->pDimensionRegions[i];
525                if (!dimrgn || !dimrgn->pSample || !dimrgn->PitchTrack) continue;
526                dimrgn->UnityNote += diff;
527            }
528        }
529        regions.update(instrument);
530        instrument_changed.emit();
531        instrument_struct_changed_signal.emit(instrument);
532    }
533    
534  bool RegionChooser::on_button_press_event(GdkEventButton* event)  bool RegionChooser::on_button_press_event(GdkEventButton* event)
535  {  {
536      if (!instrument) return true;      if (!instrument) return true;
537    
538      const int k = int(event->x / (get_width() - 1) * 128.0);      const int w = get_width() - 1;
539        const int k = x_to_key(event->x, w);
540    
541      if (event->type == GDK_BUTTON_PRESS) {      if (event->type == GDK_BUTTON_PRESS) {
542          if (event->y >= REGION_BLOCK_HEIGHT) {          if (event->y >= REGION_BLOCK_HEIGHT) {
# Line 480  bool RegionChooser::on_button_press_even Line 547  bool RegionChooser::on_button_press_even
547          }          }
548      }      }
549    
550        // left mouse button double click
551        if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
552            if (event->y < REGION_BLOCK_HEIGHT) {
553                // show dimension manager dialog for this region
554                manage_dimensions();
555            }
556        }
557    
558      if (event->y >= REGION_BLOCK_HEIGHT) return true;      if (event->y >= REGION_BLOCK_HEIGHT) return true;
559      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
560          gig::Region* r = get_region(k);          gig::Region* r = get_region(k);
# Line 539  bool RegionChooser::on_button_press_even Line 614  bool RegionChooser::on_button_press_even
614                                                        event->time);                                                        event->time);
615  #endif  #endif
616                  move.active = true;                  move.active = true;
617                  move.from_x = event->x;                  move.offset = event->x - key_to_x(region->KeyRange.low, w);
                 move.pos = 0;  
618              }              }
619          }          }
620      }      }
# Line 549  bool RegionChooser::on_button_press_even Line 623  bool RegionChooser::on_button_press_even
623    
624  gig::Region* RegionChooser::get_region(int key)  gig::Region* RegionChooser::get_region(int key)
625  {  {
626      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();  
   
627          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
628          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;  
629      }      }
630      return 0;      return 0;
631  }  }
632    
633    void RegionChooser::set_region(gig::Region* region) {
634        this->region = region;
635        queue_draw();
636        region_selected();
637        dimensionManager.set_region(region);
638    }
639    
640  void RegionChooser::motion_resize_region(int x, int y)  void RegionChooser::motion_resize_region(int x, int y)
641  {  {
642      const int w = get_width() - 1;      const int w = get_width() - 1;
# Line 575  void RegionChooser::motion_resize_region Line 647  void RegionChooser::motion_resize_region
647      else if (k > resize.max) k = resize.max;      else if (k > resize.max) k = resize.max;
648    
649      if (k != resize.pos) {      if (k != resize.pos) {
         Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
         cr->set_line_width(1);  
   
650          if (resize.mode == resize.undecided) {          if (resize.mode == resize.undecided) {
651              if (k < resize.pos) {              if (k < resize.pos) {
652                  // edit high limit of prev_region                  // edit high limit of prev_region
# Line 590  void RegionChooser::motion_resize_region Line 659  void RegionChooser::motion_resize_region
659                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
660              }              }
661          }          }
662          const Gdk::RGBA white = region == resize.region ? red : this->white;          resize.pos = k;
 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  
         const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);  
 #else  
         const Gdk::RGBA bg = get_style_context()->get_background_color();  
 #endif  
   
         int prevx = int(w * resize.pos / 128.0 + 0.5);  
         x = int(w * k / 128.0 + 0.5);  
663    
664            int x1, x2;
665          if (resize.mode == resize.moving_high_limit) {          if (resize.mode == resize.moving_high_limit) {
666              if (k > resize.pos) {              if (resize.region->KeyRange.high < resize.pos - 1) {
667                  Gdk::Cairo::set_source_rgba(cr, white);                  x1 = resize.region->KeyRange.high;
668                  cr->rectangle(prevx, 1, x - prevx, h1 - 2);                  x2 = resize.pos - 1;
                 cr->fill();  
   
                 Gdk::Cairo::set_source_rgba(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();  
669              } else {              } else {
670                  int xx = (resize.pos == resize.max &&                  x1 = resize.pos - 1;
671                            resize.max != 128) ? 1 : 0;                  x2 = resize.region->KeyRange.high;
                 Gdk::Cairo::set_source_rgba(cr, bg);  
                 cr->rectangle(x + 1, 0, prevx - x - xx, h1);  
                 cr->fill();  
672              }              }
673          } else {          } else {
674              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
675                  Gdk::Cairo::set_source_rgba(cr, white);                  x1 = resize.region->KeyRange.low;
676                  cr->rectangle(x + 1, 1, prevx - x, h1 - 2);                  x2 = resize.pos;
                 cr->fill();  
   
                 Gdk::Cairo::set_source_rgba(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();  
677              } else {              } else {
678                  int xx = (resize.pos == resize.min &&                  x1 = resize.pos;
679                            resize.min != 0) ? 1 : 0;                  x2 = resize.region->KeyRange.low;
                 Gdk::Cairo::set_source_rgba(cr, bg);  
                 cr->rectangle(prevx + xx, 0, x - prevx - xx, h1);  
                 cr->fill();  
680              }              }
681          }          }
682          Gdk::Cairo::set_source_rgba(cr, black);          x1 = key_to_x(x1, w);
683          cr->move_to(x + 0.5, 1);          x2 = key_to_x(x2 + 1, w) + 1;
684          cr->line_to(x + 0.5, h1 - 1);          Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
685          cr->stroke();  
686          resize.pos = k;          update_after_resize();
687    
688            get_window()->invalidate_rect(rect, false);
689      }      }
690  }  }
691    
692  void RegionChooser::motion_move_region(int x, int y)  void RegionChooser::motion_move_region(int x, int y)
693  {  {
694      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);  
695    
696      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);
697      if (k == move.pos) return;  
698      int new_k;      if (l == region->KeyRange.low) return;
699      bool new_touch_left;      int new_l;
700      bool new_touch_right;      int regionsize = region->KeyRange.high - region->KeyRange.low;
701      int a = 0;      int a = 0;
702      if (k > move.pos) {      if (l > region->KeyRange.low) {
703          for (gig::Region* r = regions.first() ; ; r = regions.next()) {          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
704              if (r != region) {              if (r != region) {
705                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
706    
707                  // gap: from a to b (not inclusive b)                  // gap: from a to b (not inclusive b)
708    
709                  if (region->KeyRange.high + move.pos >= b) {                  if (region->KeyRange.high >= b) {
710                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
711                  } else {                  } else {
712    
713                      if (a > region->KeyRange.low + k) {                      if (a > l) {
714                          // this gap is too far to the right, break                          // this gap is too far to the right, break
715                          break;                          break;
716                      }                      }
717    
718                      int newhigh = std::min(region->KeyRange.high + k, b - 1);                      int newhigh = std::min(l + regionsize, b - 1);
719                      int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);                      int newlo = newhigh - regionsize;
720    
721                      if (newlo >= a) {                      if (newlo >= a) {
722                          // yes it fits - it's a candidate                          // yes it fits - it's a candidate
723                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
724                      }                      }
725                  }                  }
726                  if (!r) break;                  if (!r) break;
# Line 696  void RegionChooser::motion_move_region(i Line 734  void RegionChooser::motion_move_region(i
734    
735                  // gap from a to b (not inclusive b)                  // gap from a to b (not inclusive b)
736    
737                  if (region->KeyRange.high + k >= b) {                  if (l + regionsize >= b) {
738                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
739                  } else {                  } else {
740    
741                      if (a > region->KeyRange.low + move.pos) {                      if (a > region->KeyRange.low) {
742                          // this gap is too far to the right, break                          // this gap is too far to the right, break
743                          break;                          break;
744                      }                      }
745    
746                      int newlo = std::max(region->KeyRange.low + k, a);                      int newlo = std::max(l, a);
747                      int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);                      int newhigh = newlo + regionsize;
748    
749                      if (newhigh < b) {                      if (newhigh < b) {
750                          // yes it fits - break as the first one is the best                          // yes it fits - break as the first one is the best
751                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
752                          break;                          break;
753                      }                      }
754                  }                  }
# Line 721  void RegionChooser::motion_move_region(i Line 757  void RegionChooser::motion_move_region(i
757              }              }
758          }          }
759      }      }
760      k = new_k;      if (new_l == region->KeyRange.low) return;
     if (k == move.pos) return;  
   
 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  
     const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);  
 #else  
     const Gdk::RGBA bg = get_style_context()->get_background_color();  
 #endif  
   
     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);  
   
     if (!new_touch_left) {  
         Gdk::Cairo::set_source_rgba(cr, black);  
         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_rgba(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_rgba(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_rgba(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_rgba(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_rgba(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();  
761    
762          Gdk::Cairo::set_source_rgba(cr, black);      int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
763          cr->move_to(x, 0.5);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
764          cr->line_to(std::min(x2, prevx - 1) + 1, 0.5);                                 new_l + regionsize) + 1, w) + 1;
         cr->move_to(x, h1 - 0.5);  
         cr->line_to(std::min(x2, prevx - 1) + 1, h1 - 0.5);  
         cr->stroke();  
765    
766          Gdk::Cairo::set_source_rgba(cr, red);      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
767          cr->rectangle(x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);      update_after_move(new_l);
         cr->fill();  
     }  
768    
769      move.pos = k;      get_window()->invalidate_rect(rect, false);
     move.touch_left = new_touch_left;  
     move.touch_right = new_touch_right;  
770  }  }
771    
772    
# Line 804  bool RegionChooser::on_motion_notify_eve Line 783  bool RegionChooser::on_motion_notify_eve
783          event->y >= REGION_BLOCK_HEIGHT &&          event->y >= REGION_BLOCK_HEIGHT &&
784          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
785      {      {
786          const int k = int(event->x / (get_width() - 1) * 128.0);          const int k = x_to_key(event->x, get_width() - 1);
787          if (k != currentActiveKey) {          if (k != currentActiveKey) {
788              int velocity =              int velocity =
789                  (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :                  (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
# Line 849  bool RegionChooser::is_in_resize_zone(do Line 828  bool RegionChooser::is_in_resize_zone(do
828          for (gig::Region* r = regions.first(); r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
829              next_region = regions.next();              next_region = regions.next();
830    
831              int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);              int lo = key_to_x(r->KeyRange.low, w);
832              if (x <= lo - 2) break;              if (x <= lo - 2) break;
833              if (x < lo + 2) {              if (x < lo + 2) {
834                  resize.region = r;                  resize.region = r;
# Line 872  bool RegionChooser::is_in_resize_zone(do Line 851  bool RegionChooser::is_in_resize_zone(do
851                  return resize.min != resize.max;                  return resize.min != resize.max;
852              }              }
853              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
854                  int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);                  int hi = key_to_x(r->KeyRange.high + 1, w);
855                  if (x <= hi - 2) break;                  if (x <= hi - 2) break;
856                  if (x < hi + 2) {                  if (x < hi + 2) {
857                      // edit high limit                      // edit high limit

Legend:
Removed from v.2169  
changed lines
  Added in v.2773

  ViewVC Help
Powered by ViewVC