MyGUI
3.0.3
|
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, Widget* _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 if (mWidgetTrack == nullptr) 00155 return; 00156 00157 _forcePeek(mWidgetTrack); 00158 // размер диапазана в пикселях 00159 int pos = getLineSize(); 00160 00161 // скрываем если диапазан маленький или места мало 00162 if ((mScrollRange < 2) || (pos <= mWidgetTrack->getHeight())) 00163 { 00164 mWidgetTrack->setVisible(false); 00165 if ( nullptr != mWidgetFirstPart ) mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), pos/2); 00166 if ( nullptr != mWidgetSecondPart ) mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), pos/2 + (int)mSkinRangeStart, mWidgetSecondPart->getWidth(), pos - pos/2); 00167 return; 00168 } 00169 // если скрыт то покажем 00170 if (!mWidgetTrack->isVisible()) 00171 { 00172 mWidgetTrack->setVisible(true); 00173 } 00174 00175 // и обновляем позицию 00176 pos = (int)(((size_t)(pos-getTrackSize()) * mScrollPosition) / (mScrollRange-1) + mSkinRangeStart); 00177 00178 mWidgetTrack->setPosition(mWidgetTrack->getLeft(), pos); 00179 if ( nullptr != mWidgetFirstPart ) 00180 { 00181 int height = pos + mWidgetTrack->getHeight()/2 - mWidgetFirstPart->getTop(); 00182 mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), height); 00183 } 00184 if ( nullptr != mWidgetSecondPart ) 00185 { 00186 int top = pos + mWidgetTrack->getHeight()/2; 00187 int height = mWidgetSecondPart->getHeight() + mWidgetSecondPart->getTop() - top; 00188 mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), top, mWidgetSecondPart->getWidth(), height); 00189 } 00190 } 00191 00192 void VScroll::TrackMove(int _left, int _top) 00193 { 00194 if (mWidgetTrack == nullptr) 00195 return; 00196 00197 const IntPoint& point = InputManager::getInstance().getLastLeftPressed(); 00198 00199 // расчитываем позицию виджета 00200 int start = mPreActionOffset.top + (_top - point.top); 00201 if (start < (int)mSkinRangeStart) start = (int)mSkinRangeStart; 00202 else if (start > (mCoord.height - (int)mSkinRangeEnd - mWidgetTrack->getHeight())) start = (mCoord.height - (int)mSkinRangeEnd - mWidgetTrack->getHeight()); 00203 if (mWidgetTrack->getTop() != start) mWidgetTrack->setPosition(mWidgetTrack->getLeft(), start); 00204 00205 // расчитываем положение соответствующее позиции 00206 // плюс пол позиции 00207 int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange-1) * 2); 00208 // высчитываем ближайшее значение и обновляем 00209 pos = pos * (int)(mScrollRange-1) / (getLineSize() - getTrackSize()); 00210 00211 // проверяем на выходы и изменения 00212 if (pos < 0) pos = 0; 00213 else if (pos >= (int)mScrollRange) pos = (int)mScrollRange - 1; 00214 if (pos == (int)mScrollPosition) return; 00215 00216 mScrollPosition = pos; 00217 // отсылаем событие 00218 eventScrollChangePosition(this, (int)mScrollPosition); 00219 } 00220 00221 void VScroll::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id) 00222 { 00223 // диспечерезируем нажатие своих детей как свое 00224 eventMouseButtonPressed(this, _left, _top, _id); 00225 00226 if (MouseButton::Left != _id) return; 00227 00228 if (mMoveToClick && mWidgetTrack != _sender) 00229 { 00230 mPreActionOffset = InputManager::getInstance().getLastLeftPressed(); 00231 const IntPoint& point = InputManager::getInstance().getMousePositionByLayer() - getAbsolutePosition(); 00232 00233 TrackMove(point.left, point.top); 00234 00235 } 00236 else if (_sender == mWidgetStart) 00237 { 00238 // минимальное значение 00239 if (mScrollPosition == 0) return; 00240 00241 // расчитываем следующее положение 00242 if (mScrollPosition > mScrollPage) mScrollPosition -= mScrollPage; 00243 else mScrollPosition = 0; 00244 00245 // оповещаем 00246 eventScrollChangePosition(this, (int)mScrollPosition); 00247 updateTrack(); 00248 00249 } 00250 else if (_sender == mWidgetEnd) 00251 { 00252 // максимальное значение 00253 if ( (mScrollRange < 2) || (mScrollPosition >= (mScrollRange-1)) ) return; 00254 00255 // расчитываем следующее положение 00256 if ((mScrollPosition + mScrollPage) < (mScrollRange-1)) mScrollPosition += mScrollPage; 00257 else mScrollPosition = mScrollRange - 1; 00258 00259 // оповещаем 00260 eventScrollChangePosition(this, (int)mScrollPosition); 00261 updateTrack(); 00262 00263 } 00264 else if (_sender == mWidgetFirstPart) 00265 { 00266 // минимальное значение 00267 if (mScrollPosition == 0) return; 00268 00269 // расчитываем следующее положение 00270 if (mScrollPosition > mScrollViewPage) mScrollPosition -= mScrollViewPage; 00271 else mScrollPosition = 0; 00272 00273 // оповещаем 00274 eventScrollChangePosition(this, (int)mScrollPosition); 00275 updateTrack(); 00276 00277 } 00278 else if (_sender == mWidgetSecondPart) 00279 { 00280 // максимальное значение 00281 if ( (mScrollRange < 2) || (mScrollPosition >= (mScrollRange-1)) ) return; 00282 00283 // расчитываем следующее положение 00284 if ((mScrollPosition + mScrollViewPage) < (mScrollRange-1)) mScrollPosition += mScrollViewPage; 00285 else mScrollPosition = mScrollRange - 1; 00286 00287 // оповещаем 00288 eventScrollChangePosition(this, (int)mScrollPosition); 00289 updateTrack(); 00290 00291 } 00292 else if (_sender == mWidgetTrack) 00293 { 00294 mPreActionOffset.left = _sender->getLeft(); 00295 mPreActionOffset.top = _sender->getTop(); 00296 } 00297 } 00298 00299 void VScroll::notifyMouseReleased(Widget* _sender, int _left, int _top, MouseButton _id) 00300 { 00301 updateTrack(); 00302 } 00303 00304 void VScroll::notifyMouseDrag(Widget* _sender, int _left, int _top) 00305 { 00306 TrackMove(_left, _top); 00307 } 00308 00309 void VScroll::setScrollRange(size_t _range) 00310 { 00311 if (_range == mScrollRange) return; 00312 mScrollRange = _range; 00313 mScrollPosition = (mScrollPosition < mScrollRange) ? mScrollPosition : 0; 00314 updateTrack(); 00315 } 00316 00317 void VScroll::setScrollPosition(size_t _position) 00318 { 00319 if (_position == mScrollPosition) return; 00320 if (_position >= mScrollRange) _position = 0; 00321 mScrollPosition = _position; 00322 updateTrack(); 00323 } 00324 00325 void VScroll::setPosition(const IntPoint& _point) 00326 { 00327 Base::setPosition(_point); 00328 } 00329 00330 void VScroll::setSize(const IntSize& _size) 00331 { 00332 Base::setSize(_size); 00333 // обновляем трек 00334 updateTrack(); 00335 } 00336 00337 void VScroll::setCoord(const IntCoord& _coord) 00338 { 00339 Base::setCoord(_coord); 00340 // обновляем трек 00341 updateTrack(); 00342 } 00343 00344 void VScroll::setTrackSize(int _size) 00345 { 00346 if (mWidgetTrack != nullptr) 00347 mWidgetTrack->setSize(mWidgetTrack->getWidth(), ((int)_size < (int)mMinTrackSize)? (int)mMinTrackSize : (int)_size); 00348 updateTrack(); 00349 } 00350 00351 int VScroll::getTrackSize() 00352 { 00353 return mWidgetTrack == nullptr ? 1 : mWidgetTrack->getHeight(); 00354 } 00355 00356 int VScroll::getLineSize() 00357 { 00358 return mCoord.height - (int)(mSkinRangeStart + mSkinRangeEnd); 00359 } 00360 00361 void VScroll::onMouseWheel(int _rel) 00362 { 00363 notifyMouseWheel(nullptr, _rel); 00364 00365 Base::onMouseWheel(_rel); 00366 } 00367 00368 void VScroll::notifyMouseWheel(Widget* _sender, int _rel) 00369 { 00370 if (mScrollRange < 2) return; 00371 00372 int offset = mScrollPosition; 00373 if (_rel < 0) offset += SCROLL_MOUSE_WHEEL; 00374 else offset -= SCROLL_MOUSE_WHEEL; 00375 00376 if (offset < 0) offset = 0; 00377 else if (offset > (int)(mScrollRange - 1)) offset = mScrollRange - 1; 00378 00379 if ((size_t)offset != mScrollPosition) 00380 { 00381 mScrollPosition = offset; 00382 // оповещаем 00383 eventScrollChangePosition(this, (int)mScrollPosition); 00384 updateTrack(); 00385 } 00386 } 00387 00388 void VScroll::setProperty(const std::string& _key, const std::string& _value) 00389 { 00390 if (_key == "Scroll_Range") setScrollRange(utility::parseValue<size_t>(_value)); 00391 else if (_key == "Scroll_Position") setScrollPosition(utility::parseValue<size_t>(_value)); 00392 else if (_key == "Scroll_Page") setScrollPage(utility::parseValue<size_t>(_value)); 00393 else if (_key == "Scroll_ViewPage") setScrollViewPage(utility::parseValue<size_t>(_value)); 00394 else if (_key == "Scroll_MoveToClick") setMoveToClick(utility::parseValue<bool>(_value)); 00395 else 00396 { 00397 Base::setProperty(_key, _value); 00398 return; 00399 } 00400 eventChangeProperty(this, _key, _value); 00401 } 00402 00403 } // namespace MyGUI