|
|
#include "stdafx.h"
#include "global.h"
#include "sprite.h"
#ifdef _DEBUG
#undef THIS_FILE
static CHAR BASED_CODE THIS_FILE[] = __FILE__; #endif
#ifdef _DEBUG
IMPLEMENT_DYNAMIC( CDragger, CObject ) IMPLEMENT_DYNAMIC( CMultiDragger, CDragger ) IMPLEMENT_DYNAMIC(CSprite, CDragger) #endif
#include "memtrace.h"
extern BOOL moduleInit;
/**********************************************************************/ /* CDragger Implementation */ /**********************************************************************/
/*
* OPTIMIZATION * * At the moment, draggers get a new DC whenever they need to draw or * erase. We could cut that in half easily by merging the draw/erase * code, and achieve even better wins by allocating a single DC for a * multiple selection draw/erase. */
CDragger::CDragger( CWnd* pWnd, CRect* pRect ) { ASSERT(pWnd != NULL);
m_pWnd = pWnd; m_state = hidden;
m_rect.SetRect(0,0,0,0);
if (pRect != NULL) m_rect = *pRect; }
CDragger::~CDragger() { if (m_pWnd->m_hWnd != NULL && m_state != hidden) Hide(); }
/* CDragger::Draw
* * This is a specialized Draw to draw our drag rectangles; drag * rectangles are the dotted rectangles which we draw when the user is * dragging a tracker to move or resize a control. */ void CDragger::Draw() { ASSERT( m_pWnd != NULL );
CRect rect = m_rect;
/*
* This gets complex -- hold on to your hat. The m_rect is * measured in client coordinates of the window, but since we * need to use GetWindowDC rather than GetDC (to avoid having * the m_rect clipped by the dialog's children) we must map * these coordinates to window coords. We do this by mapping * them into screen coordinates, computing the offset from the * upper left corner of the dialog's WindowRect, and mapping * them back. It's the most efficient way I can think to do * it; other suggestions are welcome. */ CRect parentRect;
m_pWnd->GetWindowRect( &parentRect ); m_pWnd->ClientToScreen( &rect );
rect.OffsetRect( -parentRect.left, -parentRect.top );
// now we've got "rect" in the coordinates of the thing we
// want to draw on.
int dx = (rect.right - rect.left) - 1; int dy = (rect.bottom - rect.top) - 1;
CDC* dc = m_pWnd->GetWindowDC();
ASSERT( dc != NULL );
CBrush* oldBrush = dc->SelectObject( GetHalftoneBrush() );
dc->PatBlt( rect.left , rect.top , dx, 1 , PATINVERT ); dc->PatBlt( rect.left , rect.bottom - 1, dx, 1 , PATINVERT ); dc->PatBlt( rect.left , rect.top , 1 , dy, PATINVERT ); dc->PatBlt( rect.right - 1, rect.top , 1 , dy, PATINVERT );
dc->SelectObject( oldBrush );
m_pWnd->ReleaseDC( dc ); }
/* CDragger::Erase
* * Since the default draw uses XOR, we can just Draw again to erase! */ void CDragger::Erase() { Draw(); }
/* CDragger::Show, Hide
* * The "drag rectangle" is the dotted rectangle which we draw when the * user is moving or resizing a control by dragging it with the mouse. * These functions erase and draw the drag rectangle, respectively. */ void CDragger::Hide() { if (m_state != shown) return;
m_state = hidden; Erase(); }
void CDragger::Show() { if (m_state != hidden) return;
m_state = shown; Draw(); }
void CDragger::Obscure( BOOL bObscure ) { if (bObscure) { if (m_state != shown) return;
Hide(); m_state = obscured; } else { if (m_state != obscured) return;
m_state = hidden; Show(); } }
/* CDragger::Move
* * Since nearly every single occurance of "CDragger->Show" occurred in * the context "Hide, m_rect = foo, Show", I decided to merge this * functionality into a single C++ function. */ void CDragger::Move(const CRect& newRect, BOOL bForceShow) { if ((m_rect == newRect) && !bForceShow) return;
BOOL fShow = bForceShow || m_state == shown; Hide(); m_rect = newRect;
if (fShow) Show(); }
void CDragger::MoveBy(int cx, int cy, BOOL bForceShow) { CSize offset (cx, cy); CPoint newTopLeft = m_rect.TopLeft() + offset; Move(newTopLeft, bForceShow); }
CRect CDragger::GetRect() const { return m_rect; }
void CDragger::Move(const CPoint& newTopLeft, BOOL bForceShow) { Move(m_rect - m_rect.TopLeft() + newTopLeft, bForceShow); }
void CDragger::SetSize(const CSize& newSize, BOOL bForceShow) { CRect newRect = m_rect; newRect.right = newRect.left + newSize.cx; newRect.bottom = newRect.top + newSize.cy;
Move(newRect, bForceShow); }
CMultiDragger::CMultiDragger() : m_draggerList() { ASSERT( m_draggerList.IsEmpty() ); }
CMultiDragger::CMultiDragger(CWnd *pWnd) : CDragger(pWnd), m_draggerList() { ASSERT(m_draggerList.IsEmpty()); }
CMultiDragger::~CMultiDragger() { POSITION pos = m_draggerList.GetHeadPosition(); while (pos != NULL) { CDragger *pDragger = (CDragger*) m_draggerList.GetNext(pos); delete pDragger; } }
CRect CMultiDragger::GetRect() const { // accumulate the bounding rectangle for the group
POSITION pos = m_draggerList.GetHeadPosition();
CRect boundRect (32767, 32767, -32767, -32767); while (pos != NULL) { CDragger *pDragger = (CDragger*) m_draggerList.GetNext(pos); boundRect.left = min (boundRect.left, pDragger->m_rect.left); boundRect.right = max (boundRect.right, pDragger->m_rect.right); boundRect.top = min (boundRect.top, pDragger->m_rect.top); boundRect.bottom= max (boundRect.bottom, pDragger->m_rect.bottom); }
return boundRect; }
void CMultiDragger::Hide() { // hide each dragger on the list
POSITION pos = m_draggerList.GetHeadPosition(); while (pos != NULL) { CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos); pDragger->Hide(); } }
void CMultiDragger::Show() { // show each dragger on the list
POSITION pos = m_draggerList.GetHeadPosition(); while (pos != NULL) { CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos); pDragger->Show(); } }
void CMultiDragger::Draw() { // draw each dragger on the list
POSITION pos = m_draggerList.GetHeadPosition(); while (pos != NULL) { CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos); pDragger->Draw(); } }
void CMultiDragger::Erase() { // erase each dragger on the list
POSITION pos = m_draggerList.GetHeadPosition();
while (pos != NULL) { CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos); pDragger->Erase(); } }
void CMultiDragger::Move(const CPoint& newTopLeft, BOOL bForceShow) { // move each dragger to the new top left
// first go through the list and find the current topmost leftmost
// point
CPoint topLeft (32767, 32767); POSITION pos = m_draggerList.GetHeadPosition(); while (pos != NULL) { CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos); CRect draggerRect = pDragger->GetRect(); if (draggerRect.left < topLeft.x) topLeft.x= draggerRect.left; if (draggerRect.top < topLeft.y) topLeft.y= draggerRect.top; }
// now find the offset and move each dragger
CSize offset = newTopLeft - topLeft; pos = m_draggerList.GetHeadPosition(); while (pos != NULL) { CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos); pDragger->MoveBy(offset.cx, offset.cy, bForceShow); } }
void CMultiDragger::Add(CDragger *pDragger) { // add the dragger to the list
ASSERT(pDragger != NULL); m_draggerList.AddTail(pDragger); }
void CMultiDragger::Remove(CDragger *pDragger) { // remove the dragger from the list
ASSERT(pDragger != NULL); POSITION pos = m_draggerList.Find(pDragger); if (pos != NULL) m_draggerList.RemoveAt(pos); }
CSprite::CSprite() : m_saveBits() { m_state = hidden; m_pWnd = NULL; }
CSprite::CSprite(CWnd* pWnd, CRect* pRect) : CDragger(pWnd, pRect), m_saveBits() { m_state = hidden; m_pWnd = pWnd; }
CSprite::~CSprite() { if (m_pWnd->m_hWnd != NULL && m_state != hidden) Hide(); }
void CSprite::Move(const CRect& newRect, BOOL bForceShow) { CRect rect = newRect;
if ((rect == m_rect) && !bForceShow) return;
STATE oldState = m_state; Hide(); if (newRect.Size() != m_rect.Size()) m_saveBits.DeleteObject(); m_rect = rect; if (bForceShow || oldState == shown) Show(); }
void CSprite::SaveBits() { CClientDC dcWnd(m_pWnd); CDC dcSave; CBitmap* pOldBitmap;
dcSave.CreateCompatibleDC(&dcWnd); if (m_saveBits.m_hObject == NULL) { m_saveBits.CreateCompatibleBitmap(&dcWnd, m_rect.Width(), m_rect.Height()); } pOldBitmap = dcSave.SelectObject(&m_saveBits); dcSave.BitBlt(0, 0, m_rect.Width(), m_rect.Height(), &dcWnd, m_rect.left, m_rect.top, SRCCOPY); dcSave.SelectObject(pOldBitmap); }
void CSprite::Erase() { if (m_saveBits.m_hObject == NULL) return;
LONG dwStyle = ::GetWindowLong(m_pWnd->m_hWnd, GWL_STYLE); ::SetWindowLong(m_pWnd->m_hWnd, GWL_STYLE, dwStyle & ~WS_CLIPCHILDREN);
CClientDC dcWnd(m_pWnd); CDC dcSave; CBitmap* pOldBitmap;
dcSave.CreateCompatibleDC(&dcWnd); pOldBitmap = dcSave.SelectObject(&m_saveBits); dcWnd.ExcludeUpdateRgn(m_pWnd); dcWnd.BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), &dcSave, 0, 0, SRCCOPY); dcSave.SelectObject(pOldBitmap);
::SetWindowLong(m_pWnd->m_hWnd, GWL_STYLE, dwStyle); }
CHighlight::CHighlight() { m_bdrSize = 2; }
CHighlight::CHighlight(CWnd *pWnd, CRect *pRect, int bdrSize) : CDragger(pWnd, pRect) { m_bdrSize = bdrSize; m_rect.InflateRect(m_bdrSize, m_bdrSize); }
CHighlight::~CHighlight() { if (m_pWnd->m_hWnd != NULL && m_state != hidden) Hide(); }
void CHighlight::Draw() { m_pWnd->UpdateWindow();
CClientDC dc(m_pWnd); CBrush *pOldBrush = dc.SelectObject(GetSysBrush(COLOR_HIGHLIGHT));
// draw the top, right, bottom and left sides
dc.PatBlt(m_rect.left + m_bdrSize, m_rect.top , m_rect.Width() - m_bdrSize, m_bdrSize , PATCOPY); dc.PatBlt(m_rect.right - m_bdrSize , m_rect.top + m_bdrSize , m_bdrSize , m_rect.Height() - m_bdrSize, PATCOPY); dc.PatBlt(m_rect.left , m_rect.bottom - m_bdrSize , m_rect.Width() - m_bdrSize, m_bdrSize , PATCOPY); dc.PatBlt(m_rect.left , m_rect.top , m_bdrSize , m_rect.Height() - m_bdrSize, PATCOPY);
// restore the state of the DC
dc.SelectObject(pOldBrush); }
void CHighlight::Erase() { m_pWnd->InvalidateRect(&m_rect); m_pWnd->UpdateWindow(); }
|