/[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 2844 - (hide annotations) (download)
Sun Sep 20 08:49:40 2015 UTC (8 years, 6 months ago) by persson
File size: 40446 byte(s)
* allow building with gtkmm 2 and G/GDK/GTK_DISABLE_DEPRECATED

1 schoenebeck 1225 /*
2 schoenebeck 2695 * Copyright (C) 2006-2015 Andreas Persson
3 schoenebeck 1225 *
4     * This program is free software; you can redistribute it and/or
5     * modify it under the terms of the GNU General Public License as
6     * published by the Free Software Foundation; either version 2, or (at
7     * your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful, but
10     * WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12     * General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with program; see the file COPYING. If not, write to the Free
16     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17     * 02110-1301 USA.
18     */
19    
20 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 <gtkmm/stock.h>
27     #include <glibmm/ustring.h>
28     #include <gtkmm/messagedialog.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 persson 2151 set_can_focus();
93 schoenebeck 2556
94     actionGroup = Gtk::ActionGroup::create();
95     actionGroup->add(
96     Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),
97     sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
98     );
99     actionGroup->add(
100     Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),
101     sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
102     );
103    
104     uiManager = Gtk::UIManager::create();
105     uiManager->insert_action_group(actionGroup);
106     Glib::ustring ui_info =
107     "<ui>"
108     " <popup name='PopupMenuInsideDimRegion'>"
109     " <menuitem action='SplitDimZone'/>"
110     " <menuitem action='DeleteDimZone'/>"
111     " </popup>"
112     // " <popup name='PopupMenuOutsideDimRegion'>"
113     // " <menuitem action='Add'/>"
114     // " </popup>"
115     "</ui>";
116     uiManager->add_ui_from_string(ui_info);
117    
118     popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
119     uiManager->get_widget("/PopupMenuInsideDimRegion"));
120     // popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
121     // uiManager->get_widget("/PopupMenuOutsideDimRegion"));
122    
123 schoenebeck 1225 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
124     Gdk::POINTER_MOTION_HINT_MASK);
125    
126 persson 2246 labels_changed = true;
127 schoenebeck 2556
128 schoenebeck 2626 set_tooltip_text(_(
129     "Right click here for options on altering dimension zones. Press and "
130     "hold CTRL key for selecting multiple dimension zones simultaniously."
131     ));
132    
133     window.signal_key_press_event().connect(
134     sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
135     );
136     window.signal_key_release_event().connect(
137     sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
138     );
139 schoenebeck 1225 }
140    
141     DimRegionChooser::~DimRegionChooser()
142     {
143     }
144    
145 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
146     bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
147 schoenebeck 1225 {
148 persson 2246 double clipx1 = e->area.x;
149     double clipx2 = e->area.x + e->area.width;
150     double clipy1 = e->area.y;
151     double clipy2 = e->area.y + e->area.height;
152    
153     const Cairo::RefPtr<Cairo::Context>& cr =
154     get_window()->create_cairo_context();
155     #else
156 persson 2169 bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
157     {
158 persson 2246 double clipx1, clipx2, clipy1, clipy2;
159     cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
160     #endif
161    
162 schoenebeck 1225 if (!region) return true;
163    
164     // This is where we draw on the window
165 persson 1623 int w = get_width();
166 schoenebeck 1225 Glib::RefPtr<Pango::Context> context = get_pango_context();
167    
168     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
169 persson 2151 cr->set_line_width(1);
170 schoenebeck 1225
171     int y = 0;
172 persson 2246 if (labels_changed || label_width - 10 > clipx1) {
173     // draw labels on the left (reflecting the dimension type)
174     double maxwidth = 0;
175     for (int i = 0 ; i < region->Dimensions ; i++) {
176     int nbZones = region->pDimensionDefinitions[i].zones;
177     if (nbZones) {
178     const char* dstr;
179     char dstrbuf[10];
180     switch (region->pDimensionDefinitions[i].dimension) {
181     case gig::dimension_none: dstr=_("none"); break;
182     case gig::dimension_samplechannel: dstr=_("samplechannel");
183     break;
184     case gig::dimension_layer: dstr=_("layer"); break;
185     case gig::dimension_velocity: dstr=_("velocity"); break;
186     case gig::dimension_channelaftertouch:
187     dstr=_("channelaftertouch"); break;
188     case gig::dimension_releasetrigger:
189     dstr=_("releasetrigger"); break;
190     case gig::dimension_keyboard: dstr=_("keyswitching"); break;
191     case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
192     case gig::dimension_random: dstr=_("random"); break;
193     case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
194     case gig::dimension_roundrobinkeyboard:
195     dstr=_("roundrobinkeyboard"); break;
196     case gig::dimension_modwheel: dstr=_("modwheel"); break;
197     case gig::dimension_breath: dstr=_("breath"); break;
198     case gig::dimension_foot: dstr=_("foot"); break;
199     case gig::dimension_portamentotime:
200     dstr=_("portamentotime"); break;
201     case gig::dimension_effect1: dstr=_("effect1"); break;
202     case gig::dimension_effect2: dstr=_("effect2"); break;
203     case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
204     case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
205     case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
206     case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
207     case gig::dimension_sustainpedal:
208     dstr=_("sustainpedal"); break;
209     case gig::dimension_portamento: dstr=_("portamento"); break;
210     case gig::dimension_sostenutopedal:
211     dstr=_("sostenutopedal"); break;
212     case gig::dimension_softpedal: dstr=_("softpedal"); break;
213     case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
214     case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
215     case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
216     case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
217     case gig::dimension_effect1depth:
218     dstr=_("effect1depth"); break;
219     case gig::dimension_effect2depth:
220     dstr=_("effect2depth"); break;
221     case gig::dimension_effect3depth:
222     dstr=_("effect3depth"); break;
223     case gig::dimension_effect4depth:
224     dstr=_("effect4depth"); break;
225     case gig::dimension_effect5depth:
226     dstr=_("effect5depth"); break;
227     default:
228     sprintf(dstrbuf, "%d",
229     region->pDimensionDefinitions[i].dimension);
230     dstr = dstrbuf;
231     break;
232     }
233     layout->set_text(dstr);
234 schoenebeck 1225
235 persson 2246 Pango::Rectangle rectangle = layout->get_logical_extents();
236     double text_w = double(rectangle.get_width()) / Pango::SCALE;
237     if (text_w > maxwidth) maxwidth = text_w;
238    
239     if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
240     double text_h = double(rectangle.get_height()) /
241     Pango::SCALE;
242 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
243 persson 2246 const Gdk::Color fg = get_style()->get_fg(get_state());
244 persson 2169 #else
245 persson 2246 const Gdk::RGBA fg =
246     get_style_context()->get_color(get_state_flags());
247 persson 2169 #endif
248 persson 2246 Gdk::Cairo::set_source_rgba(cr, fg);
249     cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
250 persson 2151 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
251 persson 2246 pango_cairo_show_layout(cr->cobj(), layout->gobj());
252 persson 2151 #else
253 persson 2246 layout->show_in_cairo_context(cr);
254 persson 2151 #endif
255 persson 2246 }
256     }
257     y += h;
258 schoenebeck 1225 }
259 persson 2246 label_width = int(maxwidth + 10);
260     labels_changed = false;
261 schoenebeck 1225 }
262 persson 2246 if (label_width >= clipx2) return true;
263 schoenebeck 1225
264     // draw dimensions' zones areas
265     y = 0;
266     int bitpos = 0;
267     for (int i = 0 ; i < region->Dimensions ; i++) {
268     int nbZones = region->pDimensionDefinitions[i].zones;
269     if (nbZones) {
270 schoenebeck 2626 const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
271    
272 persson 2246 if (y >= clipy2) break;
273     if (y + h > clipy1) {
274     // draw focus rectangle around dimension's label and zones
275     if (has_focus() && focus_line == i) {
276 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
277 schoenebeck 2627 Gdk::Rectangle farea(0, y, 150, h);
278 persson 2246 get_style()->paint_focus(get_window(), get_state(), farea,
279     *this, "",
280 schoenebeck 2627 0, y, label_width, h);
281 persson 2169 #else
282 persson 2246 get_style_context()->render_focus(cr,
283 schoenebeck 2627 0, y, label_width, h);
284 persson 2169 #endif
285 persson 2246 }
286 schoenebeck 1225
287 persson 2246 // draw top and bottom lines of dimension's zones
288     Gdk::Cairo::set_source_rgba(cr, black);
289     cr->move_to(label_width, y + 0.5);
290     cr->line_to(w, y + 0.5);
291     cr->move_to(w, y + h - 0.5);
292     cr->line_to(label_width, y + h - 0.5);
293     cr->stroke();
294 persson 2151
295 persson 2246 // erase whole dimension's zones area
296     Gdk::Cairo::set_source_rgba(cr, white);
297     cr->rectangle(label_width + 1, y + 1,
298     (w - label_width - 2), h - 2);
299     cr->fill();
300 schoenebeck 1225
301 persson 2246 int c = 0;
302 schoenebeck 2626 if (maindimregno >= 0) {
303 persson 2246 int mask =
304     ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
305     bitpos);
306 schoenebeck 2626 c = maindimregno & mask; // mask away this dimension
307 schoenebeck 1225 }
308 persson 2246 bool customsplits =
309     ((region->pDimensionDefinitions[i].split_type ==
310     gig::split_type_normal &&
311     region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
312     (region->pDimensionDefinitions[i].dimension ==
313     gig::dimension_velocity &&
314     region->pDimensionRegions[c]->VelocityUpperLimit));
315 schoenebeck 1225
316 schoenebeck 2626 // draw dimension zones
317 persson 2246 Gdk::Cairo::set_source_rgba(cr, black);
318 schoenebeck 1225 if (customsplits) {
319 persson 2246 cr->move_to(label_width + 0.5, y + 1);
320     cr->line_to(label_width + 0.5, y + h - 1);
321 schoenebeck 2626 int prevX = label_width;
322 schoenebeck 2627 int prevUpperLimit = -1;
323 persson 2246
324 schoenebeck 1225 for (int j = 0 ; j < nbZones ; j++) {
325 schoenebeck 2626 // draw dimension zone's borders for custom splits
326 persson 2246 gig::DimensionRegion* d =
327     region->pDimensionRegions[c + (j << bitpos)];
328 schoenebeck 1225 int upperLimit = d->DimensionUpperLimits[i];
329     if (!upperLimit) upperLimit = d->VelocityUpperLimit;
330     int v = upperLimit + 1;
331 persson 2246 int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
332     label_width;
333     if (x >= clipx2) break;
334     if (x < clipx1) continue;
335 schoenebeck 2626 Gdk::Cairo::set_source_rgba(cr, black);
336 persson 2246 cr->move_to(x + 0.5, y + 1);
337     cr->line_to(x + 0.5, y + h - 1);
338 schoenebeck 2626 cr->stroke();
339    
340     // draw fill for zone
341     bool isSelectedZone = this->dimzones[dimension].count(j);
342     Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
343     cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
344     cr->fill();
345    
346     // draw text showing the beginning of the dimension zone
347     // as numeric value to the user
348     {
349     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
350 schoenebeck 2627 layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
351 schoenebeck 2626 Gdk::Cairo::set_source_rgba(cr, black);
352     // get the text dimensions
353     int text_width, text_height;
354     layout->get_pixel_size(text_width, text_height);
355     // move text to the left end of the dimension zone
356 schoenebeck 2627 cr->move_to(prevX + 3, y + (h - text_height) / 2);
357 schoenebeck 2626 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
358     pango_cairo_show_layout(cr->cobj(), layout->gobj());
359     #else
360     layout->show_in_cairo_context(cr);
361     #endif
362     }
363     // draw text showing the end of the dimension zone
364     // as numeric value to the user
365     {
366     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
367     layout->set_text(Glib::Ascii::dtostr(upperLimit));
368     Gdk::Cairo::set_source_rgba(cr, black);
369     // get the text dimensions
370     int text_width, text_height;
371     layout->get_pixel_size(text_width, text_height);
372     // move text to the left end of the dimension zone
373 schoenebeck 2627 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
374 schoenebeck 2626 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
375     pango_cairo_show_layout(cr->cobj(), layout->gobj());
376     #else
377     layout->show_in_cairo_context(cr);
378     #endif
379     }
380    
381     prevX = x;
382     prevUpperLimit = upperLimit;
383 persson 2246 }
384     } else {
385 schoenebeck 2626 int prevX = 0;
386 persson 2246 for (int j = 0 ; j <= nbZones ; j++) {
387 schoenebeck 2626 // draw dimension zone's borders for normal splits
388 persson 2246 int x = int((w - label_width - 1) * j /
389     double(nbZones) + 0.5) + label_width;
390     if (x >= clipx2) break;
391     if (x < clipx1) continue;
392 schoenebeck 2626 Gdk::Cairo::set_source_rgba(cr, black);
393 persson 2246 cr->move_to(x + 0.5, y + 1);
394     cr->line_to(x + 0.5, y + h - 1);
395 schoenebeck 2626 cr->stroke();
396 persson 2246
397 schoenebeck 2626 if (j != 0) {
398     // draw fill for zone
399     bool isSelectedZone = this->dimzones[dimension].count(j-1);
400     Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
401     cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
402 persson 2151 cr->fill();
403 schoenebeck 2462
404 schoenebeck 2626 // draw text showing the beginning of the dimension zone
405     // as numeric value to the user
406     {
407     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
408     layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
409     Gdk::Cairo::set_source_rgba(cr, black);
410     // get the text dimensions
411     int text_width, text_height;
412     layout->get_pixel_size(text_width, text_height);
413     // move text to the left end of the dimension zone
414 schoenebeck 2627 cr->move_to(prevX + 3, y + (h - text_height) / 2);
415 schoenebeck 2462 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
416 schoenebeck 2626 pango_cairo_show_layout(cr->cobj(), layout->gobj());
417 schoenebeck 2462 #else
418 schoenebeck 2626 layout->show_in_cairo_context(cr);
419 schoenebeck 2462 #endif
420 schoenebeck 2626 }
421     // draw text showing the end of the dimension zone
422     // as numeric value to the user
423     {
424     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
425     layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
426     Gdk::Cairo::set_source_rgba(cr, black);
427     // get the text dimensions
428     int text_width, text_height;
429     layout->get_pixel_size(text_width, text_height);
430     // move text to the left end of the dimension zone
431 schoenebeck 2627 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
432 schoenebeck 2462 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
433 schoenebeck 2626 pango_cairo_show_layout(cr->cobj(), layout->gobj());
434 schoenebeck 2462 #else
435 schoenebeck 2626 layout->show_in_cairo_context(cr);
436 schoenebeck 2462 #endif
437 schoenebeck 2626 }
438     }
439     prevX = x;
440     }
441 schoenebeck 1225 }
442     }
443     y += h;
444     }
445     bitpos += region->pDimensionDefinitions[i].bits;
446     }
447    
448     return true;
449     }
450    
451     void DimRegionChooser::set_region(gig::Region* region)
452     {
453     this->region = region;
454 schoenebeck 2626 maindimregno = 0;
455 schoenebeck 1225 nbDimensions = 0;
456     if (region) {
457     int bitcount = 0;
458     for (int dim = 0 ; dim < region->Dimensions ; dim++) {
459     if (region->pDimensionDefinitions[dim].bits == 0) continue;
460     nbDimensions++;
461    
462 schoenebeck 2626 int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
463 persson 1303 region->pDimensionDefinitions[dim].zones - 1);
464 schoenebeck 2626 maindimregno |= (z << bitcount);
465 schoenebeck 1225 bitcount += region->pDimensionDefinitions[dim].bits;
466     }
467     }
468 persson 1261 dimregion_selected();
469 schoenebeck 2627 set_size_request(800, region ? nbDimensions * h : 0);
470 persson 2169
471 persson 2246 labels_changed = true;
472 schoenebeck 1225 queue_resize();
473 schoenebeck 2626 queue_draw();
474 schoenebeck 1225 }
475    
476 schoenebeck 2556 void DimRegionChooser::refresh_all() {
477     set_region(region);
478     }
479 persson 1533
480     void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
481     std::set<gig::DimensionRegion*>& dimregs) const
482     {
483 schoenebeck 2626 for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
484     gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
485     if (!dimRgn) continue;
486     bool isValidZone;
487     std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
488     if (!isValidZone) continue;
489     for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
490     it != dimCase.end(); ++it)
491     {
492     if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
493    
494     std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
495     this->dimzones.find(it->first);
496     if (itSelectedDimension != this->dimzones.end() &&
497     itSelectedDimension->second.count(it->second)) continue; // is selected
498    
499     goto notSelected;
500 persson 1533 }
501 schoenebeck 2626
502     dimregs.insert(dimRgn);
503    
504     notSelected:
505     ;
506 persson 1533 }
507     }
508    
509 persson 2246 void DimRegionChooser::update_after_resize()
510 schoenebeck 1225 {
511 persson 2246 if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
512 schoenebeck 1225
513 persson 2246 int bitpos = 0;
514     for (int j = 0 ; j < resize.dimension ; j++) {
515     bitpos += region->pDimensionDefinitions[j].bits;
516     }
517     int mask =
518     ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
519 schoenebeck 2626 int c = maindimregno & mask; // mask away this dimension
520 schoenebeck 1225
521 persson 2246 if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
522     // the velocity dimension didn't previously have
523     // custom v3 splits, so we initialize all splits with
524     // default values
525     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
526     for (int j = 0 ; j < nbZones ; j++) {
527     gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
528     d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
529 schoenebeck 1225 }
530 persson 2246 }
531     if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
532     // the velocity dimension didn't previously have
533     // custom v2 splits, so we initialize all splits with
534     // default values
535     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
536     for (int j = 0 ; j < nbZones ; j++) {
537     gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
538     d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
539     }
540     }
541 schoenebeck 1225
542 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];
543     // update both v2 and v3 values
544     d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
545     d->VelocityUpperLimit = resize.pos - 1;
546    
547     } else {
548     for (int i = 0 ; i < region->DimensionRegions ; ) {
549    
550     if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
551     // the dimension didn't previously have custom
552     // limits, so we have to set default limits for
553     // all the dimension regions
554     int bitpos = 0;
555     for (int j = 0 ; j < resize.dimension ; j++) {
556     bitpos += region->pDimensionDefinitions[j].bits;
557     }
558 schoenebeck 1225 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
559 persson 2246
560 schoenebeck 1225 for (int j = 0 ; j < nbZones ; j++) {
561 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
562 schoenebeck 1225 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
563     }
564     }
565 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];
566 schoenebeck 1225 d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
567    
568 persson 2246 int bitpos = 0;
569     int j;
570     for (j = 0 ; j < region->Dimensions ; j++) {
571     if (j != resize.dimension) {
572     int maxzones = 1 << region->pDimensionDefinitions[j].bits;
573     int dimj = (i >> bitpos) & (maxzones - 1);
574     if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
575 schoenebeck 1225 }
576 persson 2246 bitpos += region->pDimensionDefinitions[j].bits;
577 schoenebeck 1225 }
578 persson 2246 if (j == region->Dimensions) break;
579     i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
580 schoenebeck 1225 }
581 persson 2246 }
582     }
583    
584     bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
585     {
586     if (resize.active) {
587     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
588     get_window()->pointer_ungrab(event->time);
589     #else
590     Glib::wrap(event->device, true)->ungrab(event->time);
591     #endif
592     resize.active = false;
593    
594 persson 1261 region_changed();
595 schoenebeck 1225
596     if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
597     get_window()->set_cursor();
598     cursor_is_resize = false;
599     }
600     }
601     return true;
602     }
603    
604     bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
605     {
606 persson 1623 int w = get_width();
607 schoenebeck 1225 if (region && event->y < nbDimensions * h &&
608     event->x >= label_width && event->x < w) {
609    
610     if (is_in_resize_zone(event->x, event->y)) {
611 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
612 schoenebeck 1225 get_window()->pointer_grab(false,
613     Gdk::BUTTON_RELEASE_MASK |
614     Gdk::POINTER_MOTION_MASK |
615     Gdk::POINTER_MOTION_HINT_MASK,
616 persson 2169 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
617     event->time);
618     #else
619     Glib::wrap(event->device, true)->grab(get_window(),
620     Gdk::OWNERSHIP_NONE,
621     false,
622     Gdk::BUTTON_RELEASE_MASK |
623     Gdk::POINTER_MOTION_MASK |
624     Gdk::POINTER_MOTION_HINT_MASK,
625     Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
626     event->time);
627     #endif
628 schoenebeck 1225 resize.active = true;
629     } else {
630     int ydim = int(event->y / h);
631     int dim;
632     for (dim = 0 ; dim < region->Dimensions ; dim++) {
633     if (region->pDimensionDefinitions[dim].bits == 0) continue;
634     if (ydim == 0) break;
635     ydim--;
636     }
637     int nbZones = region->pDimensionDefinitions[dim].zones;
638    
639     int z = -1;
640     int bitpos = 0;
641     for (int i = 0 ; i < dim ; i++) {
642     bitpos += region->pDimensionDefinitions[i].bits;
643     }
644    
645     int i = dim;
646 schoenebeck 2626 if (maindimregno < 0) maindimregno = 0;
647 schoenebeck 1225 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
648 schoenebeck 2626 int c = this->maindimregno & mask; // mask away this dimension
649 schoenebeck 1225
650     bool customsplits =
651     ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
652     region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
653     (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
654     region->pDimensionRegions[c]->VelocityUpperLimit));
655     if (customsplits) {
656     int val = int((event->x - label_width) * 128 / (w - label_width - 1));
657    
658     if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
659     for (z = 0 ; z < nbZones ; z++) {
660 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
661 schoenebeck 1225 if (val <= d->DimensionUpperLimits[i]) break;
662     }
663     } else {
664     for (z = 0 ; z < nbZones ; z++) {
665 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
666 schoenebeck 1225 if (val <= d->VelocityUpperLimit) break;
667     }
668     }
669     } else {
670     z = int((event->x - label_width) * nbZones / (w - label_width - 1));
671     }
672    
673     printf("dim=%d z=%d dimensionsource=%d split_type=%d zones=%d zone_size=%f\n", dim, z,
674     region->pDimensionDefinitions[dim].dimension,
675     region->pDimensionDefinitions[dim].split_type,
676     region->pDimensionDefinitions[dim].zones,
677     region->pDimensionDefinitions[dim].zone_size);
678 schoenebeck 2626 this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
679     this->maindimregno = c | (z << bitpos);
680     this->maindimtype = region->pDimensionDefinitions[dim].dimension;
681 schoenebeck 1225
682 schoenebeck 2626 if (multiSelectKeyDown) {
683     if (dimzones[this->maindimtype].count(z)) {
684     if (dimzones[this->maindimtype].size() > 1) {
685     dimzones[this->maindimtype].erase(z);
686     }
687     } else {
688     dimzones[this->maindimtype].insert(z);
689     }
690     } else {
691     this->dimzones.clear();
692     for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
693     it != this->maindimcase.end(); ++it)
694     {
695     this->dimzones[it->first].insert(it->second);
696     }
697     }
698 schoenebeck 1225
699     focus_line = dim;
700     if (has_focus()) queue_draw();
701     else grab_focus();
702 persson 1261 dimregion_selected();
703 schoenebeck 2556
704     if (event->button == 3) {
705     printf("dimregion right click\n");
706     popup_menu_inside_dimregion->popup(event->button, event->time);
707     }
708 schoenebeck 2626
709     queue_draw();
710 schoenebeck 1225 }
711     }
712     return true;
713     }
714    
715     bool DimRegionChooser::on_motion_notify_event(GdkEventMotion* event)
716     {
717     Glib::RefPtr<Gdk::Window> window = get_window();
718     int x, y;
719     Gdk::ModifierType state = Gdk::ModifierType(0);
720     window->get_pointer(x, y, state);
721    
722     if (resize.active) {
723 persson 1623 int w = get_width();
724 schoenebeck 1225 int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
725    
726     if (k < resize.min) k = resize.min;
727     else if (k > resize.max) k = resize.max;
728    
729     if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
730    
731     if (k != resize.pos) {
732     int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
733     int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
734     int y = resize.dimension * h;
735 persson 2246 int x1, x2;
736     if (k > resize.pos) {
737     x1 = prevx;
738     x2 = x;
739 schoenebeck 1225 } else {
740 persson 2246 x1 = x;
741     x2 = prevx;
742 schoenebeck 1225 }
743 persson 2246 Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
744 persson 2151
745 schoenebeck 1225 resize.pos = k;
746 persson 2246 update_after_resize();
747 schoenebeck 2626 get_window()->invalidate_rect(rect, false); // not sufficient ...
748     queue_draw(); // ... so do a complete redraw instead.
749 schoenebeck 1225 }
750     } else {
751     if (is_in_resize_zone(x, y)) {
752     if (!cursor_is_resize) {
753 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
754     window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
755     #else
756     window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
757     #endif
758 schoenebeck 1225 cursor_is_resize = true;
759     }
760     } else if (cursor_is_resize) {
761     window->set_cursor();
762     cursor_is_resize = false;
763     }
764     }
765     return true;
766     }
767    
768     bool DimRegionChooser::is_in_resize_zone(double x, double y)
769     {
770 persson 1623 int w = get_width();
771 schoenebeck 1225 if (region && y < nbDimensions * h && x >= label_width && x < w) {
772     int ydim = int(y / h);
773     int dim;
774     int bitpos = 0;
775     for (dim = 0 ; dim < region->Dimensions ; dim++) {
776     if (region->pDimensionDefinitions[dim].bits == 0) continue;
777     if (ydim == 0) break;
778     ydim--;
779     bitpos += region->pDimensionDefinitions[dim].bits;
780     }
781     int nbZones = region->pDimensionDefinitions[dim].zones;
782    
783     int c = 0;
784 schoenebeck 2626 if (maindimregno >= 0) {
785 schoenebeck 1225 int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
786 schoenebeck 2626 c = maindimregno & mask; // mask away this dimension
787 schoenebeck 1225 }
788     const bool customsplits =
789     ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
790     region->pDimensionRegions[c]->DimensionUpperLimits[dim]) ||
791     (region->pDimensionDefinitions[dim].dimension == gig::dimension_velocity &&
792     region->pDimensionRegions[c]->VelocityUpperLimit));
793    
794     // dimensions of split_type_bit cannot be resized
795     if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
796     int prev_limit = 0;
797     for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
798 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
799 schoenebeck 1225 const int upperLimit =
800     (customsplits) ?
801     (d->DimensionUpperLimits[dim]) ?
802     d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
803     : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
804     int limit = upperLimit + 1;
805     int limitx = int((w - label_width - 1) * limit / 128.0 + 0.5) + label_width;
806     if (x <= limitx - 2) break;
807     if (x <= limitx + 2) {
808     resize.dimension = dim;
809     resize.offset = iZone << bitpos;
810     resize.pos = limit;
811     resize.min = prev_limit;
812    
813 schoenebeck 2626 int dr = (maindimregno >> bitpos) &
814 schoenebeck 1225 ((1 << region->pDimensionDefinitions[dim].bits) - 1);
815     resize.selected = dr == iZone ? resize.left :
816     dr == iZone + 1 ? resize.right : resize.none;
817    
818     iZone++;
819 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
820 schoenebeck 1225
821     const int upperLimit =
822     (customsplits) ?
823     (d->DimensionUpperLimits[dim]) ?
824     d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
825     : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
826    
827     int limit = upperLimit + 1;
828     resize.max = limit;
829     return true;
830     }
831     prev_limit = limit;
832     }
833     }
834     }
835     return false;
836     }
837    
838 schoenebeck 1339 sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
839 schoenebeck 1225 {
840 persson 1261 return dimregion_selected;
841 schoenebeck 1225 }
842    
843 schoenebeck 1339 sigc::signal<void>& DimRegionChooser::signal_region_changed()
844 persson 1261 {
845     return region_changed;
846     }
847    
848 schoenebeck 1225 bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
849     {
850 persson 2841 // TODO: check that region exists etc, that is, that it's possible
851     // to set focus
852 schoenebeck 1225 if (direction == Gtk::DIR_TAB_FORWARD ||
853     direction == Gtk::DIR_DOWN) {
854     if (!has_focus()) {
855     focus_line = 0;
856     grab_focus();
857     return true;
858     } else {
859     if (focus_line + 1 < region->Dimensions) {
860     focus_line++;
861     queue_draw();
862     return true;
863     } else {
864     return false;
865     }
866     }
867     } else if (direction == Gtk::DIR_TAB_BACKWARD ||
868     direction == Gtk::DIR_UP) {
869     if (!has_focus()) {
870     focus_line = region->Dimensions - 1;
871     grab_focus();
872     return true;
873     } else {
874     if (focus_line > 0) {
875     focus_line--;
876     queue_draw();
877     return true;
878     } else {
879     return false;
880     }
881     }
882     } else if (!has_focus()) {
883 persson 2841 // TODO: check that focus_line exists
884 schoenebeck 1225 grab_focus();
885     return true;
886     } else {
887 persson 2841 // TODO: increase or decrease value
888 schoenebeck 1225 }
889 persson 2841 return false;
890 schoenebeck 1225 }
891 schoenebeck 2556
892 schoenebeck 2626 void DimRegionChooser::split_dimension_zone() {
893     printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
894 schoenebeck 2556 try {
895 schoenebeck 2626 region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
896 schoenebeck 2556 } catch (RIFF::Exception e) {
897     Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
898     msg.run();
899     } catch (...) {
900     Glib::ustring txt = _("An unknown exception occurred!");
901     Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
902     msg.run();
903     }
904     refresh_all();
905     }
906    
907     void DimRegionChooser::delete_dimension_zone() {
908 schoenebeck 2626 printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
909 schoenebeck 2556 try {
910 schoenebeck 2626 region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
911 schoenebeck 2556 } catch (RIFF::Exception e) {
912     Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
913     msg.run();
914     } catch (...) {
915     Glib::ustring txt = _("An unknown exception occurred!");
916     Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
917     msg.run();
918     }
919     refresh_all();
920     }
921 schoenebeck 2626
922     bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
923     //printf("key down\n");
924     if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
925     multiSelectKeyDown = true;
926 persson 2841 return false;
927 schoenebeck 2626 }
928    
929     bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
930     //printf("key up\n");
931     if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
932     multiSelectKeyDown = false;
933 persson 2841 return false;
934 schoenebeck 2626 }
935    
936 schoenebeck 2695 void DimRegionChooser::resetSelectedZones() {
937     this->dimzones.clear();
938     if (!region) {
939     queue_draw(); // redraw required parts
940     return;
941     }
942     if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
943     queue_draw(); // redraw required parts
944     return;
945     }
946     if (!region->pDimensionRegions[maindimregno]) {
947     queue_draw(); // redraw required parts
948     return;
949     }
950     gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
951    
952     bool isValidZone;
953     this->maindimcase = caseOfDimRegion(dimrgn, &isValidZone);
954     if (!isValidZone) {
955     queue_draw(); // redraw required parts
956     return;
957     }
958    
959     for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
960     it != this->maindimcase.end(); ++it)
961     {
962     this->dimzones[it->first].insert(it->second);
963     }
964    
965     // redraw required parts
966     queue_draw();
967     }
968    
969     bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
970     if (!region) return false; //.selection failed
971    
972     for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
973     if (region->pDimensionRegions[dr] == dimrgn) {
974     // reset dim region zone selection to the requested specific dim region case
975     maindimregno = dr;
976     resetSelectedZones();
977    
978     // emit signal that dimregion selection has changed, for external entities
979     dimregion_selected();
980    
981     return true; // selection success
982     }
983     }
984    
985     return false; //.selection failed
986     }
987    
988 schoenebeck 2626 gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
989     if (!region) return NULL;
990     return region->pDimensionRegions[maindimregno];
991     }

  ViewVC Help
Powered by ViewVC