feat: 支持将色彩校准的值写入本地配置文件。
This commit is contained in:
parent
fc8b3164d8
commit
6e6160fc0a
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -2,7 +2,8 @@
|
|||||||
"files.autoSave": "onWindowChange",
|
"files.autoSave": "onWindowChange",
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"Itertools",
|
"Itertools",
|
||||||
"Leds"
|
"Leds",
|
||||||
|
"unlisten"
|
||||||
],
|
],
|
||||||
"idf.customExtraVars": {
|
"idf.customExtraVars": {
|
||||||
"OPENOCD_SCRIPTS": "/Users/ivan/.espressif/tools/openocd-esp32/v0.11.0-esp32-20211220/openocd-esp32/share/openocd/scripts"
|
"OPENOCD_SCRIPTS": "/Users/ivan/.espressif/tools/openocd-esp32/v0.11.0-esp32-20211220/openocd-esp32/share/openocd/scripts"
|
||||||
|
7
.vscode/tasks.json
vendored
7
.vscode/tasks.json
vendored
@ -14,7 +14,12 @@
|
|||||||
],
|
],
|
||||||
"problemMatcher": [
|
"problemMatcher": [
|
||||||
"$eslint-stylish"
|
"$eslint-stylish"
|
||||||
]
|
],
|
||||||
|
"options": {
|
||||||
|
"env": {
|
||||||
|
"RUST_LOG": "info"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "ui:dev",
|
"label": "ui:dev",
|
||||||
|
@ -5,7 +5,7 @@ use paris::{error, info};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::api::path::config_dir;
|
use tauri::api::path::config_dir;
|
||||||
|
|
||||||
use crate::screenshot::{self, LedSamplePoints};
|
use crate::screenshot::LedSamplePoints;
|
||||||
|
|
||||||
const CONFIG_FILE_NAME: &str = "cc.ivanli.ambient_light/led_strip_config.toml";
|
const CONFIG_FILE_NAME: &str = "cc.ivanli.ambient_light/led_strip_config.toml";
|
||||||
|
|
||||||
@ -26,10 +26,18 @@ pub struct LedStripConfig {
|
|||||||
pub len: usize,
|
pub len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ColorCalibration {
|
||||||
|
r: f32,
|
||||||
|
g: f32,
|
||||||
|
b: f32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
pub struct LedStripConfigGroup {
|
pub struct LedStripConfigGroup {
|
||||||
pub strips: Vec<LedStripConfig>,
|
pub strips: Vec<LedStripConfig>,
|
||||||
pub mappers: Vec<SamplePointMapper>,
|
pub mappers: Vec<SamplePointMapper>,
|
||||||
|
pub color_calibration: ColorCalibration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LedStripConfigGroup {
|
impl LedStripConfigGroup {
|
||||||
@ -115,7 +123,17 @@ impl LedStripConfigGroup {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Self { strips, mappers })
|
let color_calibration = ColorCalibration {
|
||||||
|
r: 1.0,
|
||||||
|
g: 1.0,
|
||||||
|
b: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
strips,
|
||||||
|
mappers,
|
||||||
|
color_calibration,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use tokio::sync::OnceCell;
|
|||||||
|
|
||||||
use crate::ambient_light::{config, LedStripConfigGroup};
|
use crate::ambient_light::{config, LedStripConfigGroup};
|
||||||
|
|
||||||
use super::{Border, SamplePointMapper};
|
use super::{Border, SamplePointMapper, ColorCalibration};
|
||||||
|
|
||||||
pub struct ConfigManager {
|
pub struct ConfigManager {
|
||||||
config: Arc<RwLock<LedStripConfigGroup>>,
|
config: Arc<RwLock<LedStripConfigGroup>>,
|
||||||
@ -223,4 +223,15 @@ impl ConfigManager {
|
|||||||
) -> tokio::sync::watch::Receiver<LedStripConfigGroup> {
|
) -> tokio::sync::watch::Receiver<LedStripConfigGroup> {
|
||||||
self.config_update_receiver.clone()
|
self.config_update_receiver.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn set_color_calibration(&self, color_calibration: ColorCalibration) -> anyhow::Result<()> {
|
||||||
|
let config = self.config.write().await;
|
||||||
|
|
||||||
|
let mut cloned_config = config.clone();
|
||||||
|
cloned_config.color_calibration = color_calibration;
|
||||||
|
|
||||||
|
drop(config);
|
||||||
|
|
||||||
|
self.update(&cloned_config).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ impl LedColorsPublisher {
|
|||||||
warn!("Failed to send sorted colors: {}", err);
|
warn!("Failed to send sorted colors: {}", err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
log::info!("tick: {}ms", start.elapsed().as_millis());
|
log::debug!("tick: {}ms", start.elapsed().as_millis());
|
||||||
start = tokio::time::Instant::now();
|
start = tokio::time::Instant::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,9 @@ mod rpc;
|
|||||||
pub mod screenshot;
|
pub mod screenshot;
|
||||||
mod screenshot_manager;
|
mod screenshot_manager;
|
||||||
|
|
||||||
use ambient_light::{Border, LedColorsPublisher, LedStripConfig, LedStripConfigGroup};
|
use ambient_light::{
|
||||||
|
Border, ColorCalibration, LedColorsPublisher, LedStripConfig, LedStripConfigGroup,
|
||||||
|
};
|
||||||
use core_graphics::display::{
|
use core_graphics::display::{
|
||||||
kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay,
|
kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay,
|
||||||
};
|
};
|
||||||
@ -145,14 +147,14 @@ async fn send_colors(buffer: Vec<u8>) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn move_strip_part(display_id: u32, border: Border, target_start: usize) -> Result<(), String> {
|
async fn move_strip_part(
|
||||||
|
display_id: u32,
|
||||||
|
border: Border,
|
||||||
|
target_start: usize,
|
||||||
|
) -> Result<(), String> {
|
||||||
let config_manager = ambient_light::ConfigManager::global().await;
|
let config_manager = ambient_light::ConfigManager::global().await;
|
||||||
config_manager
|
config_manager
|
||||||
.move_strip_part(
|
.move_strip_part(display_id, border, target_start)
|
||||||
display_id,
|
|
||||||
border,
|
|
||||||
target_start,
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("can not move strip part: {}", e);
|
error!("can not move strip part: {}", e);
|
||||||
@ -172,6 +174,18 @@ async fn reverse_led_strip_part(display_id: u32, border: Border) -> Result<(), S
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn set_color_calibration(calibration: ColorCalibration) -> Result<(), String> {
|
||||||
|
let config_manager = ambient_light::ConfigManager::global().await;
|
||||||
|
config_manager
|
||||||
|
.set_color_calibration(calibration)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
error!("can not set color calibration: {}", e);
|
||||||
|
e.to_string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
@ -194,6 +208,7 @@ async fn main() {
|
|||||||
send_colors,
|
send_colors,
|
||||||
move_strip_part,
|
move_strip_part,
|
||||||
reverse_led_strip_part,
|
reverse_led_strip_part,
|
||||||
|
set_color_calibration,
|
||||||
])
|
])
|
||||||
.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", "*");
|
||||||
@ -359,6 +374,7 @@ async fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let app_handle = app.handle().clone();
|
let app_handle = app.handle().clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let publisher = ambient_light::LedColorsPublisher::global().await;
|
let publisher = ambient_light::LedColorsPublisher::global().await;
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
import { Component, JSX } from 'solid-js';
|
import { Component, JSX } from 'solid-js';
|
||||||
|
|
||||||
type Props = {} & JSX.HTMLAttributes<HTMLInputElement>;
|
type Props = {
|
||||||
|
value?: number;
|
||||||
|
} & JSX.HTMLAttributes<HTMLInputElement>;
|
||||||
|
|
||||||
export const ColorSlider: Component<Props> = (props) => {
|
export const ColorSlider: Component<Props> = (props) => {
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
value="50"
|
|
||||||
{...props}
|
{...props}
|
||||||
|
max={1}
|
||||||
|
min={0}
|
||||||
|
step={0.01}
|
||||||
|
value={props.value}
|
||||||
class={
|
class={
|
||||||
'w-full h-2 bg-gradient-to-r rounded-lg appearance-none cursor-pointer dark:bg-gray-700 drop-shadow ' +
|
'w-full h-2 bg-gradient-to-r rounded-lg appearance-none cursor-pointer dark:bg-gray-700 drop-shadow ' +
|
||||||
props.class
|
props.class
|
||||||
|
@ -1,7 +1,38 @@
|
|||||||
|
import { listen } from '@tauri-apps/api/event';
|
||||||
|
import { createEffect, onCleanup } from 'solid-js';
|
||||||
|
import { ColorCalibration, LedStripConfigContainer } from '../../models/led-strip-config';
|
||||||
|
import { ledStripStore, setLedStripStore } from '../../stores/led-strip.store';
|
||||||
import { ColorSlider } from './color-slider';
|
import { ColorSlider } from './color-slider';
|
||||||
import { TestColorsBg } from './test-colors-bg';
|
import { TestColorsBg } from './test-colors-bg';
|
||||||
|
import { invoke } from '@tauri-apps/api';
|
||||||
|
|
||||||
export const WhiteBalance = () => {
|
export const WhiteBalance = () => {
|
||||||
|
// listen to config_changed event
|
||||||
|
createEffect(() => {
|
||||||
|
const unlisten = listen('config_changed', (event) => {
|
||||||
|
const { strips, mappers, color_calibration } =
|
||||||
|
event.payload as LedStripConfigContainer;
|
||||||
|
console.log(event.payload);
|
||||||
|
setLedStripStore({
|
||||||
|
strips,
|
||||||
|
mappers,
|
||||||
|
colorCalibration: color_calibration,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onCleanup(() => {
|
||||||
|
unlisten.then((unlisten) => unlisten());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateColorCalibration = (field: keyof ColorCalibration, value: number) => {
|
||||||
|
const calibration = { ...ledStripStore.colorCalibration, [field]: value };
|
||||||
|
console.log(field, calibration);
|
||||||
|
invoke('set_color_calibration', {
|
||||||
|
calibration,
|
||||||
|
}).catch((error) => console.log(error));
|
||||||
|
};
|
||||||
|
|
||||||
const exit = () => {
|
const exit = () => {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
};
|
};
|
||||||
@ -14,15 +45,42 @@ export const WhiteBalance = () => {
|
|||||||
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-10/12 max-w-lg bg-stone-200 p-5 rounded-xl drop-shadow">
|
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-10/12 max-w-lg bg-stone-200 p-5 rounded-xl drop-shadow">
|
||||||
<label class="flex items-center gap-2">
|
<label class="flex items-center gap-2">
|
||||||
<span class="w-3 block">R:</span>
|
<span class="w-3 block">R:</span>
|
||||||
<ColorSlider class="from-cyan-500 to-red-500" />
|
<ColorSlider
|
||||||
|
class="from-cyan-500 to-red-500"
|
||||||
|
value={ledStripStore.colorCalibration.r}
|
||||||
|
onInput={(ev) =>
|
||||||
|
updateColorCalibration(
|
||||||
|
'r',
|
||||||
|
(ev.target as HTMLInputElement).valueAsNumber ?? 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2">
|
<label class="flex items-center gap-2">
|
||||||
<span class="w-3 block">G:</span>
|
<span class="w-3 block">G:</span>
|
||||||
<ColorSlider class="from-pink-500 to-green-500" />
|
<ColorSlider
|
||||||
|
class="from-pink-500 to-green-500"
|
||||||
|
value={ledStripStore.colorCalibration.g}
|
||||||
|
onInput={(ev) =>
|
||||||
|
updateColorCalibration(
|
||||||
|
'g',
|
||||||
|
(ev.target as HTMLInputElement).valueAsNumber ?? 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2">
|
<label class="flex items-center gap-2">
|
||||||
<span class="w-3 block">B:</span>
|
<span class="w-3 block">B:</span>
|
||||||
<ColorSlider class="from-yellow-500 to-blue-500" />
|
<ColorSlider
|
||||||
|
class="from-yellow-500 to-blue-500"
|
||||||
|
value={ledStripStore.colorCalibration.b}
|
||||||
|
onInput={(ev) =>
|
||||||
|
updateColorCalibration(
|
||||||
|
'b',
|
||||||
|
(ev.target as HTMLInputElement).valueAsNumber ?? 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2">
|
<label class="flex items-center gap-2">
|
||||||
<span class="w-3 block">W:</span>
|
<span class="w-3 block">W:</span>
|
||||||
|
@ -6,9 +6,16 @@ export type LedStripPixelMapper = {
|
|||||||
pos: number;
|
pos: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class ColorCalibration {
|
||||||
|
r: number = 1;
|
||||||
|
g: number = 1;
|
||||||
|
b: number = 1;
|
||||||
|
}
|
||||||
|
|
||||||
export type LedStripConfigContainer = {
|
export type LedStripConfigContainer = {
|
||||||
strips: LedStripConfig[];
|
strips: LedStripConfig[];
|
||||||
mappers: LedStripPixelMapper[];
|
mappers: LedStripPixelMapper[];
|
||||||
|
color_calibration: ColorCalibration;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class LedStripConfig {
|
export class LedStripConfig {
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
import { createStore } from 'solid-js/store';
|
import { createStore } from 'solid-js/store';
|
||||||
import { LedStripConfig, LedStripPixelMapper } from '../models/led-strip-config';
|
import {
|
||||||
|
ColorCalibration,
|
||||||
|
LedStripConfig,
|
||||||
|
LedStripPixelMapper,
|
||||||
|
} from '../models/led-strip-config';
|
||||||
|
|
||||||
export const [ledStripStore, setLedStripStore] = createStore({
|
export const [ledStripStore, setLedStripStore] = createStore({
|
||||||
strips: new Array<LedStripConfig>(),
|
strips: new Array<LedStripConfig>(),
|
||||||
mappers: new Array<LedStripPixelMapper>(),
|
mappers: new Array<LedStripPixelMapper>(),
|
||||||
|
colorCalibration: new ColorCalibration(),
|
||||||
colors: new Uint8ClampedArray(),
|
colors: new Uint8ClampedArray(),
|
||||||
sortedColors: new Uint8ClampedArray(),
|
sortedColors: new Uint8ClampedArray(),
|
||||||
get totalLedCount() {
|
get totalLedCount() {
|
||||||
|
Loading…
Reference in New Issue
Block a user