From 14a143708f22581099595cfa21e9db2b89f0121f Mon Sep 17 00:00:00 2001 From: Daniel Dada Date: Fri, 21 Nov 2025 00:31:19 +0300 Subject: [PATCH] chore: restructured the project docs: added contributing guidelines and updated rreadme --- .gitignore | 14 +- CHANGELOG.md | 10 + CONTRIBUTING.md | 48 +++++ Cargo.lock | 2 +- Cargo.toml | 4 +- README.md | 82 ++++++-- examples/example_knob.rs | 26 ++- scrot.png | Bin 47184 -> 50908 bytes src/config.rs | 41 ++++ src/lib.rs | 417 +-------------------------------------- src/render.rs | 196 ++++++++++++++++++ src/style.rs | 44 +++++ src/widget.rs | 211 ++++++++++++++++++++ 13 files changed, 657 insertions(+), 438 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 src/config.rs create mode 100644 src/render.rs create mode 100644 src/style.rs create mode 100644 src/widget.rs diff --git a/.gitignore b/.gitignore index 0a23edc..71336b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,14 @@ +# Rust /target -/examples/target \ No newline at end of file +/examples/target + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ee0ae94..2bb6aea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. +## [0.3.5] - 2025-07-15 + +### 🛠 Maintenance + +- Restructured the project + +### 📚 Documentation + +- Updated readme, added contributing guidelines + ## [0.3.4] - 2025-07-15 ### 🛠 Maintenance diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..788df57 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,48 @@ +# Contributing to egui_knob + +## Getting Started + +1. Fork the repository +2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/egui_knob.git` +3. Create a new branch: `git checkout -b feature/your-feature-name` +4. Make your changes +5. Test your changes +6. Commit your changes +7. Push to the branch: `git push origin feature/your-feature-name` +8. Submit a pull request + +## Development + +### Building + +```bash +cargo build +``` + +## Running demo app + +```bash +cargo run --example example_knob +``` + +## Code Style + +- Follow Rust standard formatting (use `cargo fmt`) +- Write clear, descriptive commit messages +- Add documentation for public APIs +- Keep changes focused and atomic + +## Pull Request Guidelines + +- Add examples for new features +- Keep PRs focused on a single feature or fix +- Reference any related issues + +## Reporting Issues + +When reporting issues, please include: +- A clear description of the problem +- Steps to reproduce +- Expected vs actual behavior +- Your environment (OS, Rust version) +- Minimal code example if applicable diff --git a/Cargo.lock b/Cargo.lock index 54349b5..224ab51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -869,7 +869,7 @@ dependencies = [ [[package]] name = "egui_knob" -version = "0.3.4" +version = "0.3.5" dependencies = [ "eframe", "egui", diff --git a/Cargo.toml b/Cargo.toml index b0a9096..644badd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "egui_knob" -version = "0.3.4" +version = "0.3.5" edition = "2024" +authors = ["Daniel Dada"] description = "A simple knob widget for egui" homepage = "https://github.com/obsqrbtz/egui_knob" repository = "https://github.com/obsqrbtz/egui_knob" +documentation = "https://docs.rs/egui_knob" readme = "README.md" license = "MIT" keywords = ["egui", "ui", "widget", "knob", "range"] diff --git a/README.md b/README.md index ff3f39e..019645b 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,23 @@ # egui_knob -![Crates.io Version](https://img.shields.io/crates/v/egui_knob) +[![Crates.io](https://img.shields.io/crates/v/egui_knob)](https://crates.io/crates/egui_knob) +[![Documentation](https://docs.rs/egui_knob/badge.svg)](https://docs.rs/egui_knob) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) -Simple knob widget for egui. +A simple, customizable knob widget for egui. ![Knob Widget Screenshot](scrot.png) ## Features -- Adjustable size, font size, and stroke width. -- Customizable colors for the knob, indicator and text. -- Label positions (Top, Bottom, Left, Right). -- Label formatting. -- Two styles: Wiper and Dot. +- Adjustable size, font size, and stroke width +- Customizable colors for the knob, indicator, and text +- Label positions (Top, Bottom, Left, Right) +- Custom label formatting +- Two visual styles: Wiper and Dot +- Configurable sweep range +- Background arc with filled segments +- Adjustable drag sensitivity ## Installation @@ -22,14 +27,16 @@ To use the Knob widget in your project, add the following to your `Cargo.toml`: [dependencies] egui = "0.33" eframe = "0.33" -egui_knob = "0.3.4" +egui_knob = "0.3.5" ``` -## Usage example +## Usage + +### Basic Example ```rust use egui_knob::{Knob, KnobStyle, LabelPosition}; -use eframe::{egui}; +use eframe::egui; struct KnobApp { value: f32, @@ -56,12 +63,55 @@ impl eframe::App for KnobApp { } } -fn main() { - let options = eframe::NativeOptions::default(); +fn main() -> eframe::Result<()> { eframe::run_native( - "Minimal", - options, - Box::new(|_cc| Ok(Box::new(KnobApp::default()) as Box)), - ).unwrap(); + "Knob Example", + eframe::NativeOptions::default(), + Box::new(|_cc| Ok(Box::new(KnobApp::default()))), + ) } ``` + +### Advanced Examples + +#### Custom Sweep Range +```rust +// 270° sweep starting from the left (9 o'clock position) +Knob::new(&mut value, 0.0, 100.0, KnobStyle::Wiper) + .with_sweep_range(0.25, 0.75) + .with_label("Gain", LabelPosition::Bottom); +``` + +#### Multi-Turn Knob +```rust +// 2.5 full rotations +Knob::new(&mut value, 0.0, 1.0, KnobStyle::Dot) + .with_sweep_range(0.0, 2.5); +``` + +#### Stepped Values +```rust +// Snap to 0.1 increments +Knob::new(&mut value, 0.0, 1.0, KnobStyle::Wiper) + .with_step(Some(0.1)) + .with_label_format(|v| format!("{:.1}", v)); +``` + +#### Custom Formatting +```rust +// Display as percentage +Knob::new(&mut value, 0.0, 1.0, KnobStyle::Wiper) + .with_label_format(|v| format!("{:.0}%", v * 100.0)); +``` + +## Running demo app + +```bash +cargo run --example example_knob +``` + +Demo app is available at [examples/example_knob.rs](examples/example_knob.rs). + +## Contributing + +Contributions are welcome. Feel free to open an issue or submit a PR. diff --git a/examples/example_knob.rs b/examples/example_knob.rs index 23b3af3..fdd79ae 100644 --- a/examples/example_knob.rs +++ b/examples/example_knob.rs @@ -2,9 +2,16 @@ use eframe::egui; use egui_knob::{Knob, KnobStyle, LabelPosition}; fn main() -> eframe::Result<()> { + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default() + .with_inner_size([800.0, 600.0]) + .with_title("egui_knob demo"), + ..Default::default() + }; + eframe::run_native( "egui_knob demo", - eframe::NativeOptions::default(), + options, Box::new(|_cc| Ok(Box::new(KnobDemo::default()))), ) } @@ -36,24 +43,27 @@ impl Default for KnobDemo { impl eframe::App for KnobDemo { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { - ui.heading("egui-knob example"); + ui.heading("egui_knob demo"); ui.separator(); ui.horizontal(|ui| { - ui.checkbox(&mut self.show_bg_arc, "Show background arc"); - ui.checkbox(&mut self.show_filled, "Show filled segment"); - ui.checkbox(&mut self.use_step, "Enable step (0.1)"); + ui.label("Global Settings:"); + ui.checkbox(&mut self.show_bg_arc, "Background arc"); + ui.checkbox(&mut self.show_filled, "Filled segment"); + ui.checkbox(&mut self.use_step, "Step (0.02)"); }); ui.horizontal(|ui| { - ui.label("Knob Colors:"); + ui.label("Color Theme:"); ui.color_edit_button_srgba(&mut self.knob_color); + ui.label("Knob"); ui.color_edit_button_srgba(&mut self.line_color); + ui.label("Indicator"); ui.color_edit_button_srgba(&mut self.text_color); + ui.label("Text"); }); ui.separator(); - ui.label("👇 Scroll or drag knobs to interact:"); ui.add_space(10.0); egui::Grid::new("knob_grid") @@ -78,7 +88,7 @@ impl eframe::App for KnobDemo { .with_background_arc(self.show_bg_arc) .with_show_filled_segments(self.show_filled) .with_colors(self.knob_color, self.line_color, self.text_color) - .with_step(self.use_step.then_some(0.1)); + .with_step(self.use_step.then_some(0.02)); if *label == "Wiper, Sweep" { knob = knob.with_sweep_range(0.25, 0.75).with_size(50.0); diff --git a/scrot.png b/scrot.png index 852bf2300879ee473ea7640f5a4f6e62d2fb8554..d45350dd62ae8fcc54770a599e6dc2ce09e63e7e 100644 GIT binary patch literal 50908 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 diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..8f85683 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,41 @@ +use crate::style::{KnobColors, KnobStyle, LabelPosition}; + +pub struct KnobConfig { + pub(crate) size: f32, + pub(crate) font_size: f32, + pub(crate) stroke_width: f32, + pub(crate) colors: KnobColors, + pub(crate) label: Option, + pub(crate) label_position: LabelPosition, + pub(crate) style: KnobStyle, + pub(crate) label_offset: f32, + pub(crate) label_format: Box String>, + pub(crate) step: Option, + pub(crate) drag_sensitivity: f32, + pub(crate) show_background_arc: bool, + pub(crate) show_filled_segments: bool, + pub(crate) min_angle: f32, + pub(crate) max_angle: f32, +} + +impl KnobConfig { + pub fn new(style: KnobStyle) -> Self { + Self { + size: 40.0, + font_size: 12.0, + stroke_width: 2.0, + colors: KnobColors::default(), + label: None, + label_position: LabelPosition::Bottom, + style, + label_offset: 1.0, + label_format: Box::new(|v| format!("{:.2}", v)), + step: None, + min_angle: -std::f32::consts::PI, + max_angle: std::f32::consts::PI * 0.5, + drag_sensitivity: 0.005, + show_background_arc: true, + show_filled_segments: true, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 002110a..eb4f18f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,412 +1,7 @@ -use core::f32; +mod config; +mod render; +mod style; +mod widget; -use egui::{Align2, Color32, Rect, Response, Sense, Stroke, Ui, Vec2, Widget}; - -/// Position of the label relative to the knob -pub enum LabelPosition { - Top, - Bottom, - Left, - Right, -} - -/// Visual style of the knob indicator -#[derive(Clone, Copy)] // <--- add this! -pub enum KnobStyle { - /// A line extending from the center to the edge - Wiper, - /// A dot on the edge of the knob - Dot, -} - -/// A circular knob widget for egui that can be dragged to change a value -/// -/// # Example -/// ``` -/// let mut value = 0.5; -/// Knob::new(&mut value, 0.0, 1.0, KnobStyle::Wiper) -/// .with_size(50.0) -/// .with_label("Volume", LabelPosition::Bottom) -/// .with_step(0.1); -/// ``` -pub struct Knob<'a> { - value: &'a mut f32, - min: f32, - max: f32, - size: f32, - font_size: f32, - stroke_width: f32, - knob_color: Color32, - line_color: Color32, - text_color: Color32, - label: Option, - label_position: LabelPosition, - style: KnobStyle, - label_offset: f32, - label_format: Box String>, - step: Option, - drag_sensitivity: f32, - show_background_arc: bool, - show_filled_segments: bool, - - /// Minimum angle in radians. - /// Specifies the lower bound of the knob's rotation. - /// Expected range: 0.0 to TAU. Values outside this range are allowed if your use case requires it. - min_angle: f32, - - /// Maximum angle in radians. - /// Specifies the upper bound of the knob's rotation. - /// Can be any value > `min_angle` - /// range `max_angle` - `min_angle` > TAU is allowed but will induce multi-turn - max_angle: f32, -} - -impl<'a> Knob<'a> { - /// Creates a new knob widget - /// - /// # Arguments - /// * `value` - Mutable reference to the value controlled by the knob - /// * `min` - Minimum value - /// * `max` - Maximum value - /// * `style` - Visual style of the knob indicator - pub fn new(value: &'a mut f32, min: f32, max: f32, style: KnobStyle) -> Self { - Self { - value, - min, - max, - size: 40.0, - font_size: 12.0, - stroke_width: 2.0, - knob_color: Color32::GRAY, - line_color: Color32::GRAY, - text_color: Color32::WHITE, - label: None, - label_position: LabelPosition::Bottom, - style, - label_offset: 1.0, - label_format: Box::new(|v| format!("{:.2}", v)), - step: None, - - // Hardcode those two angles to ENSURE backward compatibility - min_angle: -std::f32::consts::PI, - max_angle: std::f32::consts::PI * 0.5, - drag_sensitivity: 0.005, - show_background_arc: true, - show_filled_segments: true, - } - } - - /// Sets the angular sweep range of the knob - /// - /// This controls where the knob starts and how far it can rotate. By default, - /// knobs start at the left (180°) and sweep 270° clockwise to bottom. - /// - /// # Arguments - /// * `start_angle_normalized` - Starting position as fraction of full circle: - /// - `0.0` = bottom (6 o'clock) - /// - `0.25` = left (9 o'clock) - /// - `0.5` = top (12 o'clock) - /// - `0.75` = right (3 o'clock) - /// * `range` - How far the knob can sweep as fraction of full circle: - /// - `0.25` = quarter turn (90°) - /// - `0.5` = half turn (180°) - /// - `0.75` = three-quarter turn (270°) - /// - `1.0` = full turn (360°) - /// - Values > 1.0 create multi-turn knobs - /// - Negative values are clamped to 0.0 - /// - /// Note: the start angle is offset by PI/2 so that `0.0` is at the bottom (6 o'clock) - pub fn with_sweep_range(mut self, start_angle_normalized: f32, range: f32) -> Self { - if start_angle_normalized.is_nan() || range.is_nan() { - return self; - } - - self.min_angle = - start_angle_normalized.rem_euclid(1.) * f32::consts::TAU + f32::consts::PI / 2.; - - // A range of 1. represent a full turn - self.max_angle = self.min_angle + range.max(0.) * f32::consts::TAU; - self - } - - /// Sets the size of the knob - pub fn with_size(mut self, size: f32) -> Self { - self.size = size; - self - } - - /// Sets the font size for the label - pub fn with_font_size(mut self, size: f32) -> Self { - self.font_size = size; - self - } - - /// Sets the stroke width for the knob's outline and indicator - pub fn with_stroke_width(mut self, width: f32) -> Self { - self.stroke_width = width; - self - } - - /// Sets the colors for different parts of the knob - /// - /// # Arguments - /// * `knob_color` - Color of the knob's outline - /// * `line_color` - Color of the indicator - /// * `text_color` - Color of the label text - pub fn with_colors( - mut self, - knob_color: Color32, - line_color: Color32, - text_color: Color32, - ) -> Self { - self.knob_color = knob_color; - self.line_color = line_color; - self.text_color = text_color; - self - } - - /// Adds a label to the knob - /// - /// # Arguments - /// * `label` - Text to display - /// * `position` - Position of the label relative to the knob - pub fn with_label(mut self, label: impl Into, position: LabelPosition) -> Self { - self.label = Some(label.into()); - self.label_position = position; - self - } - - /// Sets the spacing between the knob and its label - pub fn with_label_offset(mut self, offset: f32) -> Self { - self.label_offset = offset; - self - } - - /// Sets a custom format function for displaying the value - /// - /// # Example - /// ``` - /// # let mut value = 0.5; - /// Knob::new(&mut value, 0.0, 1.0, KnobStyle::Wiper) - /// .with_label_format(|v| format!("{:.1}%", v * 100.0)); - /// ``` - pub fn with_label_format(mut self, format: impl Fn(f32) -> String + 'static) -> Self { - self.label_format = Box::new(format); - self - } - - /// Sets the step size for value changes - /// - /// When set, the value will snap to discrete steps as the knob is dragged. - pub fn with_step(mut self, step: Option) -> Self { - self.step = step; - self - } - /// Shows the background arc showing full range - pub fn with_background_arc(mut self, enabled: bool) -> Self { - self.show_background_arc = enabled; - self - } - /// Shows filled range on the background arc - pub fn with_show_filled_segments(mut self, enabled: bool) -> Self { - self.show_filled_segments = enabled; - self - } - // Private - fn compute_angle(&self) -> f32 { - if self.min == self.max || self.value.is_nan() { - self.min_angle - } else { - self.min_angle - + (*self.value - self.min) / (self.max - self.min) - * (self.max_angle - self.min_angle) - } - } -} - -impl Widget for Knob<'_> { - fn ui(self, ui: &mut Ui) -> Response { - if self.value.is_nan() { - *self.value = self.min; - } - - let knob_size = Vec2::splat(self.size); - - let label_size = if let Some(label) = &self.label { - let font_id = egui::FontId::proportional(self.font_size); - let max_text = format!("{}: {}", label, (self.label_format)(self.max)); - ui.painter() - .layout(max_text, font_id, Color32::WHITE, f32::INFINITY) - .size() - } else { - Vec2::ZERO - }; - - let label_padding = 2.0; - - let adjusted_size = match self.label_position { - LabelPosition::Top | LabelPosition::Bottom => Vec2::new( - knob_size.x.max(label_size.x + label_padding * 2.0), - knob_size.y + label_size.y + label_padding * 2.0 + self.label_offset, - ), - LabelPosition::Left | LabelPosition::Right => Vec2::new( - knob_size.x + label_size.x + label_padding * 2.0 + self.label_offset, - knob_size.y.max(label_size.y + label_padding * 2.0), - ), - }; - - let (rect, mut response) = ui.allocate_exact_size(adjusted_size, Sense::drag()); - - if response.dragged() { - let delta = response.drag_delta().y; - let range = self.max - self.min; - let step = self.step.unwrap_or(range * self.drag_sensitivity); - let new_value = (*self.value - delta * step).clamp(self.min, self.max); - - *self.value = if let Some(step) = self.step { - let steps = ((new_value - self.min) / step).round(); - (self.min + steps * step).clamp(self.min, self.max) - } else { - new_value - }; - - if self.value.is_nan() { - *self.value = self.min; - } - - response.mark_changed(); - } - - let painter = ui.painter(); - let knob_rect = match self.label_position { - LabelPosition::Left => { - Rect::from_min_size(rect.right_top() + Vec2::new(-knob_size.x, 0.0), knob_size) - } - LabelPosition::Right => Rect::from_min_size(rect.left_top(), knob_size), - LabelPosition::Top => Rect::from_min_size( - rect.left_bottom() + Vec2::new((rect.width() - knob_size.x) / 2.0, -knob_size.y), - knob_size, - ), - LabelPosition::Bottom => Rect::from_min_size( - rect.left_top() + Vec2::new((rect.width() - knob_size.x) / 2.0, 0.0), - knob_size, - ), - }; - - let center = knob_rect.center(); - let radius = knob_size.x / 2.0; - let angle = self.compute_angle(); - let knob_hovered = response.hovered(); - let knob_color = if knob_hovered { - self.knob_color.linear_multiply(1.2) - } else { - self.knob_color - }; - - painter.circle_stroke(center, radius, Stroke::new(self.stroke_width, knob_color)); - - // Background arc (indicating full range) - if self.show_background_arc { - let arc_start = self.min_angle; - let arc_end = self.max_angle; - let segments = 64; - let arc_color = self.knob_color.gamma_multiply(0.5); // dimmed background arc - let arc_radius = radius * 0.8; - let mut points = Vec::with_capacity(segments + 1); - - for i in 0..=segments { - let t = i as f32 / segments as f32; - let angle = arc_start + (arc_end - arc_start) * t; - let pos = center + Vec2::angled(angle) * arc_radius; - points.push(pos); - } - - painter.add(egui::Shape::line( - points, - Stroke::new(self.stroke_width, arc_color), - )); - - // Filled part when background arc is enabled - if self.show_filled_segments { - let filled_segments = (segments as f32 - * ((*self.value - self.min) / (self.max - self.min)).clamp(0.0, 1.0)) - as usize; - - let mut fill_points = Vec::with_capacity(filled_segments + 1); - for i in 0..=filled_segments { - let t = i as f32 / segments as f32; - let angle = arc_start + (arc_end - arc_start) * t; - let pos = center + Vec2::angled(angle) * arc_radius; - fill_points.push(pos); - } - - painter.add(egui::Shape::line( - fill_points, - Stroke::new(self.stroke_width, self.line_color), - )); - } - } - - match self.style { - KnobStyle::Wiper => { - let pointer = center + Vec2::angled(angle) * (radius * 0.7); - painter.line_segment( - [center, pointer], - Stroke::new(self.stroke_width * 1.5, self.line_color), - ); - } - KnobStyle::Dot => { - let dot_pos = center + Vec2::angled(angle) * (radius * 0.7); - painter.circle_filled(dot_pos, self.stroke_width * 1.5, self.line_color); - } - } - - if let Some(label) = self.label { - let label_text = format!("{}: {}", label, (self.label_format)(*self.value)); - let font_id = egui::FontId::proportional(self.font_size); - - let label_padding = 2.0; - - let (label_pos, alignment) = match self.label_position { - LabelPosition::Top => ( - Vec2::new( - rect.center().x, - rect.min.y - self.label_offset + label_padding, - ), - Align2::CENTER_TOP, - ), - LabelPosition::Bottom => ( - Vec2::new(rect.center().x, rect.max.y + self.label_offset), - Align2::CENTER_BOTTOM, - ), - LabelPosition::Left => ( - Vec2::new(rect.min.x - self.label_offset, rect.center().y), - Align2::LEFT_CENTER, - ), - LabelPosition::Right => ( - Vec2::new(rect.max.x + self.label_offset, rect.center().y), - Align2::RIGHT_CENTER, - ), - }; - - ui.painter().text( - label_pos.to_pos2(), - alignment, - label_text, - font_id, - self.text_color, - ); - - if response.hovered() { - response - .clone() - .on_hover_text((self.label_format)(*self.value)); - } - } - - // Draw the bounding rect - //painter.rect_stroke(rect, 0.0, Stroke::new(1.0, Color32::RED)); - - response - } -} +pub use style::{KnobStyle, LabelPosition}; +pub use widget::Knob; diff --git a/src/render.rs b/src/render.rs new file mode 100644 index 0000000..567e11f --- /dev/null +++ b/src/render.rs @@ -0,0 +1,196 @@ +use egui::{Align2, Color32, Painter, Pos2, Rect, Stroke, Ui, Vec2}; + +use crate::config::KnobConfig; +use crate::style::{KnobStyle, LabelPosition}; + +pub(crate) struct KnobRenderer<'a> { + config: &'a KnobConfig, + value: f32, + min: f32, + max: f32, +} + +impl<'a> KnobRenderer<'a> { + pub fn new(config: &'a KnobConfig, value: f32, min: f32, max: f32) -> Self { + Self { + config, + value, + min, + max, + } + } + + pub fn compute_angle(&self) -> f32 { + if self.min == self.max || self.value.is_nan() { + self.config.min_angle + } else { + self.config.min_angle + + (self.value - self.min) / (self.max - self.min) + * (self.config.max_angle - self.config.min_angle) + } + } + + pub fn render_knob(&self, painter: &Painter, center: Pos2, radius: f32, hovered: bool) { + let knob_color = if hovered { + self.config.colors.knob_color.linear_multiply(1.2) + } else { + self.config.colors.knob_color + }; + + painter.circle_stroke( + center, + radius, + Stroke::new(self.config.stroke_width, knob_color), + ); + + if self.config.show_background_arc { + self.render_background_arc(painter, center, radius); + } + + let angle = self.compute_angle(); + match self.config.style { + KnobStyle::Wiper => { + let pointer = center + Vec2::angled(angle) * (radius * 0.7); + painter.line_segment( + [center, pointer], + Stroke::new( + self.config.stroke_width * 1.5, + self.config.colors.line_color, + ), + ); + } + KnobStyle::Dot => { + let dot_pos = center + Vec2::angled(angle) * (radius * 0.7); + painter.circle_filled( + dot_pos, + self.config.stroke_width * 1.5, + self.config.colors.line_color, + ); + } + } + } + + fn render_background_arc(&self, painter: &Painter, center: Pos2, radius: f32) { + let arc_start = self.config.min_angle; + let arc_end = self.config.max_angle; + let segments = 64; + let arc_color = self.config.colors.knob_color.gamma_multiply(0.5); + let arc_radius = radius * 0.8; + + let mut points = Vec::with_capacity(segments + 1); + for i in 0..=segments { + let t = i as f32 / segments as f32; + let angle = arc_start + (arc_end - arc_start) * t; + let pos = center + Vec2::angled(angle) * arc_radius; + points.push(pos); + } + + painter.add(egui::Shape::line( + points, + Stroke::new(self.config.stroke_width, arc_color), + )); + + if self.config.show_filled_segments { + let filled_segments = (segments as f32 + * ((self.value - self.min) / (self.max - self.min)).clamp(0.0, 1.0)) + as usize; + + let mut fill_points = Vec::with_capacity(filled_segments + 1); + for i in 0..=filled_segments { + let t = i as f32 / segments as f32; + let angle = arc_start + (arc_end - arc_start) * t; + let pos = center + Vec2::angled(angle) * arc_radius; + fill_points.push(pos); + } + + painter.add(egui::Shape::line( + fill_points, + Stroke::new(self.config.stroke_width, self.config.colors.line_color), + )); + } + } + + pub fn render_label(&self, ui: &Ui, rect: Rect) { + if let Some(label) = &self.config.label { + let label_text = format!("{}: {}", label, (self.config.label_format)(self.value)); + let font_id = egui::FontId::proportional(self.config.font_size); + let label_padding = 2.0; + + let (label_pos, alignment) = match self.config.label_position { + LabelPosition::Top => ( + Vec2::new( + rect.center().x, + rect.min.y - self.config.label_offset + label_padding, + ), + Align2::CENTER_TOP, + ), + LabelPosition::Bottom => ( + Vec2::new(rect.center().x, rect.max.y + self.config.label_offset), + Align2::CENTER_BOTTOM, + ), + LabelPosition::Left => ( + Vec2::new(rect.min.x - self.config.label_offset, rect.center().y), + Align2::LEFT_CENTER, + ), + LabelPosition::Right => ( + Vec2::new(rect.max.x + self.config.label_offset, rect.center().y), + Align2::RIGHT_CENTER, + ), + }; + + ui.painter().text( + label_pos.to_pos2(), + alignment, + label_text, + font_id, + self.config.colors.text_color, + ); + } + } + + pub fn calculate_size(&self, ui: &Ui) -> Vec2 { + let knob_size = Vec2::splat(self.config.size); + + let label_size = if let Some(label) = &self.config.label { + let font_id = egui::FontId::proportional(self.config.font_size); + let max_text = format!("{}: {}", label, (self.config.label_format)(self.max)); + ui.painter() + .layout(max_text, font_id, Color32::WHITE, f32::INFINITY) + .size() + } else { + Vec2::ZERO + }; + + let label_padding = 2.0; + + match self.config.label_position { + LabelPosition::Top | LabelPosition::Bottom => Vec2::new( + knob_size.x.max(label_size.x + label_padding * 2.0), + knob_size.y + label_size.y + label_padding * 2.0 + self.config.label_offset, + ), + LabelPosition::Left | LabelPosition::Right => Vec2::new( + knob_size.x + label_size.x + label_padding * 2.0 + self.config.label_offset, + knob_size.y.max(label_size.y + label_padding * 2.0), + ), + } + } + + pub fn calculate_knob_rect(&self, rect: Rect) -> Rect { + let knob_size = Vec2::splat(self.config.size); + + match self.config.label_position { + LabelPosition::Left => { + Rect::from_min_size(rect.right_top() + Vec2::new(-knob_size.x, 0.0), knob_size) + } + LabelPosition::Right => Rect::from_min_size(rect.left_top(), knob_size), + LabelPosition::Top => Rect::from_min_size( + rect.left_bottom() + Vec2::new((rect.width() - knob_size.x) / 2.0, -knob_size.y), + knob_size, + ), + LabelPosition::Bottom => Rect::from_min_size( + rect.left_top() + Vec2::new((rect.width() - knob_size.x) / 2.0, 0.0), + knob_size, + ), + } + } +} diff --git a/src/style.rs b/src/style.rs new file mode 100644 index 0000000..e465e9c --- /dev/null +++ b/src/style.rs @@ -0,0 +1,44 @@ +use egui::Color32; + +/// Visual style of the knob indicator +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KnobStyle { + /// A line extending from the center to the edge + Wiper, + /// A dot on the edge of the knob + Dot, +} + +/// Position of the label relative to the knob +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LabelPosition { + /// Label appears above the knob + Top, + /// Label appears below the knob + Bottom, + /// Label appears to the left of the knob + Left, + /// Label appears to the right of the knob + Right, +} + +/// Color configuration for the knob widget +#[derive(Debug, Clone, Copy)] +pub struct KnobColors { + /// Color of the knob's outline + pub knob_color: Color32, + /// Color of the indicator (wiper or dot) + pub line_color: Color32, + /// Color of the label text + pub text_color: Color32, +} + +impl Default for KnobColors { + fn default() -> Self { + Self { + knob_color: Color32::GRAY, + line_color: Color32::GRAY, + text_color: Color32::WHITE, + } + } +} diff --git a/src/widget.rs b/src/widget.rs new file mode 100644 index 0000000..370cd67 --- /dev/null +++ b/src/widget.rs @@ -0,0 +1,211 @@ +use egui::{Color32, Response, Sense, Ui, Widget}; + +use crate::config::KnobConfig; +use crate::render::KnobRenderer; +use crate::style::{KnobStyle, LabelPosition}; + +pub struct Knob<'a> { + pub(crate) value: &'a mut f32, + pub(crate) min: f32, + pub(crate) max: f32, + pub(crate) config: KnobConfig, +} + +impl<'a> Knob<'a> { + /// Creates a new knob widget + /// + /// # Arguments + /// * `value` - Mutable reference to the value controlled by the knob + /// * `min` - Minimum value + /// * `max` - Maximum value + /// * `style` - Visual style of the knob indicator + pub fn new(value: &'a mut f32, min: f32, max: f32, style: KnobStyle) -> Self { + Self { + value, + min, + max, + config: KnobConfig::new(style), + } + } + + /// Sets the angular sweep range of the knob + /// + /// This controls where the knob starts and how far it can rotate. By default, + /// knobs start at the left (180°) and sweep 270° clockwise to bottom. + /// + /// # Arguments + /// * `start_angle_normalized` - Starting position as fraction of full circle: + /// - `0.0` = bottom (6 o'clock) + /// - `0.25` = left (9 o'clock) + /// - `0.5` = top (12 o'clock) + /// - `0.75` = right (3 o'clock) + /// * `range` - How far the knob can sweep as fraction of full circle: + /// - `0.25` = quarter turn (90°) + /// - `0.5` = half turn (180°) + /// - `0.75` = three-quarter turn (270°) + /// - `1.0` = full turn (360°) + /// - Values > 1.0 create multi-turn knobs + /// - Negative values are clamped to 0.0 + /// + /// Note: the start angle is offset by PI/2 so that `0.0` is at the bottom (6 o'clock) + pub fn with_sweep_range(mut self, start_angle_normalized: f32, range: f32) -> Self { + if start_angle_normalized.is_nan() || range.is_nan() { + return self; + } + + self.config.min_angle = + start_angle_normalized.rem_euclid(1.0) * std::f32::consts::TAU + std::f32::consts::PI / 2.0; + self.config.max_angle = self.config.min_angle + range.max(0.0) * std::f32::consts::TAU; + self + } + + /// Sets the size of the knob + pub fn with_size(mut self, size: f32) -> Self { + self.config.size = size; + self + } + + /// Sets the font size for the label + pub fn with_font_size(mut self, size: f32) -> Self { + self.config.font_size = size; + self + } + + /// Sets the stroke width for the knob's outline and indicator + pub fn with_stroke_width(mut self, width: f32) -> Self { + self.config.stroke_width = width; + self + } + + /// Sets the colors for different parts of the knob + /// + /// # Arguments + /// * `knob_color` - Color of the knob's outline + /// * `line_color` - Color of the indicator + /// * `text_color` - Color of the label text + pub fn with_colors( + mut self, + knob_color: Color32, + line_color: Color32, + text_color: Color32, + ) -> Self { + self.config.colors.knob_color = knob_color; + self.config.colors.line_color = line_color; + self.config.colors.text_color = text_color; + self + } + + /// Adds a label to the knob + /// + /// # Arguments + /// * `label` - Text to display + /// * `position` - Position of the label relative to the knob + pub fn with_label(mut self, label: impl Into, position: LabelPosition) -> Self { + self.config.label = Some(label.into()); + self.config.label_position = position; + self + } + + /// Sets the spacing between the knob and its label + pub fn with_label_offset(mut self, offset: f32) -> Self { + self.config.label_offset = offset; + self + } + + /// Sets a custom format function for displaying the value + /// + /// # Example + /// ```no_run + /// use egui_knob::{Knob, KnobStyle}; + /// ui.add( + /// Knob::new(&mut value, 0.0, 1.0, KnobStyle::Wiper) + /// .with_label_format(|v| format!("{:.1}%", v * 100.0)) + /// ); + /// ``` + pub fn with_label_format(mut self, format: impl Fn(f32) -> String + 'static) -> Self { + self.config.label_format = Box::new(format); + self + } + + /// Sets the step size for value changes + pub fn with_step(mut self, step: Option) -> Self { + self.config.step = step; + self + } + + /// Controls whether to show the background arc indicating the full range + pub fn with_background_arc(mut self, enabled: bool) -> Self { + self.config.show_background_arc = enabled; + self + } + + /// Controls whether to show the filled segment on the background arc + /// + /// When enabled (and background arc is visible), displays a colored segment + /// from the minimum position to the current value position. + pub fn with_show_filled_segments(mut self, enabled: bool) -> Self { + self.config.show_filled_segments = enabled; + self + } + + /// Sets the drag sensitivity for mouse interactions + /// + /// Default is 0.005. + pub fn with_drag_sensitivity(mut self, sensitivity: f32) -> Self { + self.config.drag_sensitivity = sensitivity; + self + } + +} + +impl Widget for Knob<'_> { + fn ui(self, ui: &mut Ui) -> Response { + if self.value.is_nan() { + *self.value = self.min; + } + + let current_value = *self.value; + let renderer = KnobRenderer::new(&self.config, current_value, self.min, self.max); + let adjusted_size = renderer.calculate_size(ui); + + let (rect, response) = ui.allocate_exact_size(adjusted_size, Sense::drag()); + + let mut response = response; + if response.dragged() { + let delta = response.drag_delta().y; + let range = self.max - self.min; + let step = self.config.step.unwrap_or(range * self.config.drag_sensitivity); + let new_value = (*self.value - delta * step).clamp(self.min, self.max); + + *self.value = if let Some(step) = self.config.step { + let steps = ((new_value - self.min) / step).round(); + (self.min + steps * step).clamp(self.min, self.max) + } else { + new_value + }; + + if self.value.is_nan() { + *self.value = self.min; + } + + response.mark_changed(); + } + + let knob_rect = renderer.calculate_knob_rect(rect); + let center = knob_rect.center(); + let radius = self.config.size / 2.0; + + let updated_value = *self.value; + let updated_renderer = KnobRenderer::new(&self.config, updated_value, self.min, self.max); + updated_renderer.render_knob(ui.painter(), center, radius, response.hovered()); + updated_renderer.render_label(ui, rect); + + if self.config.label.is_some() && response.hovered() { + response + .clone() + .on_hover_text((self.config.label_format)(*self.value)); + } + + response + } +}