Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Window icons; some docs #228

Merged
merged 6 commits into from
Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions kas-theme/src/draw_shaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@ use kas::geom::Quad;
///
/// All methods draw some feature.
///
/// Methods are parameterised via a pair of normals, `(inner, outer)`. These may
/// have values from the closed range `[-1, 1]`, where -1 points inwards,
/// 0 is perpendicular to the screen towards the viewer, and 1 points outwards.
/// Methods are parameterised via a pair of normals, `(inner, outer)`, which
/// specify the surface normal direction at inner and outer edges of the feature
/// respectively (with interpolation between these edges). These have values
/// from the closed range `[-1, 1]`, where -1 points towards the inside of the
/// feature, 1 points away from the feature, and 0 is perpendicular to the
/// screen towards the viewer.
pub trait DrawShaded {
/// Add a shaded square to the draw buffer
///
/// For shading purposes, the mid-point is considered the inner edge.
fn shaded_square(&mut self, rect: Quad, norm: (f32, f32), col: Rgba);

/// Add a shaded circle to the draw buffer
///
/// For shading purposes, the mid-point is considered the inner edge.
fn shaded_circle(&mut self, rect: Quad, norm: (f32, f32), col: Rgba);

/// Add a square shaded frame to the draw buffer.
/// Add a shaded frame with square corners to the draw buffer
fn shaded_square_frame(
&mut self,
outer: Quad,
Expand All @@ -33,7 +40,7 @@ pub trait DrawShaded {
inner_col: Rgba,
);

/// Add a rounded shaded frame to the draw buffer.
/// Add a shaded frame with rounded corners to the draw buffer
fn shaded_round_frame(&mut self, outer: Quad, inner: Quad, norm: (f32, f32), col: Rgba);
}

Expand Down
15 changes: 7 additions & 8 deletions kas-theme/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@

//! KAS theme support
//!
//! This crate allows widget rendering to be customised via themes,
//! and provides mid-level draw implementations for widgets.
//! This crate provides the [`Theme`] trait, [`MultiTheme`] adapter, color
//! schemes, some supporting items, and the themes [`FlatTheme`] and
//! [`ShadedTheme`].
//!
//! Each [`Theme`] is expected to have [`Window`]-specific data,
//! and provides an implementation of [`kas::draw::DrawHandle`].
//!
//! Two themes are provided by this trait: [`FlatTheme`] and [`ShadedTheme`].
//! Additionally, a meta-theme, [`MultiTheme`], allows run-time switching
//! between themes.
//! Custom themes may be built over this crate, optionally including custom draw
//! routines (e.g. [`DrawShaded`]), provided that the shell implements support.
//! Alternatively this crate may be skipped altogether, especially for a
//! minimal shell with a custom fixed theme.

#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(feature = "gat", feature(generic_associated_types))]
Expand Down
5 changes: 4 additions & 1 deletion kas-wgpu/examples/gallery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ fn main() -> Result<(), kas_wgpu::Error> {
}
};

