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

Legend:
Removed from v.1533  
changed lines
  Added in v.3450

  ViewVC Help
Powered by ViewVC