From 48e4780994894320df6eedb194502a5849470aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?joseLu=C3=ADs?= Date: Tue, 4 Feb 2025 15:33:51 +0100 Subject: [PATCH] update `ui` items MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add modules `ui::service::{self, crossterm, miniquad}`. - add items: `CrosstermService`, `MiniquadService`, `MiniquadWindow`, `MiniquadEventHandlerExt`. - re-export a few `miniquad` items. - enable `ui··` flag via ui-related dependencies. - make ui dependencies version-specific. - misc. refactors. - update docs. --- Cargo.toml | 6 +- DOCS/CHANGELOG.md | 4 +- build/features.rs | 5 +- src/ui/mod.rs | 7 +- src/ui/service/cap/definitions.rs | 6 +- src/ui/service/crossterm/mod.rs | 20 ++++ src/ui/service/crossterm/service.rs | 159 +++++++++++++++++++++++++++ src/ui/service/miniquad/reexports.rs | 28 +++++ src/ui/service/mod.rs | 17 ++- 9 files changed, 240 insertions(+), 12 deletions(-) create mode 100644 src/ui/service/crossterm/mod.rs create mode 100644 src/ui/service/crossterm/service.rs create mode 100644 src/ui/service/miniquad/reexports.rs diff --git a/Cargo.toml b/Cargo.toml index 93d0ef0a..dc9a2b18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -640,7 +640,8 @@ optional = true # unsafe default-features = false # 8 https://docs.rs/crate/const-str/latest/features [dependencies.crossterm] # https://crates.io/crates/crossterm -version = "0.28" # ✓ https://github.com/crossterm-rs/crossterm/blob/master/CHANGELOG.md +# In sync with src::ui::service::crossterm::service +version = "0.28.1" # ✓ https://github.com/crossterm-rs/crossterm/blob/master/CHANGELOG.md optional = true # unsafe default-features = false # 9 https://docs.rs/crate/crossterm/latest/features features = ["bracketed-paste", "events"] @@ -732,9 +733,12 @@ default-features = false # 7 https://docs.rs/crate/midir/latest/features # INSTALL: libasound2-dev [dependencies.miniquad] # https://crates.io/crates/miniquad +# In sync with src::ui::service::miniquad::service version = "0.4.7" # ✗ https://github.com/not-fl3/miniquad/commits/master/ optional = true # unsafe default-features = false # 1 https://docs.rs/crate/miniquad/latest/features +# WAIT: [update conf module to derive more traits](https://github.com/not-fl3/miniquad/pull/523) +# WAIT: [use AtomicPtr in NATIVE_DISPLAY](https://github.com/not-fl3/miniquad/pull/525) [dependencies.nc] # https://crates.io/crates/nc version = "0.9.5" # ✗ https://github.com/XuShaohua/nc/commits/main/ diff --git a/DOCS/CHANGELOG.md b/DOCS/CHANGELOG.md index e6c533a4..4345b0e2 100644 --- a/DOCS/CHANGELOG.md +++ b/DOCS/CHANGELOG.md @@ -14,13 +14,15 @@ - xifer: `DataValue*`, `DataType*`, `DataRaw*`, `NoData`, `Base`, `Crockford`, `Rfc4648`, `Rfc4648Hex`. - sys: `DirApple`, `DirWindows`, `DirUnix`, `DirXdg`, `LogConfig`, - ui: `UiCap`, `UiCapImage`, `UiCapInput`, `UiCapSound`, `UiCapSystem`, `UiCapWindow`. + - `CrosstermService`. + - `MiniquadService`, `MiniquadEventHandlerExt`. - namespaces: `Iter`, `Log`. - new macros: `maybe!`, `xorshift_custom!`. - new modules: - `data::{codec::{self, radix}, list, key, table, uid, xipher}`. - `lang::{c}`. - `sys::{log, net}`. - - `ui::service`. + - `ui::service::{self, crossterm, miniquad}`. - new macro arms: - `str!`: `ip_addr`. - new methods: diff --git a/build/features.rs b/build/features.rs index 69d411b2..5bbdf6c6 100644 --- a/build/features.rs +++ b/build/features.rs @@ -172,7 +172,10 @@ mod reflection { }; pub const UI: FlagsFeatures = FlagsFeatures { flags: &["ui··"], - features: &["ui", "layout"] + features: &[ + "ui", "layout", + "dep_crossterm", "dep_fltk", "dep_girls", "dep_miniquad", "dep_sdl2", "dep_sdl3", + ] }; pub const WORK: FlagsFeatures = FlagsFeatures { flags: &["work··"], diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 3efd2f61..f1ce3a7d 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -8,11 +8,8 @@ #[cfg(ui··)] crate::items! { - #[cfg_attr(feature = "nightly_doc", doc(cfg(ui··)))] mod error; - - #[cfg_attr(feature = "nightly_doc", doc(cfg(ui··)))] - pub mod service; // UiService*, ... + pub mod service; // UiService*, UiCap* } #[cfg(feature = "layout")] @@ -29,7 +26,7 @@ crate::items! { // structural access: _mods, _all, #[cfg(ui··)] pub use super::error::*; } - pub(super) mod _pub_mods { #![allow(unused)] + mod _pub_mods { #![allow(unused)] #[cfg(feature = "layout")] pub use super::layout::_all::*; diff --git a/src/ui/service/cap/definitions.rs b/src/ui/service/cap/definitions.rs index c0346d38..c56ab09b 100644 --- a/src/ui/service/cap/definitions.rs +++ b/src/ui/service/cap/definitions.rs @@ -23,7 +23,7 @@ pub struct UiCap { pub window: Option, } -/// Image-related capabilities. +/// Image capabilities. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct UiCapImage { /// Maximum bitmap size, in native pixels. @@ -41,7 +41,7 @@ pub struct UiCapImage { // pub palette_size: u16, } -/// General Input capabilities. +/// Input capabilities. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct UiCapInput { /// Gamepad input capabilities. @@ -56,7 +56,7 @@ pub struct UiCapInput { pub touchscreen: bool, } -/// Sound and music related capabilities. +/// Sound capabilities. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct UiCapSound { /// Sound playback capabilities. diff --git a/src/ui/service/crossterm/mod.rs b/src/ui/service/crossterm/mod.rs new file mode 100644 index 00000000..35492174 --- /dev/null +++ b/src/ui/service/crossterm/mod.rs @@ -0,0 +1,20 @@ +// devela::ui::service::crossterm +// +//! `crossterm` Ui service. +// + +mod service; +// mod events; + +crate::items! { // structural access: _mods, _all + #[allow(unused)] + pub use _mods::*; + + mod _mods { + pub use super::service::*; + } + pub(super) mod _all { #![allow(unused)] + #[doc(inline)] + pub use super::_mods::*; + } +} diff --git a/src/ui/service/crossterm/service.rs b/src/ui/service/crossterm/service.rs new file mode 100644 index 00000000..f95fcdd5 --- /dev/null +++ b/src/ui/service/crossterm/service.rs @@ -0,0 +1,159 @@ +// devela::ui::service::crossterm::service +// +//! Defines [`CrosstermService`]. +// +// ISSUES +// - WAIT: [add Event::Terminate](https://github.com/crossterm-rs/crossterm/issues/554) +// - WAIT: [support ctrl+z + fg](https://github.com/crossterm-rs/crossterm/issues/494) +// +// TODO +// - window refresh, render + +use ::crossterm::{event, execute, terminal}; + +// use core::time::Duration; +use std::io; + +use crate::{ + IoError, UiCap, UiCapImage, /* Event, EventSource, */ UiCapInput, + /* Window, */ UiCapWindow, UiService, +}; + +/// `crossterm`'s UI service. +// +// https://docs.rs/crossterm/latest/crossterm/terminal/index.html +pub struct CrosstermService; +// { raw_mode: bool, } + +// TODO +// impl Drop for CrosstermService { +// fn drop(&mut self) { +// if self.raw_mode { +// self.set_raw_mode(false); +// } +// } +// } + +impl CrosstermService { + /// Creates a new `CrosstermService`. + pub fn new() -> Result { + Ok(Self { /* raw_mode: false */ }) + } + + /// Tells whether the raw mode is enabled. + // + // https://docs.rs/crossterm/latest/crossterm/terminal/fn.is_raw_mode_enabled.html + #[inline] + pub fn is_raw_mode(&self) -> Result { + terminal::is_raw_mode_enabled() + } + + /// Enables the raw mode. + // + // https://docs.rs/crossterm/latest/crossterm/terminal/fn.enable_raw_mode.html + #[inline] + pub fn enable_raw_mode(&self) -> Result<(), IoError> { + terminal::enable_raw_mode() + } + + /// Disables the raw mode. + // + // https://docs.rs/crossterm/latest/crossterm/terminal/fn.disable_raw_mode.html + #[inline] + pub fn disable_raw_mode(&self) -> Result<(), IoError> { + terminal::disable_raw_mode() + } + + /// Switches to the alternate screen. + // + // https://docs.rs/crossterm/latest/crossterm/terminal/struct.EnterAlternateScreen.html + pub fn enter_alternate_screen(&self) -> Result<(), IoError> { + Ok(execute!(io::stdout(), terminal::EnterAlternateScreen)?) + } + + /// Switches back to the main screen. + // + // https://docs.rs/crossterm/latest/crossterm/terminal/struct.LeaveAlternateScreen.html + pub fn leave_alternate_screen(&self) -> Result<(), IoError> { + Ok(execute!(io::stdout(), terminal::EnterAlternateScreen)?) + } + + /// Enables receiving mouse events. + // + // https://docs.rs/crossterm/latest/crossterm/event/struct.EnableMouseCapture.html + pub fn enable_mouse(&mut self) -> Result<(), IoError> { + Ok(execute!(io::stdout(), event::EnableMouseCapture)?) + } + /// Disables receiving mouse events. + // + // https://docs.rs/crossterm/latest/crossterm/event/struct.DisableMouseCapture.html + pub fn disable_mouse(&mut self) -> Result<(), IoError> { + Ok(execute!(io::stdout(), event::DisableMouseCapture)?) + } + + // TODO + // /// Enables bracketed paste mode. + // // + // // https://docs.rs/crossterm/latest/crossterm/event/struct.EnableBracketedPaste.html + // pub fn enable_bracketed_paste(&self) -> Result<(), IoError> { + // Ok(execute!(io::stdout(), event::EnableBracketedPaste)?) + // } + // + // /// Disables bracketed paste mode. + // // + // // https://docs.rs/crossterm/latest/crossterm/event/struct.DisableBracketedPaste.html + // pub fn disable_bracketed_paste(&self) -> Result<(), IoError> { + // Ok(execute!(io::stdout(), event::DisableBracketedPaste)?) + // } + + /// Enables focus change mode. + // + // https://docs.rs/crossterm/latest/crossterm/event/struct.EnableFocusChange.html + pub fn enable_focus_change(&self) -> Result<(), IoError> { + Ok(execute!(io::stdout(), event::EnableFocusChange)?) + } + + /// Disables focus change mode. + // + // https://docs.rs/crossterm/latest/crossterm/event/struct.DisableFocusChange.html + pub fn disable_focus_change(&self) -> Result<(), IoError> { + Ok(execute!(io::stdout(), event::DisableFocusChange)?) + } +} + +impl UiService for CrosstermService { + fn capabilities(&self) -> UiCap { + let image = Some(UiCapImage { + rgb: true, + // palette_change: false, + // palette_size: ::crossterm::style::available_color_count(), + ..Default::default() + }); + + let input = Some(UiCapInput { keyboard: true, mouse: true, ..Default::default() }); + + // let text_grid = Some(UiCapTextGridCap { + // // we don't unknown + // cell_size: None, + // // https://github.com/crossterm-rs/crossterm/issues/166 + // // custom_cell_size: false, + // // // https://github.com/crossterm-rs/crossterm/issues/677 + // // unicode: true, + // // ..Default::default() + // }); + + let window = Some(UiCapWindow { multi: false }); + + UiCap { + image, + input, + // text_grid, + window, + ..Default::default() + } + } + + fn version(&self) -> (u32, u32, u32) { + (0, 28, 1) + } +} diff --git a/src/ui/service/miniquad/reexports.rs b/src/ui/service/miniquad/reexports.rs new file mode 100644 index 00000000..01631580 --- /dev/null +++ b/src/ui/service/miniquad/reexports.rs @@ -0,0 +1,28 @@ +// devela::ui::service::miniquad::reexports +// +//! +// + +use crate::reexport; + +/* structs */ + +reexport! { "dep_miniquad", "miniquad", miniquad::conf, + doc: "Describes a hardware and platform-specific setup.", + @Conf as MiniquadConf +} +reexport! { "dep_miniquad", "miniquad", miniquad::conf, + doc: "Platform-specific settings.", + @Platform as MiniquadPlatform +} + +/* traits */ + +reexport! { "dep_miniquad", "miniquad", miniquad, + doc: "Defines how an application responds to events in miniquad.", + @EventHandler as MiniquadEventHandler +} +reexport! { "dep_miniquad", "miniquad", miniquad::graphics, + doc: "Low-level interface for rendering operations in miniquad.", + @RenderingBackend as MiniquadRenderingBackend +} diff --git a/src/ui/service/mod.rs b/src/ui/service/mod.rs index d2ba5782..c97ac800 100644 --- a/src/ui/service/mod.rs +++ b/src/ui/service/mod.rs @@ -6,16 +6,31 @@ mod cap; mod definition; +#[cfg(feature = "dep_crossterm")] +#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "dep_crossterm")))] +pub mod crossterm; +#[cfg(feature = "dep_miniquad")] +#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "dep_miniquad")))] +pub mod miniquad; + crate::items! { // structural access: _mods, _all #[allow(unused)] pub use _mods::*; + #[allow(unused)] #[doc(hidden, no_inline)] + pub use _pub_mods::*; mod _mods { #[cfg(ui··)] pub use super::{cap::*, definition::*}; } + mod _pub_mods { #![allow(unused)] + #[cfg(feature = "dep_crossterm")] + pub use super::crossterm::_all::*; + #[cfg(feature = "dep_miniquad")] + pub use super::miniquad::_all::*; + } pub(super) mod _all { #![allow(unused)] #[doc(inline)] - pub use super::_mods::*; + pub use super::{_mods::*, _pub_mods::*}; } }