mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-31 21:56:50 -06:00
Snap: view commands and guide preferences
This commit is contained in:
committed by
Brandon Thomas
parent
09c8dc3f06
commit
b0f9773205
@@ -641,6 +641,18 @@ fn preferences(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
text_field(ui, d, "pasteboard.v", 80.0);
|
||||
ui.end_row();
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
check(ui, d, "snap.alignEdges", "Align to Object Edges");
|
||||
check(ui, d, "snap.alignCenters", "Align to Object Centers");
|
||||
check(ui, d, "snap.dimensions", "Smart Dimensions");
|
||||
check(ui, d, "snap.spacing", "Smart Spacing");
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Snap to Zone");
|
||||
let mut zone = d.n("snap.zone").filter(|z| z.is_finite()).unwrap_or(4.0);
|
||||
if ui.add(egui::DragValue::new(&mut zone).speed(0.1)).changed() {
|
||||
d.fields.insert("snap.zone".into(), json!(zone));
|
||||
}
|
||||
});
|
||||
}
|
||||
"display" => {
|
||||
ui.label(egui::RichText::new("Options").font(semibold(12.0)));
|
||||
@@ -1422,6 +1434,21 @@ pub fn confirm(app: &mut DesignApp) -> Result<Value, String> {
|
||||
if let Some(v) = d.n("uiScale") {
|
||||
app.run("window.uiScale", json!({"scale": v / 100.0}))?;
|
||||
}
|
||||
if d.fields.contains_key("snap.alignEdges") {
|
||||
app.ui.align_edges = d.b("snap.alignEdges");
|
||||
}
|
||||
if d.fields.contains_key("snap.alignCenters") {
|
||||
app.ui.align_centers = d.b("snap.alignCenters");
|
||||
}
|
||||
if d.fields.contains_key("snap.dimensions") {
|
||||
app.ui.smart_dimensions = d.b("snap.dimensions");
|
||||
}
|
||||
if d.fields.contains_key("snap.spacing") {
|
||||
app.ui.smart_spacing = d.b("snap.spacing");
|
||||
}
|
||||
if let Some(zone) = d.n("snap.zone").filter(|z| z.is_finite()) {
|
||||
app.ui.snap_zone = if zone < 0.0 { 0.0 } else { zone };
|
||||
}
|
||||
if !d.fields.contains_key("horizontalUnits") {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,23 @@ const TABLE: &[(&str, [&str; 4])] = &[
|
||||
("Screen Mode", ["Bildschirmmodus", "Mode d'affichage", "Modo de pantalla", "スクリーンモード"]),
|
||||
("Grids & Guides", ["Raster und Hilfslinien", "Grilles et repères", "Cuadrículas y guías", "グリッドとガイド"]),
|
||||
("Show Rulers", ["Lineale einblenden", "Afficher les règles", "Mostrar reglas", "定規を表示"]),
|
||||
("Snap to Guides", ["An Hilfslinien ausrichten", "Coller aux repères", "Ajustar a las guías", "ガイドにスナップ"]),
|
||||
(
|
||||
"Snap to Document Grid",
|
||||
["Am Dokumentraster ausrichten", "Coller à la grille du document", "Ajustar a la cuadrícula del documento", "ドキュメントグリッドにスナップ"],
|
||||
),
|
||||
("Smart Guides", ["Smarte Hilfslinien", "Repères intelligents", "Guías inteligentes", "スマートガイド"]),
|
||||
(
|
||||
"Align to Object Edges",
|
||||
["An Objektkanten ausrichten", "Aligner sur les bords des objets", "Alinear a los bordes del objeto", "オブジェクトの端に揃える"],
|
||||
),
|
||||
(
|
||||
"Align to Object Centers",
|
||||
["An Objektmitten ausrichten", "Aligner sur les centres des objets", "Alinear a los centros del objeto", "オブジェクトの中心に揃える"],
|
||||
),
|
||||
("Smart Dimensions", ["Smarte Maße", "Mesures intelligentes", "Dimensiones inteligentes", "スマートサイズ"]),
|
||||
("Smart Spacing", ["Smarte Abstände", "Espacements intelligents", "Espaciado inteligente", "スマート間隔"]),
|
||||
("Snap to Zone", ["Fangzone", "Zone de magnétisme", "Zona de ajuste", "スナップゾーン"]),
|
||||
// Window and panels.
|
||||
("Properties", ["Eigenschaften", "Propriétés", "Propiedades", "プロパティ"]),
|
||||
("Layers", ["Ebenen", "Calques", "Capas", "レイヤー"]),
|
||||
|
||||
@@ -86,6 +86,16 @@ pub struct SavedWorkspace {
|
||||
pub floating: Vec<(String, [f32; 2])>,
|
||||
}
|
||||
|
||||
/// A missing on-by-default bool stays on. `bool::default` is false.
|
||||
fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// A missing snap zone stays at the factory width, in screen pixels.
|
||||
fn default_zone() -> f64 {
|
||||
4.0
|
||||
}
|
||||
|
||||
/// Persisted UI state.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
@@ -162,6 +172,19 @@ pub struct UiState {
|
||||
pub text_style_tab: u8,
|
||||
pub guides_locked: bool,
|
||||
pub smart_guides: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub snap_to_guides: bool,
|
||||
pub snap_to_document_grid: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub align_edges: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub align_centers: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub smart_dimensions: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub smart_spacing: bool,
|
||||
#[serde(default = "default_zone")]
|
||||
pub snap_zone: f64,
|
||||
/// Window > Contextual Task Bar.
|
||||
pub task_bar: bool,
|
||||
/// Help › About DesignCraft is open.
|
||||
@@ -228,6 +251,13 @@ impl Default for UiState {
|
||||
text_style_tab: 0,
|
||||
guides_locked: false,
|
||||
smart_guides: true,
|
||||
snap_to_guides: true,
|
||||
snap_to_document_grid: false,
|
||||
align_edges: true,
|
||||
align_centers: true,
|
||||
smart_dimensions: true,
|
||||
smart_spacing: true,
|
||||
snap_zone: 4.0,
|
||||
task_bar: true,
|
||||
about: false,
|
||||
pending_urls: Vec::new(),
|
||||
@@ -239,6 +269,23 @@ impl Default for UiState {
|
||||
}
|
||||
}
|
||||
|
||||
impl UiState {
|
||||
/// Copies the live view switches into the snap engine's view.
|
||||
pub fn snap_view(&self) -> SnapView {
|
||||
SnapView {
|
||||
snap_to_guides: self.snap_to_guides,
|
||||
snap_to_document_grid: self.snap_to_document_grid,
|
||||
show_guides: self.guides,
|
||||
smart_guides: self.smart_guides,
|
||||
align_edges: self.align_edges,
|
||||
align_centers: self.align_centers,
|
||||
smart_dimensions: self.smart_dimensions,
|
||||
smart_spacing: self.smart_spacing,
|
||||
zone_px: self.snap_zone,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Per-document view: zoom (screen points per document point) and the canvas point at the
|
||||
/// top-left of the canvas area.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
|
||||
@@ -429,7 +476,7 @@ impl DesignApp {
|
||||
self.pane = pane;
|
||||
}
|
||||
pub fn view_info(&self) -> ViewInfo {
|
||||
ViewInfo { zoom: self.view().map(|v| v.zoom).unwrap_or(1.0), snap: SnapView::FACTORY, unit: self.ui.units }
|
||||
ViewInfo { zoom: self.view().map(|v| v.zoom).unwrap_or(1.0), snap: self.ui.snap_view(), unit: self.ui.units }
|
||||
}
|
||||
|
||||
pub fn status(&mut self, s: impl Into<String>) {
|
||||
@@ -806,3 +853,20 @@ pub fn now_ms() -> f64 {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn snap_view_uses_the_saved_switches() {
|
||||
let mut ui = UiState::default();
|
||||
assert!(ui.snap_view().snap_to_guides);
|
||||
assert!(!ui.snap_view().snap_to_document_grid);
|
||||
assert_eq!(ui.snap_view().zone_px, 4.0);
|
||||
ui.snap_to_guides = false;
|
||||
ui.snap_zone = 0.0;
|
||||
assert!(!ui.snap_view().snap_to_guides);
|
||||
assert_eq!(ui.snap_view().zone_px, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,9 @@ pub const UI_COMMANDS: &[(&str, &str, Option<&str>, &str)] = &[
|
||||
("view.frameEdges", "Show/Hide Frame Edges", Some("Cmd+H"), "{}"),
|
||||
("view.rulers", "Show/Hide Rulers", Some("Cmd+R"), "{}"),
|
||||
("view.guides", "Show/Hide Guides", Some("Cmd+;"), "{}"),
|
||||
("view.snapToGuides", "Snap to Guides", Some("Cmd+Shift+;"), "{}"),
|
||||
("view.snapToDocumentGrid", "Snap to Document Grid", None, "{}"),
|
||||
("view.smartGuides", "Smart Guides", None, "{}"),
|
||||
("view.baselineGrid", "Show/Hide Baseline Grid", Some("Cmd+Alt+'"), "{}"),
|
||||
("view.textThreads", "Show/Hide Text Threads", Some("Cmd+Alt+Y"), "{}"),
|
||||
("view.hiddenCharacters", "Show/Hide Hidden Characters", Some("Cmd+Alt+I"), "{}"),
|
||||
@@ -584,6 +587,9 @@ pub const MENUS: &[(&str, &[&str])] = &[
|
||||
"-",
|
||||
">Grids & Guides",
|
||||
"ui:view.guides",
|
||||
"ui:view.snapToGuides",
|
||||
"ui:view.snapToDocumentGrid",
|
||||
"ui:view.smartGuides",
|
||||
"ui:view.baselineGrid",
|
||||
"-",
|
||||
"ui:app.deleteAllGuides",
|
||||
@@ -959,6 +965,11 @@ pub fn run_ui(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value,
|
||||
f["pasteboard.h"] = m(&doc["pasteboard"][0]);
|
||||
f["pasteboard.v"] = m(&doc["pasteboard"][1]);
|
||||
}
|
||||
f["snap.alignEdges"] = json!(app.ui.align_edges);
|
||||
f["snap.alignCenters"] = json!(app.ui.align_centers);
|
||||
f["snap.dimensions"] = json!(app.ui.smart_dimensions);
|
||||
f["snap.spacing"] = json!(app.ui.smart_spacing);
|
||||
f["snap.zone"] = json!(app.ui.snap_zone);
|
||||
f["displayQuality"] = json!(match app.ui.display_quality {
|
||||
designcraft_render::DisplayQuality::Fast => "fast",
|
||||
designcraft_render::DisplayQuality::Typical => "typical",
|
||||
@@ -1042,6 +1053,9 @@ pub fn run_ui(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value,
|
||||
}
|
||||
"view.rulers" => flag(&mut app.ui.rulers),
|
||||
"view.guides" => flag(&mut app.ui.guides),
|
||||
"view.snapToGuides" => flag(&mut app.ui.snap_to_guides),
|
||||
"view.snapToDocumentGrid" => flag(&mut app.ui.snap_to_document_grid),
|
||||
"view.smartGuides" => flag(&mut app.ui.smart_guides),
|
||||
"view.baselineGrid" => flag(&mut app.ui.baseline_grid),
|
||||
"view.textThreads" => flag(&mut app.ui.text_threads),
|
||||
"view.hiddenCharacters" => flag(&mut app.ui.hidden_characters),
|
||||
@@ -1606,6 +1620,9 @@ pub fn checked(app: &DesignApp, id: &str, params: &Value) -> Option<bool> {
|
||||
"view.typicalDisplay" => app.ui.display_quality == designcraft_render::DisplayQuality::Typical,
|
||||
"view.highQualityDisplay" => app.ui.display_quality == designcraft_render::DisplayQuality::High,
|
||||
"view.guides" => app.ui.guides,
|
||||
"view.snapToGuides" => app.ui.snap_to_guides,
|
||||
"view.snapToDocumentGrid" => app.ui.snap_to_document_grid,
|
||||
"view.smartGuides" => app.ui.smart_guides,
|
||||
"view.baselineGrid" => app.ui.baseline_grid,
|
||||
"view.textThreads" => app.ui.text_threads,
|
||||
"view.hiddenCharacters" => app.ui.hidden_characters,
|
||||
|
||||
@@ -358,8 +358,10 @@ fn document_sections(app: &mut DesignApp, ui: &mut Ui) {
|
||||
if guides != app.ui.guides {
|
||||
let _ = app.run("view.guides", json!({}));
|
||||
}
|
||||
if smart != app.ui.smart_guides {
|
||||
let _ = app.run("view.smartGuides", json!({}));
|
||||
}
|
||||
app.ui.guides_locked = locked;
|
||||
app.ui.smart_guides = smart;
|
||||
rule(ui);
|
||||
section(ui, "Quick Actions", true);
|
||||
let (a, b) = button_pair(ui, "Import File", "Insert Page");
|
||||
|
||||
Reference in New Issue
Block a user