Panda3D
 All Classes Functions Variables Enumerations
pgSliderBar.cxx
00001 // Filename: pgSliderBar.cxx
00002 // Created by:  masad (19Oct04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pgSliderBar.h"
00016 #include "pgMouseWatcherParameter.h"
00017 #include "clockObject.h"
00018 #include "throw_event.h"
00019 #include "config_pgui.h"
00020 #include "throw_event.h"
00021 #include "transformState.h"
00022 #include "mouseButton.h"
00023 
00024 TypeHandle PGSliderBar::_type_handle;
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: PGSliderBar::Constructor
00028 //       Access: Published
00029 //  Description: 
00030 ////////////////////////////////////////////////////////////////////
00031 PGSliderBar::
00032 PGSliderBar(const string &name) 
00033   : PGItem(name)
00034 {
00035   set_cull_callback();
00036 
00037   _min_value = 0.0f;
00038   _max_value = 1.0f;
00039   set_scroll_size(0.01f);
00040   set_page_size(0.1f);
00041   _ratio = 0.0f;
00042   _resize_thumb = false;
00043   _manage_pieces = false;
00044   _axis.set(1.0f, 0.0f, 0.0f);
00045   _needs_remanage = false;
00046   _needs_recompute = true;
00047   _needs_reposition = false;
00048   _scroll_button_held = NULL;
00049   _mouse_button_page = false;
00050   _dragging = false;
00051   _thumb_width = 0.1f;
00052 
00053   set_active(true);
00054 }
00055 
00056 ////////////////////////////////////////////////////////////////////
00057 //     Function: PGSliderBar::Destructor
00058 //       Access: Public, Virtual
00059 //  Description: 
00060 ////////////////////////////////////////////////////////////////////
00061 PGSliderBar::
00062 ~PGSliderBar() {
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: PGSliderBar::Copy Constructor
00067 //       Access: Protected
00068 //  Description: 
00069 ////////////////////////////////////////////////////////////////////
00070 PGSliderBar::
00071 PGSliderBar(const PGSliderBar &copy) :
00072   PGItem(copy),
00073   _min_value(copy._min_value),
00074   _max_value(copy._max_value),
00075   _scroll_value(copy._scroll_value),
00076   _scroll_ratio(copy._scroll_ratio),
00077   _page_value(copy._page_value),
00078   _page_ratio(copy._page_ratio),
00079   _ratio(copy._ratio),
00080   _resize_thumb(copy._resize_thumb),
00081   _manage_pieces(copy._manage_pieces),
00082   _axis(copy._axis)
00083 {
00084   _needs_remanage = false;
00085   _needs_recompute = true;
00086   _scroll_button_held = NULL;
00087   _mouse_button_page = false;
00088   _dragging = false;
00089 }
00090 
00091 ////////////////////////////////////////////////////////////////////
00092 //     Function: PGSliderBar::make_copy
00093 //       Access: Public, Virtual
00094 //  Description: Returns a newly-allocated Node that is a shallow copy
00095 //               of this one.  It will be a different Node pointer,
00096 //               but its internal data may or may not be shared with
00097 //               that of the original Node.
00098 ////////////////////////////////////////////////////////////////////
00099 PandaNode *PGSliderBar::
00100 make_copy() const {
00101   LightReMutexHolder holder(_lock);
00102   return new PGSliderBar(*this);
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: PGSliderBar::press
00107 //       Access: Public, Virtual
00108 //  Description: This is a callback hook function, called whenever a
00109 //               mouse or keyboard button is depressed while the mouse
00110 //               is within the region.
00111 ////////////////////////////////////////////////////////////////////
00112 void PGSliderBar::
00113 press(const MouseWatcherParameter &param, bool background) {
00114   LightReMutexHolder holder(_lock);
00115   if (param.has_mouse()) {
00116     _mouse_pos = param.get_mouse();
00117   }
00118   if (get_active() && param.get_button() == MouseButton::one()) {
00119     if (_needs_recompute) {
00120       recompute();
00121     }
00122 
00123     if (_range_x != 0.0f) {
00124       _mouse_button_page = true;
00125       _scroll_button_held = NULL;
00126       advance_page();
00127       _next_advance_time = 
00128         ClockObject::get_global_clock()->get_frame_time() + scroll_initial_delay;
00129     }
00130   }
00131   PGItem::press(param, background);
00132 }
00133 
00134 ////////////////////////////////////////////////////////////////////
00135 //     Function: PGSliderBar::release
00136 //       Access: Public, Virtual
00137 //  Description: This is a callback hook function, called whenever a
00138 //               mouse or keyboard button previously depressed with
00139 //               press() is released.
00140 ////////////////////////////////////////////////////////////////////
00141 void PGSliderBar::
00142 release(const MouseWatcherParameter &param, bool background) {
00143   LightReMutexHolder holder(_lock);
00144   if (MouseButton::is_mouse_button(param.get_button())) {
00145     _mouse_button_page = false;
00146   }
00147   if (_dragging) {
00148     end_drag();
00149   }
00150   PGItem::release(param, background);
00151 }
00152 
00153 ////////////////////////////////////////////////////////////////////
00154 //     Function: PGSliderBar::move
00155 //       Access: Protected, Virtual
00156 //  Description: This is a callback hook function, called whenever a
00157 //               mouse is moved while within the region.
00158 ////////////////////////////////////////////////////////////////////
00159 void PGSliderBar::
00160 move(const MouseWatcherParameter &param) {
00161   LightReMutexHolder holder(_lock);
00162   _mouse_pos = param.get_mouse();
00163   if (_dragging) {
00164     // We only get here if we the user originally clicked on the
00165     // track, which caused the slider to move all the way to the mouse
00166     // position, and then started dragging the mouse along the track.
00167     // In this case, we start moving the thumb as if the user had
00168     // started by dragging the thumb directly.
00169     continue_drag();
00170   }
00171 }
00172 
00173 ////////////////////////////////////////////////////////////////////
00174 //     Function: PGSliderBar::cull_callback
00175 //       Access: Protected, Virtual
00176 //  Description: This function will be called during the cull
00177 //               traversal to perform any additional operations that
00178 //               should be performed at cull time.  This may include
00179 //               additional manipulation of render state or additional
00180 //               visible/invisible decisions, or any other arbitrary
00181 //               operation.
00182 //
00183 //               Note that this function will *not* be called unless
00184 //               set_cull_callback() is called in the constructor of
00185 //               the derived class.  It is necessary to call
00186 //               set_cull_callback() to indicated that we require
00187 //               cull_callback() to be called.
00188 //
00189 //               By the time this function is called, the node has
00190 //               already passed the bounding-volume test for the
00191 //               viewing frustum, and the node's transform and state
00192 //               have already been applied to the indicated
00193 //               CullTraverserData object.
00194 //
00195 //               The return value is true if this node should be
00196 //               visible, or false if it should be culled.
00197 ////////////////////////////////////////////////////////////////////
00198 bool PGSliderBar::
00199 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00200   LightReMutexHolder holder(_lock);
00201   if (_manage_pieces && _needs_remanage) {
00202     remanage();
00203   }
00204   if (_needs_recompute) {
00205     recompute();
00206   }
00207 
00208   if (_scroll_button_held != (PGItem *)NULL && 
00209       _next_advance_time <= ClockObject::get_global_clock()->get_frame_time()) {
00210     advance_scroll();
00211   }
00212 
00213   if (_mouse_button_page && 
00214       _next_advance_time <= ClockObject::get_global_clock()->get_frame_time()) {
00215     advance_page();
00216   }
00217 
00218   if (_needs_reposition) {
00219     reposition();
00220   }
00221 
00222   return PGItem::cull_callback(trav, data);
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: PGSliderBar::xform
00227 //       Access: Public, Virtual
00228 //  Description: Transforms the contents of this node by the indicated
00229 //               matrix, if it means anything to do so.  For most
00230 //               kinds of nodes, this does nothing.
00231 ////////////////////////////////////////////////////////////////////
00232 void PGSliderBar::
00233 xform(const LMatrix4 &mat) {
00234   LightReMutexHolder holder(_lock);
00235   PGItem::xform(mat);
00236   _axis = _axis * mat;
00237 
00238   // Make sure we set the thumb to identity position first, so it
00239   // won't be accidentally flattened.
00240   if (_thumb_button != (PGButton *)NULL) {
00241     _thumb_button->clear_transform();
00242   }
00243 
00244   _needs_remanage = true;
00245   _needs_recompute = true;
00246 }
00247 
00248 ////////////////////////////////////////////////////////////////////
00249 //     Function: PGSliderBar::adjust
00250 //       Access: Public, Virtual
00251 //  Description: This is a callback hook function, called whenever the
00252 //               slider value is adjusted by the user or
00253 //               programmatically.
00254 ////////////////////////////////////////////////////////////////////
00255 void PGSliderBar::
00256 adjust() {
00257   LightReMutexHolder holder(_lock);
00258   string event = get_adjust_event();
00259   play_sound(event);
00260   throw_event(event);
00261 
00262   if (has_notify()) {
00263     get_notify()->slider_bar_adjust(this);
00264   }
00265 }
00266 
00267 ////////////////////////////////////////////////////////////////////
00268 //     Function: PGSliderBar::setup_scroll_bar
00269 //       Access: Published
00270 //  Description: Creates PGSliderBar that represents a vertical or
00271 //               horizontal scroll bar (if vertical is true or false,
00272 //               respectively), with additional buttons for scrolling,
00273 //               and a range of 0 .. 1.
00274 //
00275 //               length here is the measurement along the scroll bar,
00276 //               and width is the measurement across the scroll bar,
00277 //               whether it is vertical or horizontal (so for a
00278 //               horizontal scroll bar, the length is actually the x
00279 //               dimension, and the width is the y dimension).
00280 ////////////////////////////////////////////////////////////////////
00281 void PGSliderBar::
00282 setup_scroll_bar(bool vertical, PN_stdfloat length, PN_stdfloat width, PN_stdfloat bevel) {
00283   LightReMutexHolder holder(_lock);
00284   set_state(0);
00285   clear_state_def(0);
00286 
00287   if (vertical) {
00288     set_frame(-width / 2.0f, width / 2.0f, -length / 2.0f, length / 2.0f);
00289     _axis = LVector3::rfu(0.0f, 0.0f, -1.0f);
00290   } else {
00291     set_frame(-length / 2.0f, length / 2.0f, -width / 2.0f, width / 2.0f);
00292     _axis = LVector3::rfu(1.0f, 0.0f, 0.0f);
00293   }
00294 
00295   PGFrameStyle style;
00296   style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
00297   style.set_type(PGFrameStyle::T_flat);
00298   set_frame_style(0, style);
00299 
00300   style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
00301   style.set_type(PGFrameStyle::T_bevel_out);
00302   style.set_width(bevel, bevel);
00303 
00304   // Remove the button nodes created by a previous call to setup(), if
00305   // any.
00306   if (_thumb_button != (PGButton *)NULL) {
00307     remove_child(_thumb_button);
00308     set_thumb_button(NULL);
00309   }
00310   if (_left_button != (PGButton *)NULL) {
00311     remove_child(_left_button);
00312     set_left_button(NULL);
00313   }
00314   if (_right_button != (PGButton *)NULL) {
00315     remove_child(_right_button);
00316     set_right_button(NULL);
00317   }
00318 
00319   PT(PGButton) thumb = new PGButton("thumb");
00320   thumb->setup("", bevel);
00321   thumb->set_frame(-width / 2.0f, width / 2.0f, 
00322                    -width / 2.0f, width / 2.0f);
00323   add_child(thumb);
00324   set_thumb_button(thumb);
00325 
00326   PT(PGButton) left = new PGButton("left");
00327   left->setup("", bevel);
00328   left->set_frame(-width / 2.0f, width / 2.0f, 
00329                   -width / 2.0f, width / 2.0f);
00330   left->set_transform(TransformState::make_pos(((width - length) / 2.0f) * _axis));
00331   add_child(left);
00332   set_left_button(left);
00333 
00334   PT(PGButton) right = new PGButton("right");
00335   right->setup("", bevel);
00336   right->set_frame(-width / 2.0f, width / 2.0f, 
00337                    -width / 2.0f, width / 2.0f);
00338   right->set_transform(TransformState::make_pos(((length - width) / 2.0f) * _axis));
00339   add_child(right);
00340   set_right_button(right);
00341 
00342   set_resize_thumb(true);
00343   set_manage_pieces(true);
00344 }
00345 
00346 ////////////////////////////////////////////////////////////////////
00347 //     Function: PGSliderBar::setup_slider
00348 //       Access: Published
00349 //  Description: Creates PGSliderBar that represents a slider that the
00350 //               user can use to control an analog quantity.
00351 //
00352 //               This is functionally the same as a scroll bar, but it
00353 //               has a distinctive look.
00354 ////////////////////////////////////////////////////////////////////
00355 void PGSliderBar::
00356 setup_slider(bool vertical, PN_stdfloat length, PN_stdfloat width, PN_stdfloat bevel) {
00357   LightReMutexHolder holder(_lock);
00358   set_state(0);
00359   clear_state_def(0);
00360 
00361   if (vertical) {
00362     set_frame(-width / 2.0f, width / 2.0f, -length / 2.0f, length / 2.0f);
00363     _axis = LVector3::rfu(0.0f, 0.0f, -1.0f);
00364   } else {
00365     set_frame(-length / 2.0f, length / 2.0f, -width / 2.0f, width / 2.0f);
00366     _axis = LVector3::rfu(1.0f, 0.0f, 0.0f);
00367   }
00368 
00369   PGFrameStyle style;
00370   style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
00371   style.set_type(PGFrameStyle::T_flat);
00372   style.set_visible_scale(1.0f, 0.25f);
00373   style.set_width(bevel, bevel);
00374   set_frame_style(0, style);
00375 
00376   // Remove the button nodes created by a previous call to setup(), if
00377   // any.
00378   if (_thumb_button != (PGButton *)NULL) {
00379     remove_child(_thumb_button);
00380     set_thumb_button(NULL);
00381   }
00382   if (_left_button != (PGButton *)NULL) {
00383     remove_child(_left_button);
00384     set_left_button(NULL);
00385   }
00386   if (_right_button != (PGButton *)NULL) {
00387     remove_child(_right_button);
00388     set_right_button(NULL);
00389   }
00390 
00391   PT(PGButton) thumb = new PGButton("thumb");
00392   thumb->setup(" ", bevel);
00393   thumb->set_frame(-width / 4.0f, width / 4.0f, 
00394                    -width / 2.0f, width / 2.0f);
00395   add_child(thumb);
00396   set_thumb_button(thumb);
00397 
00398   set_resize_thumb(false);
00399   set_manage_pieces(true);
00400 }
00401 
00402 ////////////////////////////////////////////////////////////////////
00403 //     Function: PGSliderBar::set_active
00404 //       Access: Published, Virtual
00405 //  Description: Sets whether the PGItem is active for mouse watching.
00406 //               This is not necessarily related to the
00407 //               active/inactive appearance of the item, which is
00408 //               controlled by set_state(), but it does affect whether
00409 //               it responds to mouse events.
00410 ////////////////////////////////////////////////////////////////////
00411 void PGSliderBar::
00412 set_active(bool active) {
00413   LightReMutexHolder holder(_lock);
00414   PGItem::set_active(active);
00415 
00416   // This also implicitly sets the managed pieces.
00417   if (_thumb_button != (PGButton *)NULL) {
00418     _thumb_button->set_active(active);
00419   }
00420   if (_left_button != (PGButton *)NULL) {
00421     _left_button->set_active(active);
00422   }
00423   if (_right_button != (PGButton *)NULL) {
00424     _right_button->set_active(active);
00425   }
00426 }
00427 
00428 ////////////////////////////////////////////////////////////////////
00429 //     Function: PGSliderBar::remanage
00430 //       Access: Published
00431 //  Description: Manages the position and size of the scroll bars and
00432 //               the thumb.  Normally this should not need to be
00433 //               called directly.
00434 ////////////////////////////////////////////////////////////////////
00435 void PGSliderBar::
00436 remanage() {
00437   LightReMutexHolder holder(_lock);
00438   _needs_remanage = false;
00439 
00440   const LVecBase4 &frame = get_frame();
00441 
00442   PN_stdfloat width, length;
00443   if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) {
00444     // The slider is X-dominant.
00445     width = frame[3] - frame[2];
00446     length = frame[1] - frame[0];
00447     
00448   } else {
00449     // The slider is Y-dominant.
00450     width = frame[1] - frame[0];
00451     length = frame[3] - frame[2];
00452   }
00453 
00454   LVector3 center = LVector3::rfu((frame[0] + frame[1]) / 2.0f,
00455                                     0.0f,
00456                                     (frame[2] + frame[3]) / 2.0f);
00457 
00458   if (_left_button != (PGButton *)NULL) {
00459     _left_button->set_frame(-width / 2.0f, width / 2.0f, 
00460                             -width / 2.0f, width / 2.0f);
00461     _left_button->set_transform(TransformState::make_pos(center + ((width - length) / 2.0f) * _axis));
00462   }
00463 
00464   if (_right_button != (PGButton *)NULL) {
00465     _right_button->set_frame(-width / 2.0f, width / 2.0f, 
00466                              -width / 2.0f, width / 2.0f);
00467     _right_button->set_transform(TransformState::make_pos(center + ((length - width) / 2.0f) * _axis));
00468   }
00469 
00470   if (_thumb_button != (PGButton *)NULL) {
00471     _thumb_button->set_frame(-width / 2.0f, width / 2.0f, 
00472                              -width / 2.0f, width / 2.0f);
00473     _thumb_button->set_transform(TransformState::make_pos(center));
00474   }
00475 
00476   recompute();
00477 }
00478 
00479 ////////////////////////////////////////////////////////////////////
00480 //     Function: PGSliderBar::recompute
00481 //       Access: Published
00482 //  Description: Recomputes the position and size of the thumb.
00483 //               Normally this should not need to be called directly.
00484 ////////////////////////////////////////////////////////////////////
00485 void PGSliderBar::
00486 recompute() {
00487   LightReMutexHolder holder(_lock);
00488   _needs_recompute = false;
00489 
00490   if (_min_value != _max_value) {
00491     _scroll_ratio = fabs(_scroll_value / (_max_value - _min_value));
00492     _page_ratio = fabs(_page_value / (_max_value - _min_value));
00493 
00494   } else {
00495     _scroll_ratio = 0.0f;
00496     _page_ratio = 0.0f;
00497   }
00498 
00499   if (!has_frame()) {
00500     _min_x = 0.0f;
00501     _max_x = 0.0f;
00502     _thumb_width = 0.0f;
00503     _range_x = 0.0f;
00504     _thumb_start.set(0.0f, 0.0f, 0.0f);
00505 
00506   } else {
00507     LVecBase4 frame = get_frame();
00508     reduce_region(frame, _left_button);
00509     reduce_region(frame, _right_button);
00510     
00511     if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) {
00512       // The slider is X-dominant.
00513       
00514       _min_x = frame[0];
00515       _max_x = frame[1];
00516       
00517       PN_stdfloat trough_width = _max_x - _min_x;
00518       
00519       if (_thumb_button == (PGButton *)NULL) {
00520         _thumb_width = 0.0f;
00521         _range_x = 0.0f;
00522         _thumb_start.set(0.0f, 0.0f, 0.0f);
00523         
00524       } else {
00525         const LVecBase4 &thumb_frame = _thumb_button->get_frame();
00526         
00527         if (_resize_thumb) {
00528           // If we're allowed to adjust the thumb's size, we don't need to
00529           // find out how wide it is.
00530           _thumb_width = trough_width * min((PN_stdfloat)1.0, _page_ratio);
00531           _thumb_button->set_frame(-_thumb_width / 2.0f, _thumb_width / 2.0f,
00532                                    thumb_frame[2], thumb_frame[3]);
00533         } else {
00534           // If we're not adjusting the thumb's size, we do need to know
00535           // its current width.
00536           _thumb_width = thumb_frame[1] - thumb_frame[0];
00537         }
00538         
00539         _range_x = trough_width - _thumb_width;
00540         
00541         if (_axis[0] >= 0.0f) {
00542           // The slider runs forwards, left to right.
00543           _thumb_start = (_min_x - thumb_frame[0]) * _axis;
00544         } else {
00545           // The slider runs backwards: right to left.
00546           _thumb_start = (thumb_frame[1] - _max_x) * _axis;
00547         }
00548         _thumb_start += LVector3::rfu(0.0f, 0.0f, (frame[2] + frame[3]) / 2.0f);
00549       }
00550       
00551     } else {
00552       // The slider is Y-dominant.  We call it X in the variable names,
00553       // but it's really Y (or even Z).
00554       
00555       _min_x = frame[2];
00556       _max_x = frame[3];
00557       
00558       PN_stdfloat trough_width = _max_x - _min_x;
00559       
00560       if (_thumb_button == (PGButton *)NULL) {
00561         _thumb_width = 0.0f;
00562         _range_x = 0.0f;
00563         _thumb_start.set(0.0f, 0.0f, 0.0f);
00564         
00565       } else {
00566         const LVecBase4 &thumb_frame = _thumb_button->get_frame();
00567         
00568         if (_resize_thumb) {
00569           // If we're allowed to adjust the thumb's size, we don't need to
00570           // find out how wide it is.
00571           _thumb_width = trough_width * min((PN_stdfloat)1.0, _page_ratio);
00572           _thumb_button->set_frame(thumb_frame[0], thumb_frame[1],
00573                                    -_thumb_width / 2.0f, _thumb_width / 2.0f);
00574         } else {
00575           // If we're not adjusting the thumb's size, we do need to know
00576           // its current width.
00577           _thumb_width = thumb_frame[3] - thumb_frame[2];
00578         }
00579         
00580         _range_x = trough_width - _thumb_width;
00581         
00582         if (_axis[1] >= 0.0f && _axis[2] >= 0.0f) {
00583           // The slider runs forwards, bottom to top.
00584           _thumb_start = (_min_x - thumb_frame[2]) * _axis;
00585         } else {
00586           // The slider runs backwards: top to bottom.
00587           _thumb_start = (thumb_frame[3] - _max_x) * _axis;
00588         }
00589         _thumb_start += LVector3::rfu((frame[0] + frame[1]) / 2.0f, 0.0f, 0.0f);
00590       }
00591     }
00592   }
00593 
00594   reposition();
00595 }
00596 
00597 ////////////////////////////////////////////////////////////////////
00598 //     Function: PGSliderBar::frame_changed
00599 //       Access: Protected, Virtual
00600 //  Description: Called when the user changes the frame size.
00601 ////////////////////////////////////////////////////////////////////
00602 void PGSliderBar::
00603 frame_changed() {
00604   LightReMutexHolder holder(_lock);
00605   PGItem::frame_changed();
00606   _needs_remanage = true;
00607   _needs_recompute = true;
00608 }
00609 
00610 ////////////////////////////////////////////////////////////////////
00611 //     Function: PGSliderBar::item_transform_changed
00612 //       Access: Protected, Virtual
00613 //  Description: Called whenever a watched PGItem's local transform
00614 //               has been changed.
00615 ////////////////////////////////////////////////////////////////////
00616 void PGSliderBar::
00617 item_transform_changed(PGItem *) {
00618   LightReMutexHolder holder(_lock);
00619   _needs_recompute = true;
00620 }
00621 
00622 ////////////////////////////////////////////////////////////////////
00623 //     Function: PGSliderBar::item_frame_changed
00624 //       Access: Protected, Virtual
00625 //  Description: Called whenever a watched PGItem's frame
00626 //               has been changed.
00627 ////////////////////////////////////////////////////////////////////
00628 void PGSliderBar::
00629 item_frame_changed(PGItem *) {
00630   LightReMutexHolder holder(_lock);
00631   _needs_recompute = true;
00632 }
00633 
00634 ////////////////////////////////////////////////////////////////////
00635 //     Function: PGSliderBar::item_draw_mask_changed
00636 //       Access: Protected, Virtual
00637 //  Description: Called whenever a watched PGItem's draw_mask
00638 //               has been changed.
00639 ////////////////////////////////////////////////////////////////////
00640 void PGSliderBar::
00641 item_draw_mask_changed(PGItem *) {
00642   LightReMutexHolder holder(_lock);
00643   _needs_recompute = true;
00644 }
00645 
00646 ////////////////////////////////////////////////////////////////////
00647 //     Function: PGSliderBar::item_press
00648 //       Access: Protected, Virtual
00649 //  Description: Called whenever the "press" event is triggered on a
00650 //               watched PGItem.  See PGItem::press().
00651 ////////////////////////////////////////////////////////////////////
00652 void PGSliderBar::
00653 item_press(PGItem *item, const MouseWatcherParameter &param) {
00654   LightReMutexHolder holder(_lock);
00655   if (param.has_mouse()) {
00656     _mouse_pos = param.get_mouse();
00657   }
00658   if (item == _left_button || item == _right_button) {
00659     _scroll_button_held = item;
00660     _mouse_button_page = false;
00661     advance_scroll();
00662     _next_advance_time = 
00663       ClockObject::get_global_clock()->get_frame_time() + scroll_initial_delay;
00664 
00665   } else if (item == _thumb_button) {
00666     _scroll_button_held = NULL;
00667     begin_drag();
00668   }
00669 }
00670 
00671 ////////////////////////////////////////////////////////////////////
00672 //     Function: PGSliderBar::item_release
00673 //       Access: Protected, Virtual
00674 //  Description: Called whenever the "release" event is triggered on a
00675 //               watched PGItem.  See PGItem::release().
00676 ////////////////////////////////////////////////////////////////////
00677 void PGSliderBar::
00678 item_release(PGItem *item, const MouseWatcherParameter &) {
00679   LightReMutexHolder holder(_lock);
00680   if (item == _scroll_button_held) {
00681     _scroll_button_held = NULL;
00682 
00683   } else if (item == _thumb_button) {
00684     _scroll_button_held = NULL;
00685     if (_dragging) {
00686       end_drag();
00687     }
00688   }
00689 }
00690 
00691 ////////////////////////////////////////////////////////////////////
00692 //     Function: PGSliderBar::item_move
00693 //       Access: Protected, Virtual
00694 //  Description: Called whenever the "move" event is triggered on a
00695 //               watched PGItem.  See PGItem::move().
00696 ////////////////////////////////////////////////////////////////////
00697 void PGSliderBar::
00698 item_move(PGItem *item, const MouseWatcherParameter &param) {
00699   LightReMutexHolder holder(_lock);
00700   _mouse_pos = param.get_mouse();
00701   if (item == _thumb_button) {
00702     if (_dragging) {
00703       continue_drag();
00704     }
00705   }
00706 }
00707 
00708 ////////////////////////////////////////////////////////////////////
00709 //     Function: PGSliderBar::reposition
00710 //       Access: Private
00711 //  Description: A lighter-weight version of recompute(), this just
00712 //               moves the thumb, assuming all other properties are
00713 //               unchanged.
00714 ////////////////////////////////////////////////////////////////////
00715 void PGSliderBar::
00716 reposition() {
00717   _needs_reposition = false;
00718 
00719   PN_stdfloat t = get_ratio();
00720   
00721   if (_thumb_button != (PGButton *)NULL) {
00722     LPoint3 pos = (t * _range_x) * _axis + _thumb_start;
00723     CPT(TransformState) transform = TransformState::make_pos(pos);
00724     CPT(TransformState) orig_transform = _thumb_button->get_transform();
00725 
00726     // It's important not to update the transform frivolously, or
00727     // we'll get caught in an update loop.
00728     if (transform == orig_transform) {
00729       // No change.
00730     } else if (*transform < *orig_transform || *orig_transform < *transform) {
00731       _thumb_button->set_transform(transform);
00732     }
00733   }
00734 }
00735 
00736 ////////////////////////////////////////////////////////////////////
00737 //     Function: PGSliderBar::advance_scroll
00738 //       Access: Private
00739 //  Description: Advances the scroll bar by one unit in the left or
00740 //               right direction while the user is holding down the
00741 //               left or right scroll button.
00742 ////////////////////////////////////////////////////////////////////
00743 void PGSliderBar::
00744 advance_scroll() {
00745   if (_scroll_button_held == _left_button) {
00746     internal_set_ratio(max(_ratio - _scroll_ratio, (PN_stdfloat)0.0));
00747 
00748   } else if (_scroll_button_held == _right_button) {
00749     internal_set_ratio(min(_ratio + _scroll_ratio, (PN_stdfloat)1.0));
00750   }
00751 
00752   _next_advance_time = 
00753     ClockObject::get_global_clock()->get_frame_time() + scroll_continued_delay;
00754 }
00755 
00756 ////////////////////////////////////////////////////////////////////
00757 //     Function: PGSliderBar::advance_page
00758 //       Access: Private
00759 //  Description: Advances the scroll bar by one page in the left or
00760 //               right direction while the user is holding down the
00761 //               mouse button on the track.
00762 ////////////////////////////////////////////////////////////////////
00763 void PGSliderBar::
00764 advance_page() {
00765   // Is the mouse position left or right of the current thumb
00766   // position?
00767   LPoint3 mouse = mouse_to_local(_mouse_pos) - _thumb_start;
00768   PN_stdfloat target_ratio = mouse.dot(_axis) / _range_x;
00769 
00770   PN_stdfloat t;
00771   if (target_ratio < _ratio) {
00772     t = max(_ratio - _page_ratio + _scroll_ratio, target_ratio);
00773 
00774   } else {
00775     t = min(_ratio + _page_ratio - _scroll_ratio, target_ratio);
00776   }
00777   internal_set_ratio(t);
00778   if (t == target_ratio) {
00779     // We made it; begin dragging from now on until the user releases
00780     // the mouse.
00781     begin_drag();
00782   }
00783 
00784   _next_advance_time = 
00785     ClockObject::get_global_clock()->get_frame_time() + scroll_continued_delay;
00786 }
00787 
00788 ////////////////////////////////////////////////////////////////////
00789 //     Function: PGSliderBar::begin_drag
00790 //       Access: Private
00791 //  Description: Called when the user clicks down on the thumb button,
00792 //               possibly to begin dragging.
00793 ////////////////////////////////////////////////////////////////////
00794 void PGSliderBar::
00795 begin_drag() {
00796   if (_needs_recompute) {
00797     recompute();
00798   }
00799   if (_range_x != 0.0f) {
00800     PN_stdfloat current_x = mouse_to_local(_mouse_pos).dot(_axis);
00801     _drag_start_x = current_x - get_ratio() * _range_x;
00802     _dragging = true;
00803   }
00804 }
00805 
00806 ////////////////////////////////////////////////////////////////////
00807 //     Function: PGSliderBar::continue_drag
00808 //       Access: Private
00809 //  Description: Called as the user moves the mouse while still
00810 //               dragging on the thumb button.
00811 ////////////////////////////////////////////////////////////////////
00812 void PGSliderBar::
00813 continue_drag() {
00814   if (_needs_recompute) {
00815     recompute();
00816   }
00817   if (_range_x != 0.0f) {
00818     PN_stdfloat current_x = mouse_to_local(_mouse_pos).dot(_axis);
00819     internal_set_ratio((current_x - _drag_start_x) / _range_x);
00820   }
00821 }
00822 
00823 ////////////////////////////////////////////////////////////////////
00824 //     Function: PGSliderBar::end_drag
00825 //       Access: Private
00826 //  Description: Called as the user releases the mouse after dragging.
00827 ////////////////////////////////////////////////////////////////////
00828 void PGSliderBar::
00829 end_drag() {
00830   _dragging = false;
00831 }
 All Classes Functions Variables Enumerations