Improve look of tabs when using a layout other than top (#3925)

This commit is contained in:
Daniel Sage 2022-11-08 16:46:43 -05:00 committed by GitHub
parent 7714237531
commit 1741ac7482
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 151 additions and 35 deletions

View file

@ -76,6 +76,7 @@
- Minor: Migrated /chatters to Helix API. (#4088, #4097, #4114) - Minor: Migrated /chatters to Helix API. (#4088, #4097, #4114)
- Minor: Migrated /mods to Helix API. (#4103) - Minor: Migrated /mods to Helix API. (#4103)
- Minor: Add settings tooltips. (#3437) - Minor: Add settings tooltips. (#3437)
- Minor: Improved look of tabs when using a layout other than top. (#3925)
- Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716) - Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716)
- Bugfix: Fixed `Smooth scrolling on new messages` setting sometimes hiding messages. (#4028) - Bugfix: Fixed `Smooth scrolling on new messages` setting sometimes hiding messages. (#4028)
- Bugfix: Fixed a crash that can occur when closing and quickly reopening a split, then running a command. (#3852) - Bugfix: Fixed a crash that can occur when closing and quickly reopening a split, then running a command. (#3852)

View file

@ -73,6 +73,7 @@ NotebookTab *Notebook::addPage(QWidget *page, QString title, bool select)
tab->page = page; tab->page = page;
tab->setCustomTitle(title); tab->setCustomTitle(title);
tab->setTabLocation(this->tabLocation_);
Item item; Item item;
item.page = page; item.page = page;
@ -493,6 +494,7 @@ void Notebook::performLayout(bool animated)
const auto minimumTabAreaSpace = int(tabHeight * 0.5); const auto minimumTabAreaSpace = int(tabHeight * 0.5);
const auto addButtonWidth = this->showAddButton_ ? tabHeight : 0; const auto addButtonWidth = this->showAddButton_ ? tabHeight : 0;
const auto lineThickness = int(2 * scale); const auto lineThickness = int(2 * scale);
const auto tabSpacer = std::max<int>(1, int(scale * 1));
const auto buttonWidth = tabHeight; const auto buttonWidth = tabHeight;
const auto buttonHeight = tabHeight - 1; const auto buttonHeight = tabHeight - 1;
@ -544,7 +546,7 @@ void Notebook::performLayout(bool animated)
/// Layout tab /// Layout tab
item.tab->growWidth(0); item.tab->growWidth(0);
item.tab->moveAnimated(QPoint(x, y), animated); item.tab->moveAnimated(QPoint(x, y), animated);
x += item.tab->width() + std::max<int>(1, int(scale * 1)); x += item.tab->width() + tabSpacer;
} }
/// Update which tabs are in the last row /// Update which tabs are in the last row
@ -605,10 +607,12 @@ void Notebook::performLayout(bool animated)
} }
if (this->visibleButtonCount() > 0) if (this->visibleButtonCount() > 0)
y = tabHeight; y = tabHeight + lineThickness; // account for divider line
int totalButtonWidths = x; int totalButtonWidths = x;
int top = y; const int top = y + tabSpacer; // add margin
y = top;
x = left; x = left;
// zneix: if we were to remove buttons when tabs are hidden // zneix: if we were to remove buttons when tabs are hidden
@ -654,7 +658,8 @@ void Notebook::performLayout(bool animated)
/// Layout tab /// Layout tab
item.tab->growWidth(largestWidth); item.tab->growWidth(largestWidth);
item.tab->moveAnimated(QPoint(x, y), animated); item.tab->moveAnimated(QPoint(x, y), animated);
y += tabHeight; item.tab->setInLastRow(isLastColumn);
y += tabHeight + tabSpacer;
} }
if (isLastColumn && this->showAddButton_) if (isLastColumn && this->showAddButton_)
@ -704,10 +709,12 @@ void Notebook::performLayout(bool animated)
} }
if (this->visibleButtonCount() > 0) if (this->visibleButtonCount() > 0)
y = tabHeight; y = tabHeight + lineThickness; // account for divider line
int consumedButtonWidths = right - x; int consumedButtonWidths = right - x;
int top = y; const int top = y + tabSpacer; // add margin
y = top;
x = right; x = right;
// zneix: if we were to remove buttons when tabs are hidden // zneix: if we were to remove buttons when tabs are hidden
@ -758,7 +765,8 @@ void Notebook::performLayout(bool animated)
/// Layout tab /// Layout tab
item.tab->growWidth(largestWidth); item.tab->growWidth(largestWidth);
item.tab->moveAnimated(QPoint(x, y), animated); item.tab->moveAnimated(QPoint(x, y), animated);
y += tabHeight; item.tab->setInLastRow(isLastColumn);
y += tabHeight + tabSpacer;
} }
if (isLastColumn && this->showAddButton_) if (isLastColumn && this->showAddButton_)
@ -817,7 +825,7 @@ void Notebook::performLayout(bool animated)
if (this->showTabs_) if (this->showTabs_)
{ {
// reset vertical position regardless // reset vertical position regardless
y = bottom - tabHeight; y = bottom - tabHeight - tabSpacer;
// layout tabs // layout tabs
/// Notebook tabs need to know if they are in the last row. /// Notebook tabs need to know if they are in the last row.
@ -843,7 +851,7 @@ void Notebook::performLayout(bool animated)
/// Layout tab /// Layout tab
item.tab->growWidth(0); item.tab->growWidth(0);
item.tab->moveAnimated(QPoint(x, y), animated); item.tab->moveAnimated(QPoint(x, y), animated);
x += item.tab->width() + std::max<int>(1, int(scale * 1)); x += item.tab->width() + tabSpacer;
} }
/// Update which tabs are in the last row /// Update which tabs are in the last row
@ -866,7 +874,7 @@ void Notebook::performLayout(bool animated)
int consumedBottomSpace = int consumedBottomSpace =
std::max({bottom - y, consumedButtonHeights, minimumTabAreaSpace}); std::max({bottom - y, consumedButtonHeights, minimumTabAreaSpace});
int tabsStart = bottom - consumedBottomSpace; int tabsStart = bottom - consumedBottomSpace - lineThickness;
if (this->lineOffset_ != tabsStart) if (this->lineOffset_ != tabsStart)
{ {
@ -917,6 +925,13 @@ void Notebook::setTabLocation(NotebookTabLocation location)
if (location != this->tabLocation_) if (location != this->tabLocation_)
{ {
this->tabLocation_ = location; this->tabLocation_ = location;
// Update all tabs
for (const auto &item : this->items_)
{
item.tab->setTabLocation(location);
}
this->performLayout(); this->performLayout();
} }
} }

