From 86e9b072bcb5bb9e0ee52df1d1a30e048084b9c7 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Sun, 2 Apr 2023 16:08:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=81=AF=E6=9D=A1=E6=AE=B5=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/ambient_light/config.rs | 124 +----------------- src-tauri/src/ambient_light/config_manager.rs | 33 +++-- src-tauri/src/screenshot_manager.rs | 17 ++- src/App.tsx | 4 +- src/components/led-strip-part.tsx | 52 +++----- src/components/led-strip-parts-sorter.tsx | 35 +++-- src/models/led-strip-config.ts | 1 + src/stores/led-strip.store.tsx | 9 +- 8 files changed, 89 insertions(+), 186 deletions(-) diff --git a/src-tauri/src/ambient_light/config.rs b/src-tauri/src/ambient_light/config.rs index 841950c..dbd825c 100644 --- a/src-tauri/src/ambient_light/config.rs +++ b/src-tauri/src/ambient_light/config.rs @@ -17,14 +17,6 @@ pub enum Border { Right, } -#[derive(Clone, Copy, Serialize, Deserialize, Debug)] -pub struct LedStripConfigOfBorders { - pub top: Option, - pub bottom: Option, - pub left: Option, - pub right: Option, -} - #[derive(Clone, Copy, Serialize, Deserialize, Debug)] pub struct LedStripConfig { pub index: usize, @@ -119,6 +111,7 @@ impl LedStripConfigGroup { mappers.push(SamplePointMapper { start: (j + i * 4) * 30, end: (j + i * 4 + 1) * 30, + pos: (j + i * 4) * 30, }) } } @@ -126,124 +119,11 @@ impl LedStripConfigGroup { } } -#[derive(Clone, Copy, Serialize, Deserialize, Debug)] -pub struct LedStripConfigOfDisplays { - pub id: u32, - pub index_of_display: usize, - pub led_strip_of_borders: LedStripConfigOfBorders, -} - -impl LedStripConfigOfBorders { - pub fn default() -> Self { - Self { - top: None, - bottom: None, - left: None, - right: None, - } - } -} - -impl LedStripConfigOfDisplays { - pub fn default(id: u32, index_of_display: usize) -> Self { - Self { - id, - index_of_display, - led_strip_of_borders: LedStripConfigOfBorders::default(), - } - } - - pub async fn read_from_disk() -> anyhow::Result { - let path = config_dir() - .unwrap_or(current_dir().unwrap()) - .join("led_strip_config_of_displays.toml"); - - let exists = tokio::fs::try_exists(path.clone()) - .await - .map_err(|e| anyhow::anyhow!("Failed to check config file exists: {}", e))?; - - if exists { - let config = tokio::fs::read_to_string(path).await?; - - let config: Self = toml::from_str(&config) - .map_err(|e| anyhow::anyhow!("Failed to parse config file: {}", e))?; - - Ok(config) - } else { - info!("config file not exist, fallback to default config"); - Ok(Self::get_default_config().await?) - } - } - - pub async fn write_to_disk(&self) -> anyhow::Result<()> { - let path = config_dir() - .unwrap_or(current_dir().unwrap()) - .join("led_strip_config_of_displays.toml"); - - let config = toml::to_string(self).map_err(|e| { - anyhow::anyhow!("Failed to parse config file: {}. config: {:?}", e, self) - })?; - - tokio::fs::write(&path, config).await.map_err(|e| { - anyhow::anyhow!("Failed to write config file: {}. path: {:?}", e, &path) - })?; - - Ok(()) - } - - pub async fn get_default_config() -> anyhow::Result { - let displays = display_info::DisplayInfo::all().map_err(|e| { - error!("can not list display info: {}", e); - anyhow::anyhow!("can not list display info: {}", e) - })?; - - let mut configs = Vec::new(); - for (i, display) in displays.iter().enumerate() { - let config = Self { - id: display.id, - index_of_display: i, - led_strip_of_borders: LedStripConfigOfBorders { - top: Some(LedStripConfig { - index: i * 4 * 30, - display_id: display.id, - border: Border::Top, - start_pos: i * 4 * 30, - len: 30, - }), - bottom: Some(LedStripConfig { - index: i * 4 * 30 + 30, - display_id: display.id, - border: Border::Bottom, - start_pos: i * 4 * 30 + 30, - len: 30, - }), - left: Some(LedStripConfig { - index: i * 4 * 30 + 60, - display_id: display.id, - border: Border::Left, - start_pos: i * 4 * 30 + 60, - len: 30, - }), - right: Some(LedStripConfig { - index: i * 4 * 30 + 90, - display_id: display.id, - border: Border::Right, - start_pos: i * 4 * 30 + 90, - len: 30, - }), - }, - }; - configs.push(config); - } - - Ok(configs[0]) - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SamplePointMapper { pub start: usize, pub end: usize, + pub pos: usize, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/src-tauri/src/ambient_light/config_manager.rs b/src-tauri/src/ambient_light/config_manager.rs index e8f6111..a0dccaf 100644 --- a/src-tauri/src/ambient_light/config_manager.rs +++ b/src-tauri/src/ambient_light/config_manager.rs @@ -122,7 +122,8 @@ impl ConfigManager { log::info!("mapper: {:?}", mapper); } } - log::info!("mapper: {:?}", config.mappers[4]); + + Self::rebuild_mappers(&mut config); let cloned_config = config.clone(); @@ -138,17 +139,31 @@ impl ConfigManager { } fn rebuild_mappers(config: &mut LedStripConfigGroup) { - let mut prev_end = 0; + let mut prev_pos_end = 0; let mappers: Vec = config .strips .iter() - .map(|strip| { - let mapper = SamplePointMapper { - start: prev_end, - end: prev_end + strip.len, - }; - prev_end = mapper.end; - mapper + .enumerate() + .map(|(index, strip)| { + let mapper = &config.mappers[index]; + + if mapper.start < mapper.end { + let mapper = SamplePointMapper { + start: mapper.start, + end: mapper.start + strip.len, + pos: prev_pos_end, + }; + prev_pos_end = prev_pos_end + strip.len; + mapper + } else { + let mapper = SamplePointMapper { + end: mapper.end, + start: mapper.end + strip.len, + pos: prev_pos_end, + }; + prev_pos_end = prev_pos_end + strip.len; + mapper + } }) .collect(); diff --git a/src-tauri/src/screenshot_manager.rs b/src-tauri/src/screenshot_manager.rs index ecd92a4..294846c 100644 --- a/src-tauri/src/screenshot_manager.rs +++ b/src-tauri/src/screenshot_manager.rs @@ -236,22 +236,33 @@ impl ScreenshotManager { pub async fn get_sorted_colors(colors: &Vec, mappers: &Vec) -> Vec { let total_leds = mappers .iter() - .map(|mapper| mapper.end) + .map(|mapper| usize::max(mapper.start, mapper.end)) .max() .unwrap_or(0) as usize; let mut global_colors = vec![0u8; total_leds * 3]; let mut color_index = 0; mappers.iter().for_each(|group| { - if group.end > colors.len() || group.start > colors.len() { + if group.end > global_colors.len() || group.start > global_colors.len() { warn!( - "get_sorted_colors: group out of range. start: {}, end: {}, colors.len(): {}", + "get_sorted_colors: group out of range. start: {}, end: {}, global_colors.len(): {}", group.start, group.end, + global_colors.len() + ); + return; + } + + if color_index + group.start.abs_diff(group.end) > colors.len() { + warn!( + "get_sorted_colors: color_index out of range. color_index: {}, strip len: {}, colors.len(): {}", + color_index, + group.start.abs_diff(group.end), colors.len() ); return; } + if group.end > group.start { for i in group.start..group.end { let rgb = colors[color_index].get_rgb(); diff --git a/src/App.tsx b/src/App.tsx index e8d509b..d596f06 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -44,7 +44,7 @@ function App() { // listen to led_colors_changed event createEffect(() => { - const unlisten = listen('led_colors_changed', (event) => { + const unlisten = listen>('led_colors_changed', (event) => { const colors = event.payload; setLedStripStore({ @@ -59,7 +59,7 @@ function App() { // listen to led_sorted_colors_changed event createEffect(() => { - const unlisten = listen>('led_sorted_colors_changed', (event) => { + const unlisten = listen('led_sorted_colors_changed', (event) => { const sortedColors = event.payload; setLedStripStore({ diff --git a/src/components/led-strip-part.tsx b/src/components/led-strip-part.tsx index 0fa971a..274c1a6 100644 --- a/src/components/led-strip-part.tsx +++ b/src/components/led-strip-part.tsx @@ -16,6 +16,7 @@ import { useTippy } from 'solid-tippy'; import { followCursor } from 'tippy.js'; import { LedStripConfig } from '../models/led-strip-config'; import { LedStripConfigurationContext } from '../contexts/led-strip-configuration.context'; +import { ledStripStore } from '../stores/led-strip.store'; type LedStripPartProps = { config?: LedStripConfig | null; @@ -55,44 +56,31 @@ export const LedStripPart: Component = (props) => { const [ledSamplePoints, setLedSamplePoints] = createSignal(); const [colors, setColors] = createSignal([]); - // get led strip colors when screenshot updated + // update led strip colors from global store createEffect(() => { - const samplePoints = ledSamplePoints(); - if (!localProps.config || !samplePoints) { + if (!localProps.config) { return; } - let pendingCount = 0; - const unlisten = listen<{ - base64_image: string; - display_id: number; - height: number; - width: number; - }>('encoded-screenshot-updated', (event) => { - if (event.payload.display_id !== localProps.config!.display_id) { - return; - } - if (pendingCount >= 1) { - return; - } - pendingCount++; + const index = ledStripStore.strips.findIndex( + (s) => + s.display_id === localProps.config!.display_id && + s.border === localProps.config!.border, + ); - invoke('get_one_edge_colors', { - samplePoints, - displayId: event.payload.display_id, - }) - .then((colors) => { - setColors(colors); - }) - .finally(() => { - pendingCount--; - }); - }); - subscribeScreenshotUpdate(localProps.config.display_id); + if (index === -1) { + return; + } - onCleanup(() => { - unlisten.then((unlisten) => unlisten()); - }); + const mapper = ledStripStore.mappers[index]; + if (!mapper) { + return; + } + + const offset = mapper.pos; + + const colors = ledStripStore.colors.slice(offset, offset + localProps.config.len); + setColors(colors); }); // get led strip sample points diff --git a/src/components/led-strip-parts-sorter.tsx b/src/components/led-strip-parts-sorter.tsx index b4e763a..244d502 100644 --- a/src/components/led-strip-parts-sorter.tsx +++ b/src/components/led-strip-parts-sorter.tsx @@ -12,21 +12,18 @@ import { LedStripConfig, LedStripPixelMapper } from '../models/led-strip-config' import { ledStripStore } from '../stores/led-strip.store'; import { invoke } from '@tauri-apps/api'; import { LedStripConfigurationContext } from '../contexts/led-strip-configuration.context'; +import background from '../assets/transparent-grid-background.svg?url'; const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper }> = ( props, ) => { - const [fullLeds, setFullLeds] = createSignal([]); + const [fullLeds, setFullLeds] = createSignal>([]); const [dragging, setDragging] = createSignal(false); const [dragStart, setDragStart] = createSignal<{ x: number; y: number } | null>(null); const [dragCurr, setDragCurr] = createSignal<{ x: number; y: number } | null>(null); const [dragStartIndex, setDragStartIndex] = createSignal(0); const [, { setSelectedStripPart }] = useContext(LedStripConfigurationContext); - const totalLedCount = createMemo(() => { - return ledStripStore.strips.reduce((acc, strip) => acc + strip.len, 0); - }); - const move = (targetStart: number) => { if (targetStart === props.mapper.start) { return; @@ -70,7 +67,8 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper } setDragCurr({ x: ev.clientX, y: ev.clientY }); - const cellWidth = (ev.currentTarget as HTMLDivElement).clientWidth / totalLedCount(); + const cellWidth = + (ev.currentTarget as HTMLDivElement).clientWidth / ledStripStore.totalLedCount; const diff = ev.clientX - dragStart()!.x; const moved = Math.round(diff / cellWidth); if (moved === 0) { @@ -85,9 +83,13 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper // update fullLeds createEffect(() => { - const fullLeds = new Array(totalLedCount()).fill('rgba(255,255,255,0.5)'); + const fullLeds = new Array(ledStripStore.totalLedCount).fill(null); - for (let i = props.mapper.start, j = 0; i < props.mapper.end; i++, j++) { + for ( + let i = props.mapper.start, j = props.mapper.pos; + i < props.mapper.end; + i++, j++ + ) { fullLeds[i] = ledStripStore.colors[j]; } setFullLeds(fullLeds); @@ -112,11 +114,12 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper {(it) => (
)} @@ -129,8 +132,7 @@ const SorterResult: Component = () => { const [fullLeds, setFullLeds] = createSignal([]); createEffect(() => { - const totalLedCount = Math.max(0, ...ledStripStore.mappers.map((m) => m.end)); - const fullLeds = new Array(totalLedCount).fill('rgba(255,255,255,0.5)'); + const fullLeds = new Array(ledStripStore.totalLedCount).fill('rgba(255,255,255,0.1)'); ledStripStore.mappers.forEach((mapper) => { for (let i = mapper.start, j = 0; i < mapper.end; i++, j++) { @@ -165,7 +167,12 @@ export const LedStripPartsSorter: Component = () => { const context = createContext(); return ( -
+
{(strip, index) => ( diff --git a/src/models/led-strip-config.ts b/src/models/led-strip-config.ts index 1bdd25a..f5215f6 100644 --- a/src/models/led-strip-config.ts +++ b/src/models/led-strip-config.ts @@ -3,6 +3,7 @@ import { Borders } from '../constants/border'; export type LedStripPixelMapper = { start: number; end: number; + pos: number; }; export type LedStripConfigContainer = { diff --git a/src/stores/led-strip.store.tsx b/src/stores/led-strip.store.tsx index e4a2d2b..35153c0 100644 --- a/src/stores/led-strip.store.tsx +++ b/src/stores/led-strip.store.tsx @@ -1,11 +1,12 @@ import { createStore } from 'solid-js/store'; -import { DisplayConfig } from '../models/display-config'; import { LedStripConfig, LedStripPixelMapper } from '../models/led-strip-config'; export const [ledStripStore, setLedStripStore] = createStore({ - displays: new Array(), strips: new Array(), mappers: new Array(), - colors: new Uint8ClampedArray(), - sortedColors: new Array(), + colors: new Array(), + sortedColors: new Uint8ClampedArray(), + get totalLedCount() { + return Math.max(0, ...ledStripStore.mappers.map((m) => Math.max(m.start, m.end))); + }, });