Skip to content

Commit 8c34ec0

Browse files
authored
Button: add property icon-size (#9279)
It's nice that the default icon size comes from the style, but sometimes the user wants a big button with a big icon. Tested in all 5 styles, with PNG and SVG, with and without icon-size set. ChangeLog: Added `icon-size` property to Button
1 parent f2aa489 commit 8c34ec0

File tree

8 files changed

+48
-12
lines changed

8 files changed

+48
-12
lines changed

docs/astro/src/content/docs/reference/std-widgets/basic-widgets/button.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ Set to true when the button has keyboard focus
6464
The image to show in the button. Note that not all styles support drawing icons.
6565
</SlintProperty>
6666

67+
### icon-size
68+
<SlintProperty propName="icon-size" typeName="length">
69+
The size of the icon shown in the button. The default value depends on the style. The button will grow if needed to accommodate for large icon sizes.
70+
</SlintProperty>
71+
6772
### pressed
6873
<SlintProperty propName="pressed" typeName="bool" defaultValue="false" propertyVisibility="out">
6974
Set to true when the button is pressed.

internal/backends/qt/qt_widgets/button.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// cSpell: ignore qstyle unshade
55

66
use super::*;
7+
use i_slint_core::graphics::euclid;
78

89
#[allow(nonstandard_style)]
910
#[allow(unused)]
@@ -107,6 +108,7 @@ type ActualStandardButtonKind = Option<StandardButtonKind>;
107108
pub struct NativeButton {
108109
pub text: Property<SharedString>,
109110
pub icon: Property<i_slint_core::graphics::Image>,
111+
pub icon_size: Property<LogicalLength>,
110112
pub pressed: Property<bool>,
111113
pub has_hover: Property<bool>,
112114
pub checkable: Property<bool>,
@@ -166,7 +168,9 @@ impl NativeButton {
166168
Some(StandardButtonKind::Retry) => QStyle_StandardPixmap_SP_DialogRetryButton,
167169
Some(StandardButtonKind::Ignore) => QStyle_StandardPixmap_SP_DialogIgnoreButton,
168170
None => {
169-
return crate::qt_window::image_to_pixmap((&self.icon()).into(), None)
171+
let icon_size = self.icon_size().get().round() as u32;
172+
let source_size = Some(euclid::Size2D::new(icon_size, icon_size));
173+
return crate::qt_window::image_to_pixmap((&self.icon()).into(), source_size)
170174
.unwrap_or_default();
171175
}
172176
};
@@ -195,7 +199,19 @@ impl Item for NativeButton {
195199
let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);
196200
self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as "void*"] -> SlintTypeErasedWidgetPtr as "std::unique_ptr<SlintTypeErasedWidget>" {
197201
return make_unique_animated_widget<QPushButton>(animation_tracker_property_ptr);
198-
}})
202+
}});
203+
let widget_ptr: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);
204+
let icon_size = unsafe {
205+
cpp!([widget_ptr as "QWidget*" ] -> i32 as "int"
206+
{
207+
ensure_initialized();
208+
return qApp->style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget_ptr);
209+
})
210+
};
211+
Self::FIELD_OFFSETS
212+
.icon_size
213+
.apply_pin(self)
214+
.set(LogicalLength::new(icon_size as i_slint_core::Coord));
199215
}
200216

