chatwidgetview refreshes on new message

This commit is contained in:
fourtf 2017-01-16 03:15:07 +01:00
parent d924f5bd8d
commit 1194905646
21 changed files with 321 additions and 196 deletions

View file

@ -1,14 +1,10 @@
#include "channel.h"
#include "message.h"
#include "windows.h"
#include <memory>
Channel Channel::whispers(QString("/whispers"));
Channel Channel::mentions(QString("/mentions"));
QMap<QString, Channel *> Channel::channels = QMap<QString, Channel *>();
Channel::Channel(QString channel)
Channel::Channel(const QString &channel)
: m_messages()
, m_name((channel.length() > 0 && channel[0] == '#') ? channel.mid(1)
: channel)
@ -22,59 +18,6 @@ Channel::Channel(QString channel)
{
}
Channel *
Channel::addChannel(const QString &channel)
{
auto c = getChannel(channel);
if (c == NULL) {
c = new Channel(channel);
channels.insert(channel, c);
return c;
}
c->m_referenceCount++;
return c;
}
Channel *
Channel::getChannel(const QString &channel)
{
if (channel == "/whispers") {
return const_cast<Channel *>(&whispers);
}
if (channel == "/mentions") {
return const_cast<Channel *>(&mentions);
}
auto a = channels.find(channel);
if (a == channels.end()) {
return NULL;
}
return a.value();
}
void
Channel::removeChannel(const QString &channel)
{
auto c = getChannel(channel);
if (c == NULL)
return;
c->m_referenceCount--;
if (c->m_referenceCount == 0) {
channels.remove(channel);
delete c;
}
}
QVector<std::shared_ptr<Message>>
Channel::getMessagesClone()
{
@ -91,4 +34,6 @@ Channel::addMessage(std::shared_ptr<Message> message)
m_messageMutex.lock();
m_messages.append(message);
m_messageMutex.unlock();
Windows::repaintVisibleChatWidgets();
}

View file

