--- gigedit/trunk/src/gigedit/dimregionchooser.cpp 2017/04/25 20:45:54 3123 +++ gigedit/trunk/src/gigedit/dimregionchooser.cpp 2017/05/08 18:05:35 3158 @@ -20,14 +20,17 @@ #include #include "dimregionchooser.h" #include +#include #include #include #include +#include #include #include #include #include "global.h" +#include "gfx/builtinpix.h" //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them! static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) { @@ -69,10 +72,74 @@ } DimRegionChooser::DimRegionChooser(Gtk::Window& window) : - red("#8070ff"), + red("#ff476e"), + blue("#4796ff"), black("black"), white("white") { + // make sure blue hatched pattern pixmap is loaded + loadBuiltInPix(); + + // create blue hatched pattern + { + const int width = blueHatchedPattern->get_width(); + const int height = blueHatchedPattern->get_height(); + const int stride = blueHatchedPattern->get_rowstride(); + + // manually convert from RGBA to ARGB + this->blueHatchedPatternARGB = blueHatchedPattern->copy(); + const int pixelSize = stride / width; + const int totalPixels = width * height; + assert(pixelSize == 4); + unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels(); + for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) { + const unsigned char r = ptr[0]; + const unsigned char g = ptr[1]; + const unsigned char b = ptr[2]; + const unsigned char a = ptr[3]; + ptr[0] = b; + ptr[1] = g; + ptr[2] = r; + ptr[3] = a; + } + + Cairo::RefPtr imageSurface = Cairo::ImageSurface::create( + this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride + ); + this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface); + this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT); + } + + // create gray blue hatched pattern + { + const int width = grayBlueHatchedPattern->get_width(); + const int height = grayBlueHatchedPattern->get_height(); + const int stride = grayBlueHatchedPattern->get_rowstride(); + + // manually convert from RGBA to ARGB + this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy(); + const int pixelSize = stride / width; + const int totalPixels = width * height; + assert(pixelSize == 4); + unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels(); + for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) { + const unsigned char r = ptr[0]; + const unsigned char g = ptr[1]; + const unsigned char b = ptr[2]; + const unsigned char a = ptr[3]; + ptr[0] = b; + ptr[1] = g; + ptr[2] = r; + ptr[3] = a; + } + + Cairo::RefPtr imageSurface = Cairo::ImageSurface::create( + this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride + ); + this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface); + this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT); + } + instrument = 0; region = 0; maindimregno = -1; @@ -82,6 +149,8 @@ cursor_is_resize = false; h = 24; multiSelectKeyDown = false; + primaryKeyDown = false; + shiftKeyDown = false; modifybothchannels = modifyalldimregs = modifybothchannels = false; set_can_focus(); @@ -145,10 +214,14 @@ void DimRegionChooser::setModifyBothChannels(bool b) { modifybothchannels = b; + // redraw required parts + queue_draw(); } void DimRegionChooser::setModifyAllDimensionRegions(bool b) { modifyalldimregs = b; + // redraw required parts + queue_draw(); } void DimRegionChooser::setModifyAllRegions(bool b) { @@ -156,6 +229,9 @@ actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone")); actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone")); + + // redraw required parts + queue_draw(); } #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 @@ -246,9 +322,19 @@ dstr = dstrbuf; break; } - layout->set_text(dstr); + // Since bold font yields in larger label width, we first always + // set the bold text variant, retrieve its dimensions (as worst + // case dimensions of the label) ... + layout->set_markup("" + Glib::ustring(dstr) + ""); Pango::Rectangle rectangle = layout->get_logical_extents(); + // ... and then reset the label to regular font style in case + // the line is not selected. Otherwise the right hand side + // actual dimension zones would jump around on selection change. + bool isSelectedLine = (focus_line == i); + if (!isSelectedLine) + layout->set_markup(dstr); + double text_w = double(rectangle.get_width()) / Pango::SCALE; if (text_w > maxwidth) maxwidth = text_w; @@ -355,7 +441,22 @@ // draw fill for zone bool isSelectedZone = this->dimzones[dimension].count(j); - Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white); + bool isMainSelection = + this->maindimcase.find(dimension) != this->maindimcase.end() && + this->maindimcase[dimension] == j; + bool isCheckBoxSelected = + modifyalldimregs || + (modifybothchannels && + dimension == gig::dimension_samplechannel); + if (isMainSelection) + Gdk::Cairo::set_source_rgba(cr, blue); + else if (isSelectedZone) + cr->set_source(blueHatchedSurfacePattern); + else if (isCheckBoxSelected) + cr->set_source(grayBlueHatchedSurfacePattern); + else + Gdk::Cairo::set_source_rgba(cr, white); + cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1); cr->fill(); @@ -413,7 +514,21 @@ if (j != 0) { // draw fill for zone bool isSelectedZone = this->dimzones[dimension].count(j-1); - Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white); + bool isMainSelection = + this->maindimcase.find(dimension) != this->maindimcase.end() && + this->maindimcase[dimension] == (j-1); + bool isCheckBoxSelected = + modifyalldimregs || + (modifybothchannels && + dimension == gig::dimension_samplechannel); + if (isMainSelection) + Gdk::Cairo::set_source_rgba(cr, blue); + else if (isSelectedZone) + cr->set_source(blueHatchedSurfacePattern); + else if (isCheckBoxSelected) + cr->set_source(grayBlueHatchedSurfacePattern); + else + Gdk::Cairo::set_source_rgba(cr, white); cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1); cr->fill(); @@ -1130,10 +1245,30 @@ refresh_all(); } +// Cmd key on Mac, Ctrl key on all other OSs +static const guint primaryKeyL = + #if defined(__APPLE__) + GDK_KEY_Meta_L; + #else + GDK_KEY_Control_L; + #endif + +static const guint primaryKeyR = + #if defined(__APPLE__) + GDK_KEY_Meta_R; + #else + GDK_KEY_Control_R; + #endif + bool DimRegionChooser::onKeyPressed(GdkEventKey* key) { //printf("key down 0x%x\n", key->keyval); if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R) multiSelectKeyDown = true; + if (key->keyval == primaryKeyL || key->keyval == primaryKeyR) + primaryKeyDown = true; + if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R) + shiftKeyDown = true; + //FIXME: hmm, for some reason GDKMM does not fire arrow key down events, so we are doing those handlers in the key up handler instead for now /*if (key->keyval == GDK_KEY_Left) select_prev_dimzone(); @@ -1150,9 +1285,21 @@ //printf("key up 0x%x\n", key->keyval); if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R) multiSelectKeyDown = false; + if (key->keyval == primaryKeyL || key->keyval == primaryKeyR) + primaryKeyDown = false; + if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R) + shiftKeyDown = false; if (!has_focus()) return false; + // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow + // (which is supposed to switch between regions) + if (primaryKeyDown) return false; + + // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on + // mainwindow + if (shiftKeyDown) return false; + if (key->keyval == GDK_KEY_Left) select_prev_dimzone(); if (key->keyval == GDK_KEY_Right) @@ -1213,15 +1360,15 @@ return false; //.selection failed } -void DimRegionChooser::select_next_dimzone() { - select_dimzone_by_dir(+1); +void DimRegionChooser::select_next_dimzone(bool add) { + select_dimzone_by_dir(+1, add); } -void DimRegionChooser::select_prev_dimzone() { - select_dimzone_by_dir(-1); +void DimRegionChooser::select_prev_dimzone(bool add) { + select_dimzone_by_dir(-1, add); } -void DimRegionChooser::select_dimzone_by_dir(int dir) { +void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) { if (!region) return; if (!region->Dimensions) return; if (focus_line < 0) focus_line = 0; @@ -1256,8 +1403,10 @@ maindimregno = getDimensionRegionIndex(dr); - // reset selected dimregion zones - dimzones.clear(); + if (!add) { + // reset selected dimregion zones + dimzones.clear(); + } for (DimensionCase::const_iterator it = maindimcase.begin(); it != maindimcase.end(); ++it) {