/[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 2845 by persson, Sun Sep 20 10:18:22 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>
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>
29    
30  #include "global.h"  #include "global.h"
31    #include "Settings.h"
32    
33  #define REGION_BLOCK_HEIGHT             20  #define REGION_BLOCK_HEIGHT             30
34  #define KEYBOARD_HEIGHT                 40  #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 55  gig::Region* SortedRegions::first() { Line 54  gig::Region* SortedRegions::first() {
54  }  }
55    
56  gig::Region* SortedRegions::next() {  gig::Region* SortedRegions::next() {
57      region_iterator++;      ++region_iterator;
58      return region_iterator == regions.end() ? 0 : *region_iterator;      return region_iterator == regions.end() ? 0 : *region_iterator;
59  }  }
60    
# Line 81  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 101  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", _("_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 154  RegionChooser::RegionChooser() : Line 153  RegionChooser::RegionChooser() :
153      keyboard_key_released_signal.connect(      keyboard_key_released_signal.connect(
154          sigc::mem_fun(*this, &RegionChooser::on_note_off_event)          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  template<class T> inline std::string ToString(T o) {  void RegionChooser::invalidate_key(int key) {
164      std::stringstream ss;      const int h = KEYBOARD_HEIGHT;
165      ss << o;      const int w = get_width() - 1;
166      return ss.str();      int x1 = key_to_x(key - 0.5, w);
167        int x2 = key_to_x(key + 1.5, w);
168    
169        Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
170        get_window()->invalidate_rect(rect, false);
171  }  }
172    
173  void RegionChooser::on_note_on_event(int key, int velocity) {  void RegionChooser::on_note_on_event(int key, int velocity) {
174      draw_key(key, activeKeyColor);      key_pressed[key] = true;
175        invalidate_key(key);
176      m_VirtKeybVelocityLabel.set_text(ToString(velocity));      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
177  }  }
178    
179  void RegionChooser::on_note_off_event(int key, int velocity) {  void RegionChooser::on_note_off_event(int key, int velocity) {
180      if (is_black_key(key)) {      key_pressed[key] = false;
181          draw_key(key, black);      invalidate_key(key);
     } else {  
         draw_key(key, key >= 21 && key <= 108 ? white : grey1);  
     }  
182      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));      m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
183  }  }
184    
185    
186  #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
187  bool RegionChooser::on_expose_event(GdkEventExpose* e)  bool RegionChooser::on_expose_event(GdkEventExpose* e) {
188  {      double clipx1 = e->area.x;
189      return on_draw(get_window()->create_cairo_context());      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        const Cairo::RefPtr<Cairo::Context>& cr =
194            get_window()->create_cairo_context();
195    #if 0
196  }  }
197  #endif  #endif
198    #else
199  bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
200  {      double clipx1, clipx2, clipy1, clipy2;
201      const int h = KEYBOARD_HEIGHT;      cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
202      const int w = get_width() - 1;  #endif
     const int bh = int(h * 0.55);  
203    
204      cr->save();      cr->save();
205      cr->set_line_width(1);      cr->set_line_width(1);
# Line 204  bool RegionChooser::on_draw(const Cairo: Line 212  bool RegionChooser::on_draw(const Cairo:
212      Gdk::Cairo::set_source_rgba(cr, bg);      Gdk::Cairo::set_source_rgba(cr, bg);
213      cr->paint();      cr->paint();
214    
215        if (clipy2 > h1) {
216            draw_keyboard(cr, clipx1, clipx2);
217        }
218    
219        if (clipy1 < h1 && instrument) {
220            draw_regions(cr, clipx1, clipx2);
221        }
222    
223        cr->restore();
224    
225        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      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
235      cr->rectangle(0.5, h1 + 0.5, w, h - 1);      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
236      cr->stroke();      cr->stroke();
237    
238      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);  
   