@ -14,22 +14,9 @@ class Message;
class Channel
{
// static
public:
static Channel whispers;
static Channel mentions;
Channel(const QString &channel);
static Channel *addChannel(const QString &channel);
static Channel *getChannel(const QString &channel);
static void removeChannel(const QString &channel);
private:
static QMap<QString, Channel *> channels;
// members
public:
// properties
const ConcurrentMap<QString, LazyLoadedImage *> &
bttvChannelEmotes() const
@ -102,10 +89,6 @@ public:
QVector<std::shared_ptr<Message>> getMessagesClone();
private:
Channel(QString channel);
int m_referenceCount = 0;
QVector<std::shared_ptr<Message>> m_messages;
QString m_name;

58
channels.cpp Normal file
View file

@ -0,0 +1,58 @@
#include "channels.h"
Channel Channels::m_whispers(QString("/whispers"));
Channel Channels::m_mentions(QString("/mentions"));
QMap<QString, std::tuple<Channel *, int>> Channels::m_channels;
Channel *
Channels::addChannel(const QString &channel)
{
auto c = getChannel(channel);
if (c == NULL) {
c = new Channel(channel);
m_channels.insert(channel, std::tuple<Channel *, int>(c, 1));
return c;
}
return c;
}
Channel *
Channels::getChannel(const QString &channel)
{
if (channel == "/whispers") {
return &m_whispers;
}
if (channel == "/mentions") {
return &m_mentions;
}
auto a = m_channels.find(channel);
if (a == m_channels.end()) {
return NULL;
}
return std::get<0>(a.value());
}
void
Channels::removeChannel(const QString &channel)
{
auto a = m_channels.find(channel);
if (a == m_channels.end()) {
return;
}
std::get<1>(a.value())--;
if (std::get<1>(a.value()) == 0) {
m_channels.remove(channel);
delete std::get<0>(a.value());
}
}

36
channels.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef CHANNELS_H
#define CHANNELS_H
#include "channel.h"
class Channels
{
public:
static Channel *
whispers()
{
return &m_whispers;
}
static Channel *
mentions()
{
return &m_whispers;
}
static Channel *addChannel(const QString &channel);
static Channel *getChannel(const QString &channel);
static void removeChannel(const QString &channel);
private:
Channels()
{
}
static Channel m_whispers;
static Channel m_mentions;
static QMap<QString, std::tuple<Channel *, int>> m_channels;
};
#endif // CHANNELS_H

View file

@ -66,7 +66,8 @@ SOURCES += main.cpp\
resources.cpp \
windows.cpp \
chatwidgetheaderbutton.cpp \
chatwidgetheaderbuttonlabel.cpp
chatwidgetheaderbuttonlabel.cpp \
channels.cpp
HEADERS += mainwindow.h \
chatwidget.h \
@ -104,7 +105,8 @@ HEADERS += mainwindow.h \
resources.h \
windows.h \
chatwidgetheaderbutton.h \
chatwidgetheaderbuttonlabel.h
chatwidgetheaderbuttonlabel.h \
channels.h
PRECOMPILED_HEADER =

View file

@ -7,14 +7,14 @@
ChatWidget::ChatWidget(QWidget *parent)
: QWidget(parent)
, vbox(this)
, m_vbox(this)
{
vbox.setSpacing(0);
vbox.setMargin(1);
m_vbox.setSpacing(0);
m_vbox.setMargin(1);
vbox.addWidget(&header);
vbox.addWidget(&view);
vbox.addWidget(&input);
m_vbox.addWidget(&m_header);
m_vbox.addWidget(&m_view);
m_vbox.addWidget(&m_input);
}
ChatWidget::~ChatWidget()

View file

@ -17,17 +17,23 @@ public:
ChatWidget(QWidget *parent = 0);
~ChatWidget();
ChatWidgetView &
view()
{
return m_view;
}
protected:
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
private:
QFont font;
QVBoxLayout vbox;
ChatWidgetHeader header;
ChatWidgetView view;
ChatWidgetInput input;
QFont m_font;
QVBoxLayout m_vbox;
ChatWidgetHeader m_header;
ChatWidgetView m_view;
ChatWidgetInput m_input;
Channel *channel = NULL;
Channel *m_channel = NULL;
};
#endif // CHATWIDGET_H

View file

@ -1,4 +1,5 @@
#include "chatwidgetview.h"
#include "channels.h"
#include "message.h"
#include "word.h"
#include "wordpart.h"
@ -15,7 +16,26 @@ ChatWidgetView::ChatWidgetView()
scroll->scrollTo(QPointF(0, 100));
m_channel = Channel::getChannel("fourtf");
m_channel = Channels::getChannel("fourtf");
}
bool
ChatWidgetView::layoutMessages()
{
auto c = channel();
if (c == NULL)
return false;
auto messages = c->getMessagesClone();
bool redraw = false;
for (std::shared_ptr<Message> &message : messages) {
redraw |= message.get()->layout(this->width(), true);
}
return redraw;
}
void
@ -24,17 +44,7 @@ ChatWidgetView::resizeEvent(QResizeEvent *)
scrollbar.resize(scrollbar.width(), height());
scrollbar.move(width() - scrollbar.width(), 0);
auto c = channel();
if (c == NULL)
return;
auto messages = c->getMessagesClone();
for (std::shared_ptr<Message> &message : messages) {
qInfo(QString::number(width()).toStdString().c_str());
message.get()->layout(this->width(), true);
}
layoutMessages();
}
void

View file

@ -19,6 +19,8 @@ public:
return m_channel;
}
bool layoutMessages();
protected:
void resizeEvent(QResizeEvent *);

View file

