use crate::{
BoxShadow, Color, Convert, Element, ExternalTexture, ExternalVisual, FlexDirection,
InputContents, IntoHexColor, IntoLayoutPoint, Prop, ReadSignal, StyleValue, ThisStyle,
WriteSignal, with_context,
};
use std::borrow::Cow;
#[inline]
#[must_use]
pub fn ts() -> ThisStyle {
ThisStyle::new()
}
pub fn create_signal<T: Send + 'static>(initial_value: T) -> (ReadSignal<T>, WriteSignal<T>) {
with_context(|cx| cx.create_signal(initial_value))
}
#[inline]
#[must_use]
pub fn use_provided<T: Clone + 'static>() -> ReadSignal<T> {
with_context(|cx| cx.use_provided::<T>())
}
#[inline]
#[must_use]
pub fn use_provided_setter<T: Send + 'static>() -> WriteSignal<T> {
with_context(|cx| cx.use_provided_setter::<T>())
}
pub fn dynamic<P, V, F>(selector: F) -> StyleValue<V>
where
P: Clone + 'static,
V: 'static,
F: Fn(&P) -> V + Send + Sync + 'static,
{
StyleValue::Dynamic(Box::new(move || {
let signal = with_context(|cx| cx.use_provided::<P>());
let val = signal.get();
selector(&val)
}))
}
#[inline]
#[must_use]
pub fn rgb(r: u8, g: u8, b: u8) -> Color {
Color {
r: f32::from(r) / 255.0,
g: f32::from(g) / 255.0,
b: f32::from(b) / 255.0,
a: 1.0,
}
}
#[inline]
#[must_use]
pub fn rgba(r: u8, g: u8, b: u8, a: f32) -> Color {
Color {
r: f32::from(r) / 255.0,
g: f32::from(g) / 255.0,
b: f32::from(b) / 255.0,
a,
}
}
#[inline]
pub fn hex(value: impl IntoHexColor) -> Color {
value.into_hex_color()
}
#[inline]
#[must_use]
pub fn hsl(h: f32, s: f32, l: f32) -> Color {
Color::hsl(h, s, l)
}
#[inline]
#[must_use]
pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Color {
Color::hsla(h, s, l, a)
}
#[inline]
pub fn flex(style: impl Into<Prop<ThisStyle>>) -> Element {
let el = Element::new();
el.style(style)
}
#[inline]
pub fn div(style: impl Into<Prop<ThisStyle>>) -> Element {
let el = Element::new();
el.style(ts().block()).style(style)
}
pub const NO_STYLE: Option<ThisStyle> = None;
#[inline]
#[must_use]
pub fn div_n() -> Element {
flex(NO_STYLE)
}
#[inline]
pub fn h_flex(style: impl Into<Prop<ThisStyle>>) -> Element {
let el = Element::new();
el.style(ts().flex().flex_direction(FlexDirection::Row))
.style(style)
}
#[inline]
pub fn v_flex(style: impl Into<Prop<ThisStyle>>) -> Element {
let el = Element::new();
el.style(ts().flex().flex_direction(FlexDirection::Column))
.style(style)
}
#[inline]
pub fn grid_box(style: impl Into<Prop<ThisStyle>>) -> Element {
let el = Element::new();
el.style(ts().grid()).style(style)
}
#[inline]
pub fn block_box(style: impl Into<Prop<ThisStyle>>) -> Element {
let el = Element::new();
el.style(ts().block()).style(style)
}
#[inline]
pub fn hidden_box(style: impl Into<Prop<ThisStyle>>) -> Element {
let el = Element::new();
el.style(ts().hidden()).style(style)
}
#[inline]
pub fn text(content: impl Into<Prop<Cow<'static, str>>>) -> Element {
div_n().text(content)
}
#[inline]
pub fn input(contents: impl Into<Prop<InputContents>>) -> Element {
div_n().input(contents)
}
#[inline]
pub fn input_area(contents: impl Into<Prop<InputContents>>) -> Element {
div_n().input_area(contents)
}
#[inline]
pub fn external_texture(texture: impl ExternalTexture + 'static) -> Element {
div_n().external_texture(texture)
}
#[inline]
pub fn external_visual(visual: impl ExternalVisual + 'static) -> Element {
div_n().external_visual(visual)
}
#[inline]
pub fn div_d<P, F>(f: F) -> Element
where
P: Clone + 'static,
F: Fn(&P) -> ThisStyle + Send + Sync + 'static,
{
Element::new().style_d(f)
}
#[inline]
pub fn h_flex_d<P, F>(f: F) -> Element
where
P: Clone + 'static,
F: Fn(&P) -> ThisStyle + Send + Sync + 'static,
{
Element::new()
.style(ts().flex().flex_direction(FlexDirection::Row))
.style_d(f)
}
#[inline]
pub fn v_flex_d<P, F>(f: F) -> Element
where
P: Clone + 'static,
F: Fn(&P) -> ThisStyle + Send + Sync + 'static,
{
Element::new()
.style(ts().flex().flex_direction(FlexDirection::Column))
.style_d(f)
}
#[inline]
pub fn text_d<P, F, S>(f: F) -> Element
where
P: Clone + 'static,
F: Fn(&P) -> S + Send + Sync + 'static,
S: Into<Cow<'static, str>>,
{
div_n().text_d(f)
}
#[inline]
pub fn input_d<P, F>(f: F) -> Element
where
P: Clone + 'static,
F: Fn(&P) -> InputContents + Send + Sync + 'static,
{
div_n().input_d(f)
}
#[inline]
pub fn input_area_d<P, F>(f: F) -> Element
where
P: Clone + 'static,
F: Fn(&P) -> InputContents + Send + Sync + 'static,
{
div_n().input_area_d(f)
}
#[inline]
#[must_use]
pub fn shadow() -> BoxShadow {
BoxShadow::new()
}
#[inline]
pub fn blur(value: impl Convert<f32>) -> BoxShadow {
BoxShadow::new().blur(value)
}
#[inline]
pub fn offset(value: impl IntoLayoutPoint) -> BoxShadow {
BoxShadow::new().offset(value)
}
#[inline]
pub fn spread(value: impl Convert<f32>) -> BoxShadow {
BoxShadow::new().spread(value)
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Pixel(pub f32);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Percent(pub f32);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Auto;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Stretch;
#[inline]
#[must_use]
pub fn px(val: f32) -> Pixel {
Pixel(val)
}
#[inline]
#[must_use]
pub fn pct(val: f32) -> Percent {
Percent(val)
}
#[inline]
#[must_use]
pub fn auto() -> Auto {
Auto
}
#[inline]
#[must_use]
pub fn fill() -> Stretch {
Stretch
}
#[must_use]
pub fn set_win32_clipboard(text: &str) -> bool {
unsafe {
use windows::Win32::Foundation::HANDLE;
use windows::Win32::System::DataExchange::{
CloseClipboard, EmptyClipboard, OpenClipboard, SetClipboardData,
};
use windows::Win32::System::Memory::{
GMEM_MOVEABLE, GlobalAlloc, GlobalLock, GlobalUnlock,
};
let text_u16: Vec<u16> = text.encode_utf16().chain(Some(0)).collect();
let size = text_u16.len() * 2;
let Ok(h_mem) = GlobalAlloc(GMEM_MOVEABLE, size) else {
return false;
};
let ptr = GlobalLock(h_mem);
if ptr.is_null() {
return false;
}
std::ptr::copy_nonoverlapping(text_u16.as_ptr(), ptr.cast::<u16>(), text_u16.len());
let _ = GlobalUnlock(h_mem);
let mut success = false;
if OpenClipboard(None).is_ok() {
let _ = EmptyClipboard();
if SetClipboardData(13, Some(HANDLE(h_mem.0))).is_ok() {
success = true;
}
let _ = CloseClipboard();
}
success
}
}
#[must_use]
pub fn get_win32_clipboard() -> Option<String> {
unsafe {
use windows::Win32::Foundation::HGLOBAL;
use windows::Win32::System::DataExchange::{
CloseClipboard, GetClipboardData, OpenClipboard,
};
use windows::Win32::System::Memory::{GlobalLock, GlobalUnlock};
let mut result = None;
if OpenClipboard(None).is_ok() {
if let Ok(h_mem) = GetClipboardData(13) {
if !h_mem.is_invalid() {
let ptr = GlobalLock(HGLOBAL(h_mem.0));
if !ptr.is_null() {
let u16_ptr = ptr as *const u16;
let mut len = 0;
while *u16_ptr.add(len) != 0 {
len += 1;
}
let slice = std::slice::from_raw_parts(u16_ptr, len);
result = Some(String::from_utf16_lossy(slice));
let _ = GlobalUnlock(HGLOBAL(h_mem.0));
}
}
}
let _ = CloseClipboard();
}
result
}
}
#[expect(clippy::cast_precision_loss)]
#[must_use]
pub fn raw_wheel_delta_to_logical_pixels(raw_delta: f32) -> f32 {
use windows::Win32::UI::WindowsAndMessaging::{
SPI_GETWHEELSCROLLLINES, SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, SystemParametersInfoW,
};
const WHEEL_PAGESCROLL: u32 = 0xFFFF_FFFF;
let mut scroll_lines: u32 = 3; unsafe {
let _ = SystemParametersInfoW(
SPI_GETWHEELSCROLLLINES,
0,
Some((&raw mut scroll_lines).cast()),
SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS(0),
);
}
if scroll_lines == WHEEL_PAGESCROLL {
let notches = raw_delta / 120.0;
-notches * 350.0
} else {
let notches = raw_delta / 120.0;
-notches * (scroll_lines as f32) * 30.0
}
}