/[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 3105 - (hide annotations) (download)
Fri Feb 10 18:40:26 2017 UTC (7 years, 2 months ago) by schoenebeck
File size: 52685 byte(s)
* Implemented deleting dimension region zones of all regions at once, which
  is controlled by checkbox "all regions".
* Implemented splitting up dimension region zones of all regions at once,
  which is controlled by checkbox "all regions".
* Bumped version (1.0.0.svn26).

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

  ViewVC Help
Powered by ViewVC