use egui::{ComboBox, DragValue, Ui};
use gled_model::asset::midi_controller::{
MidiEffectTarget, MidiEffectTargetKind, MidiEncoder, MidiInputAction, MidiInputActionKind,
MidiRelativeEncoding, MidiSceneTarget, MidiSceneTargetKind,
};
use strum::IntoEnumIterator;
pub(super) fn input_action_from_kind(
kind: MidiInputActionKind,
current: MidiInputAction,
) -> MidiInputAction {
match kind {
MidiInputActionKind::Tap => MidiInputAction::Tap,
MidiInputActionKind::SetMainDimmer => MidiInputAction::SetMainDimmer,
MidiInputActionKind::SetMainDimmerRelative => MidiInputAction::SetMainDimmerRelative {
encoder: current_encoder_from_action(¤t),
},
MidiInputActionKind::SetBlackout => MidiInputAction::SetBlackout,
MidiInputActionKind::ToggleBlackout => MidiInputAction::ToggleBlackout,
MidiInputActionKind::SetSpeedAdd => MidiInputAction::SetSpeedAdd,
MidiInputActionKind::SetSpeedMultiply => MidiInputAction::SetSpeedMultiply,
MidiInputActionKind::SetSpeedRelative => MidiInputAction::SetSpeedRelative {
encoder: current_encoder_from_action(¤t),
},
MidiInputActionKind::SelectSceneDistributed => MidiInputAction::SelectSceneDistributed,
MidiInputActionKind::SelectSceneRelative => MidiInputAction::SelectSceneRelative {
encoder: current_encoder_from_action(¤t),
},
MidiInputActionKind::SelectSceneRow => MidiInputAction::SelectSceneRow {
encoder: current_encoder_from_action(¤t),
},
MidiInputActionKind::SelectSceneColumn => MidiInputAction::SelectSceneColumn {
encoder: current_encoder_from_action(¤t),
},
MidiInputActionKind::SelectSceneEffect => MidiInputAction::SelectSceneEffect {
index: match current {
MidiInputAction::SelectSceneEffect { index } => index,
_ => 0,
},
},
MidiInputActionKind::SelectSceneEffectRelative => {
MidiInputAction::SelectSceneEffectRelative {
encoder: current_encoder_from_action(¤t),
}
}
MidiInputActionKind::SelectSceneEffectDistributed => {
MidiInputAction::SelectSceneEffectDistributed
}
MidiInputActionKind::SelectMode => MidiInputAction::SelectMode {
mode: match current {
MidiInputAction::SelectMode { mode } => mode,
_ => 0,
},
},
MidiInputActionKind::SelectScene => MidiInputAction::SelectScene {
target: current_target_from_action(¤t),
},
MidiInputActionKind::ToggleSceneActive => MidiInputAction::ToggleSceneActive {
target: current_target_from_action(¤t),
},
MidiInputActionKind::SetSceneActive => MidiInputAction::SetSceneActive {
target: current_target_from_action(¤t),
},
MidiInputActionKind::FlashScene => MidiInputAction::FlashScene {
target: current_target_from_action(¤t),
},
MidiInputActionKind::SetSceneOpacity => MidiInputAction::SetSceneOpacity {
target: current_target_from_action(¤t),
},
MidiInputActionKind::SetSceneInputDimmer => MidiInputAction::SetSceneInputDimmer {
target: current_target_from_action(¤t),
},
MidiInputActionKind::SetSceneBeatOffset => MidiInputAction::SetSceneBeatOffset {
target: current_target_from_action(¤t),
},
MidiInputActionKind::SetSceneIgnoreMainDimmer => {
MidiInputAction::SetSceneIgnoreMainDimmer {
target: current_target_from_action(¤t),
}
}
MidiInputActionKind::SetSceneSetOffsetOnFlash => {
MidiInputAction::SetSceneSetOffsetOnFlash {
target: current_target_from_action(¤t),
}
}
MidiInputActionKind::SetSceneEffectSettingF32 => {
let setting_index = match ¤t {
MidiInputAction::SetSceneEffectSettingF32 { setting_index, .. } => *setting_index,
_ => 0,
};
MidiInputAction::SetSceneEffectSettingF32 {
target: current_target_from_action(¤t),
effect: current_effect_from_action(¤t),
setting_index,
}
}
MidiInputActionKind::SetSceneEffectOpacity => {
let effect = current_effect_from_action(¤t);
MidiInputAction::SetSceneEffectOpacity {
target: current_target_from_action(¤t),
effect,
}
}
MidiInputActionKind::SetSceneEffectColorShift => {
let effect = current_effect_from_action(¤t);
MidiInputAction::SetSceneEffectColorShift {
target: current_target_from_action(¤t),
effect,
}
}
MidiInputActionKind::SetSceneEffectBeatProgression => {
let effect = current_effect_from_action(¤t);
MidiInputAction::SetSceneEffectBeatProgression {
target: current_target_from_action(¤t),
effect,
}
}
MidiInputActionKind::SetSceneEffectBeatOffset => {
let effect = current_effect_from_action(¤t);
MidiInputAction::SetSceneEffectBeatOffset {
target: current_target_from_action(¤t),
effect,
}
}
MidiInputActionKind::SetSceneEffectSpeedExponent => {
let effect = current_effect_from_action(¤t);
MidiInputAction::SetSceneEffectSpeedExponent {
target: current_target_from_action(¤t),
effect,
}
}
MidiInputActionKind::SetSceneEffectLayout => {
let effect = current_effect_from_action(¤t);
MidiInputAction::SetSceneEffectLayout {
target: current_target_from_action(¤t),
effect,
}
}
}
}
fn current_target_from_action(action: &MidiInputAction) -> MidiSceneTarget {
match action {
MidiInputAction::SelectScene { target }
| MidiInputAction::ToggleSceneActive { target }
| MidiInputAction::SetSceneActive { target }
| MidiInputAction::FlashScene { target }
| MidiInputAction::SetSceneOpacity { target }
| MidiInputAction::SetSceneInputDimmer { target }
| MidiInputAction::SetSceneBeatOffset { target }
| MidiInputAction::SetSceneIgnoreMainDimmer { target }
| MidiInputAction::SetSceneSetOffsetOnFlash { target }
| MidiInputAction::SetSceneEffectSettingF32 { target, .. }
| MidiInputAction::SetSceneEffectOpacity { target, .. }
| MidiInputAction::SetSceneEffectColorShift { target, .. }
| MidiInputAction::SetSceneEffectBeatProgression { target, .. }
| MidiInputAction::SetSceneEffectBeatOffset { target, .. }
| MidiInputAction::SetSceneEffectSpeedExponent { target, .. }
| MidiInputAction::SetSceneEffectLayout { target, .. } => target.clone(),
_ => MidiSceneTarget::Selected,
}
}
fn current_effect_from_action(action: &MidiInputAction) -> MidiEffectTarget {
match action {
MidiInputAction::SetSceneEffectSettingF32 { effect, .. }
| MidiInputAction::SetSceneEffectOpacity { effect, .. }
| MidiInputAction::SetSceneEffectColorShift { effect, .. }
| MidiInputAction::SetSceneEffectBeatProgression { effect, .. }
| MidiInputAction::SetSceneEffectBeatOffset { effect, .. }
| MidiInputAction::SetSceneEffectSpeedExponent { effect, .. }
| MidiInputAction::SetSceneEffectLayout { effect, .. } => *effect,
_ => MidiEffectTarget::Selected,
}
}
fn current_encoder_from_action(action: &MidiInputAction) -> MidiEncoder {
match action {
MidiInputAction::SetMainDimmerRelative { encoder }
| MidiInputAction::SetSpeedRelative { encoder }
| MidiInputAction::SelectSceneRelative { encoder }
| MidiInputAction::SelectSceneRow { encoder }
| MidiInputAction::SelectSceneColumn { encoder }
| MidiInputAction::SelectSceneEffectRelative { encoder } => *encoder,
_ => MidiEncoder::default(),
}
}
pub(super) fn scene_target_editor(
ui: &mut Ui,
target: &mut MidiSceneTarget,
dirty: &mut bool,
id: String,
) {
let mut kind = MidiSceneTargetKind::from(&*target);
ComboBox::new(id, "")
.selected_text(kind.to_string())
.show_ui(ui, |ui| {
for candidate in MidiSceneTargetKind::iter() {
ui.selectable_value(&mut kind, candidate, candidate.to_string());
}
});
let next = scene_target_from_kind(kind, target.clone());
if *target != next {
*target = next;
*dirty = true;
}
match target {
MidiSceneTarget::Quick { index } => {
ui.horizontal(|ui| {
ui.label("Quick Scene Index");
if ui.add(DragValue::new(index).range(0..=7)).changed() {
*dirty = true;
}
});
}
MidiSceneTarget::Grid { row, col } => {
ui.horizontal(|ui| {
ui.label("Row");
if ui.add(DragValue::new(row).range(0..=5)).changed() {
*dirty = true;
}
ui.label("Col");
if ui.add(DragValue::new(col).range(0..=7)).changed() {
*dirty = true;
}
});
}
MidiSceneTarget::Row { col } => {
ui.horizontal(|ui| {
ui.label("Col");
if ui.add(DragValue::new(col).range(0..=7)).changed() {
*dirty = true;
}
});
}
MidiSceneTarget::Column { row } => {
ui.horizontal(|ui| {
ui.label("Row");
if ui.add(DragValue::new(row).range(0..=5)).changed() {
*dirty = true;
}
});
}
MidiSceneTarget::Selected => {}
}
}
fn scene_target_from_kind(kind: MidiSceneTargetKind, current: MidiSceneTarget) -> MidiSceneTarget {
match kind {
MidiSceneTargetKind::Selected => MidiSceneTarget::Selected,
MidiSceneTargetKind::Quick => match current {
MidiSceneTarget::Quick { index } => MidiSceneTarget::Quick { index },
_ => MidiSceneTarget::Quick { index: 0 },
},
MidiSceneTargetKind::Grid => match current {
MidiSceneTarget::Grid { row, col } => MidiSceneTarget::Grid { row, col },
MidiSceneTarget::Quick { index } => MidiSceneTarget::Grid { row: 0, col: index },
MidiSceneTarget::Row { col } => MidiSceneTarget::Grid { row: 0, col },
MidiSceneTarget::Column { row } => MidiSceneTarget::Grid { row, col: 0 },
MidiSceneTarget::Selected => MidiSceneTarget::Grid { row: 0, col: 0 },
},
MidiSceneTargetKind::Row => match current {
MidiSceneTarget::Row { col } => MidiSceneTarget::Row { col },
MidiSceneTarget::Grid { col, .. } | MidiSceneTarget::Quick { index: col } => {
MidiSceneTarget::Row { col }
}
MidiSceneTarget::Column { .. } | MidiSceneTarget::Selected => {
MidiSceneTarget::Row { col: 0 }
}
},
MidiSceneTargetKind::Column => match current {
MidiSceneTarget::Column { row } => MidiSceneTarget::Column { row },
MidiSceneTarget::Grid { row, .. } => MidiSceneTarget::Column { row },
MidiSceneTarget::Quick { .. }
| MidiSceneTarget::Row { .. }
| MidiSceneTarget::Selected => MidiSceneTarget::Column { row: 0 },
},
}
}
pub(super) fn effect_target_editor(
ui: &mut Ui,
effect: &mut MidiEffectTarget,
dirty: &mut bool,
id: String,
) -> egui::Response {
ui.horizontal(|ui| {
let mut kind = MidiEffectTargetKind::from(&*effect);
ComboBox::new(id, "")
.selected_text(kind.to_string())
.show_ui(ui, |ui| {
for candidate in MidiEffectTargetKind::iter() {
ui.selectable_value(&mut kind, candidate, candidate.to_string());
}
});
let next = match (kind, &*effect) {
(MidiEffectTargetKind::Selected, _) => MidiEffectTarget::Selected,
(MidiEffectTargetKind::Index, MidiEffectTarget::Index { index }) => {
MidiEffectTarget::Index { index: *index }
}
(MidiEffectTargetKind::Index, MidiEffectTarget::Selected) => {
MidiEffectTarget::Index { index: 0 }
}
};
if *effect != next {
*effect = next;
*dirty = true;
}
if let MidiEffectTarget::Index { index } = effect
&& ui.add(DragValue::new(index).range(0..=255)).changed()
{
*dirty = true;
}
})
.response
}
pub(super) fn encoder_editor(ui: &mut Ui, encoder: &mut MidiEncoder, dirty: &mut bool, id: String) {
ui.horizontal(|ui| {
ui.label("Steps per unit");
if ui
.add(DragValue::new(&mut encoder.steps_per_unit).range(1..=64))
.on_hover_text("Encoder steps for one scene, effect, BPM or 1/127 of the dimmer")
.changed()
{
*dirty = true;
}
});
ui.horizontal(|ui| {
ui.label("Encoder");
ComboBox::new(id, "")
.selected_text(encoder.encoding.to_string())
.show_ui(ui, |ui| {
for candidate in MidiRelativeEncoding::iter() {
if ui
.selectable_value(&mut encoder.encoding, candidate, candidate.to_string())
.changed()
{
*dirty = true;
}
}
})
.response
.on_hover_text(
"Two's complement: 127 is one step back (APC40). \
Sign magnitude: 65 is one step back (Mackie Control, iCON P1-X).",
);
});
}