Skip to content

Commit

Permalink
chore: dci icon contorl support animation
Browse files Browse the repository at this point in the history
update checkbox / radio / switch dci icons

switch: disable hover and set static image before after play
animation(use timer for now)
  • Loading branch information
kegechen committed Jul 30, 2024
1 parent bee7ec4 commit fd96858
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 41 deletions.
66 changes: 40 additions & 26 deletions qt6/src/qml/Switch.qml
Original file line number Diff line number Diff line change
Expand Up @@ -20,43 +20,57 @@ T.Switch {
topPadding: DS.Style.control.vPadding
bottomPadding: DS.Style.control.vPadding
spacing: DS.Style.control.spacing
D.ColorSelector.hovered: false // disable hover ==> normal animation

indicator: Rectangle {
indicator: D.DciIcon {
id: handle
implicitWidth: DS.Style.switchButton.indicatorWidth
implicitHeight: DS.Style.switchButton.indicatorHeight

x: text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
y: control.topPadding + (control.availableHeight - height) / 2
radius: DS.Style.control.radius
color: control.D.ColorSelector.backgroundColor
opacity: control.D.ColorSelector.controlState === D.DTK.DisabledState ? 0.4 : 1

D.DciIcon {
id: handle
x: Math.max(0, Math.min(parent.width - width, control.visualPosition * parent.width - (width / 2)))
y: (parent.height - height) / 2
width: DS.Style.switchButton.handleWidth
height: DS.Style.switchButton.handleHeight
sourceSize: Qt.size(DS.Style.switchButton.handleWidth, DS.Style.switchButton.handleHeight)
name: DS.Style.switchButton.iconName
opacity: control.D.ColorSelector.controlState === D.DTK.DisabledState && control.checked ? 0.4 : 1
palette {
highlight: control.checked ? control.palette.highlight : control.D.ColorSelector.handleColor
highlightForeground: control.palette.highlightedText
foreground: control.palette.windowText
background: control.palette.window
}
mode: control.D.ColorSelector.controlState
theme: control.D.ColorSelector.controlTheme
fallbackToQIcon: false
width: DS.Style.switchButton.handleWidth
height: DS.Style.switchButton.handleHeight
sourceSize: Qt.size(DS.Style.switchButton.indicatorWidth, DS.Style.switchButton.indicatorWidth)
name: control.checked ? "switch_on_static" : "switch_off_static"
opacity: control.D.ColorSelector.controlState === D.DTK.DisabledState && control.checked ? 0.4 : 1
palette {
highlight: control.checked ? control.palette.highlight : control.D.ColorSelector.handleColor
highlightForeground: control.palette.highlightedText
foreground: control.palette.windowText
background: control.palette.window
}
mode: control.D.ColorSelector.controlState
theme: control.D.ColorSelector.controlTheme
fallbackToQIcon: false
}

Behavior on x {
enabled: !control.down
SmoothedAnimation { velocity: 200 }
}
Timer {
id: toggletimer
interval: 200
onTriggered: {
control.toggle()
handle.name = control.checked ? "switch_on_static" : "switch_off_static"
}
}

function palyAndSetImage() {
handle.name = !control.checked ? "switch_on" : "switch_off"
handle.play(D.DTK.NormalState)
toggletimer.start();
}

Keys.onSpacePressed: palyAndSetImage()
Keys.onEnterPressed: palyAndSetImage()
Keys.onReturnPressed: palyAndSetImage()

MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: palyAndSetImage()
}

contentItem: Label {
leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
Expand Down
5 changes: 4 additions & 1 deletion src/dtkdeclarative_assets.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@
<file alias="built-in-icons/slider_point_left.dci">icons/bloom/slider_point_left.dci</file>
<file alias="built-in-icons/slider_round_hor.dci">icons/bloom/slider_round_hor.dci</file>
<file alias="built-in-icons/slider_round_ver.dci">icons/bloom/slider_round_ver.dci</file>
<file alias="built-in-icons/switch_button.dci">icons/bloom/switch_button.dci</file>
<file alias="built-in-icons/switch_on.dci">icons/bloom/switch_on.dci</file>
<file alias="built-in-icons/switch_off.dci">icons/bloom/switch_off.dci</file>
<file alias="built-in-icons/switch_on_static.dci">icons/bloom/switch_on_static.dci</file>
<file alias="built-in-icons/switch_off_static.dci">icons/bloom/switch_off_static.dci</file>
<file alias="built-in-icons/slider_point_up.dci">icons/bloom/slider_point_up.dci</file>
<file alias="built-in-icons/checkbox_mix.dci">icons/bloom/checkbox_mix.dci</file>
<file alias="built-in-icons/checkbox_checked.dci">icons/bloom/checkbox_checked.dci</file>
Expand Down
Binary file modified src/icons/bloom/checkbox_checked.dci
Binary file not shown.
Binary file modified src/icons/bloom/checkbox_unchecked.dci
Binary file not shown.
Binary file modified src/icons/bloom/radio_checked.dci
Binary file not shown.
Binary file modified src/icons/bloom/radio_unchecked.dci
Binary file not shown.
Binary file added src/icons/bloom/switch_off.dci
Binary file not shown.
Binary file added src/icons/bloom/switch_off_static.dci
Binary file not shown.
Binary file added src/icons/bloom/switch_on.dci
Binary file not shown.
Binary file added src/icons/bloom/switch_on_static.dci
Binary file not shown.
140 changes: 126 additions & 14 deletions src/private/dquickdciiconimage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,47 @@ static QString appIconThemeName()
return DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName();
}

static QString findDciIconPath(const QString &iconName, const QString &themeName)
{
QString iconPath;
auto cached = DIconTheme::cached();

if (cached) {
iconPath = cached->findDciIconFile(iconName, themeName);
} else {
iconPath = DIconTheme::findDciIconFile(iconName, themeName);
}
return iconPath;
}

static DDciIcon::Mode controlState2DciMode(int state)
{
DDciIcon::Mode dcimode = DDciIcon::Normal;
switch (state) {
case DQMLGlobalObject::NormalState:
dcimode = DDciIcon::Normal;
break;
case DQMLGlobalObject::DisabledState:
dcimode = DDciIcon::Disabled;
break;
case DQMLGlobalObject::HoveredState:
dcimode = DDciIcon::Hover;
break;
case DQMLGlobalObject::PressedState:
dcimode = DDciIcon::Pressed;
break;
default:
break;
}

return dcimode;
}

static inline DDciIcon::Theme dciTheme(DGuiApplicationHelper::ColorType type)
{
return type == DGuiApplicationHelper::DarkType ? DDciIcon::Dark : DDciIcon::Light;
}

DQuickDciIconImageItemPrivate::DQuickDciIconImageItemPrivate(DQuickDciIconImagePrivate *pqq)
: parentPriv(pqq)
{
Expand All @@ -31,11 +72,27 @@ void DQuickDciIconImageItemPrivate::maybeUpdateUrl()
return DQuickIconImagePrivate::maybeUpdateUrl();
}

QUrl url;
url.setScheme(QLatin1String("image"));
url.setHost(QLatin1String("dtk.dci.icon"));
url.setQuery(getUrlQuery());
q->setSource(url);
QString iconPath = findDciIconPath(parentPriv->imageItem->name(), appIconThemeName());
if (iconPath.isEmpty())
return DQuickIconImagePrivate::maybeUpdateUrl();

updatePlayer();

if (player)
player->setMode(controlState2DciMode(parentPriv->mode));
}

void DQuickDciIconImageItemPrivate::play(int mode)
{
Q_Q(DQuickIconImage);
if (parentPriv->imageItem->name().isEmpty() || iconType != ThemeIconName) {
return;
}

updatePlayer();

if (player)
player->play(controlState2DciMode(mode));
}

QUrlQuery DQuickDciIconImageItemPrivate::getUrlQuery()
Expand All @@ -56,6 +113,57 @@ QUrlQuery DQuickDciIconImageItemPrivate::getUrlQuery()
return query;
}

