⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 docktabsplitpane.h

📁 These listed libraries are written in WTL. But it s really hard to mix both MFC & WTL together. Obvi
💻 H
📖 第 1 页 / 共 3 页
字号:
#pragma once

#ifndef __DOCKSPLITPANE_H__
#define __DOCKSPLITPANE_H__

#ifndef __cplusplus
	#error DockTabSplitPane.h requires C++ compilation (use a .cpp suffix)
#endif

#ifndef __ATLWIN_H__
	#error DockTabSplitPane.h requires atlwin.h to be included first
#endif

#ifndef __ATLAPP_H__
	#error DockTabSplitPane.h requires atlapp.h to be included first
#endif

#ifndef __ATLCOLL_H__
	#error DockTabSplitPane.h requires atlcoll.h to be included first
#endif

#ifndef __ATLSTR_H__
	#error DockTabSplitPane.h requires atlstr.h to be included first
#endif

#ifndef __ATLTYPES_H__
	#error DockTabSplitPane.h requires atltypes.h to be included first
#endif

#ifndef __ATLSPLIT_H__
	#error DockTabSplitPane.h requires atlsplit.h to be included first
#endif

#ifndef __ATLGDI_H__
	#error DockTabSplitPane.h requires atlgdi.h to be included first
#endif

#ifndef __ATLCTRLS_H__
	#error DockTabSplitPane.h requires atlctrls.h to be included first
#endif

/*********************************************************************
DockSplitTab::SplitPane class implementation

Written by Igor Katrayev.
Copyright (c) 2003 Igor Katrayev.

This code may be used in compiled form in any way you desire. This
file may be redistributed unmodified by any means PROVIDING it is 
not sold for profit without the authors written consent, and 
providing that this notice and the authors name is included. 

This file is provided "as is" with no expressed or implied warranty.
The author accepts no liability if it causes any damage to you or your
computer whatsoever. It's free, so don't hassle me about it.

Beware of bugs.
**********************************************************************/

#include "DockTabPane.h"

namespace DockSplitTab {

// destroy pane message
#define WM_USER_DESTROY_PANE WM_USER+1
	
	_declspec(selectany) POINT pointNULL = { -1, -1};
	_declspec(selectany) RECT  rectNULL  = { -1, -1, -1, -1};
	
	template <bool t_bVertical = true>
	class SplitterT: public CSplitterWindowImpl<SplitterT<t_bVertical>, t_bVertical> {
	protected:
	public:
		
		~SplitterT() {
			
			if ( this->m_hWnd) {
				
				::DestroyWindow( this->m_hWnd);
				this->m_hWnd = NULL;
			}
		}
		
		DECLARE_WND_CLASS( _T("DockTab::Splitter"))
	};
	
	typedef SplitterT<true>  VSplitter;
	typedef SplitterT<false> HSplitter;
	
	
	class RectTracker {
	protected:
		HWND  trackWindow;
		CRect trackRect;
		
		static void drawRect( HDC hdc, LPRECT rect) {
			
			int width  = rect->right - rect->left;
			int height = rect->bottom - rect->top;
			const int size = 4;
			if ( width <= size || height <= size) {
				
				::PatBlt( hdc, rect->left, rect->top, width, height, PATINVERT);
			} else {
				
				::PatBlt( hdc, rect->left,       rect->top,         width-size,        size, PATINVERT);
				::PatBlt( hdc, rect->left+size,  rect->bottom-size, width-size,        size, PATINVERT);
				::PatBlt( hdc, rect->left,       rect->top+size,          size, height-size, PATINVERT);
				::PatBlt( hdc, rect->right-size, rect->top,               size, height-size, PATINVERT);
			}
		}
		
	public:
		
		RectTracker()
			: trackWindow( NULL)
			, trackRect( -1, -1, -1, -1)
		{}
		
		RectTracker( HWND trackWindow)
			: trackWindow( trackWindow)
			, trackRect( -1, -1, -1, -1)
		{}
		
		void emptyRect() {
			
			this->trackRect = rectNULL;
		}
		
		LPRECT getTrackRect() {
			
			return this->trackRect;
		}
		
