| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 7 | 40 | 0% |
| Commands | 0 | 3 | 0 | 0% |
| Section tags | 0 | 5 | 5 | 0% |
What each file covers
Sections
0 shared · 7 only in A · 40 only in B- − AGENTS.md
- − Shared Project Memory
- − Testing
- − Cloud LLM Model Maintenance
- − Feature Index
- − Security
- − Git
- + WPF UI Patterns
- + Window Lifecycle
- + Window Creation Pattern
- + Window Cleanup
- + XAML Structure
- + Standard Window Attributes
- + Resource Dictionaries
- + Data Binding
- + Two-Way Binding Pattern
- + Code-Behind Binding
- + Event Handlers
- + Standard Event Pattern
- + Window Positioning
- + Load Saved Position
- + Save Position on Move
- + Custom Controls
- + Draggable Window
- + Resizable Thumb
- + Transparent Windows
- + Transparency Setup
- + Opacity Binding
- + Always-On-Top
- + Topmost Property
- + Text Display
- + TextBlock with Formatting
- + ScrollViewer Pattern
- + Auto-Scroll to Bottom
- + Color Pickers
- + Color Dialog Pattern
- + Animations
- + Fade Animation
- + ComboBox Binding
- + ComboBox with Items
- + Tab Control Pattern
- + Settings Window Tabs
- + Status Bar Updates
- + Status Message Pattern
- + Dialog Windows
- + Modal Dialog Pattern
- + Confirmation Dialog
Commands
0 shared · 3 only in A · 0 only in B- − dotnet build .\UGTLive.sln --configuration Release
- − git commit
- − git push
Section tags
0 shared · 5 only in A · 5 only in B- − test
- − git-pr
- − security
- − performance
- − do-not
- + setup
- + lint-format
- + code-style
- + architecture
- + ui
Line diff
SethRobinson/UGTLive · AGENTS.md
@@ −1 @@
1# AGENTS.md
2
3Project operating instructions for AI assistants working in this repository.
4
5## Shared Project Memory
6
7- At the start of each new task or thread involving this repository, read this file before inspecting files, running commands, making a plan, or taking any other project action.
8- Treat follow-up replies in the same continuous task as part of that task. Do not reread this file unless the repository or working directory changes, this file is modified, or its instructions are no longer available in context.
9- Treat this file as the shared project memory for AI assistants.
10- Do not rely on vendor-specific, proprietary, or hidden memory systems for project facts, preferences, or operating instructions. (except to remember to ALWAYS read this file first before doing anything. Remember that.)
11- Update this file with important repo-specific information learned during work, including build commands, test commands, conventions, decisions, pitfalls, and current project preferences.
12- Keep this file accurate and current. Remove or correct stale, misleading, or incorrect information when discovered.
13- If information is temporary or uncertain, label it clearly rather than presenting it as permanent fact.
14
15Scope policy: this file holds cross-cutting rules, workflows, and gotchas that most sessions need, plus a feature index. Keep it around 30 KB. Feature deep-dives live in `docs/<topic>.md`: before working on a feature listed in the index, read its doc; when finishing feature work, update that doc and keep the index entry here to one or two lines (where it lives + the non-obvious constraint). Cross-cutting rules and new gotchas still land here directly. When a change makes anything stale, here or in a linked doc, update it in the same change.
16
17## Testing
18
19- When possible, design automated tests for new features and bug fixes.
20- Run relevant automated tests after finishing changes to guard against regressions.
21- If tests cannot be run or do not exist, state that clearly in the handoff and describe any manual verification performed.
22- Always finish project changes by building the Release configuration: `dotnet build .\UGTLive.sln --configuration Release`.
23- If a running UGTLive process prevents the Release build, capture its executable/command line, stop it, complete the build, and restart it afterward. Do not start UGTLive if it was not running before the build.
24
25Always add automation/test harnesses to test options/buttons/features as needed. Document them.
26
27## Cloud LLM Model Maintenance
28
29- Cloud and CLI model picker presets live in `src/SettingsWindow.xaml`; their fallback/default values live in `src/ConfigManager.cs`, `src/ConfigManager.Translation.cs`, and `src/SettingsWindow.TranslationSettings.cs`.
30- Subscription-backed CLI providers display as `Anthropic Sub`, `OpenAI Sub`, and `Gemini CLI (Enterprise)`, but their stable internal IDs remain `ClaudeCli`, `CodexCli`, and `GeminiCli`; use `ComboBoxItem.Tag` for the internal ID. Google ended personal/free/AI Pro/AI Ultra access through Gemini CLI on June 18, 2026; do not replace it with Antigravity CLI until `agy -p` reliably exposes captured stdout to Windows parent processes (see `docs/settings-connection-tests.md`).
31- Keep provider-specific capability handling in the matching translation service. In particular, Anthropic model generations use different manual/adaptive thinking request shapes.
32- Verify model IDs and request compatibility against current official provider documentation. Verify OpenRouter-prefixed slugs against its `/api/v1/models` catalog before adding presets.
33
34## Feature Index
35
36- Settings API/model/voice tests: see `docs/settings-connection-tests.md`. UI buttons and `--test-settings-connection` must continue to call the shared `SettingsConnectionTester` implementation.
37- OpenAI All In One Snap translation: see `docs/openai-all-in-one.md`. It is a Snap-only, visual-only `gpt-image-2` Image Edits path; Auto and realtime processing must remain on the standard OCR pipeline.
38
39
40## Security
41
42- Never commit sensitive data, including credentials, tokens, passwords, private keys, cookies, customer data, personal data, or machine-specific authentication material.
43- If an AI assistant needs authentication data or other secrets for local work, use `agents_secret.md` for those notes.
44- `agents_secret.md` must stay ignored by git and must not be committed.
45- Do not put secrets in commit messages, logs, issue text, pull request descriptions, generated docs, or other tracked files.
46- Configuration logging must pass key names through `ConfigManager.IsSensitiveConfigKey`; never print raw secret values in startup or harness output.
47- Before committing, review staged changes for accidental secrets.
48
49## Git
50
51- Never add OpenAI/Codex/Claude etc as a co-author on git commits.
52- NEVER `git commit` unless explicitly told to commit.
53- NEVER `git push` unless explicitly told to push. "Commit" means commit
54 locally only; committing is not permission to push.
55
SethRobinson/UGTLive · .cursor/rules/wpf-ui-patterns.mdc
@@ +1 @@
1---
2description: WPF-specific UI patterns and best practices
3globs: ["**/*.xaml", "**/*.xaml.cs"]
4alwaysApply: false
5---
6
7# WPF UI Patterns
8
9## Window Lifecycle
10
11### Window Creation Pattern
12Windows are typically created once and shown/hidden as needed:
13
14```csharp
15private ChatBoxWindow? _chatBoxWindow;
16
17public void ShowChatBox()
18{
19 if (_chatBoxWindow == null)
20 {
21 _chatBoxWindow = new ChatBoxWindow();
22 _chatBoxWindow.Closed += (s, e) => { _chatBoxWindow = null; };
23 }
24
25 _chatBoxWindow.Show();
26 _chatBoxWindow.Activate();
27}
28
29public void HideChatBox()
30{
31 _chatBoxWindow?.Hide();
32}
33```
34
35### Window Cleanup
36```csharp
37protected override void OnClosed(EventArgs e)
38{
39 // Save window position
40 ConfigManager.Instance.SetWindowPosition(
41 "ChatBox", Left, Top, Width, Height);
42
43 // Cleanup resources
44 base.OnClosed(e);
45}
46```
47
48## XAML Structure
49
50### Standard Window Attributes
51```xml
52<Window x:Class="UGTLive.ChatBoxWindow"
53 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
54 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55 Title="ChatBox"
56 WindowStyle="None"
57 AllowsTransparency="True"
58 Background="Transparent"
59 ResizeMode="CanResize"
60 Topmost="{Binding IsAlwaysOnTop}"
61 ShowInTaskbar="False">
62</Window>
63```
64
65### Resource Dictionaries
66Define styles in ResourceDictionary:
67
68```xml
69<Window.Resources>
70 <Style x:Key="ModernButton" TargetType="Button">
71 <Setter Property="Background" Value="#FF2D2D30"/>
72 <Setter Property="Foreground" Value="White"/>
73 <Setter Property="BorderThickness" Value="0"/>
74 <Setter Property="Padding" Value="10,5"/>
75 </Style>
76</Window.Resources>
77```
78
79## Data Binding
80
81### Two-Way Binding Pattern
82```xml
83<TextBox Text="{Binding ApiKey, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
84<CheckBox IsChecked="{Binding IsEnabled, Mode=TwoWay}"/>
85<ComboBox SelectedItem="{Binding SelectedModel, Mode=TwoWay}"/>
86```
87
88### Code-Behind Binding
89```csharp
90// Set DataContext
91this.DataContext = this;
92
93// Implement INotifyPropertyChanged
94public event PropertyChangedEventHandler? PropertyChanged;
95
96private string _apiKey = "";
97public string ApiKey
98{
99 get => _apiKey;
100 set
101 {
102 _apiKey = value;
103 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ApiKey)));
104 }
105}
106```
107
108## Event Handlers
109
110### Standard Event Pattern
111```csharp
112private void Button_Click(object sender, RoutedEventArgs e)
113{
114 if (sender is Button button)
115 {
116 // Handle click
117 }
118}
119
120private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
121{
122 if (sender is TextBox textBox)
123 {
124 // Handle text change
125 }
126}
127```
128
129## Window Positioning
130
131### Load Saved Position
132```csharp
133private void Window_Loaded(object sender, RoutedEventArgs e)
134{
135 var pos = ConfigManager.Instance.GetWindowPosition("ChatBox");
136 if (pos != null)
137 {
138 this.Left = pos.X;
139 this.Top = pos.Y;
140 this.Width = pos.Width;
141 this.Height = pos.Height;
142 }
143 else
144 {
145 // Center on screen
146 this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
147 }
148}
149```
150
151### Save Position on Move
152```csharp
153private void Window_LocationChanged(object sender, EventArgs e)
154{
155 ConfigManager.Instance.SetWindowPosition(
156 "ChatBox", Left, Top, Width, Height);
157}
158```
159
160## Custom Controls
161
162### Draggable Window
163```csharp
164private void Window_MouseDown(object sender, MouseButtonEventArgs e)
165{
166 if (e.ChangedButton == MouseButton.Left)
167 {
168 this.DragMove();
169 }
170}
171```
172
173### Resizable Thumb
174```xml
175<Thumb DragDelta="Thumb_DragDelta"
176 Width="10" Height="10"
177 Cursor="SizeNWSE"
178 HorizontalAlignment="Right"
179 VerticalAlignment="Bottom"/>
180```
181
182```csharp
183private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
184{
185 this.Width = Math.Max(100, this.Width + e.HorizontalChange);
186 this.Height = Math.Max(100, this.Height + e.VerticalChange);
187}
188```
189
190## Transparent Windows
191
192### Transparency Setup
193```xml
194<Window WindowStyle="None"
195 AllowsTransparency="True"
196 Background="Transparent">
197 <Border Background="{Binding BackgroundColor}"
198 Opacity="{Binding Opacity}"
199 CornerRadius="5">
200 <!-- Content -->
201 </Border>
202</Window>
203```
204
205### Opacity Binding
206```csharp
207public double Opacity
208{
209 get => _opacity;
210 set
211 {
212 _opacity = value;
213 this.Opacity = value / 100.0; // Convert 0-100 to 0-1
214 }
215}
216```
217
218## Always-On-Top
219
220### Topmost Property
221```xml
222<Window Topmost="{Binding IsAlwaysOnTop}"/>
223```
224
225```csharp
226public bool IsAlwaysOnTop
227{
228 get => this.Topmost;
229 set => this.Topmost = value;
230}
231```
232
233## Text Display
234
235### TextBlock with Formatting
236```xml
237<TextBlock TextWrapping="Wrap">
238 <Run Text="{Binding SourceText}" Foreground="Gray"/>
239 <LineBreak/>
240 <Run Text="{Binding TranslatedText}" Foreground="White" FontWeight="Bold"/>
241</TextBlock>
242```
243
244### ScrollViewer Pattern
245```xml
246<ScrollViewer VerticalScrollBarVisibility="Auto"
247 HorizontalScrollBarVisibility="Disabled">
248 <StackPanel Name="ContentPanel">
249 <!-- Dynamic content -->
250 </StackPanel>
251</ScrollViewer>
252```
253
254### Auto-Scroll to Bottom
255```csharp
256private void ScrollToBottom()
257{
258 Application.Current.Dispatcher.Invoke(() =>
259 {
260 if (ScrollViewer != null)
261 {
262 ScrollViewer.ScrollToEnd();
263 }
264 });
265}
266```
267
268## Color Pickers
269
270### Color Dialog Pattern
271```csharp
272using System.Windows.Forms;
273
274private void PickColorButton_Click(object sender, RoutedEventArgs e)
275{
276 using var colorDialog = new ColorDialog();
277 colorDialog.Color = System.Drawing.Color.FromArgb(
278 (int)((Color)BackgroundColor).A,
279 (int)((Color)BackgroundColor).R,
280 (int)((Color)BackgroundColor).G,
281 (int)((Color)BackgroundColor).B);
282
283 if (colorDialog.ShowDialog() == DialogResult.OK)
284 {
285 var wpfColor = Color.FromArgb(
286 colorDialog.Color.A,
287 colorDialog.Color.R,
288 colorDialog.Color.G,
289 colorDialog.Color.B);
290 BackgroundColor = wpfColor;
291 }
292}
293```
294
295## Animations
296
297### Fade Animation
298```xml
299<Window.Resources>
300 <Storyboard x:Key="FadeIn">
301 <DoubleAnimation Storyboard.TargetProperty="Opacity"
302 From="0" To="1" Duration="0:0:0.3"/>
303 </Storyboard>
304</Window.Resources>
305```
306
307```csharp
308private void FadeIn()
309{
310 var storyboard = (Storyboard)FindResource("FadeIn");
311 storyboard?.Begin(this);
312}
313```
314
315## ComboBox Binding
316
317### ComboBox with Items
318```xml
319<ComboBox Name="ModelComboBox"
320 SelectedItem="{Binding SelectedModel, Mode=TwoWay}">
321 <ComboBoxItem Content="gemini-1.5-flash"/>
322 <ComboBoxItem Content="gemini-1.5-pro"/>
323 <ComboBoxItem Content="gemini-2.0-flash"/>
324</ComboBox>
325```
326
327```csharp
328private void LoadModels()
329{
330 ModelComboBox.Items.Clear();
331 var models = new[] { "gemini-1.5-flash", "gemini-1.5-pro", "gemini-2.0-flash" };
332 foreach (var model in models)
333 {
334 ModelComboBox.Items.Add(model);
335 }
336
337 // Set selected item
338 var savedModel = ConfigManager.Instance.GetGeminiModel();
339 ModelComboBox.SelectedItem = savedModel;
340}
341```
342
343## Tab Control Pattern
344
345### Settings Window Tabs
346```xml
347<TabControl>
348 <TabItem Header="General">
349 <!-- General settings -->
350 </TabItem>
351 <TabItem Header="OCR">
352 <!-- OCR settings -->
353 </TabItem>
354 <TabItem Header="Translation">
355 <!-- Translation settings -->
356 </TabItem>
357</TabControl>
358```
359
360## Status Bar Updates
361
362### Status Message Pattern
363```csharp
364public void UpdateStatus(string message, StatusType type = StatusType.Info)
365{
366 Application.Current.Dispatcher.Invoke(() =>
367 {
368 StatusText.Text = message;
369 StatusText.Foreground = type switch
370 {
371 StatusType.Error => Brushes.Red,
372 StatusType.Warning => Brushes.Orange,
373 _ => Brushes.White
374 };
375
376 // Auto-fade after 3 seconds
377 _statusTimer?.Stop();
378 _statusTimer = new DispatcherTimer
379 {
380 Interval = TimeSpan.FromSeconds(3)
381 };
382 _statusTimer.Tick += (s, e) =>
383 {
384 StatusText.Text = "";
385 _statusTimer.Stop();
386 };
387 _statusTimer.Start();
388 });
389}
390```
391
392## Dialog Windows
393
394### Modal Dialog Pattern
395```csharp
396var dialog = new SettingsWindow();
397dialog.Owner = this;
398dialog.ShowDialog(); // Blocks until closed
399```
400
401### Confirmation Dialog
402```csharp
403var result = MessageBox.Show(
404 "Are you sure you want to delete this?",
405 "Confirm",
406 MessageBoxButton.YesNo,
407 MessageBoxImage.Question);
408
409if (result == MessageBoxResult.Yes)
410{
411 // Perform action
412}
413```
414
@@ −1 +1 @@
1−# AGENTS.md
1+---
2+description: WPF-specific UI patterns and best practices
3+globs: ["**/*.xaml", "**/*.xaml.cs"]
4+alwaysApply: false
5+---
26
3−Project operating instructions for AI assistants working in this repository.
7+# WPF UI Patterns
48
5−## Shared Project Memory
9+## Window Lifecycle
610
7−- At the start of each new task or thread involving this repository, read this file before inspecting files, running commands, making a plan, or taking any other project action.
8−- Treat follow-up replies in the same continuous task as part of that task. Do not reread this file unless the repository or working directory changes, this file is modified, or its instructions are no longer available in context.
9−- Treat this file as the shared project memory for AI assistants.
10−- Do not rely on vendor-specific, proprietary, or hidden memory systems for project facts, preferences, or operating instructions. (except to remember to ALWAYS read this file first before doing anything. Remember that.)
11−- Update this file with important repo-specific information learned during work, including build commands, test commands, conventions, decisions, pitfalls, and current project preferences.
12−- Keep this file accurate and current. Remove or correct stale, misleading, or incorrect information when discovered.
13−- If information is temporary or uncertain, label it clearly rather than presenting it as permanent fact.
11+### Window Creation Pattern
12+Windows are typically created once and shown/hidden as needed:
1413
15−Scope policy: this file holds cross-cutting rules, workflows, and gotchas that most sessions need, plus a feature index. Keep it around 30 KB. Feature deep-dives live in `docs/<topic>.md`: before working on a feature listed in the index, read its doc; when finishing feature work, update that doc and keep the index entry here to one or two lines (where it lives + the non-obvious constraint). Cross-cutting rules and new gotchas still land here directly. When a change makes anything stale, here or in a linked doc, update it in the same change.
14+```csharp
15+private ChatBoxWindow? _chatBoxWindow;
1616
17−## Testing
17+public void ShowChatBox()
18+{
19+ if (_chatBoxWindow == null)
20+ {
21+ _chatBoxWindow = new ChatBoxWindow();
22+ _chatBoxWindow.Closed += (s, e) => { _chatBoxWindow = null; };
23+ }
24+
25+ _chatBoxWindow.Show();
26+ _chatBoxWindow.Activate();
27+}
1828
19−- When possible, design automated tests for new features and bug fixes.
20−- Run relevant automated tests after finishing changes to guard against regressions.
21−- If tests cannot be run or do not exist, state that clearly in the handoff and describe any manual verification performed.
22−- Always finish project changes by building the Release configuration: `dotnet build .\UGTLive.sln --configuration Release`.
23−- If a running UGTLive process prevents the Release build, capture its executable/command line, stop it, complete the build, and restart it afterward. Do not start UGTLive if it was not running before the build.
29+public void HideChatBox()
30+{
31+ _chatBoxWindow?.Hide();
32+}
33+```
2434
25−Always add automation/test harnesses to test options/buttons/features as needed. Document them.
35+### Window Cleanup
36+```csharp
37+protected override void OnClosed(EventArgs e)
38+{
39+ // Save window position
40+ ConfigManager.Instance.SetWindowPosition(
41+ "ChatBox", Left, Top, Width, Height);
42+
43+ // Cleanup resources
44+ base.OnClosed(e);
45+}
46+```
2647
27−## Cloud LLM Model Maintenance
48+## XAML Structure
2849
29−- Cloud and CLI model picker presets live in `src/SettingsWindow.xaml`; their fallback/default values live in `src/ConfigManager.cs`, `src/ConfigManager.Translation.cs`, and `src/SettingsWindow.TranslationSettings.cs`.
30−- Subscription-backed CLI providers display as `Anthropic Sub`, `OpenAI Sub`, and `Gemini CLI (Enterprise)`, but their stable internal IDs remain `ClaudeCli`, `CodexCli`, and `GeminiCli`; use `ComboBoxItem.Tag` for the internal ID. Google ended personal/free/AI Pro/AI Ultra access through Gemini CLI on June 18, 2026; do not replace it with Antigravity CLI until `agy -p` reliably exposes captured stdout to Windows parent processes (see `docs/settings-connection-tests.md`).
31−- Keep provider-specific capability handling in the matching translation service. In particular, Anthropic model generations use different manual/adaptive thinking request shapes.
32−- Verify model IDs and request compatibility against current official provider documentation. Verify OpenRouter-prefixed slugs against its `/api/v1/models` catalog before adding presets.
50+### Standard Window Attributes
51+```xml
52+<Window x:Class="UGTLive.ChatBoxWindow"
53+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
54+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55+ Title="ChatBox"
56+ WindowStyle="None"
57+ AllowsTransparency="True"
58+ Background="Transparent"
59+ ResizeMode="CanResize"
60+ Topmost="{Binding IsAlwaysOnTop}"
61+ ShowInTaskbar="False">
62+</Window>
63+```
3364
34−## Feature Index
65+### Resource Dictionaries
66+Define styles in ResourceDictionary:
3567
36−- Settings API/model/voice tests: see `docs/settings-connection-tests.md`. UI buttons and `--test-settings-connection` must continue to call the shared `SettingsConnectionTester` implementation.
37−- OpenAI All In One Snap translation: see `docs/openai-all-in-one.md`. It is a Snap-only, visual-only `gpt-image-2` Image Edits path; Auto and realtime processing must remain on the standard OCR pipeline.
68+```xml
69+<Window.Resources>
70+ <Style x:Key="ModernButton" TargetType="Button">
71+ <Setter Property="Background" Value="#FF2D2D30"/>
72+ <Setter Property="Foreground" Value="White"/>
73+ <Setter Property="BorderThickness" Value="0"/>
74+ <Setter Property="Padding" Value="10,5"/>
75+ </Style>
76+</Window.Resources>
77+```
3878
79+## Data Binding
3980
40−## Security
81+### Two-Way Binding Pattern
82+```xml
83+<TextBox Text="{Binding ApiKey, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
84+<CheckBox IsChecked="{Binding IsEnabled, Mode=TwoWay}"/>
85+<ComboBox SelectedItem="{Binding SelectedModel, Mode=TwoWay}"/>
86+```
4187
42−- Never commit sensitive data, including credentials, tokens, passwords, private keys, cookies, customer data, personal data, or machine-specific authentication material.
43−- If an AI assistant needs authentication data or other secrets for local work, use `agents_secret.md` for those notes.
44−- `agents_secret.md` must stay ignored by git and must not be committed.
45−- Do not put secrets in commit messages, logs, issue text, pull request descriptions, generated docs, or other tracked files.
46−- Configuration logging must pass key names through `ConfigManager.IsSensitiveConfigKey`; never print raw secret values in startup or harness output.
47−- Before committing, review staged changes for accidental secrets.
88+### Code-Behind Binding
89+```csharp
90+// Set DataContext
91+this.DataContext = this;
4892
49−## Git
93+// Implement INotifyPropertyChanged
94+public event PropertyChangedEventHandler? PropertyChanged;
5095
51−- Never add OpenAI/Codex/Claude etc as a co-author on git commits.
52−- NEVER `git commit` unless explicitly told to commit.
53−- NEVER `git push` unless explicitly told to push. "Commit" means commit
54− locally only; committing is not permission to push.
96+private string _apiKey = "";
97+public string ApiKey
98+{
99+ get => _apiKey;
100+ set
101+ {
102+ _apiKey = value;
103+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ApiKey)));
104+ }
105+}
106+```
107+
108+## Event Handlers
109+
110+### Standard Event Pattern
111+```csharp
112+private void Button_Click(object sender, RoutedEventArgs e)
113+{
114+ if (sender is Button button)
115+ {
116+ // Handle click
117+ }
118+}
119+
120+private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
121+{
122+ if (sender is TextBox textBox)
123+ {
124+ // Handle text change
125+ }
126+}
127+```
128+
129+## Window Positioning
130+
131+### Load Saved Position
132+```csharp
133+private void Window_Loaded(object sender, RoutedEventArgs e)
134+{
135+ var pos = ConfigManager.Instance.GetWindowPosition("ChatBox");
136+ if (pos != null)
137+ {
138+ this.Left = pos.X;
139+ this.Top = pos.Y;
140+ this.Width = pos.Width;
141+ this.Height = pos.Height;
142+ }
143+ else
144+ {
145+ // Center on screen
146+ this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
147+ }
148+}
149+```
150+
151+### Save Position on Move
152+```csharp
153+private void Window_LocationChanged(object sender, EventArgs e)
154+{
155+ ConfigManager.Instance.SetWindowPosition(
156+ "ChatBox", Left, Top, Width, Height);
157+}
158+```
159+
160+## Custom Controls
161+
162+### Draggable Window
163+```csharp
164+private void Window_MouseDown(object sender, MouseButtonEventArgs e)
165+{
166+ if (e.ChangedButton == MouseButton.Left)
167+ {
168+ this.DragMove();
169+ }
170+}
171+```
172+
173+### Resizable Thumb
174+```xml
175+<Thumb DragDelta="Thumb_DragDelta"
176+ Width="10" Height="10"
177+ Cursor="SizeNWSE"
178+ HorizontalAlignment="Right"
179+ VerticalAlignment="Bottom"/>
180+```
181+
182+```csharp
183+private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
184+{
185+ this.Width = Math.Max(100, this.Width + e.HorizontalChange);
186+ this.Height = Math.Max(100, this.Height + e.VerticalChange);
187+}
188+```
189+
190+## Transparent Windows
191+
192+### Transparency Setup
193+```xml
194+<Window WindowStyle="None"
195+ AllowsTransparency="True"
196+ Background="Transparent">
197+ <Border Background="{Binding BackgroundColor}"
198+ Opacity="{Binding Opacity}"
199+ CornerRadius="5">
200+ <!-- Content -->
201+ </Border>
202+</Window>
203+```
204+
205+### Opacity Binding
206+```csharp
207+public double Opacity
208+{
209+ get => _opacity;
210+ set
211+ {
212+ _opacity = value;
213+ this.Opacity = value / 100.0; // Convert 0-100 to 0-1
214+ }
215+}
216+```
217+
218+## Always-On-Top
219+
220+### Topmost Property
221+```xml
222+<Window Topmost="{Binding IsAlwaysOnTop}"/>
223+```
224+
225+```csharp
226+public bool IsAlwaysOnTop
227+{
228+ get => this.Topmost;
229+ set => this.Topmost = value;
230+}
231+```
232+
233+## Text Display
234+
235+### TextBlock with Formatting
236+```xml
237+<TextBlock TextWrapping="Wrap">
238+ <Run Text="{Binding SourceText}" Foreground="Gray"/>
239+ <LineBreak/>
240+ <Run Text="{Binding TranslatedText}" Foreground="White" FontWeight="Bold"/>
241+</TextBlock>
242+```
243+
244+### ScrollViewer Pattern
245+```xml
246+<ScrollViewer VerticalScrollBarVisibility="Auto"
247+ HorizontalScrollBarVisibility="Disabled">
248+ <StackPanel Name="ContentPanel">
249+ <!-- Dynamic content -->
250+ </StackPanel>
251+</ScrollViewer>
252+```
253+
254+### Auto-Scroll to Bottom
255+```csharp
256+private void ScrollToBottom()
257+{
258+ Application.Current.Dispatcher.Invoke(() =>
259+ {
260+ if (ScrollViewer != null)
261+ {
262+ ScrollViewer.ScrollToEnd();
263+ }
264+ });
265+}
266+```
267+
268+## Color Pickers
269+
270+### Color Dialog Pattern
271+```csharp
272+using System.Windows.Forms;
273+
274+private void PickColorButton_Click(object sender, RoutedEventArgs e)
275+{
276+ using var colorDialog = new ColorDialog();
277+ colorDialog.Color = System.Drawing.Color.FromArgb(
278+ (int)((Color)BackgroundColor).A,
279+ (int)((Color)BackgroundColor).R,
280+ (int)((Color)BackgroundColor).G,
281+ (int)((Color)BackgroundColor).B);
282+
283+ if (colorDialog.ShowDialog() == DialogResult.OK)
284+ {
285+ var wpfColor = Color.FromArgb(
286+ colorDialog.Color.A,
287+ colorDialog.Color.R,
288+ colorDialog.Color.G,
289+ colorDialog.Color.B);
290+ BackgroundColor = wpfColor;
291+ }
292+}
293+```
294+
295+## Animations
296+
297+### Fade Animation
298+```xml
299+<Window.Resources>
300+ <Storyboard x:Key="FadeIn">
301+ <DoubleAnimation Storyboard.TargetProperty="Opacity"
302+ From="0" To="1" Duration="0:0:0.3"/>
303+ </Storyboard>
304+</Window.Resources>
305+```
306+
307+```csharp
308+private void FadeIn()
309+{
310+ var storyboard = (Storyboard)FindResource("FadeIn");
311+ storyboard?.Begin(this);
312+}
313+```
314+
315+## ComboBox Binding
316+
317+### ComboBox with Items
318+```xml
319+<ComboBox Name="ModelComboBox"
320+ SelectedItem="{Binding SelectedModel, Mode=TwoWay}">
321+ <ComboBoxItem Content="gemini-1.5-flash"/>
322+ <ComboBoxItem Content="gemini-1.5-pro"/>
323+ <ComboBoxItem Content="gemini-2.0-flash"/>
324+</ComboBox>
325+```
326+
327+```csharp
328+private void LoadModels()
329+{
330+ ModelComboBox.Items.Clear();
331+ var models = new[] { "gemini-1.5-flash", "gemini-1.5-pro", "gemini-2.0-flash" };
332+ foreach (var model in models)
333+ {
334+ ModelComboBox.Items.Add(model);
335+ }
336+
337+ // Set selected item
338+ var savedModel = ConfigManager.Instance.GetGeminiModel();
339+ ModelComboBox.SelectedItem = savedModel;
340+}
341+```
342+
343+## Tab Control Pattern
344+
345+### Settings Window Tabs
346+```xml
347+<TabControl>
348+ <TabItem Header="General">
349+ <!-- General settings -->
350+ </TabItem>
351+ <TabItem Header="OCR">
352+ <!-- OCR settings -->
353+ </TabItem>
354+ <TabItem Header="Translation">
355+ <!-- Translation settings -->
356+ </TabItem>
357+</TabControl>
358+```
359+
360+## Status Bar Updates
361+
362+### Status Message Pattern
363+```csharp
364+public void UpdateStatus(string message, StatusType type = StatusType.Info)
365+{
366+ Application.Current.Dispatcher.Invoke(() =>
367+ {
368+ StatusText.Text = message;
369+ StatusText.Foreground = type switch
370+ {
371+ StatusType.Error => Brushes.Red,
372+ StatusType.Warning => Brushes.Orange,
373+ _ => Brushes.White
374+ };
375+
376+ // Auto-fade after 3 seconds
377+ _statusTimer?.Stop();
378+ _statusTimer = new DispatcherTimer
379+ {
380+ Interval = TimeSpan.FromSeconds(3)
381+ };
382+ _statusTimer.Tick += (s, e) =>
383+ {
384+ StatusText.Text = "";
385+ _statusTimer.Stop();
386+ };
387+ _statusTimer.Start();
388+ });
389+}
390+```
391+
392+## Dialog Windows
393+
394+### Modal Dialog Pattern
395+```csharp
396+var dialog = new SettingsWindow();
397+dialog.Owner = this;
398+dialog.ShowDialog(); // Blocks until closed
399+```
400+
401+### Confirmation Dialog
402+```csharp
403+var result = MessageBox.Show(
404+ "Are you sure you want to delete this?",
405+ "Confirm",
406+ MessageBoxButton.YesNo,
407+ MessageBoxImage.Question);
408+
409+if (result == MessageBoxResult.Yes)
410+{
411+ // Perform action
412+}
413+```
55414
