--- gigedit/trunk/src/gigedit/mainwindow.cpp 2017/02/12 16:35:03 3109 +++ gigedit/trunk/src/gigedit/mainwindow.cpp 2017/05/03 19:00:11 3144 @@ -198,13 +198,70 @@ sigc::mem_fun(*this, &MainWindow::show_intruments_tab) ); actionGroup->add( - Gtk::Action::create("MenuScript", _("S_cript")), + Gtk::Action::create("MenuScript", _("Scr_ipt")), sigc::mem_fun(*this, &MainWindow::show_scripts_tab) ); actionGroup->add(Gtk::Action::create("AllInstruments", _("_Select"))); actionGroup->add(Gtk::Action::create("MenuEdit", _("_Edit"))); + 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 + + actionGroup->add(Gtk::Action::create("CopyDimRgn", + _("Copy selected dimension region")), + Gtk::AccelKey(GDK_KEY_c, Gdk::MOD1_MASK), + sigc::mem_fun(*this, &MainWindow::copy_selected_dimrgn)); + + actionGroup->add(Gtk::Action::create("PasteDimRgn", + _("Paste dimension region")), + Gtk::AccelKey(GDK_KEY_v, Gdk::MOD1_MASK), + sigc::mem_fun(*this, &MainWindow::paste_copied_dimrgn)); + + actionGroup->add(Gtk::Action::create("SelectPrevRegion", + _("Select Previous Region")), + Gtk::AccelKey(GDK_KEY_Left, primaryModifierKey), + sigc::mem_fun(*this, &MainWindow::select_prev_region)); + + actionGroup->add(Gtk::Action::create("SelectNextRegion", + _("Select Next Region")), + Gtk::AccelKey(GDK_KEY_Right, primaryModifierKey), + sigc::mem_fun(*this, &MainWindow::select_next_region)); + + actionGroup->add(Gtk::Action::create("SelectPrevDimRgnZone", + _("Select Previous Dimension Region Zone")), + Gtk::AccelKey(GDK_KEY_Left, Gdk::MOD1_MASK), + sigc::mem_fun(*this, &MainWindow::select_prev_dim_rgn_zone)); + + actionGroup->add(Gtk::Action::create("SelectNextDimRgnZone", + _("Select Next Dimension Region Zone")), + Gtk::AccelKey(GDK_KEY_Right, Gdk::MOD1_MASK), + sigc::mem_fun(*this, &MainWindow::select_next_dim_rgn_zone)); + + actionGroup->add(Gtk::Action::create("SelectPrevDimension", + _("Select Previous Dimension")), + Gtk::AccelKey(GDK_KEY_Up, Gdk::MOD1_MASK), + sigc::mem_fun(*this, &MainWindow::select_prev_dimension)); + + actionGroup->add(Gtk::Action::create("SelectNextDimension", + _("Select Next Dimension")), + Gtk::AccelKey(GDK_KEY_Down, Gdk::MOD1_MASK), + sigc::mem_fun(*this, &MainWindow::select_next_dimension)); + + actionGroup->add(Gtk::Action::create("SelectAddPrevDimRgnZone", + _("Add Previous Dimension Region Zone to Selection")), + Gtk::AccelKey(GDK_KEY_Left, Gdk::MOD1_MASK | Gdk::SHIFT_MASK), + sigc::mem_fun(*this, &MainWindow::select_add_prev_dim_rgn_zone)); + + actionGroup->add(Gtk::Action::create("SelectAddNextDimRgnZone", + _("Add Next Dimension Region Zone to Selection")), + Gtk::AccelKey(GDK_KEY_Right, Gdk::MOD1_MASK | Gdk::SHIFT_MASK), + sigc::mem_fun(*this, &MainWindow::select_add_next_dim_rgn_zone)); + Glib::RefPtr toggle_action = Gtk::ToggleAction::create("CopySampleUnity", _("Copy Sample's _Unity Note")); toggle_action->set_active(true); @@ -221,7 +278,7 @@ actionGroup->add(toggle_action); - actionGroup->add(Gtk::Action::create("MenuView", _("_View"))); + actionGroup->add(Gtk::Action::create("MenuView", _("Vie_w"))); toggle_action = Gtk::ToggleAction::create("Statusbar", _("_Statusbar")); toggle_action->set_active(true); @@ -379,6 +436,19 @@ " " " " " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " " " " " " " @@ -741,7 +811,13 @@ // 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); + m_TreeViewNotebook.set_current_page(1); + + Gtk::Clipboard::get()->signal_owner_change().connect( + sigc::mem_fun(*this, &MainWindow::on_clipboard_owner_change) + ); + updateClipboardPasteAvailable(); + updateClipboardCopyAvailable(); } MainWindow::~MainWindow() @@ -816,6 +892,8 @@ m_DimRegionChooser.setModifyAllRegions(all_regions); m_DimRegionChooser.setModifyAllDimensionRegions(all_dimregs); m_DimRegionChooser.setModifyBothChannels(stereo); + + updateClipboardCopyAvailable(); } void MainWindow::dimreg_all_dimregs_toggled() @@ -1448,12 +1526,12 @@ std::cout << "Starting sample import\n" << std::flush; Glib::ustring error_files; printf("Samples to import: %d\n", int(m_SampleImportQueue.size())); - for (std::list::iterator iter = m_SampleImportQueue.begin(); + for (std::map::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ) { - printf("Importing sample %s\n",(*iter).sample_path.c_str()); + printf("Importing sample %s\n",iter->second.sample_path.c_str()); SF_INFO info; info.format = 0; - SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info); + SNDFILE* hFile = sf_open(iter->second.sample_path.c_str(), SFM_READ, &info); sf_command(hFile, SFC_SET_SCALE_FLOAT_INT_READ, 0, SF_TRUE); try { if (!hFile) throw std::string(_("could not open file")); @@ -1476,6 +1554,9 @@ throw std::string(_("format not supported")); // unsupported subformat (yet?) } + // reset write position for sample + iter->first->SetPos(0); + const int bufsize = 10000; switch (bitdepth) { case 16: { @@ -1485,7 +1566,7 @@ // libsndfile does the conversion for us (if needed) int n = sf_readf_short(hFile, buffer, bufsize); // write from buffer directly (physically) into .gig file - iter->gig_sample->Write(buffer, n); + iter->first->Write(buffer, n); cnt -= n; } delete[] buffer; @@ -1505,7 +1586,7 @@ dstbuf[j++] = srcbuf[i] >> 24; } // write from buffer directly (physically) into .gig file - iter->gig_sample->Write(dstbuf, n); + iter->first->Write(dstbuf, n); cnt -= n; } delete[] srcbuf; @@ -1516,16 +1597,16 @@ // cleanup sf_close(hFile); // let the sampler re-cache the sample if needed - sample_changed_signal.emit(iter->gig_sample); + sample_changed_signal.emit(iter->first); // on success we remove the sample from the import queue, // otherwise keep it, maybe it works the next time ? - std::list::iterator cur = iter; + std::map::iterator cur = iter; ++iter; m_SampleImportQueue.erase(cur); } catch (std::string what) { // remember the files that made trouble (and their cause) if (!error_files.empty()) error_files += "\n"; - error_files += (*iter).sample_path += " (" + what + ")"; + error_files += iter->second.sample_path += " (" + what + ")"; ++iter; } } @@ -2747,7 +2828,7 @@ SampleImportItem sched_item; sched_item.gig_sample = sample; sched_item.sample_path = *iter; - m_SampleImportQueue.push_back(sched_item); + m_SampleImportQueue[sample] = sched_item; // add sample to the tree view if (replace) { row[m_SamplesModel.m_col_name] = gig_to_utf8(sample->pInfo->Name); @@ -2857,7 +2938,7 @@ SampleImportItem sched_item; sched_item.gig_sample = sample; sched_item.sample_path = filename; - m_SampleImportQueue.push_back(sched_item); + m_SampleImportQueue[sample] = sched_item; sf_close(hFile); file_changed(); } @@ -2909,15 +2990,12 @@ // if sample(s) were just previously added, remove // them from the import queue for (std::list::iterator member = members.begin(); - member != members.end(); ++member) { - for (std::list::iterator iter = m_SampleImportQueue.begin(); - iter != m_SampleImportQueue.end(); ++iter) { - if ((*iter).gig_sample == *member) { - printf("Removing previously added sample '%s' from group '%s'\n", - (*iter).sample_path.c_str(), name.c_str()); - m_SampleImportQueue.erase(iter); - break; - } + member != members.end(); ++member) + { + if (m_SampleImportQueue.count(*member)) { + printf("Removing previously added sample '%s' from group '%s'\n", + m_SampleImportQueue[sample].sample_path.c_str(), name.c_str()); + m_SampleImportQueue.erase(*member); } } file_changed(); @@ -2932,14 +3010,10 @@ samples_removed_signal.emit(); // if sample was just previously added, remove it from // the import queue - for (std::list::iterator iter = m_SampleImportQueue.begin(); - iter != m_SampleImportQueue.end(); ++iter) { - if ((*iter).gig_sample == sample) { - printf("Removing previously added sample '%s'\n", - (*iter).sample_path.c_str()); - m_SampleImportQueue.erase(iter); - break; - } + if (m_SampleImportQueue.count(sample)) { + printf("Removing previously added sample '%s'\n", + m_SampleImportQueue[sample].sample_path.c_str()); + m_SampleImportQueue.erase(sample); } dimreg_changed(); file_changed(); @@ -2995,16 +3069,11 @@ gig::Sample* sample = *itSample; // remove sample from the .gig file file->DeleteSample(sample); - // if sample was just previously added, remove it fro the import queue - for (std::list::iterator iter = m_SampleImportQueue.begin(); - iter != m_SampleImportQueue.end(); ++iter) - { - if ((*iter).gig_sample == sample) { - printf("Removing previously added sample '%s'\n", - (*iter).sample_path.c_str()); - m_SampleImportQueue.erase(iter); - break; - } + // if sample was just previously added, remove it from the import queue + if (m_SampleImportQueue.count(sample)) { + printf("Removing previously added sample '%s'\n", + m_SampleImportQueue[sample].sample_path.c_str()); + m_SampleImportQueue.erase(sample); } } } catch (RIFF::Exception e) { @@ -3580,6 +3649,165 @@ m_TreeViewNotebook.set_current_page(2); } +void MainWindow::select_prev_region() { + m_RegionChooser.select_prev_region(); +} + +void MainWindow::select_next_region() { + m_RegionChooser.select_next_region(); +} + +void MainWindow::select_next_dim_rgn_zone() { + if (m_DimRegionChooser.has_focus()) return; // avoid conflict with key stroke handler of DimenionRegionChooser + m_DimRegionChooser.select_next_dimzone(); +} + +void MainWindow::select_prev_dim_rgn_zone() { + if (m_DimRegionChooser.has_focus()) return; // avoid conflict with key stroke handler of DimenionRegionChooser + m_DimRegionChooser.select_prev_dimzone(); +} + +void MainWindow::select_add_next_dim_rgn_zone() { + m_DimRegionChooser.select_next_dimzone(true); +} + +void MainWindow::select_add_prev_dim_rgn_zone() { + m_DimRegionChooser.select_prev_dimzone(true); +} + +void MainWindow::select_prev_dimension() { + if (m_DimRegionChooser.has_focus()) return; // avoid conflict with key stroke handler of DimenionRegionChooser + m_DimRegionChooser.select_prev_dimension(); +} + +void MainWindow::select_next_dimension() { + if (m_DimRegionChooser.has_focus()) return; // avoid conflict with key stroke handler of DimenionRegionChooser + m_DimRegionChooser.select_next_dimension(); +} + +#define CLIPBOARD_DIMENSIONREGION_TARGET \ + ("libgig.DimensionRegion." + m_serializationArchive.rawDataFormat()) + +void MainWindow::copy_selected_dimrgn() { + gig::DimensionRegion* pDimRgn = m_DimRegionChooser.get_main_dimregion(); + if (!pDimRgn) { + updateClipboardPasteAvailable(); + updateClipboardCopyAvailable(); + return; + } + + std::vector targets; + targets.push_back( Gtk::TargetEntry(CLIPBOARD_DIMENSIONREGION_TARGET) ); + + Glib::RefPtr clipboard = Gtk::Clipboard::get(); + clipboard->set( + targets, + sigc::mem_fun(*this, &MainWindow::on_clipboard_get), + sigc::mem_fun(*this, &MainWindow::on_clipboard_clear) + ); + + m_serializationArchive.serialize(pDimRgn); + + updateClipboardPasteAvailable(); +} + +void MainWindow::paste_copied_dimrgn() { + Glib::RefPtr clipboard = Gtk::Clipboard::get(); + clipboard->request_contents( + CLIPBOARD_DIMENSIONREGION_TARGET, + sigc::mem_fun(*this, &MainWindow::on_clipboard_received) + ); + updateClipboardPasteAvailable(); +} + +void MainWindow::updateClipboardPasteAvailable() { + Glib::RefPtr clipboard = Gtk::Clipboard::get(); + clipboard->request_targets( + sigc::mem_fun(*this, &MainWindow::on_clipboard_received_targets) + ); +} + +void MainWindow::updateClipboardCopyAvailable() { + bool bDimensionRegionCopyIsPossible = m_DimRegionChooser.get_main_dimregion(); + static_cast( + uiManager->get_widget("/MenuBar/MenuEdit/CopyDimRgn") + )->set_sensitive(bDimensionRegionCopyIsPossible); +} + +void MainWindow::on_clipboard_owner_change(GdkEventOwnerChange* event) { + updateClipboardPasteAvailable(); +} + +void MainWindow::on_clipboard_get(Gtk::SelectionData& selection_data, guint /*info*/) { + const std::string target = selection_data.get_target(); + if (target == CLIPBOARD_DIMENSIONREGION_TARGET) { + selection_data.set( + CLIPBOARD_DIMENSIONREGION_TARGET, 8 /* "format": probably unused*/, + &m_serializationArchive.rawData()[0], + m_serializationArchive.rawData().size() + ); + } else { + std::cerr << "Clipboard: content for unknown target '" << target << "' requested\n"; + } +} + +void MainWindow::on_clipboard_clear() { + m_serializationArchive.clear(); + updateClipboardPasteAvailable(); + updateClipboardCopyAvailable(); +} + +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(); + + } catch (Serialization::Exception e) { + errorText = e.Message; + } catch (...) { + errorText = _("Unknown exception during deserialization decoding"); + } + if (!errorText.empty()) { + Glib::ustring txt = _("Pasting DimensionRegion failed:\n") + errorText; + Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR); + msg.run(); + } + } +} + +void MainWindow::on_clipboard_received_targets(const std::vector& targets) { + const bool bDimensionRegionPasteIsPossible = + std::find(targets.begin(), targets.end(), + CLIPBOARD_DIMENSIONREGION_TARGET) != targets.end(); + + static_cast( + uiManager->get_widget("/MenuBar/MenuEdit/PasteDimRgn") + )->set_sensitive(bDimensionRegionPasteIsPossible); +} + sigc::signal& MainWindow::signal_file_structure_to_be_changed() { return file_structure_to_be_changed_signal; }