New widget: StandardButton

This commit is contained in:
Olivier Goffart 2021-09-28 11:24:33 +02:00 committed by Olivier Goffart
parent 21f9850b43
commit 671df0f24f
16 changed files with 353 additions and 109 deletions

View file

@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
- sixtyfps-compiler and sixtyfps-viewer can read the .60 file content from stdin by passing `-` - sixtyfps-compiler and sixtyfps-viewer can read the .60 file content from stdin by passing `-`
- sixtyfps-viewer gained ability to read or save the property values to a json file with `--save-data` and `--load-data` - sixtyfps-viewer gained ability to read or save the property values to a json file with `--save-data` and `--load-data`
- New `StandardButton` widget
- `sixtyfps::Image` has now a `path()` accessor function in Rust and C++ to access the optional path - `sixtyfps::Image` has now a `path()` accessor function in Rust and C++ to access the optional path
of the file on disk that's backing the image. of the file on disk that's backing the image.

View file

@ -114,6 +114,7 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
"TextWrap", "TextWrap",
"ImageFit", "ImageFit",
"FillRule", "FillRule",
"StandardButtonKind",
] ]
.iter() .iter()
.chain(items.iter()) .chain(items.iter())

View file

@ -31,6 +31,34 @@ Example := Window {
} }
``` ```
## `StandardButton`
The StandardButton looks like a button, but instead of customizing with `text` and `icon`,
it can used one of the pre-defined `kind` and the text and icon will depend on the style.
### Properties
* **`kind`** (*enum*): The kind of button, one of
`ok` `cancel`, `apply`, `close`, `reset`, `help`, `yes`, `no,` `abort`, `retry` or `ignore`
* **`enabled`**: (*bool*): Defaults to true. When false, the button cannot be pressed
### Callbacks
* **`clicked`**
### Example
```60
import { StandardButton, VerticalBox } from "sixtyfps_widgets.60";
Example := Window {
VerticalBox {
StandardButton { kind: ok; }
StandardButton { kind: apply; }
StandardButton { kind: cancel; }
}
}
```
## `CheckBox` ## `CheckBox`
### Properties ### Properties

View file

