MyGUI  3.0.1
MyGUI_VScroll.cpp
Go to the documentation of this file.
1 
7 /*
8  This file is part of MyGUI.
9 
10  MyGUI is free software: you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  MyGUI is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with MyGUI. If not, see <http://www.gnu.org/licenses/>.
22 */
23 #include "MyGUI_Precompiled.h"
24 #include "MyGUI_VScroll.h"
25 #include "MyGUI_InputManager.h"
26 #include "MyGUI_Button.h"
27 #include "MyGUI_ResourceSkin.h"
28 
29 namespace MyGUI
30 {
31 
32  const int SCROLL_MOUSE_WHEEL = 50; // колличество пикселей для колеса мыши
33 
35  mWidgetStart(nullptr),
36  mWidgetEnd(nullptr),
37  mWidgetTrack(nullptr),
38  mWidgetFirstPart(nullptr),
39  mWidgetSecondPart(nullptr),
40  mSkinRangeStart(0),
41  mSkinRangeEnd(0),
42  mScrollRange(0),
43  mScrollPosition(0),
44  mScrollPage(0),
45  mScrollViewPage(0),
46  mMinTrackSize(0),
47  mMoveToClick(false)
48  {
49  }
50 
51  void VScroll::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
52  {
53  Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
54 
55  initialiseWidgetSkin(_info);
56  }
57 
59  {
60  shutdownWidgetSkin();
61  }
62 
64  {
65  shutdownWidgetSkin();
67  initialiseWidgetSkin(_info);
68  }
69 
70  void VScroll::initialiseWidgetSkin(ResourceSkin* _info)
71  {
72  // при нуле, будет игнорировать кнопки
73  mScrollPage = 1;
74  mScrollViewPage = 1;
75 
76  for (VectorWidgetPtr::iterator iter = mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
77  {
78  if (*(*iter)->_getInternalData<std::string>() == "Start")
79  {
80  MYGUI_DEBUG_ASSERT( ! mWidgetStart, "widget already assigned");
81  mWidgetStart = (*iter)->castType<Button>();
84  }
85  else if (*(*iter)->_getInternalData<std::string>() == "End")
86  {
87  MYGUI_DEBUG_ASSERT( ! mWidgetEnd, "widget already assigned");
88  mWidgetEnd = (*iter)->castType<Button>();
91  }
92  else if (*(*iter)->_getInternalData<std::string>() == "Track")
93  {
94  MYGUI_DEBUG_ASSERT( ! mWidgetTrack, "widget already assigned");
95  mWidgetTrack = (*iter)->castType<Button>();
100  mWidgetTrack->setVisible(false);
101  }
102  else if (*(*iter)->_getInternalData<std::string>() == "FirstPart")
103  {
104  MYGUI_DEBUG_ASSERT( ! mWidgetFirstPart, "widget already assigned");
105  mWidgetFirstPart = (*iter)->castType<Button>();
108  }
109  else if (*(*iter)->_getInternalData<std::string>() == "SecondPart")
110  {
111  MYGUI_DEBUG_ASSERT( ! mWidgetSecondPart, "widget already assigned");
112  mWidgetSecondPart = (*iter)->castType<Button>();
115  }
116  }
117 
118  // slider don't have buttons
119  //MYGUI_ASSERT(nullptr != mWidgetTrack, "Child Button Track not found in skin (Scroll must have Track)");
120 
121  // парсим свойства
122  const MapString& properties = _info->getProperties();
123  MapString::const_iterator iter = properties.find("TrackRangeMargins");
124  if (iter != properties.end())
125  {
126  IntSize range = IntSize::parse(iter->second);
127  mSkinRangeStart = range.width;
128  mSkinRangeEnd = range.height;
129  }
130  else
131  {
132  mSkinRangeStart = 0;
133  mSkinRangeEnd = 0;
134  }
135  iter = properties.find("MinTrackSize");
136  if (iter != properties.end()) mMinTrackSize = utility::parseInt(iter->second);
137  else mMinTrackSize = 0;
138 
139  iter = properties.find("MoveToClick");
140  if (iter != properties.end()) mMoveToClick = utility::parseBool(iter->second);
141  }
142 
143  void VScroll::shutdownWidgetSkin()
144  {
145  mWidgetStart = nullptr;
146  mWidgetEnd = nullptr;
147  mWidgetTrack = nullptr;
148  mWidgetFirstPart = nullptr;
149  mWidgetSecondPart = nullptr;
150  }
151 
153  {
154  if (mWidgetTrack == nullptr)
155  return;
156 
158  // размер диапазана в пикселях
159  int pos = getLineSize();
160 
161  // скрываем если диапазан маленький или места мало
162  if ((mScrollRange < 2) || (pos <= mWidgetTrack->getHeight()))
163  {
164  mWidgetTrack->setVisible(false);
165  if ( nullptr != mWidgetFirstPart ) mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), pos/2);
167  return;
168  }
169  // если скрыт то покажем
170  if (!mWidgetTrack->isVisible())
171  {
172  mWidgetTrack->setVisible(true);
173  }
174 
175  // и обновляем позицию
176  pos = (int)(((size_t)(pos-getTrackSize()) * mScrollPosition) / (mScrollRange-1) + mSkinRangeStart);
177 
179  if ( nullptr != mWidgetFirstPart )
180  {
181  int height = pos + mWidgetTrack->getHeight()/2 - mWidgetFirstPart->getTop();
183  }
184  if ( nullptr != mWidgetSecondPart )
185  {
186  int top = pos + mWidgetTrack->getHeight()/2;
187  int height = mWidgetSecondPart->getHeight() + mWidgetSecondPart->getTop() - top;
189  }
190  }
191 
192  void VScroll::TrackMove(int _left, int _top)
193  {
194  if (mWidgetTrack == nullptr)
195  return;
196 
198 
199  // расчитываем позицию виджета
200  int start = mPreActionOffset.top + (_top - point.top);
201  if (start < (int)mSkinRangeStart) start = (int)mSkinRangeStart;
202  else if (start > (mCoord.height - (int)mSkinRangeEnd - mWidgetTrack->getHeight())) start = (mCoord.height - (int)mSkinRangeEnd - mWidgetTrack->getHeight());
203  if (mWidgetTrack->getTop() != start) mWidgetTrack->setPosition(mWidgetTrack->getLeft(), start);
204 
205  // расчитываем положение соответствующее позиции
206  // плюс пол позиции
207  int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange-1) * 2);
208  // высчитываем ближайшее значение и обновляем
209  pos = pos * (int)(mScrollRange-1) / (getLineSize() - getTrackSize());
210 
211  // проверяем на выходы и изменения
212  if (pos < 0) pos = 0;
213  else if (pos >= (int)mScrollRange) pos = (int)mScrollRange - 1;
214  if (pos == (int)mScrollPosition) return;
215 
216  mScrollPosition = pos;
217  // отсылаем событие
219  }
220 
221  void VScroll::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
222  {
223  // диспечерезируем нажатие своих детей как свое
224  eventMouseButtonPressed(this, _left, _top, _id);
225 
226  if (MouseButton::Left != _id) return;
227 
228  if (mMoveToClick && mWidgetTrack != _sender)
229  {
232 
233  TrackMove(point.left, point.top);
234 
235  }
236  else if (_sender == mWidgetStart)
237  {
238  // минимальное значение
239  if (mScrollPosition == 0) return;
240 
241  // расчитываем следующее положение
243  else mScrollPosition = 0;
244 
245  // оповещаем
247  updateTrack();
248 
249  }
250  else if (_sender == mWidgetEnd)
251  {
252  // максимальное значение
253  if ( (mScrollRange < 2) || (mScrollPosition >= (mScrollRange-1)) ) return;
254 
255  // расчитываем следующее положение
257  else mScrollPosition = mScrollRange - 1;
258 
259  // оповещаем
261  updateTrack();
262 
263  }
264  else if (_sender == mWidgetFirstPart)
265  {
266  // минимальное значение
267  if (mScrollPosition == 0) return;
268 
269  // расчитываем следующее положение
271  else mScrollPosition = 0;
272 
273  // оповещаем
275  updateTrack();
276 
277  }
278  else if (_sender == mWidgetSecondPart)
279  {
280  // максимальное значение
281  if ( (mScrollRange < 2) || (mScrollPosition >= (mScrollRange-1)) ) return;
282 
283  // расчитываем следующее положение
285  else mScrollPosition = mScrollRange - 1;
286 
287  // оповещаем
289  updateTrack();
290 
291  }
292  else if (_sender == mWidgetTrack)
293  {
294  mPreActionOffset.left = _sender->getLeft();
295  mPreActionOffset.top = _sender->getTop();
296  }
297  }
298 
299  void VScroll::notifyMouseReleased(Widget* _sender, int _left, int _top, MouseButton _id)
300  {
301  updateTrack();
302  }
303 
304  void VScroll::notifyMouseDrag(Widget* _sender, int _left, int _top)
305  {
306  TrackMove(_left, _top);
307  }
308 
309  void VScroll::setScrollRange(size_t _range)
310  {
311  if (_range == mScrollRange) return;
312  mScrollRange = _range;
314  updateTrack();
315  }
316 
317  void VScroll::setScrollPosition(size_t _position)
318  {
319  if (_position == mScrollPosition) return;
320  if (_position >= mScrollRange) _position = 0;
321  mScrollPosition = _position;
322  updateTrack();
323  }
324 
325  void VScroll::setPosition(const IntPoint& _point)
326  {
327  Base::setPosition(_point);
328  }
329 
330  void VScroll::setSize(const IntSize& _size)
331  {
332  Base::setSize(_size);
333  // обновляем трек
334  updateTrack();
335  }
336 
337  void VScroll::setCoord(const IntCoord& _coord)
338  {
339  Base::setCoord(_coord);
340  // обновляем трек
341  updateTrack();
342  }
343 
344  void VScroll::setTrackSize(int _size)
345  {
346  if (mWidgetTrack != nullptr)
347  mWidgetTrack->setSize(mWidgetTrack->getWidth(), ((int)_size < (int)mMinTrackSize)? (int)mMinTrackSize : (int)_size);
348  updateTrack();
349  }
350 
352  {
353  return mWidgetTrack == nullptr ? 1 : mWidgetTrack->getHeight();
354  }
355 
357  {
358  return mCoord.height - (int)(mSkinRangeStart + mSkinRangeEnd);
359  }
360 
361  void VScroll::onMouseWheel(int _rel)
362  {
363  notifyMouseWheel(nullptr, _rel);
364 
365  Base::onMouseWheel(_rel);
366  }
367 
368  void VScroll::notifyMouseWheel(Widget* _sender, int _rel)
369  {
370  if (mScrollRange < 2) return;
371 
372  int offset = mScrollPosition;
373  if (_rel < 0) offset += SCROLL_MOUSE_WHEEL;
374  else offset -= SCROLL_MOUSE_WHEEL;
375 
376  if (offset < 0) offset = 0;
377  else if (offset > (int)(mScrollRange - 1)) offset = mScrollRange - 1;
378 
379  if ((size_t)offset != mScrollPosition)
380  {
381  mScrollPosition = offset;
382  // оповещаем
384  updateTrack();
385  }
386  }
387 
388  void VScroll::setProperty(const std::string& _key, const std::string& _value)
389  {
390  if (_key == "Scroll_Range") setScrollRange(utility::parseValue<size_t>(_value));
391  else if (_key == "Scroll_Position") setScrollPosition(utility::parseValue<size_t>(_value));
392  else if (_key == "Scroll_Page") setScrollPage(utility::parseValue<size_t>(_value));
393  else if (_key == "Scroll_ViewPage") setScrollViewPage(utility::parseValue<size_t>(_value));
394  else if (_key == "Scroll_MoveToClick") setMoveToClick(utility::parseValue<bool>(_value));
395  else
396  {
397  Base::setProperty(_key, _value);
398  return;
399  }
400  eventChangeProperty(this, _key, _value);
401  }
402 
403 } // namespace MyGUI