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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1103 - (show annotations) (download)
Sun Mar 18 07:26:43 2007 UTC (13 years, 5 months ago) by persson
File size: 23984 byte(s)
* implemented add and remove region
* fixed crash in DimRegionChooser for instruments without regions

1 /*
2 * Copyright (C) 2006, 2007 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 <gdkmm/cursor.h>
22
23 DimRegionChooser::DimRegionChooser()
24 {
25 // get_window() would return 0 because the Gdk::Window has not yet been realized
26 // So we can only allocate the colors here - the rest will happen in on_realize().
27 Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();
28
29 black = Gdk::Color("black");
30 white = Gdk::Color("white");
31 red = Gdk::Color("#8070ff");
32 blue = Gdk::Color("blue");
33 green = Gdk::Color("green");
34
35 colormap->alloc_color(black);
36 colormap->alloc_color(white);
37 colormap->alloc_color(red);
38 colormap->alloc_color(blue);
39 colormap->alloc_color(green);
40 instrument = 0;
41 region = 0;
42 dimregno = -1;
43 focus_line = 0;
44 resize.active = false;
45 cursor_is_resize = false;
46 h = 20;
47 w = 800;
48 set_flags(Gtk::CAN_FOCUS);
49 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
50 Gdk::POINTER_MOTION_HINT_MASK);
51
52 for (int i = 0 ; i < 256 ; i++) {
53 dimvalue_from[i] = 0;
54 dimvalue_to[i] = 1;
55 }
56 }
57
58 DimRegionChooser::~DimRegionChooser()
59 {
60 }
61
62 void DimRegionChooser::on_realize()
63 {
64 // We need to call the base on_realize()
65 Gtk::DrawingArea::on_realize();
66
67 // Now we can allocate any additional resources we need
68 Glib::RefPtr<Gdk::Window> window = get_window();
69 gc = Gdk::GC::create(window);
70 }
71
72 bool DimRegionChooser::on_expose_event(GdkEventExpose* event)
73 {
74 if (!region) return true;
75
76 // This is where we draw on the window
77 Glib::RefPtr<Gdk::Window> window = get_window();
78 Glib::RefPtr<Pango::Context> context = get_pango_context();
79
80 Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
81
82 window->clear();
83 int y = 0;
84 double maxwidth = 0;
85 for (int i = 0 ; i < region->Dimensions ; i++) {
86
87 int nbZones = region->pDimensionDefinitions[i].zones;
88 if (nbZones) {
89 char* dstr;
90 char dstrbuf[10];
91 switch (region->pDimensionDefinitions[i].dimension) {
92 case gig::dimension_none: dstr="none"; break;
93 case gig::dimension_samplechannel: dstr="samplechannel"; break;
94 case gig::dimension_layer: dstr="layer"; break;
95 case gig::dimension_velocity: dstr="velocity"; break;
96 case gig::dimension_channelaftertouch: dstr="channelaftertouch"; break;
97 case gig::dimension_releasetrigger: dstr="releasetrigger"; break;
98 case gig::dimension_keyboard: dstr="keyboard"; break;
99 case gig::dimension_roundrobin: dstr="roundrobin"; break;
100 case gig::dimension_random: dstr="random"; break;
101 case gig::dimension_smartmidi: dstr="smartmidi"; break;
102 case gig::dimension_roundrobinkeyboard: dstr="roundrobinkeyboard"; break;
103 case gig::dimension_modwheel: dstr="modwheel"; break;
104 case gig::dimension_breath: dstr="breath"; break;
105 case gig::dimension_foot: dstr="foot"; break;
106 case gig::dimension_portamentotime: dstr="portamentotime"; break;
107 case gig::dimension_effect1: dstr="effect1"; break;
108 case gig::dimension_effect2: dstr="effect2"; break;
109 case gig::dimension_genpurpose1: dstr="genpurpose1"; break;
110 case gig::dimension_genpurpose2: dstr="genpurpose2"; break;
111 case gig::dimension_genpurpose3: dstr="genpurpose3"; break;
112 case gig::dimension_genpurpose4: dstr="genpurpose4"; break;
113 case gig::dimension_sustainpedal: dstr="sustainpedal"; break;
114 case gig::dimension_portamento: dstr="portamento"; break;
115 case gig::dimension_sostenutopedal: dstr="sostenutopedal"; break;
116 case gig::dimension_softpedal: dstr="softpedal"; break;
117 case gig::dimension_genpurpose5: dstr="genpurpose5"; break;
118 case gig::dimension_genpurpose6: dstr="genpurpose6"; break;
119 case gig::dimension_genpurpose7: dstr="genpurpose7"; break;
120 case gig::dimension_genpurpose8: dstr="genpurpose8"; break;
121 case gig::dimension_effect1depth: dstr="effect1depth"; break;
122 case gig::dimension_effect2depth: dstr="effect2depth"; break;
123 case gig::dimension_effect3depth: dstr="effect3depth"; break;
124 case gig::dimension_effect4depth: dstr="effect4depth"; break;
125 case gig::dimension_effect5depth: dstr="effect5depth"; break;
126 default:
127 sprintf(dstrbuf, "%d",
128 region->pDimensionDefinitions[i].dimension);
129 dstr = dstrbuf;
130 break;
131 }
132 layout->set_text(dstr);
133
134 Pango::Rectangle rectangle = layout->get_logical_extents();
135 double text_w = double(rectangle.get_width()) / Pango::SCALE;
136 if (text_w > maxwidth) maxwidth = text_w;
137 double text_h = double(rectangle.get_height()) / Pango::SCALE;
138 Glib::RefPtr<const Gdk::GC> fg = get_style()->get_fg_gc(get_state());
139 window->draw_layout(fg, 4, int(y + (h - text_h) / 2 + 0.5), layout);
140
141 }
142 y += h;
143 }
144 y = 0;
145 int bitpos = 0;
146 label_width = int(maxwidth + 10);
147 for (int i = 0 ; i < region->Dimensions ; i++) {
148 int nbZones = region->pDimensionDefinitions[i].zones;
149 if (nbZones) {
150
151 if (has_focus() && focus_line == i) {
152 Gdk::Rectangle farea(0, y, 150, 20);
153 get_style()->paint_focus(window, get_state(), farea, *this, "",
154 0, y, label_width, 20);
155 }
156
157 Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
158 window->draw_line(black, label_width, y, w - 1, y);
159 window->draw_line(black, w - 1, y + h - 1, label_width, y + h - 1);
160 window->draw_rectangle(get_style()->get_white_gc(), true,
161 label_width + 1, y + 1, (w - label_width - 2), h - 2);
162
163 int c = 0;
164 if (dimregno >= 0) {
165 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
166 c = dimregno & mask; // mask away this dimension
167 }
168 bool customsplits =
169 ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
170 region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
171 (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
172 region->pDimensionRegions[c]->VelocityUpperLimit));
173
174 if (customsplits) {
175 window->draw_line(black, label_width, y + 1, label_width, y + h - 2);
176 for (int j = 0 ; j < nbZones ; j++) {
177 gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];
178 int upperLimit = d->DimensionUpperLimits[i];
179 if (!upperLimit) upperLimit = d->VelocityUpperLimit;
180 int v = upperLimit + 1;
181 int x = int((w - label_width - 1) * v / 128.0 + 0.5);
182 window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);
183 }
184 } else {
185 for (int j = 0 ; j <= nbZones ; j++) {
186 int x = int((w - label_width - 1) * j / double(nbZones) + 0.5);
187 window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);
188 }
189 }
190
191 if (dimregno >= 0) {
192 gc->set_foreground(red);
193 int dr = (dimregno >> bitpos) & ((1 << region->pDimensionDefinitions[i].bits) - 1);
194 if (customsplits) {
195 int x1 = 0;
196 for (int j = 0 ; j < nbZones ; j++) {
197 gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];
198 int upperLimit = d->DimensionUpperLimits[i];
199 if (!upperLimit) upperLimit = d->VelocityUpperLimit;
200 int v = upperLimit + 1;
201 int x2 = int((w - label_width - 1) * v / 128.0 + 0.5);
202 if (j == dr && x1 < x2) {
203 window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,
204 (x2 - x1) - 1, h - 2);
205 break;
206 }
207 x1 = x2;
208 }
209 } else {
210 if (dr < nbZones) {
211 int x1 = int((w - label_width - 1) * dr / double(nbZones) + 0.5);
212 int x2 = int((w - label_width - 1) * (dr + 1) / double(nbZones) + 0.5);
213 window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,
214 (x2 - x1) - 1, h - 2);
215 }
216 }
217 }
218
219 y += h;
220 }
221 bitpos += region->pDimensionDefinitions[i].bits;
222 }
223
224 return true;
225 }
226
227 void DimRegionChooser::on_size_request(GtkRequisition* requisition)
228 {
229 printf("DimRegionChooser::on_size_request\n");
230 *requisition = GtkRequisition();
231 requisition->height = region ? nbDimensions * 20 : 0;
232 requisition->width = 800;
233 }
234
235 void DimRegionChooser::set_instrument(gig::Instrument* instrument)
236 {
237 this->instrument = instrument;
238 this->region = 0;
239 this->dimregno = -1;
240 queue_draw();
241 }
242
243 void DimRegionChooser::set_region(gig::Region* region)
244 {
245 this->region = region;
246 dimregno = 0;
247 int bitcount = 0;
248 nbDimensions = 0;
249 if (region) {
250 for (int dim = 0 ; dim < region->Dimensions ; dim++) {
251 if (region->pDimensionDefinitions[dim].bits == 0) continue;
252 nbDimensions++;
253
254 int from = dimvalue_from[region->pDimensionDefinitions[dim].dimension];
255 int to = dimvalue_to[region->pDimensionDefinitions[dim].dimension];
256 int z;
257 switch (region->pDimensionDefinitions[dim].split_type) {
258 case gig::split_type_normal:
259 z = int((to + from) / 2.0 / region->pDimensionDefinitions[dim].zone_size);
260 break;
261 case gig::split_type_bit:
262 z = std::min(from, region->pDimensionDefinitions[dim].zones - 1);
263 break;
264 }
265 int mask =
266 ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) <<
267 bitcount);
268 dimregno &= mask;
269 dimregno |= (z << bitcount);
270 bitcount += region->pDimensionDefinitions[dim].bits;
271 }
272 dimreg = region->pDimensionRegions[dimregno];
273 }
274 sel_changed_signal.emit();
275 queue_resize();
276 }
277
278 /*
279 void DimRegionChooser::set_dimregno(int x) {
280 this->dimregno = x;
281 queue_draw();
282 }
283 */
284
285 bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
286 {
287 if (resize.active) {
288 get_window()->pointer_ungrab(event->time);
289 resize.active = false;
290
291 if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
292
293 int bitpos = 0;
294 for (int j = 0 ; j < resize.dimension ; j++) {
295 bitpos += region->pDimensionDefinitions[j].bits;
296 }
297 int mask =
298 ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
299 int c = dimregno & mask; // mask away this dimension
300
301 gig::DimensionRegion *d = region->pDimensionRegions[c + resize.offset];
302 if (d->DimensionUpperLimits[resize.dimension]) {
303 d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
304 } else {
305 d->VelocityUpperLimit = resize.pos - 1;
306 }
307
308 } else {
309 for (int i = 0 ; i < region->DimensionRegions ; ) {
310
311 gig::DimensionRegion *d = region->pDimensionRegions[i + resize.offset];
312 d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;
313
314 int bitpos = 0;
315 int j;
316 for (j = 0 ; j < region->Dimensions ; j++) {
317 if (j != resize.dimension) {
318 int maxzones = 1 << region->pDimensionDefinitions[j].bits;
319 int dimj = (i >> bitpos) & (maxzones - 1);
320 if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
321 }
322 bitpos += region->pDimensionDefinitions[j].bits;
323 }
324 if (j == region->Dimensions) break;
325 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
326 }
327 }
328
329 if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
330 get_window()->set_cursor();
331 cursor_is_resize = false;
332 }
333 }
334 return true;
335 }
336
337 bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
338 {
339 if (region && event->y < nbDimensions * h &&
340 event->x >= label_width && event->x < w) {
341
342 if (is_in_resize_zone(event->x, event->y)) {
343 Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);
344 get_window()->pointer_grab(false,
345 Gdk::BUTTON_RELEASE_MASK |
346 Gdk::POINTER_MOTION_MASK |
347 Gdk::POINTER_MOTION_HINT_MASK,
348 double_arrow, event->time);
349 resize.active = true;
350 } else {
351 int ydim = int(event->y / h);
352 int dim;
353 for (dim = 0 ; dim < region->Dimensions ; dim++) {
354 if (region->pDimensionDefinitions[dim].bits == 0) continue;
355 if (ydim == 0) break;
356 ydim--;
357 }
358 int nbZones = region->pDimensionDefinitions[dim].zones;
359
360 int z = -1;
361 int bitpos = 0;
362 for (int i = 0 ; i < dim ; i++) {
363 bitpos += region->pDimensionDefinitions[i].bits;
364 }
365
366 int i = dim;
367 if (dimregno < 0) dimregno = 0;
368 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
369 int c = dimregno & mask; // mask away this dimension
370
371 bool customsplits =
372 ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
373 region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
374 (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
375 region->pDimensionRegions[c]->VelocityUpperLimit));
376 if (customsplits) {
377 int val = int((event->x - label_width) * 128 / (w - label_width - 1));
378
379 if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
380 for (z = 0 ; z < nbZones ; z++) {
381 gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];
382 if (val <= d->DimensionUpperLimits[i]) break;
383 }
384 } else {
385 for (z = 0 ; z < nbZones ; z++) {
386 gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];
387 if (val <= d->VelocityUpperLimit) break;
388 }
389 }
390 } else {
391 z = int((event->x - label_width) * nbZones / (w - label_width - 1));
392 }
393
394 printf("dim=%d z=%d dimensionsource=%d split_type=%d zones=%d zone_size=%f\n", dim, z,
395 region->pDimensionDefinitions[dim].dimension,
396 region->pDimensionDefinitions[dim].split_type,
397 region->pDimensionDefinitions[dim].zones,
398 region->pDimensionDefinitions[dim].zone_size);
399 #if 0
400 switch (region->pDimensionDefinitions[dim].split_type) {
401 case gig::split_type_normal:
402 dimvalue_from[region->pDimensionDefinitions[dim].dimension] =
403 int(z * region->pDimensionDefinitions[dim].zone_size);
404 dimvalue_to[region->pDimensionDefinitions[dim].dimension] =
405 int((z + 1) * region->pDimensionDefinitions[dim].zone_size) - 1;
406 break;
407 case gig::split_type_bit:
408 dimvalue_from[region->pDimensionDefinitions[dim].dimension] = z;
409 dimvalue_to[region->pDimensionDefinitions[dim].dimension] = z + 1;
410 break;
411 }
412 #endif
413
414 dimregno = c | (z << bitpos);
415
416 focus_line = dim;
417 if (has_focus()) queue_draw();
418 else grab_focus();
419 dimreg = region->pDimensionRegions[dimregno];
420 sel_changed_signal.emit();
421 }
422 }
423 return true;
424 }
425
426 bool DimRegionChooser::on_motion_notify_event(GdkEventMotion* event)
427 {
428 Glib::RefPtr<Gdk::Window> window = get_window();
429 int x, y;
430 Gdk::ModifierType state = Gdk::ModifierType(0);
431 window->get_pointer(x, y, state);
432
433 if (resize.active) {
434 int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
435
436 if (k < resize.min) k = resize.min;
437 else if (k > resize.max) k = resize.max;
438
439 if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
440
441 if (k != resize.pos) {
442 Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
443 Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();
444
445 int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
446 int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
447 int y = resize.dimension * h;
448
449 if (resize.selected == resize.none) {
450 if (resize.pos != resize.min && resize.pos != resize.max) {
451 window->draw_line(white, prevx, y + 1, prevx, y + h - 2);
452 }
453 } else {
454 gc->set_foreground(red);
455
456 Glib::RefPtr<const Gdk::GC> left;
457 Glib::RefPtr<const Gdk::GC> right;
458 if (resize.selected == resize.left) {
459 left = gc;
460 right = white;
461 } else {
462 left = white;
463 right = gc;
464 }
465
466 if (k > resize.pos) {
467 int xx = resize.pos == resize.min ? 1 : 0;
468 window->draw_rectangle(left, true,
469 prevx + xx, y + 1, x - prevx - xx, h - 2);
470 } else {
471 int xx = resize.pos == resize.max ? 0 : 1;
472 window->draw_rectangle(right, true,
473 x, y + 1, prevx - x + xx, h - 2);
474 }
475 }
476 window->draw_line(black, x, y + 1, x, y + h - 2);
477 resize.pos = k;
478 }
479 } else {
480 if (is_in_resize_zone(x, y)) {
481 if (!cursor_is_resize) {
482 Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);
483 window->set_cursor(double_arrow);
484 cursor_is_resize = true;
485 }
486 } else if (cursor_is_resize) {
487 window->set_cursor();
488 cursor_is_resize = false;
489 }
490 }
491 return true;
492 }
493
494 bool DimRegionChooser::is_in_resize_zone(double x, double y)
495 {
496 if (region && y < nbDimensions * h && x >= label_width && x < w) {
497 int ydim = int(y / h);
498 int dim;
499 int bitpos = 0;
500 for (dim = 0 ; dim < region->Dimensions ; dim++) {
501 if (region->pDimensionDefinitions[dim].bits == 0) continue;
502 if (ydim == 0) break;
503 ydim--;
504 bitpos += region->pDimensionDefinitions[dim].bits;
505 }
506 int nbZones = region->pDimensionDefinitions[dim].zones;
507
508 int c = 0;
509 if (dimregno >= 0) {
510 int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
511 c = dimregno & mask; // mask away this dimension
512 }
513 bool customsplits =
514 ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
515 region->pDimensionRegions[c]->DimensionUpperLimits[dim]) ||
516 (region->pDimensionDefinitions[dim].dimension == gig::dimension_velocity &&
517 region->pDimensionRegions[c]->VelocityUpperLimit));
518
519 if (customsplits) {
520 int prev_limit = 0;
521 for (int j = 0 ; j < nbZones - 1 ; j++) {
522 gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];
523 int upperLimit = d->DimensionUpperLimits[dim];
524 if (!upperLimit) upperLimit = d->VelocityUpperLimit;
525 int limit = upperLimit + 1;
526 int limitx = int((w - label_width - 1) * limit / 128.0 + 0.5) + label_width;
527
528 if (x <= limitx - 2) break;
529 if (x <= limitx + 2) {
530 resize.dimension = dim;
531 resize.offset = j << bitpos;
532 resize.pos = limit;
533 resize.min = prev_limit;
534
535 int dr = (dimregno >> bitpos) &
536 ((1 << region->pDimensionDefinitions[dim].bits) - 1);
537 resize.selected = dr == j ? resize.left :
538 dr == j + 1 ? resize.right : resize.none;
539
540 j++;
541 gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];
542 int upperLimit = d->DimensionUpperLimits[dim];
543 if (!upperLimit) upperLimit = d->VelocityUpperLimit;
544 int limit = upperLimit + 1;
545 resize.max = limit;
546 return true;
547 }
548 prev_limit = limit;
549 }
550 }
551 }
552 return false;
553 }
554
555 sigc::signal<void> DimRegionChooser::signal_sel_changed()
556 {
557 return sel_changed_signal;
558 }
559
560 bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
561 {
562 // TODO: kolla att region finns osv, dvs att det g�r att s�tta
563 // fokus.
564 if (direction == Gtk::DIR_TAB_FORWARD ||
565 direction == Gtk::DIR_DOWN) {
566 if (!has_focus()) {
567 focus_line = 0;
568 grab_focus();
569 return true;
570 } else {
571 if (focus_line + 1 < region->Dimensions) {
572 focus_line++;
573 queue_draw();
574 return true;
575 } else {
576 return false;
577 }
578 }
579 } else if (direction == Gtk::DIR_TAB_BACKWARD ||
580 direction == Gtk::DIR_UP) {
581 if (!has_focus()) {
582 focus_line = region->Dimensions - 1;
583 grab_focus();
584 return true;
585 } else {
586 if (focus_line > 0) {
587 focus_line--;
588 queue_draw();
589 return true;
590 } else {
591 return false;
592 }
593 }
594 } else if (!has_focus()) {
595 // TODO: kolla att focus_line finns!
596 grab_focus();
597 return true;
598 } else {
599 // TODO: �ka eller minska v�rde!
600 }
601 }

  ViewVC Help
Powered by ViewVC