Panda3D
 All Classes Functions Variables Enumerations
pgSliderBar.cxx
1 // Filename: pgSliderBar.cxx
2 // Created by: masad (19Oct04)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pgSliderBar.h"
16 #include "pgMouseWatcherParameter.h"
17 #include "clockObject.h"
18 #include "throw_event.h"
19 #include "config_pgui.h"
20 #include "throw_event.h"
21 #include "transformState.h"
22 #include "mouseButton.h"
23 
24 TypeHandle PGSliderBar::_type_handle;
25 
26 ////////////////////////////////////////////////////////////////////
27 // Function: PGSliderBar::Constructor
28 // Access: Published
29 // Description:
30 ////////////////////////////////////////////////////////////////////
31 PGSliderBar::
32 PGSliderBar(const string &name)
33  : PGItem(name)
34 {
35  set_cull_callback();
36 
37  _min_value = 0.0f;
38  _max_value = 1.0f;
39  set_scroll_size(0.01f);
40  set_page_size(0.1f);
41  _ratio = 0.0f;
42  _resize_thumb = false;
43  _manage_pieces = false;
44  _axis.set(1.0f, 0.0f, 0.0f);
45  _needs_remanage = false;
46  _needs_recompute = true;
47  _needs_reposition = false;
48  _scroll_button_held = NULL;
49  _mouse_button_page = false;
50  _dragging = false;
51  _thumb_width = 0.1f;
52 
53  set_active(true);
54 }
55 
56 ////////////////////////////////////////////////////////////////////
57 // Function: PGSliderBar::Destructor
58 // Access: Public, Virtual
59 // Description:
60 ////////////////////////////////////////////////////////////////////
61 PGSliderBar::
62 ~PGSliderBar() {
63 }
64 
65 ////////////////////////////////////////////////////////////////////
66 // Function: PGSliderBar::Copy Constructor
67 // Access: Protected
68 // Description:
69 ////////////////////////////////////////////////////////////////////
70 PGSliderBar::
71 PGSliderBar(const PGSliderBar &copy) :
72  PGItem(copy),
73  _min_value(copy._min_value),
74  _max_value(copy._max_value),
75  _scroll_value(copy._scroll_value),
76  _scroll_ratio(copy._scroll_ratio),
77  _page_value(copy._page_value),
78  _page_ratio(copy._page_ratio),
79  _ratio(copy._ratio),
80  _resize_thumb(copy._resize_thumb),
81  _manage_pieces(copy._manage_pieces),
82  _axis(copy._axis)
83 {
84  _needs_remanage = false;
85  _needs_recompute = true;
86  _scroll_button_held = NULL;
87  _mouse_button_page = false;
88  _dragging = false;
89 }
90 
91 ////////////////////////////////////////////////////////////////////
92 // Function: PGSliderBar::make_copy
93 // Access: Public, Virtual
94 // Description: Returns a newly-allocated Node that is a shallow copy
95 // of this one. It will be a different Node pointer,
96 // but its internal data may or may not be shared with
97 // that of the original Node.
98 ////////////////////////////////////////////////////////////////////
100 make_copy() const {
101  LightReMutexHolder holder(_lock);
102  return new PGSliderBar(*this);
103 }
104 
105 ////////////////////////////////////////////////////////////////////
106 // Function: PGSliderBar::press
107 // Access: Public, Virtual
108 // Description: This is a callback hook function, called whenever a
109 // mouse or keyboard button is depressed while the mouse
110 // is within the region.
111 ////////////////////////////////////////////////////////////////////
112 void PGSliderBar::
113 press(const MouseWatcherParameter &param, bool background) {
114  LightReMutexHolder holder(_lock);
115  if (param.has_mouse()) {
116  _mouse_pos = param.get_mouse();
117  }
118  if (get_active() && param.get_button() == MouseButton::one()) {
119  if (_needs_recompute) {
120  recompute();
121  }
122 
123  if (_range_x != 0.0f) {
124  _mouse_button_page = true;
125  _scroll_button_held = NULL;
126  advance_page();
127  _next_advance_time =
128  ClockObject::get_global_clock()->get_frame_time() + scroll_initial_delay;
129  }
130  }
131  PGItem::press(param, background);
132 }
133 
134 ////////////////////////////////////////////////////////////////////
135 // Function: PGSliderBar::release
136 // Access: Public, Virtual
137 // Description: This is a callback hook function, called whenever a
138 // mouse or keyboard button previously depressed with
139 // press() is released.
140 ////////////////////////////////////////////////////////////////////
141 void PGSliderBar::
142 release(const MouseWatcherParameter &param, bool background) {
143  LightReMutexHolder holder(_lock);
145  _mouse_button_page = false;
146  }
147  if (_dragging) {
148  end_drag();
149  }
150  PGItem::release(param, background);
151 }
152 
153 ////////////////////////////////////////////////////////////////////
154 // Function: PGSliderBar::move
155 // Access: Protected, Virtual
156 // Description: This is a callback hook function, called whenever a
157 // mouse is moved while within the region.
158 ////////////////////////////////////////////////////////////////////
159 void PGSliderBar::
161  LightReMutexHolder holder(_lock);
162  _mouse_pos = param.get_mouse();
163  if (_dragging) {
164  // We only get here if we the user originally clicked on the
165  // track, which caused the slider to move all the way to the mouse
166  // position, and then started dragging the mouse along the track.
167  // In this case, we start moving the thumb as if the user had
168  // started by dragging the thumb directly.
169  continue_drag();
170  }
171 }
172 
173 ////////////////////////////////////////////////////////////////////
174 // Function: PGSliderBar::cull_callback
175 // Access: Protected, Virtual
176 // Description: This function will be called during the cull
177 // traversal to perform any additional operations that
178 // should be performed at cull time. This may include
179 // additional manipulation of render state or additional
180 // visible/invisible decisions, or any other arbitrary
181 // operation.
182 //
183 // Note that this function will *not* be called unless
184 // set_cull_callback() is called in the constructor of
185 // the derived class. It is necessary to call
186 // set_cull_callback() to indicated that we require
187 // cull_callback() to be called.
188 //
189 // By the time this function is called, the node has
190 // already passed the bounding-volume test for the
191 // viewing frustum, and the node's transform and state
192 // have already been applied to the indicated
193 // CullTraverserData object.
194 //
195 // The return value is true if this node should be
196 // visible, or false if it should be culled.
197 ////////////////////////////////////////////////////////////////////
198 bool PGSliderBar::
200  LightReMutexHolder holder(_lock);
201  if (_manage_pieces && _needs_remanage) {
202  remanage();
203  }
204  if (_needs_recompute) {
205  recompute();
206  }
207 
208  if (_scroll_button_held != (PGItem *)NULL &&
209  _next_advance_time <= ClockObject::get_global_clock()->get_frame_time()) {
210  advance_scroll();
211  }
212 
213  if (_mouse_button_page &&
214  _next_advance_time <= ClockObject::get_global_clock()->get_frame_time()) {
215  advance_page();
216  }
217 
218  if (_needs_reposition) {
219  reposition();
220  }
221 
222  return PGItem::cull_callback(trav, data);
223 }
224 
225 ////////////////////////////////////////////////////////////////////
226 // Function: PGSliderBar::xform
227 // Access: Public, Virtual
228 // Description: Transforms the contents of this node by the indicated
229 // matrix, if it means anything to do so. For most
230 // kinds of nodes, this does nothing.
231 ////////////////////////////////////////////////////////////////////
232 void PGSliderBar::
233 xform(const LMatrix4 &mat) {
234  LightReMutexHolder holder(_lock);
235  PGItem::xform(mat);
236  _axis = _axis * mat;
237 
238  // Make sure we set the thumb to identity position first, so it
239  // won't be accidentally flattened.
240  if (_thumb_button != (PGButton *)NULL) {
241  _thumb_button->clear_transform();
242  }
243 
244  _needs_remanage = true;
245  _needs_recompute = true;
246 }
247 
248 ////////////////////////////////////////////////////////////////////
249 // Function: PGSliderBar::adjust
250 // Access: Public, Virtual
251 // Description: This is a callback hook function, called whenever the
252 // slider value is adjusted by the user or
253 // programmatically.
254 ////////////////////////////////////////////////////////////////////
255 void PGSliderBar::
257  LightReMutexHolder holder(_lock);
258  string event = get_adjust_event();
259  play_sound(event);
260  throw_event(event);
261 
262  if (has_notify()) {
263  get_notify()->slider_bar_adjust(this);
264  }
265 }
266 
267 ////////////////////////////////////////////////////////////////////
268 // Function: PGSliderBar::setup_scroll_bar
269 // Access: Published
270 // Description: Creates PGSliderBar that represents a vertical or
271 // horizontal scroll bar (if vertical is true or false,
272 // respectively), with additional buttons for scrolling,
273 // and a range of 0 .. 1.
274 //
275 // length here is the measurement along the scroll bar,
276 // and width is the measurement across the scroll bar,
277 // whether it is vertical or horizontal (so for a
278 // horizontal scroll bar, the length is actually the x
279 // dimension, and the width is the y dimension).
280 ////////////////////////////////////////////////////////////////////
281 void PGSliderBar::
282 setup_scroll_bar(bool vertical, PN_stdfloat length, PN_stdfloat width, PN_stdfloat bevel) {
283  LightReMutexHolder holder(_lock);
284  set_state(0);
285  clear_state_def(0);
286 
287  if (vertical) {
288  set_frame(-width / 2.0f, width / 2.0f, -length / 2.0f, length / 2.0f);
289  _axis = LVector3::rfu(0.0f, 0.0f, -1.0f);
290  } else {
291  set_frame(-length / 2.0f, length / 2.0f, -width / 2.0f, width / 2.0f);
292  _axis = LVector3::rfu(1.0f, 0.0f, 0.0f);
293  }
294 
295  PGFrameStyle style;
296  style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
297  style.set_type(PGFrameStyle::T_flat);
298  set_frame_style(0, style);
299 
300  style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
301  style.set_type(PGFrameStyle::T_bevel_out);
302  style.set_width(bevel, bevel);
303 
304  // Remove the button nodes created by a previous call to setup(), if
305  // any.
306  if (_thumb_button != (PGButton *)NULL) {
307  remove_child(_thumb_button);
308  set_thumb_button(NULL);
309  }
310  if (_left_button != (PGButton *)NULL) {
311  remove_child(_left_button);
312  set_left_button(NULL);
313  }
314  if (_right_button != (PGButton *)NULL) {
315  remove_child(_right_button);
316  set_right_button(NULL);
317  }
318 
319  PT(PGButton) thumb = new PGButton("thumb");
320  thumb->setup("", bevel);
321  thumb->set_frame(-width / 2.0f, width / 2.0f,
322  -width / 2.0f, width / 2.0f);
323  add_child(thumb);
324  set_thumb_button(thumb);
325 
326  PT(PGButton) left = new PGButton("left");
327  left->setup("", bevel);
328  left->set_frame(-width / 2.0f, width / 2.0f,
329  -width / 2.0f, width / 2.0f);
330  left->set_transform(TransformState::make_pos(((width - length) / 2.0f) * _axis));
331  add_child(left);
332  set_left_button(left);
333 
334  PT(PGButton) right = new PGButton("right");
335  right->setup("", bevel);
336  right->set_frame(-width / 2.0f, width / 2.0f,
337  -width / 2.0f, width / 2.0f);
338  right->set_transform(TransformState::make_pos(((length - width) / 2.0f) * _axis));
339  add_child(right);
340  set_right_button(right);
341 
342  set_resize_thumb(true);
343  set_manage_pieces(true);
344 }
345 
346 ////////////////////////////////////////////////////////////////////
347 // Function: PGSliderBar::setup_slider
348 // Access: Published
349 // Description: Creates PGSliderBar that represents a slider that the
350 // user can use to control an analog quantity.
351 //
352 // This is functionally the same as a scroll bar, but it
353 // has a distinctive look.
354 ////////////////////////////////////////////////////////////////////
355 void PGSliderBar::
356 setup_slider(bool vertical, PN_stdfloat length, PN_stdfloat width, PN_stdfloat bevel) {
357  LightReMutexHolder holder(_lock);
358  set_state(0);
359  clear_state_def(0);
360 
361  if (vertical) {
362  set_frame(-width / 2.0f, width / 2.0f, -length / 2.0f, length / 2.0f);
363  _axis = LVector3::rfu(0.0f, 0.0f, -1.0f);
364  } else {
365  set_frame(-length / 2.0f, length / 2.0f, -width / 2.0f, width / 2.0f);
366  _axis = LVector3::rfu(1.0f, 0.0f, 0.0f);
367  }
368 
369  PGFrameStyle style;
370  style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
371  style.set_type(PGFrameStyle::T_flat);
372  style.set_visible_scale(1.0f, 0.25f);
373  style.set_width(bevel, bevel);
374  set_frame_style(0, style);
375 
376  // Remove the button nodes created by a previous call to setup(), if
377  // any.
378  if (_thumb_button != (PGButton *)NULL) {
379  remove_child(_thumb_button);
380  set_thumb_button(NULL);
381  }
382  if (_left_button != (PGButton *)NULL) {
383  remove_child(_left_button);
384  set_left_button(NULL);
385  }
386  if (_right_button != (PGButton *)NULL) {
387  remove_child(_right_button);
388  set_right_button(NULL);
389  }
390 
391  PT(PGButton) thumb = new PGButton("thumb");
392  thumb->setup(" ", bevel);
393  thumb->set_frame(-width / 4.0f, width / 4.0f,
394  -width / 2.0f, width / 2.0f);
395  add_child(thumb);
396  set_thumb_button(thumb);
397 
398  set_resize_thumb(false);
399  set_manage_pieces(true);
400 }
401 
402 ////////////////////////////////////////////////////////////////////
403 // Function: PGSliderBar::set_active
404 // Access: Published, Virtual
405 // Description: Sets whether the PGItem is active for mouse watching.
406 // This is not necessarily related to the
407 // active/inactive appearance of the item, which is
408 // controlled by set_state(), but it does affect whether
409 // it responds to mouse events.
410 ////////////////////////////////////////////////////////////////////
411 void PGSliderBar::
412 set_active(bool active) {
413  LightReMutexHolder holder(_lock);
414  PGItem::set_active(active);
415 
416  // This also implicitly sets the managed pieces.
417  if (_thumb_button != (PGButton *)NULL) {
418  _thumb_button->set_active(active);
419  }
420  if (_left_button != (PGButton *)NULL) {
421  _left_button->set_active(active);
422  }
423  if (_right_button != (PGButton *)NULL) {
424  _right_button->set_active(active);
425  }
426 }
427 
428 ////////////////////////////////////////////////////////////////////
429 // Function: PGSliderBar::remanage
430 // Access: Published
431 // Description: Manages the position and size of the scroll bars and
432 // the thumb. Normally this should not need to be
433 // called directly.
434 ////////////////////////////////////////////////////////////////////
435 void PGSliderBar::
437  LightReMutexHolder holder(_lock);
438  _needs_remanage = false;
439 
440  const LVecBase4 &frame = get_frame();
441 
442  PN_stdfloat width, length;
443  if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) {
444  // The slider is X-dominant.
445  width = frame[3] - frame[2];
446  length = frame[1] - frame[0];
447 
448  } else {
449  // The slider is Y-dominant.
450  width = frame[1] - frame[0];
451  length = frame[3] - frame[2];
452  }
453 
454  LVector3 center = LVector3::rfu((frame[0] + frame[1]) / 2.0f,
455  0.0f,
456  (frame[2] + frame[3]) / 2.0f);
457 
458  if (_left_button != (PGButton *)NULL) {
459  _left_button->set_frame(-width / 2.0f, width / 2.0f,
460  -width / 2.0f, width / 2.0f);
461  _left_button->set_transform(TransformState::make_pos(center + ((width - length) / 2.0f) * _axis));
462  }
463 
464  if (_right_button != (PGButton *)NULL) {
465  _right_button->set_frame(-width / 2.0f, width / 2.0f,
466  -width / 2.0f, width / 2.0f);
467  _right_button->set_transform(TransformState::make_pos(center + ((length - width) / 2.0f) * _axis));
468  }
469 
470  if (_thumb_button != (PGButton *)NULL) {
471  _thumb_button->set_frame(-width / 2.0f, width / 2.0f,
472  -width / 2.0f, width / 2.0f);
473  _thumb_button->set_transform(TransformState::make_pos(center));
474  }
475 
476  recompute();
477 }
478 
479 ////////////////////////////////////////////////////////////////////
480 // Function: PGSliderBar::recompute
481 // Access: Published
482 // Description: Recomputes the position and size of the thumb.
483 // Normally this should not need to be called directly.
484 ////////////////////////////////////////////////////////////////////
485 void PGSliderBar::
487  LightReMutexHolder holder(_lock);
488  _needs_recompute = false;
489 
490  if (_min_value != _max_value) {
491  _scroll_ratio = fabs(_scroll_value / (_max_value - _min_value));
492  _page_ratio = fabs(_page_value / (_max_value - _min_value));
493 
494  } else {
495  _scroll_ratio = 0.0f;
496  _page_ratio = 0.0f;
497  }
498 
499  if (!has_frame()) {
500  _min_x = 0.0f;
501  _max_x = 0.0f;
502  _thumb_width = 0.0f;
503  _range_x = 0.0f;
504  _thumb_start.set(0.0f, 0.0f, 0.0f);
505 
506  } else {
507  LVecBase4 frame = get_frame();
508  reduce_region(frame, _left_button);
509  reduce_region(frame, _right_button);
510 
511  if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) {
512  // The slider is X-dominant.
513 
514  _min_x = frame[0];
515  _max_x = frame[1];
516 
517  PN_stdfloat trough_width = _max_x - _min_x;
518 
519  if (_thumb_button == (PGButton *)NULL) {
520  _thumb_width = 0.0f;
521  _range_x = 0.0f;
522  _thumb_start.set(0.0f, 0.0f, 0.0f);
523 
524  } else {
525  const LVecBase4 &thumb_frame = _thumb_button->get_frame();
526 
527  if (_resize_thumb) {
528  // If we're allowed to adjust the thumb's size, we don't need to
529  // find out how wide it is.
530  _thumb_width = trough_width * min((PN_stdfloat)1.0, _page_ratio);
531  _thumb_button->set_frame(-_thumb_width / 2.0f, _thumb_width / 2.0f,
532  thumb_frame[2], thumb_frame[3]);
533  } else {
534  // If we're not adjusting the thumb's size, we do need to know
535  // its current width.
536  _thumb_width = thumb_frame[1] - thumb_frame[0];
537  }
538 
539  _range_x = trough_width - _thumb_width;
540 
541  if (_axis[0] >= 0.0f) {
542  // The slider runs forwards, left to right.
543  _thumb_start = (_min_x - thumb_frame[0]) * _axis;
544  } else {
545  // The slider runs backwards: right to left.
546  _thumb_start = (thumb_frame[1] - _max_x) * _axis;
547  }
548  _thumb_start += LVector3::rfu(0.0f, 0.0f, (frame[2] + frame[3]) / 2.0f);
549  }
550 
551  } else {
552  // The slider is Y-dominant. We call it X in the variable names,
553  // but it's really Y (or even Z).
554 
555  _min_x = frame[2];
556  _max_x = frame[3];
557 
558  PN_stdfloat trough_width = _max_x - _min_x;
559 
560  if (_thumb_button == (PGButton *)NULL) {
561  _thumb_width = 0.0f;
562  _range_x = 0.0f;
563  _thumb_start.set(0.0f, 0.0f, 0.0f);
564 
565  } else {
566  const LVecBase4 &thumb_frame = _thumb_button->get_frame();
567 
568  if (_resize_thumb) {
569  // If we're allowed to adjust the thumb's size, we don't need to
570  // find out how wide it is.
571  _thumb_width = trough_width * min((PN_stdfloat)1.0, _page_ratio);
572  _thumb_button->set_frame(thumb_frame[0], thumb_frame[1],
573  -_thumb_width / 2.0f, _thumb_width / 2.0f);
574  } else {
575  // If we're not adjusting the thumb's size, we do need to know
576  // its current width.
577  _thumb_width = thumb_frame[3] - thumb_frame[2];
578  }
579 
580  _range_x = trough_width - _thumb_width;
581 
582  if (_axis[1] >= 0.0f && _axis[2] >= 0.0f) {
583  // The slider runs forwards, bottom to top.
584  _thumb_start = (_min_x - thumb_frame[2]) * _axis;
585  } else {
586  // The slider runs backwards: top to bottom.
587  _thumb_start = (thumb_frame[3] - _max_x) * _axis;
588  }
589  _thumb_start += LVector3::rfu((frame[0] + frame[1]) / 2.0f, 0.0f, 0.0f);
590  }
591  }
592  }
593 
594  reposition();
595 }
596 
597 ////////////////////////////////////////////////////////////////////
598 // Function: PGSliderBar::frame_changed
599 // Access: Protected, Virtual
600 // Description: Called when the user changes the frame size.
601 ////////////////////////////////////////////////////////////////////
602 void PGSliderBar::
603 frame_changed() {
604  LightReMutexHolder holder(_lock);
605  PGItem::frame_changed();
606  _needs_remanage = true;
607  _needs_recompute = true;
608 }
609 
610 ////////////////////////////////////////////////////////////////////
611 // Function: PGSliderBar::item_transform_changed
612 // Access: Protected, Virtual
613 // Description: Called whenever a watched PGItem's local transform
614 // has been changed.
615 ////////////////////////////////////////////////////////////////////
616 void PGSliderBar::
617 item_transform_changed(PGItem *) {
618  LightReMutexHolder holder(_lock);
619  _needs_recompute = true;
620 }
621 
622 ////////////////////////////////////////////////////////////////////
623 // Function: PGSliderBar::item_frame_changed
624 // Access: Protected, Virtual
625 // Description: Called whenever a watched PGItem's frame
626 // has been changed.
627 ////////////////////////////////////////////////////////////////////
628 void PGSliderBar::
629 item_frame_changed(PGItem *) {
630  LightReMutexHolder holder(_lock);
631  _needs_recompute = true;
632 }
633 
634 ////////////////////////////////////////////////////////////////////
635 // Function: PGSliderBar::item_draw_mask_changed
636 // Access: Protected, Virtual
637 // Description: Called whenever a watched PGItem's draw_mask
638 // has been changed.
639 ////////////////////////////////////////////////////////////////////
640 void PGSliderBar::
641 item_draw_mask_changed(PGItem *) {
642  LightReMutexHolder holder(_lock);
643  _needs_recompute = true;
644 }
645 
646 ////////////////////////////////////////////////////////////////////
647 // Function: PGSliderBar::item_press
648 // Access: Protected, Virtual
649 // Description: Called whenever the "press" event is triggered on a
650 // watched PGItem. See PGItem::press().
651 ////////////////////////////////////////////////////////////////////
652 void PGSliderBar::
653 item_press(PGItem *item, const MouseWatcherParameter &param) {
654  LightReMutexHolder holder(_lock);
655  if (param.has_mouse()) {
656  _mouse_pos = param.get_mouse();
657  }
658  if (item == _left_button || item == _right_button) {
659  _scroll_button_held = item;
660  _mouse_button_page = false;
661  advance_scroll();
662  _next_advance_time =
663  ClockObject::get_global_clock()->get_frame_time() + scroll_initial_delay;
664 
665  } else if (item == _thumb_button) {
666  _scroll_button_held = NULL;
667  begin_drag();
668  }
669 }
670 
671 ////////////////////////////////////////////////////////////////////
672 // Function: PGSliderBar::item_release
673 // Access: Protected, Virtual
674 // Description: Called whenever the "release" event is triggered on a
675 // watched PGItem. See PGItem::release().
676 ////////////////////////////////////////////////////////////////////
677 void PGSliderBar::
678 item_release(PGItem *item, const MouseWatcherParameter &) {
679  LightReMutexHolder holder(_lock);
680  if (item == _scroll_button_held) {
681  _scroll_button_held = NULL;
682 
683  } else if (item == _thumb_button) {
684  _scroll_button_held = NULL;
685  if (_dragging) {
686  end_drag();
687  }
688  }
689 }
690 
691 ////////////////////////////////////////////////////////////////////
692 // Function: PGSliderBar::item_move
693 // Access: Protected, Virtual
694 // Description: Called whenever the "move" event is triggered on a
695 // watched PGItem. See PGItem::move().
696 ////////////////////////////////////////////////////////////////////
697 void PGSliderBar::
698 item_move(PGItem *item, const MouseWatcherParameter &param) {
699  LightReMutexHolder holder(_lock);
700  _mouse_pos = param.get_mouse();
701  if (item == _thumb_button) {
702  if (_dragging) {
703  continue_drag();
704  }
705  }
706 }
707 
708 ////////////////////////////////////////////////////////////////////
709 // Function: PGSliderBar::reposition
710 // Access: Private
711 // Description: A lighter-weight version of recompute(), this just
712 // moves the thumb, assuming all other properties are
713 // unchanged.
714 ////////////////////////////////////////////////////////////////////
715 void PGSliderBar::
716 reposition() {
717  _needs_reposition = false;
718 
719  PN_stdfloat t = get_ratio();
720 
721  if (_thumb_button != (PGButton *)NULL) {
722  LPoint3 pos = (t * _range_x) * _axis + _thumb_start;
723  CPT(TransformState) transform = TransformState::make_pos(pos);
724  CPT(TransformState) orig_transform = _thumb_button->get_transform();
725 
726  // It's important not to update the transform frivolously, or
727  // we'll get caught in an update loop.
728  if (transform == orig_transform) {
729  // No change.
730  } else if (*transform != *orig_transform) {
731  _thumb_button->set_transform(transform);
732  }
733  }
734 }
735 
736 ////////////////////////////////////////////////////////////////////
737 // Function: PGSliderBar::advance_scroll
738 // Access: Private
739 // Description: Advances the scroll bar by one unit in the left or
740 // right direction while the user is holding down the
741 // left or right scroll button.
742 ////////////////////////////////////////////////////////////////////
743 void PGSliderBar::
744 advance_scroll() {
745  if (_scroll_button_held == _left_button) {
746  internal_set_ratio(max(_ratio - _scroll_ratio, (PN_stdfloat)0.0));
747 
748  } else if (_scroll_button_held == _right_button) {
749  internal_set_ratio(min(_ratio + _scroll_ratio, (PN_stdfloat)1.0));
750  }
751 
752  _next_advance_time =
753  ClockObject::get_global_clock()->get_frame_time() + scroll_continued_delay;
754 }
755 
756 ////////////////////////////////////////////////////////////////////
757 // Function: PGSliderBar::advance_page
758 // Access: Private
759 // Description: Advances the scroll bar by one page in the left or
760 // right direction while the user is holding down the
761 // mouse button on the track.
762 ////////////////////////////////////////////////////////////////////
763 void PGSliderBar::
764 advance_page() {
765  // Is the mouse position left or right of the current thumb
766  // position?
767  LPoint3 mouse = mouse_to_local(_mouse_pos) - _thumb_start;
768  PN_stdfloat target_ratio = mouse.dot(_axis) / _range_x;
769 
770  PN_stdfloat t;
771  if (target_ratio < _ratio) {
772  t = max(_ratio - _page_ratio + _scroll_ratio, target_ratio);
773 
774  } else {
775  t = min(_ratio + _page_ratio - _scroll_ratio, target_ratio);
776  }
777  internal_set_ratio(t);
778  if (t == target_ratio) {
779  // We made it; begin dragging from now on until the user releases
780  // the mouse.
781  begin_drag();
782  }
783 
784  _next_advance_time =
785  ClockObject::get_global_clock()->get_frame_time() + scroll_continued_delay;
786 }
787 
788 ////////////////////////////////////////////////////////////////////
789 // Function: PGSliderBar::begin_drag
790 // Access: Private
791 // Description: Called when the user clicks down on the thumb button,
792 // possibly to begin dragging.
793 ////////////////////////////////////////////////////////////////////
794 void PGSliderBar::
795 begin_drag() {
796  if (_needs_recompute) {
797  recompute();
798  }
799  if (_range_x != 0.0f) {
800  PN_stdfloat current_x = mouse_to_local(_mouse_pos).dot(_axis);
801  _drag_start_x = current_x - get_ratio() * _range_x;
802  _dragging = true;
803  }
804 }
805 
806 ////////////////////////////////////////////////////////////////////
807 // Function: PGSliderBar::continue_drag
808 // Access: Private
809 // Description: Called as the user moves the mouse while still
810 // dragging on the thumb button.
811 ////////////////////////////////////////////////////////////////////
812 void PGSliderBar::
813 continue_drag() {
814  if (_needs_recompute) {
815  recompute();
816  }
817  if (_range_x != 0.0f) {
818  PN_stdfloat current_x = mouse_to_local(_mouse_pos).dot(_axis);
819  internal_set_ratio((current_x - _drag_start_x) / _range_x);
820  }
821 }
822 
823 ////////////////////////////////////////////////////////////////////
824 // Function: PGSliderBar::end_drag
825 // Access: Private
826 // Description: Called as the user releases the mouse after dragging.
827 ////////////////////////////////////////////////////////////////////
828 void PGSliderBar::
829 end_drag() {
830  _dragging = false;
831 }
ButtonHandle get_button() const
Returns the mouse or keyboard button associated with this event.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:271
virtual void set_active(bool active)
Sets whether the PGItem is active for mouse watching.
const LVecBase4 & get_frame() const
Returns the bounding rectangle of the item.
Definition: pgItem.I:131
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
void set_visible_scale(PN_stdfloat x, PN_stdfloat y)
Sets a scale factor on the visible representation of the frame, in the X and Y directions.
Definition: pgFrameStyle.I:248
void set_width(PN_stdfloat x, PN_stdfloat y)
Sets the width parameter, which has meaning only for certain frame types.
Definition: pgFrameStyle.I:172
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
Definition: pandaNode.cxx:697
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
Definition: pgItem.cxx:386
void set_resize_thumb(bool resize_thumb)
Sets the resize_thumb flag.
Definition: pgSliderBar.I:248
This is the base class for all the various kinds of gui widget objects.
Definition: pgItem.h:58
string get_adjust_event() const
Returns the event name that will be thrown when the slider bar value is adjusted by the user or progr...
Definition: pgSliderBar.I:467
PGSliderBarNotify * get_notify() const
Returns the object which will be notified when the PGSliderBar changes, if any.
Definition: pgSliderBar.I:38
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
This is a particular kind of PGItem that is specialized to behave like a normal button object...
Definition: pgButton.h:32
void set_type(Type type)
Sets the basic type of frame.
Definition: pgFrameStyle.I:76
void set_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets the bounding rectangle of the item, in local coordinates.
Definition: pgItem.I:100
This collects together the pieces of data that are accumulated for each node while walking the scene ...
static ButtonHandle one()
Returns the ButtonHandle associated with the first mouse button.
Definition: mouseButton.cxx:50
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
virtual void move(const MouseWatcherParameter &param)
This is a callback hook function, called whenever a mouse is moved while within the region...
virtual void press(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever a mouse or keyboard button is depressed while the m...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
virtual void adjust()
This is a callback hook function, called whenever the slider value is adjusted by the user or program...
static LVector3f rfu(float right, float fwd, float up, CoordinateSystem cs=CS_default)
Returns a vector that is described by its right, forward, and up components, in whatever way the coor...
Definition: lvector3.h:631
bool has_frame() const
Returns true if the item has a bounding rectangle; see set_frame().
Definition: pgItem.I:144
void remanage()
Manages the position and size of the scroll bars and the thumb.
void set_frame_style(int state, const PGFrameStyle &style)
Changes the kind of frame that will be drawn behind the item when it is in the indicated state...
Definition: pgItem.cxx:1102
const LPoint2 & get_mouse() const
Returns the mouse position at the time the event was generated, in the normalized range (-1 ...
bool has_notify() const
Returns true if there is an object configured to be notified when the PGItem changes, false otherwise.
Definition: pgItem.I:72
virtual void release(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever a mouse or keyboard button previously depressed wit...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
double get_frame_time(Thread *current_thread=Thread::get_current_thread()) const
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.I:48
virtual void release(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever a mouse or keyboard button previously depressed wit...
Definition: pgItem.cxx:726
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a)
Sets the dominant color of the frame.
Definition: pgFrameStyle.I:96
bool get_active() const
Returns whether the PGItem is currently active for mouse events.
Definition: pgItem.I:199
Similar to MutexHolder, but for a light reentrant mutex.
void set_right_button(PGButton *right_button)
Sets the PGButton object that will serve as the right scroll button for this slider.
Definition: pgSliderBar.I:409
void setup_slider(bool vertical, PN_stdfloat length, PN_stdfloat width, PN_stdfloat bevel)
Creates PGSliderBar that represents a slider that the user can use to control an analog quantity...
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
void set_state(int state)
Sets the &quot;state&quot; of this particular PGItem.
Definition: pgItem.I:175
void set_manage_pieces(bool manage_pieces)
Sets the manage_pieces flag.
Definition: pgSliderBar.I:276
void clear_state_def(int state)
Resets the NodePath assigned to the indicated state to its initial default, with only a frame represe...
Definition: pgItem.cxx:1021
void set_thumb_button(PGButton *thumb_button)
Sets the PGButton object that will serve as the thumb for this slider.
Definition: pgSliderBar.I:308
bool has_mouse() const
Returns true if this parameter has an associated mouse position, false otherwise. ...
static bool is_mouse_button(ButtonHandle button)
Returns true if the indicated ButtonHandle is a mouse button, false if it is some other kind of butto...
void set_left_button(PGButton *left_button)
Sets the PGButton object that will serve as the left scroll button for this slider.
Definition: pgSliderBar.I:358
void recompute()
Recomputes the position and size of the thumb.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This is sent along as a parameter to most events generated for a region to indicate the mouse and but...
void add_child(PandaNode *child_node, int sort=0, Thread *current_thread=Thread::get_current_thread())
Adds a new child to the node.
Definition: pandaNode.cxx:654
void setup_scroll_bar(bool vertical, PN_stdfloat length, PN_stdfloat width, PN_stdfloat bevel)
Creates PGSliderBar that represents a vertical or horizontal scroll bar (if vertical is true or false...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
virtual void set_active(bool active)
Sets whether the PGItem is active for mouse watching.
Definition: pgItem.cxx:890
PN_stdfloat get_ratio() const
Returns the current value of the slider, expressed in the range 0 .
Definition: pgSliderBar.I:219
virtual void press(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever a mouse or keyboard button is depressed while the m...
Definition: pgItem.cxx:694
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
This is a particular kind of PGItem that draws a little bar with a slider that moves from left to rig...
Definition: pgSliderBar.h:34