Panda3D
 All Classes Functions Variables Enumerations
pgScrollFrame.cxx
1 // Filename: pgScrollFrame.cxx
2 // Created by: drose (17Aug05)
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 "pgScrollFrame.h"
16 
17 TypeHandle PGScrollFrame::_type_handle;
18 
19 ////////////////////////////////////////////////////////////////////
20 // Function: PGScrollFrame::Constructor
21 // Access: Published
22 // Description:
23 ////////////////////////////////////////////////////////////////////
24 PGScrollFrame::
25 PGScrollFrame(const string &name) : PGVirtualFrame(name)
26 {
27  set_cull_callback();
28 
29  _needs_remanage = false;
30  _needs_recompute_canvas = false;
31  _needs_recompute_clip = false;
32  _has_virtual_frame = false;
33  _virtual_frame.set(0.0f, 0.0f, 0.0f, 0.0f);
34  _manage_pieces = false;
35  _auto_hide = false;
36  _horizontal_slider = NULL;
37  _vertical_slider = NULL;
38 }
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: PGScrollFrame::Destructor
42 // Access: Public, Virtual
43 // Description:
44 ////////////////////////////////////////////////////////////////////
45 PGScrollFrame::
46 ~PGScrollFrame() {
48  set_vertical_slider(NULL);
49 }
50 
51 ////////////////////////////////////////////////////////////////////
52 // Function: PGScrollFrame::Copy Constructor
53 // Access: Protected
54 // Description:
55 ////////////////////////////////////////////////////////////////////
56 PGScrollFrame::
57 PGScrollFrame(const PGScrollFrame &copy) :
58  PGVirtualFrame(copy),
59  _has_virtual_frame(copy._has_virtual_frame),
60  _virtual_frame(copy._virtual_frame),
61  _manage_pieces(copy._manage_pieces),
62  _auto_hide(copy._auto_hide)
63 {
64  _needs_remanage = false;
65  _needs_recompute_canvas = true;
66  _needs_recompute_clip = true;
67 }
68 
69 ////////////////////////////////////////////////////////////////////
70 // Function: PGScrollFrame::make_copy
71 // Access: Public, Virtual
72 // Description: Returns a newly-allocated Node that is a shallow copy
73 // of this one. It will be a different Node pointer,
74 // but its internal data may or may not be shared with
75 // that of the original Node.
76 ////////////////////////////////////////////////////////////////////
78 make_copy() const {
79  LightReMutexHolder holder(_lock);
80  return new PGScrollFrame(*this);
81 }
82 
83 ////////////////////////////////////////////////////////////////////
84 // Function: PGScrollFrame::cull_callback
85 // Access: Protected, Virtual
86 // Description: This function will be called during the cull
87 // traversal to perform any additional operations that
88 // should be performed at cull time. This may include
89 // additional manipulation of render state or additional
90 // visible/invisible decisions, or any other arbitrary
91 // operation.
92 //
93 // Note that this function will *not* be called unless
94 // set_cull_callback() is called in the constructor of
95 // the derived class. It is necessary to call
96 // set_cull_callback() to indicated that we require
97 // cull_callback() to be called.
98 //
99 // By the time this function is called, the node has
100 // already passed the bounding-volume test for the
101 // viewing frustum, and the node's transform and state
102 // have already been applied to the indicated
103 // CullTraverserData object.
104 //
105 // The return value is true if this node should be
106 // visible, or false if it should be culled.
107 ////////////////////////////////////////////////////////////////////
108 bool PGScrollFrame::
110  LightReMutexHolder holder(_lock);
111  if (_manage_pieces && _needs_remanage) {
112  remanage();
113  }
114  if (_needs_recompute_clip) {
115  recompute_clip();
116  }
117  if (_needs_recompute_canvas) {
118  recompute_canvas();
119  }
120  return PGVirtualFrame::cull_callback(trav, data);
121 }
122 
123 ////////////////////////////////////////////////////////////////////
124 // Function: PGScrollFrame::xform
125 // Access: Public, Virtual
126 // Description: Transforms the contents of this node by the indicated
127 // matrix, if it means anything to do so. For most
128 // kinds of nodes, this does nothing.
129 ////////////////////////////////////////////////////////////////////
130 void PGScrollFrame::
131 xform(const LMatrix4 &mat) {
132  LightReMutexHolder holder(_lock);
134 
135  _needs_remanage = true;
136  _needs_recompute_clip = true;
137 }
138 
139 ////////////////////////////////////////////////////////////////////
140 // Function: PGScrollFrame::setup
141 // Access: Published
142 // Description: Creates a PGScrollFrame with the indicated
143 // dimensions, and the indicated virtual frame.
144 ////////////////////////////////////////////////////////////////////
145 void PGScrollFrame::
146 setup(PN_stdfloat width, PN_stdfloat height,
147  PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top,
148  PN_stdfloat slider_width, PN_stdfloat bevel) {
149  LightReMutexHolder holder(_lock);
150  set_state(0);
151  clear_state_def(0);
152 
153  set_frame(0, width, 0, height);
154 
155  PGFrameStyle style;
156  style.set_width(bevel, bevel);
157 
158  style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
159  style.set_type(PGFrameStyle::T_ridge);
160  set_frame_style(0, style);
161 
162  set_clip_frame(bevel, width - bevel,
163  bevel, height - bevel);
164 
165  set_virtual_frame(left, right, bottom, top);
166 
167  // Remove the slider nodes created by a previous call to setup(), if
168  // any.
169  if (_horizontal_slider != (PGSliderBar *)NULL) {
170  remove_child(_horizontal_slider);
171  set_horizontal_slider(NULL);
172  }
173  if (_vertical_slider != (PGSliderBar *)NULL) {
174  remove_child(_vertical_slider);
175  set_vertical_slider(NULL);
176  }
177 
178  // Create new slider bars.
179  PT(PGSliderBar) horizontal_slider = new PGSliderBar("horizontal");
180  horizontal_slider->setup_scroll_bar(false, width - slider_width - bevel * 2, slider_width, bevel);
181  horizontal_slider->set_transform(TransformState::make_pos(LVector3::rfu(width / 2.0f - slider_width / 2.0f, 0, slider_width / 2.0f + bevel)));
182  add_child(horizontal_slider);
183  set_horizontal_slider(horizontal_slider);
184 
185  PT(PGSliderBar) vertical_slider = new PGSliderBar("vertical");
186  vertical_slider->setup_scroll_bar(true, width - slider_width - bevel * 2, slider_width, bevel);
187  add_child(vertical_slider);
188  vertical_slider->set_transform(TransformState::make_pos(LVector3::rfu(width - slider_width / 2.0f - bevel, 0, width / 2.0f + slider_width / 2.0f)));
189  set_vertical_slider(vertical_slider);
190 
191  set_manage_pieces(true);
192  set_auto_hide(true);
193 }
194 
195 ////////////////////////////////////////////////////////////////////
196 // Function: PGScrollFrame::remanage
197 // Access: Published
198 // Description: Manages the position and size of the scroll bars.
199 // Normally this should not need to be called directly.
200 ////////////////////////////////////////////////////////////////////
201 void PGScrollFrame::
203  LightReMutexHolder holder(_lock);
204  _needs_remanage = false;
205 
206  const LVecBase4 &frame = get_frame();
208 
209  // Determine which scroll bars we have in the frame.
210 
211  bool got_horizontal = false;
212  PN_stdfloat horizontal_width = 0.0f;
213  if (_horizontal_slider != (PGSliderBar *)NULL) {
214  got_horizontal = true;
215  const LVecBase4 &slider_frame = _horizontal_slider->get_frame();
216  horizontal_width = slider_frame[3] - slider_frame[2];
217  }
218 
219  bool got_vertical = false;
220  PN_stdfloat vertical_width = 0.0f;
221  if (_vertical_slider != (PGSliderBar *)NULL) {
222  got_vertical = true;
223  const LVecBase4 &slider_frame = _vertical_slider->get_frame();
224  vertical_width = slider_frame[1] - slider_frame[0];
225  }
226 
227  if (_auto_hide) {
228  // Should we hide or show either of the scroll bars? TODO.
229 
230  // Start by figuring out what our maximum clipping area will be.
231  PN_stdfloat clip_width = clip[1] - clip[0];
232  PN_stdfloat clip_height = clip[3] - clip[2];
233 
234  // And our virtual frame too.
235  const LVecBase4 &virtual_frame = get_virtual_frame();
236  PN_stdfloat virtual_width = virtual_frame[1] - virtual_frame[0];
237  PN_stdfloat virtual_height = virtual_frame[3] - virtual_frame[2];
238 
239  if (virtual_width <= clip_width &&
240  virtual_height <= clip_height) {
241  // No need for either slider.
242  got_horizontal = false;
243  got_vertical = false;
244 
245  } else {
246  if (virtual_width <= clip_width - vertical_width) {
247  // No need for the horizontal slider.
248  got_horizontal = false;
249  }
250 
251  if (virtual_height <= clip_height - horizontal_width) {
252  // No need for the vertical slider.
253  got_vertical = false;
254 
255  // Now reconsider the need for the horizontal slider.
256  if (virtual_width <= clip_width) {
257  got_horizontal = false;
258  }
259  }
260  }
261 
262  // Now show or hide the sliders appropriately.
263  if (_horizontal_slider != (PGSliderBar *)NULL) {
264  if (got_horizontal) {
265  _horizontal_slider->set_overall_hidden(false);
266  } else {
267  _horizontal_slider->set_overall_hidden(true);
268  _horizontal_slider->set_ratio(0.0f);
269  horizontal_width = 0.0f;
270  }
271  }
272  if (_vertical_slider != (PGSliderBar *)NULL) {
273  if (got_vertical) {
274  _vertical_slider->set_overall_hidden(false);
275  } else {
276  _vertical_slider->set_overall_hidden(true);
277  _vertical_slider->set_ratio(0.0f);
278  vertical_width = 0.0f;
279  }
280  }
281 
282  // Showing or hiding one of the scroll bars might have set this
283  // flag again indirectly; we clear it again to avoid a feedback
284  // loop.
285  _needs_remanage = false;
286 }
287 
288  // Are either or both of the scroll bars hidden?
289  if (got_horizontal && _horizontal_slider->is_overall_hidden()) {
290  got_horizontal = false;
291  horizontal_width = 0.0f;
292  }
293  if (got_vertical && _vertical_slider->is_overall_hidden()) {
294  got_vertical = false;
295  vertical_width = 0.0f;
296  }
297 
298  if (got_horizontal) {
299  _horizontal_slider->set_frame(clip[0], clip[1] - vertical_width,
300  clip[2], clip[2] + horizontal_width);
301  _horizontal_slider->clear_transform();
302  }
303  if (got_vertical) {
304  _vertical_slider->set_frame(clip[1] - vertical_width, clip[1],
305  clip[2] + horizontal_width, clip[3]);
306  _vertical_slider->clear_transform();
307  }
308 
309 
310  recompute();
311 }
312 
313 ////////////////////////////////////////////////////////////////////
314 // Function: PGScrollFrame::frame_changed
315 // Access: Protected, Virtual
316 // Description: Called when the user changes the frame size.
317 ////////////////////////////////////////////////////////////////////
318 void PGScrollFrame::
319 frame_changed() {
320  LightReMutexHolder holder(_lock);
321  PGVirtualFrame::frame_changed();
322  _needs_remanage = true;
323  _needs_recompute_clip = true;
324 }
325 
326 ////////////////////////////////////////////////////////////////////
327 // Function: PGScrollFrame::item_transform_changed
328 // Access: Protected, Virtual
329 // Description: Called whenever a watched PGItem's local transform
330 // has been changed.
331 ////////////////////////////////////////////////////////////////////
332 void PGScrollFrame::
333 item_transform_changed(PGItem *) {
334  LightReMutexHolder holder(_lock);
335  _needs_recompute_clip = true;
336 }
337 
338 ////////////////////////////////////////////////////////////////////
339 // Function: PGScrollFrame::item_frame_changed
340 // Access: Protected, Virtual
341 // Description: Called whenever a watched PGItem's frame
342 // has been changed.
343 ////////////////////////////////////////////////////////////////////
344 void PGScrollFrame::
345 item_frame_changed(PGItem *) {
346  LightReMutexHolder holder(_lock);
347  _needs_recompute_clip = true;
348 }
349 
350 ////////////////////////////////////////////////////////////////////
351 // Function: PGScrollFrame::item_draw_mask_changed
352 // Access: Protected, Virtual
353 // Description: Called whenever a watched PGItem's draw_mask
354 // has been changed.
355 ////////////////////////////////////////////////////////////////////
356 void PGScrollFrame::
357 item_draw_mask_changed(PGItem *) {
358  LightReMutexHolder holder(_lock);
359  _needs_remanage = true;
360  _needs_recompute_clip = true;
361 }
362 
363 ////////////////////////////////////////////////////////////////////
364 // Function: PGScrollFrame::slider_bar_adjust
365 // Access: Protected, Virtual
366 // Description: Called whenever a watched PGSliderBar's value
367 // has been changed by the user or programmatically.
368 ////////////////////////////////////////////////////////////////////
369 void PGScrollFrame::
370 slider_bar_adjust(PGSliderBar *) {
371  LightReMutexHolder holder(_lock);
372  _needs_recompute_canvas = true;
373 }
374 
375 ////////////////////////////////////////////////////////////////////
376 // Function: PGScrollFrame::recompute_clip
377 // Access: Private
378 // Description: Recomputes the clipping window of the PGScrollFrame,
379 // based on the position of the slider bars.
380 ////////////////////////////////////////////////////////////////////
381 void PGScrollFrame::
382 recompute_clip() {
383  LightReMutexHolder holder(_lock);
384  _needs_recompute_clip = false;
385  _needs_recompute_canvas = true;
386 
387  // Figure out how to remove the scroll bars from the clip region.
389  reduce_region(clip, _horizontal_slider);
390  reduce_region(clip, _vertical_slider);
391 
392  set_clip_frame(clip);
393 
394  if (_horizontal_slider != (PGSliderBar *)NULL) {
395  _horizontal_slider->set_page_size((clip[1] - clip[0]) / (_virtual_frame[1] - _virtual_frame[0]));
396  }
397  if (_vertical_slider != (PGSliderBar *)NULL) {
398  _vertical_slider->set_page_size((clip[3] - clip[2]) / (_virtual_frame[3] - _virtual_frame[2]));
399  }
400 }
401 
402 ////////////////////////////////////////////////////////////////////
403 // Function: PGScrollFrame::recompute_canvas
404 // Access: Private
405 // Description: Recomputes the portion of the virtual canvas that is
406 // visible within the PGScrollFrame, based on the values
407 // of the slider bars.
408 ////////////////////////////////////////////////////////////////////
409 void PGScrollFrame::
410 recompute_canvas() {
411  LightReMutexHolder holder(_lock);
412  _needs_recompute_canvas = false;
413 
414  const LVecBase4 &clip = get_clip_frame();
415 
416  PN_stdfloat x = interpolate_canvas(clip[0], clip[1],
417  _virtual_frame[0], _virtual_frame[1],
418  _horizontal_slider);
419 
420  PN_stdfloat y = interpolate_canvas(clip[3], clip[2],
421  _virtual_frame[3], _virtual_frame[2],
422  _vertical_slider);
423 
424  get_canvas_node()->set_transform(TransformState::make_pos(LVector3::rfu(x, 0, y)));
425 }
426 
427 ////////////////////////////////////////////////////////////////////
428 // Function: PGScrollFrame::interpolate_canvas
429 // Access: Private
430 // Description: Computes the linear translation that should be
431 // applied to the virtual canvas node, based on the
432 // corresponding slider bar's position.
433 ////////////////////////////////////////////////////////////////////
434 PN_stdfloat PGScrollFrame::
435 interpolate_canvas(PN_stdfloat clip_min, PN_stdfloat clip_max,
436  PN_stdfloat canvas_min, PN_stdfloat canvas_max,
437  PGSliderBar *slider_bar) {
438  LightReMutexHolder holder(_lock);
439  PN_stdfloat t = 0.0f;
440  if (slider_bar != (PGSliderBar *)NULL) {
441  t = slider_bar->get_ratio();
442  }
443 
444  PN_stdfloat min = clip_min - canvas_min;
445  PN_stdfloat max = clip_max - canvas_max;
446 
447  return min + t * (max - min);
448 }
void recompute()
Forces the PGScrollFrame to recompute itself right now.
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_width(PN_stdfloat x, PN_stdfloat y)
Sets the width parameter, which has meaning only for certain frame types.
Definition: pgFrameStyle.I:172
PGFrameStyle get_frame_style(int state)
Returns the kind of frame that will be drawn behind the item when it is in the indicated state...
Definition: pgItem.cxx:1087
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
This is the base class for all the various kinds of gui widget objects.
Definition: pgItem.h:58
This represents a frame that is rendered as a window onto another (possibly much larger) canvas...
void set_clip_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets the bounding rectangle of the clip frame.
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 ...
void set_manage_pieces(bool manage_pieces)
Sets the manage_pieces flag.
Definition: pgScrollFrame.I:98
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
const LVecBase4 & get_clip_frame() const
Returns the bounding rectangle of the clip frame.
void set_vertical_slider(PGSliderBar *vertical_slider)
Sets the PGSliderBar object that will serve as the vertical scroll bar for this frame.
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
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
int get_state() const
Returns the &quot;state&quot; of this particular PGItem.
Definition: pgItem.I:187
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
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
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Similar to MutexHolder, but for a light reentrant mutex.
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
void set_state(int state)
Sets the &quot;state&quot; of this particular PGItem.
Definition: pgItem.I:175
PandaNode * get_canvas_node() const
Returns the special node that holds all of the children that appear in the virtual canvas...
void set_auto_hide(bool auto_hide)
Sets the auto_hide flag.
LVecBase4 get_internal_frame(const LVecBase4 &frame) const
Computes the size of the internal frame, given the indicated external frame, appropriate for this kin...
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_virtual_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets the bounding rectangle of the virtual frame.
Definition: pgScrollFrame.I:24
void remanage()
Manages the position and size of the scroll bars.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
void setup(PN_stdfloat width, PN_stdfloat height, PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top, PN_stdfloat slider_width, PN_stdfloat bevel)
Creates a PGScrollFrame with the indicated dimensions, and the indicated virtual frame.
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
This is a special kind of frame that pretends to be much larger than it actually is.
Definition: pgScrollFrame.h:39
const LVecBase4 & get_virtual_frame() const
Returns the bounding rectangle of the virtual frame.
Definition: pgScrollFrame.I:55
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Sets the transform that will be applied to this node and below.
Definition: pandaNode.cxx:1267
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
PN_stdfloat get_ratio() const
Returns the current value of the slider, expressed in the range 0 .
Definition: pgSliderBar.I:219
void set_horizontal_slider(PGSliderBar *horizontal_slider)
Sets the PGSliderBar object that will serve as the horizontal scroll bar for this frame...
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