/[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 3226 by schoenebeck, Fri May 26 22:15:06 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006, 2007 Andreas Persson   * Copyright (C) 2006-2017 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 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include "global.h"
21  #include "regionchooser.h"  #include "regionchooser.h"
22    
23    #include <algorithm>
24    #include <assert.h>
25    
26    #include <cairomm/context.h>
27    #include <gdkmm/general.h>
28  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
29  #include <gtkmm/stock.h>  #include <gtkmm/stock.h>
30    #include <gdkmm/pixbuf.h>
31  #include <gtkmm/spinbutton.h>  #include <gtkmm/spinbutton.h>
32  #include <gtkmm/dialog.h>  #include <gtkmm/dialog.h>
 #include <libintl.h>  
 #include <math.h>  
33    
34  #define _(String) gettext(String)  #include "Settings.h"
35    #include "gfx/builtinpix.h"
36    
37    #define REGION_BLOCK_HEIGHT             30
38    #define KEYBOARD_HEIGHT                 40
39    
40    struct RegionFeatures {
41        int sampleRefs;
42        int loops;
43    
44        RegionFeatures() {
45            sampleRefs = loops = 0;
46        }
47    };
48    
49    static RegionFeatures regionFeatures(gig::Region* rgn) {
50        RegionFeatures f;
51        for (int i = 0; i < rgn->DimensionRegions; ++i) {
52            gig::DimensionRegion* dr = rgn->pDimensionRegions[i];
53            if (dr->pSample) f.sampleRefs++;
54            // the user doesn't care about loop if there is no valid sample reference
55            if (dr->pSample && dr->SampleLoops) f.loops++;
56        }
57        return f;
58    }
59    
60  RegionChooser::RegionChooser()  void SortedRegions::update(gig::Instrument* instrument) {
61        // Usually, the regions in a gig file are ordered after their key
62        // range, but there are files where they are not. The
63        // RegionChooser code needs a sorted list of regions.
64        regions.clear();
65        if (instrument) {
66            for (gig::Region* r = instrument->GetFirstRegion() ;
67                 r ;
68                 r = instrument->GetNextRegion()) {
69                regions.push_back(r);
70            }
71            sort(regions.begin(), regions.end(), *this);
72        }
73    }
74    
75    gig::Region* SortedRegions::first() {
76        region_iterator = regions.begin();
77        return region_iterator == regions.end() ? 0 : *region_iterator;
78    }
79    
80    gig::Region* SortedRegions::next() {
81        ++region_iterator;
82        return region_iterator == regions.end() ? 0 : *region_iterator;
83    }
84    
85    
86    
87    RegionChooser::RegionChooser() :
88        activeKeyColor("red"),
89        blue("#4796ff"),
90        grey1("grey69"),
91        white("white"),
92        black("black"),
93        m_VirtKeybModeChoice(_("Virtual Keyboard Mode")),
94        currentActiveKey(-1),
95        modifyallregions(false)
96  {  {
97      Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();      set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT);
98    
99        loadBuiltInPix();
100    
101        // create gray blue hatched pattern
102        {
103            const int width = grayBlueHatchedPattern->get_width();
104            const int height = grayBlueHatchedPattern->get_height();
105            const int stride = grayBlueHatchedPattern->get_rowstride();
106    
107            // manually convert from RGBA to ARGB
108            this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
109            const int pixelSize = stride / width;
110            const int totalPixels = width * height;
111            assert(pixelSize == 4);
112            unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
113            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
114                const unsigned char r = ptr[0];
115                const unsigned char g = ptr[1];
116                const unsigned char b = ptr[2];
117                const unsigned char a = ptr[3];
118                ptr[0] = b;
119                ptr[1] = g;
120                ptr[2] = r;
121                ptr[3] = a;
122            }
123    
124            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
125                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
126            );
127            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
128            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
129        }
130    
     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);  
