This commit is contained in:
hemirt 2024-10-17 20:45:39 +02:00 committed by GitHub
commit 96f9b845d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 238 additions and 14 deletions

View file

@ -204,7 +204,7 @@ void Notebook::duplicatePage(QWidget *page)
{ {
newTabPosition = tabPosition + 1; newTabPosition = tabPosition + 1;
} }
auto newTabHighlightState = item->tab->highlightState();
QString newTabTitle = ""; QString newTabTitle = "";
if (item->tab->hasCustomTitle()) if (item->tab->hasCustomTitle())
{ {
@ -213,7 +213,7 @@ void Notebook::duplicatePage(QWidget *page)
auto *tab = auto *tab =
this->addPageAt(newContainer, newTabPosition, newTabTitle, false); this->addPageAt(newContainer, newTabPosition, newTabTitle, false);
tab->setHighlightState(newTabHighlightState); tab->copyHighlightStateAndSourcesFrom(item->tab);
newContainer->setTab(tab); newContainer->setTab(tab);
} }

View file

@ -2,6 +2,7 @@
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include <ForwardDecl.hpp>
#include <pajlada/signals/signal.hpp> #include <pajlada/signals/signal.hpp>
#include <pajlada/signals/signalholder.hpp> #include <pajlada/signals/signalholder.hpp>
#include <QList> #include <QList>

View file

@ -1190,11 +1190,13 @@ void ChannelView::messageAppended(MessagePtr &message,
(this->channel_->getType() == Channel::Type::TwitchAutomod && (this->channel_->getType() == Channel::Type::TwitchAutomod &&
getSettings()->enableAutomodHighlight)) getSettings()->enableAutomodHighlight))
{ {
this->tabHighlightRequested.invoke(HighlightState::Highlighted); this->tabHighlightRequested.invoke(HighlightState::Highlighted,
message);
} }
else else
{ {
this->tabHighlightRequested.invoke(HighlightState::NewMessage); this->tabHighlightRequested.invoke(HighlightState::NewMessage,
message);
} }
} }

View file

@ -179,6 +179,9 @@ public:
LimitedQueueSnapshot<MessageLayoutPtr> &getMessagesSnapshot(); LimitedQueueSnapshot<MessageLayoutPtr> &getMessagesSnapshot();
// Returns true if message should be included
bool shouldIncludeMessage(const MessagePtr &m) const;
void queueLayout(); void queueLayout();
void invalidateBuffers(); void invalidateBuffers();
@ -214,7 +217,8 @@ public:
pajlada::Signals::Signal<QMouseEvent *> mouseDown; pajlada::Signals::Signal<QMouseEvent *> mouseDown;
pajlada::Signals::NoArgSignal selectionChanged; pajlada::Signals::NoArgSignal selectionChanged;
pajlada::Signals::Signal<HighlightState> tabHighlightRequested; pajlada::Signals::Signal<HighlightState, const MessagePtr &>
tabHighlightRequested;
pajlada::Signals::NoArgSignal liveStatusChanged; pajlada::Signals::NoArgSignal liveStatusChanged;
pajlada::Signals::Signal<const Link &> linkClicked; pajlada::Signals::Signal<const Link &> linkClicked;
pajlada::Signals::Signal<QString, FromTwitchLinkOpenChannelIn> pajlada::Signals::Signal<QString, FromTwitchLinkOpenChannelIn>
@ -374,9 +378,6 @@ private:
FilterSetPtr channelFilters_; FilterSetPtr channelFilters_;
// Returns true if message should be included
bool shouldIncludeMessage(const MessagePtr &m) const;
// Returns whether the scrollbar should have highlights // Returns whether the scrollbar should have highlights
bool showScrollbarHighlights() const; bool showScrollbarHighlights() const;

View file

