diff --git a/deckster/examples/full/deckster.toml b/deckster/examples/full/deckster.toml
index ccd0cc6..906ce3c 100644
--- a/deckster/examples/full/deckster.toml
+++ b/deckster/examples/full/deckster.toml
@@ -22,15 +22,15 @@ key_page = "default"
knob_page = "default"
[icon_packs.apps]
-path = "./apps"
+path = "icons/apps"
format = "svg"
[icon_packs.fad]
-path = "./fad"
+path = "icons/fad"
format = "svg"
global_filter = "invert"
[icon_packs.ph]
-path = "./ph"
+path = "icons/ph"
format = "svg"
global_filter = "invert"
\ No newline at end of file
diff --git a/deckster/examples/full/icons/apps/spotify.svg b/deckster/examples/full/icons/apps/spotify.svg
new file mode 100644
index 0000000..78c3a1d
--- /dev/null
+++ b/deckster/examples/full/icons/apps/spotify.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/deckster/src/icons/mod.rs b/deckster/src/icons/mod.rs
index 86ddc3c..60270b3 100644
--- a/deckster/src/icons/mod.rs
+++ b/deckster/src/icons/mod.rs
@@ -10,21 +10,67 @@ use tiny_skia::{Pixmap, Transform};
use crate::icons::filter::apply_filter;
use crate::model::config::{Config, IconFormat, IconPack};
use crate::model::icon_descriptor::{IconDescriptor, IconDescriptorSource};
+use crate::model::IconMap;
mod filter;
+#[derive(Debug)]
pub struct LoadedIcon {
- pixmap: Pixmap,
- scale: f32,
+ pub pixmap: Pixmap,
+ pub scale: f32,
}
pub fn get_used_icon_descriptors(config: &Config) -> HashSet {
let mut result: HashSet = HashSet::new();
+ fn insert_all_from_map(result: &mut HashSet, map: &IconMap) {
+ map.values().for_each(|v| {
+ result.insert(v.clone());
+ });
+ }
+
for page in config.key_pages_by_id.values() {
for key in page.keys.values() {
if let Some(d) = &key.icon {
- result.insert(d.0);
+ result.insert(d.clone());
+
+ if let Some(c) = &key.mode.media__next {
+ insert_all_from_map(&mut result, &c.icon);
+ }
+
+ if let Some(c) = &key.mode.media__play_pause {
+ insert_all_from_map(&mut result, &c.icon);
+ }
+
+ if let Some(c) = &key.mode.media__previous {
+ insert_all_from_map(&mut result, &c.icon);
+ }
+
+ if let Some(c) = &key.mode.home_assistant__button {
+ insert_all_from_map(&mut result, &c.icon);
+ }
+
+ if let Some(c) = &key.mode.home_assistant__switch {
+ insert_all_from_map(&mut result, &c.icon);
+ }
+
+ if let Some(c) = &key.mode.spotify__repeat {
+ insert_all_from_map(&mut result, &c.icon);
+ }
+
+ if let Some(c) = &key.mode.spotify__shuffle {
+ insert_all_from_map(&mut result, &c.icon);
+ }
+ }
+ }
+ }
+
+ for page in config.knob_pages_by_id.values() {
+ for knob in page.knobs.values() {
+ result.insert(knob.icon.clone());
+
+ if let Some(c) = &knob.mode.audio_volume {
+ insert_all_from_map(&mut result, &c.icon);
}
}
}
@@ -33,9 +79,9 @@ pub fn get_used_icon_descriptors(config: &Config) -> HashSet {
}
pub fn load_icons(
- icon_packs_by_id: HashMap,
+ config_directory: &Path,
+ icon_packs_by_id: &HashMap,
descriptors: HashSet,
- key_size: (u16, u16),
dpi: f32,
) -> Result> {
let mut unfiltered_pixmap_by_source: HashMap = HashMap::new();
@@ -50,7 +96,7 @@ pub fn load_icons(
let original_image = match unfiltered_pixmap_by_source.entry(descriptor.source.clone()) {
Entry::Occupied(o) => o.into_mut(),
- Entry::Vacant(v) => v.insert(read_image(&icon_packs_by_id, dpi, &fonts_db, descriptor.source.clone())?),
+ Entry::Vacant(v) => v.insert(read_image(config_directory, icon_packs_by_id, dpi, &fonts_db, descriptor.source.clone())?),
};
let pixmap = apply_filter(original_image, &descriptor.filter)?;
@@ -63,6 +109,7 @@ pub fn load_icons(
}
fn read_image(
+ config_directory: &Path,
icon_packs_by_id: &HashMap,
dpi: f32,
fonts_db: &resvg::usvg::fontdb::Database,
@@ -79,7 +126,7 @@ fn read_image(
IconFormat::Svg => "svg",
};
- pack.path.join(icon_id + "." + extension)
+ config_directory.join(&pack.path).join(icon_id + "." + extension)
}
};
diff --git a/deckster/src/main.rs b/deckster/src/main.rs
index daf30da..64b24d7 100644
--- a/deckster/src/main.rs
+++ b/deckster/src/main.rs
@@ -71,7 +71,7 @@ pub async fn main() -> Result<()> {
}
.validate()?;
- runner::start(config).await?
+ runner::start(&config_path, config).await?
}
};
@@ -79,7 +79,7 @@ pub async fn main() -> Result<()> {
}
fn read_and_deserialize(path: &Path) -> Result {
- let content = fs::read_to_string(&path).wrap_err_with(|| format!("Reading of {} failed.", path.to_string_lossy()))?;
+ let content = fs::read_to_string(path).wrap_err_with(|| format!("Reading of {} failed.", path.to_string_lossy()))?;
toml::from_str::(&content).wrap_err_with(|| format!("Parsing of {} failed.", path.to_string_lossy()))
}
diff --git a/deckster/src/model/icon_descriptor.rs b/deckster/src/model/icon_descriptor.rs
index b45114c..d9ce6ad 100644
--- a/deckster/src/model/icon_descriptor.rs
+++ b/deckster/src/model/icon_descriptor.rs
@@ -1,16 +1,14 @@
+use std::fmt::{Display, Formatter, Write};
use std::path::PathBuf;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
-use serde_with::DeserializeFromStr;
+use serde_with::{DeserializeFromStr, SerializeDisplay};
use thiserror::Error;
use crate::model::image_filter::{ImageFilter, ImageFilterFromStringError};
-#[derive(Debug, Default, PartialEq, Clone, DeserializeFromStr)]
-pub struct IconDescriptorString(pub IconDescriptor);
-
-#[derive(Debug, Default, Eq, PartialEq, Hash, Clone, Serialize, Deserialize)]
+#[derive(Debug, Default, Eq, PartialEq, Hash, Clone, SerializeDisplay, DeserializeFromStr)]
pub struct IconDescriptor {
pub source: IconDescriptorSource,
pub filter: ImageFilter,
@@ -28,7 +26,7 @@ pub enum IconDescriptorFromStrError {
MissingImageFilterClosingBracket,
}
-impl FromStr for IconDescriptorString {
+impl FromStr for IconDescriptor {
type Err = IconDescriptorFromStrError;
fn from_str(s: &str) -> Result {
@@ -57,7 +55,13 @@ impl FromStr for IconDescriptorString {
ImageFilter::from_str(&raw_filter).map_err(IconDescriptorFromStrError::InvalidImageFilter)?
};
- Ok(IconDescriptorString(IconDescriptor { source, filter }))
+ Ok(IconDescriptor { source, filter })
+ }
+}
+
+impl Display for IconDescriptor {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("{}[{}]", self.source, self.filter))
}
}
@@ -71,3 +75,13 @@ pub enum IconDescriptorSource {
},
Path(PathBuf),
}
+
+impl Display for IconDescriptorSource {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ match self {
+ IconDescriptorSource::None => f.write_str(""),
+ IconDescriptorSource::IconPack { pack_id, icon_id } => f.write_fmt(format_args!("@{}/{}", pack_id, icon_id)),
+ IconDescriptorSource::Path(path) => f.write_str(&path.to_string_lossy()),
+ }
+ }
+}
diff --git a/deckster/src/model/key_modes/home_assistant.rs b/deckster/src/model/key_modes/home_assistant.rs
index 6ff1ae8..6d71a2b 100644
--- a/deckster/src/model/key_modes/home_assistant.rs
+++ b/deckster/src/model/key_modes/home_assistant.rs
@@ -2,20 +2,20 @@ use std::collections::HashMap;
use serde::Deserialize;
-use crate::model::icon_descriptor::IconDescriptorString;
+use crate::model::icon_descriptor::IconDescriptor;
#[derive(Debug, Deserialize)]
pub struct SwitchConfig {
pub name: String,
#[serde(default)]
- pub icon: HashMap,
+ pub icon: HashMap,
}
#[derive(Debug, Deserialize)]
pub struct ButtonConfig {
pub name: String,
#[serde(default)]
- pub icon: HashMap,
+ pub icon: HashMap,
}
#[derive(Debug, Eq, PartialEq, Hash, Deserialize)]
diff --git a/deckster/src/model/key_modes/media.rs b/deckster/src/model/key_modes/media.rs
index 05ad60f..fe9ac1b 100644
--- a/deckster/src/model/key_modes/media.rs
+++ b/deckster/src/model/key_modes/media.rs
@@ -2,12 +2,12 @@ use std::collections::HashMap;
use serde::Deserialize;
-use crate::model::icon_descriptor::IconDescriptorString;
+use crate::model::icon_descriptor::IconDescriptor;
#[derive(Debug, Deserialize)]
pub struct PlayPauseConfig {
#[serde(default)]
- pub icon: HashMap,
+ pub icon: HashMap,
#[serde(default)]
pub action: PlayPauseAction,
}
@@ -24,7 +24,7 @@ pub enum PlayPauseAction {
#[derive(Debug, Deserialize)]
pub struct PreviousAndNextConfig {
#[serde(default)]
- pub icon: HashMap,
+ pub icon: HashMap,
}
#[derive(Debug, Eq, PartialEq, Hash, Deserialize)]
diff --git a/deckster/src/model/key_modes/spotify.rs b/deckster/src/model/key_modes/spotify.rs
index a6e30b4..612a424 100644
--- a/deckster/src/model/key_modes/spotify.rs
+++ b/deckster/src/model/key_modes/spotify.rs
@@ -2,18 +2,18 @@ use std::collections::HashMap;
use serde::Deserialize;
-use crate::model::icon_descriptor::IconDescriptorString;
+use crate::model::icon_descriptor::IconDescriptor;
#[derive(Debug, Deserialize)]
pub struct ShuffleConfig {
#[serde(default)]
- pub icon: HashMap,
+ pub icon: HashMap,
}
#[derive(Debug, Deserialize)]
pub struct RepeatConfig {
#[serde(default)]
- pub icon: HashMap,
+ pub icon: HashMap,
}
#[derive(Debug, Eq, PartialEq, Hash, Deserialize)]
diff --git a/deckster/src/model/key_page.rs b/deckster/src/model/key_page.rs
index d5d0379..f3a8131 100644
--- a/deckster/src/model/key_page.rs
+++ b/deckster/src/model/key_page.rs
@@ -3,7 +3,7 @@ use std::collections::HashMap;
use serde::Deserialize;
use crate::model::geometry::UIntVec2;
-use crate::model::icon_descriptor::IconDescriptorString;
+use crate::model::icon_descriptor::IconDescriptor;
use crate::model::{key_modes, KeyPosition, KnobPosition};
#[derive(Debug, Deserialize)]
@@ -46,7 +46,7 @@ pub enum ScrollingConfigAxis {
#[derive(Debug, Deserialize)]
pub struct KeyConfig {
pub label: Option,
- pub icon: Option,
+ pub icon: Option,
#[serde(default)]
pub mode: KeyModes,
}
diff --git a/deckster/src/model/knob_modes/audio_volume.rs b/deckster/src/model/knob_modes/audio_volume.rs
index 2e905ee..124937d 100644
--- a/deckster/src/model/knob_modes/audio_volume.rs
+++ b/deckster/src/model/knob_modes/audio_volume.rs
@@ -4,8 +4,8 @@ use std::num::NonZeroU8;
use regex::Regex;
use serde::Deserialize;
-use crate::model::icon_descriptor::IconDescriptorString;
use crate::model::rgb::RGB8WithOptionalA;
+use crate::model::IconMap;
#[derive(Debug, Deserialize)]
pub struct Config {
@@ -22,7 +22,7 @@ pub struct Config {
#[serde(default)]
pub label: HashMap,
#[serde(default)]
- pub icon: HashMap,
+ pub icon: IconMap,
pub circle_indicator: Option,
pub bar_indicator: Option,
}
diff --git a/deckster/src/model/knob_page.rs b/deckster/src/model/knob_page.rs
index 5d7a6f1..749794f 100644
--- a/deckster/src/model/knob_page.rs
+++ b/deckster/src/model/knob_page.rs
@@ -3,7 +3,7 @@ use std::collections::HashMap;
use enum_map::EnumMap;
use serde::Deserialize;
-use crate::model::icon_descriptor::IconDescriptorString;
+use crate::model::icon_descriptor::IconDescriptor;
use crate::model::rgb::RGB8WithOptionalA;
use crate::model::{knob_modes, KnobPosition};
@@ -24,7 +24,7 @@ pub struct Knob {
#[serde(default)]
pub label: String,
#[serde(default)]
- pub icon: IconDescriptorString,
+ pub icon: IconDescriptor,
#[serde(default)]
pub indicator: KnobIndicators,
#[serde(default)]
diff --git a/deckster/src/model/mod.rs b/deckster/src/model/mod.rs
index 5320226..6158191 100644
--- a/deckster/src/model/mod.rs
+++ b/deckster/src/model/mod.rs
@@ -1,3 +1,4 @@
+use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
@@ -8,6 +9,8 @@ use thiserror::Error;
use loupedeck_serial::characteristics::LoupedeckButton;
+use crate::model::icon_descriptor::IconDescriptor;
+
pub mod config;
pub mod geometry;
pub mod icon_descriptor;
@@ -125,3 +128,5 @@ impl Display for ButtonPosition {
})
}
}
+
+pub type IconMap = HashMap;
diff --git a/deckster/src/runner/graphics.rs b/deckster/src/runner/graphics.rs
index f48ccb7..4634b61 100644
--- a/deckster/src/runner/graphics.rs
+++ b/deckster/src/runner/graphics.rs
@@ -1,22 +1,30 @@
+use std::collections::HashMap;
+
use bytes::{BufMut, Bytes, BytesMut};
-use tiny_skia::{Color, Pixmap, PremultipliedColorU8};
+use tiny_skia::{Color, IntSize, Pixmap, PremultipliedColorU8};
use loupedeck_serial::util::Endianness;
+use crate::icons::LoadedIcon;
+use crate::model::icon_descriptor::{IconDescriptor, IconDescriptorSource};
use crate::runner::state::Key;
-pub fn render_key(width: u16, height: u16, buffer_endianness: Endianness, state: Option<&Key>) -> Bytes {
- let mut canvas = Pixmap::new(width as u32, height as u32).unwrap();
+pub fn render_key(key_size: (u16, u16), buffer_endianness: Endianness, icons: &HashMap, state: Option<&Key>) -> Bytes {
+ let mut canvas = Pixmap::new(key_size.0 as u32, key_size.1 as u32).unwrap();
if let Some(state) = state {
- canvas.fill(if state.label.is_empty() {
- Color::WHITE
- } else {
- Color::from_rgba8(0, 255, 0, 255)
- });
+ if state.icon.source != IconDescriptorSource::None {
+ let icon = &icons[&state.icon];
+ let scaled_size = IntSize::from_wh(icon.pixmap.width(), icon.pixmap.height())
+ .unwrap()
+ .scale_by(icon.scale)
+ .unwrap();
+
+ //canvas.draw_pixmap(0, 0, icon.pixmap.as_ref(), &PixmapPaint::default(), Transform::from_scale(icon.scale, icon.scale), None);
+ }
} else {
- canvas.fill(Color::BLACK);
}
+ canvas.fill(Color::WHITE);
convert_pixels_to_rgb565(canvas.pixels(), buffer_endianness).freeze()
}
diff --git a/deckster/src/runner/mod.rs b/deckster/src/runner/mod.rs
index 13c07e3..2831f90 100644
--- a/deckster/src/runner/mod.rs
+++ b/deckster/src/runner/mod.rs
@@ -1,4 +1,5 @@
use std::collections::HashMap;
+use std::path::Path;
use std::sync::Arc;
use std::thread;
@@ -15,6 +16,7 @@ use loupedeck_serial::commands::VibrationPattern;
use loupedeck_serial::device::LoupedeckDevice;
use loupedeck_serial::events::LoupedeckEvent;
+use crate::icons::{get_used_icon_descriptors, load_icons, LoadedIcon};
use crate::model;
use crate::model::icon_descriptor::IconDescriptor;
use crate::model::{ButtonPosition, KeyPath, KeyPosition, KnobPath};
@@ -24,7 +26,7 @@ use crate::runner::state::{Key, State, StateChangeCommand};
mod graphics;
mod state;
-pub async fn start(config: model::config::Config) -> Result<()> {
+pub async fn start(config_directory: &Path, config: model::config::Config) -> Result<()> {
let config = Arc::new(config);
let device = LoupedeckDevice::discover()?
.first()
@@ -32,6 +34,11 @@ pub async fn start(config: model::config::Config) -> Result<()> {
.connect()
.wrap_err("Connecting to the device failed.")?;
+ let key_grid = &device.characteristics().key_grid;
+
+ let used_icon_descriptors = get_used_icon_descriptors(&config);
+ let icons = load_icons(config_directory, &config.icon_packs, used_icon_descriptors, key_grid.display.dpi)?;
+
device.set_brightness(0.0);
device.vibrate(VibrationPattern::RiseFall);
@@ -49,7 +56,7 @@ pub async fn start(config: model::config::Config) -> Result<()> {
let cloned_commands_sender = commands_sender.clone();
let io_worker_thread = thread::Builder::new()
.name("deckster IO worker".to_owned())
- .spawn(move || do_io_work(cloned_config, device, events_receiver, cloned_commands_sender, commands_receiver))
+ .spawn(move || do_io_work(cloned_config, icons, device, events_receiver, cloned_commands_sender, commands_receiver))
.wrap_err("Could not spawn the worker thread")?;
io_worker_thread.join().unwrap();
@@ -72,7 +79,7 @@ fn create_state(config: &model::config::Config) -> State {
position: *position,
},
label: k.label.clone().unwrap_or_default(),
- icon: IconDescriptor::default(),
+ icon: k.icon.clone().unwrap_or_default(),
})
.map(|k| (k.path.position, k))
.collect(),
@@ -94,7 +101,7 @@ fn create_state(config: &model::config::Config) -> State {
position,
},
label: knob_config.label.clone(),
- icon: knob_config.icon.0.clone(),
+ icon: knob_config.icon.clone(),
value: 0.0,
}
}),
@@ -115,14 +122,23 @@ enum IoWork {
Command(StateChangeCommand),
}
+struct IoWorkerContext {
+ config: Arc,
+ icons: HashMap,
+ device: LoupedeckDevice,
+ state: State,
+}
+
fn do_io_work(
config: Arc,
+ icons: HashMap,
device: LoupedeckDevice,
events_receiver: Receiver,
commands_sender: Sender,
commands_receiver: Receiver,
) {
- let mut state = create_state(&config);
+ let state = create_state(&config);
+ let mut context = IoWorkerContext { config, icons, device, state };
loop {
let a = flume::Selector::new()
@@ -132,40 +148,34 @@ fn do_io_work(
match a {
IoWork::Event(event) => {
- if !handle_event(&config, &state, &device, &commands_sender, event) {
+ if !handle_event(&context, &commands_sender, event) {
break;
}
}
- IoWork::Command(command) => handle_command(&config, &mut state, &device, command),
+ IoWork::Command(command) => handle_command(&mut context, command),
}
}
}
-fn handle_event(
- config: &model::config::Config,
- state: &State,
- device: &LoupedeckDevice,
- commands_sender: &Sender,
- event: LoupedeckEvent,
-) -> bool {
+fn handle_event(context: &IoWorkerContext, commands_sender: &Sender, event: LoupedeckEvent) -> bool {
trace!("Handling event: {:?}", &event);
match event {
LoupedeckEvent::Disconnected => return false,
LoupedeckEvent::ButtonDown { button } => {
let position = ButtonPosition::of(&button);
- let button_config = &config.buttons[position];
+ let button_config = &context.config.buttons[position];
commands_sender
.send(StateChangeCommand::SetActivePages {
- key_page_id: button_config.key_page.as_ref().unwrap_or(&state.active_key_page_id).clone(),
- knob_page_id: button_config.knob_page.as_ref().unwrap_or(&state.active_knob_page_id).clone(),
+ key_page_id: button_config.key_page.as_ref().unwrap_or(&context.state.active_key_page_id).clone(),
+ knob_page_id: button_config.knob_page.as_ref().unwrap_or(&context.state.active_knob_page_id).clone(),
})
.unwrap()
}
LoupedeckEvent::Touch { x, y, is_end, .. } => {
if is_end {
- let characteristics = device.characteristics();
+ let characteristics = context.device.characteristics();
let display = characteristics.get_display_at_coordinates(x, y);
if let Some(display) = display {
@@ -178,11 +188,11 @@ fn handle_event(
};
let path = KeyPath {
- page_id: state.active_key_page_id.clone(),
+ page_id: context.state.active_key_page_id.clone(),
position,
};
- let value = if state.get_key(&path).label.is_empty() {
+ let value = if context.state.get_key(&path).label.is_empty() {
"a".to_owned()
} else {
String::new()
@@ -200,29 +210,29 @@ fn handle_event(
true
}
-fn handle_command(config: &model::config::Config, state: &mut State, device: &LoupedeckDevice, command: StateChangeCommand) {
+fn handle_command(context: &mut IoWorkerContext, command: StateChangeCommand) {
debug!("Handling command: {:?}", &command);
match command {
StateChangeCommand::SetActivePages { key_page_id, knob_page_id } => {
- state.active_key_page_id = key_page_id;
- state.active_knob_page_id = knob_page_id;
+ context.state.active_key_page_id = key_page_id;
+ context.state.active_knob_page_id = knob_page_id;
for button in LoupedeckButton::VARIANTS {
let position = ButtonPosition::of(button);
- device.set_button_color(*button, get_correct_button_color(config, state, position)).unwrap();
+ context.device.set_button_color(*button, get_correct_button_color(context, position)).unwrap();
}
- let key_grid = &device.characteristics().key_grid;
+ let key_grid = &context.device.characteristics().key_grid;
for index in 0..(key_grid.rows * key_grid.columns) {
- draw_key_at_index(device, state, index);
+ draw_key_at_index(context, index);
}
- device.refresh_display(&key_grid.display).unwrap();
+ context.device.refresh_display(&key_grid.display).unwrap();
}
StateChangeCommand::SetKeyLabel { path, value } => {
- state.mutate_key_for_command(
+ context.state.mutate_key_for_command(
"SetKeyLabel",
&path,
Box::new(|k| {
@@ -230,11 +240,11 @@ fn handle_command(config: &model::config::Config, state: &mut State, device: &Lo
}),
);
- draw_key_at_path_if_visible(device, state, path);
- device.refresh_display(&device.characteristics().key_grid.display).unwrap();
+ draw_key_at_path_if_visible(context, path);
+ context.device.refresh_display(&context.device.characteristics().key_grid.display).unwrap();
}
StateChangeCommand::SetKeyIcon { path, value } => {
- state.mutate_key_for_command(
+ context.state.mutate_key_for_command(
"SetKeyIcon",
&path,
Box::new(|k| {
@@ -242,8 +252,8 @@ fn handle_command(config: &model::config::Config, state: &mut State, device: &Lo
}),
);
- draw_key_at_path_if_visible(device, state, path);
- device.refresh_display(&device.characteristics().key_grid.display).unwrap();
+ draw_key_at_path_if_visible(context, path);
+ context.device.refresh_display(&context.device.characteristics().key_grid.display).unwrap();
}
}
}
@@ -251,14 +261,14 @@ fn handle_command(config: &model::config::Config, state: &mut State, device: &Lo
// active -> config.active_button_color
// no actions defined -> #000000
// inactive -> config.inactive_button_color
-fn get_correct_button_color(config: &model::config::Config, state: &mut State, button_position: ButtonPosition) -> RGB8 {
- let button_config = &config.buttons[button_position];
+fn get_correct_button_color(context: &IoWorkerContext, button_position: ButtonPosition) -> RGB8 {
+ let button_config = &context.config.buttons[button_position];
if let Some(key_page) = &button_config.key_page {
- if key_page == &state.active_key_page_id {
+ if key_page == &context.state.active_key_page_id {
if let Some(knob_page) = &button_config.knob_page {
- if knob_page == &state.active_knob_page_id {
- return config.active_button_color.into();
+ if knob_page == &context.state.active_knob_page_id {
+ return context.config.active_button_color.into();
}
}
}
@@ -266,7 +276,7 @@ fn get_correct_button_color(config: &model::config::Config, state: &mut State, b
return RGB8::new(0, 0, 0);
}
- config.inactive_button_color.into()
+ context.config.inactive_button_color.into()
}
fn get_key_index_for_position(key_grid: &LoupedeckDeviceKeyGridCharacteristics, position: KeyPosition) -> Option {
@@ -289,32 +299,30 @@ fn get_key_position_for_index(key_grid: &LoupedeckDeviceKeyGridCharacteristics,
}
}
-fn draw_key(device: &LoupedeckDevice, key_grid: &LoupedeckDeviceKeyGridCharacteristics, index: u8, key: Option<&Key>) {
+fn draw_key(context: &IoWorkerContext, index: u8, key: Option<&Key>) {
+ let key_grid = &context.device.characteristics().key_grid;
let (x, y, w, h) = key_grid.get_local_key_rect_xywh(index).unwrap();
- device
- .replace_framebuffer_area_raw(&key_grid.display, x, y, w, h, render_key(w, h, key_grid.display.endianness, key))
- .unwrap();
+ let p = render_key((w, h), key_grid.display.endianness, &context.icons, key);
+ context.device.replace_framebuffer_area_raw(&key_grid.display, x, y, w, h, p).unwrap();
}
-fn draw_key_at_index(device: &LoupedeckDevice, state: &State, index: u8) {
- let key_grid = &device.characteristics().key_grid;
- let position = get_key_position_for_index(key_grid, index);
+fn draw_key_at_index(context: &IoWorkerContext, index: u8) {
+ let position = get_key_position_for_index(&context.device.characteristics().key_grid, index);
- draw_key(device, key_grid, index, state.active_key_page().keys_by_position.get(&position));
+ draw_key(context, index, context.state.active_key_page().keys_by_position.get(&position));
}
-fn draw_key_at_position_if_visible(device: &LoupedeckDevice, state: &State, position: KeyPosition) {
- let key_grid = &device.characteristics().key_grid;
- let index = get_key_index_for_position(key_grid, position);
+fn draw_key_at_position_if_visible(context: &IoWorkerContext, position: KeyPosition) {
+ let index = get_key_index_for_position(&context.device.characteristics().key_grid, position);
if let Some(index) = index {
- draw_key(device, key_grid, index, state.active_key_page().keys_by_position.get(&position));
+ draw_key(context, index, context.state.active_key_page().keys_by_position.get(&position));
}
}
-fn draw_key_at_path_if_visible(device: &LoupedeckDevice, state: &State, path: KeyPath) {
- if state.active_key_page_id == path.page_id {
- draw_key_at_position_if_visible(device, state, path.position);
+fn draw_key_at_path_if_visible(context: &IoWorkerContext, path: KeyPath) {
+ if context.state.active_key_page_id == path.page_id {
+ draw_key_at_position_if_visible(context, path.position);
}
}