no app-level overrides are needed now. 1. on Windows, the windows buttons now behave and are drawn just like all other apps -- proper bg coloring on hover and down, and the right sizing. 2. and for the caption label, it is centered properly (by accounting for the size of the windows_buttons button set), and then when the window is too narrow, it is left-aligned in the remaining space to ensure that it stil looks good.
250 lines
8.5 KiB
Rust
250 lines
8.5 KiB
Rust
use crate::{
|
|
animator::{Animator, AnimatorAction, AnimatorImpl, Play},
|
|
button::ButtonAction,
|
|
makepad_derive_widget::*,
|
|
makepad_draw::*,
|
|
widget::*,
|
|
};
|
|
|
|
script_mod! {
|
|
use mod.prelude.widgets_internal.*
|
|
use mod.widgets.*
|
|
|
|
let DesktopButtonType = set_type_default() do #(DesktopButtonType::script_api(vm))
|
|
mod.widgets.DesktopButtonType = DesktopButtonType
|
|
|
|
mod.widgets.DesktopButtonBase = #(DesktopButton::register_widget(vm))
|
|
|
|
mod.widgets.DesktopButton = set_type_default() do mod.widgets.DesktopButtonBase{
|
|
width: 46 height: 29
|
|
draw_bg +: {
|
|
button_type: instance(DesktopButtonType.Fullscreen)
|
|
hover: instance(0.0)
|
|
down: instance(0.0)
|
|
|
|
color: uniform(theme.color_label_inner)
|
|
color_hover: uniform(theme.color_label_inner_hover)
|
|
color_down: uniform(theme.color_label_inner_down)
|
|
|
|
bg_color: uniform(#00000000)
|
|
bg_color_hover: uniform(#00000000)
|
|
bg_color_down: uniform(#00000000)
|
|
|
|
pixel: fn() {
|
|
let sdf = Sdf2d.viewport(self.pos * self.rect_size)
|
|
sdf.aa = sdf.aa * 3.0
|
|
let sz = 4.5
|
|
let c = self.rect_size * vec2(0.5, 0.5)
|
|
|
|
// Draw background
|
|
let bg = self.bg_color
|
|
.mix(self.bg_color_hover, self.hover)
|
|
.mix(self.bg_color_down, self.down);
|
|
sdf.rect(0., 0., self.rect_size.x, self.rect_size.y);
|
|
sdf.fill(bg);
|
|
|
|
let color = self.color
|
|
.mix(self.color_hover, self.hover)
|
|
.mix(self.color_down, self.down)
|
|
|
|
match self.button_type {
|
|
DesktopButtonType.WindowsMin => {
|
|
sdf.move_to(c.x - sz, c.y)
|
|
sdf.line_to(c.x + sz, c.y)
|
|
sdf.stroke(color, 0.5 + 0.5 * self.draw_pass.dpi_dilate)
|
|
return sdf.result
|
|
}
|
|
DesktopButtonType.WindowsMax => {
|
|
sdf.rect(c.x - sz, c.y - sz, 2. * sz, 2. * sz)
|
|
sdf.stroke(color, 0.5 + 0.5 * self.draw_pass.dpi_dilate)
|
|
return sdf.result
|
|
}
|
|
DesktopButtonType.WindowsMaxToggled => {
|
|
let sz = 5.
|
|
sdf.rect(c.x - sz + 1., c.y - sz - 1., 2. * sz, 2. * sz)
|
|
sdf.stroke(#f, 0.5 + 0.5 * self.draw_pass.dpi_dilate)
|
|
sdf.rect(c.x - sz - 1., c.y - sz + 1., 2. * sz, 2. * sz)
|
|
sdf.stroke(color, 0.5 + 0.5 * self.draw_pass.dpi_dilate)
|
|
return sdf.result
|
|
}
|
|
DesktopButtonType.WindowsClose => {
|
|
sdf.move_to(c.x - sz, c.y - sz)
|
|
sdf.line_to(c.x + sz, c.y + sz)
|
|
sdf.move_to(c.x - sz, c.y + sz)
|
|
sdf.line_to(c.x + sz, c.y - sz)
|
|
sdf.stroke(color, 0.5 + 0.5 * self.draw_pass.dpi_dilate)
|
|
return sdf.result
|
|
}
|
|
DesktopButtonType.XRMode => {
|
|
let w = 12.
|
|
let h = 8.
|
|
sdf.box(c.x - w, c.y - h, 2. * w, 2. * h, 2.)
|
|
sdf.circle(c.x - 5.5, c.y, 3.5)
|
|
sdf.subtract()
|
|
sdf.circle(c.x + 5.5, c.y, 3.5)
|
|
sdf.subtract()
|
|
sdf.circle(c.x, c.y + h - 0.75, 2.5)
|
|
sdf.subtract()
|
|
sdf.fill(color)
|
|
return sdf.result
|
|
}
|
|
DesktopButtonType.Fullscreen => {
|
|
let sz = 8.
|
|
sdf.rect(c.x - sz, c.y - sz, 2. * sz, 2. * sz)
|
|
sdf.rect(c.x - sz + 1.5, c.y - sz + 1.5, 2. * (sz - 1.5), 2. * (sz - 1.5))
|
|
sdf.subtract()
|
|
sdf.rect(c.x - sz + 4., c.y - sz - 2., 2. * (sz - 4.), 2. * (sz + 2.))
|
|
sdf.subtract()
|
|
sdf.rect(c.x - sz - 2., c.y - sz + 4., 2. * (sz + 2.), 2. * (sz - 4.))
|
|
sdf.subtract()
|
|
sdf.fill(color)
|
|
return sdf.result
|
|
}
|
|
DesktopButtonType.RecordOff => {
|
|
let rr = 5.0
|
|
sdf.circle(c.x, c.y, rr)
|
|
sdf.stroke(#ff3b30, 1.0 + 0.5 * self.draw_pass.dpi_dilate)
|
|
return sdf.result
|
|
}
|
|
DesktopButtonType.RecordOn => {
|
|
let rr = 5.0
|
|
sdf.circle(c.x, c.y, rr)
|
|
sdf.fill(#ff3b30)
|
|
return sdf.result
|
|
}
|
|
}
|
|
return #f00
|
|
}
|
|
}
|
|
animator: Animator{
|
|
hover: {
|
|
default: @off
|
|
off: AnimatorState{
|
|
from: {all: Forward {duration: 0.1}}
|
|
apply: {
|
|
draw_bg: {down: 0.0, hover: 0.0}
|
|
}
|
|
}
|
|
|
|
on: AnimatorState{
|
|
from: {
|
|
all: Forward {duration: 0.1}
|
|
down: Snap
|
|
}
|
|
apply: {
|
|
draw_bg: {
|
|
down: 0.0
|
|
hover: 1.0
|
|
}
|
|
}
|
|
}
|
|
|
|
down: AnimatorState{
|
|
from: {all: Snap}
|
|
apply: {
|
|
draw_bg: {
|
|
down: 1.0
|
|
hover: 1.0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Script, ScriptHook)]
|
|
#[repr(u32)]
|
|
pub enum DesktopButtonType {
|
|
WindowsMin = 1,
|
|
WindowsMax = 2,
|
|
WindowsMaxToggled = 3,
|
|
WindowsClose = 4,
|
|
XRMode = 5,
|
|
#[pick]
|
|
Fullscreen = 6,
|
|
RecordOff = 7,
|
|
RecordOn = 8,
|
|
}
|
|
|
|
#[derive(Script, ScriptHook, Widget, Animator)]
|
|
pub struct DesktopButton {
|
|
#[uid]
|
|
uid: WidgetUid,
|
|
#[source]
|
|
source: ScriptObjectRef,
|
|
#[apply_default]
|
|
animator: Animator,
|
|
#[walk]
|
|
walk: Walk,
|
|
#[visible]
|
|
#[live(true)]
|
|
visible: bool,
|
|
#[redraw]
|
|
#[live]
|
|
draw_bg: DrawQuad,
|
|
}
|
|
|
|
impl Widget for DesktopButton {
|
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) {
|
|
if !self.visible {
|
|
return;
|
|
}
|
|
|
|
let uid = self.widget_uid();
|
|
if self.animator_handle_event(cx, event).must_redraw() {
|
|
self.draw_bg.redraw(cx);
|
|
}
|
|
|
|
match event.hits(cx, self.draw_bg.area()) {
|
|
Hit::FingerDown(fe) => {
|
|
cx.widget_action(uid, ButtonAction::Pressed(fe.modifiers));
|
|
self.animator_play(cx, ids!(hover.down));
|
|
}
|
|
Hit::FingerHoverIn(_) => {
|
|
cx.set_cursor(MouseCursor::Hand);
|
|
self.animator_play(cx, ids!(hover.on));
|
|
}
|
|
Hit::FingerHoverOut(_) => {
|
|
self.animator_play(cx, ids!(hover.off));
|
|
}
|
|
Hit::FingerLongPress(_) => {
|
|
cx.widget_action(uid, ButtonAction::LongPressed);
|
|
}
|
|
Hit::FingerUp(fe) => {
|
|
if fe.is_over {
|
|
cx.widget_action(uid, ButtonAction::Clicked(fe.modifiers));
|
|
if fe.device.has_hovers() {
|
|
self.animator_play(cx, ids!(hover.on));
|
|
} else {
|
|
self.animator_play(cx, ids!(hover.off));
|
|
}
|
|
} else {
|
|
cx.widget_action(uid, ButtonAction::Released(fe.modifiers));
|
|
self.animator_play(cx, ids!(hover.off));
|
|
}
|
|
}
|
|
_ => (),
|
|
};
|
|
}
|
|
|
|
fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
|
|
if !self.visible {
|
|
return DrawStep::done();
|
|
}
|
|
|
|
let _ = self.draw_bg.draw_walk(cx, walk);
|
|
DrawStep::done()
|
|
}
|
|
}
|
|
|
|
impl DesktopButtonRef {
|
|
pub fn clicked(&self, actions: &Actions) -> bool {
|
|
if let Some(item) = actions.find_widget_action(self.widget_uid()) {
|
|
matches!(item.cast(), ButtonAction::Clicked(_))
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
}
|