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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3123 - (hide annotations) (download)
Tue Apr 25 20:45:54 2017 UTC (7 years ago) by schoenebeck
File size: 55472 byte(s)
* Implemented fast navigation through regions by keyboard accelerator
  Ctrl+Left and Ctrl+Right (on Mac: Cmd+Left and Cmd+Right).
* Implemented fast navigation through dimension region zones of currently
  selected region by keyboard accelerator Alt+Left, Alt+Right, Alt+Up,
  Alt+Down, as well as simply using the arrow keys alone if the dimension
  region chooser got focus (i.e. when it was selected by mouse previously).
* Bumped version (1.0.0.svn29).

1 schoenebeck 1225 /*
2 schoenebeck 3089 * Copyright (C) 2006-2017 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 persson 2844 #include <gtkmm/box.h>
21 schoenebeck 1225 #include "dimregionchooser.h"
22 persson 2151 #include <cairomm/context.h>
23 schoenebeck 1225 #include <gdkmm/cursor.h>
24 persson 2151 #include <gdkmm/general.h>
25 persson 2470 #include <glibmm/stringutils.h>
26 schoenebeck 2556 #include <glibmm/ustring.h>
27     #include <gtkmm/messagedialog.h>
28 schoenebeck 3089 #include <assert.h>
29 schoenebeck 1225
30 persson 1831 #include "global.h"
31    
32 schoenebeck 3123 //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
33     static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
34     DimensionCase dimCase;
35 schoenebeck 2626 if (!dr) {
36     *isValidZone = false;
37     return dimCase;
38     }
39    
40     gig::Region* rgn = (gig::Region*) dr->GetParent();
41    
42     // find the dimension region index of the passed dimension region
43     int drIndex;
44     for (drIndex = 0; drIndex < 256; ++drIndex)
45     if (rgn->pDimensionRegions[drIndex] == dr)
46     break;
47    
48     // not found in region, something's horribly wrong
49     if (drIndex == 256) {
50     fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
51     *isValidZone = false;
52 schoenebeck 3123 return DimensionCase();
53 schoenebeck 2626 }
54    
55     for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
56     const int bits = rgn->pDimensionDefinitions[d].bits;
57     dimCase[rgn->pDimensionDefinitions[d].dimension] =
58     (drIndex >> baseBits) & ((1 << bits) - 1);
59     baseBits += bits;
60     // there are also DimensionRegion objects of unused zones, skip them
61     if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
62     *isValidZone = false;
63 schoenebeck 3123 return DimensionCase();
64 schoenebeck 2626 }
65     }
66    
67     *isValidZone = true;
68     return dimCase;
69     }
70    
71     DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
72 persson 2169 red("#8070ff"),
73     black("black"),
74     white("white")
75 schoenebeck 1225 {
76     instrument = 0;
77     region = 0;
78 schoenebeck 2626 maindimregno = -1;
79 schoenebeck 3123 maindimtype = gig::dimension_none; // initialize with invalid dimension type
80 schoenebeck 1225 focus_line = 0;
81     resize.active = false;
82     cursor_is_resize = false;
83 schoenebeck 2627 h = 24;
84 schoenebeck 2626 multiSelectKeyDown = false;
85 schoenebeck 3089 modifybothchannels = modifyalldimregs = modifybothchannels = false;
86 persson 2151 set_can_focus();
87 schoenebeck 2556
88 schoenebeck 3105 const Glib::ustring txtUseCheckBoxAllRegions =
89     _("Use checkbox 'all regions' to control whether this should apply to all regions.");
90    
91 schoenebeck 2556 actionGroup = Gtk::ActionGroup::create();
92 schoenebeck 3105 actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
93     actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
94 schoenebeck 2556 actionGroup->add(
95 schoenebeck 3105 actionSplitDimZone,
96 schoenebeck 2556 sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
97     );
98 schoenebeck 3105 actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
99     actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
100 schoenebeck 2556 actionGroup->add(
101 schoenebeck 3105 actionDeleteDimZone,
102 schoenebeck 2556 sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
103     );
104    
105     uiManager = Gtk::UIManager::create();
106     uiManager->insert_action_group(actionGroup);
107     Glib::ustring ui_info =
108     "<ui>"
109     " <popup name='PopupMenuInsideDimRegion'>"
110     " <menuitem action='SplitDimZone'/>"
111     " <menuitem action='DeleteDimZone'/>"
112     " </popup>"
113     // " <popup name='PopupMenuOutsideDimRegion'>"
114     // " <menuitem action='Add'/>"
115     // " </popup>"
116     "</ui>";
117     uiManager->add_ui_from_string(ui_info);
118    
119     popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
120     uiManager->get_widget("/PopupMenuInsideDimRegion"));
121     // popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
122     // uiManager->get_widget("/PopupMenuOutsideDimRegion"));
123    
124 schoenebeck 1225 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
125     Gdk::POINTER_MOTION_HINT_MASK);
126    
127 persson 2246 labels_changed = true;
128 schoenebeck 2556
129 schoenebeck 2626 set_tooltip_text(_(
130     "Right click here for options on altering dimension zones. Press and "
131     "hold CTRL key for selecting multiple dimension zones simultaniously."
132     ));
133    
134     window.signal_key_press_event().connect(
135     sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
136     );
137     window.signal_key_release_event().connect(
138     sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
139     );
140 schoenebeck 1225 }
141    
142     DimRegionChooser::~DimRegionChooser()
143     {
144     }
145    
146 schoenebeck 3089 void DimRegionChooser::setModifyBothChannels(bool b) {
147     modifybothchannels = b;
148     }
149    
150     void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
151     modifyalldimregs = b;
152     }
153    
154     void DimRegionChooser::setModifyAllRegions(bool b) {
155     modifyallregions = b;
156 schoenebeck 3105
157     actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
158     actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
159 schoenebeck 3089 }
160    
161 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
162     bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
163 schoenebeck 1225 {
164 persson 2246 double clipx1 = e->area.x;
165     double clipx2 = e->area.x + e->area.width;
166     double clipy1 = e->area.y;
167     double clipy2 = e->area.y + e->area.height;
168    
169     const Cairo::RefPtr<Cairo::Context>& cr =
170     get_window()->create_cairo_context();
171     #else
172 persson 2169 bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
173     {
174 persson 2246 double clipx1, clipx2, clipy1, clipy2;
175     cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
176     #endif
177    
178 schoenebeck 1225 if (!region) return true;
179    
180     // This is where we draw on the window
181 persson 1623 int w = get_width();
182 schoenebeck 1225 Glib::RefPtr<Pango::Context> context = get_pango_context();
183    
184     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
185 persson 2151 cr->set_line_width(1);
186 schoenebeck 1225
187     int y = 0;
188 persson 2246 if (labels_changed || label_width - 10 > clipx1) {
189     // draw labels on the left (reflecting the dimension type)
190     double maxwidth = 0;
191     for (int i = 0 ; i < region->Dimensions ; i++) {
192     int nbZones = region->pDimensionDefinitions[i].zones;
193     if (nbZones) {
194     const char* dstr;
195     char dstrbuf[10];
196     switch (region->pDimensionDefinitions[i].dimension) {
197     case gig::dimension_none: dstr=_("none"); break;
198     case gig::dimension_samplechannel: dstr=_("samplechannel");
199     break;
200     case gig::dimension_layer: dstr=_("layer"); break;
201     case gig::dimension_velocity: dstr=_("velocity"); break;
202     case gig::dimension_channelaftertouch:
203     dstr=_("channelaftertouch"); break;
204     case gig::dimension_releasetrigger:
205     dstr=_("releasetrigger"); break;
206     case gig::dimension_keyboard: dstr=_("keyswitching"); break;
207     case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
208     case gig::dimension_random: dstr=_("random"); break;
209     case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
210     case gig::dimension_roundrobinkeyboard:
211     dstr=_("roundrobinkeyboard"); break;
212     case gig::dimension_modwheel: dstr=_("modwheel"); break;
213     case gig::dimension_breath: dstr=_("breath"); break;
214     case gig::dimension_foot: dstr=_("foot"); break;
215     case gig::dimension_portamentotime:
216     dstr=_("portamentotime"); break;
217     case gig::dimension_effect1: dstr=_("effect1"); break;
218     case gig::dimension_effect2: dstr=_("effect2"); break;
219     case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
220     case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
221     case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
222     case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
223     case gig::dimension_sustainpedal:
224     dstr=_("sustainpedal"); break;
225     case gig::dimension_portamento: dstr=_("portamento"); break;
226     case gig::dimension_sostenutopedal:
227     dstr=_("sostenutopedal"); break;
228     case gig::dimension_softpedal: dstr=_("softpedal"); break;
229     case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
230     case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
231     case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
232     case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
233     case gig::dimension_effect1depth:
234     dstr=_("effect1depth"); break;
235     case gig::dimension_effect2depth:
236     dstr=_("effect2depth"); break;
237     case gig::dimension_effect3depth:
238     dstr=_("effect3depth"); break;
239     case gig::dimension_effect4depth:
240     dstr=_("effect4depth"); break;
241     case gig::dimension_effect5depth:
242     dstr=_("effect5depth"); break;
243     default:
244     sprintf(dstrbuf, "%d",
245     region->pDimensionDefinitions[i].dimension);
246     dstr = dstrbuf;
247     break;
248     }
249     layout->set_text(dstr);
250 schoenebeck 1225
251 persson 2246 Pango::Rectangle rectangle = layout->get_logical_extents();
252     double text_w = double(rectangle.get_width()) / Pango::SCALE;
253     if (text_w > maxwidth) maxwidth = text_w;
254    
255     if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
256     double text_h = double(rectangle.get_height()) /
257     Pango::SCALE;
258 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
259 persson 2246 const Gdk::Color fg = get_style()->get_fg(get_state());
260 persson 2169 #else
261 persson 2246 const Gdk::RGBA fg =
262     get_style_context()->get_color(get_state_flags());
263 persson 2169 #endif
264 persson 2246 Gdk::Cairo::set_source_rgba(cr, fg);
265     cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
266 persson 2151 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
267 persson 2246 pango_cairo_show_layout(cr->cobj(), layout->gobj());
268 persson 2151 #else
269 persson 2246 layout->show_in_cairo_context(cr);
270 persson 2151 #endif
271 persson 2246 }
272     }
273     y += h;
274 schoenebeck 1225 }
275 persson 2246 label_width = int(maxwidth + 10);
276     labels_changed = false;
277 schoenebeck 1225 }
278 persson 2246 if (label_width >= clipx2) return true;
279 schoenebeck 1225
280     // draw dimensions' zones areas
281     y = 0;
282     int bitpos = 0;
283     for (int i = 0 ; i < region->Dimensions ; i++) {
284     int nbZones = region->pDimensionDefinitions[i].zones;
285     if (nbZones) {
286 schoenebeck 2626 const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
287    
288 persson 2246 if (y >= clipy2) break;
289     if (y + h > clipy1) {
290     // draw focus rectangle around dimension's label and zones
291     if (has_focus() && focus_line == i) {
292 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
293 schoenebeck 2627 Gdk::Rectangle farea(0, y, 150, h);
294 persson 2246 get_style()->paint_focus(get_window(), get_state(), farea,
295     *this, "",
296 schoenebeck 2627 0, y, label_width, h);
297 persson 2169 #else
298 persson 2246 get_style_context()->render_focus(cr,
299 schoenebeck 2627 0, y, label_width, h);
300 persson 2169 #endif
301 persson 2246 }
302 schoenebeck 1225
303 persson 2246 // draw top and bottom lines of dimension's zones
304     Gdk::Cairo::set_source_rgba(cr, black);
305     cr->move_to(label_width, y + 0.5);
306     cr->line_to(w, y + 0.5);
307     cr->move_to(w, y + h - 0.5);
308     cr->line_to(label_width, y + h - 0.5);
309     cr->stroke();
310 persson 2151
311 persson 2246 // erase whole dimension's zones area
312     Gdk::Cairo::set_source_rgba(cr, white);
313     cr->rectangle(label_width + 1, y + 1,
314     (w - label_width - 2), h - 2);
315     cr->fill();
316 schoenebeck 1225
317 persson 2246 int c = 0;
318 schoenebeck 2626 if (maindimregno >= 0) {
319 persson 2246 int mask =
320     ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
321     bitpos);
322 schoenebeck 2626 c = maindimregno & mask; // mask away this dimension
323 schoenebeck 1225 }
324 persson 2246 bool customsplits =
325     ((region->pDimensionDefinitions[i].split_type ==
326     gig::split_type_normal &&
327     region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
328     (region->pDimensionDefinitions[i].dimension ==
329     gig::dimension_velocity &&
330     region->pDimensionRegions[c]->VelocityUpperLimit));
331 schoenebeck 1225
332 schoenebeck 2626 // draw dimension zones
333 persson 2246 Gdk::Cairo::set_source_rgba(cr, black);
334 schoenebeck 1225 if (customsplits) {
335 persson 2246 cr->move_to(label_width + 0.5, y + 1);
336     cr->line_to(label_width + 0.5, y + h - 1);
337 schoenebeck 2626 int prevX = label_width;
338 schoenebeck 2627 int prevUpperLimit = -1;
339 persson 2246
340 schoenebeck 1225 for (int j = 0 ; j < nbZones ; j++) {
341 schoenebeck 2626 // draw dimension zone's borders for custom splits
342 persson 2246 gig::DimensionRegion* d =
343     region->pDimensionRegions[c + (j << bitpos)];
344 schoenebeck 1225 int upperLimit = d->DimensionUpperLimits[i];
345     if (!upperLimit) upperLimit = d->VelocityUpperLimit;
346     int v = upperLimit + 1;
347 persson 2246 int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
348     label_width;
349     if (x >= clipx2) break;
350     if (x < clipx1) continue;
351 schoenebeck 2626 Gdk::Cairo::set_source_rgba(cr, black);
352 persson 2246 cr->move_to(x + 0.5, y + 1);
353     cr->line_to(x + 0.5, y + h - 1);
354 schoenebeck 2626 cr->stroke();
355    
356     // draw fill for zone
357     bool isSelectedZone = this->dimzones[dimension].count(j);
358     Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
359     cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
360     cr->fill();
361    
362     // draw text showing the beginning of the dimension zone
363     // as numeric value to the user
364     {
365     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
366 schoenebeck 2627 layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
367 schoenebeck 2626 Gdk::Cairo::set_source_rgba(cr, black);
368     // get the text dimensions
369     int text_width, text_height;
370     layout->get_pixel_size(text_width, text_height);
371     // move text to the left end of the dimension zone
372 schoenebeck 2627 cr->move_to(prevX + 3, y + (h - text_height) / 2);
373 schoenebeck 2626 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
374     pango_cairo_show_layout(cr->cobj(), layout->gobj());
375     #else
376     layout->show_in_cairo_context(cr);
377     #endif
378     }
379     // draw text showing the end of the dimension zone
380     // as numeric value to the user
381     {
382     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
383     layout->set_text(Glib::Ascii::dtostr(upperLimit));
384     Gdk::Cairo::set_source_rgba(cr, black);
385     // get the text dimensions
386     int text_width, text_height;
387     layout->get_pixel_size(text_width, text_height);
388     // move text to the left end of the dimension zone
389 schoenebeck 2627 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
390 schoenebeck 2626 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
391     pango_cairo_show_layout(cr->cobj(), layout->gobj());
392     #else
393     layout->show_in_cairo_context(cr);
394     #endif
395     }
396    
397     prevX = x;
398     prevUpperLimit = upperLimit;
399 persson 2246 }
400     } else {
401 schoenebeck 2626 int prevX = 0;
402 persson 2246 for (int j = 0 ; j <= nbZones ; j++) {
403 schoenebeck 2626 // draw dimension zone's borders for normal splits
404 persson 2246 int x = int((w - label_width - 1) * j /
405     double(nbZones) + 0.5) + label_width;
406     if (x >= clipx2) break;
407     if (x < clipx1) continue;
408 schoenebeck 2626 Gdk::Cairo::set_source_rgba(cr, black);
409 persson 2246 cr->move_to(x + 0.5, y + 1);
410     cr->line_to(x + 0.5, y + h - 1);
411 schoenebeck 2626 cr->stroke();
412 persson 2246
413 schoenebeck 2626 if (j != 0) {
414     // draw fill for zone
415     bool isSelectedZone = this->dimzones[dimension].count(j-1);
416     Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
417     cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
418 persson 2151 cr->fill();
419 schoenebeck 2462
420 schoenebeck 2626 // draw text showing the beginning of the dimension zone
421     // as numeric value to the user
422     {
423     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
424     layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
425     Gdk::Cairo::set_source_rgba(cr, black);
426     // get the text dimensions
427     int text_width, text_height;
428     layout->get_pixel_size(text_width, text_height);
429     // move text to the left end of the dimension zone
430 schoenebeck 2627 cr->move_to(prevX + 3, y + (h - text_height) / 2);
431 schoenebeck 2462 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
432 schoenebeck 2626 pango_cairo_show_layout(cr->cobj(), layout->gobj());
433 schoenebeck 2462 #else
434 schoenebeck 2626 layout->show_in_cairo_context(cr);
435 schoenebeck 2462 #endif
436 schoenebeck 2626 }
437     // draw text showing the end of the dimension zone
438     // as numeric value to the user
439     {
440     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
441     layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
442     Gdk::Cairo::set_source_rgba(cr, black);
443     // get the text dimensions
444     int text_width, text_height;
445     layout->get_pixel_size(text_width, text_height);
446     // move text to the left end of the dimension zone
447 schoenebeck 2627 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
448 schoenebeck 2462 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
449 schoenebeck 2626 pango_cairo_show_layout(cr->cobj(), layout->gobj());
450 schoenebeck 2462 #else
451 schoenebeck 2626 layout->show_in_cairo_context(cr);
452 schoenebeck 2462 #endif
453 schoenebeck 2626 }
454     }
455     prevX = x;
456     }
457 schoenebeck 1225 }
458     }
459     y += h;
460     }
461     bitpos += region->pDimensionDefinitions[i].bits;
462     }
463    
464     return true;
465     }
466    
467     void DimRegionChooser::set_region(gig::Region* region)
468     {
469     this->region = region;
470 schoenebeck 2626 maindimregno = 0;
471 schoenebeck 1225 nbDimensions = 0;
472     if (region) {
473     int bitcount = 0;
474     for (int dim = 0 ; dim < region->Dimensions ; dim++) {
475     if (region->pDimensionDefinitions[dim].bits == 0) continue;
476     nbDimensions++;
477    
478 schoenebeck 2626 int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
479 persson 1303 region->pDimensionDefinitions[dim].zones - 1);
480 schoenebeck 2626 maindimregno |= (z << bitcount);
481 schoenebeck 1225 bitcount += region->pDimensionDefinitions[dim].bits;
482     }
483     }
484 persson 1261 dimregion_selected();
485 schoenebeck 2627 set_size_request(800, region ? nbDimensions * h : 0);
486 persson 2169
487 persson 2246 labels_changed = true;
488 schoenebeck 1225 queue_resize();
489 schoenebeck 2626 queue_draw();
490 schoenebeck 1225 }
491    
492 schoenebeck 2556 void DimRegionChooser::refresh_all() {
493     set_region(region);
494     }
495 persson 1533
496     void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
497     std::set<gig::DimensionRegion*>& dimregs) const
498     {
499 schoenebeck 2626 for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
500     gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
501     if (!dimRgn) continue;
502     bool isValidZone;
503     std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
504     if (!isValidZone) continue;
505     for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
506     it != dimCase.end(); ++it)
507     {
508     if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
509    
510     std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
511     this->dimzones.find(it->first);
512     if (itSelectedDimension != this->dimzones.end() &&
513     itSelectedDimension->second.count(it->second)) continue; // is selected
514    
515     goto notSelected;
516 persson 1533 }
517 schoenebeck 2626
518     dimregs.insert(dimRgn);
519    
520     notSelected:
521     ;
522 persson 1533 }
523     }
524    
525 persson 2246 void DimRegionChooser::update_after_resize()
526 schoenebeck 1225 {
527 schoenebeck 3089 const uint8_t upperLimit = resize.pos - 1;
528     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
529    
530     int bitpos = 0;
531     for (int j = 0 ; j < resize.dimension ; j++) {
532     bitpos += region->pDimensionDefinitions[j].bits;
533     }
534    
535     const int stereobitpos =
536     (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
537    
538     // the velocity dimension must be handled differently than all other
539     // dimension types, because
540     // 1. it is currently the only dimension type which allows different zone
541     // sizes for different cases
542     // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
543 persson 2246 if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
544     int mask =
545     ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
546 schoenebeck 2626 int c = maindimregno & mask; // mask away this dimension
547 schoenebeck 1225
548 persson 2246 if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
549     // the velocity dimension didn't previously have
550     // custom v3 splits, so we initialize all splits with
551     // default values
552     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
553     for (int j = 0 ; j < nbZones ; j++) {
554     gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
555     d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
556 schoenebeck 1225 }
557 persson 2246 }
558     if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
559     // the velocity dimension didn't previously have
560     // custom v2 splits, so we initialize all splits with
561     // default values
562     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
563     for (int j = 0 ; j < nbZones ; j++) {
564     gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
565     d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
566     }
567     }
568 schoenebeck 1225
569 schoenebeck 3089 int index = c + (resize.zone << bitpos);
570     gig::DimensionRegion* d = region->pDimensionRegions[index];
571 persson 2246 // update both v2 and v3 values
572 schoenebeck 3089 d->DimensionUpperLimits[resize.dimension] = upperLimit;
573     d->VelocityUpperLimit = upperLimit;
574     if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
575     gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
576     d->DimensionUpperLimits[resize.dimension] = upperLimit;
577     d->VelocityUpperLimit = upperLimit;
578     }
579 persson 2246
580 schoenebeck 3089 if (modifyalldimregs) {
581     gig::Region* rgn = NULL;
582     for (int key = 0; key < 128; ++key) {
583     if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
584     rgn = instr->GetRegion(key);
585     if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
586     gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
587     if (!dimdef) continue;
588     if (dimdef->zones != resize.dimensionDef.zones) continue;
589     const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
590     assert(iDim >= 0 && iDim < rgn->Dimensions);
591    
592     // the dimension layout might be completely different in this
593     // region, so we have to recalculate bitpos etc for this region
594     const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
595     const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
596     const int selection = resize.zone << bitpos;
597    
598     // primitive and inefficient loop implementation, however due to
599     // this circumstance the loop code is much simpler, and its lack
600     // of runtime efficiency should not be notable in practice
601     for (int idr = 0; idr < 256; ++idr) {
602     const int index = (idr & stencil) | selection;
603     assert(index >= 0 && index < 256);
604     gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
605     if (!dr) continue;
606     dr->DimensionUpperLimits[iDim] = upperLimit;
607     d->VelocityUpperLimit = upperLimit;
608     }
609     }
610     } else if (modifyallregions) { // implies modifyalldimregs is false ...
611     // resolve the precise case we need to modify for all other regions
612     DimensionCase dimCase = dimensionCaseOf(d);
613     // apply the velocity upper limit change to that resolved dim case
614     // of all regions ...
615     gig::Region* rgn = NULL;
616     for (int key = 0; key < 128; ++key) {
617     if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
618     rgn = instr->GetRegion(key);
619     gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
620     if (!dimdef) continue;
621     if (dimdef->zones != resize.dimensionDef.zones) continue;
622     const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
623     assert(iDim >= 0 && iDim < rgn->Dimensions);
624    
625     std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
626     for (int i = 0; i < dimrgns.size(); ++i) {
627     gig::DimensionRegion* dr = dimrgns[i];
628     dr->DimensionUpperLimits[iDim] = upperLimit;
629     dr->VelocityUpperLimit = upperLimit;
630     }
631     }
632     }
633 persson 2246 } else {
634     for (int i = 0 ; i < region->DimensionRegions ; ) {
635     if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
636     // the dimension didn't previously have custom
637     // limits, so we have to set default limits for
638     // all the dimension regions
639 schoenebeck 1225 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
640 persson 2246
641 schoenebeck 1225 for (int j = 0 ; j < nbZones ; j++) {
642 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
643 schoenebeck 1225 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
644     }
645     }
646 schoenebeck 3089 int index = i + (resize.zone << bitpos);
647     gig::DimensionRegion* d = region->pDimensionRegions[index];
648     d->DimensionUpperLimits[resize.dimension] = upperLimit;
649     #if 0 // the following is currently not necessary, because ATM the gig format uses for all dimension types except of the veleocity dimension the same zone sizes for all cases
650     if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
651     gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
652     d->DimensionUpperLimits[resize.dimension] = upperLimit;
653     }
654     #endif
655 persson 2246 int bitpos = 0;
656     int j;
657     for (j = 0 ; j < region->Dimensions ; j++) {
658     if (j != resize.dimension) {
659     int maxzones = 1 << region->pDimensionDefinitions[j].bits;
660     int dimj = (i >> bitpos) & (maxzones - 1);
661     if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
662 schoenebeck 1225 }
663 persson 2246 bitpos += region->pDimensionDefinitions[j].bits;
664 schoenebeck 1225 }
665 persson 2246 if (j == region->Dimensions) break;
666     i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
667 schoenebeck 1225 }
668 schoenebeck 3089
669     if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
670     gig::Region* rgn = NULL;
671     for (int key = 0; key < 128; ++key) {
672     if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
673     rgn = instr->GetRegion(key);
674     gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
675     if (!dimdef) continue;
676     if (dimdef->zones != resize.dimensionDef.zones) continue;
677     const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
678     assert(iDim >= 0 && iDim < rgn->Dimensions);
679    
680     // the dimension layout might be completely different in this
681     // region, so we have to recalculate bitpos etc for this region
682     const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
683     const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
684     const int selection = resize.zone << bitpos;
685    
686     // this loop implementation is less efficient than the above's
687     // loop implementation (which skips unnecessary dimension regions)
688     // however this code is much simpler, and its lack of runtime
689     // efficiency should not be notable in practice
690     for (int idr = 0; idr < 256; ++idr) {
691     const int index = (idr & stencil) | selection;
692     assert(index >= 0 && index < 256);
693     gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
694     if (!dr) continue;
695     dr->DimensionUpperLimits[iDim] = upperLimit;
696     }
697     }
698     }
699 persson 2246 }
700     }
701    
702     bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
703     {
704     if (resize.active) {
705     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
706     get_window()->pointer_ungrab(event->time);
707     #else
708     Glib::wrap(event->device, true)->ungrab(event->time);
709     #endif
710     resize.active = false;
711    
712 persson 1261 region_changed();
713 schoenebeck 1225
714     if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
715     get_window()->set_cursor();
716     cursor_is_resize = false;
717     }
718     }
719     return true;
720     }
721    
722     bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
723     {
724 persson 1623 int w = get_width();
725 schoenebeck 1225 if (region && event->y < nbDimensions * h &&
726     event->x >= label_width && event->x < w) {
727    
728     if (is_in_resize_zone(event->x, event->y)) {
729 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
730 schoenebeck 1225 get_window()->pointer_grab(false,
731     Gdk::BUTTON_RELEASE_MASK |
732     Gdk::POINTER_MOTION_MASK |
733     Gdk::POINTER_MOTION_HINT_MASK,
734 persson 2169 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
735     event->time);
736     #else
737     Glib::wrap(event->device, true)->grab(get_window(),
738     Gdk::OWNERSHIP_NONE,
739     false,
740     Gdk::BUTTON_RELEASE_MASK |
741     Gdk::POINTER_MOTION_MASK |
742     Gdk::POINTER_MOTION_HINT_MASK,
743     Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
744     event->time);
745     #endif
746 schoenebeck 1225 resize.active = true;
747     } else {
748     int ydim = int(event->y / h);
749     int dim;
750     for (dim = 0 ; dim < region->Dimensions ; dim++) {
751     if (region->pDimensionDefinitions[dim].bits == 0) continue;
752     if (ydim == 0) break;
753     ydim--;
754     }
755     int nbZones = region->pDimensionDefinitions[dim].zones;
756    
757     int z = -1;
758     int bitpos = 0;
759     for (int i = 0 ; i < dim ; i++) {
760     bitpos += region->pDimensionDefinitions[i].bits;
761     }
762    
763     int i = dim;
764 schoenebeck 2626 if (maindimregno < 0) maindimregno = 0;
765 schoenebeck 1225 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
766 schoenebeck 2626 int c = this->maindimregno & mask; // mask away this dimension
767 schoenebeck 1225
768     bool customsplits =
769     ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
770     region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
771     (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
772     region->pDimensionRegions[c]->VelocityUpperLimit));
773     if (customsplits) {
774     int val = int((event->x - label_width) * 128 / (w - label_width - 1));
775    
776     if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
777     for (z = 0 ; z < nbZones ; z++) {
778 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
779 schoenebeck 1225 if (val <= d->DimensionUpperLimits[i]) break;
780     }
781     } else {
782     for (z = 0 ; z < nbZones ; z++) {
783 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
784 schoenebeck 1225 if (val <= d->VelocityUpperLimit) break;
785     }
786     }
787     } else {
788     z = int((event->x - label_width) * nbZones / (w - label_width - 1));
789     }
790    
791     printf("dim=%d z=%d dimensionsource=%d split_type=%d zones=%d zone_size=%f\n", dim, z,
792     region->pDimensionDefinitions[dim].dimension,
793     region->pDimensionDefinitions[dim].split_type,
794     region->pDimensionDefinitions[dim].zones,
795     region->pDimensionDefinitions[dim].zone_size);
796 schoenebeck 2626 this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
797     this->maindimregno = c | (z << bitpos);
798     this->maindimtype = region->pDimensionDefinitions[dim].dimension;
799 schoenebeck 1225
800 schoenebeck 2626 if (multiSelectKeyDown) {
801     if (dimzones[this->maindimtype].count(z)) {
802     if (dimzones[this->maindimtype].size() > 1) {
803     dimzones[this->maindimtype].erase(z);
804     }
805     } else {
806     dimzones[this->maindimtype].insert(z);
807     }
808     } else {
809     this->dimzones.clear();
810     for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
811     it != this->maindimcase.end(); ++it)
812     {
813     this->dimzones[it->first].insert(it->second);
814     }
815     }
816 schoenebeck 1225
817     focus_line = dim;
818     if (has_focus()) queue_draw();
819     else grab_focus();
820 persson 1261 dimregion_selected();
821 schoenebeck 2556
822     if (event->button == 3) {
823     printf("dimregion right click\n");
824     popup_menu_inside_dimregion->popup(event->button, event->time);
825     }
826 schoenebeck 2626
827     queue_draw();
828 schoenebeck 1225 }
829     }
830     return true;
831     }
832    
833     bool DimRegionChooser::on_motion_notify_event(GdkEventMotion* event)
834     {
835     Glib::RefPtr<Gdk::Window> window = get_window();
836     int x, y;
837     Gdk::ModifierType state = Gdk::ModifierType(0);
838     window->get_pointer(x, y, state);
839    
840     if (resize.active) {
841 persson 1623 int w = get_width();
842 schoenebeck 1225 int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
843    
844     if (k < resize.min) k = resize.min;
845     else if (k > resize.max) k = resize.max;
846    
847     if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
848    
849     if (k != resize.pos) {
850     int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
851     int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
852     int y = resize.dimension * h;
853 persson 2246 int x1, x2;
854     if (k > resize.pos) {
855     x1 = prevx;
856     x2 = x;
857 schoenebeck 1225 } else {
858 persson 2246 x1 = x;
859     x2 = prevx;
860 schoenebeck 1225 }
861 persson 2246 Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
862 persson 2151
863 schoenebeck 1225 resize.pos = k;
864 persson 2246 update_after_resize();
865 schoenebeck 2626 get_window()->invalidate_rect(rect, false); // not sufficient ...
866     queue_draw(); // ... so do a complete redraw instead.
867 schoenebeck 1225 }
868     } else {
869     if (is_in_resize_zone(x, y)) {
870     if (!cursor_is_resize) {
871 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
872     window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
873     #else
874     window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
875     #endif
876 schoenebeck 1225 cursor_is_resize = true;
877     }
878     } else if (cursor_is_resize) {
879     window->set_cursor();
880     cursor_is_resize = false;
881     }
882     }
883     return true;
884     }
885    
886     bool DimRegionChooser::is_in_resize_zone(double x, double y)
887     {
888 persson 1623 int w = get_width();
889 schoenebeck 1225 if (region && y < nbDimensions * h && x >= label_width && x < w) {
890     int ydim = int(y / h);
891     int dim;
892     int bitpos = 0;
893     for (dim = 0 ; dim < region->Dimensions ; dim++) {
894     if (region->pDimensionDefinitions[dim].bits == 0) continue;
895     if (ydim == 0) break;
896     ydim--;
897     bitpos += region->pDimensionDefinitions[dim].bits;
898     }
899     int nbZones = region->pDimensionDefinitions[dim].zones;
900    
901     int c = 0;
902 schoenebeck 2626 if (maindimregno >= 0) {
903 schoenebeck 1225 int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
904 schoenebeck 2626 c = maindimregno & mask; // mask away this dimension
905 schoenebeck 1225 }
906     const bool customsplits =
907     ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
908     region->pDimensionRegions[c]->DimensionUpperLimits[dim]) ||
909     (region->pDimensionDefinitions[dim].dimension == gig::dimension_velocity &&
910     region->pDimensionRegions[c]->VelocityUpperLimit));
911    
912     // dimensions of split_type_bit cannot be resized
913     if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
914     int prev_limit = 0;
915     for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
916 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
917 schoenebeck 1225 const int upperLimit =
918     (customsplits) ?
919     (d->DimensionUpperLimits[dim]) ?
920     d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
921     : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
922     int limit = upperLimit + 1;
923     int limitx = int((w - label_width - 1) * limit / 128.0 + 0.5) + label_width;
924     if (x <= limitx - 2) break;
925     if (x <= limitx + 2) {
926     resize.dimension = dim;
927 schoenebeck 3089 resize.dimensionDef = region->pDimensionDefinitions[dim];
928     resize.zone = iZone;
929 schoenebeck 1225 resize.pos = limit;
930     resize.min = prev_limit;
931    
932 schoenebeck 2626 int dr = (maindimregno >> bitpos) &
933 schoenebeck 1225 ((1 << region->pDimensionDefinitions[dim].bits) - 1);
934     resize.selected = dr == iZone ? resize.left :
935     dr == iZone + 1 ? resize.right : resize.none;
936    
937     iZone++;
938 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
939 schoenebeck 1225
940     const int upperLimit =
941     (customsplits) ?
942     (d->DimensionUpperLimits[dim]) ?
943     d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
944     : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
945    
946     int limit = upperLimit + 1;
947     resize.max = limit;
948     return true;
949     }
950     prev_limit = limit;
951     }
952     }
953     }
954     return false;
955     }
956    
957 schoenebeck 1339 sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
958 schoenebeck 1225 {
959 persson 1261 return dimregion_selected;
960 schoenebeck 1225 }
961    
962 schoenebeck 1339 sigc::signal<void>& DimRegionChooser::signal_region_changed()
963 persson 1261 {
964     return region_changed;
965     }
966    
967 schoenebeck 1225 bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
968     {
969 persson 2841 // TODO: check that region exists etc, that is, that it's possible
970     // to set focus
971 schoenebeck 1225 if (direction == Gtk::DIR_TAB_FORWARD ||
972     direction == Gtk::DIR_DOWN) {
973     if (!has_focus()) {
974     focus_line = 0;
975     grab_focus();
976     return true;
977     } else {
978     if (focus_line + 1 < region->Dimensions) {
979     focus_line++;
980     queue_draw();
981     return true;
982     } else {
983     return false;
984     }
985     }
986     } else if (direction == Gtk::DIR_TAB_BACKWARD ||
987     direction == Gtk::DIR_UP) {
988     if (!has_focus()) {
989     focus_line = region->Dimensions - 1;
990     grab_focus();
991     return true;
992     } else {
993     if (focus_line > 0) {
994     focus_line--;
995     queue_draw();
996     return true;
997     } else {
998     return false;
999     }
1000     }
1001     } else if (!has_focus()) {
1002 persson 2841 // TODO: check that focus_line exists
1003 schoenebeck 1225 grab_focus();
1004     return true;
1005     } else {
1006 persson 2841 // TODO: increase or decrease value
1007 schoenebeck 1225 }
1008 persson 2841 return false;
1009 schoenebeck 1225 }
1010 schoenebeck 2556
1011 schoenebeck 2626 void DimRegionChooser::split_dimension_zone() {
1012     printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1013 schoenebeck 2556 try {
1014 schoenebeck 3105 if (!modifyallregions) {
1015     region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1016     } else {
1017     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1018     gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1019     assert(pMaindimdef != NULL);
1020     // retain structure by value since the original region will be
1021     // modified in the loop below as well
1022     gig::dimension_def_t maindimdef = *pMaindimdef;
1023     std::vector<gig::Region*> ignoredAll;
1024     std::vector<gig::Region*> ignoredMinor;
1025     std::vector<gig::Region*> ignoredCritical;
1026     gig::Region* rgn = NULL;
1027     for (int key = 0; key < 128; ++key) {
1028     if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1029     rgn = instr->GetRegion(key);
1030    
1031     // ignore all regions which do not exactly match the dimension
1032     // layout of the selected region where this operation was emitted
1033     gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1034     if (!dimdef) {
1035     ignoredAll.push_back(rgn);
1036     ignoredMinor.push_back(rgn);
1037     continue;
1038     }
1039     if (dimdef->zones != maindimdef.zones) {
1040     ignoredAll.push_back(rgn);
1041     ignoredCritical.push_back(rgn);
1042     continue;
1043     }
1044    
1045     rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1046     }
1047     if (!ignoredAll.empty()) {
1048     Glib::ustring txt;
1049     if (ignoredCritical.empty())
1050     txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1051     else if (ignoredMinor.empty())
1052     txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1053     else
1054     txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1055     ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1056     Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1057     Gtk::MessageDialog msg(txt, false, type);
1058     msg.run();
1059     }
1060     }
1061 schoenebeck 2556 } catch (RIFF::Exception e) {
1062     Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1063     msg.run();
1064     } catch (...) {
1065     Glib::ustring txt = _("An unknown exception occurred!");
1066     Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1067     msg.run();
1068     }
1069     refresh_all();
1070     }
1071    
1072     void DimRegionChooser::delete_dimension_zone() {
1073 schoenebeck 2626 printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1074 schoenebeck 2556 try {
1075 schoenebeck 3105 if (!modifyallregions) {
1076     region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1077     } else {
1078     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1079     gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1080     assert(pMaindimdef != NULL);
1081     // retain structure by value since the original region will be
1082     // modified in the loop below as well
1083     gig::dimension_def_t maindimdef = *pMaindimdef;
1084     std::vector<gig::Region*> ignoredAll;
1085     std::vector<gig::Region*> ignoredMinor;
1086     std::vector<gig::Region*> ignoredCritical;
1087     gig::Region* rgn = NULL;
1088     for (int key = 0; key < 128; ++key) {
1089     if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1090     rgn = instr->GetRegion(key);
1091    
1092     // ignore all regions which do not exactly match the dimension
1093     // layout of the selected region where this operation was emitted
1094     gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1095     if (!dimdef) {
1096     ignoredAll.push_back(rgn);
1097     ignoredMinor.push_back(rgn);
1098     continue;
1099     }
1100     if (dimdef->zones != maindimdef.zones) {
1101     ignoredAll.push_back(rgn);
1102     ignoredCritical.push_back(rgn);
1103     continue;
1104     }
1105    
1106     rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1107     }
1108     if (!ignoredAll.empty()) {
1109     Glib::ustring txt;
1110     if (ignoredCritical.empty())
1111     txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1112     else if (ignoredMinor.empty())
1113     txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1114     else
1115     txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1116     ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1117     Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1118     Gtk::MessageDialog msg(txt, false, type);
1119     msg.run();
1120     }
1121     }
1122 schoenebeck 2556 } catch (RIFF::Exception e) {
1123     Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1124     msg.run();
1125     } catch (...) {
1126     Glib::ustring txt = _("An unknown exception occurred!");
1127     Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1128     msg.run();
1129     }
1130     refresh_all();
1131     }
1132 schoenebeck 2626
1133     bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1134 schoenebeck 3123 //printf("key down 0x%x\n", key->keyval);
1135 schoenebeck 2626 if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1136     multiSelectKeyDown = true;
1137 schoenebeck 3123 //FIXME: hmm, for some reason GDKMM does not fire arrow key down events, so we are doing those handlers in the key up handler instead for now
1138     /*if (key->keyval == GDK_KEY_Left)
1139     select_prev_dimzone();
1140     if (key->keyval == GDK_KEY_Right)
1141     select_next_dimzone();
1142     if (key->keyval == GDK_KEY_Up)
1143     select_prev_dimension();
1144     if (key->keyval == GDK_KEY_Down)
1145     select_next_dimension();*/
1146 persson 2841 return false;
1147 schoenebeck 2626 }
1148    
1149     bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1150 schoenebeck 3123 //printf("key up 0x%x\n", key->keyval);
1151 schoenebeck 2626 if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1152     multiSelectKeyDown = false;
1153 schoenebeck 3123
1154     if (!has_focus()) return false;
1155    
1156     if (key->keyval == GDK_KEY_Left)
1157     select_prev_dimzone();
1158     if (key->keyval == GDK_KEY_Right)
1159     select_next_dimzone();
1160     if (key->keyval == GDK_KEY_Up)
1161     select_prev_dimension();
1162     if (key->keyval == GDK_KEY_Down)
1163     select_next_dimension();
1164    
1165 persson 2841 return false;
1166 schoenebeck 2626 }
1167    
1168 schoenebeck 2695 void DimRegionChooser::resetSelectedZones() {
1169     this->dimzones.clear();
1170     if (!region) {
1171     queue_draw(); // redraw required parts
1172     return;
1173     }
1174     if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1175     queue_draw(); // redraw required parts
1176     return;
1177     }
1178     if (!region->pDimensionRegions[maindimregno]) {
1179     queue_draw(); // redraw required parts
1180     return;
1181     }
1182     gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1183    
1184     bool isValidZone;
1185 schoenebeck 3123 this->maindimcase = dimensionCaseOf(dimrgn);
1186 schoenebeck 2695
1187     for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1188     it != this->maindimcase.end(); ++it)
1189     {
1190     this->dimzones[it->first].insert(it->second);
1191     }
1192    
1193     // redraw required parts
1194     queue_draw();
1195     }
1196    
1197     bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1198     if (!region) return false; //.selection failed
1199    
1200     for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1201     if (region->pDimensionRegions[dr] == dimrgn) {
1202     // reset dim region zone selection to the requested specific dim region case
1203     maindimregno = dr;
1204     resetSelectedZones();
1205    
1206     // emit signal that dimregion selection has changed, for external entities
1207     dimregion_selected();
1208    
1209     return true; // selection success
1210     }
1211     }
1212    
1213     return false; //.selection failed
1214     }
1215    
1216 schoenebeck 3123 void DimRegionChooser::select_next_dimzone() {
1217     select_dimzone_by_dir(+1);
1218     }
1219    
1220     void DimRegionChooser::select_prev_dimzone() {
1221     select_dimzone_by_dir(-1);
1222     }
1223    
1224     void DimRegionChooser::select_dimzone_by_dir(int dir) {
1225     if (!region) return;
1226     if (!region->Dimensions) return;
1227     if (focus_line < 0) focus_line = 0;
1228     if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1229    
1230     maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1231     if (maindimtype == gig::dimension_none) {
1232     printf("maindimtype -> none\n");
1233     return;
1234     }
1235    
1236     if (maindimcase.empty()) {
1237     maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1238     if (maindimcase.empty()) {
1239     printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1240     return;
1241     }
1242     }
1243    
1244     int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1245     if (z < 0) z = 0;
1246     if (z >= region->pDimensionDefinitions[focus_line].zones)
1247     z = region->pDimensionDefinitions[focus_line].zones - 1;
1248    
1249     maindimcase[maindimtype] = z;
1250    
1251     ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1252     if (!dr) {
1253     printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1254     return;
1255     }
1256    
1257     maindimregno = getDimensionRegionIndex(dr);
1258    
1259     // reset selected dimregion zones
1260     dimzones.clear();
1261     for (DimensionCase::const_iterator it = maindimcase.begin();
1262     it != maindimcase.end(); ++it)
1263     {
1264     dimzones[it->first].insert(it->second);
1265     }
1266    
1267     dimregion_selected();
1268    
1269     // disabled: would overwrite dimregno with wrong value
1270     //refresh_all();
1271     // so requesting just a raw repaint instead:
1272     queue_draw();
1273     }
1274    
1275     void DimRegionChooser::select_next_dimension() {
1276     if (!region) return;
1277     focus_line++;
1278     if (focus_line >= region->Dimensions)
1279     focus_line = region->Dimensions - 1;
1280     this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1281     queue_draw();
1282     }
1283    
1284     void DimRegionChooser::select_prev_dimension() {
1285     if (!region) return;
1286     focus_line--;
1287     if (focus_line < 0)
1288     focus_line = 0;
1289     this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1290     queue_draw();
1291     }
1292    
1293 schoenebeck 2626 gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1294     if (!region) return NULL;
1295     return region->pDimensionRegions[maindimregno];
1296     }

  ViewVC Help
Powered by ViewVC