		const HWND getTrackWindow() const {
			
			return this->trackWindow;
		}
		
		void drawTrackRectangle( HWND trackWindow, LPRECT rect, bool clear = true) {
			
			if ( this->trackRect.EqualRect( rect) && this->trackWindow == trackWindow)
				return;
			
			// draw a new track rectangle
			CWindowDC windowDC( trackWindow);
			CBrush brush = CDCHandle::GetHalftoneBrush();
			if ( NULL == brush.m_hBrush)
				return;
			
			CBrushHandle brushOld = windowDC.SelectBrush( brush);
			if ( clear) {
				
				if ( this->trackWindow != trackWindow)
					
					this->clearTrackRectangle();
				else if ( this->trackRect.TopLeft() != pointNULL)
				
					this->drawRect( windowDC, this->trackRect);
			}
			
			this->drawRect( windowDC, rect);
			
			windowDC.SelectBrush(brushOld);
			
			this->trackRect   = rect;
			this->trackWindow = trackWindow;
		}
		
		void clearTrackRectangle( bool clear = true) {
			
			if ( this->trackRect.TopLeft() != pointNULL) {
				
				HWND wnd          = this->trackWindow;
				this->trackWindow = reinterpret_cast<HWND>( -1);
				this->drawTrackRectangle( wnd, this->trackRect, false);
				
				if ( clear) {
					
					this->trackRect = rectNULL;
					this->trackWindow = reinterpret_cast<HWND>( -1);
				} else
					this->trackWindow = wnd;
			}
		}
	};
	
	class SplitPane
		: public CWindowImplBaseT< CWindow, CControlWinTraits>
		, public CallBackListener