@ -10,8 +10,10 @@
#include "singletons/WindowManager.hpp" #include "singletons/WindowManager.hpp"
#include "util/Helpers.hpp" #include "util/Helpers.hpp"
#include "widgets/dialogs/SettingsDialog.hpp" #include "widgets/dialogs/SettingsDialog.hpp"
#include "widgets/helper/ChannelView.hpp"
#include "widgets/Notebook.hpp" #include "widgets/Notebook.hpp"
#include "widgets/splits/DraggedSplit.hpp" #include "widgets/splits/DraggedSplit.hpp"
#include "widgets/splits/Split.hpp"
#include "widgets/splits/SplitContainer.hpp" #include "widgets/splits/SplitContainer.hpp"
#include <boost/bind/bind.hpp> #include <boost/bind/bind.hpp>
@ -302,10 +304,98 @@ bool NotebookTab::isSelected() const
return this->selected_; return this->selected_;
} }
void NotebookTab::removeHighlightSources(const HighlightSources &toRemove)
{
for (const auto &source : toRemove.newMessageSource)
{
this->highlightSources_.newMessageSource.erase(source);
}
for (const auto &source : toRemove.highlightedSource)
{
this->highlightSources_.highlightedSource.erase(source);
}
if (!this->highlightSources_.highlightedSource.empty())
{
assert(this->highlightState_ == HighlightState::Highlighted);
return;
}
if (!this->highlightSources_.newMessageSource.empty())
{
if (this->highlightState_ != HighlightState::NewMessage)
{
this->highlightState_ = HighlightState::NewMessage;
this->update();
}
}
else
{
if (this->highlightState_ != HighlightState::None)
{
this->highlightState_ = HighlightState::None;
this->update();
}
}
assert(this->highlightState_ != HighlightState::Highlighted);
}
void NotebookTab::copyHighlightStateAndSourcesFrom(const NotebookTab *sourceTab)
{
if (this->isSelected())
{
assert(this->highlightSources_.highlightedSource.empty());
assert(this->highlightSources_.newMessageSource.empty());
assert(this->highlightState_ == HighlightState::None);
return;
}
this->highlightSources_ = sourceTab->highlightSources_;
if (!this->highlightEnabled_ &&
sourceTab->highlightState_ == HighlightState::NewMessage)
{
return;
}
if (this->highlightState_ == sourceTab->highlightState_ ||
this->highlightState_ == HighlightState::Highlighted)
{
return;
}
this->highlightState_ = sourceTab->highlightState_;
this->update();
}
void NotebookTab::setSelected(bool value) void NotebookTab::setSelected(bool value)
{ {
this->selected_ = value; this->selected_ = value;
if (value)
{
auto *splitNotebook = dynamic_cast<SplitNotebook *>(this->notebook_);
if (splitNotebook)
{
for (int i = 0; i < splitNotebook->getPageCount(); ++i)
{
auto *splitContainer =
dynamic_cast<SplitContainer *>(splitNotebook->getPageAt(i));
if (splitContainer)
{
auto *tab = splitContainer->getTab();
if (tab && tab != this)
{
tab->removeHighlightSources(this->highlightSources_);
}
}
}
}
}
this->highlightSources_.clear();
this->highlightState_ = HighlightState::None; this->highlightState_ = HighlightState::None;
this->update(); this->update();
@ -358,13 +448,82 @@ bool NotebookTab::isLive() const
return this->isLive_; return this->isLive_;
} }
HighlightState NotebookTab::highlightState() const
{
return this->highlightState_;
}
void NotebookTab::setHighlightState(HighlightState newHighlightStyle) void NotebookTab::setHighlightState(HighlightState newHighlightStyle)
{ {
if (this->isSelected()) if (this->isSelected())
{ {
assert(this->highlightSources_.highlightedSource.empty());
assert(this->highlightSources_.newMessageSource.empty());
assert(this->highlightState_ == HighlightState::None);
return; return;
} }
this->highlightSources_.clear();
if (!this->highlightEnabled_ &&
newHighlightStyle == HighlightState::NewMessage)
{
return;
}
if (this->highlightState_ == newHighlightStyle ||
this->highlightState_ == HighlightState::Highlighted)
{
return;
}
this->highlightState_ = newHighlightStyle;
this->update();
}
void NotebookTab::updateHighlightState(HighlightState newHighlightStyle,
const ChannelView &channelViewSource,
const MessagePtr &message)
{
if (this->isSelected())
{
assert(this->highlightSources_.highlightedSource.empty());
assert(this->highlightSources_.newMessageSource.empty());
assert(this->highlightState_ == HighlightState::None);
return;
}
if (!this->shouldMessageHighlight(channelViewSource, message))
{
return;
}
auto underlyingChannel = channelViewSource.underlyingChannel();
switch (newHighlightStyle)
{
case HighlightState::Highlighted: {
if (!this->highlightSources_.highlightedSource.contains(
underlyingChannel))
{
this->highlightSources_.highlightedSource.insert(
underlyingChannel);
}
break;
}
case HighlightState::NewMessage: {
if (!this->highlightSources_.newMessageSource.contains(
underlyingChannel))
{
this->highlightSources_.newMessageSource.insert(
underlyingChannel);
}
break;
}
case HighlightState::None:
break;
}
if (!this->highlightEnabled_ && if (!this->highlightEnabled_ &&
newHighlightStyle == HighlightState::NewMessage) newHighlightStyle == HighlightState::NewMessage)
{ {
@ -381,9 +540,37 @@ void NotebookTab::setHighlightState(HighlightState newHighlightStyle)
this->update(); this->update();
} }
HighlightState NotebookTab::highlightState() const bool NotebookTab::shouldMessageHighlight(const ChannelView &channelViewSource,
const MessagePtr &message) const
{ {
return this->highlightState_; auto *visibleSplitContainer =
dynamic_cast<SplitContainer *>(this->notebook_->getSelectedPage());
if (visibleSplitContainer != nullptr)
{
const auto &visibleSplits = visibleSplitContainer->getSplits();
for (const auto &visibleSplit : visibleSplits)
{
auto filterIdsSource = channelViewSource.getFilterIds();
auto filterIdsSplit = visibleSplit->getChannelView().getFilterIds();
auto isSubset = []<typename T>(const QList<T> &sub,
const QList<T> &super) {
return std::ranges::all_of(sub, [&super](const auto &subItem) {
return super.contains(subItem);
});
};
if (channelViewSource.underlyingChannel() ==
visibleSplit->getChannel() &&
visibleSplit->getChannelView().shouldIncludeMessage(message) &&
isSubset(filterIdsSource, filterIdsSplit))
{
return false;
}
}
}
return true;
} }
void NotebookTab::setHighlightsEnabled(const bool &newVal) void NotebookTab::setHighlightsEnabled(const bool &newVal)

View file

@ -14,6 +14,7 @@ namespace chatterino {
inline constexpr int NOTEBOOK_TAB_HEIGHT = 28; inline constexpr int NOTEBOOK_TAB_HEIGHT = 28;
class SplitContainer; class SplitContainer;
class ChannelView;
class NotebookTab : public Button class NotebookTab : public Button
{ {
@ -59,11 +60,24 @@ public:
**/ **/
bool isLive() const; bool isLive() const;
/**
* @brief Sets the highlight state of this tab clearing highlight sources
*
* Obeys the HighlightsEnabled setting and highlight states hierarchy
*/
void setHighlightState(HighlightState style); void setHighlightState(HighlightState style);
HighlightState highlightState() const; /**
* @brief Updates the highlight state and highlight sources of this tab
*
* Obeys the HighlightsEnabled setting and the highlight state hierarchy and tracks the highlight state update sources
*/
void updateHighlightState(HighlightState style,
const ChannelView &channelViewSource,
const MessagePtr &message);
void copyHighlightStateAndSourcesFrom(const NotebookTab *sourceTab);
void setHighlightsEnabled(const bool &newVal); void setHighlightsEnabled(const bool &newVal);
bool hasHighlightsEnabled() const; bool hasHighlightsEnabled() const;
HighlightState highlightState() const;
void moveAnimated(QPoint targetPos, bool animated = true); void moveAnimated(QPoint targetPos, bool animated = true);
@ -107,6 +121,23 @@ private:
int normalTabWidthForHeight(int height) const; int normalTabWidthForHeight(int height) const;
bool shouldMessageHighlight(const ChannelView &channelViewSource,
const MessagePtr &message) const;
struct HighlightSources {
std::unordered_set<ChannelPtr> newMessageSource;
std::unordered_set<ChannelPtr> highlightedSource;
void clear()
{
this->newMessageSource.clear();
this->highlightedSource.clear();
}
} highlightSources_;
void removeHighlightSources(const HighlightSources &toRemove);
QPropertyAnimation positionChangedAnimation_; QPropertyAnimation positionChangedAnimation_;
QPoint positionAnimationDesiredPoint_; QPoint positionAnimationDesiredPoint_;

View file

@ -214,10 +214,12 @@ void SplitContainer::addSplit(Split *split)
auto &&conns = this->connectionsPerSplit_[split]; auto &&conns = this->connectionsPerSplit_[split];
conns.managedConnect(split->getChannelView().tabHighlightRequested, conns.managedConnect(split->getChannelView().tabHighlightRequested,
[this](HighlightState state) { [this, &channelView = split->getChannelView()](
HighlightState state, const MessagePtr &message) {
if (this->tab_ != nullptr) if (this->tab_ != nullptr)
{ {
this->tab_->setHighlightState(state); this->tab_->updateHighlightState(
state, channelView, message);
} }
}); });