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

1 /*
2 * Copyright (C) 2006-2015 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 // 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 red("#8070ff"),
80 black("black"),
81 white("white")
82 {
83 instrument = 0;
84 region = 0;
85 maindimregno = -1;
86 focus_line = 0;
87 resize.active = false;
88 cursor_is_resize = false;
89 h = 24;
90 multiSelectKeyDown = false;
91 set_can_focus();
92
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 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
123 Gdk::POINTER_MOTION_HINT_MASK);
124
125 labels_changed = true;
126
127 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 }
139
140 DimRegionChooser::~DimRegionChooser()
141 {
142 }
143
144 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
145 bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
146 {
147 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 bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
156 {
157 double clipx1, clipx2, clipy1, clipy2;
158 cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
159 #endif
160
161 if (!region) return true;
162
163 // This is where we draw on the window
164 int w = get_width();
165 Glib::RefPtr<Pango::Context> context = get_pango_context();
166
167 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
168 cr->set_line_width(1);
169
170 int y = 0;
171 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
234 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 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
242 const Gdk::Color fg = get_style()->get_fg(get_state());
243 #else
244 const Gdk::RGBA fg =
245 get_style_context()->get_color(get_state_flags());
246 #endif
247 Gdk::Cairo::set_source_rgba(cr, fg);
248 cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
249 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
250 pango_cairo_show_layout(cr->cobj(), layout->gobj());
251 #else
252 layout->show_in_cairo_context(cr);
253 #endif
254 }
255 }
256 y += h;
257 }
258 label_width = int(maxwidth + 10);
259 labels_changed = false;
260 }
261 if (label_width >= clipx2) return true;
262
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 const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
270
271 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 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
276 Gdk::Rectangle farea(0, y, 150, h);
277 get_style()->paint_focus(get_window(), get_state(), farea,
278 *this, "",
279 0, y, label_width, h);
280 #else
281 get_style_context()->render_focus(cr,
282 0, y, label_width, h);
283 #endif
284 }
285
286 // 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
294 // 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
300 int c = 0;
301 if (maindimregno >= 0) {
302 int mask =
303 ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
304 bitpos);
305 c = maindimregno & mask; // mask away this dimension
306 }
307 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
315 // draw dimension zones
316 Gdk::Cairo::set_source_rgba(cr, black);
317 if (customsplits) {
318 cr->move_to(label_width + 0.5, y + 1);
319 cr->line_to(label_width + 0.5, y + h - 1);
320 int prevX = label_width;
321 int prevUpperLimit = -1;
322
323 for (int j = 0 ; j < nbZones ; j++) {
324 // draw dimension zone's borders for custom splits
325 gig::DimensionRegion* d =
326 region->pDimensionRegions[c + (j << bitpos)];
327 int upperLimit = d->DimensionUpperLimits[i];
328 if (!upperLimit) upperLimit = d->VelocityUpperLimit;
329 int v = upperLimit + 1;
330 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 Gdk::Cairo::set_source_rgba(cr, black);
335 cr->move_to(x + 0.5, y + 1);
336 cr->line_to(x + 0.5, y + h - 1);
337 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 layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
350 Gdk::Cairo::set_source_rgba(cr, black);
351 // get the text dimensions
352 int text_width, text_height;
353 layout->get_pixel_size(text_width, text_height);
354 // move text to the left end of the dimension zone
355 cr->move_to(prevX + 3, y + (h - text_height) / 2);
356 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
357 pango_cairo_show_layout(cr->cobj(), layout->gobj());
358 #else
359 layout->show_in_cairo_context(cr);
360 #endif
361 }
362 // draw text showing the end of the dimension zone
363 // as numeric value to the user
364 {
365 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
366 layout->set_text(Glib::Ascii::dtostr(upperLimit));
367 Gdk::Cairo::set_source_rgba(cr, black);
368 // get the text dimensions
369 int text_width, text_height;
370 layout->get_pixel_size(text_width, text_height);
371 // move text to the left end of the dimension zone
372 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
373 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
374 pango_cairo_show_layout(cr->cobj(), layout->gobj());
375 #else
376 layout->show_in_cairo_context(cr);
377 #endif
378 }
379
380 prevX = x;
381 prevUpperLimit = upperLimit;
382 }
383 } else {
384 int prevX = 0;
385 for (int j = 0 ; j <= nbZones ; j++) {
386 // draw dimension zone's borders for normal splits
387 int x = int((w - label_width - 1) * j /
388 double(nbZones) + 0.5) + label_width;
389 if (x >= clipx2) break;
390 if (x < clipx1) continue;
391 Gdk::Cairo::set_source_rgba(cr, black);
392 cr->move_to(x + 0.5, y + 1);
393 cr->line_to(x + 0.5, y + h - 1);
394 cr->stroke();
395
396 if (j != 0) {
397 // draw fill for zone
398 bool isSelectedZone = this->dimzones[dimension].count(j-1);
399 Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);
400 cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
401 cr->fill();
402
403 // draw text showing the beginning of the dimension zone
404 // as numeric value to the user
405 {
406 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
407 layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
408 Gdk::Cairo::set_source_rgba(cr, black);
409 // get the text dimensions
410 int text_width, text_height;
411 layout->get_pixel_size(text_width, text_height);
412 // move text to the left end of the dimension zone
413 cr->move_to(prevX + 3, y + (h - text_height) / 2);
414 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
415 pango_cairo_show_layout(cr->cobj(), layout->gobj());
416 #else
417 layout->show_in_cairo_context(cr);
418 #endif
419 }
420 // draw text showing the end of the dimension zone
421 // as numeric value to the user
422 {
423 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
424 layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
425 Gdk::Cairo::set_source_rgba(cr, black);
426 // get the text dimensions
427 int text_width, text_height;
428 layout->get_pixel_size(text_width, text_height);
429 // move text to the left end of the dimension zone
430 cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
431 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
432 pango_cairo_show_layout(cr->cobj(), layout->gobj());
433 #else
434 layout->show_in_cairo_context(cr);
435 #endif
436 }
437 }
438 prevX = x;
439 }
440 }
441 }
442 y += h;
443 }
444 bitpos += region->pDimensionDefinitions[i].bits;
445 }
446
447 return true;
448 }
449
450 void DimRegionChooser::set_region(gig::Region* region)
451 {
452 this->region = region;
453 maindimregno = 0;
454 nbDimensions = 0;
455 if (region) {
456 int bitcount = 0;
457 for (int dim = 0 ; dim < region->Dimensions ; dim++) {
458 if (region->pDimensionDefinitions[dim].bits == 0) continue;
459 nbDimensions++;
460
461 int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
462 region->pDimensionDefinitions[dim].zones - 1);
463 maindimregno |= (z << bitcount);
464 bitcount += region->pDimensionDefinitions[dim].bits;
465 }
466 }
467 dimregion_selected();
468 set_size_request(800, region ? nbDimensions * h : 0);
469
470 labels_changed = true;
471 queue_resize();
472 queue_draw();
473 }
474
475 void DimRegionChooser::refresh_all() {
476 set_region(region);
477 }
478
479 void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
480 std::set<gig::DimensionRegion*>& dimregs) const
481 {
482 for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
483 gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
484 if (!dimRgn) continue;
485 bool isValidZone;
486 std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
487 if (!isValidZone) continue;
488 for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
489 it != dimCase.end(); ++it)
490 {
491 if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
492
493 std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
494 this->dimzones.find(it->first);
495 if (itSelectedDimension != this->dimzones.end() &&
496 itSelectedDimension->second.count(it->second)) continue; // is selected
497
498 goto notSelected;
499 }
500
501 dimregs.insert(dimRgn);
502
503 notSelected:
504 ;
505 }
506 }
507
508 void DimRegionChooser::update_after_resize()
509 {
510 if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
511
512 int bitpos = 0;
513 for (int j = 0 ; j < resize.dimension ; j++) {
514 bitpos += region->pDimensionDefinitions[j].bits;
515 }
516 int mask =
517 ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
518 int c = maindimregno & mask; // mask away this dimension
519
520 if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
521 // the velocity dimension didn't previously have
522 // custom v3 splits, so we initialize all splits with
523 // default values
524 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
525 for (int j = 0 ; j < nbZones ; j++) {
526 gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
527 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
528 }
529 }
530 if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
531 // the velocity dimension didn't previously have
532 // custom v2 splits, so we initialize all splits with
533 // default values
534 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
535 for (int j = 0 ; j < nbZones ; j++) {
536 gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
537 d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
538 }
539 }
540
541 gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];
542 // update both v2 and v3 values
543 d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
544 d->VelocityUpperLimit = resize.pos - 1;
545
546 } else {
547 for (int i = 0 ; i < region->DimensionRegions ; ) {
548
549 if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
550 // the dimension didn't previously have custom
551 // limits, so we have to set default limits for
552 // all the dimension regions
553 int bitpos = 0;
554 for (int j = 0 ; j < resize.dimension ; j++) {
555 bitpos += region->pDimensionDefinitions[j].bits;
556 }
557 int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
558
559 for (int j = 0 ; j < nbZones ; j++) {
560 gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
561 d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
562 }
563 }
564 gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];
565 d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
566
567 int bitpos = 0;
568 int j;
569 for (j = 0 ; j < region->Dimensions ; j++) {
570 if (j != resize.dimension) {
571 int maxzones = 1 << region->pDimensionDefinitions[j].bits;
572 int dimj = (i >> bitpos) & (maxzones - 1);
573 if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
574 }
575 bitpos += region->pDimensionDefinitions[j].bits;
576 }
577 if (j == region->Dimensions) break;
578 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
579 }
580 }
581 }
582
583 bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
584 {
585 if (resize.active) {
586 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
587 get_window()->pointer_ungrab(event->time);
588 #else
589 Glib::wrap(event->device, true)->ungrab(event->time);
590 #endif
591 resize.active = false;
592
593 region_changed();
594
595 if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
596 get_window()->set_cursor();
597 cursor_is_resize = false;
598 }
599 }
600 return true;
601 }
602
603 bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
604 {
605 int w = get_width();
606 if (region && event->y < nbDimensions * h &&
607 event->x >= label_width && event->x < w) {
608
609 if (is_in_resize_zone(event->x, event->y)) {
610 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
611 get_window()->pointer_grab(false,
612 Gdk::BUTTON_RELEASE_MASK |
613 Gdk::POINTER_MOTION_MASK |
614 Gdk::POINTER_MOTION_HINT_MASK,
615 Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
616 event->time);
617 #else
618 Glib::wrap(event->device, true)->grab(get_window(),
619 Gdk::OWNERSHIP_NONE,
620 false,
621 Gdk::BUTTON_RELEASE_MASK |
622 Gdk::POINTER_MOTION_MASK |
623 Gdk::POINTER_MOTION_HINT_MASK,
624 Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
625 event->time);
626 #endif
627 resize.active = true;
628 } else {
629 int ydim = int(event->y / h);
630 int dim;
631 for (dim = 0 ; dim < region->Dimensions ; dim++) {
632 if (region->pDimensionDefinitions[dim].bits == 0) continue;
633 if (ydim == 0) break;
634 ydim--;
635 }
636 int nbZones = region->pDimensionDefinitions[dim].zones;
637
638 int z = -1;
639 int bitpos = 0;
640 for (int i = 0 ; i < dim ; i++) {
641 bitpos += region->pDimensionDefinitions[i].bits;
642 }
643
644 int i = dim;
645 if (maindimregno < 0) maindimregno = 0;
646 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
647 int c = this->maindimregno & mask; // mask away this dimension
648
649 bool customsplits =
650 ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
651 region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
652 (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
653 region->pDimensionRegions[c]->VelocityUpperLimit));
654 if (customsplits) {
655 int val = int((event->x - label_width) * 128 / (w - label_width - 1));
656
657 if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
658 for (z = 0 ; z < nbZones ; z++) {
659 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
660 if (val <= d->DimensionUpperLimits[i]) break;
661 }
662 } else {
663 for (z = 0 ; z < nbZones ; z++) {
664 gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
665 if (val <= d->VelocityUpperLimit) break;
666 }
667 }
668 } else {
669 z = int((event->x - label_width) * nbZones / (w - label_width - 1));
670 }
671
672 printf("dim=%d z=%d dimensionsource=%d split_type=%d zones=%d zone_size=%f\n", dim, z,
673 region->pDimensionDefinitions[dim].dimension,
674 region->pDimensionDefinitions[dim].split_type,
675 region->pDimensionDefinitions[dim].zones,
676 region->pDimensionDefinitions[dim].zone_size);
677 this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
678 this->maindimregno = c | (z << bitpos);
679 this->maindimtype = region->pDimensionDefinitions[dim].dimension;
680
681 if (multiSelectKeyDown) {
682 if (dimzones[this->maindimtype].count(z)) {
683 if (dimzones[this->maindimtype].size() > 1) {
684 dimzones[this->maindimtype].erase(z);
685 }
686 } else {
687 dimzones[this->maindimtype].insert(z);
688 }
689 } else {
690 this->dimzones.clear();
691 for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
692 it != this->maindimcase.end(); ++it)
693 {
694 this->dimzones[it->first].insert(it->second);
695 }
696 }
697
698 focus_line = dim;
699 if (has_focus()) queue_draw();
700 else grab_focus();
701 dimregion_selected();
702
703 if (event->button == 3) {
704 printf("dimregion right click\n");
705 popup_menu_inside_dimregion->popup(event->button, event->time);
706 }
707
708 queue_draw();
709 }
710 }
711 return true;
712 }
713
714 bool DimRegionChooser::on_motion_notify_event(GdkEventMotion* event)
715 {
716 Glib::RefPtr<Gdk::Window> window = get_window();
717 int x, y;
718 Gdk::ModifierType state = Gdk::ModifierType(0);
719 window->get_pointer(x, y, state);
720
721 if (resize.active) {
722 int w = get_width();
723 int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
724
725 if (k < resize.min) k = resize.min;
726 else if (k > resize.max) k = resize.max;
727
728 if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
729
730 if (k != resize.pos) {
731 int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
732 int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
733 int y = resize.dimension * h;
734 int x1, x2;
735 if (k > resize.pos) {
736 x1 = prevx;
737 x2 = x;
738 } else {
739 x1 = x;
740 x2 = prevx;
741 }
742 Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
743
744 resize.pos = k;
745 update_after_resize();
746 get_window()->invalidate_rect(rect, false); // not sufficient ...
747 queue_draw(); // ... so do a complete redraw instead.
748 }
749 } else {
750 if (is_in_resize_zone(x, y)) {
751 if (!cursor_is_resize) {
752 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
753 window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
754 #else
755 window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
756 #endif
757 cursor_is_resize = true;
758 }
759 } else if (cursor_is_resize) {
760 window->set_cursor();
761 cursor_is_resize = false;
762 }
763 }
764 return true;
765 }
766
767 bool DimRegionChooser::is_in_resize_zone(double x, double y)
768 {
769 int w = get_width();
770 if (region && y < nbDimensions * h && x >= label_width && x < w) {
771 int ydim = int(y / h);
772 int dim;
773 int bitpos = 0;
774 for (dim = 0 ; dim < region->Dimensions ; dim++) {
775 if (region->pDimensionDefinitions[dim].bits == 0) continue;
776 if (ydim == 0) break;
777 ydim--;
778 bitpos += region->pDimensionDefinitions[dim].bits;
779 }
780 int nbZones = region->pDimensionDefinitions[dim].zones;
781
782 int c = 0;
783 if (maindimregno >= 0) {
784 int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
785 c = maindimregno & mask; // mask away this dimension
786 }
787 const bool customsplits =
788 ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
789 region->pDimensionRegions[c]->DimensionUpperLimits[dim]) ||
790 (region->pDimensionDefinitions[dim].dimension == gig::dimension_velocity &&
791 region->pDimensionRegions[c]->VelocityUpperLimit));
792
793 // dimensions of split_type_bit cannot be resized
794 if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
795 int prev_limit = 0;
796 for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
797 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
798 const int upperLimit =
799 (customsplits) ?
800 (d->DimensionUpperLimits[dim]) ?
801 d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
802 : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
803 int limit = upperLimit + 1;
804 int limitx = int((w - label_width - 1) * limit / 128.0 + 0.5) + label_width;
805 if (x <= limitx - 2) break;
806 if (x <= limitx + 2) {
807 resize.dimension = dim;
808 resize.offset = iZone << bitpos;
809 resize.pos = limit;
810 resize.min = prev_limit;
811
812 int dr = (maindimregno >> bitpos) &
813 ((1 << region->pDimensionDefinitions[dim].bits) - 1);
814 resize.selected = dr == iZone ? resize.left :
815 dr == iZone + 1 ? resize.right : resize.none;
816
817 iZone++;
818 gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
819
820 const int upperLimit =
821 (customsplits) ?
822 (d->DimensionUpperLimits[dim]) ?
823 d->DimensionUpperLimits[dim] : d->VelocityUpperLimit
824 : (iZone+1) * (int)region->pDimensionDefinitions[dim].zone_size - 1;
825
826 int limit = upperLimit + 1;
827 resize.max = limit;
828 return true;
829 }
830 prev_limit = limit;
831 }
832 }
833 }
834 return false;
835 }
836
837 sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
838 {
839 return dimregion_selected;
840 }
841
842 sigc::signal<void>& DimRegionChooser::signal_region_changed()
843 {
844 return region_changed;
845 }
846
847 bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
848 {
849 // TODO: check that region exists etc, that is, that it's possible
850 // to set focus
851 if (direction == Gtk::DIR_TAB_FORWARD ||
852 direction == Gtk::DIR_DOWN) {
853 if (!has_focus()) {
854 focus_line = 0;
855 grab_focus();
856 return true;
857 } else {
858 if (focus_line + 1 < region->Dimensions) {
859 focus_line++;
860 queue_draw();
861 return true;
862 } else {
863 return false;
864 }
865 }
866 } else if (direction == Gtk::DIR_TAB_BACKWARD ||
867 direction == Gtk::DIR_UP) {
868 if (!has_focus()) {
869 focus_line = region->Dimensions - 1;
870 grab_focus();
871 return true;
872 } else {
873 if (focus_line > 0) {
874 focus_line--;
875 queue_draw();
876 return true;
877 } else {
878 return false;
879 }
880 }
881 } else if (!has_focus()) {
882 // TODO: check that focus_line exists
883 grab_focus();
884 return true;
885 } else {
886 // TODO: increase or decrease value
887 }
888 return false;
889 }
890
891 void DimRegionChooser::split_dimension_zone() {
892 printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
893 try {
894 region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
895 } catch (RIFF::Exception e) {
896 Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
897 msg.run();
898 } catch (...) {
899 Glib::ustring txt = _("An unknown exception occurred!");
900 Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
901 msg.run();
902 }
903 refresh_all();
904 }
905
906 void DimRegionChooser::delete_dimension_zone() {
907 printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
908 try {
909 region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
910 } catch (RIFF::Exception e) {
911 Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
912 msg.run();
913 } catch (...) {
914 Glib::ustring txt = _("An unknown exception occurred!");
915 Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
916 msg.run();
917 }
918 refresh_all();
919 }
920
921 bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
922 //printf("key down\n");
923 if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
924 multiSelectKeyDown = true;
925 return false;
926 }
927
928 bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
929 //printf("key up\n");
930 if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
931 multiSelectKeyDown = false;
932 return false;
933 }
934
935 void DimRegionChooser::resetSelectedZones() {
936 this->dimzones.clear();
937 if (!region) {
938 queue_draw(); // redraw required parts
939 return;
940 }
941 if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
942 queue_draw(); // redraw required parts
943 return;
944 }
945 if (!region->pDimensionRegions[maindimregno]) {
946 queue_draw(); // redraw required parts
947 return;
948 }
949 gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
950
951 bool isValidZone;
952 this->maindimcase = caseOfDimRegion(dimrgn, &isValidZone);
953 if (!isValidZone) {
954 queue_draw(); // redraw required parts
955 return;
956 }
957
958 for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
959 it != this->maindimcase.end(); ++it)
960 {
961 this->dimzones[it->first].insert(it->second);
962 }
963
964 // redraw required parts
965 queue_draw();
966 }
967
968 bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
969 if (!region) return false; //.selection failed
970
971 for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
972 if (region->pDimensionRegions[dr] == dimrgn) {
973 // reset dim region zone selection to the requested specific dim region case
974 maindimregno = dr;
975 resetSelectedZones();
976
977 // emit signal that dimregion selection has changed, for external entities
978 dimregion_selected();
979
980 return true; // selection success
981 }
982 }
983
984 return false; //.selection failed
985 }
986
987 gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
988 if (!region) return NULL;
989 return region->pDimensionRegions[maindimregno];
990 }

  ViewVC Help
Powered by ViewVC