Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
905 lines
23 KiB
C++
905 lines
23 KiB
C++
// MultiSlider.cpp : implementation file
|
||
//
|
||
|
||
#include "stdafx.h"
|
||
#include "MultiSlider.h"
|
||
#include <math.h>
|
||
|
||
#ifdef _DEBUG
|
||
#define new DEBUG_NEW
|
||
#undef THIS_FILE
|
||
static char THIS_FILE[] = __FILE__;
|
||
#endif
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// CMultiSlider
|
||
|
||
|
||
/*! \fn CMultiSlider::CMultiSlider(int LayoutMask)
|
||
\brief Class costructor: initializes class variables anc layout; if none is passed a default layout
|
||
is used.*/
|
||
CMultiSlider::CMultiSlider(int LayoutMask)
|
||
{
|
||
m_hCursorArrow = ::LoadCursor(NULL, IDC_ARROW);
|
||
|
||
m_MarkersNum = 1;
|
||
|
||
m_TTRect.SetRectEmpty();
|
||
|
||
fInit = false;
|
||
|
||
m_LayoutMask = LayoutMask;
|
||
m_RangeDir = 1;
|
||
iToolTipEventDelay = 1000;
|
||
uiToolTipEventId = 2;
|
||
|
||
m_bDragBoth = false;
|
||
m_pdraggedMarker = NULL;
|
||
m_pnewMarker = NULL;
|
||
m_pSelectedMarker = NULL;
|
||
m_pTTMarker = NULL;
|
||
m_DragStartingPos = 0;
|
||
|
||
m_wndInfo.Create (this, TRUE /* Shadow */);
|
||
m_wndInfo.SetOwner (this);
|
||
m_wndInfo.Hide ();
|
||
}
|
||
|
||
/*! \fn CMultiSlider::~CMultiSlider()
|
||
\brief Class destructor: resets class variables (using CleanUp()) and releases resources.*/
|
||
CMultiSlider::~CMultiSlider()
|
||
{
|
||
m_wndInfo.DestroyWindow();
|
||
CleanUp ();
|
||
}
|
||
|
||
|
||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||
BEGIN_MESSAGE_MAP(CMultiSlider, CSliderCtrl)
|
||
//{{AFX_MSG_MAP(CMultiSlider)
|
||
ON_WM_PAINT()
|
||
ON_WM_LBUTTONDOWN()
|
||
ON_WM_LBUTTONUP()
|
||
ON_WM_MOUSEMOVE()
|
||
ON_WM_TIMER()
|
||
ON_WM_RBUTTONUP()
|
||
//}}AFX_MSG_MAP
|
||
END_MESSAGE_MAP()
|
||
#endif
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// CMultiSlider message handlers
|
||
|
||
/*! \fn void CMultiSlider::OnPaint()
|
||
\brief Draws the control components.
|
||
|
||
Manages all possible orientations of the control; at the present moment the codew is not very elegant and
|
||
concise... sorry!*/
|
||
void CMultiSlider::OnPaint()
|
||
{
|
||
CPaintDC dc(this); // device context for painting
|
||
if(!fInit) Initialize();
|
||
|
||
BOOL m_bMemDC = FALSE;
|
||
CDC* pDC = &dc;
|
||
CDC dcMem;
|
||
CBitmap bmp, *pOldBmp = NULL;
|
||
POSITION pos;
|
||
|
||
//Try to create memory dc and bitmap
|
||
if(dcMem.CreateCompatibleDC(&dc) && bmp.CreateCompatibleBitmap(&dc, clientRect.Width(), clientRect.Height()))
|
||
{
|
||
m_bMemDC = TRUE;
|
||
pOldBmp = dcMem.SelectObject(&bmp);
|
||
pDC = &dcMem;
|
||
}
|
||
|
||
// Fill background, draw border and thumb
|
||
pDC->FillSolidRect(&clientRect, GetSysColor(COLOR_WINDOW));
|
||
pDC->DrawEdge(&clientRect, BDR_SUNKENOUTER|BDR_SUNKENINNER, BF_RECT);
|
||
|
||
// Draw thumb in the specific way depending on style (ILIC)
|
||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD>̴<EFBFBD> <20><><EFBFBD><EFBFBD> <20>κ<EFBFBD>
|
||
for(pos=m_Markers.GetHeadPosition();pos != NULL;)
|
||
{
|
||
CMarker* pMarker = (CMarker*)m_Markers.GetNext(pos);
|
||
ASSERT(pMarker != NULL);
|
||
pDC->Ellipse(&pMarker->m_mainRect);
|
||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
}
|
||
// Draw thumb in the specific way depending on style (ILIC)
|
||
|
||
if(m_bMemDC)
|
||
{
|
||
CRect clipRect;
|
||
dc.GetClipBox(&clipRect);
|
||
dc.BitBlt(clipRect.left, clipRect.top, clipRect.Width(), clipRect.Height(),
|
||
&dcMem, clipRect.left, clipRect.top, SRCCOPY);
|
||
dcMem.SelectObject(pOldBmp);
|
||
}
|
||
// Do not call CSliderCtrl::OnPaint() for painting messages
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::OnLButtonDown(UINT nFlags, CPoint point)
|
||
\brief Depending on Layout configuration, manages different possible actions.
|
||
|
||
Clicking on a marker allows the user to start dragging it; if <Ctrl> is pressed and there are only
|
||
two markers, both will be dragged contemporarily. If one clicks out of the markers area, a new
|
||
markers is created - but only if the total number of markers [set with Init()] has not been reached yet.*/
|
||
void CMultiSlider::OnLButtonDown(UINT nFlags, CPoint point)
|
||
{
|
||
CString strText;
|
||
CPoint pt;
|
||
|
||
m_wndInfo.Hide ();
|
||
m_TTRect.SetRectEmpty ();
|
||
|
||
if(sliderRect.PtInRect(point))
|
||
{
|
||
m_pdraggedMarker = MarkerHitTest(point);
|
||
if(m_pdraggedMarker)
|
||
{
|
||
int ActualMarkersNum = m_Markers.GetCount();
|
||
|
||
if(nFlags & MK_CONTROL) m_bDragBoth = true;
|
||
|
||
m_DragStartingPos = m_pdraggedMarker->m_Pos;
|
||
|
||
GetMinMax(point);
|
||
|
||
if(m_LayoutMask & MLTSLD_DISPLAY_TOOLTIPS)
|
||
{
|
||
BuildTooltipText(m_pdraggedMarker, strText);
|
||
|
||
::GetCursorPos (&pt);
|
||
pt += CPoint (GetSystemMetrics (SM_CXCURSOR) / 2, GetSystemMetrics (SM_CYCURSOR) / 2);
|
||
m_wndInfo.Track (pt, strText);
|
||
}
|
||
}
|
||
}
|
||
// CSliderCtrl::OnLButtonDown(nFlags, point);
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::OnLButtonUp(UINT nFlags, CPoint point)
|
||
\brief Manages the end of an (eventual) marker dragging.
|
||
|
||
Checks whether a Marker is being dragged; if so, following actions can be taken depending on layout
|
||
and marker position:
|
||
|
||
\arg If marker has beeen dragged out of the control and MLTSLD_REMOVE_OUTGOING is included in the layout, the
|
||
marker is deleted, otherwise it is simply fixed to the correct extreme of the ChannelRect.
|
||
\arg If the dragged marker has position equal to the minimum one and that marker is not the first, dragging
|
||
is considered invalid and marker is set back to its original position (otherwise it would be impossible to
|
||
get control of it later, due to precedence with which markers are "captured").
|
||
|
||
Other features (such as preventing markers crossing) are also considered, even if the greatest of the management
|
||
is done in OnMouseMove().
|
||
*/
|
||
void CMultiSlider::OnLButtonUp(UINT nFlags, CPoint point)
|
||
{
|
||
int x;
|
||
int SliderMin, SliderWidth;
|
||
|
||
SetFocus ();
|
||
m_wndInfo.Hide ();
|
||
::SetCursor (m_hCursorArrow);
|
||
|
||
if (m_pdraggedMarker != NULL)
|
||
{
|
||
ReleaseCapture();
|
||
}
|
||
|
||
// Disable multiple dragging
|
||
m_bDragBoth = false;
|
||
|
||
SetSliderValues(&SliderMin, &SliderWidth);
|
||
|
||
// ILIC Just slightly different... :-)
|
||
if (m_StyleIdx & SLIDER_VERT)
|
||
x = (int)(((float)(point.y - SliderMin)/(float)SliderWidth * (float)m_RangeWidth) + m_RangeMin);
|
||
else
|
||
x = (int)(((float)(point.x - SliderMin)/(float)SliderWidth * (float)m_RangeWidth) + m_RangeMin);
|
||
|
||
if(m_pdraggedMarker != NULL)
|
||
{
|
||
if(x < m_RangeMin) x = m_RangeMin;
|
||
|
||
if(x > m_RangeMax) x = m_RangeMax;
|
||
|
||
// We need to avoid superposition with first marker in the origin
|
||
POSITION MyPos = m_Markers.Find(m_pdraggedMarker);
|
||
if(m_Markers.GetCount() > 1)
|
||
{
|
||
if (MyPos != m_Markers.GetHeadPosition())
|
||
if (x == m_RangeMin) x = m_DragStartingPos;
|
||
}
|
||
|
||
if(x <= m_RangeMax && x >= m_RangeMin)
|
||
{
|
||
NMHDR nmhdr;
|
||
nmhdr.hwndFrom = m_hWnd;
|
||
nmhdr.idFrom = GetDlgCtrlID();
|
||
nmhdr.code = TB_THUMBPOSITION;
|
||
GetParent()->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM) &nmhdr);
|
||
}
|
||
m_pdraggedMarker = NULL;
|
||
}
|
||
|
||
CSliderCtrl::OnLButtonUp(nFlags, point);
|
||
}
|
||
|
||
/*! \fn CMarker* CMultiSlider::MarkerHitTest(CPoint pt)
|
||
\brief Checks if the input point is inside the area of one of the markers and returns a pointer to it (or NULL
|
||
if no matching marker is found).*/
|
||
CMarker* CMultiSlider::MarkerHitTest(CPoint pt)
|
||
{
|
||
CRect mainRect;
|
||
POSITION pos;
|
||
|
||
if(m_Markers.GetCount() == 0) return NULL;
|
||
|
||
for(pos = m_Markers.GetHeadPosition();pos!=NULL;)
|
||
{
|
||
CMarker* pMarker = (CMarker*)m_Markers.GetNext(pos);
|
||
mainRect = pMarker->m_mainRect;
|
||
if(pMarker->m_mainRect.PtInRect(pt))
|
||
{
|
||
return pMarker;
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::OnMouseMove(UINT nFlags, CPoint point)
|
||
\brief Manages the markers dragging.
|
||
|
||
Changes the cursor if a marker ig going to be dragged away, blocks the dragged marker if MLTSLD_PREVENT_CROSSING
|
||
is active and there is superposition of two objects... and finally sets new position of the marker (or othe the TWO
|
||
markers in case of multiple dragging.*/
|
||
void CMultiSlider::OnMouseMove(UINT nFlags, CPoint point)
|
||
{
|
||
// CSliderCtrl::OnMouseMove(nFlags, point);
|
||
/* float x;
|
||
int SliderMin, SliderWidth;
|
||
|
||
if(m_pdraggedMarker == NULL)
|
||
{
|
||
// SetInfoWindow (point);
|
||
return;
|
||
}
|
||
|
||
SetSliderValues(&SliderMin, &SliderWidth);
|
||
|
||
CRect oldRect, newRect;
|
||
|
||
if(m_pdraggedMarker != NULL)
|
||
{
|
||
if(sliderRect.PtInRect(point))
|
||
{
|
||
if (m_StyleIdx & SLIDER_VERT)
|
||
x = ((float)(point.y - SliderMin)/(float)SliderWidth * (float)m_RangeWidth) + (float)m_RangeMin;
|
||
else
|
||
x = ((float)(point.x - SliderMin)/(float)SliderWidth * (float)m_RangeWidth) + (float)m_RangeMin;
|
||
|
||
|
||
bool bInRange = true;
|
||
float DeltaPos = x - m_pdraggedMarker->m_Pos;
|
||
// if(DeltaPos <= 0.0f) { DeltaPos -= 0.5f; } else { DeltaPos += 0.5f; }
|
||
// floorf(DeltaPos);
|
||
|
||
if (m_bDragBoth)
|
||
{
|
||
for (POSITION pos = m_Markers.GetHeadPosition (); pos != NULL;)
|
||
{
|
||
CMarker *pTmpMarker = (CMarker*) m_Markers.GetNext (pos);
|
||
|
||
int TmpNewPos = pTmpMarker->m_Pos + (int)DeltaPos;
|
||
|
||
if (TmpNewPos < m_RangeMin || TmpNewPos > m_RangeMax)
|
||
{
|
||
bInRange = false;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
bInRange = (x >= m_RangeMin && x <= m_RangeMax);
|
||
|
||
if (bInRange)
|
||
{
|
||
CMarker *pToMove = m_pdraggedMarker;
|
||
|
||
do
|
||
{
|
||
CMarker newMarker/*(pToMove->m_Index)*/;
|
||
/* oldRect = pToMove->m_mainRect;
|
||
newMarker.m_Pos = (int)(pToMove->m_Pos + DeltaPos);
|
||
SetRectangles(&newMarker);
|
||
pToMove->m_mainRect = newRect = newMarker.m_mainRect;
|
||
pToMove->m_Pos = newMarker.m_Pos;
|
||
if(oldRect != newRect)
|
||
{
|
||
Invalidate(FALSE);
|
||
UpdateWindow();
|
||
SetInfoWindow (point);
|
||
}
|
||
|
||
// We are not using multiple dragging, or we are over with it
|
||
if (!m_bDragBoth || pToMove != m_pdraggedMarker)
|
||
pToMove = NULL;
|
||
else
|
||
{
|
||
for (POSITION pos = m_Markers.GetHeadPosition (); pos != NULL;)
|
||
{
|
||
pToMove = (CMarker*) m_Markers.GetNext (pos);
|
||
|
||
// We are looking fo the other one...
|
||
if (pToMove != m_pdraggedMarker)
|
||
break;
|
||
}
|
||
}
|
||
} while (pToMove);
|
||
}
|
||
GetParent()->SendMessage(WM_HSCROLL, (WPARAM)(0x0000FFFF | (short)x << 16), (LPARAM)this->m_hWnd);
|
||
}
|
||
}*/
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::BuildTooltipText(CMarker* pMI, CString &text)
|
||
\brief Builds tooltip text - quite straightforward, isn't it?!? ;-).*/
|
||
void CMultiSlider::BuildTooltipText(CMarker* pMI, CString &text)
|
||
{
|
||
if(pMI == NULL)
|
||
return;
|
||
|
||
text = _T("");
|
||
|
||
if(m_LayoutMask & MLTSLD_INTEGERS)
|
||
text.Format(_T("%d"), pMI->m_Pos);
|
||
else
|
||
text.Format(_T("%d"), pMI->m_Pos);
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::SetInfoWindow(CPoint &point)
|
||
\brief Builds the window for the tooltip, if this feature is included in the layout.*/
|
||
void CMultiSlider::SetInfoWindow(CPoint &point)
|
||
{
|
||
CRect rectI;
|
||
BOOL bShowInfo = TRUE;
|
||
CMarker* pMI;
|
||
|
||
if (m_pdraggedMarker != NULL && (m_LayoutMask & MLTSLD_DISPLAY_TOOLTIPS) && !m_bDragBoth)
|
||
{
|
||
CString strText;
|
||
BuildTooltipText (m_pdraggedMarker, strText);
|
||
m_wndInfo.SetWindowText (strText);
|
||
m_wndInfo.ShowWindow(SW_SHOWNOACTIVATE);
|
||
m_wndInfo.Invalidate ();
|
||
m_wndInfo.UpdateWindow ();
|
||
return;
|
||
}
|
||
|
||
if (m_TTRect.PtInRect (point))
|
||
return;
|
||
|
||
m_TTRect.SetRectEmpty();
|
||
if ((pMI = MarkerHitTest(point)) == NULL)
|
||
bShowInfo = FALSE;
|
||
else
|
||
{
|
||
rectI = GetMarkerRect(pMI);
|
||
bShowInfo = rectI.PtInRect (point);
|
||
}
|
||
|
||
if (!bShowInfo)
|
||
{
|
||
ReleaseCapture ();
|
||
m_wndInfo.Hide ();
|
||
|
||
KillTimer (uiToolTipEventId);
|
||
rectI.SetRectEmpty ();
|
||
}
|
||
else
|
||
SetTimer (uiToolTipEventId, iToolTipEventDelay, NULL);
|
||
|
||
m_TTRect = rectI;
|
||
m_pTTMarker = pMI;
|
||
}
|
||
|
||
|
||
/*! \fn void CMultiSlider::OnTimer(UINT nIDEvent)
|
||
\brief For displaying Tooltips with a reasonable frequency.*/
|
||
void CMultiSlider::OnTimer(UINT nIDEvent)
|
||
{
|
||
CPaintDC dc(this);
|
||
CPoint pt;
|
||
|
||
if (m_pTTMarker != NULL && (m_LayoutMask & MLTSLD_DISPLAY_TOOLTIPS) && !m_bDragBoth)
|
||
{
|
||
CString strText;
|
||
TEXTMETRIC tm;
|
||
CSize length;
|
||
int width;
|
||
|
||
dc.GetTextMetrics(&tm);
|
||
int nTextHeight = tm.tmHeight + 2;
|
||
int nTextWidth = tm.tmMaxCharWidth + 2;
|
||
|
||
if(m_LayoutMask & MLTSLD_INTEGERS)
|
||
strText.Format("%d", m_pTTMarker->m_Pos);
|
||
else
|
||
strText.Format("%d", m_pTTMarker->m_Pos);
|
||
|
||
length = dc.GetTextExtent(strText);
|
||
width = length.cx;
|
||
BuildTooltipText(m_pTTMarker, strText);
|
||
|
||
CPoint ptCursor;
|
||
::GetCursorPos (&ptCursor);
|
||
ptCursor += CPoint (
|
||
GetSystemMetrics (SM_CXCURSOR) / 2,
|
||
GetSystemMetrics (SM_CYCURSOR) / 2);
|
||
m_wndInfo.Track (ptCursor, strText);
|
||
|
||
SetCapture ();
|
||
}
|
||
else
|
||
{
|
||
m_wndInfo.Hide ();
|
||
m_TTRect.SetRectEmpty ();
|
||
}
|
||
|
||
KillTimer (uiToolTipEventId);
|
||
|
||
CSliderCtrl::OnTimer(nIDEvent);
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::Initialize()
|
||
\brief Sets various rects (overwriting base class configuration and checks for markers intial positions.*/
|
||
void CMultiSlider::Initialize()
|
||
{
|
||
int max, min;
|
||
CPoint pt;
|
||
POSITION pos;
|
||
|
||
CPaintDC dc(this);
|
||
dc.SetMapMode(MM_TEXT);
|
||
|
||
//Get control rect, channel rect and thumb rect
|
||
GetClientRect(&clientRect);
|
||
GetThumbRect(&thumbRect);
|
||
|
||
// ILIC: Retrieve control style
|
||
DWORD Style = GetStyle();
|
||
|
||
m_StyleIdx = 0;
|
||
/* long Correction; // To make it look perfect ;-)
|
||
|
||
if (Style & TBS_VERT)
|
||
{
|
||
m_StyleIdx += 1;
|
||
|
||
Correction = -2;
|
||
|
||
CRect TmpRect;
|
||
TmpRect.top = clientRect.left;
|
||
TmpRect.bottom = clientRect.right;
|
||
TmpRect.left = clientRect.top + Correction;
|
||
TmpRect.right = clientRect.bottom + Correction;
|
||
|
||
thumbRect.left += Correction;
|
||
thumbRect.right += Correction;
|
||
|
||
channelRect = TmpRect;
|
||
}*/
|
||
|
||
// ILIC: Retrieve control style (END)
|
||
|
||
min = m_RangeMin;
|
||
max = m_RangeMax;
|
||
|
||
sliderRect = clientRect;
|
||
sliderRect.DeflateRect(2, 0);
|
||
|
||
for(pos = m_Markers.GetHeadPosition();pos!=NULL;)
|
||
{
|
||
CMarker* pMarker = (CMarker*)m_Markers.GetNext(pos);
|
||
|
||
//Remove any out of range (here no test on MLTSLD in needed as we are at the beginning...)
|
||
if((pMarker->m_Pos > m_RangeMax || pMarker->m_Pos < m_RangeMin))
|
||
RemoveLevelMarker(pMarker);
|
||
else
|
||
SetRectangles(pMarker); //Reset rectangles
|
||
}
|
||
|
||
fInit = true;
|
||
}
|
||
|
||
/*! \fn bool CMultiSlider::SetRanges(float min, float max, int MarkersNum, float *NewPos)
|
||
\brief Updates the controls after a on-the-fly change of its extremes and/or number of markers.
|
||
|
||
\param min New lower extreme of the control;
|
||
\param max New higher extreme of the control;
|
||
\param MarkersNum new total number of markers in the control;
|
||
\param NewPos vector containing starting positions for markers.
|
||
|
||
This function resets the control, sets the new extremes and inserts new markers if a list of
|
||
positions is passed. Consistency between MarkersNum and lenght of the vector NewPos relies on caller's
|
||
resposibility. \b WARNING: Color list for intervals must be eventually updated with correct functions.
|
||
*/
|
||
bool CMultiSlider::SetRanges(int min, int max, int MarkersNum, int *NewPos)
|
||
{
|
||
m_RangeMax = max;
|
||
m_RangeMin = min;
|
||
|
||
m_RangeWidth = m_RangeMax - m_RangeMin;
|
||
int i=0;
|
||
// Beware: if you change number of Markers, you should eventually update the list of colors!
|
||
if (NewPos && MarkersNum)
|
||
{
|
||
CMarker *pNewMarker;
|
||
ResetMarkers();
|
||
for (i=0; i<MarkersNum; i++)
|
||
{
|
||
pNewMarker = new CMarker;
|
||
if (!pNewMarker)
|
||
break;
|
||
|
||
pNewMarker->m_Pos = NewPos[i];
|
||
InsertMarker(pNewMarker);
|
||
}
|
||
if (i != MarkersNum)
|
||
{
|
||
ResetMarkers();
|
||
return false;
|
||
}
|
||
|
||
}
|
||
fInit = false;
|
||
Invalidate();
|
||
UpdateWindow();
|
||
return true;
|
||
}
|
||
|
||
/*! \fn bool CMultiSlider::GetRanges(float &min, float &max)
|
||
\brief Returns lower and higher extremes of the control.*/
|
||
bool CMultiSlider::GetRanges(int &min, int &max)
|
||
{
|
||
min = m_RangeMin;
|
||
max = m_RangeMax;
|
||
|
||
return true;
|
||
}
|
||
|
||
/*! \fn bool CMultiSlider::RemoveLevelMarker(CMarker *pRemoved)
|
||
\brief Removes a marker, usually because it has been dragged out of the control.*/
|
||
bool CMultiSlider::RemoveLevelMarker(CMarker *pRemoved)
|
||
{
|
||
ASSERT (pRemoved != NULL);
|
||
bool AllIsOk = false;
|
||
CRect rectTI;
|
||
rectTI = pRemoved->m_mainRect;
|
||
|
||
for (POSITION pos = m_Markers.GetHeadPosition (); pos != NULL;)
|
||
{
|
||
POSITION posSave = pos;
|
||
|
||
CMarker* pTI = (CMarker*) m_Markers.GetNext (pos);
|
||
ASSERT (pTI != NULL);
|
||
|
||
if (pTI == pRemoved)
|
||
{
|
||
m_Markers.RemoveAt (posSave);
|
||
delete pRemoved;
|
||
|
||
InvalidateRect(rectTI);
|
||
AllIsOk = true;
|
||
}
|
||
}
|
||
|
||
return AllIsOk;
|
||
}
|
||
|
||
/*! \fn int CMultiSlider::InsertMarker(CMarker *pNewMarker)
|
||
\brief Inserts a new marker into the control; starting position must me already sored in the input pointer.*/
|
||
int CMultiSlider::InsertMarker(CMarker *pNewMarker)
|
||
{
|
||
bool bInserted = false;
|
||
int i = 0;
|
||
int iIndex = -1;
|
||
|
||
for(POSITION pos = m_Markers.GetHeadPosition(); pos != NULL && !bInserted; i++)
|
||
{
|
||
POSITION posSave = pos;
|
||
CMarker* pMarker = (CMarker*)m_Markers.GetNext(pos);
|
||
ASSERT(pMarker != NULL);
|
||
|
||
if(pMarker->m_Pos >= pNewMarker->m_Pos)
|
||
{
|
||
m_Markers.InsertBefore(posSave, pNewMarker);
|
||
iIndex = i;
|
||
bInserted = true;
|
||
}
|
||
}
|
||
|
||
if(!bInserted)
|
||
{
|
||
m_Markers.AddTail(pNewMarker);
|
||
iIndex = m_Markers.GetCount() - 1;
|
||
}
|
||
|
||
return iIndex;
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::ResetMarkers()
|
||
\brief Removes all markers and sets auxiliar pointers to NULL.*/
|
||
void CMultiSlider::ResetMarkers()
|
||
{
|
||
while (!m_Markers.IsEmpty ())
|
||
{
|
||
delete m_Markers.RemoveHead();
|
||
}
|
||
|
||
m_pnewMarker = NULL;
|
||
m_pdraggedMarker = NULL;
|
||
m_pSelectedMarker = NULL;
|
||
m_pTTMarker = NULL;
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::SetRectangles(CMarker *pMarker)
|
||
\brief Builds the three rectangles necessary to draw a Marker (...unfortunately some "emprical" corrections
|
||
were necessary for different configurations...).*/
|
||
void CMultiSlider::SetRectangles(CMarker *pMarker)
|
||
{
|
||
int SliderMin, SliderWidth;
|
||
CRect top;
|
||
int x;
|
||
|
||
m_RangeMin = m_RangeMin;
|
||
m_RangeMax = m_RangeMax;
|
||
m_RangeWidth = m_RangeMax - m_RangeMin;
|
||
|
||
SetSliderValues(&SliderMin, &SliderWidth);
|
||
|
||
x = (int)((((pMarker->m_Pos - (float)m_RangeMin) / (float)m_RangeWidth) * (float)SliderWidth) + SliderMin);
|
||
|
||
// ILIC Rectangle must now be prepared in specific way depending on style...
|
||
top = clientRect;
|
||
|
||
if (m_StyleIdx & SLIDER_VERT)
|
||
{
|
||
top.top = x - 6;
|
||
top.bottom = x + 6;
|
||
top.left += 2;
|
||
top.right -= 2;
|
||
}
|
||
else
|
||
{
|
||
top.top += 2;
|
||
top.bottom -= 2;
|
||
top.left = x - 6;
|
||
top.right = x + 6;
|
||
}
|
||
// ILIC Rectangle must now be prepared in specific way depending on style... (END)
|
||
|
||
pMarker->m_mainRect = top;
|
||
}
|
||
|
||
/*! \fn int CMultiSlider::GetMarkers(float *value)
|
||
\brief Returns in input pointer \b value a list of the markers' actual positions.*/
|
||
int CMultiSlider::GetMarkers(int *value)
|
||
{
|
||
int count = 0;
|
||
POSITION pos;
|
||
|
||
for(pos=m_Markers.GetHeadPosition();pos != NULL;)
|
||
{
|
||
CMarker* pMarker = (CMarker*)m_Markers.GetNext(pos);
|
||
ASSERT(pMarker != NULL);
|
||
value[count] = pMarker->m_Pos;
|
||
count++;
|
||
}
|
||
|
||
return count;
|
||
}
|
||
|
||
/*! \fn CRect CMultiSlider::GetMarkerRect(CMarker *pMI)
|
||
\brief Returns the rect occupied by the input marker.*/
|
||
CRect CMultiSlider::GetMarkerRect(CMarker *pMI)
|
||
{
|
||
CRect rect;
|
||
|
||
rect = pMI->m_mainRect;
|
||
rect.bottom = clientRect.bottom;
|
||
|
||
return rect;
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::OnRButtonUp(UINT nFlags, CPoint point)
|
||
\brief Allows to set marker position and/or intervals' colors; necessary tests (e.g. MLTSLD_PREVENT_CROSSING) are done.*/
|
||
void CMultiSlider::OnRButtonUp(UINT nFlags, CPoint point)
|
||
{
|
||
int SliderMin, SliderWidth;
|
||
CRect tempRect;
|
||
CPoint pt;
|
||
|
||
SetSliderValues(&SliderMin, &SliderWidth);
|
||
|
||
m_wndInfo.Hide ();
|
||
m_TTRect.SetRectEmpty ();
|
||
|
||
if(sliderRect.PtInRect(point)) //Verify in window
|
||
{
|
||
m_pSelectedMarker = MarkerHitTest(point);
|
||
|
||
SetMaker(10);
|
||
}
|
||
CSliderCtrl::OnRButtonUp(nFlags, point);
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::GetMinMax(CPoint point)
|
||
\brief Returns extremal positions of markers actually present in the control.*/
|
||
void CMultiSlider::GetMinMax(CPoint point)
|
||
{
|
||
int i, count;
|
||
int x;
|
||
int SliderMin, SliderWidth;
|
||
int *values;
|
||
|
||
values = (int*)malloc(sizeof(int) * m_MarkersNum);
|
||
|
||
SetSliderValues(&SliderMin, &SliderWidth);
|
||
|
||
// ILIC Just slightly different... :-)
|
||
if (m_StyleIdx & SLIDER_VERT)
|
||
x = (int)(((float)(point.y - SliderMin)/(float)SliderWidth * (float)m_RangeWidth) + m_RangeMin);
|
||
else
|
||
x = (int)(((float)(point.x - SliderMin)/(float)SliderWidth * (float)m_RangeWidth) + m_RangeMin);
|
||
|
||
prevMin = m_RangeMin;
|
||
prevMax = m_RangeMax;
|
||
|
||
count = GetMarkers(values);
|
||
for(i=0;i<count;i++)
|
||
{
|
||
if(values[i] < x)
|
||
prevMin = values[i];
|
||
}
|
||
for(i=count-1;i>=0;i--)
|
||
{
|
||
if(values[i] > x)
|
||
prevMax = values[i];
|
||
}
|
||
|
||
free(values);
|
||
return;
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::Init(float Min, float Max, int TicFreq, int MarkersNum, float *InitPos, COLORREF* ColorsList, int LayoutMask)
|
||
\brief Initializes the control with various parameters.
|
||
|
||
\param Min Lower extreme of the marker;
|
||
\param Max Higher extreme of the marker;
|
||
\param TicFreq Number of tickmarks (... I'm noto sure about that in this moment!);
|
||
\param MarkersNum Maximum number of markers which will be inserted in the control;
|
||
\param InitPos List of initial positions of markers;
|
||
\param ColorsList List of colors to be used for intervals (obviously you need MarkersNum-1 colors...);
|
||
\param LayoutMask Mask with options for the layout.
|
||
|
||
This function allows you to initialize the control, inserting automatically all the markers at the specified conditions.
|
||
The pointers MUST point to list whose length is coherent with MarkersNum (you can't set MarkersNum to 5 and then initialize
|
||
and insert only three markers... For details about layout mask, see documentation in header file.*/
|
||
void CMultiSlider::Init(int Min, int Max, int MarkersNum, int *InitPos, int LayoutMask)
|
||
{
|
||
fInit = false;
|
||
|
||
m_RangeMin = Min;
|
||
m_RangeMax = Max;
|
||
m_RangeWidth = m_RangeMax - m_RangeMin;
|
||
if (LayoutMask != -1) m_LayoutMask = LayoutMask;
|
||
m_MarkersNum = MarkersNum;
|
||
|
||
for (int i=0; i<MarkersNum; i++)
|
||
{
|
||
if (InitPos) // Adds Markers immediately
|
||
{
|
||
CMarker *pMarker = new CMarker/*(i)*/;
|
||
pMarker->m_Pos = InitPos[i];
|
||
InsertMarker(pMarker);
|
||
}
|
||
}
|
||
|
||
Invalidate();
|
||
UpdateWindow();
|
||
}
|
||
|
||
/*! \fn void CMultiSlider::SetSliderValues(float *SliderMin, float *SliderWidth)
|
||
\brief Returns data for drawing the control.*/
|
||
void CMultiSlider::SetSliderValues(int *SliderMin, int *SliderWidth)
|
||
{
|
||
int SliderMax;
|
||
if (m_StyleIdx & SLIDER_VERT)
|
||
{
|
||
SliderMax = sliderRect.top;
|
||
*SliderMin = sliderRect.bottom;
|
||
}
|
||
else
|
||
{
|
||
SliderMax = sliderRect.right;
|
||
*SliderMin = sliderRect.left;
|
||
}
|
||
*SliderWidth = (SliderMax - *SliderMin); // in order to compensate possible sign change.
|
||
}
|
||
|
||
/*! \fn CMarker *CMultiSlider::GetNextMarker(POSITION &Pos)
|
||
\brief Returns pointer to next marker in the list.
|
||
|
||
Markers are ordered in the list by thier position in the control (from lower to higher), so this function
|
||
can be used both for ciclying over the list and for determining marker following in the slider.*/
|
||
CMarker *CMultiSlider::GetNextMarker(POSITION &Pos)
|
||
{
|
||
POSITION OrgPos = Pos;
|
||
m_Markers.GetNext(Pos);
|
||
CMarker *pTheMarker = (CMarker *) m_Markers.GetNext(Pos);
|
||
|
||
// restore Pos
|
||
Pos = OrgPos;
|
||
|
||
return pTheMarker;
|
||
}
|
||
|
||
/*! \fn CMarker *CMultiSlider::GetPrevMarker(POSITION &Pos)
|
||
\brief Returns pointer to next marker in the list.
|
||
|
||
Markers are ordered in the list by thier position in the control (from lower to higher), so this function
|
||
can be used both for ciclying over the list and for determining marker following in the slider.*/
|
||
CMarker *CMultiSlider::GetPrevMarker(POSITION &Pos)
|
||
{
|
||
POSITION OrgPos = Pos;
|
||
m_Markers.GetPrev(Pos);
|
||
CMarker *pTheMarker = (CMarker *) m_Markers.GetPrev(Pos);
|
||
|
||
// restore Pos
|
||
Pos = OrgPos;
|
||
|
||
return pTheMarker;
|
||
}
|
||
|
||
void CMultiSlider::SetMaker(int nPos)
|
||
{
|
||
if(m_RangeMin <= (float)nPos && (float)nPos <= m_RangeMax)
|
||
{
|
||
if(m_Markers.GetCount() < m_MarkersNum)
|
||
{
|
||
m_pnewMarker = new CMarker;
|
||
|
||
m_pnewMarker->m_Pos = nPos;
|
||
m_DragStartingPos = nPos;
|
||
SetRectangles(m_pnewMarker);
|
||
InsertMarker(m_pnewMarker);
|
||
Invalidate();
|
||
m_pnewMarker = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
BOOL CMultiSlider::FindMarker(int nPos)
|
||
{
|
||
POSITION pos;
|
||
|
||
for(pos = m_Markers.GetHeadPosition();pos!=NULL;)
|
||
{
|
||
CMarker* pMarker = (CMarker*)m_Markers.GetNext(pos);
|
||
if(pMarker->m_Pos == nPos)
|
||
{
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|