/[svn]/gigedit/trunk/src/gigedit/regionchooser.cpp
ViewVC logotype

Diff of /gigedit/trunk/src/gigedit/regionchooser.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1261  
changed lines
  Added in v.2442

  ViewVC Help
Powered by ViewVC