Files
ls-2019-source/extra/LS_Service/LS_launcher/Batch/TextProgressCtrl.cpp
T
2026-11-07 13:30:45 +07:00

616 lines
17 KiB
C++

// TextProgressCtrl.cpp : implementation file
//
// Written by Chris Maunder ([email protected])
// Copyright 1998-2005.
//
// TextProgressCtrl is a drop-in replacement for the standard
// CProgressCtrl that displays text in a progress control.
//
// Homepage: http://www.codeproject.com/miscctrl/text_progressctrl.asp
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is not sold for
// profit without the author's written consent, and providing that this
// notice and the author's name is included. If the source code in
// this file is used in any commercial application then an email to
// me would be nice.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to your
// computer or anything else vaguely within its vicinity.
//
// Expect bugs.
//
// Please use and enjoy. Please let me know of any bugs/mods/improvements
// that you have found/implemented and I will fix/incorporate them into this
// file.
////////////////////////////////////////////////////////////////////////////////
// Revision History - by PJ Arends ([email protected])
// July 1, 2001 - added functionality to set font to parent windows font
// July 15, 2001 - added SetTextColor() and GetTextColor() functions
// August 2, 2001 - Added functionality where the control now responds to
// PBM_* progress bar messages. Now the control can be
// controlled by sending messages to its HWND.
// - added PBM_SETTEXTCOLOR and PBM_SETSHOWTEXT messages
// - added the ability to call GetPos() via OnGetPos()
// January 3, 2005 - By Kriz: Added two basic methods some other changes to
// allow the user to switch between the three alignment
// styles LEFT, CENTER and RIGHT - even on the fly if that's
// needed. Methods: AlignText and AlignTextInvalidate
// - By C Maunder: updated the code so it compiles in VC7
// March 6, 2006 - By A. Bommarito: changed to allow text in vertical
// progress bars; added method to change text background
// color; added capability to independently control display
// of text and percentage complete; added marquee mode;
// changed to exclusively use messaging interface
// February 22, 2007 - By A. Bommarito: changed to fix problem where progress bar
// border didn't display on XP and above when a manifest file
// specified use of Version 6 of the Common Controls; fixed
// problem with AppendFormat method being used without an
// _T() around the format string - caused compile error when
// using Unicode (message from dev75040); added complete turn
// off of Marquee style (message from Robert Pickford)
//
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TextProgressCtrl.h"
//#include "CUserMemDC.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////////////////////////////////////////
// CTextProgressCtrl
#define IDT_MARQUEE 1 // timer used to update marquee style progress bar
#define EDGE_SPACE 2 // number of pixels to space text away from edge of progress bar
CTextProgressCtrl::CTextProgressCtrl()
{
// default range
m_nMin = 0;
m_nMax = 100;
// default step size
m_nStepSize = 10;
// initial starting position
m_nPos = 0;
// default colors
m_crBarClr = CLR_DEFAULT;
m_crBarBkClr = CLR_DEFAULT;
m_crTextClr = CLR_DEFAULT;
m_crTextBkClr = CLR_DEFAULT;
// default to show percent complete, all text centered
m_bShowPercent = TRUE;
m_dwTextStyle = DT_CENTER;
// default marquee bar size of 20% of full progress bar
m_nMarqueeSize = 20;
}
CTextProgressCtrl::~CTextProgressCtrl()
{
// delete vertical font if needed
if (m_VerticalFont.m_hObject)
m_VerticalFont.DeleteObject();
}
BEGIN_MESSAGE_MAP(CTextProgressCtrl, CProgressCtrl)
//{{AFX_MSG_MAP(CTextProgressCtrl)
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
ON_MESSAGE(PBM_SETRANGE, OnSetRange)
ON_MESSAGE(PBM_SETPOS, OnSetPos)
ON_MESSAGE(PBM_DELTAPOS, OnOffsetPos)
ON_MESSAGE(PBM_SETSTEP, OnSetStep)
ON_MESSAGE(PBM_STEPIT, OnStepIt)
ON_MESSAGE(PBM_SETRANGE32, OnSetRange32)
ON_MESSAGE(PBM_GETRANGE, OnGetRange)
ON_MESSAGE(PBM_GETPOS, OnGetPos)
ON_MESSAGE(PBM_SETBARCOLOR, OnSetBarColor)
ON_MESSAGE(PBM_SETBKCOLOR, OnSetBarBkColor)
ON_MESSAGE(PBM_USERGETBARCOLOR, OnGetBarColor)
ON_MESSAGE(PBM_USERGETBKCOLOR, OnGetBarBkColor)
ON_MESSAGE(PBM_SETTEXTCOLOR, OnSetTextColor)
ON_MESSAGE(PBM_GETTEXTCOLOR, OnGetTextColor)
ON_MESSAGE(PBM_SETTEXTBKCOLOR, OnSetTextBkColor)
ON_MESSAGE(PBM_GETTEXTBKCOLOR, OnGetTextBkColor)
ON_MESSAGE(PBM_SETSHOWPERCENT, OnSetShowPercent)
ON_MESSAGE(PBM_ALIGNTEXT, OnAlignText)
ON_MESSAGE(PBM_SETMARQUEE, OnSetMarquee)
ON_MESSAGE(PBM_SETMARQUEEOPTIONS, OnSetMarqueeOptions)
END_MESSAGE_MAP()
////////////////////////////////////////////////////////////////////////////////
// CTextProgressCtrl message handlers
BOOL CTextProgressCtrl::OnEraseBkgnd(CDC* /*pDC*/)
{
return TRUE;
}
void CTextProgressCtrl::OnPaint()
{
if (m_nMin >= m_nMax)
return;
CPaintDC PaintDC(this); // device context for painting
CUserMemDC dc(&PaintDC); // memory device context
// get colors to use
COLORREF crBarColor = (COLORREF)OnGetBarColor(0, 0);
COLORREF crBarBkColor = (COLORREF)OnGetBarBkColor(0, 0);
COLORREF crTextColor = (COLORREF)OnGetTextColor(0, 0);
COLORREF crTextBkColor = (COLORREF)OnGetTextBkColor(0, 0);;
// select progress bar font if there is one, else select parent font
if (GetFont())
dc.SelectObject(GetFont());
else
dc.SelectObject(GetParent()->GetFont());
// get bar dimensions and draw bar outline
BOOL bLeft = true, bMiddle = true, bRight = true;
CRect LeftRect, MiddleRect, RightRect, ClientRect;
GetClientRect(&ClientRect);
DrawEdge(dc, ClientRect, EDGE_SUNKEN, BF_ADJUST | BF_RECT | BF_FLAT);
LeftRect = MiddleRect = RightRect = ClientRect;
// compute the fractional position
double dFraction = (double)(m_nPos - m_nMin) / ((double)(m_nMax - m_nMin));
// get the control style
DWORD dwStyle = GetStyle();
// create a vertical font if needed
if ((dwStyle & PBS_VERTICAL) && (!m_VerticalFont.m_hObject))
CreateVerticalFont();
if (dwStyle & PBS_MARQUEE)
{
if (dwStyle & PBS_VERTICAL)
{
MiddleRect.top = MiddleRect.bottom - (int)((MiddleRect.Height()) * dFraction);
MiddleRect.bottom = MiddleRect.top + (((LeftRect.Height() * m_nMarqueeSize) + 50) / 100);
if (MiddleRect.bottom >= LeftRect.bottom)
{
bLeft = false;
MiddleRect.bottom = LeftRect.bottom;
}
else
LeftRect.top = MiddleRect.bottom;
if (MiddleRect.top <= RightRect.top)
{
bRight = false;
MiddleRect.top = RightRect.top;
}
else
RightRect.bottom = MiddleRect.top;
}
else
{
MiddleRect.right = MiddleRect.left + (int)((MiddleRect.Width()) * dFraction);
MiddleRect.left = MiddleRect.right - (((LeftRect.Width() * m_nMarqueeSize) + 50) / 100);
if (MiddleRect.left <= LeftRect.left)
{
bLeft = false;
MiddleRect.left = LeftRect.left;
}
else
LeftRect.right = MiddleRect.left;
if (MiddleRect.right >= RightRect.right)
{
bRight = false;
MiddleRect.right = RightRect.right;
}
else
RightRect.left = MiddleRect.right;
}
}
else
{
bLeft = false;
if (dwStyle & PBS_VERTICAL)
{
MiddleRect.top = MiddleRect.bottom - (int)((MiddleRect.Height()) * dFraction);
RightRect.bottom = MiddleRect.top;
}
else
{
MiddleRect.right = MiddleRect.left + (int)((MiddleRect.Width()) * dFraction);
RightRect.left = MiddleRect.right;
}
}
if (bLeft)
dc.FillSolidRect(LeftRect, crBarBkColor);
if (bMiddle)
dc.FillSolidRect(MiddleRect, crBarColor);
if (bRight)
dc.FillSolidRect(RightRect, crBarBkColor);
// draw text if needed
CString str;
GetWindowText(str);
if (m_bShowPercent)
str.AppendFormat(_T("%d%%"), (int)((dFraction * 100.0) + 0.5));
if (str.GetLength())
{
CFont *pOldFont = NULL;
CPoint ptStart;
CSize szText;
if (dwStyle & PBS_VERTICAL)
{
pOldFont = (CFont*)dc.SelectObject(&m_VerticalFont);
szText = dc.GetOutputTextExtent(str);
switch (m_dwTextStyle)
{
case DT_LEFT:
ptStart.y = ClientRect.bottom - 1 - EDGE_SPACE;
break;
case DT_RIGHT:
ptStart.y = ClientRect.top + szText.cx + EDGE_SPACE;
break;
case DT_CENTER:
default:
ptStart.y = ClientRect.top + szText.cx + (ClientRect.Height() - szText.cx) / 2;
break;
}
ptStart.x = ClientRect.left + ((ClientRect.Width() - szText.cy) / 2);
}
else
{
szText = dc.GetOutputTextExtent(str);
switch (m_dwTextStyle)
{
case DT_LEFT:
ptStart.x = ClientRect.left + EDGE_SPACE;
break;
case DT_RIGHT:
ptStart.x = ClientRect.right - szText.cx - 1 - EDGE_SPACE;
break;
case DT_CENTER:
default:
ptStart.x = ClientRect.left + ((ClientRect.Width() - szText.cx) / 2);
break;
}
ptStart.y = ClientRect.top + ((ClientRect.Height() - szText.cy) / 2);
}
dc.SetBkMode(TRANSPARENT);
CRgn rgn;
if (bLeft)
{
rgn.CreateRectRgn(LeftRect.left, LeftRect.top, LeftRect.right, LeftRect.bottom);
dc.SelectClipRgn(&rgn);
dc.SetTextColor(crTextColor);
dc.ExtTextOut(ptStart.x, ptStart.y, ETO_CLIPPED, &ClientRect, str, NULL);
rgn.DeleteObject();
}
if (bMiddle)
{
rgn.CreateRectRgn(MiddleRect.left, MiddleRect.top, MiddleRect.right, MiddleRect.bottom);
dc.SelectClipRgn(&rgn);
dc.SetTextColor(crTextBkColor);
dc.ExtTextOut(ptStart.x, ptStart.y, ETO_CLIPPED, &ClientRect, str, NULL);
rgn.DeleteObject();
}
if (bRight)
{
rgn.CreateRectRgn(RightRect.left, RightRect.top, RightRect.right, RightRect.bottom);
dc.SelectClipRgn(&rgn);
dc.SetTextColor(crTextColor);
dc.ExtTextOut(ptStart.x, ptStart.y, ETO_CLIPPED, &ClientRect, str, NULL);
rgn.DeleteObject();
}
if (pOldFont)
dc.SelectObject(pOldFont);
}
}
void CTextProgressCtrl::OnTimer(UINT_PTR nIDEvent)
{
static int nDirection = +1;
if (nIDEvent == IDT_MARQUEE)
{
int nPosition = GetPos();
int nMax = (int)((((double)(100 + m_nMarqueeSize) * (double)m_nMax) + 0.5) / 100.0);
if ((nDirection == 1) && (nPosition >= nMax))
nDirection = -1;
else if ((nDirection == -1) && (nPosition <= m_nMin))
nDirection = +1;
SetPos(nPosition + nDirection);
}
}
LRESULT CTextProgressCtrl::OnSetRange(WPARAM, LPARAM lparamRange)
{
// set new 16-bit range, returning old one
return (OnSetRange32(LOWORD(lparamRange), HIWORD(lparamRange)));
}
LRESULT CTextProgressCtrl::OnSetPos(WPARAM nNewPos, LPARAM)
{
// save old position for return
int nOldPos = m_nPos;
// set new position
m_nPos = (int)nNewPos;
// limit position to inside of range
DWORD dwStyle = GetStyle();
if (m_nPos < m_nMin)
m_nPos = m_nMin;
if (dwStyle & PBS_MARQUEE)
{
int nMax = (int)((((double)(100 + m_nMarqueeSize) * (double)m_nMax) + 0.5) / 100.0);
if (m_nPos > nMax)
m_nPos = nMax;
}
else if (m_nPos > m_nMax)
m_nPos = m_nMax;
// call a common routine to redraw window
CommonPaint();
// return old position
return ((LRESULT)nOldPos);
}
LRESULT CTextProgressCtrl::OnOffsetPos(WPARAM nIncrement, LPARAM)
{
// set new position, returning old one
return (OnSetPos((WPARAM)(m_nPos + (int)nIncrement), 0));
}
LRESULT CTextProgressCtrl::OnSetStep(WPARAM nStepInc, LPARAM)
{
// save old step size for return
int nOldStep = m_nStepSize;
// set new step size
m_nStepSize = (int)nStepInc;
// return old step size
return ((LRESULT)nOldStep);
}
LRESULT CTextProgressCtrl::OnStepIt(WPARAM, LPARAM)
{
// compute new position, wrapping if needed
int nPos = m_nPos + m_nStepSize;
if (nPos < m_nMin)
nPos = m_nMax - abs(m_nMin - nPos);
else if (nPos > m_nMax)
nPos = m_nMin + abs(nPos - m_nMax);
// set new position, returning old one
return ((LRESULT)OnSetPos((WPARAM)nPos, 0));
}
LRESULT CTextProgressCtrl::OnSetRange32(WPARAM nLowLim, LPARAM nHighLim)
{
// save old range for return
int nOldMin = m_nMin;
int nOldMax = m_nMax;
// set new range
m_nMin = (int)nLowLim;
m_nMax = (int)nHighLim;
// return old range (16 bit only)
return (MAKELRESULT(LOWORD(nOldMin), LOWORD(nOldMax)));
}
LRESULT CTextProgressCtrl::OnGetRange(WPARAM bWhichLimit, LPARAM pPBRange)
{
// get arguments into proper types
BOOL bType = (BOOL)bWhichLimit;
PPBRANGE pRange = (PPBRANGE)pPBRange;
// return both range limits if a pointer was provided
if (pRange)
{
pRange->iLow = m_nMin;
pRange->iHigh = m_nMax;
}
// return selected range limit
return ((LRESULT)(bType ? m_nMin : m_nMax));
}
LRESULT CTextProgressCtrl::OnGetPos(WPARAM, LPARAM)
{
// return current position
return ((LRESULT)m_nPos);
}
LRESULT CTextProgressCtrl::OnSetBarColor(WPARAM, LPARAM crBar)
{
// call a common routine to redraw window
CommonPaint();
// set new bar color, returning old one
COLORREF crOldBarClr = m_crBarClr;
m_crBarClr = (COLORREF)crBar;
return ((LRESULT)crOldBarClr);
}
LRESULT CTextProgressCtrl::OnSetBarBkColor(WPARAM, LPARAM crBarBk)
{
// call a common routine to redraw window
CommonPaint();
// set new bar background color, returning old one
COLORREF crOldBarBkClr = m_crBarBkClr;
m_crBarBkClr = (COLORREF)crBarBk;
return ((LRESULT)crOldBarBkClr);
}
LRESULT CTextProgressCtrl::OnGetBarColor(WPARAM, LPARAM)
{
// return current bar color
return ((LRESULT)((m_crBarClr == CLR_DEFAULT)? ::GetSysColor(COLOR_HIGHLIGHT) : m_crBarClr));
}
LRESULT CTextProgressCtrl::OnGetBarBkColor(WPARAM, LPARAM)
{
// return current bar background color
return ((LRESULT)((m_crBarBkClr == CLR_DEFAULT)? ::GetSysColor(COLOR_BTNFACE) : m_crBarBkClr));
}
LRESULT CTextProgressCtrl::OnSetTextColor(WPARAM, LPARAM crText)
{
// call a common routine to redraw window
CommonPaint();
// set new text color, returning old one
COLORREF crOldTextClr = m_crTextClr;
m_crTextClr = (COLORREF)crText;
return ((LRESULT)crOldTextClr);
}
LRESULT CTextProgressCtrl::OnGetTextColor(WPARAM, LPARAM)
{
// return current text color
return ((LRESULT)((m_crTextClr == CLR_DEFAULT ? ::GetSysColor(COLOR_WINDOWTEXT) : m_crTextClr)));
}
LRESULT CTextProgressCtrl::OnSetTextBkColor(WPARAM, LPARAM crTextBkClr)
{
// call a common routine to redraw window
CommonPaint();
// set new text background color, returning old one
COLORREF crOldTextBkClr = m_crTextBkClr;
m_crTextBkClr = (COLORREF)crTextBkClr;
return ((LRESULT)crOldTextBkClr);
}
LRESULT CTextProgressCtrl::OnGetTextBkColor(WPARAM, LPARAM)
{
// return current text background color
return ((LRESULT)((m_crTextBkClr == CLR_DEFAULT ? ::GetSysColor(COLOR_WINDOW) : m_crTextBkClr)));
}
LRESULT CTextProgressCtrl::OnSetShowPercent(WPARAM bShow, LPARAM)
{
// call a common routine to redraw window
CommonPaint();
// set new percent completed display state, returning old one
BOOL bOldShow = m_bShowPercent;
m_bShowPercent = (BOOL)bShow;
return ((LRESULT)bOldShow);
}
LRESULT CTextProgressCtrl::OnAlignText(WPARAM dwAlignment, LPARAM)
{
// get argument into proper type
DWORD dwAlign = (DWORD)dwAlignment;
// check input
ASSERT((dwAlign == DT_LEFT) || (dwAlign == DT_RIGHT) || (dwAlign == DT_CENTER));
// call a common routine to redraw window
CommonPaint();
// set new text alignment mode, returning old one
DWORD dwOldTextStyle = m_dwTextStyle;
m_dwTextStyle = dwAlign;
return ((LRESULT)dwOldTextStyle);
}
LRESULT CTextProgressCtrl::OnSetMarquee(WPARAM bShow, LPARAM uMsecBetweenUpdate)
{
// call a common routine to redraw window
CommonPaint();
// can't have percent complete for this style
m_bShowPercent = false;
// turn marquee mode on or off
if ((BOOL)bShow)
{
ModifyStyle(0, PBS_MARQUEE);
SetTimer(IDT_MARQUEE, (UINT)uMsecBetweenUpdate, NULL);
}
else
{
KillTimer(IDT_MARQUEE);
ModifyStyle(PBS_MARQUEE, 0);
}
// return current marquee mode
return ((LRESULT)bShow);
}
LRESULT CTextProgressCtrl::OnSetMarqueeOptions(WPARAM nBarSize, LPARAM)
{
// get argument into proper type
int nBar = (int)nBarSize;
// call a common routine to redraw window
CommonPaint();
// set new marquee bar size
m_nMarqueeSize = nBar;
// return bar size (have to return something from a message)
return ((LRESULT)nBar);
}
////////////////////////////////////////////////////////////////////////////////
// CTextProgressCtrl helper functions
void CTextProgressCtrl::CreateVerticalFont()
{
// delete old font if it exists
if (m_VerticalFont.m_hObject)
m_VerticalFont.DeleteObject();
// create a new vertical font based on the current font
LOGFONT lf;
GetFont()->GetLogFont(&lf);
lf.lfEscapement = lf.lfOrientation = 900;
m_VerticalFont.CreateFontIndirect(&lf);
}
void CTextProgressCtrl::CommonPaint()
{
//
// common place to mess with redraw options
//
// note that Invalidate() by itself won't cause
// a repaint when this control is used in a modeless
// dialog box
//
// also note that the marquee timer won't work in a modeless
// dialog - to use marquee mode in a modeless dialog the code
// that is running will have to pump Windows messages
//
RedrawWindow();
}