void DQuickDciIconImageItemPrivate::updatePlayerIconSize()
{
if (!player)
return;

int boundingSize = qMax(q_func()->sourceSize().width(), q_func()->sourceSize().height());
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (qApp->testAttribute(Qt::AA_UseHighDpiPixmaps))
#endif
boundingSize = qRound(boundingSize / devicePixelRatio);
player->setIconSize(boundingSize);

}

void DQuickDciIconImageItemPrivate::updatePlayer()
{
if (!player) {
Q_Q(DQuickIconImage);
player = new DDciIconPlayer(parentPriv->imageItem);
QObject::connect(player, &DDciIconPlayer::updated, parentPriv->imageItem, [this](){
parentPriv->imageItem->setImage(player->currentImage());
});
QObject::connect(parentPriv->imageItem, &DQuickIconImage::sourceSizeChanged, player, [this](){
updatePlayerIconSize();
});
}

QString iconPath = findDciIconPath(parentPriv->imageItem->name(), appIconThemeName());

// 防止频繁构造 dciicon
if (iconPathCache != iconPath) {
DDciIcon dciIcon(iconPath);
if (!dciIcon.isNull()) {
player->setIcon(dciIcon);
iconPathCache = iconPath;
}
}

player->setTheme(dciTheme(parentPriv->theme));

DDciIconPalette palette = parentPriv->palette;
if (!parentPriv->palette.foreground().isValid() && q_func()->color().isValid())
palette.setForeground(q_func()->color());

player->setPalette(palette);

updatePlayerIconSize();

player->setDevicePixelRatio(devicePixelRatio);
}

DQuickDciIconImagePrivate::DQuickDciIconImagePrivate(DQuickDciIconImage *qq)
: DObjectPrivate(qq)
, imageItem(new DQuickIconImage(*new DQuickDciIconImageItemPrivate(this), qq))
Expand All @@ -76,6 +184,11 @@ void DQuickDciIconImagePrivate::updateImageSourceUrl()
imageItem->d_func()->maybeUpdateUrl();
}

