Skip to content

Commit 08a4b69

Browse files
committed
Add animation control buttons to document bar
1 parent 44694ff commit 08a4b69

File tree

11 files changed

+91
-17
lines changed

11 files changed

+91
-17
lines changed

editor/src/dispatcher.rs

+2
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ impl Dispatcher {
234234
let current_tool = &self.message_handlers.tool_message_handler.tool_state.tool_data.active_tool_type;
235235
let message_logging_verbosity = self.message_handlers.debug_message_handler.message_logging_verbosity;
236236
let timing_information = self.message_handlers.animation_message_handler.timing_information();
237+
let animation = &self.message_handlers.animation_message_handler;
237238

238239
self.message_handlers.portfolio_message_handler.process_message(
239240
message,
@@ -244,6 +245,7 @@ impl Dispatcher {
244245
current_tool,
245246
message_logging_verbosity,
246247
timing_information,
248+
animation,
247249
},
248250
);
249251
}

editor/src/messages/animation/animation_message.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub enum AnimationMessage {
88
ToggleLivePreview,
99
EnableLivePreview,
1010
DisableLivePreview,
11-
ResetAnimation,
11+
RestartAnimation,
1212
SetFrameIndex(f64),
1313
SetTime(f64),
1414
UpdateTime,

editor/src/messages/animation/animation_message_handler.rs

+42-11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub enum AnimationTimeMode {
1414
#[derive(Debug, Default)]
1515
pub struct AnimationMessageHandler {
1616
live_preview: bool,
17+
/// Used to re-send the UI on the next frame after playback starts
18+
live_preview_recently_zero: bool,
1719
timestamp: f64,
1820
frame_index: f64,
1921
animation_start: Option<f64>,
@@ -29,6 +31,10 @@ impl AnimationMessageHandler {
2931
};
3032
TimingInformation { time: self.timestamp, animation_time }
3133
}
34+
35+
pub fn is_playing(&self) -> bool {
36+
self.live_preview
37+
}
3238
}
3339

3440
impl MessageHandler<AnimationMessage, ()> for AnimationMessageHandler {
@@ -38,23 +44,37 @@ impl MessageHandler<AnimationMessage, ()> for AnimationMessageHandler {
3844
if self.animation_start.is_none() {
3945
self.animation_start = Some(self.timestamp);
4046
}
41-
self.live_preview = !self.live_preview
47+
self.live_preview = !self.live_preview;
48+
49+
// Update the restart and pause/play buttons
50+
responses.add(PortfolioMessage::UpdateDocumentWidgets);
4251
}
4352
AnimationMessage::EnableLivePreview => {
4453
if self.animation_start.is_none() {
4554
self.animation_start = Some(self.timestamp);
4655
}
47-
self.live_preview = true
56+
self.live_preview = true;
57+
58+
// Update the restart and pause/play buttons
59+
responses.add(PortfolioMessage::UpdateDocumentWidgets);
60+
}
61+
AnimationMessage::DisableLivePreview => {
62+
self.live_preview = false;
63+
64+
// Update the restart and pause/play buttons
65+
responses.add(PortfolioMessage::UpdateDocumentWidgets);
4866
}
49-
AnimationMessage::DisableLivePreview => self.live_preview = false,
5067
AnimationMessage::SetFrameIndex(frame) => {
5168
self.frame_index = frame;
52-
log::debug!("set frame index to {}", frame);
53-
responses.add(PortfolioMessage::SubmitActiveGraphRender)
69+
responses.add(PortfolioMessage::SubmitActiveGraphRender);
70+
// Update the restart and pause/play buttons
71+
responses.add(PortfolioMessage::UpdateDocumentWidgets);
5472
}
5573
AnimationMessage::SetTime(time) => {
5674
self.timestamp = time;
57-
responses.add(AnimationMessage::UpdateTime);
75+
if self.live_preview {
76+
responses.add(AnimationMessage::UpdateTime);
77+
}
5878
}
5979
AnimationMessage::IncrementFrameCounter => {
6080
if self.live_preview {
@@ -64,21 +84,32 @@ impl MessageHandler<AnimationMessage, ()> for AnimationMessageHandler {
6484
}
6585
AnimationMessage::UpdateTime => {
6686
if self.live_preview {
67-
responses.add(PortfolioMessage::SubmitActiveGraphRender)
87+
responses.add(PortfolioMessage::SubmitActiveGraphRender);
88+
89+
if self.live_preview_recently_zero {
90+
// Update the restart and pause/play buttons
91+
responses.add(PortfolioMessage::UpdateDocumentWidgets);
92+
self.live_preview_recently_zero = false;
93+
}
6894
}
6995
}
70-
AnimationMessage::ResetAnimation => {
96+
AnimationMessage::RestartAnimation => {
7197
self.frame_index = 0.;
7298
self.animation_start = None;
73-
responses.add(PortfolioMessage::SubmitActiveGraphRender)
99+
self.live_preview_recently_zero = true;
100+
responses.add(PortfolioMessage::SubmitActiveGraphRender);
101+
// Update the restart and pause/play buttons
102+
responses.add(PortfolioMessage::UpdateDocumentWidgets);
103+
}
104+
AnimationMessage::SetAnimationTimeMode(animation_time_mode) => {
105+
self.animation_time_mode = animation_time_mode;
74106
}
75-
AnimationMessage::SetAnimationTimeMode(animation_time_mode) => self.animation_time_mode = animation_time_mode,
76107
}
77108
}
78109

79110
advertise_actions!(AnimationMessageDiscriminant;
80111
ToggleLivePreview,
81112
SetFrameIndex,
82-
ResetAnimation,
113+
RestartAnimation,
83114
);
84115
}

editor/src/messages/input_mapper/input_mappings.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ pub fn input_mappings() -> Mapping {
432432
entry!(KeyDown(Digit2); modifiers=[Alt], action_dispatch=DebugMessage::MessageContents),
433433
// AnimationMessage
434434
entry!(KeyDown(Space); modifiers=[Shift], action_dispatch=AnimationMessage::ToggleLivePreview),
435-
entry!(KeyDown(ArrowLeft); modifiers=[Control], action_dispatch=AnimationMessage::ResetAnimation),
435+
entry!(KeyDown(Home); modifiers=[Shift], action_dispatch=AnimationMessage::RestartAnimation),
436436
];
437437
let (mut key_up, mut key_down, mut key_up_no_repeat, mut key_down_no_repeat, mut double_click, mut wheel_scroll, mut pointer_move) = mappings;
438438

editor/src/messages/portfolio/document/document_message_handler.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use graphene_core::raster::image::ImageFrameTable;
3333
use graphene_core::vector::style::ViewMode;
3434
use graphene_std::renderer::{ClickTarget, Quad};
3535
use graphene_std::vector::{PointId, path_bool_lib};
36+
use std::time::Duration;
3637

3738
pub struct DocumentMessageData<'a> {
3839
pub document_id: DocumentId,
@@ -1988,7 +1989,7 @@ impl DocumentMessageHandler {
19881989
}
19891990
}
19901991

1991-
pub fn update_document_widgets(&self, responses: &mut VecDeque<Message>) {
1992+
pub fn update_document_widgets(&self, responses: &mut VecDeque<Message>, animation_is_playing: bool, time: Duration) {
19921993
// Document mode (dropdown menu at the left of the bar above the viewport, before the tool options)
19931994

19941995
let document_mode_layout = WidgetLayout::new(vec![LayoutGroup::Row {
@@ -2026,6 +2027,18 @@ impl DocumentMessageHandler {
20262027
let mut snapping_state2 = self.snapping_state.clone();
20272028

20282029
let mut widgets = vec![
2030+
IconButton::new("PlaybackToStart", 24)
2031+
.tooltip("Restart Animation")
2032+
.tooltip_shortcut(action_keys!(AnimationMessageDiscriminant::RestartAnimation))
2033+
.on_update(|_| AnimationMessage::RestartAnimation.into())
2034+
.disabled(time == Duration::ZERO)
2035+
.widget_holder(),
2036+
IconButton::new(if animation_is_playing { "PlaybackPause" } else { "PlaybackPlay" }, 24)
2037+
.tooltip(if animation_is_playing { "Pause Animation" } else { "Play Animation" })
2038+
.tooltip_shortcut(action_keys!(AnimationMessageDiscriminant::ToggleLivePreview))
2039+
.on_update(|_| AnimationMessage::ToggleLivePreview.into())
2040+
.widget_holder(),
2041+
Separator::new(SeparatorType::Unrelated).widget_holder(),
20292042
CheckboxInput::new(self.overlays_visible)
20302043
.icon("Overlays")
20312044
.tooltip("Overlays")

editor/src/messages/portfolio/portfolio_message_handler.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub struct PortfolioMessageData<'a> {
3434
pub current_tool: &'a ToolType,
3535
pub message_logging_verbosity: MessageLoggingVerbosity,
3636
pub timing_information: TimingInformation,
37+
pub animation: &'a AnimationMessageHandler,
3738
}
3839

3940
#[derive(Debug, Default)]
@@ -59,6 +60,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
5960
current_tool,
6061
message_logging_verbosity,
6162
timing_information,
63+
animation,
6264
} = data;
6365

6466
match message {
@@ -1108,7 +1110,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
11081110
}
11091111
PortfolioMessage::UpdateDocumentWidgets => {
11101112
if let Some(document) = self.active_document() {
1111-
document.update_document_widgets(responses);
1113+
document.update_document_widgets(responses, animation.is_playing(), timing_information.animation_time);
11121114
}
11131115
}
11141116
PortfolioMessage::UpdateOpenDocumentsList => {
@@ -1275,16 +1277,19 @@ impl PortfolioMessageHandler {
12751277

12761278
/// Get the id of the node that should be used as the target for the spreadsheet
12771279
pub fn inspect_node_id(&self) -> Option<NodeId> {
1280+
// Spreadsheet not open, skipping
12781281
if !self.spreadsheet.spreadsheet_view_open {
1279-
warn!("Spreadsheet not open, skipping…");
12801282
return None;
12811283
}
1284+
12821285
let document = self.documents.get(&self.active_document_id?)?;
12831286
let selected_nodes = document.network_interface.selected_nodes().0;
1287+
1288+
// Selected nodes != 1, skipping
12841289
if selected_nodes.len() != 1 {
1285-
warn!("selected nodes != 1, skipping…");
12861290
return None;
12871291
}
1292+
12881293
selected_nodes.first().copied()
12891294
}
12901295
}
Loading
Loading
Loading
Loading

frontend/src/utility-functions/icons.ts

+8
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ import PadlockUnlocked from "@graphite-frontend/assets/icon-16px-solid/padlock-u
163163
import Paste from "@graphite-frontend/assets/icon-16px-solid/paste.svg";
164164
import PinActive from "@graphite-frontend/assets/icon-16px-solid/pin-active.svg";
165165
import PinInactive from "@graphite-frontend/assets/icon-16px-solid/pin-inactive.svg";
166+
import PlaybackPause from "@graphite-frontend/assets/icon-16px-solid/playback-pause.svg";
167+
import PlaybackPlay from "@graphite-frontend/assets/icon-16px-solid/playback-play.svg";
168+
import PlaybackToEnd from "@graphite-frontend/assets/icon-16px-solid/playback-to-end.svg";
169+
import PlaybackToStart from "@graphite-frontend/assets/icon-16px-solid/playback-to-start.svg";
166170
import Random from "@graphite-frontend/assets/icon-16px-solid/random.svg";
167171
import Reload from "@graphite-frontend/assets/icon-16px-solid/reload.svg";
168172
import Reset from "@graphite-frontend/assets/icon-16px-solid/reset.svg";
@@ -279,6 +283,10 @@ const SOLID_16PX = {
279283
Paste: { svg: Paste, size: 16 },
280284
PinActive: { svg: PinActive, size: 16 },
281285
PinInactive: { svg: PinInactive, size: 16 },
286+
PlaybackPause: { svg: PlaybackPause, size: 16 },
287+
PlaybackPlay: { svg: PlaybackPlay, size: 16 },
288+
PlaybackToEnd: { svg: PlaybackToEnd, size: 16 },
289+
PlaybackToStart: { svg: PlaybackToStart, size: 16 },
282290
Random: { svg: Random, size: 16 },
283291
Reload: { svg: Reload, size: 16 },
284292
Reset: { svg: Reset, size: 16 },

0 commit comments

Comments
 (0)