2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-31 14:38:15 +00:00

Removing almost all animated over states in IconButton.

This commit is contained in:
John Preston
2016-11-01 15:46:34 +03:00
parent e08f5437a6
commit c932f3d9df
44 changed files with 435 additions and 307 deletions

View File

@@ -219,14 +219,14 @@ namespace anim {
using ValueType = QColor;
cvalue() = default;
cvalue(const QColor &from)
explicit cvalue(QColor from)
: _cur(from)
, _from_r(from.redF())
, _from_g(from.greenF())
, _from_b(from.blueF())
, _from_a(from.alphaF()) {
}
cvalue(const QColor &from, const QColor &to)
cvalue(QColor from, QColor to)
: _cur(from)
, _from_r(from.redF())
, _from_g(from.greenF())
@@ -237,7 +237,7 @@ namespace anim {
, _delta_b(to.blueF() - from.blueF())
, _delta_a(to.alphaF() - from.alphaF()) {
}
void start(const QColor &to) {
void start(QColor to) {
_from_r = _cur.redF();
_from_g = _cur.greenF();
_from_b = _cur.blueF();
@@ -265,7 +265,7 @@ namespace anim {
result.setAlphaF(_from_a);
return result;
}
const QColor &current() const {
QColor current() const {
return _cur;
}
QColor to() const {

View File

@@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Ui {
HistoryDownButton::HistoryDownButton(QWidget *parent) : Button(parent)
, a_arrowOpacity(st::historyAttachEmoji.opacity, st::historyAttachEmoji.opacity)
//, a_arrowOpacity(st::historyAttachEmoji.opacity, st::historyAttachEmoji.opacity)
, _a_arrowOver(animation(this, &HistoryDownButton::step_arrowOver)) {
setCursor(style::cur_pointer);
@@ -53,10 +53,8 @@ HistoryDownButton::HistoryDownButton(QWidget *parent) : Button(parent)
void HistoryDownButton::paintEvent(QPaintEvent *e) {
Painter p(this);
float64 opacity = 1.;
if (_a_show.animating(getms())) {
opacity = _a_show.current();
p.setOpacity(opacity);
p.setOpacity(_a_show.current());
p.drawPixmap(0, st::historyToDownPaddingTop, _cache);
} else if (!_shown) {
hide();
@@ -64,10 +62,8 @@ void HistoryDownButton::paintEvent(QPaintEvent *e) {
} else {
st::historyToDown.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
}
p.setOpacity(opacity * a_arrowOpacity.current());
st::historyToDownArrow.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
if (_unreadCount > 0) {
p.setOpacity(opacity);
auto unreadString = QString::number(_unreadCount);
if (unreadString.size() > 4) {
unreadString = qsl("..") + unreadString.mid(unreadString.size() - 4);
@@ -83,7 +79,7 @@ void HistoryDownButton::paintEvent(QPaintEvent *e) {
}
void HistoryDownButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
a_arrowOpacity.start((_state & (StateOver | StateDown)) ? st::historyAttachEmoji.overOpacity : st::historyAttachEmoji.opacity);
//a_arrowOpacity.start((_state & (StateOver | StateDown)) ? st::historyAttachEmoji.overOpacity : st::historyAttachEmoji.opacity);
if (source == ButtonByUser || source == ButtonByPress) {
_a_arrowOver.stop();
@@ -151,16 +147,15 @@ void EmojiButton::paintEvent(QPaintEvent *e) {
p.fillRect(e->rect(), st::historyComposeAreaBg);
auto over = _a_over.current(getms(), (_state & StateOver) ? 1. : 0.);
auto opacity = over * _st.overOpacity + (1. - over) * _st.opacity;
auto loading = a_loading.current(ms, _loading ? 1 : 0);
p.setOpacity(opacity * (1 - loading));
p.setOpacity(1 - loading);
_st.icon.paint(p, (_state & StateDown) ? _st.downIconPosition : _st.iconPosition, width());
auto over = (_state & StateOver);
auto icon = &(over ? _st.iconOver : _st.icon);
icon->paint(p, (_state & StateDown) ? _st.iconPositionDown : _st.iconPosition, width());
p.setOpacity(opacity);
p.setPen(QPen(st::historyEmojiCircleFg, st::historyEmojiCircleLine));
p.setOpacity(1.);
p.setPen(QPen(over ? st::historyEmojiCircleFgOver : st::historyEmojiCircleFg, st::historyEmojiCircleLine));
p.setBrush(Qt::NoBrush);
p.setRenderHint(QPainter::HighQualityAntialiasing);
@@ -191,9 +186,7 @@ void EmojiButton::setLoading(bool loading) {
void EmojiButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
auto over = (_state & StateOver);
if (over != (oldState & StateOver)) {
auto from = over ? 0. : 1.;
auto to = over ? 1. : 0.;
_a_over.start([this] { update(); }, from, to, _st.duration);
update();
}
}

View File

@@ -75,8 +75,6 @@ protected:
private:
const style::IconButton &_st;
FloatAnimation _a_over;
bool _loading = false;
FloatAnimation a_loading;
Animation _a_loading;

View File

@@ -29,8 +29,9 @@ IconButton::IconButton(QWidget *parent, const style::IconButton &st) : Button(pa
setCursor(style::cur_pointer);
}
void IconButton::setIcon(const style::icon *icon) {
void IconButton::setIcon(const style::icon *icon, const style::icon *iconOver) {
_iconOverride = icon;
_iconOverrideOver = iconOver;
update();
}
@@ -38,22 +39,47 @@ void IconButton::paintEvent(QPaintEvent *e) {
Painter p(this);
auto over = _a_over.current(getms(), (_state & StateOver) ? 1. : 0.);
p.setOpacity(over * _st.overOpacity + (1. - over) * _st.opacity);
auto icon = (_iconOverride ? _iconOverride : &_st.icon);
auto position = (_state & StateDown) ? _st.downIconPosition : _st.iconPosition;
auto overIcon = [this] {
if (_iconOverrideOver) {
return _iconOverrideOver;
} else if (!_st.iconOver.empty()) {
return &_st.iconOver;
} else if (_iconOverride) {
return _iconOverride;
}
return &_st.icon;
};
auto justIcon = [this] {
if (_iconOverride) {
return _iconOverride;
}
return &_st.icon;
};
auto icon = (over == 1.) ? overIcon() : justIcon();
auto position = (_state & StateDown) ? _st.iconPositionDown : _st.iconPosition;
if (position.x() < 0) {
position.setX((width() - icon->width()) / 2);
}
icon->paint(p, position, width());
if (over > 0. && over < 1.) {
auto iconOver = overIcon();
if (iconOver != icon) {
p.setOpacity(over);
iconOver->paint(p, position, width());
}
}
}
void IconButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
auto over = (_state & StateOver);
if (over != (oldState & StateOver)) {
auto from = over ? 0. : 1.;
auto to = over ? 1. : 0.;
_a_over.start([this] { update(); }, from, to, _st.duration);
if (_st.duration) {
auto from = over ? 0. : 1.;
auto to = over ? 1. : 0.;
_a_over.start([this] { update(); }, from, to, _st.duration);
} else {
update();
}
}
}
@@ -77,7 +103,7 @@ void MaskButton::paintEvent(QPaintEvent *e) {
Painter p(this);
auto clip = e->rect();
auto position = (_state & StateDown) ? _st.downIconPosition : _st.iconPosition;
auto position = (_state & StateDown) ? _st.iconPositionDown : _st.iconPosition;
if (position.x() < 0) {
position.setX((width() - _st.icon.width()) / 2);
}

View File

@@ -30,7 +30,7 @@ public:
IconButton(QWidget *parent, const style::IconButton &st);
// Pass nullptr to restore the default icon.
void setIcon(const style::icon *icon);
void setIcon(const style::icon *icon, const style::icon *iconOver = nullptr);
protected:
void paintEvent(QPaintEvent *e) override;
@@ -40,6 +40,7 @@ protected:
private:
const style::IconButton &_st;
const style::icon *_iconOverride = nullptr;
const style::icon *_iconOverrideOver = nullptr;
FloatAnimation _a_over;

View File

@@ -75,34 +75,58 @@ void stopManager() {
internal::destroyIcons();
}
QImage colorizeImage(const QImage &src, const color &c, const QRect &r) {
QImage colorizeImage(const QImage &src, QColor color, const QRect &r) {
t_assert(r.x() >= 0 && src.width() >= r.x() + r.width());
t_assert(r.y() >= 0 && src.height() >= r.y() + r.height());
int a = c->c.alpha() + 1;
int fg_r = c->c.red() * a, fg_g = c->c.green() * a, fg_b = c->c.blue() * a, fg_a = 255 * a;
auto initialAlpha = color.alpha() + 1;
auto red = color.red() * initialAlpha;
auto green = color.green() * initialAlpha;
auto blue = color.blue() * initialAlpha;
auto alpha = 255 * initialAlpha;
auto alpha_red = static_cast<uint64>(alpha) | (static_cast<uint64>(red) << 32);
auto green_blue = static_cast<uint64>(green) | (static_cast<uint64>(blue) << 32);
QImage result(r.width(), r.height(), QImage::Format_ARGB32_Premultiplied);
auto bits = result.bits();
auto maskbits = src.constBits();
int bpp = result.depth(), maskbpp = src.depth();
int bpl = result.bytesPerLine(), maskbpl = src.bytesPerLine();
for (int x = 0, xoffset = r.x(); x < r.width(); ++x) {
for (int y = 0, yoffset = r.y(); y < r.height(); ++y) {
int s = y * bpl + ((x * bpp) >> 3);
int o = maskbits[(y + yoffset) * maskbpl + (((x + xoffset) * maskbpp) >> 3)] + 1;
bits[s + 0] = (fg_b * o) >> 16;
bits[s + 1] = (fg_g * o) >> 16;
bits[s + 2] = (fg_r * o) >> 16;
bits[s + 3] = (fg_a * o) >> 16;
auto result = QImage(r.width(), r.height(), QImage::Format_ARGB32_Premultiplied);
auto resultBytesPerPixel = (src.depth() >> 3);
auto resultIntsPerPixel = 1;
auto resultIntsPerLine = (result.bytesPerLine() >> 2);
auto resultIntsAdded = resultIntsPerLine - r.width() * resultIntsPerPixel;
auto resultInts = reinterpret_cast<uint32*>(result.bits());
t_assert(resultIntsAdded >= 0);
t_assert(result.depth() == ((resultIntsPerPixel * sizeof(uint32)) << 3));
t_assert(result.bytesPerLine() == (resultIntsPerLine << 2));
auto maskBytesPerPixel = (src.depth() >> 3);
auto maskBytesPerLine = src.bytesPerLine();
auto maskBytesAdded = maskBytesPerLine - r.width() * maskBytesPerPixel;
auto maskBytes = src.constBits() + r.y() * maskBytesPerLine + r.x() * maskBytesPerPixel;
t_assert(maskBytesAdded >= 0);
t_assert(src.depth() == (maskBytesPerPixel << 3));
for (int y = 0; y != r.height(); ++y) {
for (int x = 0; x != r.width(); ++x) {
auto maskOpacity = static_cast<uint64>(*maskBytes) + 1;
auto alpha_red_masked = (alpha_red * maskOpacity) >> 16;
auto green_blue_masked = (green_blue * maskOpacity) >> 16;
auto alpha = static_cast<uint32>(alpha_red_masked & 0xFF);
auto red = static_cast<uint32>((alpha_red_masked >> 32) & 0xFF);
auto green = static_cast<uint32>(green_blue_masked & 0xFF);
auto blue = static_cast<uint32>((green_blue_masked >> 32) & 0xFF);
*resultInts = blue | (green << 8) | (red << 16) | (alpha << 24);
maskBytes += maskBytesPerPixel;
resultInts += resultIntsPerPixel;
}
maskBytes += maskBytesAdded;
resultInts += resultIntsAdded;
}
return result;
result.setDevicePixelRatio(src.devicePixelRatio());
return std_::move(result);
}
namespace internal {
QImage createCircleMask(int size, const QColor &bg, const QColor &fg) {
QImage createCircleMask(int size, QColor bg, QColor fg) {
int realSize = size * cIntRetinaFactor();
#ifndef OS_MAC_OLD
auto result = QImage(realSize, realSize, QImage::Format::Format_Grayscale8);

View File

@@ -63,11 +63,15 @@ bool setPaletteColor(QLatin1String name, uchar r, uchar g, uchar b, uchar a);
void startManager();
void stopManager();
QImage colorizeImage(const QImage &src, const color &c, const QRect &r);
QImage colorizeImage(const QImage &src, QColor c, const QRect &r);
inline QImage colorizeImage(const QImage &src, const color &c, const QRect &r) {
return colorizeImage(src, c->c, r);
}
namespace internal {
QImage createCircleMask(int size, const QColor &bg, const QColor &fg);
QImage createCircleMask(int size, QColor bg, QColor fg);
} // namespace internal

View File

@@ -44,7 +44,7 @@ void destroyColors() {
Color::Color(const Color &c) : ptr(c.owner ? new ColorData(*c.ptr) : c.ptr), owner(c.owner) {
}
Color::Color(const QColor &c) : owner(false) {
Color::Color(QColor c) : owner(false) {
init(c.red(), c.green(), c.blue(), c.alpha());
}
@@ -81,7 +81,7 @@ Color::~Color() {
ColorData::ColorData(uchar r, uchar g, uchar b, uchar a) : c(int(r), int(g), int(b), int(a)), p(c), b(c) {
}
void ColorData::set(const QColor &color) {
void ColorData::set(QColor color) {
c = color;
p = QPen(color);
b = QBrush(color);

View File

@@ -31,12 +31,12 @@ public:
Color(Qt::Initialization = Qt::Uninitialized) {
}
Color(const Color &c);
explicit Color(const QColor &c);
explicit Color(QColor c);
Color(uchar r, uchar g, uchar b, uchar a = 255);
Color &operator=(const Color &c);
~Color();
void set(const QColor &newv);
void set(QColor newv);
void set(uchar r, uchar g, uchar b, uchar a = 255);
operator const QBrush &() const;
@@ -79,7 +79,7 @@ public:
private:
ColorData(uchar r, uchar g, uchar b, uchar a);
void set(const QColor &c);
void set(QColor c);
friend class Color;
@@ -102,12 +102,26 @@ inline Color::operator const QPen &() const {
} // namespace internal
inline QColor interpolate(QColor a, QColor b, float64 opacity_b) {
auto bOpacity = static_cast<int>(opacity_b * 255), aOpacity = (255 - bOpacity);
return {
(a.red() * aOpacity + b.red() * bOpacity + 1) >> 8,
(a.green() * aOpacity + b.green() * bOpacity + 1) >> 8,
(a.blue() * aOpacity + b.blue() * bOpacity + 1) >> 8,
(a.alpha() * aOpacity + b.alpha() * bOpacity + 1) >> 8
};
}
inline QColor interpolate(const style::internal::Color &a, QColor b, float64 opacity_b) {
return interpolate(a->c, b, opacity_b);
}
inline QColor interpolate(QColor a, const style::internal::Color &b, float64 opacity_b) {
return interpolate(a, b->c, opacity_b);
}
inline QColor interpolate(const style::internal::Color &a, const style::internal::Color &b, float64 opacity_b) {
QColor result;
result.setRedF((a->c.redF() * (1. - opacity_b)) + (b->c.redF() * opacity_b));
result.setGreenF((a->c.greenF() * (1. - opacity_b)) + (b->c.greenF() * opacity_b));
result.setBlueF((a->c.blueF() * (1. - opacity_b)) + (b->c.blueF() * opacity_b));
return result;
return interpolate(a->c, b->c, opacity_b);
}
} // namespace style

View File

@@ -25,11 +25,13 @@ namespace style {
namespace internal {
namespace {
uint32 colorKey(const QColor &c) {
uint32 colorKey(QColor c) {
return (((((uint32(c.red()) << 8) | uint32(c.green())) << 8) | uint32(c.blue())) << 8) | uint32(c.alpha());
}
using IconMasks = QMap<const IconMask*, QImage>;
using IconPixmaps = QMap<QPair<const IconMask*, uint32>, QPixmap>;
NeverFreedPointer<IconMasks> iconMasks;
NeverFreedPointer<IconPixmaps> iconPixmaps;
inline int pxAdjust(int value, int scale) {
@@ -39,8 +41,9 @@ inline int pxAdjust(int value, int scale) {
return qFloor((value * scale / 4.) + 0.1);
}
QPixmap createIconPixmap(const IconMask *mask, const Color &color) {
QImage createIconMask(const IconMask *mask) {
auto maskImage = QImage::fromData(mask->data(), mask->size(), "PNG");
maskImage.setDevicePixelRatio(cRetinaFactor());
t_assert(!maskImage.isNull());
// images are layouted like this:
@@ -64,9 +67,11 @@ QPixmap createIconPixmap(const IconMask *mask, const Color &color) {
}
}
}
auto finalImage = colorizeImage(maskImage, color, r);
finalImage.setDevicePixelRatio(cRetinaFactor());
return App::pixmapFromImageInPlace(std_::move(finalImage));
return maskImage.copy(r);
}
QImage createIconImage(const QImage &mask, QColor color) {
return colorizeImage(mask, color, QRect(0, 0, mask.width(), mask.height()));
}
} // namespace
@@ -119,6 +124,29 @@ void MonoIcon::fill(QPainter &p, const QRect &rect) const {
}
}
void MonoIcon::paint(QPainter &p, const QPoint &pos, int outerw, QColor colorOverride) const {
int w = width(), h = height();
QPoint fullOffset = pos + offset();
int partPosX = rtl() ? (outerw - fullOffset.x() - w) : fullOffset.x();
int partPosY = fullOffset.y();
ensureLoaded();
if (_pixmap.isNull()) {
p.fillRect(partPosX, partPosY, w, h, colorOverride);
} else {
p.drawImage(partPosX, partPosY, createIconImage(_maskImage, colorOverride));
}
}
void MonoIcon::fill(QPainter &p, const QRect &rect, QColor colorOverride) const {
ensureLoaded();
if (_pixmap.isNull()) {
p.fillRect(rect, colorOverride);
} else {
p.drawImage(rect, createIconImage(_maskImage, colorOverride), QRect(0, 0, _pixmap.width(), _pixmap.height()));
}
}
void MonoIcon::ensureLoaded() const {
if (_size.isValid()) {
return;
@@ -155,34 +183,24 @@ void MonoIcon::ensureLoaded() const {
t_assert(!"Bad data in generated icon!");
}
} else {
if (_owningPixmap) {
_pixmap = createIconPixmap(_mask, _color);
} else {
iconPixmaps.createIfNull();
auto key = qMakePair(_mask, colorKey(_color->c));
auto i = iconPixmaps->constFind(key);
if (i == iconPixmaps->cend()) {
i = iconPixmaps->insert(key, createIconPixmap(_mask, _color));
}
_pixmap = i.value();
iconMasks.createIfNull();
auto i = iconMasks->constFind(_mask);
if (i == iconMasks->cend()) {
i = iconMasks->insert(_mask, createIconMask(_mask));
}
_maskImage = i.value();
iconPixmaps.createIfNull();
auto key = qMakePair(_mask, colorKey(_color->c));
auto j = iconPixmaps->constFind(key);
if (j == iconPixmaps->cend()) {
j = iconPixmaps->insert(key, App::pixmapFromImageInPlace(createIconImage(_maskImage, _color->c)));
}
_pixmap = j.value();
_size = _pixmap.size() / cIntRetinaFactor();
}
}
MonoIcon::MonoIcon(const IconMask *mask, const Color &color, QPoint offset, OwningPixmapTag)
: _mask(mask)
, _color(color)
, _offset(offset)
, _owningPixmap(true) {
}
void Icon::paint(QPainter &p, const QPoint &pos, int outerw) const {
for_const (auto &part, _parts) {
part.paint(p, pos, outerw);
}
}
void Icon::fill(QPainter &p, const QRect &rect) const {
if (_parts.isEmpty()) return;
@@ -194,6 +212,17 @@ void Icon::fill(QPainter &p, const QRect &rect) const {
}
}
void Icon::fill(QPainter &p, const QRect &rect, QColor colorOverride) const {
if (_parts.isEmpty()) return;
auto partSize = _parts.at(0).size();
for_const (auto &part, _parts) {
t_assert(part.offset() == QPoint(0, 0));
t_assert(part.size() == partSize);
part.fill(p, rect, colorOverride);
}
}
int Icon::width() const {
if (_width < 0) {
_width = 0;
@@ -216,6 +245,7 @@ int Icon::height() const {
void destroyIcons() {
iconPixmaps.clear();
iconMasks.clear();
}
} // namespace internal

View File

@@ -55,45 +55,31 @@ public:
QSize size() const;
QPoint offset() const;
void paint(QPainter &p, const QPoint &pos, int outerw) const;
void fill(QPainter &p, const QRect &rect) const;
MonoIcon clone(const Color &color) const {
return MonoIcon(_mask, color ? color : _color, _offset, OwningPixmapTag());
}
void paint(QPainter &p, const QPoint &pos, int outerw, QColor colorOverride) const;
void fill(QPainter &p, const QRect &rect, QColor colorOverride) const;
~MonoIcon() {
}
private:
struct OwningPixmapTag {
};
MonoIcon(const IconMask *mask, const Color &color, QPoint offset, OwningPixmapTag);
void ensureLoaded() const;
const IconMask *_mask = nullptr;
Color _color;
QPoint _offset = { 0, 0 };
mutable QImage _maskImage;
mutable QPixmap _pixmap; // for pixmaps
mutable QSize _size; // for rects
bool _owningPixmap = false;
};
class Icon {
struct ColoredCopy;
public:
Icon(Qt::Initialization) {
}
Icon(const ColoredCopy &makeCopy) {
_parts.reserve(makeCopy.copyFrom._parts.size());
auto colorIt = makeCopy.colors.cbegin(), colorsEnd = makeCopy.colors.cend();
for_const (auto &part, makeCopy.copyFrom._parts) {
auto newPart = part.clone((colorIt == colorsEnd) ? Color(Qt::Uninitialized) : *(colorIt++));
_parts.push_back(newPart);
}
}
template <typename ... MonoIcons>
Icon(const MonoIcons&... icons) {
@@ -101,14 +87,15 @@ public:
addIcons(icons...);
}
std_::unique_ptr<Icon> clone(const QVector<Color> &colors) {
return std_::make_unique<Icon>(ColoredCopy { *this, colors });
}
bool empty() const {
return _parts.empty();
}
void paint(QPainter &p, const QPoint &pos, int outerw) const;
void paint(QPainter &p, const QPoint &pos, int outerw) const {
for_const (auto &part, _parts) {
part.paint(p, pos, outerw);
}
}
void paint(QPainter &p, int x, int y, int outerw) const {
paint(p, QPoint(x, y), outerw);
}
@@ -116,6 +103,20 @@ public:
paint(p, outer.x() + (outer.width() - width()) / 2, outer.y() + (outer.height() - height()) / 2, outer.x() * 2 + outer.width());
}
void fill(QPainter &p, const QRect &rect) const;
void paint(QPainter &p, const QPoint &pos, int outerw, QColor colorOverride) const {
for_const (auto &part, _parts) {
part.paint(p, pos, outerw, colorOverride);
}
}
void paint(QPainter &p, int x, int y, int outerw, QColor colorOverride) const {
paint(p, QPoint(x, y), outerw, colorOverride);
}
void paintInCenter(QPainter &p, const QRect &outer, QColor colorOverride) const {
paint(p, outer.x() + (outer.width() - width()) / 2, outer.y() + (outer.height() - height()) / 2, outer.x() * 2 + outer.width(), colorOverride);
}
void fill(QPainter &p, const QRect &rect, QColor colorOverride) const;
int width() const;
int height() const;
QSize size() const {
@@ -123,11 +124,6 @@ public:
}
private:
struct ColoredCopy {
const Icon &copyFrom;
const QVector<Color> &colors;
};
template <typename ... MonoIcons>
void addIcons() {
}

View File

@@ -64,8 +64,8 @@ void DropdownMenu::init() {
hide();
}
QAction *DropdownMenu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon) {
return _menu->addAction(text, receiver, member, icon);
QAction *DropdownMenu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon, const style::icon *iconOver) {
return _menu->addAction(text, receiver, member, icon, iconOver);
}
QAction *DropdownMenu::addSeparator() {

View File

@@ -30,7 +30,7 @@ class DropdownMenu : public InnerDropdown {
public:
DropdownMenu(QWidget *parent, const style::DropdownMenu &st = st::defaultDropdownMenu);
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr);
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr, const style::icon *iconOver = nullptr);
QAction *addSeparator();
void clearActions();

View File

@@ -43,10 +43,10 @@ void MediaSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.setOpacity(fadeOpacity());
auto horizontal = isHorizontal();
auto ms = getms();
auto masterOpacity = fadeOpacity();
auto radius = _st.width / 2;
auto disabled = isDisabled();
auto over = getCurrentOverFactor(ms);
@@ -62,16 +62,21 @@ void MediaSlider::paintEvent(QPaintEvent *e) {
auto length = _alwaysDisplayMarker ? (horizontal ? width() : height()) : markerLength;
auto mid = qRound(from + value * length);
auto end = from + length;
auto &activeFg = disabled ? _st.disabledActiveFg : _st.activeFg;
auto &inactiveFg = disabled ? _st.disabledInactiveFg : _st.inactiveFg;
auto activeFg = disabled ? &_st.activeFgDisabled : (over == 1. ? &_st.activeFgOver : (over == 0. ? &_st.activeFg : nullptr));
auto inactiveFg = disabled ? &_st.inactiveFgDisabled : (over == 1. ? &_st.inactiveFgOver : (over == 0. ? &_st.inactiveFg : nullptr));
auto activeFgOver = activeFg ? QColor() : style::interpolate(_st.activeFg, _st.activeFgOver, over);
auto inactiveFgOver = inactiveFg ? QColor() : style::interpolate(_st.inactiveFg, _st.inactiveFgOver, over);
if (mid > from) {
auto fromClipRect = horizontal ? QRect(0, 0, mid, height()) : QRect(0, 0, width(), mid);
auto fromRect = horizontal
? QRect(from, (height() - _st.width) / 2, mid + radius - from, _st.width)
: QRect((width() - _st.width) / 2, from, _st.width, mid + radius - from);
p.setClipRect(fromClipRect);
p.setOpacity(masterOpacity * (over * _st.activeOpacity + (1. - over) * _st.inactiveOpacity));
p.setBrush(horizontal ? activeFg : inactiveFg);
if (auto brush = (horizontal ? activeFg : inactiveFg)) {
p.setBrush(*brush);
} else {
p.setBrush(horizontal ? activeFgOver : inactiveFgOver);
}
p.drawRoundedRect(fromRect, radius, radius);
}
if (end > mid) {
@@ -80,8 +85,11 @@ void MediaSlider::paintEvent(QPaintEvent *e) {
? QRect(mid - radius, (height() - _st.width) / 2, end - (mid - radius), _st.width)
: QRect((width() - _st.width) / 2, mid - radius, _st.width, end - (mid - radius));
p.setClipRect(endClipRect);
p.setOpacity(masterOpacity);
p.setBrush(horizontal ? inactiveFg : activeFg);
if (auto brush = (horizontal ? inactiveFg : activeFg)) {
p.setBrush(*brush);
} else {
p.setBrush(horizontal ? inactiveFgOver : activeFgOver);
}
p.drawRoundedRect(endRect, radius, radius);
}
auto markerSizeRatio = disabled ? 0. : (_alwaysDisplayMarker ? 1. : over);
@@ -94,8 +102,11 @@ void MediaSlider::paintEvent(QPaintEvent *e) {
auto remove = static_cast<int>(((1. - markerSizeRatio) * size) / 2.);
if (remove * 2 < size) {
p.setClipRect(rect());
p.setOpacity(masterOpacity * _st.activeOpacity);
p.setBrush(activeFg);
if (activeFg) {
p.setBrush(*activeFg);
} else {
p.setBrush(activeFgOver);
}
p.drawEllipse(seekButton.marginsRemoved(QMargins(remove, remove, remove, remove)));
}
}

View File

@@ -49,18 +49,19 @@ void Menu::init() {
setAttribute(Qt::WA_OpaquePaintEvent);
}
QAction *Menu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon) {
QAction *Menu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon, const style::icon *iconOver) {
auto action = new QAction(text, this);
connect(action, SIGNAL(triggered(bool)), receiver, member, Qt::QueuedConnection);
return addAction(action, icon);
return addAction(action, icon, iconOver);
}
QAction *Menu::addAction(QAction *action, const style::icon *icon) {
QAction *Menu::addAction(QAction *action, const style::icon *icon, const style::icon *iconOver) {
connect(action, SIGNAL(changed()), this, SLOT(actionChanged()));
_actions.push_back(action);
ActionData data;
data.icon = icon;
data.iconOver = iconOver ? iconOver : icon;
data.hasSubmenu = (action->menu() != nullptr);
_actionsData.push_back(data);
@@ -167,10 +168,8 @@ void Menu::paintEvent(QPaintEvent *e) {
} else {
auto enabled = action->isEnabled(), selected = (i == _selected && enabled);
p.fillRect(0, 0, width(), actionHeight, selected ? _st.itemBgOver : _st.itemBg);
if (data.icon) {
p.setOpacity(selected ? _st.itemIconOverOpacity : _st.itemIconOpacity);
data.icon->paint(p, _st.itemIconPosition, width());
p.setOpacity(1.);
if (auto icon = (selected ? data.iconOver : data.icon)) {
icon->paint(p, _st.itemIconPosition, width());
}
p.setPen(selected ? _st.itemFgOver : (enabled ? _st.itemFg : _st.itemFgDisabled));
p.drawTextLeft(_st.itemPadding.left(), _st.itemPadding.top(), width(), data.text);

View File

@@ -31,7 +31,7 @@ public:
Menu(QWidget *parent, const style::Menu &st = st::defaultMenu);
Menu(QWidget *parent, QMenu *menu, const style::Menu &st = st::defaultMenu);
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr);
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr, const style::icon *iconOver = nullptr);
QAction *addSeparator();
void clearActions();
@@ -92,7 +92,7 @@ private:
// Returns the new width.
int processAction(QAction *action, int index, int width);
QAction *addAction(QAction *a, const style::icon *icon = nullptr);
QAction *addAction(QAction *a, const style::icon *icon = nullptr, const style::icon *iconOver = nullptr);
void setSelected(int selected);
void clearMouseSelection();
@@ -115,6 +115,7 @@ private:
QString text;
QString shortcut;
const style::icon *icon = nullptr;
const style::icon *iconOver = nullptr;
};
using ActionsData = QList<ActionData>;

View File

@@ -80,8 +80,8 @@ void PopupMenu::handleMenuResize() {
_inner = QRect(_padding.left(), _padding.top(), width() - _padding.left() - _padding.right(), height() - _padding.top() - _padding.bottom());
}
QAction *PopupMenu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon) {
return _menu->addAction(text, receiver, member, icon);
QAction *PopupMenu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon, const style::icon *iconOver) {
return _menu->addAction(text, receiver, member, icon, iconOver);
}
QAction *PopupMenu::addSeparator() {

View File

@@ -28,7 +28,7 @@ public:
PopupMenu(const style::PopupMenu &st = st::defaultPopupMenu);
PopupMenu(QMenu *menu, const style::PopupMenu &st = st::defaultPopupMenu);
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr);
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr, const style::icon *iconOver = nullptr);
QAction *addSeparator();
void clearActions();

View File

@@ -31,12 +31,11 @@ IconButton {
width: pixels;
height: pixels;
opacity: double;
overOpacity: double;
icon: icon;
iconOver: icon;
iconPosition: point;
downIconPosition: point;
iconPositionDown: point;
duration: int;
}
@@ -52,7 +51,7 @@ MaskButton {
iconBgOver: color;
iconPosition: point;
downIconPosition: point;
iconPositionDown: point;
duration: int;
}
@@ -61,10 +60,10 @@ MediaSlider {
width: pixels;
activeFg: color;
inactiveFg: color;
disabledActiveFg: color;
disabledInactiveFg: color;
activeOpacity: double;
inactiveOpacity: double;
activeFgOver: color;
inactiveFgOver: color;
activeFgDisabled: color;
inactiveFgDisabled: color;
seekSize: size;
duration: int;
}
@@ -137,8 +136,6 @@ Menu {
itemFgShortcutDisabled: color;
itemPadding: margins;
itemIconPosition: point;
itemIconOpacity: double;
itemIconOverOpacity: double;
itemFont: font;
separatorPadding: margins;
@@ -184,15 +181,9 @@ defaultLabelSimple: LabelSimple {
textFg: windowTextFg;
}
defaultIconButton: IconButton {
opacity: 0.78;
overOpacity: 1.;
duration: 150;
}
defaultMaskButton: MaskButton {
iconPosition: point(-1px, -1px);
downIconPosition: point(-1px, -1px);
iconPositionDown: point(-1px, -1px);
duration: 150;
}
@@ -223,8 +214,6 @@ defaultMenu: Menu {
itemFgShortcutOver: #7c99b2;
itemFgShortcutDisabled: #cccccc;
itemIconPosition: point(0px, 0px);
itemIconOpacity: 1.;
itemIconOverOpacity: 1.;
itemPadding: margins(17px, 8px, 17px, 7px);
itemFont: normalFont;