Use overlays to draw artboard names (#1981)

* Artboard label overlay

* Finish artboard overlays

* cargo fmt

* Update font styling

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
James Lindsay
2024-09-20 22:04:31 +00:00
committed by GitHub
co-authored by Keavon Chambers
parent 32da545a49
commit 0d33a1ae3f
8 changed files with 71 additions and 55 deletions
@@ -50,6 +50,7 @@ pub enum DocumentMessage {
DocumentHistoryBackward,
DocumentHistoryForward,
DocumentStructureChanged,
DrawArtboardOverlays(OverlayContext),
DuplicateSelectedLayers,
EnterNestedNetwork {
node_id: NodeId,
@@ -1,11 +1,12 @@
use super::node_graph::utility_types::Transform;
use super::overlays::utility_types::Pivot;
use super::utility_types::clipboards::Clipboard;
use super::utility_types::error::EditorError;
use super::utility_types::misc::{SnappingOptions, SnappingState, GET_SNAP_BOX_FUNCTIONS, GET_SNAP_GEOMETRY_FUNCTIONS};
use super::utility_types::network_interface::{NodeNetworkInterface, TransactionStatus};
use super::utility_types::nodes::{CollapsedLayers, SelectedNodes};
use crate::application::{generate_uuid, GRAPHITE_GIT_COMMIT_HASH};
use crate::consts::{ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ROTATE_SNAP_INTERVAL};
use crate::consts::{ASYMPTOTIC_EFFECT, COLOR_OVERLAY_GRAY, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ROTATE_SNAP_INTERVAL};
use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
@@ -371,6 +372,18 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
let data_buffer: RawBuffer = self.serialize_root();
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
}
DocumentMessage::DrawArtboardOverlays(overlay_context) => {
for layer in self.metadata().all_layers() {
if !self.network_interface.is_artboard(&layer.to_node(), &[]) {
continue;
}
let Some(bounds) = self.metadata().bounding_box_document(layer) else { continue };
let name = self.network_interface.frontend_display_name(&layer.to_node(), &[]);
let transform = self.metadata().document_to_viewport * DAffine2::from_translation(bounds[0].min(bounds[1]) - DVec2::Y * 4.);
overlay_context.text_with_transform(&name, COLOR_OVERLAY_GRAY, None, transform, Pivot::BottomLeft);
}
}
DocumentMessage::DuplicateSelectedLayers => {
let parent = self.new_layer_parent(false);
let calculated_insert_index =
@@ -247,47 +247,52 @@ impl OverlayContext {
self.render_context.stroke();
}
pub fn text(&self, text: &str, pos: DVec2, background: &str, padding: f64) {
let pos = pos.round();
pub fn text(&self, text: &str, font_color: &str, background_color: Option<&str>, pos: DVec2) {
let metrics = self.render_context.measure_text(text).expect("Failed to measure the text dimensions");
self.render_context.set_fill_style(&background.into());
self.render_context.fill_rect(
pos.x + metrics.actual_bounding_box_left(),
pos.y - metrics.font_bounding_box_ascent() - metrics.font_bounding_box_descent() - padding * 2.,
metrics.actual_bounding_box_right() - metrics.actual_bounding_box_left() + padding * 2.,
metrics.font_bounding_box_ascent() + metrics.font_bounding_box_descent() + padding * 2.,
);
self.render_context.set_fill_style(&"white".into());
self.render_context
.fill_text(text, pos.x + padding, pos.y - padding - metrics.font_bounding_box_descent())
.expect("Failed to draw the text on the canvas");
let local_position = pos.round();
self.draw_text(background_color, local_position, metrics, font_color, text);
}
pub fn angle_text(&self, text: &str, pos: DVec2, direction: DVec2, padding: f64, pivot: Pivot) {
self.render_context.translate(pos.x, pos.y).expect("Failed to translate the render context to the specified position");
let angle = -direction.angle_to(DVec2::X);
self.render_context.rotate(angle).expect("Failed to rotate the render context to the specified angle");
pub fn text_with_transform(&self, text: &str, font_color: &str, background_color: Option<&str>, transform: DAffine2, origin: Pivot) {
let [a, b, c, d, e, f] = transform.to_cols_array();
self.render_context.set_transform(a, b, c, d, e, f).expect("Failed to rotate the render context to the specified angle");
let metrics = self.render_context.measure_text(text).expect("Failed to measure the text dimensions");
self.render_context.set_fill_style(&wasm_bindgen::JsValue::from_str(COLOR_OVERLAY_BLUE));
let local_position = match pivot {
Pivot::LeftCentreY => DVec2::new(padding, (metrics.actual_bounding_box_ascent() + metrics.actual_bounding_box_descent()) / 2.),
Pivot::TopCentreX => DVec2::new(
-(metrics.actual_bounding_box_right() + metrics.actual_bounding_box_left()) / 2.,
padding + metrics.font_bounding_box_ascent(),
),
let local_position = match origin {
Pivot::CenterLeft => DVec2::new(0., (metrics.actual_bounding_box_ascent() + metrics.actual_bounding_box_descent()) / 2.),
Pivot::TopCenter => DVec2::new(-(metrics.actual_bounding_box_right() + metrics.actual_bounding_box_left()) / 2., metrics.font_bounding_box_ascent()),
Pivot::BottomLeft => DVec2::ZERO,
};
self.render_context
.fill_text(text, local_position.x, local_position.y)
.expect("Failed to draw the text at the calculated position");
self.draw_text(background_color, local_position, metrics, font_color, text);
self.render_context.reset_transform().expect("Failed to reset the render context transform");
}
fn draw_text(&self, background_color: Option<&str>, local_position: DVec2, metrics: web_sys::TextMetrics, font_color: &str, text: &str) {
// Render background
if let Some(background) = background_color {
self.render_context.set_fill_style(&background.into());
self.render_context.fill_rect(
local_position.x + metrics.actual_bounding_box_left(),
local_position.y - metrics.font_bounding_box_ascent() - metrics.font_bounding_box_descent(),
metrics.actual_bounding_box_right() - metrics.actual_bounding_box_left(),
metrics.font_bounding_box_ascent() + metrics.font_bounding_box_descent(),
);
}
// Render text
self.render_context.set_font("12px Source Sans Pro, Arial, sans-serif");
self.render_context.set_fill_style(&font_color.into());
self.render_context
.fill_text(text, local_position.x, local_position.y - metrics.font_bounding_box_descent())
.expect("Failed to draw the text on the canvas");
}
}
pub enum Pivot {
LeftCentreY,
TopCentreX,
TopCenter,
CenterLeft,
BottomLeft,
}