Menu

Commit [r76]  Maximize  Restore  History

* Use a vector to store the popup window slots. This avoids showing a popup in a position where a previous one is still showing.

* First draft of drawing the popup window.

tortoisesvn 2007-04-21

changed /trunk/src/StatusBarMsgWnd.cpp
changed /trunk/src/StatusBarMsgWnd.h
added /trunk/src/memdc.h
/trunk/src/StatusBarMsgWnd.cpp Diff Switch to side-by-side view
--- a/trunk/src/StatusBarMsgWnd.cpp
+++ b/trunk/src/StatusBarMsgWnd.cpp
@@ -3,7 +3,16 @@
 #include <ShellAPI.h>
 #include <assert.h>
 
+#include "MemDC.h"
+
 int CStatusBarMsgWnd::m_counter = 0;
+vector<int> CStatusBarMsgWnd::m_slots;
+
+CStatusBarMsgWnd::~CStatusBarMsgWnd()
+{
+	if (m_icon)
+		::DestroyIcon(m_icon);
+}
 
 bool CStatusBarMsgWnd::RegisterAndCreateWindow()
 {
@@ -32,13 +41,15 @@
 	return false;
 }
 
-void CStatusBarMsgWnd::Show(LPCTSTR title, LPCTSTR text, HWND hParentWnd, UINT messageOnClick, int stay /* = 10 */)
+void CStatusBarMsgWnd::Show(LPCTSTR title, LPCTSTR text, UINT icon, HWND hParentWnd, UINT messageOnClick, int stay /* = 10 */)
 {
 	m_title = wstring(title);
 	m_text = wstring(text);
 	m_hParentWnd = hParentWnd;
 	m_messageOnClick = messageOnClick;
 	m_stay = stay;
+	m_icon = (HICON)::LoadImage(hResource, MAKEINTRESOURCE(icon), IMAGE_ICON, 
+		STATUSBARMSGWND_ICONSIZE, STATUSBARMSGWND_ICONSIZE, LR_DEFAULTCOLOR);
 
 	::SystemParametersInfo(SPI_GETWORKAREA, 0, &m_workarea, 0);
 
@@ -51,7 +62,20 @@
 
 	m_ShowTicks = 0;
 	m_counter++;
-	m_thiscounter = m_counter;
+	// find an empty slot
+	m_thiscounter = 0;
+	for (vector<int>::iterator it = m_slots.begin(); it != m_slots.end(); ++it)
+	{
+		if (*it)
+			m_thiscounter++;
+		else
+		{
+			*it = 1;
+			break;
+		}
+	}
+	if (m_thiscounter >= (int)m_slots.size())
+		m_slots.push_back(1);
 	SetTimer(*this, STATUSBARMSGWND_SHOWTIMER, 10, NULL);
 }
 
@@ -64,15 +88,38 @@
 		break;
 	case WM_TIMER:
 		return DoTimer();
+	case WM_ERASEBKGND:
+		return TRUE;
 	case WM_PAINT:
 		{
-			PAINTSTRUCT ps;
-			HDC hdc = BeginPaint(hwnd, &ps); 
 			RECT rect;
-			::GetClientRect(*this, &rect);
-			SetBkColor(hdc, ::GetSysColor(COLOR_WINDOW));
-			::ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
-			EndPaint(hwnd, &ps);
+			if (GetUpdateRect(*this, &rect, false))
+			{
+				::GetClientRect(*this, &rect);
+				// adjust the rectangle according to which part is hidden
+				switch (m_uEdge)
+				{
+				case ABE_BOTTOM:
+					rect.bottom = rect.top + m_height;
+					break;
+				case ABE_LEFT:
+					rect.left = rect.right - m_width;
+					break;
+				case ABE_RIGHT:
+					rect.right = rect.left + m_width;
+					break;
+				case ABE_TOP:
+					rect.top = rect.bottom - m_height;
+					break;
+				default:
+					break;
+				}
+				PAINTSTRUCT ps;
+				HDC hdc = BeginPaint(hwnd, &ps);
+				CMemDC memdc(hdc);
+				OnPaint(memdc, &rect, m_uEdge);
+				EndPaint(hwnd, &ps);
+			}
 		}
 		break;
 	default:
@@ -82,12 +129,84 @@
 	return 0;
 };
 
+void CStatusBarMsgWnd::OnPaint(HDC hDC, LPRECT pRect, UINT uEdge)
+{
+	// erase the background
+	SetBkColor(hDC, ::GetSysColor(COLOR_WINDOW));
+	::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, pRect, NULL, 0, NULL);
+
+	// draw a border
+	DrawEdge(hDC, pRect, EDGE_BUMP, BF_ADJUST | BF_RECT | BF_SOFT);
+
+	// draw the icon on the left
+	DrawIconEx(hDC, pRect->left + 2, pRect->top + 2, m_icon, 
+		STATUSBARMSGWND_ICONSIZE, STATUSBARMSGWND_ICONSIZE, 0, NULL, DI_NORMAL);
+
+	// draw the title
+	HFONT hFont = CreateFont(-MulDiv(10, GetDeviceCaps(hDC, LOGPIXELSY), 72), 0, 0, 0, 
+		FW_BOLD, false, false, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, 
+		CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, _T("MS Shell Dlg"));
+	HFONT hFontOld = (HFONT)SelectObject(hDC, (HGDIOBJ)hFont);
+	SetTextColor(hDC, ::GetSysColor(COLOR_WINDOWTEXT));
+	RECT titlerect = *pRect;
+	titlerect.left += (STATUSBARMSGWND_ICONSIZE + 5);
+	titlerect.top += 2;
+	titlerect.right -= 5;
+	TCHAR * textbuf = new TCHAR[m_title.size()+1];
+	_tcscpy_s(textbuf, m_title.size()+1, m_title.c_str());
+	DrawTextEx(hDC, textbuf, m_title.length(), &titlerect, DT_CALCRECT|DT_CENTER|DT_WORD_ELLIPSIS, NULL);
+	titlerect.right = pRect->right-5;
+	DrawTextEx(hDC, textbuf, m_title.length(), &titlerect, DT_CENTER|DT_WORD_ELLIPSIS, NULL);
+	delete [] textbuf;
+	SelectObject(hDC, hFontOld);
+	DeleteObject(hFont);
+
+	// draw a separator line
+	HPEN hPen = CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
+	HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
+	MoveToEx(hDC, titlerect.left, titlerect.bottom+4, NULL);
+	LineTo(hDC, titlerect.right, titlerect.bottom+4);
+	::SelectObject(hDC, hOldPen);
+	DeleteObject(hPen);
+	hPen = CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DHIGHLIGHT));
+	hOldPen = (HPEN)::SelectObject(hDC, hPen);
+	MoveToEx(hDC, titlerect.left, titlerect.bottom+5, NULL);
+	LineTo(hDC, titlerect.right, titlerect.bottom+5);
+	::SelectObject(hDC, hOldPen);
+	DeleteObject(hPen);
+
+	// draw the status text
+	hFont = CreateFont(-MulDiv(8, GetDeviceCaps(hDC, LOGPIXELSY), 72), 0, 0, 0, 
+		FW_NORMAL, false, false, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, 
+		CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, _T("MS Shell Dlg"));
+	hFontOld = (HFONT)SelectObject(hDC, (HGDIOBJ)hFont);
+	SetTextColor(hDC, ::GetSysColor(COLOR_GRAYTEXT));
+	RECT statusrect = *pRect;
+	statusrect.left += (STATUSBARMSGWND_ICONSIZE + 5);
+	statusrect.top = (titlerect.bottom + 8);
+	textbuf = new TCHAR[m_text.size()+1];
+	_tcscpy_s(textbuf, m_text.size()+1, m_text.c_str());
+	//DrawTextEx(hDC, textbuf, m_text.length(), &statusrect, DT_CALCRECT|DT_CENTER|DT_WORD_ELLIPSIS, NULL);
+	DrawTextEx(hDC, textbuf, m_text.length(), &statusrect, DT_CENTER|DT_WORD_ELLIPSIS, NULL);
+	delete [] textbuf;
+	SelectObject(hDC, hFontOld);
+	DeleteObject(hFont);
+}
+
 LRESULT CStatusBarMsgWnd::DoTimer()
 {
-	if (m_ShowTicks >= ((m_stay+2)*m_height))
+	bool finished = false;
+	if (((m_uEdge == ABE_TOP)||(m_uEdge == ABE_BOTTOM)) &&
+		(m_ShowTicks >= ((m_stay+2)*m_height)))
+		finished = true;
+	if (((m_uEdge == ABE_LEFT)||(m_uEdge == ABE_RIGHT)) &&
+		(m_ShowTicks >= ((m_stay+2)*m_width)))
+		finished = true;
+	if (finished)
 	{
 		::KillTimer(*this, STATUSBARMSGWND_SHOWTIMER);
 		DestroyWindow(*this);
+		m_slots[m_thiscounter] = 0;
 		m_counter--;
 		assert(m_counter >= 0);
 		delete this;
@@ -131,10 +250,10 @@
 		// expanding to the right
 		xPos += m_ShowTicks;
 	}
-	xPos += ((m_thiscounter-1)*m_width);
+	xPos += ((m_thiscounter)*m_width);
 
 	RECT popupRect;
-	popupRect.left = m_workarea.left + ((m_thiscounter-1)*m_width);
+	popupRect.left = m_workarea.left + ((m_thiscounter)*m_width);
 	popupRect.right = xPos;
 	popupRect.top = m_workarea.top;
 	popupRect.bottom = m_workarea.top + m_height;
@@ -162,12 +281,12 @@
 		// expanding down
 		yPos += m_ShowTicks;
 	}