View file

@ -34,6 +34,29 @@ namespace {
return 1.0; return 1.0;
#endif #endif
} }
// Translates the given rectangle by an amount in the direction to appear like the tab is selected.
// For example, if location is Top, the rectangle will be translated in the negative Y direction,
// or "up" on the screen, by amount.
void translateRectForLocation(QRect &rect, NotebookTabLocation location,
int amount)
{
switch (location)
{
case NotebookTabLocation::Top:
rect.translate(0, -amount);
break;
case NotebookTabLocation::Left:
rect.translate(-amount, 0);
break;
case NotebookTabLocation::Right:
rect.translate(amount, 0);
break;
case NotebookTabLocation::Bottom:
rect.translate(0, amount);
break;
}
}
} // namespace } // namespace
NotebookTab::NotebookTab(Notebook *notebook) NotebookTab::NotebookTab(Notebook *notebook)
@ -294,6 +317,15 @@ void NotebookTab::setInLastRow(bool value)
} }
} }
void NotebookTab::setTabLocation(NotebookTabLocation location)
{
if (this->tabLocation_ != location)
{
this->tabLocation_ = location;
this->update();
}
}
void NotebookTab::setLive(bool isLive) void NotebookTab::setLive(bool isLive)
{ {
if (this->isLive_ != isLive) if (this->isLive_ != isLive)
@ -401,19 +433,56 @@ void NotebookTab::paintEvent(QPaintEvent *)
(windowFocused ? colors.backgrounds.regular (windowFocused ? colors.backgrounds.regular
: colors.backgrounds.unfocused); : colors.backgrounds.unfocused);
auto selectionOffset = ceil((this->selected_ ? 0.f : 1.f) * scale);
// fill the tab background // fill the tab background
auto bgRect = this->rect(); auto bgRect = this->rect();
bgRect.setTop(ceil((this->selected_ ? 0.f : 1.f) * scale)); switch (this->tabLocation_)
{
case NotebookTabLocation::Top:
bgRect.setTop(selectionOffset);
break;
case NotebookTabLocation::Left:
bgRect.setLeft(selectionOffset);
break;
case NotebookTabLocation::Right:
bgRect.setRight(bgRect.width() - selectionOffset);
break;
case NotebookTabLocation::Bottom:
bgRect.setBottom(bgRect.height() - selectionOffset);
break;
}
painter.fillRect(bgRect, tabBackground); painter.fillRect(bgRect, tabBackground);
// top line // draw color indicator line
painter.fillRect( auto lineThickness = ceil((this->selected_ ? 2.f : 1.f) * scale);
QRectF(0, ceil((this->selected_ ? 0.f : 1.f) * scale), this->width(), auto lineColor = this->mouseOver_ ? colors.line.hover
ceil((this->selected_ ? 2.f : 1.f) * scale)), : (windowFocused ? colors.line.regular
this->mouseOver_ : colors.line.unfocused);
? colors.line.hover
: (windowFocused ? colors.line.regular : colors.line.unfocused)); QRect lineRect;
switch (this->tabLocation_)
{
case NotebookTabLocation::Top:
lineRect =
QRect(bgRect.left(), bgRect.y(), bgRect.width(), lineThickness);
break;
case NotebookTabLocation::Left:
lineRect =
QRect(bgRect.x(), bgRect.top(), lineThickness, bgRect.height());
break;
case NotebookTabLocation::Right:
lineRect = QRect(bgRect.right() - lineThickness, bgRect.top(),
lineThickness, bgRect.height());
break;
case NotebookTabLocation::Bottom:
lineRect = QRect(bgRect.left(), bgRect.bottom() - lineThickness,
bgRect.width(), lineThickness);
break;
}
painter.fillRect(lineRect, lineColor);
// draw live indicator // draw live indicator
if (this->isLive_ && getSettings()->showTabLive) if (this->isLive_ && getSettings()->showTabLive)
@ -426,9 +495,12 @@ void NotebookTab::paintEvent(QPaintEvent *)
painter.setBrush(b); painter.setBrush(b);
auto x = this->width() - (7 * scale); auto x = this->width() - (7 * scale);
auto y = 4 * scale + (this->isSelected() ? 0 : 1); auto y = 4 * scale;
auto diameter = 4 * scale; auto diameter = 4 * scale;
painter.drawEllipse(QRectF(x, y, diameter, diameter)); QRect liveIndicatorRect(x, y, diameter, diameter);
translateRectForLocation(liveIndicatorRect, this->tabLocation_,
this->selected_ ? 0 : -1);
painter.drawEllipse(liveIndicatorRect);
} }
// set the pen color // set the pen color
@ -440,8 +512,9 @@ void NotebookTab::paintEvent(QPaintEvent *)
// draw text // draw text
int offset = int(scale * 8); int offset = int(scale * 8);
QRect textRect(offset, this->selected_ ? 1 : 2, QRect textRect(offset, 0, this->width() - offset - offset, height);
this->width() - offset - offset, height); translateRectForLocation(textRect, this->tabLocation_,
this->selected_ ? -1 : -2);
if (this->shouldDrawXButton()) if (this->shouldDrawXButton())
{ {
@ -465,9 +538,6 @@ void NotebookTab::paintEvent(QPaintEvent *)
QRect xRect = this->getXRect(); QRect xRect = this->getXRect();
if (!xRect.isNull()) if (!xRect.isNull())
{ {
if (this->selected_)
xRect.moveTop(xRect.top() - 1);
painter.setBrush(QColor("#fff")); painter.setBrush(QColor("#fff"));
if (this->mouseOverX_) if (this->mouseOverX_)
@ -495,11 +565,26 @@ void NotebookTab::paintEvent(QPaintEvent *)
this->fancyPaint(painter); this->fancyPaint(painter);
} }
// draw line at bottom // draw line at border
if (!this->selected_ && this->isInLastRow_) if (!this->selected_ && this->isInLastRow_)
{ {
painter.fillRect(0, this->height() - 1, this->width(), 1, QRect borderRect;
app->themes->window.background); switch (this->tabLocation_)
{
case NotebookTabLocation::Top:
borderRect = QRect(0, this->height() - 1, this->width(), 1);
break;
case NotebookTabLocation::Left:
borderRect = QRect(this->width() - 1, 0, 1, this->height());
break;
case NotebookTabLocation::Right:
borderRect = QRect(0, 0, 1, this->height());
break;
case NotebookTabLocation::Bottom:
borderRect = QRect(0, 0, this->width(), 1);
break;
}
painter.fillRect(borderRect, app->themes->window.background);
} }
} }
@ -683,14 +768,26 @@ void NotebookTab::wheelEvent(QWheelEvent *event)
QRect NotebookTab::getXRect() QRect NotebookTab::getXRect()
{ {
// if (!this->notebook->getAllowUserTabManagement()) { QRect rect = this->rect();
// return QRect();
// }
float s = this->scale(); float s = this->scale();
return QRect(this->width() - static_cast<int>(20 * s), int size = static_cast<int>(16 * s);
static_cast<int>(9 * s), static_cast<int>(16 * s),
static_cast<int>(16 * s)); int centerAdjustment =
this->tabLocation_ ==
(NotebookTabLocation::Top ||
this->tabLocation_ == NotebookTabLocation::Bottom)
? (size / 3) // slightly off true center
: (size / 2); // true center
QRect xRect(rect.right() - static_cast<int>(20 * s),
rect.center().y() - centerAdjustment, size, size);
if (this->selected_)
{
translateRectForLocation(xRect, this->tabLocation_, 1);
}
return xRect;
} }
} // namespace chatterino } // namespace chatterino

View file

@ -2,6 +2,7 @@
#include "common/Common.hpp" #include "common/Common.hpp"
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include "widgets/Notebook.hpp"
#include "widgets/helper/Button.hpp" #include "widgets/helper/Button.hpp"
#include <QMenu> #include <QMenu>
@ -40,6 +41,7 @@ public:
void setSelected(bool value); void setSelected(bool value);
void setInLastRow(bool value); void setInLastRow(bool value);
void setTabLocation(NotebookTabLocation location);
void setLive(bool isLive); void setLive(bool isLive);
void setHighlightState(HighlightState style); void setHighlightState(HighlightState style);
@ -94,6 +96,7 @@ private:
bool mouseDownX_{}; bool mouseDownX_{};
bool isInLastRow_{}; bool isInLastRow_{};
int mouseWheelDelta_ = 0; int mouseWheelDelta_ = 0;
NotebookTabLocation tabLocation_ = NotebookTabLocation::Top;
HighlightState highlightState_ = HighlightState::None; HighlightState highlightState_ = HighlightState::None;
bool highlightEnabled_ = true; bool highlightEnabled_ = true;