CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/W32Util/TabControl.cpp
Views: 1401
1
#include "TabControl.h"
2
#include "DialogManager.h"
3
#include "Windows/MainWindow.h"
4
#include <windowsx.h>
5
#include <commctrl.h>
6
7
const DWORD tabControlStyleMask = ~(WS_POPUP | WS_TILEDWINDOW);
8
9
TabControl::TabControl(HWND handle, bool noDisplayArea)
10
: hwnd(handle), noDisplayArea_(noDisplayArea)
11
{
12
SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)this);
13
oldProc = (WNDPROC) SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)wndProc);
14
15
hasButtons = (GetWindowLong(handle,GWL_STYLE) & TCS_BUTTONS) != 0;
16
}
17
18
HWND TabControl::AddTabWindow(const wchar_t* className, const wchar_t *title, DWORD style)
19
{
20
TabInfo info;
21
info.hasBorder = (style & WS_BORDER) != 0;
22
23
style = (style |WS_CHILD) & tabControlStyleMask;
24
if (showTabTitles)
25
AppendPageToControl(title);
26
int index = (int)tabs.size();
27
28
RECT tabRect;
29
GetWindowRect(hwnd,&tabRect);
30
MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2);
31
TabCtrl_AdjustRect(hwnd, FALSE, &tabRect);
32
33
HWND tabHandle = CreateWindowEx(0,className,title,style,
34
tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,
35
GetParent(hwnd),0,MainWindow::GetHInstance(),0);
36
37
info.hasClientEdge = (GetWindowLong(tabHandle,GWL_EXSTYLE) & WS_EX_CLIENTEDGE) != 0;
38
if (hasButtons == false)
39
{
40
SetWindowLong(tabHandle, GWL_STYLE, GetWindowLong(tabHandle,GWL_STYLE) & (~WS_BORDER));
41
SetWindowLong(tabHandle, GWL_EXSTYLE, GetWindowLong(tabHandle,GWL_EXSTYLE) & (~WS_EX_CLIENTEDGE));
42
}
43
44
info.lastFocus = tabHandle;
45
info.pageHandle = tabHandle;
46
wcscpy_s(info.title,title);
47
tabs.push_back(info);
48
49
ShowTab(index);
50
return tabHandle;
51
}
52
53
void TabControl::AddTabDialog(Dialog* dialog, const wchar_t* title)
54
{
55
HWND handle = dialog->GetDlgHandle();
56
AddTab(handle,title);
57
}
58
59
void TabControl::AddTab(HWND handle, const wchar_t* title)
60
{
61
if (showTabTitles)
62
AppendPageToControl(title);
63
int index = (int)tabs.size();
64
65
TabInfo info = {0};
66
if (!noDisplayArea_)
67
{
68
RECT tabRect;
69
GetWindowRect(hwnd,&tabRect);
70
MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2);
71
TabCtrl_AdjustRect(hwnd, FALSE, &tabRect);
72
73
SetParent(handle,GetParent(hwnd));
74
DWORD style = (GetWindowLong(handle,GWL_STYLE) | WS_CHILD);
75
76
info.hasBorder = (style & WS_BORDER) != 0;
77
info.hasClientEdge = (GetWindowLong(handle,GWL_EXSTYLE) & WS_EX_CLIENTEDGE) != 0;
78
if (hasButtons == false)
79
{
80
style &= (~WS_BORDER);
81
SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle,GWL_EXSTYLE) & (~WS_EX_CLIENTEDGE));
82
}
83
84
SetWindowLong(handle, GWL_STYLE, style & tabControlStyleMask);
85
MoveWindow(handle,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE);
86
}
87
88
info.lastFocus = handle;
89
info.pageHandle = handle;
90
wcscpy_s(info.title,title);
91
tabs.push_back(info);
92
93
ShowTab(index);
94
}
95
96
HWND TabControl::RemoveTab(int index) {
97
int prevIndex = CurrentTabIndex();
98
if (currentTab >= index)
99
--currentTab;
100
101
HWND prevHandle = tabs[index].pageHandle;
102
if (tabs.size() == 1) {
103
TabCtrl_DeleteAllItems(hwnd);
104
tabs.clear();
105
currentTab = 0;
106
} else {
107
TabCtrl_DeleteItem(hwnd, index);
108
tabs.erase(tabs.begin() + index);
109
110
if (prevIndex == index)
111
ShowTab(currentTab, true);
112
}
113
114
return prevHandle;
115
}
116
117
int TabControl::AppendPageToControl(const wchar_t *title)
118
{
119
TCITEM tcItem;
120
ZeroMemory (&tcItem,sizeof (tcItem));
121
tcItem.mask = TCIF_TEXT;
122
tcItem.dwState = 0;
123
tcItem.pszText = (LPTSTR)title;
124
tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1;
125
tcItem.iImage = 0;
126
127
int index = TabCtrl_GetItemCount(hwnd);
128
TabCtrl_InsertItem(hwnd, index, &tcItem);
129
return index;
130
}
131
132
bool OffspringHasFocus(HWND handle)
133
{
134
HWND offspring = GetFocus();
135
HWND start = offspring;
136
137
while (offspring != NULL)
138
{
139
if (offspring == handle) return true;
140
offspring = GetParent(offspring);
141
142
// no idea if this can potentially go in circles, make sure to stop just in case
143
if (offspring == start) break;
144
}
145
146
return false;
147
}
148
149
void TabControl::ShowTab(int index, bool setControlIndex)
150
{
151
bool oldFocus = OffspringHasFocus(CurrentTabHandle());
152
if (oldFocus)
153
tabs[CurrentTabIndex()].lastFocus = GetFocus();
154
155
currentTab = index;
156
157
for (size_t i = 0; i < tabs.size(); i++)
158
{
159
if (oldFocus && i == index)
160
SetFocus(tabs[i].lastFocus);
161
if (!noDisplayArea_)
162
ShowWindow(tabs[i].pageHandle,i == index ? SW_NORMAL : SW_HIDE);
163
}
164
165
if (setControlIndex && showTabTitles)
166
TabCtrl_SetCurSel(hwnd,index);
167
}
168
169
void TabControl::ShowTab(HWND pageHandle)
170
{
171
bool oldFocus = OffspringHasFocus(CurrentTabHandle());
172
if (oldFocus)
173
tabs[CurrentTabIndex()].lastFocus = GetFocus();
174
175
for (size_t i = 0; i < tabs.size(); i++)
176
{
177
if (tabs[i].pageHandle == pageHandle)
178
{
179
currentTab = (int)i;
180
if (showTabTitles)
181
TabCtrl_SetCurSel(hwnd,i);
182
if (oldFocus)
183
SetFocus(tabs[i].lastFocus);
184
}
185
if (!noDisplayArea_)
186
ShowWindow(tabs[i].pageHandle,tabs[i].pageHandle == pageHandle ? SW_NORMAL : SW_HIDE);
187
}
188
}
189
190
void TabControl::SetShowTabTitles(bool enabled)
191
{
192
showTabTitles = enabled;
193
int itemCount = TabCtrl_GetItemCount(hwnd);
194
195
for (int i = 0; i < itemCount; i++)
196
{
197
TabCtrl_DeleteItem(hwnd,0);
198
}
199
200
if (showTabTitles)
201
{
202
for (int i = 0; i < (int) tabs.size(); i++)
203
{
204
AppendPageToControl(tabs[i].title);
205
206
if (hasButtons == false && !noDisplayArea_)
207
{
208
DWORD style = GetWindowLong(tabs[i].pageHandle,GWL_STYLE) & (~WS_BORDER);
209
SetWindowLong(tabs[i].pageHandle,GWL_STYLE,style);
210
211
DWORD exStyle = GetWindowLong(tabs[i].pageHandle,GWL_EXSTYLE) & (~WS_EX_CLIENTEDGE);
212
SetWindowLong(tabs[i].pageHandle,GWL_EXSTYLE,exStyle);
213
}
214
}
215
TabCtrl_SetCurSel(hwnd,CurrentTabIndex());
216
} else if (hasButtons == false && !noDisplayArea_)
217
{
218
for (int i = 0; i < (int) tabs.size(); i++)
219
{
220
if (tabs[i].hasBorder)
221
{
222
DWORD style = GetWindowLong(tabs[i].pageHandle,GWL_STYLE) | WS_BORDER;
223
SetWindowLong(tabs[i].pageHandle,GWL_STYLE,style);
224
}
225
226
if (tabs[i].hasClientEdge)
227
{
228
DWORD exStyle = GetWindowLong(tabs[i].pageHandle,GWL_EXSTYLE) | WS_EX_CLIENTEDGE;
229
SetWindowLong(tabs[i].pageHandle,GWL_EXSTYLE,exStyle);
230
}
231
}
232
}
233
234
OnResize();
235
}
236
237
void TabControl::SetMinTabWidth(int w)
238
{
239
TabCtrl_SetMinTabWidth(hwnd, w);
240
}
241
242
void TabControl::NextTab(bool cycle)
243
{
244
int index = CurrentTabIndex()+1;
245
if (index == tabs.size())
246
{
247
if (cycle == false)
248
index--;
249
else
250
index = 0;
251
}
252
253
ShowTab(index);
254
}
255
256
void TabControl::PreviousTab(bool cycle)
257
{
258
int index = CurrentTabIndex()-1;
259
if (index < 0)
260
{
261
if (cycle == false)
262
index = 0;
263
else
264
index = (int) tabs.size()-1;
265
}
266
267
ShowTab(index);
268
}
269
270
void TabControl::HandleNotify(LPARAM lParam)
271
{
272
NMHDR* pNotifyMessage = NULL;
273
pNotifyMessage = (LPNMHDR)lParam;
274
if (pNotifyMessage->hwndFrom == hwnd)
275
{
276
int iPage = TabCtrl_GetCurSel(hwnd);
277
ShowTab(iPage,false);
278
}
279
}
280
281
int TabControl::HitTest(const POINT &screenPos) {
282
TCHITTESTINFO hitTest{};
283
hitTest.pt = screenPos;
284
ScreenToClient(hwnd, &hitTest.pt);
285
286
return TabCtrl_HitTest(hwnd, &hitTest);
287
}
288
289
void TabControl::OnResize()
290
{
291
RECT tabRect;
292
GetWindowRect(hwnd,&tabRect);
293
MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2);
294
295
InvalidateRect(hwnd,NULL,TRUE);
296
UpdateWindow(hwnd);
297
298
// now resize tab children
299
if (showTabTitles)
300
{
301
int bottom = tabRect.bottom;
302
TabCtrl_AdjustRect(hwnd, FALSE, &tabRect);
303
if (ignoreBottomMargin) tabRect.bottom = bottom;
304
}
305
306
int current = CurrentTabIndex();
307
308
if (!noDisplayArea_)
309
{
310
for (size_t i = 0; i < tabs.size(); i++)
311
{
312
InvalidateRect(tabs[i].pageHandle,NULL,FALSE);
313
MoveWindow(tabs[i].pageHandle,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE);
314
315
if (i == current)
316
{
317
InvalidateRect(tabs[i].pageHandle,NULL,TRUE);
318
UpdateWindow(tabs[i].pageHandle);
319
}
320
}
321
}
322
}
323
324
LRESULT CALLBACK TabControl::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
325
{
326
TabControl* tabControl = (TabControl*) GetWindowLongPtr(hwnd,GWLP_USERDATA);
327
328
switch (msg)
329
{
330
case WM_SIZE:
331
tabControl->OnResize();
332
break;
333
}
334
335
return (LRESULT)CallWindowProc((WNDPROC)tabControl->oldProc,hwnd,msg,wParam,lParam);
336
}
337
338