--- gigedit/trunk/src/gigedit/mainwindow.cpp 2017/07/09 12:44:59 3299 +++ gigedit/trunk/src/gigedit/mainwindow.cpp 2017/10/28 11:20:46 3363 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,8 @@ { loadBuiltInPix(); + this->file = NULL; + // set_border_width(5); if (!Settings::singleton()->autoRestoreWindowDimension) { @@ -119,7 +122,16 @@ m_TreeViewNotebook.set_size_request(300); - m_HPaned.add1(m_TreeViewNotebook); + m_searchLabel.set_text(Glib::ustring(" ") + _("Filter:")); + m_searchField.pack_start(m_searchLabel, Gtk::PACK_SHRINK); + m_searchField.pack_start(m_searchText); + m_searchField.set_spacing(5); + + m_left_vbox.pack_start(m_TreeViewNotebook); + m_left_vbox.pack_start(m_searchField, Gtk::PACK_SHRINK); + + m_HPaned.add1(m_left_vbox); + dimreg_hbox.add(dimreg_label); dimreg_hbox.add(dimreg_all_regions); dimreg_hbox.add(dimreg_all_dimregs); @@ -221,6 +233,7 @@ sigc::mem_fun(*this, &MainWindow::show_scripts_tab) ); actionGroup->add(Gtk::Action::create("AllInstruments", _("_Select"))); + actionGroup->add(Gtk::Action::create("AssignScripts", _("Assign Script"))); actionGroup->add(Gtk::Action::create("MenuEdit", _("_Edit"))); @@ -246,6 +259,16 @@ Gtk::AccelKey(GDK_KEY_x, Gdk::MOD1_MASK), sigc::mem_fun(*this, &MainWindow::adjust_clipboard_content)); + actionGroup->add(Gtk::Action::create("SelectPrevInstr", + _("Select Previous Instrument")), + Gtk::AccelKey(GDK_KEY_Up, primaryModifierKey), + sigc::mem_fun(*this, &MainWindow::select_prev_instrument)); + + actionGroup->add(Gtk::Action::create("SelectNextInstr", + _("Select Next Instrument")), + Gtk::AccelKey(GDK_KEY_Down, primaryModifierKey), + sigc::mem_fun(*this, &MainWindow::select_next_instrument)); + actionGroup->add(Gtk::Action::create("SelectPrevRegion", _("Select Previous Region")), Gtk::AccelKey(GDK_KEY_Left, primaryModifierKey), @@ -474,6 +497,9 @@ " " " " " " + " " + " " + " " " " " " " " @@ -508,6 +534,7 @@ " " " " " " + " " " " " " " " @@ -642,6 +669,9 @@ instrument_menu = static_cast( uiManager->get_widget("/MenuBar/MenuInstrument/AllInstruments"))->get_submenu(); + assign_scripts_menu = static_cast( + uiManager->get_widget("/MenuBar/MenuInstrument/AssignScripts"))->get_submenu(); + Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar"); m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK); m_VBox.pack_start(m_HPaned); @@ -665,7 +695,12 @@ // Create the Tree model: m_refTreeModel = Gtk::ListStore::create(m_Columns); - m_TreeView.set_model(m_refTreeModel); + m_refTreeModelFilter = Gtk::TreeModelFilter::create(m_refTreeModel); + m_refTreeModelFilter->set_visible_func( + sigc::mem_fun(*this, &MainWindow::instrument_row_visible) + ); + m_TreeView.set_model(m_refTreeModelFilter); + m_TreeView.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE); m_TreeView.set_tooltip_text(_("Right click here for actions on instruments & MIDI Rules. Drag & drop to change the order of instruments.")); instrument_name_connection = m_refTreeModel->signal_row_changed().connect( @@ -841,6 +876,10 @@ dimreg_stereo.signal_toggled().connect( sigc::mem_fun(*this, &MainWindow::update_dimregs)); + m_searchText.signal_changed().connect( + sigc::mem_fun(m_refTreeModelFilter.operator->(), &Gtk::TreeModelFilter::refilter) + ); + file = 0; file_is_changed = false; @@ -849,6 +888,10 @@ // start with a new gig file by default on_action_file_new(); + m_TreeViewNotebook.signal_switch_page().connect( + sigc::mem_fun(*this, &MainWindow::on_notebook_tab_switched) + ); + // select 'Instruments' tab by default // (gtk allows this only if the tab childs are visible, thats why it's here) m_TreeViewNotebook.set_current_page(1); @@ -886,6 +929,25 @@ updateMacroMenu(); } + // setup "Assign Scripts" keyboard accelerators + { + Gtk::AccelMap::add_entry("/script_0", GDK_KEY_F1, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_1", GDK_KEY_F2, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_2", GDK_KEY_F3, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_3", GDK_KEY_F4, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_4", GDK_KEY_F5, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_5", GDK_KEY_F6, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_6", GDK_KEY_F7, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_7", GDK_KEY_F8, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_8", GDK_KEY_F9, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_9", GDK_KEY_F10, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_10", GDK_KEY_F11, Gdk::SHIFT_MASK); + Gtk::AccelMap::add_entry("/script_11", GDK_KEY_F12, Gdk::SHIFT_MASK); + + Glib::RefPtr accelGroup = this->get_accel_group(); + assign_scripts_menu->set_accel_group(accelGroup); + } + Glib::signal_idle().connect_once( sigc::mem_fun(*this, &MainWindow::bringToFront), 200 @@ -1002,6 +1064,14 @@ updateMacroMenu(); } +//NOTE: the actual signal's first argument for argument 'page' is on some gtkmm version GtkNotebookPage* and on some Gtk::Widget*. Since we don't need that argument, it is simply void* here for now. +void MainWindow::on_notebook_tab_switched(void* page, guint page_num) { + bool isInstrumentsPage = (page_num == 1); + // so far we only support filtering for the instruments list, so hide the + // filter text entry field if another tab is selected + m_searchField.set_visible(isInstrumentsPage); +} + bool MainWindow::on_delete_event(GdkEventAny* event) { return !file_is_shared && file_is_changed && !close_confirmation_dialog(); @@ -1102,6 +1172,8 @@ } } + updateScriptListOfMenu(); + m_RegionChooser.set_instrument(get_instrument()); if (Settings::singleton()->syncSamplerInstrumentSelection) { @@ -2003,7 +2075,7 @@ eGainPlus6(_("Gain +6dB"), eAttenuation, -6), eEffectSend(_("Effect send"), 0, 65535), eFineTune(_("Fine tune"), -8400, 8400), - ePitchbendRange(_("Pitchbend range"), 0, 12), + ePitchbendRange(_("Pitchbend range"), 0, 48), ePianoReleaseMode(_("Piano release mode")), eDimensionKeyRangeLow(_("Keyswitching range low")), eDimensionKeyRangeHigh(_("Keyswitching range high")) @@ -2294,13 +2366,37 @@ if (!pInstrument) return; const int iScriptSlots = pInstrument->ScriptSlotCount(); - Glib::RefPtr model = m_TreeView.get_model(); + //NOTE: This is a big mess! Sometimes GTK requires m_TreeView.get_model(), here we need m_refTreeModelFilter->get_model(), otherwise accessing children below causes an error! + //Glib::RefPtr model = m_TreeView.get_model(); + Glib::RefPtr model = m_refTreeModelFilter->get_model(); + for (int i = 0; i < model->children().size(); ++i) { Gtk::TreeModel::Row row = model->children()[i]; if (row[m_Columns.m_col_instr] != pInstrument) continue; row[m_Columns.m_col_scripts] = iScriptSlots ? ToString(iScriptSlots) : ""; break; } + + // causes the sampler to reload the instrument with the new script + on_sel_change(); +} + +void MainWindow::assignScript(gig::Script* pScript) { + if (!pScript) { + printf("assignScript() : !script\n"); + return; + } + printf("assignScript('%s')\n", pScript->Name.c_str()); + + gig::Instrument* pInstrument = get_instrument(); + if (!pInstrument) { + printf("!instrument\n"); + return; + } + + pInstrument->AddScriptSlot(pScript); + + onScriptSlotsModified(pInstrument); } void MainWindow::on_action_refresh_all() { @@ -2405,7 +2501,10 @@ void MainWindow::select_instrument(gig::Instrument* instrument) { if (!instrument) return; + //NOTE: This is a big mess! Sometimes GTK requires m_refTreeModelFilter->get_model(), here we need m_TreeView.get_model(), otherwise treeview selection below causes an error! Glib::RefPtr model = m_TreeView.get_model(); + //Glib::RefPtr model = m_refTreeModelFilter->get_model(); + for (int i = 0; i < model->children().size(); ++i) { Gtk::TreeModel::Row row = model->children()[i]; if (row[m_Columns.m_col_instr] == instrument) { @@ -2427,7 +2526,10 @@ gig::Region* pRegion = (gig::Region*) dimRgn->GetParent(); gig::Instrument* pInstrument = (gig::Instrument*) pRegion->GetParent(); + //NOTE: This is a big mess! Sometimes GTK requires m_refTreeModelFilter->get_model(), here we need m_TreeView.get_model(), otherwise treeview selection below causes an error! Glib::RefPtr model = m_TreeView.get_model(); + //Glib::RefPtr model = m_refTreeModelFilter->get_model(); + for (int i = 0; i < model->children().size(); ++i) { Gtk::TreeModel::Row row = model->children()[i]; if (row[m_Columns.m_col_instr] == pInstrument) { @@ -2575,6 +2677,52 @@ } } +void MainWindow::updateScriptListOfMenu() { + // remove all entries from "Assign Script" menu + { + const std::vector children = assign_scripts_menu->get_children(); + for (int i = 0; i < children.size(); ++i) { + Gtk::Widget* child = children[i]; + assign_scripts_menu->remove(*child); + delete child; + } + } + + int iTotalScripts = 0; + + if (!file) goto noScripts; + + // add all configured macros as menu items to the "Macro" menu + for (int iGroup = 0; file->GetScriptGroup(iGroup); ++iGroup) { + gig::ScriptGroup* pGroup = file->GetScriptGroup(iGroup); + for (int iScript = 0; pGroup->GetScript(iScript); ++iScript, ++iTotalScripts) { + gig::Script* pScript = pGroup->GetScript(iScript); + std::string name = pScript->Name; + + Gtk::MenuItem* item = new Gtk::MenuItem(name); + item->signal_activate().connect( + sigc::bind( + sigc::mem_fun(*this, &MainWindow::assignScript), pScript + ) + ); + assign_scripts_menu->append(*item); + item->set_accel_path("/script_" + ToString(iTotalScripts)); + //item->set_tooltip_text(comment); + } + } + + noScripts: + + // if there are no macros configured at all, then show a dummy entry instead + if (!iTotalScripts) { + Gtk::MenuItem* item = new Gtk::MenuItem(_("No Scripts")); + item->set_sensitive(false); + assign_scripts_menu->append(*item); + } + + assign_scripts_menu->show_all_children(); +} + Gtk::RadioMenuItem* MainWindow::add_instrument_to_menu( const Glib::ustring& name, int position) { @@ -2621,9 +2769,7 @@ instrument_name_connection.unblock(); add_instrument_to_menu(name); - - m_TreeView.get_selection()->select(iterInstr); - + select_instrument(instrument); file_changed(); } @@ -3593,6 +3739,26 @@ } } +bool MainWindow::instrument_row_visible(const Gtk::TreeModel::const_iterator& iter) { + if (!iter) + return true; + + Glib::ustring pattern = m_searchText.get_text().lowercase(); + trim(pattern); + if (pattern.empty()) return true; + + Gtk::TreeModel::Row row = *iter; + Glib::ustring name = row[m_Columns.m_col_name]; + name = name.lowercase(); + + std::vector tokens = Glib::Regex::split_simple(" ", pattern); + for (int t = 0; t < tokens.size(); ++t) + if (name.find(tokens[t]) == Glib::ustring::npos) + return false; + + return true; +} + void MainWindow::on_action_combine_instruments() { CombineInstrumentsDialog* d = new CombineInstrumentsDialog(*this, file); @@ -3875,6 +4041,29 @@ m_TreeViewNotebook.set_current_page(2); } +void MainWindow::select_instrument_by_dir(int dir) { + if (!file) return; + gig::Instrument* pInstrument = get_instrument(); + if (!pInstrument) { + select_instrument( file->GetInstrument(0) ); + return; + } + for (int i = 0; file->GetInstrument(i); ++i) { + if (file->GetInstrument(i) == pInstrument) { + select_instrument( file->GetInstrument(i + dir) ); + return; + } + } +} + +void MainWindow::select_prev_instrument() { + select_instrument_by_dir(-1); +} + +void MainWindow::select_next_instrument() { + select_instrument_by_dir(1); +} + void MainWindow::select_prev_region() { m_RegionChooser.select_prev_region(); }