131      instrument = 0;      instrument = 0;
132      region = 0;      region = 0;
133      resize.active = false;      resize.active = false;
134        move.active = false;
135      cursor_is_resize = false;      cursor_is_resize = false;
136      h1 = 20;      h1 = REGION_BLOCK_HEIGHT;
137      width = 800;  
138        // properties of the virtual keyboard
139        {
140            const char* choices[] = { _("normal"), _("chord"), 0 };
141            static const virt_keyboard_mode_t values[] = {
142                VIRT_KEYBOARD_MODE_NORMAL,
143                VIRT_KEYBOARD_MODE_CHORD
144            };
145            m_VirtKeybModeChoice.set_choices(choices, values);
146            m_VirtKeybModeChoice.set_value(VIRT_KEYBOARD_MODE_NORMAL);
147        }
148        m_VirtKeybVelocityLabelDescr.set_text(_("Note-On Velocity:"));
149        m_VirtKeybVelocityLabel.set_text("-");
150        m_VirtKeybOffVelocityLabelDescr.set_text(_("Note-Off Velocity:"));
151        m_VirtKeybOffVelocityLabel.set_text("-");
152        m_VirtKeybPropsBox.pack_start(m_VirtKeybModeChoice.label, Gtk::PACK_SHRINK);
153        m_VirtKeybPropsBox.pack_start(m_VirtKeybModeChoice.widget, Gtk::PACK_SHRINK);
154        m_VirtKeybPropsBox.pack_start(m_VirtKeybVelocityLabelDescr, Gtk::PACK_SHRINK);
155        m_VirtKeybPropsBox.pack_start(m_VirtKeybVelocityLabel, Gtk::PACK_SHRINK);
156        m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabelDescr, Gtk::PACK_SHRINK);
157        m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK);
158        m_VirtKeybPropsBox.set_spacing(10);
159        m_VirtKeybPropsBox.show();
160        for (int i = 0 ; i < 128 ; i++) key_pressed[i] = false;
161    
162      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
163      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties",
# Line 86  RegionChooser::RegionChooser() Line 194  RegionChooser::RegionChooser()
194      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
195                 Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK);
196    
197      dimensionManager.articulation_changed_signal.connect(      dimensionManager.region_to_be_changed_signal.connect(
198          sigc::mem_fun(*this, &RegionChooser::on_dimension_manager_changed)          region_to_be_changed_signal.make_slot()
199        );
200        dimensionManager.region_changed_signal.connect(
201            region_changed_signal.make_slot()
202        );
203        dimensionManager.region_changed_signal.connect(
204            sigc::hide(
205                sigc::mem_fun(*this, &RegionChooser::on_dimension_manager_changed)
206            )
207      );      );
208        keyboard_key_hit_signal.connect(
209            sigc::mem_fun(*this, &RegionChooser::on_note_on_event)
210        );
211        keyboard_key_released_signal.connect(
212            sigc::mem_fun(*this, &RegionChooser::on_note_off_event)
213        );
214        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."));
215  }  }
216    
217  RegionChooser::~RegionChooser()  RegionChooser::~RegionChooser()
218  {  {
219  }  }
220    
221  void RegionChooser::on_realize()  void RegionChooser::setModifyAllRegions(bool b) {
222  {      modifyallregions = b;
223      // We need to call the base on_realize()      // redraw required parts
224      Gtk::DrawingArea::on_realize();      queue_draw();
225    }
226    
227      // Now we can allocate any additional resources we need  void RegionChooser::invalidate_key(int key) {
228      Glib::RefPtr<Gdk::Window> window = get_window();      const int h = KEYBOARD_HEIGHT;
229      gc = Gdk::GC::create(window);      const int w = get_width() - 1;
230      window->clear();      int x1 = key_to_x(key - 0.5, w);
231        int x2 = key_to_x(key + 1.5, w);
232    
233        Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
234        get_window()->invalidate_rect(rect, false);
235  }  }
236    
237  bool RegionChooser::on_expose_event(GdkEventExpose* event)  void RegionChooser::on_note_on_event(int key, int velocity) {
238  {      key_pressed[key] = true;
239      Glib::RefPtr<Gdk::Window> window = get_window();      invalidate_key(key);
240      window->clear();      m_VirtKeybVelocityLabel.set_text(ToString(velocity));
241      const int h = 40;  }
242      const int w = width - 1;  
243    void RegionChooser::on_note_off_event(int key, int velocity) {
244        key_pressed[key] = false;
245        invalidate_key(key);
246        m_VirtKeybOffVelocityLabel.set_text(ToString(velocity));
247    }
248    
249    
250    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
251    bool RegionChooser::on_expose_event(GdkEventExpose* e) {
252        double clipx1 = e->area.x;
253        double clipx2 = e->area.x + e->area.width;
254        double clipy1 = e->area.y;
255        double clipy2 = e->area.y + e->area.height;
256    
257        const Cairo::RefPtr<Cairo::Context>& cr =
258            get_window()->create_cairo_context();
259    #if 0
260    }
261    #endif
262    #else
263    bool RegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
264        double clipx1, clipx2, clipy1, clipy2;
265        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
266    #endif
267    
268        cr->save();
269        cr->set_line_width(1);
270    
271    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
272        const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL);
273    #else
274        const Gdk::RGBA bg = get_style_context()->get_background_color();
275    #endif
276        Gdk::Cairo::set_source_rgba(cr, bg);
277        cr->paint();
278    
279        if (clipy2 > h1) {
280            draw_keyboard(cr, clipx1, clipx2);
281        }
282    
283        if (clipy1 < h1 && instrument) {
284            draw_regions(cr, clipx1, clipx2);
285        }
286    
287        cr->restore();
288    
289        return true;
290    }
291    
292    void RegionChooser::draw_keyboard(const Cairo::RefPtr<Cairo::Context>& cr,
293                                      int clip_low, int clip_high) {
294        const int h = KEYBOARD_HEIGHT;
295        const int w = get_width() - 1;
296      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
297    
298      Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();      Gdk::Cairo::set_source_rgba(cr, black);
299      Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();      cr->rectangle(0.5, h1 + 0.5, w, h - 1);
300        cr->stroke();
301    
302        int x1 = key_to_x(20.5, w);
303        Gdk::Cairo::set_source_rgba(cr, grey1);
304        cr->rectangle(1, h1 + 1, x1 - 1, h - 2);
305        cr->fill();
306    
307        int x2 = key_to_x(109.5, w);
308        Gdk::Cairo::set_source_rgba(cr, white);
309        cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
310        cr->fill();
311    
312        Gdk::Cairo::set_source_rgba(cr, grey1);
313        cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2);
314        cr->fill();
315    
316      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);  
317    
318          if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) {      int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w));
319              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);  
320    
321              int x3 = int(w * (i + 1) / 128.0 + 0.5);      for (int i = clipkey1 ; i < clipkey2 ; i++) {
322              window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh);          int note = (i + 3) % 12;
323            int x = key_to_x(i, w);
324    
325            if (note == 1 || note == 4 || note == 6 ||
326                note == 9 || note == 11) {
327                // black key: short line in the middle, with a rectangle
328                // on top
329                int x2 = key_to_x(i + 0.5, w);
330                cr->move_to(x2 + 0.5, h1 + bh + 0.5);
331                cr->line_to(x2 + 0.5, h1 + h - 1);
332                cr->stroke();
333    
334                int x3 = key_to_x(i + 1, w);
335                cr->rectangle(x, h1 + 1, x3 - x + 1, bh);
336                cr->fill();
337          } else if (note == 3 || note == 8) {          } else if (note == 3 || note == 8) {
338              window->draw_line(black, x, h1 + 1, x, h1 + h);              // C or F: long line to the left
339                cr->move_to(x + 0.5, h1 + 1);
340                cr->line_to(x + 0.5, h1 + h - 1);
341                cr->stroke();
342          }          }
343    
344            if (key_pressed[i]) draw_key(cr, i);
345    
346            if (note == 3) draw_digit(cr, i);
347      }      }
348    }
349    
     if (instrument) {  
         int i = 0;  
         gig::Region *nextRegion;  
         int x3 = -1;  
         for (gig::Region *r = instrument->GetFirstRegion() ;  
              r ;  
              r = nextRegion) {  
350    
351              if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);  void RegionChooser::draw_regions(const Cairo::RefPtr<Cairo::Context>& cr,
352              nextRegion = instrument->GetNextRegion();                                   int clip_low, int clip_high) {
353              if (!nextRegion || r->KeyRange.high + 1 != nextRegion->KeyRange.low) {      const int w = get_width() - 1;
354                  int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);  
355                  window->draw_line(black, x3, 0, x2, 0);      Gdk::Cairo::set_source_rgba(cr, black);
356                  window->draw_line(black, x3, h1 - 1, x2, h1 - 1);      gig::Region* next_region;
357                  window->draw_line(black, x2, 1, x2, h1 - 2);      int x3 = -1;
358                  window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);      for (gig::Region* r = regions.first() ; r ; r = next_region) {
359                  x3 = -1;          next_region = regions.next();
360    
361            if (x3 < 0) {
362                x3 = key_to_x(r->KeyRange.low, w);
363                if (x3 >= clip_high) break;
364            }
365            if (!next_region ||
366                r->KeyRange.high + 1 != next_region->KeyRange.low ||
367                r == region || next_region == region) {
368    
369                int x2 = key_to_x(r->KeyRange.high + 1, w);
370                if (x2 >= clip_low) {
371                    cr->move_to(x3, 0.5);
372                    cr->line_to(x2 + 0.5, 0.5);
373                    cr->line_to(x2 + 0.5, h1 - 0.5);
374                    cr->line_to(x3, h1 - 0.5);
375                    cr->stroke();
376    
377                    if (region == r)
378                        Gdk::Cairo::set_source_rgba(cr, blue);
379                    else if (modifyallregions)
380                        cr->set_source(grayBlueHatchedSurfacePattern);
381                    else
382                        Gdk::Cairo::set_source_rgba(cr, white);
383    
384                    cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2);
385                    cr->fill();
386                    Gdk::Cairo::set_source_rgba(cr, black);
387              }              }
388              i++;              x3 = -1;
389          }          }
390        }
391    
392          for (gig::Region *r = instrument->GetFirstRegion() ;      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
393               r ;          int x = key_to_x(r->KeyRange.low, w);
394               r = instrument->GetNextRegion()) {          int x2 = key_to_x(r->KeyRange.high + 1, w);
395              int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);  
396              window->draw_line(black, x, 1, x, h1 - 2);          RegionFeatures features = regionFeatures(r);
397    
398            const bool bShowLoopSymbol = features.loops > 0;
399            const bool bShowSampleRefSymbol = features.sampleRefs < r->DimensionRegions;
400            if (bShowLoopSymbol || bShowSampleRefSymbol) {
401                const int margin = 2;
402                const int wRgn = x2 - x;
403                //printf("x=%d x2=%d wRgn=%d\n", x, x2, wRgn);
404    
405                cr->save();
406                cr->set_line_width(1);
407                cr->rectangle(x, 1, wRgn, h1 - 1);
408                cr->clip();
409                if (bShowSampleRefSymbol) {
410                    const int wPic = 8;
411                    const int hPic = 8;
412                    Gdk::Cairo::set_source_pixbuf(
413                        cr, (features.sampleRefs) ? yellowDot : redDot,
414                        x + (wRgn-wPic)/2.f,
415                        (bShowLoopSymbol) ? margin : (h1-hPic)/2.f
416                    );
417                    cr->paint();
418                }
419                if (bShowLoopSymbol) {
420                    const int wPic = 12;
421                    const int hPic = 14;
422                    Gdk::Cairo::set_source_pixbuf(
423                        cr, (features.loops == r->DimensionRegions) ? blackLoop : grayLoop,
424                        x + (wRgn-wPic)/2.f,
425                        (bShowSampleRefSymbol) ? h1 - hPic - margin : (h1-hPic)/2.f
426                    );
427                    cr->paint();
428                }
429                cr->restore();
430          }          }
431        }
432    
433          if (region) {      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
434              int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);          int x = key_to_x(r->KeyRange.low, w);
435              int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);  
436              gc->set_foreground(red);          if (x < clip_low) continue;
437              window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);          if (x >= clip_high) break;
438          }  
439            cr->move_to(x + 0.5, 1);
440            cr->line_to(x + 0.5, h1 - 1);
441            cr->stroke();
442      }      }
     return true;  
 }  