-	yPos += ((m_thiscounter-1)*m_height);
+	yPos += ((m_thiscounter)*m_height);
 
 	RECT popupRect;
 	popupRect.left = m_workarea.right - m_width;
 	popupRect.right = m_workarea.right;
-	popupRect.top = m_workarea.top + ((m_thiscounter-1)*m_height);
+	popupRect.top = m_workarea.top + ((m_thiscounter)*m_height);
 	popupRect.bottom = yPos;
 	::SetWindowPos(*this, HWND_TOPMOST,
 		popupRect.left, popupRect.top, popupRect.right-popupRect.left, popupRect.bottom-popupRect.top,
@@ -193,11 +312,11 @@
 		// expanding to the left
 		xPos -= m_ShowTicks;
 	}
-	xPos -= ((m_thiscounter-1)*m_width);
+	xPos -= ((m_thiscounter)*m_width);
 
 	RECT popupRect;
 	popupRect.left = xPos;
-	popupRect.right = m_workarea.right - ((m_thiscounter-1)*m_width);
+	popupRect.right = m_workarea.right - ((m_thiscounter)*m_width);
 	popupRect.top = m_workarea.top;
 	popupRect.bottom = m_workarea.top + m_height;
 	::SetWindowPos(*this, HWND_TOPMOST,
@@ -224,13 +343,13 @@
 		// rising
 		yPos -= m_ShowTicks;
 	}
-	yPos -= ((m_thiscounter-1)*m_height);
+	yPos -= ((m_thiscounter)*m_height);
 
 	RECT popupRect;
 	popupRect.left = m_workarea.right - m_width;
 	popupRect.right = m_workarea.right;
 	popupRect.top = yPos;
-	popupRect.bottom = m_workarea.bottom - ((m_thiscounter-1)*m_height);
+	popupRect.bottom = m_workarea.bottom - ((m_thiscounter)*m_height);
 	::SetWindowPos(*this, HWND_TOPMOST,
 		popupRect.left, popupRect.top, popupRect.right-popupRect.left, popupRect.bottom-popupRect.top,
 		SWP_NOACTIVATE|SWP_SHOWWINDOW);
/trunk/src/StatusBarMsgWnd.h Diff Switch to side-by-side view
--- a/trunk/src/StatusBarMsgWnd.h
+++ b/trunk/src/StatusBarMsgWnd.h
@@ -1,30 +1,33 @@
 #pragma once
 #include "BaseWindow.h"
 #include <string>
+#include <vector>
 
 using namespace std;
 
 #define STATUSBARMSGWND_SHOWTIMER		101
