mirror of
https://github.com/danbulant/cushy
synced 2026-05-27 13:52:13 +00:00
Rounded rect drawing
This commit is contained in:
parent
8ae315e229
commit
aea9def07d
5 changed files with 107 additions and 11 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -623,7 +623,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "figures"
|
name = "figures"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/khonsulabs/figures#52d06f3623cdb47128f1537fdadfe190f7afa88e"
|
source = "git+https://github.com/khonsulabs/figures#4712514fbed861ad530bd48d4e62f8efcaa4df1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"euclid",
|
"euclid",
|
||||||
|
|
@ -1089,7 +1089,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kludgine"
|
name = "kludgine"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/khonsulabs/kludgine#74db2e6be9c79f384eafbe57af8fa92de8b8d03c"
|
source = "git+https://github.com/khonsulabs/kludgine#ca138e79a4b8ebc3bdd463006b1dadd3269183f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"alot",
|
"alot",
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ use kludgine::app::winit::event::{
|
||||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||||
};
|
};
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{IntoSigned, Point, Rect, ScreenScale, Size};
|
use kludgine::figures::{IntoSigned, IsZero, Point, Rect, ScreenScale, Size};
|
||||||
use kludgine::shapes::{Shape, StrokeOptions};
|
use kludgine::shapes::{Shape, StrokeOptions};
|
||||||
use kludgine::{Color, Kludgine};
|
use kludgine::{Color, Kludgine};
|
||||||
|
|
||||||
use crate::graphics::Graphics;
|
use crate::graphics::Graphics;
|
||||||
use crate::styles::components::{HighlightColor, LayoutOrder, WidgetBackground};
|
use crate::styles::components::{CornerRadius, HighlightColor, LayoutOrder, WidgetBackground};
|
||||||
use crate::styles::{ComponentDefinition, Styles, Theme, ThemePair};
|
use crate::styles::{ComponentDefinition, Styles, Theme, ThemePair};
|
||||||
use crate::utils::IgnorePoison;
|
use crate::utils::IgnorePoison;
|
||||||
use crate::value::{Dynamic, IntoValue, Value};
|
use crate::value::{Dynamic, IntoValue, Value};
|
||||||
|
|
@ -519,15 +519,49 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fills the background of this widget with `color`, honoring the current
|
||||||
|
/// [`CornerRadius`] setting.
|
||||||
|
///
|
||||||
|
/// If the alpha channel of `color` is 0, this function does nothing.
|
||||||
|
pub fn fill(&mut self, color: Color) {
|
||||||
|
if color.alpha() > 0 {
|
||||||
|
let visible_rect = Rect::from(self.gfx.region().size - (Px(1), Px(1)));
|
||||||
|
|
||||||
|
let radii = self.get(&CornerRadius);
|
||||||
|
let radii = radii.map(|r| r.into_px(self.gfx.scale()));
|
||||||
|
|
||||||
|
let focus_ring = if radii.is_zero() {
|
||||||
|
Shape::filled_rect(visible_rect, color)
|
||||||
|
} else {
|
||||||
|
Shape::filled_round_rect(visible_rect, radii, color)
|
||||||
|
};
|
||||||
|
self.gfx.draw_shape(&focus_ring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Strokes an outline around this widget's contents.
|
/// Strokes an outline around this widget's contents.
|
||||||
pub fn stroke_outline<Unit>(&mut self, color: Color, options: StrokeOptions<Unit>)
|
pub fn stroke_outline<Unit>(&mut self, color: Color, options: StrokeOptions<Unit>)
|
||||||
where
|
where
|
||||||
Unit: ScreenScale<Px = Px, Lp = Lp, UPx = UPx>,
|
Unit: ScreenScale<Px = Px, Lp = Lp, UPx = UPx> + IsZero,
|
||||||
{
|
{
|
||||||
let visible_rect = Rect::from(self.gfx.region().size - (Px(1), Px(1)));
|
if color.alpha() > 0 {
|
||||||
let focus_ring =
|
let visible_rect = Rect::from(self.gfx.region().size - (Px(1), Px(1)));
|
||||||
Shape::stroked_rect(visible_rect, color, options.into_px(self.gfx.scale()));
|
|
||||||
self.gfx.draw_shape(&focus_ring);
|
let radii = self.get(&CornerRadius);
|
||||||
|
let radii = radii.map(|r| r.into_px(self.gfx.scale()));
|
||||||
|
|
||||||
|
let focus_ring = if radii.is_zero() {
|
||||||
|
Shape::stroked_rect(visible_rect, color, options.into_px(self.gfx.scale()))
|
||||||
|
} else {
|
||||||
|
Shape::stroked_round_rect(
|
||||||
|
visible_rect,
|
||||||
|
radii,
|
||||||
|
color,
|
||||||
|
options.into_px(self.gfx.scale()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
self.gfx.draw_shape(&focus_ring);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the default focus ring for this widget.
|
/// Renders the default focus ring for this widget.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use ahash::AHashMap;
|
use ahash::AHashMap;
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{Fraction, IntoSigned, IntoUnsigned, Rect, ScreenScale, Size};
|
use kludgine::figures::{Fraction, IntoSigned, IntoUnsigned, IsZero, Rect, ScreenScale, Size};
|
||||||
|
use kludgine::shapes::CornerRadii;
|
||||||
use kludgine::Color;
|
use kludgine::Color;
|
||||||
use palette::{IntoColor, Okhsl, OklabHue, Srgb};
|
use palette::{IntoColor, Okhsl, OklabHue, Srgb};
|
||||||
|
|
||||||
|
|
@ -211,6 +212,18 @@ pub enum Component {
|
||||||
Custom(CustomComponent),
|
Custom(CustomComponent),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Component {
|
||||||
|
/// Returns a [`CustomComponent`] created from `component`.
|
||||||
|
///
|
||||||
|
/// Custom components allow storing nearly any type in the style system.
|
||||||
|
pub fn custom<T>(component: T) -> Self
|
||||||
|
where
|
||||||
|
T: RequireInvalidation + RefUnwindSafe + UnwindSafe + Debug + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
Self::Custom(CustomComponent::new(component))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Color> for Component {
|
impl From<Color> for Component {
|
||||||
fn from(value: Color) -> Self {
|
fn from(value: Color) -> Self {
|
||||||
Self::Color(value)
|
Self::Color(value)
|
||||||
|
|
@ -303,6 +316,42 @@ impl RequireInvalidation for Lp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Unit> From<CornerRadii<Unit>> for Component
|
||||||
|
where
|
||||||
|
Dimension: From<Unit>,
|
||||||
|
Unit: Debug + UnwindSafe + RefUnwindSafe + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
fn from(radii: CornerRadii<Unit>) -> Self {
|
||||||
|
let radii = CornerRadii {
|
||||||
|
top_left: Dimension::from(radii.top_left),
|
||||||
|
top_right: Dimension::from(radii.top_right),
|
||||||
|
bottom_right: Dimension::from(radii.bottom_right),
|
||||||
|
bottom_left: Dimension::from(radii.bottom_left),
|
||||||
|
};
|
||||||
|
Component::custom(radii)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Unit> RequireInvalidation for CornerRadii<Unit> {
|
||||||
|
fn requires_invalidation(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Component> for CornerRadii<Dimension> {
|
||||||
|
type Error = Component;
|
||||||
|
|
||||||
|
fn try_from(value: Component) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
Component::Custom(custom) => custom
|
||||||
|
.downcast()
|
||||||
|
.copied()
|
||||||
|
.ok_or_else(|| Component::Custom(custom)),
|
||||||
|
other => Err(other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A 1-dimensional measurement that may be automatically calculated.
|
/// A 1-dimensional measurement that may be automatically calculated.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum FlexibleDimension {
|
pub enum FlexibleDimension {
|
||||||
|
|
@ -373,6 +422,15 @@ impl From<Lp> for Dimension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IsZero for Dimension {
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Dimension::Px(x) => x.is_zero(),
|
||||||
|
Dimension::Lp(x) => x.is_zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ScreenScale for Dimension {
|
impl ScreenScale for Dimension {
|
||||||
type Lp = Lp;
|
type Lp = Lp;
|
||||||
type Px = Px;
|
type Px = Px;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
//! All style components supported by the built-in widgets.
|
//! All style components supported by the built-in widgets.
|
||||||
|
|
||||||
use kludgine::figures::units::Lp;
|
use kludgine::figures::units::Lp;
|
||||||
|
use kludgine::shapes::CornerRadii;
|
||||||
use kludgine::Color;
|
use kludgine::Color;
|
||||||
|
|
||||||
use crate::animation::easings::{EaseInOutQuadradic, EaseInQuadradic, EaseOutQuadradic};
|
use crate::animation::easings::{EaseInOutQuadradic, EaseInQuadradic, EaseOutQuadradic};
|
||||||
|
|
@ -133,5 +134,8 @@ define_components! {
|
||||||
/// A [`Color`] to be used as a background color for widgets that render an
|
/// A [`Color`] to be used as a background color for widgets that render an
|
||||||
/// opaque background.
|
/// opaque background.
|
||||||
OpaqueWidgetColor(Color, "opaque_color", .surface.opaque_widget)
|
OpaqueWidgetColor(Color, "opaque_color", .surface.opaque_widget)
|
||||||
|
/// A set of radius descriptions for how much roundness to apply to the
|
||||||
|
/// shapes of widgets.
|
||||||
|
CornerRadius(CornerRadii<Dimension>, "corner_radius", CornerRadii::from(Dimension::Lp(Lp::points(100))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -336,7 +336,7 @@ impl Widget for Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
let style = self.current_style(context);
|
let style = self.current_style(context);
|
||||||
context.gfx.fill(style.background);
|
context.fill(style.background);
|
||||||
|
|
||||||
let two_lp_stroke = StrokeOptions::lp_wide(Lp::points(2));
|
let two_lp_stroke = StrokeOptions::lp_wide(Lp::points(2));
|
||||||
context.stroke_outline(style.outline, two_lp_stroke);
|
context.stroke_outline(style.outline, two_lp_stroke);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue