/[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 2556 - (hide annotations) (download)
Fri May 16 23:19:23 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 34158 byte(s)
* Dimension zone amount: Support for increasing and decreasing the amount of
  dimension zones by right clicking on the respective zone and either
  selecting "delete" or "split" in the popup menu.

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 persson 2169 DimRegionChooser::DimRegionChooser() :
32     red("#8070ff"),
33     black("black"),
34     white("white")
35 schoenebeck 1225 {
36     instrument = 0;
37     region = 0;
38     dimregno = -1;
39     focus_line = 0;
40     resize.active = false;
41     cursor_is_resize = false;
42     h = 20;
43 persson 2151 set_can_focus();
44 schoenebeck 2556
45     actionGroup = Gtk::ActionGroup::create();
46     actionGroup->add(
47     Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),
48     sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
49     );
50     actionGroup->add(
51     Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),
52     sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
53     );
54    
55     uiManager = Gtk::UIManager::create();
56     uiManager->insert_action_group(actionGroup);
57     Glib::ustring ui_info =
58     "<ui>"
59     " <popup name='PopupMenuInsideDimRegion'>"
60     " <menuitem action='SplitDimZone'/>"
61     " <menuitem action='DeleteDimZone'/>"
62     " </popup>"
63     // " <popup name='PopupMenuOutsideDimRegion'>"
64     // " <menuitem action='Add'/>"
65     // " </popup>"
66     "</ui>";
67     uiManager->add_ui_from_string(ui_info);
68    
69     popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
70     uiManager->get_widget("/PopupMenuInsideDimRegion"));
71     // popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
72     // uiManager->get_widget("/PopupMenuOutsideDimRegion"));
73    
74 schoenebeck 1225 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
75     Gdk::POINTER_MOTION_HINT_MASK);
76    
77 persson 1303 for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;
78 persson 2246 labels_changed = true;
79 schoenebeck 2556
80     set_tooltip_text(_("Right click here for options on altering dimension zones."));
81 schoenebeck 1225 }
82    
83     DimRegionChooser::~DimRegionChooser()
84     {
85     }
86    
87 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
88     bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
89 schoenebeck 1225 {
90 persson 2246 double clipx1 = e->area.x;
91     double clipx2 = e->area.x + e->area.width;
92     double clipy1 = e->area.y;
93     double clipy2 = e->area.y + e->area.height;
94    
95     const Cairo::RefPtr<Cairo::Context>& cr =
96     get_window()->create_cairo_context();
97     #if 0
98 persson 2169 }
99     #endif
100 persson 2246 #else
101 persson 2169 bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
102     {
103 persson 2246 double clipx1, clipx2, clipy1, clipy2;
104     cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
105     #endif
106    
107 schoenebeck 1225 if (!region) return true;
108    
109     // This is where we draw on the window
110 persson 1623 int w = get_width();
111 schoenebeck 1225 Glib::RefPtr<Pango::Context> context = get_pango_context();
112    
113     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
114 persson 2151 cr->set_line_width(1);
115 schoenebeck 1225
116     int y = 0;
117 persson 2246 if (labels_changed || label_width - 10 > clipx1) {
118     // draw labels on the left (reflecting the dimension type)
119     double maxwidth = 0;
120     for (int i = 0 ; i < region->Dimensions ; i++) {
121     int nbZones = region->pDimensionDefinitions[i].zones;
122     if (nbZones) {
123     const char* dstr;
124     char dstrbuf[10];
125     switch (region->pDimensionDefinitions[i].dimension) {
126     case gig::dimension_none: dstr=_("none"); break;
127     case gig::dimension_samplechannel: dstr=_("samplechannel");
128     break;
129     case gig::dimension_layer: dstr=_("layer"); break;
130     case gig::dimension_velocity: dstr=_("velocity"); break;
131     case gig::dimension_channelaftertouch:
132     dstr=_("channelaftertouch"); break;
133     case gig::dimension_releasetrigger:
134     dstr=_("releasetrigger"); break;
135     case gig::dimension_keyboard: dstr=_("keyswitching"); break;
136     case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
137     case gig::dimension_random: dstr=_("random"); break;
138     case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
139     case gig::dimension_roundrobinkeyboard:
140     dstr=_("roundrobinkeyboard"); break;
141     case gig::dimension_modwheel: dstr=_("modwheel"); break;
142     case gig::dimension_breath: dstr=_("breath"); break;
143     case gig::dimension_foot: dstr=_("foot"); break;
144     case gig::dimension_portamentotime:
145     dstr=_("portamentotime"); break;
146     case gig::dimension_effect1: dstr=_("effect1"); break;
147     case gig::dimension_effect2: dstr=_("effect2"); break;
148     case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
149     case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
150     case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
151     case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
152     case gig::dimension_sustainpedal:
153     dstr=_("sustainpedal"); break;
154     case gig::dimension_portamento: dstr=_("portamento"); break;
155     case gig::dimension_sostenutopedal:
156     dstr=_("sostenutopedal"); break;
157     case gig::dimension_softpedal: dstr=_("softpedal"); break;
158     case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
159     case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
160     case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
161     case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
162     case gig::dimension_effect1depth:
163     dstr=_("effect1depth"); break;
164     case gig::dimension_effect2depth:
165     dstr=_("effect2depth"); break;
166     case gig::dimension_effect3depth:
167     dstr=_("effect3depth"); break;
168     case gig::dimension_effect4depth:
169     dstr=_("effect4depth"); break;
170     case gig::dimension_effect5depth:
171     dstr=_("effect5depth"); break;
172     default:
173     sprintf(dstrbuf, "%d",
174     region->pDimensionDefinitions[i].dimension);
175     dstr = dstrbuf;
176     break;
177     }
178     layout->set_text(dstr);
179 schoenebeck 1225
180 persson 2246 Pango::Rectangle rectangle = layout->get_logical_extents();
181     double text_w = double(rectangle.get_width()) / Pango::SCALE;
182     if (text_w > maxwidth) maxwidth = text_w;
183    
184     if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
185     double text_h = double(rectangle.get_height()) /
186     Pango::SCALE;
187 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
188 persson 2246 const Gdk::Color fg = get_style()->get_fg(get_state());
189 persson 2169 #else
190 persson 2246 const Gdk::RGBA fg =
191     get_style_context()->get_color(get_state_flags());
192 persson 2169 #endif
193 persson 2246 Gdk::Cairo::set_source_rgba(cr, fg);
194     cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
195 persson 2151 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
196 persson 2246 pango_cairo_show_layout(cr->cobj(), layout->gobj());
197 persson 2151 #else
198 persson 2246 layout->show_in_cairo_context(cr);
199 persson 2151 #endif
200 persson 2246 }
201     }
202     y += h;
203 schoenebeck 1225 }
204 persson 2246 label_width = int(maxwidth + 10);
205     labels_changed = false;
206 schoenebeck 1225 }
207 persson 2246 if (label_width >= clipx2) return true;
208 schoenebeck 1225
209     // draw dimensions' zones areas
210     y = 0;
211     int bitpos = 0;
212     for (int i = 0 ; i < region->Dimensions ; i++) {
213     int nbZones = region->pDimensionDefinitions[i].zones;
214     if (nbZones) {
215 persson 2246 if (y >= clipy2) break;
216     if (y + h > clipy1) {
217     // draw focus rectangle around dimension's label and zones
218     if (has_focus() && focus_line == i) {
219 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
220 persson 2246 Gdk::Rectangle farea(0, y, 150, 20);
221     get_style()->paint_focus(get_window(), get_state(), farea,
222     *this, "",
223     0, y, label_width, 20);
224 persson 2169 #else
225 persson 2246 get_style_context()->render_focus(cr,
226     0, y, label_width, 20);
227 persson 2169 #endif
228 persson 2246 }
229 schoenebeck 1225
230 persson 2246 // draw top and bottom lines of dimension's zones
231     Gdk::Cairo::set_source_rgba(cr, black);
232     cr->move_to(label_width, y + 0.5);
233     cr->line_to(w, y + 0.5);
234     cr->move_to(w, y + h - 0.5);
235     cr->line_to(label_width, y + h - 0.5);
236     cr->stroke();
237 persson 2151
238 persson 2246 // erase whole dimension's zones area
239     Gdk::Cairo::set_source_rgba(cr, white);
240     cr->rectangle(label_width + 1, y + 1,
241     (w - label_width - 2), h - 2);
242     cr->fill();
243 schoenebeck 1225
244 persson 2246 int c = 0;
245     if (dimregno >= 0) {
246     int mask =
247     ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
248     bitpos);
249     c = dimregno & mask; // mask away this dimension
250 schoenebeck 1225 }
251 persson 2246 bool customsplits =
252     ((region->pDimensionDefinitions[i].split_type ==
253     gig::split_type_normal &&
254     region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
255     (region->pDimensionDefinitions[i].dimension ==
256     gig::dimension_velocity &&
257     region->pDimensionRegions[c]->VelocityUpperLimit));
258 schoenebeck 1225
259 persson 2246 // draw dimension's zone borders
260     Gdk::Cairo::set_source_rgba(cr, black);
261 schoenebeck 1225 if (customsplits) {
262 persson 2246 cr->move_to(label_width + 0.5, y + 1);
263     cr->line_to(label_width + 0.5, y + h - 1);
264    
265 schoenebeck 1225 for (int j = 0 ; j < nbZones ; j++) {
266 persson 2246 gig::DimensionRegion* d =
267     region->pDimensionRegions[c + (j << bitpos)];
268 schoenebeck 1225 int upperLimit = d->DimensionUpperLimits[i];
269     if (!upperLimit) upperLimit = d->VelocityUpperLimit;
270     int v = upperLimit + 1;
271 persson 2246 int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
272     label_width;
273     if (x >= clipx2) break;
274     if (x < clipx1) continue;
275     cr->move_to(x + 0.5, y + 1);
276     cr->line_to(x + 0.5, y + h - 1);
277     }
278     } else {
279     for (int j = 0 ; j <= nbZones ; j++) {
280     int x = int((w - label_width - 1) * j /
281     double(nbZones) + 0.5) + label_width;
282     if (x >= clipx2) break;
283     if (x < clipx1) continue;
284     cr->move_to(x + 0.5, y + 1);
285     cr->line_to(x + 0.5, y + h - 1);
286     }
287     }
288     cr->stroke();
289    
290     // draw fill for currently selected zone
291     if (dimregno >= 0) {
292     Gdk::Cairo::set_source_rgba(cr, red);
293     int dr = (dimregno >> bitpos) &
294     ((1 << region->pDimensionDefinitions[i].bits) - 1);
295 schoenebeck 2462
296     int x1 = -1, x2 = -1;
297 persson 2246 if (customsplits) {
298 schoenebeck 2462 x1 = label_width;
299 persson 2246 for (int j = 0 ; j < nbZones && x1 + 1 < clipx2 ; j++) {
300     gig::DimensionRegion* d =
301     region->pDimensionRegions[c + (j << bitpos)];
302     int upperLimit = d->DimensionUpperLimits[i];
303     if (!upperLimit) {
304     upperLimit = d->VelocityUpperLimit;
305     }
306     int v = upperLimit + 1;
307 schoenebeck 2462 x2 = int((w - label_width - 1) * v / 128.0 +
308     0.5) + label_width;
309 persson 2246 if (j == dr && x1 < x2) {
310     cr->rectangle(x1 + 1, y + 1,
311     (x2 - x1) - 1, h - 2);
312     cr->fill();
313     break;
314     }
315     x1 = x2;
316     }
317     } else {
318     if (dr < nbZones) {
319 schoenebeck 2462 x1 = int((w - label_width - 1) * dr /
320     double(nbZones) + 0.5);
321     x2 = int((w - label_width - 1) * (dr + 1) /
322     double(nbZones) + 0.5);
323 persson 2151 cr->rectangle(label_width + x1 + 1, y + 1,
324     (x2 - x1) - 1, h - 2);
325     cr->fill();
326 schoenebeck 1225 }
327     }
328 schoenebeck 2462
329     // draw text showing the beginning of the dimension zone
330     // as numeric value to the user
331     if (x1 >= 0) {
332     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
333     int v = roundf(float(x1 - label_width) / float(w - label_width) * 127.f);
334     if (dr > 0) v++;
335     layout->set_text(Glib::Ascii::dtostr(v));
336     Gdk::Cairo::set_source_rgba(cr, black);
337     Pango::Rectangle rect = layout->get_logical_extents();
338    
339     int text_width, text_height;
340     // get the text dimensions
341     layout->get_pixel_size(text_width, text_height);
342     // move text to the right end of the dimension zone
343     cr->move_to(x1 + 1, y + 1);
344     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
345     pango_cairo_show_layout(cr->cobj(), layout->gobj());
346     #else
347     layout->show_in_cairo_context(cr);
348     #endif
349     }
350     // draw text showing the end of the dimension zone
351     // as numeric value to the user
352     if (x2 >= 0) {
353     Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
354     const int v = roundf(float(x2 - label_width) / float(w - label_width) * 127.f);
355     layout->set_text(Glib::Ascii::dtostr(v));
356     Gdk::Cairo::set_source_rgba(cr, black);
357     Pango::Rectangle rect = layout->get_logical_extents();
358    
359     int text_width, text_height;
360     // get the text dimensions
361     layout->get_pixel_size(text_width, text_height);
362     // move text to the right end of the dimension zone
363     cr->move_to(x2 - text_width - 1, y + 1);
364     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
365     pango_cairo_show_layout(cr->cobj(), layout->gobj());
366     #else
367     layout->show_in_cairo_context(cr);
368     #endif
369     }
370 schoenebeck 1225 }
371     }
372    
373     y += h;
374     }
375     bitpos += region->pDimensionDefinitions[i].bits;
376     }
377    
378     return true;
379     }
380    
381     void DimRegionChooser::set_region(gig::Region* region)
382     {
383     this->region = region;
384     dimregno = 0;
385     nbDimensions = 0;
386     if (region) {
387     int bitcount = 0;
388     for (int dim = 0 ; dim < region->Dimensions ; dim++) {
389     if (region->pDimensionDefinitions[dim].bits == 0) continue;
390     nbDimensions++;
391    
392 persson 1303 int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],
393     region->pDimensionDefinitions[dim].zones - 1);
394 schoenebeck 1225 dimregno |= (z << bitcount);
395     bitcount += region->pDimensionDefinitions[dim].bits;
396     }
397     dimreg = region->pDimensionRegions[dimregno];
398     } else {
399     dimreg = 0;
400     }
401 persson 1261 dimregion_selected();
402 persson 2169 set_size_request(800, region ? nbDimensions * 20 : 0);
403    
404 persson 2246 labels_changed = true;
405 schoenebeck 1225 queue_resize();
406     }
407    
408 schoenebeck 2556 void DimRegionChooser::refresh_all() {
409     set_region(region);
410     }
411 persson 1533
412     void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
413     std::set<gig::DimensionRegion*>& dimregs) const
414     {
415     int dimregno = 0;
416     int bitcount = 0;
417     int stereo_bit = 0;
418     for (int dim = 0 ; dim < region->Dimensions ; dim++) {
419     if (region->pDimensionDefinitions[dim].bits == 0) continue;
420     if (stereo &&
421     region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {
422     stereo_bit = (1 << bitcount);
423     } else {
424     int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],
425     region->pDimensionDefinitions[dim].zones - 1);
426     dimregno |= (z << bitcount);
427     }
428     bitcount += region->pDimensionDefinitions[dim].bits;
429     }
430     dimregs.insert(region->pDimensionRegions[dimregno]);
431     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);
432     }
433    
434 persson 2246 void DimRegionChooser::update_after_resize()
435 schoenebeck 1225 {
436 persson 2246 if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
437 schoenebeck 1225
438 persson 2246 int bitpos = 0;
439     for (int j = 0 ; j < resize.dimension ; j++) {
440     bitpos += region->pDimensionDefinitions[j].bits;
441     }
442     int mask =
443     ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
444     int c = dimregno & mask; // mask away this dimension
445 schoenebeck 1225
446 persson 2246 if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
447     // the velocity dimension didn't previously have
448     // custom v3 splits, so we initialize all splits with
449     // default values
450     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
451     for (int j = 0 ; j < nbZones ; j++) {
452     gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
453     d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
454 schoenebeck 1225 }
455 persson 2246 }
456     if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
457     // the velocity dimension didn't previously have
458     // custom v2 splits, so we initialize all splits with
459     // default values
460     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
461     for (int j = 0 ; j < nbZones ; j++) {
462     gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
463     d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
464     }
465     }
466 schoenebeck 1225
467 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];
468     // update both v2 and v3 values
469     d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
470     d->VelocityUpperLimit = resize.pos - 1;
471    
472     } else {
473     for (int i = 0 ; i < region->DimensionRegions ; ) {
474    
475     if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
476     // the dimension didn't previously have custom
477     // limits, so we have to set default limits for
478     // all the dimension regions
479     int bitpos = 0;
480     for (int j = 0 ; j < resize.dimension ; j++) {
481     bitpos += region->pDimensionDefinitions[j].bits;
482     }
483 schoenebeck 1225 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
484 persson 2246
485 schoenebeck 1225 for (int j = 0 ; j < nbZones ; j++) {
486 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
487 schoenebeck 1225 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
488     }
489     }
490 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];
491 schoenebeck 1225 d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
492    
493 persson 2246 int bitpos = 0;
494     int j;
495     for (j = 0 ; j < region->Dimensions ; j++) {
496     if (j != resize.dimension) {
497     int maxzones = 1 << region->pDimensionDefinitions[j].bits;
498     int dimj = (i >> bitpos) & (maxzones - 1);
499     if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
500 schoenebeck 1225 }
501 persson 2246 bitpos += region->pDimensionDefinitions[j].bits;
502 schoenebeck 1225 }
503 persson 2246 if (j == region->Dimensions) break;
504     i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
505 schoenebeck 1225 }
506 persson 2246 }
507     }
508    
509     bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
510     {
511     if (resize.active) {
512     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
513     get_window()->pointer_ungrab(event->time);
514     #else
515     Glib::wrap(event->device, true)->ungrab(event->time);
516     #endif
517     resize.active = false;
518    
519 persson 1261 region_changed();
520 schoenebeck 1225
521     if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
522     get_window()->set_cursor();
523     cursor_is_resize = false;
524     }
525     }
526     return true;
527     }
528    
529     bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
530     {
531 persson 1623 int w = get_width();
532 schoenebeck 1225 if (region && event->y < nbDimensions * h &&
533     event->x >= label_width && event->x < w) {
534    
535     if (is_in_resize_zone(event->x, event->y)) {
536 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
537 schoenebeck 1225 get_window()->pointer_grab(false,
538     Gdk::BUTTON_RELEASE_MASK |
539     Gdk::POINTER_MOTION_MASK |
540     Gdk::POINTER_MOTION_HINT_MASK,
541 persson 2169 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
542     event->time);
543     #else
544     Glib::wrap(event->device, true)->grab(get_window(),
545     Gdk::OWNERSHIP_NONE,
546     false,
547     Gdk::BUTTON_RELEASE_MASK |
548     Gdk::POINTER_MOTION_MASK |
549     Gdk::POINTER_MOTION_HINT_MASK,
550     Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
551     event->time);
552     #endif
553 schoenebeck 1225 resize.active = true;
554     } else {
555     int ydim = int(event->y / h);
556     int dim;
557     for (dim = 0 ; dim < region->Dimensions ; dim++) {
558     if (region->pDimensionDefinitions[dim].bits == 0) continue;
559     if (ydim == 0) break;
560     ydim--;
561     }
562     int nbZones = region->pDimensionDefinitions[dim].zones;
563    
564     int z = -1;
565     int bitpos = 0;
566     for (int i = 0 ; i < dim ; i++) {
567     bitpos += region->pDimensionDefinitions[i].bits;
568     }
569    
570     int i = dim;
571     if (dimregno < 0) dimregno = 0;
572     int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
573     int c = dimregno & mask; // mask away this dimension
574    
575     bool customsplits =
576     ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
577     region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
578     (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
579     region->pDimensionRegions[c]->VelocityUpperLimit));
580     if (customsplits) {
581     int val = int((event->x - label_width) * 128 / (w - label_width - 1));
582    
583     if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
584     for (z = 0 ; z < nbZones ; z++) {
585 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
586 schoenebeck 1225 if (val <= d->DimensionUpperLimits[i]) break;
587     }
588     } else {
589     for (z = 0 ; z < nbZones ; z++) {
590 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
591 schoenebeck 1225 if (val <= d->VelocityUpperLimit) break;
592     }
593     }
594     } else {
595     z = int((event->x - label_width) * nbZones / (w - label_width - 1));
596     }
597    
598     printf("dim=%d z=%d dimensionsource=%d split_type=%d zones=%d zone_size=%f\n", dim, z,
599     region->pDimensionDefinitions[dim].dimension,
600     region->pDimensionDefinitions[dim].split_type,
601     region->pDimensionDefinitions[dim].zones,
602     region->pDimensionDefinitions[dim].zone_size);
603 persson 1303 dimvalue[region->pDimensionDefinitions[dim].dimension] = z;
604 schoenebeck 1225
605     dimregno = c | (z << bitpos);
606    
607 schoenebeck 2556 this->dimtype = dim;
608     this->dimzone = z;
609    
610 schoenebeck 1225 focus_line = dim;
611     if (has_focus()) queue_draw();
612     else grab_focus();
613     dimreg = region->pDimensionRegions[dimregno];
614 persson 1261 dimregion_selected();
615 schoenebeck 2556
616     if (event->button == 3) {
617     printf("dimregion right click\n");
618     popup_menu_inside_dimregion->popup(event->button, event->time);
619     }
620 schoenebeck 1225 }
621     }
622     return true;
623     }
624    
625     bool DimRegionChooser::on_motion_notify_event(GdkEventMotion* event)
626     {
627     Glib::RefPtr<Gdk::Window> window = get_window();
628     int x, y;
629     Gdk::ModifierType state = Gdk::ModifierType(0);
630     window->get_pointer(x, y, state);
631    
632     if (resize.active) {
633 persson 1623 int w = get_width();
634 schoenebeck 1225 int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
635    
636     if (k < resize.min) k = resize.min;
637     else if (k > resize.max) k = resize.max;
638    
639     if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
640    
641     if (k != resize.pos) {
642     int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
643     int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
644     int y = resize.dimension * h;
645 persson 2246 int x1, x2;
646     if (k > resize.pos) {
647     x1 = prevx;
648     x2 = x;
649 schoenebeck 1225 } else {
650 persson 2246 x1 = x;
651     x2 = prevx;
652 schoenebeck 1225 }
653 persson 2246 Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
654 persson 2151
655 schoenebeck 1225 resize.pos = k;
656 persson 2246 update_after_resize();
657     get_window()->invalidate_rect(rect, false);
658 schoenebeck 1225 }
659     } else {
660     if (is_in_resize_zone(x, y)) {
661     if (!cursor_is_resize) {
662 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
663     window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
664     #else
665     window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
666     #endif
667 schoenebeck 1225 cursor_is_resize = true;
668     }
669     } else if (cursor_is_resize) {
670     window->set_cursor();
671     cursor_is_resize = false;
672     }
673     }
674     return true;
675     }
676    
677     bool DimRegionChooser::is_in_resize_zone(double x, double y)
678     {
679 persson 1623 int w = get_width();
680 schoenebeck 1225 if (region && y < nbDimensions * h && x >= label_width && x < w) {
681     int ydim = int(y / h);
682     int dim;
683     int bitpos = 0;
684     for (dim = 0 ; dim < region->Dimensions ; dim++) {
685     if (region->pDimensionDefinitions[dim].bits == 0) continue;
686     if (ydim == 0) break;
687     ydim--;
688     bitpos += region->pDimensionDefinitions[dim].bits;
689     }
690     int nbZones = region->pDimensionDefinitions[dim].zones;
691    
692     int c = 0;
693     if (dimregno >= 0) {
694     int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
695     c = dimregno & mask; // mask away this dimension
696     }
697     const bool customsplits =
698     ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
699     region->pDimensionRegions[c]->DimensionUpperLimits[dim]) ||
700     (region->pDimensionDefinitions[dim].dimension == gig::dimension_velocity &&
701     region->pDimensionRegions[c]->VelocityUpperLimit));
702    
703     // dimensions of split_type_bit cannot be resized
704     if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
705     int prev_limit = 0;
706     for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
707 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
708 schoenebeck 1225 const int upperLimit =
709     (customsplits) ?
710     (d->DimensionUpperLimits[dim]) ?
711     d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
712     : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
713     int limit = upperLimit + 1;
714     int limitx = int((w - label_width - 1) * limit / 128.0 + 0.5) + label_width;
715     if (x <= limitx - 2) break;
716     if (x <= limitx + 2) {
717     resize.dimension = dim;
718     resize.offset = iZone << bitpos;
719     resize.pos = limit;
720     resize.min = prev_limit;
721    
722     int dr = (dimregno >> bitpos) &
723     ((1 << region->pDimensionDefinitions[dim].bits) - 1);
724     resize.selected = dr == iZone ? resize.left :
725     dr == iZone + 1 ? resize.right : resize.none;
726    
727     iZone++;
728 persson 2246 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
729 schoenebeck 1225
730     const int upperLimit =
731     (customsplits) ?
732     (d->DimensionUpperLimits[dim]) ?
733     d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
734     : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
735    
736     int limit = upperLimit + 1;
737     resize.max = limit;
738     return true;
739     }
740     prev_limit = limit;
741     }
742     }
743     }
744     return false;
745     }
746    
747 schoenebeck 1339 sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
748 schoenebeck 1225 {
749 persson 1261 return dimregion_selected;
750 schoenebeck 1225 }
751    
752 schoenebeck 1339 sigc::signal<void>& DimRegionChooser::signal_region_changed()
753 persson 1261 {
754     return region_changed;
755     }
756    
757 schoenebeck 1225 bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
758     {
759     // TODO: kolla att region finns osv, dvs att det g�r att s�tta
760     // fokus.
761     if (direction == Gtk::DIR_TAB_FORWARD ||
762     direction == Gtk::DIR_DOWN) {
763     if (!has_focus()) {
764     focus_line = 0;
765     grab_focus();
766     return true;
767     } else {
768     if (focus_line + 1 < region->Dimensions) {
769     focus_line++;
770     queue_draw();
771     return true;
772     } else {
773     return false;
774     }
775     }
776     } else if (direction == Gtk::DIR_TAB_BACKWARD ||
777     direction == Gtk::DIR_UP) {
778     if (!has_focus()) {
779     focus_line = region->Dimensions - 1;
780     grab_focus();
781     return true;
782     } else {
783     if (focus_line > 0) {
784     focus_line--;
785     queue_draw();
786     return true;
787     } else {
788     return false;
789     }
790     }
791     } else if (!has_focus()) {
792     // TODO: kolla att focus_line finns!
793     grab_focus();
794     return true;
795     } else {
796     // TODO: �ka eller minska v�rde!
797     }
798     }
799 schoenebeck 2556
800     void DimRegionChooser::split_dimension_zone() {
801     printf("split_dimension_zone() type=%d, zone=%d\n", dimtype, dimzone);
802     try {
803     region->SplitDimensionZone(
804     region->pDimensionDefinitions[dimtype].dimension,
805     dimzone
806     );
807     } catch (RIFF::Exception e) {
808     Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
809     msg.run();
810     } catch (...) {
811     Glib::ustring txt = _("An unknown exception occurred!");
812     Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
813     msg.run();
814     }
815     refresh_all();
816     }
817    
818     void DimRegionChooser::delete_dimension_zone() {
819     printf("delete_dimension_zone() type=%d, zone=%d\n", dimtype, dimzone);
820     try {
821     region->DeleteDimensionZone(
822     region->pDimensionDefinitions[dimtype].dimension,
823     dimzone
824     );
825     } catch (RIFF::Exception e) {
826     Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
827     msg.run();
828     } catch (...) {
829     Glib::ustring txt = _("An unknown exception occurred!");
830     Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
831     msg.run();
832     }
833     refresh_all();
834     }

  ViewVC Help
Powered by ViewVC