Skip to main content

ui/
form.rs

1// form -- the kind of device the app runs on: a desktop, a tablet or a phone
2//
3//   form_factor() -> FF_DESKTOP / FF_TABLET / FF_PHONE
4//   mobile() -> bool                 a tablet or a phone (form_factor() != FF_DESKTOP)
5//
6// The platform decides, never the window's size alone: Windows, Linux, macOS and the browser are
7// FF_DESKTOP however small a window is dragged (a narrow desktop window keeps the desktop's
8// behaviour); Android and iOS are FF_TABLET, and FF_PHONE where the main window's shorter side is
9// below 600 DIP (Android's own line between a phone and a tablet, `sw600dp`; a tablet's app in a
10// narrow split screen is laid out like a phone's then).  The shorter side keeps a phone a phone
11// when it is turned.
12//
13// jfgui_FORM=desktop|tablet|phone decides instead (any platform: tests, and a look at the phone's
14// layout on the desktop; scripts: `system env jfgui_FORM phone`).
15//
16// What the library does by itself on a phone or a tablet (only there):
17//   the title bar has no caption buttons (chrome.rs: the system owns the app's window);
18//   a menu bar that does not fit its row becomes one menu button (popup.rs, menubar);
19//   the status bar's items roll sideways with the finger when the bar is too narrow (chrome.rs);
20//   windows and content dialogs keep inside the screen, what does not fit rolls (win.rs, chrome.rs);
21//   Android and iOS paint the system's bars in the colours at the app's edges (the hosts).
22// Apps ask form_factor() for what only they know: which panels a phone shows, which a tablet.
23
24use super::consts::*;
25use super::Ui;
26#[cfg(target_os = "android")]
27use gfx::Surface;
28
29/// a tablet's shorter side is at least this many DIP (Android's sw600dp)
30const TABLET_DIP: i32 = 600;
31
32impl Ui {
33    /// ui_form_factor: FF_DESKTOP, FF_TABLET or FF_PHONE (the platform's; jfgui_FORM decides
34    /// instead).  A desktop window stays FF_DESKTOP however narrow it is.
35    pub fn form_factor(&self) -> u32 {
36        self.form
37    }
38
39    /// ui_mobile: the app runs on a phone or a tablet (form_factor() != FF_DESKTOP)
40    pub fn mobile(&self) -> bool {
41        self.form != FF_DESKTOP
42    }
43
44    // form_update(w, h): the main window's pass begins (w x h px): the form factor of this frame
45    pub(crate) fn form_update(&mut self, w: i32, h: i32) {
46        let side = self.px2dip(w.min(h));
47        let mobile_os = cfg!(any(target_os = "android", target_os = "ios"));
48        self.form = match plat::env("jfgui_FORM").as_deref() {
49            Some("phone") => FF_PHONE,
50            Some("tablet") => FF_TABLET,
51            Some("desktop") => FF_DESKTOP,
52            _ if !mobile_os => FF_DESKTOP,
53            _ if side > 0 && side < TABLET_DIP => FF_PHONE,
54            _ => FF_TABLET,
55        };
56    }
57}
58
59// (Android) edge_colors(fb) -> the colours (0xRRGGBB) along the frame's top, bottom, left and right
60// edge: on each the most frequent of 9 samples (a widget touching the edge somewhere does not
61// count); the host paints the system's bars in them
62#[cfg(target_os = "android")]
63pub(crate) fn edge_colors(fb: &Surface) -> [u32; 4] {
64    let (w, h) = (fb.w, fb.h);
65    if w <= 0 || h <= 0 || fb.px.len() < (fb.stride * (h - 1) + w * 4) as usize {
66        return [0; 4];
67    }
68    let at = |x: i32, y: i32| {
69        let o = (y * fb.stride + x * 4) as usize;
70        (fb.px[o + 2] as u32) << 16 | (fb.px[o + 1] as u32) << 8 | fb.px[o] as u32
71    };
72    let edge = |f: &dyn Fn(i32) -> u32, len: i32| {
73        let s: [u32; 9] = core::array::from_fn(|k| f(((2 * k as i32 + 1) * len / 18).min(len - 1)));
74        let mut best = (s[0], 0);
75        for &c in &s {
76            let n = s.iter().filter(|&&d| d == c).count();
77            if n > best.1 {
78                best = (c, n);
79            }
80        }
81        best.0
82    };
83    [
84        edge(&|x| at(x, 0), w),
85        edge(&|x| at(x, h - 1), w),
86        edge(&|y| at(0, y), h),
87        edge(&|y| at(w - 1, y), h),
88    ]
89}
90