@ -1,14 +1,16 @@
#include "ircmanager.h"
#include "QJsonArray"
#include "QJsonDocument"
#include "QJsonObject"
#include "QNetworkReply"
#include "asyncexec.h"
#include "channel.h"
#include "future"
#include "irccommand.h"
#include "ircconnection.h"
#include "qnetworkrequest.h"
#include "channels.h"
#include <irccommand.h>
#include <ircconnection.h>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <future>
Account *IrcManager::account = nullptr;
IrcConnection *IrcManager::connection = NULL;
@ -166,7 +168,7 @@ IrcManager::privateMessageReceived(IrcPrivateMessage *message)
qInfo(message->content().toStdString().c_str());
qInfo(message->target().toStdString().c_str());
auto c = Channel::getChannel(message->target().mid(1));
auto c = Channels::getChannel(message->target().mid(1));
if (c != NULL) {
c->addMessage(std::shared_ptr<Message>(new Message(*message, *c)));
@ -209,8 +211,8 @@ IrcManager::tryAddIgnoredUser(QString const &username, QString &errorMessage)
return true;
}
errorMessage = "Error while ignoring user \"" + username + "\": " +
reply->errorString();
errorMessage = "Error while ignoring user \"" + username +
"\": " + reply->errorString();
return false;
}
@ -243,8 +245,8 @@ IrcManager::tryRemoveIgnoredUser(QString const &username, QString &errorMessage)
return true;
}
errorMessage = "Error while unignoring user \"" + username + "\": " +
reply->errorString();
errorMessage = "Error while unignoring user \"" + username +
"\": " + reply->errorString();
return false;
}

View file

@ -3,13 +3,14 @@
#define TWITCH_MAX_MESSAGELENGTH 500
#include "IrcMessage"
#include "QMap"
#include "QMutex"
#include "QString"
#include "account.h"
#include "message.h"
#include "qnetworkaccessmanager.h"
#include <IrcMessage>
#include <QMap>
#include <QMutex>
#include <QNetworkAccessManager>
#include <QString>
class IrcManager
{

View file

@ -3,6 +3,7 @@
#include "asyncexec.h"
#include "emotes.h"
#include "ircmanager.h"
#include "windows.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
@ -58,6 +59,7 @@ LazyLoadedImage::loadImage()
m_pixmap = pixmap;
Emotes::incGeneration();
Windows::layoutVisibleChatWidgets();
});
//}));
}

View file

@ -1,3 +1,4 @@
#include "channels.h"
#include "colorscheme.h"
#include "emojis.h"
#include "ircmanager.h"
@ -21,8 +22,8 @@ main(int argc, char *argv[])
MainWindow &w = Windows::mainWindow();
w.show();
Channel::addChannel("ian678");
Channel::addChannel("fourtf");
Channels::addChannel("ian678");
Channels::addChannel("fourtf");
IrcManager::connect();

View file

@ -25,3 +25,42 @@ MainWindow::MainWindow(QWidget *parent)
MainWindow::~MainWindow()
{
}
void
MainWindow::layoutVisibleChatWidgets()
{
auto *page = notebook.selected();
if (page == NULL) {
return;
}
const std::vector<ChatWidget *> &widgets = page->chatWidgets();
for (auto it = widgets.begin(); it != widgets.end(); ++it) {
ChatWidget *widget = *it;
if (widget->view().layoutMessages()) {
widget->repaint();
}
}
}
void
MainWindow::repaintVisibleChatWidgets()
{
auto *page = notebook.selected();
if (page == NULL) {
return;
}
const std::vector<ChatWidget *> &widgets = page->chatWidgets();
for (auto it = widgets.begin(); it != widgets.end(); ++it) {
ChatWidget *widget = *it;
widget->view().layoutMessages();
widget->repaint();
}
}

View file

@ -12,6 +12,9 @@ public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Notebook notebook;
void layoutVisibleChatWidgets();
void repaintVisibleChatWidgets();
};
#endif // MAINWINDOW_H

View file

