-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathXgDictList.cpp
378 lines (329 loc) · 14 KB
/
XgDictList.cpp
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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
// ラジオボタン風の状態を表示するためのイメージリストを作成する。
HIMAGELIST XgDictList_CreateRadioButtonImageList(HWND hwnd)
{
HIMAGELIST himl;
HDC hdc_wnd, hdc;
HBITMAP hbm_im, hbm_mask;
HGDIOBJ hbm_orig;
HBRUSH hbr_white = GetStockBrush(WHITE_BRUSH), hbr_black = GetStockBrush(BLACK_BRUSH);
RECT rc;
// 小さいイメージリストを作成する。
himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
ILC_COLOR | ILC_MASK, 2, 2);
// いろいろ準備。
hdc_wnd = GetDC(hwnd);
hdc = CreateCompatibleDC(hdc_wnd);
hbm_im = CreateCompatibleBitmap(hdc_wnd, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
hbm_mask = CreateBitmap(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 1, 1, NULL);
ReleaseDC(hwnd, hdc_wnd);
// マスクビットマップを描画。
SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
hbm_orig = SelectObject(hdc, hbm_mask);
FillRect(hdc, &rc, hbr_white);
InflateRect(&rc, -1, -1);
SelectObject(hdc, hbr_black);
Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
// チェックしていないアイコンを追加。
SelectObject(hdc, hbm_im);
SelectObject(hdc, GetSysColorBrush(COLOR_WINDOW));
Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
SelectObject(hdc, hbm_orig);
ImageList_Add(himl, hbm_im, hbm_mask);
// チェック済みのアイコンを追加。
SelectObject(hdc, hbm_im);
SelectObject(hdc, GetSysColorBrush(COLOR_WINDOW));
Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
InflateRect(&rc, -3, -3);
SelectObject(hdc, GetSysColorBrush(COLOR_WINDOWTEXT));
Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
SelectObject(hdc, hbm_orig);
ImageList_Add(himl, hbm_im, hbm_mask);
// 後片付け。
DeleteObject(hbm_mask);
DeleteObject(hbm_im);
DeleteDC(hdc);
return himl;
}
// リストを再読み込みする。
void XgDictList_ReloadList(HWND hwnd)
{
HWND hwndLst1 = GetDlgItem(hwnd, lst1);
// すべての項目を消去する。
ListView_DeleteAllItems(hwndLst1);
SendDlgItemMessageW(hwnd, cmb1, CB_RESETCONTENT, 0, 0);
// 辞書リストを読み込む。
XgLoadDictsAll();
// リストビューを埋める。
INT iItem = 0;
for (auto& entry : xg_dicts) {
LV_ITEMW item = { LVIF_TEXT };
// リストビューに一行追加する。列「ファイル名」のテキストを設定。
item.pszText = const_cast<LPWSTR>(PathFindFileNameW(entry.m_filename.c_str()));
item.iItem = iItem;
item.iSubItem = 0;
ListView_InsertItem(hwndLst1, &item);
// 列「表示名」のテキストを設定。
item.iItem = iItem;
item.iSubItem = 1;
item.pszText = const_cast<LPWSTR>(entry.m_friendly_name.c_str());
ListView_SetItem(hwndLst1, &item);
// ファイルの更新日時を取得するために、FindFirstFile関数を使う。
WIN32_FIND_DATAW find;
HANDLE hFind = ::FindFirstFileW(entry.m_filename.c_str(), &find);
::FindClose(hFind);
// 更新日時に従って文字列を構築する。
WCHAR szText[32];
FILETIME ftLocal;
SYSTEMTIME st;
if (hFind == INVALID_HANDLE_VALUE)
{
StringCchCopyW(szText, _countof(szText), L"N/A");
}
else
{
::FileTimeToLocalFileTime(&find.ftLastWriteTime, &ftLocal);
::FileTimeToSystemTime(&ftLocal, &st);
StringCchPrintfW(szText, _countof(szText), L"%04d-%02d-%02d %02d:%02d",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);
}
// 列「更新日時」のテキストを設定。
item.iItem = iItem;
item.iSubItem = 2;
item.pszText = szText;
ListView_SetItem(hwndLst1, &item);
++iItem;
}
// コンボボックスを埋める。
for (auto& item : xg_dicts) {
LPCWSTR pszText = PathFindFileNameW(item.m_filename.c_str());
::SendDlgItemMessageW(hwnd, cmb1, CB_ADDSTRING, 0, (LPARAM)pszText);
}
// コンボボックスの項目を選択する。
{
LPCWSTR pszText = PathFindFileNameW(xg_dict_name.c_str());
INT iItem = ::SendDlgItemMessageW(hwnd, cmb1, CB_FINDSTRINGEXACT, -1, (LPARAM)pszText);
if (iItem != CB_ERR) {
::SendDlgItemMessageW(hwnd, cmb1, CB_SETCURSEL, iItem, 0);
}
}
// リストビューの項目を選択する。
LV_FINDINFO Find = { LVFI_STRING, PathFindFileNameW(xg_dict_name.c_str()) };
iItem = ListView_FindItem(hwndLst1, -1, &Find);
ListView_SetItemState(hwndLst1, iItem, INDEXTOSTATEIMAGEMASK(2), LVIS_STATEIMAGEMASK);
ListView_EnsureVisible(hwndLst1, iItem, FALSE);
}
// リストビューのチェック位置を取得する。
INT XgDictList_GetCurSel(HWND hwnd, HWND hwndLst1)
{
INT cItems = ListView_GetItemCount(hwndLst1);
for (INT iItem = 0; iItem < cItems; ++iItem) {
UINT uState = ListView_GetItemState(hwndLst1, iItem, LVIS_STATEIMAGEMASK);
if (uState & INDEXTOSTATEIMAGEMASK(2))
return iItem;
}
return -1;
}
// リストビューのチェック情報を更新する。
void XgDictList_SetCurSel(HWND hwnd, HWND hwndLst1, INT iSelect)
{
INT cItems = ListView_GetItemCount(hwndLst1);
for (INT iItem = 0; iItem < cItems; ++iItem) {
if (iItem == iSelect) {
ListView_SetItemState(hwndLst1, iItem, INDEXTOSTATEIMAGEMASK(2), LVIS_STATEIMAGEMASK);
} else {
ListView_SetItemState(hwndLst1, iItem, INDEXTOSTATEIMAGEMASK(1), LVIS_STATEIMAGEMASK);
}
}
ListView_SetItemState(hwndLst1, iSelect, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
ListView_EnsureVisible(hwndLst1, iSelect, FALSE);
}
// [辞書]設定。
INT_PTR CALLBACK
XgDictListDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static INT m_bUpdating = 0;
HWND hwndLst1 = GetDlgItem(hwnd, lst1);
switch (uMsg)
{
case WM_INITDIALOG:
{
xg_ahSyncedDialogs[I_SYNCED_DICTLIST] = hwnd;
// 拡張リストビュースタイルを設定。
ListView_SetExtendedListViewStyle(hwndLst1,
LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_CHECKBOXES);
// 辞書リストのヘッダーの初期化を開始。
LV_COLUMNW column = { LVCF_TEXT | LVCF_WIDTH };
// ファイル名。
column.pszText = XgLoadStringDx1(IDS_FILENAME);
column.cx = 200;
ListView_InsertColumn(hwndLst1, 0, &column);
// 表示名。
column.pszText = XgLoadStringDx1(IDS_DISPLAYNAME);
column.cx = 250;
ListView_InsertColumn(hwndLst1, 1, &column);
// 更新日時。
column.pszText = XgLoadStringDx1(IDS_UPDATEDTIME);
column.cx = 125;
ListView_InsertColumn(hwndLst1, 2, &column);
// イメージリストを設定。
HIMAGELIST himl = XgDictList_CreateRadioButtonImageList(hwnd);
ListView_SetImageList(hwndLst1, himl, LVSIL_STATE);
// リストを再読み込みする。
++m_bUpdating;
XgDictList_ReloadList(hwnd);
--m_bUpdating;
}
return TRUE;
case WM_COMMAND:
// 変更があれば「更新」ボタンを有効にする。
switch (LOWORD(wParam))
{
case psh1:
if (HIWORD(wParam) == BN_CLICKED)
PropSheet_Changed(GetParent(hwnd), hwnd);
break;
case cmb1:
if (HIWORD(wParam) == CBN_EDITCHANGE ||
HIWORD(wParam) == CBN_SELCHANGE ||
HIWORD(wParam) == CBN_SELENDOK)
{
PropSheet_Changed(GetParent(hwnd), hwnd);
}
break;
}
// 実際の処理。
switch (LOWORD(wParam))
{
case psh1: // ファイルを開く。
if (HIWORD(wParam) == BN_CLICKED) {
INT iItem = XgDictList_GetCurSel(hwnd, hwndLst1);
// コンボボックスからテキストを取得。
WCHAR szText[MAX_PATH];
szText[0] = 0;
SendDlgItemMessageW(hwnd, cmb1, CB_GETLBTEXT, iItem, (LPARAM)szText);
szText[_countof(szText) - 1] = 0;
// パスファイル名を構築する。
WCHAR szPath[MAX_PATH];
GetModuleFileNameW(NULL, szPath, _countof(szPath));
PathRemoveFileSpecW(szPath);
PathAppendW(szPath, L"DICT");
PathAppendW(szPath, szText);
// シェルで開く。開けなければメモ帳で開く。
SHELLEXECUTEINFOW info = { sizeof(info), SEE_MASK_FLAG_NO_UI, hwnd };
info.lpFile = szPath;
if (!ShellExecuteExW(&info)) {
WCHAR szQuotedPath[MAX_PATH];
StringCchPrintfW(szQuotedPath, _countof(szQuotedPath), L"\"%s\"", szPath);
info.lpFile = L"notepad.exe";
info.lpParameters = szQuotedPath;
info.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&info);
}
}
break;
case psh2: // フォルダを開く。
if (HIWORD(wParam) == BN_CLICKED) {
WCHAR szPath[MAX_PATH];
GetModuleFileNameW(NULL, szPath, _countof(szPath));
PathRemoveFileSpecW(szPath);
PathAppendW(szPath, L"DICT");
ShellExecuteW(hwnd, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);
}
break;
case psh4: // 再読み込み。
XgDictList_ReloadList(hwnd);
break;
case psh5: // テーマ。
// 変更点を適用する。
PropSheet_Apply(GetParent(hwnd));
// テーマを開く。
XgTheme(hwnd);
break;
case cmb1:
if (HIWORD(wParam) == CBN_EDITCHANGE ||
HIWORD(wParam) == CBN_SELCHANGE ||
HIWORD(wParam) == CBN_SELENDOK)
{
if (m_bUpdating)
break;
// コンボボックスで現在選択されているテキストを取得。
INT iItem = (INT)::SendDlgItemMessageW(hwnd, cmb1, CB_GETCURSEL, 0, 0);
if (iItem == CB_ERR)
return 0;
// コンボボックスからテキストを取得。
WCHAR szText[MAX_PATH];
szText[0] = 0;
SendDlgItemMessageW(hwnd, cmb1, CB_GETLBTEXT, iItem, (LPARAM)szText);
szText[_countof(szText) - 1] = 0;
// リストビューからテキストを探す。
LV_FINDINFO Find = { LVFI_STRING, szText };
iItem = ListView_FindItem(hwndLst1, -1, &Find);
// リストビューの選択を更新する。
m_bUpdating++;
XgDictList_SetCurSel(hwnd, hwndLst1, iItem);
m_bUpdating--;
}
break;
}
break;
case WM_NOTIFY:
{
NMHDR *pnmhdr = (NMHDR *)lParam;
auto pListView = (NM_LISTVIEW *)lParam;
switch (pnmhdr->code) {
case PSN_APPLY: // 適用
{
INT iItem = XgDictList_GetCurSel(hwnd, hwndLst1);
// コンボボックスからテキストを取得。
WCHAR szText[MAX_PATH];
szText[0] = 0;
SendDlgItemMessageW(hwnd, cmb1, CB_GETLBTEXT, iItem, (LPARAM)szText);
szText[_countof(szText) - 1] = 0;
// パスファイル名を構築する。
WCHAR szPath[MAX_PATH];
GetModuleFileNameW(NULL, szPath, _countof(szPath));
PathRemoveFileSpecW(szPath);
PathAppendW(szPath, L"DICT");
PathAppendW(szPath, szText);
// 辞書を指定する。
xg_dict_name = szPath;
// ステータスバーを更新。
XgUpdateStatusBar(xg_hMainWnd);
// 再読み込み。
XgDictList_ReloadList(hwnd);
}
break;
case LVN_ITEMCHANGED:
if (pnmhdr->idFrom == lst1 && !m_bUpdating && (pListView->uNewState & LVIS_SELECTED)) {
// リストビューの選択が変わった。
HWND hwndLst1 = GetDlgItem(hwnd, lst1);
// テキストを取得。
WCHAR szText[MAX_PATH];
LV_ITEMW item = { LVIF_TEXT };
item.pszText = szText;
item.cchTextMax = _countof(szText);
item.iItem = pListView->iItem;
item.iSubItem = 0;
ListView_GetItem(hwndLst1, &item);
// リストビューのチェック状態を更新する。
m_bUpdating++;
XgDictList_SetCurSel(hwnd, hwndLst1, pListView->iItem);
m_bUpdating--;
// コンボボックスからテキストを探す。
INT iItem = (INT)::SendDlgItemMessageW(hwnd, cmb1, CB_FINDSTRINGEXACT, -1, (LPARAM)szText);
if (iItem != CB_ERR) {
// コンボボックスの選択を変更する。
m_bUpdating++;
::SendDlgItemMessageW(hwnd, cmb1, CB_SETCURSEL, iItem, 0);
m_bUpdating--;
// 更新ボタンを有効にする。
PropSheet_Changed(GetParent(hwnd), hwnd);
}
}
break;
}
}
break;
}
return 0;
}