mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 07:18:04 +08:00
Layout system implementation and applied to tool options bar (#499)
* initial layout system with tool options * cargo fmt * cargo fmt again * document bar defined on the backend * cargo fmt * removed RC<RefCell> * cargo fmt * - fix increment behavior - removed hashmap from layout message handler - removed no op message from layoutMessage * cargo fmt * only send documentBar when zoom or rotation is updated * ctrl-0 changes zoom properly * Code review changes Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
@@ -7,6 +7,10 @@ use crate::consts::{
|
||||
ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_EXPORT_SUFFIX, FILE_SAVE_SUFFIX, GRAPHITE_DOCUMENT_VERSION, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR,
|
||||
};
|
||||
use crate::input::InputPreprocessorMessageHandler;
|
||||
use crate::layout::widgets::{
|
||||
IconButton, LayoutRow, NumberInput, NumberInputIncrementBehavior, OptionalInput, PopoverButton, PropertyHolder, RadioEntryData, RadioInput, Separator, SeparatorDirection, SeparatorType, Widget,
|
||||
WidgetCallback, WidgetHolder, WidgetLayout,
|
||||
};
|
||||
use crate::message_prelude::*;
|
||||
use crate::EditorError;
|
||||
|
||||
@@ -459,6 +463,154 @@ impl DocumentMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
impl PropertyHolder for DocumentMessageHandler {
|
||||
fn properties(&self) -> WidgetLayout {
|
||||
WidgetLayout::new(vec![LayoutRow::Row {
|
||||
name: "".into(),
|
||||
widgets: vec![
|
||||
WidgetHolder::new(Widget::OptionalInput(OptionalInput {
|
||||
checked: self.snapping_enabled,
|
||||
icon: "Snapping".into(),
|
||||
tooltip: "Snapping".into(),
|
||||
on_update: WidgetCallback::new(|updated_optional_input| DocumentMessage::SetSnapping { snap: updated_optional_input.checked }.into()),
|
||||
})),
|
||||
WidgetHolder::new(Widget::PopoverButton(PopoverButton {
|
||||
title: "Snapping".into(),
|
||||
text: "The contents of this popover menu are coming soon".into(),
|
||||
})),
|
||||
WidgetHolder::new(Widget::Separator(Separator {
|
||||
separator_type: SeparatorType::Unrelated,
|
||||
direction: SeparatorDirection::Horizontal,
|
||||
})),
|
||||
WidgetHolder::new(Widget::OptionalInput(OptionalInput {
|
||||
checked: true,
|
||||
icon: "Grid".into(),
|
||||
tooltip: "Grid".into(),
|
||||
on_update: WidgetCallback::new(|_| FrontendMessage::DisplayDialogComingSoon { issue: Some(318) }.into()),
|
||||
})),
|
||||
WidgetHolder::new(Widget::PopoverButton(PopoverButton {
|
||||
title: "Grid".into(),
|
||||
text: "The contents of this popover menu are coming soon".into(),
|
||||
})),
|
||||
WidgetHolder::new(Widget::Separator(Separator {
|
||||
separator_type: SeparatorType::Unrelated,
|
||||
direction: SeparatorDirection::Horizontal,
|
||||
})),
|
||||
WidgetHolder::new(Widget::OptionalInput(OptionalInput {
|
||||
checked: self.overlays_visible,
|
||||
icon: "Overlays".into(),
|
||||
tooltip: "Overlays".into(),
|
||||
on_update: WidgetCallback::new(|updated_optional_input| {
|
||||
DocumentMessage::SetOverlaysVisibility {
|
||||
visible: updated_optional_input.checked,
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
})),
|
||||
WidgetHolder::new(Widget::PopoverButton(PopoverButton {
|
||||
title: "Overlays".into(),
|
||||
text: "The contents of this popover menu are coming soon".into(),
|
||||
})),
|
||||
WidgetHolder::new(Widget::Separator(Separator {
|
||||
separator_type: SeparatorType::Unrelated,
|
||||
direction: SeparatorDirection::Horizontal,
|
||||
})),
|
||||
WidgetHolder::new(Widget::RadioInput(RadioInput {
|
||||
selected_index: if self.view_mode == ViewMode::Normal { 0 } else { 1 },
|
||||
entries: vec![
|
||||
RadioEntryData {
|
||||
value: "normal".into(),
|
||||
icon: "ViewModeNormal".into(),
|
||||
tooltip: "View Mode: Normal".into(),
|
||||
on_update: WidgetCallback::new(|_| DocumentMessage::SetViewMode { view_mode: ViewMode::Normal }.into()),
|
||||
..RadioEntryData::default()
|
||||
},
|
||||
RadioEntryData {
|
||||
value: "outline".into(),
|
||||
icon: "ViewModeOutline".into(),
|
||||
tooltip: "View Mode: Outline".into(),
|
||||
on_update: WidgetCallback::new(|_| DocumentMessage::SetViewMode { view_mode: ViewMode::Outline }.into()),
|
||||
..RadioEntryData::default()
|
||||
},
|
||||
RadioEntryData {
|
||||
value: "pixels".into(),
|
||||
icon: "ViewModePixels".into(),
|
||||
tooltip: "View Mode: Pixels".into(),
|
||||
on_update: WidgetCallback::new(|_| FrontendMessage::DisplayDialogComingSoon { issue: Some(320) }.into()),
|
||||
..RadioEntryData::default()
|
||||
},
|
||||
],
|
||||
})),
|
||||
WidgetHolder::new(Widget::PopoverButton(PopoverButton {
|
||||
title: "View Mode".into(),
|
||||
text: "The contents of this popover menu are coming soon".into(),
|
||||
})),
|
||||
WidgetHolder::new(Widget::Separator(Separator {
|
||||
separator_type: SeparatorType::Section,
|
||||
direction: SeparatorDirection::Horizontal,
|
||||
})),
|
||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||
unit: "°".into(),
|
||||
value: self.movement_handler.tilt / (std::f64::consts::PI / 180.),
|
||||
increment_factor: 15.,
|
||||
on_update: WidgetCallback::new(|number_input| {
|
||||
MovementMessage::SetCanvasRotation {
|
||||
angle_radians: number_input.value * (std::f64::consts::PI / 180.),
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
..NumberInput::default()
|
||||
})),
|
||||
WidgetHolder::new(Widget::Separator(Separator {
|
||||
separator_type: SeparatorType::Section,
|
||||
direction: SeparatorDirection::Horizontal,
|
||||
})),
|
||||
WidgetHolder::new(Widget::IconButton(IconButton {
|
||||
size: 24,
|
||||
icon: "ZoomIn".into(),
|
||||
tooltip: "Zoom In".into(),
|
||||
on_update: WidgetCallback::new(|_| MovementMessage::IncreaseCanvasZoom { center_on_mouse: false }.into()),
|
||||
..IconButton::default()
|
||||
})),
|
||||
WidgetHolder::new(Widget::IconButton(IconButton {
|
||||
size: 24,
|
||||
icon: "ZoomOut".into(),
|
||||
tooltip: "Zoom Out".into(),
|
||||
on_update: WidgetCallback::new(|_| MovementMessage::DecreaseCanvasZoom { center_on_mouse: false }.into()),
|
||||
..IconButton::default()
|
||||
})),
|
||||
WidgetHolder::new(Widget::IconButton(IconButton {
|
||||
size: 24,
|
||||
icon: "ZoomReset".into(),
|
||||
tooltip: "Zoom to 100%".into(),
|
||||
on_update: WidgetCallback::new(|_| MovementMessage::SetCanvasZoom { zoom_factor: 1. }.into()),
|
||||
..IconButton::default()
|
||||
})),
|
||||
WidgetHolder::new(Widget::Separator(Separator {
|
||||
separator_type: SeparatorType::Related,
|
||||
direction: SeparatorDirection::Horizontal,
|
||||
})),
|
||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||
unit: "%".into(),
|
||||
value: self.movement_handler.zoom * 100.,
|
||||
min: Some(0.000001),
|
||||
max: Some(1000000.),
|
||||
on_update: WidgetCallback::new(|number_input| {
|
||||
MovementMessage::SetCanvasZoom {
|
||||
zoom_factor: number_input.value / 100.,
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
increment_behavior: NumberInputIncrementBehavior::Callback,
|
||||
increment_callback_decrease: WidgetCallback::new(|_| MovementMessage::DecreaseCanvasZoom { center_on_mouse: false }.into()),
|
||||
increment_callback_increase: WidgetCallback::new(|_| MovementMessage::IncreaseCanvasZoom { center_on_mouse: false }.into()),
|
||||
..NumberInput::default()
|
||||
})),
|
||||
],
|
||||
}])
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for DocumentMessageHandler {
|
||||
#[remain::check]
|
||||
fn process_action(&mut self, message: DocumentMessage, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
@@ -674,7 +826,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
responses.extend([LayerChanged { affected_layer_path }.into(), DocumentStructureChanged.into()]);
|
||||
}
|
||||
GroupSelectedLayers => {
|
||||
let mut new_folder_path: Vec<u64> = self.graphene_document.shallowest_common_folder(self.selected_layers()).unwrap_or(&[]).to_vec();
|
||||
let mut new_folder_path = self.graphene_document.shallowest_common_folder(self.selected_layers()).unwrap_or(&[]).to_vec();
|
||||
|
||||
// Required for grouping parent folders with their own children
|
||||
if !new_folder_path.is_empty() && self.selected_layers_contains(&new_folder_path) {
|
||||
|
||||
Reference in New Issue
Block a user