Skip to content

Commit

Permalink
Merge pull request #452 from kas-gui/work3
Browse files Browse the repository at this point in the history
Misc: make PRIMARY default backend, fix transparency, public kas::decorations module
  • Loading branch information
dhardy authored May 28, 2024
2 parents 492486a + 1839237 commit 34b7f08
Show file tree
Hide file tree
Showing 16 changed files with 198 additions and 133 deletions.
1 change: 1 addition & 0 deletions crates/kas-core/src/app/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ pub trait AppGraphicsBuilder {
fn new_surface<'window, W>(
shared: &mut Self::Shared,
window: W,
transparent: bool,
) -> Result<Self::Surface<'window>>
where
W: rwh::HasWindowHandle + rwh::HasDisplayHandle + Send + Sync + 'window,
Expand Down
6 changes: 5 additions & 1 deletion crates/kas-core/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,11 @@ mod test {
todo!()
}

fn new_surface<'window, W>(_: &mut Self::Shared, _: W) -> Result<Self::Surface<'window>>
fn new_surface<'window, W>(
_: &mut Self::Shared,
_: W,
_: bool,
) -> Result<Self::Surface<'window>>
where
W: rwh::HasWindowHandle + rwh::HasDisplayHandle + Send + Sync + 'window,
Self: Sized,
Expand Down
9 changes: 7 additions & 2 deletions crates/kas-core/src/app/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use super::shared::{AppSharedState, AppState};
use super::{AppData, AppGraphicsBuilder};
use crate::cast::{Cast, Conv};
use crate::config::WindowConfig;
use crate::decorations::Decorations;
use crate::draw::{color::Rgba, AnimationState, DrawSharedImpl};
use crate::event::{ConfigCx, CursorIcon, EventState};
use crate::geom::{Coord, Rect, Size};
Expand Down Expand Up @@ -109,7 +110,7 @@ impl<A: AppData, G: AppGraphicsBuilder, T: Theme<G::Shared>> Window<A, G, T> {
attrs.title = self.widget.title().to_string();
attrs.visible = false;
attrs.transparent = self.widget.transparent();
attrs.decorations = self.widget.decorations() == kas::Decorations::Server;
attrs.decorations = self.widget.decorations() == Decorations::Server;
attrs.window_icon = self.widget.icon();
let (restrict_min, restrict_max) = self.widget.restrictions();
if restrict_min {
Expand Down Expand Up @@ -173,7 +174,11 @@ impl<A: AppData, G: AppGraphicsBuilder, T: Theme<G::Shared>> Window<A, G, T> {

// NOTE: usage of Arc is inelegant, but avoids lots of unsafe code
let window = Arc::new(window);
let mut surface = G::new_surface(&mut state.shared.draw.draw, window.clone())?;
let mut surface = G::new_surface(
&mut state.shared.draw.draw,
window.clone(),
self.widget.transparent(),
)?;
surface.do_resize(&mut state.shared.draw.draw, size);

let winit_id = window.id();
Expand Down
84 changes: 58 additions & 26 deletions crates/kas-core/src/decorations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// You may obtain a copy of the License in the LICENSE-APACHE file or at:
// https://www.apache.org/licenses/LICENSE-2.0

//! Title bar
//! Window title-bar and border decorations
//!
//! Note: due to definition in kas-core, some widgets must be duplicated.

Expand Down Expand Up @@ -104,7 +104,7 @@ impl_scope! {
#[widget {
Data = ();
}]
pub struct Label {
pub(crate) struct Label {
core: widget_core!(),
text: Text<String>,
}
Expand Down Expand Up @@ -166,7 +166,7 @@ impl_scope! {
#[widget {
hover_highlight = true;
}]
pub struct MarkButton<M: Clone + Debug + 'static> {
pub(crate) struct MarkButton<M: Clone + Debug + 'static> {
core: widget_core!(),
style: MarkStyle,
msg: M,
Expand Down Expand Up @@ -215,21 +215,72 @@ enum TitleBarButton {
}

impl_scope! {
/// A window's title bar (part of decoration)
/// A set of title-bar buttons
///
/// Currently, this consists of minimise, maximise and close buttons.
#[derive(Clone, Default)]
#[widget{
layout = row! [
// self.icon,
self.title,
MarkButton::new(MarkStyle::Point(Direction::Down), TitleBarButton::Minimize),
MarkButton::new(MarkStyle::Point(Direction::Up), TitleBarButton::Maximize),
MarkButton::new(MarkStyle::X, TitleBarButton::Close),
];
}]
pub struct TitleBarButtons {
core: widget_core!(),
}

impl Self {
/// Construct
#[inline]
pub fn new() -> Self {
TitleBarButtons {
core: Default::default(),
}
}
}

impl Events for Self {
type Data = ();

fn handle_messages(&mut self, cx: &mut EventCx, _: &Self::Data) {
if let Some(msg) = cx.try_pop() {
match msg {
TitleBarButton::Minimize => {
#[cfg(winit)]
if let Some(w) = cx.winit_window() {
w.set_minimized(true);
}
}
TitleBarButton::Maximize => {
#[cfg(winit)]
if let Some(w) = cx.winit_window() {
w.set_maximized(!w.is_maximized());
}
}
TitleBarButton::Close => cx.action(self, Action::CLOSE),
}
}
}
}
}

impl_scope! {
/// A window's title bar (part of decoration)
#[derive(Clone, Default)]
#[widget{
layout = row! [
// self.icon,
self.title,
self.buttons,
];
}]
pub struct TitleBar {
core: widget_core!(),
#[widget]
title: Label,
#[widget]
buttons: TitleBarButtons,
}

