/[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 1396 by schoenebeck, Wed Oct 10 15:48:54 2007 UTC revision 3460 by persson, Sat Feb 2 07:48:50 2019 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006, 2007 Andreas Persson   * Copyright (C) 2006-2019 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=\"x-small\">%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            Glib::wrap(event->device, true)->get_seat()->ungrab();
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            Glib::wrap(event->device, true)->get_seat()->ungrab();
694    # endif
695    #endif
696          move.active = false;          move.active = false;
697    
         if (move.pos) {  
             instrument_struct_to_be_changed_signal.emit(instrument);  
             region->SetKeyRange(  
                 region->KeyRange.low  + move.pos,  
                 region->KeyRange.high + move.pos  
             );  
             instrument_struct_changed_signal.emit(instrument);  
         }  
   
698          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
699    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
700              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));              get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
701    #else
702                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;              cursor_is_resize = true;
714          }          }
715      }      }
716      return true;      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();
728                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    void RegionChooser::update_after_move(int pos)
743    {
744        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        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 321  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                Glib::wrap(event->device, true)->get_seat()->grab(
818                    get_window(),
819                    Gdk::SeatCapabilities::SEAT_CAPABILITY_ALL_POINTING,
820                    false,
821                    Gdk::Cursor::create(
822                        Glib::wrap(event->device, true)->get_seat()->get_display(),
823                        Gdk::SB_H_DOUBLE_ARROW
824                    ),
825                    reinterpret_cast<GdkEvent*>(event)
826                );
827    # endif
828    #endif
829              resize.active = true;              resize.active = true;
830          } else {          } else {
831              gig::Region* r = get_region(k);              gig::Region* r = get_region(k);
# Line 333  bool RegionChooser::on_button_press_even Line 833  bool RegionChooser::on_button_press_even
833                  region = r;                  region = r;
834                  queue_draw();                  queue_draw();
835                  region_selected();                  region_selected();
836                    dimensionManager.set_region(region);
837    
838    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
839                  get_window()->pointer_grab(false,                  get_window()->pointer_grab(false,
840                                             Gdk::BUTTON_RELEASE_MASK |                                             Gdk::BUTTON_RELEASE_MASK |
841                                             Gdk::POINTER_MOTION_MASK |                                             Gdk::POINTER_MOTION_MASK |
842                                             Gdk::POINTER_MOTION_HINT_MASK,                                             Gdk::POINTER_MOTION_HINT_MASK,
843                                             Gdk::Cursor(Gdk::FLEUR), event->time);                                             Gdk::Cursor(Gdk::FLEUR),
844                                               event->time);
845    #else
846    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
847                Glib::wrap(event->device, true)->grab(get_window(),
848                                                      Gdk::OWNERSHIP_NONE,
849                                                      false,
850                                                      Gdk::BUTTON_RELEASE_MASK |
851                                                      Gdk::POINTER_MOTION_MASK |
852                                                      Gdk::POINTER_MOTION_HINT_MASK,
853                                                      Gdk::Cursor::create(Gdk::FLEUR),
854                                                      event->time);
855    # else
856                Glib::wrap(event->device, true)->get_seat()->grab(
857                    get_window(),
858                    Gdk::SeatCapabilities::SEAT_CAPABILITY_ALL_POINTING,
859                    false,
860                    Gdk::Cursor::create(
861                        Glib::wrap(event->device, true)->get_seat()->get_display(),
862                        Gdk::FLEUR
863                    ),
864                    reinterpret_cast<GdkEvent*>(event)
865                );
866    # endif
867    #endif
868                  move.active = true;                  move.active = true;
869                  move.from_x = event->x;                  move.offset = event->x - key_to_x(region->KeyRange.low, w);
                 move.pos = 0;  
870              }              }
871          }          }
872      }      }
# Line 350  bool RegionChooser::on_button_press_even Line 875  bool RegionChooser::on_button_press_even
875    
876  gig::Region* RegionChooser::get_region(int key)  gig::Region* RegionChooser::get_region(int key)
877  {  {
878      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();  
   
879          if (key < r->KeyRange.low) return 0;          if (key < r->KeyRange.low) return 0;
880          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;  
881      }      }
882      return 0;      return 0;
883  }  }
884    
885    void RegionChooser::set_region(gig::Region* region) {
886        this->region = region;
887        queue_draw();
888        region_selected();
889        dimensionManager.set_region(region);
890    }
891    
892    void RegionChooser::select_next_region() {
893        if (!instrument) return;
894        if (!region) {
895            for (int i = 0; i < 128; ++i) {
896                ::gig::Region* rgn = instrument->GetRegion(i);
897                if (rgn) {
898                    set_region(rgn);
899                    return;
900                }
901            }
902        } else {
903            bool currentFound = false;
904            for (int i = 0; i < 128; ++i) {
905                ::gig::Region* rgn = instrument->GetRegion(i);
906                if (!rgn) continue;
907                if (currentFound) {
908                    if (rgn != region) {
909                        set_region(rgn);
910                        return;
911                    }
912                } else {
913                    if (rgn == region) currentFound = true;
914                }
915            }
916        }
917    }
918    
919    void RegionChooser::select_prev_region() {
920        if (!instrument) return;
921        if (!region) {
922            for (int i = 0; i < 128; ++i) {
923                ::gig::Region* rgn = instrument->GetRegion(i);
924                if (rgn) {
925                    set_region(rgn);
926                    return;
927                }
928            }
929        } else {
930            bool currentFound = false;
931            for (int i = 127; i >= 0; --i) {
932                ::gig::Region* rgn = instrument->GetRegion(i);
933                if (!rgn) continue;
934                if (currentFound) {
935                    if (rgn != region) {
936                        set_region(rgn);
937                        return;
938                    }
939                } else {
940                    if (rgn == region) currentFound = true;
941                }
942            }
943        }
944    }
945    
946  void RegionChooser::motion_resize_region(int x, int y)  void RegionChooser::motion_resize_region(int x, int y)
947  {  {
948      const int w = width - 1;      const int w = get_width() - 1;
     Glib::RefPtr<Gdk::Window> window = get_window();  
949    
950      int k = int(double(x) / w * 128.0 + 0.5);      int k = int(double(x) / w * 128.0 + 0.5);
951    
# Line 390  void RegionChooser::motion_resize_region Line 965  void RegionChooser::motion_resize_region
965                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
966              }              }
967          }          }
968          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);  
969    
970            int x1, x2;
971          if (resize.mode == resize.moving_high_limit) {          if (resize.mode == resize.moving_high_limit) {
972              if (k > resize.pos) {              if (resize.region->KeyRange.high < resize.pos - 1) {
973                  window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);                  x1 = resize.region->KeyRange.high;
974                  window->draw_line(black, prevx, 0, x, 0);                  x2 = resize.pos - 1;
                 window->draw_line(black, prevx, h1 - 1, x, h1 - 1);  
975              } else {              } else {
976                  int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);                  x1 = resize.pos - 1;
977                  window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);                  x2 = resize.region->KeyRange.high;
978              }              }
979          } else {          } else {
980              if (k < resize.pos) {              if (resize.region->KeyRange.low < resize.pos) {
981                  window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);                  x1 = resize.region->KeyRange.low;
982                  window->draw_line(black, x, 0, prevx, 0);                  x2 = resize.pos;
                 window->draw_line(black, x, h1 - 1, prevx, h1 - 1);  
983              } else {              } else {
984                  int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);                  x1 = resize.pos;
985                  window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);                  x2 = resize.region->KeyRange.low;
986              }              }
987          }          }
988          window->draw_line(black, x, 1, x, h1 - 2);          x1 = key_to_x(x1, w);
989          resize.pos = k;          x2 = key_to_x(x2 + 1, w) + 1;
990            Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
991    
992            update_after_resize();
993    
994            //get_window()->invalidate_rect(rect, false);
995            get_window()->invalidate(false); // repaint entire region, otherwise it would create visual artifacts
996      }      }
997  }  }
998    
999  void RegionChooser::motion_move_region(int x, int y)  void RegionChooser::motion_move_region(int x, int y)
1000  {  {
1001      const int w = width - 1;      const int w = get_width() - 1;
     Glib::RefPtr<Gdk::Window> window = get_window();  
1002    
1003      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);
1004      if (k == move.pos) return;  
1005      int new_k;      if (l == region->KeyRange.low) return;
1006      bool new_touch_left;      int new_l;
1007      bool new_touch_right;      int regionsize = region->KeyRange.high - region->KeyRange.low;
1008      int a = 0;      int a = 0;
1009      if (k > move.pos) {      if (l > region->KeyRange.low) {
1010          for (gig::Region* r = instrument->GetFirstRegion() ; ;          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
              r = instrument->GetNextRegion()) {  
1011              if (r != region) {              if (r != region) {
1012                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
1013    
1014                  // gap: from a to b (not inclusive b)                  // gap: from a to b (not inclusive b)
1015    
1016                  if (region->KeyRange.high + move.pos >= b) {                  if (region->KeyRange.high >= b) {
1017                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
1018                  } else {                  } else {
1019    
1020                      if (a > region->KeyRange.low + k) {                      if (a > l) {
1021                          // this gap is too far to the right, break                          // this gap is too far to the right, break
1022                          break;                          break;
1023                      }                      }
1024    
1025                      int newhigh = std::min(region->KeyRange.high + k, b - 1);                      int newhigh = std::min(l + regionsize, b - 1);
1026                      int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);                      int newlo = newhigh - regionsize;
1027    
1028                      if (newlo >= a) {                      if (newlo >= a) {
1029                          // yes it fits - it's a candidate                          // yes it fits - it's a candidate
1030                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
1031                      }                      }
1032                  }                  }
1033                  if (!r) break;                  if (!r) break;
# Line 467  void RegionChooser::motion_move_region(i Line 1035  void RegionChooser::motion_move_region(i
1035              }              }
1036          }          }
1037      } else {      } else {
1038          for (gig::Region* r = instrument->GetFirstRegion() ; ;          for (gig::Region* r = regions.first() ; ; r = regions.next()) {
              r = instrument->GetNextRegion()) {  
1039              if (r != region) {              if (r != region) {
1040                  int b = r ? r->KeyRange.low : 128;                  int b = r ? r->KeyRange.low : 128;
1041    
1042                  // gap from a to b (not inclusive b)                  // gap from a to b (not inclusive b)
1043    
1044                  if (region->KeyRange.high + k >= b) {                  if (l + regionsize >= b) {
1045                      // not found the current gap yet, just continue                      // not found the current gap yet, just continue
1046                  } else {                  } else {
1047    
1048                      if (a > region->KeyRange.low + move.pos) {                      if (a > region->KeyRange.low) {
1049                          // this gap is too far to the right, break                          // this gap is too far to the right, break
1050                          break;                          break;
1051                      }                      }
1052    
1053                      int newlo = std::max(region->KeyRange.low + k, a);                      int newlo = std::max(l, a);
1054                      int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);                      int newhigh = newlo + regionsize;
1055    
1056                      if (newhigh < b) {                      if (newhigh < b) {
1057                          // yes it fits - break as the first one is the best                          // yes it fits - break as the first one is the best
1058                          new_k = newlo - region->KeyRange.low;                          new_l = newlo;
                         new_touch_left = a > 0 && a == newlo;  
                         new_touch_right = b < 128 && newhigh + 1 == b;  
1059                          break;                          break;
1060                      }                      }
1061                  }                  }
# Line 499  void RegionChooser::motion_move_region(i Line 1064  void RegionChooser::motion_move_region(i
1064              }              }
1065          }          }
1066      }      }
1067      k = new_k;      if (new_l == region->KeyRange.low) return;
     if (k == move.pos) return;  