239      Gdk::Cairo::set_source_rgba(cr, grey1);      Gdk::Cairo::set_source_rgba(cr, grey1);
240      cr->rectangle(1, h1 + 1, x1 - 1, h - 2);      cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
241      cr->fill();      cr->fill();
242    
243        int x2 = key_to_x(109.5, w);
244      Gdk::Cairo::set_source_rgba(cr, white);      Gdk::Cairo::set_source_rgba(cr, white);
245      cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);      cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
246      cr->fill();      cr->fill();
# Line 224  bool RegionChooser::on_draw(const Cairo: Line 250  bool RegionChooser::on_draw(const Cairo:
250      cr->fill();      cr->fill();
251    
252      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
253      for (int i = 0 ; i < 128 ; i++) {  
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;          int note = (i + 3) % 12;
259          int x = int(w * i / 128.0 + 0.5);          int x = key_to_x(i, w);
260    
261          if (note == 1 || note == 4 || note == 6 ||          if (note == 1 || note == 4 || note == 6 ||
262              note == 9 || note == 11) {              note == 9 || note == 11) {
263              int x2 = int(w * (i + 0.5) / 128.0 + 0.5);              // 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);              cr->move_to(x2 + 0.5, h1 + bh + 0.5);
267              cr->line_to(x2 + 0.5, h1 + h - 1);              cr->line_to(x2 + 0.5, h1 + h - 1);
268              cr->stroke();              cr->stroke();
269    
270              int x3 = int(w * (i + 1) / 128.0 + 0.5);              int x3 = key_to_x(i + 1, w);
271              cr->rectangle(x, h1 + 1, x3 - x + 1, bh);              cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
272              cr->fill();              cr->fill();
273          } else if (note == 3 || note == 8) {          } else if (note == 3 || note == 8) {
274                // C or F: long line to the left
275              cr->move_to(x + 0.5, h1 + 1);              cr->move_to(x + 0.5, h1 + 1);
276              cr->line_to(x + 0.5, h1 + h - 1);              cr->line_to(x + 0.5, h1 + h - 1);
277              cr->stroke();              cr->stroke();
   
             if (note == 3) draw_digit(i);  
278          }          }
279    
280            if (key_pressed[i]) draw_key(cr, i);
281    
282            if (note == 3) draw_digit(cr, i);
283      }      }
284    }
285    
     if (instrument) {  
         int i = 0;  
         gig::Region* next_region;  
         int x3 = -1;  
         for (gig::Region* r = regions.first() ; r ; r = next_region) {  
286    
287              if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);  void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
288              next_region = regions.next();                                   int clip_low, int clip_high) {
289              if (!next_region ||      const int w = get_width() - 1;
290                  r->KeyRange.high + 1 != next_region->KeyRange.low) {  
291                  int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);      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);                  cr->move_to(x3, 0.5);
308                  cr->line_to(x2 + 0.5, 0.5);                  cr->line_to(x2 + 0.5, 0.5);
309                  cr->line_to(x2 + 0.5, h1 - 0.5);                  cr->line_to(x2 + 0.5, h1 - 0.5);
310                  cr->line_to(x3, h1 - 0.5);                  cr->line_to(x3, h1 - 0.5);
311                  cr->stroke();                  cr->stroke();
312    
313                  Gdk::Cairo::set_source_rgba(cr, white);                  Gdk::Cairo::set_source_rgba(cr, region == r ? red : white);
314                  cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);                  cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
315                  cr->fill();                  cr->fill();
316                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
   
                 x3 = -1;  
317              }              }
318              i++;              x3 = -1;
319          }          }
320        }
321    
322          for (gig::Region* r = regions.first() ; r ; r = regions.next()) {      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
323              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();  
         }  
324    
325          if (region) {          if (x < clip_low) continue;
326              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();  
         }  
     }  
