mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Added x-attach-split-to-window command line arg (#2411)
Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
58017a7546
commit
2db140d5af
21 changed files with 350 additions and 160 deletions
|
@ -61,6 +61,7 @@
|
|||
- Minor: Made username autocompletion truecase (#1199, #1883)
|
||||
- Minor: Update the listing of top-level domains. (#2345)
|
||||
- Minor: Properly respect RECONNECT messages from Twitch (#2347)
|
||||
- Minor: Added command line option to attach chatterino to another window.
|
||||
- Minor: Hide "Case-sensitive" column for user highlights. (#2404)
|
||||
- Minor: Added human-readable formatting to remaining timeout duration. (#2398)
|
||||
- Minor: Update emojis version to 13 (2020). (#1555)
|
||||
|
|
|
@ -259,6 +259,7 @@ SOURCES += \
|
|||
src/widgets/BasePopup.cpp \
|
||||
src/widgets/BaseWidget.cpp \
|
||||
src/widgets/BaseWindow.cpp \
|
||||
src/widgets/FramelessEmbedWindow.cpp \
|
||||
src/widgets/dialogs/ChannelFilterEditorDialog.cpp \
|
||||
src/widgets/dialogs/ColorPickerDialog.cpp \
|
||||
src/widgets/dialogs/EmotePopup.cpp \
|
||||
|
@ -512,6 +513,7 @@ HEADERS += \
|
|||
src/widgets/BasePopup.hpp \
|
||||
src/widgets/BaseWidget.hpp \
|
||||
src/widgets/BaseWindow.hpp \
|
||||
src/widgets/FramelessEmbedWindow.hpp \
|
||||
src/widgets/dialogs/ChannelFilterEditorDialog.hpp \
|
||||
src/widgets/dialogs/ColorPickerDialog.hpp \
|
||||
src/widgets/dialogs/EmotePopup.hpp \
|
||||
|
|
|
@ -76,7 +76,8 @@ void Application::initialize(Settings &settings, Paths &paths)
|
|||
isAppInitialized = true;
|
||||
|
||||
// Show changelog
|
||||
if (getSettings()->currentVersion.getValue() != "" &&
|
||||
if (!getArgs().isFramelessEmbed &&
|
||||
getSettings()->currentVersion.getValue() != "" &&
|
||||
getSettings()->currentVersion.getValue() != CHATTERINO_VERSION)
|
||||
{
|
||||
auto box = new QMessageBox(QMessageBox::Information, "Chatterino 2",
|
||||
|
@ -90,12 +91,15 @@ void Application::initialize(Settings &settings, Paths &paths)
|
|||
}
|
||||
}
|
||||
|
||||
if (!getArgs().isFramelessEmbed)
|
||||
{
|
||||
getSettings()->currentVersion.setValue(CHATTERINO_VERSION);
|
||||
|
||||
if (getSettings()->enableExperimentalIrc)
|
||||
{
|
||||
Irc::instance().load();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &singleton : this->singletons_)
|
||||
{
|
||||
|
@ -103,7 +107,7 @@ void Application::initialize(Settings &settings, Paths &paths)
|
|||
}
|
||||
|
||||
// add crash message
|
||||
if (getArgs().crashRecovery)
|
||||
if (!getArgs().isFramelessEmbed && getArgs().crashRecovery)
|
||||
{
|
||||
if (auto selected =
|
||||
this->windows->getMainWindow().getNotebook().getSelectedPage())
|
||||
|
@ -126,7 +130,10 @@ void Application::initialize(Settings &settings, Paths &paths)
|
|||
|
||||
this->windows->updateWordTypeMask();
|
||||
|
||||
if (!getArgs().isFramelessEmbed)
|
||||
{
|
||||
this->initNm(paths);
|
||||
}
|
||||
this->initPubsub();
|
||||
}
|
||||
|
||||
|
@ -136,7 +143,10 @@ int Application::run(QApplication &qtApp)
|
|||
|
||||
this->twitch.server->connect();
|
||||
|
||||
if (!getArgs().isFramelessEmbed)
|
||||
{
|
||||
this->windows->getMainWindow().show();
|
||||
}
|
||||
|
||||
getSettings()->betaUpdates.connect(
|
||||
[] {
|
||||
|
|
|
@ -302,6 +302,8 @@ set(SOURCE_FILES main.cpp
|
|||
widgets/BaseWidget.hpp
|
||||
widgets/BaseWindow.cpp
|
||||
widgets/BaseWindow.hpp
|
||||
widgets/FramelessEmbedWindow.cpp
|
||||
widgets/FramelessEmbedWindow.hpp
|
||||
widgets/Label.cpp
|
||||
widgets/Label.hpp
|
||||
widgets/Notebook.cpp
|
||||
|
|
|
@ -26,6 +26,9 @@ Args::Args(const QApplication &app)
|
|||
// Added to ignore the parent-window option passed during native messaging
|
||||
QCommandLineOption parentWindowOption("parent-window");
|
||||
parentWindowOption.setFlags(QCommandLineOption::HiddenFromHelp);
|
||||
QCommandLineOption parentWindowIdOption("x-attach-split-to-window", "",
|
||||
"window-id");
|
||||
parentWindowIdOption.setFlags(QCommandLineOption::HiddenFromHelp);
|
||||
|
||||
// Verbose
|
||||
QCommandLineOption verboseOption({{"v", "verbose"},
|
||||
|
@ -37,6 +40,7 @@ Args::Args(const QApplication &app)
|
|||
{{"V", "version"}, "Displays version information."},
|
||||
crashRecoveryOption,
|
||||
parentWindowOption,
|
||||
parentWindowIdOption,
|
||||
verboseOption,
|
||||
});
|
||||
parser.addOption(QCommandLineOption(
|
||||
|
@ -73,6 +77,15 @@ Args::Args(const QApplication &app)
|
|||
|
||||
this->printVersion = parser.isSet("V");
|
||||
this->crashRecovery = parser.isSet("crash-recovery");
|
||||
|
||||
if (parser.isSet(parentWindowIdOption))
|
||||
{
|
||||
this->isFramelessEmbed = true;
|
||||
this->dontSaveSettings = true;
|
||||
this->dontLoadMainWindow = true;
|
||||
|
||||
this->parentWindowId = parser.value(parentWindowIdOption).toULongLong();
|
||||
}
|
||||
}
|
||||
|
||||
void Args::applyCustomChannelLayout(const QString &argValue)
|
||||
|
|
|
@ -15,7 +15,13 @@ public:
|
|||
bool printVersion{};
|
||||
bool crashRecovery{};
|
||||
bool shouldRunBrowserExtensionHost{};
|
||||
// Shows a single chat. Used on windows to embed in another application.
|
||||
bool isFramelessEmbed{};
|
||||
boost::optional<unsigned long long> parentWindowId{};
|
||||
|
||||
// Not settings directly
|
||||
bool dontSaveSettings{};
|
||||
bool dontLoadMainWindow{};
|
||||
boost::optional<WindowLayout> customChannelLayout;
|
||||
bool verbose{};
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "util/Clamp.hpp"
|
||||
#include "util/CombinePath.hpp"
|
||||
#include "widgets/AccountSwitchPopup.hpp"
|
||||
#include "widgets/FramelessEmbedWindow.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/Window.hpp"
|
||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||
|
@ -130,6 +131,8 @@ WindowManager::WindowManager()
|
|||
});
|
||||
}
|
||||
|
||||
WindowManager::~WindowManager() = default;
|
||||
|
||||
MessageElementFlags WindowManager::getWordFlags()
|
||||
{
|
||||
return this->wordFlags_;
|
||||
|
@ -269,22 +272,14 @@ Window &WindowManager::createWindow(WindowType type, bool show)
|
|||
return *window;
|
||||
}
|
||||
|
||||
int WindowManager::windowCount()
|
||||
void WindowManager::select(Split *split)
|
||||
{
|
||||
return this->windows_.size();
|
||||
this->selectSplit.invoke(split);
|
||||
}
|
||||
|
||||
Window *WindowManager::windowAt(int index)
|
||||
void WindowManager::select(SplitContainer *container)
|
||||
{
|
||||
assertInGuiThread();
|
||||
|
||||
if (index < 0 || (size_t)index >= this->windows_.size())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
qCDebug(chatterinoWindowmanager) << "getting window at bad index" << index;
|
||||
|
||||
return this->windows_.at(index);
|
||||
this->selectSplitContainer.invoke(container);
|
||||
}
|
||||
|
||||
QPoint WindowManager::emotePopupPos()
|
||||
|
@ -324,11 +319,23 @@ void WindowManager::initialize(Settings &settings, Paths &paths)
|
|||
this->applyWindowLayout(windowLayout);
|
||||
}
|
||||
|
||||
if (getArgs().isFramelessEmbed)
|
||||
{
|
||||
this->framelessEmbedWindow_.reset(new FramelessEmbedWindow);
|
||||
this->framelessEmbedWindow_->show();
|
||||
}
|
||||
|
||||
// No main window has been created from loading, create an empty one
|
||||
if (this->mainWindow_ == nullptr)
|
||||
{
|
||||
this->mainWindow_ = &this->createWindow(WindowType::Main);
|
||||
this->mainWindow_->getNotebook().addPage(true);
|
||||
|
||||
// TODO: don't create main window if it's a frameless embed
|
||||
if (getArgs().isFramelessEmbed)
|
||||
{
|
||||
this->mainWindow_->hide();
|
||||
}
|
||||
}
|
||||
|
||||
settings.timestampFormat.connect([this](auto, auto) {
|
||||
|
@ -634,6 +641,11 @@ WindowLayout WindowManager::loadWindowLayoutFromFile() const
|
|||
|
||||
void WindowManager::applyWindowLayout(const WindowLayout &layout)
|
||||
{
|
||||
if (getArgs().dontLoadMainWindow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set emote popup position
|
||||
this->emotePopupPos_ = layout.emotePopupPos_;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "common/Channel.hpp"
|
||||
#include "common/FlagsEnum.hpp"
|
||||
#include "common/Singleton.hpp"
|
||||
|
@ -19,6 +20,7 @@ using MessageElementFlags = FlagsEnum<MessageElementFlag>;
|
|||
enum class WindowType;
|
||||
|
||||
enum class SettingsDialogPreference;
|
||||
class FramelessEmbedWindow;
|
||||
|
||||
class WindowManager final : public Singleton
|
||||
{
|
||||
|
@ -26,6 +28,7 @@ public:
|
|||
static const QString WINDOW_LAYOUT_FILENAME;
|
||||
|
||||
WindowManager();
|
||||
~WindowManager() override;
|
||||
|
||||
static void encodeChannel(IndirectChannel channel, QJsonObject &obj);
|
||||
static void encodeFilters(Split *split, QJsonArray &arr);
|
||||
|
@ -53,8 +56,8 @@ public:
|
|||
Window &getSelectedWindow();
|
||||
Window &createWindow(WindowType type, bool show = true);
|
||||
|
||||
int windowCount();
|
||||
Window *windowAt(int index);
|
||||
void select(Split *split);
|
||||
void select(SplitContainer *container);
|
||||
|
||||
QPoint emotePopupPos();
|
||||
void setEmotePopupPos(QPoint pos);
|
||||
|
@ -92,6 +95,9 @@ public:
|
|||
// It is currently being used by the "Tooltip Preview Image" system to recheck if an image is ready to be rendered.
|
||||
pajlada::Signals::NoArgSignal miscUpdate;
|
||||
|
||||
pajlada::Signals::Signal<Split *> selectSplit;
|
||||
pajlada::Signals::Signal<SplitContainer *> selectSplitContainer;
|
||||
|
||||
private:
|
||||
void encodeNodeRecursively(SplitContainer::Node *node, QJsonObject &obj);
|
||||
|
||||
|
@ -112,6 +118,7 @@ private:
|
|||
|
||||
std::vector<Window *> windows_;
|
||||
|
||||
std::unique_ptr<FramelessEmbedWindow> framelessEmbedWindow_;
|
||||
Window *mainWindow_{};
|
||||
Window *selectedWindow_{};
|
||||
|
||||
|
|
100
src/widgets/FramelessEmbedWindow.cpp
Normal file
100
src/widgets/FramelessEmbedWindow.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include "FramelessEmbedWindow.hpp"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include "Application.hpp"
|
||||
#include "QJsonDocument"
|
||||
#include "QMessageBox"
|
||||
#include "providers/twitch/TwitchIrcServer.hpp"
|
||||
//#include "widgets/helper/ChannelView.hpp"
|
||||
#include "common/Args.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
#ifdef USEWINSDK
|
||||
# include "Windows.h"
|
||||
#endif
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
FramelessEmbedWindow::FramelessEmbedWindow()
|
||||
: BaseWindow(BaseWindow::Frameless)
|
||||
{
|
||||
this->split_ = new Split((QWidget *)nullptr);
|
||||
auto layout = new QHBoxLayout;
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(this->split_);
|
||||
|
||||
this->getLayoutContainer()->setLayout(layout);
|
||||
}
|
||||
|
||||
#ifdef USEWINSDK
|
||||
bool FramelessEmbedWindow::nativeEvent(const QByteArray &eventType,
|
||||
void *message, long *result)
|
||||
{
|
||||
# if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
|
||||
MSG *msg = *reinterpret_cast<MSG **>(message);
|
||||
# else
|
||||
MSG *msg = reinterpret_cast<MSG *>(message);
|
||||
# endif
|
||||
|
||||
if (msg->message == WM_COPYDATA)
|
||||
{
|
||||
auto data = reinterpret_cast<COPYDATASTRUCT *>(msg->lParam);
|
||||
|
||||
// no idea why I have to read it to a string and then encode it back to utf-8
|
||||
auto str = QString::fromUtf8(reinterpret_cast<char *>(data->lpData),
|
||||
int(data->cbData));
|
||||
auto doc = QJsonDocument::fromJson(str.toUtf8());
|
||||
|
||||
auto root = doc.object();
|
||||
if (root.value("type").toString() == "set-channel")
|
||||
{
|
||||
if (root.value("provider").toString() == "twitch")
|
||||
{
|
||||
auto channelName = root.value("channel-name").toString();
|
||||
|
||||
this->split_->setChannel(
|
||||
getApp()->twitch2->getOrAddChannel(channelName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BaseWidget::nativeEvent(eventType, message, result);
|
||||
}
|
||||
|
||||
void FramelessEmbedWindow::showEvent(QShowEvent *)
|
||||
{
|
||||
if (!getArgs().parentWindowId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto parentHwnd =
|
||||
reinterpret_cast<HWND>(getArgs().parentWindowId.get()))
|
||||
{
|
||||
auto handle = reinterpret_cast<HWND>(this->winId());
|
||||
if (!::SetParent(handle, parentHwnd))
|
||||
{
|
||||
qApp->exit(1);
|
||||
}
|
||||
|
||||
QJsonDocument doc;
|
||||
QJsonObject root;
|
||||
root.insert("type", "created-window");
|
||||
root.insert(
|
||||
"window-id",
|
||||
QString::number(reinterpret_cast<unsigned long long>(handle)));
|
||||
doc.setObject(root);
|
||||
auto json = doc.toJson();
|
||||
json.append('\0');
|
||||
|
||||
COPYDATASTRUCT cds;
|
||||
cds.cbData = static_cast<DWORD>(json.size());
|
||||
cds.lpData = json.data();
|
||||
|
||||
::SendMessage(parentHwnd, WM_COPYDATA, reinterpret_cast<WPARAM>(handle),
|
||||
reinterpret_cast<LPARAM>(&cds));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace chatterino
|
25
src/widgets/FramelessEmbedWindow.hpp
Normal file
25
src/widgets/FramelessEmbedWindow.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Split;
|
||||
|
||||
class FramelessEmbedWindow : public BaseWindow
|
||||
{
|
||||
public:
|
||||
FramelessEmbedWindow();
|
||||
|
||||
protected:
|
||||
#ifdef USEWINSDK
|
||||
bool nativeEvent(const QByteArray &eventType, void *message,
|
||||
long *result) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
Split *split_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
|
@ -631,6 +631,29 @@ SplitNotebook::SplitNotebook(Window *parent)
|
|||
{
|
||||
this->addCustomButtons();
|
||||
}
|
||||
|
||||
this->signalHolder_.managedConnect(
|
||||
getApp()->windows->selectSplit, [this](Split *split) {
|
||||
for (auto &&item : this->items())
|
||||
{
|
||||
if (auto sc = dynamic_cast<SplitContainer *>(item.page))
|
||||
{
|
||||
auto &&splits = sc->getSplits();
|
||||
if (std::find(splits.begin(), splits.end(), split) !=
|
||||
splits.end())
|
||||
{
|
||||
this->select(item.page);
|
||||
split->setFocus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this->signalHolder_.managedConnect(getApp()->windows->selectSplitContainer,
|
||||
[this](SplitContainer *sc) {
|
||||
this->select(sc);
|
||||
});
|
||||
}
|
||||
|
||||
void SplitNotebook::showEvent(QShowEvent *)
|
||||
|
|
|
@ -64,13 +64,18 @@ protected:
|
|||
NotebookButton *getAddButton();
|
||||
NotebookButton *addCustomButton();
|
||||
|
||||
private:
|
||||
struct Item {
|
||||
NotebookTab *tab{};
|
||||
QWidget *page{};
|
||||
QWidget *selectedWidget{};
|
||||
};
|
||||
|
||||
const QList<Item> items()
|
||||
{
|
||||
return items_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool containsPage(QWidget *page);
|
||||
Item &findItem(QWidget *page);
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ void QuickSwitcherPopup::updateSuggestions(const QString &text)
|
|||
if (split->getChannel()->getName().contains(text,
|
||||
Qt::CaseInsensitive))
|
||||
{
|
||||
auto item = std::make_unique<SwitchSplitItem>(split);
|
||||
auto item = std::make_unique<SwitchSplitItem>(sc, split);
|
||||
this->switcherModel_.addItem(std::move(item));
|
||||
|
||||
// We want to continue the outer loop so we need a goto
|
||||
|
|
|
@ -7,31 +7,23 @@
|
|||
|
||||
namespace chatterino {
|
||||
|
||||
SwitchSplitItem::SwitchSplitItem(Split *split)
|
||||
: AbstractSwitcherItem(QIcon(":switcher/switch.svg"))
|
||||
, split_(split)
|
||||
, container_(split->getContainer())
|
||||
{
|
||||
}
|
||||
|
||||
SwitchSplitItem::SwitchSplitItem(SplitContainer *container)
|
||||
SwitchSplitItem::SwitchSplitItem(SplitContainer *container, Split *split)
|
||||
: AbstractSwitcherItem(QIcon(":switcher/switch.svg"))
|
||||
, container_(container)
|
||||
, split_(split)
|
||||
{
|
||||
assert(this->container_ != nullptr);
|
||||
}
|
||||
|
||||
void SwitchSplitItem::action()
|
||||
{
|
||||
auto &nb = getApp()->windows->getMainWindow().getNotebook();
|
||||
nb.select(this->container_);
|
||||
|
||||
/*
|
||||
* If the item is referring to a specific channel, select the
|
||||
* corresponding split.
|
||||
*/
|
||||
if (this->split_)
|
||||
{
|
||||
this->container_->setSelected(this->split_);
|
||||
getApp()->windows->select(this->split_);
|
||||
}
|
||||
else if (this->container_)
|
||||
{
|
||||
getApp()->windows->select(this->container_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@ namespace chatterino {
|
|||
class SwitchSplitItem : public AbstractSwitcherItem
|
||||
{
|
||||
public:
|
||||
SwitchSplitItem(Split *split);
|
||||
SwitchSplitItem(SplitContainer *container);
|
||||
SwitchSplitItem(SplitContainer *container, Split *split = nullptr);
|
||||
|
||||
virtual void action() override;
|
||||
|
||||
|
@ -22,8 +21,8 @@ public:
|
|||
virtual QSize sizeHint(const QRect &rect) const override;
|
||||
|
||||
private:
|
||||
Split *split_{};
|
||||
SplitContainer *container_{};
|
||||
Split *split_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/helper/ResizingTextEdit.hpp"
|
||||
#include "widgets/helper/SearchPopup.hpp"
|
||||
#include "widgets/splits/ClosedSplits.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
#include "widgets/splits/SplitHeader.hpp"
|
||||
#include "widgets/splits/SplitInput.hpp"
|
||||
|
@ -78,15 +77,8 @@ namespace {
|
|||
pajlada::Signals::Signal<Qt::KeyboardModifiers> Split::modifierStatusChanged;
|
||||
Qt::KeyboardModifiers Split::modifierStatus = Qt::NoModifier;
|
||||
|
||||
Split::Split(SplitContainer *parent)
|
||||
: Split(static_cast<QWidget *>(parent))
|
||||
{
|
||||
this->container_ = parent;
|
||||
}
|
||||
|
||||
Split::Split(QWidget *parent)
|
||||
: BaseWidget(parent)
|
||||
, container_(nullptr)
|
||||
, channel_(Channel::getEmpty())
|
||||
, vbox_(new QVBoxLayout(this))
|
||||
, header_(new SplitHeader(this))
|
||||
|
@ -173,7 +165,7 @@ Split::Split(QWidget *parent)
|
|||
});
|
||||
|
||||
this->view_->joinToChannel.connect([this](QString twitchChannel) {
|
||||
this->container_->appendNewSplit(false)->setChannel(
|
||||
this->openSplitRequested.invoke(
|
||||
getApp()->twitch.server->getOrAddChannel(twitchChannel));
|
||||
});
|
||||
|
||||
|
@ -294,21 +286,6 @@ ChannelView &Split::getChannelView()
|
|||
return *this->view_;
|
||||
}
|
||||
|
||||
SplitContainer *Split::getContainer()
|
||||
{
|
||||
return this->container_;
|
||||
}
|
||||
|
||||
bool Split::isInContainer() const
|
||||
{
|
||||
return this->container_ != nullptr;
|
||||
}
|
||||
|
||||
void Split::setContainer(SplitContainer *container)
|
||||
{
|
||||
this->container_ = container;
|
||||
}
|
||||
|
||||
void Split::updateInputPlaceholder()
|
||||
{
|
||||
if (!this->getChannel()->isTwitchChannel())
|
||||
|
@ -388,7 +365,7 @@ void Split::setChannel(IndirectChannel newChannel)
|
|||
}
|
||||
|
||||
this->channel_.get()->displayNameChanged.connect([this] {
|
||||
this->container_->refreshTab();
|
||||
this->actionRequested.invoke(Action::RefreshTab);
|
||||
});
|
||||
|
||||
this->channelChanged.invoke();
|
||||
|
@ -435,10 +412,7 @@ void Split::showChangeChannelPopup(const char *dialogTitle, bool empty,
|
|||
if (dialog->hasSeletedChannel())
|
||||
{
|
||||
this->setChannel(dialog->getSelectedChannel());
|
||||
if (this->isInContainer())
|
||||
{
|
||||
this->container_->refreshTab();
|
||||
}
|
||||
this->actionRequested.invoke(Action::RefreshTab);
|
||||
}
|
||||
|
||||
callback(dialog->hasSeletedChannel());
|
||||
|
@ -514,10 +488,7 @@ void Split::enterEvent(QEvent *event)
|
|||
this->overlay_->show();
|
||||
}
|
||||
|
||||
if (this->container_ != nullptr)
|
||||
{
|
||||
this->container_->resetMouseStatus();
|
||||
}
|
||||
this->actionRequested.invoke(Action::ResetMouseStatus);
|
||||
}
|
||||
|
||||
void Split::leaveEvent(QEvent *event)
|
||||
|
@ -554,23 +525,12 @@ void Split::setIsTopRightSplit(bool value)
|
|||
/// Slots
|
||||
void Split::addSibling()
|
||||
{
|
||||
if (this->container_)
|
||||
{
|
||||
this->container_->appendNewSplit(true);
|
||||
}
|
||||
this->actionRequested.invoke(Action::AppendNewSplit);
|
||||
}
|
||||
|
||||
void Split::deleteFromContainer()
|
||||
{
|
||||
if (this->container_)
|
||||
{
|
||||
this->container_->deleteSplit(this);
|
||||
auto *tab = this->getContainer()->getTab();
|
||||
tab->connect(tab, &QWidget::destroyed, [tab]() mutable {
|
||||
ClosedSplits::invalidateTab(tab);
|
||||
});
|
||||
ClosedSplits::push({this->getChannel()->getName(), tab});
|
||||
}
|
||||
this->actionRequested.invoke(Action::Delete);
|
||||
}
|
||||
|
||||
void Split::changeChannel()
|
||||
|
|
|
@ -38,7 +38,6 @@ class Split : public BaseWidget, pajlada::Signals::SignalHolder
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Split(SplitContainer *parent);
|
||||
explicit Split(QWidget *parent);
|
||||
|
||||
~Split() override;
|
||||
|
@ -48,7 +47,6 @@ public:
|
|||
pajlada::Signals::NoArgSignal focusLost;
|
||||
|
||||
ChannelView &getChannelView();
|
||||
SplitContainer *getContainer();
|
||||
|
||||
IndirectChannel getIndirectChannel();
|
||||
ChannelPtr getChannel();
|
||||
|
@ -80,6 +78,24 @@ public:
|
|||
modifierStatusChanged;
|
||||
static Qt::KeyboardModifiers modifierStatus;
|
||||
|
||||
enum class Action {
|
||||
RefreshTab,
|
||||
ResetMouseStatus,
|
||||
AppendNewSplit,
|
||||
Delete,
|
||||
|
||||
SelectSplitLeft,
|
||||
SelectSplitRight,
|
||||
SelectSplitAbove,
|
||||
SelectSplitBelow,
|
||||
};
|
||||
|
||||
pajlada::Signals::Signal<Action> actionRequested;
|
||||
pajlada::Signals::Signal<ChannelPtr> openSplitRequested;
|
||||
|
||||
// args: (SplitContainer::Direction dir, Split* parent)
|
||||
pajlada::Signals::Signal<int, Split *> insertSplitRequested;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
@ -98,7 +114,6 @@ private:
|
|||
void handleModifiers(Qt::KeyboardModifiers modifiers);
|
||||
void updateInputPlaceholder();
|
||||
|
||||
SplitContainer *container_;
|
||||
IndirectChannel channel_;
|
||||
|
||||
bool moderationMode_{};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/splits/ClosedSplits.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -160,8 +161,6 @@ void SplitContainer::insertSplit(Split *split, Direction direction,
|
|||
|
||||
assertInGuiThread();
|
||||
|
||||
split->setContainer(this);
|
||||
|
||||
if (relativeTo == nullptr)
|
||||
{
|
||||
if (this->baseNode_.type_ == Node::EmptyRoot)
|
||||
|
@ -211,7 +210,9 @@ void SplitContainer::addSplit(Split *split)
|
|||
|
||||
this->refreshTab();
|
||||
|
||||
this->managedConnect(split->getChannelView().tabHighlightRequested,
|
||||
auto &&conns = this->connectionsPerSplit_[split];
|
||||
|
||||
conns.managedConnect(split->getChannelView().tabHighlightRequested,
|
||||
[this](HighlightState state) {
|
||||
if (this->tab_ != nullptr)
|
||||
{
|
||||
|
@ -219,14 +220,64 @@ void SplitContainer::addSplit(Split *split)
|
|||
}
|
||||
});
|
||||
|
||||
this->managedConnect(split->getChannelView().liveStatusChanged, [this]() {
|
||||
conns.managedConnect(split->getChannelView().liveStatusChanged, [this]() {
|
||||
this->refreshTabLiveStatus();
|
||||
});
|
||||
|
||||
this->managedConnect(split->focused, [this, split] {
|
||||
conns.managedConnect(split->focused, [this, split] {
|
||||
this->setSelected(split);
|
||||
});
|
||||
|
||||
conns.managedConnect(split->openSplitRequested, [this](auto channel) {
|
||||
this->appendNewSplit(false)->setChannel(channel);
|
||||
});
|
||||
|
||||
conns.managedConnect(
|
||||
split->actionRequested, [this, split](Split::Action action) {
|
||||
switch (action)
|
||||
{
|
||||
case Split::Action::RefreshTab:
|
||||
this->refreshTab();
|
||||
break;
|
||||
|
||||
case Split::Action::ResetMouseStatus:
|
||||
this->resetMouseStatus();
|
||||
break;
|
||||
|
||||
case Split::Action::AppendNewSplit:
|
||||
this->appendNewSplit(true);
|
||||
break;
|
||||
|
||||
case Split::Action::Delete: {
|
||||
this->deleteSplit(split);
|
||||
auto *tab = this->getTab();
|
||||
tab->connect(tab, &QWidget::destroyed, [tab]() mutable {
|
||||
ClosedSplits::invalidateTab(tab);
|
||||
});
|
||||
ClosedSplits::push({split->getChannel()->getName(), tab});
|
||||
}
|
||||
break;
|
||||
|
||||
case Split::Action::SelectSplitLeft:
|
||||
this->selectNextSplit(SplitContainer::Left);
|
||||
break;
|
||||
case Split::Action::SelectSplitRight:
|
||||
this->selectNextSplit(SplitContainer::Right);
|
||||
break;
|
||||
case Split::Action::SelectSplitAbove:
|
||||
this->selectNextSplit(SplitContainer::Above);
|
||||
break;
|
||||
case Split::Action::SelectSplitBelow:
|
||||
this->selectNextSplit(SplitContainer::Below);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
conns.managedConnect(split->insertSplitRequested, [this](int dir,
|
||||
Split *parent) {
|
||||
this->insertSplit(new Split(this), static_cast<Direction>(dir), parent);
|
||||
});
|
||||
|
||||
this->layout();
|
||||
}
|
||||
|
||||
|
@ -282,10 +333,7 @@ SplitContainer::Position SplitContainer::releaseSplit(Split *split)
|
|||
|
||||
this->refreshTab();
|
||||
|
||||
// fourtf: really bad
|
||||
split->getChannelView().tabHighlightRequested.disconnectAll();
|
||||
|
||||
split->getChannelView().tabHighlightRequested.disconnectAll();
|
||||
this->connectionsPerSplit_.erase(this->connectionsPerSplit_.find(split));
|
||||
|
||||
return position;
|
||||
}
|
||||
|
|
|
@ -255,6 +255,9 @@ private:
|
|||
NotebookTab *tab_;
|
||||
std::vector<Split *> splits_;
|
||||
|
||||
std::unordered_map<Split *, pajlada::Signals::SignalHolder>
|
||||
connectionsPerSplit_;
|
||||
|
||||
bool isDragging_ = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -247,12 +247,8 @@ void SplitInput::installKeyPressedEvent()
|
|||
}
|
||||
if (event->modifiers() == Qt::AltModifier)
|
||||
{
|
||||
SplitContainer *page = this->split_->getContainer();
|
||||
|
||||
if (page != nullptr)
|
||||
{
|
||||
page->selectNextSplit(SplitContainer::Above);
|
||||
}
|
||||
this->split_->actionRequested.invoke(
|
||||
Split::Action::SelectSplitAbove);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -312,49 +308,37 @@ void SplitInput::installKeyPressedEvent()
|
|||
event->modifiers() == Qt::AltModifier)
|
||||
{
|
||||
// h: vim binding for left
|
||||
SplitContainer *page = this->split_->getContainer();
|
||||
event->accept();
|
||||
this->split_->actionRequested.invoke(
|
||||
Split::Action::SelectSplitLeft);
|
||||
|
||||
if (page != nullptr)
|
||||
{
|
||||
page->selectNextSplit(SplitContainer::Left);
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
else if (event->key() == Qt::Key_J &&
|
||||
event->modifiers() == Qt::AltModifier)
|
||||
{
|
||||
// j: vim binding for down
|
||||
SplitContainer *page = this->split_->getContainer();
|
||||
event->accept();
|
||||
this->split_->actionRequested.invoke(
|
||||
Split::Action::SelectSplitBelow);
|
||||
|
||||
if (page != nullptr)
|
||||
{
|
||||
page->selectNextSplit(SplitContainer::Below);
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
else if (event->key() == Qt::Key_K &&
|
||||
event->modifiers() == Qt::AltModifier)
|
||||
{
|
||||
// k: vim binding for up
|
||||
SplitContainer *page = this->split_->getContainer();
|
||||
event->accept();
|
||||
this->split_->actionRequested.invoke(
|
||||
Split::Action::SelectSplitAbove);
|
||||
|
||||
if (page != nullptr)
|
||||
{
|
||||
page->selectNextSplit(SplitContainer::Above);
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
else if (event->key() == Qt::Key_L &&
|
||||
event->modifiers() == Qt::AltModifier)
|
||||
{
|
||||
// l: vim binding for right
|
||||
SplitContainer *page = this->split_->getContainer();
|
||||
event->accept();
|
||||
this->split_->actionRequested.invoke(
|
||||
Split::Action::SelectSplitRight);
|
||||
|
||||
if (page != nullptr)
|
||||
{
|
||||
page->selectNextSplit(SplitContainer::Right);
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
else if (event->key() == Qt::Key_Down)
|
||||
{
|
||||
|
@ -364,12 +348,8 @@ void SplitInput::installKeyPressedEvent()
|
|||
}
|
||||
if (event->modifiers() == Qt::AltModifier)
|
||||
{
|
||||
SplitContainer *page = this->split_->getContainer();
|
||||
|
||||
if (page != nullptr)
|
||||
{
|
||||
page->selectNextSplit(SplitContainer::Below);
|
||||
}
|
||||
this->split_->actionRequested.invoke(
|
||||
Split::Action::SelectSplitBelow);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -422,24 +402,16 @@ void SplitInput::installKeyPressedEvent()
|
|||
{
|
||||
if (event->modifiers() == Qt::AltModifier)
|
||||
{
|
||||
SplitContainer *page = this->split_->getContainer();
|
||||
|
||||
if (page != nullptr)
|
||||
{
|
||||
page->selectNextSplit(SplitContainer::Left);
|
||||
}
|
||||
this->split_->actionRequested.invoke(
|
||||
Split::Action::SelectSplitLeft);
|
||||
}
|
||||
}
|
||||
else if (event->key() == Qt::Key_Right)
|
||||
{
|
||||
if (event->modifiers() == Qt::AltModifier)
|
||||
{
|
||||
SplitContainer *page = this->split_->getContainer();
|
||||
|
||||
if (page != nullptr)
|
||||
{
|
||||
page->selectNextSplit(SplitContainer::Right);
|
||||
}
|
||||
this->split_->actionRequested.invoke(
|
||||
Split::Action::SelectSplitRight);
|
||||
}
|
||||
}
|
||||
else if ((event->key() == Qt::Key_C ||
|
||||
|
|
|
@ -220,20 +220,15 @@ bool SplitOverlay::ButtonEventFilter::eventFilter(QObject *watched,
|
|||
case QEvent::MouseButtonRelease: {
|
||||
if (this->hoveredElement != HoveredElement::SplitMove)
|
||||
{
|
||||
SplitContainer *container =
|
||||
this->parent->split_->getContainer();
|
||||
auto dir = SplitContainer::Direction(
|
||||
this->hoveredElement + SplitContainer::Left - SplitLeft);
|
||||
|
||||
this->parent->split_->insertSplitRequested.invoke(
|
||||
static_cast<int>(dir), this->parent->split_);
|
||||
|
||||
if (container != nullptr)
|
||||
{
|
||||
auto *_split = new Split(container);
|
||||
auto dir = SplitContainer::Direction(this->hoveredElement +
|
||||
SplitContainer::Left -
|
||||
SplitLeft);
|
||||
container->insertSplit(_split, dir, this->parent->split_);
|
||||
this->parent->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue