MyGUI  3.2.0
MyGUI_ScrollBar.cpp
Go to the documentation of this file.
00001 
00006 /*
00007     This file is part of MyGUI.
00008 
00009     MyGUI is free software: you can redistribute it and/or modify
00010     it under the terms of the GNU Lesser General Public License as published by
00011     the Free Software Foundation, either version 3 of the License, or
00012     (at your option) any later version.
00013 
00014     MyGUI is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00021 */
00022 #include "MyGUI_Precompiled.h"
00023 #include "MyGUI_ScrollBar.h"
00024 #include "MyGUI_InputManager.h"
00025 #include "MyGUI_Button.h"
00026 #include "MyGUI_ResourceSkin.h"
00027 
00028 namespace MyGUI
00029 {
00030 
00031     // FIXME - move to widget property
00032     const int SCROLL_MOUSE_WHEEL = 50; // колличество пикселей для колеса мыши
00033 
00034     ScrollBar::ScrollBar() :
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         mVerticalAlignment(true)
00049     {
00050     }
00051 
00052     void ScrollBar::initialiseOverride()
00053     {
00054         Base::initialiseOverride();
00055 
00056         // при нуле, будет игнорировать кнопки
00057         mScrollPage = 1;
00058         mScrollViewPage = 1;
00059         mMinTrackSize = 0;
00060         mSkinRangeStart = 0;
00061         mSkinRangeEnd = 0;
00062 
00063         assignWidget(mWidgetStart, "Start");
00064         if (mWidgetStart != nullptr)
00065         {
00066             mWidgetStart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
00067             mWidgetStart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
00068         }
00069 
00070         assignWidget(mWidgetEnd, "End");
00071         if (mWidgetEnd != nullptr)
00072         {
00073             mWidgetEnd->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
00074             mWidgetEnd->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
00075         }
00076 
00077         assignWidget(mWidgetTrack, "Track");
00078         if (mWidgetTrack)
00079         {
00080             mWidgetTrack->eventMouseDrag += newDelegate(this, &ScrollBar::notifyMouseDrag);
00081             mWidgetTrack->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
00082             mWidgetTrack->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
00083             mWidgetTrack->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
00084             mWidgetTrack->setVisible(false);
00085         }
00086 
00087         assignWidget(mWidgetFirstPart, "FirstPart");
00088         if (mWidgetFirstPart != nullptr)
00089         {
00090             mWidgetFirstPart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
00091             mWidgetFirstPart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
00092         }
00093 
00094         assignWidget(mWidgetSecondPart, "SecondPart");
00095         if (mWidgetSecondPart != nullptr)
00096         {
00097             mWidgetSecondPart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
00098             mWidgetSecondPart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
00099         }
00100 
00101         if (isUserString("MinTrackSize"))
00102             mMinTrackSize = utility::parseValue<int>(getUserString("MinTrackSize"));
00103         if (isUserString("TrackRangeMargins"))
00104             utility::parseComplex<size_t>(getUserString("TrackRangeMargins"), mSkinRangeStart, mSkinRangeEnd);
00105 
00106         if (mWidgetTrack != nullptr)
00107         {
00108             if (mWidgetTrack->isUserString("MinTrackSize"))
00109                 mMinTrackSize = utility::parseValue<int>(mWidgetTrack->getUserString("MinTrackSize"));
00110         }
00111     }
00112 
00113     void ScrollBar::shutdownOverride()
00114     {
00115         mWidgetStart = nullptr;
00116         mWidgetEnd = nullptr;
00117         mWidgetTrack = nullptr;
00118         mWidgetFirstPart = nullptr;
00119         mWidgetSecondPart = nullptr;
00120 
00121         Base::shutdownOverride();
00122     }
00123 
00124     void ScrollBar::updateTrack()
00125     {
00126         if (mWidgetTrack == nullptr)
00127             return;
00128 
00129         _forcePick(mWidgetTrack);
00130         // размер диапазана в пикселях
00131         int pos = getLineSize();
00132 
00133         if (mVerticalAlignment)
00134         {
00135             // скрываем если диапазан маленький или места мало
00136             if ((mScrollRange < 2) || (pos <= mWidgetTrack->getHeight()))
00137             {
00138                 mWidgetTrack->setVisible(false);
00139                 if (nullptr != mWidgetFirstPart)
00140                     mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), pos / 2);
00141                 if (nullptr != mWidgetSecondPart)
00142                     mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), pos / 2 + (int)mSkinRangeStart, mWidgetSecondPart->getWidth(), pos - pos / 2);
00143                 return;
00144             }
00145             // если скрыт то покажем
00146             if (!mWidgetTrack->getVisible())
00147                 mWidgetTrack->setVisible(true);
00148 
00149             // и обновляем позицию
00150             pos = (int)(((size_t)(pos - getTrackSize()) * mScrollPosition) / (mScrollRange - 1) + mSkinRangeStart);
00151 
00152             mWidgetTrack->setPosition(mWidgetTrack->getLeft(), pos);
00153             if (nullptr != mWidgetFirstPart)
00154             {
00155                 int height = pos - mWidgetFirstPart->getTop();
00156                 mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), height);
00157             }
00158             if (nullptr != mWidgetSecondPart)
00159             {
00160                 int top = pos + mWidgetTrack->getHeight();
00161                 int height = mWidgetSecondPart->getHeight() + mWidgetSecondPart->getTop() - top;
00162                 mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), top, mWidgetSecondPart->getWidth(), height);
00163             }
00164         }
00165         else
00166         {
00167             // скрываем если диапазан маленький или места мало
00168             if ((mScrollRange < 2) || (pos <= mWidgetTrack->getWidth()))
00169             {
00170                 mWidgetTrack->setVisible(false);
00171                 if (nullptr != mWidgetFirstPart)
00172                     mWidgetFirstPart->setSize(pos / 2, mWidgetFirstPart->getHeight());
00173                 if (nullptr != mWidgetSecondPart)
00174                     mWidgetSecondPart->setCoord(pos / 2 + (int)mSkinRangeStart, mWidgetSecondPart->getTop(), pos - pos / 2, mWidgetSecondPart->getHeight());
00175                 return;
00176             }
00177             // если скрыт то покажем
00178             if (!mWidgetTrack->getVisible())
00179                 mWidgetTrack->setVisible(true);
00180 
00181             // и обновляем позицию
00182             pos = (int)(((size_t)(pos - getTrackSize()) * mScrollPosition) / (mScrollRange - 1) + mSkinRangeStart);
00183 
00184             mWidgetTrack->setPosition(pos, mWidgetTrack->getTop());
00185             if (nullptr != mWidgetFirstPart)
00186             {
00187                 int height = pos - mWidgetFirstPart->getLeft();
00188                 mWidgetFirstPart->setSize(height, mWidgetFirstPart->getHeight());
00189             }
00190             if (nullptr != mWidgetSecondPart)
00191             {
00192                 int top = pos + mWidgetTrack->getWidth();
00193                 int height = mWidgetSecondPart->getWidth() + mWidgetSecondPart->getLeft() - top;
00194                 mWidgetSecondPart->setCoord(top, mWidgetSecondPart->getTop(), height, mWidgetSecondPart->getHeight());
00195             }
00196         }
00197     }
00198 
00199     void ScrollBar::TrackMove(int _left, int _top)
00200     {
00201         if (mWidgetTrack == nullptr)
00202             return;
00203 
00204         const IntPoint& point = InputManager::getInstance().getLastPressedPosition(MouseButton::Left);
00205 
00206         if (mVerticalAlignment)
00207         {
00208             // расчитываем позицию виджета
00209             int start = mPreActionOffset.top + (_top - point.top);
00210             if (start < (int)mSkinRangeStart)
00211                 start = (int)mSkinRangeStart;
00212             else if (start > (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getHeight()))
00213                 start = (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getHeight());
00214             if (mWidgetTrack->getTop() != start)
00215                 mWidgetTrack->setPosition(mWidgetTrack->getLeft(), start);
00216 
00217             // расчитываем положение соответствующее позиции
00218             // плюс пол позиции
00219             int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange - 1) * 2);
00220             // высчитываем ближайшее значение и обновляем
00221             pos = pos * (int)(mScrollRange - 1) / (getLineSize() - getTrackSize());
00222 
00223             // проверяем на выходы и изменения
00224             if (pos < 0)
00225                 pos = 0;
00226             else if (pos >= (int)mScrollRange)
00227                 pos = (int)mScrollRange - 1;
00228             if (pos == (int)mScrollPosition)
00229                 return;
00230 
00231             mScrollPosition = pos;
00232         }
00233         else
00234         {
00235             // расчитываем позицию виджета
00236             int start = mPreActionOffset.left + (_left - point.left);
00237             if (start < (int)mSkinRangeStart)
00238                 start = (int)mSkinRangeStart;
00239             else if (start > (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getWidth()))
00240                 start = (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getWidth());
00241             if (mWidgetTrack->getLeft() != start)
00242                 mWidgetTrack->setPosition(IntPoint(start, mWidgetTrack->getTop()));
00243 
00244             // расчитываем положение соответствующее позиции
00245             // плюс пол позиции
00246             int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange - 1) * 2);
00247             // высчитываем ближайшее значение и обновляем
00248             pos = pos * (int)(mScrollRange - 1) / (getLineSize() - getTrackSize());
00249 
00250             // проверяем на выходы и изменения
00251             if (pos < 0)
00252                 pos = 0;
00253             else if (pos >= (int)mScrollRange)
00254                 pos = (int)mScrollRange - 1;
00255             if (pos == (int)mScrollPosition)
00256                 return;
00257 
00258             mScrollPosition = pos;
00259         }
00260 
00261         updateTrack();
00262 
00263         // отсылаем событие
00264         eventScrollChangePosition(this, (int)mScrollPosition);
00265     }
00266 
00267     void ScrollBar::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
00268     {
00269         // диспечерезируем нажатие своих детей как свое
00270         eventMouseButtonPressed(this, _left, _top, _id);
00271 
00272         if (MouseButton::Left != _id)
00273             return;
00274 
00275         if (mMoveToClick &&
00276             _sender != mWidgetTrack &&
00277             _sender != mWidgetStart &&
00278             _sender != mWidgetEnd)
00279         {
00280             if (mWidgetTrack != nullptr)
00281             {
00282                 mPreActionOffset = InputManager::getInstance().getLastPressedPosition(MouseButton::Left);
00283                 const IntPoint& point = InputManager::getInstance().getMousePositionByLayer() - mWidgetTrack->getParent()->getAbsolutePosition();
00284 
00285                 mPreActionOffset.left -= getTrackSize() / 2;
00286                 mPreActionOffset.top -= getTrackSize() / 2;
00287 
00288                 TrackMove(point.left, point.top);
00289             }
00290         }
00291         else if (_sender == mWidgetStart)
00292         {
00293             // минимальное значение
00294             if (mScrollPosition == 0)
00295                 return;
00296 
00297             // расчитываем следующее положение
00298             if (mScrollPosition > mScrollPage)
00299                 mScrollPosition -= mScrollPage;
00300             else
00301                 mScrollPosition = 0;
00302 
00303             // оповещаем
00304             eventScrollChangePosition(this, (int)mScrollPosition);
00305             updateTrack();
00306         }
00307         else if (_sender == mWidgetEnd)
00308         {
00309             // максимальное значение
00310             if ((mScrollRange < 2) || (mScrollPosition >= (mScrollRange - 1)))
00311                 return;
00312 
00313             // расчитываем следующее положение
00314             if ((mScrollPosition + mScrollPage) < (mScrollRange - 1))
00315                 mScrollPosition += mScrollPage;
00316             else
00317                 mScrollPosition = mScrollRange - 1;
00318 
00319             // оповещаем
00320             eventScrollChangePosition(this, (int)mScrollPosition);
00321             updateTrack();
00322         }
00323         else if (_sender == mWidgetFirstPart)
00324         {
00325             // минимальное значение
00326             if (mScrollPosition == 0)
00327                 return;
00328 
00329             // расчитываем следующее положение
00330             if (mScrollPosition > mScrollViewPage)
00331                 mScrollPosition -= mScrollViewPage;
00332             else
00333                 mScrollPosition = 0;
00334 
00335             // оповещаем
00336             eventScrollChangePosition(this, (int)mScrollPosition);
00337             updateTrack();
00338         }
00339         else if (_sender == mWidgetSecondPart)
00340         {
00341             // максимальное значение
00342             if ((mScrollRange < 2) || (mScrollPosition >= (mScrollRange - 1)))
00343                 return;
00344 
00345             // расчитываем следующее положение
00346             if ((mScrollPosition + mScrollViewPage) < (mScrollRange - 1))
00347                 mScrollPosition += mScrollViewPage;
00348             else
00349                 mScrollPosition = mScrollRange - 1;
00350 
00351             // оповещаем
00352             eventScrollChangePosition(this, (int)mScrollPosition);
00353             updateTrack();
00354         }
00355         else if (_sender == mWidgetTrack)
00356         {
00357             mPreActionOffset.left = _sender->getLeft();
00358             mPreActionOffset.top = _sender->getTop();
00359         }
00360     }
00361 
00362     void ScrollBar::notifyMouseReleased(Widget* _sender, int _left, int _top, MouseButton _id)
00363     {
00364         updateTrack();
00365     }
00366 
00367     void ScrollBar::notifyMouseDrag(Widget* _sender, int _left, int _top, MouseButton _id)
00368     {
00369         if (_id == MouseButton::Left)
00370             TrackMove(_left, _top);
00371     }
00372 
00373     void ScrollBar::setScrollRange(size_t _range)
00374     {
00375         if (_range == mScrollRange)
00376             return;
00377 
00378         mScrollRange = _range;
00379         mScrollPosition = (mScrollPosition < mScrollRange) ? mScrollPosition : 0;
00380         updateTrack();
00381     }
00382 
00383     void ScrollBar::setScrollPosition(size_t _position)
00384     {
00385         if (_position == mScrollPosition)
00386             return;
00387 
00388         if (_position >= mScrollRange)
00389             _position = 0;
00390 
00391         mScrollPosition = _position;
00392         updateTrack();
00393     }
00394 
00395     void ScrollBar::setPosition(const IntPoint& _point)
00396     {
00397         Base::setPosition(_point);
00398     }
00399 
00400     void ScrollBar::setSize(const IntSize& _size)
00401     {
00402         Base::setSize(_size);
00403         // обновляем трек
00404         updateTrack();
00405     }
00406 
00407     void ScrollBar::setCoord(const IntCoord& _coord)
00408     {
00409         Base::setCoord(_coord);
00410         // обновляем трек
00411         updateTrack();
00412     }
00413 
00414     void ScrollBar::setTrackSize(int _size)
00415     {
00416         if (mWidgetTrack != nullptr)
00417         {
00418             if (mVerticalAlignment)
00419                 mWidgetTrack->setSize(mWidgetTrack->getWidth(), ((int)_size < (int)mMinTrackSize) ? (int)mMinTrackSize : (int)_size);
00420             else
00421                 mWidgetTrack->setSize(((int)_size < (int)mMinTrackSize) ? (int)mMinTrackSize : (int)_size, mWidgetTrack->getHeight());
00422         }
00423 
00424         updateTrack();
00425     }
00426 
00427     int ScrollBar::getTrackSize() const
00428     {
00429         if (mWidgetTrack != nullptr)
00430         {
00431             if (mVerticalAlignment)
00432                 return mWidgetTrack->getHeight();
00433             else
00434                 return mWidgetTrack->getWidth();
00435         }
00436         return 1;
00437     }
00438 
00439     int ScrollBar::getLineSize() const
00440     {
00441         return getTrackPlaceLength() - (int)(mSkinRangeStart + mSkinRangeEnd);
00442     }
00443 
00444     void ScrollBar::onMouseWheel(int _rel)
00445     {
00446         notifyMouseWheel(nullptr, _rel);
00447 
00448         Base::onMouseWheel(_rel);
00449     }
00450 
00451     void ScrollBar::notifyMouseWheel(Widget* _sender, int _rel)
00452     {
00453         if (mScrollRange < 2)
00454             return;
00455 
00456         int offset = mScrollPosition;
00457         if (_rel < 0)
00458             offset += SCROLL_MOUSE_WHEEL;
00459         else
00460             offset -= SCROLL_MOUSE_WHEEL;
00461 
00462         if (offset < 0)
00463             offset = 0;
00464         else if (offset > (int)(mScrollRange - 1))
00465             offset = mScrollRange - 1;
00466 
00467         if ((size_t)offset != mScrollPosition)
00468         {
00469             mScrollPosition = offset;
00470             // оповещаем
00471             eventScrollChangePosition(this, (int)mScrollPosition);
00472             updateTrack();
00473         }
00474     }
00475 
00476     void ScrollBar::setPropertyOverride(const std::string& _key, const std::string& _value)
00477     {
00478         if (_key == "Range")
00479             setScrollRange(utility::parseValue<size_t>(_value));
00480         else if (_key == "RangePosition")
00481             setScrollPosition(utility::parseValue<size_t>(_value));
00482         else if (_key == "Page")
00483             setScrollPage(utility::parseValue<size_t>(_value));
00484         else if (_key == "ViewPage")
00485             setScrollViewPage(utility::parseValue<size_t>(_value));
00486         else if (_key == "MoveToClick")
00487             setMoveToClick(utility::parseValue<bool>(_value));
00488         else if (_key == "VerticalAlignment")
00489             setVerticalAlignment(utility::parseValue<bool>(_value));
00490         else
00491         {
00492             Base::setPropertyOverride(_key, _value);
00493             return;
00494         }
00495         eventChangeProperty(this, _key, _value);
00496     }
00497 
00498     size_t ScrollBar::getScrollRange() const
00499     {
00500         return mScrollRange;
00501     }
00502 
00503     size_t ScrollBar::getScrollPosition() const
00504     {
00505         return mScrollPosition;
00506     }
00507 
00508     void ScrollBar::setScrollPage(size_t _value)
00509     {
00510         mScrollPage = _value;
00511     }
00512 
00513     size_t ScrollBar::getScrollPage() const
00514     {
00515         return mScrollPage;
00516     }
00517 
00518     void ScrollBar::setScrollViewPage(size_t _value)
00519     {
00520         mScrollViewPage = _value;
00521     }
00522 
00523     size_t ScrollBar::getScrollViewPage() const
00524     {
00525         return mScrollViewPage;
00526     }
00527 
00528     void ScrollBar::setMinTrackSize(int _value)
00529     {
00530         mMinTrackSize = _value;
00531     }
00532 
00533     int ScrollBar::getMinTrackSize() const
00534     {
00535         return mMinTrackSize;
00536     }
00537 
00538     void ScrollBar::setMoveToClick(bool _value)
00539     {
00540         mMoveToClick = _value;
00541     }
00542 
00543     bool ScrollBar::getMoveToClick() const
00544     {
00545         return mMoveToClick;
00546     }
00547 
00548     void ScrollBar::setPosition(int _left, int _top)
00549     {
00550         setPosition(IntPoint(_left, _top));
00551     }
00552 
00553     void ScrollBar::setSize(int _width, int _height)
00554     {
00555         setSize(IntSize(_width, _height));
00556     }
00557 
00558     void ScrollBar::setCoord(int _left, int _top, int _width, int _height)
00559     {
00560         setCoord(IntCoord(_left, _top, _width, _height));
00561     }
00562 
00563     int ScrollBar::getTrackPlaceLength() const
00564     {
00565         if (mWidgetTrack != nullptr)
00566         {
00567             if (mVerticalAlignment)
00568                 return mWidgetTrack->getParent()->getHeight();
00569             else
00570                 return mWidgetTrack->getParent()->getWidth();
00571         }
00572         return 0;
00573     }
00574 
00575     void ScrollBar::setVerticalAlignment(bool _value)
00576     {
00577         mVerticalAlignment = _value;
00578 
00579         updateTrack();
00580     }
00581 
00582     bool ScrollBar::getVerticalAlignment() const
00583     {
00584         return mVerticalAlignment;
00585     }
00586 
00587 } // namespace MyGUI