Advanced Aura feature

Groundwork for 'advanced' aura modes
Add single zone + Doom light flash
Fix mocking for ROGCC
Better prepare & change to mapping of keyboard layouts to models and functions
Refactor and begin using new key layout stuff
Enable first arg to rogcc to set layout in mocking feature mode
Complete refactor of key layouts, and to RON serde
This commit is contained in:
Luke D. Jones
2022-12-11 11:50:47 +13:00
parent e3ecaa92bd
commit 1cbffedaeb
134 changed files with 8249 additions and 4390 deletions
+165 -78
View File
@@ -1,59 +1,152 @@
use egui::{Align, Color32, Vec2};
use rog_aura::{keys::KeyShape, layouts::KeyLayout, AuraModeNum};
use egui::{Color32, Pos2};
use rog_aura::advanced::LedCode;
use rog_aura::layouts::{KeyLayout, KeyShape};
use rog_aura::{AdvancedAuraType, AuraModeNum};
use crate::system_state::AuraState;
const SCALE: f32 = 2.0;
// TODO:
// - Multizone: draw regions? While iterating keys check if located in one of
// the 4 regions and mark
// - Tab for advanced effects
// - Keys need to select colour themselves
pub fn keyboard(
ui: &mut egui::Ui,
keyboard_layout: &KeyLayout,
states: &mut AuraState,
mut colour: Color32,
colour: Color32,
) {
let mut key_colour = colour;
let mut input_colour = colour;
let (keyboard_is_multizoned, keyboard_width, keyboard_is_per_key) =
match keyboard_layout.advanced_type() {
AdvancedAuraType::PerKey => (false, 0.0, true),
AdvancedAuraType::None => (false, keyboard_layout.max_width(), false),
AdvancedAuraType::Zoned(zones) => {
let width = if let Some(row) = keyboard_layout.rows_ref().get(2) {
row.width() as f32
} else {
0.0
};
(!zones.contains(&LedCode::SingleZone), width, false)
}
};
let mut start_pos = None;
let y = ui.spacing().interact_size.y;
let this_size = ui.available_size();
let keys_width = keyboard_layout.max_width() * SCALE * y;
let keys_height = keyboard_layout.max_height() * SCALE * y;
let x_start = (this_size.x - keys_width) / SCALE;
let y_start = (this_size.y - keys_height) / SCALE;
ui.spacing_mut().item_spacing = egui::vec2(0.0, 0.0);
let mut arrows_done = false;
let mut rog_done = false;
blank(ui, 0.0, y_start / y);
// Need to exclude the lightbar row if there is one
let mut keyboard_height = 0.0;
for row in keyboard_layout.rows() {
ui.horizontal_top(|ui| {
blank(ui, x_start / y, 0.0);
for (i, key) in row.row().enumerate() {
if !key.0.is_lightbar_zone() && i == 0 {
keyboard_height += row.height() as f32 * SCALE;
}
if states.current_mode == AuraModeNum::Rainbow {
colour = Color32::from_rgb(
key_colour = Color32::from_rgb(
(states.wave_red[i] as u32 * 255 / 100) as u8,
(states.wave_green[i] as u32 * 255 / 100) as u8,
(states.wave_blue[i] as u32 * 255 / 100) as u8,
);
}
// your boat
let height = if rog_done {
row.height()
} else {
// Use the first item (always a blank) to stand off the row
rog_done = true;
1.2
};
let shape = KeyShape::from(key);
if (keyboard_is_multizoned && !key.0.is_lightbar_zone())
&& states.current_mode == AuraModeNum::Rainbow
{
input_colour = key_colour;
key_colour = Color32::TRANSPARENT;
}
let label = <&str>::from(key);
if shape.is_arrow_cluster() {
if !arrows_done {
arrow_cluster(ui, colour);
arrows_done = true;
let label = <&str>::from(key.0);
let mut shape = key.1.clone();
shape.scale(SCALE);
match shape {
KeyShape::Led {
width,
height,
pad_left,
pad_right,
pad_top,
pad_bottom,
} => {
let (pos, response) = key_shape(
ui, key_colour, width, height, pad_left, pad_right, pad_top, pad_bottom,
);
if start_pos.is_none() {
start_pos = Some(pos);
} else if let Some(old_pos) = start_pos.as_mut() {
if !key.0.is_lightbar_zone() {
if pos.x < old_pos.x {
old_pos.x = pos.x;
}
if pos.y < old_pos.y {
old_pos.y = pos.y;
}
}
}
if response.on_hover_text(label).clicked() && keyboard_is_per_key {
// TODO: set an effect on the LedCode
}
}
KeyShape::Blank { width, height } => {
blank(ui, width, height);
}
} else if shape.is_blank() || shape.is_spacer() {
blank(ui, shape.width(), height);
} else if shape.is_group() {
key_group(ui, colour, shape.width(), height).on_hover_text(label);
} else {
key_shape(ui, colour, shape.width(), height).on_hover_text(label);
}
}
});
}
if keyboard_is_multizoned {
let zone_width = keyboard_width * SCALE / 4.0 - 0.1;
for n in 0..4 {
if states.current_mode == AuraModeNum::Rainbow {
input_colour = Color32::from_rgba_unmultiplied(
(states.wave_red[n] as u32 * 255 / 100) as u8,
(states.wave_green[n] as u32 * 255 / 100) as u8,
(states.wave_blue[n] as u32 * 255 / 100) as u8,
70,
);
}
if let Some(mut pos) = start_pos {
pos.x += n as f32 * zone_width * y;
let response = zone_shape(ui, input_colour, pos, zone_width, keyboard_height);
let label = format!("Zone {}", 1 + n);
if response.on_hover_text(label).clicked() {
// TODO: set an effect on the zone
}
}
}
}
}
fn key_shape(ui: &mut egui::Ui, colour: Color32, ux: f32, uy: f32) -> egui::Response {
let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0 * ux, 2.0 * uy);
#[allow(clippy::too_many_arguments)]
fn key_shape(
ui: &mut egui::Ui,
colour: Color32,
width: f32,
height: f32,
pad_left: f32,
pad_right: f32,
pad_top: f32,
pad_bottom: f32,
) -> (egui::Pos2, egui::Response) {
// First, get some space
let y = ui.spacing().interact_size.y;
let desired_size = y * egui::vec2(width + pad_left + pad_right, height + pad_top + pad_bottom);
let (mut rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
rect = rect.shrink(3.0);
// rect = rect.shrink(3.0);
if response.clicked() {
response.mark_changed();
}
@@ -62,62 +155,56 @@ fn key_shape(ui: &mut egui::Ui, colour: Color32, ux: f32, uy: f32) -> egui::Resp
});
if ui.is_rect_visible(rect) {
// Now set the actual visible rect
let visuals = ui.style().interact_selectable(&response, true);
let rect = rect.expand(visuals.expansion);
let size = y * egui::vec2(width, height);
rect.set_width(size.x);
rect.set_height(size.y);
let center = Pos2::new(
rect.center().x + pad_left * y,
rect.center().y + pad_top * y,
);
rect.set_center(center);
// let rect = rect.expand(visuals.expansion);
ui.painter().rect(rect, 0.1, colour, visuals.fg_stroke);
}
(rect.left_top(), response)
}
#[allow(clippy::too_many_arguments)]
fn zone_shape(
ui: &mut egui::Ui,
mut colour: Color32,
pos: Pos2,
width: f32,
height: f32,
) -> egui::Response {
// First, get some space
let y = ui.spacing().interact_size.y;
let desired_size = y * egui::vec2(width, height);
let rect = egui::Rect::from_min_size(pos, desired_size);
let mut response = ui.allocate_rect(rect, egui::Sense::click());
// rect = rect.shrink(3.0);
if response.clicked() {
response.mark_changed();
}
response.widget_info(|| {
egui::WidgetInfo::selected(egui::WidgetType::Checkbox, response.clicked(), "")
});
if ui.is_rect_visible(rect) {
// Now set the actual visible rect
let visuals = ui.style().interact_selectable(&response, true);
// let rect = rect.expand(visuals.expansion);
colour[3] = 20;
ui.painter().rect(rect, 0.1, colour, visuals.fg_stroke);
}
response
}
fn key_group(ui: &mut egui::Ui, colour: Color32, ux: f32, uy: f32) -> egui::Response {
let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0 * ux, 2.0 * uy);
let (mut rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
rect = rect.shrink2(Vec2::new(3.0, 3.0));
if response.clicked() {
response.mark_changed();
}
response.widget_info(|| {
egui::WidgetInfo::selected(egui::WidgetType::Checkbox, response.clicked(), "")
});
if ui.is_rect_visible(rect) {
let visuals = ui.style().interact_selectable(&response, true);
let rect = rect.expand(visuals.expansion);
let mut stroke = visuals.fg_stroke;
stroke.color = visuals.bg_fill;
ui.painter().rect(rect, 0.1, colour, stroke);
}
response
}
fn blank(ui: &mut egui::Ui, ux: f32, uy: f32) {
let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0 * ux, 2.0 * uy);
let desired_size = ui.spacing().interact_size.y * egui::vec2(ux, uy);
ui.allocate_exact_size(desired_size, egui::Sense::click());
}
/// Draws entire arrow cluster block. This is visibly different to the split-arrows.
fn arrow_cluster(ui: &mut egui::Ui, colour: Color32) {
let height = 0.7;
let space = KeyShape::ArrowSpacer;
let shape = KeyShape::Arrow;
ui.horizontal_top(|ui| {
ui.with_layout(egui::Layout::top_down(Align::LEFT), |ui| {
blank(ui, space.width(), height);
ui.horizontal(|ui| {
blank(ui, KeyShape::RowEndSpacer.width(), height);
blank(ui, KeyShape::RowEndSpacer.width(), height);
key_shape(ui, colour, shape.width(), height).on_hover_text("Left");
});
});
ui.with_layout(egui::Layout::top_down(Align::LEFT), |ui| {
key_shape(ui, colour, shape.width(), height).on_hover_text("Up");
key_shape(ui, colour, shape.width(), height).on_hover_text("Down");
});
ui.with_layout(egui::Layout::top_down(Align::LEFT), |ui| {
blank(ui, space.width(), height);
key_shape(ui, colour, shape.width(), height).on_hover_text("Right");
});
});
}