]> git.sesse.net Git - nageru/commitdiff
Make the save and load buttons in the MIDI mapping edit dialog work.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 16 Oct 2016 12:32:37 +0000 (14:32 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 22 Oct 2016 13:16:23 +0000 (15:16 +0200)
midi_mapper.cpp
midi_mapper.h
midi_mapping_dialog.cpp
midi_mapping_dialog.h

index 27e843ee33e7b2f2cfb02a3a6ed68656e8884d53..392fac4b82b89b7570fa736f4b5566bff935752d 100644 (file)
@@ -64,6 +64,26 @@ bool load_midi_mapping_from_file(const string &filename, MIDIMappingProto *new_m
        return true;
 }
 
+bool save_midi_mapping_to_file(const MIDIMappingProto &mapping_proto, const string &filename)
+{
+       // Save to disk. We use the text format because it's friendlier
+       // for a user to look at and edit.
+       int fd = open(filename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
+       if (fd == -1) {
+               perror(filename.c_str());
+               return false;
+       }
+       io::FileOutputStream output(fd);  // Takes ownership of fd.
+       if (!TextFormat::Print(mapping_proto, &output)) {
+               // TODO: Don't overwrite the old file (if any) on error.
+               output.Close();
+               return false;
+       }
+
+       output.Close();
+       return true;
+}
+
 void MIDIMapper::set_midi_mapping(const MIDIMappingProto &new_mapping)
 {
        lock_guard<mutex> lock(mapping_mu);
index 84baf1f98d707760051e0142bf35f067b7a2cce0..357666d5a1fb89eea2f02a6267ab0b973d87e0a1 100644 (file)
@@ -70,5 +70,6 @@ private:
 };
 
 bool load_midi_mapping_from_file(const std::string &filename, MIDIMappingProto *new_mapping);
+bool save_midi_mapping_to_file(const MIDIMappingProto &mapping_proto, const std::string &filename);
 
 #endif  // !defined(_MIDI_MAPPER_H)
index cd622d7493cbf6cbff52d6f95d8edc8bd5d66cf1..2f5779706f625e2a058f0cf643051300f6dc86ed 100644 (file)
@@ -123,6 +123,7 @@ MIDIMappingDialog::MIDIMappingDialog(MIDIMapper *mapper)
        add_controls("Per-bus buttons", ControlType::BUTTON, mapping_proto, per_bus_buttons);
        add_controls("Global controllers", ControlType::CONTROLLER, mapping_proto, global_controllers);
        add_controls("Global buttons", ControlType::BUTTON, mapping_proto, global_buttons);
+       fill_controls_from_mapping(mapping_proto);
 
        // Auto-resize every column but the last.
        for (unsigned column_idx = 0; column_idx < num_buses + 3; ++column_idx) {
@@ -131,6 +132,8 @@ MIDIMappingDialog::MIDIMappingDialog(MIDIMapper *mapper)
 
        connect(ui->ok_cancel_buttons, &QDialogButtonBox::accepted, this, &MIDIMappingDialog::ok_clicked);
        connect(ui->ok_cancel_buttons, &QDialogButtonBox::rejected, this, &MIDIMappingDialog::cancel_clicked);
+       connect(ui->save_button, &QPushButton::clicked, this, &MIDIMappingDialog::save_clicked);
+       connect(ui->load_button, &QPushButton::clicked, this, &MIDIMappingDialog::load_clicked);
 }
 
 MIDIMappingDialog::~MIDIMappingDialog()
@@ -149,6 +152,36 @@ void MIDIMappingDialog::cancel_clicked()
        reject();
 }
 
+void MIDIMappingDialog::save_clicked()
+{
+       unique_ptr<MIDIMappingProto> new_mapping = construct_mapping_proto_from_ui();
+       QString filename = QFileDialog::getSaveFileName(this,
+               "Save MIDI mapping", QString(), tr("Mapping files (*.midimapping)"));
+       if (!filename.endsWith(".midimapping")) {
+               filename += ".midimapping";
+       }
+       if (!save_midi_mapping_to_file(*new_mapping, filename.toStdString())) {
+               QMessageBox box;
+               box.setText("Could not save mapping to '" + filename + "'. Check that you have the right permissions and try again.");
+               box.exec();
+       }
+}
+
+void MIDIMappingDialog::load_clicked()
+{
+       QString filename = QFileDialog::getOpenFileName(this,
+               "Load MIDI mapping", QString(), tr("Mapping files (*.midimapping)"));
+       MIDIMappingProto new_mapping;
+       if (!load_midi_mapping_from_file(filename.toStdString(), &new_mapping)) {
+               QMessageBox box;
+               box.setText("Could not load mapping from '" + filename + "'. Check that the file exists, has the right permissions and is valid.");
+               box.exec();
+               return;
+       }
+
+       fill_controls_from_mapping(new_mapping);
+}
+
 namespace {
 
 template<class T>
@@ -213,7 +246,6 @@ void MIDIMappingDialog::add_bank_selector(QTreeWidgetItem *item, const MIDIMappi
        QComboBox *bank_selector = new QComboBox(this);
        bank_selector->addItems(QStringList() << "" << "Bank 1" << "Bank 2" << "Bank 3" << "Bank 4" << "Bank 5");
        bank_selector->setAutoFillBackground(true);
-       bank_selector->setCurrentIndex(get_bank(mapping_proto, bank_field_number, -1) + 1);
 
        bank_combo_boxes.push_back(InstantiatedComboBox{ bank_selector, bank_field_number });
 
@@ -243,14 +275,25 @@ void MIDIMappingDialog::add_controls(const string &heading,
                        ui->treeWidget->setItemWidget(item, bus_idx + 2, spinner);
 
                        if (control_type == ControlType::CONTROLLER) {
-                               spinner->setValue(get_controller_mapping(mapping_proto, bus_idx, control.field_number, 0));
                                controller_spinners.push_back(InstantiatedSpinner{ spinner, bus_idx, control.field_number });
                        } else {
                                assert(control_type == ControlType::BUTTON);
-                               spinner->setValue(get_button_mapping(mapping_proto, bus_idx, control.field_number, 0));
                                button_spinners.push_back(InstantiatedSpinner{ spinner, bus_idx, control.field_number });
                        }
                }
        }
        ui->treeWidget->addTopLevelItem(heading_item);
 }
+
+void MIDIMappingDialog::fill_controls_from_mapping(const MIDIMappingProto &mapping_proto)
+{
+       for (const InstantiatedSpinner &is : controller_spinners) {
+               is.spinner->setValue(get_controller_mapping(mapping_proto, is.bus_idx, is.field_number, 0));
+       }
+       for (const InstantiatedSpinner &is : button_spinners) {
+               is.spinner->setValue(get_button_mapping(mapping_proto, is.bus_idx, is.field_number, 0));
+       }
+       for (const InstantiatedComboBox &ic : bank_combo_boxes) {
+               ic.combo_box->setCurrentIndex(get_bank(mapping_proto, ic.field_number, -1) + 1);
+       }
+}
index 17cdc180c0b4ffd96bf9c86fdc2deb1fb544a48f..f2cd0bfe3e490a3eccaefac757c8d7d4da3c56b2 100644 (file)
@@ -37,6 +37,8 @@ public:
 public slots:
        void ok_clicked();
        void cancel_clicked();
+       void save_clicked();
+       void load_clicked();
 
 private:
        static constexpr unsigned num_buses = 8;
@@ -46,6 +48,7 @@ private:
        enum class ControlType { CONTROLLER, BUTTON };
        void add_controls(const std::string &heading, ControlType control_type,
                          const MIDIMappingProto &mapping_proto, const std::vector<Control> &controls);
+       void fill_controls_from_mapping(const MIDIMappingProto &mapping_proto);
 
        std::unique_ptr<MIDIMappingProto> construct_mapping_proto_from_ui();
 
@@ -54,7 +57,8 @@ private:
        MIDIMapper *mapper;
 
        // All controllers actually laid out on the grid (we need to store them
-       // so that we can read its values back into the new protobuf).
+       // so that we can move values back and forth between the controls and
+       // the protobuf on save/load).
        struct InstantiatedSpinner {
                QSpinBox *spinner;
                unsigned bus_idx;