201217
fn layout_info(
@@ -207,10 +223,12 @@ impl Item for NativeButton {
207223
let standard_button_kind = self.actual_standard_button_kind();
208224
let mut text: qttypes::QString = self.actual_text(standard_button_kind);
209225
let icon: qttypes::QPixmap = self.actual_icon(standard_button_kind);
226+
let icon_size = self.icon_size().get() as i32;
210227
let widget_ptr: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);
211228
let size = cpp!(unsafe [
212229
mut text as "QString",
213230
icon as "QPixmap",
231+
icon_size as "int",
214232
widget_ptr as "QWidget*"
215233
] -> qttypes::QSize as "QSize" {
216234
ensure_initialized();
@@ -220,11 +238,10 @@ impl Item for NativeButton {
220238
option.rect = option.fontMetrics.boundingRect(text);
221239
option.text = std::move(text);
222240
option.icon = icon;
223-
auto iconSize = qApp->style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget_ptr);
224-
option.iconSize = QSize(iconSize, iconSize);
241+
option.iconSize = QSize(icon_size, icon_size);
225242
if (!icon.isNull()) {
226-
option.rect.setHeight(qMax(option.rect.height(), iconSize));
227-
option.rect.setWidth(option.rect.width() + 4 + iconSize);
243+
option.rect.setHeight(qMax(option.rect.height(), icon_size));
244+
option.rect.setWidth(option.rect.width() + 4 + icon_size);
228245
}
229246
return qApp->style()->sizeFromContents(QStyle::CT_PushButton, &option, option.rect.size(), widget_ptr);
230247
});
@@ -348,6 +365,7 @@ impl Item for NativeButton {
348365
let has_focus = this.has_focus();
349366
let has_hover = this.has_hover();
350367
let primary = this.primary();
368+
let icon_size = this.icon_size().get().round() as i32;
351369
let colorize_icon = this.colorize_icon();
352370

353371
cpp!(unsafe [
@@ -362,6 +380,7 @@ impl Item for NativeButton {
362380
has_focus as "bool",
363381
has_hover as "bool",
364382
primary as "bool",
383+
icon_size as "int",
365384
colorize_icon as "bool",
366385
dpr as "float",
367386
initial_state as "int"
@@ -429,8 +448,7 @@ impl Item for NativeButton {
429448
} else {
430449
option.icon = icon;
431450
}
432-
auto iconSize = qApp->style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, nullptr);
433-
option.iconSize = QSize(iconSize, iconSize);
451+
option.iconSize = QSize(icon_size, icon_size);
434452
option.rect = QRect(QPoint(), size / dpr);
435453

436454
qApp->style()->drawControl(QStyle::CE_PushButton, &option, painter->get(), widget);

internal/compiler/builtins.slint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ export component NativeButton {
567567
out property <bool> has-focus;
568568
in property <bool> primary;
569569
in property <bool> colorize-icon;
570+
in property <length> icon-size;
570571
callback clicked;
571572
in property <bool> enabled: true;
572573
in property <StandardButtonKind> standard-button-kind;

internal/compiler/widgets/cosmic/button.slint

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { StateLayer } from "components.slint";
77
export component Button {
88
in property <string> text;
99
in property <image> icon;
10+
in property <length> icon-size: 20px;
1011
in property <bool> primary;
1112
in property <bool> enabled <=> state-layer.enabled;
1213
in property <bool> checkable;
@@ -55,7 +56,8 @@ export component Button {
5556
if (root.icon.width > 0 && root.icon.height > 0) : Image {
5657
y: (parent.height - self.height) / 2;
5758
source <=> root.icon;
58-
width: 20px;
59+
width: root.icon-size;
60+
min-height: root.icon-size;
5961
colorize: root.colorize-icon ? root.text-color : transparent;
6062
}
6163

internal/compiler/widgets/cupertino/button.slint

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { FocusBorder } from "components.slint";
77
export component Button {
88
in property <string> text;
99
in property <image> icon;
10+
in property <length> icon-size: 13px;
1011
in property <bool> primary;
1112
in property <bool> enabled <=> i-touch-area.enabled;
1213
in property <bool> checkable;
@@ -118,7 +119,8 @@ export component Button {
118119
if (root.icon.width > 0 && root.icon.height > 0) : Image {
119120
y: (parent.height - self.height) / 2;
120121
source <=> root.icon;
121-
width: 13px;
122+
width: root.icon-size;
123+
min-height: root.icon-size;
122124
opacity: root.enabled ? 1 : 0.5;
123125
colorize: root.colorize-icon ? root.text-color : transparent;
124126
}

internal/compiler/widgets/fluent/button.slint

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { FocusBorder } from "components.slint";
77
export component Button {
88
in property <string> text;
99
in property <image> icon;
10+
in property <length> icon-size: 20px;
1011
in property <bool> primary;
1112
in property <bool> enabled <=> i-touch-area.enabled;
1213
in property <bool> checkable;
@@ -76,7 +77,8 @@ export component Button {
7677
if (root.icon.width > 0 && root.icon.height > 0) : Image {
7778
y: (parent.height - self.height) / 2;
7879
source <=> root.icon;
79-
width: 20px;
80+
width: root.icon-size;
81+
min-height: root.icon-size;
8082
colorize: root.colorize-icon ? root.text-color : transparent;
8183
}
8284

internal/compiler/widgets/material/button.slint

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { MaterialFontSettings, MaterialPalette, Elevation } from "styling.slint"
77
component MaterialButtonBase {
88
in property <string> text;
99
in property <image> icon;
10+
in property <length> icon-size: 24px;
1011
in property <length> border-radius <=> state-layer.border-radius;
1112
in property <bool> checkable;
1213
in property <brush> text-color;
@@ -39,10 +40,13 @@ component MaterialButtonBase {
3940
spacing: 8px;
4041
padding-left: root.layout-padding-left;
4142
padding-right: root.layout-padding-right;
43+
padding-top: 5px;
44+
padding-bottom: 5px;
4245

4346
if root.icon.width > 0 && root.icon.height > 0: Image {
4447
source <=> root.icon;
45-
width: 24px;
48+
width: root.icon-size;
49+
min-height: root.icon-size;
4650
opacity: root.text-opacity;
4751
colorize: root.colorize-icon ? root.text-color : transparent;
4852
}
@@ -70,6 +74,7 @@ export component Button {
7074
in property <bool> enabled <=> base.enabled;
7175
in property <bool> checkable;
7276
in property <image> icon <=> base.icon;
77+
in property <length> icon-size <=> base.icon-size;
7378
in property <bool> primary;
7479
in property <bool> colorize-icon <=> base.colorize-icon;
7580
out property <bool> has-focus: base.has-focus;

internal/compiler/widgets/qt/button.slint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
export component Button {
55
in property <string> text <=> native.text;
66
in property <image> icon <=> native.icon;
7+
in property <length> icon_size <=> native.icon_size;
78
in property <bool> enabled <=> native.enabled;
89
in property <bool> checkable <=> native.checkable;
910
in property <bool> primary <=> native.primary;

0 commit comments

Comments
 (0)