pgraph pgui
This commit is contained in:
parent
98285edbeb
commit
d5dce0be83
|
|
@ -0,0 +1,31 @@
|
|||
// Filename: pgCullTraverser.I
|
||||
// Created by: drose (14Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGCullTraverser::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGCullTraverser::
|
||||
PGCullTraverser(qpPGTop *top, qpCullTraverser *trav) :
|
||||
qpCullTraverser(*trav),
|
||||
_top(top)
|
||||
{
|
||||
_sort_index = 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Filename: pgCullTraverser.cxx
|
||||
// Created by: drose (14Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgCullTraverser.h"
|
||||
|
||||
TypeHandle PGCullTraverser::_type_handle;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Filename: pgCullTraverser.h
|
||||
// Created by: drose (14Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PGCULLTRAVERSER_H
|
||||
#define PGCULLTRAVERSER_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "qppgTop.h"
|
||||
#include "qpcullTraverser.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGCullTraverser
|
||||
// Description : This is a specialization of CullTraverser for use
|
||||
// within the pgui system. It is substituted in for the
|
||||
// normal CullTraverser by the PGTop node. Its purpose
|
||||
// is to carry additional data through the traversal so
|
||||
// that PGItems can know how to register their regions
|
||||
// with the current MouseWatcherGroup.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PGCullTraverser : public qpCullTraverser {
|
||||
public:
|
||||
INLINE PGCullTraverser(qpPGTop *top, qpCullTraverser *trav);
|
||||
|
||||
qpPGTop *_top;
|
||||
int _sort_index;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
qpCullTraverser::init_type();
|
||||
register_type(_type_handle, "PGCullTraverser",
|
||||
qpCullTraverser::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "pgCullTraverser.I"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// Filename: qppgButton.I
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::setup
|
||||
// Access: Published
|
||||
// Description: Sets up the button using the indicated NodePath as
|
||||
// arbitrary geometry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGButton::
|
||||
setup(const qpNodePath &ready) {
|
||||
setup(ready, ready, ready, ready);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::setup
|
||||
// Access: Published
|
||||
// Description: Sets up the button using the indicated NodePath as
|
||||
// arbitrary geometry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGButton::
|
||||
setup(const qpNodePath &ready, const qpNodePath &depressed) {
|
||||
setup(ready, depressed, ready, ready);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::setup
|
||||
// Access: Published
|
||||
// Description: Sets up the button using the indicated NodePath as
|
||||
// arbitrary geometry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGButton::
|
||||
setup(const qpNodePath &ready, const qpNodePath &depressed,
|
||||
const qpNodePath &rollover) {
|
||||
setup(ready, depressed, rollover, ready);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::get_click_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the click
|
||||
// event for all qpPGButtons. The click event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGButton::
|
||||
get_click_prefix() {
|
||||
return "click-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::get_click_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// button is clicked normally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGButton::
|
||||
get_click_event(const ButtonHandle &button) const {
|
||||
return "click-" + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
// Filename: qppgButton.cxx
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qppgButton.h"
|
||||
#include "pgMouseWatcherParameter.h"
|
||||
|
||||
#include "throw_event.h"
|
||||
#include "mouseButton.h"
|
||||
#include "mouseWatcherParameter.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "transformState.h"
|
||||
|
||||
TypeHandle qpPGButton::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGButton::
|
||||
qpPGButton(const string &name) : qpPGItem(name)
|
||||
{
|
||||
_button_down = false;
|
||||
_click_buttons.insert(MouseButton::one());
|
||||
|
||||
set_active(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGButton::
|
||||
~qpPGButton() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGButton::
|
||||
qpPGButton(const qpPGButton ©) :
|
||||
qpPGItem(copy)
|
||||
{
|
||||
_button_down = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpPGButton::
|
||||
make_copy() const {
|
||||
return new qpPGButton(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::enter
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// mouse enters the region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGButton::
|
||||
enter(const MouseWatcherParameter ¶m) {
|
||||
if (get_active()) {
|
||||
set_state(_button_down ? S_depressed : S_rollover);
|
||||
}
|
||||
qpPGItem::enter(param);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::exit
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// mouse exits the region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGButton::
|
||||
exit(const MouseWatcherParameter ¶m) {
|
||||
if (get_active()) {
|
||||
set_state(S_ready);
|
||||
}
|
||||
qpPGItem::exit(param);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::press
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse or keyboard button is depressed while the mouse
|
||||
// is within the region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGButton::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (has_click_button(param.get_button())) {
|
||||
if (get_active()) {
|
||||
_button_down = true;
|
||||
set_state(S_depressed);
|
||||
}
|
||||
}
|
||||
qpPGItem::press(param, background);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::release
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse or keyboard button previously depressed with
|
||||
// press() is released.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGButton::
|
||||
release(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (has_click_button(param.get_button())) {
|
||||
_button_down = false;
|
||||
if (get_active()) {
|
||||
if (param.is_outside()) {
|
||||
set_state(S_ready);
|
||||
} else {
|
||||
set_state(S_rollover);
|
||||
click(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
qpPGItem::release(param, background);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::click
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// button is clicked down-and-up by the user normally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGButton::
|
||||
click(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_click_event(param.get_button());
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::setup
|
||||
// Access: Published
|
||||
// Description: Sets up the button as a default text button using the
|
||||
// indicated label string. The TextNode defined by
|
||||
// PGItem::get_text_node() will be used to create the
|
||||
// label geometry. This automatically sets up the frame
|
||||
// according to the size of the text.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGButton::
|
||||
setup(const string &label) {
|
||||
clear_state_def(S_ready);
|
||||
clear_state_def(S_depressed);
|
||||
clear_state_def(S_rollover);
|
||||
clear_state_def(S_inactive);
|
||||
|
||||
qpTextNode *text_node = get_text_node();
|
||||
text_node->set_text(label);
|
||||
PT(PandaNode) geom = text_node->generate();
|
||||
|
||||
LVecBase4f frame = text_node->get_card_actual();
|
||||
set_frame(frame[0] - 0.4f, frame[1] + 0.4f, frame[2] - 0.15f, frame[3] + 0.15f);
|
||||
|
||||
PT(PandaNode) ready = new PandaNode("ready");
|
||||
PT(PandaNode) depressed = new PandaNode("depressed");
|
||||
PT(PandaNode) rollover = new PandaNode("rollover");
|
||||
PT(PandaNode) inactive = new PandaNode("inactive");
|
||||
|
||||
get_state_def(S_ready)->add_child(ready);
|
||||
get_state_def(S_depressed)->add_child(depressed);
|
||||
get_state_def(S_rollover)->add_child(rollover);
|
||||
get_state_def(S_inactive)->add_child(inactive);
|
||||
|
||||
ready->add_child(geom);
|
||||
depressed->add_child(geom);
|
||||
rollover->add_child(geom);
|
||||
inactive->add_child(geom);
|
||||
|
||||
PGFrameStyle style;
|
||||
style.set_color(0.8f, 0.8f, 0.8f, 1.0);
|
||||
style.set_width(0.1f, 0.1f);
|
||||
|
||||
style.set_type(PGFrameStyle::T_bevel_out);
|
||||
set_frame_style(S_ready, style);
|
||||
|
||||
style.set_color(0.9f, 0.9f, 0.9f, 1.0);
|
||||
set_frame_style(S_rollover, style);
|
||||
|
||||
inactive->set_attrib(ColorAttrib::make_flat(Colorf(0.8f, 0.8f, 0.8f, 1.0f)));
|
||||
style.set_color(0.6f, 0.6f, 0.6f, 1.0);
|
||||
set_frame_style(S_inactive, style);
|
||||
|
||||
style.set_type(PGFrameStyle::T_bevel_in);
|
||||
style.set_color(0.8f, 0.8f, 0.8f, 1.0);
|
||||
set_frame_style(S_depressed, style);
|
||||
depressed->set_transform(TransformState::make_pos(LVector3f(0.05f, 0.0f, -0.05f)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::setup
|
||||
// Access: Published
|
||||
// Description: Sets up the button using the indicated NodePath as
|
||||
// arbitrary geometry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGButton::
|
||||
setup(const qpNodePath &ready, const qpNodePath &depressed,
|
||||
const qpNodePath &rollover, const qpNodePath &inactive) {
|
||||
clear_state_def(S_ready);
|
||||
clear_state_def(S_depressed);
|
||||
clear_state_def(S_rollover);
|
||||
clear_state_def(S_inactive);
|
||||
|
||||
instance_to_state_def(S_ready, ready);
|
||||
instance_to_state_def(S_depressed, depressed);
|
||||
instance_to_state_def(S_rollover, rollover);
|
||||
instance_to_state_def(S_inactive, inactive);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::set_active
|
||||
// Access: Published, Virtual
|
||||
// Description: Toggles the active/inactive state of the button. In
|
||||
// the case of a qpPGButton, this also changes its visual
|
||||
// appearance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGButton::
|
||||
set_active(bool active) {
|
||||
if (active != get_active()) {
|
||||
qpPGItem::set_active(active);
|
||||
set_state(active ? S_ready : S_inactive);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::add_click_button
|
||||
// Access: Published
|
||||
// Description: Adds the indicated button to the set of buttons that
|
||||
// can effectively "click" the qpPGButton. Normally, this
|
||||
// is just MouseButton::one(). Returns true if the
|
||||
// button was added, or false if it was already there.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGButton::
|
||||
add_click_button(const ButtonHandle &button) {
|
||||
return _click_buttons.insert(button).second;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::remove_click_button
|
||||
// Access: Published
|
||||
// Description: Removes the indicated button from the set of buttons
|
||||
// that can effectively "click" the qpPGButton. Normally,
|
||||
// this is just MouseButton::one(). Returns true if the
|
||||
// button was removed, or false if it was not in the
|
||||
// set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGButton::
|
||||
remove_click_button(const ButtonHandle &button) {
|
||||
return (_click_buttons.erase(button) != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGButton::has_click_button
|
||||
// Access: Published
|
||||
// Description: Returns true if the indicated button is on the set of
|
||||
// buttons that can effectively "click" the qpPGButton.
|
||||
// Normally, this is just MouseButton::one().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGButton::
|
||||
has_click_button(const ButtonHandle &button) {
|
||||
return (_click_buttons.count(button) != 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
// Filename: qppgButton.h
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef qpPGBUTTON_H
|
||||
#define qpPGBUTTON_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "qppgItem.h"
|
||||
#include "qpnodePath.h"
|
||||
#include "pset.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpPGButton
|
||||
// Description : This is a particular kind of PGItem that is
|
||||
// specialized to behave like a normal button object.
|
||||
// It keeps track of its own state, and handles mouse
|
||||
// events sensibly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpPGButton : public qpPGItem {
|
||||
PUBLISHED:
|
||||
qpPGButton(const string &name);
|
||||
virtual ~qpPGButton();
|
||||
|
||||
protected:
|
||||
qpPGButton(const qpPGButton ©);
|
||||
|
||||
public:
|
||||
virtual PandaNode *make_copy() const;
|
||||
|
||||
virtual void enter(const MouseWatcherParameter ¶m);
|
||||
virtual void exit(const MouseWatcherParameter ¶m);
|
||||
virtual void press(const MouseWatcherParameter ¶m, bool background);
|
||||
virtual void release(const MouseWatcherParameter ¶m, bool background);
|
||||
|
||||
virtual void click(const MouseWatcherParameter ¶m);
|
||||
|
||||
PUBLISHED:
|
||||
enum State {
|
||||
S_ready = 0,
|
||||
S_depressed,
|
||||
S_rollover,
|
||||
S_inactive
|
||||
};
|
||||
|
||||
void setup(const string &label);
|
||||
INLINE void setup(const qpNodePath &ready);
|
||||
INLINE void setup(const qpNodePath &ready, const qpNodePath &depressed);
|
||||
INLINE void setup(const qpNodePath &ready, const qpNodePath &depressed,
|
||||
const qpNodePath &rollover);
|
||||
void setup(const qpNodePath &ready, const qpNodePath &depressed,
|
||||
const qpNodePath &rollover, const qpNodePath &inactive);
|
||||
|
||||
virtual void set_active(bool active);
|
||||
|
||||
bool add_click_button(const ButtonHandle &button);
|
||||
bool remove_click_button(const ButtonHandle &button);
|
||||
bool has_click_button(const ButtonHandle &button);
|
||||
|
||||
INLINE static string get_click_prefix();
|
||||
INLINE string get_click_event(const ButtonHandle &button) const;
|
||||
|
||||
private:
|
||||
typedef pset<ButtonHandle> Buttons;
|
||||
Buttons _click_buttons;
|
||||
|
||||
bool _button_down;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
qpPGItem::init_type();
|
||||
register_type(_type_handle, "qpPGButton",
|
||||
qpPGItem::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "qppgButton.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
// Filename: qppgEntry.I
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_text
|
||||
// Access: Published
|
||||
// Description: Changes the text currently displayed within the
|
||||
// entry. This uses the Unicode encoding currently
|
||||
// specified for the "focus" TextNode; therefore, the
|
||||
// TextNode must exist before calling set_text().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_text(const string &text) {
|
||||
qpTextNode *text_node = get_text_def(S_focus);
|
||||
nassertv(text_node != (qpTextNode *)NULL);
|
||||
set_wtext(text_node->decode_text(text));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_text
|
||||
// Access: Published
|
||||
// Description: Returns the text currently displayed within the
|
||||
// entry. This uses the Unicode encoding currently
|
||||
// specified for the "focus" TextNode; therefore, the
|
||||
// TextNode must exist before calling get_text().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_text() const {
|
||||
qpTextNode *text_node = get_text_def(S_focus);
|
||||
nassertr(text_node != (qpTextNode *)NULL, string());
|
||||
return text_node->encode_wtext(get_wtext());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_cursor_position
|
||||
// Access: Published
|
||||
// Description: Sets the current position of the cursor. This is the
|
||||
// position within the text at which the next letter
|
||||
// typed by the user will be inserted; normally it is
|
||||
// the same as the length of the text.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_cursor_position(int position) {
|
||||
if (_cursor_position != position) {
|
||||
_cursor_position = position;
|
||||
_cursor_stale = true;
|
||||
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_cursor_position
|
||||
// Access: Published
|
||||
// Description: Returns the current position of the cursor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpPGEntry::
|
||||
get_cursor_position() const {
|
||||
return _cursor_position;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_max_chars
|
||||
// Access: Published
|
||||
// Description: Sets the maximum number of characters that may be
|
||||
// typed into the entry. This is a limit on the number
|
||||
// of characters, as opposed to the width of the entry;
|
||||
// see also set_max_width().
|
||||
//
|
||||
// If this is 0, there is no limit.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_max_chars(int max_chars) {
|
||||
_max_chars = max_chars;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_max_chars
|
||||
// Access: Published
|
||||
// Description: Returns the current maximum number of characters that
|
||||
// may be typed into the entry, or 0 if there is no
|
||||
// limit. See set_max_chars().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpPGEntry::
|
||||
get_max_chars() const {
|
||||
return _max_chars;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_max_width
|
||||
// Access: Published
|
||||
// Description: Sets the maximum width of all characters that may be
|
||||
// typed into the entry. This is a limit on the width
|
||||
// of the formatted text, not a fixed limit on the
|
||||
// number of characters; also set_max_chars().
|
||||
//
|
||||
// If this is 0, there is no limit.
|
||||
//
|
||||
// If _num_lines is more than 1, rather than being a
|
||||
// fixed width on the whole entry, this becomes instead
|
||||
// the wordwrap width (and the width limit on the entry
|
||||
// is essentially _max_width * _num_lines).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_max_width(float max_width) {
|
||||
_max_width = max_width;
|
||||
_text_geom_stale = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_max_width
|
||||
// Access: Published
|
||||
// Description: Returns the current maximum width of the characters
|
||||
// that may be typed into the entry, or 0 if there is no
|
||||
// limit. See set_max_width().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float qpPGEntry::
|
||||
get_max_width() const {
|
||||
return _max_width;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_num_lines
|
||||
// Access: Published
|
||||
// Description: Sets the number of lines of text the qpPGEntry will
|
||||
// use. This only has meaning if _max_width is not 0;
|
||||
// _max_width indicates the wordwrap width of each line.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_num_lines(int num_lines) {
|
||||
nassertv(num_lines >= 1);
|
||||
_num_lines = num_lines;
|
||||
_text_geom_stale = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_num_lines
|
||||
// Access: Published
|
||||
// Description: Returns the number of lines of text the qpPGEntry will
|
||||
// use, if _max_width is not 0. See set_num_lines().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpPGEntry::
|
||||
get_num_lines() const {
|
||||
return _num_lines;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_blink_rate
|
||||
// Access: Published
|
||||
// Description: Sets the number of times per second the cursor will
|
||||
// blink while the entry has keyboard focus.
|
||||
//
|
||||
// If this is 0, the cursor does not blink, but is held
|
||||
// steady.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_blink_rate(float blink_rate) {
|
||||
_blink_rate = blink_rate;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_blink_rate
|
||||
// Access: Published
|
||||
// Description: Returns the number of times per second the cursor
|
||||
// will blink, or 0 if the cursor is not to blink.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float qpPGEntry::
|
||||
get_blink_rate() const {
|
||||
return _blink_rate;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_cursor_def
|
||||
// Access: Published
|
||||
// Description: Returns the Node that will be rendered to represent
|
||||
// the cursor. You can attach suitable cursor geometry
|
||||
// to this node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *qpPGEntry::
|
||||
get_cursor_def() {
|
||||
return _cursor_def;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::clear_cursor_def
|
||||
// Access: Published
|
||||
// Description: Removes all the children from the cursor_def node, in
|
||||
// preparation for adding a new definition.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
clear_cursor_def() {
|
||||
get_cursor_def()->remove_all_children();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_cursor_keys_active
|
||||
// Access: Published
|
||||
// Description: Sets whether the arrow keys (and home/end) control
|
||||
// movement of the cursor. If true, they are active; if
|
||||
// false, they are ignored.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_cursor_keys_active(bool flag) {
|
||||
_cursor_keys_active = flag;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_cursor_keys_active
|
||||
// Access: Published
|
||||
// Description: Returns whether the arrow keys are currently set to
|
||||
// control movement of the cursor; see
|
||||
// set_cursor_keys_active().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpPGEntry::
|
||||
get_cursor_keys_active() const {
|
||||
return _cursor_keys_active;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_obscure_mode
|
||||
// Access: Published
|
||||
// Description: Specifies whether obscure mode should be enabled. In
|
||||
// obscure mode, a string of asterisks is displayed
|
||||
// instead of the literal text, e.g. for entering
|
||||
// passwords.
|
||||
//
|
||||
// In obscure mode, the width of the text is computed
|
||||
// based on the width of the string of asterisks, not on
|
||||
// the width of the actual text. This has implications
|
||||
// on the maximum length of text that may be entered if
|
||||
// max_width is in effect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_obscure_mode(bool flag) {
|
||||
if (_obscure_mode != flag) {
|
||||
_obscure_mode = flag;
|
||||
_text_geom_stale = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_obscure_mode
|
||||
// Access: Published
|
||||
// Description: Specifies whether obscure mode is enabled. See
|
||||
// set_obscure_mode().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpPGEntry::
|
||||
get_obscure_mode() const {
|
||||
return _obscure_mode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_accept_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the accept
|
||||
// event for all PGEntries. The accept event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_accept_prefix() {
|
||||
return "accept-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_overflow_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the overflow
|
||||
// event for all PGEntries. The overflow event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_overflow_prefix() {
|
||||
return "overflow-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_type_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the type
|
||||
// event for all PGEntries. The type event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_type_prefix() {
|
||||
return "type-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_erase_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the erase
|
||||
// event for all PGEntries. The erase event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_erase_prefix() {
|
||||
return "erase-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_accept_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// entry is accepted normally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_accept_event(const ButtonHandle &button) const {
|
||||
return "accept-" + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_overflow_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when too
|
||||
// much text is attempted to be entered into the
|
||||
// qpPGEntry, exceeding either the limit set via
|
||||
// set_max_chars() or via set_max_width().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_overflow_event() const {
|
||||
return "overflow-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_type_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown whenever
|
||||
// the user extends the text by typing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_type_event() const {
|
||||
return "type-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_erase_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown whenever
|
||||
// the user erases characters in the text.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGEntry::
|
||||
get_erase_event() const {
|
||||
return "erase-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_wtext
|
||||
// Access: Public
|
||||
// Description: Changes the text currently displayed within the
|
||||
// entry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGEntry::
|
||||
set_wtext(const wstring &wtext) {
|
||||
_wtext = wtext;
|
||||
_text_geom_stale = true;
|
||||
_cursor_stale = true;
|
||||
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_wtext
|
||||
// Access: Public
|
||||
// Description: Returns the text currently displayed within the
|
||||
// entry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const wstring &qpPGEntry::
|
||||
get_wtext() const {
|
||||
return _wtext;
|
||||
}
|
||||
|
|
@ -0,0 +1,881 @@
|
|||
// Filename: qppgEntry.cxx
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qppgEntry.h"
|
||||
#include "pgMouseWatcherParameter.h"
|
||||
|
||||
#include "qpcullTraverser.h"
|
||||
#include "throw_event.h"
|
||||
#include "transformState.h"
|
||||
#include "mouseWatcherParameter.h"
|
||||
#include "keyboardButton.h"
|
||||
#include "mouseButton.h"
|
||||
#include "lineSegs.h"
|
||||
|
||||
#include "math.h"
|
||||
|
||||
TypeHandle qpPGEntry::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGEntry::
|
||||
qpPGEntry(const string &name) :
|
||||
qpPGItem(name)
|
||||
{
|
||||
_cursor_position = 0;
|
||||
_cursor_stale = true;
|
||||
_max_chars = 0;
|
||||
_max_width = 0.0f;
|
||||
_num_lines = 1;
|
||||
_last_text_def = (qpTextNode *)NULL;
|
||||
_text_geom_stale = true;
|
||||
_blink_start = 0.0f;
|
||||
_blink_rate = 1.0f;
|
||||
|
||||
_text_render_root = new PandaNode("text_root");
|
||||
_current_text_node = (PandaNode *)NULL;
|
||||
_cursor_def = new PandaNode("cursor");
|
||||
_text_render_root->add_child(_cursor_def);
|
||||
_cursor_visible = true;
|
||||
|
||||
_cursor_keys_active = true;
|
||||
_obscure_mode = false;
|
||||
|
||||
set_active(true);
|
||||
update_state();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGEntry::
|
||||
~qpPGEntry() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::Copy Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGEntry::
|
||||
qpPGEntry(const qpPGEntry ©) :
|
||||
qpPGItem(copy),
|
||||
_wtext(copy._wtext),
|
||||
_obscured_wtext(copy._obscured_wtext),
|
||||
_cursor_position(copy._cursor_position),
|
||||
_max_chars(copy._max_chars),
|
||||
_max_width(copy._max_width),
|
||||
_text_defs(copy._text_defs),
|
||||
_blink_start(copy._blink_start),
|
||||
_blink_rate(copy._blink_rate),
|
||||
_cursor_keys_active(copy._cursor_keys_active),
|
||||
_obscure_mode(copy._obscure_mode)
|
||||
{
|
||||
_cursor_stale = true;
|
||||
_last_text_def = (qpTextNode *)NULL;
|
||||
_text_geom_stale = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpPGEntry::
|
||||
make_copy() const {
|
||||
return new qpPGEntry(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::has_cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: Should be overridden by derived classes to return
|
||||
// true if cull_callback() has been defined. Otherwise,
|
||||
// returns false to indicate cull_callback() does not
|
||||
// need to be called for this node during the cull
|
||||
// traversal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGEntry::
|
||||
has_cull_callback() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: If has_cull_callback() returns true, this function
|
||||
// will be called during the cull traversal to perform
|
||||
// any additional operations that should be performed at
|
||||
// cull time. This may include additional manipulation
|
||||
// of render state or additional visible/invisible
|
||||
// decisions, or any other arbitrary operation.
|
||||
//
|
||||
// By the time this function is called, the node has
|
||||
// already passed the bounding-volume test for the
|
||||
// viewing frustum, and the node's transform and state
|
||||
// have already been applied to the indicated
|
||||
// CullTraverserData object.
|
||||
//
|
||||
// The return value is true if this node should be
|
||||
// visible, or false if it should be culled.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGEntry::
|
||||
cull_callback(qpCullTraverser *trav, CullTraverserData &data) {
|
||||
qpPGItem::cull_callback(trav, data);
|
||||
update_text();
|
||||
update_cursor();
|
||||
|
||||
// Now render the text.
|
||||
nassertr(_text_render_root != (PandaNode *)NULL, true);
|
||||
trav->traverse(_text_render_root, data);
|
||||
|
||||
// Now continue to render everything else below this node.
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::press
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse or keyboard entry is depressed while the mouse
|
||||
// is within the region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (get_active()) {
|
||||
if (param.has_button()) {
|
||||
ButtonHandle button = param.get_button();
|
||||
|
||||
if (button == MouseButton::one() ||
|
||||
button == MouseButton::two() ||
|
||||
button == MouseButton::three()) {
|
||||
// Mouse button; set focus.
|
||||
set_focus(true);
|
||||
|
||||
} else if ((!background && get_focus()) ||
|
||||
(background && get_background_focus())) {
|
||||
// Keyboard button.
|
||||
_cursor_position = min(_cursor_position, (int)_wtext.length());
|
||||
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
||||
if (button == KeyboardButton::enter()) {
|
||||
// Enter. Accept the entry.
|
||||
accept(param);
|
||||
|
||||
} else if (button == KeyboardButton::backspace()) {
|
||||
// Backspace. Remove the character to the left of the cursor.
|
||||
if (_cursor_position > 0) {
|
||||
if (_obscure_mode && _obscured_wtext.length() == _wtext.length()) {
|
||||
_obscured_wtext.erase(_obscured_wtext.begin() + _obscured_wtext.length() - 1);
|
||||
}
|
||||
_wtext.erase(_wtext.begin() + _cursor_position - 1);
|
||||
_cursor_position--;
|
||||
_cursor_stale = true;
|
||||
_text_geom_stale = true;
|
||||
erase(param);
|
||||
}
|
||||
|
||||
} else if (button == KeyboardButton::del()) {
|
||||
// Delete. Remove the character to the right of the cursor.
|
||||
if (_cursor_position < (int)_wtext.length()) {
|
||||
if (_obscure_mode && _obscured_wtext.length() == _wtext.length()) {
|
||||
_obscured_wtext.erase(_obscured_wtext.begin() + _obscured_wtext.length() - 1);
|
||||
}
|
||||
_wtext.erase(_wtext.begin() + _cursor_position);
|
||||
_text_geom_stale = true;
|
||||
erase(param);
|
||||
}
|
||||
|
||||
} else if (button == KeyboardButton::left()) {
|
||||
if (_cursor_keys_active) {
|
||||
// Left arrow. Move the cursor position to the left.
|
||||
_cursor_position = max(_cursor_position - 1, 0);
|
||||
_cursor_stale = true;
|
||||
}
|
||||
|
||||
} else if (button == KeyboardButton::right()) {
|
||||
if (_cursor_keys_active) {
|
||||
// Right arrow. Move the cursor position to the right.
|
||||
_cursor_position = min(_cursor_position + 1, (int)_wtext.length());
|
||||
_cursor_stale = true;
|
||||
}
|
||||
|
||||
} else if (button == KeyboardButton::home()) {
|
||||
if (_cursor_keys_active) {
|
||||
// Home. Move the cursor position to the beginning.
|
||||
_cursor_position = 0;
|
||||
_cursor_stale = true;
|
||||
}
|
||||
|
||||
} else if (button == KeyboardButton::end()) {
|
||||
if (_cursor_keys_active) {
|
||||
// End. Move the cursor position to the end.
|
||||
_cursor_position = _wtext.length();
|
||||
_cursor_stale = true;
|
||||
}
|
||||
|
||||
} else if (!use_keystrokes && button.has_ascii_equivalent()) {
|
||||
// This part of the code is deprecated and will be removed
|
||||
// soon. It only supports the old button up/down method of
|
||||
// sending keystrokes, instead of the new keystroke method.
|
||||
wchar_t key = button.get_ascii_equivalent();
|
||||
if (isprint(key)) {
|
||||
// A normal visible character. Add a new character to the
|
||||
// text entry, if there's room.
|
||||
|
||||
if (get_max_chars() > 0 && (int)_wtext.length() >= get_max_chars()) {
|
||||
overflow(param);
|
||||
} else {
|
||||
wstring new_text =
|
||||
_wtext.substr(0, _cursor_position) + key +
|
||||
_wtext.substr(_cursor_position);
|
||||
|
||||
// Get a string to measure its length. In normal mode,
|
||||
// we measure the text itself. In obscure mode, we
|
||||
// measure a string of n asterisks.
|
||||
wstring measure_text;
|
||||
if (_obscure_mode) {
|
||||
measure_text = get_display_wtext() + (wchar_t)'*';
|
||||
} else {
|
||||
measure_text = new_text;
|
||||
}
|
||||
|
||||
// Check the length.
|
||||
bool too_long = false;
|
||||
if (_max_width > 0.0f) {
|
||||
qpTextNode *text_node = get_text_def(S_focus);
|
||||
if (_num_lines <= 1) {
|
||||
// If we have only one line, we can check the length
|
||||
// by simply measuring the width of the text.
|
||||
too_long = (text_node->calc_width(measure_text) > _max_width);
|
||||
|
||||
} else {
|
||||
// If we have multiple lines, we have to check the
|
||||
// length by wordwrapping it and counting up the
|
||||
// number of lines.
|
||||
wstring ww_text = text_node->wordwrap_to(measure_text, _max_width, true);
|
||||
int num_lines = 1;
|
||||
size_t last_line_start = 0;
|
||||
for (size_t p = 0;
|
||||
p < ww_text.length() && !too_long;
|
||||
++p) {
|
||||
if (ww_text[p] == '\n') {
|
||||
last_line_start = p + 1;
|
||||
num_lines++;
|
||||
too_long = (num_lines > _num_lines);
|
||||
}
|
||||
}
|
||||
|
||||
if (!too_long) {
|
||||
// We must also ensure that the last line is not too
|
||||
// long (it might be, because of additional
|
||||
// whitespace on the end).
|
||||
wstring last_line = ww_text.substr(last_line_start);
|
||||
float last_line_width = text_node->calc_width(last_line);
|
||||
if (num_lines == _num_lines) {
|
||||
// Mainly we only care about this if we're on
|
||||
// the very last line.
|
||||
too_long = (last_line_width > _max_width);
|
||||
|
||||
} else {
|
||||
// If we're not on the very last line, the width
|
||||
// is still important, just so we don't allow an
|
||||
// infinite number of spaces to accumulate.
|
||||
// However, we must allow at least *one* space
|
||||
// on the end of a line.
|
||||
if (_wtext.length() >= 1 &&
|
||||
_wtext[_wtext.length() - 1] == ' ') {
|
||||
if (last_line_width > _max_width) {
|
||||
// In this case, however, it's not exactly
|
||||
// an overflow; we just want to reject the
|
||||
// space.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (too_long) {
|
||||
overflow(param);
|
||||
|
||||
} else {
|
||||
_wtext = new_text;
|
||||
if (_obscure_mode) {
|
||||
_obscured_wtext = measure_text;
|
||||
}
|
||||
|
||||
_cursor_position++;
|
||||
_cursor_stale = true;
|
||||
_text_geom_stale = true;
|
||||
type(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
qpPGItem::press(param, background);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::keystroke
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever
|
||||
// the user types a key.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
keystroke(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (get_active()) {
|
||||
if (param.has_keycode()) {
|
||||
int keycode = param.get_keycode();
|
||||
|
||||
if (use_keystrokes) {
|
||||
if (!isascii(keycode) || isprint(keycode)) {
|
||||
// A normal visible character. Add a new character to the
|
||||
// text entry, if there's room.
|
||||
wstring new_char(1, (wchar_t)keycode);
|
||||
|
||||
if (get_max_chars() > 0 && (int)_wtext.length() >= get_max_chars()) {
|
||||
overflow(param);
|
||||
} else {
|
||||
_cursor_position = min(_cursor_position, (int)_wtext.length());
|
||||
wstring new_text =
|
||||
_wtext.substr(0, _cursor_position) + new_char +
|
||||
_wtext.substr(_cursor_position);
|
||||
|
||||
// Get a string to measure its length. In normal mode,
|
||||
// we measure the text itself. In obscure mode, we
|
||||
// measure a string of n asterisks.
|
||||
wstring measure_text;
|
||||
if (_obscure_mode) {
|
||||
measure_text = get_display_wtext() + (wchar_t)'*';
|
||||
} else {
|
||||
measure_text = new_text;
|
||||
}
|
||||
|
||||
// Check the length.
|
||||
bool too_long = false;
|
||||
if (_max_width > 0.0f) {
|
||||
qpTextNode *text_node = get_text_def(S_focus);
|
||||
if (_num_lines <= 1) {
|
||||
// If we have only one line, we can check the length
|
||||
// by simply measuring the width of the text.
|
||||
too_long = (text_node->calc_width(measure_text) > _max_width);
|
||||
|
||||
} else {
|
||||
// If we have multiple lines, we have to check the
|
||||
// length by wordwrapping it and counting up the
|
||||
// number of lines.
|
||||
wstring ww_text = text_node->wordwrap_to(measure_text, _max_width, true);
|
||||
int num_lines = 1;
|
||||
size_t last_line_start = 0;
|
||||
for (size_t p = 0;
|
||||
p < ww_text.length() && !too_long;
|
||||
++p) {
|
||||
if (ww_text[p] == '\n') {
|
||||
last_line_start = p + 1;
|
||||
num_lines++;
|
||||
too_long = (num_lines > _num_lines);
|
||||
}
|
||||
}
|
||||
|
||||
if (!too_long) {
|
||||
// We must also ensure that the last line is not too
|
||||
// long (it might be, because of additional
|
||||
// whitespace on the end).
|
||||
wstring last_line = ww_text.substr(last_line_start);
|
||||
float last_line_width = text_node->calc_width(last_line);
|
||||
if (num_lines == _num_lines) {
|
||||
// Mainly we only care about this if we're on
|
||||
// the very last line.
|
||||
too_long = (last_line_width > _max_width);
|
||||
|
||||
} else {
|
||||
// If we're not on the very last line, the width
|
||||
// is still important, just so we don't allow an
|
||||
// infinite number of spaces to accumulate.
|
||||
// However, we must allow at least *one* space
|
||||
// on the end of a line.
|
||||
if (_wtext.length() >= 1 &&
|
||||
_wtext[_wtext.length() - 1] == ' ') {
|
||||
if (last_line_width > _max_width) {
|
||||
// In this case, however, it's not exactly
|
||||
// an overflow; we just want to reject the
|
||||
// space.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (too_long) {
|
||||
overflow(param);
|
||||
|
||||
} else {
|
||||
_wtext = new_text;
|
||||
if (_obscure_mode) {
|
||||
_obscured_wtext = measure_text;
|
||||
}
|
||||
|
||||
_cursor_position += new_char.length();
|
||||
_cursor_stale = true;
|
||||
_text_geom_stale = true;
|
||||
type(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
qpPGItem::keystroke(param, background);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::accept
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// entry is accepted by the user pressing Enter normally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
accept(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_accept_event(param.get_button());
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
set_focus(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::overflow
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// entry is overflowed because the user attempts to type
|
||||
// too many characters, exceeding either set_max_chars()
|
||||
// or set_max_width().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
overflow(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_overflow_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::type
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// user extends the text by typing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
type(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_type_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::erase
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// user erase characters in the text.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
erase(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_erase_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::setup
|
||||
// Access: Published
|
||||
// Description: Sets up the entry for normal use. The width is the
|
||||
// maximum width of characters that will be typed, and
|
||||
// num_lines is the integer number of lines of text of
|
||||
// the entry. Both of these together determine the size
|
||||
// of the entry, based on the qpTextNode in effect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
setup(float width, int num_lines) {
|
||||
set_text(string());
|
||||
_cursor_position = 0;
|
||||
set_max_chars(0);
|
||||
set_max_width(width);
|
||||
set_num_lines(num_lines);
|
||||
|
||||
qpTextNode *text_node = get_text_def(S_focus);
|
||||
float line_height = text_node->get_line_height();
|
||||
|
||||
// Define determine the four corners of the frame.
|
||||
LPoint3f ll(0.0f, 0.0f, -0.3f * line_height - (line_height * (num_lines - 1)));
|
||||
LPoint3f ur(width, 0.0f, line_height);
|
||||
LPoint3f lr(ur[0], 0.0f, ll[2]);
|
||||
LPoint3f ul(ll[0], 0.0f, ur[2]);
|
||||
|
||||
// Transform each corner by the qpTextNode's transform.
|
||||
LMatrix4f mat = text_node->get_transform();
|
||||
ll = ll * mat;
|
||||
ur = ur * mat;
|
||||
lr = lr * mat;
|
||||
ul = ul * mat;
|
||||
|
||||
// And get the new minmax to define the frame. We do all this work
|
||||
// instead of just using the lower-left and upper-right corners,
|
||||
// just in case the text was rotated.
|
||||
LVecBase4f frame;
|
||||
frame[0] = min(min(ll[0], ur[0]), min(lr[0], ul[0]));
|
||||
frame[1] = max(max(ll[0], ur[0]), max(lr[0], ul[0]));
|
||||
frame[2] = min(min(ll[2], ur[2]), min(lr[2], ul[2]));
|
||||
frame[3] = max(max(ll[2], ur[2]), max(lr[2], ul[2]));
|
||||
|
||||
switch (text_node->get_align()) {
|
||||
case qpTextNode::A_left:
|
||||
// The default case.
|
||||
break;
|
||||
|
||||
case qpTextNode::A_center:
|
||||
frame[0] = -width / 2.0;
|
||||
frame[1] = width / 2.0;
|
||||
break;
|
||||
|
||||
case qpTextNode::A_right:
|
||||
frame[0] = -width;
|
||||
frame[1] = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
set_frame(frame[0] - 0.15f, frame[1] + 0.15f, frame[2], frame[3]);
|
||||
|
||||
PGFrameStyle style;
|
||||
style.set_width(0.1f, 0.1f);
|
||||
style.set_type(PGFrameStyle::T_bevel_in);
|
||||
style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
|
||||
|
||||
set_frame_style(S_no_focus, style);
|
||||
|
||||
style.set_color(0.9f, 0.9f, 0.9f, 1.0f);
|
||||
set_frame_style(S_focus, style);
|
||||
|
||||
style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
|
||||
set_frame_style(S_inactive, style);
|
||||
|
||||
// Set up a default cursor: a vertical bar.
|
||||
clear_cursor_def();
|
||||
|
||||
/*
|
||||
LineSegs ls;
|
||||
ls.set_color(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
ls.move_to(0.0f, 0.0f, -0.15f * line_height);
|
||||
ls.draw_to(0.0f, 0.0f, 0.85f * line_height);
|
||||
new RenderRelation(get_cursor_def(), ls.create());
|
||||
*/
|
||||
|
||||
// An underscore cursor would work too.
|
||||
text_node->set_text("_");
|
||||
get_cursor_def()->add_child(text_node->generate());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_text_def
|
||||
// Access: Published
|
||||
// Description: Changes the qpTextNode that will be used to render the
|
||||
// text within the entry when the entry is in the
|
||||
// indicated state. The default if nothing is specified
|
||||
// is the same qpTextNode returned by
|
||||
// qpPGItem::get_text_node().
|
||||
//
|
||||
// It is the responsibility of the user to ensure that
|
||||
// this qpTextNode has been frozen by a call to freeze().
|
||||
// Passing in an unfrozen qpTextNode will result in
|
||||
// needless work.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
set_text_def(int state, qpTextNode *node) {
|
||||
nassertv(state >= 0 && state < 1000); // Sanity check.
|
||||
if (node == (qpTextNode *)NULL && state >= (int)_text_defs.size()) {
|
||||
// If we're setting it to NULL, we don't need to slot a new one.
|
||||
return;
|
||||
}
|
||||
slot_text_def(state);
|
||||
|
||||
_text_defs[state] = node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_text_def
|
||||
// Access: Published
|
||||
// Description: Returns the qpTextNode that will be used to render the
|
||||
// text within the entry when the entry is in the
|
||||
// indicated state. See set_text_def().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpTextNode *qpPGEntry::
|
||||
get_text_def(int state) const {
|
||||
if (state < 0 || state >= (int)_text_defs.size()) {
|
||||
// If we don't have a definition, use the global one.
|
||||
return get_text_node();
|
||||
}
|
||||
if (_text_defs[state] == (qpTextNode *)NULL) {
|
||||
return get_text_node();
|
||||
}
|
||||
return _text_defs[state];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_active
|
||||
// Access: Published, Virtual
|
||||
// Description: Toggles the active/inactive state of the entry. In
|
||||
// the case of a qpPGEntry, this also changes its visual
|
||||
// appearance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
set_active(bool active) {
|
||||
qpPGItem::set_active(active);
|
||||
update_state();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::set_focus
|
||||
// Access: Published, Virtual
|
||||
// Description: Toggles the focus state of the entry. In the case of
|
||||
// a qpPGEntry, this also changes its visual appearance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
set_focus(bool focus) {
|
||||
qpPGItem::set_focus(focus);
|
||||
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
||||
update_state();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::get_display_wtext
|
||||
// Access: Private
|
||||
// Description: Returns the string that should be displayed within
|
||||
// the entry. This is normally _wtext, but it may be
|
||||
// _obscured_wtext.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const wstring &qpPGEntry::
|
||||
get_display_wtext() {
|
||||
if (_obscure_mode) {
|
||||
// If obscure mode is enabled, we should just display a bunch of
|
||||
// asterisks.
|
||||
if (_obscured_wtext.length() != _wtext.length()) {
|
||||
_obscured_wtext = wstring();
|
||||
wstring::const_iterator ti;
|
||||
for (ti = _wtext.begin(); ti != _wtext.end(); ++ti) {
|
||||
_obscured_wtext += (wchar_t)'*';
|
||||
}
|
||||
}
|
||||
|
||||
return _obscured_wtext;
|
||||
|
||||
} else {
|
||||
// In normal, non-obscure mode, we display the actual text.
|
||||
return _wtext;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::slot_text_def
|
||||
// Access: Private
|
||||
// Description: Ensures there is a slot in the array for the given
|
||||
// text definition.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
slot_text_def(int state) {
|
||||
while (state >= (int)_text_defs.size()) {
|
||||
_text_defs.push_back((qpTextNode *)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::update_text
|
||||
// Access: Private
|
||||
// Description: Causes the qpPGEntry to recompute its text, if
|
||||
// necessary.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
update_text() {
|
||||
qpTextNode *node = get_text_def(get_state());
|
||||
nassertv(node != (qpTextNode *)NULL);
|
||||
|
||||
if (_text_geom_stale || node != _last_text_def) {
|
||||
const wstring &display_wtext = get_display_wtext();
|
||||
|
||||
// We need to regenerate.
|
||||
_last_text_def = node;
|
||||
|
||||
if (_max_width > 0.0f && _num_lines > 1) {
|
||||
// Fold the text into multiple lines.
|
||||
wstring ww_text =
|
||||
_last_text_def->wordwrap_to(display_wtext, _max_width, true);
|
||||
|
||||
// And chop the lines up into pieces.
|
||||
_ww_lines.clear();
|
||||
size_t p = 0;
|
||||
size_t q = ww_text.find((wchar_t)'\n');
|
||||
while (q != string::npos) {
|
||||
_ww_lines.push_back(WWLine());
|
||||
WWLine &line = _ww_lines.back();
|
||||
line._str = ww_text.substr(p, q - p);
|
||||
|
||||
// Get the left edge of the text at this line.
|
||||
line._left = 0.0f;
|
||||
if (_last_text_def->get_align() != qpTextNode::A_left) {
|
||||
_last_text_def->set_wtext(line._str);
|
||||
line._left = _last_text_def->get_left();
|
||||
}
|
||||
|
||||
p = q + 1;
|
||||
q = ww_text.find('\n', p);
|
||||
}
|
||||
_ww_lines.push_back(WWLine());
|
||||
WWLine &line = _ww_lines.back();
|
||||
line._str = ww_text.substr(p);
|
||||
|
||||
// Get the left edge of the text at this line.
|
||||
line._left = 0.0f;
|
||||
if (_last_text_def->get_align() != qpTextNode::A_left) {
|
||||
_last_text_def->set_wtext(line._str);
|
||||
line._left = _last_text_def->get_left();
|
||||
}
|
||||
|
||||
_last_text_def->set_wtext(ww_text);
|
||||
|
||||
} else {
|
||||
// Only one line.
|
||||
_ww_lines.clear();
|
||||
_ww_lines.push_back(WWLine());
|
||||
WWLine &line = _ww_lines.back();
|
||||
line._str = display_wtext;
|
||||
|
||||
_last_text_def->set_wtext(display_wtext);
|
||||
line._left = _last_text_def->get_left();
|
||||
}
|
||||
|
||||
if (_current_text_node != (PandaNode *)NULL) {
|
||||
_text_render_root->remove_child(_current_text_node);
|
||||
}
|
||||
_current_text_node = _last_text_def->generate();
|
||||
_text_render_root->add_child(_current_text_node);
|
||||
_text_geom_stale = false;
|
||||
_cursor_stale = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::update_cursor
|
||||
// Access: Private
|
||||
// Description: Moves the cursor to its correct position.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
update_cursor() {
|
||||
qpTextNode *node = get_text_def(get_state());
|
||||
nassertv(node != (qpTextNode *)NULL);
|
||||
|
||||
if (_cursor_stale || node != _last_text_def) {
|
||||
update_text();
|
||||
|
||||
_cursor_position = min(_cursor_position, (int)_wtext.length());
|
||||
|
||||
// Determine the row and column of the cursor.
|
||||
int row = 0;
|
||||
int column = _cursor_position;
|
||||
while (row + 1 < (int)_ww_lines.size() &&
|
||||
column > (int)_ww_lines[row]._str.length()) {
|
||||
column -= _ww_lines[row]._str.length();
|
||||
row++;
|
||||
}
|
||||
|
||||
nassertv(row >= 0 && row < (int)_ww_lines.size());
|
||||
nassertv(column >= 0 && column <= (int)_ww_lines[row]._str.length());
|
||||
|
||||
float width =
|
||||
_last_text_def->calc_width(_ww_lines[row]._str.substr(0, column));
|
||||
float line_height = _last_text_def->get_line_height();
|
||||
|
||||
LVecBase3f trans(_ww_lines[row]._left + width, 0.0f, -line_height * row);
|
||||
_cursor_def->set_transform(TransformState::make_pos(trans));
|
||||
|
||||
_cursor_stale = false;
|
||||
}
|
||||
|
||||
// Should the cursor be visible?
|
||||
if (!get_focus()) {
|
||||
show_hide_cursor(false);
|
||||
} else {
|
||||
double elapsed_time =
|
||||
ClockObject::get_global_clock()->get_frame_time() - _blink_start;
|
||||
int cycle = (int)(elapsed_time * _blink_rate * 2.0f);
|
||||
bool visible = ((cycle & 1) == 0);
|
||||
show_hide_cursor(visible);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::show_hide_cursor
|
||||
// Access: Private
|
||||
// Description: Makes the cursor visible or invisible, e.g. during a
|
||||
// blink cycle.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
show_hide_cursor(bool visible) {
|
||||
if (visible != _cursor_visible) {
|
||||
if (visible) {
|
||||
// Reveal the cursor.
|
||||
_cursor_def->set_draw_mask(DrawMask::all_on());
|
||||
} else {
|
||||
// Hide the cursor.
|
||||
_cursor_def->set_draw_mask(DrawMask::all_off());
|
||||
}
|
||||
_cursor_visible = visible;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGEntry::update_state
|
||||
// Access: Private
|
||||
// Description: Determines what the correct state for the qpPGEntry
|
||||
// should be.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGEntry::
|
||||
update_state() {
|
||||
if (get_active()) {
|
||||
if (get_focus()) {
|
||||
set_state(S_focus);
|
||||
} else {
|
||||
set_state(S_no_focus);
|
||||
}
|
||||
} else {
|
||||
set_state(S_inactive);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
// Filename: qppgEntry.h
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef qpPGENTRY_H
|
||||
#define qpPGENTRY_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "qppgItem.h"
|
||||
|
||||
#include "qptextNode.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pvector.h"
|
||||
#include "clockObject.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpPGEntry
|
||||
// Description : This is a particular kind of PGItem that handles
|
||||
// simple one-line text entries, of the sort where the
|
||||
// user can type any string.
|
||||
//
|
||||
// A qpPGEntry does all of its internal manipulation on a
|
||||
// wide string, so it can store the full Unicode
|
||||
// character set. The interface can support either the
|
||||
// wide string getters and setters, or the normal 8-bit
|
||||
// string getters and setters, which use whatever
|
||||
// encoding method is specified by the associated
|
||||
// TextNode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpPGEntry : public qpPGItem {
|
||||
PUBLISHED:
|
||||
qpPGEntry(const string &name);
|
||||
virtual ~qpPGEntry();
|
||||
|
||||
protected:
|
||||
qpPGEntry(const qpPGEntry ©);
|
||||
|
||||
public:
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual bool has_cull_callback() const;
|
||||
virtual bool cull_callback(qpCullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
virtual void press(const MouseWatcherParameter ¶m, bool background);
|
||||
virtual void keystroke(const MouseWatcherParameter ¶m, bool background);
|
||||
|
||||
virtual void accept(const MouseWatcherParameter ¶m);
|
||||
virtual void overflow(const MouseWatcherParameter ¶m);
|
||||
virtual void type(const MouseWatcherParameter ¶m);
|
||||
virtual void erase(const MouseWatcherParameter ¶m);
|
||||
|
||||
PUBLISHED:
|
||||
enum State {
|
||||
S_focus = 0,
|
||||
S_no_focus,
|
||||
S_inactive
|
||||
};
|
||||
|
||||
void setup(float width, int num_lines);
|
||||
|
||||
INLINE void set_text(const string &text);
|
||||
INLINE string get_text() const;
|
||||
|
||||
INLINE void set_cursor_position(int position);
|
||||
INLINE int get_cursor_position() const;
|
||||
|
||||
INLINE void set_max_chars(int max_chars);
|
||||
INLINE int get_max_chars() const;
|
||||
INLINE void set_max_width(float max_width);
|
||||
INLINE float get_max_width() const;
|
||||
INLINE void set_num_lines(int num_lines);
|
||||
INLINE int get_num_lines() const;
|
||||
|
||||
INLINE void set_blink_rate(float blink_rate);
|
||||
INLINE float get_blink_rate() const;
|
||||
|
||||
INLINE PandaNode *get_cursor_def();
|
||||
INLINE void clear_cursor_def();
|
||||
|
||||
INLINE void set_cursor_keys_active(bool flag);
|
||||
INLINE bool get_cursor_keys_active() const;
|
||||
|
||||
INLINE void set_obscure_mode(bool flag);
|
||||
INLINE bool get_obscure_mode() const;
|
||||
|
||||
void set_text_def(int state, qpTextNode *node);
|
||||
qpTextNode *get_text_def(int state) const;
|
||||
|
||||
virtual void set_active(bool active);
|
||||
virtual void set_focus(bool focus);
|
||||
|
||||
INLINE static string get_accept_prefix();
|
||||
INLINE static string get_overflow_prefix();
|
||||
INLINE static string get_type_prefix();
|
||||
INLINE static string get_erase_prefix();
|
||||
|
||||
INLINE string get_accept_event(const ButtonHandle &button) const;
|
||||
INLINE string get_overflow_event() const;
|
||||
INLINE string get_type_event() const;
|
||||
INLINE string get_erase_event() const;
|
||||
|
||||
public:
|
||||
INLINE void set_wtext(const wstring &wtext);
|
||||
INLINE const wstring &get_wtext() const;
|
||||
|
||||
|
||||
private:
|
||||
const wstring &get_display_wtext();
|
||||
void slot_text_def(int state);
|
||||
void update_text();
|
||||
void update_cursor();
|
||||
void show_hide_cursor(bool visible);
|
||||
void update_state();
|
||||
|
||||
wstring _wtext;
|
||||
wstring _obscured_wtext;
|
||||
int _cursor_position;
|
||||
bool _cursor_stale;
|
||||
bool _cursor_visible;
|
||||
|
||||
int _max_chars;
|
||||
float _max_width;
|
||||
int _num_lines;
|
||||
|
||||
typedef pvector< PT(qpTextNode) > TextDefs;
|
||||
TextDefs _text_defs;
|
||||
|
||||
// This node is the root of the subgraph that renders both the text
|
||||
// and the cursor.
|
||||
PT(PandaNode) _text_render_root;
|
||||
|
||||
// This is the node for rendering the actual text that is parented
|
||||
// to the above node when the text is generated.
|
||||
PT(PandaNode) _current_text_node;
|
||||
qpTextNode *_last_text_def;
|
||||
bool _text_geom_stale;
|
||||
|
||||
// This is a list of each row of text in the entry, after it has
|
||||
// been wordwrapped by update_text(). It's used by update_cursor()
|
||||
// to compute the correct cursor position.
|
||||
class WWLine {
|
||||
public:
|
||||
wstring _str;
|
||||
float _left;
|
||||
};
|
||||
typedef pvector<WWLine> WWLines;
|
||||
WWLines _ww_lines;
|
||||
|
||||
// This is the node that represents the cursor geometry. It is also
|
||||
// attached to the above node, and is transformed around and/or
|
||||
// hidden according to the cursor's position and blink state.
|
||||
PandaNode *_cursor_def;
|
||||
|
||||
double _blink_start;
|
||||
double _blink_rate;
|
||||
|
||||
bool _cursor_keys_active;
|
||||
bool _obscure_mode;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
qpPGItem::init_type();
|
||||
register_type(_type_handle, "qpPGEntry",
|
||||
qpPGItem::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "qppgEntry.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,468 @@
|
|||
// Filename: qppgItem.I
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_region
|
||||
// Access: Public
|
||||
// Description: Returns the MouseWatcherRegion associated with this
|
||||
// item. Every qpPGItem has a MouseWatcherRegion
|
||||
// associated with it, that is created when the qpPGItem
|
||||
// is created; it does not change during the lifetime of
|
||||
// the qpPGItem. Even items that do not have a frame have
|
||||
// an associated MouseWatcherRegion, although it will
|
||||
// not be used in this case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGMouseWatcherRegion *qpPGItem::
|
||||
get_region() const {
|
||||
return _region;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_frame
|
||||
// Access: Published
|
||||
// Description: Sets the bounding rectangle of the item, in local
|
||||
// coordinates. This is the region on screen within
|
||||
// which the mouse will be considered to be within the
|
||||
// item. Normally, it should correspond to the bounding
|
||||
// rectangle of the visible geometry of the item.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGItem::
|
||||
set_frame(float left, float right, float bottom, float top) {
|
||||
set_frame(LVecBase4f(left, right, bottom, top));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_frame
|
||||
// Access: Published
|
||||
// Description: Sets the bounding rectangle of the item, in local
|
||||
// coordinates. This is the region on screen within
|
||||
// which the mouse will be considered to be within the
|
||||
// item. Normally, it should correspond to the bounding
|
||||
// rectangle of the visible geometry of the item.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGItem::
|
||||
set_frame(const LVecBase4f &frame) {
|
||||
_has_frame = true;
|
||||
_frame = frame;
|
||||
mark_frames_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_frame
|
||||
// Access: Published
|
||||
// Description: Returns the bounding rectangle of the item. See
|
||||
// set_frame(). It is an error to call this if
|
||||
// has_frame() returns false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase4f &qpPGItem::
|
||||
get_frame() const {
|
||||
nassertr(has_frame(), _frame);
|
||||
return _frame;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::has_frame
|
||||
// Access: Published
|
||||
// Description: Returns true if the item has a bounding rectangle;
|
||||
// see set_frame().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpPGItem::
|
||||
has_frame() const {
|
||||
return _has_frame;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::clear_frame
|
||||
// Access: Published
|
||||
// Description: Removes the bounding rectangle from the item. It
|
||||
// will no longer be possible to position the mouse
|
||||
// within the item; see set_frame().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGItem::
|
||||
clear_frame() {
|
||||
_has_frame = false;
|
||||
mark_frames_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_state
|
||||
// Access: Published
|
||||
// Description: Sets the "state" of this particular qpPGItem.
|
||||
//
|
||||
// The qpPGItem node will render as if it were the
|
||||
// subgraph assigned to the corresponding index via
|
||||
// set_state_def().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGItem::
|
||||
set_state(int state) {
|
||||
_state = state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_state
|
||||
// Access: Published
|
||||
// Description: Returns the "state" of this particular qpPGItem. See
|
||||
// set_state().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpPGItem::
|
||||
get_state() const {
|
||||
return _state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_active
|
||||
// Access: Published
|
||||
// Description: Returns whether the qpPGItem is currently active for
|
||||
// mouse events. See set_active().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpPGItem::
|
||||
get_active() const {
|
||||
return (_flags & F_active) != 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_focus
|
||||
// Access: Published
|
||||
// Description: Returns whether the qpPGItem currently has focus for
|
||||
// keyboard events. See set_focus().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpPGItem::
|
||||
get_focus() const {
|
||||
return (_flags & F_focus) != 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_background_focus
|
||||
// Access: Published
|
||||
// Description: Returns whether background_focus is currently
|
||||
// enabled. See set_background_focus().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpPGItem::
|
||||
get_background_focus() const {
|
||||
return (_flags & F_background_focus) != 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_suppress_flags
|
||||
// Access: Published
|
||||
// Description: This is just an interface to set the suppress flags
|
||||
// on the underlying MouseWatcherRegion. See
|
||||
// MouseWatcherRegion::set_suppress_flags().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGItem::
|
||||
set_suppress_flags(int suppress_flags) {
|
||||
_region->set_suppress_flags(suppress_flags);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_suppress_flags
|
||||
// Access: Published
|
||||
// Description: This is just an interface to get the suppress flags
|
||||
// on the underlying MouseWatcherRegion. See
|
||||
// MouseWatcherRegion::get_suppress_flags().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpPGItem::
|
||||
get_suppress_flags() const {
|
||||
return _region->get_suppress_flags();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_id
|
||||
// Access: Published
|
||||
// Description: Returns the unique ID assigned to this qpPGItem. This
|
||||
// will be assigned to the region created with the
|
||||
// MouseWatcher, and will thus be used to generate event
|
||||
// names.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &qpPGItem::
|
||||
get_id() const {
|
||||
return _region->get_name();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_id
|
||||
// Access: Published
|
||||
// Description: Set the unique ID assigned to this qpPGItem. It is the
|
||||
// user's responsibility to ensure that this ID is
|
||||
// unique.
|
||||
//
|
||||
// Normally, this should not need to be called, as the
|
||||
// qpPGItem will assign itself an ID when it is created,
|
||||
// but this function allows the user to decide to
|
||||
// redefine the ID to be something possibly more
|
||||
// meaningful.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGItem::
|
||||
set_id(const string &id) {
|
||||
_region->set_name(id);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_enter_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the enter
|
||||
// event for all qpPGItems. The enter event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_enter_prefix() {
|
||||
return "enter-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_exit_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the exit
|
||||
// event for all qpPGItems. The exit event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_exit_prefix() {
|
||||
return "exit-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_within_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the within
|
||||
// event for all qpPGItems. The within event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_within_prefix() {
|
||||
return "within-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_without_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the without
|
||||
// event for all qpPGItems. The without event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_without_prefix() {
|
||||
return "without-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_focus_in_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the focus_in
|
||||
// event for all qpPGItems. The focus_in event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
//
|
||||
// Unlike most item events, this event is thrown with no
|
||||
// parameters.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_focus_in_prefix() {
|
||||
return "fin-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_focus_out_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the focus_out
|
||||
// event for all qpPGItems. The focus_out event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
//
|
||||
// Unlike most item events, this event is thrown with no
|
||||
// parameters.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_focus_out_prefix() {
|
||||
return "fout-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_press_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the press
|
||||
// event for all qpPGItems. The press event is the
|
||||
// concatenation of this string followed by a button
|
||||
// name, followed by a hyphen and get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_press_prefix() {
|
||||
return "press-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_release_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the release
|
||||
// event for all qpPGItems. The release event is the
|
||||
// concatenation of this string followed by a button
|
||||
// name, followed by a hyphen and get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_release_prefix() {
|
||||
return "release-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_keystroke_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the
|
||||
// keystroke event for all qpPGItems. The keystroke event
|
||||
// is the concatenation of this string followed by a
|
||||
// hyphen and get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_keystroke_prefix() {
|
||||
return "keystroke-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_enter_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item is active and the mouse enters its frame, but
|
||||
// not any nested frames.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_enter_event() const {
|
||||
return get_enter_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_exit_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item is active and the mouse exits its frame, or
|
||||
// enters a nested frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_exit_event() const {
|
||||
return get_exit_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_within_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item is active and the mouse moves within the
|
||||
// boundaries of the frame. This is different from the
|
||||
// enter_event in that the mouse is considered within
|
||||
// the frame even if it is also within a nested frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_within_event() const {
|
||||
return get_within_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_without_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item is active and the mouse moves completely outside
|
||||
// the boundaries of the frame. This is different from
|
||||
// the exit_event in that the mouse is considered
|
||||
// within the frame even if it is also within a nested
|
||||
// frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_without_event() const {
|
||||
return get_without_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_focus_in_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item gets the keyboard focus.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_focus_in_event() const {
|
||||
return get_focus_in_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_focus_out_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item loses the keyboard focus.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_focus_out_event() const {
|
||||
return get_focus_out_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_press_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item is active and the indicated mouse or keyboard
|
||||
// button is depressed while the mouse is within the
|
||||
// frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_press_event(const ButtonHandle &button) const {
|
||||
return get_press_prefix() + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_release_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item is active and the indicated mouse or keyboard
|
||||
// button, formerly clicked down is within the frame, is
|
||||
// released.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_release_event(const ButtonHandle &button) const {
|
||||
return get_release_prefix() + button.get_name() + "-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_keystroke_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// item is active and any key is pressed by the user.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string qpPGItem::
|
||||
get_keystroke_event() const {
|
||||
return get_keystroke_prefix() + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_text_node
|
||||
// Access: Published, Static
|
||||
// Description: Changes the TextNode object that will be used by all
|
||||
// qpPGItems to generate default labels given a string.
|
||||
// This can be loaded with the default font, etc.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGItem::
|
||||
set_text_node(qpTextNode *node) {
|
||||
_text_node = node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_focus_item
|
||||
// Access: Published, Static
|
||||
// Description: Returns the one qpPGItem in the world that currently
|
||||
// has keyboard focus, if any, or NULL if no item has
|
||||
// keyboard focus. Use qpPGItem::set_focus() to activate
|
||||
// or deactivate keyboard focus on a particular item.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpPGItem *qpPGItem::
|
||||
get_focus_item() {
|
||||
return _focus_item;
|
||||
}
|
||||
|
|
@ -0,0 +1,849 @@
|
|||
// Filename: qppgItem.cxx
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qppgItem.h"
|
||||
#include "pgTop.h"
|
||||
#include "pgMouseWatcherParameter.h"
|
||||
#include "pgCullTraverser.h"
|
||||
#include "config_pgui.h"
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "throw_event.h"
|
||||
#include "string_utils.h"
|
||||
#include "qpnodePath.h"
|
||||
#include "qpcullTraverser.h"
|
||||
|
||||
#ifdef HAVE_AUDIO
|
||||
#include "audioSound.h"
|
||||
#endif
|
||||
|
||||
TypeHandle qpPGItem::_type_handle;
|
||||
PT(qpTextNode) qpPGItem::_text_node;
|
||||
qpPGItem *qpPGItem::_focus_item = (qpPGItem *)NULL;
|
||||
qpPGItem::BackgroundFocus qpPGItem::_background_focus;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGItem::
|
||||
qpPGItem(const string &name) :
|
||||
PandaNode(name)
|
||||
{
|
||||
_has_frame = false;
|
||||
_frame.set(0, 0, 0, 0);
|
||||
_region = new PGMouseWatcherRegion(this);
|
||||
_state = 0;
|
||||
_flags = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGItem::
|
||||
~qpPGItem() {
|
||||
nassertv(_region->_qpitem == this);
|
||||
_region->_qpitem = (qpPGItem *)NULL;
|
||||
|
||||
set_background_focus(false);
|
||||
if (_focus_item == this) {
|
||||
_focus_item = (qpPGItem *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGItem::
|
||||
qpPGItem(const qpPGItem ©) :
|
||||
PandaNode(copy),
|
||||
_has_frame(copy._has_frame),
|
||||
_frame(copy._frame),
|
||||
_state(copy._state),
|
||||
_flags(copy._flags)
|
||||
{
|
||||
_region = new PGMouseWatcherRegion(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::make_copy
|
||||
// Access: Protected, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpPGItem::
|
||||
make_copy() const {
|
||||
return new qpPGItem(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::xform
|
||||
// Access: Protected, Virtual
|
||||
// Description: Transforms the contents of this node by the indicated
|
||||
// matrix, if it means anything to do so. For most
|
||||
// kinds of nodes, this does nothing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
xform(const LMatrix4f &mat) {
|
||||
// Transform the frame.
|
||||
LPoint3f ll(_frame[0], 0.0, _frame[2]);
|
||||
LPoint3f ur(_frame[1], 0.0, _frame[3]);
|
||||
ll = ll * mat;
|
||||
ur = ur * mat;
|
||||
_frame.set(ll[0], ur[0], ll[2], ur[2]);
|
||||
|
||||
// Transform the individual states and their frame styles.
|
||||
StateDefs::iterator di;
|
||||
for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
|
||||
PandaNode *node = (*di)._node;
|
||||
if (node != (PandaNode *)NULL) {
|
||||
// Apply the matrix to the previous transform.
|
||||
node->set_transform(node->get_transform()->compose(TransformState::make_mat(mat)));
|
||||
|
||||
/*
|
||||
// Now flatten the transform into the subgraph.
|
||||
SceneGraphReducer gr;
|
||||
gr.apply_transitions(arc);
|
||||
*/
|
||||
}
|
||||
|
||||
// Transform the frame style too.
|
||||
if ((*di)._frame_style.xform(mat)) {
|
||||
(*di)._frame_stale = true;
|
||||
}
|
||||
}
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::has_cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: Should be overridden by derived classes to return
|
||||
// true if cull_callback() has been defined. Otherwise,
|
||||
// returns false to indicate cull_callback() does not
|
||||
// need to be called for this node during the cull
|
||||
// traversal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGItem::
|
||||
has_cull_callback() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: If has_cull_callback() returns true, this function
|
||||
// will be called during the cull traversal to perform
|
||||
// any additional operations that should be performed at
|
||||
// cull time. This may include additional manipulation
|
||||
// of render state or additional visible/invisible
|
||||
// decisions, or any other arbitrary operation.
|
||||
//
|
||||
// By the time this function is called, the node has
|
||||
// already passed the bounding-volume test for the
|
||||
// viewing frustum, and the node's transform and state
|
||||
// have already been applied to the indicated
|
||||
// CullTraverserData object.
|
||||
//
|
||||
// The return value is true if this node should be
|
||||
// visible, or false if it should be culled.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGItem::
|
||||
cull_callback(qpCullTraverser *trav, CullTraverserData &data) {
|
||||
if (has_frame() && get_active()) {
|
||||
// The item has a frame, so we want to generate a region for it
|
||||
// and update the MouseWatcher.
|
||||
|
||||
// We can only do this if our traverser is a PGCullTraverser
|
||||
// (which will be the case if this node was parented somewhere
|
||||
// under a PGTop node).
|
||||
if (trav->is_exact_type(PGCullTraverser::get_class_type())) {
|
||||
PGCullTraverser *pg_trav;
|
||||
DCAST_INTO_R(pg_trav, trav, true);
|
||||
|
||||
const LMatrix4f &transform = data._net_transform->get_mat();
|
||||
activate_region(transform, pg_trav->_sort_index);
|
||||
pg_trav->_sort_index++;
|
||||
|
||||
pg_trav->_top->add_region(get_region());
|
||||
}
|
||||
}
|
||||
|
||||
if (has_state_def(get_state())) {
|
||||
// This item has a current state definition that we should use
|
||||
// to render the item.
|
||||
PandaNode *def = get_state_def(get_state());
|
||||
trav->traverse(def, data);
|
||||
}
|
||||
|
||||
// Now continue to render everything else below this node.
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::recompute_internal_bound
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called when needed to recompute the node's
|
||||
// _internal_bound object. Nodes that contain anything
|
||||
// of substance should redefine this to do the right
|
||||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *qpPGItem::
|
||||
recompute_internal_bound() {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
BoundingVolume *bound = PandaNode::recompute_internal_bound();
|
||||
nassertr(bound != (BoundingVolume *)NULL, bound);
|
||||
|
||||
// Now actually compute the bounding volume by putting it around all
|
||||
// of our states' bounding volumes.
|
||||
pvector<const BoundingVolume *> child_volumes;
|
||||
|
||||
// We walk through the list of state defs indirectly, calling
|
||||
// get_state_def() on each one, to ensure that the frames are
|
||||
// updated correctly before we measure their bounding volumes.
|
||||
for (int i = 0; i < (int)_state_defs.size(); i++) {
|
||||
PandaNode *node = get_state_def(i);
|
||||
if (node != (PandaNode *)NULL) {
|
||||
child_volumes.push_back(&node->get_bound());
|
||||
}
|
||||
}
|
||||
|
||||
const BoundingVolume **child_begin = &child_volumes[0];
|
||||
const BoundingVolume **child_end = child_begin + child_volumes.size();
|
||||
|
||||
bound->around(child_begin, child_end);
|
||||
return bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::activate_region
|
||||
// Access: Public
|
||||
// Description: Applies the indicated scene graph transform and order
|
||||
// as determined by the traversal from PGTop.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
activate_region(const LMatrix4f &transform, int sort) {
|
||||
// Transform all four vertices, and get the new bounding box. This
|
||||
// way the region works (mostly) even if has been rotated.
|
||||
LPoint3f ll(_frame[0], 0.0, _frame[2]);
|
||||
LPoint3f lr(_frame[1], 0.0, _frame[2]);
|
||||
LPoint3f ul(_frame[0], 0.0, _frame[3]);
|
||||
LPoint3f ur(_frame[1], 0.0, _frame[3]);
|
||||
ll = ll * transform;
|
||||
lr = lr * transform;
|
||||
ul = ul * transform;
|
||||
ur = ur * transform;
|
||||
_region->set_frame(min(min(ll[0], lr[0]), min(ul[0], ur[0])),
|
||||
max(max(ll[0], lr[0]), max(ul[0], ur[0])),
|
||||
min(min(ll[2], lr[2]), min(ul[2], ur[2])),
|
||||
max(max(ll[2], lr[2]), max(ul[2], ur[2])));
|
||||
|
||||
_region->set_sort(sort);
|
||||
_region->set_active(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::enter
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// mouse enters the region. The mouse is only
|
||||
// considered to be "entered" in one region at a time;
|
||||
// in the case of nested regions, it exits the outer
|
||||
// region before entering the inner one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
enter(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_enter_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::exit
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// mouse exits the region. The mouse is only considered
|
||||
// to be "entered" in one region at a time; in the case
|
||||
// of nested regions, it exits the outer region before
|
||||
// entering the inner one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
exit(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_exit_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::within
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// mouse moves within the boundaries of the region, even
|
||||
// if it is also within the boundaries of a nested
|
||||
// region. This is different from "enter", which is
|
||||
// only called whenever the mouse is within only that
|
||||
// region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
within(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_within_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::without
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// mouse moves completely outside the boundaries of the
|
||||
// region. See within().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
without(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_without_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::focus_in
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// widget gets the keyboard focus.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
focus_in() {
|
||||
string event = get_focus_in_event();
|
||||
play_sound(event);
|
||||
throw_event(event);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::focus_out
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// widget loses the keyboard focus.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
focus_out() {
|
||||
string event = get_focus_out_event();
|
||||
play_sound(event);
|
||||
throw_event(event);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::press
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse or keyboard button is depressed while the mouse
|
||||
// is within the region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (!background) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_press_event(param.get_button());
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::release
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse or keyboard button previously depressed with
|
||||
// press() is released.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
release(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (!background) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_release_event(param.get_button());
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::keystroke
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever
|
||||
// the user presses a key.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
keystroke(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (!background) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_keystroke_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::background_press
|
||||
// Access: Public, Static
|
||||
// Description: Calls press() on all the qpPGItems with background
|
||||
// focus.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
background_press(const MouseWatcherParameter ¶m) {
|
||||
BackgroundFocus::const_iterator fi;
|
||||
for (fi = _background_focus.begin(); fi != _background_focus.end(); ++fi) {
|
||||
qpPGItem *item = *fi;
|
||||
if (!item->get_focus()) {
|
||||
item->press(param, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::background_release
|
||||
// Access: Public, Static
|
||||
// Description: Calls release() on all the qpPGItems with background
|
||||
// focus.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
background_release(const MouseWatcherParameter ¶m) {
|
||||
BackgroundFocus::const_iterator fi;
|
||||
for (fi = _background_focus.begin(); fi != _background_focus.end(); ++fi) {
|
||||
qpPGItem *item = *fi;
|
||||
if (!item->get_focus()) {
|
||||
item->release(param, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::background_keystroke
|
||||
// Access: Public, Static
|
||||
// Description: Calls keystroke() on all the qpPGItems with background
|
||||
// focus.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
background_keystroke(const MouseWatcherParameter ¶m) {
|
||||
BackgroundFocus::const_iterator fi;
|
||||
for (fi = _background_focus.begin(); fi != _background_focus.end(); ++fi) {
|
||||
qpPGItem *item = *fi;
|
||||
if (!item->get_focus()) {
|
||||
item->keystroke(param, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_active
|
||||
// Access: Published, Virtual
|
||||
// Description: Sets whether the qpPGItem is active for mouse watching.
|
||||
// This is not necessarily related to the
|
||||
// active/inactive appearance of the item, which is
|
||||
// controlled by set_state(), but it does affect whether
|
||||
// it responds to mouse events.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
set_active(bool active) {
|
||||
if (active) {
|
||||
_flags |= F_active;
|
||||
} else {
|
||||
_flags &= ~F_active;
|
||||
// Deactivating the item automatically defocuses it too.
|
||||
if (get_focus()) {
|
||||
set_focus(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_focus
|
||||
// Access: Published, Virtual
|
||||
// Description: Sets whether the qpPGItem currently has keyboard focus.
|
||||
// This simply means that the item may respond to
|
||||
// keyboard events as well as to mouse events; precisely
|
||||
// what this means is up to the individual item.
|
||||
//
|
||||
// Only one qpPGItem in the world is allowed to have focus
|
||||
// at any given time. Setting the focus on any other
|
||||
// item automatically disables the focus from the
|
||||
// previous item.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
set_focus(bool focus) {
|
||||
if (focus) {
|
||||
if (!get_active()) {
|
||||
// Cannot set focus on an inactive item.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the keyboard focus to this item.
|
||||
if (_focus_item != this) {
|
||||
if (_focus_item != (qpPGItem *)NULL) {
|
||||
// Clear the focus from whatever item currently has it.
|
||||
_focus_item->set_focus(false);
|
||||
}
|
||||
_focus_item = this;
|
||||
}
|
||||
if (!get_focus()) {
|
||||
focus_in();
|
||||
_flags |= F_focus;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (_focus_item == this) {
|
||||
// Remove this item from the focus.
|
||||
_focus_item = (qpPGItem *)NULL;
|
||||
}
|
||||
|
||||
if (get_focus()) {
|
||||
focus_out();
|
||||
_flags &= ~F_focus;
|
||||
}
|
||||
}
|
||||
_region->set_keyboard(focus);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_background_focus
|
||||
// Access: Published
|
||||
// Description: Sets the background_focus flag for this item. When
|
||||
// background_focus is enabled, the item will receive
|
||||
// keypress events even if it is not in focus; in fact,
|
||||
// even if it is not onscreen. Unlike normal focus,
|
||||
// many items may have background_focus simultaneously.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
set_background_focus(bool focus) {
|
||||
if (focus != get_background_focus()) {
|
||||
if (focus) {
|
||||
// Activate background focus.
|
||||
_flags |= F_background_focus;
|
||||
bool inserted = _background_focus.insert(this).second;
|
||||
nassertv(inserted);
|
||||
|
||||
} else {
|
||||
// Deactivate background focus.
|
||||
_flags &= ~F_background_focus;
|
||||
size_t num_erased = _background_focus.erase(this);
|
||||
nassertv(num_erased == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_num_state_defs
|
||||
// Access: Published
|
||||
// Description: Returns one more than the highest-numbered state def
|
||||
// that was ever assigned to the qpPGItem. The complete
|
||||
// set of state defs assigned may then be retrieved by
|
||||
// indexing from 0 to (get_num_state_defs() - 1).
|
||||
//
|
||||
// This is only an upper limit on the actual number of
|
||||
// state defs, since there may be holes in the list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int qpPGItem::
|
||||
get_num_state_defs() const {
|
||||
return _state_defs.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::has_state_def
|
||||
// Access: Published
|
||||
// Description: Returns true if get_state_def() has ever been called
|
||||
// for the indicated state (thus defining a render
|
||||
// subgraph for this state index), false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGItem::
|
||||
has_state_def(int state) const {
|
||||
if (state < 0 || state >= (int)_state_defs.size()) {
|
||||
return false;
|
||||
}
|
||||
return (_state_defs[state]._node != (PandaNode *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::clear_state_def
|
||||
// Access: Published
|
||||
// Description: Resets the NodePath assigned to the indicated state
|
||||
// to its initial default, with only a frame
|
||||
// representation if appropriate.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
clear_state_def(int state) {
|
||||
if (state < 0 || state >= (int)_state_defs.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PandaNode *node = _state_defs[state]._node;
|
||||
if (node != (PandaNode *)NULL) {
|
||||
node->remove_all_children();
|
||||
}
|
||||
|
||||
_state_defs[state]._frame_node = (PandaNode *)NULL;
|
||||
_state_defs[state]._frame_stale = true;
|
||||
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_state_def
|
||||
// Access: Published
|
||||
// Description: Returns the Node that is the root of the subgraph
|
||||
// that will be drawn when the qpPGItem is in the
|
||||
// indicated state. The first time this is called for a
|
||||
// particular state index, it may create the Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpPGItem::
|
||||
get_state_def(int state) {
|
||||
nassertr(state >= 0 && state < 1000, (PandaNode *)NULL); // Sanity check.
|
||||
slot_state_def(state);
|
||||
|
||||
if (_state_defs[state]._node == (PandaNode *)NULL) {
|
||||
// Create a new node.
|
||||
_state_defs[state]._node = new PandaNode("state_" + format_string(state));
|
||||
_state_defs[state]._frame_stale = true;
|
||||
}
|
||||
|
||||
if (_state_defs[state]._frame_stale) {
|
||||
update_frame(state);
|
||||
}
|
||||
|
||||
return _state_defs[state]._node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::instance_to_state_def
|
||||
// Access: Published
|
||||
// Description: Parents an instance of the bottom node of the
|
||||
// indicated NodePath to the indicated state index.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
instance_to_state_def(int state, const qpNodePath &path) {
|
||||
if (path.is_empty()) {
|
||||
// If the path is empty, quietly do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
get_state_def(state)->add_child(path.node());
|
||||
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_frame_style
|
||||
// Access: Published
|
||||
// Description: Returns the kind of frame that will be drawn behind
|
||||
// the item when it is in the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGFrameStyle qpPGItem::
|
||||
get_frame_style(int state) {
|
||||
if (state < 0 || state >= (int)_state_defs.size()) {
|
||||
return PGFrameStyle();
|
||||
}
|
||||
return _state_defs[state]._frame_style;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_frame_style
|
||||
// Access: Published
|
||||
// Description: Changes the kind of frame that will be drawn behind
|
||||
// the item when it is in the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
set_frame_style(int state, const PGFrameStyle &style) {
|
||||
// Get the state def node, mainly to ensure that this state is
|
||||
// slotted and listed as having been defined.
|
||||
PandaNode *def = get_state_def(state);
|
||||
nassertv(def != (PandaNode *)NULL);
|
||||
|
||||
_state_defs[state]._frame_style = style;
|
||||
_state_defs[state]._frame_stale = true;
|
||||
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
#ifdef HAVE_AUDIO
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::set_sound
|
||||
// Access: Published
|
||||
// Description: Sets the sound that will be played whenever the
|
||||
// indicated event occurs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
set_sound(const string &event, AudioSound *sound) {
|
||||
_sounds[event] = sound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::clear_sound
|
||||
// Access: Published
|
||||
// Description: Removes the sound associated with the indicated
|
||||
// event.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
clear_sound(const string &event) {
|
||||
_sounds.erase(event);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_sound
|
||||
// Access: Published
|
||||
// Description: Returns the sound associated with the indicated
|
||||
// event, or NULL if there is no associated sound.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AudioSound *qpPGItem::
|
||||
get_sound(const string &event) const {
|
||||
Sounds::const_iterator si = _sounds.find(event);
|
||||
if (si != _sounds.end()) {
|
||||
return (*si).second;
|
||||
}
|
||||
return (AudioSound *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::has_sound
|
||||
// Access: Published
|
||||
// Description: Returns true if there is a sound associated with the
|
||||
// indicated event, or false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGItem::
|
||||
has_sound(const string &event) const {
|
||||
return (_sounds.count(event) != 0);
|
||||
}
|
||||
#endif // HAVE_AUDIO
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::get_text_node
|
||||
// Access: Published, Static
|
||||
// Description: Returns the TextNode object that will be used by all
|
||||
// qpPGItems to generate default labels given a string.
|
||||
// This can be loaded with the default font, etc.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpTextNode *qpPGItem::
|
||||
get_text_node() {
|
||||
if (_text_node == (qpTextNode *)NULL) {
|
||||
_text_node = new qpTextNode("pguiText");
|
||||
_text_node->freeze();
|
||||
_text_node->set_text_color(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
// The default TextNode is aligned to the left, for the
|
||||
// convenience of PGEntry.
|
||||
_text_node->set_align(qpTextNode::A_left);
|
||||
}
|
||||
return _text_node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::play_sound
|
||||
// Access: Protected
|
||||
// Description: Plays the sound associated with the indicated event,
|
||||
// if there is one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
play_sound(const string &event) {
|
||||
#ifdef HAVE_AUDIO
|
||||
Sounds::const_iterator si = _sounds.find(event);
|
||||
if (si != _sounds.end()) {
|
||||
AudioSound *sound = (*si).second;
|
||||
sound->play();
|
||||
}
|
||||
#endif // HAVE_AUDIO
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::slot_state_def
|
||||
// Access: Private
|
||||
// Description: Ensures there is a slot in the array for the given
|
||||
// state definition.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
slot_state_def(int state) {
|
||||
while (state >= (int)_state_defs.size()) {
|
||||
StateDef def;
|
||||
def._frame_stale = true;
|
||||
_state_defs.push_back(def);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::update_frame
|
||||
// Access: Private
|
||||
// Description: Generates a new instance of the frame geometry for
|
||||
// the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
update_frame(int state) {
|
||||
// First, remove the old frame geometry, if any.
|
||||
if (state >= 0 && state < (int)_state_defs.size()) {
|
||||
PandaNode *old_frame = _state_defs[state]._frame_node;
|
||||
if (old_frame != (PandaNode *)NULL) {
|
||||
PandaNode *node = _state_defs[state]._node;
|
||||
nassertv(node != (PandaNode *)NULL);
|
||||
node->remove_child(old_frame);
|
||||
_state_defs[state]._frame_node = (PandaNode *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// We must turn off the stale flag first, before we call
|
||||
// get_state_def(), to prevent get_state_def() from being a
|
||||
// recursive call.
|
||||
_state_defs[state]._frame_stale = false;
|
||||
|
||||
// Now create new frame geometry.
|
||||
if (has_frame()) {
|
||||
PandaNode *node = get_state_def(state);
|
||||
nassertv(node != (PandaNode *)NULL);
|
||||
_state_defs[state]._frame_node =
|
||||
_state_defs[state]._frame_style.generate_into(node, _frame);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGItem::mark_frames_stale
|
||||
// Access: Private
|
||||
// Description: Marks all the frames in all states stale, so that
|
||||
// they will be regenerated the next time each state is
|
||||
// requested.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGItem::
|
||||
mark_frames_stale() {
|
||||
StateDefs::iterator di;
|
||||
for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
|
||||
// Remove the old frame, if any.
|
||||
PandaNode *old_frame = (*di)._frame_node;
|
||||
if (old_frame != (PandaNode *)NULL) {
|
||||
PandaNode *node = (*di)._node;
|
||||
nassertv(node != (PandaNode *)NULL);
|
||||
node->remove_child(old_frame);
|
||||
(*di)._frame_node = (PandaNode *)NULL;
|
||||
}
|
||||
|
||||
(*di)._frame_stale = true;
|
||||
}
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
// Filename: qppgItem.h
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef qpPGITEM_H
|
||||
#define qpPGITEM_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pgMouseWatcherRegion.h"
|
||||
#include "pgFrameStyle.h"
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "luse.h"
|
||||
#include "pointerTo.h"
|
||||
#include "qptextNode.h"
|
||||
|
||||
#include "pmap.h"
|
||||
|
||||
class PGTop;
|
||||
class MouseWatcherParameter;
|
||||
class AudioSound;
|
||||
class qpNodePath;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpPGItem
|
||||
// Description : This is the base class for all the various kinds of
|
||||
// gui widget objects.
|
||||
//
|
||||
// It is a Node which corresponds to a rectangular
|
||||
// region on the screen, and it may have any number of
|
||||
// "state" subgraphs, one of which is rendered at any
|
||||
// given time according to its current state.
|
||||
//
|
||||
// The qpPGItem node must be parented to the scene graph
|
||||
// somewhere beneath a PGTop node in order for this
|
||||
// behavior to work.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpPGItem : public PandaNode {
|
||||
PUBLISHED:
|
||||
qpPGItem(const string &name);
|
||||
virtual ~qpPGItem();
|
||||
|
||||
protected:
|
||||
qpPGItem(const qpPGItem ©);
|
||||
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
virtual bool has_cull_callback() const;
|
||||
virtual bool cull_callback(qpCullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
virtual BoundingVolume *recompute_internal_bound();
|
||||
|
||||
public:
|
||||
void activate_region(const LMatrix4f &transform, int sort);
|
||||
INLINE PGMouseWatcherRegion *get_region() const;
|
||||
|
||||
virtual void enter(const MouseWatcherParameter ¶m);
|
||||
virtual void exit(const MouseWatcherParameter ¶m);
|
||||
virtual void within(const MouseWatcherParameter ¶m);
|
||||
virtual void without(const MouseWatcherParameter ¶m);
|
||||
virtual void focus_in();
|
||||
virtual void focus_out();
|
||||
virtual void press(const MouseWatcherParameter ¶m, bool background);
|
||||
virtual void release(const MouseWatcherParameter ¶m, bool background);
|
||||
virtual void keystroke(const MouseWatcherParameter ¶m, bool background);
|
||||
|
||||
static void background_press(const MouseWatcherParameter ¶m);
|
||||
static void background_release(const MouseWatcherParameter ¶m);
|
||||
static void background_keystroke(const MouseWatcherParameter ¶m);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void set_frame(float left, float right, float bottom, float top);
|
||||
INLINE void set_frame(const LVecBase4f &frame);
|
||||
INLINE const LVecBase4f &get_frame() const;
|
||||
INLINE bool has_frame() const;
|
||||
INLINE void clear_frame();
|
||||
|
||||
INLINE void set_state(int state);
|
||||
INLINE int get_state() const;
|
||||
|
||||
virtual void set_active(bool active);
|
||||
INLINE bool get_active() const;
|
||||
|
||||
virtual void set_focus(bool focus);
|
||||
INLINE bool get_focus() const;
|
||||
|
||||
void set_background_focus(bool focus);
|
||||
INLINE bool get_background_focus() const;
|
||||
|
||||
INLINE void set_suppress_flags(int suppress_flags);
|
||||
INLINE int get_suppress_flags() const;
|
||||
|
||||
int get_num_state_defs() const;
|
||||
void clear_state_def(int state);
|
||||
bool has_state_def(int state) const;
|
||||
PandaNode *get_state_def(int state);
|
||||
void instance_to_state_def(int state, const qpNodePath &chain);
|
||||
|
||||
PGFrameStyle get_frame_style(int state);
|
||||
void set_frame_style(int state, const PGFrameStyle &style);
|
||||
|
||||
INLINE const string &get_id() const;
|
||||
INLINE void set_id(const string &id);
|
||||
|
||||
INLINE static string get_enter_prefix();
|
||||
INLINE static string get_exit_prefix();
|
||||
INLINE static string get_within_prefix();
|
||||
INLINE static string get_without_prefix();
|
||||
INLINE static string get_focus_in_prefix();
|
||||
INLINE static string get_focus_out_prefix();
|
||||
INLINE static string get_press_prefix();
|
||||
INLINE static string get_release_prefix();
|
||||
INLINE static string get_keystroke_prefix();
|
||||
|
||||
INLINE string get_enter_event() const;
|
||||
INLINE string get_exit_event() const;
|
||||
INLINE string get_within_event() const;
|
||||
INLINE string get_without_event() const;
|
||||
INLINE string get_focus_in_event() const;
|
||||
INLINE string get_focus_out_event() const;
|
||||
INLINE string get_press_event(const ButtonHandle &button) const;
|
||||
INLINE string get_release_event(const ButtonHandle &button) const;
|
||||
INLINE string get_keystroke_event() const;
|
||||
|
||||
#ifdef HAVE_AUDIO
|
||||
void set_sound(const string &event, AudioSound *sound);
|
||||
void clear_sound(const string &event);
|
||||
AudioSound *get_sound(const string &event) const;
|
||||
bool has_sound(const string &event) const;
|
||||
#endif
|
||||
|
||||
static qpTextNode *get_text_node();
|
||||
INLINE static void set_text_node(qpTextNode *node);
|
||||
|
||||
INLINE static qpPGItem *get_focus_item();
|
||||
|
||||
protected:
|
||||
void play_sound(const string &event);
|
||||
|
||||
private:
|
||||
void slot_state_def(int state);
|
||||
void update_frame(int state);
|
||||
void mark_frames_stale();
|
||||
|
||||
bool _has_frame;
|
||||
LVecBase4f _frame;
|
||||
int _state;
|
||||
enum Flags {
|
||||
F_active = 0x01,
|
||||
F_focus = 0x02,
|
||||
F_background_focus = 0x04,
|
||||
};
|
||||
int _flags;
|
||||
|
||||
PT(PGMouseWatcherRegion) _region;
|
||||
|
||||
class StateDef {
|
||||
public:
|
||||
PT(PandaNode) _node;
|
||||
PGFrameStyle _frame_style;
|
||||
PT(PandaNode) _frame_node;
|
||||
bool _frame_stale;
|
||||
};
|
||||
typedef pvector<StateDef> StateDefs;
|
||||
StateDefs _state_defs;
|
||||
|
||||
#ifdef HAVE_AUDIO
|
||||
typedef pmap<string, PT(AudioSound) > Sounds;
|
||||
Sounds _sounds;
|
||||
#endif
|
||||
|
||||
static PT(qpTextNode) _text_node;
|
||||
static qpPGItem *_focus_item;
|
||||
|
||||
typedef pset<qpPGItem *> BackgroundFocus;
|
||||
static BackgroundFocus _background_focus;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
PandaNode::init_type();
|
||||
register_type(_type_handle, "qpPGItem",
|
||||
PandaNode::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "qppgItem.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// Filename: qppgTop.I
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpPGTop::
|
||||
qpPGTop(const qpPGTop ©) :
|
||||
PandaNode(copy),
|
||||
_watcher(copy._watcher)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::get_mouse_watcher
|
||||
// Access: Published
|
||||
// Description: Returns the MouseWatcher pointer that the qpPGTop object
|
||||
// registers its PG items with, or NULL if the
|
||||
// MouseWatcher has not yet been set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpMouseWatcher *qpPGTop::
|
||||
get_mouse_watcher() const {
|
||||
return _watcher;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::add_region
|
||||
// Access: Public
|
||||
// Description: Adds the indicated region to the set of regions in
|
||||
// the group. Returns true if it was successfully
|
||||
// added, or false if it was already on the list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpPGTop::
|
||||
add_region(MouseWatcherRegion *region) {
|
||||
if (_watcher_group == (PGMouseWatcherGroup *)NULL) {
|
||||
return false;
|
||||
}
|
||||
return _watcher_group->add_region(region);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::clear_regions
|
||||
// Access: Public
|
||||
// Description: Removes all the regions from the group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGTop::
|
||||
clear_regions() {
|
||||
if (_watcher_group == (PGMouseWatcherGroup *)NULL) {
|
||||
return;
|
||||
}
|
||||
_watcher_group->clear_regions();
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
// Filename: qppgTop.cxx
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qppgTop.h"
|
||||
#include "pgItem.h"
|
||||
#include "pgMouseWatcherGroup.h"
|
||||
#include "pgCullTraverser.h"
|
||||
|
||||
#include "omniBoundingVolume.h"
|
||||
|
||||
TypeHandle qpPGTop::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGTop::
|
||||
qpPGTop(const string &name) :
|
||||
PandaNode(name)
|
||||
{
|
||||
_watcher_group = (PGMouseWatcherGroup *)NULL;
|
||||
|
||||
// A qpPGTop node normally has an infinite bounding volume. Screw
|
||||
// culling.
|
||||
set_bound(OmniBoundingVolume());
|
||||
set_final(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGTop::
|
||||
~qpPGTop() {
|
||||
set_mouse_watcher((qpMouseWatcher *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::make_copy
|
||||
// Access: Protected, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpPGTop::
|
||||
make_copy() const {
|
||||
return new qpPGTop(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::has_cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: Should be overridden by derived classes to return
|
||||
// true if cull_callback() has been defined. Otherwise,
|
||||
// returns false to indicate cull_callback() does not
|
||||
// need to be called for this node during the cull
|
||||
// traversal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGTop::
|
||||
has_cull_callback() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: If has_cull_callback() returns true, this function
|
||||
// will be called during the cull traversal to perform
|
||||
// any additional operations that should be performed at
|
||||
// cull time. This may include additional manipulation
|
||||
// of render state or additional visible/invisible
|
||||
// decisions, or any other arbitrary operation.
|
||||
//
|
||||
// By the time this function is called, the node has
|
||||
// already passed the bounding-volume test for the
|
||||
// viewing frustum, and the node's transform and state
|
||||
// have already been applied to the indicated
|
||||
// CullTraverserData object.
|
||||
//
|
||||
// The return value is true if this node should be
|
||||
// visible, or false if it should be culled.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGTop::
|
||||
cull_callback(qpCullTraverser *trav, CullTraverserData &data) {
|
||||
// Empty our set of regions in preparation for re-adding whichever
|
||||
// ones we encounter in the traversal that are current.
|
||||
clear_regions();
|
||||
|
||||
// Now subsitute for the normal CullTraverser a special one of our
|
||||
// own choosing. This just carries around a pointer back to the
|
||||
// PGTop node, for the convenience of PGItems to register themselves
|
||||
// as they are drawn.
|
||||
PGCullTraverser pg_trav(this, trav);
|
||||
pg_trav.traverse_below(this, data);
|
||||
|
||||
// We've taken care of the traversal, thank you.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGTop::set_mouse_watcher
|
||||
// Access: Published
|
||||
// Description: Sets the MouseWatcher pointer that the qpPGTop object
|
||||
// registers its PG items with. This must be set before
|
||||
// the PG items are active.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGTop::
|
||||
set_mouse_watcher(qpMouseWatcher *watcher) {
|
||||
if (_watcher_group != (PGMouseWatcherGroup *)NULL) {
|
||||
_watcher_group->clear_top(this);
|
||||
}
|
||||
if (_watcher != (qpMouseWatcher *)NULL) {
|
||||
_watcher->remove_group(_watcher_group);
|
||||
}
|
||||
|
||||
_watcher = watcher;
|
||||
_watcher_group = (PGMouseWatcherGroup *)NULL;
|
||||
|
||||
if (_watcher != (qpMouseWatcher *)NULL) {
|
||||
// We create a new PGMouseWatcherGroup, but we don't own the
|
||||
// reference count; the watcher will own this for us.
|
||||
_watcher_group = new PGMouseWatcherGroup(this);
|
||||
_watcher->add_group(_watcher_group);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (node->is_of_type(PGItem::get_class_type())) {
|
||||
PGItem *pgi = DCAST(PGItem, node);
|
||||
|
||||
if (pgi->has_frame() && pgi->get_active()) {
|
||||
// The item has a frame, so we want to generate a region for it
|
||||
// and update the MouseWatcher.
|
||||
|
||||
// Get the complete net transform to the PGItem from the top.
|
||||
LMatrix4f mat;
|
||||
|
||||
NodeTransitionWrapper ntw(TransformTransition::get_class_type());
|
||||
wrt(pgi, chain.begin(), chain.end(), (Node *)NULL,
|
||||
ntw, RenderRelation::get_class_type());
|
||||
const TransformTransition *tt;
|
||||
if (!get_transition_into(tt, ntw)) {
|
||||
// No relative transform.
|
||||
mat = LMatrix4f::ident_mat();
|
||||
} else {
|
||||
mat = tt->get_matrix();
|
||||
}
|
||||
|
||||
// Now apply this transform to the item's frame.
|
||||
pgi->activate_region(this, mat, _sort_index);
|
||||
_sort_index++;
|
||||
|
||||
add_region(pgi->get_region());
|
||||
}
|
||||
*/
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// Filename: qppgTop.h
|
||||
// Created by: drose (13Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef qpPGTOP_H
|
||||
#define qpPGTOP_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pgMouseWatcherGroup.h"
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "qpmouseWatcher.h"
|
||||
#include "pointerTo.h"
|
||||
|
||||
class GraphicsStateGuardian;
|
||||
class PGMouseWatcherGroup;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGTop
|
||||
// Description : The "top" node of the new Panda GUI system. This
|
||||
// node must be parented to the 2-d scene graph, and all
|
||||
// PG objects should be parented to this node or
|
||||
// somewhere below it. PG objects not parented within
|
||||
// this hierarchy will not be clickable.
|
||||
//
|
||||
// This node begins the special traversal of the PG
|
||||
// objects that registers each node within the
|
||||
// MouseWatcher and forces everything to render in a
|
||||
// depth-first, left-to-right order, appropriate for 2-d
|
||||
// objects.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpPGTop : public PandaNode {
|
||||
PUBLISHED:
|
||||
qpPGTop(const string &name);
|
||||
virtual ~qpPGTop();
|
||||
|
||||
protected:
|
||||
INLINE qpPGTop(const qpPGTop ©);
|
||||
|
||||
public:
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual bool has_cull_callback() const;
|
||||
virtual bool cull_callback(qpCullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
PUBLISHED:
|
||||
void set_mouse_watcher(qpMouseWatcher *watcher);
|
||||
INLINE qpMouseWatcher *get_mouse_watcher() const;
|
||||
|
||||
public:
|
||||
// These methods duplicate the functionality of MouseWatcherGroup.
|
||||
INLINE bool add_region(MouseWatcherRegion *region);
|
||||
INLINE void clear_regions();
|
||||
|
||||
private:
|
||||
PT(qpMouseWatcher) _watcher;
|
||||
PGMouseWatcherGroup *_watcher_group;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
PandaNode::init_type();
|
||||
register_type(_type_handle, "qpPGTop",
|
||||
PandaNode::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class PGMouseWatcherGroup;
|
||||
};
|
||||
|
||||
#include "qppgTop.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// Filename: qppgWaitBar.I
|
||||
// Created by: drose (14Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::set_range
|
||||
// Access: Published
|
||||
// Description: Sets the value at which the WaitBar indicates 100%.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGWaitBar::
|
||||
set_range(float range) {
|
||||
_range = range;
|
||||
_bar_state = -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::get_range
|
||||
// Access: Published
|
||||
// Description: Returns the value at which the WaitBar indicates 100%.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float qpPGWaitBar::
|
||||
get_range() const {
|
||||
return _range;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::set_value
|
||||
// Access: Published
|
||||
// Description: Sets the current value of the bar. This should range
|
||||
// between 0 and get_range().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGWaitBar::
|
||||
set_value(float value) {
|
||||
_value = value;
|
||||
_bar_state = -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::get_value
|
||||
// Access: Published
|
||||
// Description: Returns the current value of the bar.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float qpPGWaitBar::
|
||||
get_value() const {
|
||||
return _value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::get_percent
|
||||
// Access: Published
|
||||
// Description: Returns the percentage complete.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float qpPGWaitBar::
|
||||
get_percent() const {
|
||||
return _value / _range * 100.0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::set_bar_style
|
||||
// Access: Published
|
||||
// Description: Sets the kind of frame that is drawn on top of the
|
||||
// WaitBar to represent the amount completed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpPGWaitBar::
|
||||
set_bar_style(const PGFrameStyle &style) {
|
||||
_bar_style = style;
|
||||
_bar_state = -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::get_bar_style
|
||||
// Access: Published
|
||||
// Description: Returns the kind of frame that is drawn on top of the
|
||||
// WaitBar to represent the amount completed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGFrameStyle qpPGWaitBar::
|
||||
get_bar_style() const {
|
||||
return _bar_style;
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
// Filename: qppgWaitBar.cxx
|
||||
// Created by: drose (14Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qppgWaitBar.h"
|
||||
#include "pgMouseWatcherParameter.h"
|
||||
|
||||
#include "throw_event.h"
|
||||
|
||||
TypeHandle qpPGWaitBar::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGWaitBar::
|
||||
qpPGWaitBar(const string &name) : qpPGItem(name)
|
||||
{
|
||||
_range = 100.0;
|
||||
_value = 0.0;
|
||||
_bar_state = -1;
|
||||
_bar_node = (PandaNode *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGWaitBar::
|
||||
~qpPGWaitBar() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::Copy Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpPGWaitBar::
|
||||
qpPGWaitBar(const qpPGWaitBar ©) :
|
||||
qpPGItem(copy),
|
||||
_range(copy._range),
|
||||
_value(copy._value)
|
||||
{
|
||||
_bar_state = -1;
|
||||
_bar_node = (PandaNode *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *qpPGWaitBar::
|
||||
make_copy() const {
|
||||
return new qpPGWaitBar(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::has_cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: Should be overridden by derived classes to return
|
||||
// true if cull_callback() has been defined. Otherwise,
|
||||
// returns false to indicate cull_callback() does not
|
||||
// need to be called for this node during the cull
|
||||
// traversal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGWaitBar::
|
||||
has_cull_callback() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: If has_cull_callback() returns true, this function
|
||||
// will be called during the cull traversal to perform
|
||||
// any additional operations that should be performed at
|
||||
// cull time. This may include additional manipulation
|
||||
// of render state or additional visible/invisible
|
||||
// decisions, or any other arbitrary operation.
|
||||
//
|
||||
// By the time this function is called, the node has
|
||||
// already passed the bounding-volume test for the
|
||||
// viewing frustum, and the node's transform and state
|
||||
// have already been applied to the indicated
|
||||
// CullTraverserData object.
|
||||
//
|
||||
// The return value is true if this node should be
|
||||
// visible, or false if it should be culled.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool qpPGWaitBar::
|
||||
cull_callback(qpCullTraverser *trav, CullTraverserData &data) {
|
||||
update();
|
||||
return qpPGItem::cull_callback(trav, data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::setup
|
||||
// Access: Public
|
||||
// Description: Creates a qpPGWaitBar with the indicated dimensions,
|
||||
// with the indicated maximum range.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGWaitBar::
|
||||
setup(float width, float height, float range) {
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
set_frame(-0.5 * width, 0.5 * width, -0.5 * height, 0.5 * height);
|
||||
|
||||
PGFrameStyle style;
|
||||
style.set_width(0.05, 0.05);
|
||||
|
||||
style.set_color(0.6, 0.6, 0.6, 1.0);
|
||||
style.set_type(PGFrameStyle::T_bevel_in);
|
||||
set_frame_style(0, style);
|
||||
|
||||
style.set_color(0.8, 0.8, 0.8, 1.0);
|
||||
style.set_type(PGFrameStyle::T_bevel_out);
|
||||
set_bar_style(style);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpPGWaitBar::update
|
||||
// Access: Private
|
||||
// Description: Computes the appropriate size of the bar frame
|
||||
// according to the percentage completed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpPGWaitBar::
|
||||
update() {
|
||||
int state = get_state();
|
||||
|
||||
// If the bar was last drawn in this state and is still current, we
|
||||
// don't have to draw it again.
|
||||
if (_bar_state == state) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the old bar geometry, if any.
|
||||
if (_bar_node != (PandaNode *)NULL) {
|
||||
PandaNode *parent_node = _bar_node->get_parent(0);
|
||||
parent_node->remove_child(_bar_node);
|
||||
_bar_node = (PandaNode *)NULL;
|
||||
}
|
||||
|
||||
// Now create new bar geometry.
|
||||
if (_value != 0.0 && _range != 0.0) {
|
||||
PandaNode *node = get_state_def(state);
|
||||
nassertv(node != (PandaNode *)NULL);
|
||||
|
||||
PGFrameStyle style = get_frame_style(state);
|
||||
const LVecBase4f &frame = get_frame();
|
||||
const LVecBase2f &width = style.get_width();
|
||||
|
||||
// Put the bar within the item's frame's border.
|
||||
LVecBase4f bar_frame(frame[0] + width[0],
|
||||
frame[1] - width[0],
|
||||
frame[2] + width[1],
|
||||
frame[3] - width[1]);
|
||||
|
||||
// And scale the bar according to our value.
|
||||
float frac = _value / _range;
|
||||
frac = max(min(frac, 1.0f), 0.0f);
|
||||
bar_frame[1] = bar_frame[0] + frac * (bar_frame[1] - bar_frame[0]);
|
||||
|
||||
_bar_node = _bar_style.generate_into(node, bar_frame);
|
||||
}
|
||||
|
||||
// Indicate that the bar is current for this state.
|
||||
_bar_state = state;
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// Filename: qppgWaitBar.h
|
||||
// Created by: drose (14Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://www.panda3d.org/license.txt .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d@yahoogroups.com .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef qpPGWAITBAR_H
|
||||
#define qpPGWAITBAR_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "qppgItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpPGWaitBar
|
||||
// Description : This is a particular kind of qpPGItem that draws a
|
||||
// little bar that fills from left to right to indicate
|
||||
// a slow process gradually completing, like a
|
||||
// traditional "wait, loading" bar.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpPGWaitBar : public qpPGItem {
|
||||
PUBLISHED:
|
||||
qpPGWaitBar(const string &name = "");
|
||||
virtual ~qpPGWaitBar();
|
||||
|
||||
protected:
|
||||
qpPGWaitBar(const qpPGWaitBar ©);
|
||||
|
||||
public:
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual bool has_cull_callback() const;
|
||||
virtual bool cull_callback(qpCullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
PUBLISHED:
|
||||
void setup(float width, float height, float range);
|
||||
|
||||
INLINE void set_range(float range);
|
||||
INLINE float get_range() const;
|
||||
|
||||
INLINE void set_value(float value);
|
||||
INLINE float get_value() const;
|
||||
|
||||
INLINE float get_percent() const;
|
||||
|
||||
INLINE void set_bar_style(const PGFrameStyle &style);
|
||||
INLINE PGFrameStyle get_bar_style() const;
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
float _range, _value;
|
||||
int _bar_state;
|
||||
PGFrameStyle _bar_style;
|
||||
PT(PandaNode) _bar_node;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
qpPGItem::init_type();
|
||||
register_type(_type_handle, "qpPGWaitBar",
|
||||
qpPGItem::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "qppgWaitBar.I"
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue