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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3131 - (hide annotations) (download)
Thu Apr 27 17:28:01 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 37566 byte(s)
* Color tweaking on selected regions and selected dimension zones.
* Dimension Region Chooser: Show main selected case in opaque blue color
  (like before), but all other selected dimension zones with a blue hatched
  pattern instead.
* Dimension Region Chooser: Show the label of the currently selected
  dimension in bold font.
* Fix: Keyboard accelerator Ctrl+Left and Ctrl+Right caused the current
  dimension zone to switch as well if Dimension Region Chooser got focus.

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

  ViewVC Help
Powered by ViewVC