--- gigedit/trunk/src/gigedit/mainwindow.cpp 2015/01/04 17:19:19 2689
+++ gigedit/trunk/src/gigedit/mainwindow.cpp 2015/01/20 18:48:15 2715
@@ -261,6 +261,11 @@
sigc::mem_fun(*this, &MainWindow::on_action_view_references)
);
actionGroup->add(
+ Gtk::Action::create("ReplaceSample",
+ _("Replace Sample...")),
+ sigc::mem_fun(*this, &MainWindow::on_action_replace_sample)
+ );
+ actionGroup->add(
Gtk::Action::create("ReplaceAllSamplesInAllGroups",
_("Replace All Samples in All Groups...")),
sigc::mem_fun(*this, &MainWindow::on_action_replace_all_samples_in_all_groups)
@@ -312,6 +317,7 @@
" "
" "
" "
+ " "
" "
" "
" "
@@ -364,6 +370,7 @@
" "
" "
" "
+ " "
" "
" "
" "
@@ -448,7 +455,7 @@
// Create the Tree model:
m_refTreeModel = Gtk::ListStore::create(m_Columns);
m_TreeView.set_model(m_refTreeModel);
- m_TreeView.set_tooltip_text(_("Right click here for actions on instruments & MIDI Rules."));
+ 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(
sigc::mem_fun(*this, &MainWindow::instrument_name_changed)
);
@@ -456,6 +463,24 @@
// Add the TreeView's view columns:
m_TreeView.append_column_editable("Instrument", m_Columns.m_col_name);
m_TreeView.set_headers_visible(false);
+
+ // establish drag&drop within the instrument tree view, allowing to reorder
+ // the sequence of instruments within the gig file
+ {
+ std::vector drag_target_instrument;
+ drag_target_instrument.push_back(Gtk::TargetEntry("gig::Instrument"));
+ m_TreeView.drag_source_set(drag_target_instrument);
+ m_TreeView.drag_dest_set(drag_target_instrument);
+ m_TreeView.signal_drag_begin().connect(
+ sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drag_begin)
+ );
+ m_TreeView.signal_drag_data_get().connect(
+ sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drag_data_get)
+ );
+ m_TreeView.signal_drag_data_received().connect(
+ sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drop_drag_data_received)
+ );
+ }
// create samples treeview (including its data model)
m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
@@ -503,7 +528,7 @@
m_TreeViewScripts.signal_button_press_event().connect_notify(
sigc::mem_fun(*this, &MainWindow::on_script_treeview_button_release)
);
- //FIXME: why the heck does this double click signal_row_activated() only fired while CTRL key is pressed ?
+ //FIXME: why the heck does this double click signal_row_activated() only fire while CTRL key is pressed ?
m_TreeViewScripts.signal_row_activated().connect(
sigc::mem_fun(*this, &MainWindow::script_double_clicked)
);
@@ -562,6 +587,10 @@
sigc::mem_fun(*this, &MainWindow::on_samples_to_be_removed)
);
+ dimreg_edit.signal_select_sample().connect(
+ sigc::mem_fun(*this, &MainWindow::select_sample)
+ );
+
m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
sigc::hide(
sigc::bind(
@@ -943,6 +972,12 @@
int response = dialog.run();
dialog.hide();
+ // user decided to exit app without saving
+ if (response == Gtk::RESPONSE_NO) return true;
+
+ // user cancelled dialog, thus don't close app
+ if (response == Gtk::RESPONSE_CANCEL) return false;
+
// TODO: the following return valid is disabled and hard coded instead for
// now, due to the fact that saving with progress bar is now implemented
// asynchronously, as a result the app does not close automatically anymore
@@ -1159,7 +1194,7 @@
file_structure_changed_signal.emit(this->file);
- load_gig(this->file, this->filename.c_str());
+ __refreshEntireGUI();
progress_dialog->hide();
}
@@ -1883,6 +1918,77 @@
}
}
+void MainWindow::select_instrument(gig::Instrument* instrument) {
+ if (!instrument) return;
+
+ Glib::RefPtr model = m_TreeView.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) {
+ // select and show the respective instrument in the list view
+ show_intruments_tab();
+ m_TreeView.get_selection()->select(model->children()[i]);
+ Gtk::TreePath path(
+ m_TreeView.get_selection()->get_selected()
+ );
+ m_TreeView.scroll_to_row(path);
+ on_sel_change(); // the regular instrument selection change callback
+ }
+ }
+}
+
+/// Returns true if requested dimension region was successfully selected and scrolled to in the list view, false on error.
+bool MainWindow::select_dimension_region(gig::DimensionRegion* dimRgn) {
+ gig::Region* pRegion = (gig::Region*) dimRgn->GetParent();
+ gig::Instrument* pInstrument = (gig::Instrument*) pRegion->GetParent();
+
+ Glib::RefPtr model = m_TreeView.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) {
+ // select and show the respective instrument in the list view
+ show_intruments_tab();
+ m_TreeView.get_selection()->select(model->children()[i]);
+ Gtk::TreePath path(
+ m_TreeView.get_selection()->get_selected()
+ );
+ m_TreeView.scroll_to_row(path);
+ on_sel_change(); // the regular instrument selection change callback
+
+ // select respective region in the region selector
+ m_RegionChooser.set_region(pRegion);
+
+ // select and show the respective dimension region in the editor
+ //update_dimregs();
+ if (!m_DimRegionChooser.select_dimregion(dimRgn)) return false;
+ //dimreg_edit.set_dim_region(dimRgn);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void MainWindow::select_sample(gig::Sample* sample) {
+ Glib::RefPtr model = m_TreeViewSamples.get_model();
+ for (int g = 0; g < model->children().size(); ++g) {
+ Gtk::TreeModel::Row rowGroup = model->children()[g];
+ for (int s = 0; s < rowGroup.children().size(); ++s) {
+ Gtk::TreeModel::Row rowSample = rowGroup.children()[s];
+ if (rowSample[m_SamplesModel.m_col_sample] == sample) {
+ show_samples_tab();
+ m_TreeViewSamples.get_selection()->select(rowGroup.children()[s]);
+ Gtk::TreePath path(
+ m_TreeViewSamples.get_selection()->get_selected()
+ );
+ m_TreeViewSamples.scroll_to_row(path);
+ return;
+ }
+ }
+ }
+}
+
void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
Gtk::Menu* sample_popup =
@@ -2235,28 +2341,40 @@
file_changed();
}
+void MainWindow::on_action_replace_sample() {
+ add_or_replace_sample(true);
+}
+
void MainWindow::on_action_add_sample() {
+ add_or_replace_sample(false);
+}
+
+void MainWindow::add_or_replace_sample(bool replace) {
if (!file) return;
- // get selected group
+
+ // get selected group (and probably selected sample)
Glib::RefPtr sel = m_TreeViewSamples.get_selection();
Gtk::TreeModel::iterator it = sel->get_selected();
if (!it) return;
Gtk::TreeModel::Row row = *it;
+ gig::Sample* sample = NULL;
gig::Group* group = row[m_SamplesModel.m_col_group];
if (!group) { // not a group, but a sample is selected (probably)
- gig::Sample* sample = row[m_SamplesModel.m_col_sample];
- if (!sample) return;
+ if (replace) sample = row[m_SamplesModel.m_col_sample];
+ if (!row[m_SamplesModel.m_col_sample]) return;
it = row.parent(); // resolve parent (that is the sample's group)
if (!it) return;
- row = *it;
- group = row[m_SamplesModel.m_col_group];
+ if (!replace) row = *it;
+ group = (*it)[m_SamplesModel.m_col_group];
if (!group) return;
}
+ if (replace && !sample) return;
+
// show 'browse for file' dialog
- Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
+ Gtk::FileChooserDialog dialog(*this, replace ? _("Replace Sample with") : _("Add Sample(s)"));
dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
- dialog.set_select_multiple(true);
+ 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
#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
@@ -2327,8 +2445,8 @@
sf_close(hFile); // close sound file
throw std::string(_("format not supported")); // unsupported subformat (yet?)
}
- // add a new sample to the .gig file
- gig::Sample* sample = file->AddSample();
+ // add a new sample to the .gig file (if adding is requested actually)
+ if (!replace) sample = file->AddSample();
// file name without path
Glib::ustring filename = Glib::filename_display_basename(*iter);
// remove file extension if there is one
@@ -2379,7 +2497,7 @@
// physically when File::Save() is called)
sample->Resize(info.frames);
// make sure sample is part of the selected group
- group->AddSample(sample);
+ if (!replace) group->AddSample(sample);
// schedule that physical resize and sample import
// (data copying), performed when "Save" is requested
SampleImportItem sched_item;
@@ -2387,13 +2505,17 @@
sched_item.sample_path = *iter;
m_SampleImportQueue.push_back(sched_item);
// add sample to the tree view
- Gtk::TreeModel::iterator iterSample =
- m_refSamplesTreeModel->append(row.children());
- Gtk::TreeModel::Row rowSample = *iterSample;
- rowSample[m_SamplesModel.m_col_name] =
- gig_to_utf8(sample->pInfo->Name);
- rowSample[m_SamplesModel.m_col_sample] = sample;
- rowSample[m_SamplesModel.m_col_group] = NULL;
+ if (replace) {
+ row[m_SamplesModel.m_col_name] = gig_to_utf8(sample->pInfo->Name);
+ } else {
+ Gtk::TreeModel::iterator iterSample =
+ m_refSamplesTreeModel->append(row.children());
+ Gtk::TreeModel::Row rowSample = *iterSample;
+ rowSample[m_SamplesModel.m_col_name] =
+ gig_to_utf8(sample->pInfo->Name);
+ rowSample[m_SamplesModel.m_col_sample] = sample;
+ rowSample[m_SamplesModel.m_col_group] = NULL;
+ }
// close sound file
sf_close(hFile);
file_changed();
@@ -2404,7 +2526,11 @@
}
// show error message box when some file(s) could not be opened / added
if (!error_files.empty()) {
- Glib::ustring txt = _("Could not add the following sample(s):\n") + error_files;
+ Glib::ustring txt =
+ (replace
+ ? _("Failed to replace sample with:\n")
+ : _("Could not add the following sample(s):\n"))
+ + error_files;
Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
msg.run();
}
@@ -2614,6 +2740,62 @@
sizeof(script)/*length of data in bytes*/);
}
+// see comment on on_sample_treeview_drag_begin()
+void MainWindow::on_instruments_treeview_drag_begin(const Glib::RefPtr& context)
+{
+ first_call_to_drag_data_get = true;
+}
+
+void MainWindow::on_instruments_treeview_drag_data_get(const Glib::RefPtr&,
+ Gtk::SelectionData& selection_data, guint, guint)
+{
+ if (!first_call_to_drag_data_get) return;
+ first_call_to_drag_data_get = false;
+
+ // get selected source instrument
+ gig::Instrument* src = NULL;
+ {
+ Glib::RefPtr sel = m_TreeView.get_selection();
+ Gtk::TreeModel::iterator it = sel->get_selected();
+ if (it) {
+ Gtk::TreeModel::Row row = *it;
+ src = row[m_Columns.m_col_instr];
+ }
+ }
+ if (!src) return;
+
+ // pass the source gig::Instrument as pointer
+ selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&src,
+ sizeof(src)/*length of data in bytes*/);
+}
+
+void MainWindow::on_instruments_treeview_drop_drag_data_received(
+ const Glib::RefPtr& context, int x, int y,
+ const Gtk::SelectionData& selection_data, guint, guint time)
+{
+ gig::Instrument* src = *((gig::Instrument**) selection_data.get_data());
+ if (!src || selection_data.get_length() != sizeof(gig::Instrument*))
+ return;
+
+ gig::Instrument* dst = NULL;
+ {
+ Gtk::TreeModel::Path path;
+ const bool found = m_TreeView.get_path_at_pos(x, y, path);
+ if (!found) return;
+
+ Gtk::TreeModel::iterator iter = m_refTreeModel->get_iter(path);
+ if (!iter) return;
+ Gtk::TreeModel::Row row = *iter;
+ dst = row[m_Columns.m_col_instr];
+ }
+ if (!dst) return;
+
+ //printf("dragdrop received src=%s dst=%s\n", src->pInfo->Name.c_str(), dst->pInfo->Name.c_str());
+ src->MoveTo(dst);
+ __refreshEntireGUI();
+ select_instrument(src);
+}
+
// For some reason drag_data_get gets called two times for each
// drag'n'drop (at least when target is an Entry). This work-around
// makes sure the code in drag_data_get and drop_drag_data_received is
@@ -2836,6 +3018,9 @@
ReferencesView* d = new ReferencesView(*this);
d->setSample(sample);
+ d->dimension_region_selected.connect(
+ sigc::mem_fun(*this, &MainWindow::select_dimension_region)
+ );
d->show_all();
d->resize(500, 400);
d->run();