mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
Implement outline view mode (#401)
* Created wasm binding to action's of the radio buttons which control the view mode
Added entry to DocumentMessage Enum
* draw in wireframe mode by changing parameters on each shape
added functions/changed behavior to do as above
not working yet
- newly added shapes should be drawn in wireframe
- setting fill to "none" on a path does not only draw an outline
- maybe the stroke width is 0?
* Wire frame view mostly functional for ellipses
- Need to implement for all shapes
- BUG: shapes don't immediatley update upon changing view-mode
* Fixed: active document now updates after view mode swap
* The Pros:
- wire frame mode effects all shapes correctly
The Cons:
- wire frame mode effects everything, including things that maybe shouldn't be, like select boxes and pen lines
* wire frame view no longer effects overlay layers
* Fixed: While in wireframe view the pen tool will draw regular thickness lines.
* some commenting
* Fixed potential bug:
In layer/file system with a Folder layer with a sub-layer that is also
a Folder cache_dirty must be set in order for all shapes to update properly
* refactored code to use ViewMode enum names throughout
* Changed: All wireframe lines are blank
cargo fmt
* Wireframe thickness doesn't change as a result of zooming
- Added DocumentMessage::ReRenderDocument, which marks layers as dirty and renders with the updated render-string
- All "zoom" messages in the movement_handler send a re-render message
- while in wireframe view, the "render-transform" of all shapes includes the root layer transform
Added getter/setter methods for graphene::Document::view_mode
* cargo fmt
* wireframe now has proper thickness after "Zoom Canvas to Fit all" action
* Refactored
- Changed FrontendMessage::UpdateCanvas to RenderDocument message to allow for lazy evaluation
- Created DocumentOperation::SetViewMode to be more consistent with existing code
- removed log statement
- Added constants for empty fill and thin-black stroke
* cargo fmt
* Removed ReRenderDocument message
* cargo fmt
* Fixes as suggested by TrueDoctor
* clean up merge
cargo fmt
* Refactor:
moved view_mode to DocumentMessageHandler
* Polishing
* changed those two comments
* Remove unknown todo comment
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
@@ -16,8 +16,8 @@ use kurbo::PathSeg;
|
||||
use log::warn;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use graphene::layers::BlendMode;
|
||||
use graphene::{document::Document as GrapheneDocument, layers::LayerDataType, DocumentError, LayerId};
|
||||
use graphene::layers::{style::ViewMode, BlendMode, LayerDataType};
|
||||
use graphene::{document::Document as GrapheneDocument, DocumentError, LayerId};
|
||||
use graphene::{DocumentResponse, Operation as DocumentOperation};
|
||||
|
||||
type DocumentSave = (GrapheneDocument, HashMap<Vec<LayerId>, LayerData>);
|
||||
@@ -68,6 +68,7 @@ pub struct DocumentMessageHandler {
|
||||
movement_handler: MovementMessageHandler,
|
||||
transform_layer_handler: TransformLayerMessageHandler,
|
||||
pub snapping_enabled: bool,
|
||||
pub view_mode: ViewMode,
|
||||
}
|
||||
|
||||
impl Default for DocumentMessageHandler {
|
||||
@@ -83,6 +84,7 @@ impl Default for DocumentMessageHandler {
|
||||
movement_handler: MovementMessageHandler::default(),
|
||||
transform_layer_handler: TransformLayerMessageHandler::default(),
|
||||
snapping_enabled: true,
|
||||
view_mode: ViewMode::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,6 +124,9 @@ pub enum DocumentMessage {
|
||||
ExportDocument,
|
||||
SaveDocument,
|
||||
RenderDocument,
|
||||
DirtyRenderDocument,
|
||||
DirtyRenderDocumentInOutlineView,
|
||||
SetViewMode(ViewMode),
|
||||
Undo,
|
||||
Redo,
|
||||
DocumentHistoryBackward,
|
||||
@@ -162,6 +167,7 @@ impl DocumentMessageHandler {
|
||||
movement_handler: MovementMessageHandler::default(),
|
||||
transform_layer_handler: TransformLayerMessageHandler::default(),
|
||||
snapping_enabled: true,
|
||||
view_mode: ViewMode::default(),
|
||||
};
|
||||
document.graphene_document.root.transform = document.layerdata(&[]).calculate_offset_transform(ipp.viewport_bounds.size() / 2.);
|
||||
document
|
||||
@@ -479,7 +485,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
||||
size.x,
|
||||
size.y,
|
||||
"\n",
|
||||
self.graphene_document.render_root()
|
||||
self.graphene_document.render_root(self.view_mode)
|
||||
),
|
||||
name,
|
||||
}
|
||||
@@ -570,6 +576,10 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
||||
responses.push_front(DocumentOperation::DeleteLayer { path }.into());
|
||||
}
|
||||
}
|
||||
SetViewMode(mode) => {
|
||||
self.view_mode = mode;
|
||||
responses.push_front(DocumentMessage::DirtyRenderDocument.into());
|
||||
}
|
||||
DuplicateSelectedLayers => {
|
||||
self.backup(responses);
|
||||
for path in self.selected_layers_sorted() {
|
||||
@@ -659,7 +669,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
||||
responses.push_back(FolderChanged(vec![]).into());
|
||||
}
|
||||
FolderChanged(path) => {
|
||||
let _ = self.graphene_document.render_root();
|
||||
let _ = self.graphene_document.render_root(self.view_mode);
|
||||
responses.extend([LayerChanged(path).into(), DocumentStructureChanged.into()]);
|
||||
}
|
||||
DocumentStructureChanged => {
|
||||
@@ -672,7 +682,6 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
||||
(!overlay).then(|| FrontendMessage::UpdateLayer { data: entry }.into())
|
||||
}));
|
||||
}
|
||||
|
||||
DispatchOperation(op) => match self.graphene_document.handle_operation(&op) {
|
||||
Ok(Some(document_responses)) => {
|
||||
for response in document_responses {
|
||||
@@ -702,7 +711,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
||||
RenderDocument => {
|
||||
responses.push_back(
|
||||
FrontendMessage::UpdateCanvas {
|
||||
document: self.graphene_document.render_root(),
|
||||
document: self.graphene_document.render_root(self.view_mode),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
@@ -720,8 +729,8 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
||||
let scrollbar_size = viewport_size / bounds_length;
|
||||
|
||||
let log = root_layerdata.scale.log2();
|
||||
let ruler_inverval = if log < 0. { 100. * 2_f64.powf(-log.ceil()) } else { 100. / 2_f64.powf(log.ceil()) };
|
||||
let ruler_spacing = ruler_inverval * root_layerdata.scale;
|
||||
let ruler_interval = if log < 0. { 100. * 2_f64.powf(-log.ceil()) } else { 100. / 2_f64.powf(log.ceil()) };
|
||||
let ruler_spacing = ruler_interval * root_layerdata.scale;
|
||||
|
||||
let ruler_origin = self.graphene_document.root.transform.transform_point2(DVec2::ZERO);
|
||||
|
||||
@@ -738,12 +747,22 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
||||
FrontendMessage::UpdateRulers {
|
||||
origin: ruler_origin.into(),
|
||||
spacing: ruler_spacing,
|
||||
interval: ruler_inverval,
|
||||
interval: ruler_interval,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
DirtyRenderDocument => {
|
||||
// Mark all non-overlay caches as dirty
|
||||
GrapheneDocument::visit_all_shapes(&mut self.graphene_document.root, &mut |_| {});
|
||||
|
||||
responses.push_back(DocumentMessage::RenderDocument.into());
|
||||
}
|
||||
DirtyRenderDocumentInOutlineView => {
|
||||
if self.view_mode == ViewMode::Outline {
|
||||
responses.push_front(DocumentMessage::DirtyRenderDocument.into());
|
||||
}
|
||||
}
|
||||
NudgeSelectedLayers(x, y) => {
|
||||
self.backup(responses);
|
||||
for path in self.selected_layers().map(|path| path.to_vec()) {
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use crate::consts::VIEWPORT_ROTATE_SNAP_INTERVAL;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene::layers::{BlendMode, LayerDataType};
|
||||
use graphene::{
|
||||
layers::{Layer, LayerData as DocumentLayerData},
|
||||
LayerId,
|
||||
};
|
||||
use graphene::layers::{style::ViewMode, BlendMode, Layer, LayerData as DocumentLayerData, LayerDataType};
|
||||
use graphene::LayerId;
|
||||
use serde::{
|
||||
ser::{SerializeSeq, SerializeStruct},
|
||||
Deserialize, Serialize,
|
||||
@@ -64,7 +61,7 @@ pub fn layer_panel_entry(layer_data: &LayerData, transform: DAffine2, layer: &La
|
||||
let arr = arr.iter().map(|x| (*x).into()).collect::<Vec<(f64, f64)>>();
|
||||
|
||||
let mut thumbnail = String::new();
|
||||
layer.data.clone().render(&mut thumbnail, &mut vec![transform]);
|
||||
layer.data.clone().render(&mut thumbnail, &mut vec![transform], ViewMode::Normal);
|
||||
let transform = transform.to_cols_array().iter().map(ToString::to_string).collect::<Vec<_>>().join(",");
|
||||
let thumbnail = if let [(x_min, y_min), (x_max, y_max)] = arr.as_slice() {
|
||||
format!(
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
pub use super::layer_panel::*;
|
||||
|
||||
use super::LayerData;
|
||||
|
||||
pub use crate::document::layer_panel::*;
|
||||
use crate::document::{DocumentMessage, LayerData};
|
||||
use crate::message_prelude::*;
|
||||
use crate::{
|
||||
consts::{VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_SCALE_MAX, VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_WHEEL_RATE},
|
||||
input::{mouse::ViewportBounds, mouse::ViewportPosition, InputPreprocessor},
|
||||
};
|
||||
use glam::DVec2;
|
||||
use graphene::document::Document;
|
||||
use graphene::layers::style::ViewMode;
|
||||
use graphene::Operation as DocumentOperation;
|
||||
|
||||
use glam::DVec2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
@@ -132,21 +131,27 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
|
||||
layerdata.scale = new.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
|
||||
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
|
||||
responses.push_back(ToolMessage::SelectedLayersChanged.into());
|
||||
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
|
||||
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
|
||||
}
|
||||
IncreaseCanvasZoom => {
|
||||
// TODO: Eliminate redundant code by making this call SetCanvasZoom
|
||||
layerdata.scale = *VIEWPORT_ZOOM_LEVELS.iter().find(|scale| **scale > layerdata.scale).unwrap_or(&layerdata.scale);
|
||||
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
|
||||
responses.push_back(ToolMessage::SelectedLayersChanged.into());
|
||||
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
|
||||
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
|
||||
}
|
||||
DecreaseCanvasZoom => {
|
||||
// TODO: Eliminate redundant code by making this call SetCanvasZoom
|
||||
layerdata.scale = *VIEWPORT_ZOOM_LEVELS.iter().rev().find(|scale| **scale < layerdata.scale).unwrap_or(&layerdata.scale);
|
||||
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
|
||||
responses.push_back(ToolMessage::SelectedLayersChanged.into());
|
||||
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
|
||||
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
|
||||
}
|
||||
WheelCanvasZoom => {
|
||||
// TODO: Eliminate redundant code by making this call SetCanvasZoom
|
||||
let scroll = ipp.mouse.scroll_delta.scroll_delta();
|
||||
let mouse = ipp.mouse.position;
|
||||
let viewport_bounds = ipp.viewport_bounds.size();
|
||||
@@ -165,6 +170,7 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
|
||||
layerdata.translation += transformed_delta;
|
||||
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
|
||||
responses.push_back(ToolMessage::SelectedLayersChanged.into());
|
||||
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
|
||||
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
|
||||
}
|
||||
WheelCanvasTranslate { use_y_as_x } => {
|
||||
@@ -199,6 +205,7 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
|
||||
layerdata.scale *= new_scale;
|
||||
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
|
||||
responses.push_back(ToolMessage::SelectedLayersChanged.into());
|
||||
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
|
||||
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user