	{
	typedef CWindow TBase;
	typedef CControlWinTraits TWinTraits;
	typedef CWindowImplBaseT< CWindow, CControlWinTraits> ParentClass;
	
	//----------------- protected classes
	protected:
		
		class DragContext
			: public RectTracker {
		
		public:
			
			Pane::TabPaneHitTest tabPaneHitTest;
			
			// Constructor/destructor for DragContext class
			DragContext()
				: RectTracker()
				, tabPaneHitTest( Pane::TabPaneHitTest_Unknown)
			{}
			
			~DragContext() {
				
				this->clearTrackRectangle();
			}
		};
		
	//----------------- protected members
	protected:
		
		WTL::CImageList imageList;
		
		CAtlMap< HWND, VSplitter*> verSplitterMap;
		
		CAtlMap< HWND, HSplitter*> horSplitterMap;
		
		CAtlMap< HWND, Pane*> paneMap;
		
		CAtlMap< HWND, Pane*> clientViewPaneMap;
		
		Pane* currentPane;
		HWND  rootWnd;
		
		DragContext* dragContext;
		CallBackListener* cbListener;
		bool tabOnTop;
		
	//----------------- protected interface
	protected:
		
		// Get a pane by a given point in screen coordinates
		Pane* getPane( long x, long y) {
			
			CPoint dropPoint( x, y);
			Pane* result = NULL;
			
			POSITION position = this->paneMap.GetStartPosition();
			if ( position)
				do {
					
					Pane* pane = this->paneMap.GetNextValue( position);
					CPoint pt = dropPoint;
					pane->ScreenToClient( &pt);
					CRect rect;
					pane->GetClientRect( &rect);
					if ( rect.PtInRect( pt)) {
						result = pane;
						break;
					}
				} while ( position);
			return result;
		} // Pane* getPane( long x, long y)
		
		void moveCurrentTab( Pane* sourcePane, Pane* targetPane) {
			
			ATLASSERT( NULL != sourcePane && NULL != targetPane && targetPane != sourcePane);
			
			HWND clientWin = sourcePane->moveCurrentTabTo( targetPane);
			this->clientViewPaneMap[clientWin] = targetPane;
			
			HWND sourcePaneParentWnd = sourcePane->GetParent();
			targetPane->SetFocus();
			targetPane->updateLayout();
			
			if ( sourcePane->isEmpty() && sourcePaneParentWnd != this->m_hWnd) {
				// important:
				// destroy the source pane via the message queue becouse this call maybe done by a tab control
				// belonging to the source pane. we don't want to destroy it before it ends.
				this->PostMessage( WM_USER_DESTROY_PANE, 0, (LPARAM) sourcePane->m_hWnd);
			}
			return;
		} // moveCurrentTab( Pane* sourcePane, Pane* targetPane);
		
		void splitWithCurrentTab( Pane* sourcePane, Pane* targetPane, Pane::TabPaneHitTest where) {
			
			ATLASSERT( NULL != sourcePane);
			ATLASSERT( NULL != targetPane);
			ATLASSERT(    Pane::TabPaneHitTest_Right  == where
			           || Pane::TabPaneHitTest_Left   == where
			           || Pane::TabPaneHitTest_Top    == where
			           || Pane::TabPaneHitTest_Bottom == where
			         );
			
			VSplitter* verSplitter;
			HSplitter* horSplitter;
			CAtlMap< HWND, HSplitter*>::CPair* horSplitPair;
			CAtlMap< HWND, VSplitter*>::CPair* verSplitPair;
			CRect newPaneRect;
			CRect newSplitterRect;
			CRect sourcePaneRect;
			CRect targetPaneRect;
			
			HWND newSplitterWnd = NULL;
			HWND targetPaneParent = ::GetParent( targetPane->m_hWnd);
			
			CRect targetRect;
			targetPane->GetWindowRect( &targetRect);
			
			// create a new splitter
			bool isVertical;
			switch ( where) {
			case Pane::TabPaneHitTest_Right:
			case Pane::TabPaneHitTest_Left: {
					
					isVertical = true;
					verSplitter = new VSplitter();
					verSplitter->Create( targetPaneParent, &rectNULL, NULL, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0);
					this->verSplitterMap.SetAt( verSplitter->m_hWnd, verSplitter);
					
					newSplitterWnd = verSplitter->m_hWnd;
				}
				break;
				
			case Pane::TabPaneHitTest_Top:
			case Pane::TabPaneHitTest_Bottom: {
					
					isVertical = false;
					horSplitter = new HSplitter();
					horSplitter->Create( targetPaneParent, &rectNULL, NULL, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0);
					this->horSplitterMap.SetAt( horSplitter->m_hWnd, horSplitter);
					
					newSplitterWnd = horSplitter->m_hWnd;
				}
				break;
			}
			
			// create a new pane and move the current tab from the target pane to the new one
			Pane* newPane = new Pane( this, this->tabOnTop);
			newPane->Create( newSplitterWnd);
			this->paneMap[ newPane->m_hWnd] = newPane;
			
			HWND clientWin = sourcePane->moveCurrentTabTo( newPane);
			this->clientViewPaneMap[ clientWin] = newPane;
			
			// assign the splitter as the parent window to the target pane
			targetPane->SetParent( newSplitterWnd);
			
			// work out with the splitter parent window
			if ( this->m_hWnd == targetPaneParent) {
				
				// the first splitter created
				this->rootWnd   = newSplitterWnd;
				newSplitterRect = CRect( 0, 0, targetRect.Width(), targetRect.Height());
				
			} else {
				
				// get a parent splitter for the target pane and reassign the pane to the new splitter created
				VSplitter* parentVerSplitter = NULL;
				HSplitter* parentHorSplitter = NULL;
				
				::SetParent( newSplitterWnd, targetPaneParent);
				if ( NULL != ( verSplitPair = this->verSplitterMap.Lookup( targetPaneParent))) {
					
					// it is a vertical splitter
					parentVerSplitter = verSplitPair->m_value;
					
					if ( parentVerSplitter->GetSplitterPane( SPLIT_PANE_LEFT) == targetPane->m_hWnd) {
						
						parentVerSplitter->SetSplitterPane( SPLIT_PANE_LEFT, newSplitterWnd, false);
						parentVerSplitter->GetSplitterPaneRect( SPLIT_PANE_LEFT, &newSplitterRect);
						
					} else if ( parentVerSplitter->GetSplitterPane( SPLIT_PANE_RIGHT) == targetPane->m_hWnd) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -