// MultiSlider.cpp : implementation file // #include "stdafx.h" #include "MultiSlider.h" #include #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) ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // ½½¶óÀÌ´õ Âï´Â ºÎºÐ 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 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; im_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=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; im_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; }