-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathManagerWindow.xaml.cs
More file actions
264 lines (229 loc) · 10 KB
/
ManagerWindow.xaml.cs
File metadata and controls
264 lines (229 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
namespace OverlayScope
{
/// <summary>
/// 複数のオーバーレイプロファイルを管理するためのメインウィンドウ。
/// </summary>
public partial class ManagerWindow : Window
{
#region Win32 API
/// <summary>
/// 指定されたウィンドウをフォアグラウンドにし、アクティブ化するためのWin32 API関数。
/// </summary>
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
#endregion
#region Private Nested Classes
/// <summary>
/// Webサーバーから取得するバージョン情報JSONを格納するためのクラス。
/// </summary>
private class UpdateInfo
{
public string? latestVersion { get; set; }
public string? releaseNotes { get; set; }
public string? githubUrl { get; set; }
public string? websiteUrl { get; set; }
}
#endregion
/// <summary>
/// UIにバインドされるプロファイルのコレクション。
/// </summary>
public ObservableCollection<OverlayProfile> Profiles { get; set; } = new();
public ManagerWindow()
{
InitializeComponent();
LoadProfiles();
this.DataContext = this; // XAMLがこのクラスのプロパティを参照できるように設定
// ウィンドウの表示が完了したタイミングで、更新確認処理を開始する
this.ContentRendered += ManagerWindow_ContentRendered;
}
#region Window Events
/// <summary>
/// ウィンドウの表示完了後に一度だけ呼び出されるイベントハンドラ。
/// </summary>
private async void ManagerWindow_ContentRendered(object? sender, EventArgs e)
{
// 更新確認がUIスレッドをブロックしないように非同期で実行
await CheckForUpdatesAsync();
}
/// <summary>
/// 管理ウィンドウが閉じられる時の処理。
/// </summary>
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 現在のプロファイル一覧をファイルに保存
SettingsManager.SaveProfiles(Profiles.ToList());
// 開いているすべてのオーバーレイウィンドウを閉じる
foreach (var profile in Profiles.ToList())
{
profile.ActiveWindow?.Close();
}
}
#endregion
#region Update Check Logic
/// <summary>
/// Webサーバーにバージョン情報を問い合わせ、新しいバージョンがあればユーザーに通知します。
/// </summary>
private async Task CheckForUpdatesAsync()
{
// バージョン情報が置かれているURL
string versionUrl = "http://masherhouse.com/wp-content/uploads/2025/08/version.json";
try
{
using (var client = new HttpClient())
{
// JSONファイルを非同期でダウンロード
string json = await client.GetStringAsync(versionUrl);
var updateInfo = JsonSerializer.Deserialize<UpdateInfo>(json);
if (updateInfo?.latestVersion == null) return;
// アプリ自身のバージョンを取得
var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
if (currentVersion == null) return;
var latestVersion = new Version(updateInfo.latestVersion);
// Webサーバー上のバージョンの方が新しければ、ユーザーに通知
if (latestVersion > currentVersion)
{
var dialog = new UpdateNotificationWindow(updateInfo.latestVersion, updateInfo.releaseNotes ?? "");
dialog.Owner = this;
dialog.ShowDialog();
// ダイアログの結果に応じてダウンロードページを開く
string urlToOpen = "";
if (dialog.Result == UpdateActionResult.GoToGitHub) { urlToOpen = updateInfo.githubUrl ?? ""; }
else if (dialog.Result == UpdateActionResult.GoToWebsite) { urlToOpen = updateInfo.websiteUrl ?? ""; }
if (!string.IsNullOrEmpty(urlToOpen))
{
Process.Start(new ProcessStartInfo(urlToOpen) { UseShellExecute = true });
}
}
}
}
catch (Exception)
{
// 更新の確認中にエラーが発生してもアプリの起動は妨げない (例: オフライン時)
}
}
#endregion
#region Profile Management
/// <summary>
/// JSONファイルからプロファイルの一覧を読み込みます。
/// </summary>
private void LoadProfiles()
{
var loadedProfiles = SettingsManager.LoadProfiles();
Profiles = new ObservableCollection<OverlayProfile>(loadedProfiles);
}
/// <summary>
/// 「新規作成」ボタンがクリックされた時の処理。
/// </summary>
private void CreateNew_Click(object sender, RoutedEventArgs e)
{
var newProfile = new OverlayProfile();
this.Hide(); // 範囲選択中は管理ウィンドウを非表示にする
AreaSelectorWindow selector = new AreaSelectorWindow();
if (selector.ShowDialog() == true && selector.SelectedArea.Width > 0)
{
// 選択された範囲で新しいプロファイルを作成
newProfile.CaptureArea = new System.Drawing.Rectangle(
(int)selector.SelectedArea.X, (int)selector.SelectedArea.Y,
(int)selector.SelectedArea.Width, (int)selector.SelectedArea.Height);
newProfile.WindowPosition = new System.Windows.Point(selector.SelectedArea.X, selector.SelectedArea.Y);
Profiles.Add(newProfile);
newProfile.IsActive = true;
ToggleOverlay(newProfile); // 新しいウィンドウを表示・アクティブ化
}
this.Show(); // 範囲選択が終わったら管理ウィンドウを再表示
}
/// <summary>
/// 「ON/OFF」ボタンがクリックされた時の処理。
/// </summary>
private void Toggle_Click(object sender, RoutedEventArgs e)
{
if (sender is ToggleButton toggleButton && toggleButton.Tag is OverlayProfile profile)
{
profile.IsActive = toggleButton.IsChecked ?? false;
ToggleOverlay(profile);
}
}
/// <summary>
/// 「設定変更」ボタンがクリックされた時の処理。
/// </summary>
private void Settings_Click(object sender, RoutedEventArgs e)
{
if (sender is Button button && button.Tag is OverlayProfile profile)
{
ActivateOverlay(profile);
}
}
/// <summary>
/// 「削除」ボタンがクリックされた時の処理。
/// </summary>
private void Delete_Click(object sender, RoutedEventArgs e)
{
if (sender is Button button && button.Tag is OverlayProfile profile)
{
if (MessageBox.Show($"「{profile.Name}」を削除しますか?", "削除の確認", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
// もし表示中なら、まずウィンドウを閉じる
if (profile.IsActive)
{
profile.IsActive = false;
ToggleOverlay(profile);
}
Profiles.Remove(profile);
}
}
}
/// <summary>
/// プロファイルの状態に基づいてオーバーレイウィンドウの表示/非表示を切り替えます。
/// </summary>
private void ToggleOverlay(OverlayProfile profile)
{
if (profile.IsActive)
{
// ウィンドウがまだ存在しない場合のみ、新しく作成する
if (profile.ActiveWindow == null)
{
var overlay = new MainWindow(profile);
overlay.Owner = this;
profile.ActiveWindow = overlay;
overlay.Show();
}
ActivateOverlay(profile);
}
else
{
// ウィンドウを閉じる
profile.ActiveWindow?.Close();
profile.ActiveWindow = null;
}
}
/// <summary>
/// 指定されたプロファイルのオーバーレイウィンドウをアクティブ化します。
/// </summary>
private void ActivateOverlay(OverlayProfile profile)
{
if (profile.IsActive && profile.ActiveWindow != null)
{
var helper = new WindowInteropHelper(profile.ActiveWindow);
if (helper.Handle != System.IntPtr.Zero)
{
SetForegroundWindow(helper.Handle);
}
}
}
#endregion
}
}