-
+#define STATUSBARMSGWND_ICONSIZE		32
 class CStatusBarMsgWnd : public CWindow
 {
 public:
 	CStatusBarMsgWnd(HINSTANCE hInst, const WNDCLASSEX* wcx = NULL) 
 		: CWindow(hInst, wcx) 
-		, m_width(150)
-		, m_height(50)
+		, m_width(200)
+		, m_height(80)
+		, m_icon(NULL)
 	{
 		RegisterAndCreateWindow();
 	}
 
-	void				Show(LPCTSTR title, LPCTSTR text, HWND hParentWnd, UINT messageOnClick, int stay = 10);
+	void				Show(LPCTSTR title, LPCTSTR text, UINT icon, HWND hParentWnd, UINT messageOnClick, int stay = 10);
 private:
 	// deconstructor private to prevent creating an instance on the stack
 	// --> must be created on the heap!
-	~CStatusBarMsgWnd(void) {}
+	~CStatusBarMsgWnd(void);
 
 
 protected:
+	virtual void		OnPaint(HDC hDC, LPRECT pRect, UINT uEdge);
 	/**
 	 * Registers the window class and creates the window.
 	 */
@@ -41,6 +44,7 @@
 private:
 	wstring				m_title;
 	wstring				m_text;
+	HICON				m_icon;
 	UINT				m_messageOnClick;
 	HWND				m_hParentWnd;
 
@@ -54,5 +58,6 @@
 
 	int					m_thiscounter;
 	static int			m_counter;
+	static vector<int>	m_slots;
 };
 
