--- gigedit/trunk/src/mainwindow.cpp 2007/03/06 01:17:03 1075 +++ gigedit/trunk/src/mainwindow.cpp 2007/03/08 19:18:23 1085 @@ -27,10 +27,20 @@ #if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6 #define ABOUT_DIALOG #include +#include #endif +#include +#include + #define _(String) gettext(String) +template inline std::string ToString(T o) { + std::stringstream ss; + ss << o; + return ss.str(); +} + bool update_gui; uint8_t& access_UnityNote(gig::DimensionRegion* dimreg) @@ -523,8 +533,8 @@ m_TreeView.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &MainWindow::on_button_release)); - // Add the TreeView, inside a ScrolledWindow, with the button underneath: - m_ScrolledWindow.add(m_TreeView); + // Add the TreeView tab, inside a ScrolledWindow, with the button underneath: + m_ScrolledWindow.add(m_TreeViewNotebook); m_ScrolledWindow.set_size_request(400, 600); m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); @@ -783,6 +793,10 @@ m_HPaned.add2(m_Notebook); + m_TreeViewNotebook.append_page(m_TreeViewSamples, "Samples"); + m_TreeViewNotebook.append_page(m_TreeView, "Instruments"); + + actionGroup = Gtk::ActionGroup::create(); actionGroup->add(Gtk::Action::create("MenuFile", _("_File"))); @@ -826,11 +840,29 @@ sigc::mem_fun( *this, &MainWindow::on_action_help_about)); #endif - action = Gtk::Action::create("Remove", "Ta bort"); + action = Gtk::Action::create("Remove", Gtk::Stock::REMOVE); actionGroup->add(action, sigc::mem_fun( *this, &MainWindow::hide)); + // sample right-click popup actions + actionGroup->add( + Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES), + sigc::mem_fun(*this, &MainWindow::on_action_sample_properties) + ); + actionGroup->add( + Gtk::Action::create("AddGroup", _("Add _Group")), + sigc::mem_fun(*this, &MainWindow::on_action_add_group) + ); + actionGroup->add( + Gtk::Action::create("AddSample", _("Add _Sample(s)")), + sigc::mem_fun(*this, &MainWindow::on_action_add_sample) + ); + actionGroup->add( + Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE), + sigc::mem_fun(*this, &MainWindow::on_action_remove_sample) + ); + uiManager = Gtk::UIManager::create(); uiManager->insert_action_group(actionGroup); // add_accel_group(uiManager->get_accel_group()); @@ -861,6 +893,13 @@ " " " " " " + " " + " " + " " + " " + " " + " " + " " ""; uiManager->add_ui_from_string(ui_info); @@ -886,6 +925,15 @@ m_TreeView.append_column("Instrument", m_Columns.m_col_name); m_TreeView.set_headers_visible(false); + // create samples treeview (including its data model) + m_refSamplesTreeModel = Gtk::TreeStore::create(m_SamplesModel); + m_TreeViewSamples.set_model(m_refSamplesTreeModel); + m_TreeViewSamples.append_column("Samples", m_SamplesModel.m_col_name); + m_TreeViewSamples.set_headers_visible(false); + m_TreeViewSamples.signal_button_press_event().connect_notify( + sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release) + ); + file = 0; show_all_children(); @@ -1255,6 +1303,7 @@ instrument_menu->get_submenu()->items().clear(); m_refTreeModel->clear(); + m_refSamplesTreeModel->clear(); if (file) delete file; // getInfo(dialog.get_filename().c_str(), *this); @@ -1510,6 +1559,21 @@ } instrument_menu->show(); instrument_menu->get_submenu()->show_all_children(); + + for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) { + Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append(); + Gtk::TreeModel::Row rowGroup = *iterGroup; + rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str(); + rowGroup[m_SamplesModel.m_col_group] = group; + rowGroup[m_SamplesModel.m_col_sample] = NULL; + for (gig::Sample* sample = group->GetFirstSample(); sample; sample = group->GetNextSample()) { + Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(rowGroup.children()); + Gtk::TreeModel::Row rowSample = *iterSample; + rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str(); + rowSample[m_SamplesModel.m_col_sample] = sample; + rowSample[m_SamplesModel.m_col_group] = NULL; + } + } } void MainWindow::on_button_release(GdkEventButton* button) @@ -1535,3 +1599,159 @@ void MainWindow::on_instrument_selection_change(int index) { m_RegionChooser.set_instrument(file->GetInstrument(index)); } + +void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) { + if (button->type == GDK_BUTTON_PRESS && button->button == 3) { + Gtk::Menu* sample_popup = + dynamic_cast(uiManager->get_widget("/SamplePopupMenu")); + // update enabled/disabled state of sample popup items + Glib::RefPtr sel = m_TreeViewSamples.get_selection(); + Gtk::TreeModel::iterator it = sel->get_selected(); + bool group_selected = false; + bool sample_selected = false; + if (it) { + Gtk::TreeModel::Row row = *it; + group_selected = row[m_SamplesModel.m_col_group]; + sample_selected = row[m_SamplesModel.m_col_sample]; + } + dynamic_cast(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->set_sensitive(group_selected || sample_selected); + dynamic_cast(uiManager->get_widget("/SamplePopupMenu/AddSample"))->set_sensitive(group_selected || sample_selected); + dynamic_cast(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->set_sensitive(file); + dynamic_cast(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->set_sensitive(group_selected || sample_selected); + // show sample popup + sample_popup->popup(button->button, button->time); + } +} + +void MainWindow::on_action_sample_properties() { + //TODO: show a dialog where the selected sample's properties can be edited +} + +void MainWindow::on_action_add_group() { + static int __sample_indexer = 0; + if (!file) return; + gig::Group* group = file->AddGroup(); + group->Name = "Unnamed Group"; + if (__sample_indexer) group->Name += " " + ToString(__sample_indexer); + __sample_indexer++; + // update sample tree view + Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append(); + Gtk::TreeModel::Row rowGroup = *iterGroup; + rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str(); + rowGroup[m_SamplesModel.m_col_sample] = NULL; + rowGroup[m_SamplesModel.m_col_group] = group; +} + +void MainWindow::on_action_add_sample() { + if (!file) return; + // get selected group + Glib::RefPtr sel = m_TreeViewSamples.get_selection(); + Gtk::TreeModel::iterator it = sel->get_selected(); + if (!it) return; + Gtk::TreeModel::Row row = *it; + 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; + it = row.parent(); // resolve parent (that is the sample's group) + if (!it) return; + row = *it; + group = row[m_SamplesModel.m_col_group]; + if (!group) return; + } + // show 'browse for file' dialog + Gtk::FileChooserDialog dialog(*this, _("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); + Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile (yet to do ;-) + soundfilter.add_pattern("*.wav"); + soundfilter.set_name("Sound Files"); + Gtk::FileFilter allpassfilter; // matches every file + allpassfilter.add_pattern("*.*"); + allpassfilter.set_name("All Files"); + dialog.add_filter(soundfilter); + dialog.add_filter(allpassfilter); + if (dialog.run() == Gtk::RESPONSE_OK) { + Glib::ustring error_files; + Glib::SListHandle filenames = dialog.get_filenames(); + for (Glib::SListHandle::iterator iter = filenames.begin(); iter != filenames.end(); ++iter) { + printf("Adding sample %s\n",(*iter).c_str()); + // use libsndfile to retrieve file informations + SF_INFO info; + info.format = 0; + SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info); + try { + if (!hFile) throw std::string("could not open file"); + int bitdepth; + switch (info.format & 0xff) { + case SF_FORMAT_PCM_S8: + bitdepth = 8; + break; + case SF_FORMAT_PCM_16: + bitdepth = 16; + break; + case SF_FORMAT_PCM_24: + bitdepth = 24; + break; + case SF_FORMAT_PCM_32: + bitdepth = 32; + break; + default: + 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(); + sample->pInfo->Name = (*iter).raw(); + sample->Channels = info.channels; + sample->BitDepth = bitdepth; + sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels; + sample->SamplesPerSecond = info.samplerate; + // schedule resizing the sample (which will be done physically when File::Save() is called) + sample->Resize(info.frames); + // 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] = sample->pInfo->Name.c_str(); + rowSample[m_SamplesModel.m_col_sample] = sample; + rowSample[m_SamplesModel.m_col_group] = NULL; + // close sound file + sf_close(hFile); + } catch (std::string what) { // remember the files that made trouble (and their cause) + if (error_files.size()) error_files += "\n"; + error_files += *iter += " (" + what + ")"; + } + } + // show error message box when some file(s) could not be opened / added + if (error_files.size()) { + Glib::ustring txt = "Could not add the following sample(s):\n" + error_files; + Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR); + msg.run(); + } + } +} + +void MainWindow::on_action_remove_sample() { + if (!file) return; + Glib::RefPtr sel = m_TreeViewSamples.get_selection(); + Gtk::TreeModel::iterator it = sel->get_selected(); + if (it) { + Gtk::TreeModel::Row row = *it; + gig::Group* group = row[m_SamplesModel.m_col_group]; + gig::Sample* sample = row[m_SamplesModel.m_col_sample]; + try { + // remove group or sample from the gig file + if (group) { + file->DeleteGroup(group); + } else if (sample) { + file->DeleteSample(sample); + } + // remove respective row(s) from samples tree view + m_refSamplesTreeModel->erase(it); + } catch (RIFF::Exception e) { + Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR); + msg.run(); + } + } +}