@ -1,5 +1,5 @@
import { listen } from '@tauri-apps/api/event' ;
import { Component , createEffect , onCleanup } from 'solid-js' ;
import { Component , createEffect , onCleanup , createSignal } from 'solid-js' ;
import { ColorCalibration , LedStripConfigContainer } from '../../models/led-strip-config' ;
import { ledStripStore , setLedStripStore } from '../../stores/led-strip.store' ;
import { ColorSlider } from './color-slider' ;
@ -7,6 +7,8 @@ import { TestColorsBg } from './test-colors-bg';
import { invoke } from '@tauri-apps/api/core' ;
import { VsClose } from 'solid-icons/vs' ;
import { BiRegularReset } from 'solid-icons/bi' ;
import { BsFullscreen , BsFullscreenExit } from 'solid-icons/bs' ;
import { getCurrentWindow } from '@tauri-apps/api/window' ;
import transparentBg from '../../assets/transparent-grid-background.svg?url' ;
const Value : Component < { value : number } > = ( props ) = > {
@ -18,6 +20,82 @@ const Value: Component<{ value: number }> = (props) => {
} ;
export const WhiteBalance = ( ) = > {
const [ isFullscreen , setIsFullscreen ] = createSignal ( false ) ;
const [ panelPosition , setPanelPosition ] = createSignal ( { x : 0 , y : 0 } ) ;
const [ isDragging , setIsDragging ] = createSignal ( false ) ;
const [ dragOffset , setDragOffset ] = createSignal ( { x : 0 , y : 0 } ) ;
// 自动进入全屏模式
createEffect ( ( ) = > {
const autoEnterFullscreen = async ( ) = > {
try {
const window = getCurrentWindow ( ) ;
const currentFullscreen = await window . isFullscreen ( ) ;
if ( ! currentFullscreen ) {
await window . setFullscreen ( true ) ;
setIsFullscreen ( true ) ;
} else {
setIsFullscreen ( true ) ;
}
} catch ( error ) {
console . error ( 'Failed to auto enter fullscreen:' , error ) ;
}
} ;
autoEnterFullscreen ( ) ;
} ) ;
// 初始化面板位置到屏幕中央
createEffect ( ( ) = > {
if ( isFullscreen ( ) ) {
const centerX = window . innerWidth / 2 - 160 ; // 160是面板宽度的一半
const centerY = window . innerHeight / 2 - 200 ; // 200是面板高度的一半
setPanelPosition ( { x : centerX , y : centerY } ) ;
}
} ) ;
// 拖拽处理函数
const handleMouseDown = ( e : MouseEvent ) = > {
setIsDragging ( true ) ;
const rect = ( e . currentTarget as HTMLElement ) . getBoundingClientRect ( ) ;
setDragOffset ( {
x : e.clientX - rect . left ,
y : e.clientY - rect . top
} ) ;
e . preventDefault ( ) ;
} ;
const handleMouseMove = ( e : MouseEvent ) = > {
if ( isDragging ( ) ) {
const newX = e . clientX - dragOffset ( ) . x ;
const newY = e . clientY - dragOffset ( ) . y ;
// 限制面板在屏幕范围内
const maxX = window . innerWidth - 320 ; // 320是面板宽度
const maxY = window . innerHeight - 400 ; // 400是面板高度
setPanelPosition ( {
x : Math.max ( 0 , Math . min ( newX , maxX ) ) ,
y : Math.max ( 0 , Math . min ( newY , maxY ) )
} ) ;
}
} ;
const handleMouseUp = ( ) = > {
setIsDragging ( false ) ;
} ;
// 添加全局鼠标事件监听
createEffect ( ( ) = > {
if ( isDragging ( ) ) {
document . addEventListener ( 'mousemove' , handleMouseMove ) ;
document . addEventListener ( 'mouseup' , handleMouseUp ) ;
} else {
document . removeEventListener ( 'mousemove' , handleMouseMove ) ;
document . removeEventListener ( 'mouseup' , handleMouseUp ) ;
}
} ) ;
// listen to config_changed event
createEffect ( ( ) = > {
const unlisten = listen ( 'config_changed' , ( event ) = > {
@ -31,20 +109,48 @@ export const WhiteBalance = () => {
} ) ;
} ) ;
onCleanup ( ( ) = > {
unlisten . then ( ( unlisten ) = > unlisten ( ) ) ;
onCleanup ( async ( ) = > {
( await unlisten ) ( ) ;
} ) ;
} ) ;
const updateColorCalibration = ( field : keyof ColorCalibration , value : number ) = > {
const calibration = { . . . ledStripStore . colorCalibration , [ field ] : value } ;
invoke ( 'set_color_calibration' , {
calibration ,
} ) . catch ( ( error ) = > console . log ( error ) ) ;
const updateColorCalibration = (
key : keyof ColorCalibration ,
value : number ,
) = > {
const calibration = { . . . ledStripStore . colorCalibration } ;
calibration [ key ] = value ;
setLedStripStore ( 'colorCalibration' , calibration ) ;
invoke ( 'set_color_calibration' , { calibration } ) . catch ( ( error ) = >
console . log ( error ) ,
) ;
} ;
const toggleFullscreen = async ( ) = > {
try {
const window = getCurrentWindow ( ) ;
const currentFullscreen = await window . isFullscreen ( ) ;
await window . setFullscreen ( ! currentFullscreen ) ;
setIsFullscreen ( ! currentFullscreen ) ;
// 退出全屏时重置面板位置
if ( currentFullscreen ) {
setPanelPosition ( { x : 0 , y : 0 } ) ;
}
} catch ( error ) {
console . error ( 'Failed to toggle fullscreen:' , error ) ;
}
} ;
const exit = ( ) = > {
// 退出时确保退出全屏模式
if ( isFullscreen ( ) ) {
toggleFullscreen ( ) . then ( ( ) = > {
window . history . back ( ) ;
} ) ;
} else {
window . history . back ( ) ;
}
} ;
const reset = ( ) = > {
@ -54,10 +160,17 @@ export const WhiteBalance = () => {
} ;
return (
< >
{ /* 普通模式 */ }
{ ! isFullscreen ( ) && (
< div class = "space-y-6" >
< div class = "flex items-center justify-between" >
< h1 class = "text-2xl font-bold text-base-content" > 白 平 衡 调 节 < / h1 >
< div class = "flex gap-2" >
< button class = "btn btn-outline btn-sm" onClick = { toggleFullscreen } title = "进入全屏" >
< BsFullscreen size = { 16 } / >
全 屏
< / button >
< button class = "btn btn-outline btn-sm" onClick = { reset } title = "重置到100%" >
< BiRegularReset size = { 16 } / >
重 置
@ -160,12 +273,160 @@ export const WhiteBalance = () => {
< / div >
< / div >
< div class = "text-xs text-base-content/50 mt-4" >
💡 提 示 : 调 节 RGB滑块来校正LED灯条的白平衡 , 使 白 色 更 加 纯 净
{ /* 使用说明 - 可展开 */ }
< div class = "collapse collapse-arrow bg-base-100 mt-4" >
< input type = "checkbox" / >
< div class = "collapse-title text-sm font-medium text-base-content/80" >
💡 白 平 衡 调 节 使 用 说 明
< / div >
< div class = "collapse-content text-xs text-base-content/70 space-y-3" >
< div class = "space-y-2" >
< p class = "font-semibold text-primary" > 🎯 推 荐 使 用 方 法 : < / p >
< ol class = "list-decimal list-inside space-y-1 ml-2" >
< li > 点 击 上 方 "全屏" 按 钮 进 入 全 屏 模 式 < / li >
< li > 全 屏 模 式 下 屏 幕 边 缘 会 显 示 彩 色 条 带 < / li >
< li > 将 RGB控制面板拖拽到合适位置 < / li >
< li > 对 比 LED灯条颜色与屏幕边缘颜色 < / li >
< / ol >
< / div >
< div class = "space-y-2" >
< p class = "font-semibold text-secondary" > 🔧 调 节 技 巧 : < / p >
< ul class = "list-disc list-inside space-y-1 ml-2" >
< li > < span class = "text-red-500 font-medium" > 红 色 偏 强 < / span > : 降 低 R值 , LED会减少红色成分 < / li >
< li > < span class = "text-green-500 font-medium" > 绿 色 偏 强 < / span > : 降 低 G值 , LED会减少绿色成分 < / li >
< li > < span class = "text-blue-500 font-medium" > 蓝 色 偏 强 < / span > : 降 低 B值 , LED会减少蓝色成分 < / li >
< li > < span class = "text-base-content font-medium" > 白 色 发 黄 < / span > : 适 当 提 高 B值 , 降 低 R / G值 < / li >
< li > < span class = "text-base-content font-medium" > 白 色 发 蓝 < / span > : 适 当 降 低 B值 , 提 高 R / G值 < / li >
< / ul >
< / div >
< div class = "space-y-2" >
< p class = "font-semibold text-accent" > 📋 对 比 方 法 : < / p >
< ul class = "list-disc list-inside space-y-1 ml-2" >
< li > 重 点 观 察 白 色 区 域 , 确 保 LED白光与屏幕白色一致 < / li >
< li > 检 查 彩 色 区 域 , 确 保 LED颜色饱和度合适 < / li >
< li > 在 不 同 环 境 光 下 测 试 , 确 保 效 果 稳 定 < / li >
< li > 调 节 完 成 后 可 点 击 "重置" 按 钮 恢 复 默 认 值 < / li >
< / ul >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
) }
{ /* 全屏模式 */ }
{ isFullscreen ( ) && (
< div class = "fixed inset-0 w-screen h-screen bg-black z-50" >
{ /* 全屏颜色测试区域 - 紧贴边缘 */ }
< div class = "absolute inset-0 w-full h-full" >
< TestColorsBg / >
< / div >
{ /* 可拖拽的RGB控制面板 */ }
< div
class = "fixed w-80 bg-base-200/95 backdrop-blur-sm rounded-lg shadow-xl z-60 cursor-move select-none"
style = { {
left : ` ${ panelPosition ( ) . x } px ` ,
top : ` ${ panelPosition ( ) . y } px ` ,
transform : 'none'
} }
onMouseDown = { handleMouseDown }
>
< div class = "card-body p-4" >
< div class = "card-title text-base mb-3 flex justify-between items-center" >
< div class = "flex items-center gap-2" >
< span class = "text-xs opacity-60" > ⋮ ⋮ < / span >
< span > RGB调节 < / span >
< div class = "badge badge-secondary badge-outline" > 可 拖 拽 < / div >
< / div >
< button class = "btn btn-ghost btn-xs" onClick = { toggleFullscreen } title = "退出全屏" >
< BsFullscreenExit size = { 14 } / >
< / button >
< / div >
< div class = "space-y-4" >
< div class = "form-control" >
< label class = "label" >
< span class = "label-text font-semibold text-red-500" > 红 色 ( R ) < / span >
< Value value = { ledStripStore . colorCalibration . r } / >
< / label >
< ColorSlider
class = "from-cyan-500 to-red-500"
value = { ledStripStore . colorCalibration . r }
onInput = { ( ev ) = >
updateColorCalibration (
'r' ,
( ev . target as HTMLInputElement ) . valueAsNumber ? ? 1 ,
)
}
/ >
< / div >
< div class = "form-control" >
< label class = "label" >
< span class = "label-text font-semibold text-green-500" > 绿 色 ( G ) < / span >
< Value value = { ledStripStore . colorCalibration . g } / >
< / label >
< ColorSlider
class = "from-pink-500 to-green-500"
value = { ledStripStore . colorCalibration . g }
onInput = { ( ev ) = >
updateColorCalibration (
'g' ,
( ev . target as HTMLInputElement ) . valueAsNumber ? ? 1 ,
)
}
/ >
< / div >
< div class = "form-control" >
< label class = "label" >
< span class = "label-text font-semibold text-blue-500" > 蓝 色 ( B ) < / span >
< Value value = { ledStripStore . colorCalibration . b } / >
< / label >
< ColorSlider
class = "from-yellow-500 to-blue-500"
value = { ledStripStore . colorCalibration . b }
onInput = { ( ev ) = >
updateColorCalibration (
'b' ,
( ev . target as HTMLInputElement ) . valueAsNumber ? ? 1 ,
)
}
/ >
< / div >
< div class = "form-control" >
< label class = "label" >
< span class = "label-text font-semibold text-base-content/70" > 白 色 ( W ) < / span >
< div class = "badge badge-outline badge-sm" > 暂 未 启 用 < / div >
< / label >
< ColorSlider class = "from-yellow-50 to-cyan-50" disabled / >
< / div >
< / div >
< div class = "text-xs text-base-content/60 mt-3 p-2 bg-base-300/50 rounded" >
💡 对 比 屏 幕 边 缘 颜 色 与 LED灯条 , 调 节 RGB滑块使颜色一致
< / div >
< div class = "flex gap-2 mt-4" >
< button class = "btn btn-outline btn-sm flex-1" onClick = { reset } title = "重置到100%" >
< BiRegularReset size = { 14 } / >
重 置
< / button >
< button class = "btn btn-primary btn-sm flex-1" onClick = { exit } title = "返回" >
< VsClose size = { 14 } / >
返 回
< / button >
< / div >
< / div >
< / div >
< / div >
) }
< / >
) ;
} ;