@ -12,19 +12,19 @@
Notebook::Notebook(QWidget *parent)
: QWidget(parent)
, addButton(this)
, settingsButton(this)
, userButton(this)
, m_addButton(this)
, m_settingsButton(this)
, m_userButton(this)
{
connect(&settingsButton, SIGNAL(clicked()), this,
connect(&m_settingsButton, SIGNAL(clicked()), this,
SLOT(settingsButtonClicked()));
settingsButton.resize(24, 24);
settingsButton.icon = NotebookButton::IconSettings;
userButton.resize(24, 24);
userButton.move(24, 0);
userButton.icon = NotebookButton::IconUser;
addButton.resize(24, 24);
m_settingsButton.resize(24, 24);
m_settingsButton.icon = NotebookButton::IconSettings;
m_userButton.resize(24, 24);
m_userButton.move(24, 0);
m_userButton.icon = NotebookButton::IconUser;
m_addButton.resize(24, 24);
}
void
@ -41,11 +41,11 @@ Notebook::addPage()
auto tab = new NotebookTab(this);
auto page = new NotebookPage(this, tab);
if (pages.count() == 0) {
if (m_pages.count() == 0) {
select(page);
}
this->pages.append(page);
this->m_pages.append(page);
return page;
}
@ -53,7 +53,7 @@ Notebook::addPage()
void
Notebook::select(NotebookPage *page)
{
if (page == selected)
if (page == m_selected)
return;
if (page != nullptr) {
@ -61,12 +61,12 @@ Notebook::select(NotebookPage *page)
page->tab->setSelected(true);
}
if (selected != nullptr) {
selected->setHidden(true);
selected->tab->setSelected(false);
if (m_selected != nullptr) {
m_selected->setHidden(true);
m_selected->tab->setSelected(false);
}
selected = page;
m_selected = page;
performLayout();
}
@ -78,11 +78,11 @@ Notebook::performLayout()
int tabHeight = 16;
bool first = true;
for (auto &i : pages) {
for (auto &i : m_pages) {
tabHeight = i->tab->height();
if (!first &&
(i == pages.last() ? tabHeight : 0) + x + i->tab->width() >
(i == m_pages.last() ? tabHeight : 0) + x + i->tab->width() >
width()) {
y += i->tab->height();
i->tab->move(0, y);
@ -95,11 +95,11 @@ Notebook::performLayout()
first = false;
}
this->addButton.move(x, y);
this->m_addButton.move(x, y);
if (selected != nullptr) {
selected->move(0, y + tabHeight);
selected->resize(width(), height() - y - tabHeight);
if (m_selected != nullptr) {
m_selected->move(0, y + tabHeight);
m_selected->resize(width(), height() - y - tabHeight);
}
}

View file

@ -19,6 +19,13 @@ public:
enum HighlightType { none, highlighted, newMessage };
void select(NotebookPage *page);
NotebookPage *
selected()
{
return m_selected;
}
void performLayout();
protected:
@ -30,13 +37,13 @@ public slots:
void settingsButtonClicked();
private:
QList<NotebookPage *> pages;
QList<NotebookPage *> m_pages;
NotebookButton addButton;
NotebookButton settingsButton;
NotebookButton userButton;
NotebookButton m_addButton;
NotebookButton m_settingsButton;
NotebookButton m_userButton;
NotebookPage *selected = nullptr;
NotebookPage *m_selected = nullptr;
};
#endif // NOTEBOOK_H

View file

@ -14,8 +14,9 @@ std::pair<int, int> NotebookPage::dropPosition = std::pair<int, int>(-1, -1);
NotebookPage::NotebookPage(QWidget *parent, NotebookTab *tab)
: QWidget(parent)
, parentbox(this)
, preview(this)
, m_parentbox(this)
, m_preview(this)
, m_chatWidgets()
{
this->tab = tab;
tab->page = this;
@ -23,19 +24,27 @@ NotebookPage::NotebookPage(QWidget *parent, NotebookTab *tab)
setHidden(true);
setAcceptDrops(true);
parentbox.addSpacing(2);
parentbox.addLayout(&hbox);
parentbox.setMargin(0);
m_parentbox.addSpacing(2);
m_parentbox.addLayout(&m_hbox);
m_parentbox.setMargin(0);
hbox.setSpacing(1);
hbox.setMargin(0);
m_hbox.setSpacing(1);
m_hbox.setMargin(0);
}
std::pair<int, int>
NotebookPage::removeFromLayout(ChatWidget *widget)
{
for (int i = 0; i < hbox.count(); ++i) {
auto vbox = static_cast<QVBoxLayout *>(hbox.itemAt(i));
for (auto it = m_chatWidgets.begin(); it != m_chatWidgets.end(); ++it) {
if (*it == widget) {
m_chatWidgets.erase(it);
break;
}
}
for (int i = 0; i < m_hbox.count(); ++i) {
auto vbox = static_cast<QVBoxLayout *>(m_hbox.itemAt(i));
for (int j = 0; j < vbox->count(); ++j) {
if (vbox->itemAt(j)->widget() != widget)
@ -46,13 +55,12 @@ NotebookPage::removeFromLayout(ChatWidget *widget)
bool isLastItem = vbox->count() == 0;
if (isLastItem) {
hbox.removeItem(vbox);
m_hbox.removeItem(vbox);
delete vbox;
}
return std::pair<int, int>(i, isLastItem ? -1 : j);
;
}
}
@ -64,12 +72,14 @@ NotebookPage::addToLayout(
ChatWidget *widget,
std::pair<int, int> position = std::pair<int, int>(-1, -1))
{
m_chatWidgets.push_back(widget);
// add vbox at the end
if (position.first < 0 || position.first >= hbox.count()) {
if (position.first < 0 || position.first >= m_hbox.count()) {
auto vbox = new QVBoxLayout();
vbox->addWidget(widget);
hbox.addLayout(vbox);
m_hbox.addLayout(vbox);
return;
}
@ -78,12 +88,12 @@ NotebookPage::addToLayout(
auto vbox = new QVBoxLayout();
vbox->addWidget(widget);
hbox.insertLayout(position.first, vbox);
m_hbox.insertLayout(position.first, vbox);
return;
}
// add to existing vbox
auto vbox = static_cast<QVBoxLayout *>(hbox.itemAt(position.first));
auto vbox = static_cast<QVBoxLayout *>(m_hbox.itemAt(position.first));
vbox->insertWidget(std::max(0, std::min(vbox->count(), position.second)),
widget);
@ -92,7 +102,7 @@ NotebookPage::addToLayout(
void
NotebookPage::enterEvent(QEvent *)
{
if (hbox.count() == 0) {
if (m_hbox.count() == 0) {
setCursor(QCursor(Qt::PointingHandCursor));
} else {
setCursor(QCursor(Qt::ArrowCursor));
@ -107,8 +117,9 @@ NotebookPage::leaveEvent(QEvent *)
void
NotebookPage::mouseReleaseEvent(QMouseEvent *event)
{
if (hbox.count() == 0 && event->button() == Qt::LeftButton) {
if (m_hbox.count() == 0 && event->button() == Qt::LeftButton) {
addToLayout(new ChatWidget(), std::pair<int, int>(-1, -1));
setCursor(QCursor(Qt::ArrowCursor));
}
}
@ -120,27 +131,28 @@ NotebookPage::dragEnterEvent(QDragEnterEvent *event)
return;
if (isDraggingSplit) {
dropRegions.clear();
m_dropRegions.clear();
if (hbox.count() == 0) {
dropRegions.push_back(
if (m_hbox.count() == 0) {
m_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, height()),
std::pair<int, int>(i, -1)));
for (int i = 0; i < m_hbox.count() + 1; ++i) {
m_dropRegions.push_back(DropRegion(
QRect(((i * 4 - 1) * width() / m_hbox.count()) / 4, 0,
width() / m_hbox.count() / 2, height()),
std::pair<int, int>(i, -1)));
}
for (int i = 0; i < hbox.count(); ++i) {
auto vbox = static_cast<QVBoxLayout *>(hbox.itemAt(i));
for (int i = 0; i < m_hbox.count(); ++i) {
auto vbox = static_cast<QVBoxLayout *>(m_hbox.itemAt(i));
for (int j = 0; j < vbox->count() + 1; ++j) {
dropRegions.push_back(DropRegion(
QRect(i * width() / hbox.count(),
m_dropRegions.push_back(DropRegion(
QRect(i * width() / m_hbox.count(),
((j * 2 - 1) * height() / vbox->count()) / 2,
width() / hbox.count(), height() / vbox->count()),
width() / m_hbox.count(),
height() / vbox->count()),
std::pair<int, int>(i, j)));
}
}
@ -161,18 +173,18 @@ NotebookPage::dragMoveEvent(QDragMoveEvent *event)
void
NotebookPage::setPreviewRect(QPoint mousePos)
{
for (DropRegion region : dropRegions) {
for (DropRegion region : m_dropRegions) {
if (region.rect.contains(mousePos)) {
preview.move(region.rect.x(), region.rect.y());
preview.resize(region.rect.width(), region.rect.height());
preview.show();
preview.raise();
m_preview.move(region.rect.x(), region.rect.y());
m_preview.resize(region.rect.width(), region.rect.height());
m_preview.show();
m_preview.raise();
dropPosition = region.position;
return;
} else {
preview.hide();
m_preview.hide();
}
}
}
@ -180,7 +192,7 @@ NotebookPage::setPreviewRect(QPoint mousePos)
void
NotebookPage::dragLeaveEvent(QDragLeaveEvent *event)
{
preview.hide();
m_preview.hide();
}
void
@ -194,7 +206,7 @@ NotebookPage::dropEvent(QDropEvent *event)
addToLayout(NotebookPage::draggingSplit, dropPosition);
}
preview.hide();
m_preview.hide();
}
void
@ -202,7 +214,7 @@ NotebookPage::paintEvent(QPaintEvent *)
{
QPainter painter(this);
if (hbox.count() == 0) {
if (m_hbox.count() == 0) {
painter.fillRect(rect(), ColorScheme::instance().ChatBackground);
painter.fillRect(0, 0, width(), 2,

View file

@ -19,12 +19,16 @@ class NotebookPage : public QWidget
public:
NotebookPage(QWidget *parent, NotebookTab *tab);
NotebookTab *tab;
QVBoxLayout parentbox;
QHBoxLayout hbox;
std::pair<int, int> removeFromLayout(ChatWidget *widget);
void addToLayout(ChatWidget *widget, std::pair<int, int> position);
const std::vector<ChatWidget *> &
chatWidgets() const
{
return m_chatWidgets;
}
static bool isDraggingSplit;
static ChatWidget *draggingSplit;
static std::pair<int, int> dropPosition;
@ -52,9 +56,13 @@ protected:
}
};
std::vector<DropRegion> dropRegions;
QVBoxLayout m_parentbox;
QHBoxLayout m_hbox;
NotebookPageDropPreview preview;
std::vector<ChatWidget *> m_chatWidgets;
std::vector<DropRegion> m_dropRegions;
NotebookPageDropPreview m_preview;
private:
void setPreviewRect(QPoint mousePos);

View file

@ -5,6 +5,13 @@ QMutex Windows::m_windowMutex;
MainWindow *Windows::m_mainWindow(NULL);
void
Windows::invalidateEmotes()
Windows::layoutVisibleChatWidgets()
{
m_mainWindow->layoutVisibleChatWidgets();
}
void
Windows::repaintVisibleChatWidgets()
{
m_mainWindow->repaintVisibleChatWidgets();
}

View file

@ -8,7 +8,8 @@
class Windows
{
public:
static void invalidateEmotes();
static void layoutVisibleChatWidgets();
static void repaintVisibleChatWidgets();
static MainWindow &
mainWindow()