// Copyright (c) 2002 // Sergey Klimov (kidd@ukr.net) #ifndef __WTL_DW__FLYING_TABS_H__ #define __WTL_DW__FLYING_TABS_H__ #pragma once #include #include #include #include #include #include "DDTracker.h" //#include #ifndef __ATLGDIX_H__ #error FlyingTabs.h requires atlgdix.h to be included first #endif // NOTE: See CustomTabCtrl.h and DotNetTabCtrl.h for copyright information. // Please download the latest versions of these files from from The Codeproject article // "Custom Tab Controls, Tabbed Frame and Tabbed MDI" by Daniel Bowen (dbowen@es.com) // http://www.codeproject.com/wtl/TabbingFramework.asp //#include //#include #ifndef __CUSTOMTABCTRL_H__ #error FlyingTabs.h requires CustomTabCtrl.h to be included first #endif #ifndef __DOTNET_TABCTRL_H__ #error FlyingTabs.h requires DotNetTabCtrl.h to be included first #endif namespace dockwins{ #define CTCN_TABLEAVCTRL CTCN_LAST-1 #ifndef CTCS_VERTICAL #define CTCS_VERTICAL TCS_VERTICAL #endif class CFlyingTabCtrl : public CDotNetTabCtrlImpl { typedef CDotNetTabCtrlImpl baseClass; typedef CFlyingTabCtrl thisClass; protected: class CTabMoveTracker : public CDDTrackerBaseT { typedef thisClass CTabCtrl; public: CTabMoveTracker(CTabCtrl& ctrlTab,int index) :m_ctrlTab(ctrlTab),m_curItem(index),m_prevItem(-1) { DWORD style = ctrlTab.GetWindowLong(GWL_STYLE); m_bHorizontal=(style&CTCS_VERTICAL)==0; } bool IsHorisontal() const { return m_bHorizontal; } void OnMove(long x, long y) { int pos = IsHorisontal() ? x : y; CTCHITTESTINFO tchti = { 0 }; tchti.pt.x = x; tchti.pt.y = y; int index=m_ctrlTab.HitTest(&tchti); if(index!=-1) { if(( index!=m_curItem) && !( ( index==m_prevItem) && ( (pos-m_prevPos)*(m_prevItem-m_curItem) <=0) ) ) { m_ctrlTab.SwapItemPositions(m_curItem,index, false, false); // m_ctrlTab.MoveItem(m_curItem,index); m_curItem=index; m_ctrlTab.SetCurSel(m_curItem); m_prevItem=m_ctrlTab.HitTest(&tchti); } } else ::ReleaseCapture(); /* { NMHDR nmh; nmh.hwndFrom = m_ctrlTab.m_hWnd; nmh.idFrom=m_ctrlTab.GetDlgCtrlID(); nmh.code=CTCN_TABLEAVCTRL; if(!::SendMessage(m_ctrlTab.GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM)&nmh)) ::ReleaseCapture(); } */ m_prevPos = pos; } protected: CTabCtrl& m_ctrlTab; int m_curItem; int m_prevItem; int m_prevPos; bool m_bHorizontal; }; protected: void UpdateTabAreaHeight() { // Take into consideration system metrics when determining // the height of the tab area const int nNominalHeight = 24; const int nNominalFontLogicalUnits = 11; // 8 point Tahoma with 96 DPI // Use the actual font of the tab control assert(IsWindow()); HFONT hFont = GetFont(); if(hFont != NULL) { CClientDC dc(this->m_hWnd); CFontHandle hFontOld = dc.SelectFont(hFont); TEXTMETRIC tm = {0}; dc.GetTextMetrics(&tm); dc.SelectFont(hFontOld); m_tabBarHeight = (BYTE)(nNominalHeight + (nNominalHeight * ((double)tm.tmAscent / (double)nNominalFontLogicalUnits) - nNominalHeight) / 2); } else m_tabBarHeight = 24; } void AdjustTabRect(LPRECT pRc) const { int tabHeight = m_tabBarHeight ; DWORD style = GetWindowLong(GWL_STYLE); if(style&CTCS_VERTICAL) { if(style&CTCS_BOTTOM) pRc->left=pRc->right - tabHeight; else pRc->right=pRc->left + tabHeight; } else { if(style&CTCS_BOTTOM) pRc->top=pRc->bottom - tabHeight; else pRc->bottom=pRc->top + tabHeight; } } public: bool GetTabsRect(LPRECT pRc) const { return (GetClientRect(pRc)!=FALSE); } /* int InsertItem(int nItem, LPCTSTR sText = NULL, int nImage = -1, HWND hWndTabView = NULL, LPCTSTR sToolTip = NULL, bool bSelectItem = false) { return baseClass::InsertItem(nItem, sText, nImage, hWndTabView, sToolTip, bSelectItem); } int InsertItem(int nItem, CTabViewTabItem* pItem, bool bSelectItem = false) { return baseClass::InsertItem(nItem, pItem, bSelectItem); } */ int InsertItem(int index, LPCTSTR ptxt = NULL, int image = -1, DWORD_PTR param=0) { CTabViewTabItem* pItem = baseClass::CreateNewItem(); if(pItem) { pItem->SetText(ptxt); pItem->SetImageIndex(image); pItem->SetTabView(reinterpret_cast(param)); pItem->SetToolTip(ptxt); return baseClass::InsertItem(index,pItem,true); } return -1; } DWORD_PTR GetItemData(int index) const { return reinterpret_cast(GetItem(index)->GetTabView()); } void DeleteItem(CTabViewTabItem* pItem) { baseClass::DeleteItem(pItem); } BOOL DeleteItem(size_t nItem, bool bUpdateSelection = true, bool bNotify = true) { return baseClass::DeleteItem(nItem, bUpdateSelection, bNotify); } BOOL DeleteItem(int index,bool bUpdateSelection = true) { return DeleteItem(index, bUpdateSelection , false); } BOOL SetWindowPos(HWND hWndInsertAfter, LPCRECT lpRect, UINT nFlags) { CRect rc(lpRect); AdjustTabRect(rc); BOOL bRes=baseClass::SetWindowPos(hWndInsertAfter,&rc,nFlags); return bRes; } BOOL AdjustRect( BOOL bLarger, LPRECT pRc) const { int tabHeight = bLarger ? -m_tabBarHeight : m_tabBarHeight ; DWORD style = GetWindowLong(GWL_STYLE); if(style&CTCS_VERTICAL) { if(style&CTCS_BOTTOM) pRc->right-=tabHeight; else pRc->left+=tabHeight; } else { if(style&CTCS_BOTTOM) pRc->bottom-=tabHeight; else pRc->top+=tabHeight; } return TRUE; } DECLARE_WND_CLASS(_T("CFlyingTabCtrl")) BEGIN_MSG_MAP(thisClass) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_SETFONT, OnSetFont) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk) CHAIN_MSG_MAP(baseClass) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { UpdateTabAreaHeight(); bHandled=FALSE; return NULL; } LRESULT OnSetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { UpdateTabAreaHeight(); bHandled=FALSE; return NULL; } LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT lRes=baseClass::OnLButtonDown(uMsg,wParam,lParam,bHandled); bHandled=TRUE; CTCHITTESTINFO tchti = { 0 }; tchti.pt.x = GET_X_LPARAM(lParam); tchti.pt.y = GET_Y_LPARAM(lParam); int index=HitTest(&tchti); if(index!=-1) { ClientToScreen(&tchti.pt); if(DragDetect(m_hWnd,tchti.pt)) { CTabMoveTracker tracker(*this,index); if(TrackDragAndDrop(tracker,m_hWnd)) { CTCHITTESTINFO tchti = { 0 }; ::GetCursorPos(&tchti.pt); ScreenToClient(&tchti.pt); int index=HitTest(&tchti); if(index==-1) { MSG msg; while(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) DispatchMessage(&msg); NMHDR nmh; nmh.hwndFrom = m_hWnd; nmh.idFrom=GetDlgCtrlID(); nmh.code=CTCN_TABLEAVCTRL; ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM)&nmh); } } } } return lRes; } LRESULT OnLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { CTCHITTESTINFO tchti = { 0 }; tchti.pt.x = GET_X_LPARAM(lParam); tchti.pt.y = GET_Y_LPARAM(lParam); int index=HitTest(&tchti); if(index!=-1) { NMHDR nmh; nmh.hwndFrom = m_hWnd; nmh.idFrom=GetDlgCtrlID(); nmh.code=NM_DBLCLK; ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM)&nmh); } return 0; } protected: int m_tabBarHeight; }; }//namespace dockwins #endif // __WTL_DW__FLYING_TABS_H__