move around files

This commit is contained in:
Rasmus Karlsson
2017-06-06 14:48:14 +02:00
parent 71f64cd6ff
commit ccf8e3bd83
148 changed files with 115 additions and 107 deletions
+1
View File
@@ -0,0 +1 @@
../.clang-format
+41
View File
@@ -0,0 +1,41 @@
#include "widgets/accountpopup.h"
#include "channel.h"
#include "ui_accountpopupform.h"
#include <QDebug>
namespace chatterino {
namespace widgets {
AccountPopupWidget::AccountPopupWidget(SharedChannel &channel)
: QWidget(nullptr)
, _ui(new Ui::AccountPopup)
, _channel(channel)
{
_ui->setupUi(this);
resize(0, 0);
setWindowFlags(Qt::FramelessWindowHint);
// Close button
connect(_ui->btnClose, &QPushButton::clicked, [=]() {
hide(); //
});
connect(_ui->btnPurge, &QPushButton::clicked, [=]() {
qDebug() << "xD: " << _channel->getName();
printf("Channel pointer in dialog: %p\n", _channel.get());
//_channel->sendMessage(QString(".timeout %1 0").arg(_ui->lblUsername->text()));
_channel->sendMessage("xD");
});
}
void AccountPopupWidget::setName(const QString &name)
{
_ui->lblUsername->setText(name);
}
} // namespace widgets
} // namespace chatterino
+35
View File
@@ -0,0 +1,35 @@
#ifndef USERPOPUPWIDGET_H
#define USERPOPUPWIDGET_H
#include <QWidget>
#include <memory>
namespace Ui {
class AccountPopup;
}
namespace chatterino {
class Channel;
namespace widgets {
class AccountPopupWidget : public QWidget
{
Q_OBJECT
public:
AccountPopupWidget(std::shared_ptr<Channel> &channel);
void setName(const QString &name);
private:
Ui::AccountPopup *_ui;
std::shared_ptr<Channel> &_channel;
};
} // namespace widgets
} // namespace chatterino
#endif // USERPOPUPWIDGET_H
+197
View File
@@ -0,0 +1,197 @@
#include "widgets/chatwidget.h"
#include "channelmanager.h"
#include "colorscheme.h"
#include "settingsmanager.h"
#include "widgets/textinputdialog.h"
#include <QDebug>
#include <QFont>
#include <QFontDatabase>
#include <QPainter>
#include <QVBoxLayout>
#include <boost/signals2.hpp>
using namespace chatterino::messages;
namespace chatterino {
namespace widgets {
ChatWidget::ChatWidget(QWidget *parent)
: QWidget(parent)
, _messages()
, _channel(ChannelManager::getInstance().getEmpty())
, _channelName(QString())
, _vbox(this)
, _header(this)
, _view(this)
, _input(this)
{
this->_vbox.setSpacing(0);
this->_vbox.setMargin(1);
this->_vbox.addWidget(&_header);
this->_vbox.addWidget(&_view, 1);
this->_vbox.addWidget(&_input);
}
ChatWidget::~ChatWidget()
{
detachChannel();
}
std::shared_ptr<Channel> ChatWidget::getChannel() const
{
return _channel;
}
std::shared_ptr<Channel> &ChatWidget::getChannelRef()
{
return _channel;
}
const QString &ChatWidget::getChannelName() const
{
return _channelName;
}
void ChatWidget::setChannelName(const QString &name)
{
QString channelName = name.trimmed();
// return if channel name is the same
if (QString::compare(channelName, _channelName, Qt::CaseInsensitive) == 0) {
_channelName = channelName;
_header.updateChannelText();
return;
}
// remove current channel
if (!_channelName.isEmpty()) {
ChannelManager::getInstance().removeChannel(_channelName);
detachChannel();
}
// update members
_channelName = channelName;
// update messages
_messages.clear();
printf("Set channel name xD %s\n", qPrintable(name));
if (channelName.isEmpty()) {
_channel = NULL;
} else {
_channel = ChannelManager::getInstance().addChannel(channelName);
printf("Created channel FeelsGoodMan %p\n", _channel.get());
attachChannel(_channel);
}
// update header
_header.updateChannelText();
// update view
_view.layoutMessages();
_view.update();
}
void ChatWidget::attachChannel(SharedChannel channel)
{
// on new message
_messageAppendedConnection = channel->messageAppended.connect([this](SharedMessage &message) {
SharedMessageRef deleted;
auto messageRef = new MessageRef(message);
if (_messages.appendItem(SharedMessageRef(messageRef), deleted)) {
qreal value = std::max(0.0, _view.getScrollbar()->getDesiredValue() - 1);
_view.getScrollbar()->setDesiredValue(value, false);
}
});
// on message removed
_messageRemovedConnection = _channel->messageRemovedFromStart.connect([](SharedMessage &) {
//
});
auto snapshot = _channel.get()->getMessageSnapshot();
for (int i = 0; i < snapshot.getSize(); i++) {
SharedMessageRef deleted;
auto messageRef = new MessageRef(snapshot[i]);
_messages.appendItem(SharedMessageRef(messageRef), deleted);
}
}
void ChatWidget::detachChannel()
{
// on message added
_messageAppendedConnection.disconnect();
// on message removed
_messageRemovedConnection.disconnect();
}
LimitedQueueSnapshot<SharedMessageRef> ChatWidget::getMessagesSnapshot()
{
return _messages.getSnapshot();
}
void ChatWidget::showChangeChannelPopup()
{
// create new input dialog and execute it
TextInputDialog dialog(this);
dialog.setText(_channelName);
if (dialog.exec() == QDialog::Accepted) {
setChannelName(dialog.getText());
}
}
void ChatWidget::layoutMessages()
{
if (_view.layoutMessages()) {
_view.update();
}
}
void ChatWidget::updateGifEmotes()
{
_view.updateGifEmotes();
}
void ChatWidget::paintEvent(QPaintEvent *)
{
// color the background of the chat
QPainter painter(this);
painter.fillRect(this->rect(), ColorScheme::getInstance().ChatBackground);
}
void ChatWidget::load(const boost::property_tree::ptree &tree)
{
// load tab text
try {
this->setChannelName(QString::fromStdString(tree.get<std::string>("channelName")));
} catch (boost::property_tree::ptree_error) {
}
}
boost::property_tree::ptree ChatWidget::save()
{
boost::property_tree::ptree tree;
tree.put("channelName", this->getChannelName().toStdString());
return tree;
}
} // namespace widgets
} // namespace chatterino
+69
View File
@@ -0,0 +1,69 @@
#ifndef CHATWIDGET_H
#define CHATWIDGET_H
#include "channel.h"
#include "messages/limitedqueuesnapshot.h"
#include "messages/messageref.h"
#include "messages/word.h"
#include "messages/wordpart.h"
#include "widgets/chatwidgetheader.h"
#include "widgets/chatwidgetinput.h"
#include "widgets/chatwidgetview.h"
#include <QFont>
#include <QVBoxLayout>
#include <QWidget>
#include <boost/property_tree/ptree.hpp>
#include <boost/signals2/connection.hpp>
namespace chatterino {
namespace widgets {
class ChatWidget : public QWidget
{
Q_OBJECT
public:
ChatWidget(QWidget *parent = 0);
~ChatWidget();
SharedChannel getChannel() const;
SharedChannel &getChannelRef();
const QString &getChannelName() const;
void setChannelName(const QString &name);
void showChangeChannelPopup();
messages::LimitedQueueSnapshot<messages::SharedMessageRef> getMessagesSnapshot();
void layoutMessages();
void updateGifEmotes();
protected:
void paintEvent(QPaintEvent *) override;
private:
void attachChannel(std::shared_ptr<Channel> _channel);
void detachChannel();
messages::LimitedQueue<messages::SharedMessageRef> _messages;
SharedChannel _channel;
QString _channelName;
QFont _font;
QVBoxLayout _vbox;
ChatWidgetHeader _header;
ChatWidgetView _view;
ChatWidgetInput _input;
boost::signals2::connection _messageAppendedConnection;
boost::signals2::connection _messageRemovedConnection;
public:
void load(const boost::property_tree::ptree &tree);
boost::property_tree::ptree save();
};
} // namespace widgets
} // namespace chatterino
#endif // CHATWIDGET_H
+199
View File
@@ -0,0 +1,199 @@
#include "widgets/chatwidgetheader.h"
#include "colorscheme.h"
#include "widgets/chatwidget.h"
#include "widgets/notebookpage.h"
#include <QByteArray>
#include <QDrag>
#include <QMimeData>
#include <QPainter>
namespace chatterino {
namespace widgets {
ChatWidgetHeader::ChatWidgetHeader(ChatWidget *parent)
: QWidget()
, _chatWidget(parent)
, _dragStart()
, _dragging(false)
, _leftLabel()
, _middleLabel()
, _rightLabel()
, _leftMenu(this)
, _rightMenu(this)
{
setFixedHeight(32);
updateColors();
updateChannelText();
setLayout(&_hbox);
_hbox.setMargin(0);
_hbox.addWidget(&_leftLabel);
_hbox.addWidget(&_middleLabel, 1);
_hbox.addWidget(&_rightLabel);
// left
_leftLabel.getLabel().setTextFormat(Qt::RichText);
_leftLabel.getLabel().setText("<img src=':/images/tool_moreCollapser_off16.png' />");
QObject::connect(&_leftLabel, &ChatWidgetHeaderButton::clicked, this,
&ChatWidgetHeader::leftButtonClicked);
_leftMenu.addAction("Add new split", this, SLOT(menuAddSplit()), QKeySequence(tr("Ctrl+T")));
_leftMenu.addAction("Close split", this, SLOT(menuCloseSplit()), QKeySequence(tr("Ctrl+W")));
_leftMenu.addAction("Move split", this, SLOT(menuMoveSplit()));
_leftMenu.addAction("Popup", this, SLOT(menuPopup()));
_leftMenu.addSeparator();
_leftMenu.addAction("Change channel", this, SLOT(menuChangeChannel()),
QKeySequence(tr("Ctrl+R")));
_leftMenu.addAction("Clear chat", this, SLOT(menuClearChat()));
_leftMenu.addAction("Open channel", this, SLOT(menuOpenChannel()));
_leftMenu.addAction("Open pop-out player", this, SLOT(menuPopupPlayer()));
_leftMenu.addSeparator();
_leftMenu.addAction("Reload channel emotes", this, SLOT(menuReloadChannelEmotes()));
_leftMenu.addAction("Manual reconnect", this, SLOT(menuManualReconnect()));
_leftMenu.addSeparator();
_leftMenu.addAction("Show changelog", this, SLOT(menuShowChangelog()));
// middle
_middleLabel.setAlignment(Qt::AlignCenter);
connect(&_middleLabel, &SignalLabel::mouseDoubleClick, this,
&ChatWidgetHeader::mouseDoubleClickEvent);
// connect(&this->middleLabel, &SignalLabel::mouseDown, this,
// &ChatWidgetHeader::mouseDoubleClickEvent);
// right
_rightLabel.setMinimumWidth(height());
_rightLabel.getLabel().setTextFormat(Qt::RichText);
_rightLabel.getLabel().setText("ayy");
}
void ChatWidgetHeader::updateColors()
{
QPalette palette;
palette.setColor(QPalette::Foreground, ColorScheme::getInstance().Text);
_leftLabel.setPalette(palette);
_middleLabel.setPalette(palette);
_rightLabel.setPalette(palette);
}
void ChatWidgetHeader::updateChannelText()
{
const QString &c = _chatWidget->getChannelName();
_middleLabel.setText(c.isEmpty() ? "<no channel>" : c);
}
void ChatWidgetHeader::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.fillRect(rect(), ColorScheme::getInstance().ChatHeaderBackground);
painter.setPen(ColorScheme::getInstance().ChatHeaderBorder);
painter.drawRect(0, 0, width() - 1, height() - 1);
}
void ChatWidgetHeader::mousePressEvent(QMouseEvent *event)
{
_dragging = true;
_dragStart = event->pos();
}
void ChatWidgetHeader::mouseMoveEvent(QMouseEvent *event)
{
if (_dragging) {
if (std::abs(_dragStart.x() - event->pos().x()) > 12 ||
std::abs(_dragStart.y() - event->pos().y()) > 12) {
auto chatWidget = _chatWidget;
auto page = static_cast<NotebookPage *>(chatWidget->parentWidget());
if (page != NULL) {
NotebookPage::isDraggingSplit = true;
NotebookPage::draggingSplit = chatWidget;
auto originalLocation = page->removeFromLayout(chatWidget);
// page->update();
QDrag *drag = new QDrag(chatWidget);
QMimeData *mimeData = new QMimeData;
mimeData->setData("chatterino/split", "xD");
drag->setMimeData(mimeData);
Qt::DropAction dropAction = drag->exec(Qt::MoveAction);
if (dropAction == Qt::IgnoreAction) {
page->addToLayout(chatWidget, originalLocation);
}
NotebookPage::isDraggingSplit = false;
}
}
}
}
void ChatWidgetHeader::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
_chatWidget->showChangeChannelPopup();
}
}
void ChatWidgetHeader::leftButtonClicked()
{
_leftMenu.move(_leftLabel.mapToGlobal(QPoint(0, _leftLabel.height())));
_leftMenu.show();
}
void ChatWidgetHeader::rightButtonClicked()
{
}
void ChatWidgetHeader::menuAddSplit()
{
auto page = static_cast<NotebookPage *>(_chatWidget->parentWidget());
page->addChat();
}
void ChatWidgetHeader::menuCloseSplit()
{
printf("Close split\n");
}
void ChatWidgetHeader::menuMoveSplit()
{
}
void ChatWidgetHeader::menuPopup()
{
auto widget = new ChatWidget();
widget->setChannelName(_chatWidget->getChannelName());
widget->show();
}
void ChatWidgetHeader::menuChangeChannel()
{
_chatWidget->showChangeChannelPopup();
}
void ChatWidgetHeader::menuClearChat()
{
}
void ChatWidgetHeader::menuOpenChannel()
{
}
void ChatWidgetHeader::menuPopupPlayer()
{
}
void ChatWidgetHeader::menuReloadChannelEmotes()
{
}
void ChatWidgetHeader::menuManualReconnect()
{
}
void ChatWidgetHeader::menuShowChangelog()
{
}
}
}
+75
View File
@@ -0,0 +1,75 @@
#ifndef CHATWIDGETHEADER_H
#define CHATWIDGETHEADER_H
#include "signallabel.h"
#include "widgets/chatwidgetheaderbutton.h"
#include <QAction>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QPoint>
#include <QWidget>
namespace chatterino {
namespace widgets {
class ChatWidget;
class ChatWidgetHeader : public QWidget
{
Q_OBJECT
public:
explicit ChatWidgetHeader(ChatWidget *parent);
ChatWidget *getChatWidget() const
{
return _chatWidget;
}
void updateColors();
void updateChannelText();
protected:
void paintEvent(QPaintEvent *);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
private:
ChatWidget * const _chatWidget;
QPoint _dragStart;
bool _dragging;
QHBoxLayout _hbox;
ChatWidgetHeaderButton _leftLabel;
SignalLabel _middleLabel;
ChatWidgetHeaderButton _rightLabel;
QMenu _leftMenu;
QMenu _rightMenu;
void leftButtonClicked();
void rightButtonClicked();
private slots:
void menuAddSplit();
void menuCloseSplit();
void menuMoveSplit();
void menuPopup();
void menuChangeChannel();
void menuClearChat();
void menuOpenChannel();
void menuPopupPlayer();
void menuReloadChannelEmotes();
void menuManualReconnect();
void menuShowChangelog();
};
}
}
#endif // CHATWIDGETHEADER_H
+98
View File
@@ -0,0 +1,98 @@
#include "widgets/chatwidgetheaderbutton.h"
#include "colorscheme.h"
#include <QBrush>
#include <QPainter>
namespace chatterino {
namespace widgets {
ChatWidgetHeaderButton::ChatWidgetHeaderButton(int spacing)
: QWidget()
, _hbox()
, _label()
, _mouseOver(false)
, _mouseDown(false)
{
setLayout(&_hbox);
_label.setAlignment(Qt::AlignCenter);
_hbox.setMargin(0);
_hbox.addSpacing(spacing);
_hbox.addWidget(&_label);
_hbox.addSpacing(spacing);
QObject::connect(&_label, &SignalLabel::mouseUp, this,
&ChatWidgetHeaderButton::labelMouseUp);
QObject::connect(&_label, &SignalLabel::mouseDown, this,
&ChatWidgetHeaderButton::labelMouseDown);
}
void ChatWidgetHeaderButton::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QBrush brush(ColorScheme::getInstance().IsLightTheme ? QColor(0, 0, 0, 32)
: QColor(255, 255, 255, 32));
if (_mouseDown) {
painter.fillRect(rect(), brush);
}
if (_mouseOver) {
painter.fillRect(rect(), brush);
}
}
void ChatWidgetHeaderButton::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
_mouseDown = true;
update();
}
}
void ChatWidgetHeaderButton::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
_mouseDown = false;
update();
emit clicked();
}
}
void ChatWidgetHeaderButton::enterEvent(QEvent *)
{
_mouseOver = true;
update();
}
void ChatWidgetHeaderButton::leaveEvent(QEvent *)
{
_mouseOver = false;
update();
}
void ChatWidgetHeaderButton::labelMouseUp()
{
_mouseDown = false;
update();
emit clicked();
}
void ChatWidgetHeaderButton::labelMouseDown()
{
_mouseDown = true;
update();
}
}
}
+51
View File
@@ -0,0 +1,51 @@
#ifndef CHATWIDGETHEADERBUTTON_H
#define CHATWIDGETHEADERBUTTON_H
#include "widgets/signallabel.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QPaintEvent>
#include <QWidget>
namespace chatterino {
namespace widgets {
class ChatWidgetHeaderButton : public QWidget
{
Q_OBJECT
public:
explicit ChatWidgetHeaderButton(int spacing = 6);
SignalLabel &getLabel()
{
return _label;
}
signals:
void clicked();
protected:
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
void enterEvent(QEvent *) Q_DECL_OVERRIDE;
void leaveEvent(QEvent *) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
private:
QHBoxLayout _hbox;
SignalLabel _label;
bool _mouseOver;
bool _mouseDown;
void labelMouseUp();
void labelMouseDown();
};
}
}
#endif // CHATWIDGETHEADERBUTTON_H
+141
View File
@@ -0,0 +1,141 @@
#include "widgets/chatwidgetinput.h"
#include "chatwidget.h"
#include "colorscheme.h"
#include "ircmanager.h"
#include "settingsmanager.h"
#include <QCompleter>
#include <QPainter>
#include <boost/signals2.hpp>
namespace chatterino {
namespace widgets {
ChatWidgetInput::ChatWidgetInput(ChatWidget *widget)
: _chatWidget(widget)
, _hbox()
, _vbox()
, _editContainer()
, _edit()
, _textLengthLabel()
, _emotesLabel(0)
{
setLayout(&_hbox);
setMaximumHeight(150);
_hbox.setMargin(4);
_hbox.addLayout(&_editContainer);
_hbox.addLayout(&_vbox);
_editContainer.addWidget(&_edit);
_editContainer.setMargin(4);
_vbox.addWidget(&_textLengthLabel);
_vbox.addStretch(1);
_vbox.addWidget(&_emotesLabel);
_textLengthLabel.setText("100");
_textLengthLabel.setAlignment(Qt::AlignRight);
_emotesLabel.getLabel().setTextFormat(Qt::RichText);
_emotesLabel.getLabel().setText(
"<img src=':/images/Emoji_Color_1F60A_19.png' width='12' height='12' "
"/>");
QObject::connect(&_edit, &ResizingTextEdit::textChanged, this,
&ChatWidgetInput::editTextChanged);
// QObject::connect(&edit, &ResizingTextEdit::keyPressEvent, this,
// &ChatWidgetInput::editKeyPressed);
refreshTheme();
setMessageLengthVisisble(SettingsManager::getInstance().showMessageLength.get());
QStringList list;
list.append("asd");
list.append("asdf");
list.append("asdg");
list.append("asdh");
QCompleter *completer = new QCompleter(list, &_edit);
completer->setWidget(&_edit);
_edit.keyPressed.connect([this/*, completer*/](QKeyEvent *event) {
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
auto c = _chatWidget->getChannel();
if (c == nullptr) {
return;
}
c->sendMessage(_edit.toPlainText());
event->accept();
_edit.setText(QString());
}
// else {
// completer->setCompletionPrefix("asdf");
// completer->complete();
// // completer->popup();
// }
});
/* XXX(pajlada): FIX THIS
QObject::connect(&Settings::getInstance().showMessageLength,
&BoolSetting::valueChanged, this,
&ChatWidgetInput::setMessageLengthVisisble);
*/
}
ChatWidgetInput::~ChatWidgetInput()
{
/* XXX(pajlada): FIX THIS
QObject::disconnect(
&Settings::getInstance().getShowMessageLength(),
&BoolSetting::valueChanged, this,
&ChatWidgetInput::setMessageLengthVisisble);
*/
}
void ChatWidgetInput::refreshTheme()
{
QPalette palette;
palette.setColor(QPalette::Foreground, ColorScheme::getInstance().Text);
_textLengthLabel.setPalette(palette);
_edit.setStyleSheet(ColorScheme::getInstance().InputStyleSheet);
}
void ChatWidgetInput::editTextChanged()
{
}
// void
// ChatWidgetInput::editKeyPressed(QKeyEvent *event)
//{
// if (event->key() == Qt::Key_Enter) {
// event->accept();
// IrcManager::send("PRIVMSG #" + edit.toPlainText();
// edit.setText(QString());
// }
//}
void ChatWidgetInput::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.fillRect(rect(), ColorScheme::getInstance().ChatInputBackground);
painter.setPen(ColorScheme::getInstance().ChatInputBorder);
painter.drawRect(0, 0, width() - 1, height() - 1);
}
void ChatWidgetInput::resizeEvent(QResizeEvent *)
{
if (height() == maximumHeight()) {
_edit.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
} else {
_edit.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
}
}
}
+55
View File
@@ -0,0 +1,55 @@
#ifndef CHATWIDGETINPUT_H
#define CHATWIDGETINPUT_H
#include "resizingtextedit.h"
#include "widgets/chatwidgetheaderbutton.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPaintEvent>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QWidget>
namespace chatterino {
namespace widgets {
class ChatWidget;
class ChatWidgetInput : public QWidget
{
Q_OBJECT
public:
ChatWidgetInput(ChatWidget *parent);
~ChatWidgetInput();
protected:
void paintEvent(QPaintEvent *);
void resizeEvent(QResizeEvent *);
private:
ChatWidget *_chatWidget;
QHBoxLayout _hbox;
QVBoxLayout _vbox;
QHBoxLayout _editContainer;
ResizingTextEdit _edit;
QLabel _textLengthLabel;
ChatWidgetHeaderButton _emotesLabel;
private slots:
void refreshTheme();
void setMessageLengthVisisble(bool value)
{
_textLengthLabel.setHidden(!value);
}
void editTextChanged();
// void editKeyPressed(QKeyEvent *event);
};
} // namespace widgets
} // namespace chatterino
#endif // CHATWIDGETINPUT_H
+407
View File
@@ -0,0 +1,407 @@
#include "widgets/chatwidgetview.h"
#include "channelmanager.h"
#include "colorscheme.h"
#include "messages/message.h"
#include "messages/wordpart.h"
#include "settingsmanager.h"
#include "ui_accountpopupform.h"
#include "util/distancebetweenpoints.h"
#include "widgets/chatwidget.h"
#include <math.h>
#include <QDebug>
#include <QGraphicsBlurEffect>
#include <QPainter>
#include <chrono>
#include <functional>
namespace chatterino {
namespace widgets {
ChatWidgetView::ChatWidgetView(ChatWidget *parent)
: QWidget()
, _chatWidget(parent)
, _scrollbar(this)
, _userPopupWidget(_chatWidget->getChannelRef())
, _onlyUpdateEmotes(false)
, _mouseDown(false)
, _lastPressPosition()
{
setAttribute(Qt::WA_OpaquePaintEvent);
_scrollbar.setSmallChange(5);
setMouseTracking(true);
QObject::connect(&SettingsManager::getInstance(), &SettingsManager::wordTypeMaskChanged, this,
&ChatWidgetView::wordTypeMaskChanged);
_scrollbar.getCurrentValueChanged().connect([this] { update(); });
}
ChatWidgetView::~ChatWidgetView()
{
QObject::disconnect(&SettingsManager::getInstance(), &SettingsManager::wordTypeMaskChanged,
this, &ChatWidgetView::wordTypeMaskChanged);
}
bool ChatWidgetView::layoutMessages()
{
auto messages = _chatWidget->getMessagesSnapshot();
if (messages.getSize() == 0) {
_scrollbar.setVisible(false);
return false;
}
bool showScrollbar = false, redraw = false;
int start = _scrollbar.getCurrentValue();
int layoutWidth = _scrollbar.isVisible() ? width() - _scrollbar.width() : width();
// layout the visible messages in the view
if (messages.getSize() > start) {
int y = -(messages[start]->getHeight() * (fmod(_scrollbar.getCurrentValue(), 1)));
for (int i = start; i < messages.getSize(); ++i) {
auto message = messages[i];
redraw |= message->layout(layoutWidth, true);
y += message->getHeight();
if (y >= height()) {
break;
}
}
}
// layout the messages at the bottom to determine the scrollbar thumb size
int h = height() - 8;
for (int i = messages.getSize() - 1; i >= 0; i--) {
auto *message = messages[i].get();
message->layout(layoutWidth, true);
h -= message->getHeight();
if (h < 0) {
_scrollbar.setLargeChange((messages.getSize() - i) + (qreal)h / message->getHeight());
_scrollbar.setDesiredValue(_scrollbar.getDesiredValue());
showScrollbar = true;
break;
}
}
_scrollbar.setVisible(showScrollbar);
if (!showScrollbar) {
_scrollbar.setDesiredValue(0);
}
_scrollbar.setMaximum(messages.getSize());
return redraw;
}
void ChatWidgetView::updateGifEmotes()
{
_onlyUpdateEmotes = true;
update();
}
ScrollBar *ChatWidgetView::getScrollbar()
{
return &_scrollbar;
}
void ChatWidgetView::resizeEvent(QResizeEvent *)
{
_scrollbar.resize(_scrollbar.width(), height());
_scrollbar.move(width() - _scrollbar.width(), 0);
layoutMessages();
update();
}
void ChatWidgetView::paintEvent(QPaintEvent *event)
{
QPainter _painter(this);
_painter.setRenderHint(QPainter::SmoothPixmapTransform);
ColorScheme &scheme = ColorScheme::getInstance();
// only update gif emotes
if (_onlyUpdateEmotes) {
_onlyUpdateEmotes = false;
for (GifEmoteData &item : _gifEmotes) {
_painter.fillRect(item.rect, scheme.ChatBackground);
_painter.drawPixmap(item.rect, *item.image->getPixmap());
}
return;
}
// update all messages
_gifEmotes.clear();
_painter.fillRect(rect(), scheme.ChatBackground);
// code for tesing colors
/*
QColor color;
static ConcurrentMap<qreal, QImage *> imgCache;
std::function<QImage *(qreal)> getImg = [&scheme](qreal light) {
return imgCache.getOrAdd(light, [&scheme, &light] {
QImage *img = new QImage(150, 50, QImage::Format_RGB32);
QColor color;
for (int j = 0; j < 50; j++) {
for (qreal i = 0; i < 150; i++) {
color = QColor::fromHslF(i / 150.0, light, j / 50.0);
scheme.normalizeColor(color);
img->setPixelColor(i, j, color);
}
}
return img;
});
};
for (qreal k = 0; k < 4.8; k++) {
auto img = getImg(k / 5);
painter.drawImage(QRect(k * 150, 0, 150, 150), *img);
}
painter.fillRect(QRect(0, 9, 500, 2), QColor(0, 0, 0));*/
auto messages = _chatWidget->getMessagesSnapshot();
int start = _scrollbar.getCurrentValue();
if (start >= messages.getSize()) {
return;
}
int y = -(messages[start].get()->getHeight() * (fmod(_scrollbar.getCurrentValue(), 1)));
for (int i = start; i < messages.getSize(); ++i) {
messages::MessageRef *messageRef = messages[i].get();
std::shared_ptr<QPixmap> bufferPtr = messageRef->buffer;
QPixmap *buffer = bufferPtr.get();
bool updateBuffer = messageRef->updateBuffer;
if (buffer == nullptr) {
buffer = new QPixmap(width(), messageRef->getHeight());
bufferPtr = std::shared_ptr<QPixmap>(buffer);
updateBuffer = true;
}
// update messages that have been changed
if (updateBuffer) {
QPainter painter(buffer);
painter.fillRect(buffer->rect(), scheme.ChatBackground);
for (messages::WordPart const &wordPart : messageRef->getWordParts()) {
// image
if (wordPart.getWord().isImage()) {
messages::LazyLoadedImage &lli = wordPart.getWord().getImage();
const QPixmap *image = lli.getPixmap();
if (image != nullptr) {
painter.drawPixmap(QRect(wordPart.getX(), wordPart.getY(),
wordPart.getWidth(), wordPart.getHeight()),
*image);
}
}
// text
else {
QColor color = wordPart.getWord().getColor();
ColorScheme::getInstance().normalizeColor(color);
painter.setPen(color);
painter.setFont(wordPart.getWord().getFont());
painter.drawText(QRectF(wordPart.getX(), wordPart.getY(), 10000, 10000),
wordPart.getText(), QTextOption(Qt::AlignLeft | Qt::AlignTop));
}
}
messageRef->updateBuffer = false;
}
// get gif emotes
for (messages::WordPart const &wordPart : messageRef->getWordParts()) {
if (wordPart.getWord().isImage()) {
messages::LazyLoadedImage &lli = wordPart.getWord().getImage();
if (lli.getAnimated()) {
GifEmoteData data;
data.image = &lli;
QRect rect(wordPart.getX(), wordPart.getY() + y, wordPart.getWidth(),
wordPart.getHeight());
data.rect = rect;
_gifEmotes.push_back(data);
}
}
}
messageRef->buffer = bufferPtr;
_painter.drawPixmap(0, y, *buffer);
y += messageRef->getHeight();
if (y > height()) {
break;
}
}
for (GifEmoteData &item : _gifEmotes) {
_painter.fillRect(item.rect, scheme.ChatBackground);
_painter.drawPixmap(item.rect, *item.image->getPixmap());
}
}
void ChatWidgetView::wheelEvent(QWheelEvent *event)
{
if (_scrollbar.isVisible()) {
auto mouseMultiplier = SettingsManager::getInstance().mouseScrollMultiplier.get();
_scrollbar.setDesiredValue(
_scrollbar.getDesiredValue() - event->delta() / 10.0 * mouseMultiplier, true);
}
}
void ChatWidgetView::mouseMoveEvent(QMouseEvent *event)
{
std::shared_ptr<messages::MessageRef> message;
QPoint relativePos;
if (!tryGetMessageAt(event->pos(), message, relativePos)) {
setCursor(Qt::ArrowCursor);
return;
}
// int index = message->getSelectionIndex(relativePos);
// qDebug() << index;
messages::Word hoverWord;
if (!message->tryGetWordPart(relativePos, hoverWord)) {
setCursor(Qt::ArrowCursor);
return;
}
if (hoverWord.getLink().isValid()) {
setCursor(Qt::PointingHandCursor);
} else {
setCursor(Qt::ArrowCursor);
}
}
void ChatWidgetView::mousePressEvent(QMouseEvent *event)
{
_mouseDown = true;
_lastPressPosition = event->screenPos();
}
void ChatWidgetView::mouseReleaseEvent(QMouseEvent *event)
{
if (!_mouseDown) {
// We didn't grab the mouse press, so we shouldn't be handling the mouse
// release
return;
}
_mouseDown = false;
float distance = util::distanceBetweenPoints(_lastPressPosition, event->screenPos());
qDebug() << "Distance: " << distance;
if (fabsf(distance) > 15.f) {
// It wasn't a proper click, so we don't care about that here
return;
}
// If you clicked and released less than X pixels away, it counts
// as a click!
// show user thing pajaW
std::shared_ptr<messages::MessageRef> message;
QPoint relativePos;
if (!tryGetMessageAt(event->pos(), message, relativePos)) {
// No message at clicked position
_userPopupWidget.hide();
return;
}
messages::Word hoverWord;
if (!message->tryGetWordPart(relativePos, hoverWord)) {
return;
}
auto &link = hoverWord.getLink();
switch (link.getType()) {
case messages::Link::UserInfo:
auto user = message->getMessage()->getUserName();
_userPopupWidget.setName(user);
_userPopupWidget.move(event->screenPos().toPoint());
_userPopupWidget.show();
_userPopupWidget.setFocus();
qDebug() << "Clicked " << user << "s message";
break;
}
}
bool ChatWidgetView::tryGetMessageAt(QPoint p, std::shared_ptr<messages::MessageRef> &_message,
QPoint &relativePos)
{
auto messages = _chatWidget->getMessagesSnapshot();
int start = _scrollbar.getCurrentValue();
if (start >= messages.getSize()) {
return false;
}
int y = -(messages[start]->getHeight() * (fmod(_scrollbar.getCurrentValue(), 1)));
for (int i = start; i < messages.getSize(); ++i) {
auto message = messages[i];
if (p.y() < y + message->getHeight()) {
relativePos = QPoint(p.x(), p.y() - y);
_message = message;
return true;
}
y += message->getHeight();
}
return false;
}
} // namespace widgets
} // namespace chatterino
+73
View File
@@ -0,0 +1,73 @@
#ifndef CHATVIEW_H
#define CHATVIEW_H
#include "channel.h"
#include "messages/lazyloadedimage.h"
#include "messages/messageref.h"
#include "messages/word.h"
#include "widgets/accountpopup.h"
#include "widgets/scrollbar.h"
#include <QPaintEvent>
#include <QScroller>
#include <QWheelEvent>
#include <QWidget>
namespace chatterino {
namespace widgets {
class ChatWidget;
class ChatWidgetView : public QWidget
{
public:
explicit ChatWidgetView(ChatWidget *parent);
~ChatWidgetView();
bool layoutMessages();
void updateGifEmotes();
ScrollBar *getScrollbar();
protected:
void resizeEvent(QResizeEvent *) override;
void paintEvent(QPaintEvent *) override;
void wheelEvent(QWheelEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
bool tryGetMessageAt(QPoint p, std::shared_ptr<messages::MessageRef> &message,
QPoint &relativePos);
private:
struct GifEmoteData {
messages::LazyLoadedImage *image;
QRect rect;
};
std::vector<GifEmoteData> _gifEmotes;
ChatWidget *_chatWidget;
ScrollBar _scrollbar;
AccountPopupWidget _userPopupWidget;
bool _onlyUpdateEmotes;
// Mouse event variables
bool _mouseDown;
QPointF _lastPressPosition;
private slots:
void wordTypeMaskChanged()
{
layoutMessages();
update();
}
};
} // namespace widgets
} // namespace chatterino
#endif // CHATVIEW_H
+141
View File
@@ -0,0 +1,141 @@
#include "fancybutton.h"
#include <QDebug>
#include <QPainter>
namespace chatterino {
namespace widgets {
FancyButton::FancyButton(QWidget *parent)
: QWidget(parent)
, _selected()
, _mouseOver()
, _mouseDown()
, _mousePos()
, _hoverMultiplier()
, _effectTimer()
, _mouseEffectColor(QColor(255, 255, 255))
{
connect(&_effectTimer, &QTimer::timeout, this, &FancyButton::onMouseEffectTimeout);
_effectTimer.setInterval(20);
_effectTimer.start();
}
void FancyButton::setMouseEffectColor(QColor color)
{
_mouseEffectColor = color;
}
void FancyButton::paintEvent(QPaintEvent *)
{
QPainter painter;
fancyPaint(painter);
}
void FancyButton::fancyPaint(QPainter &painter)
{
QColor &c = _mouseEffectColor;
if (_hoverMultiplier > 0) {
QRadialGradient gradient(_mousePos.x(), _mousePos.y(), 50, _mousePos.x(), _mousePos.y());
gradient.setColorAt(0, QColor(c.red(), c.green(), c.blue(), (int)(24 * _hoverMultiplier)));
gradient.setColorAt(1, QColor(c.red(), c.green(), c.blue(), (int)(12 * _hoverMultiplier)));
painter.fillRect(this->rect(), gradient);
}
for (auto effect : _clickEffects) {
QRadialGradient gradient(effect.position.x(), effect.position.y(),
effect.progress * (float)width() * 2, effect.position.x(),
effect.position.y());
gradient.setColorAt(
0, QColor(c.red(), c.green(), c.blue(), (int)((1 - effect.progress) * 95)));
gradient.setColorAt(
0.9999, QColor(c.red(), c.green(), c.blue(), (int)((1 - effect.progress) * 95)));
gradient.setColorAt(1, QColor(c.red(), c.green(), c.blue(), (int)(0)));
painter.fillRect(this->rect(), gradient);
}
}
void FancyButton::enterEvent(QEvent *)
{
_mouseOver = true;
}
void FancyButton::leaveEvent(QEvent *)
{
_mouseOver = false;
}
void FancyButton::mousePressEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton) {
return;
}
_clickEffects.push_back(ClickEffect(event->pos()));
_mouseDown = true;
}
void FancyButton::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton) {
return;
}
_mouseDown = false;
}
void FancyButton::mouseMoveEvent(QMouseEvent *event)
{
_mousePos = event->pos();
}
void FancyButton::onMouseEffectTimeout()
{
bool performUpdate = false;
if (_selected) {
if (_hoverMultiplier != 0) {
_hoverMultiplier = std::max(0.0, _hoverMultiplier - 0.1);
performUpdate = true;
}
} else if (_mouseOver) {
if (_hoverMultiplier != 1) {
_hoverMultiplier = std::min(1.0, _hoverMultiplier + 0.5);
performUpdate = true;
}
} else {
if (_hoverMultiplier != 0) {
_hoverMultiplier = std::max(0.0, _hoverMultiplier - 0.3);
performUpdate = true;
}
}
if (_clickEffects.size() != 0) {
performUpdate = true;
for (auto it = _clickEffects.begin(); it != _clickEffects.end();) {
(*it).progress += _mouseDown ? 0.02 : 0.07;
if ((*it).progress >= 1.0) {
it = _clickEffects.erase(it);
} else {
it++;
}
}
}
if (performUpdate) {
update();
}
}
}
}
+55
View File
@@ -0,0 +1,55 @@
#ifndef FANCYBUTTON_H
#define FANCYBUTTON_H
#include <QMouseEvent>
#include <QPainter>
#include <QPoint>
#include <QTimer>
#include <QWidget>
namespace chatterino {
namespace widgets {
class FancyButton : public QWidget
{
struct ClickEffect {
float progress;
QPoint position;
ClickEffect(QPoint position)
: progress()
, position(position)
{
}
};
public:
FancyButton(QWidget *parent = nullptr);
void setMouseEffectColor(QColor color);
protected:
void paintEvent(QPaintEvent *) override;
void enterEvent(QEvent *) override;
void leaveEvent(QEvent *) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void fancyPaint(QPainter &painter);
private:
bool _selected;
bool _mouseOver;
bool _mouseDown;
QPoint _mousePos;
float _hoverMultiplier;
QTimer _effectTimer;
std::vector<ClickEffect> _clickEffects;
QColor _mouseEffectColor;
void onMouseEffectTimeout();
};
}
}
#endif // FANCYBUTTON_H
+154
View File
@@ -0,0 +1,154 @@
#include "widgets/mainwindow.h"
#include "colorscheme.h"
#include "settingsmanager.h"
#include "widgets/chatwidget.h"
#include "widgets/notebook.h"
#include "widgets/settingsdialog.h"
#include <QDebug>
#include <QPalette>
#include <QShortcut>
#include <QVBoxLayout>
#include <boost/foreach.hpp>
#ifdef USEWINSDK
#include "Windows.h"
#endif
namespace chatterino {
namespace widgets {
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
, _notebook(this)
, _loaded(false)
, _titleBar()
{
QVBoxLayout *layout = new QVBoxLayout(this);
// add titlebar
// if (SettingsManager::getInstance().useCustomWindowFrame.get()) {
// layout->addWidget(&_titleBar);
// }
layout->addWidget(&_notebook);
setLayout(layout);
// set margin
// if (SettingsManager::getInstance().useCustomWindowFrame.get()) {
// layout->setMargin(1);
// } else {
layout->setMargin(0);
// }
QPalette palette;
palette.setColor(QPalette::Background, ColorScheme::getInstance().TabPanelBackground);
setPalette(palette);
resize(1280, 800);
// Initialize program-wide hotkeys
{
// CTRL+P: Open Settings Dialog
auto shortcut = new QShortcut(QKeySequence("CTRL+P"), this);
connect(shortcut, &QShortcut::activated, []() {
SettingsDialog::showDialog(); //
});
}
}
MainWindow::~MainWindow()
{
}
void MainWindow::layoutVisibleChatWidgets(Channel *channel)
{
auto *page = _notebook.getSelectedPage();
if (page == NULL) {
return;
}
const std::vector<ChatWidget *> &widgets = page->getChatWidgets();
for (auto it = widgets.begin(); it != widgets.end(); ++it) {
ChatWidget *widget = *it;
if (channel == NULL || channel == widget->getChannel().get()) {
widget->layoutMessages();
}
}
}
void MainWindow::repaintVisibleChatWidgets(Channel *channel)
{
auto *page = _notebook.getSelectedPage();
if (page == NULL) {
return;
}
const std::vector<ChatWidget *> &widgets = page->getChatWidgets();
for (auto it = widgets.begin(); it != widgets.end(); ++it) {
ChatWidget *widget = *it;
if (channel == NULL || channel == widget->getChannel().get()) {
widget->layoutMessages();
}
}
}
void MainWindow::repaintGifEmotes()
{
auto *page = _notebook.getSelectedPage();
if (page == NULL) {
return;
}
const std::vector<ChatWidget *> &widgets = page->getChatWidgets();
for (auto it = widgets.begin(); it != widgets.end(); ++it) {
ChatWidget *widget = *it;
widget->updateGifEmotes();
}
}
void MainWindow::load(const boost::property_tree::ptree &tree)
{
this->_notebook.load(tree);
_loaded = true;
}
boost::property_tree::ptree MainWindow::save()
{
boost::property_tree::ptree child;
child.put("type", "main");
_notebook.save(child);
return child;
}
void MainWindow::loadDefaults()
{
_notebook.loadDefaults();
_loaded = true;
}
bool MainWindow::isLoaded() const
{
return _loaded;
}
Notebook &MainWindow::getNotebook()
{
return _notebook;
}
} // namespace widgets
} // namespace chatterino
+46
View File
@@ -0,0 +1,46 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "widgets/notebook.h"
#include "widgets/titlebar.h"
#ifdef USEWINSDK
#include <platform/borderless/qwinwidget.h>
#endif
#include <QMainWindow>
#include <boost/property_tree/ptree.hpp>
namespace chatterino {
namespace widgets {
class MainWindow : public QWidget
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void layoutVisibleChatWidgets(Channel *channel = nullptr);
void repaintVisibleChatWidgets(Channel *channel = nullptr);
void repaintGifEmotes();
void load(const boost::property_tree::ptree &tree);
boost::property_tree::ptree save();
void loadDefaults();
bool isLoaded() const;
Notebook &getNotebook();
private:
Notebook _notebook;
bool _loaded;
TitleBar _titleBar;
};
} // namespace widgets
} // namespace chatterino
#endif // MAINWINDOW_H
+259
View File
@@ -0,0 +1,259 @@
#include "widgets/notebook.h"
#include "colorscheme.h"
#include "widgets/notebookbutton.h"
#include "widgets/notebookpage.h"
#include "widgets/notebooktab.h"
#include "widgets/settingsdialog.h"
#include <QDebug>
#include <QFile>
#include <QFormLayout>
#include <QLayout>
#include <QList>
#include <QShortcut>
#include <QStandardPaths>
#include <QWidget>
#include <boost/foreach.hpp>
namespace chatterino {
namespace widgets {
Notebook::Notebook(QWidget *parent)
: QWidget(parent)
, _addButton(this)
, _settingsButton(this)
, _userButton(this)
, _selectedPage(nullptr)
{
connect(&_settingsButton, SIGNAL(clicked()), this, SLOT(settingsButtonClicked()));
connect(&_userButton, SIGNAL(clicked()), this, SLOT(usersButtonClicked()));
connect(&_addButton, SIGNAL(clicked()), this, SLOT(addPageButtonClicked()));
_settingsButton.resize(24, 24);
_settingsButton.icon = NotebookButton::IconSettings;
_userButton.resize(24, 24);
_userButton.move(24, 0);
_userButton.icon = NotebookButton::IconUser;
_addButton.resize(24, 24);
SettingsManager::getInstance().hidePreferencesButton.valueChanged.connect(
[this](const bool &) { performLayout(); });
SettingsManager::getInstance().hideUserButton.valueChanged.connect(
[this](const bool &) { performLayout(); });
// Initialize notebook hotkeys
{
// CTRL+T: Create new split (Add page)
auto shortcut = new QShortcut(QKeySequence("CTRL+T"), this);
connect(shortcut, &QShortcut::activated, [this]() {
printf("ctrL+t pressed\n"); //
if (this->_selectedPage == nullptr) {
return;
}
this->_selectedPage->addChat();
});
}
}
NotebookPage *Notebook::addPage(bool select)
{
auto tab = new NotebookTab(this);
auto page = new NotebookPage(this, tab);
tab->show();
if (select || _pages.count() == 0) {
this->select(page);
}
_pages.append(page);
performLayout();
return page;
}
void Notebook::removePage(NotebookPage *page)
{
int index = _pages.indexOf(page);
if (_pages.size() == 1) {
select(NULL);
} else if (index == _pages.count() - 1) {
select(_pages[index - 1]);
} else {
select(_pages[index + 1]);
}
delete page->getTab();
delete page;
_pages.removeOne(page);
if (_pages.size() == 0) {
addPage();
}
performLayout();
}
void Notebook::select(NotebookPage *page)
{
if (page == _selectedPage)
return;
if (page != nullptr) {
page->setHidden(false);
page->getTab()->setSelected(true);
page->getTab()->raise();
}
if (_selectedPage != nullptr) {
_selectedPage->setHidden(true);
_selectedPage->getTab()->setSelected(false);
}
_selectedPage = page;
performLayout();
}
NotebookPage *Notebook::tabAt(QPoint point, int &index)
{
int i = 0;
for (auto *page : _pages) {
if (page->getTab()->getDesiredRect().contains(point)) {
index = i;
return page;
}
i++;
}
index = -1;
return nullptr;
}
void Notebook::rearrangePage(NotebookPage *page, int index)
{
_pages.move(_pages.indexOf(page), index);
performLayout();
}
void Notebook::performLayout(bool animated)
{
int x = 0, y = 0;
if (SettingsManager::getInstance().hidePreferencesButton.get()) {
_settingsButton.hide();
} else {
_settingsButton.show();
x += 24;
}
if (SettingsManager::getInstance().hideUserButton.get()) {
_userButton.hide();
} else {
_userButton.move(x, 0);
_userButton.show();
x += 24;
}
int tabHeight = 16;
bool first = true;
for (auto &i : _pages) {
tabHeight = i->getTab()->height();
if (!first && (i == _pages.last() ? tabHeight : 0) + x + i->getTab()->width() > width()) {
y += i->getTab()->height();
i->getTab()->moveAnimated(QPoint(0, y), animated);
x = i->getTab()->width();
} else {
i->getTab()->moveAnimated(QPoint(x, y), animated);
x += i->getTab()->width();
}
first = false;
}
_addButton.move(x, y);
if (_selectedPage != nullptr) {
_selectedPage->move(0, y + tabHeight);
_selectedPage->resize(width(), height() - y - tabHeight);
}
}
void Notebook::resizeEvent(QResizeEvent *)
{
performLayout(false);
}
void Notebook::settingsButtonClicked()
{
SettingsDialog::showDialog();
}
void Notebook::usersButtonClicked()
{
}
void Notebook::addPageButtonClicked()
{
addPage(true);
}
void Notebook::load(const boost::property_tree::ptree &tree)
{
// Read a list of tabs
try {
BOOST_FOREACH (const boost::property_tree::ptree::value_type &v, tree.get_child("tabs.")) {
bool select = v.second.get<bool>("selected", false);
auto page = addPage(select);
auto tab = page->getTab();
tab->load(v.second);
page->load(v.second);
}
} catch (boost::property_tree::ptree_error &) {
// can't read tabs
}
if (_pages.size() == 0) {
// No pages saved, show default stuff
loadDefaults();
}
}
void Notebook::save(boost::property_tree::ptree &tree)
{
boost::property_tree::ptree tabs;
// Iterate through all tabs and add them to our tabs property thing
for (const auto &page : _pages) {
boost::property_tree::ptree pTab = page->getTab()->save();
boost::property_tree::ptree pChats = page->save();
if (pChats.size() > 0) {
pTab.add_child("columns", pChats);
}
tabs.push_back(std::make_pair("", pTab));
}
tree.add_child("tabs", tabs);
}
void Notebook::loadDefaults()
{
addPage();
}
} // namespace widgets
} // namespace chatterino
+67
View File
@@ -0,0 +1,67 @@
#ifndef NOTEBOOK_H
#define NOTEBOOK_H
#include "widgets/notebookbutton.h"
#include "widgets/notebookpage.h"
#include "widgets/notebooktab.h"
#include <QList>
#include <QWidget>
#include <boost/property_tree/ptree.hpp>
namespace chatterino {
namespace widgets {
class Notebook : public QWidget
{
Q_OBJECT
public:
enum HighlightType { none, highlighted, newMessage };
Notebook(QWidget *parent);
NotebookPage *addPage(bool select = false);
void removePage(NotebookPage *page);
void select(NotebookPage *page);
NotebookPage *getSelectedPage()
{
return _selectedPage;
}
void performLayout(bool animate = true);
NotebookPage *tabAt(QPoint point, int &index);
void rearrangePage(NotebookPage *page, int index);
protected:
void resizeEvent(QResizeEvent *);
void settingsButtonMouseReleased(QMouseEvent *event);
public slots:
void settingsButtonClicked();
void usersButtonClicked();
void addPageButtonClicked();
private:
QList<NotebookPage *> _pages;
NotebookButton _addButton;
NotebookButton _settingsButton;
NotebookButton _userButton;
NotebookPage *_selectedPage;
public:
void load(const boost::property_tree::ptree &tree);
void save(boost::property_tree::ptree &tree);
void loadDefaults();
};
} // namespace widgets
} // namespace chatterino
#endif // NOTEBOOK_H
+106
View File
@@ -0,0 +1,106 @@
#include "widgets/notebookbutton.h"
#include "colorscheme.h"
#include "widgets/fancybutton.h"
#include <QMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QRadialGradient>
namespace chatterino {
namespace widgets {
NotebookButton::NotebookButton(QWidget *parent)
: FancyButton(parent)
{
setMouseEffectColor(QColor(0, 0, 0));
}
void NotebookButton::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QColor background;
QColor foreground;
auto &colorScheme = ColorScheme::getInstance();
if (_mouseDown) {
background = colorScheme.TabSelectedBackground;
foreground = colorScheme.TabSelectedText;
} else if (_mouseOver) {
background = colorScheme.TabHoverBackground;
foreground = colorScheme.TabSelectedBackground;
} else {
background = colorScheme.TabPanelBackground;
// foreground = colorScheme.TabSelectedBackground;
foreground = QColor(230, 230, 230);
}
painter.setPen(Qt::NoPen);
painter.fillRect(this->rect(), background);
float h = height(), w = width();
if (icon == IconPlus) {
painter.fillRect(
QRectF((h / 12) * 2 + 1, (h / 12) * 5 + 1, w - ((h / 12) * 5), (h / 12) * 1),
foreground);
painter.fillRect(
QRectF((h / 12) * 5 + 1, (h / 12) * 2 + 1, (h / 12) * 1, w - ((h / 12) * 5)),
foreground);
} else if (icon == IconUser) {
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::HighQualityAntialiasing);
auto a = w / 8;
QPainterPath path;
path.arcMoveTo(a, 4 * a, 6 * a, 6 * a, 0);
path.arcTo(a, 4 * a, 6 * a, 6 * a, 0, 180);
painter.fillPath(path, foreground);
painter.setBrush(background);
painter.drawEllipse(2 * a, 1 * a, 4 * a, 4 * a);
painter.setBrush(foreground);
painter.drawEllipse(2.5 * a, 1.5 * a, 3 * a + 1, 3 * a);
} else // IconSettings
{
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::HighQualityAntialiasing);
auto a = w / 8;
QPainterPath path;
path.arcMoveTo(a, a, 6 * a, 6 * a, 0 - (360 / 32.0));
for (int i = 0; i < 8; i++) {
path.arcTo(a, a, 6 * a, 6 * a, i * (360 / 8.0) - (360 / 32.0), (360 / 32.0));
path.arcTo(2 * a, 2 * a, 4 * a, 4 * a, i * (360 / 8.0) + (360 / 32.0), (360 / 32.0));
}
painter.fillPath(path, foreground);
painter.setBrush(background);
painter.drawEllipse(3 * a, 3 * a, 2 * a, 2 * a);
}
fancyPaint(painter);
}
void NotebookButton::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
_mouseDown = false;
update();
emit clicked();
}
FancyButton::mouseReleaseEvent(event);
}
}
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef NOTEBOOKBUTTON_H
#define NOTEBOOKBUTTON_H
#include "fancybutton.h"
#include <QWidget>
namespace chatterino {
namespace widgets {
class NotebookButton : public FancyButton
{
Q_OBJECT
public:
static const int IconPlus = 0;
static const int IconUser = 1;
static const int IconSettings = 2;
int icon = 0;
NotebookButton(QWidget *parent);
protected:
void paintEvent(QPaintEvent *) override;
void mouseReleaseEvent(QMouseEvent *event) override;
signals:
void clicked();
private:
bool _mouseOver = false;
bool _mouseDown = false;
QPoint _mousePos;
};
} // namespace widgets
} // namespace chatterino
#endif // NOTEBOOKBUTTON_H
+350
View File
@@ -0,0 +1,350 @@
#include "widgets/notebookpage.h"
#include "colorscheme.h"
#include "widgets/chatwidget.h"
#include "widgets/notebooktab.h"
#include <QDebug>
#include <QHBoxLayout>
#include <QMimeData>
#include <QObject>
#include <QPainter>
#include <QVBoxLayout>
#include <QWidget>
#include <boost/foreach.hpp>
namespace chatterino {
namespace widgets {
bool NotebookPage::isDraggingSplit = false;
ChatWidget *NotebookPage::draggingSplit = NULL;
std::pair<int, int> NotebookPage::dropPosition = std::pair<int, int>(-1, -1);
NotebookPage::NotebookPage(QWidget *parent, NotebookTab *tab)
: QWidget(parent)
, _tab(tab)
, _parentbox(this)
, _chatWidgets()
, _preview(this)
{
tab->page = this;
setHidden(true);
setAcceptDrops(true);
_parentbox.addSpacing(2);
_parentbox.addLayout(&_hbox);
_parentbox.setMargin(0);
_hbox.setSpacing(1);
_hbox.setMargin(0);
}
const std::vector<ChatWidget *> &NotebookPage::getChatWidgets() const
{
return _chatWidgets;
}
NotebookTab *NotebookPage::getTab() const
{
return _tab;
}
void
NotebookPage::addChat(bool openChannelNameDialog)
{
ChatWidget *w = new ChatWidget();
if (openChannelNameDialog) {
w->showChangeChannelPopup();
}
addToLayout(w, std::pair<int, int>(-1, -1));
}
std::pair<int, int> NotebookPage::removeFromLayout(ChatWidget *widget)
{
// remove from chatWidgets vector
for (auto it = _chatWidgets.begin(); it != _chatWidgets.end(); ++it) {
if (*it == widget) {
_chatWidgets.erase(it);
break;
}
}
// remove from box and return location
for (int i = 0; i < _hbox.count(); ++i) {
auto vbox = static_cast<QVBoxLayout *>(_hbox.itemAt(i));
for (int j = 0; j < vbox->count(); ++j) {
if (vbox->itemAt(j)->widget() != widget) {
continue;
}
widget->setParent(NULL);
bool isLastItem = vbox->count() == 0;
if (isLastItem) {
_hbox.removeItem(vbox);
delete vbox;
}
return std::pair<int, int>(i, isLastItem ? -1 : j);
}
}
return std::pair<int, int>(-1, -1);
}
void NotebookPage::addToLayout(ChatWidget *widget,
std::pair<int, int> position = std::pair<int, int>(-1, -1))
{
_chatWidgets.push_back(widget);
// add vbox at the end
if (position.first < 0 || position.first >= _hbox.count()) {
auto vbox = new QVBoxLayout();
vbox->addWidget(widget);
_hbox.addLayout(vbox, 1);
return;
}
// insert vbox
if (position.second == -1) {
auto vbox = new QVBoxLayout();
vbox->addWidget(widget);
_hbox.insertLayout(position.first, vbox, 1);
return;
}
// add to existing vbox
auto vbox = static_cast<QVBoxLayout *>(_hbox.itemAt(position.first));
vbox->insertWidget(std::max(0, std::min(vbox->count(), position.second)), widget);
}
void NotebookPage::enterEvent(QEvent *)
{
if (_hbox.count() == 0) {
setCursor(QCursor(Qt::PointingHandCursor));
} else {
setCursor(QCursor(Qt::ArrowCursor));
}
}
void NotebookPage::leaveEvent(QEvent *)
{
}
void NotebookPage::mouseReleaseEvent(QMouseEvent *event)
{
if (_hbox.count() == 0 && event->button() == Qt::LeftButton) {
// "Add Chat" was clicked
addToLayout(new ChatWidget(), std::pair<int, int>(-1, -1));
setCursor(QCursor(Qt::ArrowCursor));
}
}
void NotebookPage::dragEnterEvent(QDragEnterEvent *event)
{
if (!event->mimeData()->hasFormat("chatterino/split"))
return;
if (isDraggingSplit) {
return;
}
_dropRegions.clear();
if (_hbox.count() == 0) {
_dropRegions.push_back(DropRegion(rect(), std::pair<int, int>(-1, -1)));
} else {
for (int i = 0; i < _hbox.count() + 1; ++i) {
_dropRegions.push_back(DropRegion(QRect(((i * 4 - 1) * width() / _hbox.count()) / 4, 0,
width() / _hbox.count() / 2 + 1, height() + 1),
std::pair<int, int>(i, -1)));
}
for (int i = 0; i < _hbox.count(); ++i) {
auto vbox = static_cast<QVBoxLayout *>(_hbox.itemAt(i));
for (int j = 0; j < vbox->count() + 1; ++j) {
_dropRegions.push_back(DropRegion(
QRect(i * width() / _hbox.count(), ((j * 2 - 1) * height() / vbox->count()) / 2,
width() / _hbox.count() + 1, height() / vbox->count() + 1),
std::pair<int, int>(i, j)));
}
}
}
setPreviewRect(event->pos());
event->acceptProposedAction();
}
void NotebookPage::dragMoveEvent(QDragMoveEvent *event)
{
setPreviewRect(event->pos());
}
void NotebookPage::setPreviewRect(QPoint mousePos)
{
for (DropRegion region : _dropRegions) {
if (region.rect.contains(mousePos)) {
_preview.setBounds(region.rect);
if (!_preview.isVisible()) {
_preview.show();
_preview.raise();
}
dropPosition = region.position;
return;
}
}
_preview.hide();
}
void NotebookPage::dragLeaveEvent(QDragLeaveEvent *event)
{
_preview.hide();
}
void NotebookPage::dropEvent(QDropEvent *event)
{
if (isDraggingSplit) {
event->acceptProposedAction();
NotebookPage::draggingSplit->setParent(this);
addToLayout(NotebookPage::draggingSplit, dropPosition);
}
_preview.hide();
}
void NotebookPage::paintEvent(QPaintEvent *)
{
QPainter painter(this);
if (_hbox.count() == 0) {
painter.fillRect(rect(), ColorScheme::getInstance().ChatBackground);
painter.fillRect(0, 0, width(), 2, ColorScheme::getInstance().TabSelectedBackground);
painter.setPen(ColorScheme::getInstance().Text);
painter.drawText(rect(), "Add Chat", QTextOption(Qt::AlignCenter));
} else {
painter.fillRect(rect(), ColorScheme::getInstance().TabSelectedBackground);
painter.fillRect(0, 0, width(), 2, ColorScheme::getInstance().TabSelectedBackground);
}
}
static std::pair<int, int> getWidgetPositionInLayout(QLayout *layout, const ChatWidget *chatWidget)
{
for (int i = 0; i < layout->count(); ++i) {
printf("xD\n");
}
return std::make_pair(-1, -1);
}
std::pair<int, int> NotebookPage::getChatPosition(const ChatWidget *chatWidget)
{
auto layout = _hbox.layout();
if (layout == nullptr) {
return std::make_pair(-1, -1);
}
return getWidgetPositionInLayout(layout, chatWidget);
}
void NotebookPage::load(const boost::property_tree::ptree &tree)
{
try {
int column = 0;
for (const auto &v : tree.get_child("columns.")) {
int row = 0;
for (const auto &innerV : v.second.get_child("")) {
auto widget = new ChatWidget();
widget->load(innerV.second);
addToLayout(widget, std::pair<int, int>(column, row));
++row;
}
++column;
}
} catch (boost::property_tree::ptree_error &) {
// can't read tabs
}
}
static void saveFromLayout(QLayout *layout, boost::property_tree::ptree &tree)
{
for (int i = 0; i < layout->count(); ++i) {
auto item = layout->itemAt(i);
auto innerLayout = item->layout();
if (innerLayout != nullptr) {
boost::property_tree::ptree innerLayoutTree;
saveFromLayout(innerLayout, innerLayoutTree);
if (innerLayoutTree.size() > 0) {
tree.push_back(std::make_pair("", innerLayoutTree));
}
continue;
}
auto widget = item->widget();
if (widget == nullptr) {
// This layoutitem does not manage a widget for some reason
continue;
}
ChatWidget *chatWidget = qobject_cast<ChatWidget *>(widget);
if (chatWidget != nullptr) {
boost::property_tree::ptree chat = chatWidget->save();
tree.push_back(std::make_pair("", chat));
continue;
}
}
}
boost::property_tree::ptree NotebookPage::save()
{
boost::property_tree::ptree tree;
auto layout = _hbox.layout();
saveFromLayout(layout, tree);
/*
for (const auto &chat : chatWidgets) {
boost::property_tree::ptree child = chat->save();
// Set child position
child.put("position", "5,3");
tree.push_back(std::make_pair("", child));
}
*/
return tree;
}
} // namespace widgets
} // namespace chatterino
+86
View File
@@ -0,0 +1,86 @@
#ifndef NOTEBOOKPAGE_H
#define NOTEBOOKPAGE_H
#include "widgets/chatwidget.h"
#include "widgets/notebookpage.h"
#include "widgets/notebookpagedroppreview.h"
#include "widgets/notebooktab.h"
#include <QDragEnterEvent>
#include <QHBoxLayout>
#include <QRect>
#include <QVBoxLayout>
#include <QVector>
#include <QWidget>
#include <boost/property_tree/ptree.hpp>
#include <boost/signals2.hpp>
namespace chatterino {
namespace widgets {
class NotebookPage : public QWidget
{
Q_OBJECT
public:
NotebookPage(QWidget *parent, NotebookTab *_tab);
std::pair<int, int> removeFromLayout(ChatWidget *widget);
void addToLayout(ChatWidget *widget, std::pair<int, int> position);
const std::vector<ChatWidget *> &getChatWidgets() const;
NotebookTab *getTab() const;
void addChat(bool openChannelNameDialog = false);
static bool isDraggingSplit;
static ChatWidget *draggingSplit;
static std::pair<int, int> dropPosition;
protected:
void paintEvent(QPaintEvent *) override;
void enterEvent(QEvent *) override;
void leaveEvent(QEvent *) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dragLeaveEvent(QDragLeaveEvent *event) override;
void dropEvent(QDropEvent *event) override;
private:
struct DropRegion {
QRect rect;
std::pair<int, int> position;
DropRegion(QRect rect, std::pair<int, int> position)
{
this->rect = rect;
this->position = position;
}
};
NotebookTab *_tab;
QVBoxLayout _parentbox;
QHBoxLayout _hbox;
std::vector<ChatWidget *> _chatWidgets;
std::vector<DropRegion> _dropRegions;
NotebookPageDropPreview _preview;
void setPreviewRect(QPoint mousePos);
std::pair<int, int> getChatPosition(const ChatWidget *chatWidget);
public:
void load(const boost::property_tree::ptree &tree);
boost::property_tree::ptree save();
};
} // namespace widgets
} // namespace chatterino
#endif // NOTEBOOKPAGE_H
+54
View File
@@ -0,0 +1,54 @@
#include "widgets/notebookpagedroppreview.h"
#include "colorscheme.h"
#include <QDebug>
#include <QPainter>
namespace chatterino {
namespace widgets {
NotebookPageDropPreview::NotebookPageDropPreview(QWidget *parent)
: QWidget(parent)
, positionAnimation(this, "geometry")
, desiredGeometry()
, animate(false)
{
this->positionAnimation.setEasingCurve(QEasingCurve(QEasingCurve::InCubic));
this->setHidden(true);
}
void NotebookPageDropPreview::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.fillRect(8, 8, width() - 17, height() - 17,
ColorScheme::getInstance().DropPreviewBackground);
}
void NotebookPageDropPreview::hideEvent(QHideEvent *)
{
animate = false;
}
void NotebookPageDropPreview::setBounds(const QRect &rect)
{
if (rect == this->desiredGeometry) {
return;
}
if (animate) {
this->positionAnimation.stop();
this->positionAnimation.setDuration(50);
this->positionAnimation.setStartValue(this->geometry());
this->positionAnimation.setEndValue(rect);
this->positionAnimation.start();
} else {
this->setGeometry(rect);
}
this->desiredGeometry = rect;
animate = true;
}
}
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef NOTEBOOKPAGEDROPPREVIEW_H
#define NOTEBOOKPAGEDROPPREVIEW_H
#include <QPropertyAnimation>
#include <QWidget>
namespace chatterino {
namespace widgets {
class NotebookPageDropPreview : public QWidget
{
public:
NotebookPageDropPreview(QWidget *parent);
void setBounds(const QRect &rect);
protected:
void paintEvent(QPaintEvent *);
void hideEvent(QHideEvent *);
QPropertyAnimation positionAnimation;
QRect desiredGeometry;
bool animate;
};
} // namespace widgets
} // namespace chatterino
#endif // NOTEBOOKPAGEDROPPREVIEW_H
+250
View File
@@ -0,0 +1,250 @@
#include "widgets/notebooktab.h"
#include "colorscheme.h"
#include "settingsmanager.h"
#include "widgets/notebook.h"
#include <QPainter>
namespace chatterino {
namespace widgets {
NotebookTab::NotebookTab(Notebook *notebook)
: QWidget(notebook)
, _posAnimation(this, "pos")
, _posAnimated(false)
, _posAnimationDesired()
, _notebook(notebook)
, _title("<no title>")
, _selected(false)
, _mouseOver(false)
, _mouseDown(false)
, _mouseOverX(false)
, _mouseDownX(false)
, _highlightStyle(HighlightNone)
{
this->calcSize();
this->setAcceptDrops(true);
_posAnimation.setEasingCurve(QEasingCurve(QEasingCurve::InCubic));
this->_hideXConnection = SettingsManager::getInstance().hideTabX.valueChanged.connect(
boost::bind(&NotebookTab::hideTabXChanged, this, _1));
this->setMouseTracking(true);
}
NotebookTab::~NotebookTab()
{
this->_hideXConnection.disconnect();
}
void NotebookTab::calcSize()
{
if (SettingsManager::getInstance().hideTabX.get()) {
resize(fontMetrics().width(_title) + 8, 24);
} else {
resize(fontMetrics().width(_title) + 8 + 24, 24);
}
if (parent() != nullptr) {
((Notebook *)parent())->performLayout(true);
}
}
const QString &NotebookTab::getTitle() const
{
return _title;
}
void NotebookTab::setTitle(const QString &title)
{
_title = title;
}
bool NotebookTab::getSelected()
{
return _selected;
}
void NotebookTab::setSelected(bool value)
{
_selected = value;
update();
}
NotebookTab::HighlightStyle NotebookTab::getHighlightStyle() const
{
return _highlightStyle;
}
void NotebookTab::setHighlightStyle(HighlightStyle style)
{
_highlightStyle = style;
update();
}
QRect NotebookTab::getDesiredRect() const
{
return QRect(_posAnimationDesired, size());
}
void NotebookTab::hideTabXChanged(bool)
{
calcSize();
update();
}
void NotebookTab::moveAnimated(QPoint pos, bool animated)
{
_posAnimationDesired = pos;
if ((window() != NULL && !window()->isVisible()) || !animated || _posAnimated == false) {
move(pos);
_posAnimated = true;
return;
}
if (_posAnimation.endValue() == pos) {
return;
}
_posAnimation.stop();
_posAnimation.setDuration(75);
_posAnimation.setStartValue(this->pos());
_posAnimation.setEndValue(pos);
_posAnimation.start();
}
void NotebookTab::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QColor fg = QColor(0, 0, 0);
auto &colorScheme = ColorScheme::getInstance();
if (_selected) {
painter.fillRect(rect(), colorScheme.TabSelectedBackground);
fg = colorScheme.TabSelectedText;
} else if (_mouseOver) {
painter.fillRect(rect(), colorScheme.TabHoverBackground);
fg = colorScheme.TabHoverText;
} else if (_highlightStyle == HighlightHighlighted) {
painter.fillRect(rect(), colorScheme.TabHighlightedBackground);
fg = colorScheme.TabHighlightedText;
} else if (_highlightStyle == HighlightNewMessage) {
painter.fillRect(rect(), colorScheme.TabNewMessageBackground);
fg = colorScheme.TabHighlightedText;
} else {
painter.fillRect(rect(), colorScheme.TabBackground);
fg = colorScheme.TabText;
}
painter.setPen(fg);
QRect rect(0, 0, width() - (SettingsManager::getInstance().hideTabX.get() ? 0 : 16), height());
painter.drawText(rect, _title, QTextOption(Qt::AlignCenter));
if (!SettingsManager::getInstance().hideTabX.get() && (_mouseOver || _selected)) {
if (_mouseOverX) {
painter.fillRect(getXRect(), QColor(0, 0, 0, 64));
if (_mouseDownX) {
painter.fillRect(getXRect(), QColor(0, 0, 0, 64));
}
}
painter.drawLine(getXRect().topLeft() + QPoint(4, 4),
getXRect().bottomRight() + QPoint(-4, -4));
painter.drawLine(getXRect().topRight() + QPoint(-4, 4),
getXRect().bottomLeft() + QPoint(4, -4));
}
}
void NotebookTab::mousePressEvent(QMouseEvent *event)
{
_mouseDown = true;
_mouseDownX = getXRect().contains(event->pos());
update();
_notebook->select(page);
}
void NotebookTab::mouseReleaseEvent(QMouseEvent *event)
{
_mouseDown = false;
if (!SettingsManager::getInstance().hideTabX.get() && _mouseDownX &&
getXRect().contains(event->pos())) {
_mouseDownX = false;
_notebook->removePage(page);
} else {
update();
}
}
void NotebookTab::enterEvent(QEvent *)
{
_mouseOver = true;
update();
}
void NotebookTab::leaveEvent(QEvent *)
{
_mouseOverX = _mouseOver = false;
update();
}
void NotebookTab::dragEnterEvent(QDragEnterEvent *)
{
_notebook->select(page);
}
void NotebookTab::mouseMoveEvent(QMouseEvent *event)
{
bool overX = getXRect().contains(event->pos());
if (overX != _mouseOverX) {
_mouseOverX = overX && !SettingsManager::getInstance().hideTabX.get();
update();
}
if (_mouseDown && !getDesiredRect().contains(event->pos())) {
QPoint relPoint = mapToParent(event->pos());
int index;
NotebookPage *clickedPage = _notebook->tabAt(relPoint, index);
if (clickedPage != nullptr && clickedPage != page) {
_notebook->rearrangePage(clickedPage, index);
}
}
}
void NotebookTab::load(const boost::property_tree::ptree &tree)
{
// Load tab title
try {
setTitle(QString::fromStdString(tree.get<std::string>("title")));
} catch (boost::property_tree::ptree_error) {
}
}
boost::property_tree::ptree NotebookTab::save()
{
boost::property_tree::ptree tree;
tree.put("title", getTitle().toStdString());
return tree;
}
} // namespace widgets
} // namespace chatterino
+87
View File
@@ -0,0 +1,87 @@
#ifndef NOTEBOOKTAB_H
#define NOTEBOOKTAB_H
#include <QPropertyAnimation>
#include <QWidget>
#include <boost/property_tree/ptree.hpp>
#include <boost/signals2.hpp>
#include <boost/signals2/connection.hpp>
namespace chatterino {
namespace widgets {
class Notebook;
class NotebookPage;
class NotebookTab : public QWidget
{
Q_OBJECT
public:
enum HighlightStyle { HighlightNone, HighlightHighlighted, HighlightNewMessage };
explicit NotebookTab(Notebook *_notebook);
~NotebookTab();
void calcSize();
NotebookPage *page;
const QString &getTitle() const;
void setTitle(const QString &title);
bool getSelected();
void setSelected(bool value);
HighlightStyle getHighlightStyle() const;
void setHighlightStyle(HighlightStyle style);
void moveAnimated(QPoint pos, bool animated = true);
QRect getDesiredRect() const;
void hideTabXChanged(bool);
protected:
void paintEvent(QPaintEvent *) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void enterEvent(QEvent *) override;
void leaveEvent(QEvent *) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
private:
boost::signals2::connection _hideXConnection;
QPropertyAnimation _posAnimation;
bool _posAnimated;
QPoint _posAnimationDesired;
Notebook *_notebook;
QString _title;
bool _selected;
bool _mouseOver;
bool _mouseDown;
bool _mouseOverX;
bool _mouseDownX;
HighlightStyle _highlightStyle;
QRect getXRect()
{
return QRect(this->width() - 20, 4, 16, 16);
}
public:
void load(const boost::property_tree::ptree &tree);
boost::property_tree::ptree save();
};
} // namespace widgets
} // namespace chatterino
#endif // NOTEBOOKTAB_H
+54
View File
@@ -0,0 +1,54 @@
#ifndef RESIZINGTEXTEDIT_H
#define RESIZINGTEXTEDIT_H
#include <QKeyEvent>
#include <QTextEdit>
#include <boost/signals2.hpp>
class ResizingTextEdit : public QTextEdit
{
public:
ResizingTextEdit()
: keyPressed()
{
auto sizePolicy = this->sizePolicy();
sizePolicy.setHeightForWidth(true);
sizePolicy.setVerticalPolicy(QSizePolicy::Preferred);
this->setSizePolicy(sizePolicy);
QObject::connect(this, &QTextEdit::textChanged, this, &QWidget::updateGeometry);
}
QSize sizeHint() const override
{
return QSize(this->width(), this->heightForWidth(this->width()));
}
bool hasHeightForWidth() const override
{
return true;
}
boost::signals2::signal<void(QKeyEvent *)> keyPressed;
protected:
int heightForWidth(int) const override
{
auto margins = this->contentsMargins();
return margins.top() + document()->size().height() + margins.bottom() + 5;
}
void keyPressEvent(QKeyEvent *event) override
{
event->ignore();
keyPressed(event);
if (!event->isAccepted()) {
QTextEdit::keyPressEvent(event);
}
}
};
#endif // RESIZINGTEXTEDIT_H
+305
View File
@@ -0,0 +1,305 @@
#include "widgets/scrollbar.h"
#include "colorscheme.h"
#include <QMouseEvent>
#include <QPainter>
#define MIN_THUMB_HEIGHT 10
namespace chatterino {
namespace widgets {
ScrollBar::ScrollBar(QWidget *widget)
: QWidget(widget)
, _mutex()
, _currentValueAnimation(this, "currentValue")
, _highlights(nullptr)
, _mouseOverIndex(-1)
, _mouseDownIndex(-1)
, _lastMousePosition()
, _buttonHeight(16)
, _trackHeight(100)
, _thumbRect()
, _maximum()
, _minimum()
, _largeChange()
, _smallChange()
, _desiredValue()
, _currentValue()
, _currentValueChanged()
{
resize(16, 100);
_currentValueAnimation.setDuration(250);
_currentValueAnimation.setEasingCurve(QEasingCurve(QEasingCurve::OutCubic));
setMouseTracking(true);
}
ScrollBar::~ScrollBar()
{
auto highlight = _highlights;
while (highlight != NULL) {
auto tmp = highlight->next;
delete highlight;
highlight = tmp;
}
}
void ScrollBar::removeHighlightsWhere(std::function<bool(ScrollBarHighlight &)> func)
{
_mutex.lock();
ScrollBarHighlight *last = NULL;
ScrollBarHighlight *current = _highlights;
while (current != NULL) {
if (func(*current)) {
if (last == NULL) {
_highlights = current->next;
} else {
last->next = current->next;
}
auto oldCurrent = current;
current = current->next;
last = current;
delete oldCurrent;
}
}
_mutex.unlock();
}
void ScrollBar::addHighlight(ScrollBarHighlight *highlight)
{
_mutex.lock();
if (_highlights == NULL) {
_highlights = highlight;
} else {
highlight->next = _highlights->next;
_highlights->next = highlight;
}
_mutex.unlock();
}
void ScrollBar::setMaximum(qreal value)
{
_maximum = value;
updateScroll();
}
void ScrollBar::setMinimum(qreal value)
{
_minimum = value;
updateScroll();
}
void ScrollBar::setLargeChange(qreal value)
{
_largeChange = value;
updateScroll();
}
void ScrollBar::setSmallChange(qreal value)
{
_smallChange = value;
updateScroll();
}
void ScrollBar::setDesiredValue(qreal value, bool animated)
{
value = std::max(_minimum, std::min(_maximum - _largeChange, value));
if (_desiredValue != value) {
if (animated) {
_currentValueAnimation.stop();
_currentValueAnimation.setStartValue(_currentValue);
_currentValueAnimation.setEndValue(value);
_currentValueAnimation.start();
} else {
if (_currentValueAnimation.state() != QPropertyAnimation::Running) {
// currentValueAnimation.stop();
setCurrentValue(value);
}
}
}
_desiredValue = value;
}
qreal ScrollBar::getMaximum() const
{
return _maximum;
}
qreal ScrollBar::getMinimum() const
{
return _minimum;
}
qreal ScrollBar::getLargeChange() const
{
return _largeChange;
}
qreal ScrollBar::getSmallChange() const
{
return _smallChange;
}
qreal ScrollBar::getDesiredValue() const
{
return _desiredValue;
}
qreal ScrollBar::getCurrentValue() const
{
return _currentValue;
}
boost::signals2::signal<void()> &ScrollBar::getCurrentValueChanged()
{
return _currentValueChanged;
}
void ScrollBar::setCurrentValue(qreal value)
{
value = std::max(_minimum, std::min(_maximum - _largeChange, value));
if (_currentValue != value) {
_currentValue = value;
updateScroll();
_currentValueChanged();
update();
}
}
void ScrollBar::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.fillRect(rect(), ColorScheme::getInstance().ScrollbarBG);
painter.fillRect(QRect(0, 0, width(), _buttonHeight), QColor(255, 0, 0));
painter.fillRect(QRect(0, height() - _buttonHeight, width(), _buttonHeight), QColor(255, 0, 0));
painter.fillRect(_thumbRect, QColor(0, 255, 255));
// ScrollBarHighlight *highlight = highlights;
_mutex.lock();
// do {
// painter.fillRect();
// } while ((highlight = highlight->next()) != NULL);
_mutex.unlock();
}
void ScrollBar::mouseMoveEvent(QMouseEvent *event)
{
if (_mouseDownIndex == -1) {
int y = event->pos().y();
auto oldIndex = _mouseOverIndex;
if (y < _buttonHeight) {
_mouseOverIndex = 0;
} else if (y < _thumbRect.y()) {
_mouseOverIndex = 1;
} else if (_thumbRect.contains(2, y)) {
_mouseOverIndex = 2;
} else if (y < height() - _buttonHeight) {
_mouseOverIndex = 3;
} else {
_mouseOverIndex = 4;
}
if (oldIndex != _mouseOverIndex) {
update();
}
} else if (_mouseDownIndex == 2) {
int delta = event->pos().y() - _lastMousePosition.y();
setDesiredValue(_desiredValue + (qreal)delta / _trackHeight * _maximum);
}
_lastMousePosition = event->pos();
}
void ScrollBar::mousePressEvent(QMouseEvent *event)
{
int y = event->pos().y();
if (y < _buttonHeight) {
_mouseDownIndex = 0;
} else if (y < _thumbRect.y()) {
_mouseDownIndex = 1;
} else if (_thumbRect.contains(2, y)) {
_mouseDownIndex = 2;
} else if (y < height() - _buttonHeight) {
_mouseDownIndex = 3;
} else {
_mouseDownIndex = 4;
}
}
void ScrollBar::mouseReleaseEvent(QMouseEvent *event)
{
int y = event->pos().y();
if (y < _buttonHeight) {
if (_mouseDownIndex == 0) {
setDesiredValue(_desiredValue - _smallChange, true);
}
} else if (y < _thumbRect.y()) {
if (_mouseDownIndex == 1) {
setDesiredValue(_desiredValue - _smallChange, true);
}
} else if (_thumbRect.contains(2, y)) {
// do nothing
} else if (y < height() - _buttonHeight) {
if (_mouseDownIndex == 3) {
setDesiredValue(_desiredValue + _smallChange, true);
}
} else {
if (_mouseDownIndex == 4) {
setDesiredValue(_desiredValue + _smallChange, true);
}
}
_mouseDownIndex = -1;
update();
}
void ScrollBar::leaveEvent(QEvent *)
{
_mouseOverIndex = -1;
update();
}
void ScrollBar::updateScroll()
{
_trackHeight = height() - _buttonHeight - _buttonHeight - MIN_THUMB_HEIGHT - 1;
_thumbRect = QRect(0, (int)(_currentValue / _maximum * _trackHeight) + 1 + _buttonHeight,
width(), (int)(_largeChange / _maximum * _trackHeight) + MIN_THUMB_HEIGHT);
update();
}
}
}
+80
View File
@@ -0,0 +1,80 @@
#ifndef SCROLLBAR_H
#define SCROLLBAR_H
#include "widgets/scrollbarhighlight.h"
#include <QMutex>
#include <QPropertyAnimation>
#include <QWidget>
#include <boost/signals2.hpp>
#include <functional>
namespace chatterino {
namespace widgets {
class ScrollBar : public QWidget
{
Q_OBJECT
public:
ScrollBar(QWidget *parent = 0);
~ScrollBar();
void removeHighlightsWhere(std::function<bool(ScrollBarHighlight &)> func);
void addHighlight(ScrollBarHighlight *highlight);
Q_PROPERTY(qreal _desiredValue READ getDesiredValue WRITE setDesiredValue)
void setMaximum(qreal value);
void setMinimum(qreal value);
void setLargeChange(qreal value);
void setSmallChange(qreal value);
void setDesiredValue(qreal value, bool animated = false);
qreal getMaximum() const;
qreal getMinimum() const;
qreal getLargeChange() const;
qreal getSmallChange() const;
qreal getDesiredValue() const;
qreal getCurrentValue() const;
boost::signals2::signal<void()> &getCurrentValueChanged();
void setCurrentValue(qreal value);
private:
Q_PROPERTY(qreal _currentValue READ getCurrentValue WRITE setCurrentValue)
QMutex _mutex;
QPropertyAnimation _currentValueAnimation;
ScrollBarHighlight *_highlights;
void paintEvent(QPaintEvent *);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void leaveEvent(QEvent *);
int _mouseOverIndex;
int _mouseDownIndex;
QPoint _lastMousePosition;
int _buttonHeight;
int _trackHeight;
QRect _thumbRect;
qreal _maximum;
qreal _minimum;
qreal _largeChange;
qreal _smallChange;
qreal _desiredValue;
qreal _currentValue;
boost::signals2::signal<void()> _currentValueChanged;
void updateScroll();
};
}
}
#endif // SCROLLBAR_H
+16
View File
@@ -0,0 +1,16 @@
#include "widgets/scrollbarhighlight.h"
#include "colorscheme.h"
namespace chatterino {
namespace widgets {
ScrollBarHighlight::ScrollBarHighlight(float position, int colorIndex, Style style, QString tag)
: _style(style)
, _position(position)
, _colorIndex(std::max(0, std::min(ColorScheme::getInstance().HighlightColorCount, colorIndex)))
, _tag(tag)
{
}
} // namespace widgets
} // namespace chatterino
+49
View File
@@ -0,0 +1,49 @@
#ifndef SCROLLBARHIGHLIGHT_H
#define SCROLLBARHIGHLIGHT_H
#include "QString"
namespace chatterino {
namespace widgets {
class ScrollBarHighlight
{
public:
enum Style { Default, Left, Right, SingleLine };
ScrollBarHighlight(float getPosition, int getColorIndex, Style getStyle = Default,
QString _tag = "");
Style getStyle()
{
return _style;
}
float getPosition()
{
return _position;
}
int getColorIndex()
{
return _colorIndex;
}
QString getTag()
{
return _tag;
}
ScrollBarHighlight *next = nullptr;
private:
Style _style;
float _position;
int _colorIndex;
QString _tag;
};
} // namespace widgets
} // namespace chatterino
#endif // SCROLLBARHIGHLIGHT_H
+339
View File
@@ -0,0 +1,339 @@
#include "widgets/settingsdialog.h"
#include "accountmanager.h"
#include "twitch/twitchuser.h"
#include "widgets/settingsdialogtab.h"
#include "windowmanager.h"
#include <QComboBox>
#include <QFile>
#include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
#include <QListWidget>
#include <QPalette>
#include <QResource>
namespace chatterino {
namespace widgets {
SettingsDialog::SettingsDialog()
: _snapshot(SettingsManager::getInstance().createSnapshot())
{
QFile file(":/qss/settings.qss");
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
setStyleSheet(styleSheet);
QPalette palette;
palette.setColor(QPalette::Background, QColor("#444"));
setPalette(palette);
_pageStack.setObjectName("pages");
setLayout(&_vbox);
_vbox.addLayout(&_hbox);
_vbox.addWidget(&_buttonBox);
auto tabWidget = new QWidget();
tabWidget->setObjectName("tabWidget");
tabWidget->setLayout(&_tabs);
tabWidget->setFixedWidth(200);
_hbox.addWidget(tabWidget);
_hbox.addLayout(&_pageStack);
_buttonBox.addButton(&_okButton, QDialogButtonBox::ButtonRole::AcceptRole);
_buttonBox.addButton(&_cancelButton, QDialogButtonBox::ButtonRole::RejectRole);
QObject::connect(&_okButton, &QPushButton::clicked, this, &SettingsDialog::okButtonClicked);
QObject::connect(&_cancelButton, &QPushButton::clicked, this,
&SettingsDialog::cancelButtonClicked);
_okButton.setText("OK");
_cancelButton.setText("Cancel");
resize(600, 500);
addTabs();
}
void SettingsDialog::addTabs()
{
SettingsManager &settings = SettingsManager::getInstance();
QVBoxLayout *vbox;
// Accounts
vbox = new QVBoxLayout();
{
// add remove buttons
auto buttonBox = new QDialogButtonBox(this);
auto addButton = new QPushButton("add", this);
auto removeButton = new QPushButton("remove", this);
buttonBox->addButton(addButton, QDialogButtonBox::YesRole);
buttonBox->addButton(removeButton, QDialogButtonBox::NoRole);
vbox->addWidget(buttonBox);
// listview
auto listWidget = new QListWidget(this);
listWidget->addItem("xD");
listWidget->addItem("vi von");
listWidget->addItem("monkaS");
for (auto &user : AccountManager::getInstance().getTwitchUsers()) {
listWidget->addItem(user.getUserName());
}
vbox->addWidget(listWidget);
}
// vbox->addStretch(1);
addTab(vbox, "Accounts", ":/images/Message_16xLG.png");
// Appearance
vbox = new QVBoxLayout();
{
auto group = new QGroupBox("Application");
auto form = new QFormLayout();
auto combo = new QComboBox();
auto slider = new QSlider(Qt::Horizontal);
auto font = new QPushButton("select");
auto compactTabs = createCheckbox("Hide tab X", settings.hideTabX);
auto hidePreferencesButton = createCheckbox("Hide preferences button (ctrl+p to show)",
settings.hidePreferencesButton);
auto hideUserButton = createCheckbox("Hide user button", settings.hideUserButton);
form->addRow("Theme:", combo);
form->addRow("Theme color:", slider);
form->addRow("Font:", font);
form->addRow("Tabbar:", compactTabs);
form->addRow("", hidePreferencesButton);
form->addRow("", hideUserButton);
// theme
combo->addItem("White");
combo->addItem("Light");
combo->addItem("Dark");
combo->addItem("Black");
QString theme = settings.theme.get();
theme = theme.toLower();
if (theme == "light") {
combo->setCurrentIndex(0);
} else if (theme == "white") {
combo->setCurrentIndex(1);
} else if (theme == "black") {
combo->setCurrentIndex(3);
} else {
combo->setCurrentIndex(2);
}
QObject::connect(combo, &QComboBox::currentTextChanged, this,
[&settings](const QString &value) { settings.theme.set(value); });
// theme hue
slider->setMinimum(0);
slider->setMaximum(1000);
float hue = settings.themeHue.get();
slider->setValue(std::min(std::max(hue, (float)0.0), (float)1.0) * 1000);
QObject::connect(slider, &QSlider::valueChanged, this, [&settings](int value) {
settings.themeHue.set(value / 1000.0);
WindowManager::getInstance().updateAll();
});
group->setLayout(form);
vbox->addWidget(group);
}
{
auto group = new QGroupBox("Messages");
auto v = new QVBoxLayout();
v->addWidget(createCheckbox("Show timestamp", settings.showTimestamps));
v->addWidget(createCheckbox("Show seconds in timestamp", settings.showTimestampSeconds));
v->addWidget(createCheckbox("Allow sending duplicate messages (add a space at the end)",
settings.allowDouplicateMessages));
v->addWidget(createCheckbox("Seperate messages", settings.seperateMessages));
v->addWidget(createCheckbox("Show message length", settings.showMessageLength));
group->setLayout(v);
vbox->addWidget(group);
}
vbox->addStretch(1);
addTab(vbox, "Appearance", ":/images/AppearanceEditorPart_16x.png");
// Behaviour
vbox = new QVBoxLayout();
{
auto form = new QFormLayout();
form->addRow("Window:", createCheckbox("Window always on top", settings.windowTopMost));
form->addRow("Messages:", createCheckbox("Mention users with a @ (except in commands)",
settings.mentionUsersWithAt));
form->addRow("", createCheckbox("Hide input box if empty", settings.hideEmptyInput));
form->addRow("", createCheckbox("Show last read message indicator",
settings.showLastMessageIndicator));
// auto v = new QVBoxLayout();
// v->addWidget(new QLabel("Mouse scroll speed"));
auto scroll = new QSlider(Qt::Horizontal);
form->addRow("Mouse scroll speed:", scroll);
// v->addWidget(scroll);
// v->addStretch(1);
// vbox->addLayout(v);
vbox->addLayout(form);
}
vbox->addStretch(1);
addTab(vbox, "Behaviour", ":/images/AppearanceEditorPart_16x.png");
// Commands
vbox = new QVBoxLayout();
vbox->addWidget(new QLabel());
vbox->addStretch(1);
addTab(vbox, "Commands", ":/images/CustomActionEditor_16x.png");
// Emotes
vbox = new QVBoxLayout();
vbox->addWidget(createCheckbox("Enable Twitch Emotes", settings.enableTwitchEmotes));
vbox->addWidget(createCheckbox("Enable BetterTTV Emotes", settings.enableBttvEmotes));
vbox->addWidget(createCheckbox("Enable FrankerFaceZ Emotes", settings.enableFfzEmotes));
vbox->addWidget(createCheckbox("Enable Gif Emotes", settings.enableGifs));
vbox->addWidget(createCheckbox("Enable Emojis", settings.enableEmojis));
vbox->addWidget(createCheckbox("Enable Twitch Emotes", settings.enableTwitchEmotes));
vbox->addStretch(1);
addTab(vbox, "Emotes", ":/images/Emoji_Color_1F60A_19.png");
// Ignored Users
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Ignored Users", ":/images/StatusAnnotations_Blocked_16xLG_color.png");
// Ignored Messages
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Ignored Messages", ":/images/Filter_16x.png");
// Links
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Links", ":/images/VSO_Link_blue_16x.png");
// Logging
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Logs", ":/images/VSO_Link_blue_16x.png");
// Highlighting
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Highlighting", ":/images/format_Bold_16xLG.png");
// Whispers
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Whispers", ":/images/Message_16xLG.png");
// Add stretch
_tabs.addStretch(1);
}
void SettingsDialog::addTab(QLayout *layout, QString title, QString imageRes)
{
auto widget = new QWidget();
widget->setLayout(layout);
auto tab = new SettingsDialogTab(this, title, imageRes);
tab->setWidget(widget);
_tabs.addWidget(tab, 0, Qt::AlignTop);
_pageStack.addWidget(widget);
if (_tabs.count() == 1) {
select(tab);
}
}
void SettingsDialog::select(SettingsDialogTab *tab)
{
_pageStack.setCurrentWidget(tab->getWidget());
if (_selectedTab != NULL) {
_selectedTab->setSelected(false);
_selectedTab->setStyleSheet("color: #FFF");
}
tab->setSelected(true);
tab->setStyleSheet("background: #555; color: #FFF");
_selectedTab = tab;
}
void SettingsDialog::showDialog()
{
static SettingsDialog *instance = new SettingsDialog();
instance->show();
instance->activateWindow();
instance->raise();
instance->setFocus();
}
/// Widget creation helpers
QCheckBox *SettingsDialog::createCheckbox(const QString &title, Setting<bool> &setting)
{
auto checkbox = new QCheckBox(title);
// Set checkbox initial state
checkbox->setChecked(setting.get());
QObject::connect(checkbox, &QCheckBox::toggled, this,
[&setting](bool state) { setting.set(state); });
return checkbox;
}
void SettingsDialog::okButtonClicked()
{
this->close();
}
void SettingsDialog::cancelButtonClicked()
{
_snapshot.apply();
this->close();
}
} // namespace widgets
} // namespace chatterino
+58
View File
@@ -0,0 +1,58 @@
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H
#include "settingsmanager.h"
#include "settingssnapshot.h"
#include "widgets/settingsdialogtab.h"
#include <QButtonGroup>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QListView>
#include <QMainWindow>
#include <QPushButton>
#include <QStackedLayout>
#include <QVBoxLayout>
#include <QWidget>
namespace chatterino {
namespace widgets {
class SettingsDialog : public QWidget
{
public:
SettingsDialog();
void select(SettingsDialogTab *tab);
static void showDialog();
private:
SettingsSnapshot _snapshot;
QVBoxLayout _tabs;
QVBoxLayout _vbox;
QHBoxLayout _hbox;
QStackedLayout _pageStack;
QDialogButtonBox _buttonBox;
QPushButton _okButton;
QPushButton _cancelButton;
void addTab(QLayout *layout, QString title, QString imageRes);
void addTabs();
SettingsDialogTab *_selectedTab = NULL;
/// Widget creation helpers
QCheckBox *createCheckbox(const QString &title, Setting<bool> &setting);
void okButtonClicked();
void cancelButtonClicked();
};
} // namespace widgets
} // namespace chatterino
#endif // SETTINGSDIALOG_H
+75
View File
@@ -0,0 +1,75 @@
#include "widgets/settingsdialogtab.h"
#include "widgets/settingsdialog.h"
#include <QPainter>
#include <QStyleOption>
namespace chatterino {
namespace widgets {
SettingsDialogTab::SettingsDialogTab(SettingsDialog *dialog, QString label, QString imageRes)
: _label(label)
, _image(QImage(imageRes))
, _dialog(dialog)
, _selected(false)
{
setFixedHeight(32);
setCursor(QCursor(Qt::PointingHandCursor));
setStyleSheet("color: #FFF");
}
void SettingsDialogTab::setSelected(bool selected)
{
if (_selected == selected)
return;
_selected = selected;
emit selectedChanged(selected);
}
bool SettingsDialogTab::getSelected() const
{
return _selected;
}
QWidget *SettingsDialogTab::getWidget()
{
return _widget;
}
void SettingsDialogTab::setWidget(QWidget *widget)
{
_widget = widget;
}
void SettingsDialogTab::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QStyleOption opt;
opt.init(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
int a = (height() - _image.width()) / 2;
painter.drawImage(a, a, _image);
a = a + a + _image.width();
painter.drawText(QRect(a, 0, width() - a, height()), _label,
QTextOption(Qt::AlignLeft | Qt::AlignVCenter));
}
void SettingsDialogTab::mousePressEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton) {
return;
}
_dialog->select(this);
}
} // namespace widgets
} // namespace chatterino
+43
View File
@@ -0,0 +1,43 @@
#ifndef SETTINGSNOTEBOOKTAB_H
#define SETTINGSNOTEBOOKTAB_H
#include <QPaintEvent>
#include <QWidget>
namespace chatterino {
namespace widgets {
class SettingsDialog;
class SettingsDialogTab : public QWidget
{
Q_OBJECT
Q_PROPERTY(bool getSelected READ getSelected WRITE setSelected NOTIFY selectedChanged)
public:
SettingsDialogTab(SettingsDialog *_dialog, QString _label, QString imageRes);
void setSelected(bool selected);
bool getSelected() const;
QWidget *getWidget();
void setWidget(QWidget *widget);
signals:
void selectedChanged(bool);
private:
void paintEvent(QPaintEvent *);
void mousePressEvent(QMouseEvent *event);
QWidget *_widget;
QString _label;
QImage _image;
SettingsDialog *_dialog;
bool _selected;
};
} // namespace widgets
} // namespace chatterino
#endif // SETTINGSNOTEBOOKTAB_H
+56
View File
@@ -0,0 +1,56 @@
#ifndef SIGNALLABEL_H
#define SIGNALLABEL_H
#include <QFlags>
#include <QLabel>
#include <QMouseEvent>
#include <QWidget>
class SignalLabel : public QLabel
{
Q_OBJECT
public:
explicit SignalLabel(QWidget *parent = 0, Qt::WindowFlags f = 0)
: QLabel(parent, f)
{
}
virtual ~SignalLabel() = default;
signals:
void mouseDoubleClick(QMouseEvent *ev);
void mouseDown();
void mouseUp();
protected:
virtual void mouseDoubleClickEvent(QMouseEvent *ev) override
{
emit this->mouseDoubleClick(ev);
}
virtual void mousePressEvent(QMouseEvent *event) override
{
if (event->button() == Qt::LeftButton) {
emit mouseDown();
}
event->ignore();
}
void mouseReleaseEvent(QMouseEvent *event) override
{
if (event->button() == Qt::LeftButton) {
emit mouseUp();
}
event->ignore();
}
virtual void mouseMoveEvent(QMouseEvent *event) override
{
event->ignore();
}
};
#endif // SIGNALLABEL_H
+42
View File
@@ -0,0 +1,42 @@
#include "widgets/textinputdialog.h"
#include <QSizePolicy>
namespace chatterino {
namespace widgets {
TextInputDialog::TextInputDialog(QWidget *parent)
: QDialog(parent)
, _vbox(this)
, _lineEdit()
, _buttonBox()
, _okButton("OK")
, _cancelButton("Cancel")
{
_vbox.addWidget(&_lineEdit);
_vbox.addLayout(&_buttonBox);
_buttonBox.addStretch(1);
_buttonBox.addWidget(&_okButton);
_buttonBox.addWidget(&_cancelButton);
QObject::connect(&_okButton, SIGNAL(clicked()), this, SLOT(okButtonClicked()));
QObject::connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(cancelButtonClicked()));
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setWindowFlags((windowFlags() & ~(Qt::WindowContextHelpButtonHint)) | Qt::Dialog |
Qt::MSWindowsFixedSizeDialogHint);
}
void TextInputDialog::okButtonClicked()
{
accept();
close();
}
void TextInputDialog::cancelButtonClicked()
{
reject();
close();
}
}
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef TEXTINPUTDIALOG_H
#define TEXTINPUTDIALOG_H
#include <QDialog>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QString>
#include <QVBoxLayout>
namespace chatterino {
namespace widgets {
class TextInputDialog : public QDialog
{
Q_OBJECT
public:
TextInputDialog(QWidget *parent = NULL);
QString getText() const
{
return _lineEdit.text();
}
void setText(const QString &text)
{
_lineEdit.setText(text);
}
private:
QVBoxLayout _vbox;
QLineEdit _lineEdit;
QHBoxLayout _buttonBox;
QPushButton _okButton;
QPushButton _cancelButton;
private slots:
void okButtonClicked();
void cancelButtonClicked();
};
}
}
#endif // TEXTINPUTDIALOG_H
+11
View File
@@ -0,0 +1,11 @@
#include "titlebar.h"
namespace chatterino {
namespace widgets {
TitleBar::TitleBar(QWidget *parent)
: QWidget(parent)
{
setFixedHeight(32);
}
}
}
+16
View File
@@ -0,0 +1,16 @@
#ifndef TITLEBAR_H
#define TITLEBAR_H
#include <QWidget>
namespace chatterino {
namespace widgets {
class TitleBar : public QWidget
{
public:
TitleBar(QWidget *parent = nullptr);
};
}
}
#endif // TITLEBAR_H