diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e32117..e94638c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.22...3.26) +cmake_minimum_required(VERSION 3.22...3.28) include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE) @@ -73,12 +73,10 @@ target_sources( ./src/ui/mmg-fields.cpp ./src/ui/mmg-lcd-number.cpp ./src/ui/mmg-midi-buttons.cpp - ./src/ui/mmg-list-widget.cpp ./src/ui/mmg-number-display.cpp ./src/ui/mmg-string-display.cpp + ./src/ui/mmg-message-display.cpp ./src/ui/mmg-action-display.cpp - ./src/ui/mmg-binding-display.cpp - ./src/ui/mmg-manager-display.cpp ./src/ui/mmg-echo-window.cpp) target_sources( @@ -113,12 +111,10 @@ target_sources( ./src/ui/mmg-fields.h ./src/ui/mmg-lcd-number.h ./src/ui/mmg-midi-buttons.h - ./src/ui/mmg-list-widget.h ./src/ui/mmg-number-display.h ./src/ui/mmg-string-display.h + ./src/ui/mmg-message-display.h ./src/ui/mmg-action-display.h - ./src/ui/mmg-binding-display.h - ./src/ui/mmg-manager-display.h ./src/ui/mmg-echo-window.h) target_sources(${CMAKE_PROJECT_NAME} PRIVATE ./src/ui/resources.qrc) diff --git a/README.md b/README.md index 0afcee6..5786433 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## Announcement -**The new version 3.0.0 Beta is now available! Go check out all of the new features.**


+**The new version 3.0.0 Beta 2 is now available! Go check out all of the new features.**


# obs-midi-mg diff --git a/buildspec.json b/buildspec.json index 10410f2..8211ef2 100644 --- a/buildspec.json +++ b/buildspec.json @@ -42,6 +42,6 @@ "email": "nhielost@gmail.com", "website": "https://github.com/nhielost/obs-midi-mg", "uuids": { - "windowsApp": "DE01A141-BB0F-488A-B195-839997257E65" + "windowsApp": "4B306DCD-DA45-4F74-BE41-B66947BA118A" } } diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 63e9859..b81a695 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -111,7 +111,10 @@ Actions.VideoSources.Sub.Output.Screenshot="Screenshot Taken" Actions.VideoSources.Sub.Output.Custom="Custom Source Settings Changed" Actions.AudioSources.AudioSource="Audio Source" -Actions.AudioSources.Volume="Volume (dB)" +Actions.AudioSources.Volume="Volume" +Actions.AudioSources.Format="Volume Format" +Actions.AudioSources.Format.Percent="Percentage (%)" +Actions.AudioSources.Format.Decibels="Decibels (dB)" Actions.AudioSources.Sub.Input.ChangeVolume="Change Source Volume" Actions.AudioSources.Sub.Input.IncrementVolume="Increment Source Volume" Actions.AudioSources.Sub.Input.Mute="Mute Source" @@ -188,12 +191,20 @@ Actions.MIDI.Sub.Output.Message="Messages Sent to Devices" Binding.Name="Binding" Binding.Untitled="Untitled Binding" -Binding.Selected="%1 selected" +Binding.Names="Bindings" +Binding.Reset="Action Reset Mode" +Binding.Reset.Triggered="Reset when reactivated" +Binding.Reset.Continuous="Never reset" Binding.Input="Input Binding" Binding.Output="Output Binding" +Collection.Name="Collection" +Collection.Untitled="Untitled Collection" + Device.Name="Device" +Device.Dummy="Restricted Device" Device.Thru.Label="Send Through Incoming Messages" +Device.Check.Label="Check MIDI Device Capabilities..." Device.Status.Input="Input Status" Device.Status.Output="Output Status" Device.Status.Connected="Connected" @@ -255,10 +266,13 @@ StringDisplay.UpperBound="Upper Bound (corresponds to MIDI value of the number o StringDisplay.LowerToggle="On State (will be used first)" StringDisplay.UpperToggle="Off State (will be used after On State)" -UI.Buttons.Create="Add" -UI.Buttons.Copy="Copy" -UI.Buttons.Delete="Delete" -UI.Buttons.Bindings="Bindings" +UI.Buttons.New="New..." +UI.Buttons.Copy="Duplicate..." +UI.Buttons.Move="Move Binding to..." +UI.Buttons.Delete="Delete..." +UI.Buttons.Enable="Enable Binding..." +UI.Buttons.Switch="Change Binding Type..." +UI.Buttons.Collections="Binding Collections" UI.Buttons.Devices="Devices" UI.Buttons.Messages="Messages" UI.Buttons.Actions="Actions" @@ -267,23 +281,22 @@ UI.Buttons.Export="Export" UI.Buttons.Import="Import" UI.Buttons.Help="Help" UI.Buttons.BugReport="Report a Bug" -UI.Buttons.Confirm="Confirm" -UI.Buttons.Edit="Edit" -UI.MessageOptions.ToggleNote="Toggle Note On / Off Messages" -UI.MessageOptions.ToggleVelocity="Toggle Velocity" +UI.Buttons.Confirm="Save Changes..." UI.MessageBox.Title.PermanentRemove="Delete Confirmation" UI.MessageBox.Text.PermanentRemove="This operation cannot be undone. Are you sure you want to do this?" -UI.MessageBox.Title.ActionSwitch="Change Action Type" -UI.MessageBox.Text.ActionSwitch="Switching action types will clear all existing action data. Are you sure you want to do this?" UI.MessageBox.Title.BindingSwitch="Change Binding Type" UI.MessageBox.Text.BindingSwitch="Switching binding types will clear all existing binding data. Are you sure you want to do this?" UI.MessageBox.Title.FieldsError="Custom Setup Error" UI.MessageBox.Text.FieldsError="The custom fields menu could not be displayed.\n\nThe source is invalid or does not exist." +UI.MessageBox.Title.PortOpenError="MIDI Device Port Error" +UI.MessageBox.Text.PortOpenError="This MIDI port could not be opened. Check the log file for more details." +UI.MessageBox.Title.DeviceRemove="MIDI Device Removal" +UI.MessageBox.Text.DeviceRemove="This MIDI device will be removed from this list. Are you sure you want to do this?" +UI.MessageBox.Title.DeviceCheck="MIDI Device Capability Check" +UI.MessageBox.Text.DeviceCheck="Capabilities checked successfully." UI.Filesystem.ExportTitle="Save Bindings..." UI.Filesystem.ImportTitle="Open Configuration File..." UI.Filesystem.FileType="JSON Files (*.json)" UI.Listen.Once="Listen Once..." UI.Listen.Continuous="Listen Continuous..." -UI.Listen.Cancel="Cancel..." -UI.Select="Select %1s" -UI.SelectionNotice="Click to select an item. To select multiple items, press Ctrl or Shift when clicking an item.\n\nItems selected towards the top have the highest priority. Dragging an item around adjusts this priority." \ No newline at end of file +UI.Listen.Cancel="Cancel..." \ No newline at end of file diff --git a/libremidi b/libremidi index e80dcd6..b5ef80a 160000 --- a/libremidi +++ b/libremidi @@ -1 +1 @@ -Subproject commit e80dcd6e8e691f9d28bbb215fab0e5ad48dac966 +Subproject commit b5ef80a462b2d06583f16e9c88c46a143268763f diff --git a/src/actions/mmg-action-audio-sources.cpp b/src/actions/mmg-action-audio-sources.cpp index e2a48d9..418484b 100644 --- a/src/actions/mmg-action-audio-sources.cpp +++ b/src/actions/mmg-action-audio-sources.cpp @@ -48,6 +48,12 @@ MMGActionAudioSources::MMGActionAudioSources(MMGActionManager *parent, const QJs blog(LOG_DEBUG, "Action created."); } +const QStringList MMGActionAudioSources::subNames() const +{ + return subModuleTextList( + {"ChangeVolume", "IncrementVolume", "Mute", "Unmute", "ToggleMute", "AudioOffset", "AudioMonitor"}); +} + void MMGActionAudioSources::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); @@ -96,8 +102,7 @@ void MMGActionAudioSources::createDisplay(QWidget *parent) void MMGActionAudioSources::setComboOptions(QComboBox *sub) { - sub->addItems(subModuleTextList( - {"ChangeVolume", "IncrementVolume", "Mute", "Unmute", "ToggleMute", "AudioOffset", "AudioMonitor"})); + MMGAction::setComboOptions(sub); if (type() == TYPE_OUTPUT) enable_combo_option(sub, 1, false); } @@ -243,7 +248,7 @@ void MMGActionAudioSources::execute(const MMGMessage *midi) const util_value /= 100.0; util_value += obs_source_get_volume(obs_source); } else { - util_value = convertDecibels( + util_value = convertDecibels( convertDecibels(obs_source_get_volume(obs_source), true) + util_value, false); } obs_source_set_volume(obs_source, util_value); diff --git a/src/actions/mmg-action-audio-sources.h b/src/actions/mmg-action-audio-sources.h index 45c7205..02e1ba3 100644 --- a/src/actions/mmg-action-audio-sources.h +++ b/src/actions/mmg-action-audio-sources.h @@ -46,6 +46,7 @@ class MMGActionAudioSources : public MMGAction { Category category() const override { return MMGACTION_SOURCE_AUDIO; }; const QString trName() const override { return "AudioSources"; }; + const QStringList subNames() const override; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; diff --git a/src/actions/mmg-action-collections.cpp b/src/actions/mmg-action-collections.cpp index 00a7a18..e8d7898 100644 --- a/src/actions/mmg-action-collections.cpp +++ b/src/actions/mmg-action-collections.cpp @@ -26,6 +26,24 @@ MMGActionCollections::MMGActionCollections(MMGActionManager *parent, const QJson blog(LOG_DEBUG, "Action created."); } +const QStringList MMGActionCollections::subNames() const +{ + QStringList opts; + + switch (type()) { + case TYPE_INPUT: + default: + opts << subModuleText("Switch"); + break; + + case TYPE_OUTPUT: + opts << subModuleTextList({"Changing", "Changed", "Toggle"}); + break; + } + + return opts; +} + void MMGActionCollections::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); @@ -61,26 +79,6 @@ void MMGActionCollections::createDisplay(QWidget *parent) collection_display->setDisplayMode(MMGStringDisplay::MODE_NORMAL); } -void MMGActionCollections::setComboOptions(QComboBox *sub) -{ - QStringList opts; - - switch (type()) { - case TYPE_INPUT: - opts << subModuleText("Switch"); - break; - - case TYPE_OUTPUT: - opts << subModuleTextList({"Changing", "Changed", "Toggle"}); - break; - - default: - break; - } - - sub->addItems(opts); -} - void MMGActionCollections::setActionParams() { MMGStringDisplay *collection_display = display()->stringDisplays()->fieldAt(0); diff --git a/src/actions/mmg-action-collections.h b/src/actions/mmg-action-collections.h index 779c69d..de0b2ee 100644 --- a/src/actions/mmg-action-collections.h +++ b/src/actions/mmg-action-collections.h @@ -30,6 +30,7 @@ class MMGActionCollections : public MMGAction { Category category() const override { return MMGACTION_COLLECTION; }; const QString trName() const override { return "Collections"; }; + const QStringList subNames() const override; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; @@ -37,7 +38,6 @@ class MMGActionCollections : public MMGAction { void toggle() override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; diff --git a/src/actions/mmg-action-filters.cpp b/src/actions/mmg-action-filters.cpp index c42fa98..c27ecba 100644 --- a/src/actions/mmg-action-filters.cpp +++ b/src/actions/mmg-action-filters.cpp @@ -36,6 +36,11 @@ MMGActionFilters::MMGActionFilters(MMGActionManager *parent, const QJsonObject & blog(LOG_DEBUG, "Action created."); } +const QStringList MMGActionFilters::subNames() const +{ + return subModuleTextList({"Show", "Hide", "ToggleDisplay", "Reorder", "Custom"}); +} + void MMGActionFilters::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); @@ -84,11 +89,6 @@ void MMGActionFilters::createDisplay(QWidget *parent) display()->numberDisplays()->addNew(&num); } -void MMGActionFilters::setComboOptions(QComboBox *sub) -{ - sub->addItems(subModuleTextList({"Show", "Hide", "ToggleDisplay", "Reorder", "Custom"})); -} - void MMGActionFilters::setActionParams() { display()->stringDisplays()->hideAll(); diff --git a/src/actions/mmg-action-filters.h b/src/actions/mmg-action-filters.h index c900984..de3ecf8 100644 --- a/src/actions/mmg-action-filters.h +++ b/src/actions/mmg-action-filters.h @@ -30,6 +30,7 @@ class MMGActionFilters : public MMGAction { Category category() const override { return MMGACTION_FILTER; }; const QString trName() const override { return "Filters"; }; + const QStringList subNames() const override; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; @@ -37,7 +38,6 @@ class MMGActionFilters : public MMGAction { void toggle() override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; diff --git a/src/actions/mmg-action-hotkeys.cpp b/src/actions/mmg-action-hotkeys.cpp index e8c796a..e59c161 100644 --- a/src/actions/mmg-action-hotkeys.cpp +++ b/src/actions/mmg-action-hotkeys.cpp @@ -74,11 +74,6 @@ void MMGActionHotkeys::createDisplay(QWidget *parent) hotkey_display->setDisplayMode(MMGStringDisplay::MODE_NORMAL); } -void MMGActionHotkeys::setComboOptions(QComboBox *sub) -{ - sub->addItem(subModuleText("Activate")); -} - void MMGActionHotkeys::setActionParams() { display()->stringDisplays()->hideAll(); diff --git a/src/actions/mmg-action-hotkeys.h b/src/actions/mmg-action-hotkeys.h index f3dae8b..d3cea61 100644 --- a/src/actions/mmg-action-hotkeys.h +++ b/src/actions/mmg-action-hotkeys.h @@ -30,6 +30,7 @@ class MMGActionHotkeys : public MMGAction { Category category() const override { return MMGACTION_HOTKEY; }; const QString trName() const override { return "Hotkeys"; }; + const QStringList subNames() const override { return {subModuleText("Activate")}; }; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; @@ -37,7 +38,6 @@ class MMGActionHotkeys : public MMGAction { void toggle() override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *) const override; diff --git a/src/actions/mmg-action-media-sources.cpp b/src/actions/mmg-action-media-sources.cpp index cde9ac9..d87e54b 100644 --- a/src/actions/mmg-action-media-sources.cpp +++ b/src/actions/mmg-action-media-sources.cpp @@ -27,6 +27,28 @@ MMGActionMediaSources::MMGActionMediaSources(MMGActionManager *parent, const QJs blog(LOG_DEBUG, "Action created."); } +const QStringList MMGActionMediaSources::subNames() const +{ + QStringList opts; + + switch (type()) { + case TYPE_INPUT: + default: + opts << subModuleText("PlayPause") + << obstr_all("ContextBar.MediaControls", {"RestartMedia", "StopMedia"}) + << subModuleText("SetTime") + << obstr_all("ContextBar.MediaControls", {"PlaylistNext", "PlaylistPrevious"}); + break; + + case TYPE_OUTPUT: + opts << subModuleTextList({"Played", "Paused", "Restarted", "Stopped"}); + break; + } + + opts << subModuleTextList({"SkipForward", "SkipBackward"}); + return opts; +} + void MMGActionMediaSources::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); @@ -62,30 +84,6 @@ void MMGActionMediaSources::createDisplay(QWidget *parent) display()->numberDisplays()->addNew(&num); } -void MMGActionMediaSources::setComboOptions(QComboBox *sub) -{ - QStringList opts; - - switch (type()) { - case TYPE_INPUT: - opts << subModuleText("PlayPause") - << obstr_all("ContextBar.MediaControls", {"RestartMedia", "StopMedia"}) - << subModuleText("SetTime") - << obstr_all("ContextBar.MediaControls", {"PlaylistNext", "PlaylistPrevious"}); - break; - - case TYPE_OUTPUT: - opts << subModuleTextList({"Played", "Paused", "Restarted", "Stopped"}); - break; - - default: - break; - } - - opts << subModuleTextList({"SkipForward", "SkipBackward"}); - sub->addItems(opts); -} - void MMGActionMediaSources::setActionParams() { MMGStringDisplay *source_display = display()->stringDisplays()->fieldAt(0); diff --git a/src/actions/mmg-action-media-sources.h b/src/actions/mmg-action-media-sources.h index 100af5d..1bda3d0 100644 --- a/src/actions/mmg-action-media-sources.h +++ b/src/actions/mmg-action-media-sources.h @@ -46,13 +46,13 @@ class MMGActionMediaSources : public MMGAction { Category category() const override { return MMGACTION_SOURCE_MEDIA; }; const QString trName() const override { return "MediaSources"; }; + const QStringList subNames() const override; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; void setEditable(bool edit) override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; diff --git a/src/actions/mmg-action-midi.cpp b/src/actions/mmg-action-midi.cpp index 7ac32d0..436609c 100644 --- a/src/actions/mmg-action-midi.cpp +++ b/src/actions/mmg-action-midi.cpp @@ -22,30 +22,13 @@ with this program. If not, see using namespace MMGUtils; // MMGActionMIDI -MMGActionMIDI::MMGActionMIDI(MMGActionManager *parent, const QJsonObject &json_obj) : MMGAction(parent, json_obj) +MMGActionMIDI::MMGActionMIDI(MMGActionManager *parent, const QJsonObject &json_obj) + : MMGAction(parent, json_obj), messages(new MMGMessageManager(this)), _queue(new MMGConnectionQueue(this)) { - midi_binding = new MMGBinding(nullptr, json_obj); - midi_binding->setParent(this); - - MMGDeviceList devices = midi_binding->usedDevices(); - MMGMessageList messages = midi_binding->usedMessages(); - midi_binding->setType(TYPE_OUTPUT); - type_check = type(); - midi_binding->setUsedDevices(devices); - midi_binding->setUsedMessages(messages); - - _queue = new MMGConnectionQueue(this); - if (json_obj.contains("device")) { - QJsonObject message_obj = json_obj; - MMGDevice *device = manager(device)->find(json_obj["device"].toString()); - if (device) midi_binding->setUsedDevices({device}); - } - - if (json_obj.contains("channel")) { - QJsonObject message_obj = json_obj; - message_obj["name"] = mmgtr("Actions.Composite.MIDIMessageName"); - midi_binding->setUsedMessages({manager(message)->add(message_obj)}); + messages->add(json_obj); + } else { + messages->load(json_obj["messages"].toArray()); } blog(LOG_DEBUG, "Action created."); @@ -55,17 +38,7 @@ void MMGActionMIDI::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); - QJsonArray devices_array; - for (MMGDevice *device : midi_binding->usedDevices()) - devices_array += device->name(); - - json_obj["devices"] = devices_array; - - QJsonArray messages_array; - for (MMGMessage *message : midi_binding->usedMessages()) - messages_array += message->name(); - - json_obj["messages"] = messages_array; + messages->json("messages", json_obj); } void MMGActionMIDI::copy(MMGAction *dest) const @@ -75,61 +48,38 @@ void MMGActionMIDI::copy(MMGAction *dest) const auto casted = dynamic_cast(dest); if (!casted) return; - midi_binding->copy(casted->midi_binding); + casted->messages->clear(); + for (MMGMessage *message : *messages) + message->copy(casted->messages->add()); } void MMGActionMIDI::createDisplay(QWidget *parent) { MMGAction::createDisplay(parent); - binding_display = new MMGBindingDisplay(display(), false); - binding_display->layout()->setContentsMargins(10, 10, 10, 10); - binding_display->setStorage(midi_binding); - connect(binding_display, &MMGBindingDisplay::edited, this, &MMGActionMIDI::editClicked); - display()->setFields(binding_display); -} - -void MMGActionMIDI::editClicked(int page) -{ - emit display()->editRequest(midi_binding, page); -} - -void MMGActionMIDI::setComboOptions(QComboBox *sub) -{ - sub->addItems(subModuleTextList({"Message"})); + message_display = new MMGMessageDisplay(display()); + display()->setFields(message_display); } void MMGActionMIDI::setActionParams() { - if (type() != type_check) { // To clear on type change - midi_binding->setType(TYPE_INPUT); - midi_binding->setType(TYPE_OUTPUT); - } - type_check = type(); - binding_display->display(); + message_display->setStorage(messages->at(0)); + //message_display->display(); } void MMGActionMIDI::execute(const MMGMessage *midi) const { QScopedPointer sent_message(new MMGMessage); - for (MMGDevice *device : midi_binding->usedDevices()) { - if (!device->isActive(TYPE_OUTPUT)) { - blog(LOG_INFO, QString("Output device <%1> is not connected. (Is the output device enabled?)") - .arg(device->name())); - continue; - } + for (MMGMessage *message : *messages) { + message->copy(sent_message.data()); - for (MMGMessage *message : midi_binding->usedMessages()) { - message->copy(sent_message.data()); + if (sent_message->type().state() == STATE_MIDI) sent_message->type() = midi->type(); + sent_message->channel().chooseOther(midi->channel()); + sent_message->note().chooseOther(midi->note()); + sent_message->value().chooseOther(midi->value()); - if (sent_message->type().state() == STATE_MIDI) sent_message->type() = midi->type(); - sent_message->channel().chooseOther(midi->channel()); - sent_message->note().chooseOther(midi->note()); - sent_message->value().chooseOther(midi->value()); - - device->sendMessage(sent_message.data()); - } + sent_message->send(); } blog(LOG_DEBUG, "Successfully executed."); @@ -163,21 +113,21 @@ void MMGConnectionQueue::connectQueue() resetQueue(); if (queue.isEmpty()) return; - for (MMGDevice *device : action->midi_binding->usedDevices()) - connect(device, &MMGMIDIPort::messageReceived, this, &MMGConnectionQueue::messageFound); + connect(action->messages->at(0)->device(), &MMGMIDIPort::messageReceived, this, + &MMGConnectionQueue::messageFound); } void MMGConnectionQueue::disconnectQueue() { - for (MMGDevice *device : action->midi_binding->usedDevices()) - disconnect(device, &MMGMIDIPort::messageReceived, this, nullptr); + if (queue.isEmpty()) return; + disconnect(queue.head()->device(), &MMGMIDIPort::messageReceived, this, nullptr); } void MMGConnectionQueue::resetQueue() { queue.clear(); - for (MMGMessage *message : action->midi_binding->usedMessages()) + for (MMGMessage *message : *action->messages) queue.enqueue(message); } @@ -189,8 +139,9 @@ void MMGConnectionQueue::resetConnections() void MMGConnectionQueue::messageFound(const MMGSharedMessage &incoming) { - MMGMessage *message = manager(message)->find(queue.head()->name()); + MMGMessage *message = queue.head(); if (!message) { + disconnectQueue(); queue.dequeue(); messageFound(incoming); // Try the next message return; @@ -198,8 +149,11 @@ void MMGConnectionQueue::messageFound(const MMGSharedMessage &incoming) if (!message->acceptable(incoming.get())) return; - queue.dequeue(); message->toggle(); + disconnectQueue(); + + message = queue.dequeue(); + connect(message->device(), &MMGMIDIPort::messageReceived, this, &MMGConnectionQueue::messageFound); if (queue.isEmpty()) { emit action->eventTriggered(); diff --git a/src/actions/mmg-action-midi.h b/src/actions/mmg-action-midi.h index 92d9ae1..2c6e7ab 100644 --- a/src/actions/mmg-action-midi.h +++ b/src/actions/mmg-action-midi.h @@ -18,7 +18,7 @@ with this program. If not, see #pragma once #include "mmg-action.h" -#include "../ui/mmg-binding-display.h" +#include "../ui/mmg-message-display.h" #include #include @@ -31,34 +31,29 @@ class MMGActionMIDI : public MMGAction { public: MMGActionMIDI(MMGActionManager *parent, const QJsonObject &json_obj); - ~MMGActionMIDI() { midi_binding->setType(MMGUtils::TYPE_NONE); }; enum Actions { MIDI_SEND_MESSAGES }; enum Events { MIDI_MESSAGES_SENT }; Category category() const override { return MMGACTION_MIDI; }; const QString trName() const override { return "MIDI"; }; + const QStringList subNames() const override { return {subModuleText("Message")}; }; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; void connectOBSSignals() override; void disconnectOBSSignals() override; -private slots: - void editClicked(int page); - private: - MMGBinding *midi_binding; - MMGUtils::DeviceType type_check; - + MMGMessageManager *messages; MMGConnectionQueue *_queue; - MMGBindingDisplay *binding_display = nullptr; + + MMGMessageDisplay *message_display = nullptr; friend class MMGConnectionQueue; }; diff --git a/src/actions/mmg-action-none.h b/src/actions/mmg-action-none.h index e9db1e8..863030f 100644 --- a/src/actions/mmg-action-none.h +++ b/src/actions/mmg-action-none.h @@ -30,9 +30,7 @@ class MMGActionNone : public MMGAction { Category category() const override { return MMGACTION_NONE; }; const QString trName() const override { return "None"; }; - - void setComboOptions(QComboBox *sub) override { sub->addItem(mmgtr("Actions.Titles.None")); }; - void setActionParams() override{}; + const QStringList subNames() const override { return {mmgtr("Actions.Titles.None")}; }; void execute(const MMGMessage *) const override { blog(LOG_DEBUG, "Successfully executed."); }; void connectOBSSignals() override{}; diff --git a/src/actions/mmg-action-profiles.cpp b/src/actions/mmg-action-profiles.cpp index 38e7cb7..7f39bac 100644 --- a/src/actions/mmg-action-profiles.cpp +++ b/src/actions/mmg-action-profiles.cpp @@ -26,6 +26,24 @@ MMGActionProfiles::MMGActionProfiles(MMGActionManager *parent, const QJsonObject blog(LOG_DEBUG, "Action created."); } +const QStringList MMGActionProfiles::subNames() const +{ + QStringList opts; + + switch (type()) { + case TYPE_INPUT: + default: + opts << subModuleText("Switch"); + break; + + case TYPE_OUTPUT: + opts << subModuleTextList({"Changing", "Changed", "Toggle"}); + break; + } + + return opts; +} + void MMGActionProfiles::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); @@ -61,26 +79,6 @@ void MMGActionProfiles::createDisplay(QWidget *parent) profile_display->setDisplayMode(MMGStringDisplay::MODE_NORMAL); } -void MMGActionProfiles::setComboOptions(QComboBox *sub) -{ - QStringList opts; - - switch (type()) { - case TYPE_INPUT: - opts << subModuleText("Switch"); - break; - - case TYPE_OUTPUT: - opts << subModuleTextList({"Changing", "Changed", "Toggle"}); - break; - - default: - break; - } - - sub->addItems(opts); -} - void MMGActionProfiles::setActionParams() { MMGStringDisplay *profile_display = display()->stringDisplays()->fieldAt(0); diff --git a/src/actions/mmg-action-profiles.h b/src/actions/mmg-action-profiles.h index 7b93574..e600db0 100644 --- a/src/actions/mmg-action-profiles.h +++ b/src/actions/mmg-action-profiles.h @@ -30,6 +30,7 @@ class MMGActionProfiles : public MMGAction { Category category() const override { return MMGACTION_PROFILE; }; const QString trName() const override { return "Profiles"; }; + const QStringList subNames() const override; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; @@ -37,7 +38,6 @@ class MMGActionProfiles : public MMGAction { void toggle() override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; diff --git a/src/actions/mmg-action-record.cpp b/src/actions/mmg-action-record.cpp index dc1ef21..5431f34 100644 --- a/src/actions/mmg-action-record.cpp +++ b/src/actions/mmg-action-record.cpp @@ -25,12 +25,13 @@ MMGActionRecord::MMGActionRecord(MMGActionManager *parent, const QJsonObject &js blog(LOG_DEBUG, "Action created."); } -void MMGActionRecord::setComboOptions(QComboBox *sub) +const QStringList MMGActionRecord::subNames() const { QStringList opts; switch (type()) { case TYPE_INPUT: + default: opts << obstr_all("Basic.Main", {"StartRecording", "StopRecording"}) << subModuleText("Toggle") << obstr_all("Basic.Main", {"PauseRecording", "UnpauseRecording"}) << subModuleText("TogglePause"); @@ -40,12 +41,9 @@ void MMGActionRecord::setComboOptions(QComboBox *sub) opts << subModuleTextList({"Starting", "Started", "Stopping", "Stopped", "ToggleStarting", "ToggleStarted", "Paused", "Resumed", "TogglePaused"}); break; - - default: - break; } - sub->addItems(opts); + return opts; } void MMGActionRecord::execute(const MMGMessage *) const diff --git a/src/actions/mmg-action-record.h b/src/actions/mmg-action-record.h index bca5b7b..19e7ef3 100644 --- a/src/actions/mmg-action-record.h +++ b/src/actions/mmg-action-record.h @@ -40,9 +40,7 @@ class MMGActionRecord : public MMGAction { Category category() const override { return MMGACTION_RECORD; }; const QString trName() const override { return "Recording"; }; - - void setComboOptions(QComboBox *sub) override; - void setActionParams() override{}; + const QStringList subNames() const override; void execute(const MMGMessage *) const override; void connectOBSSignals() override; diff --git a/src/actions/mmg-action-replaybuffer.cpp b/src/actions/mmg-action-replaybuffer.cpp index 7642da6..df7a6a4 100644 --- a/src/actions/mmg-action-replaybuffer.cpp +++ b/src/actions/mmg-action-replaybuffer.cpp @@ -28,12 +28,13 @@ MMGActionReplayBuffer::MMGActionReplayBuffer(MMGActionManager *parent, const QJs blog(LOG_DEBUG, "Action created."); } -void MMGActionReplayBuffer::setComboOptions(QComboBox *sub) +const QStringList MMGActionReplayBuffer::subNames() const { QStringList opts; switch (type()) { case TYPE_INPUT: + default: opts << obstr_all("Basic.Main", {"StartReplayBuffer", "StopReplayBuffer"}) << subModuleText("Toggle") << subModuleText("Save"); break; @@ -42,12 +43,9 @@ void MMGActionReplayBuffer::setComboOptions(QComboBox *sub) opts << subModuleTextList({"Starting", "Started", "Stopping", "Stopped", "ToggleStarting", "ToggleStarted", "Save"}); break; - - default: - break; } - sub->addItems(opts); + return opts; } void MMGActionReplayBuffer::execute(const MMGMessage *) const diff --git a/src/actions/mmg-action-replaybuffer.h b/src/actions/mmg-action-replaybuffer.h index a6fed33..4bdbfd2 100644 --- a/src/actions/mmg-action-replaybuffer.h +++ b/src/actions/mmg-action-replaybuffer.h @@ -38,9 +38,7 @@ class MMGActionReplayBuffer : public MMGAction { Category category() const override { return MMGACTION_REPBUF; }; const QString trName() const override { return "ReplayBuffer"; }; - - void setComboOptions(QComboBox *sub) override; - void setActionParams() override{}; + const QStringList subNames() const override; void execute(const MMGMessage *midi) const override; void connectOBSSignals() override; diff --git a/src/actions/mmg-action-scenes.cpp b/src/actions/mmg-action-scenes.cpp index 0662a0c..796bbeb 100644 --- a/src/actions/mmg-action-scenes.cpp +++ b/src/actions/mmg-action-scenes.cpp @@ -61,11 +61,6 @@ void MMGActionScenes::createDisplay(QWidget *parent) scene_display->setDisplayMode(MMGStringDisplay::MODE_NORMAL); } -void MMGActionScenes::setComboOptions(QComboBox *sub) -{ - sub->addItem(subModuleText("Switch")); -} - void MMGActionScenes::setActionParams() { MMGStringDisplay *scene_display = display()->stringDisplays()->fieldAt(0); diff --git a/src/actions/mmg-action-scenes.h b/src/actions/mmg-action-scenes.h index 49aa6df..848da11 100644 --- a/src/actions/mmg-action-scenes.h +++ b/src/actions/mmg-action-scenes.h @@ -30,6 +30,7 @@ class MMGActionScenes : public MMGAction { Category category() const override { return MMGACTION_SCENE; }; const QString trName() const override { return "Scenes"; }; + const QStringList subNames() const override { return {subModuleText("Switch")}; }; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; @@ -37,7 +38,6 @@ class MMGActionScenes : public MMGAction { void toggle() override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; diff --git a/src/actions/mmg-action-stream.cpp b/src/actions/mmg-action-stream.cpp index 80441e6..f80bbf1 100644 --- a/src/actions/mmg-action-stream.cpp +++ b/src/actions/mmg-action-stream.cpp @@ -25,12 +25,13 @@ MMGActionStream::MMGActionStream(MMGActionManager *parent, const QJsonObject &js blog(LOG_DEBUG, "Action created."); } -void MMGActionStream::setComboOptions(QComboBox *sub) +const QStringList MMGActionStream::subNames() const { QStringList opts; switch (type()) { case TYPE_INPUT: + default: opts << obstr_all("Basic.Main", {"StartStreaming", "StopStreaming"}) << subModuleText("Toggle"); break; @@ -38,12 +39,9 @@ void MMGActionStream::setComboOptions(QComboBox *sub) opts << subModuleTextList( {"Starting", "Started", "Stopping", "Stopped", "ToggleStarting", "ToggleStarted"}); break; - - default: - break; } - sub->addItems(opts); + return opts; } void MMGActionStream::execute(const MMGMessage *) const diff --git a/src/actions/mmg-action-stream.h b/src/actions/mmg-action-stream.h index 6cb76d3..7272a2b 100644 --- a/src/actions/mmg-action-stream.h +++ b/src/actions/mmg-action-stream.h @@ -36,9 +36,7 @@ class MMGActionStream : public MMGAction { Category category() const override { return MMGACTION_STREAM; }; const QString trName() const override { return "Streaming"; }; - - void setComboOptions(QComboBox *sub) override; - void setActionParams() override{}; + const QStringList subNames() const override; void execute(const MMGMessage *) const override; void connectOBSSignals() override; diff --git a/src/actions/mmg-action-studiomode.cpp b/src/actions/mmg-action-studiomode.cpp index e2de8c1..68f895f 100644 --- a/src/actions/mmg-action-studiomode.cpp +++ b/src/actions/mmg-action-studiomode.cpp @@ -27,6 +27,25 @@ MMGActionStudioMode::MMGActionStudioMode(MMGActionManager *parent, const QJsonOb blog(LOG_DEBUG, "Action created."); } +const QStringList MMGActionStudioMode::subNames() const +{ + QStringList opts; + + switch (type()) { + case TYPE_INPUT: + default: + opts << subModuleTextList( + {"Activate", "Deactivate", "ToggleActivate", "PreviewChange", "Transition"}); + break; + + case TYPE_OUTPUT: + opts << subModuleTextList({"Activate", "Deactivate", "ToggleActivate", "PreviewChange"}); + break; + } + + return opts; +} + void MMGActionStudioMode::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); @@ -62,27 +81,6 @@ void MMGActionStudioMode::createDisplay(QWidget *parent) scene_display->setDisplayMode(MMGStringDisplay::MODE_NORMAL); } -void MMGActionStudioMode::setComboOptions(QComboBox *sub) -{ - QStringList opts; - - switch (type()) { - case TYPE_INPUT: - opts << subModuleTextList( - {"Activate", "Deactivate", "ToggleActivate", "PreviewChange", "Transition"}); - break; - - case TYPE_OUTPUT: - opts << subModuleTextList({"Activate", "Deactivate", "ToggleActivate", "PreviewChange"}); - break; - - default: - break; - } - - sub->addItems(opts); -} - void MMGActionStudioMode::setActionParams() { MMGStringDisplay *scene_display = display()->stringDisplays()->fieldAt(0); diff --git a/src/actions/mmg-action-studiomode.h b/src/actions/mmg-action-studiomode.h index 57d1920..88ef855 100644 --- a/src/actions/mmg-action-studiomode.h +++ b/src/actions/mmg-action-studiomode.h @@ -36,6 +36,7 @@ class MMGActionStudioMode : public MMGAction { Category category() const override { return MMGACTION_STUDIOMODE; }; const QString trName() const override { return "StudioMode"; }; + const QStringList subNames() const override; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; @@ -43,7 +44,6 @@ class MMGActionStudioMode : public MMGAction { void toggle() override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; diff --git a/src/actions/mmg-action-transitions.cpp b/src/actions/mmg-action-transitions.cpp index 41b8304..2515e90 100644 --- a/src/actions/mmg-action-transitions.cpp +++ b/src/actions/mmg-action-transitions.cpp @@ -49,6 +49,27 @@ MMGActionTransitions::MMGActionTransitions(MMGActionManager *parent, const QJson blog(LOG_DEBUG, "Action created."); } +const QStringList MMGActionTransitions::subNames() const +{ + QStringList opts; + + switch (type()) { + case TYPE_INPUT: + default: + opts << subModuleTextList( + {"CurrentChange", "SourceShow", "SourceHide", "TBarChange", "TBarToggle"}); + break; + + case TYPE_OUTPUT: + opts << subModuleTextList({"CurrentChange", "DurationChange", "Started", "Stopped", + "ToggleStarted", "TBarChange"}); + break; + } + + opts << subModuleText("Custom"); + return opts; +} + void MMGActionTransitions::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); @@ -103,29 +124,6 @@ void MMGActionTransitions::createDisplay(QWidget *parent) display()->numberDisplays()->addNew(&num); } -void MMGActionTransitions::setComboOptions(QComboBox *sub) -{ - QStringList opts; - - switch (type()) { - case TYPE_INPUT: - opts << subModuleTextList( - {"CurrentChange", "SourceShow", "SourceHide", "TBarChange", "TBarToggle"}); - break; - - case TYPE_OUTPUT: - opts << subModuleTextList({"CurrentChange", "DurationChange", "Started", "Stopped", - "ToggleStarted", "TBarChange"}); - break; - - default: - break; - } - - opts << subModuleText("Custom"); - sub->addItems(opts); -} - void MMGActionTransitions::setActionParams() { display()->stringDisplays()->hideAll(); diff --git a/src/actions/mmg-action-transitions.h b/src/actions/mmg-action-transitions.h index e80db4c..43c3853 100644 --- a/src/actions/mmg-action-transitions.h +++ b/src/actions/mmg-action-transitions.h @@ -45,6 +45,7 @@ class MMGActionTransitions : public MMGAction { Category category() const override { return MMGACTION_TRANSITION; }; const QString trName() const override { return "Transitions"; }; + const QStringList subNames() const override; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; @@ -52,7 +53,6 @@ class MMGActionTransitions : public MMGAction { void toggle() override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; diff --git a/src/actions/mmg-action-video-sources.cpp b/src/actions/mmg-action-video-sources.cpp index 66e237d..38db550 100644 --- a/src/actions/mmg-action-video-sources.cpp +++ b/src/actions/mmg-action-video-sources.cpp @@ -41,6 +41,13 @@ MMGActionVideoSources::MMGActionVideoSources(MMGActionManager *parent, const QJs blog(LOG_DEBUG, "Action created."); } +const QStringList MMGActionVideoSources::subNames() const +{ + return subModuleTextList({"Move", "Display", "Locking", "Crop", "Align", "Scale", "ScaleFiltering", "Rotate", + "BoundingBoxType", "BoundingBoxSize", "BoundingBoxAlign", "BlendingMode", + "Screenshot", "Custom"}); +} + void MMGActionVideoSources::json(QJsonObject &json_obj) const { MMGAction::json(json_obj); @@ -110,13 +117,6 @@ void MMGActionVideoSources::createDisplay(QWidget *parent) display()->numberDisplays()->addNew(&nums[3]); } -void MMGActionVideoSources::setComboOptions(QComboBox *sub) -{ - sub->addItems(subModuleTextList({"Move", "Display", "Locking", "Crop", "Align", "Scale", "ScaleFiltering", - "Rotate", "BoundingBoxType", "BoundingBoxSize", "BoundingBoxAlign", - "BlendingMode", "Screenshot", "Custom"})); -} - void MMGActionVideoSources::setActionParams() { display()->stringDisplays()->hideAll(); diff --git a/src/actions/mmg-action-video-sources.h b/src/actions/mmg-action-video-sources.h index 66c132f..1f6b125 100644 --- a/src/actions/mmg-action-video-sources.h +++ b/src/actions/mmg-action-video-sources.h @@ -68,6 +68,7 @@ class MMGActionVideoSources : public MMGAction { Category category() const override { return MMGACTION_SOURCE_VIDEO; }; const QString trName() const override { return "VideoSources"; }; + const QStringList subNames() const override; void json(QJsonObject &json_obj) const override; void copy(MMGAction *dest) const override; @@ -75,7 +76,6 @@ class MMGActionVideoSources : public MMGAction { void toggle() override; void createDisplay(QWidget *parent) override; - void setComboOptions(QComboBox *sub) override; void setActionParams() override; void execute(const MMGMessage *midi) const override; diff --git a/src/actions/mmg-action-virtualcam.cpp b/src/actions/mmg-action-virtualcam.cpp index 057560b..2dfc283 100644 --- a/src/actions/mmg-action-virtualcam.cpp +++ b/src/actions/mmg-action-virtualcam.cpp @@ -26,12 +26,13 @@ MMGActionVirtualCam::MMGActionVirtualCam(MMGActionManager *parent, const QJsonOb blog(LOG_DEBUG, "Action created."); } -void MMGActionVirtualCam::setComboOptions(QComboBox *sub) +const QStringList MMGActionVirtualCam::subNames() const { QStringList opts; switch (type()) { case TYPE_INPUT: + default: opts << obstr_all("Basic.Main", {"StartVirtualCam", "StopVirtualCam"}) << subModuleText("Toggle"); break; @@ -39,12 +40,9 @@ void MMGActionVirtualCam::setComboOptions(QComboBox *sub) case TYPE_OUTPUT: opts << subModuleTextList({"Started", "Stopped", "Toggle"}); break; - - default: - break; } - sub->addItems(opts); + return opts; } void MMGActionVirtualCam::execute(const MMGMessage *) const diff --git a/src/actions/mmg-action-virtualcam.h b/src/actions/mmg-action-virtualcam.h index 9260e1c..27bdc6e 100644 --- a/src/actions/mmg-action-virtualcam.h +++ b/src/actions/mmg-action-virtualcam.h @@ -30,9 +30,7 @@ class MMGActionVirtualCam : public MMGAction { Category category() const override { return MMGACTION_VIRCAM; }; const QString trName() const override { return "VirtualCamera"; }; - - void setComboOptions(QComboBox *sub) override; - void setActionParams() override{}; + const QStringList subNames() const override; void execute(const MMGMessage *) const override; void connectOBSSignals() override; diff --git a/src/actions/mmg-action.cpp b/src/actions/mmg-action.cpp index 9fad7f0..27dff7d 100644 --- a/src/actions/mmg-action.cpp +++ b/src/actions/mmg-action.cpp @@ -40,8 +40,7 @@ using namespace MMGUtils; // MMGAction MMGAction::MMGAction(MMGActionManager *parent, const QJsonObject &json_obj) : QObject(parent) { - connect(this, &QObject::destroyed, [&]() { emit deleting(this); }); - _name = json_obj["name"].toString(mmgtr("Actions.Untitled")); + setObjectName(json_obj["name"].toString(mmgtr("Actions.Untitled"))); _type = (DeviceType)json_obj["type"].toInt(); subcategory = json_obj["sub"].toInt(); } @@ -59,12 +58,12 @@ void MMGAction::setType(DeviceType type) void MMGAction::blog(int log_status, const QString &message) const { - global_blog(log_status, QString("[Actions] <%1> %2").arg(_name).arg(message)); + global_blog(log_status, QString("[Actions] <%1> %2").arg(objectName()).arg(message)); } void MMGAction::json(QJsonObject &json_obj) const { - json_obj["name"] = _name; + json_obj["name"] = objectName(); json_obj["category"] = (int)category(); json_obj["sub"] = subcategory; json_obj["type"] = type(); @@ -72,7 +71,7 @@ void MMGAction::json(QJsonObject &json_obj) const void MMGAction::copy(MMGAction *dest) const { - dest->setName(_name); + dest->setObjectName(objectName()); dest->setType(_type); dest->setSub(subcategory); } @@ -94,16 +93,14 @@ const QStringList MMGAction::subModuleTextList(const QStringList &footer_list) c return opts; } -void MMGAction::addConnection(MMGBinding *binding) +QDataStream &operator<<(QDataStream &out, const MMGAction *&obj) { - connect(this, &MMGAction::deleting, binding, &MMGBinding::removeAction); - connect(this, &MMGAction::replacing, binding, &MMGBinding::replaceAction); + return out << (const QObject *&)obj; } -void MMGAction::removeConnection(MMGBinding *binding) +QDataStream &operator>>(QDataStream &in, MMGAction *&obj) { - disconnect(this, &MMGAction::deleting, binding, nullptr); - disconnect(this, &MMGAction::replacing, binding, nullptr); + return in >> (QObject *&)obj; } // End MMGAction @@ -112,7 +109,7 @@ MMGAction *MMGActionManager::add(const QJsonObject &json_obj) { MMGAction *action = nullptr; changeActionCategory(action, json_obj); - if (find(action->name()) != action) setUniqueName(action); + if (find(action->objectName()) != action) setUniqueName(action); return action; } @@ -123,11 +120,6 @@ MMGAction *MMGActionManager::copy(MMGAction *action) return MMGManager::copy(action, add(json_obj)); } -bool MMGActionManager::filter(DeviceType type, MMGAction *check) const -{ - return type == TYPE_NONE || check->type() == type; -} - void MMGActionManager::changeActionCategory(MMGAction *&action, const QJsonObject &json_obj) { MMGAction *new_action = nullptr; diff --git a/src/actions/mmg-action.h b/src/actions/mmg-action.h index d82639b..19b4a77 100644 --- a/src/actions/mmg-action.h +++ b/src/actions/mmg-action.h @@ -30,7 +30,7 @@ class MMGAction : public QObject { public: MMGAction(MMGActionManager *parent, const QJsonObject &json_obj); - virtual ~MMGAction() { emit deleting(this); }; + virtual ~MMGAction() = default; enum Category { MMGACTION_NONE, @@ -53,9 +53,7 @@ class MMGAction : public QObject { virtual Category category() const = 0; virtual const QString trName() const = 0; - - const QString &name() const { return _name; }; - void setName(const QString &name) { _name = name; }; + virtual const QStringList subNames() const = 0; MMGUtils::DeviceType type() const { return _type; }; void setType(MMGUtils::DeviceType type); @@ -72,35 +70,31 @@ class MMGAction : public QObject { virtual void createDisplay(QWidget *parent) { _display = new MMGActionDisplay(parent); }; MMGActionDisplay *display() const { return _display; }; - virtual void setComboOptions(QComboBox *sub) = 0; - virtual void setActionParams() = 0; + virtual void setComboOptions(QComboBox *sub) { sub->addItems(subNames()); }; + virtual void setActionParams(){}; const QString subModuleText(const QString &footer) const; const QStringList subModuleTextList(const QStringList &footer_list) const; - void addConnection(MMGBinding *binding); - void removeConnection(MMGBinding *binding); - virtual void execute(const MMGMessage *midi) const = 0; virtual void connectOBSSignals() = 0; virtual void disconnectOBSSignals() = 0; signals: - void deleting(MMGAction *); void replacing(MMGAction *); void executed() const; void eventTriggered(const QList &values = {MMGUtils::MMGNumber()}) const; private: - QString _name; - MMGUtils::DeviceType _type; short subcategory = 0; MMGActionDisplay *_display = nullptr; }; using MMGActionList = QList; +QDataStream &operator<<(QDataStream &out, const MMGAction *&obj); +QDataStream &operator>>(QDataStream &in, MMGAction *&obj); class MMGActionManager : public MMGManager { @@ -110,7 +104,6 @@ class MMGActionManager : public MMGManager { MMGAction *add(const QJsonObject &json_obj = QJsonObject()) override; MMGAction *copy(MMGAction *action) override; - bool filter(MMGUtils::DeviceType type, MMGAction *check) const override; void changeActionCategory(MMGAction *&action, const QJsonObject &json_obj = QJsonObject()); }; diff --git a/src/mmg-binding.cpp b/src/mmg-binding.cpp index 8561171..27c36e4 100644 --- a/src/mmg-binding.cpp +++ b/src/mmg-binding.cpp @@ -22,87 +22,68 @@ with this program. If not, see using namespace MMGUtils; -#define SHORT_ENUMERATE(kind, statement) \ - for (auto kind : _##kind##s) \ - statement - // MMGBinding -MMGBinding::MMGBinding(MMGBindingManager *parent, const QJsonObject &json_obj) : QObject(parent) +MMGBinding::MMGBinding(MMGBindingManager *parent, const QJsonObject &json_obj) + : QObject(parent), _messages(new MMGMessageManager(this)), _actions(new MMGActionManager(this)) { thread = new MMGBindingThread(this); - _name = json_obj["name"].toString(mmgtr("Binding.Untitled")); + setObjectName(json_obj["name"].toString(mmgtr("Binding.Untitled"))); _enabled = json_obj["enabled"].toBool(true); _type = (DeviceType)json_obj["type"].toInt(); + reset_mode = json_obj["reset_mode"].toInt(); - for (const QJsonValue &device_name : json_obj["devices"].toArray()) - _devices += manager(device)->find(device_name.toString()); - SHORT_ENUMERATE(device, device->addConnection(this)); - - for (const QJsonValue &message_name : json_obj["messages"].toArray()) - _messages += manager(message)->find(message_name.toString()); - SHORT_ENUMERATE(message, message->addConnection(this)); - - for (const QJsonValue &action_name : json_obj["actions"].toArray()) - _actions += manager(action)->find(action_name.toString()); - SHORT_ENUMERATE(action, action->addConnection(this)); + _messages->load(json_obj["messages"].toArray()); + _actions->load(json_obj["actions"].toArray()); - if (json_obj.contains("settings")) { - _settings = new MMGBindingSettings(nullptr, json_obj["settings"].toObject()); - } else { - _settings = new MMGBindingSettings(nullptr); - auto casted_settings = dynamic_cast(manager(setting)->at(1)); - if (casted_settings) casted_settings->copy(_settings); - } - _settings->setParent(this); + setEnabled(_enabled); } void MMGBinding::setType(DeviceType type) { if (_type == type) return; + setConnected(false); _type = type; - setUsedDevices({}); - setUsedMessages({}); - setUsedActions({}); + + _messages->clear(false); + _actions->clear(false); + _actions->at(0)->setType(type); + + setConnected(true); } void MMGBinding::json(QJsonObject &binding_obj) const { - binding_obj["name"] = _name; + binding_obj["name"] = objectName(); binding_obj["enabled"] = _enabled; - binding_obj["type"] = type(); - - QJsonArray device_arr; - SHORT_ENUMERATE(device, device_arr += device->name()); - binding_obj["devices"] = device_arr; - - QJsonArray message_arr; - SHORT_ENUMERATE(message, message_arr += message->name()); - binding_obj["messages"] = message_arr; + binding_obj["type"] = _type; + binding_obj["reset_mode"] = reset_mode; - QJsonArray action_arr; - SHORT_ENUMERATE(action, action_arr += action->name()); - binding_obj["actions"] = action_arr; - - QJsonObject settings_obj; - _settings->json(settings_obj); - binding_obj["settings"] = settings_obj; + _messages->json("messages", binding_obj); + _actions->json("actions", binding_obj); } void MMGBinding::blog(int log_status, const QString &message) const { - global_blog(log_status, QString("[Bindings] <%1> %2").arg(_name).arg(message)); + global_blog(log_status, QString("[Bindings] <%1> %2").arg(objectName()).arg(message)); } void MMGBinding::copy(MMGBinding *dest) { - dest->setName(_name); - dest->setUsedDevices(_devices); - dest->setUsedMessages(_messages); - dest->setUsedActions(_actions); + dest->setObjectName(objectName()); + dest->reset_mode = reset_mode; + dest->_type = _type; + + QJsonObject json_obj; + dest->_messages->clear(); + dest->_actions->clear(); + _messages->json("messages", json_obj); + _actions->json("actions", json_obj); + dest->_messages->load(json_obj["messages"].toArray()); + dest->_actions->load(json_obj["actions"].toArray()); + dest->setEnabled(_enabled); - dest->_settings->copy(_settings); } void MMGBinding::setEnabled(bool val) @@ -112,81 +93,32 @@ void MMGBinding::setEnabled(bool val) setConnected(true); } -void MMGBinding::setUsedDevices(const MMGDeviceList &devices) -{ - setConnected(false); - SHORT_ENUMERATE(device, device->removeConnection(this)); - - _devices = devices; - - setConnected(true); - SHORT_ENUMERATE(device, device->addConnection(this)); -} - -void MMGBinding::setUsedMessages(const MMGMessageList &messages) -{ - SHORT_ENUMERATE(message, message->removeConnection(this)); - - _messages = messages; - - SHORT_ENUMERATE(message, message->addConnection(this)); -} - -void MMGBinding::setUsedActions(const MMGActionList &actions) -{ - setConnected(false); - SHORT_ENUMERATE(action, action->removeConnection(this)); - - _actions = actions; - - setConnected(true); - SHORT_ENUMERATE(action, action->addConnection(this)); -} - -void MMGBinding::replaceAction(MMGAction *action) -{ - auto sender_action = dynamic_cast(sender()); - if (!sender_action) return; - - setConnected(false); - - if (action->type() != type()) { - _actions.removeOne(sender_action); - sender_action->removeConnection(this); - } else { - _actions[_actions.indexOf(sender_action)] = action; - action->addConnection(this); - } - - setConnected(true); -} - void MMGBinding::setConnected(bool _connected) { if (_connected && (!_enabled || connected)) return; + MMGMIDIPort *device = messages(0)->device(); + switch (_type) { case TYPE_INPUT: default: - for (MMGDevice *device : _devices) { - if (_connected) { - connect(device, &MMGMIDIPort::messageReceived, this, &MMGBinding::executeInput, - Qt::UniqueConnection); - } else { - disconnect(device, &MMGMIDIPort::messageReceived, this, nullptr); - } + if (!device) break; + if (_connected) { + connect(device, &MMGMIDIPort::messageReceived, this, &MMGBinding::executeInput, + Qt::UniqueConnection); + } else { + disconnect(device, &MMGMIDIPort::messageReceived, this, nullptr); } + device->incConnection(_connected); break; case TYPE_OUTPUT: - for (MMGAction *action : _actions) { - if (_connected) { - connect(action, &MMGAction::eventTriggered, this, &MMGBinding::executeOutput); - action->connectOBSSignals(); - } else { - disconnect(action, &MMGAction::eventTriggered, this, nullptr); - action->disconnectOBSSignals(); - } + if (_connected) { + connect(actions(0), &MMGAction::eventTriggered, this, &MMGBinding::executeOutput); + actions(0)->connectOBSSignals(); + } else { + disconnect(actions(0), &MMGAction::eventTriggered, this, nullptr); + actions(0)->disconnectOBSSignals(); } break; } @@ -196,15 +128,30 @@ void MMGBinding::setConnected(bool _connected) void MMGBinding::executeInput(const MMGSharedMessage &incoming) const { - MMGBindingThread *exec_thread = _settings->resetBehavior() ? thread->createNew() : thread; + if (!messages(0)->acceptable(incoming.get())) { + blog(LOG_DEBUG, "Message received is not acceptable."); + return; + } + + MMGBindingThread *exec_thread = reset_mode ? thread->createNew() : thread; exec_thread->restart(incoming.get()); } void MMGBinding::executeOutput(const QList &values) const { - MMGBindingThread *exec_thread = _settings->resetBehavior() ? thread->createNew() : thread; + MMGBindingThread *exec_thread = reset_mode ? thread->createNew() : thread; exec_thread->restart(values); } + +QDataStream &operator<<(QDataStream &out, const MMGBinding *&obj) +{ + return out << (const QObject *&)obj; +} + +QDataStream &operator>>(QDataStream &in, MMGBinding *&obj) +{ + return in >> (QObject *&)obj; +} // End MMGBinding // MMGBindingThread @@ -236,7 +183,7 @@ void MMGBindingThread::run() void MMGBindingThread::sendMessages() { - if (binding->_messages.isEmpty()) { + if (binding->_messages->size() < 1) { blog(LOG_INFO, "FAILED: No messages to send!"); return; } @@ -248,52 +195,37 @@ void MMGBindingThread::sendMessages() int i; MMGNumber used_value; - for (MMGDevice *device : binding->_devices) { - for (i = 0; i < binding->_messages.size(); ++i) { - // if (mutex.try_lock_for(binding->getChronoTime())) return; - if (mutex.try_lock()) return; + for (i = 0; i < binding->_messages->size(); ++i) { + if (mutex.try_lock()) return; - binding->_messages[i]->copy(applied_message); + binding->messages(i)->copy(applied_message); - used_value = incoming_values.size() < i ? incoming_values[i] : incoming_values.last(); - applied_message->applyValues(used_value); + used_value = incoming_values.size() < i ? incoming_values[i] : incoming_values.last(); + applied_message->applyValues(used_value); - device->sendMessage(applied_message); - } + applied_message->send(); } - for (MMGMessage *message : binding->_messages) + for (MMGMessage *message : *binding->_messages) message->toggle(); - binding->_actions[0]->toggle(); + binding->actions(0)->toggle(); } void MMGBindingThread::doActions() { - if (binding->_messages.isEmpty()) { - blog(LOG_INFO, "FAILED: No message to check for!"); - return; - } - - MMGMessage *checked_message = binding->_messages[0]; - if (!checked_message->acceptable(incoming_message)) { - blog(LOG_DEBUG, "Message received is not acceptable."); - return; - } - - checked_message->copy(applied_message); + incoming_message->copy(applied_message); applied_message->type() = incoming_message->type().value(); applied_message->channel() = incoming_message->channel().value(); applied_message->note() = incoming_message->note().value(); applied_message->value() = incoming_message->value().value(); - for (MMGAction *action : binding->_actions) { - // if (mutex.try_lock_for(binding->getChronoTime())) return; + for (MMGAction *action : *binding->_actions) { if (mutex.try_lock()) return; action->execute(applied_message); } - checked_message->toggle(); - for (MMGAction *action : binding->_actions) + binding->messages(0)->toggle(); + for (MMGAction *action : *binding->_actions) action->toggle(); } @@ -331,14 +263,35 @@ MMGBindingThread *MMGBindingThread::createNew() const // End MMGBindingThread // MMGBindingManager +MMGBindingManager::MMGBindingManager(QObject *parent, const QJsonObject &json_obj) : MMGManager(parent) +{ + setObjectName(json_obj["name"].toString(mmgtr("Collection.Untitled"))); + + for (const QJsonValue &val : json_obj["bindings"].toArray()) + add(val.toObject()); + + if (size() < 1) add(); +} + MMGBinding *MMGBindingManager::add(const QJsonObject &json_obj) { return MMGManager::add(new MMGBinding(this, json_obj)); } -bool MMGBindingManager::filter(DeviceType type, MMGBinding *check) const +void MMGBindingManager::copy(MMGBindingManager *dest) +{ + dest->setObjectName(objectName()); + + dest->clear(); + for (MMGBinding *binding : _list) { + dest->copy(binding); + } +} + +void MMGBindingManager::json(QJsonObject &json_obj) const { - return type == TYPE_NONE || check->type() == type; + json_obj["name"] = objectName(); + MMGManager::json("bindings", json_obj); } void MMGBindingManager::resetConnections() @@ -348,4 +301,21 @@ void MMGBindingManager::resetConnections() binding->setConnected(true); } } + +QDataStream &operator<<(QDataStream &out, const MMGBindingManager *&obj) +{ + return out << (const QObject *&)obj; +} + +QDataStream &operator>>(QDataStream &in, MMGBindingManager *&obj) +{ + return in >> (QObject *&)obj; +} // End MMGBindingManager + +// MMGCollections +MMGBindingManager *MMGCollections::add(const QJsonObject &json_obj) +{ + return MMGManager::add(new MMGBindingManager(this, json_obj)); +} +// End MMGCollections diff --git a/src/mmg-binding.h b/src/mmg-binding.h index 32a7892..793fc4c 100644 --- a/src/mmg-binding.h +++ b/src/mmg-binding.h @@ -19,13 +19,11 @@ with this program. If not, see #ifndef MMG_BINDING_H #define MMG_BINDING_H -#include "mmg-device.h" #include "mmg-message.h" #include "actions/mmg-action.h" #include -class MMGBindingSettings; class MMGBindingThread; class MMGBindingManager; @@ -35,8 +33,7 @@ class MMGBinding : public QObject { public: MMGBinding(MMGBindingManager *parent, const QJsonObject &json_obj = QJsonObject()); - const QString &name() const { return _name; }; - void setName(const QString &val) { _name = val; }; + enum ResetMode { MMGBINDING_TRIGGERED, MMGBINDING_CONTINUOUS }; MMGUtils::DeviceType type() const { return _type; }; void setType(MMGUtils::DeviceType type); @@ -45,47 +42,38 @@ class MMGBinding : public QObject { void setEnabled(bool val); void setConnected(bool connected); + ResetMode resetMode() const { return (ResetMode)reset_mode; }; + void setResetMode(short mode) { reset_mode = mode; } + void json(QJsonObject &binding_obj) const; void blog(int log_status, const QString &message) const; void copy(MMGBinding *dest); - const MMGDeviceList &usedDevices() const { return _devices; }; - void setUsedDevices(const MMGDeviceList &devices); - - const MMGMessageList &usedMessages() const { return _messages; }; - void setUsedMessages(const MMGMessageList &messages); - - const MMGActionList &usedActions() const { return _actions; }; - virtual void setUsedActions(const MMGActionList &actions); + MMGMessageManager *messages() const { return _messages; }; + MMGActionManager *actions() const { return _actions; }; - MMGBindingSettings *settings() const { return _settings; }; - -public slots: - void removeDevice(MMGDevice *device) { _devices.removeOne(device); }; - void removeMessage(MMGMessage *message) { _messages.removeOne(message); }; - void removeAction(MMGAction *action) { _actions.removeOne(action); }; - void replaceAction(MMGAction *action); + MMGMessage *messages(int index) const { return _messages->at(index); }; + MMGAction *actions(int index) const { return _actions->at(index); }; private slots: - void executeInput(const MMGSharedMessage &message) const; - void executeOutput(const QList &values) const; + void executeInput(const MMGSharedMessage &) const; + void executeOutput(const QList &) const; private: - QString _name; MMGUtils::DeviceType _type; - bool _enabled; bool connected = false; + short reset_mode = 0; - MMGDeviceList _devices; - MMGMessageList _messages; - MMGActionList _actions; - MMGBindingSettings *_settings; + MMGMessageManager *_messages; + MMGActionManager *_actions; MMGBindingThread *thread; friend class MMGBindingThread; }; +QDataStream &operator<<(QDataStream &out, const MMGBinding *&obj); +QDataStream &operator>>(QDataStream &in, MMGBinding *&obj); class MMGBindingThread : public QThread { Q_OBJECT @@ -123,12 +111,24 @@ class MMGBindingThread : public QThread { class MMGBindingManager : public MMGManager { public: - MMGBindingManager(QObject *parent) : MMGManager(parent){}; + MMGBindingManager(QObject *parent, const QJsonObject &json_obj); MMGBinding *add(const QJsonObject &json_obj = QJsonObject()) override; + MMGBinding *copy(MMGBinding *binding) override { return MMGManager::copy(binding); }; - bool filter(MMGUtils::DeviceType type, MMGBinding *check) const override; + void json(QJsonObject &json_obj) const; + void copy(MMGBindingManager *dest); void resetConnections(); }; +QDataStream &operator<<(QDataStream &out, const MMGBindingManager *&obj); +QDataStream &operator>>(QDataStream &in, MMGBindingManager *&obj); + +class MMGCollections : public MMGManager { + +public: + MMGCollections(QObject *parent) : MMGManager(parent){}; + + MMGBindingManager *add(const QJsonObject &json_obj = QJsonObject()) override; +}; #endif // MMG_BINDING_H diff --git a/src/mmg-config.cpp b/src/mmg-config.cpp index 040a36e..307cd23 100644 --- a/src/mmg-config.cpp +++ b/src/mmg-config.cpp @@ -24,15 +24,16 @@ with this program. If not, see using namespace MMGUtils; +// MMGConfig MMGConfig::MMGConfig() - : _devices(new MMGDeviceManager(this)), - _messages(new MMGMessageManager(this)), - _actions(new MMGActionManager(this)), - _bindings(new MMGBindingManager(this)), - _settings(new MMGSettingsManager(this)), + : _collections(new MMGCollections(this)), + _devices(new MMGDeviceManager(this)), + _settings(new MMGSettings(this)), _signals(new MMGSignals(this)), - _midi(nullptr) + _midi(nullptr), + + old_config(new MMGOldConfig(this)) { } @@ -54,8 +55,7 @@ void MMGConfig::load(const QString &path_str) blog(LOG_INFO, "Loading configuration..."); - auto default_path = obs_module_config_path(filepath().qtocs()); - QFile file(!path_str.isEmpty() ? qPrintable(path_str) : default_path); + QFile file(filepath(path_str)); file.open(QFile::ReadOnly | QFile::Text); QByteArray config_contents; if (file.exists()) { @@ -66,10 +66,9 @@ void MMGConfig::load(const QString &path_str) config_contents = "{}"; } file.close(); - bfree(default_path); QJsonParseError parse_err; - QJsonDocument doc = QJsonDocument::fromJson(config_contents, &parse_err); + QJsonObject doc = QJsonDocument::fromJson(config_contents, &parse_err).object(); if (parse_err.error != QJsonParseError::NoError) { blog(LOG_INFO, "Configuration file data could not be loaded correctly. Reason: " + parse_err.errorString()); @@ -77,100 +76,14 @@ void MMGConfig::load(const QString &path_str) blog(LOG_INFO, "Configuration file data loaded. Extracting..."); } - if (doc["config"].isArray()) { - // 2.0.0 - 2.3.1 JSON file - blog(LOG_INFO, "Old file data extraction detected. Converting..."); - - QMap internal_action_objs; - - for (const QJsonValue &device_obj : doc["config"].toArray()) { - QString device_name = device_obj["name"].toString(); - QStringList split = device_name.split(" "); - - if (bool ok; split.last().toUInt(&ok) >= 0 && ok) { - split.removeLast(); - device_name = split.join(" "); - } - - for (const QJsonValue &binding_obj : device_obj["bindings"].toArray()) { - MMGBinding *binding = _bindings->add(binding_obj.toObject()); - if (_bindings->find(binding->name()) != binding) _bindings->setUniqueName(binding); - - MMGDevice *device = _devices->find(device_name); - if (device) binding->setUsedDevices({device}); + old_config->load(doc); - MMGMessage *message = _messages->add(binding_obj["message"].toObject()); - message->setName(QString("[%1] %2").arg(device_name).arg(message->name())); - if (_messages->find(message->name()) != message) _messages->setUniqueName(message); - binding->setUsedMessages({message}); + _devices->load(doc["devices"].toArray()); + _collections->load(doc["collections"].toArray()); + _settings->load(doc["preferences"].toObject()); - QJsonObject action_obj = binding_obj["action"].toObject(); - if (action_obj["category"].toInt() == 16) { - internal_action_objs[binding] = action_obj; - } else { - MMGAction *action = _actions->add(action_obj); - action->setName(QString("[%1] %2").arg(device_name).arg(action->name())); - if (_actions->find(action->name()) != action) _actions->setUniqueName(action); - binding->setUsedActions({action}); - } - } - } + old_config->postLoad(); - for (MMGBinding *binding : internal_action_objs.keys()) { - QJsonObject internal_action_obj = internal_action_objs[binding]; - MMGActionList actions; - MMGAction *action; - - if (internal_action_obj.contains("str1")) { - for (int i = 0; i < 3; ++i) { - action = _actions->find( - internal_action_obj[num_to_str(i + 1, "str")].toString()); - if (action) actions += action; - } - } else if (internal_action_obj.contains("action1")) { - for (int i = 0; i < 3; ++i) { - action = _actions->find( - internal_action_obj[num_to_str(i + 1, "action")].toString()); - if (action) actions += action; - } - } else if (internal_action_obj.contains("actions")) { - for (const QJsonValue &value : internal_action_obj["actions"].toArray()) { - action = _actions->find(value["name"].toString()); - if (action) actions += action; - } - } - - binding->setUsedActions(actions); - } - - blog(LOG_INFO, "Conversion complete."); - } else if (doc["config"].isObject()) { - // post 3.0.0 JSON file - QJsonObject config_obj = doc["config"].toObject(); - _devices->load(config_obj["devices"].toArray()); - _messages->load(config_obj["messages"].toArray()); - _actions->load(config_obj["actions"].toArray()); - // Bindings must load last to get memory from other managers - _bindings->load(config_obj["bindings"].toArray()); - } - - // Load input device from pre v2.3.0 versions - auto device = _devices->find(doc["active_device"].toString()); - if (device) device->setActive(TYPE_INPUT, true); - - // Load settings - if (doc["preferences"].isObject()) { - QJsonObject preferences = doc["preferences"].toObject(); - if (preferences["thru_device"].isString() && device) - device->setThru(preferences["thru_device"].toString()); - } - QJsonArray settings_default_arr; - for (uint i = 0; i < MMGSettingsManager::visiblePanes(); ++i) - settings_default_arr += QJsonObject(); - _settings->load(doc["settings"].toArray(settings_default_arr)); - - //finish: - blog(LOG_INFO, "Configuration file data extraction complete."); blog(LOG_INFO, "Configuration loading complete."); } @@ -178,19 +91,14 @@ void MMGConfig::save(const QString &path_str) const { QJsonObject save_obj; - QJsonObject config_obj; - _devices->json("devices", config_obj); - _bindings->json("bindings", config_obj); - _messages->json("messages", config_obj); - _actions->json("actions", config_obj); - save_obj["config"] = config_obj; - - _settings->json("settings", save_obj); + _devices->json("devices", save_obj); + _collections->json("collections", save_obj); + _settings->json("preferences", save_obj); save_obj["savedate"] = QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss-zzz"); + save_obj["version"] = OBS_MIDIMG_VERSION; - auto default_path = obs_module_config_path(filepath().qtocs()); - QFile file(!path_str.isEmpty() ? qPrintable(path_str) : default_path); + QFile file(filepath(path_str)); file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate); qlonglong result = file.write(json_to_str(save_obj)); if (result < 0) { @@ -199,18 +107,128 @@ void MMGConfig::save(const QString &path_str) const blog(LOG_INFO, QString("Configuration successfully saved to %1.").arg(file.fileName())); } file.close(); - bfree(default_path); } void MMGConfig::clearAllData() { - _messages->clear(); - _actions->clear(); - _bindings->clear(); - _settings->clear(); + _collections->clear(); +} + +QString MMGConfig::filepath(const QString &path_str) +{ + auto default_path = obs_module_config_path("obs-midi-mg-config.json"); + QString full_path = !path_str.isEmpty() ? path_str : QString(default_path); + bfree(default_path); + return full_path; +} +// End MMGConfig + +// MMGOldConfig +void MMGOldConfig::load(QJsonObject &doc) +{ + if (!doc["config"].isArray()) return; + + // 2.0.0 - 2.3.1 JSON file (before 2.0.0 is not supported) + blog(LOG_INFO, "Old file data detected. Converting..."); + + QJsonArray device_array; + QJsonArray collection_array; + + for (const QJsonValue &device_val : doc["config"].toArray()) { + QJsonObject collection_obj; + + // Get Proper Device Name and Setup + QString device_name = device_val["name"].toString(); + cleanDeviceName(device_name); + + QJsonObject device_obj; + device_obj["name"] = device_name; + if (doc["active_device"].toString().contains(device_name)) { + device_obj["active"] = 1; + device_obj["thru"] = doc["preferences"][QString("thru_device")].toString(); + } + device_array += device_obj; + collection_obj["name"] = device_name; + + // Get Bindings + QJsonArray binding_array; + + for (const QJsonValue &binding_val : device_val["bindings"].toArray()) { + QJsonObject binding_obj = binding_val.toObject(); + + QJsonArray message_array; + binding_obj["message"].toObject()["device"] = device_name; + message_array += binding_obj["message"]; + binding_obj["messages"] = message_array; + + QJsonArray action_array; + QJsonObject action_obj = binding_obj["action"].toObject(); + if (action_obj["category"].toInt() == 16) { + if (action_obj.contains("actions")) { + for (const QJsonValue &action_val : action_obj["actions"].toArray()) { + QJsonObject internal_obj; + internal_obj["name"] = action_val["action"]; + action_array += internal_obj; + } + } else { + for (int i = 0; i < 3; ++i) { + QJsonObject internal_obj; + internal_obj["name"] = + action_obj[(action_obj.contains("str1") ? "str" : "action") + + QString::number(i + 1)]; + action_array += internal_obj; + } + } + old_internal_bindings.insert(device_name, binding_obj["name"].toString()); + } else { + action_array += action_obj; + } + binding_obj["actions"] = action_array; + + binding_array += binding_obj; + } + collection_obj["bindings"] = binding_array; + + collection_array += collection_obj; + } + + doc["devices"] = device_array; + doc["collections"] = collection_array; + + blog(LOG_INFO, "Conversion completed successfully."); } -QString MMGConfig::filepath() +void MMGOldConfig::postLoad() { - return "obs-midi-mg-config.json"; -} \ No newline at end of file + for (const QString &collection_name : old_internal_bindings.keys()) { + MMGBindingManager *collection = manager(collection)->find(collection_name); + if (!collection) continue; + + for (const QString &binding_name : old_internal_bindings.values(collection_name)) { + MMGBinding *binding = collection->find(binding_name); + if (!binding) continue; + + QStringList action_list = binding->actions()->names(); + binding->actions()->clear(); + for (const QString &action : action_list) { + MMGBinding *internal_action_binding = collection->find(action); + if (!internal_action_binding) continue; + + binding->actions()->copy(internal_action_binding->actions(0))->setObjectName(action); + } + } + } + + old_internal_bindings.clear(); +} + +void MMGOldConfig::cleanDeviceName(QString &device_name) const +{ + QStringList split = device_name.split(" "); + + if (bool ok; split.last().toUInt(&ok) >= 0 && ok) { + split.removeLast(); + device_name = split.join(" "); + } +} +// End MMGOldConfig \ No newline at end of file diff --git a/src/mmg-config.h b/src/mmg-config.h index 267a916..b3cc140 100644 --- a/src/mmg-config.h +++ b/src/mmg-config.h @@ -19,9 +19,12 @@ with this program. If not, see #ifndef MMG_CONFIG_H #define MMG_CONFIG_H +#include "mmg-device.h" #include "mmg-binding.h" #include "mmg-settings.h" +class MMGOldConfig; + class MMGConfig : public QObject { Q_OBJECT @@ -34,28 +37,46 @@ class MMGConfig : public QObject { void save(const QString &path_str = QString()) const; void clearAllData(); + MMGCollections *collections() const { return _collections; }; MMGDeviceManager *devices() const { return _devices; }; - MMGMessageManager *messages() const { return _messages; }; - MMGActionManager *actions() const { return _actions; }; - MMGBindingManager *bindings() const { return _bindings; }; - MMGSettingsManager *settings() const { return _settings; }; + MMGSettings *settings() const { return _settings; }; MMGSignals *mmgsignals() const { return _signals; }; MMGMIDI *midi() const { return _midi; }; - static QString filepath(); + static QString filename() { return "obs-midi-mg-config.json"; }; + static QString filepath(const QString &path_str); private: + MMGCollections *_collections; MMGDeviceManager *_devices; - MMGMessageManager *_messages; - MMGActionManager *_actions; - MMGBindingManager *_bindings; - MMGSettingsManager *_settings; + MMGSettings *_settings; MMGSignals *_signals; MMGMIDI *_midi; + + MMGOldConfig *old_config; }; +#define enum_manager(which) for (auto val : *manager(which)) #define manager(which) config()->which##s() +#define midi() config()->midi() + +class MMGOldConfig : public QObject { + Q_OBJECT + +public: + MMGOldConfig(MMGConfig *parent) : QObject(parent), new_config(parent) {} + + void blog(int log_status, const QString &message) { new_config->blog(log_status, message); }; + void load(QJsonObject &doc); + void postLoad(); + +private: + void cleanDeviceName(QString &) const; + + MMGConfig *new_config; + QMultiMap old_internal_bindings; +}; #endif // MMG_CONFIG_H diff --git a/src/mmg-device.cpp b/src/mmg-device.cpp index 4186194..1a59724 100644 --- a/src/mmg-device.cpp +++ b/src/mmg-device.cpp @@ -25,13 +25,11 @@ using namespace MMGUtils; MMGDevice::MMGDevice(MMGDeviceManager *parent, const QJsonObject &json_obj) : MMGMIDIPort(parent, json_obj) { update(json_obj); - - connect(this, &QObject::destroyed, [&]() { emit deleting(this); }); } void MMGDevice::json(QJsonObject &device_obj) const { - device_obj["name"] = _name; + device_obj["name"] = objectName(); device_obj["active"] = (int)_active; if (!_thru.isEmpty()) device_obj["thru"] = _thru; } @@ -61,28 +59,50 @@ void MMGDevice::setActive(DeviceType type, bool active) { if (!editable || isActive(type) == active || !isCapable(type)) return; + !isActive(type) ? openPort(type) : closePort(type); + // Is the port not in the correct state? + if (isPortOpen(type) == isActive(type)) { + open_message_box("PortOpenError"); + return; + } + switch (type) { case TYPE_INPUT: _active ^= 0b01; // 00 -> 01, 10 -> 11, 01 -> 00, 11 -> 10 + break; case TYPE_OUTPUT: _active ^= 0b10; // 00 -> 10, 01 -> 11, 10 -> 00, 11 -> 01 + break; default: break; } - - isActive(type) ? openPort(type) : closePort(type); } -void MMGDevice::addConnection(MMGBinding *binding) +void MMGDevice::checkCapable() { - connect(this, &MMGDevice::deleting, binding, &MMGBinding::removeDevice); -} + uint active = _active; + _active = 0; -void MMGDevice::removeConnection(MMGBinding *binding) -{ - disconnect(this, &MMGDevice::deleting, binding, nullptr); + blog(LOG_INFO, "Checking device capabilities..."); + + closePort(TYPE_INPUT); + closePort(TYPE_OUTPUT); + + openPort(TYPE_INPUT); + setCapable(TYPE_INPUT, isPortOpen(TYPE_INPUT)); + + openPort(TYPE_OUTPUT); + setCapable(TYPE_OUTPUT, isPortOpen(TYPE_OUTPUT)); + + closePort(TYPE_INPUT); + closePort(TYPE_OUTPUT); + + blog(LOG_INFO, "Device capabilities checked. Re-opening active ports..."); + + setActive(TYPE_INPUT, active & 0b01); + setActive(TYPE_OUTPUT, active & 0b10); } // End MMGDevice @@ -95,6 +115,7 @@ MMGDevice *MMGDeviceManager::add(const QJsonObject &json_obj) current_device->update(json_obj); return current_device; } else { + if (find(mmgtr("Device.Dummy"))) remove(find(mmgtr("Device.Dummy"))); return MMGManager::add(new MMGDevice(this, json_obj)); } } @@ -106,16 +127,11 @@ MMGDevice *MMGDeviceManager::add(const QString &name) return add(json_obj); } -bool MMGDeviceManager::filter(DeviceType type, MMGDevice *check) const -{ - return check->isCapable(type); -} - const QStringList MMGDeviceManager::capableDevices(DeviceType type) const { QStringList devices; for (MMGDevice *device : _list) { - if (device->isCapable(type)) devices += device->name(); + if (device->isCapable(type)) devices += device->objectName(); } return devices; } diff --git a/src/mmg-device.h b/src/mmg-device.h index 29a46ae..59148c2 100644 --- a/src/mmg-device.h +++ b/src/mmg-device.h @@ -41,11 +41,7 @@ class MMGDevice : public MMGMIDIPort { bool isActive(MMGUtils::DeviceType type) const; void setActive(MMGUtils::DeviceType type, bool active); - void addConnection(MMGBinding *binding); - void removeConnection(MMGBinding *binding); - -signals: - void deleting(MMGDevice *device); + void checkCapable(); private: uint _active : 2 = 0; @@ -62,8 +58,6 @@ class MMGDeviceManager : public MMGManager { MMGDevice *add(const QJsonObject &json_obj = QJsonObject()) override; MMGDevice *add(const QString &name); - bool filter(MMGUtils::DeviceType type, MMGDevice *check) const override; - const QStringList capableDevices(MMGUtils::DeviceType) const; }; diff --git a/src/mmg-manager.cpp b/src/mmg-manager.cpp index 28cbc9b..db6b3ca 100644 --- a/src/mmg-manager.cpp +++ b/src/mmg-manager.cpp @@ -25,7 +25,8 @@ template T *MMGManager::add(T *new_t) { if (!new_t) return nullptr; _list.append(new_t); - if (find(new_t->name()) != new_t) setUniqueName(new_t); + new_t->setParent(this); + if (!new_t->objectName().isEmpty() && find(new_t->objectName()) != new_t) setUniqueName(new_t); return new_t; } @@ -37,14 +38,14 @@ template T *MMGManager::copy(T *source) template T *MMGManager::copy(T *source, T *dest) { source->copy(dest); - if (find(dest->name()) != dest) setUniqueName(dest); + if (!dest->objectName().isEmpty() && find(dest->objectName()) != dest) setUniqueName(dest); return dest; } template T *MMGManager::find(const QString &name) const { for (T *value : _list) { - if (value->name() == name) return value; + if (value->objectName() == name) return value; } return nullptr; } @@ -57,12 +58,21 @@ template void MMGManager::move(int from, int to) template void MMGManager::setUniqueName(T *source, qulonglong count) { - QString new_name = QString("%1 (%2)").arg(source->name()).arg(count); + QString new_name = QString("%1 (%2)").arg(source->objectName()).arg(count); if (find(new_name)) { setUniqueName(source, ++count); return; } - source->setName(new_name); + source->setObjectName(new_name); +} + +template const QStringList MMGManager::names() const +{ + QStringList names; + for (T *val : _list) { + names += val->objectName(); + } + return names; } template void MMGManager::remove(T *source) @@ -71,10 +81,11 @@ template void MMGManager::remove(T *source) delete source; } -template void MMGManager::clear() +template void MMGManager::clear(bool full) { qDeleteAll(_list); _list.clear(); + if (!full) add(); } template void MMGManager::load(const QJsonArray &json_arr) @@ -82,6 +93,7 @@ template void MMGManager::load(const QJsonArray &json_arr) for (const QJsonValue &value : json_arr) { add(value.toObject()); } + if (size() < 1) add(); } template void MMGManager::json(const QString &key, QJsonObject &json_obj) const diff --git a/src/mmg-manager.h b/src/mmg-manager.h index c4dd4ed..814217a 100644 --- a/src/mmg-manager.h +++ b/src/mmg-manager.h @@ -29,15 +29,16 @@ template class MMGManager : public QObject { T *find(const QString &name) const; void move(int from, int to); void remove(T *source); - void clear(); + void clear(bool full = true); void load(const QJsonArray &json_arr); void json(const QString &key, QJsonObject &json_obj) const; void setUniqueName(T *source, qulonglong count = 2); - virtual bool filter(MMGUtils::DeviceType, T *) const { return true; }; + const QStringList names() const; - const QList &list() const { return _list; }; T *at(qsizetype i) const { return _list.value(i); }; + qsizetype size() const { return _list.size(); }; + auto begin() const { return _list.begin(); }; auto end() const { return _list.end(); }; diff --git a/src/mmg-message.cpp b/src/mmg-message.cpp index ec59079..6dd1bac 100644 --- a/src/mmg-message.cpp +++ b/src/mmg-message.cpp @@ -26,33 +26,33 @@ MMGMessage::MMGMessage(QObject *parent) : QObject(parent) { setRanges(); - _name = mmgtr("Message.Untitled"); + setObjectName(mmgtr("Message.Untitled")); + setDevice(manager(device)->at(0)); _channel = 1; _type = mmgtr("Message.Type.NoteOn"); _value.setState(STATE_MIDI); - - connect(this, &QObject::destroyed, [&]() { emit deleting(this); }); } -MMGMessage::MMGMessage(const libremidi::message &message) +MMGMessage::MMGMessage(MMGMIDIPort *device, const libremidi::message &message) { setRanges(); + setDevice(device); _channel = message.get_channel(); _type = getType(message); _note = getNote(message); _value = getValue(message); - - connect(this, &QObject::destroyed, [&]() { emit deleting(this); }); } MMGMessage::MMGMessage(const QJsonObject &json_obj) : _channel(json_obj, "channel"), _type(json_obj, "type"), _note(json_obj, "note"), _value(json_obj, "value") { - _name = json_obj["name"].toString(mmgtr("Message.Untitled")); - setRanges(); + setObjectName(json_obj["name"].toString(mmgtr("Message.Untitled"))); + + setDevice(manager(device)->find(json_obj["device"].toString())); + if (_channel == 0) _channel = 1; if ((json_obj["value_require"].isBool() && !(json_obj["value_require"].toBool())) || _value < 0) @@ -66,8 +66,16 @@ MMGMessage::MMGMessage(const QJsonObject &json_obj) _type.setState(STATE_TOGGLE); _type.setMax(mmgtr("Message.Type.NoteOff")); } +} + +void MMGMessage::setDevice(MMGMIDIPort *device) +{ + disconnect(_device, &QObject::destroyed, this, nullptr); - connect(this, &QObject::destroyed, [&]() { emit deleting(this); }); + _device = device; + if (!device) return; + + connect(_device, &QObject::destroyed, this, [&]() { _device = nullptr; }); } void MMGMessage::blog(int log_status, const QString &message) const @@ -77,7 +85,8 @@ void MMGMessage::blog(int log_status, const QString &message) const void MMGMessage::json(QJsonObject &message_obj) const { - message_obj["name"] = _name; + message_obj["name"] = objectName(); + message_obj["device"] = _device ? _device->objectName() : ""; _channel.json(message_obj, "channel"); _type.json(message_obj, "type"); _note.json(message_obj, "note"); @@ -86,7 +95,8 @@ void MMGMessage::json(QJsonObject &message_obj) const void MMGMessage::copy(MMGMessage *dest) const { - dest->_name = _name; + dest->setObjectName(objectName()); + dest->_device = _device; dest->_channel = _channel.copy(); dest->_type = _type.copy(); dest->_note = _note.copy(); @@ -112,10 +122,10 @@ void MMGMessage::toggle() bool MMGMessage::acceptable(const MMGMessage *test) const { bool accepted = true; + accepted &= _device == test->_device; accepted &= _channel.acceptable(test->channel()); accepted &= (_type == test->type().value()); - if (_type != mmgtr("Message.Type.ProgramChange") && _type != mmgtr("Message.Type.PitchBend")) - accepted &= _note.acceptable(test->note()); + if (!valueOnlyType()) accepted &= _note.acceptable(test->note()); return accepted && _value.acceptable(test->value()); } @@ -132,14 +142,14 @@ void MMGMessage::applyValues(const MMGNumber &applied) _value.chooseOther(applied); } -void MMGMessage::addConnection(MMGBinding *binding) +void MMGMessage::send() { - connect(this, &MMGMessage::deleting, binding, &MMGBinding::removeMessage); + if (_device) _device->sendMessage(this); } -void MMGMessage::removeConnection(MMGBinding *binding) +bool MMGMessage::valueOnlyType() const { - disconnect(this, &MMGMessage::deleting, binding, nullptr); + return _type == mmgtr("Message.Type.ProgramChange") || _type == mmgtr("Message.Type.PitchBend"); } int MMGMessage::getNote(const libremidi::message &mess) @@ -244,6 +254,16 @@ void MMGMessage::setRanges() if (_note.state() == STATE_FIXED && _note.max() == 100) _note.setMax(127); if (_value.state() == STATE_FIXED && _value.max() == 100) _value.setMax(127); } + +QDataStream &operator<<(QDataStream &out, const MMGMessage *&obj) +{ + return out << (const QObject *&)obj; +} + +QDataStream &operator>>(QDataStream &in, MMGMessage *&obj) +{ + return in >> (QObject *&)obj; +} // End MMGMessage // MMGMessageManager diff --git a/src/mmg-message.h b/src/mmg-message.h index 7b1afe3..7697197 100644 --- a/src/mmg-message.h +++ b/src/mmg-message.h @@ -23,6 +23,7 @@ with this program. If not, see #include "mmg-manager.h" class MMGBinding; +class MMGMIDIPort; class MMGMessage : public QObject { Q_OBJECT @@ -30,10 +31,10 @@ class MMGMessage : public QObject { public: MMGMessage(QObject *parent = nullptr); MMGMessage(const QJsonObject &json_obj); - MMGMessage(const libremidi::message &message); + MMGMessage(MMGMIDIPort *device, const libremidi::message &message); - const QString &name() const { return _name; }; - void setName(const QString &name) { _name = name; }; + MMGMIDIPort *device() const { return _device; }; + void setDevice(MMGMIDIPort *device); MMGUtils::MMGNumber &channel() { return _channel; }; MMGUtils::MMGString &type() { return _type; }; @@ -52,32 +53,30 @@ class MMGMessage : public QObject { bool acceptable(const MMGMessage *test) const; void applyValues(const MMGUtils::MMGNumber &applied); - - void addConnection(MMGBinding *binding); - void removeConnection(MMGBinding *binding); + void send(); + bool valueOnlyType() const; static QString getType(const libremidi::message &mess); static int getNote(const libremidi::message &mess); static int getValue(const libremidi::message &mess); static const QStringList acceptedTypes(); -signals: - void deleting(MMGMessage *); - private: - QString _name; - MMGUtils::MMGNumber _channel; MMGUtils::MMGString _type; MMGUtils::MMGNumber _note; MMGUtils::MMGNumber _value; + MMGMIDIPort *_device = nullptr; + void setRanges(); }; using MMGMessageList = QList; -using MMGSharedMessage = QSharedPointer; +using MMGSharedMessage = std::shared_ptr; Q_DECLARE_METATYPE(MMGSharedMessage); +QDataStream &operator<<(QDataStream &out, const MMGMessage *&obj); +QDataStream &operator>>(QDataStream &in, MMGMessage *&obj); class MMGMessageManager : public MMGManager { diff --git a/src/mmg-midi.cpp b/src/mmg-midi.cpp index aafbad2..c9cf6a3 100644 --- a/src/mmg-midi.cpp +++ b/src/mmg-midi.cpp @@ -22,19 +22,29 @@ with this program. If not, see using namespace MMGUtils; MMGMIDIPort::MMGMIDIPort(QObject *parent, const QJsonObject &json_obj) - : QObject(parent), - _name(json_obj["name"].toString()), - midi_in(midi()->inputConfig(this)), - midi_out(midi()->outputConfig()) + : QObject(parent), midi_in(midi()->inputConfig(this)), midi_out(midi()->outputConfig()) { - //thru_timer = new MMGTimer(this); + setObjectName(json_obj["name"].toString(mmgtr("Device.Dummy"))); + //thru_timer = new MMGTimer(this); //connect(thru_timer, &MMGTimer::stopping, this, &MMGMIDIPort::closeOutputPort); } void MMGMIDIPort::blog(int log_status, const QString &_message) const { - global_blog(log_status, QString("[MIDI] <%1> %2").arg(_name).arg(_message)); + global_blog(log_status, QString("[MIDI] <%1> %2").arg(objectName()).arg(_message)); +} + +void MMGMIDIPort::incListening(bool listen) +{ + if (!listen && listening < 1) return; + listen ? listening++ : listening--; +} + +void MMGMIDIPort::incConnection(bool connect) +{ + if (!connect && connections < 1) return; + connect ? connections++ : connections--; } void MMGMIDIPort::openPort(DeviceType type) @@ -164,15 +174,15 @@ void MMGMIDIPort::sendThru() blog(LOG_INFO, "Device is not connected or does not exist."); return; } - port->sendMessage(message.data()); + port->sendMessage(message.get()); } void MMGMIDIPort::callback(const libremidi::message &msg) { - message.reset(new MMGMessage(msg)); + message.reset(new MMGMessage(this, msg)); - if (midi()->isListening()) { - emit midi()->messageListened(message); + if (listening) { + emit messageListened(message); } else { emit messageReceived(message); sendThru(); @@ -183,14 +193,13 @@ void MMGMIDIPort::callback(const libremidi::message &msg) // MMGMIDI MMGMIDI::MMGMIDI(QObject *parent) : QObject(parent), - observer({ - .on_error = [&](libremidi::midi_error e, std::string_view str) { backendError(e, str); }, - .on_warning = [&](libremidi::midi_error e, std::string_view str) { backendError(e, str); }, - .input_added = [&](libremidi::input_port port) { inputAdded(port); }, - .input_removed = [&](libremidi::input_port port) { inputRemoved(port); }, - .output_added = [&](libremidi::output_port port) { outputAdded(port); }, - .output_removed = [&](libremidi::output_port port) { outputRemoved(port); }, - }) + observer({.on_error = [&](libremidi::midi_error e, std::string_view str) { backendError(e, str); }, + .on_warning = [&](libremidi::midi_error e, std::string_view str) { backendError(e, str); }, + .input_added = [&](libremidi::input_port port) { inputAdded(port); }, + .input_removed = [&](libremidi::input_port port) { inputRemoved(port); }, + .output_added = [&](libremidi::output_port port) { outputAdded(port); }, + .output_removed = [&](libremidi::output_port port) { outputRemoved(port); }, + .track_virtual = true}) { } @@ -223,11 +232,12 @@ void MMGMIDI::inputAdded(const libremidi::input_port &port) MMGDevice *adding_device = manager(device)->find(port_name); if (!adding_device) { adding_device = manager(device)->add(port_name); - blog(LOG_INFO, QString("New device <%1> detected.").arg(port_name)); + blog(LOG_INFO, QString("Device <%1> detected.").arg(port_name)); } adding_device->in_port_info = port; adding_device->setCapable(TYPE_INPUT, true); + emit deviceCapableChange(); } void MMGMIDI::inputRemoved(const libremidi::input_port &port) @@ -241,6 +251,7 @@ void MMGMIDI::inputRemoved(const libremidi::input_port &port) if (!removing_device->isCapable(TYPE_NONE)) return; manager(device)->remove(removing_device); blog(LOG_INFO, QString("Device <%1> removed.").arg(port_name)); + emit deviceCapableChange(); } void MMGMIDI::outputAdded(const libremidi::output_port &port) @@ -250,11 +261,12 @@ void MMGMIDI::outputAdded(const libremidi::output_port &port) MMGDevice *adding_device = manager(device)->find(port_name); if (!adding_device) { adding_device = manager(device)->add(port_name); - blog(LOG_INFO, QString("New device <%1> detected.").arg(port_name)); + blog(LOG_INFO, QString("Device <%1> detected.").arg(port_name)); } adding_device->out_port_info = port; adding_device->setCapable(TYPE_OUTPUT, true); + emit deviceCapableChange(); } void MMGMIDI::outputRemoved(const libremidi::output_port &port) @@ -268,6 +280,7 @@ void MMGMIDI::outputRemoved(const libremidi::output_port &port) if (!removing_device->isCapable(TYPE_NONE)) return; manager(device)->remove(removing_device); blog(LOG_INFO, QString("Device <%1> removed.").arg(port_name)); + emit deviceCapableChange(); } void MMGMIDI::backendError(libremidi::midi_error error, std::string_view string) const @@ -281,33 +294,28 @@ void MMGMIDI::backendError(libremidi::midi_error error, std::string_view string) case libremidi::UNSPECIFIED: default: - blog(LOG_INFO, "{ERROR (Unknown)} " + err_string); + blog(LOG_INFO, "{UNKNOWN ERROR} " + err_string); break; case libremidi::NO_DEVICES_FOUND: - blog(LOG_INFO, "{ERROR (No Devices)} " + err_string); + blog(LOG_INFO, "{NO DEVICES} " + err_string); break; case libremidi::INVALID_DEVICE: case libremidi::INVALID_PARAMETER: case libremidi::INVALID_USE: - blog(LOG_INFO, "{ERROR (Invalid Usage)} " + err_string); + blog(LOG_INFO, "{INVALID USAGE} " + err_string); break; case libremidi::MEMORY_ERROR: - blog(LOG_INFO, "{ERROR (Memory)} " + err_string); + blog(LOG_INFO, "{MEMORY ERROR} " + err_string); break; case libremidi::DRIVER_ERROR: case libremidi::SYSTEM_ERROR: case libremidi::THREAD_ERROR: - blog(LOG_INFO, "{ERROR (System)} " + err_string); + blog(LOG_INFO, "{SYSTEM ERROR} " + err_string); break; } } -// End MMGMIDI - -MMGMIDI *midi() -{ - return config()->midi(); -} \ No newline at end of file +// End MMGMIDI \ No newline at end of file diff --git a/src/mmg-midi.h b/src/mmg-midi.h index 09b1d4b..8612f89 100644 --- a/src/mmg-midi.h +++ b/src/mmg-midi.h @@ -26,12 +26,14 @@ class MMGMIDIPort : public QObject { Q_OBJECT public: - const QString &name() const { return _name; }; - void setName(const QString &){}; - const QString &thru() const { return _thru; }; void setThru(const QString &device) { _thru = device; }; + bool isListening() const { return listening > 0; }; + void incListening(bool listen); + + void incConnection(bool connect); + bool isPortOpen(MMGUtils::DeviceType type) const; bool isCapable(MMGUtils::DeviceType type) const; QString status(MMGUtils::DeviceType type) const; @@ -45,26 +47,30 @@ class MMGMIDIPort : public QObject { void closePort(MMGUtils::DeviceType type); signals: + void messageListened(const MMGSharedMessage &); void messageReceived(const MMGSharedMessage &); public slots: void sendMessage(const MMGMessage *midi); protected: - QString _name; QString _thru; uint _capable : 2 = 0; + int listening = 0; + int connections = 0; + + void setCapable(MMGUtils::DeviceType type, bool capable); + +private: libremidi::input_port in_port_info; libremidi::midi_in midi_in; libremidi::output_port out_port_info; libremidi::midi_out midi_out; -private: MMGSharedMessage message; - void setCapable(MMGUtils::DeviceType type, bool capable); void callback(const libremidi::message &msg); void sendThru(); @@ -82,17 +88,12 @@ class MMGMIDI : public QObject { const libremidi::input_configuration inputConfig(MMGMIDIPort *port) const; const libremidi::output_configuration outputConfig() const; - bool isListening() const { return listening; }; - void setListening(bool listen) { listening = listen; }; - signals: - void messageListened(const MMGSharedMessage &); + void deviceCapableChange(); private: libremidi::observer observer; - bool listening = false; - void inputAdded(const libremidi::input_port &port); void inputRemoved(const libremidi::input_port &port); void outputAdded(const libremidi::output_port &port); @@ -101,5 +102,4 @@ class MMGMIDI : public QObject { void backendError(libremidi::midi_error, std::string_view) const; }; -MMGMIDI *midi(); #endif // MMG_MIDI_H diff --git a/src/mmg-settings.cpp b/src/mmg-settings.cpp index 88b6091..1647d15 100644 --- a/src/mmg-settings.cpp +++ b/src/mmg-settings.cpp @@ -23,112 +23,8 @@ with this program. If not, see using namespace MMGUtils; -// MMGSettings -MMGSettings::MMGSettings(MMGSettingsManager *parent) : QObject(parent), editable(&parent->isEditable()) {} -// End MMGSettings +MMGSettings::MMGSettings(QObject *parent) : QObject(parent) {} -// MMGGeneralSettings -MMGGeneralSettings::MMGGeneralSettings(MMGSettingsManager *parent, const QJsonObject &json_obj) : MMGSettings(parent) -{ - Q_UNUSED(json_obj); -} +void MMGSettings::json(const QString &key, QJsonObject &json_obj) const {} -void MMGGeneralSettings::json(QJsonObject &settings_obj) const -{ - Q_UNUSED(settings_obj); -} - -void MMGGeneralSettings::createDisplay(QWidget *parent) -{ - MMGSettings::createDisplay(parent); -} -// End MMGGeneralSettings - -// MMGBindingSettings -MMGBindingSettings::MMGBindingSettings(MMGSettingsManager *parent, const QJsonObject &json_obj) : MMGSettings(parent) -{ - reset_behavior = resetBehaviorOptions()[json_obj["reset_behavior"].toInt()]; -} - -void MMGBindingSettings::json(QJsonObject &settings_obj) const -{ - settings_obj["reset_behavior"] = resetBehavior(); -} - -void MMGBindingSettings::copy(MMGSettings *dest) -{ - auto casted = dynamic_cast(dest); - if (!casted) return; - - casted->reset_behavior = reset_behavior.copy(); -} - -void MMGBindingSettings::createDisplay(QWidget *parent) -{ - MMGSettings::createDisplay(parent); - - MMGStringDisplay *reset_behavior_display = new MMGStringDisplay(display()); - reset_behavior_display->setDisplayMode(MMGStringDisplay::MODE_THIN); - reset_behavior_display->setDescription(mmgtr("Preferences.Binding.ResetBehavior")); - reset_behavior_display->setStorage(&reset_behavior, resetBehaviorOptions()); - connect(reset_behavior_display, &MMGStringDisplay::stringChanged, this, - &MMGBindingSettings::resetBehaviorChanged); - connect(reset_behavior_display, &MMGStringDisplay::stringChanged, this, &MMGBindingSettings::setLabel); - - reset_behavior_desc = new QLabel(display()); - reset_behavior_desc->setGeometry(0, 50, 330, 80); - reset_behavior_desc->setWordWrap(true); - reset_behavior_desc->setAlignment(Qt::AlignVCenter); - setLabel(); -} - -const QStringList MMGBindingSettings::resetBehaviorOptions() -{ - return mmgtr_all("Preferences.Binding.ResetBehavior.Option", {"Yes", "No"}); -} - -void MMGBindingSettings::setLabel() -{ - reset_behavior_desc->setText(mmgtr_two("Preferences.Binding.ResetBehavior.Text", "No", "Yes", resetBehavior())); -} - -// End MMGBindingSettings - -// MMGMessageLogSettings -void MMGMessageLogSettings::json(QJsonObject &settings_obj) const -{ - Q_UNUSED(settings_obj); -} - -void MMGMessageLogSettings::createDisplay(QWidget *parent) -{ - MMGSettings::createDisplay(parent); -} -// End MMGMessageLogSettings - -// MMGSettingsManager -MMGSettings *MMGSettingsManager::add(const QJsonObject &json_obj) -{ - MMGSettings *settings = nullptr; - - switch (_list.size()) { - case 0: - settings = new MMGGeneralSettings(this, json_obj); - break; - - case 1: - settings = new MMGBindingSettings(this, json_obj); - break; - - case 2: - //settings = new MMGMessageLogSettings(this); - break; - - default: - return nullptr; - } - - _list += settings; - return settings; -} -// End MMGSettingsManager +void MMGSettings::load(const QJsonObject &json_obj) {} \ No newline at end of file diff --git a/src/mmg-settings.h b/src/mmg-settings.h index 331ad6b..bb02f84 100644 --- a/src/mmg-settings.h +++ b/src/mmg-settings.h @@ -20,97 +20,18 @@ with this program. If not, see #define MMG_SETTINGS_H #include "mmg-utils.h" -#include "mmg-manager.h" - -class MMGBinding; -class MMGSettingsManager; class MMGSettings : public QObject { public: - MMGSettings(MMGSettingsManager *parent); - - virtual QString name() const = 0; - void setName(const QString &){}; - - virtual void json(QJsonObject &json_obj) const = 0; - virtual void copy(MMGSettings *){}; - bool isEditable() const { return *editable; }; - - virtual void createDisplay(QWidget *parent) { _display = new QWidget(parent); }; - QWidget *display() const { return _display; }; - -private: - const bool *editable; - QWidget *_display = nullptr; -}; - -class MMGGeneralSettings : public MMGSettings { - Q_OBJECT - -public: - MMGGeneralSettings(MMGSettingsManager *parent, const QJsonObject &json_obj = QJsonObject()); - - QString name() const override { return mmgtr("Preferences.General"); }; - void json(QJsonObject &json_obj) const override; - void createDisplay(QWidget *parent) override; -}; - -class MMGBindingSettings : public MMGSettings { - Q_OBJECT - -public: - MMGBindingSettings(MMGSettingsManager *parent, const QJsonObject &json_obj = QJsonObject()); - - enum ResetBehavior { BEHAVIOR_RESET, BEHAVIOR_NO_RESET }; - - QString name() const override { return mmgtr("Preferences.Binding"); }; - void json(QJsonObject &json_obj) const override; - void copy(MMGSettings *dest) override; - void createDisplay(QWidget *parent) override; - - ResetBehavior resetBehavior() const { return (ResetBehavior)resetBehaviorOptions().indexOf(reset_behavior); }; - - static const QStringList resetBehaviorOptions(); - -signals: - void resetBehaviorChanged(); - -private slots: - void setLabel(); - -private: - MMGUtils::MMGString reset_behavior; - - QLabel *reset_behavior_desc; -}; - -class MMGMessageLogSettings : public MMGSettings { - Q_OBJECT - -public: - MMGMessageLogSettings(MMGSettingsManager *parent) : MMGSettings(parent){}; - - QString name() const override { return mmgtr("Preferences.Log"); }; - void json(QJsonObject &) const override; - void createDisplay(QWidget *parent) override; -}; - -class MMGSettingsManager : public MMGManager { - -public: - MMGSettingsManager(QObject *parent) : MMGManager(parent){}; - - const bool &isEditable() const { return editable; }; - void setEditable(bool edit) { editable = edit; }; - bool filter(MMGUtils::DeviceType type, MMGSettings *) const override { return type == MMGUtils::TYPE_NONE; }; - - MMGSettings *add(const QJsonObject &json_obj = QJsonObject()) override; + MMGSettings(QObject *parent); - static uint visiblePanes() { return 2; }; + void json(const QString &key, QJsonObject &json_obj) const; + void load(const QJsonObject &json_obj); + //bool isEditable() const { return editable; }; private: - bool editable = true; + //bool editable = true; }; #endif // MMG_SETTINGS_H diff --git a/src/mmg-signal.cpp b/src/mmg-signal.cpp index 750ab9e..5e57f3e 100644 --- a/src/mmg-signal.cpp +++ b/src/mmg-signal.cpp @@ -254,7 +254,8 @@ void MMGSignals::frontendCallback(obs_frontend_event event, void *ptr) emit _signals->frontendEvent(event); if (event == OBS_FRONTEND_EVENT_FINISHED_LOADING) { - manager(binding)->resetConnections(); + enum_manager(collection) val->resetConnections(); + _signals->blockSignals(false); } } diff --git a/src/mmg-utils.cpp b/src/mmg-utils.cpp index 90dfd54..4a33a9c 100644 --- a/src/mmg-utils.cpp +++ b/src/mmg-utils.cpp @@ -34,6 +34,19 @@ void global_blog(int log_status, const QString &message) blog(log_status, "[obs-midi-mg] %s", message.qtocs()); } +QDataStream &operator<<(QDataStream &out, const QObject *&obj) +{ + return out << *(quint64 *)(&obj); +} + +QDataStream &operator>>(QDataStream &in, QObject *&obj) +{ + quint64 data; + in >> data; + obj = *(QObject **)(&data); + return in; +} + namespace MMGUtils { // MMGNumber @@ -274,25 +287,6 @@ QStringList obstr_all(const QString &header, const QStringList &list) return tr_list; } -void set_message_labels(const QString &type, MMGNumberDisplay *note_display, MMGNumberDisplay *value_display) -{ - if (type == mmgtr("Message.Type.NoteOn") || type == mmgtr("Message.Type.NoteOff")) { - note_display->setVisible(true); - note_display->setDescription(mmgtr("Message.Note")); - value_display->setDescription(mmgtr("Message.Velocity")); - } else if (type == mmgtr("Message.Type.ControlChange")) { - note_display->setVisible(true); - note_display->setDescription(mmgtr("Message.Control")); - value_display->setDescription(mmgtr("Message.Value")); - } else if (type == mmgtr("Message.Type.ProgramChange")) { - note_display->setVisible(false); - value_display->setDescription(mmgtr("Message.Program")); - } else if (type == mmgtr("Message.Type.PitchBend")) { - note_display->setVisible(false); - value_display->setDescription(mmgtr("Message.PitchAdjust")); - } -} - bool num_between(double num, double lower, double higher, bool inclusive) { return inclusive ? ((num >= lower) && (num <= higher)) : ((num > lower) && (num < higher)); @@ -322,6 +316,11 @@ void enable_combo_option(QComboBox *combo, int index, bool enable) qobject_cast(combo->model())->item(index)->setEnabled(enable); } +QIcon mmg_icon(const QString &icon_name) +{ + return QIcon(QString(":/icons/%1.svg").arg(icon_name)); +} + void obs_source_custom_update(obs_source_t *source, const QJsonObject &action_json, const MMGMessage *midi) { if (!source) return; diff --git a/src/mmg-utils.h b/src/mmg-utils.h index c93671c..abe481e 100644 --- a/src/mmg-utils.h +++ b/src/mmg-utils.h @@ -36,8 +36,10 @@ with this program. If not, see void global_blog(int log_status, const QString &message); +QDataStream &operator<<(QDataStream &out, const QObject *&obj); +QDataStream &operator>>(QDataStream &in, QObject *&obj); + class MMGMessage; -class MMGNumberDisplay; namespace MMGUtils { @@ -167,8 +169,6 @@ QString mmgtr_two(const char *header, const char *opt1, const char *opt2, bool d QStringList mmgtr_all(const QString &header, const QStringList &list); QStringList obstr_all(const QString &header, const QStringList &list); -void set_message_labels(const QString &type, MMGNumberDisplay *note_display, MMGNumberDisplay *value_display); - const QByteArray json_to_str(const QJsonObject &json_obj); const QJsonObject json_from_str(const QByteArray &str); @@ -176,6 +176,7 @@ bool num_between(double num, double lower, double higher, bool inclusive = true) QString num_to_str(int num, const QString &prefix = ""); void enable_combo_option(QComboBox *combo, int index, bool enable); +QIcon mmg_icon(const QString &icon_name); bool open_message_box(const QString &message, bool information = true); diff --git a/src/ui/icons/move.svg b/src/ui/icons/move.svg new file mode 100644 index 0000000..10c7919 --- /dev/null +++ b/src/ui/icons/move.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/ui/mmg-binding-display.cpp b/src/ui/mmg-binding-display.cpp deleted file mode 100644 index bbfa23a..0000000 --- a/src/ui/mmg-binding-display.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* -obs-midi-mg -Copyright (C) 2022-2023 nhielost - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see -*/ - -#include "mmg-binding-display.h" -#include "../mmg-settings.h" - -using namespace MMGUtils; - -void generateLabel(QWidget *parent, const QString &text) -{ - QLabel *label = new QLabel(parent); - label->setMinimumSize(150, 40); - label->setAlignment(Qt::AlignCenter); - label->setWordWrap(true); - label->setText(text); - parent->layout()->addWidget(label); -} - -template void generateContentsLabels(QWidget *parent, const QList &values) -{ - QLayoutItem *item; - while (!!(item = parent->layout()->takeAt(0))) { - delete item->widget(); - delete item; - } - - if (values.isEmpty()) { - generateLabel(parent, mmgtr("Actions.Titles.None")); - return; - } - - for (T *data : values) - generateLabel(parent, data->name()); -} - -MMGBindingDisplay::MMGBindingDisplay(QWidget *parent, bool executable) : QWidget(parent), _executable(executable) -{ - head_layout = new QVBoxLayout(this); - head_layout->setContentsMargins(20, 20, 20, 20); - head_layout->setSpacing(40); - head_layout->setSizeConstraint(QLayout::SetMinimumSize); - -#define CREATE_ROW(which, name, rgb, index) \ - which##s_widget = new QWidget(this); \ - which##s_widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding); \ - which##s_widget->setMinimumSize(351, 40); \ - which##s_widget->setMaximumSize(351, 16777215); \ - \ - QHBoxLayout *which##s_layout = new QHBoxLayout(which##s_widget); \ - which##s_layout->setContentsMargins(0, 0, 0, 0); \ - which##s_layout->setSpacing(15); \ - which##s_layout->setSizeConstraint(QLayout::SetMinimumSize); \ - \ - QPushButton *which##s_button = new QPushButton(which##s_widget); \ - which##s_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); \ - which##s_button->setFixedSize(40, 40); \ - which##s_button->setCursor(Qt::PointingHandCursor); \ - which##s_button->setStyleSheet("border: 1px solid " rgb ";"); \ - which##s_button->setIcon(QIcon(":/icons/edit.svg")); \ - which##s_button->setIconSize(QSize(20, 20)); \ - which##s_button->setProperty("page", index); \ - connect(which##s_button, &QPushButton::clicked, this, &MMGBindingDisplay::emitEdited); \ - which##s_layout->addWidget(which##s_button, 0, Qt::AlignTop); \ - \ - which##s_label = new QLabel(which##s_widget); \ - which##s_label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); \ - which##s_label->setFixedSize(90, 40); \ - which##s_label->setText(mmgtr(name)); \ - which##s_label->setWordWrap(true); \ - which##s_label->setMargin(5); \ - which##s_layout->addWidget(which##s_label, 0, Qt::AlignTop); \ - \ - current_##which##s = new QWidget(which##s_widget); \ - current_##which##s->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding); \ - current_##which##s->setMinimumSize(150, 40); \ - \ - QVBoxLayout *current_##which##s_layout = new QVBoxLayout(current_##which##s); \ - current_##which##s_layout->setContentsMargins(0, 0, 0, 0); \ - current_##which##s_layout->setSpacing(10); \ - current_##which##s_layout->setSizeConstraint(QLayout::SetMinimumSize); \ - \ - which##s_layout->addWidget(current_##which##s, 0, Qt::AlignCenter); \ - \ - head_layout->addWidget(which##s_widget) - - CREATE_ROW(device, "UI.Buttons.Devices", "rgb(0, 0, 255)", 1); - CREATE_ROW(message, "UI.Buttons.Messages", "rgb(0, 255, 0)", 2); - if (executable) { - CREATE_ROW(action, "UI.Buttons.Actions", "rgb(255, 0, 0)", 3); - CREATE_ROW(setting, "UI.Buttons.Preferences", "rgb(224, 224, 0)", 4); - } - -#undef CREATE_ROW -} - -void MMGBindingDisplay::setStorage(MMGBinding *binding) -{ - current_binding = binding; - display(); -} - -void MMGBindingDisplay::display() -{ - generateContentsLabels(current_devices, current_binding->usedDevices()); - generateContentsLabels(current_messages, current_binding->usedMessages()); - if (!_executable) return; - - generateContentsLabels(current_actions, current_binding->usedActions()); - - bool is_output = current_binding->type() == TYPE_OUTPUT; - head_layout->removeWidget(messages_widget); - head_layout->removeWidget(actions_widget); - - head_layout->insertWidget(1, is_output ? actions_widget : messages_widget); - head_layout->insertWidget(2, is_output ? messages_widget : actions_widget); - messages_label->setText(mmgtr(is_output ? "UI.Buttons.Messages" : "Message.Name")); - actions_label->setText(mmgtr(is_output ? "Actions.Name" : "UI.Buttons.Actions")); -} - -void MMGBindingDisplay::emitEdited() -{ - emit edited(sender()->property("page").toInt()); -} diff --git a/src/ui/mmg-binding-display.h b/src/ui/mmg-binding-display.h deleted file mode 100644 index a02efe5..0000000 --- a/src/ui/mmg-binding-display.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -obs-midi-mg -Copyright (C) 2022-2023 nhielost - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see -*/ - -#ifndef MMG_BINDING_DISPLAY_H -#define MMG_BINDING_DISPLAY_H - -#include "../mmg-binding.h" - -#include - -class MMGBindingDisplay : public QWidget { - Q_OBJECT - -public: - MMGBindingDisplay(QWidget *parent, bool executable); - - void setStorage(MMGBinding *binding); - void display(); - -signals: - void edited(int page); - -private slots: - void emitEdited(); - -private: - bool _executable = true; - MMGBinding *current_binding = nullptr; - - QVBoxLayout *head_layout; - - QWidget *devices_widget; - QWidget *messages_widget; - QWidget *actions_widget; - QWidget *settings_widget; - - QLabel *devices_label; - QLabel *messages_label; - QLabel *actions_label; - QLabel *settings_label; - - QWidget *current_devices; - QWidget *current_messages; - QWidget *current_actions; - QWidget *current_settings; -}; - -#endif // MMG_BINDING_DISPLAY_H diff --git a/src/ui/mmg-echo-window.cpp b/src/ui/mmg-echo-window.cpp index f71b354..8875a94 100644 --- a/src/ui/mmg-echo-window.cpp +++ b/src/ui/mmg-echo-window.cpp @@ -20,99 +20,38 @@ with this program. If not, see #include "../mmg-config.h" #include +#include #include #include #include using namespace MMGUtils; -#define MANAGER_SWITCH(_enum, macro) \ - switch (_enum) { \ - case 0: \ - macro(binding); \ - break; \ - case 1: \ - macro(device); \ - break; \ - case 2: \ - macro(message); \ - break; \ - case 3: \ - macro(action); \ - break; \ - case 4: \ - macro(preference); \ - break; \ - default: \ - break; \ +#define REFRESH_STRUCTURE(structure, _manager) \ + structure->clear(); \ + for (auto *val : *_manager) { \ + QListWidgetItem *new_item = new QListWidgetItem; \ + new_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | \ + (structure->property("editable").isNull() ? Qt::ItemIsEditable : Qt::NoItemFlags)); \ + new_item->setText(val->objectName()); \ + new_item->setData(260, QVariant::fromValue(val)); \ + structure->addItem(new_item); \ } +#define ITEM_DATA(type) item ? item->data(260).value() : nullptr + MMGEchoWindow::MMGEchoWindow(QWidget *parent) : QDialog(parent, Qt::Dialog), ui(new Ui::MMGEchoWindow) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); ui->setupUi(this); ui->label_version->setText(OBS_MIDIMG_VERSION); - type_display = new MMGStringDisplay(ui->message_frame); - type_display->setDisplayMode(MMGStringDisplay::MODE_NORMAL); - type_display->move(10, 10); - type_display->setDescription(mmgtr("Message.Type.Text")); - type_display->setBounds(MMGMessage::acceptedTypes()); - type_display->setOptions(MIDIBUTTON_MIDI | MIDIBUTTON_TOGGLE); - - channel_display = new MMGNumberDisplay(ui->message_frame); - channel_display->move(10, 120); - channel_display->setDescription(mmgtr("Message.Channel")); - channel_display->setBounds(1, 16); - channel_display->setOptions(MIDIBUTTON_MIDI | MIDIBUTTON_CUSTOM | MIDIBUTTON_TOGGLE); - - note_display = new MMGNumberDisplay(ui->message_frame); - note_display->move(10, 210); - note_display->setDescription(mmgtr("Message.Note")); - note_display->setBounds(0, 127); - note_display->setOptions(MIDIBUTTON_MIDI | MIDIBUTTON_CUSTOM | MIDIBUTTON_TOGGLE); - - value_display = new MMGNumberDisplay(ui->message_frame); - value_display->move(10, 300); - value_display->setDescription(mmgtr("Message.Velocity")); - value_display->setBounds(0, 127); - value_display->setOptions(MIDIBUTTON_MIDI | MIDIBUTTON_CUSTOM | MIDIBUTTON_TOGGLE); - value_display->lower(); - - main_binding_display = new MMGBindingDisplay(ui->binding_frame, true); - main_binding_display->setFixedSize(350, 320); - - devices_display = new MMGManagerDisplay(ui->device_page, manager(device)); - devices_display->setGeometry(10, 10, 341, 461); - devices_display->setItemsEditable(false); - - bindings_display = new MMGManagerDisplay(ui->binding_page, manager(binding)); - bindings_display->setGeometry(10, 10, 341, 461); - - messages_display = new MMGManagerDisplay(ui->message_page, manager(message)); - messages_display->setGeometry(10, 10, 341, 461); - - actions_display = new MMGManagerDisplay(ui->action_page, manager(action)); - actions_display->setGeometry(10, 10, 341, 461); - - preferences_display = new MMGManagerDisplay(ui->preferences_page, manager(setting)); - preferences_display->setGeometry(10, 10, 341, 461); - preferences_display->setItemsEditable(false); - - QButtonGroup *pages_button_group = new QButtonGroup(this); - pages_button_group->addButton(ui->button_binding_display, 0); - pages_button_group->addButton(ui->button_device_display, 1); - pages_button_group->addButton(ui->button_message_display, 2); - pages_button_group->addButton(ui->button_action_display, 3); - pages_button_group->addButton(ui->button_preferences, 4); - connect(pages_button_group, &QButtonGroup::idClicked, this, &MMGEchoWindow::onScreenChange); - - ui->button_confirm->setVisible(false); - ui->label_binding_selection_notice->setVisible(false); - ui->scroll_binding_contents->setWidget(main_binding_display); - ui->editor_binding_contents->setVisible(false); - - connect(midi(), &MMGMIDI::messageListened, this, &MMGEchoWindow::updateMessage); + menu_binding_groups = new QMenu(this); + menu_binding_groups->setTitle(mmgtr("UI.Buttons.Move")); + menu_binding_groups->setIcon(mmg_icon("move")); + + message_display = new MMGMessageDisplay(ui->message_frame); + message_display->move(10, 10); translate(); connectUISignals(); @@ -120,23 +59,21 @@ MMGEchoWindow::MMGEchoWindow(QWidget *parent) : QDialog(parent, Qt::Dialog), ui( void MMGEchoWindow::displayWindow() { - bindings_display->displayAll(); - devices_display->displayAll(); - messages_display->displayAll(); - actions_display->displayAll(); - preferences_display->displayAll(); - ui->button_binding_display->setChecked(true); - onScreenChange(0); + ui->pages->setCurrentIndex(0); + + ui->editor_device->setVisible(false); + + REFRESH_STRUCTURE(ui->structure_devices, manager(device)); + REFRESH_STRUCTURE(ui->structure_collections, manager(collection)); + collectionShow(); setVisible(true); } void MMGEchoWindow::reject() { - if (ui->button_listen_once->isChecked() || ui->button_listen_continuous->isChecked()) { - ui->button_listen_once->setChecked(false); - ui->button_listen_continuous->setChecked(false); - } + for (MMGDevice *device : *manager(device)) + emit device->messageListened(nullptr); config()->save(); @@ -145,66 +82,76 @@ void MMGEchoWindow::reject() void MMGEchoWindow::connectUISignals() { + // Collection Display Connections + connect(ui->structure_collections, &QListWidget::itemClicked, this, &MMGEchoWindow::collectionShow); + connect(ui->structure_collections, &QListWidget::itemChanged, this, &MMGEchoWindow::onCollectionRename); + connect(ui->structure_collections->model(), &QAbstractItemModel::rowsMoved, this, + &MMGEchoWindow::onCollectionMove); + connect(ui->button_add_collection, &QPushButton::clicked, this, &MMGEchoWindow::onCollectionAdd); + connect(ui->button_edit_collection, &QPushButton::clicked, this, &MMGEchoWindow::onCollectionEdit); + connect(ui->button_remove_collection, &QPushButton::clicked, this, &MMGEchoWindow::onCollectionRemove); + connect(ui->button_confirm, &QPushButton::clicked, this, &MMGEchoWindow::onCollectionConfirm); + // Device Display Connections - connect(devices_display, &MMGListWidget::selected, this, &MMGEchoWindow::deviceShow); + connect(midi(), &MMGMIDI::deviceCapableChange, this, + [&]() { REFRESH_STRUCTURE(ui->structure_devices, manager(device)); }); + connect(ui->structure_devices, &QListWidget::itemClicked, this, &MMGEchoWindow::deviceShow); connect(ui->button_in_enable, &QAbstractButton::toggled, this, &MMGEchoWindow::onDeviceInputActiveChange); connect(ui->button_thru, &QAbstractButton::toggled, this, &MMGEchoWindow::onDeviceThruStateChange); connect(ui->editor_thru, &QComboBox::currentTextChanged, this, &MMGEchoWindow::onDeviceThruChange); connect(ui->button_out_enable, &QAbstractButton::toggled, this, &MMGEchoWindow::onDeviceOutputActiveChange); + connect(ui->button_device_check, &QPushButton::clicked, this, &MMGEchoWindow::onDeviceCheck); + connect(ui->button_remove_device, &QPushButton::clicked, this, &MMGEchoWindow::onDeviceRemove); + + // Multipurpose Display Connections + connect(ui->structure_multi, &QListWidget::itemClicked, this, &MMGEchoWindow::multiShow); + connect(ui->structure_multi, &QListWidget::itemChanged, this, &MMGEchoWindow::onMultiRename); + connect(ui->structure_multi->model(), &QAbstractItemModel::rowsMoved, this, &MMGEchoWindow::onMultiMove); + connect(ui->editor_multi_select, &QComboBox::currentIndexChanged, this, &MMGEchoWindow::onMultiSelect); + connect(ui->button_multi_edit, &QPushButton::clicked, this, &MMGEchoWindow::onMultiClick); + connect(ui->button_add, &QPushButton::clicked, this, &MMGEchoWindow::onAddClick); + connect(ui->button_duplicate, &QPushButton::clicked, this, &MMGEchoWindow::onCopyClick); + connect(ui->button_move, &QPushButton::clicked, this, &MMGEchoWindow::onMoveClick); + connect(ui->button_remove, &QPushButton::clicked, this, &MMGEchoWindow::onRemoveClick); - // Message Display Connections - connect(messages_display, &MMGListWidget::selected, this, &MMGEchoWindow::messageShow); - connect(type_display, &MMGStringDisplay::stringChanged, this, &MMGEchoWindow::onMessageTypeChange); - connect(ui->button_listen_continuous, &QAbstractButton::toggled, this, &MMGEchoWindow::onListenContinuousClick); - connect(ui->button_listen_once, &QAbstractButton::toggled, this, &MMGEchoWindow::onListenOnceClick); + // Binding Display Connections + connect(ui->button_enable, &QAbstractButton::toggled, this, &MMGEchoWindow::onBindingActiveChange); + connect(ui->button_switch, &QAbstractButton::toggled, this, &MMGEchoWindow::onBindingSwitch); + connect(ui->editor_binding_reset, &QComboBox::currentIndexChanged, this, &MMGEchoWindow::onBindingResetChange); // Action Display Connections - connect(actions_display, &MMGListWidget::selected, this, &MMGEchoWindow::actionShow); connect(ui->editor_cat, &QComboBox::currentIndexChanged, this, &MMGEchoWindow::onActionCategoryChange); - connect(ui->button_action_switch, &QAbstractButton::toggled, this, &MMGEchoWindow::onActionSwitch); connect(ui->editor_sub, &QComboBox::currentIndexChanged, this, &MMGEchoWindow::onActionSubChange); - // Binding Display Connections - connect(bindings_display, &MMGListWidget::selected, this, &MMGEchoWindow::bindingShow); - connect(bindings_display, &MMGListWidget::itemMoved, manager(binding), &MMGBindingManager::resetConnections); - connect(ui->button_binding_enable, &QAbstractButton::toggled, this, &MMGEchoWindow::onBindingActiveChange); - connect(ui->button_binding_switch, &QAbstractButton::toggled, this, &MMGEchoWindow::onBindingSwitch); - connect(main_binding_display, &MMGBindingDisplay::edited, this, &MMGEchoWindow::onBindingFieldEdit); - // Preferences Connections - connect(preferences_display, &MMGListWidget::selected, this, &MMGEchoWindow::preferenceShow); - connect(ui->button_export, &QPushButton::clicked, this, &MMGEchoWindow::exportBindings); connect(ui->button_import, &QPushButton::clicked, this, &MMGEchoWindow::importBindings); connect(ui->button_help_advanced, &QPushButton::clicked, this, &MMGEchoWindow::openHelp); connect(ui->button_bug_report, &QPushButton::clicked, this, &MMGEchoWindow::reportBug); connect(ui->button_update_check, &QPushButton::clicked, this, &MMGEchoWindow::checkForUpdates); - - // Upper Button Connections - connect(ui->button_add, &QPushButton::clicked, this, &MMGEchoWindow::onAddClick); - connect(ui->button_duplicate, &QPushButton::clicked, this, &MMGEchoWindow::onCopyClick); - connect(ui->button_remove, &QPushButton::clicked, this, &MMGEchoWindow::onRemoveClick); - connect(ui->button_confirm, &QPushButton::clicked, this, &MMGEchoWindow::onConfirmClick); } void MMGEchoWindow::translate() { - ui->button_add->setToolTip(mmgtr("UI.Buttons.Create")); + ui->button_edit_collection->setToolTip(mmgtr("UI.Buttons.Edit")); + + ui->label_overview_header->setText(mmgtr("UI.Buttons.Collections")); + ui->label_device_header->setToolTip(mmgtr("UI.Buttons.Devices")); + ui->label_preferences_header->setToolTip(mmgtr("UI.Buttons.Preferences")); + + ui->button_confirm->setToolTip(mmgtr("UI.Buttons.Confirm")); + ui->button_add->setToolTip(mmgtr("UI.Buttons.New")); ui->button_duplicate->setToolTip(mmgtr("UI.Buttons.Copy")); ui->button_remove->setToolTip(mmgtr("UI.Buttons.Delete")); - ui->button_binding_display->setToolTip(mmgtr("UI.Buttons.Bindings")); - ui->button_device_display->setToolTip(mmgtr("UI.Buttons.Devices")); - ui->button_message_display->setToolTip(mmgtr("UI.Buttons.Messages")); - ui->button_action_display->setToolTip(mmgtr("UI.Buttons.Actions")); - ui->button_preferences->setToolTip(mmgtr("UI.Buttons.Preferences")); - - ui->label_binding_selection_notice->setText(mmgtr("UI.SelectionNotice")); + ui->button_enable->setToolTip(mmgtr("UI.Buttons.Enable")); + ui->button_switch->setToolTip(mmgtr("UI.Buttons.Switch")); + ui->button_move->setToolTip(mmgtr("UI.Buttons.Move")); + ui->label_binding_reset->setText(mmgtr("Binding.Reset")); + ui->editor_binding_reset->addItems(mmgtr_all("Binding.Reset", {"Triggered", "Continuous"})); ui->label_thru->setText(mmgtr("Device.Thru.Label")); - - ui->button_listen_once->setText(mmgtr("UI.Listen.Once")); - ui->button_listen_continuous->setText(mmgtr("UI.Listen.Continuous")); + ui->button_device_check->setText(mmgtr("Device.Check.Label")); ui->label_cat->setText(mmgtr("Actions.Category")); ui->label_sub->setText(mmgtr("Actions.Name")); @@ -214,8 +161,6 @@ void MMGEchoWindow::translate() "StudioMode", "Scenes", "VideoSources", "AudioSources", "MediaSources", "Transitions", "Filters", "Hotkeys", "Profiles", "Collections", "MIDI"})); - ui->label_device_edit->setText(mmgtr("UI.Buttons.Devices")); - ui->button_export->setToolTip(mmgtr("UI.Buttons.Export")); ui->button_import->setToolTip(mmgtr("UI.Buttons.Import")); ui->button_help_advanced->setToolTip(mmgtr("UI.Buttons.Help")); @@ -224,112 +169,102 @@ void MMGEchoWindow::translate() ui->button_update_check->setText(mmgtr("Preferences.Updates")); } -void MMGEchoWindow::onAddClick() +int MMGEchoWindow::multiIndex(DeviceType type) const { -#define ON_ADD(which) which##s_display->addNew() - MANAGER_SWITCH(ui->pages->currentIndex(), ON_ADD); -#undef ON_ADD + if (ui->editor_multi_select->signalsBlocked()) return 0; + if (current_binding->type() == type) return 0; + return ui->editor_multi_select->currentIndex(); } -void MMGEchoWindow::onCopyClick() +void MMGEchoWindow::collectionShow(QListWidgetItem *item) { -#define ON_COPY(which) which##s_display->copy() - MANAGER_SWITCH(ui->pages->currentIndex(), ON_COPY); -#undef ON_COPY -} + current_manager = ITEM_DATA(MMGBindingManager); -void MMGEchoWindow::onRemoveClick() -{ - if (!open_message_box("PermanentRemove", false)) return; + ui->editor_secondary_collection_buttons->setVisible(!!current_manager); + if (!!current_manager) { + QString size_str = " "; + qsizetype size = current_manager->size(); + size_str.prepend(QString::number(size)); + size_str.append(mmgtr_two("Binding", "Name", "Names", size < 2)); + ui->label_collection_size->setText(size_str); + } + + menu_binding_groups->clear(); + for (MMGBindingManager *manager : *manager(collection)) { + if (manager == current_manager) continue; -#define ON_REMOVE(which) which##s_display->remove() - MANAGER_SWITCH(ui->pages->currentIndex(), ON_REMOVE); -#undef ON_REMOVE + QAction *new_action = new QAction(this); + new_action->setText(manager->objectName()); + new_action->setData(QVariant::fromValue(manager)); + connect(new_action, &QAction::triggered, this, &MMGEchoWindow::onMoveSelect); + menu_binding_groups->addAction(new_action); + } } -void MMGEchoWindow::onConfirmClick() +void MMGEchoWindow::onCollectionRename(QListWidgetItem *item) { - binding_edit = false; - ui->button_confirm->setVisible(false); - ui->label_binding_selection_notice->setVisible(false); - - ui->button_add->setEnabled(true); - ui->button_binding_display->setEnabled(true); - ui->button_device_display->setEnabled(true); - ui->button_message_display->setEnabled(true); - ui->button_action_display->setEnabled(true); - ui->button_preferences->setEnabled(true); + if (!item) return; + current_manager->setObjectName(item->text()); +} - switch (ui->pages->currentIndex()) { - case 1: - current_binding->setUsedDevices(devices_display->selectedValues()); - devices_display->setSelectionMode(QAbstractItemView::SingleSelection); - devices_display->setFilterType(TYPE_NONE); - devices_display->displayAll(); - break; +void MMGEchoWindow::onCollectionMove(const QModelIndex &, int from, int, const QModelIndex &, int to) +{ + manager(collection)->move(from, to); +} - case 2: - current_binding->setUsedMessages(messages_display->selectedValues()); - messages_display->setSelectionMode(QAbstractItemView::SingleSelection); - messages_display->setFilterType(TYPE_NONE); - messages_display->setItemsEditable(true); - break; +void MMGEchoWindow::onCollectionAdd() +{ + manager(collection)->add(); + REFRESH_STRUCTURE(ui->structure_collections, manager(collection)); +} - case 3: - current_binding->setUsedActions(actions_display->selectedValues()); - actions_display->setSelectionMode(QAbstractItemView::SingleSelection); - actions_display->setFilterType(TYPE_NONE); - actions_display->setItemsEditable(true); - break; +void MMGEchoWindow::onCollectionEdit() +{ + int index = ui->pages->currentIndex() ^ 1; + ui->pages->setCurrentIndex(index); - case 4: - preferences_display->setFilterType(TYPE_NONE); - preferences_display->displayAll(); - break; + if (index == 1) { + REFRESH_STRUCTURE(ui->structure_multi, current_manager); + multiShow(); + } else { + ui->structure_collections->clearSelection(); + ui->structure_devices->clearSelection(); + collectionShow(); + deviceShow(); + } +} +void MMGEchoWindow::onCollectionConfirm() +{ + switch (multi_mode) { + case MODE_BINDING: default: + onCollectionEdit(); break; - } - if (!manager(binding)->list().contains(current_binding)) { - // Action Request Binding (those are not registered in the manager) - ui->button_action_display->click(); - current_binding = nullptr; - } else { - // Normal Binding Access - ui->button_binding_display->click(); + case MODE_ACTION: + case MODE_MESSAGE: + multi_mode = MODE_BINDING; + onMultiChange(); + break; } } -void MMGEchoWindow::onScreenChange(int page) +void MMGEchoWindow::onCollectionRemove() { - ui->pages->setCurrentIndex(page); - ui->button_add->setEnabled(true); - ui->button_duplicate->setEnabled(false); - ui->button_remove->setEnabled(false); - QString name; - -#define ON_TYPE_SET(which) \ - which##Show(); \ - name = #which - MANAGER_SWITCH(page, ON_TYPE_SET); -#undef ON_TYPE_SET - - if (binding_edit) return; - name[0] = name[0].toUpper(); - name = QString("UI.Buttons.%1s").arg(name); - ui->label_header->setText(mmgtr(name.qtocs())); + if (!current_manager) return; + if (!open_message_box("PermanentRemove", false)) return; + manager(collection)->remove(current_manager); + current_manager = nullptr; + REFRESH_STRUCTURE(ui->structure_collections, manager(collection)); + collectionShow(nullptr); } -void MMGEchoWindow::deviceShow() +void MMGEchoWindow::deviceShow(QListWidgetItem *item) { - ui->button_add->setEnabled(false); - ui->button_duplicate->setEnabled(false); - ui->button_remove->setEnabled(false); - - current_device = devices_display->currentValue(); - ui->device_frame->setVisible(!!current_device && !binding_edit); - if (!current_device || binding_edit) return; + current_device = item ? item->data(260).value() : nullptr; + ui->editor_device->setVisible(!!current_device); + if (!current_device) return; MMGNoEdit no_edit_device(current_device); QSignalBlocker blocker_in_enable(ui->button_in_enable); @@ -341,29 +276,20 @@ void MMGEchoWindow::deviceShow() ui->button_in_enable->setChecked(current_device->isActive(TYPE_INPUT)); onDeviceInputActiveChange(current_device->isActive(TYPE_INPUT)); + ui->button_out_enable->setEnabled(current_device->isCapable(TYPE_OUTPUT)); + ui->button_out_enable->setChecked(current_device->isActive(TYPE_OUTPUT)); + onDeviceOutputActiveChange(current_device->isActive(TYPE_OUTPUT)); + ui->editor_thru->clear(); for (MMGDevice *device : *manager(device)) - if (device->isCapable(TYPE_OUTPUT)) ui->editor_thru->addItem(device->name()); + if (device->isCapable(TYPE_OUTPUT)) ui->editor_thru->addItem(device->objectName()); bool thru_enabled = current_device->isActive(TYPE_INPUT) && !current_device->thru().isEmpty(); ui->button_thru->setChecked(thru_enabled); onDeviceThruStateChange(thru_enabled); ui->editor_thru->setCurrentText(current_device->thru()); - ui->button_out_enable->setEnabled(current_device->isCapable(TYPE_OUTPUT)); - ui->button_out_enable->setChecked(current_device->isActive(TYPE_OUTPUT)); - onDeviceOutputActiveChange(current_device->isActive(TYPE_OUTPUT)); -} - -void MMGEchoWindow::deviceBindingEdit() -{ - ui->label_header->setText(QString(mmgtr("UI.Select")).arg(mmgtr("Device.Name"))); - - devices_display->setSelectionMode(QAbstractItemView::ExtendedSelection); - devices_display->setFilterType(current_binding->type()); - devices_display->displayAll(); - - devices_display->selectValues(current_binding->usedDevices()); + ui->button_remove_device->setVisible(!current_device->isCapable(TYPE_NONE)); } void MMGEchoWindow::onDeviceInputActiveChange(bool toggled) @@ -373,9 +299,8 @@ void MMGEchoWindow::onDeviceInputActiveChange(bool toggled) ui->button_in_enable->setChecked(toggled); ui->label_in_connect->setText(current_device->status(TYPE_INPUT)); - ui->button_thru->setVisible(toggled); - ui->label_thru->setVisible(toggled); - ui->editor_thru->setVisible(toggled && ui->button_thru->isChecked()); + ui->editor_device_thru->setVisible(toggled); + ui->editor_thru->setVisible(ui->button_thru->isChecked()); } void MMGEchoWindow::onDeviceOutputActiveChange(bool toggled) @@ -388,7 +313,6 @@ void MMGEchoWindow::onDeviceOutputActiveChange(bool toggled) void MMGEchoWindow::onDeviceThruStateChange(bool toggled) { - ui->button_thru->setIcon(QIcon(QString(":/icons/toggle-%1.svg").arg(toggled ? "on" : "off"))); ui->editor_thru->setVisible(toggled); if (ui->editor_thru->signalsBlocked()) return; @@ -400,256 +324,350 @@ void MMGEchoWindow::onDeviceThruChange(const QString &device) current_device->setThru(device); } -void MMGEchoWindow::messageShow() +void MMGEchoWindow::onDeviceCheck() { - current_message = messages_display->currentValue(); - bool enable_frame = !!current_message && !binding_edit; - ui->message_frame->setVisible(enable_frame); - ui->button_duplicate->setEnabled(enable_frame); - ui->button_remove->setEnabled(enable_frame); - if (!enable_frame) return; + current_device->checkCapable(); + deviceShow(ui->structure_devices->currentItem()); + open_message_box("DeviceCheck"); +} - MMGNoEdit no_edit_message(current_message); +void MMGEchoWindow::onDeviceRemove() +{ + if (!open_message_box("DeviceRemove", false)) return; - type_display->setStorage(¤t_message->type()); - channel_display->setStorage(¤t_message->channel()); - note_display->setStorage(¤t_message->note()); - value_display->setStorage(¤t_message->value()); - onMessageTypeChange(); + manager(device)->remove(current_device); + REFRESH_STRUCTURE(ui->structure_devices, manager(device)); + deviceShow(nullptr); } -void MMGEchoWindow::messageBindingEdit() +void MMGEchoWindow::multiShow(QListWidgetItem *item) { - ui->label_header->setText(QString(mmgtr("UI.Select")).arg(mmgtr("Message.Name"))); + ui->editor_secondary_buttons->setVisible(!!item); + ui->label_binding_name->setVisible(!!item); - messages_display->setSelectionMode(current_binding->type() == TYPE_OUTPUT ? QAbstractItemView::ExtendedSelection - : QAbstractItemView::SingleSelection); - messages_display->setFilterType(current_binding->type()); - messages_display->displayAll(); + switch (multi_mode) { + case MODE_BINDING: + default: + bindingShow(item); + ui->button_move->setVisible(!menu_binding_groups->isEmpty()); + ui->button_remove->setVisible(current_manager->size() > 1); + break; - messages_display->selectValues(current_binding->usedMessages()); -} + case MODE_ACTION: + actionShow(item); + ui->button_move->setVisible(false); + ui->button_remove->setVisible(current_binding->actions()->size() > 1); + break; -void MMGEchoWindow::onMessageTypeChange() -{ - set_message_labels(current_message->type(), note_display, value_display); + case MODE_MESSAGE: + messageShow(item); + ui->button_move->setVisible(false); + ui->button_remove->setVisible(current_binding->messages()->size() > 1); + break; + } } -void MMGEchoWindow::onListenOnceClick(bool toggled) +void MMGEchoWindow::onMultiRename(QListWidgetItem *item) { - ui->button_listen_once->setText(mmgtr_two("UI.Listen", "Cancel", "Once", toggled)); - if (listening_mode == 2) { - QSignalBlocker blocker_continuous(ui->button_listen_continuous); - ui->button_listen_continuous->setChecked(false); - ui->button_listen_continuous->setText(mmgtr("UI.Listen.Continuous")); + if (!item) return; + + switch (multi_mode) { + case MODE_BINDING: + default: + current_binding->setObjectName(item->text()); + break; + + case MODE_ACTION: + current_action->setObjectName(item->text()); + break; + + case MODE_MESSAGE: + current_message->setObjectName(item->text()); + break; } - midi()->setListening(toggled); - listening_mode = toggled; - global_blog(LOG_DEBUG, toggled ? "Single listen activated." : "Listening deactivated."); + ui->label_binding_name->setText(item->text()); } -void MMGEchoWindow::onListenContinuousClick(bool toggled) +void MMGEchoWindow::onMultiMove(const QModelIndex &, int from, int, const QModelIndex &, int to) { - ui->button_listen_continuous->setText(mmgtr_two("UI.Listen", "Cancel", "Continuous", toggled)); - if (listening_mode == 1) { - QSignalBlocker blocker_once(ui->button_listen_once); - ui->button_listen_once->setChecked(false); - ui->button_listen_once->setText(mmgtr("UI.Listen.Once")); - } - midi()->setListening(toggled); - listening_mode = toggled ? 2 : 0; - global_blog(LOG_DEBUG, toggled ? "Continuous listen activated." : "Listening deactivated."); -} - -void MMGEchoWindow::updateMessage(const MMGSharedMessage &incoming) -{ - if (!incoming) return; - if (listening_mode < 1) return; - // Check the validity of the message type (whether it is one of the five - // supported types) - if (MMGMessage::acceptedTypes().indexOf(incoming->type()) == -1) return; - if (listening_mode == 1) { - ui->button_listen_once->setText(mmgtr("UI.Listen.Once")); - ui->button_listen_once->setChecked(false); - midi()->setListening(false); + switch (multi_mode) { + case MODE_BINDING: + default: + current_manager->move(from, to); + break; + + case MODE_ACTION: + current_binding->actions()->move(from, to); + break; + + case MODE_MESSAGE: + current_binding->messages()->move(from, to); + break; } - current_message = messages_display->currentValue(); - QString name = current_message->name(); +} - incoming->copy(current_message); - current_message->setName(name); - current_message->value().setMax(127); +void MMGEchoWindow::onMultiSelect(int) +{ + if (!current_binding) return; messageShow(); + actionShow(); } -void MMGEchoWindow::actionShow() +void MMGEchoWindow::onMultiClick() { - current_action = actions_display->currentValue(); - bool enable_frame = !!current_action && !binding_edit; - ui->action_frame->setVisible(enable_frame); - ui->button_duplicate->setEnabled(enable_frame); - ui->button_remove->setEnabled(enable_frame); - if (!enable_frame) return; + multi_mode = current_binding->type() == TYPE_OUTPUT ? MODE_MESSAGE : MODE_ACTION; + onMultiChange(); +} - MMGNoEdit no_edit_action(current_action); - QSignalBlocker blocker_switch(ui->button_action_switch); - QSignalBlocker blocker_cat(ui->editor_cat); - QSignalBlocker blocker_sub(ui->editor_sub); +void MMGEchoWindow::onMultiChange() +{ + MMGBinding *binding = current_binding; + bindingShow(); + current_binding = binding; + ui->editor_secondary_buttons->setVisible(false); + ui->label_binding_name->setVisible(false); - ui->editor_cat->setCurrentIndex((int)current_action->category()); + switch (multi_mode) { + case MODE_BINDING: + default: + REFRESH_STRUCTURE(ui->structure_multi, current_manager); + break; - ui->button_action_switch->setChecked((bool)current_action->type()); - onActionSwitch((bool)current_action->type()); + case MODE_ACTION: + REFRESH_STRUCTURE(ui->structure_multi, current_binding->actions()); + break; - ui->editor_sub->setCurrentIndex(current_action->sub()); - onActionSubChange(current_action->sub()); + case MODE_MESSAGE: + REFRESH_STRUCTURE(ui->structure_multi, current_binding->messages()); + break; + } } -void MMGEchoWindow::actionBindingEdit() +void MMGEchoWindow::onAddClick() { - ui->label_header->setText(QString(mmgtr("UI.Select")).arg(mmgtr("Actions.Name"))); + switch (multi_mode) { + case MODE_BINDING: + default: + current_manager->add(); + REFRESH_STRUCTURE(ui->structure_multi, current_manager); + break; - actions_display->setSelectionMode(current_binding->type() == TYPE_INPUT ? QAbstractItemView::ExtendedSelection - : QAbstractItemView::SingleSelection); - actions_display->setFilterType(current_binding->type()); - actions_display->displayAll(); + case MODE_ACTION: + current_binding->actions()->add(); + REFRESH_STRUCTURE(ui->structure_multi, current_binding->actions()); + break; - actions_display->selectValues(current_binding->usedActions()); + case MODE_MESSAGE: + current_binding->messages()->add(); + REFRESH_STRUCTURE(ui->structure_multi, current_binding->messages()); + break; + } } -void MMGEchoWindow::onActionCategoryChange(int index) +void MMGEchoWindow::onCopyClick() { - QJsonObject json_obj; - json_obj["category"] = index; - manager(action)->changeActionCategory(current_action, json_obj); - actions_display->updateData(); - - onActionSubUpdate(); -} + if (!current_binding) return; -void MMGEchoWindow::onActionSwitch(bool toggled) -{ - if (!ui->button_action_switch->signalsBlocked()) { - QSignalBlocker blocker_action_switch(ui->button_action_switch); - ui->button_action_switch->setChecked(!toggled); - if (!open_message_box("ActionSwitch", false)) return; - ui->button_action_switch->setChecked(toggled); - } + switch (multi_mode) { + case MODE_BINDING: + default: + current_manager->copy(current_binding); + REFRESH_STRUCTURE(ui->structure_multi, current_manager); + break; - current_action->setType((DeviceType)toggled); - ui->button_action_switch->setIcon(QIcon(toggled ? ":/icons/switch-out.svg" : ":/icons/switch-in.svg")); + case MODE_ACTION: + current_binding->actions()->copy(current_action); + REFRESH_STRUCTURE(ui->structure_multi, current_binding->actions()); + break; - onActionSubUpdate(); + case MODE_MESSAGE: + current_binding->messages()->copy(current_message); + REFRESH_STRUCTURE(ui->structure_multi, current_binding->messages()); + break; + } } -void MMGEchoWindow::onActionSubUpdate() +void MMGEchoWindow::onMoveClick() { - ui->editor_sub->clear(); - current_action->setComboOptions(ui->editor_sub); + if (menu_binding_groups->isEmpty()) return; + menu_binding_groups->popup(QCursor::pos()); } -void MMGEchoWindow::onActionSubChange(int index) +void MMGEchoWindow::onMoveSelect() { - if (index < 0) return; + if (!sender()) return; - current_action->setSub(index); + auto action = qobject_cast(sender()); + if (!action) return; - if (!current_action->display()) { - current_action->createDisplay(ui->action_display_editor); - connect(current_action->display(), &MMGActionDisplay::editRequest, this, - &MMGEchoWindow::onActionEditRequest); - ui->action_display_editor->addWidget(current_action->display()); - } + MMGBindingManager *manager = action->data().value(); + MMGBinding *moved_binding = manager->add(); + current_binding->copy(moved_binding); + current_manager->remove(current_binding); - current_action->display()->setParent(ui->action_display_editor); - current_action->setActionParams(); - ui->action_display_editor->setCurrentWidget(current_action->display()); + REFRESH_STRUCTURE(ui->structure_multi, current_manager); + bindingShow(); } -void MMGEchoWindow::onActionEditRequest(MMGBinding *binding, int page) +void MMGEchoWindow::onRemoveClick() { - if (!sender() || !binding) return; + if (!current_binding) return; + if (!open_message_box("PermanentRemove", false)) return; - current_binding = binding; - onBindingFieldEdit(page); + switch (multi_mode) { + case MODE_BINDING: + default: + current_manager->remove(current_binding); + current_binding = nullptr; + REFRESH_STRUCTURE(ui->structure_multi, current_manager); + break; + + case MODE_ACTION: + current_binding->actions()->remove(current_action); + current_action = nullptr; + REFRESH_STRUCTURE(ui->structure_multi, current_binding->actions()); + break; + + case MODE_MESSAGE: + current_binding->messages()->remove(current_message); + current_message = nullptr; + REFRESH_STRUCTURE(ui->structure_multi, current_binding->messages()); + break; + } + + multiShow(); } -void MMGEchoWindow::bindingShow() +void MMGEchoWindow::bindingShow(QListWidgetItem *item) { - current_binding = bindings_display->currentValue(); - ui->binding_frame->setVisible(!!current_binding); - ui->button_duplicate->setEnabled(!!current_binding); - ui->button_remove->setEnabled(!!current_binding); + current_binding = ITEM_DATA(MMGBinding); + + ui->editor_binding->setVisible(!!current_binding); + ui->editor_multi_access->setVisible(!!current_binding); + + QSignalBlocker blocker_enable(ui->button_enable); + QSignalBlocker blocker_switch(ui->button_switch); + QSignalBlocker blocker_binding_reset(ui->editor_binding_reset); + QSignalBlocker blocker_multi_select(ui->editor_multi_select); + + messageShow(); + actionShow(); + if (!current_binding) return; - QSignalBlocker blocker_binding_enable(ui->button_binding_enable); - QSignalBlocker blocker_binding_switch(ui->button_binding_switch); - main_binding_display->setStorage(current_binding); + ui->label_binding_name->setText(current_binding->objectName()); + bool is_output = current_binding->type() == TYPE_OUTPUT; + ui->message_frame->move(is_output ? 720 : 360, 60); + ui->action_frame->move(is_output ? 360 : 720, 60); - ui->button_binding_enable->setChecked(current_binding->enabled()); + ui->button_enable->setChecked(current_binding->enabled()); onBindingActiveChange(current_binding->enabled()); - ui->button_binding_switch->setChecked((bool)current_binding->type()); + ui->button_switch->setChecked((bool)current_binding->type()); onBindingSwitch((bool)current_binding->type()); + + ui->editor_binding_reset->setCurrentIndex((int)current_binding->resetMode()); + onBindingResetChange((int)current_binding->resetMode()); + + ui->editor_multi_select->clear(); + ui->editor_multi_select->addItems(is_output ? current_binding->messages()->names() + : current_binding->actions()->names()); } void MMGEchoWindow::onBindingActiveChange(bool toggled) { current_binding->setEnabled(toggled); - ui->label_binding_enable->setText(mmgtr_two("Plugin", "Enabled", "Disabled", toggled)); } void MMGEchoWindow::onBindingSwitch(bool toggled) { - if (!ui->button_binding_switch->signalsBlocked()) { - QSignalBlocker blocker_binding_switch(ui->button_binding_switch); - ui->button_binding_switch->setChecked(!toggled); + if (!ui->button_switch->signalsBlocked()) { + QSignalBlocker blocker_switch(ui->button_switch); + ui->button_switch->setChecked(!toggled); if (!open_message_box("BindingSwitch", false)) return; + ui->button_switch->setChecked(toggled); } - ui->label_binding_switch->setText(mmgtr_two("Binding", "Output", "Input", toggled)); - ui->button_binding_switch->setIcon(QIcon(toggled ? ":/icons/switch-out.svg" : ":/icons/switch-in.svg")); - - if (ui->button_binding_switch->signalsBlocked()) return; + if (ui->button_switch->signalsBlocked()) return; current_binding->setType((DeviceType)toggled); - bindings_display->updateData(); - bindingShow(); + bindingShow(ui->structure_multi->currentItem()); } -void MMGEchoWindow::onBindingFieldEdit(int page) +void MMGEchoWindow::onBindingResetChange(int index) { - if (page < 1) return; + current_binding->setResetMode(index); +} - ui->button_confirm->setVisible(true); - ui->label_binding_selection_notice->setVisible(true); +void MMGEchoWindow::messageShow(QListWidgetItem *item) +{ + current_message = ITEM_DATA(MMGMessage); + if (current_binding && !current_message) current_message = current_binding->messages(multiIndex(TYPE_INPUT)); - ui->button_binding_display->setEnabled(false); - ui->button_device_display->setEnabled(false); - ui->button_message_display->setEnabled(false); - ui->button_action_display->setEnabled(false); - ui->button_preferences->setEnabled(false); + ui->message_frame->setVisible(!!current_message); + if (!current_message) return; - binding_edit = true; + if (multi_mode == MODE_MESSAGE) ui->label_binding_name->setText(current_message->objectName()); -#define ON_BINDING_EDIT(which) \ - which##s_display->setItemsEditable(false); \ - which##BindingEdit() - MANAGER_SWITCH(page, ON_BINDING_EDIT); -#undef ON_BINDING_EDIT + MMGNoEdit no_edit_message(current_message); + message_display->setStorage(current_message); +} + +void MMGEchoWindow::actionShow(QListWidgetItem *item) +{ + current_action = ITEM_DATA(MMGAction); + if (current_binding && !current_action) current_action = current_binding->actions(multiIndex(TYPE_OUTPUT)); + + ui->action_frame->setVisible(!!current_binding); + if (!current_action) return; + + if (multi_mode == MODE_ACTION) ui->label_binding_name->setText(current_action->objectName()); + + MMGNoEdit no_edit_action(current_action); + QSignalBlocker blocker_cat(ui->editor_cat); + QSignalBlocker blocker_sub(ui->editor_sub); - onScreenChange(page); + ui->editor_cat->setCurrentIndex((int)current_action->category()); + onActionSubUpdate(); - ui->button_add->setEnabled(false); - ui->button_duplicate->setEnabled(false); - ui->button_remove->setEnabled(false); + ui->editor_sub->setCurrentIndex(current_action->sub()); + onActionSubChange(current_action->sub()); } -void MMGEchoWindow::preferenceShow() +void MMGEchoWindow::onActionCategoryChange(int index) +{ + QJsonObject json_obj; + json_obj["category"] = index; + current_binding->actions()->changeActionCategory(current_action, json_obj); + if (multi_mode == MODE_ACTION) { REFRESH_STRUCTURE(ui->structure_multi, current_binding->actions()); } + + onActionSubUpdate(); +} + +void MMGEchoWindow::onActionSubUpdate() { - ui->button_add->setEnabled(false); + ui->editor_sub->clear(); + current_action->setComboOptions(ui->editor_sub); +} + +void MMGEchoWindow::onActionSubChange(int index) +{ + if (index < 0) return; + + current_action->setSub(index); + + if (!current_action->display()) { + current_action->createDisplay(ui->editor_action_display); + ui->editor_action_display->addWidget(current_action->display()); + } - MMGSettings *current_settings = binding_edit ? current_binding->settings() + ui->editor_action_display->setCurrentWidget(current_action->display()); + current_action->setActionParams(); +} + +void MMGEchoWindow::preferenceShow() +{ + /*MMGSettings *current_settings = binding_edit ? current_binding->settings() : preferences_display->currentValue(); ui->preferences_frame->setVisible(!!current_settings); if (!current_settings) return; @@ -658,24 +676,12 @@ void MMGEchoWindow::preferenceShow() if (!current_settings->display()) current_settings->createDisplay(this); ui->scroll_preferences->takeWidget(); - ui->scroll_preferences->setWidget(current_settings->display()); -} - -void MMGEchoWindow::preferenceBindingEdit() -{ - ui->label_binding_selection_notice->setVisible(false); - - ui->label_header->setText(mmgtr("Preferences.Binding.Header")); - - preferences_display->setFilterType(current_binding->type()); - preferences_display->displayAll(); - - preferenceShow(); + ui->scroll_preferences->setWidget(current_settings->display());*/ } void MMGEchoWindow::exportBindings() { - QString filepath = QFileDialog::getSaveFileName(this, mmgtr("UI.Filesystem.ExportTitle"), MMGConfig::filepath(), + QString filepath = QFileDialog::getSaveFileName(this, mmgtr("UI.Filesystem.ExportTitle"), MMGConfig::filename(), mmgtr("UI.Filesystem.FileType")); if (!filepath.isNull()) config()->save(filepath); } diff --git a/src/ui/mmg-echo-window.h b/src/ui/mmg-echo-window.h index 1c526cd..e3734e5 100644 --- a/src/ui/mmg-echo-window.h +++ b/src/ui/mmg-echo-window.h @@ -10,14 +10,12 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ + #pragma once #include #include "ui_mmg-echo-window.h" -#include "mmg-number-display.h" -#include "mmg-string-display.h" -#include "mmg-binding-display.h" -#include "mmg-manager-display.h" +#include "mmg-message-display.h" #include "../mmg-device.h" class MMGEchoWindow : public QDialog { @@ -27,74 +25,74 @@ class MMGEchoWindow : public QDialog { explicit MMGEchoWindow(QWidget *parent); ~MMGEchoWindow() override; + enum MultiMode { MODE_BINDING, MODE_ACTION, MODE_MESSAGE }; + private: Ui::MMGEchoWindow *ui; - MMGBindingDisplay *main_binding_display; - - MMGStringDisplay *type_display; - MMGNumberDisplay *channel_display; - MMGNumberDisplay *note_display; - MMGNumberDisplay *value_display; + QMenu *menu_binding_groups; - MMGManagerDisplay *devices_display; - MMGManagerDisplay *bindings_display; - MMGManagerDisplay *messages_display; - MMGManagerDisplay *actions_display; - MMGManagerDisplay *preferences_display; + MMGMessageDisplay *message_display; + MMGBindingManager *current_manager = nullptr; MMGDevice *current_device = nullptr; + MMGBinding *current_binding = nullptr; MMGMessage *current_message = nullptr; MMGAction *current_action = nullptr; - - short listening_mode = 0; - bool binding_edit = false; + MultiMode multi_mode = MODE_BINDING; void reject() override; void connectUISignals(); void translate(); + int multiIndex(MMGUtils::DeviceType) const; + public slots: void displayWindow(); - void updateMessage(const MMGSharedMessage &); private slots: - void onAddClick(); - void onCopyClick(); - void onRemoveClick(); - void onConfirmClick(); - void onScreenChange(int page); - - void deviceShow(); - void deviceBindingEdit(); + void collectionShow(QListWidgetItem *item = nullptr); + void onCollectionRename(QListWidgetItem *item); + void onCollectionMove(const QModelIndex &, int from, int, const QModelIndex &, int to); + void onCollectionAdd(); + void onCollectionEdit(); + void onCollectionConfirm(); + void onCollectionRemove(); + + void deviceShow(QListWidgetItem *item = nullptr); void onDeviceInputActiveChange(bool toggled); void onDeviceOutputActiveChange(bool toggled); void onDeviceThruStateChange(bool toggled); void onDeviceThruChange(const QString &device); + void onDeviceCheck(); + void onDeviceRemove(); + + void multiShow(QListWidgetItem *item = nullptr); + void onMultiRename(QListWidgetItem *item); + void onMultiMove(const QModelIndex &, int from, int, const QModelIndex &, int to); + void onMultiSelect(int); + void onMultiClick(); + void onMultiChange(); + void onAddClick(); + void onCopyClick(); + void onMoveClick(); + void onMoveSelect(); + void onRemoveClick(); - void messageShow(); - void messageBindingEdit(); - void onMessageTypeChange(); - void onListenOnceClick(bool toggled); - void onListenContinuousClick(bool toggled); + void bindingShow(QListWidgetItem *item = nullptr); + void onBindingActiveChange(bool toggled); + void onBindingSwitch(bool toggled); + void onBindingResetChange(int index); - void actionShow(); - void actionBindingEdit(); + void messageShow(QListWidgetItem *item = nullptr); + + void actionShow(QListWidgetItem *item = nullptr); void onActionCategoryChange(int index); - void onActionSwitch(bool toggled); void onActionSubUpdate(); void onActionSubChange(int index); - void onActionEditRequest(MMGBinding *binding, int page); - - void bindingShow(); - void bindingBindingEdit(){}; - void onBindingActiveChange(bool toggled); - void onBindingSwitch(bool toggled); - void onBindingFieldEdit(int page); void preferenceShow(); - void preferenceBindingEdit(); void exportBindings(); void importBindings(); void openHelp() const; diff --git a/src/ui/mmg-echo-window.ui b/src/ui/mmg-echo-window.ui index c212c2f..09f7d78 100644 --- a/src/ui/mmg-echo-window.ui +++ b/src/ui/mmg-echo-window.ui @@ -9,7 +9,7 @@ 0 0 - 720 + 1080 530 @@ -21,14 +21,14 @@ - 720 - 530 + 0 + 0 - 720 - 530 + 5000 + 5000 @@ -53,9 +53,9 @@ 0 - 50 - 721 - 481 + 0 + 1081 + 581 @@ -77,34 +77,41 @@ 10 + + Qt::ClickFocus + + + #pages > QWidget > QFrame { + border-radius: 4px; +} + 0 0 - - - - - - - - - + + - 360 - 10 + 720 + 60 351 461 + + Qt::ClickFocus + false - border-color: rgb(255, 255, 255); + #preferences_frame { + border-color: rgb(224, 224, 0); + background-color: rgba(224, 224, 0, 7%); +} QFrame::StyledPanel @@ -118,35 +125,58 @@ 2 - - - true + + + + 10 + 410 + 151 + 41 + + + + + Tahoma + 9 + + + + Made by nhielost + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + - 20 - 20 - 40 - 40 + 280 + 410 + 61 + 41 - - - 0 - 0 - + + + Tahoma + 9 + - - - 40 - 40 - + + v1.0.0 - - - 40 - 40 - + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 360 + 41 + 41 + @@ -157,29 +187,29 @@ PointingHandCursor + + Qt::StrongFocus + + + + - :/icons/activate.svg:/icons/activate.svg + :/icons/export.svg:/icons/export.svg - 20 - 20 + 21 + 21 - - true - - - - true - + - 80 - 20 - 131 + 60 + 360 + 41 41 @@ -189,55 +219,63 @@ 9 - - Disabled + + PointingHandCursor - - true + + Qt::StrongFocus + + + + :/icons/import.svg:/icons/import.svg + + + + 21 + 21 + - + - 0 - 140 - 351 - 1 + 110 + 360 + 41 + 41 - - Qt::Horizontal + + + Tahoma + 9 + - - - - true + + PointingHandCursor - - - 20 - 80 - 40 - 40 - + + Qt::StrongFocus - - - 0 - 0 - + + + :/icons/help.svg:/icons/help.svg - + - 40 - 40 + 21 + 21 - - - 40 - 40 - + + + + + 160 + 360 + 41 + 41 + @@ -248,168 +286,158 @@ PointingHandCursor + + Qt::StrongFocus + - :/icons/switch-in.svg:/icons/switch-in.svg + :/icons/bugreport.svg:/icons/bugreport.svg - 30 - 30 + 21 + 21 - - true - - - - true - + - 80 - 80 + 210 + 360 131 41 + + + 0 + 0 + + Tahoma 9 - - Input Binding - - - true - - - - - - 1 - 141 - 349 - 319 - + + PointingHandCursor - - QFrame::NoFrame + + Qt::StrongFocus - - Qt::ScrollBarAlwaysOff + + Updates... - + false - - Qt::AlignCenter - - - - - 14 - 19 - 321 - 281 - - - - + - 360 - 150 - 351 - 319 + 10 + 60 + 340 + 461 - - - 351 - 319 - + + Qt::ClickFocus - - - 351 - 319 - + + false + + + #overview_frame { + border-color: rgb(3, 3, 3); + background-color: rgba(3, 3, 3, 10%); +} - + + QFrame::StyledPanel + + + QFrame::Plain + + + 3 + + + 2 + + - 0 - - - QLayout::SetMinimumSize + 10 - 0 + 10 - 0 + 10 - 0 + 10 - 0 - - - - - - 0 - 0 - + 10 + + + + + Qt::ClickFocus - - - 351 - 40 - + + true - - - 351 - 16777215 - + + border-color: #000000; + + + Qt::ScrollBarAlwaysOff + + + true - + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + true + + + + + + - 311 + 320 40 - + - 15 - - - QLayout::SetMinimumSize + 10 - 20 + 0 - 20 + 0 - 20 + 0 - 20 + 0 - - - - true - + + 0 @@ -437,12 +465,9 @@ PointingHandCursor - - border: 1px solid rgb(0, 0, 255); - - :/icons/edit.svg:/icons/edit.svg + :/icons/add.svg:/icons/add.svg @@ -450,204 +475,247 @@ 20 - - 1 + + false - - - - true - - - - 0 - 0 - - + + - 90 - 40 - - - - - 16777215 - 40 + 270 + 0 - - - Tahoma - 9 - - - - Devices - - - true - - - 5 - - - - - - - true - - - - 0 - 0 - - - - - Tahoma - 9 - - - - None - - - Qt::AlignCenter - - - true - + + + 10 + + + QLayout::SetMaximumSize + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + 0 + 40 + + + + + Tahoma + 9 + + + + 100 Bindings + + + Qt::AlignCenter + + + false + + + + + + + + 40 + 40 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/edit.svg:/icons/edit.svg + + + + 20 + 20 + + + + false + + + + + + + + 40 + 40 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/delete.svg:/icons/delete.svg + + + + 20 + 20 + + + + false + + + + + + + + + + 360 + 60 + 350 + 461 + + + + Qt::ClickFocus + + + #device_frame { + border-color: rgb(0, 0, 255); + background-color: rgba(0, 0, 255, 10%); +} + + + QFrame::StyledPanel + + + + 10 + + + 10 + + + 10 + + + 10 + + + 10 + - - - - 0 - 1 - + + + Qt::ClickFocus - - - 16777215 - 1 - + + border-color: #000000; - - QFrame::Plain + + true - - Qt::Horizontal + + false - - - - - 0 - 0 - - - - - 351 - 40 - - + + - 351 - 16777215 - - - - - 311 - 40 + 330 + 240 - + - 15 - - - QLayout::SetMinimumSize + 10 - 20 + 0 - 20 + 0 - 20 + 0 - 20 + 0 - - - - true - - - - 0 - 0 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - border: 1px solid rgb(0, 255, 0); - - - - :/icons/edit.svg:/icons/edit.svg - - - - 20 - 20 - - - - 2 - - - - - - - true - + + 0 @@ -656,186 +724,372 @@ - 90 - 40 - - - - - 16777215 - 40 + 330 + 90 - - - Tahoma - 9 - - - - Messages - - - true - - - 5 - - - - - - - true - - - - 0 - 0 - - - - - Tahoma - 9 - - - - None - - - Qt::AlignCenter - - - true - + + + true + + + + 0 + 0 + 40 + 40 + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/activate.svg:/icons/activate.svg + + + + 20 + 20 + + + + true + + + + + true + + + + 210 + 0 + 121 + 41 + + + + + Tahoma + 9 + + + + Unavailable + + + Qt::AlignCenter + + + false + + + + + true + + + + 210 + 50 + 121 + 41 + + + + + Tahoma + 9 + + + + Unavailable + + + Qt::AlignCenter + + + false + + + + + true + + + + 0 + 50 + 40 + 40 + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/activate.svg:/icons/activate.svg + + + + 20 + 20 + + + + true + + + + + true + + + + 50 + 50 + 151 + 41 + + + + + Tahoma + 9 + + + + Output Status + + + true + + + + + true + + + + 50 + 0 + 151 + 41 + + + + + Tahoma + 9 + + + + Input Status + + + true + + - - - - - - - - 0 - 1 - - - - - 16777215 - 1 - - - - QFrame::Plain - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - - 351 - 40 - - - - - 351 - 16777215 - - - - - 311 - 40 - - - - - 15 - - - QLayout::SetMinimumSize - - - 20 - - - 20 - - - 20 - - - 20 - - - - true - + - + 0 0 - 40 - 40 - - - - - 40 - 40 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - border: 1px solid rgb(255, 0, 0); - - - - :/icons/edit.svg:/icons/edit.svg - - - - 20 - 20 + 0 + 0 - - 3 - + + + QLayout::SetMaximumSize + + + QFormLayout::AllNonFixedFieldsGrow + + + 10 + + + 10 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/toggle-off.svg + :/icons/toggle-on.svg:/icons/toggle-off.svg + + + + 20 + 20 + + + + true + + + + + + + true + + + + 0 + 40 + + + + + Tahoma + 9 + + + + Send Through Incoming Messages + + + true + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + Tahoma + 9 + + + + + - - - - true - + + 0 @@ -844,92 +1098,255 @@ - 90 + 330 40 - 16777215 + 330 40 - - - Tahoma - 9 - - - - Actions - - - true - - - 5 - - - - - - - true - - - - 0 - 0 - - - - - Tahoma - 9 - - - - None - - - Qt::AlignCenter - - - true - + + + 10 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 40 + 40 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/delete.svg:/icons/delete.svg + + + + 20 + 20 + + + + false + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Check MIDI Device Capabilities... + + + false + + + + - - - - - 0 - 0 - - - - - - - + + + true + + + + 10 + 10 + 341 + 41 + + + + + sans-serif + -1 + false + true + + + + font: bold 18px sans-serif; + + + Binding Collections + + + Qt::AlignCenter + + + true + + + + + true + 360 10 351 + 40 + + + + + 0 + 40 + + + + + sans-serif + -1 + false + true + + + + font: bold 18px sans-serif; + + + MIDI Devices + + + Qt::AlignCenter + + + true + + + + + true + + + + 720 + 10 + 351 + 41 + + + + + sans-serif + -1 + false + true + + + + font: bold 18px sans-serif; + + + Preferences + + + Qt::AlignCenter + + + true + + + + + + + + + + + + + + + 360 + 60 + 351 461 + + Qt::ClickFocus + false - border-color: rgb(0, 0, 255); + #message_frame { + border-color: rgb(0, 255, 0); + background-color: rgba(0, 255, 0, 7%); +} QFrame::StyledPanel @@ -943,16 +1360,44 @@ 2 - - - true - + + + + + 720 + 60 + 351 + 461 + + + + Qt::ClickFocus + + + #action_frame { + border-color: rgb(255, 0, 0); + background-color: rgba(255, 0, 0, 7%); +} + + + QFrame::StyledPanel + + + QFrame::Plain + + + 3 + + + 2 + + - 20 - 20 - 40 - 40 + 110 + 10 + 231 + 41 @@ -961,17 +1406,107 @@ 0 - - - 40 - 40 - + + + Tahoma + 9 + - - - 40 - 40 - + + + None + + + + + Streaming + + + + + Recording + + + + + Virtual Camera + + + + + Replay Buffer + + + + + Studio Mode + + + + + Scene Switching + + + + + Video Sources + + + + + Audio Sources + + + + + Media Sources + + + + + Transitions + + + + + Filters + + + + + Hotkeys + + + + + Profiles + + + + + Scene Collections + + + + + MIDI + + + + + + + 110 + 60 + 231 + 41 + + + + + 0 + 0 + @@ -979,32 +1514,38 @@ 9 - - PointingHandCursor + + + + + 0 + 110 + 351 + 1 + - - - :/icons/activate.svg:/icons/activate.svg + + border-color: rgb(255, 0, 0); - - - 20 - 20 - + + QFrame::Plain - - true + + 3 + + + Qt::Horizontal - + true - 80 - 20 - 131 + 10 + 10 + 91 41 @@ -1015,21 +1556,21 @@ - Input Status + Category true - + true - 220 - 20 - 111 + 10 + 60 + 91 41 @@ -1040,25 +1581,619 @@ - Unavailable - - - Qt::AlignCenter + Action - false + true - - - true + + + + 1 + 111 + 349 + 349 + + + + QScrollArea, .QWidget, QLayout > * { + background-color: rgba(0, 0, 0, 0%); +} + + + + + + true + + + + 10 + 10 + 40 + 40 + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + + :/icons/confirm.svg:/icons/confirm.svg + + + + 20 + 20 + + + + false + + + + + true + + + + 60 + 10 + 651 + 41 + + + + + sans-serif + -1 + false + true + + + + font: bold 18px sans-serif; + + + Collection Name + + + Qt::AlignCenter + + + true + + + + + + 10 + 60 + 340 + 461 + + + + Qt::ClickFocus + + + #binding_frame { + border-color: rgb(255, 255, 255); + background-color: rgba(255, 255, 255, 5%); +} + + + QFrame::StyledPanel + + + 3 + + + 2 + + + + 10 + + + 10 + + + 10 + + + 10 + + + 10 + + + + + 10 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + + :/icons/add.svg:/icons/add.svg + + + + 20 + 20 + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 10 + + + QLayout::SetMaximumSize + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + + + + :/icons/copy.svg:/icons/copy.svg + + + + 20 + 20 + + + + false + + + + + + + + 40 + 40 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/move.svg:/icons/move.svg + + + + 20 + 20 + + + + false + + + + + + + + 40 + 40 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/delete.svg:/icons/delete.svg + + + + 20 + 20 + + + + false + + + + + + + + + + + + + Qt::ClickFocus + + + Qt::DefaultContextMenu + + + true + + + border-color: #000000; + + + Qt::ScrollBarAlwaysOff + + + true + + + QAbstractItemView::InternalMove + + + true + + + + + + + + 320 + 70 + + + + + + 120 + 30 + 201 + 41 + + + + + 0 + 0 + + + + + Tahoma + 9 + + + + + + true + + + + 10 + 20 + 40 + 40 + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/activate.svg:/icons/activate.svg + + + + 20 + 20 + + + + true + + + + + true + + + + 60 + 20 + 40 + 40 + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + Tahoma + 9 + + + + PointingHandCursor + + + Qt::ClickFocus + + + + :/icons/switch-in.svg + :/icons/switch-out.svg:/icons/switch-in.svg + + + + 30 + 30 + + + + true + + + + + true + + + + 120 + 0 + 201 + 31 + + + + + Tahoma + 9 + + + + Action Reset Mode + + + true + + + + + + + + + + 720 + 10 + 351 + 41 + + + - 20 - 250 - 40 - 40 + 0 + 0 + 301 + 41 @@ -1067,13 +2202,34 @@ 0 - - + + + Tahoma + 9 + + + + + Untitled Action + + + + + + + 310 + 0 40 40 - + + + + + 40 + 40 + - + 40 40 @@ -1088,9 +2244,12 @@ PointingHandCursor + + Qt::ClickFocus + - :/icons/activate.svg:/icons/activate.svg + :/icons/edit.svg:/icons/edit.svg @@ -1098,1243 +2257,25 @@ 20 - - true - - - - - true - - - - 80 - 250 - 131 - 41 - - - - - Tahoma - 9 - - - - Output Status - - - true + + false - - - true - - - - 220 - 250 - 111 - 41 - - - - - Tahoma - 9 - - - - Unavailable - - - Qt::AlignCenter - - - false - - - - - - 80 - 130 - 251 - 41 - - - - - 0 - 0 - - - - - Tahoma - 9 - - - - - - true - - - - 80 - 80 - 251 - 41 - - - - - Tahoma - 9 - - - - Send Through Incoming Messages - - - true - - - - - true - - - - 20 - 80 - 40 - 40 - - - - - 0 - 0 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/toggle-off.svg:/icons/toggle-off.svg - - - - 20 - 20 - - - - true - - - - - - 0 - 230 - 351 - 1 - - - - Qt::Horizontal - - - - - - - - - 360 - 10 - 351 - 461 - - - - false - - - border-color: rgb(0, 255, 0); - - - QFrame::StyledPanel - - - QFrame::Plain - - - 3 - - - 2 - - - - - 180 - 420 - 161 - 31 - - - - - 0 - 0 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - Listen Continuous... - - - true - - - - - - 10 - 420 - 161 - 31 - - - - - 0 - 0 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - Listen Once... - - - true - - - - - - - - - 360 - 10 - 351 - 461 - - - - border-color: rgb(255, 0, 0); - - - QFrame::StyledPanel - - - QFrame::Plain - - - 3 - - - 2 - - - - - 110 - 10 - 181 - 41 - - - - - 0 - 0 - - - - - Tahoma - 9 - - - - - None - - - - - Streaming - - - - - Recording - - - - - Virtual Camera - - - - - Replay Buffer - - - - - Studio Mode - - - - - Scene Switching - - - - - Video Sources - - - - - Audio Sources - - - - - Media Sources - - - - - Transitions - - - - - Filters - - - - - Hotkeys - - - - - Profiles - - - - - Scene Collections - - - - - Composite - - - - - - - 110 - 60 - 231 - 41 - - - - - 0 - 0 - - - - - Tahoma - 9 - - - - - - - 0 - 110 - 351 - 1 - - - - QFrame::Plain - - - 3 - - - Qt::Horizontal - - - - - - 1 - 111 - 349 - 349 - - - - - - - true - - - - 10 - 10 - 91 - 41 - - - - - Tahoma - 9 - - - - Category - - - true - - - - - true - - - - 10 - 60 - 91 - 41 - - - - - Tahoma - 9 - - - - Action - - - true - - - - - - 300 - 10 - 40 - 40 - - - - - 0 - 0 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - - - - :/icons/switch-in.svg:/icons/switch-in.svg - - - - 30 - 30 - - - - true - - - false - - - - - - - - - 360 - 10 - 351 - 461 - - - - false - - - border-color: rgb(224, 224, 0); - - - QFrame::StyledPanel - - - QFrame::Plain - - - 3 - - - 2 - - - - - 10 - 410 - 151 - 41 - - - - - Tahoma - 9 - - - - Made by nhielost - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - 280 - 410 - 61 - 41 - - - - - Tahoma - 9 - - - - v1.0.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 360 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - - - - :/icons/export.svg:/icons/export.svg - - - - 21 - 21 - - - - - - - 60 - 360 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/import.svg:/icons/import.svg - - - - 21 - 21 - - - - - - - 110 - 360 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/help.svg:/icons/help.svg - - - - 21 - 21 - - - - - - - 160 - 360 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/bugreport.svg:/icons/bugreport.svg - - - - 21 - 21 - - - - - - - 210 - 360 - 131 - 41 - - - - - 0 - 0 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - Updates... - - - false - - - - - - 10 - 10 - 331 - 341 - - - - - 0 - 0 - - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOff - - - true - - - - - 0 - 0 - 331 - 341 - - - - - - - - 670 - 10 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/preferences.svg:/icons/preferences.svg - - - - 21 - 21 - - - - true - - - - - - 570 - 10 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/message.svg:/icons/message.svg - - - - 21 - 21 - - - - true - - - - - - 470 - 10 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/binding.svg:/icons/binding.svg - - - - 21 - 21 - - - - true - - - - - - 620 - 10 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/action.svg:/icons/action.svg - - - - 21 - 21 - - - - true - - - - - - 520 - 10 - 41 - 41 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/device.svg:/icons/device.svg - - - - 24 - 24 - - - - true - - - - - - 10 - 10 - 40 - 40 - - - - - 0 - 0 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/add.svg:/icons/add.svg - - - - 20 - 20 - - - - false - - - - - - 60 - 10 - 40 - 40 - - - - - 0 - 0 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - - - - :/icons/copy.svg:/icons/copy.svg - - - - 20 - 20 - - - - false - - - - - - 110 - 10 - 40 - 40 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - - :/icons/delete.svg:/icons/delete.svg - - - - 20 - 20 - - - - false - - - - - true - - - - 160 - 10 - 301 - 41 - - - - - Tahoma - 16 - true - - - - font-size: 16pt; - - - Bindings - - - Qt::AlignCenter - - - true - - - - - - 295 - 470 - 40 - 40 - - - - - 0 - 0 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - Tahoma - 9 - - - - PointingHandCursor - - - border: 1px solid rgb(0, 0, 0); - - - - :/icons/confirm.svg:/icons/confirm.svg - - - - 20 - 20 - - - - false - - - - - true - - - - 370 - 70 - 331 - 441 - - - - - Tahoma - 10 - - - - font-size: 10pt; - - - Click to select an item. To select multiple items, press Ctrl or Shift while clicking an item. - -Items selected towards the top have the highest priority. Dragging an item around adjusts this priority. - - - Qt::AlignCenter - - - true - - + + button_export + button_import + button_help_advanced + button_bug_report + button_update_check + button_confirm + editor_binding_reset + editor_cat + editor_sub + diff --git a/src/ui/mmg-fields.cpp b/src/ui/mmg-fields.cpp index 4bc360f..7efcfe9 100644 --- a/src/ui/mmg-fields.cpp +++ b/src/ui/mmg-fields.cpp @@ -264,7 +264,7 @@ MMGOBSBooleanField::MMGOBSBooleanField(QWidget *p, const MMGOBSFieldInit &init) button = new QPushButton(this); button->setCheckable(true); button->setGeometry(220, 20, 50, 50); - button->setIcon(QIcon(":/icons/confirm.svg")); + button->setIcon(mmg_icon("confirm")); button->setIconSize(QSize(28, 28)); button->setCursor(Qt::PointingHandCursor); diff --git a/src/ui/mmg-lcd-number.cpp b/src/ui/mmg-lcd-number.cpp index a8bfde5..adfc80e 100644 --- a/src/ui/mmg-lcd-number.cpp +++ b/src/ui/mmg-lcd-number.cpp @@ -55,7 +55,7 @@ MMGLCDNumber::MMGLCDNumber(QWidget *parent) : QWidget(parent) "border-radius: 0; " "border-top-left-radius: 3px; " "border-top-right-radius: 3px;"); - inc_button->setIcon(QIcon(":/icons/increase.svg")); + inc_button->setIcon(mmg_icon("increase")); inc_button->setIconSize(QSize(7, 7)); connect(inc_button, &QAbstractButton::pressed, this, &MMGLCDNumber::delayAutoRepeatInc); connect(inc_button, &QAbstractButton::released, this, &MMGLCDNumber::autoRepeatCancel); @@ -66,7 +66,7 @@ MMGLCDNumber::MMGLCDNumber(QWidget *parent) : QWidget(parent) "border-radius: 0; " "border-bottom-left-radius: 3px; " "border-bottom-right-radius: 3px;"); - dec_button->setIcon(QIcon(":/icons/decrease.svg")); + dec_button->setIcon(mmg_icon("decrease")); dec_button->setIconSize(QSize(7, 7)); connect(dec_button, &QAbstractButton::pressed, this, &MMGLCDNumber::delayAutoRepeatDec); connect(dec_button, &QAbstractButton::released, this, &MMGLCDNumber::autoRepeatCancel); @@ -213,7 +213,7 @@ void MMGLCDNumber::keyPressEvent(QKeyEvent *event) case Qt::Key_Minus: if (edit_string.contains("-")) { edit_string.remove(0, 1); - } else { + } else { edit_string.prepend("-"); } break; @@ -231,7 +231,7 @@ void MMGLCDNumber::keyPressEvent(QKeyEvent *event) return; default: - event->ignore(); + event->ignore(); return; } diff --git a/src/ui/mmg-list-widget.cpp b/src/ui/mmg-list-widget.cpp deleted file mode 100644 index bf5ae24..0000000 --- a/src/ui/mmg-list-widget.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* -obs-midi-mg -Copyright (C) 2022-2023 nhielost - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see -*/ - -#include "mmg-list-widget.h" -#include "../mmg-binding.h" - -#include - -using namespace MMGUtils; - -MMGListWidget::MMGListWidget(QWidget *parent) : QListWidget(parent) -{ - setDragEnabled(true); - viewport()->setAcceptDrops(true); - setDropIndicatorShown(true); - setDragDropMode(QAbstractItemView::InternalMove); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setStyleSheet("border-color: rgb(0, 0, 0);"); - setWordWrap(true); - - connect(this, &QListWidget::itemClicked, this, &MMGListWidget::selected); - connect(this, &QListWidget::itemChanged, this, &MMGListWidget::rename); - connect(model(), &QAbstractItemModel::rowsMoved, this, &MMGListWidget::move); -} - -QMimeData *MMGListWidget::mimeData(const QList &items) const -{ - QMimeData *mime = new QMimeData; - QByteArray ba; - QDataStream stream(&ba, QIODeviceBase::WriteOnly); - - for (QListWidgetItem *item : items) { - void *_data = item->data(dataRole()).data(); - stream << *(quint64 *)(&_data); - } - - mime->setData(mimeTypes()[0], ba); - return mime; -} - -void MMGListWidget::setItemsEditable(bool editable) -{ - items_editable = editable; - displayAll(); -} diff --git a/src/ui/mmg-list-widget.h b/src/ui/mmg-list-widget.h deleted file mode 100644 index ac70662..0000000 --- a/src/ui/mmg-list-widget.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -obs-midi-mg -Copyright (C) 2022-2023 nhielost - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see -*/ - -#ifndef MMG_LIST_WIDGET_H -#define MMG_LIST_WIDGET_H - -#include "../mmg-utils.h" - -#include -#include - -class MMGBinding; - -class MMGListWidget : public QListWidget { - Q_OBJECT - -public: - MMGListWidget(QWidget *parent); - virtual ~MMGListWidget() = default; - - enum SelectionType { SELECTION_ONE, SELECTION_MULTIPLE }; - - MMGUtils::DeviceType filterType() const { return filter_type; }; - void setFilterType(MMGUtils::DeviceType device_type) { filter_type = device_type; }; - - int indexOf(const QListWidgetItem *item) const { return indexFromItem(item).row(); }; - virtual void displayAll() = 0; - virtual void updateData() = 0; - static int dataRole() { return 260; }; - - void setItemsEditable(bool editable); - -signals: - void allDisplayed(); - void selected(); - void itemMoved(); - -public slots: - virtual void addNew() = 0; - virtual void copy() = 0; - virtual void remove() = 0; - -protected slots: - virtual void rename(QListWidgetItem *widget_item) = 0; - virtual void move(const QModelIndex &parent, int start, int end, const QModelIndex &dest, int row) = 0; - -protected: - QMimeData *mimeData(const QList &items) const override; - QStringList mimeTypes() const override { return {"application/x-mmg-manager-data"}; } - - bool items_editable = true; - MMGUtils::DeviceType filter_type = MMGUtils::TYPE_NONE; -}; - -#endif // MMG_LIST_WIDGET_H diff --git a/src/ui/mmg-manager-display.cpp b/src/ui/mmg-manager-display.cpp deleted file mode 100644 index 268b02e..0000000 --- a/src/ui/mmg-manager-display.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* -obs-midi-mg -Copyright (C) 2022-2023 nhielost - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see -*/ - -#ifndef MMG_MANAGER_DISPLAY_CPP -#define MMG_MANAGER_DISPLAY_CPP - -#include "mmg-manager-display.h" - -template T *MMGManagerDisplay::getValue(QListWidgetItem *widget_item) const -{ - if (!widget_item) return nullptr; - return widget_item->data(dataRole()).value(); -} - -template void MMGManagerDisplay::selectValues(const QList &values) -{ - for (int i = 0; i < count(); ++i) { - QListWidgetItem *_item = item(i); - _item->setSelected(values.contains(getValue(_item))); - } -} - -template const QList MMGManagerDisplay::selectedValues() const -{ - QList selected; - selected.resize(count()); - - for (QListWidgetItem *item : selectedItems()) - selected[indexOf(item)] = getValue(item); - - for (int i = 0; i < selected.size(); ++i) - if (!selected[i]) selected.removeAt(i--); - - return selected; -} - -template void MMGManagerDisplay::displayAll() -{ - clear(); - for (T *value : *_manager) - if (_manager->filter(filter_type, value)) insertData(count(), value); - - clearSelection(); - emit allDisplayed(); -} - -template void MMGManagerDisplay::insertData(int index, T *data) -{ - QListWidgetItem *new_item = new QListWidgetItem; - new_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | - (items_editable ? Qt::ItemIsEditable : Qt::NoItemFlags)); - new_item->setText(data->name()); - new_item->setData(dataRole(), QVariant::fromValue(data)); - insertItem(index, new_item); -} - -template void MMGManagerDisplay::updateData() -{ - for (int i = 0; i < count(); ++i) { - QListWidgetItem *widget_item = item(i); - T *value = _manager->at(i); - if (getValue(widget_item) != value) widget_item->setData(dataRole(), QVariant::fromValue(value)); - } -} - -template void MMGManagerDisplay::remove() -{ - T *data = currentValue(); - if (!data) return; - - _manager->remove(data); - - delete currentItem(); - - emit selected(); -} - -template void MMGManagerDisplay::rename(QListWidgetItem *widget_item) -{ - if (!widget_item) return; - - if (currentRow() != row(widget_item)) setCurrentItem(widget_item); - - T *value = getValue(widget_item); - QString new_name = widget_item->text(); - - if (value->name() == new_name) return; - if (!!_manager->find(new_name)) { - currentItem()->setText(value->name()); - } else { - value->setName(new_name); - } -} - -template void MMGManagerDisplay::move(const QModelIndex &, int start, int, const QModelIndex &, int row) -{ - if (selectionMode() != SingleSelection) return; - _manager->move(start, row); - emit itemMoved(); -} - -#endif // MMG_MANAGER_DISPLAY_CPP diff --git a/src/ui/mmg-manager-display.h b/src/ui/mmg-manager-display.h deleted file mode 100644 index 49ca043..0000000 --- a/src/ui/mmg-manager-display.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -obs-midi-mg -Copyright (C) 2022-2023 nhielost - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see -*/ - -#ifndef MMG_MANAGER_DISPLAY_H -#define MMG_MANAGER_DISPLAY_H - -#include "mmg-list-widget.h" -#include "../mmg-utils.h" -#include "../mmg-config.h" - -template class MMGManagerDisplay : public MMGListWidget { - -public: - MMGManagerDisplay(QWidget *parent, MMGManager *storage) : MMGListWidget(parent), _manager(storage){}; - - T *getValue(QListWidgetItem *item) const; - T *currentValue() const { return getValue(currentItem()); }; - - void selectValues(const QList &values); - const QList selectedValues() const; - - void displayAll() override; - void insertData(int index, T *data); - void updateData(); - - void addNew() override { insertData(count(), _manager->add()); }; - void copy() override { insertData(count(), _manager->copy(currentValue())); }; - void remove() override; - -protected: - MMGManager *_manager; - - void rename(QListWidgetItem *widget_item) override; - void move(const QModelIndex &, int start, int, const QModelIndex &, int row) override; -}; - -#include "mmg-manager-display.cpp" - -#endif // MMG_MANAGER_DISPLAY_H diff --git a/src/ui/mmg-message-display.cpp b/src/ui/mmg-message-display.cpp new file mode 100644 index 0000000..3c4e4e2 --- /dev/null +++ b/src/ui/mmg-message-display.cpp @@ -0,0 +1,169 @@ +/* +obs-midi-mg +Copyright (C) 2022-2023 nhielost + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#include "mmg-message-display.h" + +using namespace MMGUtils; + +MMGMessageDisplay::MMGMessageDisplay(QWidget *parent) : QWidget(parent) +{ + setFixedSize(330, 440); + + device_display = new MMGStringDisplay(this); + device_display->move(0, 5); + device_display->setDescription(mmgtr("Device.Name")); + connect(device_display, &MMGStringDisplay::stringChanged, this, &MMGMessageDisplay::setDevice); + + type_display = new MMGStringDisplay(this); + type_display->setDisplayMode(MMGStringDisplay::MODE_NORMAL); + type_display->move(0, 55); + type_display->setDescription(mmgtr("Message.Type.Text")); + type_display->setBounds(MMGMessage::acceptedTypes()); + type_display->setOptions(MIDIBUTTON_MIDI | MIDIBUTTON_TOGGLE); + connect(type_display, &MMGStringDisplay::stringChanged, this, &MMGMessageDisplay::setLabels); + + channel_display = new MMGNumberDisplay(this); + channel_display->move(0, 150); + channel_display->setDescription(mmgtr("Message.Channel")); + channel_display->setBounds(1, 16); + channel_display->setOptions(MIDIBUTTON_MIDI | MIDIBUTTON_CUSTOM | MIDIBUTTON_TOGGLE); + + note_display = new MMGNumberDisplay(this); + note_display->move(0, 235); + note_display->setDescription(mmgtr("Message.Note")); + note_display->setBounds(0, 127); + note_display->setOptions(MIDIBUTTON_MIDI | MIDIBUTTON_CUSTOM | MIDIBUTTON_TOGGLE); + + value_display = new MMGNumberDisplay(this); + value_display->move(0, 320); + value_display->setDescription(mmgtr("Message.Velocity")); + value_display->setBounds(0, 127); + value_display->setOptions(MIDIBUTTON_MIDI | MIDIBUTTON_CUSTOM | MIDIBUTTON_TOGGLE); + value_display->lower(); + + listen_once_button = new QPushButton(this); + listen_once_button->setGeometry(0, 407, 160, 30); + listen_once_button->setCursor(Qt::PointingHandCursor); + listen_once_button->setCheckable(true); + listen_once_button->setText(mmgtr("UI.Listen.Once")); + connect(listen_once_button, &QAbstractButton::toggled, this, &MMGMessageDisplay::onListenOnceClick); + + listen_continuous_button = new QPushButton(this); + listen_continuous_button->setGeometry(170, 407, 160, 30); + listen_continuous_button->setCursor(Qt::PointingHandCursor); + listen_continuous_button->setCheckable(true); + listen_continuous_button->setText(mmgtr("UI.Listen.Continuous")); + connect(listen_continuous_button, &QAbstractButton::toggled, this, &MMGMessageDisplay::onListenContinuousClick); + + device_display->setBounds(manager(device)->names()); +} + +void MMGMessageDisplay::setStorage(MMGMessage *storage) +{ + _storage = storage; + + MMGNoEdit no_edit_storage(storage); + device_display->setStorage(&_device); + type_display->setStorage(&storage->type()); + channel_display->setStorage(&storage->channel()); + note_display->setStorage(&storage->note()); + value_display->setStorage(&storage->value()); + + device_display->setBounds(manager(device)->names()); + setLabels(); +} + +void MMGMessageDisplay::connectDevice(bool connected) +{ + MMGMIDIPort *device = _storage->device(); + if (!device) return; + + if (connected) { + connect(device, &MMGMIDIPort::messageListened, this, &MMGMessageDisplay::updateMessage); + } else { + disconnect(device, &MMGMIDIPort::messageListened, this, &MMGMessageDisplay::updateMessage); + } +} + +void MMGMessageDisplay::setLabels() +{ + if (!_storage) return; + + if (_storage->type() == mmgtr("Message.Type.NoteOn") || _storage->type() == mmgtr("Message.Type.NoteOff")) { + note_display->setVisible(true); + note_display->setDescription(mmgtr("Message.Note")); + value_display->setDescription(mmgtr("Message.Velocity")); + } else if (_storage->type() == mmgtr("Message.Type.ControlChange")) { + note_display->setVisible(true); + note_display->setDescription(mmgtr("Message.Control")); + value_display->setDescription(mmgtr("Message.Value")); + } else if (_storage->type() == mmgtr("Message.Type.ProgramChange")) { + note_display->setVisible(false); + value_display->setDescription(mmgtr("Message.Program")); + } else if (_storage->type() == mmgtr("Message.Type.PitchBend")) { + note_display->setVisible(false); + value_display->setDescription(mmgtr("Message.PitchAdjust")); + } +} + +void MMGMessageDisplay::setDevice() +{ + connectDevice(false); + _storage->setDevice(manager(device)->find(_device)); +} + +void MMGMessageDisplay::onListenOnceClick(bool toggled) +{ + listen_once_button->setText(mmgtr_two("UI.Listen", "Cancel", "Once", toggled)); + if (listening_mode == 2) listen_continuous_button->setChecked(false); + _storage->device()->incListening(toggled); + connectDevice(toggled); + listening_mode = toggled; + global_blog(LOG_DEBUG, toggled ? "Single listen activated." : "Listening deactivated."); +} + +void MMGMessageDisplay::onListenContinuousClick(bool toggled) +{ + listen_continuous_button->setText(mmgtr_two("UI.Listen", "Cancel", "Continuous", toggled)); + if (listening_mode == 1) listen_once_button->setChecked(false); + _storage->device()->incListening(toggled); + connectDevice(toggled); + listening_mode = toggled * 2; + global_blog(LOG_DEBUG, toggled ? "Continuous listen activated." : "Listening deactivated."); +} + +void MMGMessageDisplay::updateMessage(const MMGSharedMessage &incoming) +{ + if (listening_mode < 1) return; + if (!incoming) { // Closed without turning off Listen function + listen_once_button->setChecked(false); + return; + } + // Check the validity of the message type (whether it is one of the five supported types) + if (MMGMessage::acceptedTypes().indexOf(incoming->type()) == -1) return; + if (listening_mode == 1) listen_once_button->setChecked(false); + + incoming->copy(_storage); + _storage->value().setMax(127); + + MMGNoEdit no_edit_message(_storage); + type_display->display(); + channel_display->display(); + note_display->display(); + value_display->display(); +} \ No newline at end of file diff --git a/src/ui/mmg-message-display.h b/src/ui/mmg-message-display.h new file mode 100644 index 0000000..15d287a --- /dev/null +++ b/src/ui/mmg-message-display.h @@ -0,0 +1,57 @@ +/* +obs-midi-mg +Copyright (C) 2022-2023 nhielost + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#ifndef MMG_MESSAGE_DISPLAY_H +#define MMG_MESSAGE_DISPLAY_H + +#include "../mmg-utils.h" +#include "../mmg-config.h" + +class MMGMessageDisplay : public QWidget { + Q_OBJECT + +public: + MMGMessageDisplay(QWidget *parent); + + void setStorage(MMGMessage *storage); + void connectDevice(bool); + +public slots: + void setLabels(); + void setDevice(); + void onListenOnceClick(bool); + void onListenContinuousClick(bool); + void updateMessage(const MMGSharedMessage &); + +private: + MMGMessage *_storage = nullptr; + MMGUtils::MMGString _device; + + MMGStringDisplay *device_display; + MMGStringDisplay *type_display; + MMGNumberDisplay *channel_display; + MMGNumberDisplay *note_display; + MMGNumberDisplay *value_display; + + QPushButton *listen_once_button; + QPushButton *listen_continuous_button; + + short listening_mode = 0; +}; + +#endif // MMG_MESSAGE_DISPLAY_H diff --git a/src/ui/mmg-midi-buttons.cpp b/src/ui/mmg-midi-buttons.cpp index ec20b41..b4abc6b 100644 --- a/src/ui/mmg-midi-buttons.cpp +++ b/src/ui/mmg-midi-buttons.cpp @@ -35,20 +35,20 @@ MMGMIDIButtons::MMGMIDIButtons(QWidget *parent) : QWidget(parent) fixed_button = new QPushButton(this); //fixed_button->setGeometry(0, 0, 30, 30); - fixed_button->setIcon(QIcon(":/icons/fixed.svg")); + fixed_button->setIcon(mmg_icon("fixed")); fixed_button->setIconSize({12, 12}); midi_button = new QPushButton(this); //midi_button->setGeometry(40, 0, 30, 30); - midi_button->setIcon(QIcon(":/icons/midi.svg")); + midi_button->setIcon(mmg_icon("midi")); midi_button->setIconSize({18, 18}); custom_button = new QPushButton(this); //custom_button->setGeometry(80, 0, 30, 30); - custom_button->setIcon(QIcon(":/icons/custom.svg")); + custom_button->setIcon(mmg_icon("custom")); ignore_button = new QPushButton(this); - ignore_button->setIcon(QIcon(":/icons/disable.svg")); + ignore_button->setIcon(mmg_icon("disable")); toggle_button = new QPushButton(this); connect(toggle_button, &QPushButton::toggled, this, &MMGMIDIButtons::setToggleIcon); @@ -105,5 +105,5 @@ void MMGMIDIButtons::setState(int state) void MMGMIDIButtons::setToggleIcon(bool toggled) { - toggle_button->setIcon(QIcon(toggled ? ":/icons/toggle-on.svg" : ":/icons/toggle-off.svg")); + toggle_button->setIcon(mmg_icon(toggled ? "toggle-on" : "toggle-off")); } diff --git a/src/ui/resources.qrc b/src/ui/resources.qrc index 062a71b..77b0ed0 100644 --- a/src/ui/resources.qrc +++ b/src/ui/resources.qrc @@ -20,6 +20,7 @@ icons/increase.svg icons/message.svg icons/midi.svg + icons/move.svg icons/preferences.svg icons/switch-in.svg icons/switch-out.svg