Panda3D
|
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 ©) : 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 ¶m, 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 ¶m, 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 ¶m) { 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 ¶m) { 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 ¶m) { 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 }