void DQuickDciIconImagePrivate::play(DQMLGlobalObject::ControlState mode)
{
imageItem->d_func()->play(mode);
}

DQuickDciIconImage::DQuickDciIconImage(QQuickItem *parent)
: QQuickItem(parent)
, DObject(*new DQuickDciIconImagePrivate(this))
Expand Down Expand Up @@ -119,6 +232,13 @@ void DQuickDciIconImage::setMode(DQMLGlobalObject::ControlState mode)
Q_EMIT modeChanged();
}

void DQuickDciIconImage::play(DQMLGlobalObject::ControlState mode)
{
D_D(DQuickDciIconImage);
if (d->imageItem)
d->play(mode);
}

DGuiApplicationHelper::ColorType DQuickDciIconImage::theme() const
{
D_DC(DQuickDciIconImage);
Expand Down Expand Up @@ -226,15 +346,7 @@ Dtk::Quick::DQuickIconImage *DQuickDciIconImage::imageItem() const

bool DQuickDciIconImage::isNull(const QString &iconName)
{
QString iconPath;
auto cached = DIconTheme::cached();

if (cached) {
iconPath = cached->findDciIconFile(iconName, appIconThemeName());
} else {
iconPath = DIconTheme::findDciIconFile(iconName, appIconThemeName());
}
return iconPath.isEmpty();
return findDciIconPath(iconName, appIconThemeName()).isEmpty();
}

DQuickIconAttached *DQuickDciIconImage::qmlAttachedProperties(QObject *object)
Expand Down
1 change: 1 addition & 0 deletions src/private/dquickdciiconimage_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class DQuickDciIconImage : public QQuickItem, DCORE_NAMESPACE::DObject

DQMLGlobalObject::ControlState mode() const;
void setMode(DQMLGlobalObject::ControlState mode);
Q_INVOKABLE void play(DQMLGlobalObject::ControlState mode);

DGuiApplicationHelper::ColorType theme() const;
void setTheme(DGuiApplicationHelper::ColorType theme);
Expand Down
7 changes: 7 additions & 0 deletions src/private/dquickdciiconimage_p_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <dobject_p.h>
#include <DDciIconPalette>
#include <DDciIconPlayer>

DQUICK_BEGIN_NAMESPACE
class DQuickDciIconImageItemPrivate;
Expand All @@ -22,10 +23,15 @@ class DQuickDciIconImageItemPrivate : public DQuickIconImagePrivate
public:
DQuickDciIconImageItemPrivate(DQuickDciIconImagePrivate *pqq);
void maybeUpdateUrl();
void play(int mode);
QUrlQuery getUrlQuery();

void updatePlayer();
void updatePlayerIconSize();
private:
DQuickDciIconImagePrivate *parentPriv;
DDciIconPlayer *player = nullptr;
QString iconPathCache;
};

class DQuickDciIconImagePrivate : public DCORE_NAMESPACE::DObjectPrivate
Expand All @@ -36,6 +42,7 @@ class DQuickDciIconImagePrivate : public DCORE_NAMESPACE::DObjectPrivate
DQuickDciIconImagePrivate(DQuickDciIconImage *qq);
void layout();
void updateImageSourceUrl();
void play(DQMLGlobalObject::ControlState mode);

DDciIconPalette palette;
DQuickIconImage *imageItem;
Expand Down
11 changes: 11 additions & 0 deletions src/private/dquickiconimage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ void DQuickIconImagePrivate::maybeUpdateUrl()
q->setSource(url);
}

void DQuickIconImagePrivate::play(int mode)
{
Q_UNUSED(mode)
}

QUrlQuery DQuickIconImagePrivate::getUrlQuery()
{
QUrlQuery query;
Expand Down Expand Up @@ -316,6 +321,12 @@ void DQuickIconImage::setFallbackSource(const QUrl &newSource)
d->maybeUpdateUrl();
}

void DQuickIconImage::setImage(const QImage &img)
{
D_D(DQuickIconImage);
d->setImage(img);
}

DQuickIconImage::DQuickIconImage(DQuickIconImagePrivate &dd, QQuickItem *parent)
: QQuickImage(dd, parent)
{
Expand Down
1 change: 1 addition & 0 deletions src/private/dquickiconimage_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public Q_SLOTS:
void setMode(Mode mode);
void setColor(const QColor &color);
void setFallbackSource(const QUrl &newSource);
void setImage(const QImage &img);

Q_SIGNALS:
void nameChanged();
Expand Down
1 change: 1 addition & 0 deletions src/private/dquickiconimage_p_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class DQuickIconImagePrivate : public QQuickImagePrivate
public:
void init();
virtual void maybeUpdateUrl();
virtual void play(int mode);
QUrlQuery getUrlQuery();
DQuickIconImage::Mode getIconMode() const;

Expand Down

0 comments on commit fd96858

Please sign in to comment.