MyGUI
3.2.0
|
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