M glyphstool/src/font.rs => glyphstool/src/font.rs +1 -1
@@ 52,7 52,7 @@ pub struct Node {
pub node_type: NodeType,
}
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy, PartialEq)]
pub enum NodeType {
Line,
OffCurve,
M glyphstool/src/lib.rs => glyphstool/src/lib.rs +1 -1
@@ 6,7 6,7 @@ mod plist;
mod stretch;
mod to_plist;
-pub use font::Font;
+pub use font::{Font, NodeType};
pub use from_plist::FromPlist;
pub use plist::Plist;
pub use stretch::stretch;
M src/app_state.rs => src/app_state.rs +8 -0
@@ 3,6 3,7 @@ use std::sync::Arc;
use nalgebra::DVector;
+use glyphstool::NodeType;
use rbf_interp::{Basis, Scatter};
use druid::kurbo::Point;
@@ 21,6 22,8 @@ pub struct AppState {
pub masters: Arc<Vec<Master>>,
pub interp_type: InterpType,
+
+ pub structure: Arc<Vec<Vec<NodeType>>>,
}
#[derive(Clone, Copy, PartialEq)]
@@ 43,6 46,7 @@ impl Data for AppState {
&& self.pts.same(&other.pts)
&& self.masters.same(&other.masters)
&& self.interp_type.same(&other.interp_type)
+ && self.structure.same(&other.structure)
}
}
@@ 214,6 218,10 @@ impl AppState {
pub fn set_pts(&mut self, pts: Vec<InterpPt>) {
*Arc::make_mut(&mut self.pts) = pts;
}
+
+ pub fn set_structure(&mut self, structure: Vec<Vec<NodeType>>) {
+ *Arc::make_mut(&mut self.structure) = structure;
+ }
}
impl InterpPt {
M src/interp_pane.rs => src/interp_pane.rs +47 -7
@@ 1,7 1,9 @@
use std::ops::Deref;
use std::sync::Arc;
-use druid::kurbo::{Circle, Size};
+use glyphstool::NodeType;
+
+use druid::kurbo::{BezPath, Circle, Point, Size};
use druid::piet::{Color, RenderContext};
use druid::{
BaseState, BoxConstraints, Env, Event, EventCtx, LayoutCtx, PaintCtx, UpdateCtx, Widget,
@@ 25,6 27,36 @@ enum PtState {
IsMaster,
}
+fn reconstruct_path(pts: &[Point], structure: &[Vec<NodeType>]) -> BezPath {
+ let mut bez_path = BezPath::new();
+ let mut j = 0;
+ for subpath in structure {
+ let mut start_ix = 0;
+ while subpath[start_ix] == NodeType::OffCurve {
+ start_ix += 1;
+ }
+ let n = subpath.len();
+ bez_path.move_to(pts[j + start_ix]);
+ let mut ctrl_pts = Vec::with_capacity(2);
+ for i in 0..n {
+ let ix = (start_ix + i + 1) % n;
+ let node_type = subpath[ix];
+ let p = pts[j + ix];
+ match node_type {
+ NodeType::Line => bez_path.line_to(p),
+ NodeType::OffCurve => ctrl_pts.push(p),
+ NodeType::Curve | NodeType::CurveSmooth => {
+ bez_path.curve_to(ctrl_pts[0], ctrl_pts[1], p);
+ ctrl_pts.clear();
+ }
+ }
+ }
+ bez_path.close_path();
+ j += n;
+ }
+ bez_path
+}
+
impl Widget<AppState> for InterpPane {
fn paint(
&mut self,
@@ 40,17 72,25 @@ impl Widget<AppState> for InterpPane {
} else {
PtState::Interpolated
};
- for (i, pt) in data.pts.iter().enumerate() {
+ let pts: Vec<_> = data
+ .pts
+ .iter()
+ .map(|pt| pt.eval(width, weight, data.interp_type))
+ .collect();
+ let fill_color = Color::WHITE;
+ let path = reconstruct_path(&pts, &data.structure);
+ paint_ctx.fill(path, &fill_color);
+ for i in 0..pts.len() {
let fg_color = match pt_state {
- PtState::CanAddMaster => Color::WHITE,
- PtState::Interpolated => Color::WHITE.with_alpha(0.5),
+ PtState::CanAddMaster => Color::rgb8(0x80, 0x80, 0xff),
+ PtState::Interpolated => Color::rgb8(0x80, 0x80, 0xff).with_alpha(0.8),
_ => Color::rgb(0xff, 0, 0),
};
let is_selected = data.sel == Some(i);
- let interp = pt.eval(width, weight, data.interp_type);
- let radius = if is_selected { 6.0 } else { 5.0 };
+ let interp = pts[i];
+ let radius = if is_selected { 3.0 } else { 2.0 };
let circle = Circle::new(interp, radius);
- paint_ctx.render_ctx.fill(circle, &fg_color);
+ paint_ctx.fill(circle, &fg_color);
}
}
M src/main.rs => src/main.rs +10 -0
@@ 94,12 94,20 @@ fn set_app_state_for_glyph(app_state: &mut AppState, font: &Font, glyphname: &st
app_state.add_weight(weight);
}
if let Some(glyph) = font.get_glyph(glyphname) {
+ let mut structure = Vec::new();
+ let mut first_layer = true;
let mut pts = Vec::new();
for layer in &glyph.layers {
if let Some(&weight) = weight_map.get(&layer.layer_id) {
let mut i = 0;
for p in layer.paths.as_ref().unwrap() {
+ if first_layer {
+ structure.push(Vec::new());
+ }
for n in &p.nodes {
+ if first_layer {
+ structure.last_mut().unwrap().push(n.node_type);
+ }
if i == pts.len() {
pts.push(InterpPt::default());
}
@@ 113,8 121,10 @@ fn set_app_state_for_glyph(app_state: &mut AppState, font: &Font, glyphname: &st
}
}
}
+ first_layer = false;
}
app_state.set_pts(pts);
+ app_state.set_structure(structure);
}
}