Compare commits

...

2 Commits

6 changed files with 122 additions and 43 deletions

View File

@ -123,7 +123,35 @@ impl ConfigManager {
} }
} }
Self::rebuild_mappers(&mut config); let cloned_config = config.clone();
drop(config);
self.update(&cloned_config).await?;
self.config_update_sender
.send(cloned_config)
.map_err(|e| anyhow::anyhow!("Failed to send config update: {}", e))?;
Ok(())
}
pub async fn reverse_led_strip_part(
&self,
display_id: u32,
border: Border,
) -> anyhow::Result<()> {
let mut config = self.config.write().await;
for (index, strip) in config.clone().strips.iter().enumerate() {
if strip.display_id == display_id && strip.border == border {
let mut mapper = config.mappers[index].borrow_mut();
let start = mapper.start;
mapper.start = mapper.end;
mapper.end = start;
}
}
let cloned_config = config.clone(); let cloned_config = config.clone();

View File

@ -175,6 +175,18 @@ async fn move_strip_part(display_id: u32, border: Border, target_start: usize) -
}) })
} }
#[tauri::command]
async fn reverse_led_strip_part(display_id: u32, border: Border) -> Result<(), String> {
let config_manager = ambient_light::ConfigManager::global().await;
config_manager
.reverse_led_strip_part(display_id, border)
.await
.map_err(|e| {
error!("can not reverse led strip part: {}", e);
e.to_string()
})
}
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
env_logger::init(); env_logger::init();
@ -197,6 +209,7 @@ async fn main() {
patch_led_strip_len, patch_led_strip_len,
send_colors, send_colors,
move_strip_part, move_strip_part,
reverse_led_strip_part,
]) ])
.register_uri_scheme_protocol("ambient-light", move |_app, request| { .register_uri_scheme_protocol("ambient-light", move |_app, request| {
let response = ResponseBuilder::new().header("Access-Control-Allow-Origin", "*"); let response = ResponseBuilder::new().header("Access-Control-Allow-Origin", "*");

View File

@ -4,13 +4,13 @@ use core_graphics::display::{
kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay, kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay,
}; };
use paris::{error, info, warn}; use paris::{error, info, warn};
use serde::{Deserialize, Serialize};
use tauri::{async_runtime::RwLock, Window}; use tauri::{async_runtime::RwLock, Window};
use tokio::sync::{watch, OnceCell}; use tokio::sync::{watch, OnceCell};
use crate::{ use crate::{
ambient_light::{SamplePointConfig, SamplePointMapper}, ambient_light::{SamplePointConfig, SamplePointMapper},
screenshot::{LedSamplePoints, ScreenSamplePoints, Screenshot, ScreenshotPayload}, led_color::LedColor, led_color::LedColor,
screenshot::{ScreenSamplePoints, Screenshot, ScreenshotPayload},
}; };
pub fn take_screenshot(display_id: u32, scale_factor: f32) -> anyhow::Result<Screenshot> { pub fn take_screenshot(display_id: u32, scale_factor: f32) -> anyhow::Result<Screenshot> {
@ -220,7 +220,6 @@ impl ScreenshotManager {
configs: &Vec<SamplePointConfig>, configs: &Vec<SamplePointConfig>,
screenshots: &Vec<Screenshot>, screenshots: &Vec<Screenshot>,
) -> Vec<LedColor> { ) -> Vec<LedColor> {
let mut all_colors = vec![]; let mut all_colors = vec![];
for (index, screenshot) in screenshots.iter().enumerate() { for (index, screenshot) in screenshots.iter().enumerate() {
@ -233,7 +232,10 @@ impl ScreenshotManager {
all_colors all_colors
} }
pub async fn get_sorted_colors(colors: &Vec<LedColor>, mappers: &Vec<SamplePointMapper>) -> Vec<u8> { pub async fn get_sorted_colors(
colors: &Vec<LedColor>,
mappers: &Vec<SamplePointMapper>,
) -> Vec<u8> {
let total_leds = mappers let total_leds = mappers
.iter() .iter()
.map(|mapper| usize::max(mapper.start, mapper.end)) .map(|mapper| usize::max(mapper.start, mapper.end))

View File

@ -1,11 +1,15 @@
import { import {
batch,
Component, Component,
createContext, createContext,
createEffect, createEffect,
createMemo, createMemo,
createSignal, createSignal,
For, For,
Index,
JSX, JSX,
on,
untrack,
useContext, useContext,
} from 'solid-js'; } from 'solid-js';
import { LedStripConfig, LedStripPixelMapper } from '../models/led-strip-config'; import { LedStripConfig, LedStripPixelMapper } from '../models/led-strip-config';
@ -22,13 +26,13 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper
const [dragStart, setDragStart] = createSignal<{ x: number; y: number } | null>(null); const [dragStart, setDragStart] = createSignal<{ x: number; y: number } | null>(null);
const [dragCurr, setDragCurr] = createSignal<{ x: number; y: number } | null>(null); const [dragCurr, setDragCurr] = createSignal<{ x: number; y: number } | null>(null);
const [dragStartIndex, setDragStartIndex] = createSignal<number>(0); const [dragStartIndex, setDragStartIndex] = createSignal<number>(0);
const [cellWidth, setCellWidth] = createSignal<number>(0);
const [, { setSelectedStripPart }] = useContext(LedStripConfigurationContext); const [, { setSelectedStripPart }] = useContext(LedStripConfigurationContext);
const move = (targetStart: number) => { const move = (targetStart: number) => {
if (targetStart === props.mapper.start) { if (targetStart === props.mapper.start) {
return; return;
} }
console.log(`target_start ${targetStart}`);
invoke('move_strip_part', { invoke('move_strip_part', {
displayId: props.strip.display_id, displayId: props.strip.display_id,
border: props.strip.border, border: props.strip.border,
@ -36,6 +40,25 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper
}).catch((err) => console.error(err)); }).catch((err) => console.error(err));
}; };
// reset translateX on config updated
createEffect(() => {
const indexDiff = props.mapper.start - dragStartIndex();
untrack(() => {
if (!dragStart() || !dragCurr()) {
return;
}
const compensation = indexDiff * cellWidth();
batch(() => {
setDragStartIndex(props.mapper.start);
setDragStart({
x: dragStart()!.x + compensation,
y: dragCurr()!.y,
});
});
});
});
const onPointerDown = (ev: PointerEvent) => { const onPointerDown = (ev: PointerEvent) => {
if (ev.button !== 0) { if (ev.button !== 0) {
return; return;
@ -74,6 +97,7 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper
if (moved === 0) { if (moved === 0) {
return; return;
} }
setCellWidth(cellWidth);
move(props.mapper.start + moved); move(props.mapper.start + moved);
}; };
@ -81,17 +105,43 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper
setSelectedStripPart(null); setSelectedStripPart(null);
}; };
const reverse = () => {
invoke('reverse_led_strip_part', {
displayId: props.strip.display_id,
border: props.strip.border,
}).catch((err) => console.error(err));
};
// update fullLeds // update fullLeds
createEffect(() => { createEffect(() => {
const fullLeds = new Array(ledStripStore.totalLedCount).fill(null); const fullLeds = new Array(ledStripStore.totalLedCount).fill(null);
for ( // if (props.mapper.start < props.mapper.end) {
let i = props.mapper.start, j = props.mapper.pos; // for (
i < props.mapper.end; // let i = props.mapper.start, j = props.mapper.pos;
i++, j++ // i < props.mapper.end;
) { // i++, j++
// ) {
// fullLeds[i] = ledStripStore.colors[j];
// }
// } else {
// for (
// let i = props.mapper.start, j = props.mapper.pos;
// i >= props.mapper.end;
// i--, j++
// ) {
// fullLeds[i] = ledStripStore.colors[j];
// }
// }
// 优化上面的代码
const { start, end, pos } = props.mapper;
const isForward = start < end;
const step = isForward ? 1 : -1;
for (let i = start, j = pos; i !== end; i += step, j++) {
fullLeds[i] = ledStripStore.colors[j]; fullLeds[i] = ledStripStore.colors[j];
} }
setFullLeds(fullLeds); setFullLeds(fullLeds);
}); });
@ -109,6 +159,7 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper
onPointerDown={onPointerDown} onPointerDown={onPointerDown}
onPointerUp={onPointerUp} onPointerUp={onPointerUp}
onPointerLeave={onPointerLeave} onPointerLeave={onPointerLeave}
ondblclick={reverse}
> >
<For each={fullLeds()}> <For each={fullLeds()}>
{(it) => ( {(it) => (
@ -132,15 +183,20 @@ const SorterResult: Component = () => {
const [fullLeds, setFullLeds] = createSignal<string[]>([]); const [fullLeds, setFullLeds] = createSignal<string[]>([]);
createEffect(() => { createEffect(() => {
const fullLeds = new Array(ledStripStore.totalLedCount).fill('rgba(255,255,255,0.1)'); const colors = ledStripStore.sortedColors;
const fullLeds = new Array(ledStripStore.totalLedCount)
.fill('rgba(255,255,255,0.1)')
.map((_, i) => {
let c1 = `rgb(${Math.floor(colors[i * 3] * 0.8)}, ${Math.floor(
colors[i * 3 + 1] * 0.8,
)}, ${Math.floor(colors[i * 3 + 2] * 0.8)})`;
let c2 = `rgb(${Math.floor(colors[i * 3] * 1.2)}, ${Math.floor(
colors[i * 3 + 1] * 1.2,
)}, ${Math.floor(colors[i * 3 + 2] * 1.2)})`;
ledStripStore.mappers.forEach((mapper) => { return `linear-gradient(70deg, ${c1}, ${c2})`;
for (let i = mapper.start, j = 0; i < mapper.end; i++, j++) { });
fullLeds[i] = `rgb(${ledStripStore.sortedColors[i * 3]}, ${ console.log(fullLeds);
ledStripStore.sortedColors[i * 3 + 1]
}, ${ledStripStore.sortedColors[i * 3 + 2]})`;
}
});
setFullLeds(fullLeds); setFullLeds(fullLeds);
}); });
@ -174,11 +230,11 @@ export const LedStripPartsSorter: Component = () => {
}} }}
> >
<SorterResult /> <SorterResult />
<For each={ledStripStore.strips}> <Index each={ledStripStore.strips}>
{(strip, index) => ( {(strip, index) => (
<SorterItem strip={strip} mapper={ledStripStore.mappers[index()]} /> <SorterItem strip={strip()} mapper={ledStripStore.mappers[index]} />
)} )}
</For> </Index>
</div> </div>
); );
}; };

View File

@ -1,8 +0,0 @@
import { DisplayConfig } from './display-config';
export class PickerConfiguration {
constructor(
public display_configs: DisplayConfig[] = [],
public config_version: number = 1,
) {}
}

View File

@ -1,12 +0,0 @@
import { DisplayConfig } from './display-config';
export class ScreenshotDto {
encode_image!: string;
config!: DisplayConfig;
colors!: {
top: Uint8Array;
bottom: Uint8Array;
left: Uint8Array;
right: Uint8Array;
};
}