/ internal / desktop / theme.go
theme.go
  1  package desktop
  2  
  3  import (
  4  	"image/color"
  5  
  6  	"fyne.io/fyne/v2"
  7  	"fyne.io/fyne/v2/theme"
  8  )
  9  
 10  // ThemeMode 主题模式
 11  type ThemeMode int
 12  
 13  const (
 14  	ThemeModeLight ThemeMode = iota
 15  	ThemeModeDark
 16  	ThemeModeAuto
 17  )
 18  
 19  // customTheme 自定义主题
 20  type customTheme struct {
 21  	baseTheme fyne.Theme
 22  	mode      ThemeMode
 23  	forceDark bool
 24  	// 添加主题变化回调
 25  	onThemeChange []func(ThemeMode)
 26  }
 27  
 28  func NewCustomTheme(mode ThemeMode) fyne.Theme {
 29  	forceDark := mode == ThemeModeDark
 30  	return &customTheme{
 31  		baseTheme:     theme.DefaultTheme(),
 32  		mode:          mode,
 33  		forceDark:     forceDark,
 34  		onThemeChange: make([]func(ThemeMode), 0),
 35  	}
 36  }
 37  
 38  func (t *customTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color {
 39  	if t.forceDark || (t.mode == ThemeModeAuto && variant == theme.VariantDark) || t.mode == ThemeModeDark {
 40  		return t.darkColors(name)
 41  	}
 42  	return t.lightColors(name)
 43  }
 44  
 45  // lightColors 明亮主题配色方案
 46  func (t *customTheme) lightColors(name fyne.ThemeColorName) color.Color {
 47  	switch name {
 48  	// 主色系 - 更现代的蓝色
 49  	case theme.ColorNamePrimary:
 50  		return color.NRGBA{R: 59, G: 130, B: 246, A: 255} // 更鲜艳的蓝色
 51  
 52  	// 背景与前景
 53  	case theme.ColorNameBackground:
 54  		return color.NRGBA{R: 248, G: 250, B: 252, A: 255} // 极浅灰背景
 55  	case theme.ColorNameForeground:
 56  		return color.NRGBA{R: 17, G: 24, B: 39, A: 255} // 深灰文字
 57  	case theme.ColorNameDisabled:
 58  		return color.NRGBA{R: 156, G: 163, B: 175, A: 150} // 柔和禁用色
 59  
 60  	// 按钮状态
 61  	case theme.ColorNameButton:
 62  		return color.NRGBA{R: 59, G: 130, B: 246, A: 255}
 63  	case theme.ColorNameHover:
 64  		return color.NRGBA{R: 37, G: 99, B: 235, A: 255} // 深蓝悬停
 65  	case theme.ColorNamePressed:
 66  		return color.NRGBA{R: 29, G: 78, B: 216, A: 255} // 更深蓝按下
 67  
 68  	// 输入组件
 69  	case theme.ColorNameInputBackground:
 70  		return color.NRGBA{R: 255, G: 255, B: 255, A: 255} // 纯白输入框
 71  	case theme.ColorNameInputBorder:
 72  		return color.NRGBA{R: 209, G: 213, B: 219, A: 255} // 浅灰边框
 73  	case theme.ColorNamePlaceHolder:
 74  		return color.NRGBA{R: 156, G: 163, B: 175, A: 200} // 灰占位符
 75  
 76  	// 其他
 77  	case theme.ColorNameSelection:
 78  		return color.NRGBA{R: 219, G: 234, B: 254, A: 180} // 淡蓝选中
 79  	case theme.ColorNameScrollBar:
 80  		return color.NRGBA{R: 209, G: 213, B: 219, A: 200}
 81  	case theme.ColorNameShadow:
 82  		return color.NRGBA{R: 0, G: 0, B: 0, A: 25} // 柔和阴影
 83  
 84  	// 状态色
 85  	case theme.ColorNameError:
 86  		return color.NRGBA{R: 239, G: 68, B: 68, A: 255} // 红色错误
 87  	case theme.ColorNameWarning:
 88  		return color.NRGBA{R: 245, G: 158, B: 11, A: 255} // 橙色警告
 89  	case theme.ColorNameSuccess:
 90  		return color.NRGBA{R: 34, G: 197, B: 94, A: 255} // 绿色成功
 91  	case theme.ColorNameFocus:
 92  		return color.NRGBA{R: 59, G: 130, B: 246, A: 100} // 半透明焦点
 93  
 94  	default:
 95  		return t.baseTheme.Color(name, theme.VariantLight)
 96  	}
 97  }
 98  
 99  // darkColors 夜晚主题配色方案
100  func (t *customTheme) darkColors(name fyne.ThemeColorName) color.Color {
101  	switch name {
102  	// 主色系
103  	case theme.ColorNamePrimary:
104  		return color.NRGBA{R: 96, G: 165, B: 250, A: 255} // 亮蓝色
105  
106  	// 背景与前景
107  	case theme.ColorNameBackground:
108  		return color.NRGBA{R: 15, G: 23, B: 42, A: 255} // 深蓝灰背景
109  	case theme.ColorNameForeground:
110  		return color.NRGBA{R: 248, G: 250, B: 252, A: 255} // 浅灰文字
111  	case theme.ColorNameDisabled:
112  		return color.NRGBA{R: 100, G: 116, B: 139, A: 150} // 深色禁用
113  
114  	// 按钮状态
115  	case theme.ColorNameButton:
116  		return color.NRGBA{R: 30, G: 41, B: 59, A: 255} // 深按钮背景
117  	case theme.ColorNameHover:
118  		return color.NRGBA{R: 51, G: 65, B: 85, A: 255} // 浅灰悬停
119  	case theme.ColorNamePressed:
120  		return color.NRGBA{R: 15, G: 23, B: 42, A: 255} // 更深按下
121  
122  	// 输入组件
123  	case theme.ColorNameInputBackground:
124  		return color.NRGBA{R: 30, G: 41, B: 59, A: 255} // 深输入框背景
125  	case theme.ColorNameInputBorder:
126  		return color.NRGBA{R: 51, G: 65, B: 85, A: 255} // 深边框
127  	case theme.ColorNamePlaceHolder:
128  		return color.NRGBA{R: 148, G: 163, B: 184, A: 200} // 灰占位符
129  
130  	// 其他
131  	case theme.ColorNameSelection:
132  		return color.NRGBA{R: 59, G: 130, B: 246, A: 180} // 蓝色选中
133  	case theme.ColorNameScrollBar:
134  		return color.NRGBA{R: 51, G: 65, B: 85, A: 200} // 深滚动条
135  	case theme.ColorNameShadow:
136  		return color.NRGBA{R: 0, G: 0, B: 0, A: 50} // 深色阴影
137  
138  	// 状态色(更鲜艳)
139  	case theme.ColorNameError:
140  		return color.NRGBA{R: 248, G: 113, B: 113, A: 255}
141  	case theme.ColorNameWarning:
142  		return color.NRGBA{R: 251, G: 191, B: 36, A: 255}
143  	case theme.ColorNameSuccess:
144  		return color.NRGBA{R: 74, G: 222, B: 128, A: 255}
145  	case theme.ColorNameFocus:
146  		return color.NRGBA{R: 96, G: 165, B: 250, A: 100}
147  
148  	default:
149  		return t.baseTheme.Color(name, theme.VariantDark)
150  	}
151  }
152  
153  func (t *customTheme) Icon(name fyne.ThemeIconName) fyne.Resource {
154  	return t.baseTheme.Icon(name)
155  }
156  
157  func (t *customTheme) Font(style fyne.TextStyle) fyne.Resource {
158  	return t.baseTheme.Font(style)
159  }
160  
161  func (t *customTheme) Size(name fyne.ThemeSizeName) float32 {
162  	switch name {
163  	case theme.SizeNamePadding:
164  		return 12
165  	case theme.SizeNameInlineIcon:
166  		return 20
167  	case theme.SizeNameScrollBar:
168  		return 8
169  	case theme.SizeNameScrollBarSmall:
170  		return 4
171  	case theme.SizeNameSeparatorThickness:
172  		return 1
173  	case theme.SizeNameText:
174  		return 14
175  	case theme.SizeNameInputBorder:
176  		return 1.5
177  	case theme.SizeNameInputRadius:
178  		return 6
179  	default:
180  		return t.baseTheme.Size(name)
181  	}
182  }
183  
184  // GetThemeMode 获取当前主题模式
185  func (t *customTheme) GetThemeMode() ThemeMode {
186  	return t.mode
187  }
188  
189  // SetThemeMode 设置主题模式
190  func (t *customTheme) SetThemeMode(mode ThemeMode) {
191  	if t.mode != mode {
192  		t.mode = mode
193  		t.forceDark = mode == ThemeModeDark
194  		// 通知所有回调函数
195  		for _, callback := range t.onThemeChange {
196  			callback(mode)
197  		}
198  	}
199  }
200  
201  // AddThemeChangeCallback 添加主题变化回调
202  func (t *customTheme) AddThemeChangeCallback(callback func(ThemeMode)) {
203  	t.onThemeChange = append(t.onThemeChange, callback)
204  }