443    
444        // if there is no region yet, show the user some hint text that he may
445        // right click on this area to create a new region
446        if (!regions.first()) {
447            Glib::RefPtr<Pango::Context> context = get_pango_context();
448            Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
449            layout->set_alignment(Pango::ALIGN_CENTER);
450            layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***");
451            layout->set_width(get_width() * Pango::SCALE);
452            //layout->set_height(get_height() * Pango::SCALE);
453            layout->set_spacing(10);
454            Gdk::Cairo::set_source_rgba(cr, blue);
455            // get the text dimensions
456            int text_width, text_height;
457            layout->get_pixel_size(text_width, text_height);
458            cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2);
459    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
460            pango_cairo_show_layout(cr->cobj(), layout->gobj());
461    #else
462            layout->show_in_cairo_context(cr);
463    #endif
464        }
465    }
466    
467  void RegionChooser::on_size_request(GtkRequisition* requisition)  bool RegionChooser::is_black_key(int key) {
468  {      const int note = (key + 3) % 12;
469      *requisition = GtkRequisition();      return note == 1 || note == 4 || note == 6 || note == 9 || note == 11;
     requisition->height = 40 + 20;  
     requisition->width = 500;  
470  }  }
471    
472    void RegionChooser::draw_digit(const Cairo::RefPtr<Cairo::Context>& cr,
473                                   int key) {
474        const int h = KEYBOARD_HEIGHT;
475        const int w = get_width() - 1;
476        Glib::RefPtr<Pango::Layout> layout =
477            Pango::Layout::create(get_pango_context());
478        char buf[30];
479        sprintf(buf, "<span size=\"8000\">%d</span>", key / 12 - 1);
480        layout->set_markup(buf);
481        Pango::Rectangle rectangle = layout->get_logical_extents();
482        double text_w = double(rectangle.get_width()) / Pango::SCALE;
483        double text_h = double(rectangle.get_height()) / Pango::SCALE;
484        double x = w * (key + 0.75) / 128.0;
485        Gdk::Cairo::set_source_rgba(cr, black);
486        cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5));
487    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
488        pango_cairo_show_layout(cr->cobj(), layout->gobj());
489    #else
490        layout->show_in_cairo_context(cr);
491    #endif
492    }
493    
494  // not used  void RegionChooser::draw_key(const Cairo::RefPtr<Cairo::Context>& cr,
495  void RegionChooser::draw_region(int from, int to, const Gdk::Color& color)                               int key) {
496  {      const int h = KEYBOARD_HEIGHT;
497      const int h = 40;      const int w = get_width() - 1;
     const int w = width;  
498      const int bh = int(h * 0.55);      const int bh = int(h * 0.55);
499    
500      Glib::RefPtr<Gdk::Window> window = get_window();      Gdk::Cairo::set_source_rgba(cr, activeKeyColor);
     gc->set_foreground(color);  
501    
502      for (int i = from ; i < to ; i++) {      int note = (key + 3) % 12;
503          int note = (i + 3) % 12;      int x = key_to_x(key, w) + 1;
504          int x = int(w * i / 128.0 + 0.5) + 1;      int x2 = key_to_x(key + 1.5, w);
505          int x2 = int(w * (i + 1.5) / 128.0 + 0.5);      int x3 = key_to_x(key + 1, w);
506          int x3 = int(w * (i + 1) / 128.0 + 0.5);      int x4 = key_to_x(key - 0.5, w);
507          int x4 = int(w * (i - 0.5) / 128 + 0.5) + 1;      int w1 = x3 - x;
508          int w1 = x3 - x;      switch (note) {
509          switch (note) {      case 0: case 5: case 10:
510          case 0: case 5: case 10:          cr->rectangle(x, h1 + 1, w1, bh);
511              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);          cr->fill();
512              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);
513              break;          cr->fill();
514          case 2: case 7:          break;
515              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);      case 2: case 7:
516              window->draw_rectangle(gc, true, x4, h1 + bh + 1, x3 - x4, h - bh - 2);          cr->rectangle(x, h1 + 1, w1, bh);
517              break;          cr->fill();
518          case 3: case 8:          cr->rectangle(x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2);
519              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);          cr->fill();
520              window->draw_rectangle(gc, true, x, h1 + bh + 1, x2 - x, h - bh - 2);          break;
521              break;      case 3: case 8:
522          default:          cr->rectangle(x, h1 + 1, w1, bh);
523              window->draw_rectangle(gc, true, x, h1 + 1, w1, bh - 1);          cr->fill();
524              break;          cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2);
525          }          cr->fill();
526            break;
527        default:
528            cr->rectangle(x, h1 + 1, w1, bh - 1);
529            cr->fill();
530            break;
531      }      }
532        Gdk::Cairo::set_source_rgba(cr, black);
533  }  }
534    
535  void RegionChooser::set_instrument(gig::Instrument* instrument)  void RegionChooser::set_instrument(gig::Instrument* instrument)
536  {  {
537      this->instrument = instrument;      this->instrument = instrument;
538      region = instrument ? instrument->GetFirstRegion() : 0;      regions.update(instrument);
539        region = regions.first();
540      queue_draw();      queue_draw();
541      region_selected();      region_selected();
542        dimensionManager.set_region(region);
543  }  }
544    
545  bool RegionChooser::on_button_release_event(GdkEventButton* event)  bool RegionChooser::on_button_release_event(GdkEventButton* event)
546  {  {
547        const int k = x_to_key(event->x, get_width() - 1);
548    
549        // handle-note off on virtual keyboard
550        if (event->type == GDK_BUTTON_RELEASE) {
551            int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
552                           int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
553            if (velocity <= 0) velocity = 1;
554            switch (m_VirtKeybModeChoice.get_value()) {
555                case VIRT_KEYBOARD_MODE_CHORD:
556                    if (event->y >= REGION_BLOCK_HEIGHT)
557                        keyboard_key_released_signal.emit(k, velocity);
558                    break;
559                case VIRT_KEYBOARD_MODE_NORMAL:
560                default:
561                    if (currentActiveKey >= 0 && currentActiveKey <= 127) {
562                        keyboard_key_released_signal.emit(currentActiveKey, velocity);
563                        currentActiveKey = -1;
564                    }
565                    break;
566            }
567        }
568    
569      if (resize.active) {      if (resize.active) {
570    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
571          get_window()->pointer_ungrab(event->time);          get_window()->pointer_ungrab(event->time);
572    #else
573            Glib::wrap(event->device, true)->ungrab(event->time);
574    #endif
575          resize.active = false;          resize.active = false;
576    
         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();  
             }  
         }  
   
577          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
578              get_window()->set_cursor();              get_window()->set_cursor();
579              cursor_is_resize = false;              cursor_is_resize = false;
580          }          }
581        } else if (move.active) {
582    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
583            get_window()->pointer_ungrab(event->time);
584    #else
585            Glib::wrap(event->device, true)->ungrab(event->time);
586    #endif
587            move.active = false;
588    
589            if (is_in_resize_zone(event->x, event->y)) {
590    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
591                get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
592    #else
593                get_window()->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
594    #endif
595                cursor_is_resize = true;
596            }
597      }      }
598      return true;      return true;
599  }  }
600    
601    void RegionChooser::update_after_resize()
602    {
603        if (resize.mode == resize.moving_high_limit) {
604            if (resize.region->KeyRange.high != resize.pos - 1) {
605                instrument_struct_to_be_changed_signal.emit(instrument);
606                resize.region->SetKeyRange(resize.region->KeyRange.low,
607                                           resize.pos - 1);
608                regions.update(instrument);
609                instrument_changed.emit();
610                instrument_struct_changed_signal.emit(instrument);
611            }
612        } else if (resize.mode == resize.moving_low_limit) {
613            if (resize.region->KeyRange.low != resize.pos) {
614                instrument_struct_to_be_changed_signal.emit(instrument);
615                resize.region->SetKeyRange(resize.pos,
616                                           resize.region->KeyRange.high);
617                regions.update(instrument);
618                instrument_changed.emit();
619                instrument_struct_changed_signal.emit(instrument);
620            }
621        }
622    }
623    
624    void RegionChooser::update_after_move(int pos)
625    {
626        instrument_struct_to_be_changed_signal.emit(instrument);
627        const int range = region->KeyRange.high - region->KeyRange.low;
628        const int diff  = pos - int(region->KeyRange.low);
629        region->SetKeyRange(pos, pos + range);
630        if (Settings::singleton()->moveRootNoteWithRegionMoved) {
631            for (int i = 0; i < 256; ++i) {
632                gig::DimensionRegion* dimrgn = region->pDimensionRegions[i];
633                if (!dimrgn || !dimrgn->pSample || !dimrgn->PitchTrack) continue;
634                dimrgn->UnityNote += diff;
635            }
636        }
637        regions.update(instrument);
638        instrument_changed.emit();
639        instrument_struct_changed_signal.emit(instrument);
640    }
641    
642  bool RegionChooser::on_button_press_event(GdkEventButton* event)  bool RegionChooser::on_button_press_event(GdkEventButton* event)
643  {  {
644      if (!instrument) return true;      if (!instrument) return true;
645    
646      int k = int(event->x / (width - 1) * 128.0);      const int w = get_width() - 1;
647        const int k = x_to_key(event->x, w);
648    
649        if (event->type == GDK_BUTTON_PRESS) {
650            if (event->y >= REGION_BLOCK_HEIGHT) {
651                int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
652                               int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1;
653                currentActiveKey = k;
654                keyboard_key_hit_signal.emit(k, velocity);
655            }
656        }
657    
658        // left mouse button double click
659        if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
660            if (event->y < REGION_BLOCK_HEIGHT) {
661                // show dimension manager dialog for this region
662                manage_dimensions();
663            }
664        }
665    
666        if (event->y >= REGION_BLOCK_HEIGHT) return true;
667      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {      if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
668          gig::Region* r = get_region(k);          gig::Region* r = get_region(k);
669          if (r) {          if (r) {
670              region = r;              region = r;
671              queue_draw();              queue_draw();
672              region_selected();              region_selected();
673                dimensionManager.set_region(region);
674              popup_menu_inside_region->popup(event->button, event->time);              popup_menu_inside_region->popup(event->button, event->time);
675          } else {          } else {
676              new_region_pos = k;              new_region_pos = k;
# Line 271  bool RegionChooser::on_button_press_even Line 678  bool RegionChooser::on_button_press_even
678          }          }
679      } else {      } else {
680          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
681              Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
682              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
683                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
684                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
685                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
686                                         double_arrow, event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
687                                           event->time);
688    #else
689                Glib::wrap(event->device, true)->grab(get_window(),
690                                                      Gdk::OWNERSHIP_NONE,
691                                                      false,
692                                                      Gdk::BUTTON_RELEASE_MASK |
693                                                      Gdk::POINTER_MOTION_MASK |
694                                                      Gdk::POINTER_MOTION_HINT_MASK,
695                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
696                                                      event->time);
697    #endif
698              resize.active = true;              resize.active = true;
699          } else {          } else {
700              gig::Region* r = get_region(k);              gig::Region* r = get_region(k);
# Line 284  bool RegionChooser::on_button_press_even Line 702  bool RegionChooser::on_button_press_even
702                  region = r;                  region = r;
703                  queue_draw();                  queue_draw();
704                  region_selected();                  region_selected();
705                    dimensionManager.set_region(region);
706    
707    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
708                    get_window()->pointer_grab(false,
709                                               Gdk::BUTTON_RELEASE_MASK |
710                                               Gdk::POINTER_MOTION_MASK |
711                                               Gdk::POINTER_MOTION_HINT_MASK,
712                                               Gdk::Cursor(Gdk::FLEUR),
713                                               event->time);
714    #else
715                    Glib::wrap(event->device, true)->grab(get_window(),
716                                                          Gdk::OWNERSHIP_NONE,
717                                                          false,
718                                                          Gdk::BUTTON_RELEASE_MASK |
719                                                          Gdk::POINTER_MOTION_MASK |
720                                                          Gdk::POINTER_MOTION_HINT_MASK,
721                                                          Gdk::Cursor::create(Gdk::FLEUR),
722                                                          event->time);
723    #endif
724                    move.active = true;
725                    move.offset = event->x - key_to_x(region->KeyRange.low, w);
726              }              }
727          }          }
728      }      }
# Line 292  bool RegionChooser::on_button_press_even Line 731  bool RegionChooser::on_button_press_even
731    
732  gig::Region* RegionChooser::get_region(int key)  gig::Region* RegionChooser::get_region(int key)
733  {  {
734      for (gig::Region *r = instrument->GetFirstRegion() ; r ;      for (gig::Region* r = regions.first() ; r ; r = regions.next()) {
          r = instrument->GetNextRegion()) {  
735          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
736          if (key <= r->KeyRange.high) return r;          if (key <= r->KeyRange.high) return r;
737      }      }
738      return 0;      return 0;
739  }  }
740    
741  bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)  void RegionChooser::set_region(gig::Region* region) {
742  {      this->region = region;
743      const int w = width - 1;      queue_draw();
744      Glib::RefPtr<Gdk::Window> window = get_window();      region_selected();
745      int x, y;      dimensionManager.set_region(region);
746      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);  
747    
748          if (k < resize.min) k = resize.min;  void RegionChooser::select_next_region() {
749          else if (k > resize.max) k = resize.max;      if (!instrument) return;
750        if (!region) {
751            for (int i = 0; i < 128; ++i) {
752                ::gig::Region* rgn = instrument->GetRegion(i);
753                if (rgn) {
754                    set_region(rgn);
755                    return;
756                }
757            }
758        } else {
759            bool currentFound = false;
760            for (int i = 0; i < 128; ++i) {
761                ::gig::Region* rgn = instrument->GetRegion(i);
762                if (!rgn) continue;
763                if (currentFound) {
764                    if (rgn != region) {
765                        set_region(rgn);
766                        return;
767                    }
768                } else {
769                    if (rgn == region) currentFound = true;
770                }
771            }
772        }
773    }
774    
775          if (k != resize.pos) {  void RegionChooser::select_prev_region() {
776              if (resize.mode == resize.undecided) {      if (!instrument) return;
777                  if (k < resize.pos) {      if (!region) {
778                      // edit high limit of prev_region          for (int i = 0; i < 128; ++i) {
779                      resize.max = resize.region->KeyRange.low;              ::gig::Region* rgn = instrument->GetRegion(i);
780                      resize.region = resize.prev_region;              if (rgn) {
781                      resize.mode = resize.moving_high_limit;                  set_region(rgn);
782                  } else {                  return;
783                      // edit low limit of region              }
784                      resize.min = resize.prev_region->KeyRange.high + 1;          }
785                      resize.mode = resize.moving_low_limit;      } else {
786            bool currentFound = false;
787            for (int i = 127; i >= 0; --i) {
788                ::gig::Region* rgn = instrument->GetRegion(i);
789                if (!rgn) continue;
790                if (currentFound) {
791                    if (rgn != region) {
792                        set_region(rgn);
793                        return;
794                  }                  }
795                } else {
796                    if (rgn == region) currentFound = true;
797                }
798            }
799        }
800    }
801    
802    void RegionChooser::motion_resize_region(int x, int y)
803    {
804        const int w = get_width() - 1;
805    
806        int k = int(double(x) / w * 128.0 + 0.5);
807    
808        if (k < resize.min) k = resize.min;
809        else if (k > resize.max) k = resize.max;
810    
811        if (k != resize.pos) {
812            if (resize.mode == resize.undecided) {
813                if (k < resize.pos) {
814                    // edit high limit of prev_region
815                    resize.max = resize.region->KeyRange.low;
816                    resize.region = resize.prev_region;
817                    resize.mode = resize.moving_high_limit;
818                } else {
819                    // edit low limit of region
820                    resize.min = resize.prev_region->KeyRange.high + 1;
821                    resize.mode = resize.moving_low_limit;
822                }
823            }
824            resize.pos = k;
825    
826            int x1, x2;
827            if (resize.mode == resize.moving_high_limit) {
828                if (resize.region->KeyRange.high < resize.pos - 1) {
829                    x1 = resize.region->KeyRange.high;
830                    x2 = resize.pos - 1;
831                } else {
832                    x1 = resize.pos - 1;
833                    x2 = resize.region->KeyRange.high;
834                }
835            } else {
836                if (resize.region->KeyRange.low < resize.pos) {
837                    x1 = resize.region->KeyRange.low;
838                    x2 = resize.pos;
839                } else {
840                    x1 = resize.pos;
841                    x2 = resize.region->KeyRange.low;
842              }              }
843              Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();          }
844              Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();          x1 = key_to_x(x1, w);
845              if (region == resize.region) {          x2 = key_to_x(x2 + 1, w) + 1;
846                  gc->set_foreground(red);          Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
847                  white = gc;  
848              }          update_after_resize();
849              Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);  
850              int prevx = int(w * resize.pos / 128.0 + 0.5);          //get_window()->invalidate_rect(rect, false);
851              x = int(w * k / 128.0 + 0.5);          get_window()->invalidate(false); // repaint entire region, otherwise it would create visual artifacts
852        }
853              if (resize.mode == resize.moving_high_limit) {  }
854                  if (k > resize.pos) {  
855                      window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);  void RegionChooser::motion_move_region(int x, int y)
856                      window->draw_line(black, prevx, 0, x, 0);  {
857                      window->draw_line(black, prevx, h1 - 1, x, h1 - 1);      const int w = get_width() - 1;
858    
859        int l = int(double(x - move.offset) / w * 128.0 + 0.5);
860    
861        if (l == region->KeyRange.low) return;
862        int new_l;
863        int regionsize = region->KeyRange.high - region->KeyRange.low;
864        int a = 0;
865        if (l > region->KeyRange.low) {
866            for (gig::Region* r = regions.first() ; ; r = regions.next()) {
867                if (r != region) {
868                    int b = r ? r->KeyRange.low : 128;
869    
870                    // gap: from a to b (not inclusive b)
871    
872                    if (region->KeyRange.high >= b) {
873                        // not found the current gap yet, just continue
874                  } else {                  } else {
875                      int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);  
876                      window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);                      if (a > l) {
877                            // this gap is too far to the right, break
878                            break;
879                        }
880    
881                        int newhigh = std::min(l + regionsize, b - 1);
882                        int newlo = newhigh - regionsize;
883    
884                        if (newlo >= a) {
885                            // yes it fits - it's a candidate
886                            new_l = newlo;
887                        }
888                  }                  }
889              } else {                  if (!r) break;
890                  if (k < resize.pos) {                  a = r->KeyRange.high + 1;
891                      window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);              }
892                      window->draw_line(black, x, 0, prevx, 0);          }
893                      window->draw_line(black, x, h1 - 1, prevx, h1 - 1);      } else {
894            for (gig::Region* r = regions.first() ; ; r = regions.next()) {
895                if (r != region) {
896                    int b = r ? r->KeyRange.low : 128;
897    
898                    // gap from a to b (not inclusive b)
899    
900                    if (l + regionsize >= b) {
901                        // not found the current gap yet, just continue
902                  } else {                  } else {
903                      int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);  
904                      window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);                      if (a > region->KeyRange.low) {
905                            // this gap is too far to the right, break
906                            break;
907                        }
908    
909                        int newlo = std::max(l, a);
910                        int newhigh = newlo + regionsize;
911    
912                        if (newhigh < b) {
913                            // yes it fits - break as the first one is the best
914                            new_l = newlo;
915                            break;
916                        }
917                  }                  }
918                    if (!r) break;
919                    a = r->KeyRange.high + 1;
920              }              }
             window->draw_line(black, x, 1, x, h1 - 2);  
             resize.pos = k;  