/trunk/src/memdc.h Diff Switch to side-by-side view
--- a
+++ b/trunk/src/memdc.h
@@ -0,0 +1,181 @@
+#pragma once
+
+//////////////////////////////////////////////////
+// CMemDC - memory DC
+//
+// Author: Keith Rule
+// Email:  keithr@europa.com
+// Copyright 1996-1997, Keith Rule
+//
+// You may freely use or modify this code provided this
+// Copyright is included in all derived versions.
+//
+// History - 10/3/97 Fixed scrolling bug.
+//                   Added print support.
+//           25 feb 98 - fixed minor assertion bug
+//
+// This class implements a memory Device Context
+
+#ifdef _MFC_VER
+class CMemDC : public CDC
+{
+public:
+	// constructor sets up the memory DC
+	CMemDC(CDC* pDC, bool bTempOnly = false, int nOffset = 0) : CDC()
+    {
+		ASSERT(pDC != NULL);
+		
+		m_pDC = pDC;
+		m_pOldBitmap = NULL;
+        m_bMemDC = ((!pDC->IsPrinting()) && (!GetSystemMetrics(SM_REMOTESESSION)));
+		m_bTempOnly = bTempOnly;
+		
+        if (m_bMemDC)	// Create a Memory DC
+		{
+            pDC->GetClipBox(&m_rect);
+            CreateCompatibleDC(pDC);
+            m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width() - nOffset, m_rect.Height());
+			m_pOldBitmap = SelectObject(&m_bitmap);
+            SetWindowOrg(m_rect.left, m_rect.top);
+        }
+		else		// Make a copy of the relevant parts of the current DC for printing
+		{
+            m_bPrinting = pDC->m_bPrinting;
+            m_hDC		= pDC->m_hDC;
+            m_hAttribDC = pDC->m_hAttribDC;
+        }
+
+		FillSolidRect(m_rect, pDC->GetBkColor());
+	}
+	
+	CMemDC(CDC* pDC, const CRect* pRect) : CDC()
+	{
+		ASSERT(pDC != NULL); 
+
+		// Some initialization
+		m_pDC = pDC;
+		m_pOldBitmap = NULL;
+		m_bMemDC = !pDC->IsPrinting();
+		m_bTempOnly = false;
+
+		// Get the rectangle to draw
+		if (pRect == NULL) {
+			pDC->GetClipBox(&m_rect);
+		} else {
+			m_rect = *pRect;
+		}
+
+		if (m_bMemDC) {
+			// Create a Memory DC
+			CreateCompatibleDC(pDC);
+			pDC->LPtoDP(&m_rect);
+
+			m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
+			m_pOldBitmap = SelectObject(&m_bitmap);
+
+			SetMapMode(pDC->GetMapMode());
+
+			SetWindowExt(pDC->GetWindowExt());
+			SetViewportExt(pDC->GetViewportExt());
+
+			pDC->DPtoLP(&m_rect);
+			SetWindowOrg(m_rect.left, m_rect.top);
+		} else {
+			// Make a copy of the relevant parts of the current DC for printing
+			m_bPrinting = pDC->m_bPrinting;
+			m_hDC       = pDC->m_hDC;
+			m_hAttribDC = pDC->m_hAttribDC;
+		}
+
+		// Fill background 
+		FillSolidRect(m_rect, pDC->GetBkColor());
+	}
+	
+	// Destructor copies the contents of the mem DC to the original DC
+	~CMemDC()
+    {
+		if (m_bMemDC) {	
+			// Copy the off screen bitmap onto the screen.
+			if (!m_bTempOnly)
+				m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
+								this, m_rect.left, m_rect.top, SRCCOPY);
+			
+            //Swap back the original bitmap.
+            SelectObject(m_pOldBitmap);
+		} else {
+			// All we need to do is replace the DC with an illegal value,
+			// this keeps us from accidentally deleting the handles associated with
+			// the CDC that was passed to the constructor.
+            m_hDC = m_hAttribDC = NULL;
+		}
+	}
+	
+	// Allow usage as a pointer
+    CMemDC* operator->() {return this;}
+	
+    // Allow usage as a pointer
+    operator CMemDC*() {return this;}
+
+private:
+	CBitmap  m_bitmap;		// Off screen bitmap
+    CBitmap* m_pOldBitmap;	// bitmap originally found in CMemDC
+    CDC*     m_pDC;			// Saves CDC passed in constructor
+    CRect    m_rect;		// Rectangle of drawing area.
+    BOOL     m_bMemDC;		// TRUE if CDC really is a Memory DC.
+	BOOL	 m_bTempOnly;	// Whether to copy the contents on the real DC on destroy
+};
+#else
+class CMemDC
+{
+public:
+
+	// constructor sets up the memory DC
+	CMemDC(HDC hDC, bool bTempOnly = false, int nOffset = 0) 
+	{	
+		UNREFERENCED_PARAMETER(nOffset);
+		m_hDC = hDC;
+		m_hOldBitmap = NULL;
+		m_bTempOnly = bTempOnly;
+
+		GetClipBox(m_hDC, &m_rect);
+		m_hMemDC = ::CreateCompatibleDC(m_hDC);
+		m_hBitmap = CreateCompatibleBitmap(m_hDC, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top);
+		m_hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hBitmap);
+		SetWindowOrgEx(m_hMemDC, m_rect.left, m_rect.top, NULL);
+	}
+
+	// Destructor copies the contents of the mem DC to the original DC
+	~CMemDC()
+	{
+		if (m_hMemDC) {	
+			// Copy the off screen bitmap onto the screen.
+			if (!m_bTempOnly)
+				BitBlt(m_hDC, m_rect.left, m_rect.top, m_rect.right-m_rect.left, m_rect.bottom-m_rect.top, m_hMemDC, m_rect.left, m_rect.top, SRCCOPY);
+
+			//Swap back the original bitmap.
+			SelectObject(m_hMemDC, m_hOldBitmap);
+			DeleteObject(m_hBitmap);
+			DeleteDC(m_hMemDC);
+		} else {
+			// All we need to do is replace the DC with an illegal value,
+			// this keeps us from accidentally deleting the handles associated with
+			// the CDC that was passed to the constructor.
+			DeleteObject(m_hBitmap);
+			DeleteDC(m_hMemDC);
+			m_hMemDC = NULL;
+		}
+	}
+
+	// Allow usage as a pointer
+	operator HDC() {return m_hMemDC;}
+private:
+	HBITMAP  m_hBitmap;		// Off screen bitmap
+	HBITMAP	 m_hOldBitmap;	// bitmap originally found in CMemDC
+	HDC      m_hDC;			// Saves CDC passed in constructor
+	HDC		 m_hMemDC;		// our own memory DC
+	RECT	 m_rect;		// Rectangle of drawing area.
+	bool	 m_bTempOnly;	// Whether to copy the contents on the real DC on destroy
+};
+
+#endif
+
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.