void resize() { // No point in doing this before we have the client size (ie at first construction): if (m_client[1] > 0) { uint sd = 1; FgVect2I pos(0), sz = m_client; pos[sd] = -m_si.nPos; for (size_t ii=0; ii<m_panes.size(); ++ii) { sz[sd] = m_panes[ii]->getMinSize()[sd]; if ((pos[sd] > m_client[sd]) || (pos[sd]+sz[sd] < 0)) m_panes[ii]->showWindow(false); else { m_panes[ii]->moveWindow(pos,sz); m_panes[ii]->showWindow(true); } pos[sd] += sz[sd]; } // Note that Windows wants the total range of the scrollable area, // not the effective slider range resulting from subtracting the // currently displayed range: m_si.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE; m_si.nMax = sumDims()[sd]; m_si.nPage = m_client[sd]; // Windows will clamp the position and otherwise adjust: SetScrollInfo(hwndThis,SB_VERT,&m_si,TRUE); m_si.fMask = SIF_ALL; GetScrollInfo(hwndThis,SB_VERT,&m_si); } }
virtual void saveState() { fgSaveXml(m_store+".xml",m_currPane,false); for (size_t ii=0; ii<m_panes.size(); ++ii) m_panes[ii]->saveState(); }
virtual FgVect2B wantStretch() const { for (size_t ii=0; ii<m_panes.size(); ++ii) if (m_panes[ii]->wantStretch()[0]) return FgVect2B(true,true); return FgVect2B(false,true); }
FgGuiWinTabs(const FgGuiApiTabs & api) : m_api(api) { FGASSERT(m_api.tabs.size()>0); for (size_t ii=0; ii<m_api.tabs.size(); ++ii) m_panes.push_back(api.tabs[ii].win->getInstance()); m_currPane = 0; }
FgVect2UI sumDims() const { FgVect2UI sum(0); for (size_t ii=0; ii<m_panes.size(); ++ii) sum += m_panes[ii]->getMinSize(); return sum; }
virtual FgVect2UI getMinSize() const { FgVect2UI max(0); for (size_t ii=0; ii<m_panes.size(); ++ii) { const FgGuiTab & tab = m_api.tabs[ii]; FgVect2UI pad(tab.padLeft+tab.padRight,tab.padTop+tab.padBottom); max = fgMax(max,m_panes[ii]->getMinSize()+pad); } return max + FgVect2UI(0,37); }
virtual void updateIfChanged() { //fgout << fgnl << "SplitScroll::updateIfChanged"; if (g_gg.dg.update(m_api.updateFlagIdx)) { //fgout << " ... updating" << fgpush; // call DestroyWindow in all created sub-windows: for (size_t ii=0; ii<m_panes.size(); ++ii) m_panes[ii]->destroy(); FgGuiPtrs panes = m_api.getPanes(); m_panes.resize(panes.size()); for (size_t ii=0; ii<m_panes.size(); ++ii) { m_panes[ii] = panes[ii]->getInstance(); m_panes[ii]->create(hwndThis,int(ii),m_store+"_"+fgToString(ii),0UL,true); } //fgout << fgpop; } for (size_t ii=0; ii<m_panes.size(); ++ii) m_panes[ii]->updateIfChanged(); }
virtual void create(HWND parentHwnd,int ident,const FgString & store,DWORD extStyle,bool visible) { //fgout << fgnl << "Tabs::create visible: " << visible << " extStyle: " << extStyle << fgpush; m_store = store; uint cp; if (fgLoadXml(m_store+".xml",cp,false)) if (cp < m_panes.size()) m_currPane = cp; FgCreateChild cc; cc.extStyle = extStyle; cc.visible = visible; fgCreateChild(parentHwnd,ident,this,cc); //fgout << fgpop; }
LRESULT wndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { if (msg == WM_CREATE) { //fgout << fgnl << "Tabs::WM_CREATE" << fgpush; hwndThis = hwnd; // Creating the panes before the tabs fixes the problem of trackbars not being visible // on first paint (almost ... top/bottom arrows don't appear). No idea why. for (size_t ii=0; ii<m_panes.size(); ++ii) { // Set visibility here to avoid sending 'ShowWindow' messages, which also // send WM_SIZE. The sizing will all be done after creation when ShowWindow // is called from the client level. m_panes[ii]->create(hwnd, int(ii+1), // Child identifiers start at 1 since 0 taken above. Not used anyway. m_store+"_"+fgToString(ii), NULL, ii==m_currPane); } m_tabHwnd = CreateWindowEx(0, WC_TABCONTROL, L"", WS_CHILD | WS_VISIBLE, 0,0,0,0, hwnd, 0, // Identifier 0 s_fgGuiWin.hinst, NULL); TCITEM tc = {0}; tc.mask = TCIF_TEXT; for (size_t ii=0; ii<m_panes.size(); ++ii) { wstring wstr = m_api.tabs[ii].label.as_wstring(); wstr += wchar_t(0); tc.pszText = &wstr[0]; TabCtrl_InsertItem(m_tabHwnd,ii,&tc); } SendMessage(m_tabHwnd,TCM_SETCURSEL,m_currPane,0); if (m_api.tabs[m_currPane].onSelect != NULL) m_api.tabs[m_currPane].onSelect(); //fgout << fgpop; return 0; } else if (msg == WM_SIZE) { m_client = FgVect2I(LOWORD(lParam),HIWORD(lParam)); if (m_client[0] * m_client[1] > 0) { //fgout << fgnl << "Tabs::WM_SIZE: " << m_api.tabs[0].label << " : " << m_client << fgpush; resize(hwnd); //fgout << fgpop; } return 0; } else if (msg == WM_NOTIFY) { LPNMHDR lpnmhdr = (LPNMHDR)lParam; if (lpnmhdr->code == TCN_SELCHANGE) { int idx = int(SendMessage(m_tabHwnd,TCM_GETCURSEL,0,0)); // This can apparently be -1 for 'no tab selected': if ((idx >= 0) && (size_t(idx) < m_panes.size())) { //fgout << fgnl << "Tabs::WM_NOTIFY: " << idx << fgpush; if (uint(idx) != m_currPane) { m_panes[m_currPane]->showWindow(false); m_currPane = uint(idx); // Must do update check and resize since these are not done when the // tab is not visible: m_panes[m_currPane]->updateIfChanged(); resizeCurrPane(); m_panes[m_currPane]->showWindow(true); if (m_api.tabs[m_currPane].onSelect != NULL) m_api.tabs[m_currPane].onSelect(); InvalidateRect(hwndThis,NULL,TRUE); } //fgout << fgpop; } } return 0; } else if (msg == WM_PAINT) { //fgout << fgnl << "Tabs::WM_PAINT"; } return DefWindowProc(hwnd,msg,wParam,lParam); }
LRESULT wndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { if (message == WM_CREATE) { //fgout << fgnl << "SplitScroll::WM_CREATE" << fgpush; hwndThis = hwnd; FGASSERT(m_panes.empty()); FgGuiPtrs panes = m_api.getPanes(); m_panes.resize(panes.size()); for (size_t ii=0; ii<m_panes.size(); ++ii) { m_panes[ii] = panes[ii]->getInstance(); m_panes[ii]->create(hwndThis,int(ii),m_store+"_"+fgToString(ii),0UL,true); } g_gg.dg.update(m_api.updateFlagIdx); //fgout << fgpop; return 0; } else if (message == WM_SIZE) { m_client = FgVect2I(LOWORD(lParam),HIWORD(lParam)); if (m_client[0] * m_client[1] > 0) { //fgout << fgnl << "SplitScroll::WM_SIZE: " << m_client << fgpush; resize(); //fgout << fgpop; } return 0; } else if (message == WM_VSCROLL) { //fgout << "SplitScroll::WM_VSCROLL"; int tmp = m_si.nPos; // Get the current state, esp. trackbar drag position: m_si.fMask = SIF_ALL; GetScrollInfo(hwnd,SB_VERT,&m_si); int msg = LOWORD(wParam); if (msg == SB_TOP) m_si.nPos = m_si.nMin; else if (msg == SB_BOTTOM) m_si.nPos = m_si.nMax; else if (msg == SB_LINEUP) m_si.nPos -= 5; else if (msg == SB_LINEDOWN) m_si.nPos += 5; else if (msg == SB_PAGEUP) m_si.nPos -= m_client[1]; else if (msg == SB_PAGEDOWN) m_si.nPos += m_client[1]; else if (msg == SB_THUMBTRACK) m_si.nPos = m_si.nTrackPos; m_si.fMask = SIF_POS; SetScrollInfo(hwnd,SB_VERT,&m_si,TRUE); // Windows may clamp the position: GetScrollInfo(hwnd,SB_VERT,&m_si); if (m_si.nPos != tmp) { resize(); InvalidateRect(hwndThis,NULL,TRUE); } return 0; } else if (message == WM_PAINT) { //fgout << fgnl << "SplitScroll::WM_PAINT"; } return DefWindowProc(hwnd,message,wParam,lParam); }
virtual void saveState() { for (size_t ii=0; ii<m_panes.size(); ++ii) m_panes[ii]->saveState(); }
LRESULT wndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { switch (message) { case WM_CREATE: { //fgout << fgnl << "FgGuiWinTabs::WM_CREATE " << m_api.tabs[0].label; hwndThis = hwnd; m_tabHwnd = CreateWindowEx(0, WC_TABCONTROL, L"", WS_CHILD | WS_VISIBLE | TCS_FIXEDWIDTH, 0,0,0,0, hwnd, NULL, s_fgGuiWin.hinst, NULL); TCITEM tc = {0}; tc.mask = TCIF_TEXT; for (size_t ii=0; ii<m_panes.size(); ++ii) { wstring wstr = m_api.tabs[ii].label.as_wstring(); wstr += wchar_t(0); tc.pszText = &wstr[0]; TabCtrl_InsertItem(m_tabHwnd,ii,&tc); m_panes[ii]->create(hwnd,int(ii),m_store+"_"+fgToString(ii),NULL,false); } SendMessage(m_tabHwnd,TCM_SETCURSEL,m_currPane,0); m_panes[m_currPane]->showWindow(true); return 0; } case WM_SIZE: { m_client = FgVect2I(LOWORD(lParam),HIWORD(lParam)); //fgout << fgnl << "FgGuiWinTabs::WM_SIZE " << m_api.tabs[0].label << " : " << m_client; if (m_client[0] * m_client[1] > 0) resize(hwnd); return 0; } case WM_NOTIFY: { LPNMHDR lpnmhdr = (LPNMHDR)lParam; if (lpnmhdr->code == TCN_SELCHANGE) { int idx = int(SendMessage(m_tabHwnd,TCM_GETCURSEL,0,0)); // This can apparently be -1 for 'no tab selected': if ((idx >= 0) && (size_t(idx) < m_panes.size())) { if (uint(idx) != m_currPane) { m_panes[m_currPane]->showWindow(false); m_currPane = uint(idx); m_panes[m_currPane]->showWindow(true); resizeCurrPane(); m_panes[m_currPane]->updateIfChanged(); // This is needed only for the first time a tab is selected, and only // for *some* of the sub-sub windows. No idea why: InvalidateRect(hwnd,&m_dispArea,FALSE); } } } return 0; } } return DefWindowProc(hwnd,message,wParam,lParam); }