/[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 2627 - (hide annotations) (download)
Thu Jun 12 16:12:55 2014 UTC (9 years, 9 months ago) by schoenebeck
File size: 39111 byte(s)
* Increased region selector height by 50%.
* Increased dimension region selector height by 20%.
* Some minor fixes.
* Updated "about" dialog: not so immature anymore ;-).
* Configure script: require at least LinuxSampler v1.0.0.

1 schoenebeck 1225 /*
2 schoenebeck 2556 * Copyright (C) 2006-2014 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     Pango::Rectangle rect = layout->get_logical_extents();
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     Pango::Rectangle rect = layout->get_logical_extents();
370     // get the text dimensions
371     int text_width, text_height;
372     layout->get_pixel_size(text_width, text_height);
373     // move text to the left end of the dimension zone
374 schoenebeck 2627 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
375 schoenebeck 2626 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
376     pango_cairo_show_layout(cr->cobj(), layout->gobj());
377     #else
378     layout->show_in_cairo_context(cr);
379     #endif
380     }
381    
382     prevX = x;
383     prevUpperLimit = upperLimit;
384 persson 2246 }
385     } else {
386 schoenebeck 2626 int prevX = 0;
387 persson 2246 for (int j = 0 ; j <= nbZones ; j++) {
388 schoenebeck 2626 // draw dimension zone's borders for normal splits
389 persson 2246 int x = int((w - label_width - 1) * j /
390     double(nbZones) + 0.5) + label_width;
391     if (x >= clipx2) break;
392     if (x < clipx1) continue;
393 schoenebeck 2626 Gdk::Cairo::set_source_rgba(cr, black);
394 persson 2246 cr->move_to(x + 0.5, y + 1);
395     cr->line_to(x + 0.5, y + h - 1);
396 schoenebeck 2626 cr->stroke();
397 persson 2246
398 schoenebeck 2626 if (j != 0) {
399     // draw fill for zone
400     bool isSelectedZone = this->dimzones[dimension].count(j-1);
401     Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
402     cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
403 persson 2151 cr->fill();
404 schoenebeck 2462
405 schoenebeck 2626 // draw text showing the beginning of the dimension zone
406     // as numeric value to the user
407     {
408     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
409     layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
410     Gdk::Cairo::set_source_rgba(cr, black);
411     Pango::Rectangle rect = layout->get_logical_extents();
412     // get the text dimensions
413     int text_width, text_height;
414     layout->get_pixel_size(text_width, text_height);
415     // move text to the left end of the dimension zone
416 schoenebeck 2627 cr->move_to(prevX + 3, y + (h - text_height) / 2);
417 schoenebeck 2462 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
418 schoenebeck 2626 pango_cairo_show_layout(cr->cobj(), layout->gobj());
419 schoenebeck 2462 #else
420 schoenebeck 2626 layout->show_in_cairo_context(cr);
421 schoenebeck 2462 #endif
422 schoenebeck 2626 }
423     // draw text showing the end of the dimension zone
424     // as numeric value to the user
425     {
426     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
427     layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
428     Gdk::Cairo::set_source_rgba(cr, black);
429     Pango::Rectangle rect = layout->get_logical_extents();
430     // get the text dimensions
431     int text_width, text_height;
432     layout->get_pixel_size(text_width, text_height);
433     // move text to the left end of the dimension zone
434 schoenebeck 2627 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
435 schoenebeck 2462 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
436 schoenebeck 2626 pango_cairo_show_layout(cr->cobj(), layout->gobj());
437 schoenebeck 2462 #else
438 schoenebeck 2626 layout->show_in_cairo_context(cr);
439 schoenebeck 2462 #endif
440 schoenebeck 2626 }
441     }
442     prevX = x;
443     }
444 schoenebeck 1225 }
445     }
446     y += h;
447     }
448     bitpos += region->pDimensionDefinitions[i].bits;
449     }
450    
451     return true;
452     }
453    
454     void DimRegionChooser::set_region(gig::Region* region)
455     {
456     this->region = region;
457 schoenebeck 2626 maindimregno = 0;
458 schoenebeck 1225 nbDimensions = 0;
459     if (region) {
460     int bitcount = 0;
461     for (int dim = 0 ; dim < region->Dimensions ; dim++) {
462     if (region->pDimensionDefinitions[dim].bits == 0) continue;
463     nbDimensions++;
464    
465 schoenebeck 2626 int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
466 persson 1303 region->pDimensionDefinitions[dim].zones - 1);
467 schoenebeck 2626 maindimregno |= (z << bitcount);
468 schoenebeck 1225 bitcount += region->pDimensionDefinitions[dim].bits;
469     }
470     }
471 persson 1261 dimregion_selected();
472 schoenebeck 2627 set_size_request(800, region ? nbDimensions * h : 0);
473 persson 2169
474 persson 2246 labels_changed = true;
475 schoenebeck 1225 queue_resize();
476 schoenebeck 2626 queue_draw();
477 schoenebeck 1225 }
478    
479 schoenebeck 2556 void DimRegionChooser::refresh_all() {
480     set_region(region);
481     }
482 persson 1533
483     void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
484     std::set<gig::DimensionRegion*>& dimregs) const
485     {
486 schoenebeck 2626 for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
487     gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
488     if (!dimRgn) continue;
489     bool isValidZone;
490     std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
491     if (!isValidZone) continue;
492     for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
493     it != dimCase.end(); ++it)
494     {
495     if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
496    
497     std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
498     this->dimzones.find(it->first);
499     if (itSelectedDimension != this->dimzones.end() &&
500     itSelectedDimension->second.count(it->second)) continue; // is selected
501    
502     goto notSelected;
503 persson 1533 }
504 schoenebeck 2626
505     dimregs.insert(dimRgn);
506    
507     notSelected:
508     ;
509 persson 1533 }
510     }
511    
512 persson 2246 void DimRegionChooser::update_after_resize()
513 schoenebeck 1225 {
514 persson 2246 if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
515 schoenebeck 1225
516 persson 2246 int bitpos = 0;
517     for (int j = 0 ; j < resize.dimension ; j++) {
518     bitpos += region->pDimensionDefinitions[j].bits;
519     }
520     int mask =
521     ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
522 schoenebeck 2626 int c = maindimregno & mask; // mask away this dimension
523 schoenebeck 1225
524 persson 2246 if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
525     // the velocity dimension didn't previously have
526     // custom v3 splits, so we initialize all splits with
527     // default values
528     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
529     for (int j = 0 ; j < nbZones ; j++) {
530     gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
531     d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
532 schoenebeck 1225 }
533 persson 2246 }
534     if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
535     // the velocity dimension didn't previously have
536     // custom v2 splits, so we initialize all splits with
537     // default values
538     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
539     for (int j = 0 ; j < nbZones ; j++) {
540     gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
541     d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
542     }
543     }
544 schoenebeck 1225
545 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];
546     // update both v2 and v3 values
547     d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
548     d->VelocityUpperLimit = resize.pos - 1;
549    
550     } else {
551     for (int i = 0 ; i < region->DimensionRegions ; ) {
552    
553     if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
554     // the dimension didn't previously have custom
555     // limits, so we have to set default limits for
556     // all the dimension regions
557     int bitpos = 0;
558     for (int j = 0 ; j < resize.dimension ; j++) {
559     bitpos += region->pDimensionDefinitions[j].bits;
560     }
561 schoenebeck 1225 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
562 persson 2246
563 schoenebeck 1225 for (int j = 0 ; j < nbZones ; j++) {
564 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
565 schoenebeck 1225 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
566     }
567     }
568 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];
569 schoenebeck 1225 d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
570    
571 persson 2246 int bitpos = 0;
572     int j;
573     for (j = 0 ; j < region->Dimensions ; j++) {
574     if (j != resize.dimension) {
575     int maxzones = 1 << region->pDimensionDefinitions[j].bits;
576     int dimj = (i >> bitpos) & (maxzones - 1);
577     if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
578 schoenebeck 1225 }
579 persson 2246 bitpos += region->pDimensionDefinitions[j].bits;
580 schoenebeck 1225 }
581 persson 2246 if (j == region->Dimensions) break;
582     i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
583 schoenebeck 1225 }
584 persson 2246 }
585     }
586    
587     bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
588     {
589     if (resize.active) {
590     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
591     get_window()->pointer_ungrab(event->time);
592     #else
593     Glib::wrap(event->device, true)->ungrab(event->time);
594     #endif
595     resize.active = false;
596    
597 persson 1261 region_changed();
598 schoenebeck 1225
599     if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
600     get_window()->set_cursor();
601     cursor_is_resize = false;
602     }
603     }
604     return true;
605     }
606    
607     bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
608     {
609 persson 1623 int w = get_width();
610 schoenebeck 1225 if (region && event->y < nbDimensions * h &&
611     event->x >= label_width && event->x < w) {
612    
613     if (is_in_resize_zone(event->x, event->y)) {
614 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
615 schoenebeck 1225 get_window()->pointer_grab(false,
616     Gdk::BUTTON_RELEASE_MASK |
617     Gdk::POINTER_MOTION_MASK |
618     Gdk::POINTER_MOTION_HINT_MASK,
619 persson 2169 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
620     event->time);
621     #else
622     Glib::wrap(event->device, true)->grab(get_window(),
623     Gdk::OWNERSHIP_NONE,
624     false,
625     Gdk::BUTTON_RELEASE_MASK |
626     Gdk::POINTER_MOTION_MASK |
627     Gdk::POINTER_MOTION_HINT_MASK,
628     Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
629     event->time);
630     #endif
631 schoenebeck 1225 resize.active = true;
632     } else {
633     int ydim = int(event->y / h);
634     int dim;
635     for (dim = 0 ; dim < region->Dimensions ; dim++) {
636     if (region->pDimensionDefinitions[dim].bits == 0) continue;
637     if (ydim == 0) break;
638     ydim--;
639     }
640     int nbZones = region->pDimensionDefinitions[dim].zones;
641    
642     int z = -1;
643     int bitpos = 0;
644     for (int i = 0 ; i < dim ; i++) {
645     bitpos += region->pDimensionDefinitions[i].bits;
646     }
647    
648     int i = dim;
649 schoenebeck 2626 if (maindimregno < 0) maindimregno = 0;
650 schoenebeck 1225 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
651 schoenebeck 2626 int c = this->maindimregno & mask; // mask away this dimension
652 schoenebeck 1225
653     bool customsplits =
654     ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
655     region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
656     (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
657     region->pDimensionRegions[c]->VelocityUpperLimit));
658     if (customsplits) {
659     int val = int((event->x - label_width) * 128 / (w - label_width - 1));
660    
661     if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
662     for (z = 0 ; z < nbZones ; z++) {
663 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
664 schoenebeck 1225 if (val <= d->DimensionUpperLimits[i]) break;
665     }
666     } else {
667     for (z = 0 ; z < nbZones ; z++) {
668 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
669 schoenebeck 1225 if (val <= d->VelocityUpperLimit) break;
670     }
671     }
672     } else {
673     z = int((event->x - label_width) * nbZones / (w - label_width - 1));
674     }
675    
676     printf("dim=%d z=%d dimensionsource=%d split_type=%d zones=%d zone_size=%f\n", dim, z,
677     region->pDimensionDefinitions[dim].dimension,
678     region->pDimensionDefinitions[dim].split_type,
679     region->pDimensionDefinitions[dim].zones,
680     region->pDimensionDefinitions[dim].zone_size);
681 schoenebeck 2626 this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
682     this->maindimregno = c | (z << bitpos);
683     this->maindimtype = region->pDimensionDefinitions[dim].dimension;
684 schoenebeck 1225
685 schoenebeck 2626 if (multiSelectKeyDown) {
686     if (dimzones[this->maindimtype].count(z)) {
687     if (dimzones[this->maindimtype].size() > 1) {
688     dimzones[this->maindimtype].erase(z);
689     }
690     } else {
691     dimzones[this->maindimtype].insert(z);
692     }
693     } else {
694     this->dimzones.clear();
695     for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
696     it != this->maindimcase.end(); ++it)
697     {
698     this->dimzones[it->first].insert(it->second);
699     }
700     }
701 schoenebeck 1225
702     focus_line = dim;
703     if (has_focus()) queue_draw();
704     else grab_focus();
705 persson 1261 dimregion_selected();
706 schoenebeck 2556
707     if (event->button == 3) {
708     printf("dimregion right click\n");
709     popup_menu_inside_dimregion->popup(event->button, event->time);
710     }
711 schoenebeck 2626
712     queue_draw();
713 schoenebeck 1225 }
714     }
715     return true;
716     }
717    
718     bool DimRegionChooser::on_motion_notify_event(GdkEventMotion* event)
719     {
720     Glib::RefPtr<Gdk::Window> window = get_window();
721     int x, y;
722     Gdk::ModifierType state = Gdk::ModifierType(0);
723     window->get_pointer(x, y, state);
724    
725     if (resize.active) {
726 persson 1623 int w = get_width();
727 schoenebeck 1225 int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
728    
729     if (k < resize.min) k = resize.min;
730     else if (k > resize.max) k = resize.max;
731    
732     if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
733    
734     if (k != resize.pos) {
735     int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
736     int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
737     int y = resize.dimension * h;
738 persson 2246 int x1, x2;
739     if (k > resize.pos) {
740     x1 = prevx;
741     x2 = x;
742 schoenebeck 1225 } else {
743 persson 2246 x1 = x;
744     x2 = prevx;
745 schoenebeck 1225 }
746 persson 2246 Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
747 persson 2151
748 schoenebeck 1225 resize.pos = k;
749 persson 2246 update_after_resize();
750 schoenebeck 2626 get_window()->invalidate_rect(rect, false); // not sufficient ...
751     queue_draw(); // ... so do a complete redraw instead.
752 schoenebeck 1225 }
753     } else {
754     if (is_in_resize_zone(x, y)) {
755     if (!cursor_is_resize) {
756 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
757     window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
758     #else
759     window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
760     #endif
761 schoenebeck 1225 cursor_is_resize = true;
762     }
763     } else if (cursor_is_resize) {
764     window->set_cursor();
765     cursor_is_resize = false;
766     }
767     }
768     return true;
769     }
770    
771     bool DimRegionChooser::is_in_resize_zone(double x, double y)
772     {
773 persson 1623 int w = get_width();
774 schoenebeck 1225 if (region && y < nbDimensions * h && x >= label_width && x < w) {
775     int ydim = int(y / h);
776     int dim;
777     int bitpos = 0;
778     for (dim = 0 ; dim < region->Dimensions ; dim++) {
779     if (region->pDimensionDefinitions[dim].bits == 0) continue;
780     if (ydim == 0) break;
781     ydim--;
782     bitpos += region->pDimensionDefinitions[dim].bits;
783     }
784     int nbZones = region->pDimensionDefinitions[dim].zones;
785    
786     int c = 0;
787 schoenebeck 2626 if (maindimregno >= 0) {
788 schoenebeck 1225 int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
789 schoenebeck 2626 c = maindimregno & mask; // mask away this dimension
790 schoenebeck 1225 }
791     const bool customsplits =
792     ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
793     region->pDimensionRegions[c]->DimensionUpperLimits[dim]) ||
794     (region->pDimensionDefinitions[dim].dimension == gig::dimension_velocity &&
795     region->pDimensionRegions[c]->VelocityUpperLimit));
796    
797     // dimensions of split_type_bit cannot be resized
798     if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
799     int prev_limit = 0;
800     for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
801 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
802 schoenebeck 1225 const int upperLimit =
803     (customsplits) ?
804     (d->DimensionUpperLimits[dim]) ?
805     d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
806     : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
807     int limit = upperLimit + 1;
808     int limitx = int((w - label_width - 1) * limit / 128.0 + 0.5) + label_width;
809     if (x <= limitx - 2) break;
810     if (x <= limitx + 2) {
811     resize.dimension = dim;
812     resize.offset = iZone << bitpos;
813     resize.pos = limit;
814     resize.min = prev_limit;
815    
816 schoenebeck 2626 int dr = (maindimregno >> bitpos) &
817 schoenebeck 1225 ((1 << region->pDimensionDefinitions[dim].bits) - 1);
818     resize.selected = dr == iZone ? resize.left :
819     dr == iZone + 1 ? resize.right : resize.none;
820    
821     iZone++;
822 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
823 schoenebeck 1225
824     const int upperLimit =
825     (customsplits) ?
826     (d->DimensionUpperLimits[dim]) ?
827     d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
828     : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
829    
830     int limit = upperLimit + 1;
831     resize.max = limit;
832     return true;
833     }
834     prev_limit = limit;
835     }
836     }
837     }
838     return false;
839     }
840    
841 schoenebeck 1339 sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
842 schoenebeck 1225 {
843 persson 1261 return dimregion_selected;
844 schoenebeck 1225 }
845    
846 schoenebeck 1339 sigc::signal<void>& DimRegionChooser::signal_region_changed()
847 persson 1261 {
848     return region_changed;
849     }
850    
851 schoenebeck 1225 bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
852     {
853     // TODO: kolla att region finns osv, dvs att det g�r att s�tta
854     // fokus.
855     if (direction == Gtk::DIR_TAB_FORWARD ||
856     direction == Gtk::DIR_DOWN) {
857     if (!has_focus()) {
858     focus_line = 0;
859     grab_focus();
860     return true;
861     } else {
862     if (focus_line + 1 < region->Dimensions) {
863     focus_line++;
864     queue_draw();
865     return true;
866     } else {
867     return false;
868     }
869     }
870     } else if (direction == Gtk::DIR_TAB_BACKWARD ||
871     direction == Gtk::DIR_UP) {
872     if (!has_focus()) {
873     focus_line = region->Dimensions - 1;
874     grab_focus();
875     return true;
876     } else {
877     if (focus_line > 0) {
878     focus_line--;
879     queue_draw();
880     return true;
881     } else {
882     return false;
883     }
884     }
885     } else if (!has_focus()) {
886     // TODO: kolla att focus_line finns!
887     grab_focus();
888     return true;
889     } else {
890     // TODO: �ka eller minska v�rde!
891     }
892     }
893 schoenebeck 2556
894 schoenebeck 2626 void DimRegionChooser::split_dimension_zone() {
895     printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
896 schoenebeck 2556 try {
897 schoenebeck 2626 region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
898 schoenebeck 2556 } catch (RIFF::Exception e) {
899     Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
900     msg.run();
901     } catch (...) {
902     Glib::ustring txt = _("An unknown exception occurred!");
903     Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
904     msg.run();
905     }
906     refresh_all();
907     }
908    
909     void DimRegionChooser::delete_dimension_zone() {
910 schoenebeck 2626 printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
911 schoenebeck 2556 try {
912 schoenebeck 2626 region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
913 schoenebeck 2556 } catch (RIFF::Exception e) {
914     Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
915     msg.run();
916     } catch (...) {
917     Glib::ustring txt = _("An unknown exception occurred!");
918     Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
919     msg.run();
920     }
921     refresh_all();
922     }
923 schoenebeck 2626
924     bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
925     //printf("key down\n");
926     if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
927     multiSelectKeyDown = true;
928     }
929    
930     bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
931     //printf("key up\n");
932     if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
933     multiSelectKeyDown = false;
934     }
935    
936     gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
937     if (!region) return NULL;
938     return region->pDimensionRegions[maindimregno];
939     }

  ViewVC Help
Powered by ViewVC