📄 guicontrolbar.cpp
字号:
//-----------------------------------------------------------------------//
// This is a part of the GuiLib MFC Extention. //
// Autor : Francisco Campos //
// (C) 2002 Francisco Campos <www.beyondata.com> All rights reserved //
// This code is provided "as is", with absolutely no warranty expressed //
// or implied. Any use is at your own risk. //
// You must obtain the author's consent before you can include this code //
// in a software library. //
// If the source code in this file is used in any application //
// then acknowledgement must be made to the author of this program //
// fco_campos@tutopia.com //
// Version :1.1 //
// Modified by : Francisco Campos //
//-----------------------------------------------------------------------//
// GuiControlBar.cpp : implementation file
#include "stdafx.h"
#include "..\header\GuiControlBar.h"
#include "..\header\GuiDockContext.h"
#include "..\header\guicontrolbar.h"
#include "..\header\GuiDrawLayer.h"
#include "..\header\guicontrolbar.h"
// CGuiControlBar
IMPLEMENT_DYNAMIC(CGuiControlBar, CControlBar)
CGuiControlBar::CGuiControlBar()
{
nGapGripper=20;
m_bActive=FALSE;
m_bOldActive=FALSE;
m_sizeMinFloating=m_sizeVert=m_sizeHorz=CSize(200,100);
m_sizeHorzt=CSize(200,100);
m_sizeVertt=CSize(200,100);
m_pos=0;
m_Last=0;
m_bTracking=FALSE;
m_rcBorder=CRect(0,0,0,0);
m_rcOldBorder=CRect(0,0,0,0);
m_ptOld=CPoint(0,0);
m_sizeMinV=CSize(28,28);
m_sizeMinH=CSize(28,28);
m_Initialize=FALSE;
m_First=-1;
m_bForcepaint=FALSE;
m_stateBtn=NORMAL;
m_clrFondo=GuiDrawLayer::GetRGBColorFace();
m_bSupportMultiView=FALSE;
m_MenuContext=NULL;
}
CGuiControlBar::~CGuiControlBar()
{
}
BEGIN_MESSAGE_MAP(CGuiControlBar, CControlBar)
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_NCLBUTTONDOWN()
ON_WM_NCRBUTTONDOWN()
ON_WM_NCLBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_NCPAINT()
ON_WM_NCCALCSIZE()
ON_WM_WINDOWPOSCHANGED()
ON_WM_PAINT()
ON_WM_LBUTTONDBLCLK()
ON_WM_NCLBUTTONDBLCLK()
ON_WM_NCHITTEST()
ON_WM_SETCURSOR()
ON_WM_SIZE()
ON_WM_NCMOUSEMOVE()
ON_WM_TIMER()
ON_COMMAND(WM_SHOWTITLE, OnShowTitle)
ON_WM_SYSCOLORCHANGE()
END_MESSAGE_MAP()
// CGuiControlBar message handlers
void CGuiControlBar::OnUpdateCmdUI(CFrameWnd* /*pTarget*/, BOOL /*bDisableIfNoHndler*/)
{
CWnd* pFocus = GetFocus();
m_bOldActive=(pFocus->GetSafeHwnd() && IsChild(pFocus));
m_bForcepaint=TRUE;
if (!m_bActive && m_bOldActive)
OnActiveWindow();
m_bForcepaint=FALSE;
}
void CGuiControlBar::OnSysColorChange( )
{
m_clrFondo=GuiDrawLayer::GetRGBColorFace();
CControlBar::OnSysColorChange( );
}
BOOL CGuiControlBar::Create(LPCTSTR lpszWindowName, DWORD dwStyle,CWnd* pParentWnd, UINT nID)
{
// TODO: Add your specialized code here and/or call the base class
//gran parte del codigo se tomo como guia de clases MFC
ASSERT_VALID(pParentWnd); // must have a parent
//en esta linea se verifica que la ventana debe disponer de un estilo fijo o dinamico
//pero no los dos.el estilo Dynamic permite cambiar el tama駉 dela ventana mientras flota
//pero no cuando esta docking, el estilo fijo determina las columnas en que se disponen los
//componentes y permance asi.
ASSERT(!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC)));
// save the style
//en dwStyle debe asignarse un tipo de alineaci髇 por ejemplo CBRS_TOP,etc de lo contrario
//se generase un ASSERT al acambiar el Style
dwStyle|=CBRS_TOP;
m_dwStyle = (dwStyle & CBRS_ALL);//save the original style
dwStyle &= ~CBRS_ALL;
//en la siguiente instruccion el proposito que se busca es evitar el parpadeo
//cuando se refresca la ventana.
//WS_CLIPCHILDREN : recorta el area de las ventanas hijas cuando se dibuja sobre
// la ventana que la contiene.
//WS_CLIPSIBLING : cuando se recibe el mensaje paint se recorta el area de las otras ventanas
// hijas superpuestas, que estan fuera de la region.
dwStyle |= WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
//con el estilo CS_DBLCLKS, lo que se busca es que al recibir un doble clic
//la ventana reaccione,ojo el problema es que esto lo hace solo con el area cliente.
LPCTSTR lpszClassName=::AfxRegisterWndClass(CS_DBLCLKS,
::LoadCursor(NULL,IDC_ARROW),
::GetSysColorBrush(COLOR_BTNFACE),
NULL);
//poque no se llama a CControlBar::Create, bueno, da igual llamar a cualquiera, CWnd o CControlBar
//esto debido a que CControlbar se deriva de CWnd y porque ademas CControlBar no sobrecarga el
//metodo Create, nosotros si porque tenemos que particularizar, cosas.
BOOL bResp= CWnd::Create(lpszClassName, lpszWindowName, dwStyle, CRect(0,0,0,0), pParentWnd, nID);
if (!bResp) return FALSE;
return TRUE;
}
int CGuiControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CControlBar::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
//aqui es cuando llamamos a nuestra clase CGuiDockContext, de esta manera
//sobrecargamos el clase original que para nuestros propositos no nos sirve.
//porque ?, bueno porque me interesa que no se pegen las toolbar en el interior
//de las ventanas.
if (m_pDockContext==NULL)
m_pDockContext=new CGuiDockContext(this);
ASSERT(m_pDockContext);
m_CloseBtn.SetData(6,"Close");
m_CloseBtn.SetImageList(IDB_DOCKBAR,9,10,RGB(255,0,255));
return 0;
}
void CGuiControlBar::OnShowTitle()
{
ActiveCaption();
SendMessage(WM_NCPAINT);
}
//esta funcion calcula el tama駉 horizontal de la ventana,no importa si esta
//docking a izquierda o derecha o arriba o abajo.Debemos disponer de un espacio equitativo entre todas
//ventanas que se encuentren docking ya sea en una fila o columna.
CSize CGuiControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
//la funcion original toma el ancho o alto dependiendo del sentido que nos
//indica bHorz.
ASSERT_VALID(this);
if (IsFloating())
return m_sizeMinFloating;
else
{
//si bStrerch es TRUE significa que esta ventana no se puede hacer
//Docking
if (bStretch)
{
if (bHorz)
return CSize(32767, m_sizeHorz.cy);
else
return CSize(m_sizeVert.cx, 32767);
}
}
int Len=GetHiWid();
int nWidth = GetWidthMax();
int nMinSpace=0;//minimo espacio requerido con lo tama駉s normales
int nMinimo=0; //minimo espacio de los tama駉s minimos
int nRealBars=0;
int m_First=GetFirstPos();
for (int nPos = m_First; nPos <= m_Last; nPos++)
{
CGuiControlBar* pBar = GetGuiControlBar(nPos,TRUE);
if (pBar== NULL) continue;
if (!pBar->IsVisible()) continue;
if (!pBar->IsKindOf(RUNTIME_CLASS(CGuiControlBar)))
{
CPoint pt(GetMessagePos());
m_pDockSite->FloatControlBar(pBar,pt);
continue;
}
if(IsVert())
pBar->m_sizeVert.cx=nWidth;
else
pBar->m_sizeHorz.cy=nWidth; //todas se hacen con el mismo ancho
nMinSpace+=IsVert() ? pBar->m_sizeVert.cy:pBar->m_sizeHorz.cx; //minimo espacio para alinear las barras
nRealBars++; //cuantas barras realmente existen
}
//si el tama駉 de las barras en la fila es mayor que
//el espacio disponible, luego la solucion salomonica es
//repartir el espacio entre todas.
if (nRealBars == 1 )
{
if (bHorz)
return m_sizeHorz= CSize(Len,m_sizeHorz.cy);
else
return m_sizeVert=CSize(m_sizeVert.cx,Len);
}
int nDif=Len-nMinSpace;
if (abs(nDif) !=0)
{
BOOL bGrow=FALSE;
if (nDif > 0)
bGrow=TRUE;
nDif=abs(nDif);
while(nDif > 0)
{
for (int nPos = m_First; nPos <= m_Last; nPos++)
{
CGuiControlBar* pBar = GetGuiControlBar(nPos);
if (pBar== NULL) continue;
if(IsVert())
{
if(bGrow)
pBar->m_sizeVert.cy+=1;
else
{
if (pBar->m_sizeVert.cy-1 < pBar->m_sizeMinV.cy)
{
nDif--; //bug fixed
continue;
}
pBar->m_sizeVert.cy-=1;
}
}
else
{
if(bGrow)
pBar->m_sizeHorz.cx+=1;
else
{
if (pBar->m_sizeHorz.cx-1 < pBar->m_sizeMinH.cx)
{
nDif--; //bug fixed
continue;
}
pBar->m_sizeHorz.cx-=1;
}
}
nDif--;
if(nDif==0) break;
}
}
}
//--reubicar las ventanas, sin esta rutina nada funciona
RecalWindowPos();
if (IsHorz())
return m_sizeHorz;
else
return m_sizeVert;
}
//esta rutina dispone de la posici髇 en el Dockbar de la pila de ventanas
void CGuiControlBar::RecalWindowPos()
{
int m_First=GetFirstPos();
int m_Last=GetLastPos();
int m_This=m_pDockBar->FindBar(this);
CRect rcWin=GetDockRect();
int m_VertPos=0;
for(int i=m_First; i<= m_Last; i++)
{
CGuiControlBar* pBar = GetGuiControlBar(i);
if (pBar == NULL) continue;
CRect rcBar;
pBar->GetWindowRect(rcBar);
rcBar.OffsetRect(-rcWin.TopLeft());
if (IsVert())
{
if (i==m_First)
{
rcBar.top=0;
}
else
rcBar.top=m_VertPos;
}
else
{
if (i==m_First)
rcBar.left=0;
else
rcBar.left=m_VertPos;
}
pBar->MoveWindow(rcBar);
m_VertPos+=IsVert()? rcBar.Height():rcBar.Width();
}
m_pDockSite->DelayRecalcLayout();
m_pDockSite->DelayRecalcLayout();
}
CRect CGuiControlBar::GetDockRect()
{
CRect rcWin;
if (IsVert())
if (IsLeft())
m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_LEFT)->GetWindowRect(rcWin);
else
m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_RIGHT)->GetWindowRect(rcWin);
else
if(IsBottom())
m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_BOTTOM)->GetWindowRect(rcWin);
else
m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_TOP)->GetWindowRect(rcWin);
return rcWin;
}
int CGuiControlBar::GetWidthMax()
{
m_pos=m_pDockBar->FindBar(this);
m_Last=GetLastPos();
int nWidth=0;
for (int nPos = GetFirstPos(); nPos <= m_Last; nPos++)
{
CGuiControlBar* pBar = GetGuiControlBar(nPos);
if (pBar== NULL) continue;
nWidth=max(nWidth,IsVert() ? pBar->m_sizeVert.cx:pBar->m_sizeHorz.cy);
}
return nWidth;
}
CGuiControlBar* CGuiControlBar::GetGuiControlBar(int nPos,BOOL bAll) const
{
CGuiControlBar* pResult = (CGuiControlBar*)m_pDockBar->m_arrBars[nPos];
if (bAll==FALSE)
{
if (HIWORD(pResult) == NULL) return NULL;
else if (!pResult->IsVisible()) return NULL;
else if (!pResult->IsKindOf(RUNTIME_CLASS(CGuiControlBar))) return NULL;
}
else
{
if (HIWORD(pResult) == NULL)
return NULL;
}
return pResult;
}
//En esta funci髇 se calcula el tama駉 de la ventana cuando esta flotando
//y gestionar cuando el mouse es presionado en las esquinas.
//#define HTTOPLEFT 13
//#define HTTOPRIGHT 14
//#define HTBOTTOMLEFT 16
//#define HTBOTTOMRIGHT 17
CSize CGuiControlBar::CalcDynamicLayout(int nLength, DWORD nMode)
{
m_pDockSite->DelayRecalcLayout();
if (IsFloating())
{
// Enable diagonal arrow cursor for resizing
//m_sizeVert=m_sizeHorz=CSize(200,200);
GetParent()->GetParent()->ModifyStyle(MFS_4THICKFRAME/*|WS_CAPTION*/,0);
}
if (nMode & (LM_HORZDOCK | LM_VERTDOCK))
{
m_pDockSite->DelayRecalcLayout();
//obligar a reposicionar la ventana, de lo contrario cuando vuelva de un doble click
//desde la ventana CMiniFrameWnd queda sin area cliente
SetWindowPos(NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER |
SWP_NOACTIVATE | SWP_FRAMECHANGED|SWP_NOREDRAW);
return CControlBar::CalcDynamicLayout(nLength, nMode);
}
if (nMode & LM_MRUWIDTH)
return m_sizeMinFloating;
if (nMode & LM_COMMIT)
return m_sizeMinFloating ;
if (IsFloating())
{
CRect rcWin;
POINT cpt;
GetCursorPos(&cpt);
GetParent()->GetParent()->GetWindowRect(&rcWin);
int nXOffset=0;int nYOffset=0;
switch (m_pDockContext->m_nHitTest)
{
//------------------------------------------------------------------
case HTLEFT:
m_pDockContext->m_rectFrameDragHorz= rcWin;
m_pDockContext->m_rectFrameDragHorz.left = cpt.x;
m_sizeMinFloating.cx = max(rcWin.right - cpt.x,32)-4 ;
m_sizeMinFloating.cy = max((rcWin.bottom -rcWin.top)-nGapGripper-5,32)+2 ;
return m_sizeMinFloating;
break;
case HTTOP:
m_pDockContext->m_rectFrameDragHorz=rcWin;
m_pDockContext->m_rectFrameDragHorz.top = cpt.y;
m_sizeMinFloating.cx = max(rcWin.right-rcWin.left-2,32)-4 ;
m_sizeMinFloating.cy = max((rcWin.bottom -nGapGripper-cpt.y-3),32) ;
return m_sizeMinFloating;
break;
case HTRIGHT:
m_pDockContext->m_rectFrameDragHorz=rcWin;
m_pDockContext->m_rectFrameDragHorz.right = cpt.x;
m_sizeMinFloating.cy = max(rcWin.bottom -rcWin.top-nGapGripper-3,32) ;
m_sizeMinFloating.cx = max(cpt.x-rcWin.left-4,32);
return m_sizeMinFloating;
break;
case HTBOTTOM:
m_pDockContext->m_rectFrameDragHorz=rcWin;
m_sizeMinFloating.cy = max(cpt.y-rcWin.top -nGapGripper-3,32) ;
m_sizeMinFloating.cx = max(rcWin.right-rcWin.left-2,32)-4 ;
m_pDockContext->m_rectFrameDragHorz.bottom = cpt.y-4;
return m_sizeMinFloating;
break;
case HTTOPLEFT:
//---------------------------------------------------------
//En este caso crece la ventana a izquierda y hacia arriba
//izquierda incrementa cx y top incrementa cy
m_sizeMinFloating.cx = max(rcWin.right - cpt.x,32)-3 ;
m_sizeMinFloating.cy = max(rcWin.bottom -nGapGripper-cpt.y,32)-2 ;
m_pDockContext->m_rectFrameDragHorz.top = cpt.y-1;
m_pDockContext->m_rectFrameDragHorz.left = cpt.x-2;
return m_sizeMinFloating;
break;
case HTTOPRIGHT:
m_sizeMinFloating.cx = max(cpt.x-rcWin.left,32)-4 ;
m_sizeMinFloating.cy = max(rcWin.bottom -nGapGripper-cpt.y,32)-2 ;
m_pDockContext->m_rectFrameDragHorz.top = cpt.y-1;
m_pDockContext->m_rectFrameDragHorz.right = cpt.x-2;
return m_sizeMinFloating;
break;
case HTBOTTOMLEFT:
m_sizeMinFloating.cx = max(rcWin.right - cpt.x,32)-4;
m_sizeMinFloating.cy = max(cpt.y-rcWin.top -nGapGripper,32)-2 ;
m_pDockContext->m_rectFrameDragHorz.top = rcWin.top;
m_pDockContext->m_rectFrameDragHorz.bottom = cpt.y-1;
m_pDockContext->m_rectFrameDragHorz.left = cpt.x-2;
return m_sizeMinFloating;
break;
case HTBOTTOMRIGHT:
m_sizeMinFloating.cx = max(cpt.x-rcWin.left,32);
m_sizeMinFloating.cy = max(cpt.y-rcWin.top -nGapGripper,32) ;
m_pDockContext->m_rectFrameDragHorz.top = rcWin.top;
m_pDockContext->m_rectFrameDragHorz.bottom = cpt.y+1;
m_pDockContext->m_rectFrameDragHorz.right = cpt.x+2;
return m_sizeMinFloating;
break;
}
}
if(nMode & LM_LENGTHY)
m_sizeMinFloating.cy = max(nLength,32);
else
m_sizeMinFloating.cx = max(nLength,32);
return m_sizeMinFloating;
}
void CGuiControlBar::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_pDockBar != NULL)
{
ActiveCaption();
m_pDockContext->ToggleDocking();
}
else
CWnd::OnLButtonDblClk(nFlags, point);
}
void CGuiControlBar::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (m_pDockBar != NULL)
{
// start the drag
ClientToScreen(&point);
m_pDockContext->StartDrag(point);
}
else
CControlBar::OnLButtonDown(nFlags, point);
}
void CGuiControlBar::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (m_pDockBar != NULL)
{
// start the drag
ReleaseCapture();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -