added public properties

This commit is contained in:
2025-02-03 12:15:36 +03:00
parent beb338d44d
commit a484653f70
3 changed files with 160 additions and 9 deletions

26
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'demo'",
"cargo": {
"args": [
"build",
"--bin=demo",
"--package=egui_knob"
],
"filter": {
"name": "demo",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
]
}

View File

@@ -15,15 +15,39 @@ struct KnobExample {
impl Default for KnobExample {
fn default() -> Self {
Self { value: 0.5 }
Self { value: 0.0 }
}
}
impl eframe::App for KnobExample {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.add(Knob::new(&mut self.value, 0.0, 1.0));
ui.label(format!("Value: {:.2}", self.value));
ui.horizontal(|ui| {
ui.add_space(15.0);
ui.add(
Knob::new(&mut self.value, 0.0, 100.0)
.with_label("Gain", egui_knob::LabelPosition::Bottom)
.with_size(50.0),
);
ui.add_space(15.0);
ui.add(
Knob::new(&mut self.value, 0.0, 100.0)
.with_label("Gain", egui_knob::LabelPosition::Bottom)
.with_size(50.0),
);
ui.add_space(15.0);
ui.add(
Knob::new(&mut self.value, 0.0, 100.0)
.with_label("Gain", egui_knob::LabelPosition::Bottom)
.with_size(50.0),
);
ui.add_space(15.0);
ui.add(
Knob::new(&mut self.value, 0.0, 100.0)
.with_label("Gain", egui_knob::LabelPosition::Bottom)
.with_size(50.0),
);
});
});
}
}

View File

@@ -1,20 +1,72 @@
use egui::{Response, Sense, Ui, Vec2, Widget};
use egui::{Align2, Color32, Response, Sense, Stroke, Ui, Vec2, Widget};
pub enum LabelPosition {
Top,
Bottom,
Left,
Right,
}
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,
label: Option<String>,
label_position: LabelPosition,
}
impl<'a> Knob<'a> {
pub fn new(value: &'a mut f32, min: f32, max: f32) -> Self {
Self { value, min, max }
Self {
value,
min,
max,
size: 40.0,
font_size: 12.0,
stroke_width: 2.0,
knob_color: Color32::GRAY,
line_color: Color32::GRAY,
label: None,
label_position: LabelPosition::Bottom,
}
}
pub fn with_size(mut self, size: f32) -> Self {
self.size = size;
self
}
pub fn with_font_size(mut self, size: f32) -> Self {
self.font_size = size;
self
}
pub fn with_stroke_width(mut self, width: f32) -> Self {
self.stroke_width = width;
self
}
pub fn with_colors(mut self, knob_color: Color32, line_color: Color32) -> Self {
self.knob_color = knob_color;
self.line_color = line_color;
self
}
pub fn with_label(mut self, label: impl Into<String>, position: LabelPosition) -> Self {
self.label = Some(label.into());
self.label_position = position;
self
}
}
impl Widget for Knob<'_> {
fn ui(self, ui: &mut Ui) -> Response {
let desired_size = Vec2::splat(40.0);
let desired_size = Vec2::splat(self.size);
let (rect, response) = ui.allocate_exact_size(desired_size, Sense::drag());
if response.dragged() {
@@ -28,11 +80,60 @@ impl Widget for Knob<'_> {
let center = rect.center();
let radius = rect.width() / 2.0;
let angle = (*self.value - self.min) / (self.max - self.min) * std::f32::consts::PI * 1.5
- std::f32::consts::PI * 0.75;
- std::f32::consts::PI;
painter.circle_stroke(center, radius, egui::Stroke::new(2.0, ui.visuals().text_color()));
// Draw knob circle
painter.circle_stroke(
center,
radius,
Stroke::new(self.stroke_width, self.knob_color),
);
// Draw pointer line
let pointer = center + Vec2::angled(angle) * (radius * 0.7);
painter.line_segment([center, pointer], egui::Stroke::new(3.0, ui.visuals().text_color()));
painter.line_segment(
[center, pointer],
Stroke::new(self.stroke_width * 1.5, self.line_color),
);
if let Some(label) = self.label {
let label_text = format!("{label}: {:.2}", self.value);
let font_id = egui::FontId::proportional(self.font_size);
let text_size = ui
.painter()
.layout(
label_text.clone(),
font_id.clone(),
Color32::WHITE,
f32::INFINITY,
)
.size();
let label_offset = 12.0;
let label_pos = match self.label_position {
LabelPosition::Top => {
center + Vec2::new(-text_size.x / 2.0, -radius - label_offset - text_size.y)
}
LabelPosition::Bottom => {
center + Vec2::new(-text_size.x / 2.0, radius + label_offset)
}
LabelPosition::Left => {
center + Vec2::new(-radius - label_offset - text_size.x, -text_size.y / 2.0)
}
LabelPosition::Right => {
center + Vec2::new(radius + label_offset, -text_size.y / 2.0)
}
};
ui.painter().text(
label_pos,
Align2::LEFT_TOP,
label_text,
font_id,
Color32::WHITE,
);
}
response
}