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

Annotation of /gigedit/trunk/src/regionchooser.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1090 - (hide annotations) (download)
Sat Mar 10 17:08:15 2007 UTC (17 years, 1 month ago) by persson
File size: 12932 byte(s)
* implemented resizing of regions

1 persson 1052 /*
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 "regionchooser.h"
21     #include <gdkmm/cursor.h>
22    
23     RegionChooser::RegionChooser()
24     {
25     Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();
26    
27     black = Gdk::Color("black");
28     white = Gdk::Color("white");
29     red = Gdk::Color("#8070ff");
30     blue = Gdk::Color("#c098ff");
31     green = Gdk::Color("#a088ff");
32     grey1 = Gdk::Color("red");
33    
34     colormap->alloc_color(black);
35     colormap->alloc_color(white);
36     colormap->alloc_color(red);
37     colormap->alloc_color(blue);
38     colormap->alloc_color(green);
39     colormap->alloc_color(grey1);
40     instrument = 0;
41     region = 0;
42 persson 1090 resize.active = false;
43     cursor_is_resize = false;
44     h1 = 20;
45     width = 800;
46 persson 1052
47 persson 1090 add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
48     Gdk::POINTER_MOTION_HINT_MASK);
49 persson 1052 }
50    
51     RegionChooser::~RegionChooser()
52     {
53     }
54    
55     void RegionChooser::on_realize()
56     {
57     // We need to call the base on_realize()
58     Gtk::DrawingArea::on_realize();
59    
60     // Now we can allocate any additional resources we need
61     Glib::RefPtr<Gdk::Window> window = get_window();
62     gc = Gdk::GC::create(window);
63     window->clear();
64     }
65    
66     bool RegionChooser::on_expose_event(GdkEventExpose* event)
67     {
68     Glib::RefPtr<Gdk::Window> window = get_window();
69     window->clear();
70     const int h = 40;
71 persson 1090 const int w = width - 1;
72 persson 1052 const int bh = int(h * 0.55);
73    
74     Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
75     Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();
76    
77     window->draw_rectangle(black, false, 0, h1, w, h - 1);
78     window->draw_rectangle(white, true, 1, h1 + 1, w - 1, h - 2);
79     for (int i = 0 ; i < 128 ; i++) {
80     int note = (i + 3) % 12;
81     int x = int(w * i / 128.0 + 0.5);
82    
83     if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) {
84     int x2 = int(w * (i + 0.5) / 128.0 + 0.5);
85     window->draw_line(black, x2, h1 + bh, x2, h1 + h);
86    
87     int x3 = int(w * (i + 1) / 128.0 + 0.5);
88     window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh);
89     } else if (note == 3 || note == 8) {
90     window->draw_line(black, x, h1 + 1, x, h1 + h);
91     }
92     }
93    
94     if (instrument) {
95     int i = 0;
96     gig::Region *nextRegion;
97     int x3 = -1;
98     for (gig::Region *r = instrument->GetFirstRegion() ;
99     r ;
100     r = nextRegion) {
101    
102     if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);
103     nextRegion = instrument->GetNextRegion();
104     if (!nextRegion || r->KeyRange.high + 1 != nextRegion->KeyRange.low) {
105     int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
106     window->draw_line(black, x3, 0, x2, 0);
107     window->draw_line(black, x3, h1 - 1, x2, h1 - 1);
108     window->draw_line(black, x2, 1, x2, h1 - 2);
109     window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);
110     x3 = -1;
111     }
112     i++;
113     }
114    
115     for (gig::Region *r = instrument->GetFirstRegion() ;
116     r ;
117     r = instrument->GetNextRegion()) {
118     int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);
119     window->draw_line(black, x, 1, x, h1 - 2);
120     }
121    
122     if (region) {
123     int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);
124     int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);
125     gc->set_foreground(red);
126     window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);
127     }
128     }
129     return true;
130     }
131    
132    
133     void RegionChooser::on_size_request(GtkRequisition* requisition)
134     {
135     *requisition = GtkRequisition();
136     requisition->height = 40 + 20;
137     requisition->width = 500;
138     }
139    
140    
141 persson 1090 // not used
142 persson 1052 void RegionChooser::draw_region(int from, int to, const Gdk::Color& color)
143     {
144     const int h = 40;
145 persson 1090 const int w = width;
146 persson 1052 const int bh = int(h * 0.55);
147    
148     Glib::RefPtr<Gdk::Window> window = get_window();
149     gc->set_foreground(color);
150    
151     for (int i = from ; i < to ; i++) {
152     int note = (i + 3) % 12;
153     int x = int(w * i / 128.0 + 0.5) + 1;
154     int x2 = int(w * (i + 1.5) / 128.0 + 0.5);
155     int x3 = int(w * (i + 1) / 128.0 + 0.5);
156     int x4 = int(w * (i - 0.5) / 128 + 0.5) + 1;
157     int w1 = x3 - x;
158     switch (note) {
159     case 0: case 5: case 10:
160     window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
161     window->draw_rectangle(gc, true, x4, h1 + bh + 1, x2 - x4, h - bh - 2);
162     break;
163     case 2: case 7:
164     window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
165     window->draw_rectangle(gc, true, x4, h1 + bh + 1, x3 - x4, h - bh - 2);
166     break;
167     case 3: case 8:
168     window->draw_rectangle(gc, true, x, h1 + 1, w1, bh);
169     window->draw_rectangle(gc, true, x, h1 + bh + 1, x2 - x, h - bh - 2);
170     break;
171     default:
172     window->draw_rectangle(gc, true, x, h1 + 1, w1, bh - 1);
173     break;
174     }
175     }
176     }
177    
178     void RegionChooser::set_instrument(gig::Instrument* instrument)
179     {
180     this->instrument = instrument;
181     region = instrument->GetFirstRegion();
182     queue_draw();
183     sel_changed_signal.emit();
184     }
185    
186     void RegionChooser::set_region(gig::Region* region)
187     {
188     this->region = region;
189     queue_draw();
190     }
191    
192 persson 1090 bool RegionChooser::on_button_release_event(GdkEventButton* event)
193     {
194     if (resize.active) {
195     get_window()->pointer_ungrab(event->time);
196     resize.active = false;
197    
198     if (resize.mode == resize.moving_high_limit) {
199     resize.region->KeyRange.high = resize.pos - 1;
200     } else if (resize.mode == resize.moving_low_limit) {
201     resize.region->KeyRange.low = resize.pos;
202     }
203    
204     if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
205     get_window()->set_cursor();
206     cursor_is_resize = false;
207     }
208     }
209     return true;
210     }
211    
212 persson 1052 bool RegionChooser::on_button_press_event(GdkEventButton* event)
213     {
214 persson 1090 if (instrument) {
215     if (is_in_resize_zone(event->x, event->y)) {
216     Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);
217     get_window()->pointer_grab(false,
218     Gdk::BUTTON_RELEASE_MASK |
219     Gdk::POINTER_MOTION_MASK |
220     Gdk::POINTER_MOTION_HINT_MASK,
221     double_arrow, event->time);
222     resize.active = true;
223     } else {
224     const int w = width - 1;
225     int i = 0;
226     for (gig::Region *r = instrument->GetFirstRegion() ; r ;
227     r = instrument->GetNextRegion()) {
228 persson 1052
229 persson 1090 int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);
230     int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
231     if (event->x >= x && event->x < x2) {
232     region = r;
233     break;
234     }
235     i++;
236 persson 1052 }
237 persson 1090 queue_draw();
238     sel_changed_signal.emit();
239 persson 1052 }
240     }
241     }
242    
243     bool RegionChooser::on_motion_notify_event(GdkEventMotion* event)
244     {
245 persson 1090 const int w = width - 1;
246     Glib::RefPtr<Gdk::Window> window = get_window();
247     int x, y;
248     Gdk::ModifierType state = Gdk::ModifierType(0);
249     window->get_pointer(x, y, state);
250     if (resize.active) {
251     int k = int(double(x) / w * 128.0 + 0.5);
252    
253     if (k < resize.min) k = resize.min;
254     else if (k > resize.max) k = resize.max;
255    
256     if (k != resize.pos) {
257     if (resize.mode == resize.undecided) {
258     if (k < resize.pos) {
259     // edit high limit of prev_region
260     resize.max = resize.region->KeyRange.low;
261     resize.region = resize.prev_region;
262     resize.mode = resize.moving_high_limit;
263     } else {
264     // edit low limit of region
265     resize.min = resize.prev_region->KeyRange.high + 1;
266     resize.mode = resize.moving_low_limit;
267     }
268     }
269     Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
270     Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();
271     if (region == resize.region) {
272     gc->set_foreground(red);
273     white = gc;
274     }
275     Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);
276     int prevx = int(w * resize.pos / 128.0 + 0.5);
277     x = int(w * k / 128.0 + 0.5);
278    
279     if (resize.mode == resize.moving_high_limit) {
280     if (k > resize.pos) {
281     window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);
282     window->draw_line(black, prevx, 0, x, 0);
283     window->draw_line(black, prevx, h1 - 1, x, h1 - 1);
284     } else {
285     int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);
286     window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);
287     }
288     } else {
289     if (k < resize.pos) {
290     window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);
291     window->draw_line(black, x, 0, prevx, 0);
292     window->draw_line(black, x, h1 - 1, prevx, h1 - 1);
293     } else {
294     int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);
295     window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);
296     }
297     }
298     window->draw_line(black, x, 1, x, h1 - 2);
299     resize.pos = k;
300 persson 1052 }
301 persson 1090 } else {
302     if (is_in_resize_zone(x, y)) {
303     if (!cursor_is_resize) {
304     Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);
305     window->set_cursor(double_arrow);
306     cursor_is_resize = true;
307     }
308     } else if (cursor_is_resize) {
309     window->set_cursor();
310     cursor_is_resize = false;
311     }
312 persson 1052 }
313 persson 1090
314     return true;
315 persson 1052 }
316    
317 persson 1090 bool RegionChooser::is_in_resize_zone(double x, double y) {
318     const int w = width - 1;
319    
320     if (instrument && y >= 0 && y <= h1) {
321     gig::Region* prev_region = 0;
322     gig::Region* next_region;
323     for (gig::Region* r = instrument->GetFirstRegion() ; r ; r = next_region) {
324     next_region = instrument->GetNextRegion();
325    
326     int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5);
327     if (x <= lo - 2) break;
328     if (x < lo + 2) {
329     resize.region = r;
330     resize.pos = r->KeyRange.low;
331     resize.max = r->KeyRange.high;
332    
333     if (prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low) {
334     // we don't know yet if it's the high limit of
335     // prev_region or the low limit of r that's going
336     // to be edited
337     resize.mode = resize.undecided;
338     resize.min = prev_region->KeyRange.low + 1;
339     resize.prev_region = prev_region;
340     return true;
341     }
342    
343     // edit low limit
344     resize.mode = resize.moving_low_limit;
345     resize.min = prev_region ? prev_region->KeyRange.high + 1 : 0;
346     return true;
347     }
348     if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
349     int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
350     if (x <= hi - 2) break;
351     if (x < hi + 2) {
352     // edit high limit
353     resize.region = r;
354     resize.pos = r->KeyRange.high + 1;
355     resize.mode = resize.moving_high_limit;
356     resize.min = r->KeyRange.low + 1;
357     resize.max = next_region ? next_region->KeyRange.low : 128;
358     return true;
359     }
360     }
361     prev_region = r;
362     }
363     }
364     return false;
365     }
366    
367 persson 1052 sigc::signal<void> RegionChooser::signal_sel_changed()
368     {
369     return sel_changed_signal;
370     }

  ViewVC Help
Powered by ViewVC