CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Windows/W32Util/TabControl.cpp
Views: 1401
#include "TabControl.h"1#include "DialogManager.h"2#include "Windows/MainWindow.h"3#include <windowsx.h>4#include <commctrl.h>56const DWORD tabControlStyleMask = ~(WS_POPUP | WS_TILEDWINDOW);78TabControl::TabControl(HWND handle, bool noDisplayArea)9: hwnd(handle), noDisplayArea_(noDisplayArea)10{11SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)this);12oldProc = (WNDPROC) SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)wndProc);1314hasButtons = (GetWindowLong(handle,GWL_STYLE) & TCS_BUTTONS) != 0;15}1617HWND TabControl::AddTabWindow(const wchar_t* className, const wchar_t *title, DWORD style)18{19TabInfo info;20info.hasBorder = (style & WS_BORDER) != 0;2122style = (style |WS_CHILD) & tabControlStyleMask;23if (showTabTitles)24AppendPageToControl(title);25int index = (int)tabs.size();2627RECT tabRect;28GetWindowRect(hwnd,&tabRect);29MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2);30TabCtrl_AdjustRect(hwnd, FALSE, &tabRect);3132HWND tabHandle = CreateWindowEx(0,className,title,style,33tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,34GetParent(hwnd),0,MainWindow::GetHInstance(),0);3536info.hasClientEdge = (GetWindowLong(tabHandle,GWL_EXSTYLE) & WS_EX_CLIENTEDGE) != 0;37if (hasButtons == false)38{39SetWindowLong(tabHandle, GWL_STYLE, GetWindowLong(tabHandle,GWL_STYLE) & (~WS_BORDER));40SetWindowLong(tabHandle, GWL_EXSTYLE, GetWindowLong(tabHandle,GWL_EXSTYLE) & (~WS_EX_CLIENTEDGE));41}4243info.lastFocus = tabHandle;44info.pageHandle = tabHandle;45wcscpy_s(info.title,title);46tabs.push_back(info);4748ShowTab(index);49return tabHandle;50}5152void TabControl::AddTabDialog(Dialog* dialog, const wchar_t* title)53{54HWND handle = dialog->GetDlgHandle();55AddTab(handle,title);56}5758void TabControl::AddTab(HWND handle, const wchar_t* title)59{60if (showTabTitles)61AppendPageToControl(title);62int index = (int)tabs.size();6364TabInfo info = {0};65if (!noDisplayArea_)66{67RECT tabRect;68GetWindowRect(hwnd,&tabRect);69MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2);70TabCtrl_AdjustRect(hwnd, FALSE, &tabRect);7172SetParent(handle,GetParent(hwnd));73DWORD style = (GetWindowLong(handle,GWL_STYLE) | WS_CHILD);7475info.hasBorder = (style & WS_BORDER) != 0;76info.hasClientEdge = (GetWindowLong(handle,GWL_EXSTYLE) & WS_EX_CLIENTEDGE) != 0;77if (hasButtons == false)78{79style &= (~WS_BORDER);80SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle,GWL_EXSTYLE) & (~WS_EX_CLIENTEDGE));81}8283SetWindowLong(handle, GWL_STYLE, style & tabControlStyleMask);84MoveWindow(handle,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE);85}8687info.lastFocus = handle;88info.pageHandle = handle;89wcscpy_s(info.title,title);90tabs.push_back(info);9192ShowTab(index);93}9495HWND TabControl::RemoveTab(int index) {96int prevIndex = CurrentTabIndex();97if (currentTab >= index)98--currentTab;99100HWND prevHandle = tabs[index].pageHandle;101if (tabs.size() == 1) {102TabCtrl_DeleteAllItems(hwnd);103tabs.clear();104currentTab = 0;105} else {106TabCtrl_DeleteItem(hwnd, index);107tabs.erase(tabs.begin() + index);108109if (prevIndex == index)110ShowTab(currentTab, true);111}112113return prevHandle;114}115116int TabControl::AppendPageToControl(const wchar_t *title)117{118TCITEM tcItem;119ZeroMemory (&tcItem,sizeof (tcItem));120tcItem.mask = TCIF_TEXT;121tcItem.dwState = 0;122tcItem.pszText = (LPTSTR)title;123tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1;124tcItem.iImage = 0;125126int index = TabCtrl_GetItemCount(hwnd);127TabCtrl_InsertItem(hwnd, index, &tcItem);128return index;129}130131bool OffspringHasFocus(HWND handle)132{133HWND offspring = GetFocus();134HWND start = offspring;135136while (offspring != NULL)137{138if (offspring == handle) return true;139offspring = GetParent(offspring);140141// no idea if this can potentially go in circles, make sure to stop just in case142if (offspring == start) break;143}144145return false;146}147148void TabControl::ShowTab(int index, bool setControlIndex)149{150bool oldFocus = OffspringHasFocus(CurrentTabHandle());151if (oldFocus)152tabs[CurrentTabIndex()].lastFocus = GetFocus();153154currentTab = index;155156for (size_t i = 0; i < tabs.size(); i++)157{158if (oldFocus && i == index)159SetFocus(tabs[i].lastFocus);160if (!noDisplayArea_)161ShowWindow(tabs[i].pageHandle,i == index ? SW_NORMAL : SW_HIDE);162}163164if (setControlIndex && showTabTitles)165TabCtrl_SetCurSel(hwnd,index);166}167168void TabControl::ShowTab(HWND pageHandle)169{170bool oldFocus = OffspringHasFocus(CurrentTabHandle());171if (oldFocus)172tabs[CurrentTabIndex()].lastFocus = GetFocus();173174for (size_t i = 0; i < tabs.size(); i++)175{176if (tabs[i].pageHandle == pageHandle)177{178currentTab = (int)i;179if (showTabTitles)180TabCtrl_SetCurSel(hwnd,i);181if (oldFocus)182SetFocus(tabs[i].lastFocus);183}184if (!noDisplayArea_)185ShowWindow(tabs[i].pageHandle,tabs[i].pageHandle == pageHandle ? SW_NORMAL : SW_HIDE);186}187}188189void TabControl::SetShowTabTitles(bool enabled)190{191showTabTitles = enabled;192int itemCount = TabCtrl_GetItemCount(hwnd);193194for (int i = 0; i < itemCount; i++)195{196TabCtrl_DeleteItem(hwnd,0);197}198199if (showTabTitles)200{201for (int i = 0; i < (int) tabs.size(); i++)202{203AppendPageToControl(tabs[i].title);204205if (hasButtons == false && !noDisplayArea_)206{207DWORD style = GetWindowLong(tabs[i].pageHandle,GWL_STYLE) & (~WS_BORDER);208SetWindowLong(tabs[i].pageHandle,GWL_STYLE,style);209210DWORD exStyle = GetWindowLong(tabs[i].pageHandle,GWL_EXSTYLE) & (~WS_EX_CLIENTEDGE);211SetWindowLong(tabs[i].pageHandle,GWL_EXSTYLE,exStyle);212}213}214TabCtrl_SetCurSel(hwnd,CurrentTabIndex());215} else if (hasButtons == false && !noDisplayArea_)216{217for (int i = 0; i < (int) tabs.size(); i++)218{219if (tabs[i].hasBorder)220{221DWORD style = GetWindowLong(tabs[i].pageHandle,GWL_STYLE) | WS_BORDER;222SetWindowLong(tabs[i].pageHandle,GWL_STYLE,style);223}224225if (tabs[i].hasClientEdge)226{227DWORD exStyle = GetWindowLong(tabs[i].pageHandle,GWL_EXSTYLE) | WS_EX_CLIENTEDGE;228SetWindowLong(tabs[i].pageHandle,GWL_EXSTYLE,exStyle);229}230}231}232233OnResize();234}235236void TabControl::SetMinTabWidth(int w)237{238TabCtrl_SetMinTabWidth(hwnd, w);239}240241void TabControl::NextTab(bool cycle)242{243int index = CurrentTabIndex()+1;244if (index == tabs.size())245{246if (cycle == false)247index--;248else249index = 0;250}251252ShowTab(index);253}254255void TabControl::PreviousTab(bool cycle)256{257int index = CurrentTabIndex()-1;258if (index < 0)259{260if (cycle == false)261index = 0;262else263index = (int) tabs.size()-1;264}265266ShowTab(index);267}268269void TabControl::HandleNotify(LPARAM lParam)270{271NMHDR* pNotifyMessage = NULL;272pNotifyMessage = (LPNMHDR)lParam;273if (pNotifyMessage->hwndFrom == hwnd)274{275int iPage = TabCtrl_GetCurSel(hwnd);276ShowTab(iPage,false);277}278}279280int TabControl::HitTest(const POINT &screenPos) {281TCHITTESTINFO hitTest{};282hitTest.pt = screenPos;283ScreenToClient(hwnd, &hitTest.pt);284285return TabCtrl_HitTest(hwnd, &hitTest);286}287288void TabControl::OnResize()289{290RECT tabRect;291GetWindowRect(hwnd,&tabRect);292MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2);293294InvalidateRect(hwnd,NULL,TRUE);295UpdateWindow(hwnd);296297// now resize tab children298if (showTabTitles)299{300int bottom = tabRect.bottom;301TabCtrl_AdjustRect(hwnd, FALSE, &tabRect);302if (ignoreBottomMargin) tabRect.bottom = bottom;303}304305int current = CurrentTabIndex();306307if (!noDisplayArea_)308{309for (size_t i = 0; i < tabs.size(); i++)310{311InvalidateRect(tabs[i].pageHandle,NULL,FALSE);312MoveWindow(tabs[i].pageHandle,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE);313314if (i == current)315{316InvalidateRect(tabs[i].pageHandle,NULL,TRUE);317UpdateWindow(tabs[i].pageHandle);318}319}320}321}322323LRESULT CALLBACK TabControl::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)324{325TabControl* tabControl = (TabControl*) GetWindowLongPtr(hwnd,GWLP_USERDATA);326327switch (msg)328{329case WM_SIZE:330tabControl->OnResize();331break;332}333334return (LRESULT)CallWindowProc((WNDPROC)tabControl->oldProc,hwnd,msg,wParam,lParam);335}336337338