use egui::{DragValue, Frame, Grid, Ui};
use gled_model::asset::midi_controller::{MidiOutputBindingKind, MidiTrigger};
use super::intent::Intent;
use super::list_state::LearnRequest;
use super::rule_card::Cards;
use super::rules::{Members, Rule, feedback_role, message_name};
pub(crate) fn midi_details(ui: &mut Ui, cards: &mut Cards, rule: &Rule) {
let control = &cards.controls[rule.control];
Frame::NONE
.fill(ui.visuals().extreme_bg_color)
.inner_margin(6.0)
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.label(format!(
"{} sends {}",
control.name,
describe(&control.trigger)
));
if ui
.small_button("Learn again")
.on_hover_text("Then move the control")
.clicked()
{
cards.state.learn_request = Some(LearnRequest::Control(rule.control));
}
});
if let Some(press) = rule.press {
let touch = cards.mapping.input_bindings[press].touch.clone();
touch_row(ui, cards, rule, &touch);
}
Grid::new(("midi feedback", rule.control, rule.mode))
.num_columns(5)
.show(ui, |ui| {
for &output in &rule.feedback {
feedback_row(ui, cards, rule, output);
ui.end_row();
}
});
for index in rule.press.iter().chain(&rule.release) {
ui.weak(&cards.mapping.input_bindings[*index].name);
}
});
}
fn describe(trigger: &MidiTrigger) -> String {
let channel = (trigger.status & 0x0F) + 1;
match trigger.status & 0xF0 {
0x80 | 0x90 => format!("note {} on channel {channel}", trigger.data1),
0xB0 => format!("controller (CC) {} on channel {channel}", trigger.data1),
0xE0 => format!("pitch bend on channel {channel}"),
_ => format!(
"{} (status {}, data {})",
message_name(trigger),
trigger.status,
trigger.data1
),
}
}
fn touch_row(ui: &mut Ui, cards: &mut Cards, rule: &Rule, touch: &Option<MidiTrigger>) {
ui.horizontal(|ui| {
let mut sensitive = touch.is_some();
let mut edited = touch.clone();
let mut changed = ui
.checkbox(&mut sensitive, "Touch note")
.on_hover_text(
"The note a motor fader sends while a finger rests on it; \
gled outlines what it changes meanwhile",
)
.changed();
if changed {
edited = sensitive.then_some(MidiTrigger {
status: 0x90,
data1: 0,
match_data1: true,
});
}
if let Some(touch) = edited.as_mut() {
ui.label("note");
changed |= ui
.add(DragValue::new(&mut touch.data1).range(0..=127))
.changed();
let mut channel = (touch.status & 0x0F) + 1;
ui.label("channel");
if ui.add(DragValue::new(&mut channel).range(1..=16)).changed() {
touch.status = 0x90 | (channel - 1);
changed = true;
}
}
if changed {
cards.intents.push(Intent::SetTouch {
members: Members::single(rule.clone()),
touch: edited,
});
}
});
}
fn feedback_row(ui: &mut Ui, cards: &mut Cards, rule: &Rule, output: usize) {
let kind = &cards.mapping.output_bindings[output].kind;
let role = feedback_role(cards.controls, rule, kind);
ui.label(role.name());
let mut edited = kind.clone();
let mut changed = false;
match &mut edited {
MidiOutputBindingKind::Value(value) => {
changed |= status_data(ui, &mut value.status, &mut value.data1);
ui.horizontal(|ui| {
ui.label("off");
changed |= ui
.add(DragValue::new(&mut value.min).range(0..=127))
.changed();
ui.label("full");
changed |= ui
.add(DragValue::new(&mut value.max).range(0..=127))
.changed();
ui.label("on")
.on_hover_text("The value sent for \"on\", such as a lit button's color");
changed |= ui
.add(DragValue::new(&mut value.active_value).range(0..=127))
.changed();
});
}
MidiOutputBindingKind::SceneColorValue(color) => {
changed |= status_data(ui, &mut color.status, &mut color.data1);
ui.label("");
}
MidiOutputBindingKind::Meter(meter) => {
let mut strip = meter.strip + 1;
ui.horizontal(|ui| {
ui.label("strip");
if ui.add(DragValue::new(&mut strip).range(1..=8)).changed() {
meter.strip = strip - 1;
changed = true;
}
});
ui.label("");
}
}
if changed {
cards.intents.push(Intent::SetFeedbackKind {
output,
kind: edited,
});
}
}
fn status_data(ui: &mut Ui, status: &mut u8, data1: &mut u8) -> bool {
let mut changed = false;
ui.horizontal(|ui| {
let mut channel = (*status & 0x0F) + 1;
let kind = *status & 0xF0;
let label = match kind {
0x90 => "note",
0xB0 => "CC",
0xE0 => "pitch bend",
_ => "data",
};
ui.label("channel");
if ui.add(DragValue::new(&mut channel).range(1..=16)).changed() {
*status = kind | (channel - 1);
changed = true;
}
if kind != 0xE0 {
ui.label(label);
changed |= ui.add(DragValue::new(data1).range(0..=127)).changed();
} else {
ui.label(label);
}
});
changed
}