• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

MyGUI_VScroll.cpp

Go to the documentation of this file.
00001 
00007 /*
00008     This file is part of MyGUI.
00009     
00010     MyGUI is free software: you can redistribute it and/or modify
00011     it under the terms of the GNU Lesser General Public License as published by
00012     the Free Software Foundation, either version 3 of the License, or
00013     (at your option) any later version.
00014     
00015     MyGUI is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU Lesser General Public License for more details.
00019     
00020     You should have received a copy of the GNU Lesser General Public License
00021     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00022 */
00023 #include "MyGUI_Precompiled.h"
00024 #include "MyGUI_VScroll.h"
00025 #include "MyGUI_InputManager.h"
00026 #include "MyGUI_Button.h"
00027 #include "MyGUI_ResourceSkin.h"
00028 
00029 namespace MyGUI
00030 {
00031 
00032     const int SCROLL_MOUSE_WHEEL = 50; // колличество пикселей для колеса мыши
00033 
00034     VScroll::VScroll() :
00035         mWidgetStart(nullptr),
00036         mWidgetEnd(nullptr),
00037         mWidgetTrack(nullptr),
00038         mWidgetFirstPart(nullptr),
00039         mWidgetSecondPart(nullptr),
00040         mSkinRangeStart(0),
00041         mSkinRangeEnd(0),
00042         mScrollRange(0),
00043         mScrollPosition(0),
00044         mScrollPage(0),
00045         mScrollViewPage(0),
00046         mMinTrackSize(0),
00047         mMoveToClick(false)
00048     {
00049     }
00050 
00051     void VScroll::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, WidgetPtr _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
00052     {
00053         Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
00054 
00055         initialiseWidgetSkin(_info);
00056     }
00057 
00058     VScroll::~VScroll()
00059     {
00060         shutdownWidgetSkin();
00061     }
00062 
00063     void VScroll::baseChangeWidgetSkin(ResourceSkin* _info)
00064     {
00065         shutdownWidgetSkin();
00066         Base::baseChangeWidgetSkin(_info);
00067         initialiseWidgetSkin(_info);
00068     }
00069 
00070     void VScroll::initialiseWidgetSkin(ResourceSkin* _info)
00071     {
00072         // при нуле, будет игнорировать кнопки
00073         mScrollPage = 1;
00074         mScrollViewPage = 1;
00075 
00076         for (VectorWidgetPtr::iterator iter = mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
00077         {
00078             if (*(*iter)->_getInternalData<std::string>() == "Start")
00079             {
00080                 MYGUI_DEBUG_ASSERT( ! mWidgetStart, "widget already assigned");
00081                 mWidgetStart = (*iter)->castType<Button>();
00082                 mWidgetStart->eventMouseButtonPressed = newDelegate(this, &VScroll::notifyMousePressed);
00083                 mWidgetStart->eventMouseWheel = newDelegate(this, &VScroll::notifyMouseWheel);
00084             }
00085             else if (*(*iter)->_getInternalData<std::string>() == "End")
00086             {
00087                 MYGUI_DEBUG_ASSERT( ! mWidgetEnd, "widget already assigned");
00088                 mWidgetEnd = (*iter)->castType<Button>();
00089                 mWidgetEnd->eventMouseButtonPressed = newDelegate(this, &VScroll::notifyMousePressed);
00090                 mWidgetEnd->eventMouseWheel = newDelegate(this, &VScroll::notifyMouseWheel);
00091             }
00092             else if (*(*iter)->_getInternalData<std::string>() == "Track")
00093             {
00094                 MYGUI_DEBUG_ASSERT( ! mWidgetTrack, "widget already assigned");
00095                 mWidgetTrack = (*iter)->castType<Button>();
00096                 mWidgetTrack->eventMouseDrag = newDelegate(this, &VScroll::notifyMouseDrag);
00097                 mWidgetTrack->eventMouseButtonPressed = newDelegate(this, &VScroll::notifyMousePressed);
00098                 mWidgetTrack->eventMouseButtonReleased = newDelegate(this, &VScroll::notifyMouseReleased);
00099                 mWidgetTrack->eventMouseWheel = newDelegate(this, &VScroll::notifyMouseWheel);
00100                 mWidgetTrack->setVisible(false);
00101             }
00102             else if (*(*iter)->_getInternalData<std::string>() == "FirstPart")
00103             {
00104                 MYGUI_DEBUG_ASSERT( ! mWidgetFirstPart, "widget already assigned");
00105                 mWidgetFirstPart = (*iter)->castType<Button>();
00106                 mWidgetFirstPart->eventMouseButtonPressed = newDelegate(this, &VScroll::notifyMousePressed);
00107                 mWidgetFirstPart->eventMouseWheel = newDelegate(this, &VScroll::notifyMouseWheel);
00108             }
00109             else if (*(*iter)->_getInternalData<std::string>() == "SecondPart")
00110             {
00111                 MYGUI_DEBUG_ASSERT( ! mWidgetSecondPart, "widget already assigned");
00112                 mWidgetSecondPart = (*iter)->castType<Button>();
00113                 mWidgetSecondPart->eventMouseButtonPressed = newDelegate(this, &VScroll::notifyMousePressed);
00114                 mWidgetSecondPart->eventMouseWheel = newDelegate(this, &VScroll::notifyMouseWheel);
00115             }
00116         }
00117 
00118         // slider don't have buttons
00119         MYGUI_ASSERT(nullptr != mWidgetTrack, "Child Button Track not found in skin (Scroll must have Track)");
00120 
00121         // парсим свойства
00122         const MapString& properties = _info->getProperties();
00123         MapString::const_iterator iter = properties.find("TrackRangeMargins");
00124         if (iter != properties.end())
00125         {
00126             IntSize range = IntSize::parse(iter->second);
00127             mSkinRangeStart = range.width;
00128             mSkinRangeEnd = range.height;
00129         }
00130         else
00131         {
00132             mSkinRangeStart = 0;
00133             mSkinRangeEnd = 0;
00134         }
00135         iter = properties.find("MinTrackSize");
00136         if (iter != properties.end()) mMinTrackSize = utility::parseInt(iter->second);
00137         else mMinTrackSize = 0;
00138 
00139         iter = properties.find("MoveToClick");
00140         if (iter != properties.end()) mMoveToClick = utility::parseBool(iter->second);
00141     }
00142 
00143     void VScroll::shutdownWidgetSkin()
00144     {
00145         mWidgetStart = nullptr;
00146         mWidgetEnd = nullptr;
00147         mWidgetTrack = nullptr;
00148         mWidgetFirstPart = nullptr;
00149         mWidgetSecondPart = nullptr;
00150     }
00151 
00152     void VScroll::updateTrack()
00153     {
00154         _forcePeek(mWidgetTrack);
00155         // размер диапазана в пикселях
00156         int pos = getLineSize();
00157 
00158         // скрываем если диапазан маленький или места мало
00159         if ((mScrollRange < 2) || (pos <= mWidgetTrack->getHeight())) {
00160             mWidgetTrack->setVisible(false);
00161             if ( nullptr != mWidgetFirstPart ) mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), pos/2);
00162             if ( nullptr != mWidgetSecondPart ) mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), pos/2 + (int)mSkinRangeStart, mWidgetSecondPart->getWidth(), pos - pos/2);
00163             return;
00164         }
00165         // если скрыт то покажем
00166         if (false == mWidgetTrack->isVisible())
00167         {
00168             mWidgetTrack->setVisible(true);
00169         }
00170 
00171         // и обновляем позицию
00172         pos = (int)(((size_t)(pos-getTrackSize()) * mScrollPosition) / (mScrollRange-1) + mSkinRangeStart);
00173 
00174         mWidgetTrack->setPosition(mWidgetTrack->getLeft(), pos);
00175         if ( nullptr != mWidgetFirstPart )
00176         {
00177             int height = pos + mWidgetTrack->getHeight()/2 - mWidgetFirstPart->getTop();
00178             mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), height);
00179         }
00180         if ( nullptr != mWidgetSecondPart )
00181         {
00182             int top = pos + mWidgetTrack->getHeight()/2;
00183             int height = mWidgetSecondPart->getHeight() + mWidgetSecondPart->getTop() - top;
00184             mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), top, mWidgetSecondPart->getWidth(), height);
00185         }
00186     }
00187 
00188     void VScroll::TrackMove(int _left, int _top)
00189     {
00190         const IntPoint& point = InputManager::getInstance().getLastLeftPressed();
00191 
00192         // расчитываем позицию виджета
00193         int start = mPreActionOffset.top + (_top - point.top);
00194         if (start < (int)mSkinRangeStart) start = (int)mSkinRangeStart;
00195         else if (start > (mCoord.height - (int)mSkinRangeEnd - mWidgetTrack->getHeight())) start = (mCoord.height - (int)mSkinRangeEnd - mWidgetTrack->getHeight());
00196         if (mWidgetTrack->getTop() != start) mWidgetTrack->setPosition(mWidgetTrack->getLeft(), start);
00197 
00198         // расчитываем положение соответствующее позиции
00199         // плюс пол позиции
00200         int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange-1) * 2);
00201         // высчитываем ближайшее значение и обновляем
00202         pos = pos * (int)(mScrollRange-1) / (getLineSize() - getTrackSize());
00203 
00204         // проверяем на выходы и изменения
00205         if (pos < 0) pos = 0;
00206         else if (pos >= (int)mScrollRange) pos = (int)mScrollRange - 1;
00207         if (pos == (int)mScrollPosition) return;
00208 
00209         mScrollPosition = pos;
00210         // отсылаем событие
00211         eventScrollChangePosition(this, (int)mScrollPosition);
00212     }
00213 
00214     void VScroll::notifyMousePressed(WidgetPtr _sender, int _left, int _top, MouseButton _id)
00215     {
00216         // диспечерезируем нажатие своих детей как свое
00217         eventMouseButtonPressed(this, _left, _top, _id);
00218 
00219         if (MouseButton::Left != _id) return;
00220 
00221         if (mMoveToClick && mWidgetTrack != _sender)
00222         {
00223             mPreActionOffset = InputManager::getInstance().getLastLeftPressed();
00224             const IntPoint& point = InputManager::getInstance().getMousePosition() - getAbsolutePosition();
00225 
00226             TrackMove(point.left, point.top);
00227 
00228         }
00229         else if (_sender == mWidgetStart)
00230         {
00231             // минимальное значение
00232             if (mScrollPosition == 0) return;
00233 
00234             // расчитываем следующее положение
00235             if (mScrollPosition > mScrollPage) mScrollPosition -= mScrollPage;
00236             else mScrollPosition = 0;
00237 
00238             // оповещаем
00239             eventScrollChangePosition(this, (int)mScrollPosition);
00240             updateTrack();
00241 
00242         }
00243         else if (_sender == mWidgetEnd)
00244         {
00245             // максимальное значение
00246             if ( (mScrollRange < 2) || (mScrollPosition >= (mScrollRange-1)) ) return;
00247 
00248             // расчитываем следующее положение
00249             if ((mScrollPosition + mScrollPage) < (mScrollRange-1)) mScrollPosition += mScrollPage;
00250             else mScrollPosition = mScrollRange - 1;
00251 
00252             // оповещаем
00253             eventScrollChangePosition(this, (int)mScrollPosition);
00254             updateTrack();
00255 
00256         }
00257         else if (_sender == mWidgetFirstPart)
00258         {
00259             // минимальное значение
00260             if (mScrollPosition == 0) return;
00261 
00262             // расчитываем следующее положение
00263             if (mScrollPosition > mScrollViewPage) mScrollPosition -= mScrollViewPage;
00264             else mScrollPosition = 0;
00265 
00266             // оповещаем
00267             eventScrollChangePosition(this, (int)mScrollPosition);
00268             updateTrack();
00269 
00270         }
00271         else if (_sender == mWidgetSecondPart)
00272         {
00273             // максимальное значение
00274             if ( (mScrollRange < 2) || (mScrollPosition >= (mScrollRange-1)) ) return;
00275 
00276             // расчитываем следующее положение
00277             if ((mScrollPosition + mScrollViewPage) < (mScrollRange-1)) mScrollPosition += mScrollViewPage;
00278             else mScrollPosition = mScrollRange - 1;
00279 
00280             // оповещаем
00281             eventScrollChangePosition(this, (int)mScrollPosition);
00282             updateTrack();
00283 
00284         }
00285         else if (_sender == mWidgetTrack)
00286         {
00287             mPreActionOffset.left = _sender->getLeft();
00288             mPreActionOffset.top = _sender->getTop();
00289         }
00290     }
00291 
00292     void VScroll::notifyMouseReleased(WidgetPtr _sender, int _left, int _top, MouseButton _id)
00293     {
00294         updateTrack();
00295     }
00296 
00297     void VScroll::notifyMouseDrag(WidgetPtr _sender, int _left, int _top)
00298     {
00299         TrackMove(_left, _top);
00300     }
00301 
00302     void VScroll::setScrollRange(size_t _range)
00303     {
00304         if (_range == mScrollRange) return;
00305         mScrollRange = _range;
00306         mScrollPosition = (mScrollPosition < mScrollRange) ? mScrollPosition : 0;
00307         updateTrack();
00308     }
00309 
00310     void VScroll::setScrollPosition(size_t _position)
00311     {
00312         if (_position == mScrollPosition) return;
00313         if (_position >= mScrollRange) _position = 0;
00314         mScrollPosition = _position;
00315         updateTrack();
00316     }
00317 
00318     void VScroll::setPosition(const IntPoint& _point)
00319     {
00320         Base::setPosition(_point);
00321     }
00322 
00323     void VScroll::setSize(const IntSize& _size)
00324     {
00325         Base::setSize(_size);
00326         // обновляем трек
00327         updateTrack();
00328     }
00329 
00330     void VScroll::setCoord(const IntCoord& _coord)
00331     {
00332         Base::setCoord(_coord);
00333         // обновляем трек
00334         updateTrack();
00335     }
00336 
00337     void VScroll::setTrackSize(int _size)
00338     {
00339         mWidgetTrack->setSize(mWidgetTrack->getWidth(), ((int)_size < (int)mMinTrackSize)? (int)mMinTrackSize : (int)_size);
00340         updateTrack();
00341     }
00342 
00343     int VScroll::getTrackSize()
00344     {
00345         return mWidgetTrack->getHeight();
00346     }
00347 
00348     int VScroll::getLineSize()
00349     {
00350         return mCoord.height - (int)(mSkinRangeStart + mSkinRangeEnd);
00351     }
00352 
00353     void VScroll::onMouseWheel(int _rel)
00354     {
00355         notifyMouseWheel(nullptr, _rel);
00356 
00357         Base::onMouseWheel(_rel);
00358     }
00359 
00360     void VScroll::notifyMouseWheel(WidgetPtr _sender, int _rel)
00361     {
00362         if (mScrollRange < 2) return;
00363 
00364         int offset = mScrollPosition;
00365         if (_rel < 0) offset += SCROLL_MOUSE_WHEEL;
00366         else offset -= SCROLL_MOUSE_WHEEL;
00367 
00368         if (offset < 0) offset = 0;
00369         else if (offset > (int)(mScrollRange - 1)) offset = mScrollRange - 1;
00370 
00371         if ((size_t)offset != mScrollPosition) {
00372             mScrollPosition = offset;
00373             // оповещаем
00374             eventScrollChangePosition(this, (int)mScrollPosition);
00375             updateTrack();
00376         }
00377     }
00378 
00379     void VScroll::setProperty(const std::string& _key, const std::string& _value)
00380     {
00381         if (_key == "Scroll_Range") setScrollRange(utility::parseValue<size_t>(_value));
00382         else if (_key == "Scroll_Position") setScrollPosition(utility::parseValue<size_t>(_value));
00383         else if (_key == "Scroll_Page") setScrollPage(utility::parseValue<size_t>(_value));
00384         else if (_key == "Scroll_ViewPage") setScrollViewPage(utility::parseValue<size_t>(_value));
00385         else if (_key == "Scroll_MoveToClick") setMoveToClick(utility::parseValue<bool>(_value));
00386         else Base::setProperty(_key, _value);
00387     }
00388 
00389 } // namespace MyGUI

Generated on Sun Jan 30 2011 for MyGUI by  doxygen 1.7.1