Improve tabbed slider design.
This commit is contained in:
parent
f3ba8fea57
commit
6441266879
10 changed files with 76 additions and 46 deletions
|
@ -351,11 +351,7 @@ filtersRemove: IconButton(stickersRemove) {
|
||||||
|
|
||||||
emojiPanMargins: margins(10px, 10px, 10px, 10px);
|
emojiPanMargins: margins(10px, 10px, 10px, 10px);
|
||||||
|
|
||||||
emojiTabs: SettingsSlider(defaultTabsSlider) {
|
emojiTabs: defaultTabsSlider;
|
||||||
height: 43px;
|
|
||||||
barTop: 40px;
|
|
||||||
labelTop: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
emojiCategoryIconTop: 6px;
|
emojiCategoryIconTop: 6px;
|
||||||
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
|
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
|
||||||
|
|
|
@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/unique_qptr.h"
|
#include "base/unique_qptr.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class SettingsSlider;
|
|
||||||
class VerticalLayout;
|
class VerticalLayout;
|
||||||
class SearchFieldController;
|
class SearchFieldController;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -10,10 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <rpl/event_stream.h>
|
#include <rpl/event_stream.h>
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class SettingsSlider;
|
|
||||||
} // namespace Ui
|
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
class ConnectionState;
|
class ConnectionState;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
|
@ -15,7 +15,6 @@ enum class SharedMediaType : signed char;
|
||||||
} // namespace Storage
|
} // namespace Storage
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class SettingsSlider;
|
|
||||||
class FadeShadow;
|
class FadeShadow;
|
||||||
class PlainShadow;
|
class PlainShadow;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
|
|
@ -14,7 +14,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "info/media/info_media_list_widget.h"
|
#include "info/media/info_media_list_widget.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class SettingsSlider;
|
|
||||||
class VerticalLayout;
|
class VerticalLayout;
|
||||||
class SearchFieldController;
|
class SearchFieldController;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/unique_qptr.h"
|
#include "base/unique_qptr.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class SettingsSlider;
|
|
||||||
class VerticalLayout;
|
class VerticalLayout;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
DiscreteSlider::DiscreteSlider(QWidget *parent) : RpWidget(parent) {
|
DiscreteSlider::DiscreteSlider(QWidget *parent, bool snapToLabel)
|
||||||
|
: RpWidget(parent)
|
||||||
|
, _snapToLabel(snapToLabel) {
|
||||||
setCursor(style::cur_pointer);
|
setCursor(style::cur_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,9 +82,23 @@ void DiscreteSlider::setSections(const std::vector<QString> &labels) {
|
||||||
resizeToWidth(width());
|
resizeToWidth(width());
|
||||||
}
|
}
|
||||||
|
|
||||||
int DiscreteSlider::getCurrentActiveLeft() {
|
DiscreteSlider::Range DiscreteSlider::getFinalActiveRange() const {
|
||||||
const auto left = _sections.empty() ? 0 : _sections[_selected].left;
|
const auto raw = _sections.empty() ? nullptr : &_sections[_selected];
|
||||||
return _a_left.value(left);
|
if (!raw) {
|
||||||
|
return { 0, 0 };
|
||||||
|
}
|
||||||
|
const auto width = _snapToLabel
|
||||||
|
? std::min(raw->width, raw->label.maxWidth())
|
||||||
|
: raw->width;
|
||||||
|
return { raw->left + ((raw->width - width) / 2), width };
|
||||||
|
}
|
||||||
|
|
||||||
|
DiscreteSlider::Range DiscreteSlider::getCurrentActiveRange() const {
|
||||||
|
const auto to = getFinalActiveRange();
|
||||||
|
return {
|
||||||
|
int(base::SafeRound(_a_left.value(to.left))),
|
||||||
|
int(base::SafeRound(_a_width.value(to.width))),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Lambda>
|
template <typename Lambda>
|
||||||
|
@ -138,11 +154,13 @@ void DiscreteSlider::setSelectedSection(int index) {
|
||||||
if (index < 0 || index >= _sections.size()) return;
|
if (index < 0 || index >= _sections.size()) return;
|
||||||
|
|
||||||
if (_selected != index) {
|
if (_selected != index) {
|
||||||
auto from = _sections[_selected].left;
|
const auto from = getFinalActiveRange();
|
||||||
_selected = index;
|
_selected = index;
|
||||||
auto to = _sections[_selected].left;
|
const auto to = getFinalActiveRange();
|
||||||
auto duration = getAnimationDuration();
|
const auto duration = getAnimationDuration();
|
||||||
_a_left.start([this] { update(); }, from, to, duration);
|
const auto updater = [=] { update(); };
|
||||||
|
_a_left.start(updater, from.left, to.left, duration);
|
||||||
|
_a_width.start(updater, from.width, to.width, duration);
|
||||||
_callbackAfterMs = crl::now() + duration;
|
_callbackAfterMs = crl::now() + duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,7 +184,7 @@ DiscreteSlider::Section::Section(
|
||||||
SettingsSlider::SettingsSlider(
|
SettingsSlider::SettingsSlider(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
const style::SettingsSlider &st)
|
const style::SettingsSlider &st)
|
||||||
: DiscreteSlider(parent)
|
: DiscreteSlider(parent, st.barSnapToLabel)
|
||||||
, _st(st) {
|
, _st(st) {
|
||||||
if (_st.barRadius > 0) {
|
if (_st.barRadius > 0) {
|
||||||
_bar.emplace(_st.barRadius, _st.barFg);
|
_bar.emplace(_st.barRadius, _st.barFg);
|
||||||
|
@ -299,7 +317,7 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
auto clip = e->rect();
|
auto clip = e->rect();
|
||||||
auto activeLeft = getCurrentActiveLeft();
|
auto range = getCurrentActiveRange();
|
||||||
|
|
||||||
const auto drawRect = [&](QRect rect, bool active = false) {
|
const auto drawRect = [&](QRect rect, bool active = false) {
|
||||||
const auto &bar = active ? _barActive : _bar;
|
const auto &bar = active ? _barActive : _bar;
|
||||||
|
@ -310,9 +328,14 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
enumerateSections([&](Section §ion) {
|
enumerateSections([&](Section §ion) {
|
||||||
|
const auto activeWidth = _st.barSnapToLabel
|
||||||
|
? section.label.maxWidth()
|
||||||
|
: section.width;
|
||||||
|
const auto activeLeft = section.left
|
||||||
|
+ (section.width - activeWidth) / 2;
|
||||||
auto active = 1.
|
auto active = 1.
|
||||||
- std::clamp(
|
- std::clamp(
|
||||||
qAbs(activeLeft - section.left) / float64(section.width),
|
qAbs(range.left - activeLeft) / float64(section.width),
|
||||||
0.,
|
0.,
|
||||||
1.);
|
1.);
|
||||||
if (section.ripple) {
|
if (section.ripple) {
|
||||||
|
@ -322,15 +345,16 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
|
||||||
section.ripple.reset();
|
section.ripple.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto from = section.left, tofill = section.width;
|
if (!_st.barSnapToLabel) {
|
||||||
if (activeLeft > from) {
|
auto from = activeLeft, tofill = activeWidth;
|
||||||
auto fill = qMin(tofill, activeLeft - from);
|
if (range.left > from) {
|
||||||
|
auto fill = qMin(tofill, range.left - from);
|
||||||
drawRect(myrtlrect(from, _st.barTop, fill, _st.barStroke));
|
drawRect(myrtlrect(from, _st.barTop, fill, _st.barStroke));
|
||||||
from += fill;
|
from += fill;
|
||||||
tofill -= fill;
|
tofill -= fill;
|
||||||
}
|
}
|
||||||
if (activeLeft + section.width > from) {
|
if (range.left + activeWidth > from) {
|
||||||
if (auto fill = qMin(tofill, activeLeft + section.width - from)) {
|
if (auto fill = qMin(tofill, range.left + activeWidth - from)) {
|
||||||
drawRect(
|
drawRect(
|
||||||
myrtlrect(from, _st.barTop, fill, _st.barStroke),
|
myrtlrect(from, _st.barTop, fill, _st.barStroke),
|
||||||
true);
|
true);
|
||||||
|
@ -341,17 +365,27 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
|
||||||
if (tofill) {
|
if (tofill) {
|
||||||
drawRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke));
|
drawRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke));
|
||||||
}
|
}
|
||||||
if (myrtlrect(section.left, _st.labelTop, section.width, _st.labelStyle.font->height).intersects(clip)) {
|
}
|
||||||
|
const auto labelLeft = section.left + (section.width - section.label.maxWidth()) / 2;
|
||||||
|
if (myrtlrect(labelLeft, _st.labelTop, section.label.maxWidth(), _st.labelStyle.font->height).intersects(clip)) {
|
||||||
p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
|
p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
|
||||||
section.label.drawLeft(
|
section.label.drawLeft(
|
||||||
p,
|
p,
|
||||||
section.left + (section.width - section.label.maxWidth()) / 2,
|
labelLeft,
|
||||||
_st.labelTop,
|
_st.labelTop,
|
||||||
section.label.maxWidth(),
|
section.label.maxWidth(),
|
||||||
width());
|
width());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
if (_st.barSnapToLabel) {
|
||||||
|
const auto add = _st.barStroke / 2;
|
||||||
|
const auto from = std::max(range.left - add, 0);
|
||||||
|
const auto till = std::min(range.left + range.width + add, width());
|
||||||
|
if (from < till) {
|
||||||
|
drawRect(myrtlrect(from, _st.barTop, till - from, _st.barStroke), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -18,7 +18,7 @@ class RippleAnimation;
|
||||||
|
|
||||||
class DiscreteSlider : public RpWidget {
|
class DiscreteSlider : public RpWidget {
|
||||||
public:
|
public:
|
||||||
DiscreteSlider(QWidget *parent);
|
DiscreteSlider(QWidget *parent, bool snapToLabel);
|
||||||
|
|
||||||
void addSection(const QString &label);
|
void addSection(const QString &label);
|
||||||
void setSections(const std::vector<QString> &labels);
|
void setSections(const std::vector<QString> &labels);
|
||||||
|
@ -49,10 +49,15 @@ protected:
|
||||||
Ui::Text::String label;
|
Ui::Text::String label;
|
||||||
std::unique_ptr<RippleAnimation> ripple;
|
std::unique_ptr<RippleAnimation> ripple;
|
||||||
};
|
};
|
||||||
|
struct Range {
|
||||||
|
int left = 0;
|
||||||
|
int width = 0;
|
||||||
|
};
|
||||||
|
|
||||||
int getCurrentActiveLeft();
|
[[nodiscard]] Range getFinalActiveRange() const;
|
||||||
|
[[nodiscard]] Range getCurrentActiveRange() const;
|
||||||
|
|
||||||
int getSectionsCount() const {
|
[[nodiscard]] int getSectionsCount() const {
|
||||||
return _sections.size();
|
return _sections.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +72,7 @@ protected:
|
||||||
|
|
||||||
void stopAnimation() {
|
void stopAnimation() {
|
||||||
_a_left.stop();
|
_a_left.stop();
|
||||||
|
_a_width.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSelectOnPress(bool selectOnPress);
|
void setSelectOnPress(bool selectOnPress);
|
||||||
|
@ -82,12 +88,14 @@ private:
|
||||||
std::vector<Section> _sections;
|
std::vector<Section> _sections;
|
||||||
int _activeIndex = 0;
|
int _activeIndex = 0;
|
||||||
bool _selectOnPress = true;
|
bool _selectOnPress = true;
|
||||||
|
bool _snapToLabel = false;
|
||||||
|
|
||||||
rpl::event_stream<int> _sectionActivated;
|
rpl::event_stream<int> _sectionActivated;
|
||||||
|
|
||||||
int _pressed = -1;
|
int _pressed = -1;
|
||||||
int _selected = 0;
|
int _selected = 0;
|
||||||
Ui::Animations::Simple _a_left;
|
Ui::Animations::Simple _a_left;
|
||||||
|
Ui::Animations::Simple _a_width;
|
||||||
|
|
||||||
int _timerId = -1;
|
int _timerId = -1;
|
||||||
crl::time _callbackAfterMs = 0;
|
crl::time _callbackAfterMs = 0;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 5a11029c461416407a423ac9921356fba0088ab6
|
Subproject commit 2d03abc7de8558ae8862688a226b3d5a817dc466
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0f25a9451012c7fba93777a009f3b5dcc0f1ca89
|
Subproject commit 5f2e0a32b12df1468419b123ac8fb4bb17cf47cc
|
Loading…
Reference in a new issue