Repository navigation
Expand file tree
/
Copy pathgui_menu.cpp
More file actions
436 lines (411 loc) · 23.2 KB
/
Copy pathgui_menu.cpp
File metadata and controls
436 lines (411 loc) · 23.2 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
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
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
// Menu construction, synchronization, and owner drawing.
#include "gui_menu.hpp"
#include "gui_frf.hpp"
#include "gui_hotkeys.hpp"
#include "gui_controls.hpp"
#include "gui_state.hpp"
#include "gui_theme.hpp"
#include "gui_text.hpp"
#include "gui_ids.hpp"
#include "gui_documents.hpp"
#include "gui_playback.hpp"
#include "gui_side_panel.hpp"
#include "gui_settings.hpp"
#include "gui_analysis_source.hpp"
namespace gui {
std::wstring menu_text(const wchar_t* base, int command) {
const HotkeyBinding* binding = find_hotkey_binding(command);
if (!binding || binding->key == 0) return base;
std::wstring hk = hotkey_text(binding->fvirt, binding->key);
if (hk.empty()) return base;
return std::wstring(base) + L"\t" + hk;
}
void append_menu_popup_owner_draw(HMENU menu, HMENU popup, const std::wstring& text,
bool top_level) {
AppendMenuW(
menu,
MF_OWNERDRAW | MF_POPUP,
reinterpret_cast<UINT_PTR>(popup),
reinterpret_cast<LPCWSTR>(stash_menu_entry(text, top_level, true)));
}
void append_menu_item_owner_draw(HMENU menu, UINT id, const std::wstring& text,
const std::wstring& subtitle, bool recent_file) {
AppendMenuW(
menu,
MF_OWNERDRAW | MF_STRING,
id,
reinterpret_cast<LPCWSTR>(stash_menu_entry(text, false, false, subtitle, recent_file)));
}
void modify_menu_item_owner_draw(HMENU menu, UINT id, const std::wstring& text) {
ModifyMenuW(
menu,
id,
MF_BYCOMMAND | MF_OWNERDRAW,
id,
reinterpret_cast<LPCWSTR>(stash_menu_entry(text, false, false)));
}
std::wstring menu_item_left_text(const std::wstring& text) {
std::size_t tab = text.find(L'\t');
return (tab == std::wstring::npos) ? text : text.substr(0, tab);
}
std::wstring menu_item_right_text(const std::wstring& text) {
std::size_t tab = text.find(L'\t');
return (tab == std::wstring::npos) ? L"" : text.substr(tab + 1);
}
void measure_owner_draw_menu(MEASUREITEMSTRUCT* mis) {
if (!mis || mis->CtlType != ODT_MENU) return;
const OwnerDrawMenuEntry* entry = reinterpret_cast<const OwnerDrawMenuEntry*>(mis->itemData);
const std::wstring text = entry ? entry->text : L"";
const std::wstring subtitle = entry ? entry->subtitle : L"";
const std::wstring left = menu_item_left_text(text);
const std::wstring right = menu_item_right_text(text);
HDC dc = GetDC(g.main ? g.main : nullptr);
HFONT font = (entry && entry->top_level && g.menu_font)
? g.menu_font
: (g.ui_font ? g.ui_font : reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT)));
HGDIOBJ old_font = SelectObject(dc, font);
SIZE left_sz{};
SIZE right_sz{};
GetTextExtentPoint32W(dc, left.c_str(), static_cast<int>(left.size()), &left_sz);
GetTextExtentPoint32W(dc, right.c_str(), static_cast<int>(right.size()), &right_sz);
SIZE subtitle_sz{};
if (!subtitle.empty()) GetTextExtentPoint32W(dc, subtitle.c_str(), static_cast<int>(subtitle.size()), &subtitle_sz);
SelectObject(dc, old_font);
ReleaseDC(g.main ? g.main : nullptr, dc);
if (entry && entry->top_level) {
mis->itemWidth = left_sz.cx + 24;
mis->itemHeight = max(34u, static_cast<UINT>(left_sz.cy + 18));
return;
}
const UINT check_col = 28;
const UINT left_pad = 10;
const UINT right_pad = 12;
const UINT gap = right.empty() ? 0 : 24;
const UINT arrow_space = (entry && entry->popup) ? 18 : 0;
const LONG content_width = entry && entry->recent_file
? min<LONG>(360, max(left_sz.cx, subtitle_sz.cx))
: left_sz.cx;
mis->itemWidth = check_col + left_pad + content_width + gap + right_sz.cx + arrow_space + right_pad;
mis->itemHeight = entry && entry->recent_file
? max(42u, static_cast<UINT>(left_sz.cy + subtitle_sz.cy + 15))
: max(24u, static_cast<UINT>(max(left_sz.cy, right_sz.cy) + 10));
}
void draw_owner_draw_menu(const DRAWITEMSTRUCT* dis) {
if (!dis || dis->CtlType != ODT_MENU) return;
auto blend = [](COLORREF a, COLORREF b, int weight_b) {
weight_b = std::clamp(weight_b, 0, 255);
const int weight_a = 255 - weight_b;
return RGB(
(GetRValue(a) * weight_a + GetRValue(b) * weight_b) / 255,
(GetGValue(a) * weight_a + GetGValue(b) * weight_b) / 255,
(GetBValue(a) * weight_a + GetBValue(b) * weight_b) / 255);
};
const OwnerDrawMenuEntry* entry = reinterpret_cast<const OwnerDrawMenuEntry*>(dis->itemData);
const std::wstring text = entry ? entry->text : L"";
const std::wstring subtitle = entry ? entry->subtitle : L"";
const std::wstring left = menu_item_left_text(text);
const std::wstring right = menu_item_right_text(text);
RECT r = dis->rcItem;
const bool selected = (dis->itemState & ODS_SELECTED) != 0;
const bool hot = selected || (dis->itemState & ODS_HOTLIGHT) != 0;
const bool disabled = (dis->itemState & ODS_DISABLED) != 0;
const bool checked = (dis->itemState & ODS_CHECKED) != 0;
COLORREF bg = hot ? g_theme->btn_hover : g_theme->bg_toolbar;
COLORREF text_col = disabled ? g_theme->text_secondary : g_theme->text_primary;
HBRUSH bg_brush = CreateSolidBrush(bg);
FillRect(dis->hDC, &r, bg_brush);
DeleteObject(bg_brush);
SetBkMode(dis->hDC, TRANSPARENT);
SetTextColor(dis->hDC, text_col);
HFONT font = (entry && entry->top_level && g.menu_font)
? g.menu_font
: (g.ui_font ? g.ui_font : reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT)));
HGDIOBJ old_font = SelectObject(dis->hDC, font);
if (entry && entry->top_level) {
RECT text_rect = r;
text_rect.bottom -= 1;
if (hot && !disabled) {
RECT hi = r;
hi.left += 1;
hi.right -= 1;
hi.top += 1;
hi.bottom -= 1;
const int accent_weight = (g_theme == &kDarkTheme) ? 42 : 58;
const COLORREF hi_fill = blend(g_theme->bg_toolbar, g_theme->accent, accent_weight);
const COLORREF hi_border = blend(g_theme->btn_border, g_theme->accent, (g_theme == &kDarkTheme) ? 88 : 120);
fill_rounded_rect(dis->hDC, hi, hi_fill, hi_border, 4);
text_col = (g_theme == &kDarkTheme) ? RGB(255, 255, 255) : g_theme->accent_hover;
SetTextColor(dis->hDC, text_col);
RECT underline = { hi.left + 5, hi.bottom - 1, hi.right - 5, hi.bottom };
HBRUSH underline_brush = CreateSolidBrush(g_theme->accent);
FillRect(dis->hDC, &underline, underline_brush);
DeleteObject(underline_brush);
}
DrawTextW(
dis->hDC, left.c_str(), -1, &text_rect,
DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
SelectObject(dis->hDC, old_font);
return;
}
RECT check_rect = r;
check_rect.right = check_rect.left + 28;
RECT left_rect = r;
left_rect.left = check_rect.right + 10;
RECT right_rect = r;
right_rect.right = r.right - 12 - ((entry && entry->popup) ? 18 : 0);
SIZE shortcut_size{};
GetTextExtentPoint32W(dis->hDC, right.c_str(), static_cast<int>(right.size()), &shortcut_size);
right_rect.left = max(left_rect.left, right_rect.right - shortcut_size.cx);
left_rect.right = right.empty() ? right_rect.right : right_rect.left - 24;
if (entry && entry->recent_file) {
RECT card = r;
InflateRect(&card, -3, -2);
if (hot) fill_rounded_rect(dis->hDC, card, mix_color(g_theme->btn_hover, g_theme->accent, 24),
mix_color(g_theme->btn_border, g_theme->accent, 88), 5);
left_rect.top += 4;
left_rect.bottom = (r.top + r.bottom) / 2 + 2;
DrawTextW(dis->hDC, left.c_str(), -1, &left_rect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS);
RECT subtitle_rect = left_rect;
subtitle_rect.top = left_rect.bottom;
subtitle_rect.bottom = r.bottom - 4;
SetTextColor(dis->hDC, disabled ? g_theme->text_secondary : mix_color(g_theme->text_secondary, g_theme->bg_toolbar, 28));
DrawTextW(dis->hDC, subtitle.c_str(), -1, &subtitle_rect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS);
SetTextColor(dis->hDC, text_col);
} else {
DrawTextW(
dis->hDC, left.c_str(), -1, &left_rect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS);
}
if (!right.empty()) {
DrawTextW(
dis->hDC, right.c_str(), -1, &right_rect,
DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
}
if (checked) {
RECT box = check_rect;
box.left += 7;
box.right = box.left + 14;
box.top = r.top + max(0L, ((r.bottom - r.top) - 14) / 2);
box.bottom = box.top + 14;
HBRUSH accent_brush = CreateSolidBrush(g_theme->btn_active);
FillRect(dis->hDC, &box, accent_brush);
DeleteObject(accent_brush);
HPEN pen = CreatePen(PS_SOLID, 2, RGB(255, 255, 255));
HGDIOBJ old_pen = SelectObject(dis->hDC, pen);
MoveToEx(dis->hDC, box.left + 3, box.top + 7, nullptr);
LineTo(dis->hDC, box.left + 6, box.top + 10);
LineTo(dis->hDC, box.right - 3, box.top + 4);
SelectObject(dis->hDC, old_pen);
DeleteObject(pen);
}
if (entry && entry->popup) {
POINT pts[3] = {
{ r.right - 12, r.top + (r.bottom - r.top) / 2 - 4 },
{ r.right - 12, r.top + (r.bottom - r.top) / 2 + 4 },
{ r.right - 7, r.top + (r.bottom - r.top) / 2 }
};
HBRUSH arrow_brush = CreateSolidBrush(text_col);
HPEN arrow_pen = CreatePen(PS_SOLID, 1, text_col);
HGDIOBJ old_brush = SelectObject(dis->hDC, arrow_brush);
HGDIOBJ old_pen = SelectObject(dis->hDC, arrow_pen);
Polygon(dis->hDC, pts, 3);
SelectObject(dis->hDC, old_pen);
SelectObject(dis->hDC, old_brush);
DeleteObject(arrow_pen);
DeleteObject(arrow_brush);
// Windows draws its submenu arrow after WM_DRAWITEM, even for
// MF_OWNERDRAW. Keep that second glyph off our themed item. The
// menu manager restores the DC before drawing the next item.
ExcludeClipRect(dis->hDC, r.left, r.top, r.right, r.bottom);
}
SelectObject(dis->hDC, old_font);
}
// Refresh every checkable menu item from the current app state. Cheap, so we
// just call it whenever a toggle changes (menu, toolbar, or accelerator).
void sync_menu() {
if (g.mode_time) EnableWindow(g.mode_time, !g.ds.frequency_axis);
const bool frf_available = has_data() && !g.ds.frequency_axis && g.ds.channel_count() >= 2;
if (g.mode_frf) EnableWindow(g.mode_frf, frf_available);
for (HWND button : g.buttons) {
if (button && !frf_command_supported(GetDlgCtrlID(button))) EnableWindow(button, g.mode != AnalysisMode::FRF);
}
if (!g.menu) return;
EnableMenuItem(g.menu,IDM_STOP_PLAYBACK,MF_BYCOMMAND |
(g.mode==AnalysisMode::Time && g.playhead_active ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(g.menu, IDM_MODE_FRF, MF_BYCOMMAND | (frf_available ? MF_ENABLED : MF_GRAYED));
for(auto id:{IDM_ANALYSIS_ENTIRE,IDM_ANALYSIS_INTERVAL,IDM_ANALYSIS_VISIBLE})
EnableMenuItem(g.menu,id,MF_BYCOMMAND | (has_data() && !g.ds.frequency_axis ? MF_ENABLED : MF_GRAYED));
CheckMenuItem(g.menu,IDM_ANALYSIS_ENTIRE,MF_BYCOMMAND | (!has_fft_window() ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(g.menu,IDM_ANALYSIS_INTERVAL,MF_BYCOMMAND | (has_fft_window() ? MF_CHECKED : MF_UNCHECKED));
for (int id : {IDC_PLAY, IDC_MEASURE, IDM_ADD_MARKER, IDM_ADD_VLINE, IDM_ADD_HLINE,
IDM_ADD_LINE_EXACT, IDM_CLEAR_POINTS, IDM_CLEAR_MARKERS, IDM_CLEAR_LINES,
IDM_VISMOOTH, IDM_CURVE_SYMBOLS})
EnableMenuItem(g.menu, id, MF_BYCOMMAND |
(g.mode == AnalysisMode::FRF && !frf_command_supported(id) ? MF_GRAYED : MF_ENABLED));
EnableMenuItem(g.menu, IDM_MODE_TIME, MF_BYCOMMAND | (g.ds.frequency_axis ? MF_GRAYED : MF_ENABLED));
auto chk = [&](UINT id, bool on) {
CheckMenuItem(g.menu, id, MF_BYCOMMAND | (on ? MF_CHECKED : MF_UNCHECKED));
};
chk(IDM_MODE_TIME, (g.mode == AnalysisMode::Time));
chk(IDM_MODE_FREQ, (g.mode == AnalysisMode::FFT));
chk(IDM_MODE_FRF, g.mode == AnalysisMode::FRF);
chk(IDM_VISMOOTH, g.visual_smooth);
chk(IDM_CURVE_SYMBOLS, g.distinguish_curves);
chk(IDM_CHANNEL_LEGEND, g.show_channel_legend);
chk(IDM_MARKER_VALUES, g.show_marker_values);
EnableMenuItem(g.menu, IDM_CHANNEL_LEGEND, MF_BYCOMMAND |
(g.mode == AnalysisMode::FRF ? MF_GRAYED : MF_ENABLED));
chk(IDM_VPAN, g.vertical_pan);
chk(IDC_MEASURE, g.measure_mode);
chk(IDC_CURSOR_TOOL, !g.measure_mode && !g.pending_marker && g.pending_line == 0);
chk(IDM_ADD_MARKER, g.pending_marker);
chk(IDM_ADD_VLINE, g.pending_line == 1);
chk(IDM_ADD_HLINE, g.pending_line == 2);
chk(IDC_AUTOY, g.mode == AnalysisMode::FRF ? (g.frf.auto_y && g.frf.reference_auto_y) : g.auto_y);
chk(IDM_THEME, g_theme == &kDarkTheme);
chk(IDM_LANG_RU, g_str == &kRu);
chk(IDM_LANG_EN, g_str == &kEn);
std::wstring theme_label = menu_text(g_theme == &kDarkTheme ? g_str->theme_light : g_str->theme_dark, IDM_THEME);
modify_menu_item_owner_draw(g.menu, IDM_THEME, theme_label);
redraw_toolbar_buttons();
}
HMENU make_menu() {
const bool english = (g_str == &kEn);
const auto text = [english](const wchar_t* english_text, const wchar_t* russian_text) {
return english ? english_text : russian_text;
};
const HMENU bar = CreateMenu();
const HMENU file = CreatePopupMenu();
const std::wstring open_text = menu_text(text(L"Open file…", L"Открыть файл…"), IDC_OPEN);
const std::wstring save_png_text = menu_text(text(L"Save PNG…", L"Сохранить PNG…"), IDC_SAVEPNG);
const std::wstring save_as_text = menu_text(text(L"Save as…", L"Сохранить как…"), IDC_SAVECSV);
const std::wstring undo_text = menu_text(text(L"Undo", L"Отменить"), IDM_UNDO);
const std::wstring redo_text = menu_text(text(L"Redo", L"Повторить"), IDM_REDO);
append_menu_item_owner_draw(file, IDC_OPEN, open_text);
append_menu_item_owner_draw(file, IDM_OPEN_INTERVAL, text(L"Open recording interval…", L"Открыть участок записи…"));
const HMENU recent = CreatePopupMenu();
if (g.recent_files.empty()) {
append_menu_item_owner_draw(recent, IDM_RECENT_FILE_BASE, text(L"No recent files", L"Недавних файлов нет"));
EnableMenuItem(recent, IDM_RECENT_FILE_BASE, MF_BYCOMMAND | MF_GRAYED);
} else {
for (std::size_t i = 0; i < g.recent_files.size() && i < kMaxRecentFiles; ++i) {
const std::wstring& path = g.recent_files[i];
const std::size_t slash = path.find_last_of(L"\\/");
const std::wstring name = slash == std::wstring::npos ? path : path.substr(slash + 1);
const std::wstring folder = slash == std::wstring::npos ? L"" : path.substr(0, slash);
append_menu_item_owner_draw(recent, IDM_RECENT_FILE_BASE + static_cast<int>(i),
name, folder, true);
}
}
append_menu_popup_owner_draw(file, recent, text(L"Recent files", L"Недавние файлы"), false);
const HMENU documents = CreatePopupMenu();
const std::size_t document_count = open_document_count();
if (document_count == 0) {
append_menu_item_owner_draw(documents, IDM_OPEN_DOCUMENT_BASE,
text(L"No open files", L"Нет открытых файлов"));
EnableMenuItem(documents, IDM_OPEN_DOCUMENT_BASE, MF_BYCOMMAND | MF_GRAYED);
} else {
const std::size_t max_documents = static_cast<std::size_t>(IDM_CLOSE_DOCUMENT - IDM_OPEN_DOCUMENT_BASE);
for (std::size_t i = 0; i < document_count && i < max_documents; ++i) {
append_menu_item_owner_draw(documents, IDM_OPEN_DOCUMENT_BASE + static_cast<int>(i),
open_document_label(i, true));
}
AppendMenuW(documents, MF_SEPARATOR, 0, nullptr);
append_menu_item_owner_draw(documents, IDM_CLOSE_DOCUMENT,
text(L"Close current file", L"Закрыть текущий файл"));
}
append_menu_popup_owner_draw(file, documents, text(L"Open files", L"Открытые файлы"), false);
append_menu_item_owner_draw(file, IDC_SAVEPNG, save_png_text);
append_menu_item_owner_draw(file, IDC_SAVECSV, save_as_text);
AppendMenuW(file, MF_SEPARATOR, 0, nullptr);
append_menu_item_owner_draw(file, IDM_UNDO, undo_text);
append_menu_item_owner_draw(file, IDM_REDO, redo_text);
AppendMenuW(file, MF_SEPARATOR, 0, nullptr);
append_menu_item_owner_draw(file, IDM_EXIT, text(L"Exit\tAlt+F4", L"Выход\tAlt+F4"));
append_menu_popup_owner_draw(bar, file, text(L"File", L"Файл"));
const HMENU view = CreatePopupMenu();
const std::wstring mode_time_text = menu_text(text(L"Signal", L"Сигнал"), IDM_MODE_TIME);
const std::wstring mode_freq_text = menu_text(text(L"Spectrum (FFT)", L"Спектр (БПФ)"), IDM_MODE_FREQ);
const std::wstring zoom_in_text = menu_text(text(L"Zoom in", L"Увеличить"), IDC_ZOOMIN);
const std::wstring zoom_out_text = menu_text(text(L"Zoom out", L"Уменьшить"), IDC_ZOOMOUT);
const std::wstring reset_text = menu_text(text(L"Reset view", L"Сбросить вид"), IDC_RESET);
const std::wstring start_text = menu_text(text(L"Go to start", L"В начало"), IDC_GOTO_START);
const std::wstring end_text = menu_text(text(L"Go to end", L"В конец"), IDC_GOTO_END);
const std::wstring autoy_text = menu_text(text(L"Auto scale", L"Автомасштабирование"), IDC_AUTOY);
const std::wstring smooth_text = menu_text(text(L"Channel smoothing", L"Сглаживание каналов"), IDM_VISMOOTH);
const std::wstring curve_symbols_text = menu_text(
text(L"Curve symbols for grayscale", L"Фигуры кривых для Ч/Б"), IDM_CURVE_SYMBOLS);
const std::wstring vpan_text = menu_text(text(L"Vertical pan", L"Вертикальное панорамирование"), IDM_VPAN);
const std::wstring play_text = menu_text(text(L"Play / Pause signal", L"Воспроизведение / пауза сигнала"), IDC_PLAY);
const std::wstring theme_text = menu_text(text(L"Dark theme", L"Тёмная тема"), IDM_THEME);
append_menu_item_owner_draw(view, IDM_MODE_TIME, mode_time_text);
append_menu_item_owner_draw(view, IDM_MODE_FREQ, mode_freq_text);
append_menu_item_owner_draw(view, IDM_MODE_FRF, text(L"FRF / Frequency response", L"FRF / АЧХ"));
AppendMenuW(view, MF_SEPARATOR, 0, nullptr);
append_menu_item_owner_draw(view, IDC_ZOOMIN, zoom_in_text);
append_menu_item_owner_draw(view, IDC_ZOOMOUT, zoom_out_text);
append_menu_item_owner_draw(view, IDC_RESET, reset_text);
append_menu_item_owner_draw(view, IDC_GOTO_START, start_text);
append_menu_item_owner_draw(view, IDC_GOTO_END, end_text);
AppendMenuW(view, MF_SEPARATOR, 0, nullptr);
append_menu_item_owner_draw(view, IDC_AUTOY, autoy_text);
append_menu_item_owner_draw(view, IDM_VISMOOTH, smooth_text);
append_menu_item_owner_draw(view, IDM_CURVE_SYMBOLS, curve_symbols_text);
append_menu_item_owner_draw(view, IDM_CHANNEL_LEGEND, menu_text(text(L"Channel legend", L"Легенда каналов"),IDM_CHANNEL_LEGEND));
append_menu_item_owner_draw(view, IDM_MARKER_VALUES, menu_text(text(L"Marker values", L"Значения маркеров"),IDM_MARKER_VALUES));
append_menu_item_owner_draw(view, IDM_VPAN, vpan_text);
append_menu_item_owner_draw(view, IDC_PLAY, play_text);
append_menu_item_owner_draw(view,IDM_STOP_PLAYBACK,text(L"Stop and hide timeline",L"Остановить и убрать таймлайн"));
append_menu_item_owner_draw(view, IDM_SPEED_CUSTOM, speed_menu_text());
append_menu_item_owner_draw(view, IDM_THEME, theme_text);
append_menu_popup_owner_draw(bar, view, text(L"View", L"Вид"));
const HMENU analysis=CreatePopupMenu();
append_menu_item_owner_draw(analysis,IDM_ANALYSIS_ENTIRE,menu_text(text(L"Entire recording",L"Вся запись"),IDM_ANALYSIS_ENTIRE));
append_menu_item_owner_draw(analysis,IDM_ANALYSIS_INTERVAL,menu_text(text(L"Interval…",L"Участок…"),IDM_ANALYSIS_INTERVAL));
append_menu_item_owner_draw(analysis,IDM_ANALYSIS_VISIBLE,menu_text(text(L"Use visible interval",L"Взять видимый участок"),IDM_ANALYSIS_VISIBLE));
append_menu_popup_owner_draw(bar,analysis,text(L"Analysis",L"Анализ"));
const HMENU tools = CreatePopupMenu();
append_menu_item_owner_draw(tools, IDC_CURSOR_TOOL, menu_text(text(L"Cursor", L"Курсор"),IDC_CURSOR_TOOL));
const std::wstring measure_text = menu_text(text(L"Points", L"Точки"), IDC_MEASURE);
const std::wstring marker_text = menu_text(text(L"Marker", L"Маркер"), IDM_ADD_MARKER);
const std::wstring vline_text = menu_text(text(L"Vertical line", L"Вертикальная линия"), IDM_ADD_VLINE);
const std::wstring exact_line_text = menu_text(text(L"Set line (exact)", L"Задать линию (точно)"), IDM_ADD_LINE_EXACT);
const std::wstring hline_text = menu_text(text(L"Horizontal line", L"Горизонтальная линия"), IDM_ADD_HLINE);
append_menu_item_owner_draw(tools, IDC_MEASURE, measure_text);
append_menu_item_owner_draw(tools, IDM_ADD_MARKER, marker_text);
append_menu_item_owner_draw(tools, IDM_ADD_VLINE, vline_text);
append_menu_item_owner_draw(tools, IDM_ADD_HLINE, hline_text);
append_menu_item_owner_draw(tools, IDM_ADD_LINE_EXACT, exact_line_text);
AppendMenuW(tools, MF_SEPARATOR, 0, nullptr);
append_menu_item_owner_draw(tools, IDM_CLEAR_POINTS, text(L"Clear points", L"Очистить точки"));
append_menu_item_owner_draw(tools, IDM_CLEAR_MARKERS, text(L"Clear markers", L"Очистить маркеры"));
append_menu_item_owner_draw(tools, IDM_CLEAR_LINES, text(L"Clear lines", L"Очистить линии"));
append_menu_popup_owner_draw(bar, tools, text(L"Tools", L"Инструменты"));
const HMENU settings = CreatePopupMenu();
append_menu_item_owner_draw(settings, IDM_SETTINGS, text(L"General settings", L"Общие настройки"));
append_menu_popup_owner_draw(bar, settings, text(L"Settings", L"Настройки"));
const HMENU help = CreatePopupMenu();
const std::wstring hotkeys_text = menu_text(text(L"Keyboard shortcuts", L"Горячие клавиши"), IDM_HOTKEYS);
append_menu_item_owner_draw(help, IDM_HOTKEYS, hotkeys_text);
append_menu_item_owner_draw(help, IDM_ABOUT, text(L"Start screen", L"Начальный экран"));
append_menu_popup_owner_draw(bar, help, text(L"Help", L"Справка"));
return bar;
}
void rebuild_menu_bar() {
if (!g.main) return;
SetMenu(g.main, nullptr);
if (g.menu) DestroyMenu(g.menu);
g_menu_text_storage.clear();
g.menu = make_menu();
SetMenu(g.main, welcome_visible() ? nullptr : g.menu);
MENUINFO mi{};
mi.cbSize = sizeof(mi);
mi.fMask = MIM_BACKGROUND | MIM_APPLYTOSUBMENUS;
mi.hbrBack = CreateSolidBrush(g_theme->bg_toolbar);
SetMenuInfo(g.menu, &mi);
sync_menu();
DrawMenuBar(g.main);
}
} // namespace gui