From 6b74ba6590df97b4d06502d6d89f8c27846d72af Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Tue, 10 Feb 2026 12:00:12 +0300 Subject: [PATCH] [lab5] Settings UI --- lab5/Cargo.toml | 1 + lab5/src/main.rs | 175 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 175 insertions(+), 1 deletion(-) diff --git a/lab5/Cargo.toml b/lab5/Cargo.toml index 86dbc78..58775de 100644 --- a/lab5/Cargo.toml +++ b/lab5/Cargo.toml @@ -9,6 +9,7 @@ workspace = true rand = "0.9.2" eframe = { version = "0.33.3", default-features = false, features = ["default_fonts", "glow"] } egui_extras = { version = "0.33.3" } +tsp-utility = { path = "../tsp-utility" } [profile.dev.package.eframe] opt-level = 2 diff --git a/lab5/src/main.rs b/lab5/src/main.rs index 552b8c2..48ca370 100644 --- a/lab5/src/main.rs +++ b/lab5/src/main.rs @@ -1,3 +1,176 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + mod algo; -fn main() {} \ No newline at end of file +use eframe::egui; +use eframe::egui::{Frame, Ui}; +use eframe::emath::Numeric; +use std::collections::HashSet; +use std::ops::RangeInclusive; +use tsp_utility::graph::{EdgesVec, VerticesVec}; +use tsp_utility::gui::lengths_table::{UpdatePending, draw_lengths_table}; + +fn main() -> eframe::Result { + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default().with_inner_size([640.0, 400.0]), + ..Default::default() + }; + eframe::run_native( + "Ants simulation", + options, + Box::new(|_cc| Ok(Box::::default())), + ) +} + +enum ViewState { + Stop, + Running { lastUpdateTimestamp: u64 }, + VertexMove { vertexId: usize }, +} + +enum GlobalState { + Edit {}, + Running { view_state: ViewState }, +} + +struct MyApp { + edges: EdgesVec<()>, + vertices: VerticesVec, + vertex_update: UpdatePending, + population_size: usize, + rounds: usize, + mutation_chance: f64, + state: GlobalState, +} + +impl Default for MyApp { + fn default() -> Self { + return Self { + edges: EdgesVec::new(), + vertices: VerticesVec::new(), + vertex_update: UpdatePending::NoChange, + population_size: 2, + rounds: 1, + mutation_chance: 0.1, + state: GlobalState::Edit {}, + }; + } +} + +fn _slider( + ui: &mut Ui, + name: &str, + storage: &mut T, + range: RangeInclusive, + step: f64, +) { + let label = ui.label(name); + + ui.scope(|ui| { + ui.spacing_mut().slider_width = ui.available_width() + - ui.spacing().interact_size.x + - ui.spacing().button_padding.x * 2.0; + ui.add(egui::Slider::new(storage, range).step_by(step)) + .labelled_by(label.id); + }); +} + +impl eframe::App for MyApp { + fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) { + egui::CentralPanel::default().show(ui, |ui| match self.state { + GlobalState::Edit {} => { + match self.vertex_update { + UpdatePending::NoChange => {} + UpdatePending::Add => { + let new_vi = self.vertices.add(HashSet::new()); + let mut newEdgesSet = HashSet::new(); + for (vi, v) in self.vertices.iter_indexed_mut() { + if (vi == new_vi) { + continue; + } + let ei = self.edges.add(new_vi, vi, 1.0, ()); + newEdgesSet.insert(ei); + v.insert(ei); + } + self.vertices[new_vi] = newEdgesSet; + self.vertex_update = UpdatePending::NoChange; + } + UpdatePending::Remove(vi) => { + let mut eis = Vec::with_capacity(self.vertices[vi].len()); + for ei in self.vertices[vi].iter() { + eis.push(*ei) + } + for ei in eis { + self.vertices[self.edges[ei].another(vi)].remove(&ei); + self.edges.remove(ei); + } + self.vertices.remove(vi); + self.vertex_update = UpdatePending::NoChange; + } + } + edit_panel(self, ui) + } + GlobalState::Running { .. } => { + ui.add_enabled_ui(false, |ui| edit_panel(self, ui)); + ui.ctx().show_viewport_immediate( + egui::ViewportId::from_hash_of("Visualisation"), + egui::ViewportBuilder::default() + .with_title("Visualisation") + .with_inner_size([640.0, 480.0]) + .with_resizable(false), + |ui, _| { + egui::CentralPanel::default() + .frame(Frame::default().inner_margin(0.0)) + .show(ui, |ui| visualization_panel(self, ui)); + }, + ); + } + }); + } +} + +fn edit_panel(data: &mut MyApp, ui: &mut Ui) { + let run: bool; + + _slider( + ui, + "Population size", + &mut data.population_size, + 2..=1000, + 1.0, + ); + ui.label(""); + _slider(ui, "Rounds", &mut data.rounds, 1..=100, 1.0); + ui.label(""); + _slider( + ui, + "Mutation chance", + &mut data.mutation_chance, + 0.0..=1.0, + 0.001, + ); + + ui.horizontal(|ui| { + if ui.button("Add vertex").clicked() { + data.vertex_update = UpdatePending::Add; + } + ui.separator(); + let run = ui.button("Run").clicked(); + }); + + draw_lengths_table( + ui, + &mut data.vertices, + &mut data.edges, + &mut data.vertex_update, + ) +} + +fn visualization_panel(data: &mut MyApp, ui: &mut Ui) { + ui.horizontal(|ui| { + if ui.button("Exit").clicked() {} + + if ui.button("Step").clicked() {} + ui.label(""); + }); +}