@ -153,7 +153,7 @@ export Flickable := _ {
//-default_size_binding:expands_to_parent_geometry //-default_size_binding:expands_to_parent_geometry
} }
export WindowItem := _ { WindowItem := _ {
property <length> width: native_output; property <length> width: native_output;
property <length> height: native_output; property <length> height: native_output;
property <color> background; // StyleMetrics.window_background set in apply_default_properties_from_style property <color> background; // StyleMetrics.window_background set in apply_default_properties_from_style
@ -429,6 +429,8 @@ export NativeButton := _ {
property <bool> pressed: native_output; property <bool> pressed: native_output;
callback clicked; callback clicked;
property <bool> enabled: true; property <bool> enabled: true;
property <StandardButtonKind> standard-button-kind;
property <bool> is-standard-button;
//-is_internal //-is_internal
} }

View file

@ -174,6 +174,13 @@ impl TypeRegister {
declare_enum("ImageRendering", &["smooth", "pixelated"]); declare_enum("ImageRendering", &["smooth", "pixelated"]);
declare_enum("EventResult", &["reject", "accept"]); declare_enum("EventResult", &["reject", "accept"]);
declare_enum("FillRule", &["nonzero", "evenodd"]); declare_enum("FillRule", &["nonzero", "evenodd"]);
declare_enum(
"StandardButtonKind",
&[
"ok", "cancel", "apply", "close", "reset", "help", "yes", "no", "abort", "retry",
"ignore",
],
);
register.supported_property_animation_types.insert(Type::Float32.to_string()); register.supported_property_animation_types.insert(Type::Float32.to_string());
register.supported_property_animation_types.insert(Type::Int32.to_string()); register.supported_property_animation_types.insert(Type::Int32.to_string());

View file

@ -0,0 +1,27 @@
/* LICENSE BEGIN
This file is part of the SixtyFPS Project -- https://sixtyfps.io
Copyright (c) 2021 Olivier Goffart <olivier.goffart@sixtyfps.io>
Copyright (c) 2021 Simon Hausmann <simon.hausmann@sixtyfps.io>
SPDX-License-Identifier: GPL-3.0-only
This file is also available under commercial licensing terms.
Please contact info@sixtyfps.io for more information.
LICENSE END */
import { StyleMetrics, Button } from "sixtyfps_widgets_impl.60";
export StandardButton := Button {
property <StandardButtonKind> kind;
text:
kind == StandardButtonKind.ok ? "Ok" :
kind == StandardButtonKind.cancel ? "Cancel" :
kind == StandardButtonKind.apply ? "Apply" :
kind == StandardButtonKind.close ? "Close" :
kind == StandardButtonKind.reset ? "Reset" :
kind == StandardButtonKind.help ? "Help" :
kind == StandardButtonKind.yes ? "Yes" :
kind == StandardButtonKind.no ? "No" :
kind == StandardButtonKind.abort ? "Abort" :
kind == StandardButtonKind.retry ? "Retry" :
kind == StandardButtonKind.ignore ? "Ignore" : "";
}

View file

@ -9,48 +9,9 @@
LICENSE END */ LICENSE END */
import { LineEditInner, TextEdit } from "../common/common.60"; import { LineEditInner, TextEdit } from "../common/common.60";
import { StyleMetrics, ScrollView, Palette } from "sixtyfps_widgets_impl.60"; import { StandardButton } from "../common/standardbutton.60";
export { StyleMetrics, ScrollView, TextEdit } import { StyleMetrics, ScrollView, Button, Palette } from "sixtyfps_widgets_impl.60";
export { StyleMetrics, ScrollView, Button, StandardButton, TextEdit }
export Button := Rectangle {
callback clicked <=> touch.clicked;
property<string> text <=> text.text;
property<bool> pressed: self.enabled && touch.pressed;
property<bool> enabled <=> touch.enabled;
property<image> icon;
property<length> font-size <=> text.font-size;
border-width: 1px;
border-radius: 2px;
border-color: !enabled ? Palette.neutralLighter : Palette.neutralSecondaryAlt;
background: !enabled ? Palette.neutralLighter
: touch.pressed ? Palette.neutralLight
: touch.has-hover ? Palette.neutralLighter
: Palette.white;
horizontal-stretch: 0;
vertical-stretch: 0;
min-height: 32px;
HorizontalLayout {
padding-left: 16px;
padding-right: 16px;
spacing: 8px;
if (icon.width > 0 && icon.height > 0): Image {
source <=> icon;
width: 24px;
}
text := Text {
color: !enabled ? Palette.neutralTertiary : Palette.neutralDark;
horizontal-alignment: center;
vertical-alignment: center;
font-weight: 600;
}
}
touch := TouchArea {}
}
export CheckBox := Rectangle { export CheckBox := Rectangle {
callback toggled; callback toggled;

View file

@ -75,6 +75,45 @@ export global StyleMetrics := {
property<color> textedit-text-color-disabled: #a19f9d;//Palette.neutralTertiary; property<color> textedit-text-color-disabled: #a19f9d;//Palette.neutralTertiary;
} }
export Button := Rectangle {
callback clicked <=> touch.clicked;
property<string> text <=> text.text;
property<bool> pressed: self.enabled && touch.pressed;
property<bool> enabled <=> touch.enabled;
property<image> icon;
property<length> font-size <=> text.font-size;
border-width: 1px;
border-radius: 2px;
border-color: !enabled ? Palette.neutralLighter : Palette.neutralSecondaryAlt;
background: !enabled ? Palette.neutralLighter
: touch.pressed ? Palette.neutralLight
: touch.has-hover ? Palette.neutralLighter
: Palette.white;
horizontal-stretch: 0;
vertical-stretch: 0;
min-height: 32px;
HorizontalLayout {
padding-left: 16px;
padding-right: 16px;
spacing: 8px;
if (icon.width > 0 && icon.height > 0): Image {
source <=> icon;
width: 24px;
}
text := Text {
color: !enabled ? Palette.neutralTertiary : Palette.neutralDark;
horizontal-alignment: center;
vertical-alignment: center;
font-weight: 600;
}
}
touch := TouchArea {}
}
ScrollBar := Rectangle { ScrollBar := Rectangle {
background: white; background: white;

View file

@ -17,6 +17,11 @@ export Button := NativeButton {
property<length> font-size; property<length> font-size;
enabled: true; enabled: true;
} }
export StandardButton := NativeButton {
property<StandardButtonKind> kind <=> self.standard-button-kind;
is-standard-button: true;
}
export CheckBox := NativeCheckBox { } export CheckBox := NativeCheckBox { }
export SpinBox := NativeSpinBox { property<length> font-size; } export SpinBox := NativeSpinBox { property<length> font-size; }
export Slider := NativeSlider { } export Slider := NativeSlider { }

View file

@ -10,58 +10,9 @@ LICENSE END */
import { LineEditInner, TextEdit } from "../common/common.60"; import { LineEditInner, TextEdit } from "../common/common.60";
import { StyleMetrics, ScrollView, Palette } from "sixtyfps_widgets_impl.60"; import { StandardButton } from "../common/standardbutton.60";
export { StyleMetrics, ScrollView, TextEdit } import { StyleMetrics, ScrollView, Button, Palette } from "sixtyfps_widgets_impl.60";
export { StyleMetrics, ScrollView, Button, StandardButton, TextEdit }
export Button := Rectangle {
callback clicked;
property<string> text;
property<length> font-size;
property<bool> pressed: self.enabled && touch-area.pressed;
property<bool> enabled <=> touch-area.enabled;
property<image> icon;
border-width: 1px;
border-radius: 2px;
border-color: Palette.text-color;
background: !self.enabled ? Palette.button-background-disabled: self.pressed ? Palette.button-pressed : (touch-area.has-hover ? Palette.button-hover : Palette.button-background);
animate background { duration: 100ms; }
horizontal-stretch: 0;
vertical-stretch: 0;
HorizontalLayout {
padding-top: root.border-radius + 8px;
padding-bottom: root.border-radius + 8px;
padding-left: root.border-radius + 16px;
padding-right: root.border-radius + 16px;
spacing: StyleMetrics.layout-spacing;
if (icon.width > 0 && icon.height > 0): Image {
source <=> icon;
// Avoid that the icon makes the button grow. This isn't quite a perfect approximation,
// as the glyphs are typically a bit smaller than the font size. 12px is the default
// in the GL backend.
width: root.font-size > 0 ? root.font-size : 12px;
}
Text {
text: root.text;
font-size: root.font-size;
horizontal-alignment: center;
vertical-alignment: center;
color: root.enabled ? Palette.text-color : Palette.text-color-disabled;
}
}
touch-area := TouchArea {
width: root.width;
height: root.height;
clicked => {
root.clicked();
}
}
}
export CheckBox := Rectangle { export CheckBox := Rectangle {
callback toggled; callback toggled;

View file

@ -36,6 +36,56 @@ export global StyleMetrics := {
property<color> textedit-text-color-disabled: lightgray;// Palette.text-color-disabled; property<color> textedit-text-color-disabled: lightgray;// Palette.text-color-disabled;
} }
export Button := Rectangle {
callback clicked;
property<string> text;
property<length> font-size;
property<bool> pressed: self.enabled && touch-area.pressed;
property<bool> enabled <=> touch-area.enabled;
property<image> icon;
border-width: 1px;
border-radius: 2px;
border-color: Palette.text-color;
background: !self.enabled ? Palette.button-background-disabled: self.pressed ? Palette.button-pressed : (touch-area.has-hover ? Palette.button-hover : Palette.button-background);
animate background { duration: 100ms; }
horizontal-stretch: 0;
vertical-stretch: 0;
HorizontalLayout {
padding-top: root.border-radius + 8px;
padding-bottom: root.border-radius + 8px;
padding-left: root.border-radius + 16px;
padding-right: root.border-radius + 16px;
spacing: StyleMetrics.layout-spacing;
if (icon.width > 0 && icon.height > 0): Image {
source <=> icon;
// Avoid that the icon makes the button grow. This isn't quite a perfect approximation,
// as the glyphs are typically a bit smaller than the font size. 12px is the default
// in the GL backend.
width: root.font-size > 0 ? root.font-size : 12px;
}
Text {
text: root.text;
font-size: root.font-size;
horizontal-alignment: center;
vertical-alignment: center;
color: root.enabled ? Palette.text-color : Palette.text-color-disabled;
}
}
touch-area := TouchArea {
width: root.width;
height: root.height;
clicked => {
root.clicked();
}
}
}
ScrollBar := Rectangle { ScrollBar := Rectangle {
background: white; background: white;
border-color: Palette.button-background; border-color: Palette.button-background;

View file

@ -1240,3 +1240,26 @@ declare_item_vtable! {
declare_item_vtable! { declare_item_vtable! {
fn sixtyfps_get_ClippedImageVTable() -> ClippedImageVTable for ClippedImage fn sixtyfps_get_ClippedImageVTable() -> ClippedImageVTable for ClippedImage
} }
#[derive(Copy, Clone, Debug, PartialEq, strum_macros::EnumString, strum_macros::Display)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub enum StandardButtonKind {
ok,
cancel,
apply,
close,
reset,
help,
yes,
no,
abort,
retry,
ignore,
}
impl Default for StandardButtonKind {
fn default() -> Self {
Self::ok
}
}

View file

@ -47,6 +47,7 @@ declare_ValueType![
crate::items::EventResult, crate::items::EventResult,
crate::Brush, crate::Brush,
crate::items::FillRule, crate::items::FillRule,
crate::items::StandardButtonKind,
crate::graphics::Point, crate::graphics::Point,
]; ];

View file

@ -311,6 +311,7 @@ declare_value_enum_conversion!(sixtyfps_corelib::items::ImageRendering, ImageRen
declare_value_enum_conversion!(sixtyfps_corelib::input::KeyEventType, KeyEventType); declare_value_enum_conversion!(sixtyfps_corelib::input::KeyEventType, KeyEventType);
declare_value_enum_conversion!(sixtyfps_corelib::items::EventResult, EventResult); declare_value_enum_conversion!(sixtyfps_corelib::items::EventResult, EventResult);
declare_value_enum_conversion!(sixtyfps_corelib::items::FillRule, FillRule); declare_value_enum_conversion!(sixtyfps_corelib::items::FillRule, FillRule);
declare_value_enum_conversion!(sixtyfps_corelib::items::StandardButtonKind, StandardButtonKind);
impl From<sixtyfps_corelib::animations::Instant> for Value { impl From<sixtyfps_corelib::animations::Instant> for Value {
fn from(value: sixtyfps_corelib::animations::Instant) -> Self { fn from(value: sixtyfps_corelib::animations::Instant) -> Self {

View file

@ -889,6 +889,9 @@ pub(crate) fn generate_component<'id>(
"TextOverflow" => property_info::<sixtyfps_corelib::items::TextOverflow>(), "TextOverflow" => property_info::<sixtyfps_corelib::items::TextOverflow>(),
"ImageFit" => property_info::<sixtyfps_corelib::items::ImageFit>(), "ImageFit" => property_info::<sixtyfps_corelib::items::ImageFit>(),
"FillRule" => property_info::<sixtyfps_corelib::items::FillRule>(), "FillRule" => property_info::<sixtyfps_corelib::items::FillRule>(),
"StandardButtonKind" => {
property_info::<sixtyfps_corelib::items::StandardButtonKind>()
}
_ => panic!("unknown enum"), _ => panic!("unknown enum"),
}, },
Type::LayoutCache => property_info::<SharedVector<f32>>(), Type::LayoutCache => property_info::<SharedVector<f32>>(),

View file

@ -10,6 +10,98 @@ LICENSE END */
use super::*; use super::*;
#[allow(nonstandard_style)]
#[allow(unused)]
mod standard_button {
// Generated with
// bindgen /usr/include/qt/QtWidgets/qstyle.h --whitelist-type QStyle -- -I /usr/include/qt -xc++ | grep _StandardPixmap_ -A1
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 sixtyfps_corelib::items::StandardButtonKind;
use standard_button::*;
type ActualStandardButtonKind = Option<StandardButtonKind>;
#[repr(C)] #[repr(C)]
#[derive(FieldOffsets, Default, SixtyFPSElement)] #[derive(FieldOffsets, Default, SixtyFPSElement)]
#[pin] #[pin]
@ -23,9 +115,69 @@ pub struct NativeButton {
pub enabled: Property<bool>, pub enabled: Property<bool>,
pub pressed: Property<bool>, pub pressed: Property<bool>,
pub clicked: Callback<VoidArg>, pub clicked: Callback<VoidArg>,
pub standard_button_kind: Property<StandardButtonKind>,
pub is_standard_button: Property<bool>,
pub cached_rendering_data: CachedRenderingData, 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 {
// We would need to use the private API to get the text from QPlatformTheme
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::load_image_from_resource(
(&self.icon()).into(),
None,
Default::default(),
)
.unwrap_or_default();
}
};
cpp!(unsafe [style_icon as "QStyle::StandardPixmap"] -> qttypes::QPixmap as "QPixmap" {
ensure_initialized();
return qApp->style()->standardPixmap(style_icon);
})
}
}
impl Item for NativeButton { impl Item for NativeButton {
fn init(self: Pin<&Self>, _window: &WindowRc) {} fn init(self: Pin<&Self>, _window: &WindowRc) {}
@ -38,13 +190,9 @@ impl Item for NativeButton {
orientation: Orientation, orientation: Orientation,
_window: &WindowRc, _window: &WindowRc,
) -> LayoutInfo { ) -> LayoutInfo {
let mut text: qttypes::QString = self.text().as_str().into(); let standard_button_kind = self.actual_standard_button_kind();
let icon: qttypes::QPixmap = crate::qt_window::load_image_from_resource( let mut text: qttypes::QString = self.actual_text(standard_button_kind);
(&self.icon()).into(), let icon: qttypes::QPixmap = self.actual_icon(standard_button_kind);
None,
Default::default(),
)
.unwrap_or_default();
let size = cpp!(unsafe [ let size = cpp!(unsafe [
mut text as "QString", mut text as "QString",
icon as "QPixmap" icon as "QPixmap"
@ -119,13 +267,9 @@ impl Item for NativeButton {
fn_render! { this dpr size painter initial_state => fn_render! { this dpr size painter initial_state =>
let down: bool = this.pressed(); let down: bool = this.pressed();
let text: qttypes::QString = this.text().as_str().into(); let standard_button_kind = this.actual_standard_button_kind();
let icon : qttypes::QPixmap = crate::qt_window::load_image_from_resource( let text: qttypes::QString = this.actual_text(standard_button_kind);
(&this.icon()).into(), let icon: qttypes::QPixmap = this.actual_icon(standard_button_kind);
None,
Default::default(),
)
.unwrap_or_default();
let enabled = this.enabled(); let enabled = this.enabled();
cpp!(unsafe [ cpp!(unsafe [