/[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 2695 - (show annotations) (download)
Tue Jan 6 18:11:27 2015 UTC (9 years, 2 months ago) by schoenebeck
File size: 40695 byte(s)
* Sample Referenve View Dialog: Clicking on a reference in the list closes
  the dialog and jumps directly to the respective instrument, region and
  dimension region the respective sample reference is located at.

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

  ViewVC Help
Powered by ViewVC