This commit is contained in:
romkazvo
2023-08-07 19:29:24 +08:00
commit 34d6c5d489
4832 changed files with 1389451 additions and 0 deletions

View File

@@ -0,0 +1,661 @@
// NumberCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "NumberCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CNumberCtrl
CNumberCtrl::CNumberCtrl()
{
m_btnStatus = 0;
m_btnWidth = 10;
m_draggin = false;
m_value = 0;
m_min = 0;
m_max = 10000;
m_step = 0.01f;
m_enabled = true;
m_noNotify = false;
m_integer = false;
m_iInternalPrecision=2; // default internal precision for floats
m_nFlags = 0;
m_bUndoEnabled = false;
m_bDragged = false;
m_multiplier = 1;
}
CNumberCtrl::~CNumberCtrl()
{
}
BEGIN_MESSAGE_MAP(CNumberCtrl, CWnd)
//{{AFX_MSG_MAP(CNumberCtrl)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_ENABLE()
ON_WM_SETFOCUS()
ON_EN_SETFOCUS(IDC_EDIT,OnEditSetFocus)
ON_EN_KILLFOCUS(IDC_EDIT,OnEditKillFocus)
//}}AFX_MSG_MAP
ON_WM_SIZE()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNumberCtrl message handlers
void CNumberCtrl::Create( CWnd* parentWnd,CRect &rc,UINT nID,int nFlags )
{
m_nFlags = nFlags;
HCURSOR arrowCursor = AfxGetApp()->LoadStandardCursor( IDC_ARROW );
CreateEx( 0,AfxRegisterWndClass(NULL,arrowCursor,NULL/*(HBRUSH)GetStockObject(LTGRAY_BRUSH)*/),NULL,WS_CHILD|WS_VISIBLE|WS_TABSTOP,rc,parentWnd,nID );
}
void CNumberCtrl::Create( CWnd* parentWnd,UINT ctrlID,int flags )
{
ASSERT( parentWnd );
m_nFlags = flags;
CRect rc;
CWnd *ctrl = parentWnd->GetDlgItem( ctrlID );
ctrl->SetDlgCtrlID( ctrlID + 10000 );
ctrl->ShowWindow( SW_HIDE );
ctrl->GetWindowRect( rc );
parentWnd->ScreenToClient(rc);
HCURSOR arrowCursor = AfxGetApp()->LoadStandardCursor( IDC_ARROW );
CreateEx( 0,AfxRegisterWndClass(NULL,arrowCursor,NULL/*(HBRUSH)GetStockObject(LTGRAY_BRUSH)*/),NULL,WS_CHILD|WS_VISIBLE|WS_TABSTOP,rc,parentWnd,ctrlID );
}
int CNumberCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_upDownCursor = AfxGetApp()->LoadStandardCursor( IDC_SIZENS );
m_upArrow = (HICON)LoadImage( AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_UP_ARROW),IMAGE_ICON,5,5,LR_DEFAULTCOLOR );
m_downArrow = (HICON)LoadImage( AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_DOWN_ARROW),IMAGE_ICON,5,5,LR_DEFAULTCOLOR );
CRect rc;
GetClientRect( rc );
if (m_nFlags & LEFTARROW)
{
rc.left += m_btnWidth+3;
}
else
{
rc.right -= m_btnWidth+1;
}
DWORD nFlags = WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL;
if (m_nFlags & LEFTALIGN)
nFlags |= ES_LEFT;
else
nFlags |= ES_RIGHT;
if (!(m_nFlags & NOBORDER))
nFlags |= WS_BORDER;
//m_edit.Create( WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|ES_RIGHT|ES_AUTOHSCROLL,rc,this,IDC_EDIT );
m_edit.Create( nFlags,rc,this,IDC_EDIT );
// m_edit.Create( WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,rc,this,IDC_EDIT );
m_edit.SetFont( CFont::FromHandle( (HFONT)::GetStockObject(DEFAULT_GUI_FONT)) );
m_edit.SetUpdateCallback( functor(*this, &CNumberCtrl::OnEditChanged) );
float val = m_value;
m_value = val+1;
SetInternalValue( val );
return 0;
}
void CNumberCtrl::SetLeftAlign( bool left )
{
if (m_edit)
{
if (left)
m_edit.ModifyStyle( ES_RIGHT,ES_LEFT );
else
m_edit.ModifyStyle( ES_LEFT,ES_RIGHT );
}
}
void CNumberCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
DrawButtons( dc );
// Do not call CWnd::OnPaint() for painting messages
}
void CNumberCtrl::DrawButtons( CDC &dc )
{
CRect rc;
GetClientRect( rc );
if (!m_enabled)
{
//dc.FillRect( rc,CBrush::FromHandle((HBRUSH)GetStockObject(LTGRAY_BRUSH)) );
dc.FillSolidRect( rc,GetSysColor(COLOR_3DFACE) );
return;
}
int x = 0;
if (!(m_nFlags & LEFTARROW))
{
x = rc.right-m_btnWidth;
}
int y = rc.top;
int w = m_btnWidth;
int h = rc.bottom;
int h2 = h/2;
COLORREF hilight = RGB(255,255,255);
COLORREF shadow = RGB(100,100,100);
//dc.Draw3dRect( x,y,w,h/2-1,hilight,shadow );
//dc.Draw3dRect( x,y+h/2+1,w,h/2-1,hilight,shadow );
int smallOfs = 0;
if (rc.bottom <= 18)
smallOfs = 1;
//dc.FillRect()
//dc.SelectObject(b1);
//dc.Rectangle( x,y, x+w,y+h2 );
//dc.SelectObject(b2);
//dc.Rectangle( x,y+h2, x+w,y+h );
if (m_btnStatus == 1 || m_btnStatus == 3)
{
dc.Draw3dRect( x,y,w,h2,shadow,hilight );
}
else
{
dc.Draw3dRect( x,y,w,h2,hilight,shadow );
//DrawIconEx( dc,x+1,y+2,m_upArrow,5,5,0,0,DI_NORMAL );
}
if (m_btnStatus == 2 || m_btnStatus == 3)
dc.Draw3dRect( x,y+h2+1,w,h2-1+smallOfs,shadow,hilight );
else
dc.Draw3dRect( x,y+h2+1,w,h2-1+smallOfs,hilight,shadow );
DrawIconEx( dc,x+2,y+2,m_upArrow,5,5,0,0,DI_NORMAL );
DrawIconEx( dc,x+2,y+h2+3-smallOfs,m_downArrow,5,5,0,0,DI_NORMAL );
}
void CNumberCtrl::GetBtnRect( int btn,CRect &rc )
{
CRect rcw;
GetClientRect( rcw );
int x = 0;
if (!(m_nFlags & LEFTARROW))
{
x = rcw.right-m_btnWidth;
}
int y = rcw.top;
int w = m_btnWidth;
int h = rcw.bottom;
int h2 = h/2;
if (btn == 0)
{
rc.SetRect( x,y,x+w,y+h2 );
}
else if (btn == 1)
{
rc.SetRect( x,y+h2+1,x+w,y+h );
}
}
int CNumberCtrl::GetBtn( CPoint point )
{
for (int i = 0; i < 2; i++)
{
CRect rc;
GetBtnRect( i,rc );
if (rc.PtInRect(point))
{
return i;
}
}
return -1;
}
void CNumberCtrl::SetBtnStatus( int s )
{
m_btnStatus = s;
RedrawWindow();
}
void CNumberCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
if (!m_enabled)
return;
m_btnStatus = 0;
int btn = GetBtn(point);
if (btn >= 0)
{
SetBtnStatus( btn+1 );
m_bDragged = false;
// Start undo.
if (m_bUndoEnabled)
GetIEditor()->BeginUndo();
}
m_mousePos = point;
SetCapture();
m_draggin = true;
CWnd::OnLButtonDown(nFlags, point);
}
void CNumberCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
if (!m_enabled)
return;
bool bLButonDown = false;
m_draggin = false;
if (GetCapture() == this)
{
bLButonDown = true;
ReleaseCapture();
}
SetBtnStatus( 0 );
//if (m_endUpdateCallback)
//m_endUpdateCallback(this);
if (m_bUndoEnabled && GetIEditor()->IsUndoRecording())
GetIEditor()->AcceptUndo( m_undoText );
if (bLButonDown)
{
int btn = GetBtn(point);
if (!m_bDragged && btn >= 0)
{
float prevValue = m_value;
if (btn == 0)
SetInternalValue( GetInternalValue() + m_step );
if (btn == 1)
SetInternalValue( GetInternalValue() - m_step );
if (prevValue != m_value)
NotifyUpdate(false);
}
else if (m_bDragged)
{
// Send last non tracking update after tracking.
NotifyUpdate(false);
}
}
///CWnd::OnLButtonUp(nFlags, point);
if (m_edit)
m_edit.SetFocus();
}
void CNumberCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_enabled)
return;
if (point == m_mousePos)
return;
if (m_draggin)
{
m_bDragged = true;
float prevValue = m_value;
SetCursor( m_upDownCursor );
if (m_btnStatus != 3)
SetBtnStatus(3);
if (!m_integer)
{
// Floating control.
int y = (point.y-m_mousePos.y) * abs((point.y-m_mousePos.y));
SetInternalValue( GetInternalValue() - m_step*y );
}
else
{
// Integer control.
int y = point.y-m_mousePos.y;
SetInternalValue( GetInternalValue() - m_step*y );
}
CPoint cp;
GetCursorPos( &cp );
int sX = GetSystemMetrics(SM_CXSCREEN);
int sY = GetSystemMetrics(SM_CYSCREEN);
if (cp.y < 20 || cp.y > sY-20)
{
// When near end of screen, prevent cursor from moving.
CPoint p = m_mousePos;
ClientToScreen(&p);
SetCursorPos( p.x,p.y );
}
else
{
m_mousePos = point;
}
if (prevValue != m_value)
NotifyUpdate(true);
}
CWnd::OnMouseMove(nFlags, point);
}
void CNumberCtrl::SetRange( float min,float max )
{
m_min = min;
m_max = max;
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::SetInternalValue( float val )
{
CString s;
if (val < m_min) val = m_min;
if (val > m_max) val = m_max;
if (m_integer)
{
if ((int)m_value == (int)val)
return;
s.Format( "%d",(int)val );
}
else
{
double prec = pow(10.0f,m_iInternalPrecision);
if (fabs(val-m_value) < 0.9f/prec)
return;
/*
if (val == int(val))
{
// Optimize float to string storage.
s.Format( "%i",int(val) );
}
else
{
int digits = CalculateDecimalPlaces(val,m_iInternalPrecision); // m.m. calculate the digits right from the comma
char fmt[12];
if (digits < 2)
digits = 2;
sprintf(fmt,"%%.%df",digits); // e.g. "%.2f"
s.Format( fmt,val );
}
*/
double v = val;
v = v*(prec);
int intpart = RoundFloatToInt(v);
v = (double)intpart / prec;
// Round it to precision.
s.Format( "%g",v );
}
m_value = val;
if (m_edit)
{
m_noNotify = true;
m_edit.SetText( s );
m_noNotify = false;
}
}
//////////////////////////////////////////////////////////////////////////
float CNumberCtrl::GetInternalValue() const
{
if (!m_enabled)
return m_value;
if (m_edit)
{
CString str;
m_edit.GetWindowText(str);
m_value = atof( (const char*)str );
}
return m_value;
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::SetValue( float val,float step )
{
m_step = step;
if (m_integer && m_step < 1)
m_step = 1;
SetInternalValue( val*m_multiplier );
}
//////////////////////////////////////////////////////////////////////////
float CNumberCtrl::GetValue() const
{
return GetInternalValue() / m_multiplier;
}
//////////////////////////////////////////////////////////////////////////
float CNumberCtrl::GetStep() const
{
return m_step;
}
//////////////////////////////////////////////////////////////////////////
CString CNumberCtrl::GetValueAsString() const
{
CString str;
/*
int digits = CalculateDecimalPlaces(GetValue(),m_iInternalPrecision); // m.m. calculate the digits right from the comma
char fmt[12];
sprintf(fmt,"%%.%df",digits); // e.g. "%.2f"
str.Format( fmt,m_value );
*/
str.Format( "%g",m_value/m_multiplier );
return str;
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::OnEditChanged()
{
static bool inUpdate = false;
if (!inUpdate)
{
float prevValue = m_value;
float v = GetInternalValue();
if (v < m_min) v = m_min;
if (v > m_max) v = m_max;
if (v != m_value)
{
SetInternalValue( v );
}
if (prevValue != m_value)
NotifyUpdate(false);
inUpdate = false;
}
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::OnEnable(BOOL bEnable)
{
CWnd::OnEnable(bEnable);
m_enabled = (bEnable == TRUE);
if (m_edit)
{
m_edit.EnableWindow(bEnable);
RedrawWindow();
}
}
void CNumberCtrl::NotifyUpdate( bool tracking )
{
if (m_noNotify)
return;
if (!tracking && m_bUndoEnabled)
GetIEditor()->BeginUndo();
if (m_updateCallback)
m_updateCallback(this);
CWnd *parent = GetParent();
if (parent)
{
if (!tracking)
{
::SendMessage( parent->GetSafeHwnd(),WM_COMMAND,MAKEWPARAM( GetDlgCtrlID(),EN_CHANGE ),(LPARAM)GetSafeHwnd() );
}
::SendMessage( parent->GetSafeHwnd(),WM_COMMAND,MAKEWPARAM( GetDlgCtrlID(),EN_UPDATE ),(LPARAM)GetSafeHwnd() );
}
m_lastUpdateValue = m_value;
if (!tracking && m_bUndoEnabled)
GetIEditor()->AcceptUndo( m_undoText );
}
void CNumberCtrl::OnSetFocus(CWnd* pOldWnd)
{
CWnd::OnSetFocus(pOldWnd);
if (m_edit)
{
m_edit.SetFocus();
m_edit.SetSel(0,-1);
}
}
void CNumberCtrl::SetInteger( bool enable )
{
m_integer = enable;
m_step = 1;
float f = GetInternalValue();
m_value = f+1;
SetInternalValue(f);
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::OnEditSetFocus()
{
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::OnEditKillFocus()
{
//if (m_bUpdating && m_endUpdateCallback)
//m_endUpdateCallback(this);
if (m_value != m_lastUpdateValue)
NotifyUpdate(false);
}
//////////////////////////////////////////////////////////////////////////
// calculate the digits right from the comma
int CNumberCtrl::CalculateDecimalPlaces( float infNumber, int iniMaxPlaces )
{
assert(iniMaxPlaces>=0);
char str[256],*_str=str;
sprintf(str,"%f",infNumber);
while(*_str!='.')_str++; // search the comma
int ret=0;
if(*_str!=0) // comma?
{
int cur=1;
_str++; // jump over comma
while(*_str>='0' && *_str<='9')
{
if(*_str!='0')ret=cur;
_str++;cur++;
}
if(ret>iniMaxPlaces)ret=iniMaxPlaces; // bound to maximum
}
return(ret);
}
//! m.m. (default is 2)
void CNumberCtrl::SetInternalPrecision( int iniDigits )
{
assert(iniDigits>=0);
m_iInternalPrecision=iniDigits;
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::EnableUndo( const CString& undoText )
{
m_undoText = undoText;
m_bUndoEnabled = true;
}
void CNumberCtrl::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
if (m_edit.m_hWnd)
{
CRect rc;
GetClientRect( rc );
if (m_nFlags & LEFTARROW)
{
rc.left += m_btnWidth+3;
}
else
{
rc.right -= m_btnWidth+1;
}
m_edit.MoveWindow(rc,FALSE);
}
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::SetFont( CFont* pFont,BOOL bRedraw )
{
CWnd::SetFont(pFont,bRedraw);
if (m_edit.m_hWnd)
m_edit.SetFont(pFont,bRedraw);
}
//////////////////////////////////////////////////////////////////////////
void CNumberCtrl::SetMultiplier( float fMultiplier )
{
if (fMultiplier != 0)
m_multiplier = fMultiplier;
}