impl Self {
Expand All @@ -239,6 +290,7 @@ impl_scope! {
TitleBar {
core: Default::default(),
title: Label::new(title),
buttons: Default::default(),
}
}

Expand All @@ -265,25 +317,5 @@ impl_scope! {
_ => Unused,
}
}

fn handle_messages(&mut self, cx: &mut EventCx, _: &Self::Data) {
if let Some(msg) = cx.try_pop() {
match msg {
TitleBarButton::Minimize => {
#[cfg(winit)]
if let Some(w) = cx.winit_window() {
w.set_minimized(true);
}
}
TitleBarButton::Maximize => {
#[cfg(winit)]
if let Some(w) = cx.winit_window() {
w.set_maximized(!w.is_maximized());
}
}
TitleBarButton::Close => cx.action(self, Action::CLOSE),
}
}
}
}
}
96 changes: 48 additions & 48 deletions crates/kas-core/src/draw/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,53 @@ impl Rgba8Srgb {
)
}
}

/// Compile-time parser for sRGB and sRGBA colours
pub const fn try_parse_srgb(s: &[u8]) -> Result<Rgba8Srgb, ParseError> {
if s.len() != 6 && s.len() != 8 {
return Err(ParseError::Length);
}

// `val` is copied from the hex crate:
// Copyright (c) 2013-2014 The Rust Project Developers.
// Copyright (c) 2015-2020 The rust-hex Developers.
const fn val(c: u8) -> Result<u8, ()> {
match c {
b'A'..=b'F' => Ok(c - b'A' + 10),
b'a'..=b'f' => Ok(c - b'a' + 10),
b'0'..=b'9' => Ok(c - b'0'),
_ => Err(()),
}
}

const fn byte(a: u8, b: u8) -> Result<u8, ()> {
match (val(a), val(b)) {
(Ok(hi), Ok(lo)) => Ok(hi << 4 | lo),
_ => Err(()),
}
}

let r = byte(s[0], s[1]);
let g = byte(s[2], s[3]);
let b = byte(s[4], s[5]);
let a = if s.len() == 8 { byte(s[6], s[7]) } else { Ok(0xFF) };

match (r, g, b, a) {
(Ok(r), Ok(g), Ok(b), Ok(a)) => Ok(Rgba8Srgb([r, g, b, a])),
_ => Err(ParseError::InvalidHex),
}
}

/// Compile-time parser for sRGB and sRGBA colours
///
/// This method has worse diagnostics on error due to limited const-
pub const fn parse_srgb(s: &[u8]) -> Rgba8Srgb {
match Self::try_parse_srgb(s) {
Ok(result) => result,
Err(ParseError::Length) => panic!("invalid length (expected 6 or 8 bytes"),
Err(ParseError::InvalidHex) => panic!("invalid hex byte (expected 0-9, a-f or A-F)"),
}
}
}

impl From<Rgba8Srgb> for [u8; 4] {
Expand Down Expand Up @@ -303,54 +350,7 @@ impl std::str::FromStr for Rgba8Srgb {
if s[0] == b'#' {
s = &s[1..];
}
try_parse_srgb(&s)
}
}

/// Compile-time parser for sRGB and sRGBA colours
pub const fn try_parse_srgb(s: &[u8]) -> Result<Rgba8Srgb, ParseError> {
if s.len() != 6 && s.len() != 8 {
return Err(ParseError::Length);
}

// `val` is copied from the hex crate:
// Copyright (c) 2013-2014 The Rust Project Developers.
// Copyright (c) 2015-2020 The rust-hex Developers.
const fn val(c: u8) -> Result<u8, ()> {
match c {
b'A'..=b'F' => Ok(c - b'A' + 10),
b'a'..=b'f' => Ok(c - b'a' + 10),
b'0'..=b'9' => Ok(c - b'0'),
_ => Err(()),
}
}

const fn byte(a: u8, b: u8) -> Result<u8, ()> {
match (val(a), val(b)) {
(Ok(hi), Ok(lo)) => Ok(hi << 4 | lo),
_ => Err(()),
}
}

let r = byte(s[0], s[1]);
let g = byte(s[2], s[3]);
let b = byte(s[4], s[5]);
let a = if s.len() == 8 { byte(s[6], s[7]) } else { Ok(0xFF) };

match (r, g, b, a) {
(Ok(r), Ok(g), Ok(b), Ok(a)) => Ok(Rgba8Srgb([r, g, b, a])),
_ => Err(ParseError::InvalidHex),
}
}

/// Compile-time parser for sRGB and sRGBA colours
///
/// This method has worse diagnostics on error due to limited const-
pub const fn parse_srgb(s: &[u8]) -> Rgba8Srgb {
match try_parse_srgb(s) {
Ok(result) => result,
Err(ParseError::Length) => panic!("invalid length (expected 6 or 8 bytes"),
Err(ParseError::InvalidHex) => panic!("invalid hex byte (expected 0-9, a-f or A-F)"),
Rgba8Srgb::try_parse_srgb(&s)
}
}

Expand Down
3 changes: 1 addition & 2 deletions crates/kas-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ extern crate self as kas;
// internal modules:
mod action;
mod core;
mod decorations;
pub mod decorations;
mod popup;
mod root;

pub use crate::core::*;
pub use action::Action;
pub use decorations::Decorations;
pub use kas_macros::{autoimpl, extends, impl_default, widget};
pub use kas_macros::{cell_collection, collection, impl_anon, impl_scope, widget_index};
#[doc(inline)] pub use popup::Popup;
Expand Down
2 changes: 1 addition & 1 deletion crates/kas-core/src/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ impl<Data: 'static> Window<Data> {
}

/// Get the preference for window decorations
pub fn decorations(&self) -> crate::Decorations {
pub fn decorations(&self) -> Decorations {
self.decorations
}

Expand Down
Loading

0 comments on commit 34b7f08

Please sign in to comment.