Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vista #1562

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ members = [
"tools/parameter_tester",
"tools/pepsi",
"tools/twix",
"tools/vista",
"tools/widget_gallery",
]
resolver = "2"
Expand Down
2 changes: 1 addition & 1 deletion crates/hulk/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use hulk_manifest::collect_hulk_cyclers;
use source_analyzer::{pretty::to_string_pretty, structs::Structs};

fn main() -> Result<()> {
let cyclers = collect_hulk_cyclers()?;
let cyclers = collect_hulk_cyclers("..")?;
for path in cyclers.watch_paths() {
println!("cargo:rerun-if-changed={}", path.display());
}
Expand Down
2 changes: 1 addition & 1 deletion crates/hulk_imagine/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use hulk_manifest::collect_hulk_cyclers;
use source_analyzer::{pretty::to_string_pretty, structs::Structs};

fn main() -> Result<()> {
let mut cyclers = collect_hulk_cyclers()?;
let mut cyclers = collect_hulk_cyclers("..")?;
cyclers
.cyclers
.retain(|cycler| cycler.name != "ObjectDetection");
Expand Down
5 changes: 3 additions & 2 deletions crates/hulk_manifest/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::path::Path;

use source_analyzer::{
cyclers::{CyclerKind, Cyclers},
error::Error,
manifest::{CyclerManifest, FrameworkManifest},
};

pub fn collect_hulk_cyclers() -> Result<Cyclers, Error> {
pub fn collect_hulk_cyclers(root: impl AsRef<Path>) -> Result<Cyclers, Error> {
let manifest = FrameworkManifest {
cyclers: vec![
CyclerManifest {
Expand Down Expand Up @@ -123,6 +125,5 @@ pub fn collect_hulk_cyclers() -> Result<Cyclers, Error> {
],
};

let root = "..";
Cyclers::try_from_manifest(manifest, root)
}
2 changes: 1 addition & 1 deletion crates/hulk_replayer/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use source_analyzer::{pretty::to_string_pretty, structs::Structs};

fn main() -> Result<()> {
#[allow(unused_mut)] // must not be mut if "with_detection" feature is disabled
let mut cyclers = collect_hulk_cyclers()?;
let mut cyclers = collect_hulk_cyclers("..")?;
#[cfg(not(feature = "with_object_detection"))]
cyclers
.cyclers
Expand Down
73 changes: 22 additions & 51 deletions crates/hulk_widgets/src/segmented_control.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
use egui::{
vec2, Align2, Context, Id, InnerResponse, Key, Rect, Response, Rounding, Sense, TextStyle, Ui,
Widget,
};
use egui::{vec2, Align2, Id, Key, Rect, Response, Rounding, Sense, TextStyle, Ui, Widget};

const ANIMATION_TIME_SECONDS: f32 = 0.1;

pub struct SegmentedControl<'ui, T> {
selectables: &'ui [T],
id: Id,
selected: &'ui mut usize,
selectables: &'ui [T],
rounding: Option<Rounding>,
text_style: TextStyle,
}

#[derive(Debug, Default, Clone)]
struct SegmentedControlState {
selected: usize,
}

impl<'ui, T: ToString> SegmentedControl<'ui, T> {
pub fn new(id: impl Into<Id>, selectables: &'ui [T]) -> Self {
pub fn new(id: impl Into<Id>, selected: &'ui mut usize, selectables: &'ui [T]) -> Self {
SegmentedControl {
id: id.into(),
selected,
selectables,
rounding: None,
text_style: TextStyle::Body,
Expand All @@ -31,25 +25,20 @@ impl<'ui, T: ToString> SegmentedControl<'ui, T> {
self.rounding = Some(rounding.into());
self
}
}

pub fn ui(self, ui: &mut Ui) -> InnerResponse<&'ui T> {
let mut state = load_state(ui.ctx(), self.id);
let response = self.show(ui, &mut state);
let selected = &self.selectables[state.selected];
save_state(ui.ctx(), self.id, state);
InnerResponse::new(selected, response)
}

fn show(&self, ui: &mut Ui, state: &mut SegmentedControlState) -> Response {
impl<T: ToString> Widget for SegmentedControl<'_, T> {
fn ui(mut self, ui: &mut Ui) -> Response {
let this = &mut self;
let width = ui.available_width();
let text_style = ui
.style()
.text_styles
.get(&self.text_style)
.get(&this.text_style)
.expect("failed to get text style")
.clone();
let text_size = text_style.size * ui.ctx().pixels_per_point();
let rounding = self
let rounding = this
.rounding
.unwrap_or(ui.style().noninteractive().rounding);

Expand All @@ -58,41 +47,41 @@ impl<'ui, T: ToString> SegmentedControl<'ui, T> {
if response.contains_pointer() {
ui.input(|reader| {
if reader.key_pressed(Key::ArrowLeft) || reader.key_pressed(Key::ArrowDown) {
state.selected = state.selected.saturating_sub(1);
*this.selected = this.selected.saturating_sub(1);
response.mark_changed();
} else if reader.key_pressed(Key::ArrowRight) || reader.key_pressed(Key::ArrowUp) {
state.selected = (state.selected + 1).min(self.selectables.len() - 1);
*this.selected = (*this.selected + 1).min(this.selectables.len() - 1);
response.mark_changed();
}
})
}
painter.rect_filled(response.rect, rounding, ui.style().visuals.extreme_bg_color);

let text_rects = text_rects(response.rect, self.selectables.len());
let text_rects = text_rects(response.rect, this.selectables.len());
let offset = text_rects[0].width();

let translation = ui.ctx().animate_value_with_time(
self.id,
offset * state.selected as f32,
this.id,
offset * *this.selected as f32,
ANIMATION_TIME_SECONDS,
);
let selector_rect = text_rects[0].translate(vec2(translation, 0.0)).shrink(2.0);
let selector_response =
ui.interact(selector_rect, self.id.with("selector"), Sense::click());
ui.interact(selector_rect, this.id.with("selector"), Sense::click());
let selector_style = ui.style().interact(&selector_response);
painter.rect_filled(selector_rect, rounding, selector_style.bg_fill);

let noninteractive_style = ui.style().noninteractive();

for (idx, (&rect, text)) in text_rects.iter().zip(self.selectables.iter()).enumerate() {
let label_response = ui.interact(rect, self.id.with(idx), Sense::click());
for (idx, (&rect, text)) in text_rects.iter().zip(this.selectables.iter()).enumerate() {
let label_response = ui.interact(rect, this.id.with(idx), Sense::click());
let style = ui.style().interact(&response);

let show_line = idx > 0 && state.selected != idx && state.selected + 1 != idx;
let show_line = idx > 0 && *this.selected != idx && *this.selected + 1 != idx;
{
let animated_height = ui
.ctx()
.animate_bool(self.id.with("vline").with(idx), show_line);
.animate_bool(this.id.with("vline").with(idx), show_line);

let height = vec2(0.0, rect.height() - 4.0);
let center = rect.left_center();
Expand All @@ -107,7 +96,7 @@ impl<'ui, T: ToString> SegmentedControl<'ui, T> {
}

if label_response.clicked() {
state.selected = idx;
*this.selected = idx;
response.mark_changed();
}
painter.text(
Expand All @@ -122,24 +111,6 @@ impl<'ui, T: ToString> SegmentedControl<'ui, T> {
}
}

impl<T: ToString> Widget for SegmentedControl<'_, T> {
fn ui(self, ui: &mut Ui) -> Response {
let mut state = load_state(ui.ctx(), self.id);
let response = self.show(ui, &mut state);
save_state(ui.ctx(), self.id, state);
response
}
}

fn load_state(ctx: &Context, id: Id) -> SegmentedControlState {
let persisted = ctx.data_mut(|reader| reader.get_temp(id));
persisted.unwrap_or_default()
}

fn save_state(ctx: &Context, id: Id, state: SegmentedControlState) {
ctx.data_mut(|writer| writer.insert_temp(id, state));
}

fn text_rects(mut rect: Rect, number_of_texts: usize) -> Vec<Rect> {
let base_width = rect.width() / number_of_texts as f32;
let base_rect = {
Expand Down
1 change: 1 addition & 0 deletions tools/pepsi/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ async fn resolve_manifest_path(
Some("parameter_tester") => repository.root.join("tools/parameter_tester/Cargo.toml"),
Some("pepsi") => repository.root.join("tools/pepsi/Cargo.toml"),
Some("twix") => repository.root.join("tools/twix/Cargo.toml"),
Some("vista") => repository.root.join("tools/vista/Cargo.toml"),
Some("widget_gallery") => repository.root.join("tools/widget_gallery/Cargo.toml"),

_ => compose_manifest_path(manifest).await.wrap_err_with(|| {
Expand Down
11 changes: 7 additions & 4 deletions tools/twix/src/panels/behavior_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,13 @@ impl Widget for &mut BehaviorSimulatorPanel {
ui.add_space(50.0);

let robots = (1..=7).collect::<Vec<_>>();
let robot_selection =
SegmentedControl::new("robot-selector", &robots).ui(ui);
self.selected_robot = *robot_selection.inner;
if robot_selection.response.changed() {
let response = SegmentedControl::new(
"robot-selector",
&mut self.selected_robot,
&robots,
)
.ui(ui);
if response.changed() {
self.nao.write(
"parameters.selected_robot",
TextOrBinary::Text(self.selected_robot.into()),
Expand Down
14 changes: 14 additions & 0 deletions tools/vista/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "vista"
version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true

[dependencies]
eframe.workspace = true
hulk_manifest.workspace = true
hulk_widgets.workspace = true
repository.workspace = true
source_analyzer.workspace = true
tokio.workspace = true
Loading
Loading