1068    
1069      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);
1070      int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);      int x2 = key_to_x(std::max(int(region->KeyRange.high),
1071      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);  
1072    
1073          window->draw_rectangle(gc, true, x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);      Gdk::Rectangle rect(x1, 0, x2 - x1, h1);
1074      }      update_after_move(new_l);
1075    
1076      move.pos = k;      get_window()->invalidate_rect(rect, false);
     move.touch_left = new_touch_left;  
     move.touch_right = new_touch_right;  
1077  }  }
1078    
1079    
# Line 543  bool RegionChooser::on_motion_notify_eve Line 1081  bool RegionChooser::on_motion_notify_eve
1081  {  {
1082      Glib::RefPtr<Gdk::Window> window = get_window();      Glib::RefPtr<Gdk::Window> window = get_window();
1083      int x, y;      int x, y;
1084    #if HAS_GDKMM_SEAT
1085        x = event->x;
1086        y = event->y;
1087        Gdk::ModifierType state = Gdk::ModifierType(event->state);
1088    #else
1089      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
1090      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
1091    #endif
1092    
1093        // handle virtual MIDI keyboard
1094        if (m_VirtKeybModeChoice.get_value() != VIRT_KEYBOARD_MODE_CHORD &&
1095            currentActiveKey > 0 &&
1096            event->y >= REGION_BLOCK_HEIGHT &&
1097            event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT)
1098        {
1099            const int k = x_to_key(event->x, get_width() - 1);
1100            if (k != currentActiveKey) {
1101                int velocity =
1102                    (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 :
1103                    int(float(event->y - REGION_BLOCK_HEIGHT) /
1104                        float(KEYBOARD_HEIGHT) * 128.0f) + 1;
1105                if (velocity <= 0) velocity = 1;
1106                keyboard_key_released_signal.emit(currentActiveKey, velocity);
1107                currentActiveKey = k;
1108                keyboard_key_hit_signal.emit(k, velocity);
1109            }
1110        }
1111    
1112      if (resize.active) {      if (resize.active) {
1113          motion_resize_region(x, y);          motion_resize_region(x, y);
# Line 553  bool RegionChooser::on_motion_notify_eve Line 1116  bool RegionChooser::on_motion_notify_eve
1116      } else {      } else {
1117          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
1118              if (!cursor_is_resize) {              if (!cursor_is_resize) {
1119    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1120                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1121    #else
1122                    window->set_cursor(
1123    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1124                        Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1125    # else
1126                        Gdk::Cursor::create(
1127                            Glib::wrap(event->device, true)->get_seat()->get_display(),
1128                            Gdk::SB_H_DOUBLE_ARROW
1129                        )
1130    # endif
1131                    );
1132    #endif
1133                  cursor_is_resize = true;                  cursor_is_resize = true;
1134              }              }
1135          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 566  bool RegionChooser::on_motion_notify_eve Line 1142  bool RegionChooser::on_motion_notify_eve
1142  }  }
1143    
1144  bool RegionChooser::is_in_resize_zone(double x, double y) {  bool RegionChooser::is_in_resize_zone(double x, double y) {
1145      const int w = width - 1;      const int w = get_width() - 1;
1146    
1147      if (instrument && y >= 0 && y <= h1) {      if (instrument && y >= 0 && y <= h1) {
1148          gig::Region* prev_region = 0;          gig::Region* prev_region = 0;
1149          gig::Region* next_region;          gig::Region* next_region;
1150          for (gig::Region* r = instrument->GetFirstRegion() ; r ; r = next_region) {          for (gig::Region* r = regions.first(); r ; r = next_region) {
1151              next_region = instrument->GetNextRegion();              next_region = regions.next();
1152    
1153              int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);              int lo = key_to_x(r->KeyRange.low, w);
1154              if (x <= lo - 2) break;              if (x <= lo - 2) break;
1155              if (x < lo + 2) {              if (x < lo + 2) {
1156                  resize.region = r;                  resize.region = r;
# Line 588  bool RegionChooser::is_in_resize_zone(do Line 1164  bool RegionChooser::is_in_resize_zone(do
1164                      resize.mode = resize.undecided;                      resize.mode = resize.undecided;
1165                      resize.min = prev_region->KeyRange.low + 1;                      resize.min = prev_region->KeyRange.low + 1;
1166                      resize.prev_region = prev_region;                      resize.prev_region = prev_region;
1167                      return true;                      return resize.min != resize.max;
1168                  }                  }
1169    
1170                  // edit low limit                  // edit low limit
1171                  resize.mode = resize.moving_low_limit;                  resize.mode = resize.moving_low_limit;
1172                  resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;                  resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
1173                  return true;                  return resize.min != resize.max;
1174              }              }
1175              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {              if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
1176                  int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);                  int hi = key_to_x(r->KeyRange.high + 1, w);
1177                  if (x <= hi - 2) break;                  if (x <= hi - 2) break;
1178                  if (x < hi + 2) {                  if (x < hi + 2) {
1179                      // edit high limit                      // edit high limit
# Line 606  bool RegionChooser::is_in_resize_zone(do Line 1182  bool RegionChooser::is_in_resize_zone(do
1182                      resize.mode = resize.moving_high_limit;                      resize.mode = resize.moving_high_limit;
1183                      resize.min = r->KeyRange.low + 1;                      resize.min = r->KeyRange.low + 1;
1184                      resize.max = next_region ? next_region->KeyRange.low : 128;                      resize.max = next_region ? next_region->KeyRange.low : 128;
1185                      return true;                      return resize.min != resize.max;
1186                  }                  }
1187              }              }
1188              prev_region = r;              prev_region = r;
# Line 628  sigc::signal<void>& RegionChooser::signa Line 1204  sigc::signal<void>& RegionChooser::signa
1204  void RegionChooser::show_region_properties()  void RegionChooser::show_region_properties()
1205  {  {
1206      if (!region) return;      if (!region) return;
1207      Gtk::Dialog dialog("Region Properties", true /*modal*/);      Gtk::Dialog dialog(_("Region Properties"), true /*modal*/);
1208      // add "Keygroup" checkbox      // add "Keygroup" checkbox
1209      Gtk::CheckButton checkBoxKeygroup("Member of a Keygroup (Exclusive Group)");      Gtk::CheckButton checkBoxKeygroup(_("Member of a Keygroup (Exclusive Group)"));
1210      checkBoxKeygroup.set_active(region->KeyGroup);      checkBoxKeygroup.set_active(region->KeyGroup);
1211    #if USE_GTKMM_BOX
1212        dialog.get_content_area()->pack_start(checkBoxKeygroup);
1213    #else
1214      dialog.get_vbox()->pack_start(checkBoxKeygroup);      dialog.get_vbox()->pack_start(checkBoxKeygroup);
1215    #endif
1216      checkBoxKeygroup.show();      checkBoxKeygroup.show();
1217      // add "Keygroup" spinbox      // add "Keygroup" spinbox
1218      Gtk::Adjustment adjustment(1, 1, pow(2,32));  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1219        Gtk::Adjustment adjustment(1, 1, 999);
1220      Gtk::SpinButton spinBox(adjustment);      Gtk::SpinButton spinBox(adjustment);
1221    #else
1222        Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999));
1223    #endif
1224      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);      if (region->KeyGroup) spinBox.set_value(region->KeyGroup);
1225    #if USE_GTKMM_BOX
1226        dialog.get_content_area()->pack_start(spinBox);
1227    #else
1228      dialog.get_vbox()->pack_start(spinBox);      dialog.get_vbox()->pack_start(spinBox);
1229    #endif
1230      spinBox.show();      spinBox.show();
1231      // add OK and CANCEL buttons to the dialog      // add OK and CANCEL buttons to the dialog
1232    #if HAS_GTKMM_STOCK
1233      dialog.add_button(Gtk::Stock::OK, 0);      dialog.add_button(Gtk::Stock::OK, 0);
1234      dialog.add_button(Gtk::Stock::CANCEL, 1);      dialog.add_button(Gtk::Stock::CANCEL, 1);
1235    #else
1236        dialog.add_button(_("_OK"), 0);
1237        dialog.add_button(_("_Cancel"), 1);
1238    #endif
1239        dialog.set_position(Gtk::WIN_POS_MOUSE);
1240    #if HAS_GTKMM_SHOW_ALL_CHILDREN
1241      dialog.show_all_children();      dialog.show_all_children();
1242    #endif
1243      if (!dialog.run()) { // OK selected ...      if (!dialog.run()) { // OK selected ...
1244          region->KeyGroup =          region->KeyGroup =
1245              (checkBoxKeygroup.get_active()) ? spinBox.get_value_as_int() : 0;              (checkBoxKeygroup.get_active()) ? spinBox.get_value_as_int() : 0;
# Line 658  void RegionChooser::add_region() Line 1254  void RegionChooser::add_region()
1254      region->SetKeyRange(new_region_pos, new_region_pos);      region->SetKeyRange(new_region_pos, new_region_pos);
1255    
1256      instrument_struct_changed_signal.emit(instrument);      instrument_struct_changed_signal.emit(instrument);
1257        regions.update(instrument);
1258    
1259      queue_draw();      queue_draw();
1260      region_selected();      region_selected();
1261        dimensionManager.set_region(region);
1262      instrument_changed();      instrument_changed();
1263  }  }
1264    
# Line 669  void RegionChooser::delete_region() Line 1267  void RegionChooser::delete_region()
1267      instrument_struct_to_be_changed_signal.emit(instrument);      instrument_struct_to_be_changed_signal.emit(instrument);
1268      instrument->DeleteRegion(region);      instrument->DeleteRegion(region);
1269      instrument_struct_changed_signal.emit(instrument);      instrument_struct_changed_signal.emit(instrument);
1270        regions.update(instrument);
1271    
1272      region = 0;      region = 0;
1273      queue_draw();      queue_draw();
1274      region_selected();      region_selected();
1275        dimensionManager.set_region(region);
1276      instrument_changed();      instrument_changed();
1277  }  }
1278    
# Line 703  sigc::signal<void, gig::Region*>& Region Line 1303  sigc::signal<void, gig::Region*>& Region
1303  sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {  sigc::signal<void, gig::Region*>& RegionChooser::signal_region_changed_signal() {
1304      return region_changed_signal;      return region_changed_signal;
1305  }  }
1306    
1307    sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_hit() {
1308        return keyboard_key_hit_signal;
1309    }
1310    
1311    sigc::signal<void, int/*key*/, int/*velocity*/>& RegionChooser::signal_keyboard_key_released() {
1312        return keyboard_key_released_signal;
1313    }

Legend:
Removed from v.1396  
changed lines
  Added in v.3460

  ViewVC Help
Powered by ViewVC