Skip to content
1 change: 1 addition & 0 deletions editor/src/messages/frontend/frontend_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ pub enum FrontendMessage {
origin: (f64, f64),
spacing: f64,
interval: f64,
visible: bool,
},
UpdateDocumentScrollbars {
position: (f64, f64),
Expand Down
1 change: 1 addition & 0 deletions editor/src/messages/input_mapper/default_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ pub fn default_mapping() -> Mapping {
entry!(KeyDown(KeyI); modifiers=[Accel], action_dispatch=PortfolioMessage::Import),
entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=PortfolioMessage::Cut { clipboard: Clipboard::Device }),
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=PortfolioMessage::Copy { clipboard: Clipboard::Device }),
entry!(KeyDown(KeyR); modifiers=[Alt], action_dispatch=PortfolioMessage::ToggleRulers),
//
// FrontendMessage
entry!(KeyDown(KeyV); modifiers=[Accel], action_dispatch=FrontendMessage::TriggerPaste),
Expand Down
10 changes: 10 additions & 0 deletions editor/src/messages/portfolio/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ use graphene_core::raster::ImageFrame;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};

/// Utility function for providing a default boolean value to serde.
#[inline(always)]
fn return_true() -> bool {
true
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DocumentMessageHandler {
pub document_legacy: DocumentLegacy,
Expand All @@ -43,6 +49,8 @@ pub struct DocumentMessageHandler {
#[serde(skip)]
pub snapping_state: SnappingState,
pub overlays_visible: bool,
#[serde(default = "return_true")]
pub rulers_visible: bool,

#[serde(skip)]
pub document_undo_history: VecDeque<DocumentSave>,
Expand Down Expand Up @@ -81,6 +89,7 @@ impl Default for DocumentMessageHandler {
view_mode: ViewMode::default(),
snapping_state: SnappingState::default(),
overlays_visible: true,
rulers_visible: true,

document_undo_history: VecDeque::new(),
document_redo_history: VecDeque::new(),
Expand Down Expand Up @@ -614,6 +623,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
origin: ruler_origin.into(),
spacing: ruler_spacing,
interval: ruler_interval,
visible: self.rulers_visible,
});
}
RenderScrollbars => {
Expand Down
25 changes: 18 additions & 7 deletions editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use crate::messages::prelude::*;
#[derive(Debug, Clone, Default)]
pub struct MenuBarMessageHandler {
no_active_document: bool,
rulers_hidden: bool,
}

impl MessageHandler<MenuBarMessage, bool> for MenuBarMessageHandler {
impl MessageHandler<MenuBarMessage, (bool, bool)> for MenuBarMessageHandler {
#[remain::check]
fn process_message(&mut self, message: MenuBarMessage, responses: &mut VecDeque<Message>, has_active_document: bool) {
fn process_message(&mut self, message: MenuBarMessage, responses: &mut VecDeque<Message>, (has_active_document, rulers_hidden): (bool, bool)) {
use MenuBarMessage::*;
self.no_active_document = !has_active_document;

self.rulers_hidden = rulers_hidden;
#[remain::sorted]
match message {
SendLayout => self.send_layout(responses, LayoutTarget::MenuBar),
Expand Down Expand Up @@ -289,8 +290,17 @@ impl LayoutHolder for MenuBarMessageHandler {
disabled: no_active_document,
..MenuBarEntry::default()
},
],
vec![
MenuBarEntry {
label: "Zoom to Fit Selection".into(),
shortcut: action_keys!(NavigationMessageDiscriminant::FitViewportToSelection),
action: MenuBarEntry::create_action(|_| NavigationMessage::FitViewportToSelection.into()),
disabled: no_active_document,
..MenuBarEntry::default()
},
MenuBarEntry {
label: "Zoom to Fit".into(),
label: "Zoom to Fit All".into(),
shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasToFitAll),
action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasToFitAll.into()),
disabled: no_active_document,
Expand All @@ -312,9 +322,10 @@ impl LayoutHolder for MenuBarMessageHandler {
},
],
vec![MenuBarEntry {
label: "Frame Selected".into(),
shortcut: action_keys!(NavigationMessageDiscriminant::FitViewportToSelection),
action: MenuBarEntry::create_action(|_| NavigationMessage::FitViewportToSelection.into()),
label: "Rulers".into(),
icon: Some(if self.rulers_hidden { "CheckboxUnchecked" } else { "CheckboxChecked" }.into()),
shortcut: action_keys!(PortfolioMessageDiscriminant::ToggleRulers),
action: MenuBarEntry::create_action(|_| PortfolioMessage::ToggleRulers.into()),
disabled: no_active_document,
..MenuBarEntry::default()
}],
Expand Down
1 change: 1 addition & 0 deletions editor/src/messages/portfolio/portfolio_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ pub enum PortfolioMessage {
document_id: u64,
layer_path: Vec<LayerId>,
},
ToggleRulers,
UpdateDocumentWidgets,
UpdateOpenDocumentsList,
}
17 changes: 16 additions & 1 deletion editor/src/messages/portfolio/portfolio_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
match message {
// Sub-messages
#[remain::unsorted]
PortfolioMessage::MenuBar(message) => self.menu_bar_message_handler.process_message(message, responses, has_active_document),
PortfolioMessage::MenuBar(message) => {
if let Some(document_id) = self.active_document_id {
if let Some(document) = self.documents.get_mut(&document_id) {
self.menu_bar_message_handler.process_message(message, responses, (has_active_document, document.rulers_visible));
}
}
}
#[remain::unsorted]
PortfolioMessage::Document(message) => {
if let Some(document_id) = self.active_document_id {
Expand Down Expand Up @@ -517,6 +523,14 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
});
}
}
PortfolioMessage::ToggleRulers => {
if let Some(document) = self.active_document_mut() {
document.rulers_visible = !document.rulers_visible;

responses.add(DocumentMessage::RenderRulers);
responses.add(MenuBarMessage::SendLayout);
}
}
PortfolioMessage::UpdateDocumentWidgets => {
if let Some(document) = self.active_document() {
document.update_document_widgets(responses);
Expand Down Expand Up @@ -552,6 +566,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
OpenDocument,
PasteIntoFolder,
PrevDocument,
ToggleRulers,
);

if self.graph_view_overlay_open {
Expand Down
24 changes: 15 additions & 9 deletions frontend/src/components/panels/Document.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
let rulerOrigin: XY = { x: 0, y: 0 };
let rulerSpacing = 100;
let rulerInterval = 100;
let rulersVisible = true;

// Rendered SVG viewport data
let artworkSvg = "";
Expand Down Expand Up @@ -213,10 +214,11 @@
scrollbarMultiplier = multiplier;
}

export function updateDocumentRulers(origin: XY, spacing: number, interval: number) {
export function updateDocumentRulers(origin: XY, spacing: number, interval: number, visible: boolean) {
rulerOrigin = origin;
rulerSpacing = spacing;
rulerInterval = interval;
rulersVisible = visible;
}

// Update mouse cursor icon
Expand Down Expand Up @@ -371,8 +373,8 @@
editor.subscriptions.subscribeJsMessage(UpdateDocumentRulers, async (data) => {
await tick();

const { origin, spacing, interval } = data;
updateDocumentRulers(origin, spacing, interval);
const { origin, spacing, interval, visible } = data;
updateDocumentRulers(origin, spacing, interval, visible);
});

// Update mouse cursor icon
Expand Down Expand Up @@ -440,13 +442,17 @@
</LayoutCol>
</LayoutCol>
<LayoutCol class="table">
<LayoutRow class="ruler-or-scrollbar top-ruler">
<RulerInput origin={rulerOrigin.x} majorMarkSpacing={rulerSpacing} numberInterval={rulerInterval} direction="Horizontal" bind:this={rulerHorizontal} />
</LayoutRow>
{#if rulersVisible}
<LayoutRow class="ruler-or-scrollbar top-ruler">
<RulerInput origin={rulerOrigin.x} majorMarkSpacing={rulerSpacing} numberInterval={rulerInterval} direction="Horizontal" bind:this={rulerHorizontal} />
</LayoutRow>
{/if}
<LayoutRow class="viewport-container">
<LayoutCol class="ruler-or-scrollbar">
<RulerInput origin={rulerOrigin.y} majorMarkSpacing={rulerSpacing} numberInterval={rulerInterval} direction="Vertical" bind:this={rulerVertical} />
</LayoutCol>
{#if rulersVisible}
<LayoutCol class="ruler-or-scrollbar">
<RulerInput origin={rulerOrigin.y} majorMarkSpacing={rulerSpacing} numberInterval={rulerInterval} direction="Vertical" bind:this={rulerVertical} />
</LayoutCol>
{/if}
<LayoutCol class="viewport-container" styles={{ cursor: canvasCursor }}>
{#if cursorEyedropper}
<EyedropperPreview
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/widgets/inputs/RulerInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
</script>

<script lang="ts">
import { onMount } from "svelte";

const RULER_THICKNESS = 16;
const MAJOR_MARK_THICKNESS = 16;
const MEDIUM_MARK_THICKNESS = 6;
Expand Down Expand Up @@ -96,6 +98,8 @@
const remainder = n % m;
return Math.floor(remainder >= 0 ? remainder : remainder + m);
}

onMount(resize);
</script>

<div class={`ruler-input ${direction.toLowerCase()}`} bind:this={rulerInput}>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/wasm-communication/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,8 @@ export class UpdateDocumentRulers extends JsMessage {
readonly spacing!: number;

readonly interval!: number;

readonly visible!: boolean;
}

export class UpdateEyedropperSamplingState extends JsMessage {
Expand Down