327    
328      cr->restore();          cr->move_to(x + 0.5, 1);
329            cr->line_to(x + 0.5, h1 - 1);
330            cr->stroke();
331        }
332    
333      return true;      // 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) {  bool RegionChooser::is_black_key(int key) {
357      const int note = (key + 3) % 12;      const int note = (key + 3) % 12;
358      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
359  }  }
360    
361  void RegionChooser::draw_digit(int key) {  void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
362                                   int key) {
363      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
364      const int w = get_width() - 1;      const int w = get_width() - 1;
365      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(get_pango_context());      Glib::RefPtr<Pango::Layout> layout =
366            Pango::Layout::create(get_pango_context());
367      char buf[30];      char buf[30];
368      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);      sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
369      layout->set_markup(buf);      layout->set_markup(buf);
# Line 312  void RegionChooser::draw_digit(int key) Line 371  void RegionChooser::draw_digit(int key)
371      double text_w = double(rectangle.get_width()) / Pango::SCALE;      double text_w = double(rectangle.get_width()) / Pango::SCALE;
372      double text_h = double(rectangle.get_height()) / Pango::SCALE;      double text_h = double(rectangle.get_height()) / Pango::SCALE;
373      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();  
374      Gdk::Cairo::set_source_rgba(cr, black);      Gdk::Cairo::set_source_rgba(cr, black);
375      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));
376  #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 380  void RegionChooser::draw_digit(int key)
380  #endif  #endif
381  }  }
382    
383  void RegionChooser::draw_key(int key, const Gdk::RGBA& color)  void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
384  {                               int key) {
385      const int h = KEYBOARD_HEIGHT;      const int h = KEYBOARD_HEIGHT;
386      const int w = get_width() - 1;      const int w = get_width() - 1;
387      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
388    
389      Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     Gdk::Cairo::set_source_rgba(cr, color);  
390    
391      int note = (key + 3) % 12;      int note = (key + 3) % 12;
392      int x = int(w * key / 128.0 + 0.5) + 1;      int x = key_to_x(key, w) + 1;
393      int x2 = int(w * (key + 1.5) / 128.0 + 0.5);      int x2 = key_to_x(key + 1.5, w);
394      int x3 = int(w * (key + 1) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
395      int x4 = int(w * (key - 0.5) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
396      int w1 = x3 - x;      int w1 = x3 - x;
397      switch (note) {      switch (note) {
398      case 0: case 5: case 10:      case 0: case 5: case 10:
# Line 355  void RegionChooser::draw_key(int key, co Line 412  void RegionChooser::draw_key(int key, co
412          cr->fill();          cr->fill();
413          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
414          cr->fill();          cr->fill();
         if (note == 3) draw_digit(key);  
415          break;          break;
416      default:      default:
417          cr->rectangle(x, h1 + 1, w1, bh - 1);          cr->rectangle(x, h1 + 1, w1, bh - 1);
418          cr->fill();          cr->fill();
419          break;          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)
# Line 376  void RegionChooser::set_instrument(gig:: Line 433  void RegionChooser::set_instrument(gig::
433    
434  bool RegionChooser::on_button_release_event(GdkEventButton* event)  bool RegionChooser::on_button_release_event(GdkEventButton* event)
435  {  {
436      const int k = int(event->x / (get_width() - 1) * 128.0);      const int k = x_to_key(event->x, get_width() - 1);
437    
438      // handle-note off on virtual keyboard      // handle-note off on virtual keyboard
439      if (event->type == GDK_BUTTON_RELEASE) {      if (event->type == GDK_BUTTON_RELEASE) {
# Line 406  bool RegionChooser::on_button_release_ev Line 463  bool RegionChooser::on_button_release_ev
463  #endif  #endif
464          resize.active = false;          resize.active = false;
465    
         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);  
             }  
         }  
   
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;
# Line 442  bool RegionChooser::on_button_release_ev Line 475  bool RegionChooser::on_button_release_ev
475  #endif  #endif
476          move.active = false;          move.active = false;
477    
         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);  
         }  
   
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  #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));
# Line 465  bool RegionChooser::on_button_release_ev Line 487  bool RegionChooser::on_button_release_ev
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      const int k = int(event->x / (get_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) {      if (event->type == GDK_BUTTON_PRESS) {
539          if (event->y >= REGION_BLOCK_HEIGHT) {          if (event->y >= REGION_BLOCK_HEIGHT) {
# Line 480  bool RegionChooser::on_button_press_even Line 544  bool RegionChooser::on_button_press_even
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;      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);
# Line 539  bool RegionChooser::on_button_press_even Line 611  bool RegionChooser::on_button_press_even
611                                                        event->time);                                                        event->time);
612  #endif  #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 549  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 = regions.first() ; r ; r = next_region) {  
         next_region = regions.next();  
   
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 = get_width() - 1;      const int w = get_width() - 1;
# Line 575  void RegionChooser::motion_resize_region Line 644  void RegionChooser::motion_resize_region
644      else if (k > resize.max) k = resize.max;      else if (k > resize.max) k = resize.max;
645    
646      if (k != resize.pos) {      if (k != resize.pos) {
         Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
         cr->set_line_width(1);  
   
647          if (resize.mode == resize.undecided) {          if (resize.mode == resize.undecided) {
648              if (k < resize.pos) {              if (k < resize.pos) {
649                  // edit high limit of prev_region                  // edit high limit of prev_region
# Line 590  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          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);  
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                  Gdk::Cairo::set_source_rgba(cr, white);                  x1 = resize.region->KeyRange.high;
665                  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();  
666              } else {              } else {
667                  int xx = (resize.pos == resize.max &&                  x1 = resize.pos - 1;
668                            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();  
669              }              }
670          } else {          } else {
671              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
672                  Gdk::Cairo::set_source_rgba(cr, white);                  x1 = resize.region->KeyRange.low;
673                  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();  
674              } else {              } else {
675                  int xx = (resize.pos == resize.min &&                  x1 = resize.pos;
676                            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();  
677              }              }
678          }          }
679          Gdk::Cairo::set_source_rgba(cr, black);          x1 = key_to_x(x1, w);
680          cr->move_to(x + 0.5, 1);          x2 = key_to_x(x2 + 1, w) + 1;
681          cr->line_to(x + 0.5, h1 - 1);          Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
682          cr->stroke();  
683          resize.pos = k;          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 = get_width() - 1;      const int w = get_width() - 1;
     Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();  
     cr->set_line_width(1);  
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 = regions.first() ; ; r = regions.next()) {          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
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 696  void RegionChooser::motion_move_region(i Line 731  void RegionChooser::motion_move_region(i
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 721  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;  
   
 #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();  
758    
759          Gdk::Cairo::set_source_rgba(cr, black);      int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
760          cr->move_to(x, 0.5);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
761          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();  
762    
763          Gdk::Cairo::set_source_rgba(cr, red);      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
764          cr->rectangle(x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);      update_after_move(new_l);
         cr->fill();  
     }  
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 804  bool RegionChooser::on_motion_notify_eve Line 780  bool RegionChooser::on_motion_notify_eve
780          event->y >= REGION_BLOCK_HEIGHT &&          event->y >= REGION_BLOCK_HEIGHT &&
781          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)          event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
782      {      {
783          const int k = int(event->x / (get_width() - 1) * 128.0);          const int k = x_to_key(event->x, get_width() - 1);
784          if (k != currentActiveKey) {          if (k != currentActiveKey) {
785              int velocity =              int velocity =
786                  (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 825  bool RegionChooser::is_in_resize_zone(do
825          for (gig::Region* r = regions.first(); r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
826              next_region = regions.next();              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 872  bool RegionChooser::is_in_resize_zone(do Line 848  bool RegionChooser::is_in_resize_zone(do
848                  return resize.min != resize.max;                  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 920  void RegionChooser::show_region_properti Line 896  void RegionChooser::show_region_properti
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 =

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

  ViewVC Help
Powered by ViewVC