From dc2959396c191696ee3d79f9793799d20e9fc1c1 Mon Sep 17 00:00:00 2001 From: Fenrir Date: Mon, 19 Feb 2024 14:41:01 -0700 Subject: [PATCH] Add basic error applet support --- ctru-rs/src/applets/error.rs | 56 ++++++++++++++++++++++++++++++++++++ ctru-rs/src/applets/mod.rs | 1 + ctru-sys/build.rs | 2 ++ ctru-sys/src/lib.rs | 16 +++++++++++ 4 files changed, 75 insertions(+) create mode 100644 ctru-rs/src/applets/error.rs diff --git a/ctru-rs/src/applets/error.rs b/ctru-rs/src/applets/error.rs new file mode 100644 index 00000000..ef7cea7f --- /dev/null +++ b/ctru-rs/src/applets/error.rs @@ -0,0 +1,56 @@ +//! Error applet +//! +//! This applet displays error text as a pop-up message on the lower screen. +#![doc(alias = "Error")] + +use crate::services::{apt::Apt, gfx::Gfx}; + +use ctru_sys::errorConf; + +/// Configuration struct to set up the Error applet. +#[doc(alias = "errorConf")] +pub struct ErrorApplet { + state: Box, +} + +/// The kind of error applet to display. +#[doc(alias = "errorType")] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u32)] +pub enum Kind { + /// Error text is centered in the error applet window. + Center = ctru_sys::ERROR_TEXT, + /// Error text starts at the top of the error applet window. + Top = ctru_sys::ERROR_TEXT_WORD_WRAP, +} + +impl ErrorApplet { + /// Initialize the error applet with the provided text kind. + #[doc(alias = "errorInit")] + pub fn new(kind: Kind) -> Self { + let mut state = Box::::default(); + + unsafe { ctru_sys::errorInit(state.as_mut(), kind as _, 0) }; + + Self { state } + } + + /// Sets the error text to display. + #[doc(alias = "errorText")] + pub fn set_text(&mut self, text: &str) { + for (idx, code_unit) in text + .encode_utf16() + .chain(std::iter::once(0)) + .take(self.state.Text.len() - 1) + .enumerate() + { + self.state.Text[idx] = code_unit; + } + } + + /// Launches the error applet. + #[doc(alias = "errorDisp")] + pub fn launch(&mut self, _apt: &Apt, _gfx: &Gfx) { + unsafe { ctru_sys::errorDisp(self.state.as_mut()) } + } +} diff --git a/ctru-rs/src/applets/mod.rs b/ctru-rs/src/applets/mod.rs index 244fb74f..838ef6b7 100644 --- a/ctru-rs/src/applets/mod.rs +++ b/ctru-rs/src/applets/mod.rs @@ -8,5 +8,6 @@ //! //! Applets block execution of the thread that launches them as long as the user doesn't close the applet. +pub mod error; pub mod mii_selector; pub mod swkbd; diff --git a/ctru-sys/build.rs b/ctru-sys/build.rs index 5e71ae05..ff140bb3 100644 --- a/ctru-sys/build.rs +++ b/ctru-sys/build.rs @@ -79,6 +79,8 @@ fn main() { .blocklist_type("u(8|16|32|64)") .blocklist_type("__builtin_va_list") .blocklist_type("__va_list") + .blocklist_type("errorReturnCode") + .blocklist_type("errorScreenFlag") .opaque_type("MiiData") .derive_default(true) .wrap_static_fns(true) diff --git a/ctru-sys/src/lib.rs b/ctru-sys/src/lib.rs index b9f71de9..38f0d37a 100644 --- a/ctru-sys/src/lib.rs +++ b/ctru-sys/src/lib.rs @@ -16,6 +16,22 @@ pub mod result; pub use result::*; +// Fun fact: bindgen can and will generate enum values of the wrong size, and if a generated struct contains fields +// using those values, then that struct will have the wrong size and field offsets too. To fix that problem, +// you have to blocklist the enum type in bindgen and manually define it with the proper data type. +pub const ERROR_UNKNOWN: errorReturnCode = -1; +pub const ERROR_NONE: errorReturnCode = 0; +pub const ERROR_SUCCESS: errorReturnCode = 1; +pub const ERROR_NOT_SUPPORTED: errorReturnCode = 2; +pub const ERROR_HOME_BUTTON: errorReturnCode = 10; +pub const ERROR_SOFTWARE_RESET: errorReturnCode = 11; +pub const ERROR_POWER_BUTTON: errorReturnCode = 12; +pub type errorReturnCode = libc::c_schar; + +pub const ERROR_NORMAL: errorScreenFlag = 0; +pub const ERROR_STEREO: errorScreenFlag = 1; +pub type errorScreenFlag = libc::c_char; + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); /// In lieu of a proper errno function exposed by libc