-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
listbox.h
304 lines (242 loc) · 10.4 KB
/
listbox.h
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
#pragma once
#include "stdafx.h"
#include "default_ui_hacks.h"
#include "queue_helpers.h"
#include "DropSourceImpl.h"
#include "DropTargetImpl.h"
#include "config.h"
#include "queuecontents_titleformat_hook.h"
#include "ui_element_host.h"
#include "reorder_helpers.h"
#include "queuecontents_lock.h"
/*
Some (useful?) resources:
http://www.codeproject.com/KB/wtl/customdrawlist_wtl.aspx Custom drawn controls
http://www.codeproject.com/KB/list/Dragger.aspx Dragger stuff
*/
// No list item context menu
enum {
// Show/Hide Column Header
ID_SHOW_COLUMN_HEADER = 1
};
// List item context menu
enum {
// let's not redefine
/*ID_SHOW_COLUMN_HEADER*/
// ID for "Remove"
ID_REMOVE = 2,
// ID for "Move to Top" and
ID_MOVE_TOP = 3,
// ID for "Move Up"
ID_MOVE_UP = 4,
// ID for "Move Down"
ID_MOVE_DOWN = 5,
// ID for "Move to Bottom"
ID_MOVE_BOTTOM = 6
/*
// The range ID_CONTEXT_FIRST through ID_CONTEXT_LAST is reserved
// for menu entries from menu_manager.
ID_CONTEXT_FIRST,
ID_CONTEXT_LAST = ID_CONTEXT_FIRST + 1000,
*/
};
// Header item context menu
enum {
// let's not redefine
/*ID_SHOW_COLUMN_HEADER*/
// Reserved for columns
ID_COLUMNS_FIRST = 2,
// Reserved for columns
ID_COLUMNS_LAST = ID_COLUMNS_FIRST + 1000,
ID_MORE = ID_COLUMNS_LAST + 1,
ID_RELATIVE_WIDTHS = ID_COLUMNS_LAST + 2, // "Auto-scale Columns with Window Size"
ID_BORDER_NONE = ID_COLUMNS_LAST + 3,
ID_BORDER_GREY = ID_COLUMNS_LAST + 4,
ID_BORDER_SUNKEN = ID_COLUMNS_LAST + 5
};
class CCustomListView : public WTL::CCustomDraw<CCustomListView>, public ATL::CWindowImpl<CCustomListView, WTL::CListViewCtrl>,
public MetaDbHandleDropTarget, public DropSourceInternalDraggingNotify
{
public:
BEGIN_MSG_MAP_EX(CCustomListView)
//NOTIFY_CODE_HANDLER(LVN_BEGINDRAG, OnBeginDrag)
MSG_WM_CREATE(OnCreate)
MSG_WM_SYSKEYDOWN(OnSysKeyDown)
MSG_WM_KEYDOWN(OnKeyDown)
MSG_WM_GETDLGCODE(OnGetDlgCode)
MSG_WM_MOUSEMOVE(OnMouseMove)
MSG_WM_LBUTTONUP(OnLButtonUp)
MSG_WM_DESTROY(OnDestroy)
if(uMsg == WM_CONTEXTMENU) {
if(m_callback.is_valid() && m_callback->is_edit_mode_enabled()) {
SetMsgHandled(TRUE);
lResult = ::DefWindowProc(hWnd, uMsg, wParam, lParam);
if(IsMsgHandled()) {
return TRUE;
}
}
}
MSG_WM_SETFOCUS(OnSetFocus)
MSG_WM_KILLFOCUS(OnKillFocus)
MSG_WM_CONTEXTMENU(OnContextMenu)
MSG_WM_LBUTTONDOWN(OnLButtonDown)
MSG_WM_CAPTURECHANGED(OnCaptureChanged)
NOTIFY_CODE_HANDLER(HDN_ENDTRACK, OnHeaderEndTrack) // Column resize has ended
NOTIFY_CODE_HANDLER(HDN_ENDDRAG, OnHeaderEndDrag) // Just before Columns are reordered, after the drag ended
NOTIFY_CODE_HANDLER(HDN_BEGINDRAG, OnHeaderBeginDrag) // Colum drag started
NOTIFY_CODE_HANDLER(HDN_DIVIDERDBLCLICK, OnHeaderDividerDblClick);
CHAIN_MSG_MAP(CCustomDraw<CCustomListView>)
END_MSG_MAP()
CCustomListView();
void SetColors(COLORREF backroundcolor,
COLORREF selectioncolor, COLORREF textcolor, COLORREF insertmarkercolor, COLORREF selectionrectanglecolor, COLORREF textselectedcolor);
// CCustomDraw
DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/);
DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw);
DWORD OnItemPostPaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw);
// gets selected indices in the index-ascending order
template<class t_list>
void GetSelectedIndices(t_list& p_out);
// MetaDbHandleDropTarget, we work-around through no virtual member function templates restriction
virtual void GetSelectedIndices(pfc::list_base_t<t_size>& p_out);
void GetSelectedItemsMetaDbHandles(metadb_handle_list_ref p_out);
void GetMetaDbHandles(const pfc::list_base_const_t<t_size>& indices, metadb_handle_list_ref p_out);
void SetSelectedIndices(const pfc::list_base_const_t<t_size>& p_in);
// Drop target stuff
STDMETHOD(DragLeave)();
STDMETHOD(DragEnter)(DWORD grfKeyState, CPoint pt_screen, CPoint pt_client, DWORD *pdwEffect);
STDMETHOD(DragOver)(DWORD grfKeyState, CPoint pt_screen, CPoint pt_client, DWORD *pdwEffect);
STDMETHOD(Drop)(const pfc::list_base_const_t<metadb_handle_ptr>& handles, DWORD grfKeyState, CPoint pt_screen, CPoint pt_client, DWORD *pdwEffect,
const pfc::list_base_const_t<t_size>& selection, bool internal_dragging, const ActivePlaylistInformation & active_playlist_information);
// DetermineDropAction is called from the DropTargetImpl to determine proper effect
// Currently we ignore Drop method's effects
STDMETHOD(DetermineDropAction)(DWORD grfKeyState, CPoint pt_screen, CPoint pt_client, DWORD *pdwEffect, bool internal_dragging);
// DropSourceInternalDraggingNotify
virtual void SetInternalDragging(bool value);
virtual bool GetInternalDragging();
// Called when queue is changed
void QueueRefresh();
void SetHost(ui_element_host* host);
// Column modifications
void AddUIColumn(long column_id);
void RemoveUIColumn(long column_id);
template<typename array_t>
void ReorderUIColumns(const array_t& order);
void RelayoutUIColumns();
// Show or hides colum header based on current status
void ShowHideColumnHeader();
void AppendShowColumnHeaderMenu(CMenuHandle menu, int ID);
int AddColumnHelper(LPCTSTR strItem, int nItem, int nSubItem = -1,
int nFmt = LVCFMT_LEFT) {
int nMask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
return AddColumn(strItem, nItem, nSubItem, nMask, nFmt);
}
void BuildContextMenu(CPoint screen_point, CMenuHandle menu, unsigned p_id_base);
void CommandContextMenu(CPoint screen_point, unsigned p_id, unsigned p_id_base);
void EditModeContextMenuGetFocusPoint(CPoint & pt);
void SetCallback(ui_element_instance_callback_ptr p_callback);
// Updates column widths, and width of the ui element
// Saves the modification.
// Returns true on success.
bool UpdateSettingsWidths();
metadb_handle_list_ref GetAllMetadbs();
private:
int OnCreate(LPCREATESTRUCT lpCreateStruct);
void DrawSelectionRectangle(CDC & cdc, const CRect & rect, const CRect & prev_rect);
void OnContextMenu(CWindow wnd, CPoint point);
void BuildHeaderContextMenu(CMenuHandle menu, unsigned p_id_base, CPoint point);
void BuildListItemContextMenu(CMenuHandle menu, unsigned p_id_base, CPoint point);
void BuildListNoItemContextMenu(CMenuHandle menu, unsigned p_id_base, CPoint point);
void BuildFrameStyleContextMenu(CMenuHandle menu, unsigned p_id_base, CPoint point);
void CommandHeaderContextMenu(unsigned p_id, unsigned p_id_base, CPoint point);
void CommandListItemContextMenu(unsigned p_id, unsigned p_id_base, CPoint point);
void CommandListNoItemContextMenu(unsigned p_id, unsigned p_id_base, CPoint point);
void CommandFrameStyleContextMenu(unsigned menu, unsigned p_id_base, CPoint point);
// Selection related
void OnMouseMove(UINT nFlags, CPoint point);
void OnLButtonUp(UINT nFlags, CPoint point);
void OnLButtonDown(UINT nFlags, CPoint point);
void UpdateInsertMarker(int i);
void DrawInsertMarker(int i, bool enable);
void UpdateSelection(CPoint end_point, bool applyCtrlSelection = false);
void SelectIndices(int start, int end, bool applyCtrlSelection = false);
void OnCaptureChanged(CWindow wnd);
void OnDestroy();
void MoveSelectedItems(bool up);
void OnSetFocus(CWindow wndOld);
void OnKillFocus(CWindow wndFocus);
int IndexToOrder(int index);
// direction = 0 <-> focused, direction < 0 upper, direction > 0 lower
void SelectRelativeToCurrentlyFocusedItem(int direction, bool page, bool unionselection);
LRESULT OnHeaderEndTrack(int /*wParam*/, LPNMHDR lParam, BOOL& bHandled);
LRESULT OnHeaderEndDrag(int /*wParam*/, LPNMHDR lParam, BOOL& bHandled);
LRESULT OnHeaderBeginDrag(int /*wParam*/, LPNMHDR lParam, BOOL& bHandled);
LRESULT OnHeaderDividerDblClick(int /*wParam*/, LPNMHDR lParam, BOOL& bHandled);
int DetermineItemSelectionIndex(CPoint point);
int DetermineItemInsertionIndex(CPoint point);
// Methods for adding items to listview control:
// Called when adding a new column
void AddItems(pfc::list_t<t_playback_queue_item> items, t_size column_order);
void AddItems(pfc::list_t<t_playback_queue_item> items);
void AddItem(t_playback_queue_item item, t_size index);
// Adds Item to a certain column
void AddItem(t_playback_queue_item item, t_size index, t_size column_index);
// Other
// process ESC etc. messages
void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
// Ensure that we get all KeyDown messages
UINT OnGetDlgCode(LPMSG lpMsg);
// Delete selected
void DeleteSelected();
// Select all items
void SelectAll();
void DeselectAll();
void ShowFocusRectangle();
void SetSharedSelection(metadb_handle_list_cref p_items);
void _print_header_debug_info(); // for debugging columns
// This is used to notify other components of the selection
// in our window. In this overly simplistic case, our selection
// will be empty, when playback is stopped. Otherwise it will
// contain the playing track.
ui_selection_holder::ptr m_shared_selection;
COLORREF m_backgroundcolor;
COLORREF m_selectioncolor;
COLORREF m_textcolor;
COLORREF m_textselectedcolor;
COLORREF m_insertmarkercolor;
COLORREF m_selectionrectanglecolor;
// flag used in custom draw
bool m_selected;
bool m_focused;
// are we dragging inside the control at the moment
bool m_internal_dragging;
// index of the prev. insertion marker
int m_prev_insert_marker;
pfc::com_ptr_t<IDropTarget> m_droptarget_ptr;
metadb_handle_list m_metadbs;
queuecontents_titleformat_hook m_hook;
// are we selecting currently
bool m_selecting;
// are we selecting with ctrl
bool m_ctrl_selecting;
// are we selecting with shift
bool m_shift_selecting;
bool m_header_dragging;
// Used for holding state in ctrl+selections
pfc::avltree_t<t_size> m_selection;
// start index of the selection rectangle
int m_selection_start_index;
// start index of the shift selection
int m_shift_selection_start_index;
// for restoring focus rectangle
int m_focused_item;
// For rectangle drawing...
CPoint m_selection_start_point;
CRect m_selection_lastRect;
// insert marker line weight
static const int LINEWEIGHT = 3;
ui_element_host* m_host;
pfc::array_staticsize_t<long> m_header_context_menu_column_ids;
ui_element_instance_callback_ptr m_callback;
};