diff --git a/src/singletons/WindowManager.cpp b/src/singletons/WindowManager.cpp index 77b69da40..f63f27a22 100644 --- a/src/singletons/WindowManager.cpp +++ b/src/singletons/WindowManager.cpp @@ -16,6 +16,7 @@ #include "util/CombinePath.hpp" #include "util/FilesystemHelpers.hpp" #include "util/SignalListener.hpp" +#include "util/Variant.hpp" #include "widgets/AccountSwitchPopup.hpp" #include "widgets/dialogs/SettingsDialog.hpp" #include "widgets/FramelessEmbedWindow.hpp" @@ -38,6 +39,8 @@ #include #include +using namespace Qt::Literals; + namespace { std::optional &shouldMoveOutOfBoundsWindow() @@ -676,92 +679,62 @@ void WindowManager::encodeTab(SplitContainer *tab, bool isSelected, // splits QJsonObject splits; - WindowManager::encodeNodeRecursively(tab->getBaseNode(), splits); + WindowManager::encodeNodeRecursively(tab->buildDescriptor(), splits); obj.insert("splits2", splits); } -void WindowManager::encodeNodeRecursively(SplitNode *node, QJsonObject &obj) +void WindowManager::encodeNodeRecursively(const NodeDescriptor &descriptor, + QJsonObject &obj) { - switch (node->getType()) - { - case SplitNode::Type::Split: { - obj.insert("type", "split"); - obj.insert("moderationMode", node->getSplit()->getModerationMode()); + std::visit(variant::Overloaded{ + [&](const SplitNodeDescriptor &split) { + obj.insert("type", "split"); + obj.insert("flexh", split.flexH_); + obj.insert("flexv", split.flexV_); - QJsonObject split; - WindowManager::encodeChannel(node->getSplit()->getIndirectChannel(), - split); - obj.insert("data", split); + obj.insert("moderationMode", split.moderationMode_); - QJsonArray filters; - WindowManager::encodeFilters(node->getSplit(), filters); - obj.insert("filters", filters); + QJsonObject data{{"type"_L1, split.type_}}; + if (!split.channelName_.isEmpty()) + { + data.insert("name"_L1, split.channelName_); + } + obj.insert("data", data); - auto spellOverride = node->getSplit()->checkSpellingOverride(); - if (spellOverride) - { - obj["checkSpelling"] = *spellOverride; - } - } - break; - case SplitNode::Type::HorizontalContainer: - case SplitNode::Type::VerticalContainer: { - obj.insert("type", - node->getType() == SplitNode::Type::HorizontalContainer - ? "horizontal" - : "vertical"); + QJsonArray filters; + WindowManager::encodeFilters(split.filters_, filters); + obj.insert("filters", filters); - QJsonArray itemsArr; - for (const auto &n : node->getChildren()) - { - QJsonObject subObj; - WindowManager::encodeNodeRecursively(n.get(), subObj); - itemsArr.append(subObj); - } - obj.insert("items", itemsArr); - } - break; + if (split.spellCheckOverride.has_value()) + { + obj["checkSpelling"] = *split.spellCheckOverride; + } + }, + [&](const ContainerNodeDescriptor &container) { + obj.insert("type", container.vertical_ ? "vertical" + : "horizontal"); + obj.insert("flexh", container.flexH_); + obj.insert("flexv", container.flexV_); - default: - break; - } - - obj.insert("flexh", node->getHorizontalFlex()); - obj.insert("flexv", node->getVerticalFlex()); + QJsonArray itemsArr; + for (const auto &n : container.items_) + { + QJsonObject subObj; + WindowManager::encodeNodeRecursively(n, subObj); + itemsArr.append(subObj); + } + obj.insert("items", itemsArr); + }, + }, + descriptor); } -void WindowManager::encodeChannel(IndirectChannel channel, QJsonObject &obj) +void WindowManager::encodeFilters(std::span filters, + QJsonArray &arr) { assertInGuiThread(); - obj.insert("type", qmagicenum::enumNameString(channel.getType())); - switch (channel.getType()) - { - case Channel::Type::Twitch: - case Channel::Type::Misc: - obj.insert("name", channel.get()->getName()); - break; - - case Channel::Type::TwitchWhispers: - case Channel::Type::TwitchWatching: - case Channel::Type::TwitchMentions: - case Channel::Type::TwitchLive: - case Channel::Type::TwitchAutomod: - - // FIXME: Remove these (#5703) - case Channel::Type::None: - case Channel::Type::Direct: - case Channel::Type::TwitchEnd: - break; - } -} - -void WindowManager::encodeFilters(Split *split, QJsonArray &arr) -{ - assertInGuiThread(); - - auto filters = split->getFilters(); for (const auto &f : filters) { arr.append(f.toString(QUuid::WithoutBraces)); diff --git a/src/singletons/WindowManager.hpp b/src/singletons/WindowManager.hpp index 77e1e5564..e9ff24236 100644 --- a/src/singletons/WindowManager.hpp +++ b/src/singletons/WindowManager.hpp @@ -26,7 +26,13 @@ class Window; class ChannelView; class IndirectChannel; class Split; + struct SplitDescriptor; +struct SplitNodeDescriptor; +struct ContainerNodeDescriptor; +using NodeDescriptor = + std::variant; + class Channel; using ChannelPtr = std::shared_ptr; struct Message; @@ -63,8 +69,7 @@ public: static void encodeTab(SplitContainer *tab, bool isSelected, QJsonObject &obj); - static void encodeChannel(IndirectChannel channel, QJsonObject &obj); - static void encodeFilters(Split *split, QJsonArray &arr); + static void encodeFilters(std::span filters, QJsonArray &arr); void showSettingsDialog( QWidget *parent, @@ -162,7 +167,7 @@ public: pajlada::Signals::Signal scrollToMessageSignal; private: - static void encodeNodeRecursively(SplitContainer::Node *node, + static void encodeNodeRecursively(const NodeDescriptor &descriptor, QJsonObject &obj); // Load window layout from the window-layout.json file diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index 7b86f2eca..8f899a6ed 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -1358,6 +1358,38 @@ void Split::setInputReply(const MessagePtr &reply) this->input_->setReply(reply); } +SplitDescriptor Split::buildDescriptor() const +{ + SplitDescriptor descriptor; + descriptor.moderationMode_ = this->getModerationMode(); + descriptor.filters_ = this->getFilters(); + descriptor.spellCheckOverride = this->checkSpellingOverride(); + + auto chan = this->getChannel(); + descriptor.type_ = qmagicenum::enumNameString(chan->getType()); + switch (chan->getType()) + { + case Channel::Type::Twitch: + case Channel::Type::Misc: + descriptor.channelName_ = chan->getName(); + break; + + case Channel::Type::TwitchWhispers: + case Channel::Type::TwitchWatching: + case Channel::Type::TwitchMentions: + case Channel::Type::TwitchLive: + case Channel::Type::TwitchAutomod: + + // FIXME: Remove these (#5703) + case Channel::Type::None: + case Channel::Type::Direct: + case Channel::Type::TwitchEnd: + break; + } + + return descriptor; +} + void Split::unpause() { this->view_->unpause(PauseReason::KeyboardModifier); diff --git a/src/widgets/splits/Split.hpp b/src/widgets/splits/Split.hpp index 3a5b807fe..2058de26f 100644 --- a/src/widgets/splits/Split.hpp +++ b/src/widgets/splits/Split.hpp @@ -27,6 +27,8 @@ class PinnedMessageWidget; class SelectChannelDialog; class OverlayWindow; +struct SplitDescriptor; + // Each ChatWidget consists of three sub-elements that handle their own part of // the chat widget: ChatWidgetHeader // - Responsible for rendering which channel the ChatWidget is in, and the @@ -86,6 +88,8 @@ public: void setInputReply(const MessagePtr &reply); + SplitDescriptor buildDescriptor() const; + // This is called on window focus lost void unpause(); diff --git a/src/widgets/splits/SplitContainer.cpp b/src/widgets/splits/SplitContainer.cpp index 152ca508c..43642ad87 100644 --- a/src/widgets/splits/SplitContainer.cpp +++ b/src/widgets/splits/SplitContainer.cpp @@ -841,44 +841,14 @@ void SplitContainer::popup() window.show(); } -QString channelTypeToString(Channel::Type value) noexcept -{ - using Type = chatterino::Channel::Type; - switch (value) - { - default: - assert(false && "value cannot be serialized"); - return "never"; - - case Type::Twitch: - return "twitch"; - case Type::TwitchWhispers: - return "whispers"; - case Type::TwitchWatching: - return "watching"; - case Type::TwitchMentions: - return "mentions"; - case Type::TwitchLive: - return "live"; - case Type::TwitchAutomod: - return "automod"; - case Type::Misc: - return "misc"; - } -} - NodeDescriptor SplitContainer::buildDescriptorRecursively( const Node *currentNode) const { - if (currentNode->children_.empty()) + if (currentNode->children_.empty() && currentNode->split_) { - const auto channelType = - currentNode->split_->getIndirectChannel().getType(); - - SplitNodeDescriptor result; - result.type_ = channelTypeToString(channelType); - result.channelName_ = currentNode->split_->getChannel()->getName(); - result.filters_ = currentNode->split_->getFilters(); + SplitNodeDescriptor result(currentNode->split_->buildDescriptor()); + result.flexH_ = currentNode->flexH_; + result.flexV_ = currentNode->flexV_; return result; } @@ -890,6 +860,8 @@ NodeDescriptor SplitContainer::buildDescriptorRecursively( descriptor.items_.push_back( this->buildDescriptorRecursively(child.get())); } + descriptor.flexH_ = currentNode->flexH_; + descriptor.flexV_ = currentNode->flexV_; return descriptor; }