diff --git a/examples/dial_test.rs b/examples/dial_test.rs new file mode 100644 index 0000000000000000000000000000000000000000..40ec480a50fa9e1475ba57d16df36b46015ae1f1 --- /dev/null +++ b/examples/dial_test.rs @@ -0,0 +1,93 @@ +// Copyright 2019 The xi-editor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! An example of an animating widget. + +use std::f64::consts::PI; + +use druid::kurbo::{BezPath, Line}; +use druid::widget::{Flex, Label, WidgetExt}; +use druid::{ + AppLauncher, BoxConstraints, Color, Data, Env, Event, EventCtx, LayoutCtx, Lens, LensWrap, + LinearGradient, PaintCtx, PlatformError, Point, RenderContext, Size, UnitPoint, UpdateCtx, + Vec2, WheelEvent, Widget, WindowDesc, +}; + +use log::info; + +use druid_widgets::*; + +#[derive(Clone, Data, Lens)] +struct DialData { + value: f64, +} + +fn build_app() -> impl Widget<(DialData)> { + let solid = Color::rgb8(0x3a, 0x3a, 0x3a); + let gradient = LinearGradient::new( + UnitPoint::TOP_LEFT, + UnitPoint::BOTTOM_RIGHT, + (Color::rgb8(0x11, 0x11, 0x11), Color::rgb8(0xbb, 0xbb, 0xbb)), + ); + + Flex::column() + .with_child( + Flex::row() + .with_child( + Label::new("top left") + .background(solid.clone()) + .padding(10.0), + 1.0, + ) + .with_child( + LensWrap::new(Dial::new(Size::new(100.0, 100.0)), DialData::value) + .background(solid.clone()) + .padding(10.0), + 0.0, + ) + .with_child( + Label::new("top right") + .background(solid.clone()) + .padding(10.0), + 1.0, + ), + 0.0, // vertical + ) + .with_child( + Flex::row() + .with_child( + Label::new("bottom left") + .background(gradient.clone()) + .rounded(10.0) + .padding(10.0), + 0.0, + ) + .with_child( + Label::new("bottom right") + .border(solid.clone(), 4.0) + .rounded(10.0) + .padding(10.0), + 1.0, + ), + 1.0, + ) +} + +fn main() -> Result<(), PlatformError> { + AppLauncher::with_window(WindowDesc::new(build_app)) + .use_simple_logger() + .launch(DialData { value: 0.0 })?; + + Ok(()) +} diff --git a/src/dial.rs b/src/dial.rs new file mode 100644 index 0000000000000000000000000000000000000000..b9a3444552d0051a9dc881a4b3ebefe2a7ba38fa --- /dev/null +++ b/src/dial.rs @@ -0,0 +1,83 @@ +use std::f64::consts::PI; + +use druid::kurbo::{BezPath, Line}; +use druid::widget::{Align, Flex, Label, WidgetExt}; +use druid::{ + AppLauncher, BoxConstraints, Color, Data, Env, Event, EventCtx, LayoutCtx, LinearGradient, + PaintCtx, PlatformError, Point, RenderContext, Size, UnitPoint, UpdateCtx, Vec2, WheelEvent, + Widget, WindowDesc, +}; +use log::info; +use std::convert::From; +#[derive(Debug, Clone, Default)] +pub struct Dial { + // properties for the Dial + value: f64, + size: Size, +} + +impl Dial { + pub fn new(size: Size) -> impl Widget<f64> { + Self { value: 0.0, size } + } +} + +impl Widget<f64> for Dial { + fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut f64, _env: &Env) { + match event { + Event::Wheel(w) => { + let mut delta = w.delta.y / (120 * 10) as f64; // 1% for my machine + if w.mods.shift { + delta = delta / 10.0; + }; + if w.mods.ctrl { + delta = delta / 10.0; + }; + + // set data + // maybe we can get scroll wheel direction from Env/Preferences + *data = *data - delta; + *data = f64::min(1.0, f64::max(0.0, *data)); + + ctx.invalidate(); + } + _ => (), + } + } + + fn update(&mut self, ctx: &mut UpdateCtx, _old_data: Option<&f64>, _data: &f64, _env: &Env) { + ctx.invalidate(); + } + fn layout( + &mut self, + _layout_ctx: &mut LayoutCtx, + bc: &BoxConstraints, + _data: &f64, + _env: &Env, + ) -> Size { + bc.constrain(self.size) + } + + fn paint(&mut self, paint_ctx: &mut PaintCtx, data: &f64, _env: &Env) { + info!("dial paint"); + // for some reason origin (0,0) seems not to point to the border not the interior + let center = Point::new(self.size.width / 2.0, self.size.height / 2.0); + let diameter = 0.8 * self.size.width / 2.0; + let mut path = BezPath::new(); + let ambit0 = center + diameter * Vec2::from_angle(0.0); + path.move_to(ambit0); + for v in (0..360).step_by(10) { + let ambit = center + diameter * Vec2::from_angle(v as f64 / 360.0 * 2.0 * PI); + path.line_to(ambit); + } + path.close_path(); + paint_ctx.stroke(path, &Color::WHITE, 1.0); + + let mut path = BezPath::new(); + path.move_to(center); + path.line_to( + center + diameter * Vec2::from_angle(data * 2.0 * 0.75 * PI + 2.0 * PI * 0.375), + ); + paint_ctx.stroke(path, &Color::WHITE, 1.0); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..d39bf795b3f7136012404652f1e519db9c134faf --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +mod dial; + +pub use dial::*; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 78644872dc3d66c4310675fa20f024f22125862f..0000000000000000000000000000000000000000 --- a/src/main.rs +++ /dev/null @@ -1,28 +0,0 @@ -use druid::widget::{Align, Button, Flex, Label, Padding, WidgetExt}; -use druid::{AppLauncher, LocalizedString, Widget, WindowDesc}; - -use log::info; -fn main() { - let main_window = WindowDesc::new(ui_builder); - let data = 0_u32; - AppLauncher::with_window(main_window) - .use_simple_logger() - .launch(data) - .expect("launch failed"); -} - -fn ui_builder() -> impl Widget<u32> { - // The label text will be computed dynamically based on the current locale and count - let text = - LocalizedString::new("hello-counter").with_arg("count", |data: &u32, _env| (*data).into()); - let label = Label::new(text).padding(5.0).center(); - let button = Button::new("increment", |_ctx, data, _env| { - *data += 1; - info!("Button Pressed"); - }) - .padding(5.0); - - Flex::column() - .with_child(label, 1.0) - .with_child(button, 1.0) -}