~raph/interp-toy

33881b89df4e22faa7321317e00328b127a1a40e — Raph Levien 2 years ago abff8f3
Snap to latest druid version

Use delicious native radio buttons!
8 files changed, 51 insertions(+), 86 deletions(-)

M Cargo.lock
M Cargo.toml
M src/interp_pane.rs
M src/lens2.rs
M src/list.rs
M src/main.rs
M src/master.rs
D src/radio.rs
M Cargo.lock => Cargo.lock +29 -6
@@ 103,6 103,17 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "chrono"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
 "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 183,13 194,14 @@ dependencies = [
[[package]]
name = "druid"
version = "0.3.0"
source = "git+https://github.com/xi-editor/druid?rev=88d18be0155791cac0d910f22d0552dd44ec3814#88d18be0155791cac0d910f22d0552dd44ec3814"
source = "git+https://github.com/xi-editor/druid?rev=cfbde68ca16c67b20268a5999da469ed76999b82#cfbde68ca16c67b20268a5999da469ed76999b82"
dependencies = [
 "druid-shell 0.3.0 (git+https://github.com/xi-editor/druid?rev=88d18be0155791cac0d910f22d0552dd44ec3814)",
 "druid-shell 0.3.0 (git+https://github.com/xi-editor/druid?rev=cfbde68ca16c67b20268a5999da469ed76999b82)",
 "fluent-bundle 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "fluent-locale 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "fluent-syntax 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "simple_logger 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "unic-langid 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]


@@ 197,7 209,7 @@ dependencies = [
[[package]]
name = "druid-shell"
version = "0.3.0"
source = "git+https://github.com/xi-editor/druid?rev=88d18be0155791cac0d910f22d0552dd44ec3814#88d18be0155791cac0d910f22d0552dd44ec3814"
source = "git+https://github.com/xi-editor/druid?rev=cfbde68ca16c67b20268a5999da469ed76999b82#cfbde68ca16c67b20268a5999da469ed76999b82"
dependencies = [
 "cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)",


@@ 315,7 327,7 @@ dependencies = [
name = "interp-toy"
version = "0.1.0"
dependencies = [
 "druid 0.3.0 (git+https://github.com/xi-editor/druid?rev=88d18be0155791cac0d910f22d0552dd44ec3814)",
 "druid 0.3.0 (git+https://github.com/xi-editor/druid?rev=cfbde68ca16c67b20268a5999da469ed76999b82)",
 "nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "rbf-interp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]


@@ 795,6 807,15 @@ version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "simple_logger"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1040,6 1061,7 @@ dependencies = [
"checksum cairo-sys-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "90a1ec04603a78c111886a385edcec396dbfbc57ea26b9e74aeea6a1fe55dcca"
"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"


@@ 1048,8 1070,8 @@ dependencies = [
"checksum direct2d 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7fa6ff10857eb253d1ae16987ebfd27372f4129b0c7a3fa41466fbdf7e453e75"
"checksum direct3d11 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "315aa929e68ba066cb6fb86f1b22af24f517e02fd9b5734c4d07e42cb9f4aefa"
"checksum directwrite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8cdcd739e9351c411b8caf5cab32a27c818cfe06260595da121382ecdd22083d"
"checksum druid 0.3.0 (git+https://github.com/xi-editor/druid?rev=88d18be0155791cac0d910f22d0552dd44ec3814)" = "<none>"
"checksum druid-shell 0.3.0 (git+https://github.com/xi-editor/druid?rev=88d18be0155791cac0d910f22d0552dd44ec3814)" = "<none>"
"checksum druid 0.3.0 (git+https://github.com/xi-editor/druid?rev=cfbde68ca16c67b20268a5999da469ed76999b82)" = "<none>"
"checksum druid-shell 0.3.0 (git+https://github.com/xi-editor/druid?rev=cfbde68ca16c67b20268a5999da469ed76999b82)" = "<none>"
"checksum dxgi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1639bbfd6765e92a40267d217a7acbac5b49320b68013f39a8e4376aa8c1e091"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"


@@ 1117,6 1139,7 @@ dependencies = [
"checksum rental-impl 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "82260d54cf2cbe9608df161f7e7c98e81fae702aa13af9e4d5d39dc2ffb25ab6"
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum simple_logger 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a4756ecc75607ba957820ac0a2413a6c27e6c61191cda0c62c6dcea4da88870"
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"

M Cargo.toml => Cargo.toml +1 -1
@@ 7,6 7,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
druid = {git = "https://github.com/xi-editor/druid", rev = "88d18be0155791cac0d910f22d0552dd44ec3814" }
druid = {git = "https://github.com/xi-editor/druid", rev = "cfbde68ca16c67b20268a5999da469ed76999b82" }
rbf-interp = "0.1.3"
nalgebra = "0.18"

M src/interp_pane.rs => src/interp_pane.rs +3 -4
@@ 4,7 4,7 @@ use std::sync::Arc;
use druid::kurbo::{Circle, Size};
use druid::piet::{Color, RenderContext};
use druid::{
    Action, BaseState, BoxConstraints, Env, Event, EventCtx, LayoutCtx, PaintCtx, UpdateCtx, Widget,
    BaseState, BoxConstraints, Env, Event, EventCtx, LayoutCtx, PaintCtx, UpdateCtx, Widget,
};

use crate::AppState;


@@ 74,7 74,7 @@ impl Widget<AppState> for InterpPane {
        ctx: &mut EventCtx,
        data: &mut AppState,
        _env: &Env,
    ) -> Option<Action> {
    ) {
        let width = data.shared.width;
        let weight = data.shared.weight;
        match event {


@@ 87,7 87,7 @@ impl Widget<AppState> for InterpPane {
                    if interp.distance(pos) < 5.0 {
                        self.drag_ix = Some(i);
                        data.sel = Some(i);
                        return None;
                        return;
                    }
                }
                self.drag_ix = Some(pts.len());


@@ 110,7 110,6 @@ impl Widget<AppState> for InterpPane {
            }
            _ => (),
        }
        None
    }

    fn update(

M src/lens2.rs => src/lens2.rs +3 -3
@@ 20,7 20,7 @@ use std::marker::PhantomData;
use druid::kurbo::Size;

use druid::{
    Action, BaseState, BoxConstraints, Data, Env, Event, EventCtx, LayoutCtx, PaintCtx, UpdateCtx,
    BaseState, BoxConstraints, Data, Env, Event, EventCtx, LayoutCtx, PaintCtx, UpdateCtx,
    Widget,
};



@@ 169,10 169,10 @@ where
        ctx: &mut EventCtx,
        data: &mut T,
        env: &Env,
    ) -> Option<Action> {
    ) {
        let inner = &mut self.inner;
        self.lens
            .with_mut(data, |data| inner.event(event, ctx, data, env))
            .with_mut(data, |data| inner.event(event, ctx, data, env));
    }

    fn update(&mut self, ctx: &mut UpdateCtx, old_data: Option<&T>, data: &T, env: &Env) {

M src/list.rs => src/list.rs +5 -9
@@ 5,7 5,7 @@ use std::sync::Arc;
use druid::kurbo::{Point, Rect, Size};

use druid::{
    Action, BaseState, BoxConstraints, Data, Env, Event, EventCtx, LayoutCtx, PaintCtx, UpdateCtx,
    BaseState, BoxConstraints, Data, Env, Event, EventCtx, LayoutCtx, PaintCtx, UpdateCtx,
    Widget, WidgetPod,
};



@@ 65,13 65,12 @@ impl<T: Data, F: FnMut() -> Box<dyn Widget<T>>> Widget<Arc<Vec<T>>> for List<T, 
        ctx: &mut EventCtx,
        data: &mut Arc<Vec<T>>,
        env: &Env,
    ) -> Option<Action> {
        let mut action = None;
    ) {
        let mut new_data = Vec::with_capacity(data.len());
        let mut any_changed = false;
        for (child, child_data) in self.children.iter_mut().zip(data.iter()) {
            let mut d = child_data.to_owned();
            action = Action::merge(action, child.event(event, ctx, &mut d, env));
            child.event(event, ctx, &mut d, env);
            if !any_changed && !child_data.same(&d) {
                any_changed = true;
            }


@@ 80,7 79,6 @@ impl<T: Data, F: FnMut() -> Box<dyn Widget<T>>> Widget<Arc<Vec<T>>> for List<T, 
        if any_changed {
            *data = Arc::new(new_data);
        }
        action
    }

    fn update(


@@ 155,15 153,14 @@ impl<T1: Data, T: Data, F: FnMut() -> Box<dyn Widget<(T1, T)>>> Widget<(T1, Arc<
        ctx: &mut EventCtx,
        data: &mut (T1, Arc<Vec<T>>),
        env: &Env,
    ) -> Option<Action> {
        let mut action = None;
    ) {
        let mut new_shared = data.0.to_owned();
        let mut new_data = Vec::with_capacity(data.1.len());
        let mut any_shared_changed = false;
        let mut any_el_changed = false;
        for (child, child_data) in self.children.iter_mut().zip(data.1.iter()) {
            let mut d = (new_shared.clone(), child_data.to_owned());
            action = Action::merge(action, child.event(event, ctx, &mut d, env));
            child.event(event, ctx, &mut d, env);
            if !any_shared_changed && !new_shared.same(&d.0) {
                any_shared_changed = true;
            }


@@ 183,7 180,6 @@ impl<T1: Data, T: Data, F: FnMut() -> Box<dyn Widget<(T1, T)>>> Widget<(T1, Arc<
        if any_el_changed {
            data.1 = Arc::new(new_data);
        }
        action
    }

    fn update(

M src/main.rs => src/main.rs +6 -12
@@ 1,4 1,4 @@
use druid::widget::{ActionWrapper, Button, Column, DynLabel, Padding, Row, Scroll, Slider};
use druid::widget::{Button, Column, DynLabel, Padding, RadioGroup, Row, Scroll, Slider};
use druid::{AppLauncher, LensWrap, LocalizedString, Widget, WindowDesc};

mod app_state;


@@ 6,14 6,12 @@ mod interp_pane;
mod lens2;
mod list;
mod master;
mod radio;

use app_state::{lenses, AppState, InterpPt, InterpType};
use interp_pane::InterpPane;
use lens2::{Lens2Wrap, Pair};
use list::List;
use master::MasterItem;
use radio::radio;

fn build_ui() -> impl Widget<AppState> {
    let pane = InterpPane::default();


@@ 33,17 31,16 @@ fn build_ui() -> impl Widget<AppState> {
    col.add_child(Padding::uniform(5.0, label_wdth), 0.0);
    col.add_child(
        LensWrap::new(
            radio(vec![
                (InterpType::Gaussian, LocalizedString::new("Gaussian")),
                (InterpType::ThinPlate, LocalizedString::new("Thin plate")),
                (InterpType::Linear, LocalizedString::new("Linear")),
            RadioGroup::new(vec![
                (LocalizedString::new("Gaussian"), InterpType::Gaussian),
                (LocalizedString::new("Thin plate"), InterpType::ThinPlate),
                (LocalizedString::new("Linear"), InterpType::Linear),
            ]),
            lenses::app_state::InterpType,
        ),
        0.0,
    );
    let new_master_button = Button::new("New Master");
    let new_master_button = ActionWrapper::new(new_master_button, |data: &mut AppState, _env| {
    let new_master_button = Button::new("New Master", |_ctx, data: &mut AppState, _env| {
        data.add_new_master()
    });
    col.add_child(Padding::uniform(5.0, new_master_button), 0.0);


@@ 55,7 52,6 @@ fn build_ui() -> impl Widget<AppState> {
        .vertical(),
        1.0,
    );
    let col = ActionWrapper::new(col, |data: &mut AppState, _env| data.shared.width += 0.1);
    let mut row = Row::new();
    row.add_child(pane, 2.0);
    row.add_child(col, 1.0);


@@ 63,8 59,6 @@ fn build_ui() -> impl Widget<AppState> {
}

fn main() {
    druid::shell::init();

    let app_state = AppState::default();
    let title = LocalizedString::new("Interpolation toy");
    let window = WindowDesc::new(build_ui).title(title);

M src/master.rs => src/master.rs +4 -4
@@ 3,7 3,7 @@
use druid::kurbo::{Point, Rect, Size};

use druid::{
    Action, BaseState, BoxConstraints, BoxedWidget, Env, Event, EventCtx, LayoutCtx, PaintCtx,
    BaseState, BoxConstraints, BoxedWidget, Env, Event, EventCtx, LayoutCtx, PaintCtx,
    UpdateCtx, Widget, WidgetPod,
};



@@ 60,16 60,16 @@ impl Widget<(Shared, Master)> for MasterItem {
        ctx: &mut EventCtx,
        data: &mut (Shared, Master),
        env: &Env,
    ) -> Option<Action> {
    ) {
        match event {
            Event::MouseDown(_) => {
                data.0.weight = data.1.weight;
                data.0.width = data.1.width;
                return None;
                return;
            }
            _ => (),
        }
        self.child.event(event, ctx, data, env)
        self.child.event(event, ctx, data, env);
    }

    fn update(

D src/radio.rs => src/radio.rs +0 -47
@@ 1,47 0,0 @@
//! A somewhat hacked-up version of a radio button using lensing.

use druid::widget::{Checkbox, Column, Label, Padding, Row};
use druid::{Data, Lens, LensWrap, LocalizedString, Widget};

struct EnumLens<T: Data> {
    variant: T,
}

impl<T: Data> EnumLens<T> {
    pub fn new(variant: T) -> Self {
        EnumLens { variant }
    }
}

impl<T: Data> Lens<T, bool> for EnumLens<T> {
    fn get<'a>(&self, data: &'a T) -> &'a bool {
        if data.same(&self.variant) {
            &true
        } else {
            &false
        }
    }

    fn with_mut<V, F: FnOnce(&mut bool) -> V>(&self, data: &mut T, f: F) -> V {
        let mut is_set = data.same(&self.variant);
        let val = f(&mut is_set);
        if is_set {
            *data = self.variant.clone()
        }
        val
    }
}

pub fn radio<T: Data + 'static>(
    variants: impl IntoIterator<Item = (T, LocalizedString<bool>)>,
) -> impl Widget<T> {
    let mut col = Column::new();
    for (variant, label) in variants.into_iter() {
        let mut row = Row::new();
        row.add_child(Checkbox::new(), 0.0);
        row.add_child(Label::new(label), 1.0);
        let lensed = LensWrap::new(row, EnumLens::new(variant));
        col.add_child(Padding::uniform(3.0, lensed), 0.0);
    }
    col
}