--- gigedit/trunk/src/gigedit/regionchooser.cpp 2009/02/03 19:38:19 1831 +++ gigedit/trunk/src/gigedit/regionchooser.cpp 2014/06/12 16:12:55 2627 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2009 Andreas Persson + * Copyright (C) 2006-2014 Andreas Persson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,18 +18,20 @@ */ #include "regionchooser.h" + #include + +#include +#include #include #include #include #include -#include -#include #include "global.h" -#define REGION_BLOCK_HEIGHT 20 -#define KEYBOARD_HEIGHT 40 +#define REGION_BLOCK_HEIGHT 30 +#define KEYBOARD_HEIGHT 40 void SortedRegions::update(gig::Instrument* instrument) { // Usually, the regions in a gig file are ordered after their key @@ -37,7 +39,7 @@ // RegionChooser code needs a sorted list of regions. regions.clear(); if (instrument) { - for (gig::Region *r = instrument->GetFirstRegion() ; + for (gig::Region* r = instrument->GetFirstRegion() ; r ; r = instrument->GetNextRegion()) { regions.push_back(r); @@ -59,22 +61,16 @@ RegionChooser::RegionChooser() : + activeKeyColor("red"), + red("#8070ff"), + grey1("grey69"), + white("white"), + black("black"), m_VirtKeybModeChoice(_("Virtual Keyboard Mode")), currentActiveKey(-1) { - Glib::RefPtr colormap = get_default_colormap(); + set_size_request(500, KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT); - red = Gdk::Color("#8070ff"); - grey1 = Gdk::Color("#b0b0b0"); - activeKeyColor = Gdk::Color("#ff0000"); - white = Gdk::Color("#ffffff"); - black = Gdk::Color("#000000"); - - colormap->alloc_color(red); - colormap->alloc_color(grey1); - colormap->alloc_color(activeKeyColor); - colormap->alloc_color(white); - colormap->alloc_color(black); instrument = 0; region = 0; resize.active = false; @@ -84,7 +80,7 @@ // properties of the virtual keyboard { - const char* choices[] = { _("normal"), _("chord"), NULL }; + const char* choices[] = { _("normal"), _("chord"), 0 }; static const virt_keyboard_mode_t values[] = { VIRT_KEYBOARD_MODE_NORMAL, VIRT_KEYBOARD_MODE_CHORD @@ -104,6 +100,7 @@ m_VirtKeybPropsBox.pack_start(m_VirtKeybOffVelocityLabel, Gtk::PACK_SHRINK); m_VirtKeybPropsBox.set_spacing(10); m_VirtKeybPropsBox.show(); + for (int i = 0 ; i < 128 ; i++) key_pressed[i] = false; actionGroup = Gtk::ActionGroup::create(); actionGroup->add(Gtk::Action::create("Properties", @@ -157,118 +154,205 @@ keyboard_key_released_signal.connect( sigc::mem_fun(*this, &RegionChooser::on_note_off_event) ); + set_tooltip_text(_("Right click here for adding new region. Use mouse pointer for moving (dragging) or resizing existing regions (by pointing at region's boundary). Right click on an existing region for more actions.")); } RegionChooser::~RegionChooser() { } -template inline std::string ToString(T o) { - std::stringstream ss; - ss << o; - return ss.str(); +void RegionChooser::invalidate_key(int key) { + const int h = KEYBOARD_HEIGHT; + const int w = get_width() - 1; + int x1 = key_to_x(key - 0.5, w); + int x2 = key_to_x(key + 1.5, w); + + Gdk::Rectangle rect(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2); + get_window()->invalidate_rect(rect, false); } void RegionChooser::on_note_on_event(int key, int velocity) { - draw_region(key, key+1, activeKeyColor); + key_pressed[key] = true; + invalidate_key(key); m_VirtKeybVelocityLabel.set_text(ToString(velocity)); } void RegionChooser::on_note_off_event(int key, int velocity) { - if (is_black_key(key)) - draw_region(key, key+1, black); - else - draw_region(key, key+1, white); + key_pressed[key] = false; + invalidate_key(key); m_VirtKeybOffVelocityLabel.set_text(ToString(velocity)); } -void RegionChooser::on_realize() -{ - // We need to call the base on_realize() - Gtk::DrawingArea::on_realize(); - // Now we can allocate any additional resources we need - Glib::RefPtr window = get_window(); - gc = Gdk::GC::create(window); - window->clear(); +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 +bool RegionChooser::on_expose_event(GdkEventExpose* e) { + double clipx1 = e->area.x; + double clipx2 = e->area.x + e->area.width; + double clipy1 = e->area.y; + double clipy2 = e->area.y + e->area.height; + + const Cairo::RefPtr& cr = + get_window()->create_cairo_context(); +#if 0 +} +#endif +#else +bool RegionChooser::on_draw(const Cairo::RefPtr& cr) { + double clipx1, clipx2, clipy1, clipy2; + cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2); +#endif + + cr->save(); + cr->set_line_width(1); + +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 + const Gdk::Color bg = get_style()->get_bg(Gtk::STATE_NORMAL); +#else + const Gdk::RGBA bg = get_style_context()->get_background_color(); +#endif + Gdk::Cairo::set_source_rgba(cr, bg); + cr->paint(); + + if (clipy2 > h1) { + draw_keyboard(cr, clipx1, clipx2); + } + + if (clipy1 < h1 && instrument) { + draw_regions(cr, clipx1, clipx2); + } + + cr->restore(); + + return true; } -bool RegionChooser::on_expose_event(GdkEventExpose* event) -{ - Glib::RefPtr window = get_window(); - window->clear(); +void RegionChooser::draw_keyboard(const Cairo::RefPtr& cr, + int clip_low, int clip_high) { const int h = KEYBOARD_HEIGHT; const int w = get_width() - 1; const int bh = int(h * 0.55); - Glib::RefPtr black = get_style()->get_black_gc(); - Glib::RefPtr white = get_style()->get_white_gc(); + Gdk::Cairo::set_source_rgba(cr, black); + cr->rectangle(0.5, h1 + 0.5, w, h - 1); + cr->stroke(); + + int x1 = key_to_x(20.5, w); + Gdk::Cairo::set_source_rgba(cr, grey1); + cr->rectangle(1, h1 + 1, x1 - 1, h - 2); + cr->fill(); + + int x2 = key_to_x(109.5, w); + Gdk::Cairo::set_source_rgba(cr, white); + cr->rectangle(x1 + 1, h1 + 1, x2 - x1 - 1, h - 2); + cr->fill(); + + Gdk::Cairo::set_source_rgba(cr, grey1); + cr->rectangle(x2 + 1, h1 + 1, w - x2 - 1, h - 2); + cr->fill(); - window->draw_rectangle(black, false, 0, h1, w, h - 1); - gc->set_foreground(grey1); - int x1 = int(w * 20.5 / 128.0 + 0.5); - int x2 = int(w * 109.5 / 128.0 + 0.5); - window->draw_rectangle(gc, true, 1, h1 + 1, - x1 - 1, h - 2); - window->draw_rectangle(white, true, x1 + 1, h1 + 1, x2 - x1 - 1, h - 2); - window->draw_rectangle(gc, true, x2 + 1, h1 + 1, - w - x2 - 1, h - 2); - for (int i = 0 ; i < 128 ; i++) { - int note = (i + 3) % 12; - int x = int(w * i / 128.0 + 0.5); + Gdk::Cairo::set_source_rgba(cr, black); - if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) { - int x2 = int(w * (i + 0.5) / 128.0 + 0.5); - window->draw_line(black, x2, h1 + bh, x2, h1 + h); + int clipkey1 = std::max(0, x_to_key_right(clip_low - 1, w)); + int clipkey2 = std::min(x_to_key_right(clip_high - 1, w) + 1, 128); - int x3 = int(w * (i + 1) / 128.0 + 0.5); - window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh); + for (int i = clipkey1 ; i < clipkey2 ; i++) { + int note = (i + 3) % 12; + int x = key_to_x(i, w); + + if (note == 1 || note == 4 || note == 6 || + note == 9 || note == 11) { + // black key: short line in the middle, with a rectangle + // on top + int x2 = key_to_x(i + 0.5, w); + cr->move_to(x2 + 0.5, h1 + bh + 0.5); + cr->line_to(x2 + 0.5, h1 + h - 1); + cr->stroke(); + + int x3 = key_to_x(i + 1, w); + cr->rectangle(x, h1 + 1, x3 - x + 1, bh); + cr->fill(); } else if (note == 3 || note == 8) { - window->draw_line(black, x, h1 + 1, x, h1 + h); + // C or F: long line to the left + cr->move_to(x + 0.5, h1 + 1); + cr->line_to(x + 0.5, h1 + h - 1); + cr->stroke(); } - if (note == 3) draw_digit(i); + + if (key_pressed[i]) draw_key(cr, i); + + if (note == 3) draw_digit(cr, i); } +} - if (instrument) { - int i = 0; - gig::Region *next_region; - int x3 = -1; - for (gig::Region *r = regions.first() ; r ; r = next_region) { - if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5); - next_region = regions.next(); - if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) { - int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5); - window->draw_line(black, x3, 0, x2, 0); - window->draw_line(black, x3, h1 - 1, x2, h1 - 1); - window->draw_line(black, x2, 1, x2, h1 - 2); - window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2); - x3 = -1; - } - i++; - } +void RegionChooser::draw_regions(const Cairo::RefPtr& cr, + int clip_low, int clip_high) { + const int w = get_width() - 1; - for (gig::Region *r = regions.first() ; r ; r = regions.next()) { - int x = int(w * (r->KeyRange.low) / 128.0 + 0.5); - window->draw_line(black, x, 1, x, h1 - 2); - } + Gdk::Cairo::set_source_rgba(cr, black); + gig::Region* next_region; + int x3 = -1; + for (gig::Region* r = regions.first() ; r ; r = next_region) { + next_region = regions.next(); - if (region) { - int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5); - int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5); - gc->set_foreground(red); - window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2); + if (x3 < 0) { + x3 = key_to_x(r->KeyRange.low, w); + if (x3 >= clip_high) break; + } + if (!next_region || + r->KeyRange.high + 1 != next_region->KeyRange.low || + r == region || next_region == region) { + + int x2 = key_to_x(r->KeyRange.high + 1, w); + if (x2 >= clip_low) { + cr->move_to(x3, 0.5); + cr->line_to(x2 + 0.5, 0.5); + cr->line_to(x2 + 0.5, h1 - 0.5); + cr->line_to(x3, h1 - 0.5); + cr->stroke(); + + Gdk::Cairo::set_source_rgba(cr, region == r ? red : white); + cr->rectangle(x3 + 1, 1, x2 - x3 - 1, h1 - 2); + cr->fill(); + Gdk::Cairo::set_source_rgba(cr, black); + } + x3 = -1; } } - return true; -} - -void RegionChooser::on_size_request(GtkRequisition* requisition) -{ - *requisition = GtkRequisition(); - requisition->height = KEYBOARD_HEIGHT + REGION_BLOCK_HEIGHT; - requisition->width = 500; + for (gig::Region* r = regions.first() ; r ; r = regions.next()) { + int x = key_to_x(r->KeyRange.low, w); + + if (x < clip_low) continue; + if (x >= clip_high) break; + + cr->move_to(x + 0.5, 1); + cr->line_to(x + 0.5, h1 - 1); + cr->stroke(); + } + + // if there is no region yet, show the user some hint text that he may + // right click on this area to create a new region + if (!regions.first()) { + Glib::RefPtr context = get_pango_context(); + Glib::RefPtr layout = Pango::Layout::create(context); + layout->set_alignment(Pango::ALIGN_CENTER); + layout->set_text(Glib::ustring("*** ") + _("Right click here to create a region.") + " ***"); + layout->set_width(get_width() * Pango::SCALE); + //layout->set_height(get_height() * Pango::SCALE); + layout->set_spacing(10); + Gdk::Cairo::set_source_rgba(cr, red); + // get the text dimensions + Pango::Rectangle rect = layout->get_logical_extents(); + int text_width, text_height; + layout->get_pixel_size(text_width, text_height); + cr->move_to(0, (REGION_BLOCK_HEIGHT - text_height) / 2); +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2 + pango_cairo_show_layout(cr->cobj(), layout->gobj()); +#else + layout->show_in_cairo_context(cr); +#endif + } } bool RegionChooser::is_black_key(int key) { @@ -276,10 +360,12 @@ return note == 1 || note == 4 || note == 6 || note == 9 || note == 11; } -void RegionChooser::draw_digit(int key) { +void RegionChooser::draw_digit(const Cairo::RefPtr& cr, + int key) { const int h = KEYBOARD_HEIGHT; const int w = get_width() - 1; - Glib::RefPtr layout = Pango::Layout::create(get_pango_context()); + Glib::RefPtr layout = + Pango::Layout::create(get_pango_context()); char buf[30]; sprintf(buf, "%d", key / 12 - 1); layout->set_markup(buf); @@ -287,45 +373,54 @@ double text_w = double(rectangle.get_width()) / Pango::SCALE; double text_h = double(rectangle.get_height()) / Pango::SCALE; double x = w * (key + 0.75) / 128.0; - get_window()->draw_layout(get_style()->get_black_gc(), int(x - text_w / 2 + 1), - int(h1 + h - text_h + 0.5), layout); + Gdk::Cairo::set_source_rgba(cr, black); + cr->move_to(int(x - text_w / 2 + 1), int(h1 + h - text_h + 0.5)); +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2 + pango_cairo_show_layout(cr->cobj(), layout->gobj()); +#else + layout->show_in_cairo_context(cr); +#endif } -void RegionChooser::draw_region(int from, int to, const Gdk::Color& color) -{ +void RegionChooser::draw_key(const Cairo::RefPtr& cr, + int key) { const int h = KEYBOARD_HEIGHT; const int w = get_width() - 1; const int bh = int(h * 0.55); - Glib::RefPtr window = get_window(); - gc->set_foreground(color); + Gdk::Cairo::set_source_rgba(cr, activeKeyColor); - for (int i = from ; i < to ; i++) { - int note = (i + 3) % 12; - int x = int(w * i / 128.0 + 0.5) + 1; - int x2 = int(w * (i + 1.5) / 128.0 + 0.5); - int x3 = int(w * (i + 1) / 128.0 + 0.5); - int x4 = int(w * (i - 0.5) / 128.0 + 0.5); - int w1 = x3 - x; - switch (note) { - case 0: case 5: case 10: - window->draw_rectangle(gc, true, x, h1 + 1, w1, bh); - window->draw_rectangle(gc, true, x4 + 1, h1 + bh + 1, x2 - x4 - 1, h - bh - 2); - break; - case 2: case 7: - window->draw_rectangle(gc, true, x, h1 + 1, w1, bh); - window->draw_rectangle(gc, true, x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2); - break; - case 3: case 8: - window->draw_rectangle(gc, true, x, h1 + 1, w1, bh); - window->draw_rectangle(gc, true, x, h1 + bh + 1, x2 - x, h - bh - 2); - if (note == 3) draw_digit(i); - break; - default: - window->draw_rectangle(gc, true, x, h1 + 1, w1, bh - 1); - break; - } + int note = (key + 3) % 12; + int x = key_to_x(key, w) + 1; + int x2 = key_to_x(key + 1.5, w); + int x3 = key_to_x(key + 1, w); + int x4 = key_to_x(key - 0.5, w); + int w1 = x3 - x; + switch (note) { + case 0: case 5: case 10: + cr->rectangle(x, h1 + 1, w1, bh); + cr->fill(); + cr->rectangle(x4 + 1, h1 + bh + 1, x2 - x4 - 1, h - bh - 2); + cr->fill(); + break; + case 2: case 7: + cr->rectangle(x, h1 + 1, w1, bh); + cr->fill(); + cr->rectangle(x4 + 1, h1 + bh + 1, x3 - x4 - 1, h - bh - 2); + cr->fill(); + break; + case 3: case 8: + cr->rectangle(x, h1 + 1, w1, bh); + cr->fill(); + cr->rectangle(x, h1 + bh + 1, x2 - x, h - bh - 2); + cr->fill(); + break; + default: + cr->rectangle(x, h1 + 1, w1, bh - 1); + cr->fill(); + break; } + Gdk::Cairo::set_source_rgba(cr, black); } void RegionChooser::set_instrument(gig::Instrument* instrument) @@ -340,7 +435,7 @@ bool RegionChooser::on_button_release_event(GdkEventButton* event) { - const int k = int(event->x / (get_width() - 1) * 128.0); + const int k = x_to_key(event->x, get_width() - 1); // handle-note off on virtual keyboard if (event->type == GDK_BUTTON_RELEASE) { @@ -363,65 +458,76 @@ } if (resize.active) { +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 get_window()->pointer_ungrab(event->time); +#else + Glib::wrap(event->device, true)->ungrab(event->time); +#endif resize.active = false; - if (resize.mode == resize.moving_high_limit) { - if (resize.region->KeyRange.high != resize.pos - 1) { - instrument_struct_to_be_changed_signal.emit(instrument); - resize.region->SetKeyRange( - resize.region->KeyRange.low, // low - resize.pos - 1 // high - ); - regions.update(instrument); - instrument_changed.emit(); - instrument_struct_changed_signal.emit(instrument); - } - } else if (resize.mode == resize.moving_low_limit) { - if (resize.region->KeyRange.low != resize.pos) { - instrument_struct_to_be_changed_signal.emit(instrument); - resize.region->SetKeyRange( - resize.pos, // low - resize.region->KeyRange.high // high - ); - regions.update(instrument); - instrument_changed.emit(); - instrument_struct_changed_signal.emit(instrument); - } - } - if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) { get_window()->set_cursor(); cursor_is_resize = false; } } else if (move.active) { +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 get_window()->pointer_ungrab(event->time); +#else + Glib::wrap(event->device, true)->ungrab(event->time); +#endif move.active = false; - if (move.pos) { + if (is_in_resize_zone(event->x, event->y)) { +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 + get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW)); +#else + get_window()->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)); +#endif + cursor_is_resize = true; + } + } + return true; +} + +void RegionChooser::update_after_resize() +{ + if (resize.mode == resize.moving_high_limit) { + if (resize.region->KeyRange.high != resize.pos - 1) { instrument_struct_to_be_changed_signal.emit(instrument); - region->SetKeyRange( - region->KeyRange.low + move.pos, - region->KeyRange.high + move.pos - ); + resize.region->SetKeyRange(resize.region->KeyRange.low, + resize.pos - 1); regions.update(instrument); instrument_changed.emit(); instrument_struct_changed_signal.emit(instrument); } - - if (is_in_resize_zone(event->x, event->y)) { - get_window()->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW)); - cursor_is_resize = true; + } else if (resize.mode == resize.moving_low_limit) { + if (resize.region->KeyRange.low != resize.pos) { + instrument_struct_to_be_changed_signal.emit(instrument); + resize.region->SetKeyRange(resize.pos, + resize.region->KeyRange.high); + regions.update(instrument); + instrument_changed.emit(); + instrument_struct_changed_signal.emit(instrument); } } - return true; +} + +void RegionChooser::update_after_move(int pos) +{ + instrument_struct_to_be_changed_signal.emit(instrument); + region->SetKeyRange(pos, pos + region->KeyRange.high - + region->KeyRange.low); + regions.update(instrument); + instrument_changed.emit(); + instrument_struct_changed_signal.emit(instrument); } bool RegionChooser::on_button_press_event(GdkEventButton* event) { if (!instrument) return true; - const int k = int(event->x / (get_width() - 1) * 128.0); + const int w = get_width() - 1; + const int k = x_to_key(event->x, w); if (event->type == GDK_BUTTON_PRESS) { if (event->y >= REGION_BLOCK_HEIGHT) { @@ -447,11 +553,23 @@ } } else { if (is_in_resize_zone(event->x, event->y)) { +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 get_window()->pointer_grab(false, Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK, - Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW), event->time); + Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW), + event->time); +#else + Glib::wrap(event->device, true)->grab(get_window(), + Gdk::OWNERSHIP_NONE, + false, + Gdk::BUTTON_RELEASE_MASK | + Gdk::POINTER_MOTION_MASK | + Gdk::POINTER_MOTION_HINT_MASK, + Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW), + event->time); +#endif resize.active = true; } else { gig::Region* r = get_region(k); @@ -461,14 +579,25 @@ region_selected(); dimensionManager.set_region(region); +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 get_window()->pointer_grab(false, Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK, - Gdk::Cursor(Gdk::FLEUR), event->time); + Gdk::Cursor(Gdk::FLEUR), + event->time); +#else + Glib::wrap(event->device, true)->grab(get_window(), + Gdk::OWNERSHIP_NONE, + false, + Gdk::BUTTON_RELEASE_MASK | + Gdk::POINTER_MOTION_MASK | + Gdk::POINTER_MOTION_HINT_MASK, + Gdk::Cursor::create(Gdk::FLEUR), + event->time); +#endif move.active = true; - move.from_x = event->x; - move.pos = 0; + move.offset = event->x - key_to_x(region->KeyRange.low, w); } } } @@ -477,18 +606,9 @@ gig::Region* RegionChooser::get_region(int key) { - gig::Region* prev_region = 0; - gig::Region* next_region; - for (gig::Region *r = regions.first() ; r ; r = next_region) { - next_region = regions.next(); - + for (gig::Region* r = regions.first() ; r ; r = regions.next()) { if (key < r->KeyRange.low) return 0; - if (key <= r->KeyRange.high) { - move.touch_left = prev_region && prev_region->KeyRange.high + 1 == r->KeyRange.low; - move.touch_right = next_region && r->KeyRange.high + 1 == next_region->KeyRange.low; - return r; - } - prev_region = r; + if (key <= r->KeyRange.high) return r; } return 0; } @@ -496,7 +616,6 @@ void RegionChooser::motion_resize_region(int x, int y) { const int w = get_width() - 1; - Glib::RefPtr window = get_window(); int k = int(double(x) / w * 128.0 + 0.5); @@ -516,75 +635,68 @@ resize.mode = resize.moving_low_limit; } } - Glib::RefPtr black = get_style()->get_black_gc(); - Glib::RefPtr white = get_style()->get_white_gc(); - if (region == resize.region) { - gc->set_foreground(red); - white = gc; - } - Glib::RefPtr bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL); - int prevx = int(w * resize.pos / 128.0 + 0.5); - x = int(w * k / 128.0 + 0.5); + resize.pos = k; + int x1, x2; if (resize.mode == resize.moving_high_limit) { - if (k > resize.pos) { - window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2); - window->draw_line(black, prevx, 0, x, 0); - window->draw_line(black, prevx, h1 - 1, x, h1 - 1); + if (resize.region->KeyRange.high < resize.pos - 1) { + x1 = resize.region->KeyRange.high; + x2 = resize.pos - 1; } else { - int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0); - window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1); + x1 = resize.pos - 1; + x2 = resize.region->KeyRange.high; } } else { - if (k < resize.pos) { - window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2); - window->draw_line(black, x, 0, prevx, 0); - window->draw_line(black, x, h1 - 1, prevx, h1 - 1); + if (resize.region->KeyRange.low < resize.pos) { + x1 = resize.region->KeyRange.low; + x2 = resize.pos; } else { - int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0); - window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1); + x1 = resize.pos; + x2 = resize.region->KeyRange.low; } } - window->draw_line(black, x, 1, x, h1 - 2); - resize.pos = k; + x1 = key_to_x(x1, w); + x2 = key_to_x(x2 + 1, w) + 1; + Gdk::Rectangle rect(x1, 0, x2 - x1, h1); + + update_after_resize(); + + get_window()->invalidate_rect(rect, false); } } void RegionChooser::motion_move_region(int x, int y) { const int w = get_width() - 1; - Glib::RefPtr window = get_window(); - int k = int(double(x - move.from_x) / w * 128.0 + 0.5); - if (k == move.pos) return; - int new_k; - bool new_touch_left; - bool new_touch_right; + int l = int(double(x - move.offset) / w * 128.0 + 0.5); + + if (l == region->KeyRange.low) return; + int new_l; + int regionsize = region->KeyRange.high - region->KeyRange.low; int a = 0; - if (k > move.pos) { + if (l > region->KeyRange.low) { for (gig::Region* r = regions.first() ; ; r = regions.next()) { if (r != region) { int b = r ? r->KeyRange.low : 128; // gap: from a to b (not inclusive b) - if (region->KeyRange.high + move.pos >= b) { + if (region->KeyRange.high >= b) { // not found the current gap yet, just continue } else { - if (a > region->KeyRange.low + k) { + if (a > l) { // this gap is too far to the right, break break; } - int newhigh = std::min(region->KeyRange.high + k, b - 1); - int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low); + int newhigh = std::min(l + regionsize, b - 1); + int newlo = newhigh - regionsize; if (newlo >= a) { // yes it fits - it's a candidate - new_k = newlo - region->KeyRange.low; - new_touch_left = a > 0 && a == newlo; - new_touch_right = b < 128 && newhigh + 1 == b; + new_l = newlo; } } if (!r) break; @@ -598,23 +710,21 @@ // gap from a to b (not inclusive b) - if (region->KeyRange.high + k >= b) { + if (l + regionsize >= b) { // not found the current gap yet, just continue } else { - if (a > region->KeyRange.low + move.pos) { + if (a > region->KeyRange.low) { // this gap is too far to the right, break break; } - int newlo = std::max(region->KeyRange.low + k, a); - int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low); + int newlo = std::max(l, a); + int newhigh = newlo + regionsize; if (newhigh < b) { // yes it fits - break as the first one is the best - new_k = newlo - region->KeyRange.low; - new_touch_left = a > 0 && a == newlo; - new_touch_right = b < 128 && newhigh + 1 == b; + new_l = newlo; break; } } @@ -623,43 +733,16 @@ } } } - k = new_k; - if (k == move.pos) return; - - Glib::RefPtr bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL); - int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5); - x = int(w * (k + region->KeyRange.low) / 128.0 + 0.5); - int prevx2 = int(w * (move.pos + region->KeyRange.high + 1) / 128.0 + 0.5); - int x2 = int(w * (k + region->KeyRange.high + 1) / 128.0 + 0.5); - Glib::RefPtr black = get_style()->get_black_gc(); - gc->set_foreground(red); - - if (!new_touch_left) window->draw_line(black, x, 1, x, h1 - 2); - if (!new_touch_right) window->draw_line(black, x2, 1, x2, h1 - 2); - - if (k > move.pos) { - window->draw_rectangle(bg, true, prevx + (move.touch_left ? 1 : 0), 0, - std::min(x, prevx2 + 1 - (move.touch_right ? 1 : 0)) - - (prevx + (move.touch_left ? 1 : 0)), h1); - - window->draw_line(black, std::max(x, prevx2 + 1), 0, x2, 0); - window->draw_line(black, std::max(x, prevx2 + 1), h1 - 1, x2, h1 - 1); - window->draw_rectangle(gc, true, std::max(x + 1, prevx2), 1, - x2 - std::max(x + 1, prevx2), h1 - 2); - } else { - window->draw_rectangle(bg, true, std::max(x2 + 1, prevx + (move.touch_left ? 1 : 0)), 0, - prevx2 + 1 - (move.touch_right ? 1 : 0) - - std::max(x2 + 1, prevx + (move.touch_left ? 1 : 0)), h1); + if (new_l == region->KeyRange.low) return; - window->draw_line(black, x, 0, std::min(x2, prevx - 1), 0); - window->draw_line(black, x, h1 - 1, std::min(x2, prevx - 1), h1 - 1); + int x1 = key_to_x(std::min(int(region->KeyRange.low), new_l), w); + int x2 = key_to_x(std::max(int(region->KeyRange.high), + new_l + regionsize) + 1, w) + 1; - window->draw_rectangle(gc, true, x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2); - } + Gdk::Rectangle rect(x1, 0, x2 - x1, h1); + update_after_move(new_l); - move.pos = k; - move.touch_left = new_touch_left; - move.touch_right = new_touch_right; + get_window()->invalidate_rect(rect, false); } @@ -676,13 +759,17 @@ event->y >= REGION_BLOCK_HEIGHT && event->y < REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT) { - const int k = int(event->x / (get_width() - 1) * 128.0); - int velocity = (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 : - int(float(event->y - REGION_BLOCK_HEIGHT) / float(KEYBOARD_HEIGHT) * 128.0f) + 1; - if (velocity <= 0) velocity = 1; - keyboard_key_released_signal.emit(currentActiveKey, velocity); - currentActiveKey = k; - keyboard_key_hit_signal.emit(k, velocity); + const int k = x_to_key(event->x, get_width() - 1); + if (k != currentActiveKey) { + int velocity = + (event->y >= REGION_BLOCK_HEIGHT + KEYBOARD_HEIGHT - 1) ? 127 : + int(float(event->y - REGION_BLOCK_HEIGHT) / + float(KEYBOARD_HEIGHT) * 128.0f) + 1; + if (velocity <= 0) velocity = 1; + keyboard_key_released_signal.emit(currentActiveKey, velocity); + currentActiveKey = k; + keyboard_key_hit_signal.emit(k, velocity); + } } if (resize.active) { @@ -692,7 +779,11 @@ } else { if (is_in_resize_zone(x, y)) { if (!cursor_is_resize) { +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW)); +#else + window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)); +#endif cursor_is_resize = true; } } else if (cursor_is_resize) { @@ -713,7 +804,7 @@ for (gig::Region* r = regions.first(); r ; r = next_region) { next_region = regions.next(); - int lo = int(w * (r->KeyRange.low) / 128.0 + 0.5); + int lo = key_to_x(r->KeyRange.low, w); if (x <= lo - 2) break; if (x < lo + 2) { resize.region = r; @@ -736,7 +827,7 @@ return resize.min != resize.max; } if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) { - int hi = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5); + int hi = key_to_x(r->KeyRange.high + 1, w); if (x <= hi - 2) break; if (x < hi + 2) { // edit high limit @@ -774,8 +865,12 @@ dialog.get_vbox()->pack_start(checkBoxKeygroup); checkBoxKeygroup.show(); // add "Keygroup" spinbox - Gtk::Adjustment adjustment(1, 1, pow(2,32)); +#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 + Gtk::Adjustment adjustment(1, 1, 999); Gtk::SpinButton spinBox(adjustment); +#else + Gtk::SpinButton spinBox(Gtk::Adjustment::create(1, 1, 999)); +#endif if (region->KeyGroup) spinBox.set_value(region->KeyGroup); dialog.get_vbox()->pack_start(spinBox); spinBox.show();