mirror of
https://github.com/wayvr-org/wayvr.git
synced 2026-10-28 21:02:27 +01:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94326603b5 | ||
|
|
340397f872 | ||
|
|
48e1818367 | ||
|
|
299b61b240 |
No files matched your search
@@ -9,8 +9,9 @@
|
||||
gap="8"
|
||||
round="8"/>
|
||||
|
||||
<!-- id -->
|
||||
<template name="GroupBox">
|
||||
<rectangle macro="group_box">
|
||||
<rectangle macro="group_box" id="rect">
|
||||
<CHILDREN/>
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<!-- device_name, device_icon -->
|
||||
<template name="DeviceSlider">
|
||||
<GroupBox>
|
||||
<GroupBox id="rect">
|
||||
<div width="100%" align_items="center" justify_content="center" gap="8">
|
||||
<sprite src_builtin="${device_icon}" width="16" height="16" color="on_background" />
|
||||
<label text="${device_name}" margin_right="8" size="12" weight="bold" color="on_background" />
|
||||
@@ -47,8 +47,17 @@
|
||||
|
||||
<elements>
|
||||
<div flex_direction="column" gap="4">
|
||||
<div id="devices" flex_direction="column" gap="4" max_height="400" overflow_y="scroll">
|
||||
<!--
|
||||
this div shouldn't be technically needed, but there's a bug in
|
||||
the newest taffy version (or we're doing something wrong),
|
||||
causing the scrollbar to show up, even if it's not overflowing.
|
||||
OVERFLOW_START_THRESHOLD_UNITS is already set to 3, but it's not
|
||||
sufficient enough in this case?? (margin_bottom="4" fixes that).
|
||||
-->
|
||||
<div width="100%" flex_direction="column" max_height="400" overflow_y="scroll">
|
||||
<div id="devices" width="100%" flex_direction="column" gap="4" margin_bottom="4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- bottom buttons -->
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div flex_direction="column" gap="8" width="100%" align_items="center">
|
||||
<div flex_direction="column" gap="8" width="100%" align_items="center" overflow_y="scroll">
|
||||
<div id="list_parent" flex_grow="1" flex_wrap="wrap" flex_direction="row" gap="4" width="100%" justify_content="center"></div>
|
||||
</div>
|
||||
</elements>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<rectangle position="absolute" width="100%" height="3" round="4" color="highlight(opacity-0.1)" />
|
||||
|
||||
<!-- Top bar contents -->
|
||||
<div gap="16" align_items="center">
|
||||
<div gap="16" align_items="center" id="top_bar_contents">
|
||||
<!-- Back button -->
|
||||
<Button id="but_back" width="48" height="48" color="on_background_contrast(transparent)" border_color="on_background_contrast(transparent)">
|
||||
<sprite src_builtin="@/dashboard/back.svg" width="24" height="24" color="on_background_contrast" />
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<layout version="2">
|
||||
<elements>
|
||||
<div id="list" gap="8" flex_wrap="wrap" align_self="baseline">
|
||||
<!-- filled-in at runtime -->
|
||||
<div flex_direction="column" overflow_y="scroll">
|
||||
<div id="list" gap="8" flex_direction="row" flex_wrap="wrap">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -1,11 +1,11 @@
|
||||
<layout version="2">
|
||||
<elements>
|
||||
<div flex_direction="column" gap="8" width="100%" align_items="center">
|
||||
<div flex_direction="column" gap="8" width="100%" >
|
||||
<div flex_direction="row" gap="4" align_self="end">
|
||||
<Button id="btn_refresh" tooltip="RELOAD_FROM_DISK" width="32" height="32" sprite_src_builtin="@/dashboard/refresh.svg" />
|
||||
<Button id="btn_download_skymaps" height="32" translation="APP_SETTINGS.BROWSE_ONLINE_CATALOG" sprite_src_builtin="@/dashboard/download.svg"/>
|
||||
</div>
|
||||
<div id="list_parent" gap="8" flex_direction="row" flex_wrap="wrap" />
|
||||
<div id="list_parent" gap="8" flex_direction="row" flex_wrap="wrap" overflow_y="scroll" justify_content="center"/>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -15,9 +15,12 @@
|
||||
flex_direction="column"
|
||||
gap="4"
|
||||
width="256"
|
||||
max_width="450"
|
||||
height="200"
|
||||
align_items="center"
|
||||
flex_grow="1"
|
||||
align_self="start">
|
||||
<image id="image_preview" width="100%" height="128" round="6">
|
||||
<image id="image_preview" width="100%" aspect_ratio="2.0" round="6">
|
||||
<!-- new_pass is required, because we need to render rectangles at the top of the image. Sorry. -->
|
||||
<div new_pass="1" id="resolution_pips" gap="4" margin="6"/>
|
||||
</image>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{marker::PhantomData, rc::Rc};
|
||||
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
assets::AssetPathRef,
|
||||
color::{WguiColor, WguiColorName, WguiNamedColor},
|
||||
components::{ComponentTrait, button::ComponentButton},
|
||||
@@ -61,7 +61,7 @@ fn get_supporter_anim(
|
||||
Animation::new_ex(
|
||||
btn.base().get_id(),
|
||||
1234,
|
||||
480,
|
||||
AnimationDuration::SecondsFixed(8.0),
|
||||
AnimationEasing::Linear,
|
||||
Box::new(move |common, data| {
|
||||
let opacity_in = f32::clamp(data.pos * FADE_SPEED, 0.0, 1.0);
|
||||
|
||||
@@ -3,7 +3,9 @@ use std::{
|
||||
rc::{Rc, Weak},
|
||||
};
|
||||
|
||||
use glam::Vec2;
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
assets::AssetPathRef,
|
||||
components::button::ComponentButton,
|
||||
event::{EventAlterables, StyleSetRequest},
|
||||
@@ -12,7 +14,7 @@ use wgui::{
|
||||
layout::{Layout, LayoutTask, LayoutTasks, WidgetID},
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
taffy::Rect,
|
||||
widget::label::WidgetLabel,
|
||||
widget::{WidgetObj, label::WidgetLabel},
|
||||
};
|
||||
use wlx_common::config::GeneralConfig;
|
||||
|
||||
@@ -251,6 +253,13 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
struct MountPopupPrepareResult {
|
||||
popup_handle: PopupHandle,
|
||||
id_content: WidgetID,
|
||||
id_top_bar_contents: WidgetID,
|
||||
id_popup_title: WidgetID,
|
||||
}
|
||||
|
||||
impl PopupManager {
|
||||
pub fn new(params: PopupManagerParams) -> Self {
|
||||
Self {
|
||||
@@ -273,7 +282,7 @@ impl PopupManager {
|
||||
frontend_tasks: &FrontendTasks,
|
||||
popup_title: &Translation,
|
||||
popup_padding: PopupPadding,
|
||||
) -> anyhow::Result<(PopupHandle, WidgetID /* content widget ID */)> {
|
||||
) -> anyhow::Result<MountPopupPrepareResult> {
|
||||
let doc_params = &ParseDocumentParams {
|
||||
globals: globals.clone(),
|
||||
path: AssetPathRef::BuiltIn("gui/view/popup_window.xml"),
|
||||
@@ -283,6 +292,7 @@ impl PopupManager {
|
||||
|
||||
let id_root = state.get_widget_id("root")?;
|
||||
let id_content = state.get_widget_id("content")?;
|
||||
let id_top_bar_contents = state.get_widget_id("top_bar_contents")?;
|
||||
|
||||
let padding = match popup_padding {
|
||||
PopupPadding::Normal => 16.0_f32,
|
||||
@@ -294,10 +304,11 @@ impl PopupManager {
|
||||
StyleSetRequest::Padding(Rect::length(padding)),
|
||||
));
|
||||
|
||||
{
|
||||
let id_popup_title = {
|
||||
let mut label_title = state.fetch_widget_as::<WidgetLabel>(&layout.state, "popup_title")?;
|
||||
label_title.set_text_simple(&mut globals.get(), popup_title.clone());
|
||||
}
|
||||
label_title.get_id()
|
||||
};
|
||||
|
||||
let but_back = state.fetch_component_as::<ComponentButton>("but_back")?;
|
||||
|
||||
@@ -338,7 +349,13 @@ impl PopupManager {
|
||||
});
|
||||
|
||||
frontend_tasks.push(FrontendTask::RefreshPopupManager);
|
||||
Ok((popup_handle, id_content))
|
||||
|
||||
Ok(MountPopupPrepareResult {
|
||||
popup_handle,
|
||||
id_content,
|
||||
id_top_bar_contents,
|
||||
id_popup_title,
|
||||
})
|
||||
}
|
||||
|
||||
/// Mount a new popup on top of the existing popup stack.
|
||||
@@ -356,18 +373,43 @@ impl PopupManager {
|
||||
anyhow::bail!("mount_popup_once called more than once");
|
||||
};
|
||||
|
||||
let (popup_handle, id_content) =
|
||||
self.mount_popup_prepare(globals, layout, frontend_tasks, ¶ms.title, params.extra.padding)?;
|
||||
let res = self.mount_popup_prepare(globals, layout, frontend_tasks, ¶ms.title, params.extra.padding)?;
|
||||
|
||||
// text fade-in
|
||||
Animation::effect_label_fade_in(
|
||||
res.id_popup_title,
|
||||
AnimationDuration::Seconds(0.25),
|
||||
AnimationEasing::OutQuad,
|
||||
)
|
||||
.submit_l(layout);
|
||||
|
||||
// top bar slide
|
||||
Animation::effect_slide(
|
||||
res.id_top_bar_contents,
|
||||
AnimationDuration::Seconds(0.5),
|
||||
AnimationEasing::OutQuint,
|
||||
Vec2::new(10.0, 0.0),
|
||||
)
|
||||
.submit_l(layout);
|
||||
|
||||
// content slide
|
||||
Animation::effect_slide(
|
||||
res.id_content,
|
||||
AnimationDuration::Seconds(0.5),
|
||||
AnimationEasing::OutQuint,
|
||||
Vec2::new(5.0, 0.0),
|
||||
)
|
||||
.submit_l(layout);
|
||||
|
||||
// mount user-set popup content
|
||||
let closed_callback = on_content_func(PopupContentFuncData {
|
||||
layout,
|
||||
handle: popup_handle.clone(),
|
||||
id_content,
|
||||
handle: res.popup_handle.clone(),
|
||||
id_content: res.id_content,
|
||||
config,
|
||||
})?;
|
||||
|
||||
popup_handle.state.borrow_mut().closed_callback = Some(closed_callback);
|
||||
res.popup_handle.state.borrow_mut().closed_callback = Some(closed_callback);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use glam::{Mat4, Vec3};
|
||||
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
color::{WguiColor, WguiColorName},
|
||||
components::tooltip::{TOOLTIP_BORDER_COLOR, TOOLTIP_COLOR},
|
||||
i18n::Translation,
|
||||
@@ -45,7 +45,9 @@ impl Drop for MountedToast {
|
||||
}
|
||||
}
|
||||
|
||||
const TOAST_DURATION_TICKS: u32 = 150;
|
||||
fn def_toast_duration() -> AnimationDuration {
|
||||
AnimationDuration::Seconds(2.5)
|
||||
}
|
||||
|
||||
impl ToastManager {
|
||||
pub fn new() -> Self {
|
||||
@@ -116,9 +118,9 @@ impl ToastManager {
|
||||
let (label, _) = layout.add_child(rect.id, label, taffy::Style { ..Default::default() })?;
|
||||
|
||||
// show-up animation
|
||||
layout.animations.add(Animation::new(
|
||||
Animation::new(
|
||||
rect.id,
|
||||
(TOAST_DURATION_TICKS as f32 * layout.state.theme.animation_mult) as u32,
|
||||
def_toast_duration(),
|
||||
AnimationEasing::Linear,
|
||||
Box::new(move |common, data| {
|
||||
let pos_showup = AnimationEasing::OutQuint.interpolate((data.pos * 4.0).min(1.0));
|
||||
@@ -143,7 +145,8 @@ impl ToastManager {
|
||||
);
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
));
|
||||
)
|
||||
.submit_l(layout);
|
||||
|
||||
state.toast = Some(MountedToast {
|
||||
id_root: root.id,
|
||||
@@ -165,7 +168,7 @@ impl ToastManager {
|
||||
|
||||
if state.timeout == 0 {
|
||||
state.toast = None;
|
||||
state.timeout = TOAST_DURATION_TICKS;
|
||||
state.timeout = def_toast_duration().to_ticks(layout.state.ticks_per_second, layout.state.theme.animation_mult);
|
||||
// mount next
|
||||
if let Some(content) = state.queue.pop_front() {
|
||||
self.mount_toast(layout, &mut state, content)?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use glam::{Mat4, Vec2};
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
assets::AssetPathRef,
|
||||
color::WguiColorName,
|
||||
components::{self, button::ButtonClickCallback},
|
||||
@@ -145,9 +145,9 @@ pub fn create_loading(par: CreateLoadingParams) -> anyhow::Result<WidgetID> {
|
||||
let id_root = data.get_widget_id("root")?;
|
||||
let id_sprite_loading = data.get_widget_id("sprite_loading")?;
|
||||
|
||||
par.layout.animations.add(Animation::new(
|
||||
Animation::new(
|
||||
id_sprite_loading,
|
||||
60 * 30, /* spin it for 30 seconds at most */
|
||||
AnimationDuration::SecondsFixed(120.0), /* spin it for 120 seconds at most */
|
||||
AnimationEasing::Linear,
|
||||
Box::new(move |common, data| {
|
||||
// spin it
|
||||
@@ -161,7 +161,8 @@ pub fn create_loading(par: CreateLoadingParams) -> anyhow::Result<WidgetID> {
|
||||
}
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
));
|
||||
)
|
||||
.submit_l(par.layout);
|
||||
|
||||
Ok(id_root)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ use wgui::{
|
||||
layout::{Layout, WidgetID},
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
|
||||
task::Tasks,
|
||||
widget::ConstructEssentials,
|
||||
widget::{ConstructEssentials, rectangle::WidgetRectangle},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -802,6 +802,13 @@ impl View {
|
||||
par,
|
||||
)?;
|
||||
|
||||
if params.checked {
|
||||
let rect = data.fetch_widget(¶ms.layout.state, "rect")?;
|
||||
let mut rect = rect.widget.cast::<WidgetRectangle>()?;
|
||||
rect.set_color(&mut params.layout.common(), WguiColorName::BackgroundVariant.into());
|
||||
rect.set_border_color(&mut params.layout.common(), WguiColorName::Primary.into());
|
||||
}
|
||||
|
||||
let mut common = params.layout.common();
|
||||
let checkbox = data.fetch_component_as::<ComponentCheckbox>("checkbox")?;
|
||||
let btn_mute = data.fetch_component_as::<ComponentButton>("btn_mute")?;
|
||||
|
||||
@@ -6,22 +6,23 @@
|
||||
padding="16"
|
||||
flex_direction="column"
|
||||
gap="8"
|
||||
color="background" border_color="outline" border="2" round="8">
|
||||
color="background" border_color="outline" border="2" round="8"
|
||||
id="rect">
|
||||
|
||||
<!-- Toast title -->
|
||||
<div flex_direction="row" align_items="center" gap="8">
|
||||
<sprite src="@/icons/bell.svg" color="primary" min_width="32" min_height="32" max_width="32" max_height="32" flex_grow="1" />
|
||||
<label wrap="1" id="toast_title" color="primary" weight="bold" size="25" padding_left="16" padding_right="16" />
|
||||
<div flex_direction="row" align_items="center" gap="8" id="div_title">
|
||||
<sprite id="sprite_bell" src="@/icons/bell.svg" color="primary" min_width="32" min_height="32" max_width="32" max_height="32" flex_grow="1" />
|
||||
<label wrap="1" id="label_title" color="primary" weight="bold" size="25" padding_left="16" padding_right="16" />
|
||||
</div>
|
||||
|
||||
<!-- A simple separator -->
|
||||
<rectangle width="100%" height="2" color="outline" />
|
||||
<rectangle id="rect_separator" width="100%" height="2" color="outline" />
|
||||
|
||||
<div>
|
||||
<!-- Toast message -->
|
||||
<label id="toast_body" color="on_background" wrap="1" size="20" padding_left="16" padding_right="16" />
|
||||
<label id="label_body" color="on_background" wrap="1" size="20" padding_left="16" padding_right="16" />
|
||||
</div>
|
||||
</rectangle>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
</layout>
|
||||
@@ -625,6 +625,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
)
|
||||
.with_timeout(1.0)
|
||||
.with_lerp_amount(1.0)
|
||||
.with_animate(false)
|
||||
.with_sound(i == 0)
|
||||
.submit_at(app, now + Duration::from_secs(i as _));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::rc::Rc;
|
||||
|
||||
use anyhow::Context;
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
color::{WguiColor, WguiColorName},
|
||||
components::button::ComponentButton,
|
||||
event::CallbackDataCommon,
|
||||
@@ -76,11 +76,7 @@ impl InteractLockHandler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(
|
||||
&mut self,
|
||||
common: &mut CallbackDataCommon,
|
||||
anim_mult: f32,
|
||||
) -> Box<ModifyOverlayTask> {
|
||||
pub fn toggle(&mut self, common: &mut CallbackDataCommon) -> Box<ModifyOverlayTask> {
|
||||
let rect_color = self.color;
|
||||
|
||||
self.interactable = !self.interactable;
|
||||
@@ -91,7 +87,7 @@ impl InteractLockHandler {
|
||||
let anim = if self.interactable {
|
||||
Animation::new(
|
||||
self.id,
|
||||
(10. * anim_mult) as _,
|
||||
AnimationDuration::Seconds(0.1666),
|
||||
AnimationEasing::OutQuad,
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
@@ -108,7 +104,7 @@ impl InteractLockHandler {
|
||||
} else {
|
||||
Animation::new(
|
||||
self.id,
|
||||
(10. * anim_mult) as _,
|
||||
AnimationDuration::Seconds(0.1666),
|
||||
AnimationEasing::OutBack,
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
|
||||
@@ -365,8 +365,6 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
resize: ResizeState::None,
|
||||
};
|
||||
|
||||
let anim_mult = app.wgui_theme.animation_mult;
|
||||
|
||||
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, parser, attribs, _app| {
|
||||
let Ok(button) = parser
|
||||
.fetch_component_from_widget_id_as::<ComponentButton>(&layout.state, attribs.widget_id)
|
||||
@@ -395,7 +393,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
}
|
||||
|
||||
let sel = OverlaySelector::Id(*state.id.borrow());
|
||||
let task = state.lock.toggle(common, anim_mult);
|
||||
let task = state.lock.toggle(common);
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::Modify(sel, task)));
|
||||
Ok(EventResult::Consumed)
|
||||
|
||||
@@ -15,7 +15,7 @@ use anyhow::Context;
|
||||
use glam::{FloatExt, Mat4, Vec2, vec2, vec3};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
assets::AssetPathRef,
|
||||
color::{WguiColor, WguiColorName},
|
||||
event::{self, CallbackMetadata, EventListenerKind},
|
||||
@@ -74,8 +74,6 @@ pub(super) fn create_keyboard_panel(
|
||||
|
||||
let doc_params = new_doc_params(&mut panel);
|
||||
|
||||
let anim_mult = app.wgui_theme.animation_mult;
|
||||
|
||||
let root = panel
|
||||
.parser_state
|
||||
.get_widget_id("keyboard_root")
|
||||
@@ -206,7 +204,7 @@ pub(super) fn create_keyboard_panel(
|
||||
let k = key_state.clone();
|
||||
move |common, data, _app, _state| {
|
||||
common.alterables.trigger_haptics();
|
||||
on_enter_anim(k.clone(), common, data, anim_mult, width_mul);
|
||||
on_enter_anim(k.clone(), common, data, width_mul);
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
@@ -218,7 +216,7 @@ pub(super) fn create_keyboard_panel(
|
||||
let k = key_state.clone();
|
||||
move |common, data, _app, _state| {
|
||||
common.alterables.trigger_haptics();
|
||||
on_leave_anim(k.clone(), common, data, anim_mult, width_mul);
|
||||
on_leave_anim(k.clone(), common, data, width_mul);
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
@@ -415,12 +413,11 @@ fn on_enter_anim(
|
||||
key_state: Rc<KeyState>,
|
||||
common: &mut event::CallbackDataCommon,
|
||||
data: &event::CallbackData,
|
||||
anim_mult: f32,
|
||||
width_mult: f32,
|
||||
) {
|
||||
common.alterables.animate(Animation::new(
|
||||
Animation::new(
|
||||
data.widget_id,
|
||||
(10. * anim_mult) as _,
|
||||
AnimationDuration::Seconds(0.1666),
|
||||
AnimationEasing::OutBack,
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
@@ -456,19 +453,19 @@ fn on_enter_anim(
|
||||
get_anim_transform(data.pos, data.widget_boundary.size, width_mult);
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
));
|
||||
)
|
||||
.submit(common.alterables);
|
||||
}
|
||||
|
||||
fn on_leave_anim(
|
||||
key_state: Rc<KeyState>,
|
||||
common: &mut event::CallbackDataCommon,
|
||||
data: &event::CallbackData,
|
||||
anim_mult: f32,
|
||||
width_mult: f32,
|
||||
) {
|
||||
common.alterables.animate(Animation::new(
|
||||
Animation::new(
|
||||
data.widget_id,
|
||||
(15. * anim_mult) as _,
|
||||
AnimationDuration::Seconds(0.25),
|
||||
AnimationEasing::OutQuad,
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
@@ -506,7 +503,8 @@ fn on_leave_anim(
|
||||
get_anim_transform(1.0 - data.pos, data.widget_boundary.size, width_mult);
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
));
|
||||
)
|
||||
.submit(common.alterables);
|
||||
}
|
||||
|
||||
fn on_press_anim(
|
||||
|
||||
+115
-5
@@ -5,9 +5,11 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use glam::{Affine3A, Quat, Vec3, vec3};
|
||||
use glam::{Affine3A, Quat, Vec2, Vec3, vec3};
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationDuration, AnimationEasing, AnimationStartDelay},
|
||||
i18n::{I18n, Translation},
|
||||
parser::Fetchable,
|
||||
widget::label::WidgetLabel,
|
||||
};
|
||||
use wlx_common::{
|
||||
@@ -30,6 +32,7 @@ pub struct ToastParams {
|
||||
pub opacity: f32,
|
||||
pub timeout: f32,
|
||||
pub lerp_amount: f32,
|
||||
pub animate: bool,
|
||||
pub sound: bool,
|
||||
pub topic: ToastTopic,
|
||||
}
|
||||
@@ -56,6 +59,7 @@ impl Toast {
|
||||
opacity: 1.0,
|
||||
lerp_amount: 0.1,
|
||||
timeout: 3.0,
|
||||
animate: true,
|
||||
sound: false,
|
||||
topic,
|
||||
},
|
||||
@@ -82,6 +86,11 @@ impl Toast {
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn with_animate(mut self, animate: bool) -> Self {
|
||||
self.params.animate = animate;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn submit(self, app: &mut AppState) {
|
||||
self.submit_at(app, Instant::now());
|
||||
}
|
||||
@@ -200,21 +209,21 @@ fn new_toast(toast: BakedToast, app: &mut AppState) -> Option<OverlayWindowConfi
|
||||
|
||||
let on_custom_id: OnCustomIdFunc<()> =
|
||||
Box::new(move |id, widget, _doc_params, layout, _parser_state, ()| {
|
||||
if &*id == "toast_title" {
|
||||
if &*id == "label_title" {
|
||||
let mut label = layout
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetLabel>(widget)
|
||||
.context("toast.xml: missing element with id: toast_title")?;
|
||||
.context("toast.xml: missing element with id: label_title")?;
|
||||
let mut globals = layout.state.globals.get();
|
||||
label.set_text_simple(&mut globals, title.clone());
|
||||
}
|
||||
if &*id == "toast_body" {
|
||||
if &*id == "label_body" {
|
||||
let mut label = layout
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetLabel>(widget)
|
||||
.context("toast.xml: missing element with id: toast_body")?;
|
||||
.context("toast.xml: missing element with id: label_body")?;
|
||||
let mut globals = layout.state.globals.get();
|
||||
label.set_text_simple(&mut globals, body.clone());
|
||||
}
|
||||
@@ -233,6 +242,107 @@ fn new_toast(toast: BakedToast, app: &mut AppState) -> Option<OverlayWindowConfi
|
||||
.inspect_err(|e| log::error!("Could not create toast: {e:?}"))
|
||||
.ok()?;
|
||||
|
||||
// animations
|
||||
if toast.params.animate {
|
||||
let id_div_title = panel.parser_state.get_widget_id("div_title").ok()?;
|
||||
let id_label_body = panel.parser_state.get_widget_id("label_body").ok()?;
|
||||
let id_label_title = panel.parser_state.get_widget_id("label_title").ok()?;
|
||||
let id_rect = panel.parser_state.get_widget_id("rect").ok()?;
|
||||
let id_rect_separator = panel.parser_state.get_widget_id("rect_separator").ok()?;
|
||||
let id_sprite_bell = panel.parser_state.get_widget_id("sprite_bell").ok()?;
|
||||
|
||||
// schedule timeouts
|
||||
let time_window = 0.5;
|
||||
if toast.params.timeout > time_window && toast.params.timeout < 150.0 {
|
||||
let dur = AnimationDuration::SecondsFixed(time_window);
|
||||
let easing = AnimationEasing::OutQuad;
|
||||
|
||||
let mut add = |a: Animation| {
|
||||
a.reversed()
|
||||
.delayed(AnimationStartDelay::SecondsFixed(
|
||||
toast.params.timeout - time_window,
|
||||
))
|
||||
.with_id(1)
|
||||
.submit_l(&mut panel.layout);
|
||||
};
|
||||
|
||||
add(Animation::effect_rectangle_fade_in(id_rect, dur, easing));
|
||||
add(Animation::effect_scale(
|
||||
id_rect_separator,
|
||||
dur,
|
||||
easing,
|
||||
Vec2::new(0.0, 1.0),
|
||||
Vec2::new(1.0, 1.0),
|
||||
));
|
||||
add(Animation::effect_label_fade_in(id_label_title, dur, easing));
|
||||
add(Animation::effect_label_fade_in(id_label_body, dur, easing));
|
||||
add(Animation::effect_sprite_fade_in(
|
||||
id_sprite_bell,
|
||||
dur,
|
||||
easing,
|
||||
));
|
||||
}
|
||||
|
||||
// separator scale
|
||||
Animation::effect_scale(
|
||||
id_rect_separator,
|
||||
AnimationDuration::Seconds(1.0),
|
||||
AnimationEasing::OutBack,
|
||||
Vec2::new(0.0, 1.0),
|
||||
Vec2::new(1.0, 1.0),
|
||||
)
|
||||
.submit_l(&mut panel.layout);
|
||||
|
||||
// rectangle opacity
|
||||
Animation::effect_rectangle_fade_in(
|
||||
id_rect,
|
||||
AnimationDuration::Seconds(0.5),
|
||||
AnimationEasing::OutQuad,
|
||||
)
|
||||
.submit_l(&mut panel.layout);
|
||||
|
||||
// title animation
|
||||
Animation::effect_slide(
|
||||
id_div_title,
|
||||
AnimationDuration::Seconds(1.0),
|
||||
AnimationEasing::OutQuint,
|
||||
Vec2::new(15.0, 0.0),
|
||||
)
|
||||
.submit_l(&mut panel.layout);
|
||||
|
||||
Animation::effect_label_fade_in(
|
||||
id_label_title,
|
||||
AnimationDuration::Seconds(0.5),
|
||||
AnimationEasing::OutQuad,
|
||||
)
|
||||
.submit_l(&mut panel.layout);
|
||||
|
||||
Animation::effect_sprite_fade_in(
|
||||
id_sprite_bell,
|
||||
AnimationDuration::Seconds(0.5),
|
||||
AnimationEasing::OutQuad,
|
||||
)
|
||||
.submit_l(&mut panel.layout);
|
||||
|
||||
// body animation
|
||||
Animation::effect_slide(
|
||||
id_label_body,
|
||||
AnimationDuration::Seconds(1.0),
|
||||
AnimationEasing::OutQuint,
|
||||
Vec2::new(15.0, 0.0),
|
||||
)
|
||||
.delayed(AnimationStartDelay::Seconds(0.3))
|
||||
.submit_l(&mut panel.layout);
|
||||
|
||||
Animation::effect_label_fade_in(
|
||||
id_label_body,
|
||||
AnimationDuration::Seconds(0.5),
|
||||
AnimationEasing::OutQuint,
|
||||
)
|
||||
.delayed(AnimationStartDelay::Seconds(0.3))
|
||||
.submit_l(&mut panel.layout);
|
||||
}
|
||||
|
||||
panel
|
||||
.update_layout(app)
|
||||
.context("layout update failed")
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
|
||||
use glam::Affine3A;
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
color::WguiColor,
|
||||
components::button::ComponentButton,
|
||||
drawing::Color,
|
||||
@@ -97,10 +97,10 @@ fn start_progress_state(
|
||||
let id_rect_vu_meter = state.id_rect_vu_meter;
|
||||
let id_label_progress = state.id_label_progress;
|
||||
|
||||
common.alterables.animate(Animation::new_ex(
|
||||
Animation::new_ex(
|
||||
id_rect_vu_meter, /* any tbh */
|
||||
0,
|
||||
60 * 120, // max 120 seconds (whisper_stt MAX_DURATION is currently set to 30, account for processing time)
|
||||
AnimationDuration::SecondsFixed(120.0), // max 120 seconds (whisper_stt MAX_DURATION is currently set to 30, account for processing time)
|
||||
AnimationEasing::Linear,
|
||||
Box::new(move |common, data| {
|
||||
let rect_vu_meter = data.obj.cast_mut::<WidgetRectangle>().unwrap();
|
||||
@@ -156,7 +156,8 @@ fn start_progress_state(
|
||||
);
|
||||
}
|
||||
}),
|
||||
));
|
||||
)
|
||||
.submit(common.alterables);
|
||||
}
|
||||
|
||||
fn reset_progress_state(common: &mut CallbackDataCommon, state: &WhisperState) {
|
||||
|
||||
+217
-17
@@ -1,12 +1,14 @@
|
||||
use glam::FloatExt;
|
||||
use glam::{FloatExt, Mat4, Vec2, Vec3};
|
||||
|
||||
use crate::{
|
||||
drawing::Boundary,
|
||||
event::{CallbackDataCommon, EventAlterables},
|
||||
layout::{LayoutState, WidgetID},
|
||||
widget::{WidgetData, WidgetObj},
|
||||
layout::{Layout, LayoutState, WidgetID},
|
||||
renderer_vk::{self},
|
||||
widget::{WidgetData, WidgetObj, label::WidgetLabel, rectangle::WidgetRectangle, sprite::WidgetSprite},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AnimationEasing {
|
||||
Linear,
|
||||
InQuad, // ^2
|
||||
@@ -53,12 +55,55 @@ pub struct CallbackData<'a> {
|
||||
}
|
||||
|
||||
pub type AnimationCallback = Box<dyn Fn(&mut CallbackDataCommon, &mut CallbackData)>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AnimationDuration {
|
||||
Seconds(f32), // multiplied by animation_mult
|
||||
SecondsFixed(f32),
|
||||
Infinity,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AnimationStartDelay {
|
||||
Seconds(f32), // multiplied by animation_mult
|
||||
SecondsFixed(f32),
|
||||
}
|
||||
|
||||
impl AnimationDuration {
|
||||
pub fn to_ticks(&self, ticks_per_seconds: u32, animation_mult: f32) -> u32 {
|
||||
match self {
|
||||
AnimationDuration::Seconds(secs) => (secs * ticks_per_seconds as f32 * animation_mult) as u32,
|
||||
AnimationDuration::SecondsFixed(secs) => (secs * ticks_per_seconds as f32) as u32,
|
||||
AnimationDuration::Infinity => u32::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AnimationStartDelay {
|
||||
pub fn to_ticks(&self, ticks_per_seconds: u32, animation_mult: f32) -> u32 {
|
||||
match self {
|
||||
AnimationStartDelay::Seconds(secs) => (secs * ticks_per_seconds as f32 * animation_mult) as u32,
|
||||
AnimationStartDelay::SecondsFixed(secs) => (secs * ticks_per_seconds as f32) as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Ticks {
|
||||
delay: u32,
|
||||
remaining: u32,
|
||||
duration: u32,
|
||||
}
|
||||
|
||||
pub struct Animation {
|
||||
target_widget: WidgetID,
|
||||
|
||||
id: u32,
|
||||
ticks_remaining: u32,
|
||||
ticks_duration: u32,
|
||||
duration: AnimationDuration,
|
||||
start_delay_secs: Option<AnimationStartDelay>,
|
||||
reversed: bool,
|
||||
|
||||
// filled-in at first iteration
|
||||
ticks: Option<Ticks>,
|
||||
|
||||
easing: AnimationEasing,
|
||||
|
||||
@@ -70,14 +115,136 @@ pub struct Animation {
|
||||
}
|
||||
|
||||
impl Animation {
|
||||
pub fn new(target_widget: WidgetID, ticks: u32, easing: AnimationEasing, callback: AnimationCallback) -> Self {
|
||||
Self::new_ex(target_widget, 0, ticks, easing, callback)
|
||||
pub fn new(
|
||||
target_widget: WidgetID,
|
||||
duration: AnimationDuration,
|
||||
easing: AnimationEasing,
|
||||
callback: AnimationCallback,
|
||||
) -> Self {
|
||||
Self::new_ex(target_widget, 0, duration, easing, callback)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn delayed(self, delay: AnimationStartDelay) -> Self {
|
||||
let mut this = self;
|
||||
this.start_delay_secs = Some(delay);
|
||||
this
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn with_id(self, id: u32) -> Self {
|
||||
let mut this = self;
|
||||
this.id = id;
|
||||
this
|
||||
}
|
||||
|
||||
// invert pos with 1.0 - pos
|
||||
#[must_use]
|
||||
pub const fn reversed(self) -> Self {
|
||||
let mut this = self;
|
||||
this.reversed = true;
|
||||
this
|
||||
}
|
||||
|
||||
pub fn submit(self, alterables: &mut EventAlterables) {
|
||||
alterables.animate(self);
|
||||
}
|
||||
|
||||
pub fn submit_l(self, layout: &mut Layout) {
|
||||
self.submit(&mut layout.alterables);
|
||||
}
|
||||
|
||||
pub fn effect_slide(
|
||||
target_widget: WidgetID,
|
||||
duration: AnimationDuration,
|
||||
easing: AnimationEasing,
|
||||
dir: Vec2,
|
||||
) -> Self {
|
||||
Animation::new(
|
||||
target_widget,
|
||||
duration,
|
||||
easing,
|
||||
Box::new(move |common, data| {
|
||||
data.data.transform =
|
||||
Mat4::from_translation(Vec3::new((1.0 - data.pos) * dir.x, (1.0 - data.pos) * dir.y, 0.0));
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn effect_scale(
|
||||
target_widget: WidgetID,
|
||||
duration: AnimationDuration,
|
||||
easing: AnimationEasing,
|
||||
from: Vec2,
|
||||
to: Vec2, // (1.0, 1.0) - normal scale
|
||||
) -> Self {
|
||||
Animation::new(
|
||||
target_widget,
|
||||
duration,
|
||||
easing,
|
||||
Box::new(move |common, data| {
|
||||
let scale = Vec3::new(from.x.lerp(to.x, data.pos), from.y.lerp(to.y, data.pos), 0.0);
|
||||
data.data.transform = renderer_vk::util::centered_matrix(data.widget_boundary.size, &Mat4::from_scale(scale));
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn effect_label_fade_in(target_widget: WidgetID, duration: AnimationDuration, easing: AnimationEasing) -> Self {
|
||||
Animation::new(
|
||||
target_widget,
|
||||
duration,
|
||||
easing,
|
||||
Box::new(move |common, data| {
|
||||
let Ok(label) = data.obj.cast_mut::<WidgetLabel>() else {
|
||||
debug_assert!(false); // cast failed
|
||||
return;
|
||||
};
|
||||
label.set_color(common, label.get_color().with_alpha(data.pos), true);
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn effect_rectangle_fade_in(
|
||||
target_widget: WidgetID,
|
||||
duration: AnimationDuration,
|
||||
easing: AnimationEasing,
|
||||
) -> Self {
|
||||
Animation::new(
|
||||
target_widget,
|
||||
duration,
|
||||
easing,
|
||||
Box::new(move |common, data| {
|
||||
let Ok(rectangle) = data.obj.cast_mut::<WidgetRectangle>() else {
|
||||
debug_assert!(false); // cast failed
|
||||
return;
|
||||
};
|
||||
rectangle.set_color(common, rectangle.get_color().with_alpha(data.pos));
|
||||
rectangle.set_border_color(common, rectangle.get_border_color().with_alpha(data.pos));
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn effect_sprite_fade_in(target_widget: WidgetID, duration: AnimationDuration, easing: AnimationEasing) -> Self {
|
||||
Animation::new(
|
||||
target_widget,
|
||||
duration,
|
||||
easing,
|
||||
Box::new(move |common, data| {
|
||||
let Ok(sprite) = data.obj.cast_mut::<WidgetSprite>() else {
|
||||
debug_assert!(false); // cast failed
|
||||
return;
|
||||
};
|
||||
sprite.set_color(common, sprite.get_color().with_alpha(data.pos));
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_ex(
|
||||
target_widget: WidgetID,
|
||||
animation_id: u32,
|
||||
ticks: u32,
|
||||
duration: AnimationDuration,
|
||||
easing: AnimationEasing,
|
||||
callback: AnimationCallback,
|
||||
) -> Self {
|
||||
@@ -86,21 +253,25 @@ impl Animation {
|
||||
id: animation_id,
|
||||
callback,
|
||||
easing,
|
||||
ticks_duration: ticks,
|
||||
ticks_remaining: ticks,
|
||||
duration,
|
||||
ticks: None,
|
||||
last_tick: false,
|
||||
pos: 0.0,
|
||||
pos_prev: 0.0,
|
||||
start_delay_secs: None,
|
||||
reversed: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// @returns false if it wants to be stopped
|
||||
#[must_use]
|
||||
fn call(&self, state: &LayoutState, alterables: &mut EventAlterables, pos: f32) -> bool {
|
||||
fn call(&self, state: &LayoutState, alterables: &mut EventAlterables, raw_pos: f32) -> bool {
|
||||
let Some(widget) = state.widgets.get(self.target_widget).cloned() else {
|
||||
return false; // failed
|
||||
};
|
||||
|
||||
let pos = if self.reversed { 1.0 - raw_pos } else { raw_pos };
|
||||
|
||||
let mut widget_state = widget.state();
|
||||
let (data, obj) = widget_state.get_data_obj_mut();
|
||||
let mut stop_me = false;
|
||||
@@ -130,8 +301,27 @@ pub struct Animations {
|
||||
impl Animations {
|
||||
pub fn tick(&mut self, state: &LayoutState, alterables: &mut EventAlterables) {
|
||||
for anim in &mut self.running_animations {
|
||||
let x = 1.0 - (anim.ticks_remaining as f32 / anim.ticks_duration as f32);
|
||||
let pos = if anim.ticks_remaining > 0 {
|
||||
let mut ticks = anim.ticks.take().unwrap_or_else(|| {
|
||||
let ticks = anim
|
||||
.duration
|
||||
.to_ticks(state.ticks_per_second, state.theme.animation_mult);
|
||||
Ticks {
|
||||
remaining: ticks,
|
||||
duration: ticks,
|
||||
delay: anim.start_delay_secs.map_or(0, |delay| {
|
||||
delay.to_ticks(state.ticks_per_second, state.theme.animation_mult)
|
||||
}),
|
||||
}
|
||||
});
|
||||
|
||||
if ticks.delay > 0 {
|
||||
ticks.delay -= 1;
|
||||
anim.ticks = Some(ticks);
|
||||
continue;
|
||||
}
|
||||
|
||||
let x = 1.0 - (ticks.remaining as f32 / ticks.duration as f32);
|
||||
let pos = if ticks.remaining > 0 {
|
||||
anim.easing.interpolate(x)
|
||||
} else {
|
||||
anim.last_tick = true;
|
||||
@@ -145,8 +335,10 @@ impl Animations {
|
||||
let _ = anim.call(state, alterables, 1.0);
|
||||
alterables.needs_redraw = true;
|
||||
} else {
|
||||
anim.ticks_remaining -= 1;
|
||||
ticks.remaining -= 1;
|
||||
}
|
||||
|
||||
anim.ticks = Some(ticks);
|
||||
}
|
||||
|
||||
self.running_animations.retain(|anim| !anim.last_tick);
|
||||
@@ -155,15 +347,23 @@ impl Animations {
|
||||
pub fn process(&mut self, state: &LayoutState, alterables: &mut EventAlterables, alpha: f32) {
|
||||
for anim in &mut self.running_animations {
|
||||
let pos = anim.pos_prev.lerp(anim.pos, alpha);
|
||||
if !anim.call(state, alterables, pos) {
|
||||
anim.ticks_remaining = 0;
|
||||
if !anim.call(state, alterables, pos)
|
||||
&& let Some(ticks) = &mut anim.ticks
|
||||
{
|
||||
ticks.remaining = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, anim: Animation) {
|
||||
pub fn add(&mut self, anim: Animation, state: &LayoutState, alterables: &mut EventAlterables) {
|
||||
// prevent running two animations at once
|
||||
self.stop_by_widget(anim.target_widget, Some(anim.id));
|
||||
|
||||
// call the animation for the first time with pos 0.0
|
||||
if !anim.call(state, alterables, 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.running_animations.push(anim);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
assets::AssetPathRef,
|
||||
color::{ParentColor, WguiColor, WguiColorName},
|
||||
components::{
|
||||
@@ -266,17 +266,15 @@ impl ComponentButton {
|
||||
return;
|
||||
}
|
||||
|
||||
let (anim_mult, gradient_intensity) = {
|
||||
let gradient_intensity = {
|
||||
let theme = &common.state.theme;
|
||||
(theme.animation_mult, theme.gradient_intensity)
|
||||
theme.gradient_intensity
|
||||
};
|
||||
|
||||
let anim_ticks = if sticky_down { 5. } else { 10. };
|
||||
|
||||
let state = self.state.clone();
|
||||
let anim = Animation::new(
|
||||
self.data.id_rect,
|
||||
(anim_ticks * anim_mult) as _,
|
||||
AnimationDuration::Seconds(if sticky_down { 0.083 } else { 0.1666 }),
|
||||
AnimationEasing::OutCubic,
|
||||
Box::new(move |common, anim_data| {
|
||||
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
@@ -383,10 +381,10 @@ fn anim_hover(
|
||||
rect.params.border_color = init_border_color.lerp(&globals.palette, &colors.hover_border_color, mult);
|
||||
}
|
||||
|
||||
fn anim_hover_create(state: Rc<RefCell<State>>, widget_id: WidgetID, fade_in: bool, anim_mult: f32) -> Animation {
|
||||
fn anim_hover_create(state: Rc<RefCell<State>>, widget_id: WidgetID, fade_in: bool) -> Animation {
|
||||
Animation::new(
|
||||
widget_id,
|
||||
((if fade_in { 5. } else { 10. }) * anim_mult) as _,
|
||||
AnimationDuration::Seconds(if fade_in { 0.0833 } else { 0.1666 }),
|
||||
AnimationEasing::OutCubic,
|
||||
Box::new(move |common, anim_data| {
|
||||
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
@@ -413,7 +411,6 @@ fn register_event_mouse_enter(
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection,
|
||||
tooltip_info: Option<components::tooltip::TooltipInfo>,
|
||||
anim_mult: f32,
|
||||
) -> EventListenerID {
|
||||
listeners.register(
|
||||
EventListenerKind::MouseEnter,
|
||||
@@ -423,7 +420,7 @@ fn register_event_mouse_enter(
|
||||
common.alterables.mark_redraw();
|
||||
common
|
||||
.alterables
|
||||
.animate(anim_hover_create(state.clone(), event_data.widget_id, true, anim_mult));
|
||||
.animate(anim_hover_create(state.clone(), event_data.widget_id, true));
|
||||
|
||||
ComponentTooltip::register_hover_in(common, &tooltip_info, data.id_rect, state.clone());
|
||||
|
||||
@@ -433,18 +430,14 @@ fn register_event_mouse_enter(
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_leave(
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection,
|
||||
anim_mult: f32,
|
||||
) -> EventListenerID {
|
||||
fn register_event_mouse_leave(state: Rc<RefCell<State>>, listeners: &mut EventListenerCollection) -> EventListenerID {
|
||||
listeners.register(
|
||||
EventListenerKind::MouseLeave,
|
||||
Box::new(move |common, event_data, (), ()| {
|
||||
common.alterables.trigger_haptics();
|
||||
common
|
||||
.alterables
|
||||
.animate(anim_hover_create(state.clone(), event_data.widget_id, false, anim_mult));
|
||||
.animate(anim_hover_create(state.clone(), event_data.widget_id, false));
|
||||
let mut state = state.borrow_mut();
|
||||
state.active_tooltip = None;
|
||||
state.hovered = false;
|
||||
@@ -702,11 +695,10 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||
id: root.id,
|
||||
lhandles: {
|
||||
let listeners = &mut root.widget.state().event_listeners;
|
||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||
vec![
|
||||
register_event_mouse_cancel(state.clone(), listeners),
|
||||
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip, anim_mult),
|
||||
register_event_mouse_leave(state.clone(), listeners, anim_mult),
|
||||
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip),
|
||||
register_event_mouse_leave(state.clone(), listeners),
|
||||
register_event_mouse_press(state.clone(), listeners),
|
||||
register_event_mouse_release(data.clone(), state.clone(), listeners),
|
||||
]
|
||||
|
||||
@@ -8,7 +8,7 @@ use taffy::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
color::{WguiColor, WguiColorName},
|
||||
components::{
|
||||
Component, ComponentBase, ComponentTrait, DestroyData, RefreshData,
|
||||
@@ -182,11 +182,11 @@ fn anim_hover(anim_data: &mut crate::animation::CallbackData<'_>, pos: f32, _pre
|
||||
};
|
||||
}
|
||||
|
||||
fn anim_hover_in(state: &Rc<RefCell<State>>, data: &Rc<Data>, anim_mult: f32) -> Animation {
|
||||
fn anim_hover_in(state: &Rc<RefCell<State>>, data: &Rc<Data>) -> Animation {
|
||||
let down = state.borrow().down;
|
||||
Animation::new(
|
||||
data.id_outer_box,
|
||||
(5. * anim_mult) as _,
|
||||
AnimationDuration::Seconds(0.0833),
|
||||
AnimationEasing::OutQuad,
|
||||
Box::new(move |common, anim_data| {
|
||||
anim_hover(anim_data, anim_data.pos, down);
|
||||
@@ -195,11 +195,11 @@ fn anim_hover_in(state: &Rc<RefCell<State>>, data: &Rc<Data>, anim_mult: f32) ->
|
||||
)
|
||||
}
|
||||
|
||||
fn anim_hover_out(state: &Rc<RefCell<State>>, data: &Rc<Data>, anim_mult: f32) -> Animation {
|
||||
fn anim_hover_out(state: &Rc<RefCell<State>>, data: &Rc<Data>) -> Animation {
|
||||
let down = state.borrow().down;
|
||||
Animation::new(
|
||||
data.id_outer_box,
|
||||
(8. * anim_mult) as _,
|
||||
AnimationDuration::Seconds(0.0833),
|
||||
AnimationEasing::OutQuad,
|
||||
Box::new(move |common, anim_data| {
|
||||
anim_hover(anim_data, 1.0 - anim_data.pos, down);
|
||||
@@ -213,13 +213,12 @@ fn register_event_mouse_enter(
|
||||
data: Rc<Data>,
|
||||
listeners: &mut EventListenerCollection,
|
||||
tooltip_info: Option<tooltip::TooltipInfo>,
|
||||
anim_mult: f32,
|
||||
) -> EventListenerID {
|
||||
listeners.register(
|
||||
EventListenerKind::MouseEnter,
|
||||
Box::new(move |common, _event_data, (), ()| {
|
||||
common.alterables.trigger_haptics();
|
||||
common.alterables.animate(anim_hover_in(&state, &data, anim_mult));
|
||||
anim_hover_in(&state, &data).submit(common.alterables);
|
||||
|
||||
ComponentTooltip::register_hover_in(common, &tooltip_info, data.id_container, state.clone());
|
||||
|
||||
@@ -247,13 +246,12 @@ fn register_event_mouse_leave(
|
||||
state: Rc<RefCell<State>>,
|
||||
data: Rc<Data>,
|
||||
listeners: &mut EventListenerCollection,
|
||||
anim_mult: f32,
|
||||
) -> EventListenerID {
|
||||
listeners.register(
|
||||
EventListenerKind::MouseLeave,
|
||||
Box::new(move |common, _event_data, (), ()| {
|
||||
common.alterables.trigger_haptics();
|
||||
common.alterables.animate(anim_hover_out(&state, &data, anim_mult));
|
||||
anim_hover_out(&state, &data).submit(common.alterables);
|
||||
|
||||
let checked = {
|
||||
let mut state = state.borrow_mut();
|
||||
@@ -509,10 +507,9 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||
id: root.id,
|
||||
lhandles: {
|
||||
let listeners = &mut root.widget.state().event_listeners;
|
||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||
vec![
|
||||
register_event_mouse_enter(state.clone(), data.clone(), listeners, params.tooltip, anim_mult),
|
||||
register_event_mouse_leave(state.clone(), data.clone(), listeners, anim_mult),
|
||||
register_event_mouse_enter(state.clone(), data.clone(), listeners, params.tooltip),
|
||||
register_event_mouse_leave(state.clone(), data.clone(), listeners),
|
||||
register_event_mouse_cancel(state.clone(), listeners),
|
||||
register_event_mouse_press(state.clone(), data.clone(), listeners),
|
||||
register_event_mouse_release(data.clone(), state.clone(), listeners),
|
||||
|
||||
@@ -7,7 +7,7 @@ use glam::FloatExt;
|
||||
use taffy::prelude::{auto, length, percent};
|
||||
|
||||
use crate::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
color::{WguiColor, WguiColorName},
|
||||
components::{Component, ComponentBase, ComponentTrait, FocusChangeData, RefreshData},
|
||||
event::{self, CallbackDataCommon, CallbackMetadata, EventListenerCollection, EventListenerKind, StyleSetRequest},
|
||||
@@ -53,58 +53,46 @@ pub struct ComponentEditBox {
|
||||
state: Rc<RefCell<State>>,
|
||||
}
|
||||
|
||||
fn anim_bottom_rect(
|
||||
common: &mut CallbackDataCommon,
|
||||
accent_color: WguiColor,
|
||||
id_rect: WidgetID,
|
||||
anim_mult: f32,
|
||||
focused: bool,
|
||||
) {
|
||||
common.alterables.animate(Animation::new(
|
||||
id_rect,
|
||||
(10.0 * anim_mult) as _,
|
||||
AnimationEasing::OutQuad,
|
||||
{
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
let pos_bidir = if focused { data.pos } else { 1.0 - data.pos };
|
||||
fn anim_bottom_rect(common: &mut CallbackDataCommon, accent_color: WguiColor, id_rect: WidgetID, focused: bool) {
|
||||
Animation::new(id_rect, AnimationDuration::Seconds(0.1666), AnimationEasing::OutQuad, {
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
let pos_bidir = if focused { data.pos } else { 1.0 - data.pos };
|
||||
|
||||
let color_lerped = accent_color.lerp(
|
||||
&common.globals().palette,
|
||||
&WguiColorName::OnBackgroundVariant.into(),
|
||||
pos_bidir,
|
||||
);
|
||||
rect.set_color(common, color_lerped);
|
||||
let color_lerped = accent_color.lerp(
|
||||
&common.globals().palette,
|
||||
&WguiColorName::OnBackgroundVariant.into(),
|
||||
pos_bidir,
|
||||
);
|
||||
rect.set_color(common, color_lerped);
|
||||
|
||||
common.alterables.set_style(
|
||||
data.widget_id,
|
||||
StyleSetRequest::Size(taffy::Size {
|
||||
width: percent(0.95.lerp(1.0, pos_bidir)),
|
||||
height: length(1.0 + pos_bidir),
|
||||
}),
|
||||
);
|
||||
common.alterables.set_style(
|
||||
data.widget_id,
|
||||
StyleSetRequest::Size(taffy::Size {
|
||||
width: percent(0.95.lerp(1.0, pos_bidir)),
|
||||
height: length(1.0 + pos_bidir),
|
||||
}),
|
||||
);
|
||||
|
||||
common.alterables.set_style(
|
||||
data.widget_id,
|
||||
StyleSetRequest::Margin(taffy::Rect {
|
||||
bottom: length(pos_bidir),
|
||||
left: auto(),
|
||||
right: auto(),
|
||||
top: auto(),
|
||||
}),
|
||||
);
|
||||
common.alterables.set_style(
|
||||
data.widget_id,
|
||||
StyleSetRequest::Margin(taffy::Rect {
|
||||
bottom: length(pos_bidir),
|
||||
left: auto(),
|
||||
right: auto(),
|
||||
top: auto(),
|
||||
}),
|
||||
);
|
||||
|
||||
common.alterables.mark_redraw();
|
||||
})
|
||||
},
|
||||
));
|
||||
common.alterables.mark_redraw();
|
||||
})
|
||||
})
|
||||
.submit(common.alterables);
|
||||
}
|
||||
|
||||
fn refresh_all(common: &mut CallbackDataCommon, data: &Data, state: &mut State) -> Option<()> {
|
||||
let theme = &common.state.theme;
|
||||
let editbox_color = WguiColor::from(WguiColorName::BackgroundVariant);
|
||||
let accent_color = WguiColor::from(WguiColorName::Primary);
|
||||
let anim_mult = theme.animation_mult;
|
||||
|
||||
let (rect_color, border_color) = if state.focused {
|
||||
(editbox_color.add_rgb(0.15), editbox_color.add_rgb(0.15 + 0.25))
|
||||
@@ -120,7 +108,7 @@ fn refresh_all(common: &mut CallbackDataCommon, data: &Data, state: &mut State)
|
||||
rect.set_color(common, rect_color);
|
||||
|
||||
if state.focused_prev != state.focused || state.first_refresh {
|
||||
anim_bottom_rect(common, accent_color, data.id_rect_bottom, anim_mult, state.focused);
|
||||
anim_bottom_rect(common, accent_color, data.id_rect_bottom, state.focused);
|
||||
state.focused_prev = state.focused;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use glam::{Mat4, Vec2, Vec3};
|
||||
use taffy::prelude::{length, percent};
|
||||
|
||||
use crate::{
|
||||
animation::{Animation, AnimationCallback, AnimationEasing},
|
||||
animation::{Animation, AnimationCallback, AnimationDuration, AnimationEasing},
|
||||
color::{WguiColor, WguiColorName},
|
||||
components::{
|
||||
Component, ComponentBase, ComponentTrait, DestroyData, RefreshData,
|
||||
@@ -404,53 +404,23 @@ fn get_callback_label(inverse: bool) -> AnimationCallback {
|
||||
})
|
||||
}
|
||||
|
||||
fn on_enter_anim(
|
||||
common: &mut event::CallbackDataCommon,
|
||||
id_handle: WidgetID,
|
||||
id_label: Option<WidgetID>,
|
||||
anim_mult: f32,
|
||||
) {
|
||||
let duration = 20. * anim_mult;
|
||||
fn on_enter_anim(common: &mut event::CallbackDataCommon, id_handle: WidgetID, id_label: Option<WidgetID>) {
|
||||
let duration = AnimationDuration::Seconds(0.333);
|
||||
|
||||
common.alterables.animate(Animation::new(
|
||||
id_handle,
|
||||
duration as _,
|
||||
AnimationEasing::OutBack,
|
||||
get_callback_rect(false),
|
||||
));
|
||||
Animation::new(id_handle, duration, AnimationEasing::OutBack, get_callback_rect(false)).submit(common.alterables);
|
||||
|
||||
if let Some(id_label) = id_label {
|
||||
common.alterables.animate(Animation::new(
|
||||
id_label,
|
||||
duration as _,
|
||||
AnimationEasing::OutBack,
|
||||
get_callback_label(false),
|
||||
));
|
||||
Animation::new(id_label, duration, AnimationEasing::OutBack, get_callback_label(false)).submit(common.alterables);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_leave_anim(
|
||||
common: &mut event::CallbackDataCommon,
|
||||
id_handle: WidgetID,
|
||||
id_label: Option<WidgetID>,
|
||||
anim_mult: f32,
|
||||
) {
|
||||
let duration = 10. * anim_mult;
|
||||
fn on_leave_anim(common: &mut event::CallbackDataCommon, id_handle: WidgetID, id_label: Option<WidgetID>) {
|
||||
let duration = AnimationDuration::Seconds(0.0833);
|
||||
|
||||
common.alterables.animate(Animation::new(
|
||||
id_handle,
|
||||
duration as _,
|
||||
AnimationEasing::OutQuad,
|
||||
get_callback_rect(true),
|
||||
));
|
||||
Animation::new(id_handle, duration, AnimationEasing::OutQuad, get_callback_rect(true)).submit(common.alterables);
|
||||
|
||||
if let Some(id_label) = id_label {
|
||||
common.alterables.animate(Animation::new(
|
||||
id_label,
|
||||
duration as _,
|
||||
AnimationEasing::OutQuad,
|
||||
get_callback_label(true),
|
||||
));
|
||||
Animation::new(id_label, duration, AnimationEasing::OutQuad, get_callback_label(true)).submit(common.alterables);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,13 +469,7 @@ fn get_handle_dist(common: &mut CallbackDataCommon, handle: &SliderHandleData, m
|
||||
|
||||
const MAX_HOVER_DIST: f32 = 64.0;
|
||||
|
||||
fn update_handle_hovers(
|
||||
common: &mut CallbackDataCommon,
|
||||
data: &Data,
|
||||
state: &mut State,
|
||||
anim_mult: f32,
|
||||
mouse_pos: Vec2,
|
||||
) {
|
||||
fn update_handle_hovers(common: &mut CallbackDataCommon, data: &Data, state: &mut State, mouse_pos: Vec2) {
|
||||
let hovered1_prev = state.hovered1;
|
||||
let hovered2_prev = state.hovered2;
|
||||
|
||||
@@ -536,9 +500,9 @@ fn update_handle_hovers(
|
||||
// hover state changed, run animations
|
||||
if state.hovered1 != hovered1_prev {
|
||||
if state.hovered1 && !hovered1_prev {
|
||||
on_enter_anim(common, data.handle1.id_handle_rect, data.handle1.id_label, anim_mult);
|
||||
on_enter_anim(common, data.handle1.id_handle_rect, data.handle1.id_label);
|
||||
} else {
|
||||
on_leave_anim(common, data.handle1.id_handle_rect, data.handle1.id_label, anim_mult);
|
||||
on_leave_anim(common, data.handle1.id_handle_rect, data.handle1.id_label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,9 +510,9 @@ fn update_handle_hovers(
|
||||
&& let Some(handle2) = data.handle2.as_ref()
|
||||
{
|
||||
if state.hovered2 && !hovered2_prev {
|
||||
on_enter_anim(common, handle2.id_handle_rect, handle2.id_label, anim_mult);
|
||||
on_enter_anim(common, handle2.id_handle_rect, handle2.id_label);
|
||||
} else {
|
||||
on_leave_anim(common, handle2.id_handle_rect, handle2.id_label, anim_mult);
|
||||
on_leave_anim(common, handle2.id_handle_rect, handle2.id_label);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -557,7 +521,6 @@ fn register_event_mouse_motion(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection,
|
||||
anim_mult: f32,
|
||||
) -> event::EventListenerID {
|
||||
listeners.register(
|
||||
EventListenerKind::MouseMotion,
|
||||
@@ -575,7 +538,7 @@ fn register_event_mouse_motion(
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
update_handle_hovers(common, &data, &mut state, anim_mult, pos_relative);
|
||||
update_handle_hovers(common, &data, &mut state, pos_relative);
|
||||
|
||||
if let Some(dragged_by) = &state.dragged_by
|
||||
&& dragged_by.device == pos.device
|
||||
@@ -769,11 +732,10 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||
id: root.id,
|
||||
lhandles: {
|
||||
let listeners = &mut root.widget.state().event_listeners;
|
||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||
vec![
|
||||
register_event_mouse_enter(state.clone(), listeners, params.tooltip),
|
||||
register_event_mouse_leave(state.clone(), listeners),
|
||||
register_event_mouse_motion(data.clone(), state.clone(), listeners, anim_mult),
|
||||
register_event_mouse_motion(data.clone(), state.clone(), listeners),
|
||||
register_event_mouse_press(data.clone(), state.clone(), listeners),
|
||||
register_event_mouse_release(state.clone(), listeners),
|
||||
]
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc};
|
||||
use taffy::prelude::length;
|
||||
|
||||
use crate::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
color::{WguiColor, WguiColorName},
|
||||
components::{self, Component, ComponentBase, ComponentTrait, RefreshData},
|
||||
event::CallbackDataCommon,
|
||||
@@ -292,39 +292,34 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||
TooltipSide::Bottom => Vec2::new(0.0, 1.0),
|
||||
};
|
||||
|
||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||
ess.layout.animations.add(Animation::new(
|
||||
rect.id,
|
||||
(10.0 * anim_mult) as u32,
|
||||
AnimationEasing::OutQuad,
|
||||
{
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap(); /* safe */
|
||||
let alpha = data.pos;
|
||||
rect.params.color = rect.params.color.with_alpha(alpha);
|
||||
rect.params.border_color = rect.params.border_color.with_alpha(alpha);
|
||||
Animation::new(rect.id, AnimationDuration::Seconds(0.1666), AnimationEasing::OutQuad, {
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap(); /* safe */
|
||||
let alpha = data.pos;
|
||||
rect.params.color = rect.params.color.with_alpha(alpha);
|
||||
rect.params.border_color = rect.params.border_color.with_alpha(alpha);
|
||||
|
||||
let position_shift = state.borrow().position_shift;
|
||||
let position_shift = state.borrow().position_shift;
|
||||
|
||||
let dir_mult = (1.0 - data.pos) * 5.0;
|
||||
data.data.transform = Mat4::from_translation(Vec3::new(
|
||||
direction.x * dir_mult + position_shift.x,
|
||||
direction.y * dir_mult + position_shift.y,
|
||||
0.0,
|
||||
));
|
||||
let dir_mult = (1.0 - data.pos) * 5.0;
|
||||
data.data.transform = Mat4::from_translation(Vec3::new(
|
||||
direction.x * dir_mult + position_shift.x,
|
||||
direction.y * dir_mult + position_shift.y,
|
||||
0.0,
|
||||
));
|
||||
|
||||
if let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(label.id) {
|
||||
label.set_color(
|
||||
common,
|
||||
WguiColor::from(WguiColorName::OnBackground).with_alpha(alpha),
|
||||
true,
|
||||
);
|
||||
}
|
||||
if let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(label.id) {
|
||||
label.set_color(
|
||||
common,
|
||||
WguiColor::from(WguiColorName::OnBackground).with_alpha(alpha),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
common.alterables.mark_redraw();
|
||||
})
|
||||
},
|
||||
));
|
||||
common.alterables.mark_redraw();
|
||||
})
|
||||
})
|
||||
.submit_l(ess.layout);
|
||||
|
||||
ess.layout.defer_component_refresh(Component(tooltip.clone()));
|
||||
Ok((div, tooltip))
|
||||
|
||||
@@ -2,7 +2,7 @@ use image::ImageBuffer;
|
||||
use taffy::prelude::percent;
|
||||
|
||||
use crate::{
|
||||
animation::Animation,
|
||||
animation::{Animation, AnimationDuration},
|
||||
assets::AssetPathRef,
|
||||
color::WguiColorName,
|
||||
components::{Component, ComponentBase, ComponentTrait, RefreshData},
|
||||
@@ -112,10 +112,10 @@ impl ComponentVideo {
|
||||
let start_time = get_millis();
|
||||
// log::info!("num frames: {}", source.demuxer.num_frames);
|
||||
|
||||
layout.animations.add(Animation::new_ex(
|
||||
Animation::new_ex(
|
||||
self.data.id_image,
|
||||
PLAYBACK_ANIMATION_ID,
|
||||
u32::MAX, // infinity
|
||||
AnimationDuration::Infinity,
|
||||
crate::animation::AnimationEasing::Linear,
|
||||
Box::new({
|
||||
let state_ref = self.state.clone();
|
||||
@@ -163,7 +163,8 @@ impl ComponentVideo {
|
||||
}
|
||||
}
|
||||
}),
|
||||
));
|
||||
)
|
||||
.submit_l(layout);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -129,6 +129,7 @@ pub struct LayoutState {
|
||||
pub nodes: WidgetNodeMap,
|
||||
pub tree: taffy::tree::TaffyTree<WidgetID>,
|
||||
pub components_by_widget_id: SecondaryMap<WidgetID, ComponentWeak>,
|
||||
pub ticks_per_second: u32,
|
||||
}
|
||||
|
||||
pub struct ModifyLayoutStateData<'a> {
|
||||
@@ -572,6 +573,7 @@ impl Layout {
|
||||
globals,
|
||||
theme: params.theme,
|
||||
components_by_widget_id: SecondaryMap::default(),
|
||||
ticks_per_second: 60, // hard-coded
|
||||
};
|
||||
|
||||
let size = if params.resize_to_parent {
|
||||
@@ -755,7 +757,7 @@ impl Layout {
|
||||
while let Some(task) = tasks.pop_front() {
|
||||
match task {
|
||||
LayoutTask::PlayAnimation(animation) => {
|
||||
self.animations.add(animation);
|
||||
self.alterables.animate(animation);
|
||||
}
|
||||
LayoutTask::RefreshPalette => {
|
||||
let root = self.tree_root_widget;
|
||||
@@ -894,7 +896,7 @@ impl Layout {
|
||||
if !alterables.animations.is_empty() {
|
||||
self.mark_redraw();
|
||||
for anim in alterables.animations {
|
||||
self.animations.add(anim);
|
||||
self.animations.add(anim, &self.state, &mut self.alterables);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ impl TooltipAttribs {
|
||||
pub fn get_info(self) -> Option<tooltip::TooltipInfo> {
|
||||
self.tooltip.map(|text| tooltip::TooltipInfo {
|
||||
text,
|
||||
side: self.tooltip_side.map_or(tooltip::TooltipSide::Top, |f| f),
|
||||
side: self.tooltip_side.unwrap_or(tooltip::TooltipSide::Top),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,10 +971,8 @@ fn process_attribs<'a>(
|
||||
ctx.doc_params.path.get_str()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if let Some(pair) = process_attrib(&file.template_parameters, ctx, key, value) {
|
||||
res.push(pair);
|
||||
}
|
||||
} else if let Some(pair) = process_attrib(&file.template_parameters, ctx, key, value) {
|
||||
res.push(pair);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -608,8 +608,16 @@ impl WidgetState {
|
||||
|
||||
let mult = scrollbar_info.get_potential_scroll_axis_multiplier(params.taffy_layout);
|
||||
|
||||
let scroll_diff_x = if mult.x == 0.0 { 0.0 } else { -mouse_diff.x / mult.x };
|
||||
let scroll_diff_y = if mult.y == 0.0 { 0.0 } else { -mouse_diff.y / mult.y };
|
||||
let scroll_diff_x = if mult.x == 0.0 || !active_x {
|
||||
0.0
|
||||
} else {
|
||||
-mouse_diff.x / mult.x
|
||||
};
|
||||
let scroll_diff_y = if mult.y == 0.0 || !active_y {
|
||||
0.0
|
||||
} else {
|
||||
-mouse_diff.y / mult.y
|
||||
};
|
||||
|
||||
self.data.scrolling_target = self.data.swipe_scroll_start + Vec2::new(scroll_diff_x, scroll_diff_y);
|
||||
params.alterables.mark_tick(self.obj.get_id());
|
||||
|
||||
@@ -44,10 +44,18 @@ impl WidgetRectangle {
|
||||
common.mark_widget_dirty(self.id);
|
||||
}
|
||||
|
||||
pub const fn get_color(&self) -> WguiColor {
|
||||
self.params.color
|
||||
}
|
||||
|
||||
pub fn set_border_color(&mut self, common: &mut CallbackDataCommon, color: WguiColor) {
|
||||
self.params.border_color = color;
|
||||
common.mark_widget_dirty(self.id);
|
||||
}
|
||||
|
||||
pub const fn get_border_color(&self) -> WguiColor {
|
||||
self.params.border_color
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetObj for WidgetRectangle {
|
||||
|
||||
@@ -4,7 +4,7 @@ use glam::Vec2;
|
||||
use taffy::prelude::{length, percent};
|
||||
|
||||
use crate::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
assets::AssetPathRef,
|
||||
components::button::ComponentButton,
|
||||
drawing,
|
||||
@@ -183,16 +183,17 @@ impl WguiWindow {
|
||||
)?;
|
||||
|
||||
// Fade animation
|
||||
params.layout.animations.add(Animation::new(
|
||||
Animation::new(
|
||||
widget.id,
|
||||
20,
|
||||
AnimationDuration::Seconds(0.333),
|
||||
AnimationEasing::OutQuad,
|
||||
Box::new(|common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap() /* should always succeed */;
|
||||
rect.params.color = drawing::Color::new(0.0, 0.0, 0.0, data.pos * 0.3).into();
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
));
|
||||
)
|
||||
.submit_l(params.layout);
|
||||
|
||||
Some(widget)
|
||||
} else {
|
||||
@@ -216,6 +217,15 @@ impl WguiWindow {
|
||||
|
||||
let globals = params.layout.state.globals.clone();
|
||||
|
||||
// window slide animation
|
||||
Animation::effect_slide(
|
||||
widget.id,
|
||||
AnimationDuration::Seconds(0.5),
|
||||
AnimationEasing::OutQuint,
|
||||
Vec2::new(0.0, 16.0),
|
||||
)
|
||||
.submit_l(params.layout);
|
||||
|
||||
let content_id = if params.extra.with_decorations {
|
||||
let xml_path: AssetPathRef = AssetPathRef::WguiInternal("wgui/window_frame.xml");
|
||||
|
||||
|
||||
Reference in new issue
Block a user