i_slint_backend_qt/qt_widgets/
button.rsuse super::*;
#[allow(nonstandard_style)]
#[allow(unused)]
mod standard_button {
pub const QStyle_StandardPixmap_SP_TitleBarMenuButton: QStyle_StandardPixmap = 0;
pub const QStyle_StandardPixmap_SP_TitleBarMinButton: QStyle_StandardPixmap = 1;
pub const QStyle_StandardPixmap_SP_TitleBarMaxButton: QStyle_StandardPixmap = 2;
pub const QStyle_StandardPixmap_SP_TitleBarCloseButton: QStyle_StandardPixmap = 3;
pub const QStyle_StandardPixmap_SP_TitleBarNormalButton: QStyle_StandardPixmap = 4;
pub const QStyle_StandardPixmap_SP_TitleBarShadeButton: QStyle_StandardPixmap = 5;
pub const QStyle_StandardPixmap_SP_TitleBarUnshadeButton: QStyle_StandardPixmap = 6;
pub const QStyle_StandardPixmap_SP_TitleBarContextHelpButton: QStyle_StandardPixmap = 7;
pub const QStyle_StandardPixmap_SP_DockWidgetCloseButton: QStyle_StandardPixmap = 8;
pub const QStyle_StandardPixmap_SP_MessageBoxInformation: QStyle_StandardPixmap = 9;
pub const QStyle_StandardPixmap_SP_MessageBoxWarning: QStyle_StandardPixmap = 10;
pub const QStyle_StandardPixmap_SP_MessageBoxCritical: QStyle_StandardPixmap = 11;
pub const QStyle_StandardPixmap_SP_MessageBoxQuestion: QStyle_StandardPixmap = 12;
pub const QStyle_StandardPixmap_SP_DesktopIcon: QStyle_StandardPixmap = 13;
pub const QStyle_StandardPixmap_SP_TrashIcon: QStyle_StandardPixmap = 14;
pub const QStyle_StandardPixmap_SP_ComputerIcon: QStyle_StandardPixmap = 15;
pub const QStyle_StandardPixmap_SP_DriveFDIcon: QStyle_StandardPixmap = 16;
pub const QStyle_StandardPixmap_SP_DriveHDIcon: QStyle_StandardPixmap = 17;
pub const QStyle_StandardPixmap_SP_DriveCDIcon: QStyle_StandardPixmap = 18;
pub const QStyle_StandardPixmap_SP_DriveDVDIcon: QStyle_StandardPixmap = 19;
pub const QStyle_StandardPixmap_SP_DriveNetIcon: QStyle_StandardPixmap = 20;
pub const QStyle_StandardPixmap_SP_DirOpenIcon: QStyle_StandardPixmap = 21;
pub const QStyle_StandardPixmap_SP_DirClosedIcon: QStyle_StandardPixmap = 22;
pub const QStyle_StandardPixmap_SP_DirLinkIcon: QStyle_StandardPixmap = 23;
pub const QStyle_StandardPixmap_SP_DirLinkOpenIcon: QStyle_StandardPixmap = 24;
pub const QStyle_StandardPixmap_SP_FileIcon: QStyle_StandardPixmap = 25;
pub const QStyle_StandardPixmap_SP_FileLinkIcon: QStyle_StandardPixmap = 26;
pub const QStyle_StandardPixmap_SP_ToolBarHorizontalExtensionButton: QStyle_StandardPixmap = 27;
pub const QStyle_StandardPixmap_SP_ToolBarVerticalExtensionButton: QStyle_StandardPixmap = 28;
pub const QStyle_StandardPixmap_SP_FileDialogStart: QStyle_StandardPixmap = 29;
pub const QStyle_StandardPixmap_SP_FileDialogEnd: QStyle_StandardPixmap = 30;
pub const QStyle_StandardPixmap_SP_FileDialogToParent: QStyle_StandardPixmap = 31;
pub const QStyle_StandardPixmap_SP_FileDialogNewFolder: QStyle_StandardPixmap = 32;
pub const QStyle_StandardPixmap_SP_FileDialogDetailedView: QStyle_StandardPixmap = 33;
pub const QStyle_StandardPixmap_SP_FileDialogInfoView: QStyle_StandardPixmap = 34;
pub const QStyle_StandardPixmap_SP_FileDialogContentsView: QStyle_StandardPixmap = 35;
pub const QStyle_StandardPixmap_SP_FileDialogListView: QStyle_StandardPixmap = 36;
pub const QStyle_StandardPixmap_SP_FileDialogBack: QStyle_StandardPixmap = 37;
pub const QStyle_StandardPixmap_SP_DirIcon: QStyle_StandardPixmap = 38;
pub const QStyle_StandardPixmap_SP_DialogOkButton: QStyle_StandardPixmap = 39;
pub const QStyle_StandardPixmap_SP_DialogCancelButton: QStyle_StandardPixmap = 40;
pub const QStyle_StandardPixmap_SP_DialogHelpButton: QStyle_StandardPixmap = 41;
pub const QStyle_StandardPixmap_SP_DialogOpenButton: QStyle_StandardPixmap = 42;
pub const QStyle_StandardPixmap_SP_DialogSaveButton: QStyle_StandardPixmap = 43;
pub const QStyle_StandardPixmap_SP_DialogCloseButton: QStyle_StandardPixmap = 44;
pub const QStyle_StandardPixmap_SP_DialogApplyButton: QStyle_StandardPixmap = 45;
pub const QStyle_StandardPixmap_SP_DialogResetButton: QStyle_StandardPixmap = 46;
pub const QStyle_StandardPixmap_SP_DialogDiscardButton: QStyle_StandardPixmap = 47;
pub const QStyle_StandardPixmap_SP_DialogYesButton: QStyle_StandardPixmap = 48;
pub const QStyle_StandardPixmap_SP_DialogNoButton: QStyle_StandardPixmap = 49;
pub const QStyle_StandardPixmap_SP_ArrowUp: QStyle_StandardPixmap = 50;
pub const QStyle_StandardPixmap_SP_ArrowDown: QStyle_StandardPixmap = 51;
pub const QStyle_StandardPixmap_SP_ArrowLeft: QStyle_StandardPixmap = 52;
pub const QStyle_StandardPixmap_SP_ArrowRight: QStyle_StandardPixmap = 53;
pub const QStyle_StandardPixmap_SP_ArrowBack: QStyle_StandardPixmap = 54;
pub const QStyle_StandardPixmap_SP_ArrowForward: QStyle_StandardPixmap = 55;
pub const QStyle_StandardPixmap_SP_DirHomeIcon: QStyle_StandardPixmap = 56;
pub const QStyle_StandardPixmap_SP_CommandLink: QStyle_StandardPixmap = 57;
pub const QStyle_StandardPixmap_SP_VistaShield: QStyle_StandardPixmap = 58;
pub const QStyle_StandardPixmap_SP_BrowserReload: QStyle_StandardPixmap = 59;
pub const QStyle_StandardPixmap_SP_BrowserStop: QStyle_StandardPixmap = 60;
pub const QStyle_StandardPixmap_SP_MediaPlay: QStyle_StandardPixmap = 61;
pub const QStyle_StandardPixmap_SP_MediaStop: QStyle_StandardPixmap = 62;
pub const QStyle_StandardPixmap_SP_MediaPause: QStyle_StandardPixmap = 63;
pub const QStyle_StandardPixmap_SP_MediaSkipForward: QStyle_StandardPixmap = 64;
pub const QStyle_StandardPixmap_SP_MediaSkipBackward: QStyle_StandardPixmap = 65;
pub const QStyle_StandardPixmap_SP_MediaSeekForward: QStyle_StandardPixmap = 66;
pub const QStyle_StandardPixmap_SP_MediaSeekBackward: QStyle_StandardPixmap = 67;
pub const QStyle_StandardPixmap_SP_MediaVolume: QStyle_StandardPixmap = 68;
pub const QStyle_StandardPixmap_SP_MediaVolumeMuted: QStyle_StandardPixmap = 69;
pub const QStyle_StandardPixmap_SP_LineEditClearButton: QStyle_StandardPixmap = 70;
pub const QStyle_StandardPixmap_SP_DialogYesToAllButton: QStyle_StandardPixmap = 71;
pub const QStyle_StandardPixmap_SP_DialogNoToAllButton: QStyle_StandardPixmap = 72;
pub const QStyle_StandardPixmap_SP_DialogSaveAllButton: QStyle_StandardPixmap = 73;
pub const QStyle_StandardPixmap_SP_DialogAbortButton: QStyle_StandardPixmap = 74;
pub const QStyle_StandardPixmap_SP_DialogRetryButton: QStyle_StandardPixmap = 75;
pub const QStyle_StandardPixmap_SP_DialogIgnoreButton: QStyle_StandardPixmap = 76;
pub const QStyle_StandardPixmap_SP_RestoreDefaultsButton: QStyle_StandardPixmap = 77;
pub const QStyle_StandardPixmap_SP_CustomBase: QStyle_StandardPixmap = 4026531840;
pub type QStyle_StandardPixmap = ::std::os::raw::c_uint;
}
use i_slint_core::{
input::{FocusEventResult, KeyEventType},
items::StandardButtonKind,
platform::PointerEventButton,
};
use standard_button::*;
type ActualStandardButtonKind = Option<StandardButtonKind>;
#[repr(C)]
#[derive(FieldOffsets, Default, SlintElement)]
#[pin]
pub struct NativeButton {
pub text: Property<SharedString>,
pub icon: Property<i_slint_core::graphics::Image>,
pub pressed: Property<bool>,
pub has_hover: Property<bool>,
pub checkable: Property<bool>,
pub checked: Property<bool>,
pub primary: Property<bool>,
pub has_focus: Property<bool>,
pub clicked: Callback<VoidArg>,
pub enabled: Property<bool>,
pub colorize_icon: Property<bool>,
pub standard_button_kind: Property<StandardButtonKind>,
pub is_standard_button: Property<bool>,
widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,
animation_tracker: Property<i32>,
pub cached_rendering_data: CachedRenderingData,
}
impl NativeButton {
fn actual_standard_button_kind(self: Pin<&Self>) -> ActualStandardButtonKind {
self.is_standard_button().then(|| self.standard_button_kind())
}
fn actual_text(
self: Pin<&Self>,
standard_button_kind: ActualStandardButtonKind,
) -> qttypes::QString {
match standard_button_kind {
Some(StandardButtonKind::Ok) => "OK".into(),
Some(StandardButtonKind::Cancel) => "Cancel".into(),
Some(StandardButtonKind::Apply) => "Apply".into(),
Some(StandardButtonKind::Close) => "Close".into(),
Some(StandardButtonKind::Reset) => "Reset".into(),
Some(StandardButtonKind::Help) => "Help".into(),
Some(StandardButtonKind::Yes) => "Yes".into(),
Some(StandardButtonKind::No) => "No".into(),
Some(StandardButtonKind::Abort) => "Abort".into(),
Some(StandardButtonKind::Retry) => "Retry".into(),
Some(StandardButtonKind::Ignore) => "Ignore".into(),
None => self.text().as_str().into(),
}
}
fn actual_icon(
self: Pin<&Self>,
standard_button_kind: ActualStandardButtonKind,
) -> qttypes::QPixmap {
let style_icon = match standard_button_kind {
Some(StandardButtonKind::Ok) => QStyle_StandardPixmap_SP_DialogOkButton,
Some(StandardButtonKind::Cancel) => QStyle_StandardPixmap_SP_DialogCancelButton,
Some(StandardButtonKind::Apply) => QStyle_StandardPixmap_SP_DialogApplyButton,
Some(StandardButtonKind::Close) => QStyle_StandardPixmap_SP_DialogCloseButton,
Some(StandardButtonKind::Reset) => QStyle_StandardPixmap_SP_DialogResetButton,
Some(StandardButtonKind::Help) => QStyle_StandardPixmap_SP_DialogHelpButton,
Some(StandardButtonKind::Yes) => QStyle_StandardPixmap_SP_DialogYesButton,
Some(StandardButtonKind::No) => QStyle_StandardPixmap_SP_DialogNoButton,
Some(StandardButtonKind::Abort) => QStyle_StandardPixmap_SP_DialogAbortButton,
Some(StandardButtonKind::Retry) => QStyle_StandardPixmap_SP_DialogRetryButton,
Some(StandardButtonKind::Ignore) => QStyle_StandardPixmap_SP_DialogIgnoreButton,
None => {
return crate::qt_window::image_to_pixmap((&self.icon()).into(), None)
.unwrap_or_default();
}
};
let widget_ptr: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);
cpp!(unsafe [style_icon as "QStyle::StandardPixmap", widget_ptr as "QWidget*"] -> qttypes::QPixmap as "QPixmap" {
ensure_initialized();
auto style = qApp->style();
if (!style->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons, nullptr, widget_ptr))
return QPixmap();
return style->standardPixmap(style_icon);
})
}
fn activate(self: Pin<&Self>) {
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(false);
if self.checkable() {
let checked = Self::FIELD_OFFSETS.checked.apply_pin(self);
checked.set(!checked.get());
}
Self::FIELD_OFFSETS.clicked.apply_pin(self).call(&());
}
}
impl Item for NativeButton {
fn init(self: Pin<&Self>, _self_rc: &ItemRc) {
let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);
self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as "void*"] -> SlintTypeErasedWidgetPtr as "std::unique_ptr<SlintTypeErasedWidget>" {
return make_unique_animated_widget<QPushButton>(animation_tracker_property_ptr);
}})
}
fn layout_info(
self: Pin<&Self>,
orientation: Orientation,
_window_adapter: &Rc<dyn WindowAdapter>,
) -> LayoutInfo {
let standard_button_kind = self.actual_standard_button_kind();
let mut text: qttypes::QString = self.actual_text(standard_button_kind);
let icon: qttypes::QPixmap = self.actual_icon(standard_button_kind);
let widget_ptr: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);
let size = cpp!(unsafe [
mut text as "QString",
icon as "QPixmap",
widget_ptr as "QWidget*"
] -> qttypes::QSize as "QSize" {
ensure_initialized();
QStyleOptionButton option;
if (text.isEmpty())
text = "**";
option.rect = option.fontMetrics.boundingRect(text);
option.text = std::move(text);
option.icon = icon;
auto iconSize = qApp->style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget_ptr);
option.iconSize = QSize(iconSize, iconSize);
if (!icon.isNull()) {
option.rect.setHeight(qMax(option.rect.height(), iconSize));
option.rect.setWidth(option.rect.width() + 4 + iconSize);
}
return qApp->style()->sizeFromContents(QStyle::CT_PushButton, &option, option.rect.size(), widget_ptr);
});
let min = match orientation {
Orientation::Horizontal => size.width as f32,
Orientation::Vertical => size.height as f32,
};
LayoutInfo { min, preferred: min, ..LayoutInfo::default() }
}
fn input_event_filter_before_children(
self: Pin<&Self>,
event: MouseEvent,
_window_adapter: &Rc<dyn WindowAdapter>,
_self_rc: &ItemRc,
) -> InputEventFilterResult {
Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(!matches!(event, MouseEvent::Exit));
InputEventFilterResult::ForwardEvent
}
fn input_event(
self: Pin<&Self>,
event: MouseEvent,
_window_adapter: &Rc<dyn WindowAdapter>,
self_rc: &i_slint_core::items::ItemRc,
) -> InputEventResult {
if matches!(event, MouseEvent::Exit) {
Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false);
}
let enabled = self.enabled();
if !enabled {
return InputEventResult::EventIgnored;
}
let was_pressed = self.pressed();
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event {
MouseEvent::Pressed { button, .. } => button == PointerEventButton::Left,
MouseEvent::Exit | MouseEvent::Released { .. } => false,
MouseEvent::Moved { .. } => {
return if was_pressed {
InputEventResult::GrabMouse
} else {
InputEventResult::EventAccepted
}
}
MouseEvent::Wheel { .. } => return InputEventResult::EventIgnored,
});
if let MouseEvent::Released { position, .. } = event {
let geo = self_rc.geometry();
if LogicalRect::new(LogicalPoint::default(), geo.size).contains(position) && was_pressed
{
self.activate();
}
InputEventResult::EventAccepted
} else {
InputEventResult::GrabMouse
}
}
fn key_event(
self: Pin<&Self>,
event: &KeyEvent,
_window_adapter: &Rc<dyn WindowAdapter>,
_self_rc: &ItemRc,
) -> KeyEventResult {
match event.event_type {
KeyEventType::KeyPressed if event.text == " " || event.text == "\n" => {
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(true);
KeyEventResult::EventAccepted
}
KeyEventType::KeyPressed => KeyEventResult::EventIgnored,
KeyEventType::KeyReleased if event.text == " " || event.text == "\n" => {
self.activate();
KeyEventResult::EventAccepted
}
KeyEventType::KeyReleased => KeyEventResult::EventIgnored,
KeyEventType::UpdateComposition | KeyEventType::CommitComposition => {
KeyEventResult::EventIgnored
}
}
}
fn focus_event(
self: Pin<&Self>,
event: &FocusEvent,
_window_adapter: &Rc<dyn WindowAdapter>,
_self_rc: &ItemRc,
) -> FocusEventResult {
if self.enabled() {
Self::FIELD_OFFSETS
.has_focus
.apply_pin(self)
.set(event == &FocusEvent::FocusIn || event == &FocusEvent::WindowReceivedFocus);
FocusEventResult::FocusAccepted
} else {
FocusEventResult::FocusIgnored
}
}
fn_render! { this dpr size painter widget initial_state =>
let down: bool = this.pressed();
let checked: bool = this.checked();
let standard_button_kind = this.actual_standard_button_kind();
let text: qttypes::QString = this.actual_text(standard_button_kind);
let icon: qttypes::QPixmap = this.actual_icon(standard_button_kind);
let enabled = this.enabled();
let has_focus = this.has_focus();
let has_hover = this.has_hover();
let primary = this.primary();
let colorize_icon = this.colorize_icon();
cpp!(unsafe [
painter as "QPainterPtr*",
widget as "QWidget*",
text as "QString",
icon as "QPixmap",
enabled as "bool",
size as "QSize",
down as "bool",
checked as "bool",
has_focus as "bool",
has_hover as "bool",
primary as "bool",
colorize_icon as "bool",
dpr as "float",
initial_state as "int"
] {
class ColorizedIconEngine : public QIconEngine
{
public:
ColorizedIconEngine(const QIcon &icon, const QColor &color) : m_icon(icon), m_color(color) { }
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override
{
QPixmap iconPixmap = m_icon.pixmap(size, mode, state);
if (!iconPixmap.isNull()) {
QPainter colorizePainter(&iconPixmap);
colorizePainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
colorizePainter.fillRect(iconPixmap.rect(), m_color);
}
return iconPixmap;
}
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override
{
painter->drawPixmap(rect, this->pixmap(rect.size(), mode, state));
}
QIconEngine *clone() const override { return new ColorizedIconEngine(m_icon, m_color); }
private:
QIcon m_icon;
QColor m_color;
};
QStyleOptionButton option;
option.styleObject = widget;
option.state |= QStyle::State(initial_state);
option.text = std::move(text);
QColor iconColor = qApp->palette().color(QPalette::ButtonText).rgba();
if (down) {
option.state |= QStyle::State_Sunken;
} else {
option.state |= QStyle::State_Raised;
}
if (checked) {
option.state |= QStyle::State_On;
}
if (enabled) {
option.state |= QStyle::State_Enabled;
} else {
option.palette.setCurrentColorGroup(QPalette::Disabled);
iconColor = qApp->palette().color(QPalette::Disabled, QPalette::ButtonText).rgba();
}
if (has_focus) {
option.state |= QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange | QStyle::State_Item;
}
if (has_hover) {
option.state |= QStyle::State_MouseOver;
}
if (primary) {
option.features |= QStyleOptionButton::DefaultButton;
}
if (colorize_icon) {
option.icon = QIcon(new ColorizedIconEngine(icon, iconColor));
} else {
option.icon = icon;
}
auto iconSize = qApp->style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, nullptr);
option.iconSize = QSize(iconSize, iconSize);
option.rect = QRect(QPoint(), size / dpr);
qApp->style()->drawControl(QStyle::CE_PushButton, &option, painter->get(), widget);
});
}
}
impl ItemConsts for NativeButton {
const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
}
declare_item_vtable! {
fn slint_get_NativeButtonVTable() -> NativeButtonVTable for NativeButton
}