let window = Window::new(
let mut window = Window::new(
"Widget Gallery",
make_widget! {
#[layout(column)]
Expand Down Expand Up @@ -332,6 +332,9 @@ fn main() -> Result<(), kas_wgpu::Error> {
}
},
);
if let Err(err) = window.load_icon_from_path("res/gallery.png") {
println!("Failed to load window icon: {}", err);
}

toolkit.add(window)?;
toolkit.run()
Expand Down
3 changes: 1 addition & 2 deletions kas-wgpu/src/draw/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ pub trait CustomPipeBuilder {
/// [`crate::Toolkit::new_custom`].
///
/// Note that `kas-wgpu` accepts only a single custom pipe. To use more than
/// one, you will have to implement your own multiplexer (presumably using an
/// enum for the `Param` type).
/// one custom graphics pipeline, you must implement your own multiplexer.
pub trait CustomPipe: 'static {
/// Associated per-window state for the custom pipe
type Window: CustomWindow;
Expand Down
3 changes: 3 additions & 0 deletions kas-wgpu/src/draw/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::mem::size_of;
use std::num::NonZeroU32;

use super::{atlases, ShaderManager};
use kas::cast::Conv;
use kas::draw::{ImageError, ImageFormat, ImageId, PassId};
use kas::geom::{Quad, Vec2};

Expand All @@ -32,6 +33,8 @@ impl Image {
) {
// TODO(opt): use StagingBelt for upload (when supported)? Or our own equivalent.
let size = self.size;
assert!(data.len() > 0);
assert_eq!(data.len(), 4 * usize::conv(size.0) * usize::conv(size.1));
queue.write_texture(
wgpu::ImageCopyTexture {
texture: atlas_pipe.get_texture(self.atlas),
Expand Down
1 change: 0 additions & 1 deletion kas-wgpu/src/draw/shaded_round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ impl Pipeline {
}

impl Window {
/// Bounds on input: `0 ≤ inner_radius ≤ 1`.
pub fn circle(&mut self, pass: PassId, rect: Quad, mut norm: Vec2, col: Rgba) {
let aa = rect.a;
let bb = rect.b;
Expand Down
15 changes: 11 additions & 4 deletions kas-wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@

//! KAS shell over [winit] and [WebGPU]
//!
//! This crate provides an implementation of KAS, using [WebGPU] for
//! GPU-accelerated rendering.
//! This crate implements a KAS shell (backend) using [WebGPU] for
//! GPU-accelerated rendering and [winit] for windowing, thus it should be
//! portable to most desktop and potentially also mobile platforms.
//!
//! Windowing is provided by [winit].
//! Clipboard functionality is (currently) provided by the [clipboard] crate.
//! This crate supports themes via the [`kas_theme`] crate, including shaded
//! drawing.
//!
//! Custom GPU-accelerated drawing is supported via [`draw::CustomPipe`]
//! (see the [Mandlebrot example](https://github.com/kas-gui/kas/blob/master/kas-wgpu/examples/mandlebrot.rs)).
//!
//! By default, some environment variables are read for configuration.
//! See [`options::Options::from_env`] for documentation.
//!
//! [WebGPU]: https://github.com/gfx-rs/wgpu-rs
//! [winit]: https://github.com/rust-windowing/winit
Expand Down
10 changes: 4 additions & 6 deletions kas-wgpu/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl Options {
///
/// The following environment variables are read, in case-insensitive mode.
///
/// ### Config
/// # Config files
///
/// WARNING: file formats are not stable and may not be compatible across
/// KAS versions (aside from patch versions)!
Expand All @@ -83,22 +83,20 @@ impl Options {
///
/// - `Read` (default): read-only
/// - `ReadWrite`: read on start-up, write on exit
/// - `WriteDefault`: generate platform-default configuration, and write
/// it to the config path, overwriting any existing config
/// - `WriteDefault`: generate platform-default configuration and write
/// it to the config path(s) specified, overwriting any existing config
///
/// Note: in the future, the default will likely change to a read-write mode,
/// allowing changes to be written out.
///
/// ### Power preference
/// # Graphics options
///
/// The `KAS_POWER_PREFERENCE` variable supports:
///
/// - `Default`
/// - `LowPower`
/// - `HighPerformance`
///
/// ### Backend
///
/// The `KAS_BACKENDS` variable supports:
///
/// - `Vulkan`
Expand Down
5 changes: 4 additions & 1 deletion kas-wgpu/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ impl<C: CustomPipe, T: Theme<DrawPipe<C>>> Window<C, T> {
if restrict_dimensions.1 {
builder = builder.with_max_inner_size(ideal);
}
let window = builder.with_title(widget.title()).build(elwt)?;
let window = builder
.with_title(widget.title())
.with_window_icon(widget.icon())
.build(elwt)?;

shared.init_clipboard(&window);

Expand Down
4 changes: 4 additions & 0 deletions src/core/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ pub trait Window: Widget<Msg = event::VoidMsg> {
/// Get the window title
fn title(&self) -> &str;

/// Get the window icon, if any
#[cfg(feature = "winit")]
fn icon(&self) -> Option<winit::window::Icon>;

/// Whether to limit the maximum size of a window
///
/// All widgets' size rules allow calculation of two sizes: the minimum
Expand Down
4 changes: 4 additions & 0 deletions src/draw/draw_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ pub trait DrawShared {
///
/// This should be called at least once on each image before display. May be
/// called again to update the image contents.
///
/// `id` must refer to an allocation of some size `(w, h)`, such that
/// `data.len() == b * w * h` where `b` is the number of bytes per pixel,
/// according to `format`. Data must be in row-major order.
fn image_upload(&mut self, id: ImageId, data: &[u8], format: ImageFormat);

/// Load an image from a path, autodetecting file type
Expand Down
6 changes: 4 additions & 2 deletions src/draw/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl ImageId {
/// Image formats available for upload
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ImageFormat {
/// 8-bit RGBA values
/// 8-bit unsigned RGBA values (4 bytes per pixel)
Rgba8,
}

Expand Down Expand Up @@ -77,7 +77,9 @@ impl Images {
return Ok(*id);
}

let image = image::io::Reader::open(path)?.decode()?;
let image = image::io::Reader::open(path)?
.with_guessed_format()?
.decode()?;
// TODO(opt): we convert to RGBA8 since this is the only format common
// to both the image crate and WGPU. It may not be optimal however.
// It also assumes that the image colour space is sRGB.
Expand Down
13 changes: 7 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@

//! KAS GUI Toolkit
//!
//! KAS is a GUI library. This crate provides the following:
//! This is the main KAS crate, featuring:
//!
//! - the [`Widget`] trait family, with [`macros`] to implement them
//! - a [`layout`] solver and [`event`] handling for widgets
//! - building blocks including [`geom`] types and a [`draw`] API
//! - some pre-build widgets: the [`widget`] module
//! - high-level themable and mid-level [`draw`] APIs
//! - [`event`] handling code
//! - [`geom`]-etry types and widget [`layout`] solvers
//! - a [`widget`] library
//!
//! See also these external crates:
//!
//! - [`kas-theme`](https://crates.io/crates/kas-theme) - [docs.rs](https://docs.rs/kas-theme) - theme API + themes
//! - [`kas-wgpu`](https://crates.io/crates/kas-wgpu) - [docs.rs](https://docs.rs/kas-wgpu) - WebGPU + winit integration
//! - `kas-theme` - [crates.io](https://crates.io/crates/kas-theme) - [docs.rs](https://docs.rs/kas-theme) - theme API + themes
//! - `kas-wgpu` - [crates.io](https://crates.io/crates/kas-wgpu) - [docs.rs](https://docs.rs/kas-wgpu) - WebGPU + winit integration
//!
//! Also refer to:
//!
Expand Down
5 changes: 5 additions & 0 deletions src/widget/dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ impl<T: FormattableText + 'static> kas::Window for MessageBox<T> {
&self.title
}

#[cfg(feature = "winit")]
fn icon(&self) -> Option<winit::window::Icon> {
None // TODO
}

fn restrict_dimensions(&self) -> (bool, bool) {
(true, true)
}
Expand Down
44 changes: 41 additions & 3 deletions src/widget/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@

//! Window widgets

use smallvec::SmallVec;
use std::fmt::{self, Debug};

use kas::layout;
use kas::prelude::*;
use kas::{Future, WindowId};
use smallvec::SmallVec;
#[cfg(feature = "winit")]
use std::error::Error;
use std::fmt::{self, Debug};
#[cfg(feature = "winit")]
use std::path::Path;
#[cfg(feature = "winit")]
use winit::window::Icon;

/// The main instantiation of the [`Window`] trait.
#[derive(Widget)]
Expand All @@ -24,6 +29,8 @@ pub struct Window<W: Widget + 'static> {
w: W,
popups: SmallVec<[(WindowId, kas::Popup); 16]>,
drop: Option<(Box<dyn FnMut(&mut W)>, UpdateHandle)>,
#[cfg(feature = "winit")]
icon: Option<winit::window::Icon>,
}

impl<W: Widget> Debug for Window<W> {
Expand All @@ -47,6 +54,8 @@ impl<W: Widget + Clone> Clone for Window<W> {
w: self.w.clone(),
popups: Default::default(), // these are temporary; don't clone
drop: None, // we cannot clone this!
#[cfg(feature = "winit")]
icon: self.icon.clone(),
}
}
}
Expand All @@ -61,6 +70,8 @@ impl<W: Widget> Window<W> {
w,
popups: Default::default(),
drop: None,
#[cfg(feature = "winit")]
icon: None,
}
}

Expand Down Expand Up @@ -109,6 +120,28 @@ impl<W: Widget> Window<W> {
self.drop = Some((finish, update));
(future, update)
}

/// Set the window icon
#[cfg(feature = "winit")]
pub fn set_icon(&mut self, icon: Option<Icon>) {
self.icon = icon;
}

/// Load the window icon from a path
///
/// On error the icon is not set. The window may still be used.
#[cfg(feature = "winit")]
pub fn load_icon_from_path<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Box<dyn Error>> {
// TODO(opt): image loading could be de-duplicated with
// DrawShared::image_from_path, but this may not be worthwhile.
let im = image::io::Reader::open(path)?
.with_guessed_format()?
.decode()?
.into_rgba8();
let (w, h) = im.dimensions();
self.icon = Some(Icon::from_rgba(im.into_vec(), w, h)?);
Ok(())
}
}

impl<W: Widget> Layout for Window<W> {
Expand Down Expand Up @@ -165,6 +198,11 @@ impl<M: Into<VoidMsg>, W: Widget<Msg = M> + 'static> kas::Window for Window<W> {
&self.title
}

#[cfg(feature = "winit")]
fn icon(&self) -> Option<winit::window::Icon> {
self.icon.clone()
}

fn restrict_dimensions(&self) -> (bool, bool) {
self.restrict_dimensions
}
Expand Down