diff --git a/Telegram/Resources/icons/chat/menu_sidebar1.svg b/Telegram/Resources/icons/chat/menu_sidebar1.svg
new file mode 100644
index 0000000000..ae5d1b0c45
--- /dev/null
+++ b/Telegram/Resources/icons/chat/menu_sidebar1.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/Telegram/Resources/icons/chat/menu_sidebar2.svg b/Telegram/Resources/icons/chat/menu_sidebar2.svg
new file mode 100644
index 0000000000..177ce3e81d
--- /dev/null
+++ b/Telegram/Resources/icons/chat/menu_sidebar2.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/Telegram/Resources/icons/chat/menu_sidebar3.svg b/Telegram/Resources/icons/chat/menu_sidebar3.svg
new file mode 100644
index 0000000000..7d47fa7682
--- /dev/null
+++ b/Telegram/Resources/icons/chat/menu_sidebar3.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 429828155c..e52226ce51 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -7034,7 +7034,8 @@ void HistoryWidget::updateHistoryGeometry(
const auto subsectionTabsTop = _topBar->bottomNoMargins();
auto newScrollHeight = height()
- subsectionTabsTop
- - (_subsectionTabs ? _subsectionTabs->topSkip() : 0);
+ - (_subsectionTabs ? _subsectionTabs->topSkip() : 0)
+ - (_subsectionTabs ? _subsectionTabs->bottomSkip() : 0);
if (_translateBar) {
newScrollHeight -= _translateBar->height();
}
@@ -7113,8 +7114,11 @@ void HistoryWidget::updateHistoryGeometry(
controller()->floatPlayerAreaUpdated();
}
if (_subsectionTabs) {
+ const auto tabsBottomSkip = _subsectionTabs->bottomSkip();
const auto scrollBottom = _scroll->y() + newScrollHeight;
- const auto areaHeight = scrollBottom - subsectionTabsTop;
+ const auto areaHeight = scrollBottom
+ + tabsBottomSkip
+ - subsectionTabsTop;
_subsectionTabs->setBoundingRect(
{ 0, subsectionTabsTop, width(), areaHeight });
}
diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
index aa446c58d8..1d301c1504 100644
--- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
@@ -2645,6 +2645,9 @@ void ChatWidget::updateControlsGeometry() {
const auto tabsLeftSkip = _subsectionTabs
? _subsectionTabs->leftSkip()
: 0;
+ const auto tabsBottomSkip = _subsectionTabs
+ ? _subsectionTabs->bottomSkip()
+ : 0;
const auto innerWidth = contentWidth - tabsLeftSkip;
const auto subsectionTabsTop = _topBar->bottomNoMargins();
_topBars->move(tabsLeftSkip, subsectionTabsTop
@@ -2682,6 +2685,8 @@ void ChatWidget::updateControlsGeometry() {
} else {
bottom -= _composeControls->heightCurrent();
}
+ const auto composeTop = bottom;
+ bottom -= tabsBottomSkip;
_topBars->resize(innerWidth, top + st::lineWidth);
top += _topBars->y();
@@ -2704,12 +2709,14 @@ void ChatWidget::updateControlsGeometry() {
}
updateInnerVisibleArea();
}
- _composeControls->move(0, bottom);
+ _composeControls->move(0, composeTop);
_composeControls->setAutocompleteBoundingRect(_scroll->geometry());
if (_subsectionTabs) {
const auto scrollBottom = _scroll->y() + scrollHeight;
- const auto areaHeight = scrollBottom - subsectionTabsTop;
+ const auto areaHeight = scrollBottom
+ + tabsBottomSkip
+ - subsectionTabsTop;
_subsectionTabs->setBoundingRect(
{ 0, subsectionTabsTop, width(), areaHeight });
}
diff --git a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp
index 5c4049307a..3d48814554 100644
--- a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp
@@ -80,22 +80,31 @@ SubsectionTabs::SubsectionTabs(
SubsectionTabs::~SubsectionTabs() {
delete base::take(_horizontal);
delete base::take(_vertical);
+ delete base::take(_bottom);
delete base::take(_shadow);
}
void SubsectionTabs::setup(not_null parent) {
const auto peerId = _history->peer->id;
- if (session().settings().verticalSubsectionTabs(peerId)) {
+ const auto mode = session().settings().subsectionTabsMode(peerId);
+ if (mode == qint32(SubsectionTabsMode::Left)) {
setupVertical(parent);
+ } else if (mode == qint32(SubsectionTabsMode::Bottom)) {
+ setupHorizontal(parent, true);
} else {
- setupHorizontal(parent);
+ setupHorizontal(parent, false);
}
}
-void SubsectionTabs::setupHorizontal(not_null parent) {
+void SubsectionTabs::setupHorizontal(
+ not_null parent,
+ bool bottom) {
delete base::take(_vertical);
- _horizontal = Ui::CreateChild(parent);
- _horizontal->show();
+ delete base::take(bottom ? _horizontal : _bottom);
+ auto &widgetRef = bottom ? _bottom : _horizontal;
+ widgetRef = Ui::CreateChild(parent);
+ widgetRef->show();
+ const auto widget = widgetRef;
if (!_shadow) {
_shadow = Ui::CreateChild(parent);
@@ -105,19 +114,24 @@ void SubsectionTabs::setupHorizontal(not_null parent) {
}
const auto toggle = Ui::CreateChild(
- _horizontal,
+ widget,
st::chatTabsToggle);
toggle->show();
+ toggle->setIconOverride(
+ bottom ? &st::chatTabsToggleIconBottom : &st::chatTabsToggleIconTop,
+ (bottom
+ ? &st::chatTabsToggleIconBottomOver
+ : &st::chatTabsToggleIconTopOver));
toggle->setClickedCallback([=] {
toggleModes();
});
toggle->move(0, 0);
const auto scroll = Ui::CreateChild(
- _horizontal,
+ widget,
st::chatTabsScroll,
true);
scroll->show();
- const auto shadow = Ui::CreateChild(_horizontal);
+ const auto shadow = Ui::CreateChild(widget);
const auto slider = scroll->setOwnedWidget(
object_ptr(scroll));
_reorder = std::make_unique(slider, scroll);
@@ -130,8 +144,8 @@ void SubsectionTabs::setupHorizontal(not_null parent) {
) | rpl::map([=] { return scroll->scrollLeft() > 0; }));
shadow->setAttribute(Qt::WA_TransparentForMouseEvents);
- _horizontal->resize(
- _horizontal->width(),
+ widget->resize(
+ widget->width(),
std::max(toggle->height(), slider->height()));
scroll->setCustomWheelProcess([=](not_null e) {
@@ -145,7 +159,7 @@ void SubsectionTabs::setupHorizontal(not_null parent) {
return true;
});
- _horizontal->sizeValue(
+ widget->sizeValue(
) | rpl::on_next([=](QSize size) {
const auto togglew = toggle->width();
const auto height = size.height();
@@ -153,13 +167,26 @@ void SubsectionTabs::setupHorizontal(not_null parent) {
shadow->setGeometry(togglew, 0, st::lineWidth, height);
}, scroll->lifetime());
- _horizontal->paintRequest() | rpl::on_next([=](QRect clip) {
- QPainter(_horizontal).fillRect(
+ widget->paintRequest() | rpl::on_next([=](QRect clip) {
+ auto p = QPainter(widget);
+
+ const auto line = st::lineWidth;
+ p.fillRect(
clip.intersected(
- _horizontal->rect().marginsRemoved(
- { 0, 0, 0, st::lineWidth })),
+ widget->rect().marginsRemoved(
+ { 0, bottom ? line : 0, 0, bottom ? 0 : line })),
st::windowBg);
- }, _horizontal->lifetime());
+ if (bottom) {
+ const auto shadow = QRect(
+ 0,
+ widget->height() - line,
+ widget->width(),
+ line);
+ if (clip.intersects(shadow)) {
+ p.fillRect(clip.intersected(shadow), st::shadowFg);
+ }
+ }
+ }, widget->lifetime());
_layoutRequests.fire({});
@@ -168,6 +195,7 @@ void SubsectionTabs::setupHorizontal(not_null parent) {
void SubsectionTabs::setupVertical(not_null parent) {
delete base::take(_horizontal);
+ delete base::take(_bottom);
_vertical = Ui::CreateChild(parent);
_vertical->show();
@@ -180,8 +208,9 @@ void SubsectionTabs::setupVertical(not_null parent) {
_vertical,
st::chatTabsToggle);
toggle->show();
- const auto active = &st::chatTabsToggleActive;
- toggle->setIconOverride(active, active);
+ toggle->setIconOverride(
+ &st::chatTabsToggleIconLeft,
+ &st::chatTabsToggleIconLeftOver);
toggle->setClickedCallback([=] {
toggleModes();
});
@@ -566,7 +595,7 @@ void SubsectionTabs::startFillingSlider(
void SubsectionTabs::showThreadContextMenu(not_null thread) {
_menu = nullptr;
_menu = base::make_unique_q(
- _horizontal ? _horizontal : _vertical,
+ activeWidget(),
st::popupMenuExpandedSeparator);
const auto addAction = Ui::Menu::CreateAddActionCallback(_menu);
@@ -605,17 +634,27 @@ rpl::producer<> SubsectionTabs::dataChanged() const {
}
void SubsectionTabs::toggleModes() {
- Expects((_horizontal || _vertical) && _shadow);
+ Expects((_horizontal || _vertical || _bottom) && _shadow);
const auto peerId = _history->peer->id;
- const auto nowVertical = (_horizontal != nullptr);
- session().settings().setVerticalSubsectionTabs(peerId, nowVertical);
+ const auto parent = activeWidget()->parentWidget();
+ const auto current = session().settings().subsectionTabsMode(peerId);
+ const auto next = (current == qint32(SubsectionTabsMode::Top))
+ ? SubsectionTabsMode::Bottom
+ : (current == qint32(SubsectionTabsMode::Bottom))
+ ? SubsectionTabsMode::Left
+ : SubsectionTabsMode::Top;
+ session().settings().setSubsectionTabsMode(
+ peerId,
+ qint32(next));
session().saveSettingsDelayed();
- if (_horizontal) {
- setupVertical(_horizontal->parentWidget());
+ if (next == SubsectionTabsMode::Left) {
+ setupVertical(parent);
+ } else if (next == SubsectionTabsMode::Bottom) {
+ setupHorizontal(parent, true);
} else {
- setupHorizontal(_vertical->parentWidget());
+ setupHorizontal(parent, false);
}
}
@@ -634,21 +673,17 @@ rpl::producer<> SubsectionTabs::removeRequests() const {
}
void SubsectionTabs::extractToParent(not_null parent) {
- Expects((_horizontal || _vertical) && _shadow);
+ Expects((_horizontal || _vertical || _bottom) && _shadow);
- if (_vertical) {
- _vertical->hide();
- _vertical->setParent(parent);
- } else {
- _horizontal->hide();
- _horizontal->setParent(parent);
- }
+ const auto widget = activeWidget();
+ widget->hide();
+ widget->setParent(parent);
_shadow->hide();
_shadow->setParent(parent);
}
void SubsectionTabs::setBoundingRect(QRect boundingRect) {
- Expects((_horizontal || _vertical) && _shadow);
+ Expects((_horizontal || _vertical || _bottom) && _shadow);
if (_horizontal) {
_horizontal->setGeometry(
@@ -661,7 +696,7 @@ void SubsectionTabs::setBoundingRect(QRect boundingRect) {
_horizontal->y() + _horizontal->height() - st::lineWidth,
boundingRect.width(),
st::lineWidth);
- } else {
+ } else if (_vertical) {
_vertical->setGeometry(
boundingRect.x(),
boundingRect.y(),
@@ -672,6 +707,18 @@ void SubsectionTabs::setBoundingRect(QRect boundingRect) {
boundingRect.y(),
st::lineWidth,
boundingRect.height());
+ } else {
+ _bottom->setGeometry(
+ boundingRect.x(),
+ boundingRect.y() + boundingRect.height()
+ - _bottom->height(),
+ boundingRect.width(),
+ _bottom->height());
+ _shadow->setGeometry(
+ boundingRect.x(),
+ _bottom->y(),
+ boundingRect.width(),
+ st::lineWidth);
}
}
@@ -687,14 +734,14 @@ int SubsectionTabs::topSkip() const {
return _horizontal ? (_horizontal->height() - st::lineWidth) : 0;
}
-void SubsectionTabs::raise() {
- Expects((_horizontal || _vertical) && _shadow);
+int SubsectionTabs::bottomSkip() const {
+ return _bottom ? (_bottom->height() - st::lineWidth) : 0;
+}
- if (_horizontal) {
- _horizontal->raise();
- } else {
- _vertical->raise();
- }
+void SubsectionTabs::raise() {
+ Expects((_horizontal || _vertical || _bottom) && _shadow);
+
+ activeWidget()->raise();
_shadow->raise();
}
@@ -707,13 +754,9 @@ void SubsectionTabs::hide() {
}
void SubsectionTabs::setVisible(bool shown) {
- Expects((_horizontal || _vertical) && _shadow);
+ Expects((_horizontal || _vertical || _bottom) && _shadow);
- if (_horizontal) {
- _horizontal->setVisible(shown);
- } else {
- _vertical->setVisible(shown);
- }
+ activeWidget()->setVisible(shown);
_shadow->setVisible(shown);
}
@@ -829,7 +872,7 @@ void SubsectionTabs::refreshSlice() {
if (_slice != slice) {
_slice = std::move(slice);
_refreshed.fire({});
- Assert((!_horizontal && !_vertical)
+ Assert((!_horizontal && !_vertical && !_bottom)
|| (_slice.size() == _sectionsSlice.size()));
}
});
@@ -908,22 +951,22 @@ Main::Session &SubsectionTabs::session() {
return _history->session();
}
+Ui::RpWidget *SubsectionTabs::activeWidget() const {
+ return _horizontal ? _horizontal : _vertical ? _vertical : _bottom;
+}
+
bool SubsectionTabs::switchTo(
not_null thread,
not_null parent) {
- Expects((_horizontal || _vertical) && _shadow);
+ Expects((_horizontal || _vertical || _bottom) && _shadow);
if (thread->owningHistory() != _history) {
return false;
}
_active = thread;
- if (_vertical) {
- _vertical->setParent(parent);
- _vertical->show();
- } else {
- _horizontal->setParent(parent);
- _horizontal->show();
- }
+ const auto widget = activeWidget();
+ widget->setParent(parent);
+ widget->show();
_shadow->setParent(parent);
_shadow->show();
_refreshed.fire({});
diff --git a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h
index 01be891f4b..987b9ceb26 100644
--- a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h
+++ b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h
@@ -34,6 +34,12 @@ class SubsectionSliderReorder;
namespace HistoryView {
+enum class SubsectionTabsMode : qint32 {
+ Top = 0,
+ Left = 1,
+ Bottom = 2,
+};
+
class SubsectionTabs final {
public:
SubsectionTabs(
@@ -59,6 +65,7 @@ public:
[[nodiscard]] rpl::producer<> layoutRequests() const;
[[nodiscard]] int leftSkip() const;
[[nodiscard]] int topSkip() const;
+ [[nodiscard]] int bottomSkip() const;
void raise();
void show();
@@ -80,7 +87,7 @@ private:
};
void track();
- void setupHorizontal(not_null parent);
+ void setupHorizontal(not_null parent, bool bottom);
void setupVertical(not_null parent);
void toggleModes();
void setVisible(bool shown);
@@ -92,6 +99,7 @@ private:
void loadMore();
void setup(not_null parent);
[[nodiscard]] rpl::producer<> dataChanged() const;
+ [[nodiscard]] Ui::RpWidget *activeWidget() const;
void setupSlider(
not_null scroll,
@@ -118,6 +126,7 @@ private:
Ui::RpWidget *_horizontal = nullptr;
Ui::RpWidget *_vertical = nullptr;
+ Ui::RpWidget *_bottom = nullptr;
Ui::RpWidget *_shadow = nullptr;
std::unique_ptr _reorder;
int _reordering = 0;
diff --git a/Telegram/SourceFiles/main/main_session_settings.cpp b/Telegram/SourceFiles/main/main_session_settings.cpp
index 9e1b1cb7bc..18ad7cb0f7 100644
--- a/Telegram/SourceFiles/main/main_session_settings.cpp
+++ b/Telegram/SourceFiles/main/main_session_settings.cpp
@@ -46,7 +46,6 @@ QByteArray SessionSettings::serialize() const {
+ sizeof(qint32) * 3
+ _hiddenPinnedMessages.size() * (sizeof(quint64) * 4)
+ sizeof(qint32)
- + _verticalSubsectionTabs.size() * sizeof(quint64)
+ sizeof(qint32) // _ringtoneDefaultVolumes size
+ (_ringtoneDefaultVolumes.size()
* (0
@@ -69,6 +68,8 @@ QByteArray SessionSettings::serialize() const {
size += sizeof(qint32) // _moderateCommonGroups size
+ (_moderateCommonGroups.size() * sizeof(qint32));
size += sizeof(qint32);
+ size += sizeof(qint32)
+ + _subsectionTabsModes.size() * (sizeof(quint64) + sizeof(qint32));
auto result = QByteArray();
result.reserve(size);
@@ -120,10 +121,7 @@ QByteArray SessionSettings::serialize() const {
<< SerializePeerId(key.monoforumPeerId)
<< qint64(value.bare);
}
- stream << qint32(_verticalSubsectionTabs.size());
- for (const auto &peerId : _verticalSubsectionTabs) {
- stream << SerializePeerId(peerId);
- }
+ stream << qint32(0);
stream << qint32(_ringtoneDefaultVolumes.size());
for (const auto &[key, value] : _ringtoneDefaultVolumes) {
stream << uint8_t(key) << ushort(value);
@@ -155,6 +153,10 @@ QByteArray SessionSettings::serialize() const {
stream << qint32(filterId);
}
stream << qint32(_disableSharingBoxShowsCount);
+ stream << qint32(_subsectionTabsModes.size());
+ for (const auto &[peerId, mode] : _subsectionTabsModes) {
+ stream << SerializePeerId(peerId) << qint32(mode);
+ }
}
Ensures(result.size() == size);
@@ -214,7 +216,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
std::vector appDictionariesEnabled;
qint32 appAutoDownloadDictionaries = app.autoDownloadDictionaries() ? 1 : 0;
base::flat_map hiddenPinnedMessages;
- base::flat_set verticalSubsectionTabs;
+ base::flat_map subsectionTabsModes;
qint32 dialogsFiltersEnabled = _dialogsFiltersEnabled ? 1 : 0;
qint32 supportAllSilent = _supportAllSilent ? 1 : 0;
qint32 photoEditorHintShowsCount = _photoEditorHintShowsCount;
@@ -547,7 +549,8 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
"Bad data for SessionSettings::addFromSerialized()"));
return;
}
- verticalSubsectionTabs.emplace(DeserializePeerId(peerId));
+ subsectionTabsModes.emplace(
+ DeserializePeerId(peerId), qint32(1));
}
}
}
@@ -665,6 +668,24 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> disableSharingBoxShowsCount;
}
+ if (!stream.atEnd()) {
+ auto count = qint32(0);
+ stream >> count;
+ if (stream.status() == QDataStream::Ok) {
+ for (auto i = 0; i != count; ++i) {
+ auto peerId = quint64();
+ auto mode = qint32(0);
+ stream >> peerId >> mode;
+ if (stream.status() != QDataStream::Ok) {
+ LOG(("App Error: "
+ "Bad data for SessionSettings::addFromSerialized()"));
+ return;
+ }
+ subsectionTabsModes.emplace(
+ DeserializePeerId(peerId), mode);
+ }
+ }
+ }
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for SessionSettings::addFromSerialized()"));
@@ -711,7 +732,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
_mutePeriods = std::move(mutePeriods);
_lastNonPremiumLimitDownload = lastNonPremiumLimitDownload;
_lastNonPremiumLimitUpload = lastNonPremiumLimitUpload;
- _verticalSubsectionTabs = std::move(verticalSubsectionTabs);
+ _subsectionTabsModes = std::move(subsectionTabsModes);
_ringtoneDefaultVolumes = std::move(ringtoneDefaultVolumes);
_ringtoneVolumes = std::move(ringtoneVolumes);
_ratedTranscriptions = std::move(ratedTranscriptions);
@@ -864,17 +885,18 @@ void SessionSettings::setHiddenPinnedMessageId(
}
}
-bool SessionSettings::verticalSubsectionTabs(PeerId peerId) const {
- return _verticalSubsectionTabs.contains(peerId);
+qint32 SessionSettings::subsectionTabsMode(PeerId peerId) const {
+ const auto i = _subsectionTabsModes.find(peerId);
+ return (i != end(_subsectionTabsModes)) ? i->second : 0;
}
-void SessionSettings::setVerticalSubsectionTabs(
+void SessionSettings::setSubsectionTabsMode(
PeerId peerId,
- bool vertical) {
- if (vertical) {
- _verticalSubsectionTabs.emplace(peerId);
+ qint32 mode) {
+ if (mode) {
+ _subsectionTabsModes[peerId] = mode;
} else {
- _verticalSubsectionTabs.remove(peerId);
+ _subsectionTabsModes.remove(peerId);
}
}
diff --git a/Telegram/SourceFiles/main/main_session_settings.h b/Telegram/SourceFiles/main/main_session_settings.h
index 34d13ccb2c..750c149a4d 100644
--- a/Telegram/SourceFiles/main/main_session_settings.h
+++ b/Telegram/SourceFiles/main/main_session_settings.h
@@ -124,8 +124,8 @@ public:
PeerId monoforumPeerId,
MsgId msgId);
- [[nodiscard]] bool verticalSubsectionTabs(PeerId peerId) const;
- void setVerticalSubsectionTabs(PeerId peerId, bool vertical);
+ [[nodiscard]] qint32 subsectionTabsMode(PeerId peerId) const;
+ void setSubsectionTabsMode(PeerId peerId, qint32 mode);
[[nodiscard]] bool dialogsFiltersEnabled() const {
return _dialogsFiltersEnabled;
@@ -211,7 +211,7 @@ private:
rpl::variable _archiveInMainMenu = false;
rpl::variable _skipArchiveInSearch = false;
base::flat_map _hiddenPinnedMessages;
- base::flat_set _verticalSubsectionTabs;
+ base::flat_map _subsectionTabsModes;
base::flat_map _ringtoneDefaultVolumes;
base::flat_map _ringtoneVolumes;
bool _dialogsFiltersEnabled = false;
diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style
index f7116837c7..d3228885a3 100644
--- a/Telegram/SourceFiles/ui/chat/chat.style
+++ b/Telegram/SourceFiles/ui/chat/chat.style
@@ -1376,7 +1376,12 @@ chatTabsToggle: IconButton(defaultIconButton) {
iconOver: icon {{ "top_bar_profile-flip_horizontal", menuIconFgOver }};
ripple: emptyRippleAnimation;
}
-chatTabsToggleActive: icon {{ "top_bar_profile-flip_horizontal", windowActiveTextFg }};
+chatTabsToggleIconTop: icon {{ "chat/menu_sidebar2-24x24", menuIconFg }};
+chatTabsToggleIconTopOver: icon {{ "chat/menu_sidebar2-24x24", menuIconFgOver }};
+chatTabsToggleIconLeft: icon {{ "chat/menu_sidebar3-24x24", menuIconFg }};
+chatTabsToggleIconLeftOver: icon {{ "chat/menu_sidebar3-24x24", menuIconFgOver }};
+chatTabsToggleIconBottom: icon {{ "chat/menu_sidebar1-24x24", menuIconFg }};
+chatTabsToggleIconBottomOver: icon {{ "chat/menu_sidebar1-24x24", menuIconFgOver }};
chatTabsScroll: ScrollArea(defaultScrollArea) {
barHidden: true;
}