/[svn]/gigedit/trunk/src/gigedit/dimregionchooser.cpp
ViewVC logotype

Contents of /gigedit/trunk/src/gigedit/dimregionchooser.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2556 - (show 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 /*
2 * Copyright (C) 2006-2014 Andreas Persson
3 *
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 #include <cairomm/context.h>
22 #include <gdkmm/cursor.h>
23 #include <gdkmm/general.h>
24 #include <glibmm/stringutils.h>
25 #include <gtkmm/stock.h>
26 #include <glibmm/ustring.h>
27 #include <gtkmm/messagedialog.h>
28
29 #include "global.h"
30
31 DimRegionChooser::DimRegionChooser() :
32 red("#8070ff"),
33 black("black"),
34 white("white")
35 {
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 set_can_focus();
44
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 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
75 Gdk::POINTER_MOTION_HINT_MASK);
76
77 for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;
78 labels_changed = true;
79
80 set_tooltip_text(_("Right click here for options on altering dimension zones."));
81 }
82
83 DimRegionChooser::~DimRegionChooser()
84 {
85 }
86
87 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
88 bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
89 {
90 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 }
99 #endif
100 #else
101 bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
102 {
103 double clipx1, clipx2, clipy1, clipy2;
104 cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
105 #endif
106
107 if (!region) return true;
108
109 // This is where we draw on the window
110 int w = get_width();
111 Glib::RefPtr<Pango::Context> context = get_pango_context();
112
113 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
114 cr->set_line_width(1);
115
116 int y = 0;
117 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
180 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 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
188 const Gdk::Color fg = get_style()->get_fg(get_state());
189 #else
190 const Gdk::RGBA fg =
191 get_style_context()->get_color(get_state_flags());
192 #endif
193 Gdk::Cairo::set_source_rgba(cr, fg);
194 cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
195 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
196 pango_cairo_show_layout(cr->cobj(), layout->gobj());
197 #else
198 layout->show_in_cairo_context(cr);
199 #endif
200 }
201 }
202 y += h;
203 }
204 label_width = int(maxwidth + 10);
205 labels_changed = false;
206 }
207 if (label_width >= clipx2) return true;
208
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 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 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
220 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 #else
225 get_style_context()->render_focus(cr,
226 0, y, label_width, 20);
227 #endif
228 }
229
230 // 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
238 // 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
244 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 }
251 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
259 // draw dimension's zone borders
260 Gdk::Cairo::set_source_rgba(cr, black);
261 if (customsplits) {
262 cr->move_to(label_width + 0.5, y + 1);
263 cr->line_to(label_width + 0.5, y + h - 1);
264
265 for (int j = 0 ; j < nbZones ; j++) {
266 gig::DimensionRegion* d =
267 region->pDimensionRegions[c + (j << bitpos)];
268 int upperLimit = d->DimensionUpperLimits[i];
269 if (!upperLimit) upperLimit = d->VelocityUpperLimit;
270 int v = upperLimit + 1;
271 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
296 int x1 = -1, x2 = -1;
297 if (customsplits) {
298 x1 = label_width;
299 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 x2 = int((w - label_width - 1) * v / 128.0 +
308 0.5) + label_width;
309 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 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 cr->rectangle(label_width + x1 + 1, y + 1,
324 (x2 - x1) - 1, h - 2);
325 cr->fill();
326 }
327 }
328
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 }
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 int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],
393 region->pDimensionDefinitions[dim].zones - 1);
394 dimregno |= (z << bitcount);
395 bitcount += region->pDimensionDefinitions[dim].bits;
396 }
397 dimreg = region->pDimensionRegions[dimregno];
398 } else {
399 dimreg = 0;
400 }
401 dimregion_selected();
402 set_size_request(800, region ? nbDimensions * 20 : 0);
403
404 labels_changed = true;
405 queue_resize();
406 }
407
408 void DimRegionChooser::refresh_all() {
409 set_region(region);
410 }
411
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 void DimRegionChooser::update_after_resize()
435 {
436 if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
437
438 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
446 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 }
455 }
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
467 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 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
484
485 for (int j = 0 ; j < nbZones ; j++) {
486 gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
487 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
488 }
489 }
490 gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];
491 d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
492
493 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 }
501 bitpos += region->pDimensionDefinitions[j].bits;
502 }
503 if (j == region->Dimensions) break;
504 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
505 }
506 }
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 region_changed();
520
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 int w = get_width();
532 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 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
537 get_window()->pointer_grab(false,
538 Gdk::BUTTON_RELEASE_MASK |
539 Gdk::POINTER_MOTION_MASK |
540 Gdk::POINTER_MOTION_HINT_MASK,
541 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 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 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
586 if (val <= d->DimensionUpperLimits[i]) break;
587 }
588 } else {
589 for (z = 0 ; z < nbZones ; z++) {
590 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
591 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 dimvalue[region->pDimensionDefinitions[dim].dimension] = z;
604
605 dimregno = c | (z << bitpos);
606
607 this->dimtype = dim;
608 this->dimzone = z;
609
610 focus_line = dim;
611 if (has_focus()) queue_draw();
612 else grab_focus();
613 dimreg = region->pDimensionRegions[dimregno];
614 dimregion_selected();
615
616 if (event->button == 3) {
617 printf("dimregion right click\n");
618 popup_menu_inside_dimregion->popup(event->button, event->time);
619 }
620 }
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 int w = get_width();
634 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 int x1, x2;
646 if (k > resize.pos) {
647 x1 = prevx;
648 x2 = x;
649 } else {
650 x1 = x;
651 x2 = prevx;
652 }
653 Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
654
655 resize.pos = k;
656 update_after_resize();
657 get_window()->invalidate_rect(rect, false);
658 }
659 } else {
660 if (is_in_resize_zone(x, y)) {
661 if (!cursor_is_resize) {
662 #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 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 int w = get_width();
680 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 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
708 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 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
729
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 sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
748 {
749 return dimregion_selected;
750 }
751
752 sigc::signal<void>& DimRegionChooser::signal_region_changed()
753 {
754 return region_changed;
755 }
756
757 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
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