mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
parent
4ec2c0d8b3
commit
cb06579c29
19 changed files with 291 additions and 316 deletions
|
@ -21,10 +21,10 @@ Application::Application()
|
|||
|
||||
singletons::LoggingManager::getInstance();
|
||||
|
||||
singletons::SettingManager::getInstance().init();
|
||||
singletons::SettingManager::getInstance().initialize();
|
||||
singletons::CommandManager::getInstance().loadCommands();
|
||||
|
||||
singletons::WindowManager::getInstance().initMainWindow();
|
||||
singletons::WindowManager::getInstance().initialize();
|
||||
|
||||
// Initialize everything we need
|
||||
singletons::EmoteManager::getInstance().loadGlobalEmotes();
|
||||
|
|
|
@ -47,7 +47,7 @@ bool SettingManager::isIgnoredEmote(const QString &)
|
|||
return false;
|
||||
}
|
||||
|
||||
void SettingManager::init()
|
||||
void SettingManager::initialize()
|
||||
{
|
||||
QString settingsPath = PathManager::getInstance().settingsFolderPath + "/settings.json";
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
messages::MessageElement::Flags getWordFlags();
|
||||
bool isIgnoredEmote(const QString &emote);
|
||||
|
||||
void init();
|
||||
void initialize();
|
||||
|
||||
/// Appearance
|
||||
BoolSetting showTimestamps = {"/appearance/messages/showTimestamps", true};
|
||||
|
|
|
@ -129,8 +129,8 @@ void ThemeManager::actuallyUpdate(double hue, double multiplier)
|
|||
this->messages.textColors.system = QColor(140, 127, 127);
|
||||
|
||||
this->messages.backgrounds.regular = splits.background;
|
||||
this->messages.backgrounds.highlighted = blendColors(
|
||||
this->tabs.selected.backgrounds.regular.color(), this->messages.backgrounds.regular, 0.8);
|
||||
this->messages.backgrounds.highlighted =
|
||||
blendColors(themeColor, this->messages.backgrounds.regular, 0.8);
|
||||
// this->messages.backgrounds.resub
|
||||
// this->messages.backgrounds.whisper
|
||||
this->messages.disabled = getColor(0, sat, 1, 0.6);
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#include "windowmanager.hpp"
|
||||
#include "debug/log.hpp"
|
||||
#include "providers/twitch/twitchserver.hpp"
|
||||
#include "singletons/fontmanager.hpp"
|
||||
#include "singletons/pathmanager.hpp"
|
||||
#include "singletons/thememanager.hpp"
|
||||
#include "widgets/accountswitchpopupwidget.hpp"
|
||||
#include "widgets/settingsdialog.hpp"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#define SETTINGS_FILENAME "/layout.json"
|
||||
|
||||
namespace chatterino {
|
||||
namespace singletons {
|
||||
|
||||
|
@ -51,11 +58,6 @@ WindowManager::WindowManager(ThemeManager &_themeManager)
|
|||
_themeManager.repaintVisibleChatWidgets.connect([this] { this->repaintVisibleChatWidgets(); });
|
||||
}
|
||||
|
||||
void WindowManager::initMainWindow()
|
||||
{
|
||||
this->selectedWindow = this->mainWindow = new widgets::Window("main", this->themeManager, true);
|
||||
}
|
||||
|
||||
void WindowManager::layoutVisibleChatWidgets(Channel *channel)
|
||||
{
|
||||
this->layout.invoke(channel);
|
||||
|
@ -90,12 +92,12 @@ widgets::Window &WindowManager::getSelectedWindow()
|
|||
return *this->selectedWindow;
|
||||
}
|
||||
|
||||
widgets::Window &WindowManager::createWindow()
|
||||
widgets::Window &WindowManager::createWindow(widgets::Window::WindowType type)
|
||||
{
|
||||
auto *window = new widgets::Window("external", this->themeManager, false);
|
||||
window->getNotebook().addNewPage();
|
||||
auto *window = new widgets::Window(this->themeManager, type);
|
||||
|
||||
this->windows.push_back(window);
|
||||
window->show();
|
||||
|
||||
return *window;
|
||||
}
|
||||
|
@ -115,14 +117,168 @@ widgets::Window *WindowManager::windowAt(int index)
|
|||
return this->windows.at(index);
|
||||
}
|
||||
|
||||
void WindowManager::initialize()
|
||||
{
|
||||
assert(!this->initialized);
|
||||
|
||||
// load file
|
||||
QString settingsPath = PathManager::getInstance().settingsFolderPath + SETTINGS_FILENAME;
|
||||
QFile file(settingsPath);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QByteArray data = file.readAll();
|
||||
QJsonDocument document = QJsonDocument::fromJson(data);
|
||||
QJsonArray windows_arr = document.object().value("windows").toArray();
|
||||
|
||||
// "deserialize"
|
||||
for (QJsonValue window_val : windows_arr) {
|
||||
QJsonObject window_obj = window_val.toObject();
|
||||
|
||||
// get type
|
||||
QString type_val = window_obj.value("type").toString();
|
||||
widgets::Window::WindowType type =
|
||||
type_val == "main" ? widgets::Window::Main : widgets::Window::Popup;
|
||||
|
||||
if (type == widgets::Window::Main && mainWindow != nullptr) {
|
||||
type = widgets::Window::Popup;
|
||||
}
|
||||
|
||||
widgets::Window &window = createWindow(type);
|
||||
|
||||
if (type == widgets::Window::Main) {
|
||||
mainWindow = &window;
|
||||
}
|
||||
|
||||
// get geometry
|
||||
{
|
||||
int x = window_obj.value("x").toInt(-1);
|
||||
int y = window_obj.value("y").toInt(-1);
|
||||
int width = window_obj.value("width").toInt(-1);
|
||||
int height = window_obj.value("height").toInt(-1);
|
||||
|
||||
if (x != -1 && y != -1 && width != -1 && height != -1) {
|
||||
window.setGeometry(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
// load tabs
|
||||
QJsonArray tabs = window_obj.value("tabs").toArray();
|
||||
for (QJsonValue tab_val : tabs) {
|
||||
widgets::SplitContainer *tab = window.getNotebook().addNewPage();
|
||||
|
||||
QJsonObject tab_obj = tab_val.toObject();
|
||||
|
||||
// set custom title
|
||||
QJsonValue title_val = tab_obj.value("title");
|
||||
if (title_val.isString()) {
|
||||
tab->getTab()->setTitle(title_val.toString());
|
||||
tab->getTab()->useDefaultTitle = false;
|
||||
}
|
||||
|
||||
// load splits
|
||||
int colNr = 0;
|
||||
for (QJsonValue column_val : tab_obj.value("splits").toArray()) {
|
||||
for (QJsonValue split_val : column_val.toArray()) {
|
||||
widgets::Split *split = new widgets::Split(tab);
|
||||
|
||||
QJsonObject split_obj = split_val.toObject();
|
||||
QJsonValue channelName_val = split_obj.value("channelName");
|
||||
if (channelName_val.isString()) {
|
||||
split->setChannel(providers::twitch::TwitchServer::getInstance().addChannel(
|
||||
channelName_val.toString()));
|
||||
}
|
||||
|
||||
tab->addToLayout(split, std::make_pair(colNr, -1));
|
||||
}
|
||||
colNr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mainWindow == nullptr) {
|
||||
mainWindow = &createWindow(widgets::Window::Main);
|
||||
mainWindow->getNotebook().addNewPage(true);
|
||||
}
|
||||
|
||||
this->initialized = true;
|
||||
}
|
||||
|
||||
void WindowManager::save()
|
||||
{
|
||||
assert(this->mainWindow);
|
||||
|
||||
this->mainWindow->save();
|
||||
QJsonDocument document;
|
||||
|
||||
// "serialize"
|
||||
QJsonArray window_arr;
|
||||
for (widgets::Window *window : this->windows) {
|
||||
window->save();
|
||||
QJsonObject window_obj;
|
||||
|
||||
// window type
|
||||
switch (window->getType()) {
|
||||
case widgets::Window::Main:
|
||||
window_obj.insert("type", "main");
|
||||
break;
|
||||
case widgets::Window::Popup:
|
||||
window_obj.insert("type", "popup");
|
||||
break;
|
||||
}
|
||||
|
||||
// window geometry
|
||||
window_obj.insert("x", window->x());
|
||||
window_obj.insert("y", window->y());
|
||||
window_obj.insert("width", window->width());
|
||||
window_obj.insert("height", window->height());
|
||||
|
||||
// window tabs
|
||||
QJsonArray tabs_arr;
|
||||
|
||||
for (int tab_i = 0; tab_i < window->getNotebook().tabCount(); tab_i++) {
|
||||
QJsonObject tab_obj;
|
||||
widgets::SplitContainer *tab = window->getNotebook().tabAt(tab_i);
|
||||
|
||||
// custom tab title
|
||||
if (!tab->getTab()->useDefaultTitle) {
|
||||
tab_obj.insert("title", tab->getTab()->getTitle());
|
||||
}
|
||||
|
||||
// splits
|
||||
QJsonArray columns_arr;
|
||||
std::vector<std::vector<widgets::Split *>> columns = tab->getColumns();
|
||||
|
||||
for (std::vector<widgets::Split *> &cells : columns) {
|
||||
QJsonArray cells_arr;
|
||||
|
||||
for (widgets::Split *cell : cells) {
|
||||
QJsonObject cell_obj;
|
||||
cell_obj.insert("channelName", cell->getChannel()->name);
|
||||
|
||||
cells_arr.append(cell_obj);
|
||||
}
|
||||
columns_arr.append(cells_arr);
|
||||
}
|
||||
|
||||
tab_obj.insert("splits", columns_arr);
|
||||
tabs_arr.append(tab_obj);
|
||||
}
|
||||
|
||||
window_obj.insert("tabs", tabs_arr);
|
||||
window_arr.append(window_obj);
|
||||
}
|
||||
|
||||
QJsonObject obj;
|
||||
obj.insert("windows", window_arr);
|
||||
document.setObject(obj);
|
||||
|
||||
// save file
|
||||
QString settingsPath = PathManager::getInstance().settingsFolderPath + SETTINGS_FILENAME;
|
||||
QFile file(settingsPath);
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||
file.write(document.toJson());
|
||||
file.flush();
|
||||
}
|
||||
|
||||
void WindowManager::closeAll()
|
||||
{
|
||||
for (widgets::Window *window : windows) {
|
||||
window->close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ public:
|
|||
void showSettingsDialog();
|
||||
void showAccountSelectPopup(QPoint point);
|
||||
|
||||
void initMainWindow();
|
||||
void layoutVisibleChatWidgets(Channel *channel = nullptr);
|
||||
void repaintVisibleChatWidgets(Channel *channel = nullptr);
|
||||
void repaintGifEmotes();
|
||||
|
@ -25,12 +24,14 @@ public:
|
|||
|
||||
widgets::Window &getMainWindow();
|
||||
widgets::Window &getSelectedWindow();
|
||||
widgets::Window &createWindow();
|
||||
widgets::Window &createWindow(widgets::Window::WindowType type);
|
||||
|
||||
int windowCount();
|
||||
widgets::Window *windowAt(int index);
|
||||
|
||||
void save();
|
||||
void initialize();
|
||||
void closeAll();
|
||||
|
||||
pajlada::Signals::NoArgSignal repaintGifs;
|
||||
pajlada::Signals::Signal<Channel *> layout;
|
||||
|
@ -38,6 +39,8 @@ public:
|
|||
private:
|
||||
ThemeManager &themeManager;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
std::vector<widgets::Window *> windows;
|
||||
|
||||
widgets::Window *mainWindow = nullptr;
|
||||
|
|
|
@ -69,7 +69,12 @@ void BaseWindow::init()
|
|||
layout->addLayout(buttonLayout);
|
||||
|
||||
// title
|
||||
QLabel *title = new QLabel(" Chatterino");
|
||||
// QLabel *title = new QLabel(" Chatterino");
|
||||
QLabel *title = new QLabel("");
|
||||
QSizePolicy policy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
|
||||
policy.setHorizontalStretch(1);
|
||||
title->setBaseSize(0, 0);
|
||||
title->setSizePolicy(policy);
|
||||
buttonLayout->addWidget(title);
|
||||
this->titleLabel = title;
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ ChannelView::ChannelView(BaseWidget *parent)
|
|||
QObject::connect(this->layoutCooldown, &QTimer::timeout, [this] {
|
||||
if (this->layoutQueued) {
|
||||
this->layoutMessages();
|
||||
this->layoutQueued = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -137,15 +138,15 @@ void ChannelView::themeRefreshEvent()
|
|||
|
||||
void ChannelView::queueUpdate()
|
||||
{
|
||||
if (this->updateTimer.isActive()) {
|
||||
this->updateQueued = true;
|
||||
return;
|
||||
}
|
||||
// if (this->updateTimer.isActive()) {
|
||||
// this->updateQueued = true;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// this->repaint();
|
||||
this->update();
|
||||
|
||||
this->updateTimer.start();
|
||||
// this->updateTimer.start();
|
||||
}
|
||||
|
||||
void ChannelView::layoutMessages()
|
||||
|
|
|
@ -17,14 +17,10 @@
|
|||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
NotebookTab::NotebookTab(Notebook *_notebook, const std::string &_uuid)
|
||||
NotebookTab::NotebookTab(Notebook *_notebook)
|
||||
: BaseWidget(_notebook)
|
||||
, uuid(_uuid)
|
||||
, settingRoot(fS("/containers/{}/tab", this->uuid))
|
||||
, positionChangedAnimation(this, "pos")
|
||||
, notebook(_notebook)
|
||||
, title(fS("{}/title", this->settingRoot), "")
|
||||
, useDefaultBehaviour(fS("{}/useDefaultBehaviour", this->settingRoot), true)
|
||||
, menu(this)
|
||||
{
|
||||
this->setAcceptDrops(true);
|
||||
|
@ -40,7 +36,7 @@ NotebookTab::NotebookTab(Notebook *_notebook, const std::string &_uuid)
|
|||
TextInputDialog d(this);
|
||||
|
||||
d.setWindowTitle("Change tab title (Leave empty for default behaviour)");
|
||||
if (this->useDefaultBehaviour) {
|
||||
if (this->useDefaultTitle) {
|
||||
d.setText("");
|
||||
} else {
|
||||
d.setText(this->getTitle());
|
||||
|
@ -49,10 +45,10 @@ NotebookTab::NotebookTab(Notebook *_notebook, const std::string &_uuid)
|
|||
if (d.exec() == QDialog::Accepted) {
|
||||
QString newTitle = d.getText();
|
||||
if (newTitle.isEmpty()) {
|
||||
this->useDefaultBehaviour = true;
|
||||
this->useDefaultTitle = true;
|
||||
this->page->refreshTitle();
|
||||
} else {
|
||||
this->useDefaultBehaviour = false;
|
||||
this->useDefaultTitle = false;
|
||||
this->setTitle(newTitle);
|
||||
}
|
||||
}
|
||||
|
@ -82,11 +78,10 @@ void NotebookTab::updateSize()
|
|||
|
||||
int width;
|
||||
|
||||
QString qTitle(qS(this->title));
|
||||
if (singletons::SettingManager::getInstance().hideTabX) {
|
||||
width = (int)((fontMetrics().width(qTitle) + 16 /*+ 16*/) * scale);
|
||||
width = (int)((fontMetrics().width(this->title) + 16 /*+ 16*/) * scale);
|
||||
} else {
|
||||
width = (int)((fontMetrics().width(qTitle) + 8 + 24 /*+ 16*/) * scale);
|
||||
width = (int)((fontMetrics().width(this->title) + 8 + 24 /*+ 16*/) * scale);
|
||||
}
|
||||
|
||||
this->resize(std::min((int)(150 * scale), width), (int)(24 * scale));
|
||||
|
@ -96,17 +91,15 @@ void NotebookTab::updateSize()
|
|||
}
|
||||
}
|
||||
|
||||
QString NotebookTab::getTitle() const
|
||||
const QString &NotebookTab::getTitle() const
|
||||
{
|
||||
return qS(this->title);
|
||||
return this->title;
|
||||
}
|
||||
|
||||
void NotebookTab::setTitle(const QString &newTitle)
|
||||
{
|
||||
auto stdTitle = newTitle.toStdString();
|
||||
|
||||
if (this->title != stdTitle) {
|
||||
this->title = stdTitle;
|
||||
if (this->title != newTitle) {
|
||||
this->title = newTitle;
|
||||
this->updateSize();
|
||||
this->update();
|
||||
}
|
||||
|
|
|
@ -18,17 +18,14 @@ class NotebookTab : public BaseWidget
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
const std::string uuid;
|
||||
const std::string settingRoot;
|
||||
|
||||
public:
|
||||
explicit NotebookTab(Notebook *_notebook, const std::string &_uuid);
|
||||
explicit NotebookTab(Notebook *_notebook);
|
||||
|
||||
void updateSize();
|
||||
|
||||
SplitContainer *page;
|
||||
|
||||
QString getTitle() const;
|
||||
const QString &getTitle() const;
|
||||
void setTitle(const QString &newTitle);
|
||||
bool isSelected() const;
|
||||
void setSelected(bool value);
|
||||
|
@ -63,10 +60,10 @@ private:
|
|||
|
||||
Notebook *notebook;
|
||||
|
||||
pajlada::Settings::Setting<std::string> title;
|
||||
QString title;
|
||||
|
||||
public:
|
||||
pajlada::Settings::Setting<bool> useDefaultBehaviour;
|
||||
bool useDefaultTitle = true;
|
||||
|
||||
private:
|
||||
bool selected = false;
|
||||
|
|
|
@ -155,7 +155,7 @@ void SplitHeader::scaleChangedEvent(float scale)
|
|||
|
||||
void SplitHeader::updateChannelText()
|
||||
{
|
||||
const QString channelName = this->split->channelName;
|
||||
const QString channelName = this->split->getChannel()->name;
|
||||
if (channelName.isEmpty()) {
|
||||
this->titleLabel->setText("<no channel>");
|
||||
return;
|
||||
|
|
|
@ -22,15 +22,13 @@
|
|||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
Notebook::Notebook(Window *parent, bool _showButtons, const std::string &settingPrefix)
|
||||
Notebook::Notebook(Window *parent, bool _showButtons)
|
||||
: BaseWidget(parent)
|
||||
, settingRoot(fS("{}/notebook", settingPrefix))
|
||||
, parentWindow(parent)
|
||||
, addButton(this)
|
||||
, settingsButton(this)
|
||||
, userButton(this)
|
||||
, showButtons(_showButtons)
|
||||
, tabs(fS("{}/tabs", this->settingRoot))
|
||||
, closeConfirmDialog(this)
|
||||
{
|
||||
this->connect(&this->settingsButton, SIGNAL(clicked()), this, SLOT(settingsButtonClicked()));
|
||||
|
@ -47,8 +45,6 @@ Notebook::Notebook(Window *parent, bool _showButtons, const std::string &setting
|
|||
settingsManager.hidePreferencesButton.connectSimple([this](auto) { this->performLayout(); });
|
||||
settingsManager.hideUserButton.connectSimple([this](auto) { this->performLayout(); });
|
||||
|
||||
this->loadTabs();
|
||||
|
||||
closeConfirmDialog.setText("Are you sure you want to close this tab?");
|
||||
closeConfirmDialog.setIcon(QMessageBox::Icon::Question);
|
||||
closeConfirmDialog.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
|
||||
|
@ -57,15 +53,10 @@ Notebook::Notebook(Window *parent, bool _showButtons, const std::string &setting
|
|||
this->scaleChangedEvent(this->getScale());
|
||||
}
|
||||
|
||||
SplitContainer *Notebook::addNewPage()
|
||||
SplitContainer *Notebook::addNewPage(bool select)
|
||||
{
|
||||
return this->addPage(CreateUUID().toStdString(), true);
|
||||
}
|
||||
|
||||
SplitContainer *Notebook::addPage(const std::string &uuid, bool select)
|
||||
{
|
||||
auto tab = new NotebookTab(this, uuid);
|
||||
auto page = new SplitContainer(this, tab, uuid);
|
||||
auto tab = new NotebookTab(this);
|
||||
auto page = new SplitContainer(this, tab);
|
||||
|
||||
tab->show();
|
||||
|
||||
|
@ -178,6 +169,11 @@ SplitContainer *Notebook::tabAt(QPoint point, int &index, int maxWidth)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
SplitContainer *Notebook::tabAt(int index)
|
||||
{
|
||||
return this->pages[index];
|
||||
}
|
||||
|
||||
void Notebook::rearrangePage(SplitContainer *page, int index)
|
||||
{
|
||||
this->pages.move(this->pages.indexOf(page), index);
|
||||
|
@ -244,7 +240,7 @@ void Notebook::performLayout(bool animated)
|
|||
for (auto &i : this->pages) {
|
||||
if (!first &&
|
||||
(i == this->pages.last() ? tabHeight : 0) + x + i->getTab()->width() > width()) {
|
||||
y += i->getTab()->height() - 1;
|
||||
y += i->getTab()->height();
|
||||
// y += 20;
|
||||
i->getTab()->moveAnimated(QPoint(0, y), animated);
|
||||
x = i->getTab()->width();
|
||||
|
@ -310,33 +306,7 @@ void Notebook::usersButtonClicked()
|
|||
|
||||
void Notebook::addPageButtonClicked()
|
||||
{
|
||||
QTimer::singleShot(80, [this] { this->addNewPage(); });
|
||||
}
|
||||
|
||||
void Notebook::loadTabs()
|
||||
{
|
||||
const std::vector<std::string> tabArray = this->tabs.getValue();
|
||||
|
||||
if (tabArray.size() == 0) {
|
||||
this->addNewPage();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const std::string &tabUUID : tabArray) {
|
||||
this->addPage(tabUUID);
|
||||
}
|
||||
}
|
||||
|
||||
void Notebook::save()
|
||||
{
|
||||
std::vector<std::string> tabArray;
|
||||
|
||||
for (const auto &page : this->pages) {
|
||||
tabArray.push_back(page->getUUID());
|
||||
page->save();
|
||||
}
|
||||
|
||||
this->tabs = tabArray;
|
||||
QTimer::singleShot(80, [this] { this->addNewPage(true); });
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
|
|
|
@ -18,23 +18,24 @@ class Notebook : public BaseWidget
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::string settingRoot;
|
||||
|
||||
public:
|
||||
enum HighlightType { none, highlighted, newMessage };
|
||||
|
||||
explicit Notebook(Window *parent, bool _showButtons, const std::string &settingPrefix);
|
||||
explicit Notebook(Window *parent, bool _showButtons);
|
||||
|
||||
SplitContainer *addNewPage();
|
||||
SplitContainer *addPage(const std::string &uuid, bool select = false);
|
||||
SplitContainer *addNewPage(bool select = false);
|
||||
|
||||
void removePage(SplitContainer *page);
|
||||
void removeCurrentPage();
|
||||
void select(SplitContainer *page);
|
||||
void selectIndex(int index);
|
||||
|
||||
SplitContainer *getSelectedPage() const
|
||||
SplitContainer *getOrAddSelectedPage()
|
||||
{
|
||||
if (selectedPage == nullptr) {
|
||||
this->addNewPage(true);
|
||||
}
|
||||
|
||||
return selectedPage;
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,7 @@ public:
|
|||
|
||||
int tabCount();
|
||||
SplitContainer *tabAt(QPoint point, int &index, int maxWidth = 2000000000);
|
||||
SplitContainer *tabAt(int index);
|
||||
void rearrangePage(SplitContainer *page, int index);
|
||||
|
||||
void nextTab();
|
||||
|
@ -71,14 +73,7 @@ private:
|
|||
|
||||
bool showButtons;
|
||||
|
||||
pajlada::Settings::Setting<std::vector<std::string>> tabs;
|
||||
|
||||
void loadTabs();
|
||||
|
||||
QMessageBox closeConfirmDialog;
|
||||
|
||||
public:
|
||||
void save();
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
|
|
|
@ -36,11 +36,8 @@ using namespace chatterino::messages;
|
|||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
Split::Split(SplitContainer *parent, const std::string &_uuid)
|
||||
Split::Split(SplitContainer *parent)
|
||||
: BaseWidget(parent)
|
||||
, uuid(_uuid)
|
||||
, settingRoot(fS("/splits/{}", this->uuid))
|
||||
, channelName(fS("{}/channelName", this->settingRoot))
|
||||
, parentPage(*parent)
|
||||
, channel(Channel::getEmpty())
|
||||
, vbox(this)
|
||||
|
@ -86,11 +83,6 @@ Split::Split(SplitContainer *parent, const std::string &_uuid)
|
|||
// CreateShortcut(this, "ALT+SHIFT+UP", &Split::doIncFlexY);
|
||||
// CreateShortcut(this, "ALT+SHIFT+DOWN", &Split::doDecFlexY);
|
||||
|
||||
this->channelName.getValueChangedSignal().connect(
|
||||
std::bind(&Split::channelNameUpdated, this, std::placeholders::_1));
|
||||
|
||||
this->channelNameUpdated(this->channelName.getValue());
|
||||
|
||||
this->input.ui.textEdit->installEventFilter(parent);
|
||||
|
||||
this->view.mouseDown.connect([this](QMouseEvent *) { this->giveFocus(Qt::MouseFocusReason); });
|
||||
|
@ -130,11 +122,6 @@ Split::~Split()
|
|||
this->channelIDChangedConnection.disconnect();
|
||||
}
|
||||
|
||||
const std::string &Split::getUUID() const
|
||||
{
|
||||
return this->uuid;
|
||||
}
|
||||
|
||||
ChannelPtr Split::getChannel() const
|
||||
{
|
||||
return this->channel;
|
||||
|
@ -156,6 +143,7 @@ void Split::setChannel(ChannelPtr _newChannel)
|
|||
}
|
||||
|
||||
this->header.updateModerationModeIcon();
|
||||
this->header.updateChannelText();
|
||||
|
||||
this->channelChanged.invoke();
|
||||
}
|
||||
|
@ -196,19 +184,6 @@ bool Split::getModerationMode() const
|
|||
return this->moderationMode;
|
||||
}
|
||||
|
||||
void Split::channelNameUpdated(const QString &newChannelName)
|
||||
{
|
||||
// update messages
|
||||
if (newChannelName.isEmpty()) {
|
||||
this->setChannel(Channel::getEmpty());
|
||||
} else {
|
||||
this->setChannel(TwitchServer::getInstance().addChannel(newChannelName));
|
||||
}
|
||||
|
||||
// update header
|
||||
this->header.updateChannelText();
|
||||
}
|
||||
|
||||
bool Split::showChangeChannelPopup(const char *dialogTitle, bool empty)
|
||||
{
|
||||
// create new input dialog and execute it
|
||||
|
@ -217,13 +192,13 @@ bool Split::showChangeChannelPopup(const char *dialogTitle, bool empty)
|
|||
dialog.setWindowTitle(dialogTitle);
|
||||
|
||||
if (!empty) {
|
||||
dialog.setText(this->channelName);
|
||||
dialog.setText(this->channel->name);
|
||||
}
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
QString newChannelName = dialog.getText().trimmed();
|
||||
|
||||
this->channelName = newChannelName;
|
||||
this->setChannel(providers::twitch::TwitchServer::getInstance().addChannel(newChannelName));
|
||||
this->parentPage.refreshTitle();
|
||||
|
||||
return true;
|
||||
|
@ -328,12 +303,13 @@ void Split::doChangeChannel()
|
|||
|
||||
void Split::doPopup()
|
||||
{
|
||||
Window &window = singletons::WindowManager::getInstance().createWindow();
|
||||
Window &window = singletons::WindowManager::getInstance().createWindow(Window::Popup);
|
||||
|
||||
Split *split = new Split(static_cast<SplitContainer *>(window.getNotebook().getSelectedPage()),
|
||||
this->uuid);
|
||||
Split *split =
|
||||
new Split(static_cast<SplitContainer *>(window.getNotebook().getOrAddSelectedPage()));
|
||||
|
||||
window.getNotebook().getSelectedPage()->addToLayout(split);
|
||||
split->setChannel(this->getChannel());
|
||||
window.getNotebook().getOrAddSelectedPage()->addToLayout(split);
|
||||
|
||||
window.show();
|
||||
}
|
||||
|
@ -366,7 +342,7 @@ void Split::doOpenPopupPlayer()
|
|||
void Split::doOpenStreamlink()
|
||||
{
|
||||
try {
|
||||
streamlink::Start(this->channelName.getValue());
|
||||
streamlink::Start(this->channel->name);
|
||||
} catch (const streamlink::Exception &ex) {
|
||||
debug::Log("Error in doOpenStreamlink: {}", ex.what());
|
||||
}
|
||||
|
|
|
@ -42,14 +42,10 @@ class Split : public BaseWidget
|
|||
|
||||
Q_OBJECT
|
||||
|
||||
const std::string uuid;
|
||||
const std::string settingRoot;
|
||||
|
||||
public:
|
||||
Split(SplitContainer *parent, const std::string &_uuid);
|
||||
Split(SplitContainer *parent);
|
||||
~Split() override;
|
||||
|
||||
pajlada::Settings::Setting<QString> channelName;
|
||||
pajlada::Signals::NoArgSignal channelChanged;
|
||||
|
||||
ChannelView &getChannelView()
|
||||
|
@ -57,8 +53,9 @@ public:
|
|||
return this->view;
|
||||
}
|
||||
|
||||
const std::string &getUUID() const;
|
||||
ChannelPtr getChannel() const;
|
||||
void setChannel(ChannelPtr newChannel);
|
||||
|
||||
void setFlexSizeX(double x);
|
||||
double getFlexSizeX();
|
||||
void setFlexSizeY(double y);
|
||||
|
@ -98,8 +95,6 @@ private:
|
|||
|
||||
pajlada::Signals::Connection channelIDChangedConnection;
|
||||
pajlada::Signals::Connection usermodeChangedConnection;
|
||||
|
||||
void setChannel(ChannelPtr newChannel);
|
||||
void doOpenAccountPopupWidget(AccountPopupWidget *widget, QString user);
|
||||
void channelNameUpdated(const QString &newChannelName);
|
||||
void handleModifiers(QEvent *event, Qt::KeyboardModifiers modifiers);
|
||||
|
|
|
@ -26,12 +26,9 @@ bool SplitContainer::isDraggingSplit = false;
|
|||
Split *SplitContainer::draggingSplit = nullptr;
|
||||
std::pair<int, int> SplitContainer::dropPosition = std::pair<int, int>(-1, -1);
|
||||
|
||||
SplitContainer::SplitContainer(Notebook *parent, NotebookTab *_tab, const std::string &_uuid)
|
||||
SplitContainer::SplitContainer(Notebook *parent, NotebookTab *_tab)
|
||||
: BaseWidget(parent->themeManager, parent)
|
||||
, uuid(_uuid)
|
||||
, settingRoot(fS("/containers/{}", this->uuid))
|
||||
, tab(_tab)
|
||||
, chats(fS("{}/chats", this->settingRoot))
|
||||
, dropPreview(this)
|
||||
{
|
||||
this->tab->page = this;
|
||||
|
@ -48,8 +45,6 @@ SplitContainer::SplitContainer(Notebook *parent, NotebookTab *_tab, const std::s
|
|||
this->ui.hbox.setSpacing(1);
|
||||
this->ui.hbox.setMargin(0);
|
||||
|
||||
this->loadSplits();
|
||||
|
||||
this->refreshTitle();
|
||||
}
|
||||
|
||||
|
@ -147,6 +142,24 @@ const std::vector<Split *> &SplitContainer::getSplits() const
|
|||
return this->splits;
|
||||
}
|
||||
|
||||
std::vector<std::vector<Split *>> SplitContainer::getColumns() const
|
||||
{
|
||||
std::vector<std::vector<Split *>> columns;
|
||||
|
||||
for (int i = 0; i < this->ui.hbox.count(); i++) {
|
||||
std::vector<Split *> cells;
|
||||
|
||||
QLayout *vbox = this->ui.hbox.itemAt(i)->layout();
|
||||
for (int j = 0; j < vbox->count(); j++) {
|
||||
cells.push_back(dynamic_cast<Split *>(vbox->itemAt(j)->widget()));
|
||||
}
|
||||
|
||||
columns.push_back(cells);
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
NotebookTab *SplitContainer::getTab() const
|
||||
{
|
||||
return this->tab;
|
||||
|
@ -447,7 +460,7 @@ std::pair<int, int> SplitContainer::getChatPosition(const Split *chatWidget)
|
|||
|
||||
Split *SplitContainer::createChatWidget(const std::string &uuid)
|
||||
{
|
||||
auto split = new Split(this, uuid);
|
||||
auto split = new Split(this);
|
||||
|
||||
split->getChannelView().highlightedMessageReceived.connect([this] {
|
||||
// fourtf: error potentionally here
|
||||
|
@ -459,7 +472,7 @@ Split *SplitContainer::createChatWidget(const std::string &uuid)
|
|||
|
||||
void SplitContainer::refreshTitle()
|
||||
{
|
||||
if (!this->tab->useDefaultBehaviour) {
|
||||
if (!this->tab->useDefaultTitle) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -467,7 +480,7 @@ void SplitContainer::refreshTitle()
|
|||
bool first = true;
|
||||
|
||||
for (const auto &chatWidget : this->splits) {
|
||||
auto channelName = chatWidget->channelName.getValue();
|
||||
auto channelName = chatWidget->getChannel()->name;
|
||||
if (channelName.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -487,83 +500,5 @@ void SplitContainer::refreshTitle()
|
|||
this->tab->setTitle(newTitle);
|
||||
}
|
||||
|
||||
void SplitContainer::loadSplits()
|
||||
{
|
||||
const auto hboxes = this->chats.getValue();
|
||||
int column = 0;
|
||||
for (const std::vector<std::string> &hbox : hboxes) {
|
||||
int row = 0;
|
||||
for (const std::string &chatUUID : hbox) {
|
||||
Split *split = this->createChatWidget(chatUUID);
|
||||
|
||||
this->addToLayout(split, std::pair<int, int>(column, row));
|
||||
|
||||
++row;
|
||||
}
|
||||
++column;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
static void saveFromLayout(QLayout *layout, Container &container)
|
||||
{
|
||||
for (int i = 0; i < layout->count(); ++i) {
|
||||
auto item = layout->itemAt(i);
|
||||
|
||||
auto innerLayout = item->layout();
|
||||
if (innerLayout != nullptr) {
|
||||
std::vector<std::string> vbox;
|
||||
|
||||
for (int j = 0; j < innerLayout->count(); ++j) {
|
||||
auto innerItem = innerLayout->itemAt(j);
|
||||
auto innerWidget = innerItem->widget();
|
||||
if (innerWidget == nullptr) {
|
||||
assert(false);
|
||||
continue;
|
||||
}
|
||||
Split *innerSplit = qobject_cast<Split *>(innerWidget);
|
||||
vbox.push_back(innerSplit->getUUID());
|
||||
}
|
||||
|
||||
container.push_back(vbox);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SplitContainer::save()
|
||||
{
|
||||
auto layout = this->ui.hbox.layout();
|
||||
|
||||
std::vector<std::vector<std::string>> _chats;
|
||||
|
||||
for (int i = 0; i < layout->count(); ++i) {
|
||||
auto item = layout->itemAt(i);
|
||||
|
||||
auto innerLayout = item->layout();
|
||||
if (innerLayout != nullptr) {
|
||||
std::vector<std::string> vbox;
|
||||
|
||||
for (int j = 0; j < innerLayout->count(); ++j) {
|
||||
auto innerItem = innerLayout->itemAt(j);
|
||||
auto innerWidget = innerItem->widget();
|
||||
if (innerWidget == nullptr) {
|
||||
assert(false);
|
||||
continue;
|
||||
}
|
||||
Split *innerSplit = qobject_cast<Split *>(innerWidget);
|
||||
vbox.push_back(innerSplit->getUUID());
|
||||
}
|
||||
|
||||
_chats.push_back(vbox);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
this->chats = _chats;
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -19,21 +19,14 @@ class SplitContainer : public BaseWidget
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
const std::string uuid;
|
||||
const std::string settingRoot;
|
||||
|
||||
public:
|
||||
SplitContainer(Notebook *parent, NotebookTab *_tab, const std::string &_uuid);
|
||||
|
||||
const std::string &getUUID() const
|
||||
{
|
||||
return this->uuid;
|
||||
}
|
||||
SplitContainer(Notebook *parent, NotebookTab *_tab);
|
||||
|
||||
std::pair<int, int> removeFromLayout(Split *widget);
|
||||
void addToLayout(Split *widget, std::pair<int, int> position = std::pair<int, int>(-1, -1));
|
||||
|
||||
const std::vector<Split *> &getSplits() const;
|
||||
std::vector<std::vector<Split *>> getColumns() const;
|
||||
NotebookTab *getTab() const;
|
||||
|
||||
void addChat(bool openChannelNameDialog = false, std::string chatUUID = std::string());
|
||||
|
@ -90,8 +83,6 @@ private:
|
|||
std::vector<Split *> splits;
|
||||
std::vector<DropRegion> dropRegions;
|
||||
|
||||
pajlada::Settings::Setting<std::vector<std::vector<std::string>>> chats;
|
||||
|
||||
NotebookPageDropPreview dropPreview;
|
||||
|
||||
void setPreviewRect(QPoint mousePos);
|
||||
|
|
|
@ -18,13 +18,11 @@
|
|||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
Window::Window(const QString &windowName, singletons::ThemeManager &_themeManager,
|
||||
bool _isMainWindow)
|
||||
Window::Window(singletons::ThemeManager &_themeManager, WindowType _type)
|
||||
: BaseWindow(_themeManager, nullptr, true)
|
||||
, settingRoot(fS("/windows/{}", windowName))
|
||||
, windowGeometry(this->settingRoot)
|
||||
, type(_type)
|
||||
, dpi(this->getScale())
|
||||
, notebook(this, _isMainWindow, this->settingRoot)
|
||||
, notebook(this, !this->hasCustomWindowFrame())
|
||||
{
|
||||
singletons::AccountManager::getInstance().Twitch.currentUsername.connect(
|
||||
[this](const std::string &newUsername, auto) {
|
||||
|
@ -35,7 +33,7 @@ Window::Window(const QString &windowName, singletons::ThemeManager &_themeManage
|
|||
}
|
||||
});
|
||||
|
||||
if (this->hasCustomWindowFrame()) {
|
||||
if (this->hasCustomWindowFrame() && _type == Window::Main) {
|
||||
this->addTitleBarButton(TitleBarButton::Settings, [] {
|
||||
singletons::WindowManager::getInstance().showSettingsDialog();
|
||||
});
|
||||
|
@ -49,6 +47,12 @@ Window::Window(const QString &windowName, singletons::ThemeManager &_themeManage
|
|||
});
|
||||
}
|
||||
|
||||
if (_type == Window::Main) {
|
||||
this->resize((int)(600 * this->getScale()), (int)(500 * this->getScale()));
|
||||
} else {
|
||||
this->resize((int)(300 * this->getScale()), (int)(500 * this->getScale()));
|
||||
}
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(&this->notebook);
|
||||
|
@ -59,8 +63,6 @@ Window::Window(const QString &windowName, singletons::ThemeManager &_themeManage
|
|||
|
||||
this->themeRefreshEvent();
|
||||
|
||||
this->loadGeometry();
|
||||
|
||||
/// Initialize program-wide hotkeys
|
||||
// CTRL+P: Open Settings Dialog
|
||||
CreateWindowShortcut(this, "CTRL+P", [] { SettingsDialog::showDialog(); });
|
||||
|
@ -77,7 +79,7 @@ Window::Window(const QString &windowName, singletons::ThemeManager &_themeManage
|
|||
CreateWindowShortcut(this, "CTRL+9", [this] { this->notebook.selectIndex(8); });
|
||||
|
||||
// CTRL+SHIFT+T: New tab
|
||||
CreateWindowShortcut(this, "CTRL+SHIFT+T", [this] { this->notebook.addNewPage(); });
|
||||
CreateWindowShortcut(this, "CTRL+SHIFT+T", [this] { this->notebook.addNewPage(true); });
|
||||
|
||||
// CTRL+SHIFT+W: Close current tab
|
||||
CreateWindowShortcut(this, "CTRL+SHIFT+W", [this] { this->notebook.removeCurrentPage(); });
|
||||
|
@ -102,9 +104,14 @@ Window::Window(const QString &windowName, singletons::ThemeManager &_themeManage
|
|||
// });
|
||||
}
|
||||
|
||||
Window::WindowType Window::getType()
|
||||
{
|
||||
return this->type;
|
||||
}
|
||||
|
||||
void Window::repaintVisibleChatWidgets(Channel *channel)
|
||||
{
|
||||
auto *page = this->notebook.getSelectedPage();
|
||||
auto *page = this->notebook.getOrAddSelectedPage();
|
||||
|
||||
if (page == nullptr) {
|
||||
return;
|
||||
|
@ -127,18 +134,6 @@ void Window::refreshWindowTitle(const QString &username)
|
|||
this->setWindowTitle(username + " - Chatterino for Twitch");
|
||||
}
|
||||
|
||||
void Window::closeEvent(QCloseEvent *)
|
||||
{
|
||||
const QRect &geom = this->geometry();
|
||||
|
||||
this->windowGeometry.x = geom.x();
|
||||
this->windowGeometry.y = geom.y();
|
||||
this->windowGeometry.width = geom.width();
|
||||
this->windowGeometry.height = geom.height();
|
||||
|
||||
this->closed.invoke();
|
||||
}
|
||||
|
||||
bool Window::event(QEvent *e)
|
||||
{
|
||||
switch (e->type()) {
|
||||
|
@ -146,7 +141,7 @@ bool Window::event(QEvent *e)
|
|||
break;
|
||||
|
||||
case QEvent::WindowDeactivate: {
|
||||
auto page = this->notebook.getSelectedPage();
|
||||
auto page = this->notebook.getOrAddSelectedPage();
|
||||
|
||||
if (page != nullptr) {
|
||||
std::vector<Split *> splits = page->getSplits();
|
||||
|
@ -160,35 +155,14 @@ bool Window::event(QEvent *e)
|
|||
return BaseWindow::event(e);
|
||||
}
|
||||
|
||||
void Window::loadGeometry()
|
||||
void Window::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
bool doSetGeometry = false;
|
||||
QRect loadedGeometry;
|
||||
if (!this->windowGeometry.x.isDefaultValue() && !this->windowGeometry.y.isDefaultValue()) {
|
||||
loadedGeometry.setX(this->windowGeometry.x);
|
||||
loadedGeometry.setY(this->windowGeometry.y);
|
||||
doSetGeometry = true;
|
||||
if (this->type == Window::Main) {
|
||||
singletons::WindowManager::getInstance().save();
|
||||
singletons::WindowManager::getInstance().closeAll();
|
||||
}
|
||||
|
||||
if (!this->windowGeometry.width.isDefaultValue() &&
|
||||
!this->windowGeometry.height.isDefaultValue()) {
|
||||
loadedGeometry.setWidth(this->windowGeometry.width);
|
||||
loadedGeometry.setHeight(this->windowGeometry.height);
|
||||
} else {
|
||||
loadedGeometry.setWidth(1280);
|
||||
loadedGeometry.setHeight(720);
|
||||
}
|
||||
|
||||
if (doSetGeometry) {
|
||||
this->setGeometry(loadedGeometry);
|
||||
} else {
|
||||
this->resize(loadedGeometry.width(), loadedGeometry.height());
|
||||
}
|
||||
}
|
||||
|
||||
void Window::save()
|
||||
{
|
||||
this->notebook.save();
|
||||
this->closed.invoke();
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
|
|
|
@ -18,32 +18,14 @@ class ThemeManager;
|
|||
|
||||
namespace widgets {
|
||||
|
||||
struct WindowGeometry {
|
||||
WindowGeometry(const std::string &settingPrefix)
|
||||
: x(fS("{}/geometry/x", settingPrefix))
|
||||
, y(fS("{}/geometry/y", settingPrefix))
|
||||
, width(fS("{}/geometry/width", settingPrefix))
|
||||
, height(fS("{}/geometry/height", settingPrefix))
|
||||
{
|
||||
}
|
||||
|
||||
pajlada::Settings::Setting<int> x;
|
||||
pajlada::Settings::Setting<int> y;
|
||||
pajlada::Settings::Setting<int> width;
|
||||
pajlada::Settings::Setting<int> height;
|
||||
};
|
||||
|
||||
class Window : public BaseWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::string settingRoot;
|
||||
|
||||
WindowGeometry windowGeometry;
|
||||
|
||||
public:
|
||||
explicit Window(const QString &windowName, singletons::ThemeManager &_themeManager,
|
||||
bool isMainWindow);
|
||||
enum WindowType { Main, Popup };
|
||||
|
||||
explicit Window(singletons::ThemeManager &_themeManager, WindowType type);
|
||||
|
||||
void repaintVisibleChatWidgets(Channel *channel = nullptr);
|
||||
|
||||
|
@ -53,17 +35,19 @@ public:
|
|||
|
||||
pajlada::Signals::NoArgSignal closed;
|
||||
|
||||
WindowType getType();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
private:
|
||||
WindowType type;
|
||||
float dpi;
|
||||
|
||||
void loadGeometry();
|
||||
|
||||
Notebook notebook;
|
||||
// TitleBar titleBar;
|
||||
|
||||
friend class Notebook;
|
||||
|
||||
|
|
Loading…
Reference in a new issue