1use azul_core::{
9 callbacks::Update,
10 dom::{Dom, IdOrClass, IdOrClass::Class, IdOrClassVec},
11 refany::RefAny,
12};
13use azul_css::css::BoxOrStatic;
14use azul_css::{
15 dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec},
16 props::{
17 basic::{ColorU, PixelValueNoPercent, PixelValue, FloatValue},
18 layout::{LayoutDisplay, LayoutFlexDirection, LayoutPaddingTop, LayoutPaddingBottom, LayoutPaddingLeft, LayoutPaddingRight, LayoutFlexGrow},
19 property::{CssProperty, StyleBoxShadowValue, LayoutFlexGrowValue},
20 style::{StyleBackgroundContent, StyleBackgroundContentVec, StyleBoxShadow, BoxShadowClipMode, LayoutBorderTopWidth, LayoutBorderBottomWidth, LayoutBorderLeftWidth, LayoutBorderRightWidth, StyleBorderTopStyle, BorderStyle, StyleBorderBottomStyle, StyleBorderLeftStyle, StyleBorderRightStyle, StyleBorderTopColor, StyleBorderBottomColor, StyleBorderLeftColor, StyleBorderRightColor, StyleBorderTopLeftRadius, StyleBorderTopRightRadius, StyleBorderBottomLeftRadius, StyleBorderBottomRightRadius},
21 },
22 impl_option_inner, AzString,
23};
24
25use crate::callbacks::CallbackInfo;
26
27const CARD_BORDER_COLOR: ColorU = ColorU {
29 r: 222,
30 g: 226,
31 b: 230,
32 a: 255,
33};
34const CARD_BG_COLOR: ColorU = ColorU {
36 r: 255,
37 g: 255,
38 b: 255,
39 a: 255,
40};
41const CARD_SHADOW_COLOR: ColorU = ColorU {
43 r: 0,
44 g: 0,
45 b: 0,
46 a: 38,
47};
48
49const CARD_BG_ITEMS: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(CARD_BG_COLOR)];
50const CARD_BG: StyleBackgroundContentVec =
51 StyleBackgroundContentVec::from_const_slice(CARD_BG_ITEMS);
52
53static CARD_SHADOW: StyleBoxShadow = StyleBoxShadow {
55 offset_x: PixelValueNoPercent {
56 inner: PixelValue::const_px(0),
57 },
58 offset_y: PixelValueNoPercent {
59 inner: PixelValue::const_px(2),
60 },
61 blur_radius: PixelValueNoPercent {
62 inner: PixelValue::const_px(6),
63 },
64 spread_radius: PixelValueNoPercent {
65 inner: PixelValue::const_px(0),
66 },
67 clip_mode: BoxShadowClipMode::Outset,
68 color: CARD_SHADOW_COLOR,
69};
70
71const CARD_STYLE: &[CssPropertyWithConditions] = &[
72 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::Flex)),
73 CssPropertyWithConditions::simple(CssProperty::const_flex_direction(
74 LayoutFlexDirection::Column,
75 )),
76 CssPropertyWithConditions::simple(CssProperty::const_background_content(CARD_BG)),
77 CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
79 12,
80 ))),
81 CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
82 LayoutPaddingBottom::const_px(12),
83 )),
84 CssPropertyWithConditions::simple(CssProperty::const_padding_left(LayoutPaddingLeft::const_px(
85 12,
86 ))),
87 CssPropertyWithConditions::simple(CssProperty::const_padding_right(
88 LayoutPaddingRight::const_px(12),
89 )),
90 CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
92 LayoutBorderTopWidth::const_px(1),
93 )),
94 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
95 LayoutBorderBottomWidth::const_px(1),
96 )),
97 CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
98 LayoutBorderLeftWidth::const_px(1),
99 )),
100 CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
101 LayoutBorderRightWidth::const_px(1),
102 )),
103 CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
104 inner: BorderStyle::Solid,
105 })),
106 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
107 StyleBorderBottomStyle {
108 inner: BorderStyle::Solid,
109 },
110 )),
111 CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
112 inner: BorderStyle::Solid,
113 })),
114 CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
115 StyleBorderRightStyle {
116 inner: BorderStyle::Solid,
117 },
118 )),
119 CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
120 inner: CARD_BORDER_COLOR,
121 })),
122 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
123 StyleBorderBottomColor {
124 inner: CARD_BORDER_COLOR,
125 },
126 )),
127 CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
128 inner: CARD_BORDER_COLOR,
129 })),
130 CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
131 StyleBorderRightColor {
132 inner: CARD_BORDER_COLOR,
133 },
134 )),
135 CssPropertyWithConditions::simple(CssProperty::const_border_top_left_radius(
137 StyleBorderTopLeftRadius::const_px(8),
138 )),
139 CssPropertyWithConditions::simple(CssProperty::const_border_top_right_radius(
140 StyleBorderTopRightRadius::const_px(8),
141 )),
142 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_left_radius(
143 StyleBorderBottomLeftRadius::const_px(8),
144 )),
145 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_right_radius(
146 StyleBorderBottomRightRadius::const_px(8),
147 )),
148 CssPropertyWithConditions::simple(CssProperty::BoxShadowTop(StyleBoxShadowValue::Exact(
150 BoxOrStatic::Static(&raw const CARD_SHADOW),
151 ))),
152 CssPropertyWithConditions::simple(CssProperty::BoxShadowBottom(StyleBoxShadowValue::Exact(
153 BoxOrStatic::Static(&raw const CARD_SHADOW),
154 ))),
155 CssPropertyWithConditions::simple(CssProperty::BoxShadowLeft(StyleBoxShadowValue::Exact(
156 BoxOrStatic::Static(&raw const CARD_SHADOW),
157 ))),
158 CssPropertyWithConditions::simple(CssProperty::BoxShadowRight(StyleBoxShadowValue::Exact(
159 BoxOrStatic::Static(&raw const CARD_SHADOW),
160 ))),
161];
162
163#[derive(Debug, Clone, PartialEq)]
166#[repr(C)]
167pub struct Card {
168 pub content: Dom,
170 pub flex_grow: f32,
172 pub on_click: OptionCardOnClick,
174}
175
176pub type CardOnClickCallbackType = extern "C" fn(RefAny, CallbackInfo) -> Update;
178impl_widget_callback!(
179 CardOnClick,
180 OptionCardOnClick,
181 CardOnClickCallback,
182 CardOnClickCallbackType
183);
184
185azul_core::impl_managed_callback! {
187 wrapper: CardOnClickCallback,
188 info_ty: CallbackInfo,
189 return_ty: Update,
190 default_ret: Update::DoNothing,
191 invoker_static: CARD_ON_CLICK_INVOKER,
192 invoker_ty: AzCardOnClickCallbackInvoker,
193 thunk_fn: az_card_on_click_callback_thunk,
194 setter_fn: AzApp_setCardOnClickCallbackInvoker,
195 from_handle_fn: AzCardOnClickCallback_createFromHostHandle,
196}
197
198impl Card {
199 #[must_use] pub const fn create(content: Dom) -> Self {
201 Self {
202 content,
203 flex_grow: 0.0,
204 on_click: OptionCardOnClick::None,
205 }
206 }
207
208 #[must_use] pub const fn swap_with_default(&mut self) -> Self {
210 let mut s = Self::create(Dom::create_div());
211 core::mem::swap(&mut s, self);
212 s
213 }
214
215 pub fn set_content(&mut self, content: Dom) {
217 self.content = content;
218 }
219
220 #[must_use] pub fn with_content(mut self, content: Dom) -> Self {
222 self.set_content(content);
223 self
224 }
225
226 pub const fn set_flex_grow(&mut self, flex_grow: f32) {
228 self.flex_grow = flex_grow;
229 }
230
231 #[must_use] pub const fn with_flex_grow(mut self, flex_grow: f32) -> Self {
233 self.set_flex_grow(flex_grow);
234 self
235 }
236
237 pub fn set_on_click<C: Into<CardOnClickCallback>>(&mut self, data: RefAny, on_click: C) {
239 self.on_click = Some(CardOnClick {
240 refany: data,
241 callback: on_click.into(),
242 })
243 .into();
244 }
245
246 #[must_use] pub fn with_on_click<C: Into<CardOnClickCallback>>(
248 mut self,
249 data: RefAny,
250 on_click: C,
251 ) -> Self {
252 self.set_on_click(data, on_click);
253 self
254 }
255
256 #[must_use] pub fn dom(self) -> Dom {
257 use azul_core::{
258 callbacks::{CoreCallback, CoreCallbackData},
259 dom::{EventFilter, HoverEventFilter},
260 };
261
262 static CARD_CLASS: &[IdOrClass] =
263 &[Class(AzString::from_const_str("__azul-native-card"))];
264
265 let callbacks = match self.on_click.into_option() {
268 Some(CardOnClick {
269 refany: data,
270 callback,
271 }) => vec![CoreCallbackData {
272 event: EventFilter::Hover(HoverEventFilter::MouseUp),
273 callback: CoreCallback {
274 cb: callback.cb as *const () as usize,
275 ctx: callback.ctx,
276 },
277 refany: data,
278 }],
279 None => Vec::new(),
280 };
281
282 let mut props = vec![CssPropertyWithConditions::simple(CssProperty::FlexGrow(
284 LayoutFlexGrowValue::Exact(LayoutFlexGrow {
285 inner: FloatValue::new(self.flex_grow),
286 }),
287 ))];
288 props.extend_from_slice(CARD_STYLE);
289
290 Dom::create_div()
291 .with_ids_and_classes(IdOrClassVec::from_const_slice(CARD_CLASS))
292 .with_css_props(CssPropertyWithConditionsVec::from_vec(props))
293 .with_callbacks(callbacks.into())
294 .with_children(vec![self.content].into())
295 }
296}
297
298impl Default for Card {
299 fn default() -> Self {
300 Self::create(Dom::create_div())
301 }
302}
303
304impl From<Card> for Dom {
305 fn from(c: Card) -> Self {
306 c.dom()
307 }
308}