--- gigedit/trunk/src/gigedit/dimregionchooser.cpp 2017/01/15 19:18:39 3089 +++ gigedit/trunk/src/gigedit/dimregionchooser.cpp 2017/04/25 20:45:54 3123 @@ -29,17 +29,9 @@ #include "global.h" -// taken from gdk/gdkkeysyms.h -// (define on demand, to avoid unnecessary dev lib package build dependency) -#ifndef GDK_KEY_Control_L -# define GDK_KEY_Control_L 0xffe3 -#endif -#ifndef GDK_KEY_Control_R -# define GDK_KEY_Control_R 0xffe4 -#endif - -static std::map caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) { - std::map dimCase; +//TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them! +static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) { + DimensionCase dimCase; if (!dr) { *isValidZone = false; return dimCase; @@ -57,7 +49,7 @@ if (drIndex == 256) { fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n"); *isValidZone = false; - return std::map(); + return DimensionCase(); } for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) { @@ -68,7 +60,7 @@ // there are also DimensionRegion objects of unused zones, skip them if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) { *isValidZone = false; - return std::map(); + return DimensionCase(); } } @@ -84,6 +76,7 @@ instrument = 0; region = 0; maindimregno = -1; + maindimtype = gig::dimension_none; // initialize with invalid dimension type focus_line = 0; resize.active = false; cursor_is_resize = false; @@ -92,13 +85,20 @@ modifybothchannels = modifyalldimregs = modifybothchannels = false; set_can_focus(); + const Glib::ustring txtUseCheckBoxAllRegions = + _("Use checkbox 'all regions' to control whether this should apply to all regions."); + actionGroup = Gtk::ActionGroup::create(); + actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions); + actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why??? actionGroup->add( - Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")), + actionSplitDimZone, sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone) ); + actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions); + actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why??? actionGroup->add( - Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")), + actionDeleteDimZone, sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone) ); @@ -153,6 +153,9 @@ void DimRegionChooser::setModifyAllRegions(bool b) { modifyallregions = b; + + actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone")); + actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone")); } #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 @@ -1008,7 +1011,53 @@ void DimRegionChooser::split_dimension_zone() { printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]); try { - region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]); + if (!modifyallregions) { + region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]); + } else { + gig::Instrument* instr = (gig::Instrument*)region->GetParent(); + gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype); + assert(pMaindimdef != NULL); + // retain structure by value since the original region will be + // modified in the loop below as well + gig::dimension_def_t maindimdef = *pMaindimdef; + std::vector ignoredAll; + std::vector ignoredMinor; + std::vector ignoredCritical; + gig::Region* rgn = NULL; + for (int key = 0; key < 128; ++key) { + if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue; + rgn = instr->GetRegion(key); + + // ignore all regions which do not exactly match the dimension + // layout of the selected region where this operation was emitted + gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype); + if (!dimdef) { + ignoredAll.push_back(rgn); + ignoredMinor.push_back(rgn); + continue; + } + if (dimdef->zones != maindimdef.zones) { + ignoredAll.push_back(rgn); + ignoredCritical.push_back(rgn); + continue; + } + + rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]); + } + if (!ignoredAll.empty()) { + Glib::ustring txt; + if (ignoredCritical.empty()) + txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type."); + else if (ignoredMinor.empty()) + txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!"); + else + txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") + + ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!"); + Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING; + Gtk::MessageDialog msg(txt, false, type); + msg.run(); + } + } } catch (RIFF::Exception e) { Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR); msg.run(); @@ -1023,7 +1072,53 @@ void DimRegionChooser::delete_dimension_zone() { printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]); try { - region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]); + if (!modifyallregions) { + region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]); + } else { + gig::Instrument* instr = (gig::Instrument*)region->GetParent(); + gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype); + assert(pMaindimdef != NULL); + // retain structure by value since the original region will be + // modified in the loop below as well + gig::dimension_def_t maindimdef = *pMaindimdef; + std::vector ignoredAll; + std::vector ignoredMinor; + std::vector ignoredCritical; + gig::Region* rgn = NULL; + for (int key = 0; key < 128; ++key) { + if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue; + rgn = instr->GetRegion(key); + + // ignore all regions which do not exactly match the dimension + // layout of the selected region where this operation was emitted + gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype); + if (!dimdef) { + ignoredAll.push_back(rgn); + ignoredMinor.push_back(rgn); + continue; + } + if (dimdef->zones != maindimdef.zones) { + ignoredAll.push_back(rgn); + ignoredCritical.push_back(rgn); + continue; + } + + rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]); + } + if (!ignoredAll.empty()) { + Glib::ustring txt; + if (ignoredCritical.empty()) + txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type."); + else if (ignoredMinor.empty()) + txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!"); + else + txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") + + ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!"); + Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING; + Gtk::MessageDialog msg(txt, false, type); + msg.run(); + } + } } catch (RIFF::Exception e) { Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR); msg.run(); @@ -1036,16 +1131,37 @@ } bool DimRegionChooser::onKeyPressed(GdkEventKey* key) { - //printf("key down\n"); + //printf("key down 0x%x\n", key->keyval); if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R) multiSelectKeyDown = 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(); + if (key->keyval == GDK_KEY_Right) + select_next_dimzone(); + if (key->keyval == GDK_KEY_Up) + select_prev_dimension(); + if (key->keyval == GDK_KEY_Down) + select_next_dimension();*/ return false; } bool DimRegionChooser::onKeyReleased(GdkEventKey* key) { - //printf("key up\n"); + //printf("key up 0x%x\n", key->keyval); if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R) multiSelectKeyDown = false; + + if (!has_focus()) return false; + + if (key->keyval == GDK_KEY_Left) + select_prev_dimzone(); + if (key->keyval == GDK_KEY_Right) + select_next_dimzone(); + if (key->keyval == GDK_KEY_Up) + select_prev_dimension(); + if (key->keyval == GDK_KEY_Down) + select_next_dimension(); + return false; } @@ -1066,11 +1182,7 @@ gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno]; bool isValidZone; - this->maindimcase = caseOfDimRegion(dimrgn, &isValidZone); - if (!isValidZone) { - queue_draw(); // redraw required parts - return; - } + this->maindimcase = dimensionCaseOf(dimrgn); for (std::map::const_iterator it = this->maindimcase.begin(); it != this->maindimcase.end(); ++it) @@ -1101,6 +1213,83 @@ return false; //.selection failed } +void DimRegionChooser::select_next_dimzone() { + select_dimzone_by_dir(+1); +} + +void DimRegionChooser::select_prev_dimzone() { + select_dimzone_by_dir(-1); +} + +void DimRegionChooser::select_dimzone_by_dir(int dir) { + if (!region) return; + if (!region->Dimensions) return; + if (focus_line < 0) focus_line = 0; + if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1; + + maindimtype = region->pDimensionDefinitions[focus_line].dimension; + if (maindimtype == gig::dimension_none) { + printf("maindimtype -> none\n"); + return; + } + + if (maindimcase.empty()) { + maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]); + if (maindimcase.empty()) { + printf("caseOfDimregion(%d) -> empty\n", maindimregno); + return; + } + } + + int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1; + if (z < 0) z = 0; + if (z >= region->pDimensionDefinitions[focus_line].zones) + z = region->pDimensionDefinitions[focus_line].zones - 1; + + maindimcase[maindimtype] = z; + + ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region); + if (!dr) { + printf("select_dimzone_by_dir(%d) -> !dr\n", dir); + return; + } + + maindimregno = getDimensionRegionIndex(dr); + + // reset selected dimregion zones + dimzones.clear(); + for (DimensionCase::const_iterator it = maindimcase.begin(); + it != maindimcase.end(); ++it) + { + dimzones[it->first].insert(it->second); + } + + dimregion_selected(); + + // disabled: would overwrite dimregno with wrong value + //refresh_all(); + // so requesting just a raw repaint instead: + queue_draw(); +} + +void DimRegionChooser::select_next_dimension() { + if (!region) return; + focus_line++; + if (focus_line >= region->Dimensions) + focus_line = region->Dimensions - 1; + this->maindimtype = region->pDimensionDefinitions[focus_line].dimension; + queue_draw(); +} + +void DimRegionChooser::select_prev_dimension() { + if (!region) return; + focus_line--; + if (focus_line < 0) + focus_line = 0; + this->maindimtype = region->pDimensionDefinitions[focus_line].dimension; + queue_draw(); +} + gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const { if (!region) return NULL; return region->pDimensionRegions[maindimregno];