Panda3D
Loading...
Searching...
No Matches
pgScrollFrame.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file pgScrollFrame.cxx
10 * @author drose
11 * @date 2005-08-17
12 */
13
14#include "pgScrollFrame.h"
15
16TypeHandle PGScrollFrame::_type_handle;
17
18/**
19 *
20 */
21PGScrollFrame::
22PGScrollFrame(const std::string &name) :
23 PGVirtualFrame(name),
24 _needs_remanage(false),
25 _needs_recompute_clip(false),
26 _has_virtual_frame(false),
27 _virtual_frame(0.0f, 0.0f, 0.0f, 0.0f),
28 _manage_pieces(false),
29 _auto_hide(false)
30{
31 _canvas_computed.test_and_set();
32
33 set_cull_callback();
34}
35
36/**
37 *
38 */
39PGScrollFrame::
40~PGScrollFrame() {
41 set_horizontal_slider(nullptr);
42 set_vertical_slider(nullptr);
43}
44
45/**
46 *
47 */
48PGScrollFrame::
49PGScrollFrame(const PGScrollFrame &copy) :
50 PGVirtualFrame(copy),
51 _has_virtual_frame(copy._has_virtual_frame),
52 _virtual_frame(copy._virtual_frame),
53 _manage_pieces(copy._manage_pieces),
54 _auto_hide(copy._auto_hide)
55{
56 _needs_remanage = false;
57 _needs_recompute_clip = true;
58 _canvas_computed.clear();
59}
60
61/**
62 * Returns a newly-allocated Node that is a shallow copy of this one. It will
63 * be a different Node pointer, but its internal data may or may not be shared
64 * with that of the original Node.
65 */
67make_copy() const {
68 LightReMutexHolder holder(_lock);
69 return new PGScrollFrame(*this);
70}
71
72/**
73 * This function will be called during the cull traversal to perform any
74 * additional operations that should be performed at cull time. This may
75 * include additional manipulation of render state or additional
76 * visible/invisible decisions, or any other arbitrary operation.
77 *
78 * Note that this function will *not* be called unless set_cull_callback() is
79 * called in the constructor of the derived class. It is necessary to call
80 * set_cull_callback() to indicated that we require cull_callback() to be
81 * called.
82 *
83 * By the time this function is called, the node has already passed the
84 * bounding-volume test for the viewing frustum, and the node's transform and
85 * state have already been applied to the indicated CullTraverserData object.
86 *
87 * The return value is true if this node should be visible, or false if it
88 * should be culled.
89 */
92 LightReMutexHolder holder(_lock);
93 if (_manage_pieces && _needs_remanage) {
94 remanage();
95 }
96 if (_needs_recompute_clip) {
97 recompute_clip();
98 }
99 if (!_canvas_computed.test_and_set()) {
100 recompute_canvas();
101 }
102 return PGVirtualFrame::cull_callback(trav, data);
103}
104
105/**
106 * Transforms the contents of this node by the indicated matrix, if it means
107 * anything to do so. For most kinds of nodes, this does nothing.
108 */
110xform(const LMatrix4 &mat) {
111 LightReMutexHolder holder(_lock);
113
114 _needs_remanage = true;
115 _needs_recompute_clip = true;
116}
117
118/**
119 * Creates a PGScrollFrame with the indicated dimensions, and the indicated
120 * virtual frame.
121 */
123setup(PN_stdfloat width, PN_stdfloat height,
124 PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top,
125 PN_stdfloat slider_width, PN_stdfloat bevel) {
126 LightReMutexHolder holder(_lock);
127 set_state(0);
129
130 set_frame(0, width, 0, height);
131
132 PGFrameStyle style;
133 style.set_width(bevel, bevel);
134
135 style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
136 style.set_type(PGFrameStyle::T_ridge);
137 set_frame_style(0, style);
138
139 set_clip_frame(bevel, width - bevel,
140 bevel, height - bevel);
141
142 set_virtual_frame(left, right, bottom, top);
143
144 // Remove the slider nodes created by a previous call to setup(), if any.
145 if (_horizontal_slider != nullptr) {
146 remove_child(_horizontal_slider);
147 set_horizontal_slider(nullptr);
148 }
149 if (_vertical_slider != nullptr) {
150 remove_child(_vertical_slider);
151 set_vertical_slider(nullptr);
152 }
153
154 // Create new slider bars.
155 PT(PGSliderBar) horizontal_slider = new PGSliderBar("horizontal");
156 horizontal_slider->setup_scroll_bar(false, width - slider_width - bevel * 2, slider_width, bevel);
157 horizontal_slider->set_transform(TransformState::make_pos(LVector3::rfu(width / 2.0f - slider_width / 2.0f, 0, slider_width / 2.0f + bevel)));
158 add_child(horizontal_slider);
159 set_horizontal_slider(horizontal_slider);
160
161 PT(PGSliderBar) vertical_slider = new PGSliderBar("vertical");
162 vertical_slider->setup_scroll_bar(true, width - slider_width - bevel * 2, slider_width, bevel);
163 add_child(vertical_slider);
164 vertical_slider->set_transform(TransformState::make_pos(LVector3::rfu(width - slider_width / 2.0f - bevel, 0, width / 2.0f + slider_width / 2.0f)));
165 set_vertical_slider(vertical_slider);
166
167 set_manage_pieces(true);
168 set_auto_hide(true);
169}
170
171/**
172 * Manages the position and size of the scroll bars. Normally this should not
173 * need to be called directly.
174 */
176remanage() {
177 LightReMutexHolder holder(_lock);
178 _needs_remanage = false;
179
180 const LVecBase4 &frame = get_frame();
181 LVecBase4 clip = get_frame_style(get_state()).get_internal_frame(frame);
182
183 // Determine which scroll bars we have in the frame.
184
185 bool got_horizontal = false;
186 PN_stdfloat horizontal_width = 0.0f;
187 if (_horizontal_slider != nullptr) {
188 got_horizontal = true;
189 const LVecBase4 &slider_frame = _horizontal_slider->get_frame();
190 horizontal_width = slider_frame[3] - slider_frame[2];
191 }
192
193 bool got_vertical = false;
194 PN_stdfloat vertical_width = 0.0f;
195 if (_vertical_slider != nullptr) {
196 got_vertical = true;
197 const LVecBase4 &slider_frame = _vertical_slider->get_frame();
198 vertical_width = slider_frame[1] - slider_frame[0];
199 }
200
201 if (_auto_hide) {
202 // Should we hide or show either of the scroll bars? TODO.
203
204 // Start by figuring out what our maximum clipping area will be.
205 PN_stdfloat clip_width = clip[1] - clip[0];
206 PN_stdfloat clip_height = clip[3] - clip[2];
207
208 // And our virtual frame too.
209 const LVecBase4 &virtual_frame = get_virtual_frame();
210 PN_stdfloat virtual_width = virtual_frame[1] - virtual_frame[0];
211 PN_stdfloat virtual_height = virtual_frame[3] - virtual_frame[2];
212
213 if (virtual_width <= clip_width &&
214 virtual_height <= clip_height) {
215 // No need for either slider.
216 got_horizontal = false;
217 got_vertical = false;
218
219 } else {
220 if (virtual_width <= clip_width - vertical_width) {
221 // No need for the horizontal slider.
222 got_horizontal = false;
223 }
224
225 if (virtual_height <= clip_height - horizontal_width) {
226 // No need for the vertical slider.
227 got_vertical = false;
228
229 // Now reconsider the need for the horizontal slider.
230 if (virtual_width <= clip_width) {
231 got_horizontal = false;
232 }
233 }
234 }
235
236 // Now show or hide the sliders appropriately.
237 if (_horizontal_slider != nullptr) {
238 if (got_horizontal) {
239 _horizontal_slider->set_overall_hidden(false);
240 } else {
241 _horizontal_slider->set_overall_hidden(true);
242 _horizontal_slider->set_ratio(0.0f);
243 horizontal_width = 0.0f;
244 }
245 }
246 if (_vertical_slider != nullptr) {
247 if (got_vertical) {
248 _vertical_slider->set_overall_hidden(false);
249 } else {
250 _vertical_slider->set_overall_hidden(true);
251 _vertical_slider->set_ratio(0.0f);
252 vertical_width = 0.0f;
253 }
254 }
255
256 // Showing or hiding one of the scroll bars might have set this flag again
257 // indirectly; we clear it again to avoid a feedback loop.
258 _needs_remanage = false;
259 }
260
261 // Are either or both of the scroll bars hidden?
262 if (got_horizontal && _horizontal_slider->is_overall_hidden()) {
263 got_horizontal = false;
264 horizontal_width = 0.0f;
265 }
266 if (got_vertical && _vertical_slider->is_overall_hidden()) {
267 got_vertical = false;
268 vertical_width = 0.0f;
269 }
270
271 if (got_horizontal) {
272 _horizontal_slider->set_frame(clip[0], clip[1] - vertical_width,
273 clip[2], clip[2] + horizontal_width);
274 _horizontal_slider->clear_transform();
275 }
276 if (got_vertical) {
277 _vertical_slider->set_frame(clip[1] - vertical_width, clip[1],
278 clip[2] + horizontal_width, clip[3]);
279 _vertical_slider->clear_transform();
280 }
281
282
283 recompute();
284}
285
286/**
287 * Called when the user changes the frame size. Assumes the lock is held.
288 */
289void PGScrollFrame::
290frame_changed() {
291 PGVirtualFrame::frame_changed();
292 _needs_remanage = true;
293 _needs_recompute_clip = true;
294}
295
296/**
297 * Called whenever a watched PGItem's local transform has been changed.
298 */
299void PGScrollFrame::
300item_transform_changed(PGItem *) {
301 LightReMutexHolder holder(_lock);
302 _needs_recompute_clip = true;
303}
304
305/**
306 * Called whenever a watched PGItem's frame has been changed.
307 */
308void PGScrollFrame::
309item_frame_changed(PGItem *) {
310 LightReMutexHolder holder(_lock);
311 _needs_recompute_clip = true;
312}
313
314/**
315 * Called whenever a watched PGItem's draw_mask has been changed.
316 */
317void PGScrollFrame::
318item_draw_mask_changed(PGItem *) {
319 LightReMutexHolder holder(_lock);
320 _needs_remanage = true;
321 _needs_recompute_clip = true;
322}
323
324/**
325 * Called whenever a watched PGSliderBar's value has been changed by the user
326 * or programmatically.
327 */
328void PGScrollFrame::
329slider_bar_adjust(PGSliderBar *) {
330 // Indicate that recompute_canvas() needs to be called.
331 _canvas_computed.clear();
332}
333
334/**
335 * Recomputes the clipping window of the PGScrollFrame, based on the position
336 * of the slider bars.
337 *
338 * Assumes the lock is held.
339 */
340void PGScrollFrame::
341recompute_clip() {
342 _needs_recompute_clip = false;
343 _canvas_computed.clear();
344
345 // Figure out how to remove the scroll bars from the clip region.
347 reduce_region(clip, _horizontal_slider);
348 reduce_region(clip, _vertical_slider);
349
350 set_clip_frame(clip);
351
352 if (_horizontal_slider != nullptr) {
353 _horizontal_slider->set_page_size((clip[1] - clip[0]) / (_virtual_frame[1] - _virtual_frame[0]));
354 }
355 if (_vertical_slider != nullptr) {
356 _vertical_slider->set_page_size((clip[3] - clip[2]) / (_virtual_frame[3] - _virtual_frame[2]));
357 }
358}
359
360/**
361 * Recomputes the portion of the virtual canvas that is visible within the
362 * PGScrollFrame, based on the values of the slider bars.
363 *
364 * Assumes the lock is held.
365 */
366void PGScrollFrame::
367recompute_canvas() {
368 const LVecBase4 &clip = _has_clip_frame ? _clip_frame : get_frame();
369
370 // Set this to true before we sample the slider bar ratios.
371 // If slider_bar_adjust happens to get called while we do this, no big deal,
372 // this method will just be called again next frame.
373 _canvas_computed.test_and_set();
374
375 PN_stdfloat cx, cy;
376 cx = interpolate_canvas(clip[0], clip[1],
377 _virtual_frame[0], _virtual_frame[1],
378 _horizontal_slider);
379
380 cy = interpolate_canvas(clip[3], clip[2],
381 _virtual_frame[3], _virtual_frame[2],
382 _vertical_slider);
383
384 _canvas_node->set_transform(TransformState::make_pos(LVector3::rfu(cx, 0, cy)));
385}
386
387/**
388 * Computes the linear translation that should be applied to the virtual
389 * canvas node, based on the corresponding slider bar's position.
390 *
391 * Assumes the lock is held.
392 */
393PN_stdfloat PGScrollFrame::
394interpolate_canvas(PN_stdfloat clip_min, PN_stdfloat clip_max,
395 PN_stdfloat canvas_min, PN_stdfloat canvas_max,
396 PGSliderBar *slider_bar) {
397 PN_stdfloat t = 0.0f;
398 if (slider_bar != nullptr) {
399 t = slider_bar->get_ratio();
400 }
401
402 PN_stdfloat min = clip_min - canvas_min;
403 PN_stdfloat max = clip_max - canvas_max;
404
405 return min + t * (max - min);
406}
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Similar to MutexHolder, but for a light reentrant mutex.
void set_type(Type type)
Sets the basic type of frame.
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a)
Sets the dominant color of the frame.
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 set_width(PN_stdfloat x, PN_stdfloat y)
Sets the width parameter, which has meaning only for certain frame types.
This is the base class for all the various kinds of gui widget objects.
Definition pgItem.h:53
const LVecBase4 & get_frame() const
Returns the bounding rectangle of the item.
Definition pgItem.I:106
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:1007
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:953
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:81
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:994
int get_state() const
Returns the "state" of this particular PGItem.
Definition pgItem.I:150
This is a special kind of frame that pretends to be much larger than it actually is.
void set_manage_pieces(bool manage_pieces)
Sets the manage_pieces flag.
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
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_virtual_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets the bounding rectangle of the virtual frame.
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.
const LVecBase4 & get_virtual_frame() const
Returns the bounding rectangle of the virtual frame.
void set_auto_hide(bool auto_hide)
Sets the auto_hide flag.
void set_horizontal_slider(PGSliderBar *horizontal_slider)
Sets the PGSliderBar object that will serve as the horizontal scroll bar for this frame.
void remanage()
Manages the position and size of the scroll bars.
void recompute()
Forces the PGScrollFrame to recompute itself right now.
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_vertical_slider(PGSliderBar *vertical_slider)
Sets the PGSliderBar object that will serve as the vertical 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:31
PN_stdfloat get_ratio() const
Returns the current value of the slider, expressed in the range 0 .
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.
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so.
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
Definition pandaNode.h:173
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.