921          }          }
922        }
923        if (new_l == region->KeyRange.low) return;
924    
925        int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w);
926        int x2 = key_to_x(std::max(int(region->KeyRange.high),
927                                   new_l + regionsize) + 1, w) + 1;
928    
929        Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
930        update_after_move(new_l);
931    
932        get_window()->invalidate_rect(rect, false);
933    }
934    
935    
936    bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)
937    {
938        Glib::RefPtr<Gdk::Window> window = get_window();
939        int x, y;
940        Gdk::ModifierType state = Gdk::ModifierType(0);
941        window->get_pointer(x, y, state);
942    
943        // handle virtual MIDI keyboard
944        if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&
945            currentActiveKey > 0 &&
946            event->y >= REGION_BLOCK_HEIGHT &&
947            event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
948        {
949            const int k = x_to_key(event->x, get_width() - 1);
950            if (k != currentActiveKey) {
951                int velocity =
952                    (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
953                    int(float(event->y - REGION_BLOCK_HEIGHT) /
954                        float(KEYBOARD_HEIGHT) * 128.0f) + 1;
955                if (velocity <= 0) velocity = 1;
956                keyboard_key_released_signal.emit(currentActiveKey, velocity);
957                currentActiveKey = k;
958                keyboard_key_hit_signal.emit(k, velocity);
959            }
960        }
961    
962        if (resize.active) {
963            motion_resize_region(x, y);
964        } else if (move.active) {
965            motion_move_region(x, y);
966      } else {      } else {
967          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
968              if (!cursor_is_resize) {              if (!cursor_is_resize) {
969                  Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
970                  window->set_cursor(double_arrow);                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
971    #else
972                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
973    #endif
974                  cursor_is_resize = true;                  cursor_is_resize = true;
975              }              }
976          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 375  bool RegionChooser::on_motion_notify_eve Line 983  bool RegionChooser::on_motion_notify_eve
983  }  }
984    
985  bool RegionChooser::is_in_resize_zone(double x, double y) {  bool RegionChooser::is_in_resize_zone(double x, double y) {
986      const int w = width - 1;      const int w = get_width() - 1;
987    
988      if (instrument && y >= 0 && y <= h1) {      if (instrument && y >= 0 && y <= h1) {
989          gig::Region* prev_region = 0;          gig::Region* prev_region = 0;
990          gig::Region* next_region;          gig::Region* next_region;
991          for (gig::Region* r = instrument->GetFirstRegion() ; r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
992              next_region = instrument->GetNextRegion();              next_region = regions.next();
993    
994              int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);              int lo = key_to_x(r->KeyRange.low, w);
995              if (x <= lo - 2) break;              if (x <= lo - 2) break;
996              if (x < lo + 2) {              if (x < lo + 2) {
997                  resize.region = r;                  resize.region = r;
# Line 397  bool RegionChooser::is_in_resize_zone(do Line 1005  bool RegionChooser::is_in_resize_zone(do
1005                      resize.mode = resize.undecided;                      resize.mode = resize.undecided;
1006                      resize.min = prev_region->KeyRange.low + 1;                      resize.min = prev_region->KeyRange.low + 1;
1007                      resize.prev_region = prev_region;                      resize.prev_region = prev_region;
1008                      return true;                      return resize.min != resize.max;
1009                  }                  }
1010    
1011                  // edit low limit                  // edit low limit
1012                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
1013                  resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;                  resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
1014                  return true;                  return resize.min != resize.max;
1015              }              }
1016              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
1017                  int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);                  int hi = key_to_x(r->KeyRange.high + 1, w);
1018                  if (x <= hi - 2) break;                  if (x <= hi - 2) break;
1019                  if (x < hi + 2) {                  if (x < hi + 2) {
1020                      // edit high limit                      // edit high limit
# Line 415  bool RegionChooser::is_in_resize_zone(do Line 1023  bool RegionChooser::is_in_resize_zone(do
1023                      resize.mode = resize.moving_high_limit;                      resize.mode = resize.moving_high_limit;
1024                      resize.min = r->KeyRange.low + 1;                      resize.min = r->KeyRange.low + 1;
1025                      resize.max = next_region ? next_region->KeyRange.low : 128;                      resize.max = next_region ? next_region->KeyRange.low : 128;
1026                      return true;                      return resize.min != resize.max;
1027                  }                  }
1028              }              }
1029              prev_region = r;              prev_region = r;
# Line 424  bool RegionChooser::is_in_resize_zone(do Line 1032  bool RegionChooser::is_in_resize_zone(do
1032      return false;      return false;
1033  }  }
1034    
1035  sigc::signal<void> RegionChooser::signal_region_selected()  sigc::signal<void>& RegionChooser::signal_region_selected()
1036  {  {
1037      return region_selected;      return region_selected;
1038  }  }
1039    
1040  sigc::signal<void> RegionChooser::signal_instrument_changed()  sigc::signal<void>& RegionChooser::signal_instrument_changed()
1041  {  {
1042      return instrument_changed;      return instrument_changed;
1043  }  }
# Line 437  sigc::signal<void> RegionChooser::signal Line 1045  sigc::signal<void> RegionChooser::signal
1045  void RegionChooser::show_region_properties()  void RegionChooser::show_region_properties()
1046  {  {
1047      if (!region) return;      if (!region) return;
1048      Gtk::Dialog dialog("Region Properties", true /*modal*/);      Gtk::Dialog dialog(_("Region Properties"), true /*modal*/);
1049      // add "Keygroup" checkbox      // add "Keygroup" checkbox
1050      Gtk::CheckButton checkBoxKeygroup("Member of a Keygroup (Exclusive Group)");      Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));
1051      checkBoxKeygroup.set_active(region->KeyGroup);      checkBoxKeygroup.set_active(region->KeyGroup);
1052      dialog.get_vbox()->pack_start(checkBoxKeygroup);      dialog.get_vbox()->pack_start(checkBoxKeygroup);
1053      checkBoxKeygroup.show();      checkBoxKeygroup.show();
1054      // add "Keygroup" spinbox      // add "Keygroup" spinbox
1055      Gtk::Adjustment adjustment(1, 1, pow(2,32));  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1056        Gtk::Adjustment adjustment(1, 1, 999);
1057      Gtk::SpinButton spinBox(adjustment);      Gtk::SpinButton spinBox(adjustment);
1058    #else
1059        Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1060    #endif
1061      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
1062      dialog.get_vbox()->pack_start(spinBox);      dialog.get_vbox()->pack_start(spinBox);
1063      spinBox.show();      spinBox.show();
1064      // add OK and CANCEL buttons to the dialog      // add OK and CANCEL buttons to the dialog
1065      dialog.add_button(Gtk::Stock::OK, 0);      dialog.add_button(Gtk::Stock::OK, 0);
1066      dialog.add_button(Gtk::Stock::CANCEL, 1);      dialog.add_button(Gtk::Stock::CANCEL, 1);
1067        dialog.set_position(Gtk::WIN_POS_MOUSE);
1068      dialog.show_all_children();      dialog.show_all_children();
1069      if (!dialog.run()) { // OK selected ...      if (!dialog.run()) { // OK selected ...
1070          region->KeyGroup =          region->KeyGroup =
# Line 461  void RegionChooser::show_region_properti Line 1074  void RegionChooser::show_region_properti
1074    
1075  void RegionChooser::add_region()  void RegionChooser::add_region()
1076  {  {
1077      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;  
     }  
1078    
1079      region = instrument->AddRegion();      region = instrument->AddRegion();
1080      region->KeyRange.low = region->KeyRange.high = new_region_pos;      region->SetKeyRange(new_region_pos, new_region_pos);
1081    
1082        instrument_struct_changed_signal.emit(instrument);
1083        regions.update(instrument);
1084    
     instrument->MoveRegion(region, r);  
1085      queue_draw();      queue_draw();
1086      region_selected();      region_selected();
1087        dimensionManager.set_region(region);
1088      instrument_changed();      instrument_changed();
1089  }  }
1090    
1091  void RegionChooser::delete_region()  void RegionChooser::delete_region()
1092  {  {
1093        instrument_struct_to_be_changed_signal.emit(instrument);
1094      instrument->DeleteRegion(region);      instrument->DeleteRegion(region);
1095        instrument_struct_changed_signal.emit(instrument);
1096        regions.update(instrument);
1097    
1098      region = 0;      region = 0;
1099      queue_draw();      queue_draw();
1100      region_selected();      region_selected();
1101        dimensionManager.set_region(region);
1102      instrument_changed();      instrument_changed();
1103  }  }
1104    
# Line 495  void RegionChooser::on_dimension_manager Line 1113  void RegionChooser::on_dimension_manager
1113      region_selected();      region_selected();
1114      instrument_changed();      instrument_changed();
1115  }  }
1116    
1117    sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_to_be_changed() {
1118        return instrument_struct_to_be_changed_signal;
1119    }
1120    
1121    sigc::signal<void, gig::Instrument*>& RegionChooser::signal_instrument_struct_changed() {
1122        return instrument_struct_changed_signal;
1123    }
1124    
1125    sigc::signal<void, gig::Region*>& RegionChooser::signal_region_to_be_changed() {
1126        return region_to_be_changed_signal;
1127    }
1128    
1129    sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {
1130        return region_changed_signal;
1131    }
1132    
1133    sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_hit() {
1134        return keyboard_key_hit_signal;
1135    }
1136    
1137    sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_released() {
1138        return keyboard_key_released_signal;
1139    }

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

  ViewVC Help
Powered by ViewVC