/
vmenu.hpp
340 lines (301 loc) · 13 KB
/
vmenu.hpp
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
#ifndef VMENU_HPP_DF9F4258_12AF_4721_9D5F_BE29A59649C2
#define VMENU_HPP_DF9F4258_12AF_4721_9D5F_BE29A59649C2
#pragma once
/*
vmenu.hpp
Обычное вертикальное меню
а так же:
* список в DI_COMBOBOX
* список в DI_LISTBOX
* ...
*/
/*
Copyright © 1996 Eugene Roshal
Copyright © 2000 Far Group
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "modal.hpp"
#include "bitflags.hpp"
#include "synchro.hpp"
#include "colors.hpp"
// Цветовые атрибуты - индексы в массиве цветов
enum vmenu_colors
{
VMenuColorBody = 0, // подложка
VMenuColorBox = 1, // рамка
VMenuColorTitle = 2, // заголовок - верхний и нижний
VMenuColorText = 3, // Текст пункта
VMenuColorHilite = 4, // HotKey
VMenuColorSeparator = 5, // separator
VMenuColorSelected = 6, // Выбранный
VMenuColorHSelect = 7, // Выбранный - HotKey
VMenuColorScrollBar = 8, // ScrollBar
VMenuColorDisabled = 9, // Disabled
VMenuColorArrows =10, // '<' & '>' обычные
VMenuColorArrowsSelect =11, // '<' & '>' выбранные
VMenuColorArrowsDisabled =12, // '<' & '>' Disabled
VMenuColorGrayed =13, // "серый"
VMenuColorSelGrayed =14, // выбранный "серый"
VMENU_COLOR_COUNT, // всегда последняя - размерность массива
};
enum VMENU_FLAGS
{
VMENU_NONE =0x00000000,
VMENU_ALWAYSSCROLLBAR =0x00000100, // всегда показывать скроллбар
VMENU_LISTBOX =0x00000200, // Это список в диалоге
VMENU_SHOWNOBOX =0x00000400, // показать без рамки
VMENU_AUTOHIGHLIGHT =0x00000800, // автоматически выбирать симолы подсветки
VMENU_REVERSEHIGHLIGHT =0x00001000, // ... только с конца
VMENU_UPDATEREQUIRED =0x00002000, // лист необходимо обновить (перерисовать)
VMENU_DISABLEDRAWBACKGROUND=0x00004000, // подложку не рисовать
VMENU_WRAPMODE =0x00008000, // зацикленный список (при перемещении)
VMENU_SHOWAMPERSAND =0x00010000, // символ '&' показывать AS IS
VMENU_WARNDIALOG =0x00020000, //
VMENU_LISTHASFOCUS =0x00200000, // меню является списком в диалоге и имеет фокус
VMENU_COMBOBOX =0x00400000, // меню является комбобоксом и обрабатывается менеджером по-особому.
VMENU_MOUSEDOWN =0x00800000, //
VMENU_CHANGECONSOLETITLE =0x01000000, //
VMENU_MOUSEREACTION =0x02000000, // реагировать на движение мыши? (перемещать позицию при перемещении курсора мыши?)
VMENU_DISABLED =0x04000000, //
VMENU_NOMERGEBORDER =0x08000000, //
VMENU_REFILTERREQUIRED =0x10000000, // перед отрисовкой необходимо обновить фильтр
VMENU_LISTSINGLEBOX =0x20000000, // список, всегда с одинарной рамкой
VMENU_COMBOBOXEVENTKEY =0x40000000, // посылать события клавиатуры в диалоговую проц. для открытого комбобокса
VMENU_COMBOBOXEVENTMOUSE =0x80000000, // посылать события мыши в диалоговую проц. для открытого комбобокса
};
class Dialog;
class SaveScreen;
struct MenuItemEx
{
NONCOPYABLE(MenuItemEx);
TRIVIALLY_MOVABLE(MenuItemEx);
MenuItemEx(const string& Text = L""):
strName(Text),
Flags(),
ShowPos(),
AccelKey(),
AmpPos(),
Len(),
Idx2()
{
}
string strName;
UINT64 Flags; // Флаги пункта
any UserData;
int ShowPos;
DWORD AccelKey;
short AmpPos; // Позиция автоназначенной подсветки
short Len[2]; // размеры 2-х частей
short Idx2; // начало 2-й части
std::list<std::pair<int, int>> Annotations;
UINT64 SetCheck(int Value)
{
if (Value)
{
Flags|=LIF_CHECKED;
Flags &= ~0xFFFF;
if (Value!=1) Flags|=Value&0xFFFF;
}
else
{
Flags&=~(0xFFFF|LIF_CHECKED);
}
return Flags;
}
UINT64 SetSelect(int Value) { if (Value) Flags|=LIF_SELECTED; else Flags&=~LIF_SELECTED; return Flags;}
UINT64 SetDisable(int Value) { if (Value) Flags|=LIF_DISABLE; else Flags&=~LIF_DISABLE; return Flags;}
};
struct MenuDataEx
{
const wchar_t *Name;
LISTITEMFLAGS Flags;
DWORD AccelKey;
DWORD SetCheck(int Value)
{
if (Value)
{
Flags &= ~0xFFFF;
Flags|=((Value&0xFFFF)|LIF_CHECKED);
}
else
Flags&=~(0xFFFF|LIF_CHECKED);
return Flags;
}
DWORD SetSelect(int Value) { if (Value) Flags|=LIF_SELECTED; else Flags&=~LIF_SELECTED; return Flags;}
DWORD SetDisable(int Value) { if (Value) Flags|=LIF_DISABLE; else Flags&=~LIF_DISABLE; return Flags;}
DWORD SetGrayed(int Value) { if (Value) Flags|=LIF_GRAYED; else Flags&=~LIF_GRAYED; return Flags;}
};
struct SortItemParam
{
bool Reverse;
int Offset;
};
class window;
class VMenu: public SimpleModal
{
struct private_tag {};
public:
static vmenu_ptr create(const string& Title, const MenuDataEx *Data, int ItemCount, int MaxHeight = 0, DWORD Flags = 0, Dialog *ParentDialog = nullptr);
VMenu(private_tag, const string& Title, int MaxHeight, Dialog *ParentDialog);
virtual ~VMenu();
virtual void Show() override;
virtual void Hide() override;
virtual string GetTitle() const override;
virtual FARMACROAREA GetMacroArea() const override;
virtual int GetTypeAndName(string &strType, string &strName) override;
virtual int GetType() const override { return CheckFlags(VMENU_COMBOBOX) ? windowtype_combobox : windowtype_menu; }
virtual int ProcessKey(const Manager::Key& Key) override;
virtual int ProcessMouse(const MOUSE_EVENT_RECORD *MouseEvent) override;
virtual __int64 VMProcess(int OpCode, void *vParam = nullptr, __int64 iParam = 0) override;
virtual void ResizeConsole() override;
virtual void SetDeleting(void) override;
virtual void ShowConsoleTitle() override;
void FastShow() { ShowMenu(); }
void ResetCursor();
void SetTitle(const string& Title);
void SetBottomTitle(const wchar_t *BottomTitle);
string &GetBottomTitle(string &strDest);
void SetDialogStyle(bool Style) { ChangeFlags(VMENU_WARNDIALOG, Style); SetColors(nullptr); }
void SetUpdateRequired(bool SetUpdate) { ChangeFlags(VMENU_UPDATEREQUIRED, SetUpdate); }
void SetBoxType(int BoxType);
void SetMenuFlags(DWORD Flags) { VMFlags.Set(Flags); }
void ClearFlags(DWORD Flags) { VMFlags.Clear(Flags); }
bool CheckFlags(DWORD Flags) const { return VMFlags.Check(Flags); }
DWORD GetFlags() const { return VMFlags.Flags(); }
DWORD ChangeFlags(DWORD Flags, bool Status) { return VMFlags.Change(Flags, Status); }
void AssignHighlights(int Reverse);
void SetColors(const FarDialogItemColors *ColorsIn = nullptr);
void GetColors(FarDialogItemColors *ColorsOut);
void SetOneColor(int Index, PaletteColors Color);
int ProcessFilterKey(int Key);
void clear();
int DeleteItem(int ID, int Count = 1);
int AddItem(MenuItemEx&& NewItem, int PosAdd = 0x7FFFFFFF);
int AddItem(const FarList *NewItem);
int AddItem(const wchar_t *NewStrItem);
int InsertItem(const FarListInsert *NewItem);
int UpdateItem(const FarListUpdate *NewItem);
int FindItem(const FarListFind *FindItem);
int FindItem(int StartIndex, const string& Pattern, UINT64 Flags = 0);
void RestoreFilteredItems();
void FilterStringUpdated();
void FilterUpdateHeight(bool bShrink = false);
void SetFilterEnabled(bool bEnabled) { bFilterEnabled = bEnabled; }
void SetFilterLocked(bool bLocked) { bFilterEnabled = bLocked; }
bool AddToFilter(const wchar_t *str);
void SetFilterString(const wchar_t *str);
size_t size() const { return Items.size(); }
bool empty() const { return Items.empty(); }
int GetShowItemCount() const { return static_cast<int>(Items.size() - ItemHiddenCount); }
int GetVisualPos(int Pos);
int VisualPosToReal(int VPos);
template<class T>
T* GetUserDataPtr(int Position = -1)
{
return any_cast<T>(GetUserData(Position));
}
void SetUserData(const any& Data, int Position = -1);
int GetSelectPos() const { return SelectPos; }
int GetLastSelectPosResult() const { return SelectPosResult; }
int GetSelectPos(FarListPos *ListPos) const;
int SetSelectPos(const FarListPos *ListPos, int Direct = 0);
int SetSelectPos(int Pos, int Direct, bool stop_on_edge = false);
int GetCheck(int Position = -1);
void SetCheck(int Check, int Position = -1);
bool UpdateRequired() const;
void UpdateItemFlags(int Pos, UINT64 NewFlags);
MenuItemEx& at(size_t n);
MenuItemEx& current() { return at(-1); }
void SortItems(bool Reverse = false, int Offset = 0);
bool Pack();
BOOL GetVMenuInfo(FarListInfo* Info) const;
void SetMaxHeight(int NewMaxHeight);
size_t GetVDialogItemID() const { return DialogItemID; }
void SetVDialogItemID(size_t NewDialogItemID) { DialogItemID = NewDialogItemID; }
void SetId(const GUID& Id);
const GUID& Id() const;
bool IsComboBox() const { return ParentDialog && CheckFlags(VMENU_COMBOBOX); }
Dialog *GetDialog() {return ParentDialog;}
template<class predicate>
void SortItems(predicate Pred, bool Reverse = false, int Offset = 0)
{
SCOPED_ACTION(CriticalSectionLock)(CS);
SortItemParam Param { Reverse, Offset };
std::sort(ALL_RANGE(Items), [&](const auto& a, const auto& b) { return Pred(a, b, Param); });
// скорректируем SelectPos
UpdateSelectPos();
SetMenuFlags(VMENU_UPDATEREQUIRED);
}
static FarListItem *MenuItem2FarList(const MenuItemEx *ListItem, FarListItem *Item);
static std::vector<string> AddHotkeys(const range<MenuDataEx*>& MenuItems);
private:
void init(const MenuDataEx *Data, int ItemsCount, DWORD Flags);
virtual void DisplayObject() override;
void ShowMenu(bool IsParent = false);
void DrawTitles();
int GetItemPosition(int Position) const;
bool CheckKeyHiOrAcc(DWORD Key,int Type,int Translate,bool ChangePos,int& NewPos);
int CheckHighlights(wchar_t Chr,int StartPos=0);
wchar_t GetHighlights(const MenuItemEx *_item);
bool ShiftItemShowPos(int Pos,int Direct);
bool ItemCanHaveFocus(UINT64 Flags) const;
bool ItemCanBeEntered(UINT64 Flags) const;
bool ItemIsVisible(UINT64 Flags) const;
void UpdateMaxLengthFromTitles();
void UpdateMaxLength(size_t Length);
void UpdateInternalCounters(UINT64 OldFlags, UINT64 NewFlags);
bool ShouldSendKeyToFilter(int Key) const;
//корректировка текущей позиции и флагов SELECTED
void UpdateSelectPos();
any* GetUserData(int Position = -1);
string strTitle;
string strBottomTitle;
int SelectPos;
int SelectPosResult;
int TopPos;
int MaxHeight;
bool WasAutoHeight;
size_t m_MaxLength;
int m_BoxType;
window_ptr CurrentWindow;
bool PrevCursorVisible;
DWORD PrevCursorSize;
// переменная, отвечающая за отображение scrollbar в DI_LISTBOX & DI_COMBOBOX
BitFlags VMFlags;
BitFlags VMOldFlags;
// Для LisBox - родитель в виде диалога
Dialog *ParentDialog;
size_t DialogItemID;
mutable CriticalSection CS;
bool bFilterEnabled;
bool bFilterLocked;
string strFilter;
std::vector<MenuItemEx> Items;
intptr_t ItemHiddenCount;
intptr_t ItemSubMenusCount;
FarColor Colors[VMENU_COLOR_COUNT];
size_t MaxLineWidth;
bool bRightBtnPressed;
GUID MenuId;
};
#endif // VMENU_HPP_DF9F4258_12AF_4721_9D5F_BE29A59649C2