setting up data, wrangling ui

main
aprzn 2 years ago
parent d3b17e38f5
commit 45e741359f

@ -6,11 +6,13 @@ use eframe::egui;
use std::boxed::Box;
use std::collections::VecDeque;
use std::marker::PhantomData;
use symphonia::core::io::{MediaSource, MediaSourceStream};
struct PipeDash {
msg_queue: VecDeque<Message>,
selected_level: Option<usize>,
level_list: Vec<gd::OuterLevel>,
loaded_song: Option<Song>,
editor: Editor,
}
@ -29,13 +31,22 @@ enum Message {
struct Editor {
scroll_pos: f32,
pts_per_second: f32,
beats_per_bar: f32,
subdivisions: f32,
beat_rate: music::BeatRate,
time_signatures: music::TimeSignature,
data: GdlData,
}
struct GdlData {
green_lines: music::Lines,
orange_lines: music::Lines,
yellow_lines: music::Lines,
beat_rate: music::BeatRate,
time_signatures: music::TimeSignature,
}
struct Song {
name: String,
id: u32,
stream: MediaSourceStream,
}
struct Orange;
@ -45,12 +56,31 @@ struct Green;
struct BeatRateWidget<'a>(&'a mut Editor);
struct TimeSignatureWidget<'a>(&'a mut Editor);
struct LinesWidget<'a, C: WithColor>(&'a mut Editor, PhantomData<C>);
struct WaveformWidget<'a>(&'a mut Editor);
trait WithColor {}
trait WithColor {
const COLOR: Color;
}
impl WithColor for Orange {}
impl WithColor for Yellow {}
impl WithColor for Green {}
impl From<Color> for eframe::epaint::Color32 {
fn from(rhs: Color) -> Self {
match rhs {
Color::Green => Self::from_rgb(0, 255, 0),
Color::Orange => Self::from_rgb(255, 127, 0),
Color::Yellow => Self::from_rgb(255, 255, 0),
}
}
}
impl WithColor for Orange {
const COLOR: Color = Color::Orange;
}
impl WithColor for Yellow {
const COLOR: Color = Color::Yellow;
}
impl WithColor for Green {
const COLOR: Color = Color::Green;
}
impl Editor {
pub fn beat_rate_widget(&mut self) -> BeatRateWidget {
@ -64,6 +94,10 @@ impl Editor {
pub fn lines_widget<C: WithColor>(&mut self) -> LinesWidget<C> {
LinesWidget(self, Default::default())
}
pub fn waveform_widget(&mut self) -> WaveformWidget {
WaveformWidget(self)
}
}
impl<'a> egui::Widget for BeatRateWidget<'a> {
@ -100,22 +134,58 @@ impl<'a> egui::Widget for TimeSignatureWidget<'a> {
}
}
impl<'a, C: WithColor> egui::Widget for LinesWidget<'a, C> {
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
// 1. choose size
let max_rect = ui.max_rect();
let preferred_size = egui::Vec2::new(max_rect.size().x, 60.0);
// 2. allocate space
let (rect, res) = ui.allocate_exact_size(preferred_size, egui::Sense::click_and_drag());
// 3. handle interactions
// 4. draw widget
if ui.is_rect_visible(rect) {
ui.painter()
.rect_filled(rect, 0f32, eframe::epaint::Color32::from_gray(0));
}
res
}
}
impl<'a> egui::Widget for WaveformWidget<'a> {
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
// 1. choose size
let max_rect = ui.max_rect();
let preferred_size = egui::Vec2::new(max_rect.size().x, 60.0);
// 2. allocate space
let (rect, res) = ui.allocate_exact_size(preferred_size, egui::Sense::click_and_drag());
// 3. handle interactions
// 4. draw widget
if ui.is_rect_visible(rect) {
ui.painter()
.rect_filled(rect, 0f32, eframe::epaint::Color32::from_gray(0));
}
res
}
}
impl PipeDash {
fn new(_cc: &eframe::CreationContext) -> Self {
Self {
selected_level: None,
msg_queue: VecDeque::new(),
level_list: gd::OuterLevel::load_all(),
loaded_song: None,
editor: Editor {
scroll_pos: 0f32,
pts_per_second: 5f32,
beats_per_bar: 4.0,
subdivisions: 4.0,
beat_rate: music::StaticBeatRate::from_bpm(120f32).into(),
time_signatures: music::StaticTimeSignature::new(4, 4).into(),
green_lines: music::Lines::new(),
orange_lines: music::Lines::new(),
yellow_lines: music::Lines::new(),
data: GdlData {
beat_rate: music::StaticBeatRate::from_bpm(120f32).into(),
time_signatures: music::StaticTimeSignature::new(4, 4).into(),
green_lines: music::Lines::new(),
orange_lines: music::Lines::new(),
yellow_lines: music::Lines::new(),
},
},
}
}
@ -124,20 +194,25 @@ impl PipeDash {
egui::SidePanel::left("level_picker")
.default_width(100f32)
.show(ctx, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
ui.with_layout(egui::Layout::top_down_justified(egui::Align::Min), |ui| {
for (idx, level) in self.level_list.iter().enumerate() {
if ui
.selectable_label(
self.selected_level == Some(idx),
level.display_name(),
)
.clicked()
{
self.msg_queue.push_back(Message::LevelSelected(idx));
}
}
})
ui.with_layout(egui::Layout::top_down(egui::Align::LEFT).with_main_justify(false), |ui| {
ui.with_layout(egui::Layout::top_down(egui::Align::LEFT).with_main_justify(true), |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
ui.with_layout(egui::Layout::top_down_justified(egui::Align::Min), |ui| {
for (idx, level) in self.level_list.iter().enumerate() {
if ui
.selectable_label(
self.selected_level == Some(idx),
level.display_name(),
)
.clicked()
{
self.msg_queue.push_back(Message::LevelSelected(idx));
}
}
})
});
});
ui.button("Load Level");
});
});
}
@ -145,11 +220,27 @@ impl PipeDash {
fn center_panel(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.vertical_centered_justified(|ui| {
ui.vertical(|ui| {
ui.label("Song name");
ui.label("Song id");
});
ui.label(
egui::RichText::new(match &self.loaded_song {
Some(song) => &song.name,
None => "No song loaded...",
})
.size(32.0),
);
ui.label(
egui::RichText::new(match &self.loaded_song {
Some(song) => song.id.to_string(),
None => "No song loaded...".into(),
})
.size(20.0),
);
ui.add(self.editor.time_signature_widget());
ui.add(self.editor.beat_rate_widget());
ui.add(self.editor.lines_widget::<Green>());
ui.add(self.editor.lines_widget::<Yellow>());
ui.add(self.editor.lines_widget::<Orange>());
ui.add(self.editor.waveform_widget());
});
});
}

Loading…
Cancel
Save