--- gigedit/trunk/src/gigedit/mainwindow.cpp 2017/05/03 19:00:11 3144 +++ gigedit/trunk/src/gigedit/mainwindow.cpp 2017/05/13 18:56:36 3179 @@ -35,9 +35,11 @@ #include #include #include +#include #include #include #include +#include #if GTKMM_MAJOR_VERSION < 3 #include "wrapLabel.hh" #endif @@ -58,6 +60,8 @@ #include "../../gfx/status_attached.xpm" #include "../../gfx/status_detached.xpm" #include "gfx/builtinpix.h" +#include "MacroEditor.h" +#include "MacrosSetup.h" MainWindow::MainWindow() : m_DimRegionChooser(*this), @@ -153,28 +157,30 @@ actionGroup = Gtk::ActionGroup::create(); actionGroup->add(Gtk::Action::create("MenuFile", _("_File"))); - actionGroup->add(Gtk::Action::create("New", _("_New")), - Gtk::AccelKey("n"), + actionGroup->add(Gtk::Action::create("New", Gtk::Stock::NEW), sigc::mem_fun( *this, &MainWindow::on_action_file_new)); - actionGroup->add(Gtk::Action::create("Open", _("_Open...")), - Gtk::AccelKey("o"), + Glib::RefPtr action = + Gtk::Action::create("Open", Gtk::Stock::OPEN); + action->property_label() = action->property_label() + "..."; + actionGroup->add(action, sigc::mem_fun( *this, &MainWindow::on_action_file_open)); - actionGroup->add(Gtk::Action::create("Save", _("_Save")), - Gtk::AccelKey("s"), + actionGroup->add(Gtk::Action::create("Save", Gtk::Stock::SAVE), sigc::mem_fun( *this, &MainWindow::on_action_file_save)); - actionGroup->add(Gtk::Action::create("SaveAs", _("Save _As...")), + action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS); + action->property_label() = action->property_label() + "..."; + actionGroup->add(action, Gtk::AccelKey("s"), sigc::mem_fun( *this, &MainWindow::on_action_file_save_as)); actionGroup->add(Gtk::Action::create("Properties", - _("_Properties")), + Gtk::Stock::PROPERTIES), sigc::mem_fun( *this, &MainWindow::on_action_file_properties)); actionGroup->add(Gtk::Action::create("InstrProperties", - _("_Properties")), + Gtk::Stock::PROPERTIES), sigc::mem_fun( *this, &MainWindow::show_instr_props)); actionGroup->add(Gtk::Action::create("MidiRules", @@ -185,8 +191,7 @@ _("_Script Slots...")), sigc::mem_fun( *this, &MainWindow::show_script_slots)); - actionGroup->add(Gtk::Action::create("Quit", _("_Quit")), - Gtk::AccelKey("q"), + actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT), sigc::mem_fun( *this, &MainWindow::on_action_quit)); actionGroup->add( @@ -222,6 +227,11 @@ Gtk::AccelKey(GDK_KEY_v, Gdk::MOD1_MASK), sigc::mem_fun(*this, &MainWindow::paste_copied_dimrgn)); + actionGroup->add(Gtk::Action::create("AdjustClipboard", + _("Adjust Clipboard Content")), + Gtk::AccelKey(GDK_KEY_x, Gdk::MOD1_MASK), + sigc::mem_fun(*this, &MainWindow::adjust_clipboard_content)); + actionGroup->add(Gtk::Action::create("SelectPrevRegion", _("Select Previous Region")), Gtk::AccelKey(GDK_KEY_Left, primaryModifierKey), @@ -278,6 +288,9 @@ actionGroup->add(toggle_action); + actionGroup->add(Gtk::Action::create("MenuMacro", _("_Macro"))); + + actionGroup->add(Gtk::Action::create("MenuView", _("Vie_w"))); toggle_action = Gtk::ToggleAction::create("Statusbar", _("_Statusbar")); @@ -305,8 +318,10 @@ sigc::mem_fun(*this, &MainWindow::on_action_refresh_all) ); - actionGroup->add(Gtk::Action::create("MenuHelp", _("_Help"))); - actionGroup->add(Gtk::Action::create("About", _("_About")), + action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP); + actionGroup->add(Gtk::Action::create("MenuHelp", + action->property_label())); + actionGroup->add(Gtk::Action::create("About", Gtk::Stock::ABOUT), sigc::mem_fun( *this, &MainWindow::on_action_help_about)); actionGroup->add( @@ -318,7 +333,7 @@ sigc::mem_fun(*this, &MainWindow::on_action_duplicate_instrument) ); actionGroup->add( - Gtk::Action::create("RemoveInstrument", _("_Remove")), + Gtk::Action::create("RemoveInstrument", Gtk::Stock::REMOVE), sigc::mem_fun(*this, &MainWindow::on_action_remove_instrument) ); @@ -365,7 +380,7 @@ // sample right-click popup actions actionGroup->add( - Gtk::Action::create("SampleProperties", _("_Properties")), + Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES), sigc::mem_fun(*this, &MainWindow::on_action_sample_properties) ); actionGroup->add( @@ -377,7 +392,7 @@ sigc::mem_fun(*this, &MainWindow::on_action_add_sample) ); actionGroup->add( - Gtk::Action::create("RemoveSample", _("_Remove")), + Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE), sigc::mem_fun(*this, &MainWindow::on_action_remove_sample) ); actionGroup->add( @@ -413,7 +428,7 @@ sigc::mem_fun(*this, &MainWindow::on_action_edit_script) ); actionGroup->add( - Gtk::Action::create("RemoveScript", _("_Remove")), + Gtk::Action::create("RemoveScript", Gtk::Stock::REMOVE), sigc::mem_fun(*this, &MainWindow::on_action_remove_script) ); @@ -437,6 +452,7 @@ " " " " " " + " " " " " " " " @@ -453,6 +469,8 @@ " " " " " " + " " + " " " " " " " " @@ -818,12 +836,144 @@ ); updateClipboardPasteAvailable(); updateClipboardCopyAvailable(); + + // setup macros and their keyboard accelerators + { + Gtk::Menu* menuMacro = dynamic_cast( + uiManager->get_widget("/MenuBar/MenuMacro") + )->get_submenu(); + + const Gdk::ModifierType primaryModifierKey = +#if defined(__APPLE__) + Gdk::META_MASK; // Cmd key on Mac +#else + Gdk::CONTROL_MASK; // Ctrl key on all other OSs +#endif + + const Gdk::ModifierType noModifier = (Gdk::ModifierType)0; + Gtk::AccelMap::add_entry("/macro_0", GDK_KEY_F1, noModifier); + Gtk::AccelMap::add_entry("/macro_1", GDK_KEY_F2, noModifier); + Gtk::AccelMap::add_entry("/macro_2", GDK_KEY_F3, noModifier); + Gtk::AccelMap::add_entry("/macro_3", GDK_KEY_F4, noModifier); + Gtk::AccelMap::add_entry("/macro_4", GDK_KEY_F5, noModifier); + Gtk::AccelMap::add_entry("/macro_5", GDK_KEY_F6, noModifier); + Gtk::AccelMap::add_entry("/macro_6", GDK_KEY_F7, noModifier); + Gtk::AccelMap::add_entry("/macro_7", GDK_KEY_F8, noModifier); + Gtk::AccelMap::add_entry("/macro_8", GDK_KEY_F9, noModifier); + Gtk::AccelMap::add_entry("/macro_9", GDK_KEY_F10, noModifier); + Gtk::AccelMap::add_entry("/macro_10", GDK_KEY_F11, noModifier); + Gtk::AccelMap::add_entry("/macro_11", GDK_KEY_F12, noModifier); + Gtk::AccelMap::add_entry("/SetupMacros", 'm', primaryModifierKey); + + Glib::RefPtr accelGroup = this->get_accel_group(); + menuMacro->set_accel_group(accelGroup); + + updateMacroMenu(); + } } MainWindow::~MainWindow() { } +void MainWindow::updateMacroMenu() { + Gtk::Menu* menuMacro = dynamic_cast( + uiManager->get_widget("/MenuBar/MenuMacro") + )->get_submenu(); + + // remove all entries from "Macro" menu + { + const std::vector children = menuMacro->get_children(); + for (int i = 0; i < children.size(); ++i) { + Gtk::Widget* child = children[i]; + menuMacro->remove(*child); + delete child; + } + } + + // (re)load all macros from config file + try { + Settings::singleton()->loadMacros(m_macros); + } catch (Serialization::Exception e) { + std::cerr << "Exception while loading macros: " << e.Message << std::endl; + } catch (...) { + std::cerr << "Unknown exception while loading macros!" << std::endl; + } + + // add all configured macros as menu items to the "Macro" menu + for (int iMacro = 0; iMacro < m_macros.size(); ++iMacro) { + const Serialization::Archive& macro = m_macros[iMacro]; + std::string name = + macro.name().empty() ? + (std::string(_("Unnamed Macro")) + " " + ToString(iMacro+1)) : macro.name(); + Gtk::MenuItem* item = new Gtk::MenuItem(name); + item->signal_activate().connect( + sigc::bind( + sigc::mem_fun(*this, &MainWindow::onMacroSelected), iMacro + ) + ); + menuMacro->append(*item); + item->set_accel_path("/macro_" + ToString(iMacro)); + Glib::ustring comment = macro.comment(); + if (!comment.empty()) + item->set_tooltip_text(comment); + } + // if there are no macros configured at all, then show a dummy entry instead + if (m_macros.empty()) { + Gtk::MenuItem* item = new Gtk::MenuItem(_("No Macros")); + item->set_sensitive(false); + menuMacro->append(*item); + } + + // add separator line to menu + menuMacro->append(*new Gtk::SeparatorMenuItem); + + { + Gtk::MenuItem* item = new Gtk::MenuItem(_("Setup Macros ...")); + item->signal_activate().connect( + sigc::mem_fun(*this, &MainWindow::setupMacros) + ); + menuMacro->append(*item); + item->set_accel_path("/SetupMacros"); + } + + menuMacro->show_all_children(); +} + +void MainWindow::onMacroSelected(int iMacro) { + printf("onMacroSelected(%d)\n", iMacro); + if (iMacro < 0 || iMacro >= m_macros.size()) return; + Glib::ustring errorText; + try { + applyMacro(m_macros[iMacro]); + } catch (Serialization::Exception e) { + errorText = e.Message; + } catch (...) { + errorText = _("Unknown exception while applying macro"); + } + if (!errorText.empty()) { + Glib::ustring txt = _("Applying macro failed:\n") + errorText; + Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR); + msg.run(); + } +} + +void MainWindow::setupMacros() { + MacrosSetup* setup = new MacrosSetup(); + gig::DimensionRegion* pDimRgn = m_DimRegionChooser.get_main_dimregion(); + setup->setMacros(m_macros, &m_serializationArchive, pDimRgn); + setup->signal_macros_changed().connect( + sigc::mem_fun(*this, &MainWindow::onMacrosSetupChanged) + ); + setup->show(); +} + +void MainWindow::onMacrosSetupChanged(const std::vector& macros) { + m_macros = macros; + Settings::singleton()->saveMacros(m_macros); + updateMacroMenu(); +} + bool MainWindow::on_delete_event(GdkEventAny* event) { return !file_is_shared && file_is_changed && !close_confirmation_dialog(); @@ -889,6 +1039,7 @@ } } + m_RegionChooser.setModifyAllRegions(all_regions); m_DimRegionChooser.setModifyAllRegions(all_regions); m_DimRegionChooser.setModifyAllDimensionRegions(all_dimregs); m_DimRegionChooser.setModifyBothChannels(stereo); @@ -1053,7 +1204,7 @@ // save the file as separate temporary file first, // then move the saved file over the old file // (may result in performance speedup during save) - String tmpname = filename + ".TMP"; + gig::String tmpname = filename + ".TMP"; gig->Save(tmpname, &progress); #if defined(WIN32) if (!DeleteFile(filename.c_str())) { @@ -1196,8 +1347,8 @@ g_free(msg); dialog.set_secondary_text(_("If you close without saving, your changes will be lost.")); dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO); - dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); - dialog.add_button(file_has_name ? _("_Save") : _("Save _As"), Gtk::RESPONSE_YES); + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES); dialog.set_default_response(Gtk::RESPONSE_YES); int response = dialog.run(); dialog.hide(); @@ -1228,7 +1379,7 @@ "used by the sampler until you tell the sampler explicitly to " "load it.")); dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES); - dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog.set_default_response(Gtk::RESPONSE_CANCEL); int response = dialog.run(); dialog.hide(); @@ -1242,8 +1393,8 @@ if (file_is_shared && !leaving_shared_mode_dialog()) return; Gtk::FileChooserDialog dialog(*this, _("Open file")); - dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); - dialog.add_button(_("_Open"), Gtk::RESPONSE_OK); + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); dialog.set_default_response(Gtk::RESPONSE_OK); #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 Gtk::FileFilter filter; @@ -1438,9 +1589,9 @@ bool MainWindow::file_save_as() { - Gtk::FileChooserDialog dialog(*this, _("Save As"), Gtk::FILE_CHOOSER_ACTION_SAVE); - dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); - dialog.add_button(_("_Save"), Gtk::RESPONSE_OK); + Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE); + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); dialog.set_default_response(Gtk::RESPONSE_OK); dialog.set_do_overwrite_confirmation(); @@ -1685,7 +1836,7 @@ eSourceForm(_("Source form")), eCommissioned(_("Commissioned")), eSubject(_("Subject")), - quitButton(_("_Close"), true), + quitButton(Gtk::Stock::CLOSE), table(2, 1), m_file(NULL) { @@ -1808,7 +1959,7 @@ } InstrumentProps::InstrumentProps() : - quitButton(_("_Close"), true), + quitButton(Gtk::Stock::CLOSE), table(2,1), eName(_("Name")), eIsDrum(_("Is drum")), @@ -2697,8 +2848,8 @@ // show 'browse for file' dialog Gtk::FileChooserDialog dialog(*this, replace ? _("Replace Sample with") : _("Add Sample(s)")); - dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); - dialog.add_button(_("_Open"), Gtk::RESPONSE_OK); + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); dialog.set_select_multiple(!replace); // allow multi audio file selection only when adding new samples, does not make sense when replacing a specific sample // matches all file types supported by libsndfile @@ -2898,7 +3049,7 @@ dialog.get_vbox()->pack_start(entryArea, Gtk::PACK_SHRINK); description.show(); entryArea.show_all(); - dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog.add_button(_("Select"), Gtk::RESPONSE_OK); dialog.set_select_multiple(false); if (current_sample_dir != "") { @@ -3522,7 +3673,7 @@ } Gtk::FileChooserDialog dialog(*this, _("Merge .gig files")); - dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog.add_button(_("Merge"), Gtk::RESPONSE_OK); dialog.set_default_response(Gtk::RESPONSE_CANCEL); #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 @@ -3720,6 +3871,12 @@ updateClipboardPasteAvailable(); } +void MainWindow::adjust_clipboard_content() { + MacroEditor* editor = new MacroEditor(); + editor->setMacro(&m_serializationArchive, true); + editor->show(); +} + void MainWindow::updateClipboardPasteAvailable() { Glib::RefPtr clipboard = Gtk::Clipboard::get(); clipboard->request_targets( @@ -3757,38 +3914,36 @@ updateClipboardCopyAvailable(); } +//NOTE: Might throw exception !!! +void MainWindow::applyMacro(Serialization::Archive& macro) { + gig::DimensionRegion* pDimRgn = m_DimRegionChooser.get_main_dimregion(); + if (!pDimRgn) return; + + for (std::set::iterator itDimReg = dimreg_edit.dimregs.begin(); + itDimReg != dimreg_edit.dimregs.end(); ++itDimReg) + { + gig::DimensionRegion* pDimRgn = *itDimReg; + DimRegionChangeGuard(this, pDimRgn); + macro.deserialize(pDimRgn); + } + //region_changed() + file_changed(); + dimreg_changed(); +} + void MainWindow::on_clipboard_received(const Gtk::SelectionData& selection_data) { const std::string target = selection_data.get_target(); if (target == CLIPBOARD_DIMENSIONREGION_TARGET) { - gig::DimensionRegion* pDimRgn = m_DimRegionChooser.get_main_dimregion(); - if (!pDimRgn) return; - Glib::ustring errorText; try { m_serializationArchive.decode( selection_data.get_data(), selection_data.get_length() ); - - for (std::set::iterator itDimReg = dimreg_edit.dimregs.begin(); - itDimReg != dimreg_edit.dimregs.end(); ++itDimReg) - { - gig::DimensionRegion* pDimRgn = *itDimReg; - - dimreg_to_be_changed_signal.emit(pDimRgn); - - m_serializationArchive.deserialize(pDimRgn); - - dimreg_changed_signal.emit(pDimRgn); - } - - //region_changed() - file_changed(); - dimreg_changed(); - + applyMacro(m_serializationArchive); } catch (Serialization::Exception e) { errorText = e.Message; } catch (...) { - errorText = _("Unknown exception during deserialization decoding"); + errorText = _("Unknown exception while pasting DimensionRegion"); } if (!errorText.empty()) { Glib::ustring txt = _("Pasting DimensionRegion failed:\n") + errorText; @@ -3806,6 +3961,10 @@ static_cast( uiManager->get_widget("/MenuBar/MenuEdit/PasteDimRgn") )->set_sensitive(bDimensionRegionPasteIsPossible); + + static_cast( + uiManager->get_widget("/MenuBar/MenuEdit/AdjustClipboard") + )->set_sensitive(bDimensionRegionPasteIsPossible); } sigc::signal& MainWindow::signal_file_structure_to_be_changed() {