1use crate::items::{DialogButtonRole, LayoutAlignment};
9use crate::{slice::Slice, Coord, SharedVector};
10use alloc::vec::Vec;
11
12pub use crate::items::Orientation;
13
14#[repr(C)]
17#[derive(Clone, Copy, Debug, PartialEq)]
18pub struct LayoutInfo {
19 pub max: Coord,
21 pub max_percent: Coord,
23 pub min: Coord,
25 pub min_percent: Coord,
27 pub preferred: Coord,
29 pub stretch: f32,
31}
32
33impl Default for LayoutInfo {
34 fn default() -> Self {
35 LayoutInfo {
36 min: 0 as _,
37 max: Coord::MAX,
38 min_percent: 0 as _,
39 max_percent: 100 as _,
40 preferred: 0 as _,
41 stretch: 0 as _,
42 }
43 }
44}
45
46impl LayoutInfo {
47 #[must_use]
49 pub fn merge(&self, other: &LayoutInfo) -> Self {
50 Self {
51 min: self.min.max(other.min),
52 max: self.max.min(other.max),
53 min_percent: self.min_percent.max(other.min_percent),
54 max_percent: self.max_percent.min(other.max_percent),
55 preferred: self.preferred.max(other.preferred),
56 stretch: self.stretch.min(other.stretch),
57 }
58 }
59
60 #[must_use]
62 pub fn preferred_bounded(&self) -> Coord {
63 self.preferred.min(self.max).max(self.min)
64 }
65}
66
67impl core::ops::Add for LayoutInfo {
68 type Output = Self;
69
70 fn add(self, rhs: Self) -> Self::Output {
71 self.merge(&rhs)
72 }
73}
74
75pub fn min_max_size_for_layout_constraints(
77 constraints_horizontal: LayoutInfo,
78 constraints_vertical: LayoutInfo,
79) -> (Option<crate::api::LogicalSize>, Option<crate::api::LogicalSize>) {
80 let min_width = constraints_horizontal.min.min(constraints_horizontal.max) as f32;
81 let min_height = constraints_vertical.min.min(constraints_vertical.max) as f32;
82 let max_width = constraints_horizontal.max.max(constraints_horizontal.min) as f32;
83 let max_height = constraints_vertical.max.max(constraints_vertical.min) as f32;
84
85 let min_size = if min_width > 0. || min_height > 0. || cfg!(target_arch = "wasm32") {
89 Some(crate::api::LogicalSize::new(min_width, min_height))
90 } else {
91 None
92 };
93
94 let max_size = if (max_width > 0.
95 && max_height > 0.
96 && (max_width < i32::MAX as f32 || max_height < i32::MAX as f32))
97 || cfg!(target_arch = "wasm32")
98 {
99 let window_size_max = 16_777_215.;
101 Some(crate::api::LogicalSize::new(
102 max_width.min(window_size_max),
103 max_height.min(window_size_max),
104 ))
105 } else {
106 None
107 };
108
109 (min_size, max_size)
110}
111
112trait Saturating {
115 fn add(_: Self, _: Self) -> Self;
116}
117impl Saturating for i32 {
118 #[inline]
119 fn add(a: Self, b: Self) -> Self {
120 a.saturating_add(b)
121 }
122}
123impl Saturating for f32 {
124 #[inline]
125 fn add(a: Self, b: Self) -> Self {
126 a + b
127 }
128}
129
130mod grid_internal {
131 use super::*;
132
133 fn order_coord<T: PartialOrd>(a: &T, b: &T) -> core::cmp::Ordering {
134 a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal)
135 }
136
137 #[derive(Debug, Clone)]
138 pub struct LayoutData {
139 pub min: Coord,
141 pub max: Coord,
142 pub pref: Coord,
143 pub stretch: f32,
144
145 pub pos: Coord,
147 pub size: Coord,
148 }
149
150 impl Default for LayoutData {
151 fn default() -> Self {
152 LayoutData {
153 min: 0 as _,
154 max: Coord::MAX,
155 pref: 0 as _,
156 stretch: f32::MAX,
157 pos: 0 as _,
158 size: 0 as _,
159 }
160 }
161 }
162
163 trait Adjust {
164 fn can_grow(_: &LayoutData) -> Coord;
165 fn to_distribute(expected_size: Coord, current_size: Coord) -> Coord;
166 fn distribute(_: &mut LayoutData, val: Coord);
167 }
168
169 struct Grow;
170 impl Adjust for Grow {
171 fn can_grow(it: &LayoutData) -> Coord {
172 it.max - it.size
173 }
174
175 fn to_distribute(expected_size: Coord, current_size: Coord) -> Coord {
176 expected_size - current_size
177 }
178
179 fn distribute(it: &mut LayoutData, val: Coord) {
180 it.size += val;
181 }
182 }
183
184 struct Shrink;
185 impl Adjust for Shrink {
186 fn can_grow(it: &LayoutData) -> Coord {
187 it.size - it.min
188 }
189
190 fn to_distribute(expected_size: Coord, current_size: Coord) -> Coord {
191 current_size - expected_size
192 }
193
194 fn distribute(it: &mut LayoutData, val: Coord) {
195 it.size -= val;
196 }
197 }
198
199 #[allow(clippy::unnecessary_cast)] fn adjust_items<A: Adjust>(data: &mut [LayoutData], size_without_spacing: Coord) -> Option<()> {
201 loop {
202 let size_cannot_grow: Coord = data
203 .iter()
204 .filter(|it| A::can_grow(it) <= 0 as _)
205 .map(|it| it.size)
206 .fold(0 as Coord, Saturating::add);
207
208 let total_stretch: f32 =
209 data.iter().filter(|it| A::can_grow(it) > 0 as _).map(|it| it.stretch).sum();
210
211 let actual_stretch = |s: f32| if total_stretch <= 0. { 1. } else { s };
212
213 let max_grow = data
214 .iter()
215 .filter(|it| A::can_grow(it) > 0 as _)
216 .map(|it| A::can_grow(it) as f32 / actual_stretch(it.stretch))
217 .min_by(order_coord)?;
218
219 let current_size: Coord = data
220 .iter()
221 .filter(|it| A::can_grow(it) > 0 as _)
222 .map(|it| it.size)
223 .fold(0 as _, Saturating::add);
224
225 let to_distribute =
227 A::to_distribute(size_without_spacing, size_cannot_grow + current_size) as f32;
228 if to_distribute <= 0. || max_grow <= 0. {
229 return Some(());
230 }
231
232 let grow = if total_stretch <= 0. {
233 to_distribute
234 / (data.iter().filter(|it| A::can_grow(it) > 0 as _).count() as Coord) as f32
235 } else {
236 to_distribute / total_stretch
237 }
238 .min(max_grow);
239
240 let mut distributed = 0 as Coord;
241 for it in data.iter_mut().filter(|it| A::can_grow(it) > 0 as Coord) {
242 let val = (grow * actual_stretch(it.stretch)) as Coord;
243 A::distribute(it, val);
244 distributed += val;
245 }
246
247 if distributed <= 0 as Coord {
248 if let Some(it) = data
251 .iter_mut()
252 .filter(|it| A::can_grow(it) > 0 as _)
253 .max_by(|a, b| actual_stretch(a.stretch).total_cmp(&b.stretch))
254 {
255 A::distribute(it, to_distribute as Coord);
256 }
257 return Some(());
258 }
259 }
260 }
261
262 pub fn layout_items(data: &mut [LayoutData], start_pos: Coord, size: Coord, spacing: Coord) {
263 let size_without_spacing = size - spacing * (data.len() - 1) as Coord;
264
265 let mut pref = 0 as Coord;
266 for it in data.iter_mut() {
267 it.size = it.pref;
268 pref += it.pref;
269 }
270 if size_without_spacing >= pref {
271 adjust_items::<Grow>(data, size_without_spacing);
272 } else if size_without_spacing < pref {
273 adjust_items::<Shrink>(data, size_without_spacing);
274 }
275
276 let mut pos = start_pos;
277 for it in data.iter_mut() {
278 it.pos = pos;
279 pos = Saturating::add(pos, Saturating::add(it.size, spacing));
280 }
281 }
282
283 #[test]
284 #[allow(clippy::float_cmp)] fn test_layout_items() {
286 let my_items = &mut [
287 LayoutData { min: 100., max: 200., pref: 100., stretch: 1., ..Default::default() },
288 LayoutData { min: 50., max: 300., pref: 100., stretch: 1., ..Default::default() },
289 LayoutData { min: 50., max: 150., pref: 100., stretch: 1., ..Default::default() },
290 ];
291
292 layout_items(my_items, 100., 650., 0.);
293 assert_eq!(my_items[0].size, 200.);
294 assert_eq!(my_items[1].size, 300.);
295 assert_eq!(my_items[2].size, 150.);
296
297 layout_items(my_items, 100., 200., 0.);
298 assert_eq!(my_items[0].size, 100.);
299 assert_eq!(my_items[1].size, 50.);
300 assert_eq!(my_items[2].size, 50.);
301
302 layout_items(my_items, 100., 300., 0.);
303 assert_eq!(my_items[0].size, 100.);
304 assert_eq!(my_items[1].size, 100.);
305 assert_eq!(my_items[2].size, 100.);
306 }
307
308 pub fn to_layout_data(
310 data: &[GridLayoutCellData],
311 spacing: Coord,
312 size: Option<Coord>,
313 ) -> Vec<LayoutData> {
314 let mut num = 0usize;
315 for cell in data {
316 num = num.max(cell.col_or_row as usize + cell.span.max(1) as usize);
317 }
318 if num < 1 {
319 return Default::default();
320 }
321 let mut layout_data =
322 alloc::vec![grid_internal::LayoutData { stretch: 1., ..Default::default() }; num];
323 let mut has_spans = false;
324 for cell in data {
325 let constraint = &cell.constraint;
326 let mut max = constraint.max;
327 if let Some(size) = size {
328 max = max.min(size * constraint.max_percent / 100 as Coord);
329 }
330 for c in 0..(cell.span as usize) {
331 let cdata = &mut layout_data[cell.col_or_row as usize + c];
332 cdata.max = cdata.max.min(max);
333 }
334 if cell.span == 1 {
335 let mut min = constraint.min;
336 if let Some(size) = size {
337 min = min.max(size * constraint.min_percent / 100 as Coord);
338 }
339 let pref = constraint.preferred.min(max).max(min);
340 let cdata = &mut layout_data[cell.col_or_row as usize];
341 cdata.min = cdata.min.max(min);
342 cdata.pref = cdata.pref.max(pref);
343 cdata.stretch = cdata.stretch.min(constraint.stretch);
344 } else {
345 has_spans = true;
346 }
347 }
348 if has_spans {
349 for cell in data.iter().filter(|cell| cell.span > 1) {
351 let span_data = &mut layout_data
352 [(cell.col_or_row as usize)..(cell.col_or_row + cell.span) as usize];
353 let mut min = cell.constraint.min;
354 if let Some(size) = size {
355 min = min.max(size * cell.constraint.min_percent / 100 as Coord);
356 }
357 grid_internal::layout_items(span_data, 0 as _, min, spacing);
358 for cdata in span_data {
359 if cdata.min < cdata.size {
360 cdata.min = cdata.size;
361 }
362 }
363 }
364 for cell in data.iter().filter(|cell| cell.span > 1) {
366 let span_data = &mut layout_data
367 [(cell.col_or_row as usize)..(cell.col_or_row + cell.span) as usize];
368 let mut max = cell.constraint.max;
369 if let Some(size) = size {
370 max = max.min(size * cell.constraint.max_percent / 100 as Coord);
371 }
372 grid_internal::layout_items(span_data, 0 as _, max, spacing);
373 for cdata in span_data {
374 if cdata.max > cdata.size {
375 cdata.max = cdata.size;
376 }
377 }
378 }
379 for cell in data.iter().filter(|cell| cell.span > 1) {
381 let span_data = &mut layout_data
382 [(cell.col_or_row as usize)..(cell.col_or_row + cell.span) as usize];
383 grid_internal::layout_items(span_data, 0 as _, cell.constraint.preferred, spacing);
384 for cdata in span_data {
385 cdata.pref = cdata.pref.max(cdata.size).min(cdata.max).max(cdata.min);
386 }
387 }
388 for cell in data.iter().filter(|cell| cell.span > 1) {
390 let span_data = &mut layout_data
391 [(cell.col_or_row as usize)..(cell.col_or_row + cell.span) as usize];
392 let total_stretch: f32 = span_data.iter().map(|c| c.stretch).sum();
393 if total_stretch > cell.constraint.stretch {
394 for cdata in span_data {
395 cdata.stretch *= cell.constraint.stretch / total_stretch;
396 }
397 }
398 }
399 }
400 layout_data
401 }
402}
403
404#[repr(C)]
405pub struct Constraint {
406 pub min: Coord,
407 pub max: Coord,
408}
409
410impl Default for Constraint {
411 fn default() -> Self {
412 Constraint { min: 0 as Coord, max: Coord::MAX }
413 }
414}
415
416#[repr(C)]
417#[derive(Copy, Clone, Debug, Default)]
418pub struct Padding {
419 pub begin: Coord,
420 pub end: Coord,
421}
422
423#[repr(C)]
424#[derive(Debug)]
425pub struct GridLayoutData<'a> {
426 pub size: Coord,
427 pub spacing: Coord,
428 pub padding: Padding,
429 pub cells: Slice<'a, GridLayoutCellData>,
430}
431
432#[repr(C)]
433#[derive(Default, Debug)]
434pub struct GridLayoutCellData {
435 pub col_or_row: u16,
437 pub span: u16,
439 pub constraint: LayoutInfo,
440}
441
442pub fn solve_grid_layout(data: &GridLayoutData) -> SharedVector<Coord> {
444 let mut layout_data =
445 grid_internal::to_layout_data(data.cells.as_slice(), data.spacing, Some(data.size));
446
447 if layout_data.is_empty() {
448 return Default::default();
449 }
450
451 grid_internal::layout_items(
452 &mut layout_data,
453 data.padding.begin,
454 data.size - (data.padding.begin + data.padding.end),
455 data.spacing,
456 );
457
458 let mut result = SharedVector::with_capacity(4 * data.cells.len());
459 for cell in data.cells.iter() {
460 let cdata = &layout_data[cell.col_or_row as usize];
461 result.push(cdata.pos);
462 result.push(if cell.span > 0 {
463 let first_cell = &layout_data[cell.col_or_row as usize];
464 let last_cell = &layout_data[cell.col_or_row as usize + cell.span as usize - 1];
465 last_cell.pos + last_cell.size - first_cell.pos
466 } else {
467 0 as Coord
468 });
469 }
470 result
471}
472
473pub fn grid_layout_info(
474 cells: Slice<GridLayoutCellData>,
475 spacing: Coord,
476 padding: &Padding,
477) -> LayoutInfo {
478 let layout_data = grid_internal::to_layout_data(cells.as_slice(), spacing, None);
479 if layout_data.is_empty() {
480 return Default::default();
481 }
482 let spacing_w = spacing * (layout_data.len() - 1) as Coord + padding.begin + padding.end;
483 let min = layout_data.iter().map(|data| data.min).sum::<Coord>() + spacing_w;
484 let max = layout_data.iter().map(|data| data.max).fold(spacing_w, Saturating::add);
485 let preferred = layout_data.iter().map(|data| data.pref).sum::<Coord>() + spacing_w;
486 let stretch = layout_data.iter().map(|data| data.stretch).sum::<f32>();
487 LayoutInfo { min, max, min_percent: 0 as _, max_percent: 100 as _, preferred, stretch }
488}
489
490#[repr(C)]
491#[derive(Debug)]
492pub struct BoxLayoutData<'a> {
496 pub size: Coord,
497 pub spacing: Coord,
498 pub padding: Padding,
499 pub alignment: LayoutAlignment,
500 pub cells: Slice<'a, BoxLayoutCellData>,
501}
502
503#[repr(C)]
504#[derive(Default, Debug, Clone)]
505pub struct BoxLayoutCellData {
506 pub constraint: LayoutInfo,
507}
508
509pub fn solve_box_layout(data: &BoxLayoutData, repeater_indexes: Slice<u32>) -> SharedVector<Coord> {
511 let mut result = SharedVector::<Coord>::default();
512 result.resize(data.cells.len() * 2 + repeater_indexes.len(), 0 as _);
513
514 if data.cells.is_empty() {
515 return result;
516 }
517
518 let mut layout_data: Vec<_> = data
519 .cells
520 .iter()
521 .map(|c| {
522 let min = c.constraint.min.max(c.constraint.min_percent * data.size / 100 as Coord);
523 let max = c.constraint.max.min(c.constraint.max_percent * data.size / 100 as Coord);
524 grid_internal::LayoutData {
525 min,
526 max,
527 pref: c.constraint.preferred.min(max).max(min),
528 stretch: c.constraint.stretch,
529 ..Default::default()
530 }
531 })
532 .collect();
533
534 let size_without_padding = data.size - data.padding.begin - data.padding.end;
535 let pref_size: Coord = layout_data.iter().map(|it| it.pref).sum();
536 let num_spacings = (layout_data.len() - 1) as Coord;
537 let spacings = data.spacing * num_spacings;
538
539 let align = match data.alignment {
540 LayoutAlignment::Stretch => {
541 grid_internal::layout_items(
542 &mut layout_data,
543 data.padding.begin,
544 size_without_padding,
545 data.spacing,
546 );
547 None
548 }
549 _ if size_without_padding <= pref_size + spacings => {
550 grid_internal::layout_items(
551 &mut layout_data,
552 data.padding.begin,
553 size_without_padding,
554 data.spacing,
555 );
556 None
557 }
558 LayoutAlignment::Center => Some((
559 data.padding.begin + (size_without_padding - pref_size - spacings) / 2 as Coord,
560 data.spacing,
561 )),
562 LayoutAlignment::Start => Some((data.padding.begin, data.spacing)),
563 LayoutAlignment::End => {
564 Some((data.padding.begin + (size_without_padding - pref_size - spacings), data.spacing))
565 }
566 LayoutAlignment::SpaceBetween => {
567 Some((data.padding.begin, (size_without_padding - pref_size) / num_spacings))
568 }
569 LayoutAlignment::SpaceAround => {
570 let spacing = (size_without_padding - pref_size) / (num_spacings + 1 as Coord);
571 Some((data.padding.begin + spacing / 2 as Coord, spacing))
572 }
573 };
574 if let Some((mut pos, spacing)) = align {
575 for it in &mut layout_data {
576 it.pos = pos;
577 it.size = it.pref;
578 pos += spacing + it.size;
579 }
580 }
581
582 let res = result.make_mut_slice();
583
584 let mut repeat_offset =
586 res.len() / 2 - repeater_indexes.iter().skip(1).step_by(2).sum::<u32>() as usize;
587 let mut next_rep = 0;
589 let mut current_offset = 0;
591 for (idx, layout) in layout_data.iter().enumerate() {
592 let o = loop {
593 if let Some(nr) = repeater_indexes.get(next_rep * 2) {
594 let nr = *nr as usize;
595 if nr == idx {
596 for o in 0..2 {
597 res[current_offset * 2 + o] = (repeat_offset * 2 + o) as _;
598 }
599 current_offset += 1;
600 }
601 if idx >= nr {
602 if idx - nr == repeater_indexes[next_rep * 2 + 1] as usize {
603 next_rep += 1;
604 continue;
605 }
606 repeat_offset += 1;
607 break repeat_offset - 1;
608 }
609 }
610 current_offset += 1;
611 break current_offset - 1;
612 };
613 res[o * 2] = layout.pos;
614 res[o * 2 + 1] = layout.size;
615 }
616 result
617}
618
619pub fn box_layout_info(
621 cells: Slice<BoxLayoutCellData>,
622 spacing: Coord,
623 padding: &Padding,
624 alignment: LayoutAlignment,
625) -> LayoutInfo {
626 let count = cells.len();
627 if count < 1 {
628 return LayoutInfo { max: 0 as _, ..LayoutInfo::default() };
629 };
630 let is_stretch = alignment == LayoutAlignment::Stretch;
631 let extra_w = padding.begin + padding.end + spacing * (count - 1) as Coord;
632 let min = cells.iter().map(|c| c.constraint.min).sum::<Coord>() + extra_w;
633 let max = if is_stretch {
634 (cells.iter().map(|c| c.constraint.max).fold(extra_w, Saturating::add)).max(min)
635 } else {
636 Coord::MAX
637 };
638 let preferred = cells.iter().map(|c| c.constraint.preferred_bounded()).sum::<Coord>() + extra_w;
639 let stretch = cells.iter().map(|c| c.constraint.stretch).sum::<f32>();
640 LayoutInfo { min, max, min_percent: 0 as _, max_percent: 100 as _, preferred, stretch }
641}
642
643pub fn box_layout_info_ortho(cells: Slice<BoxLayoutCellData>, padding: &Padding) -> LayoutInfo {
644 let count = cells.len();
645 if count < 1 {
646 return LayoutInfo { max: 0 as _, ..LayoutInfo::default() };
647 };
648 let extra_w = padding.begin + padding.end;
649
650 let mut fold =
651 cells.iter().fold(LayoutInfo { stretch: f32::MAX, ..Default::default() }, |a, b| {
652 a.merge(&b.constraint)
653 });
654 fold.max = fold.max.max(fold.min);
655 fold.preferred = fold.preferred.clamp(fold.min, fold.max);
656 fold.min += extra_w;
657 fold.max = Saturating::add(fold.max, extra_w);
658 fold.preferred += extra_w;
659 fold
660}
661
662pub fn reorder_dialog_button_layout(cells: &mut [GridLayoutCellData], roles: &[DialogButtonRole]) {
667 fn add_buttons(
668 cells: &mut [GridLayoutCellData],
669 roles: &[DialogButtonRole],
670 idx: &mut u16,
671 role: DialogButtonRole,
672 ) {
673 for (cell, r) in cells.iter_mut().zip(roles.iter()) {
674 if *r == role {
675 cell.col_or_row = *idx;
676 *idx += 1;
677 }
678 }
679 }
680
681 #[cfg(feature = "std")]
682 fn is_kde() -> bool {
683 std::env::var("XDG_CURRENT_DESKTOP")
685 .ok()
686 .and_then(|v| v.as_bytes().first().copied())
687 .is_some_and(|x| x.eq_ignore_ascii_case(&b'K'))
688 }
689 #[cfg(not(feature = "std"))]
690 let is_kde = || true;
691
692 let mut idx = 0;
693
694 if cfg!(windows) {
695 add_buttons(cells, roles, &mut idx, DialogButtonRole::Reset);
696 idx += 1;
697 add_buttons(cells, roles, &mut idx, DialogButtonRole::Accept);
698 add_buttons(cells, roles, &mut idx, DialogButtonRole::Action);
699 add_buttons(cells, roles, &mut idx, DialogButtonRole::Reject);
700 add_buttons(cells, roles, &mut idx, DialogButtonRole::Apply);
701 add_buttons(cells, roles, &mut idx, DialogButtonRole::Help);
702 } else if cfg!(target_os = "macos") {
703 add_buttons(cells, roles, &mut idx, DialogButtonRole::Help);
704 add_buttons(cells, roles, &mut idx, DialogButtonRole::Reset);
705 add_buttons(cells, roles, &mut idx, DialogButtonRole::Apply);
706 add_buttons(cells, roles, &mut idx, DialogButtonRole::Action);
707 idx += 1;
708 add_buttons(cells, roles, &mut idx, DialogButtonRole::Reject);
709 add_buttons(cells, roles, &mut idx, DialogButtonRole::Accept);
710 } else if is_kde() {
711 add_buttons(cells, roles, &mut idx, DialogButtonRole::Help);
713 add_buttons(cells, roles, &mut idx, DialogButtonRole::Reset);
714 idx += 1;
715 add_buttons(cells, roles, &mut idx, DialogButtonRole::Action);
716 add_buttons(cells, roles, &mut idx, DialogButtonRole::Accept);
717 add_buttons(cells, roles, &mut idx, DialogButtonRole::Apply);
718 add_buttons(cells, roles, &mut idx, DialogButtonRole::Reject);
719 } else {
720 add_buttons(cells, roles, &mut idx, DialogButtonRole::Help);
722 add_buttons(cells, roles, &mut idx, DialogButtonRole::Reset);
723 idx += 1;
724 add_buttons(cells, roles, &mut idx, DialogButtonRole::Action);
725 add_buttons(cells, roles, &mut idx, DialogButtonRole::Apply);
726 add_buttons(cells, roles, &mut idx, DialogButtonRole::Reject);
727 add_buttons(cells, roles, &mut idx, DialogButtonRole::Accept);
728 }
729}
730
731#[cfg(feature = "ffi")]
732pub(crate) mod ffi {
733 #![allow(unsafe_code)]
734
735 use super::*;
736
737 #[unsafe(no_mangle)]
738 pub extern "C" fn slint_solve_grid_layout(
739 data: &GridLayoutData,
740 result: &mut SharedVector<Coord>,
741 ) {
742 *result = super::solve_grid_layout(data)
743 }
744
745 #[unsafe(no_mangle)]
746 pub extern "C" fn slint_grid_layout_info(
747 cells: Slice<GridLayoutCellData>,
748 spacing: Coord,
749 padding: &Padding,
750 ) -> LayoutInfo {
751 super::grid_layout_info(cells, spacing, padding)
752 }
753
754 #[unsafe(no_mangle)]
755 pub extern "C" fn slint_solve_box_layout(
756 data: &BoxLayoutData,
757 repeater_indexes: Slice<u32>,
758 result: &mut SharedVector<Coord>,
759 ) {
760 *result = super::solve_box_layout(data, repeater_indexes)
761 }
762
763 #[unsafe(no_mangle)]
764 pub extern "C" fn slint_box_layout_info(
766 cells: Slice<BoxLayoutCellData>,
767 spacing: Coord,
768 padding: &Padding,
769 alignment: LayoutAlignment,
770 ) -> LayoutInfo {
771 super::box_layout_info(cells, spacing, padding, alignment)
772 }
773
774 #[unsafe(no_mangle)]
775 pub extern "C" fn slint_box_layout_info_ortho(
777 cells: Slice<BoxLayoutCellData>,
778 padding: &Padding,
779 ) -> LayoutInfo {
780 super::box_layout_info_ortho(cells, padding)
781 }
782
783 #[unsafe(no_mangle)]
788 pub unsafe extern "C" fn slint_reorder_dialog_button_layout(
789 cells: *mut GridLayoutCellData,
790 roles: Slice<DialogButtonRole>,
791 ) {
792 reorder_dialog_button_layout(core::slice::from_raw_parts_mut(cells, roles.len()), &roles);
793 }
794}