/[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 2841 - (hide annotations) (download)
Sun Aug 30 10:00:49 2015 UTC (8 years, 7 months ago) by persson
File size: 40423 byte(s)
* allow building with G_DISABLE_DEPRECATED
* fixed building without liblinuxsampler on Mac
* fixed some compiler and cppcheck warnings

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

  ViewVC Help
Powered by ViewVC