16 #include "pgMouseWatcherParameter.h"
18 #include "cullTraverser.h"
19 #include "cullTraverserData.h"
20 #include "throw_event.h"
21 #include "transformState.h"
22 #include "mouseWatcherParameter.h"
23 #include "keyboardButton.h"
24 #include "mouseButton.h"
26 #include "textEncoder.h"
27 #include "config_text.h"
39 PGEntry(
const string &name) :
41 _text(get_text_node()),
42 _obscure_text(get_text_node())
48 _candidate_highlight_start = 0;
49 _candidate_highlight_end = 0;
50 _candidate_cursor_pos = 0;
54 _accept_enabled =
true;
56 _text_geom_stale =
true;
57 _text_geom_flattened =
true;
61 _text_render_root =
NodePath(
"text_root");
63 CPT(TransformState) transform = TransformState::make_mat(
LMatrix4::convert_mat(CS_default, CS_zup_right));
64 _text_render_root.set_transform(transform);
66 _cursor_scale = _text_render_root.attach_new_node("cursor_scale");
67 _cursor_def = _cursor_scale.attach_new_node("cursor");
68 _cursor_visible = true;
73 _candidate_active = "candidate_active";
74 _candidate_inactive = "candidate_inactive";
76 _cursor_keys_active = true;
77 _obscure_mode = false;
78 _overflow_mode = false;
80 _current_padding = 0.0f;
108 _obscure_text(copy._obscure_text),
109 _cursor_position(copy._cursor_position),
110 _cursor_visible(copy._cursor_visible),
111 _candidate_highlight_start(copy._candidate_highlight_start),
112 _candidate_highlight_end(copy._candidate_highlight_end),
113 _candidate_cursor_pos(copy._candidate_cursor_pos),
114 _max_chars(copy._max_chars),
115 _max_width(copy._max_width),
116 _num_lines(copy._num_lines),
117 _accept_enabled(copy._accept_enabled),
118 _candidate_active(copy._candidate_active),
119 _candidate_inactive(copy._candidate_inactive),
120 _text_defs(copy._text_defs),
121 _blink_start(copy._blink_start),
122 _blink_rate(copy._blink_rate),
123 _cursor_keys_active(copy._cursor_keys_active),
124 _obscure_mode(copy._obscure_mode),
125 _overflow_mode(copy._overflow_mode)
127 _cursor_stale =
true;
129 _text_geom_stale =
true;
130 _text_geom_flattened =
true;
132 _text_render_root =
NodePath(
"text_root");
133 _cursor_scale = _text_render_root.attach_new_node(
"cursor_scale");
134 _cursor_scale.set_transform(copy._cursor_scale.
get_transform());
135 _cursor_def = copy._cursor_def.
copy_to(_cursor_scale);
194 PGItem::cull_callback(trav, data);
233 }
else if ((!background &&
get_focus()) ||
236 if (!_candidate_wtext.empty()) {
237 _candidate_wtext = wstring();
238 _text_geom_stale =
true;
243 if (button == KeyboardButton::enter()) {
245 if (_accept_enabled) {
252 }
else if (button == KeyboardButton::backspace()) {
254 if (_cursor_position > 0) {
255 _text.
set_wsubstr(wstring(), _cursor_position - 1, 1);
257 _cursor_stale =
true;
258 _text_geom_stale =
true;
262 }
else if (button == KeyboardButton::del()) {
266 _text_geom_stale =
true;
270 }
else if (button == KeyboardButton::left()) {
271 if (_cursor_keys_active) {
274 if (_cursor_position < 0) {
275 _cursor_position = 0;
280 _cursor_stale =
true;
282 _text_geom_stale =
true;
286 }
else if (button == KeyboardButton::right()) {
287 if (_cursor_keys_active) {
296 _cursor_stale =
true;
298 _text_geom_stale =
true;
302 }
else if (button == KeyboardButton::home()) {
303 if (_cursor_keys_active) {
305 _cursor_position = 0;
306 _cursor_stale =
true;
308 _text_geom_stale =
true;
313 }
else if (button == KeyboardButton::end()) {
314 if (_cursor_keys_active) {
317 _cursor_stale =
true;
319 _text_geom_stale =
true;
346 if (!isascii(keycode) || isprint(keycode)) {
349 if (!_candidate_wtext.empty()) {
350 _candidate_wtext = wstring();
351 _text_geom_stale =
true;
353 wstring new_char(1, (
wchar_t)keycode);
363 bool too_long = !_text.
set_wsubstr(new_char, _cursor_position, 0);
371 if (!too_long && (_text.
get_num_rows() == _num_lines) && !overflow_mode) {
376 int r = _num_lines - 1;
378 PN_stdfloat last_line_width =
380 too_long = (last_line_width > _max_width);
383 if (!too_long && keycode ==
' ' && !overflow_mode) {
390 _text.
calc_r_c(r, c, _cursor_position);
401 PN_stdfloat current_line_width =
403 if (current_line_width > _max_width) {
415 _cursor_stale =
true;
429 _cursor_position += new_char.length();
430 _cursor_stale =
true;
431 _text_geom_stale =
true;
457 _text_geom_stale =
true;
458 if (!_candidate_wtext.empty()) {
568 setup(PN_stdfloat width,
int num_lines) {
576 float bottom = -0.3f * line_height - (line_height * (num_lines - 1));
578 LMatrix4 mat = text_node->get_transform();
611 frame[0] = min(min(ll[right_axis], ur[right_axis]), min(lr[right_axis], ul[right_axis]));
612 frame[1] = max(max(ll[right_axis], ur[right_axis]), max(lr[right_axis], ul[right_axis]));
613 frame[2] = min(min(ll[up_axis], ur[up_axis]), min(lr[up_axis], ul[up_axis]));
614 frame[3] = max(max(ll[up_axis], ur[up_axis]), max(lr[up_axis], ul[up_axis]));
616 switch (text_node->get_align()) {
617 case TextNode::A_left:
618 case TextNode::A_boxed_left:
622 case TextNode::A_center:
623 case TextNode::A_boxed_center:
624 frame[0] = -width / 2.0;
625 frame[1] = width / 2.0;
628 case TextNode::A_right:
629 case TextNode::A_boxed_right:
635 set_frame(frame[0] - 0.15f, frame[1] + 0.15f, frame[2], frame[3]);
639 style.
set_type(PGFrameStyle::T_bevel_in);
661 _cursor_position = 0;
667 _accept_enabled =
true;
676 ls.
set_color(text_node->get_text_color());
677 ls.
move_to(0.0f, 0.0f, -0.15f * line_height);
678 ls.
draw_to(0.0f, 0.0f, 0.70f * line_height);
700 nassertv(state >= 0 && state < 1000);
701 if (node == (
TextNode *)NULL && state >= (
int)_text_defs.size()) {
705 slot_text_def(state);
707 _text_defs[state] = node;
720 if (state < 0 || state >= (
int)_text_defs.size()) {
724 if (_text_defs[state] == (
TextNode *)NULL) {
727 return _text_defs[state];
771 if ((ch & ~0x7f) != 0) {
786 slot_text_def(
int state) {
787 while (state >= (
int)_text_defs.size()) {
788 _text_defs.push_back((
TextNode *)NULL);
803 if (_text_geom_stale || node != _last_text_def) {
810 if (node != _last_text_def) {
814 _last_text_def = node;
824 assembled = _obscure_text.assemble_text();
826 }
else if (_candidate_wtext.empty()) {
829 assembled = _text.assemble_text();
840 cseq += wstring(1, (
wchar_t)text_push_properties_key);
842 cseq += wstring(1, (
wchar_t)text_push_properties_key);
843 cseq += _candidate_wtext.substr(0, _candidate_highlight_start);
844 cseq += wstring(1, (
wchar_t)text_push_properties_key);
846 cseq += wstring(1, (
wchar_t)text_push_properties_key);
847 cseq += _candidate_wtext.substr(_candidate_highlight_start,
848 _candidate_highlight_end - _candidate_highlight_start);
849 cseq += wstring(1, (
wchar_t)text_pop_properties_key);
850 cseq += _candidate_wtext.substr(_candidate_highlight_end);
851 cseq += wstring(1, (
wchar_t)text_pop_properties_key);
855 ctext.set_wsubstr(cseq, _cursor_position, 0);
856 assembled = ctext.assemble_text();
866 _current_text.
set_mat(node->get_transform());
870 PN_stdfloat cursor_graphic_pos = _text.
get_xpos(0, _cursor_position);
871 PN_stdfloat min_padding = (cursor_graphic_pos - _max_width);
891 if (_current_padding < min_padding || _current_padding > cursor_graphic_pos){
892 _current_padding = min_padding + (cursor_graphic_pos - min_padding) * 0.5;
895 if (_current_padding < 0){
896 _current_padding = 0;
899 _current_text.set_x(_current_text.get_x() - _current_padding);
905 _text_geom_stale =
false;
906 _text_geom_flattened =
false;
907 _cursor_stale =
true;
912 if (!
get_focus() && !_text_geom_flattened) {
914 _text_geom_flattened =
true;
927 _cursor_scale.
set_mat(node->get_transform());
928 _cursor_scale.
set_color(node->get_text_color());
930 if (_cursor_stale || node != _last_text_def) {
937 PN_stdfloat xpos, ypos;
939 _obscure_text.
calc_r_c(row, column, _cursor_position);
940 xpos = _obscure_text.
get_xpos(row, column);
941 ypos = _obscure_text.
get_ypos(row, column);
943 _text.
calc_r_c(row, column, _cursor_position);
948 _cursor_def.
set_pos(xpos - _current_padding, 0.0f, ypos);
949 _cursor_stale =
false;
955 if (!
get_focus() || !_candidate_wtext.empty()) {
956 show_hide_cursor(
false);
958 double elapsed_time =
960 int cycle = (int)(elapsed_time * _blink_rate * 2.0f);
961 bool visible = ((cycle & 1) == 0);
962 show_hide_cursor(visible);
973 show_hide_cursor(
bool visible) {
974 if (visible != _cursor_visible) {
976 _cursor_scale.
show();
978 _cursor_scale.
hide();
980 _cursor_visible = visible;
int get_max_chars() const
Returns the current maximum number of characters that may be typed into the entry, or 0 if there is no limit.
ButtonHandle get_button() const
Returns the mouse or keyboard button associated with this event.
PN_stdfloat get_line_height() const
Returns the number of units high each line of text is.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
void setup_minimal(PN_stdfloat width, int num_lines)
Sets up the entry without creating any frame or other decoration.
A basic node of the scene graph or data graph.
void set_max_width(PN_stdfloat max_width)
Sets the maximum width of all characters that may be typed into the entry.
This specialization on MouseWatcherParameter allows us to tag on additional elements to events for th...
TextProperties get_properties(const string &name)
Returns the TextProperties associated with the indicated name.
int get_num_characters() const
Returns the number of characters of text, before wordwrapping.
void set_width(PN_stdfloat x, PN_stdfloat y)
Sets the width parameter, which has meaning only for certain frame types.
string get_type_event() const
Returns the event name that will be thrown whenever the user extends the text by typing.
int get_num_cols(int r) const
Returns the number of characters and/or graphic objects in the nth row.
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
bool get_background_focus() const
Returns whether background_focus is currently enabled.
virtual void overflow(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the entry is overflowed because the user attempts t...
string get_overflow_event() const
Returns the event name that will be thrown when too much text is attempted to be entered into the PGE...
NodePath copy_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Functions like instance_to(), except a deep copy is made of the referenced node and all of its descen...
int get_num_rows() const
Returns the number of rows of text after it has all been wordwrapped and assembled.
This is the base class for all the various kinds of gui widget objects.
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
An optional parameter associated with an event.
void clear_cursor_def()
Removes all the children from the cursor_def node, in preparation for adding a new definition...
bool is_wtext() const
Returns true if any of the characters in the string returned by get_wtext() are out of the range of a...
string get_erase_event() const
Returns the event name that will be thrown whenever the user erases characters in the text...
This is a particular kind of PGItem that handles simple one-line or short multi-line text entries...
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
wchar_t get_character(int n) const
Returns the character at the indicated position in the pre-wordwrapped string.
void set_type(Type type)
Sets the basic type of frame.
void set_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets the bounding rectangle of the item, in local coordinates.
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
PandaNode * node() const
Returns the referenced node of the path.
GeomNode * create(bool dynamic=false)
Creates a new GeomNode that will render the series of line segments and points described via calls to...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
void set_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the translation component of the transform, leaving rotation and scale untouched.
virtual void press(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever a mouse or keyboard entry is depressed while the mo...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a=1.0, int priority=0)
Applies a scene-graph color to the referenced node.
bool has_keycode() const
Returns true if this parameter has an associated keycode, false otherwise.
void show()
Undoes the effect of a previous hide() on this node: makes the referenced node (and the entire subgra...
void set_properties(const TextProperties &properties)
Specifies the default TextProperties that are applied to the text in the absence of any nested proper...
void set_multiline_mode(bool flag)
Sets the multiline mode flag.
static TextPropertiesManager * get_global_ptr()
Returns the pointer to the global TextPropertiesManager object.
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
size_t get_highlight_start() const
Returns the first highlighted character in the candidate string.
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a=1.0f)
Establishes the color that will be assigned to all vertices created by future calls to move_to() and ...
virtual void erase(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the user erase characters in the text...
void move_to(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Moves the pen to the given point without drawing a line.
virtual void accept_failed(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the user presses Enter but we can't accept the inpu...
Encapsulates creation of a series of connected or disconnected line segments or points, for drawing paths or rays.
void set_frame_style(int state, const PGFrameStyle &style)
Changes the kind of frame that will be drawn behind the item when it is in the indicated state...
void set_wordwrap(PN_stdfloat wordwrap)
Sets the text up to automatically wordwrap when it exceeds the indicated width.
string get_cursormove_event() const
Returns the event name that will be thrown whenever the cursor moves.
PN_stdfloat get_xpos(int r, int c) const
Returns the x position of the origin of the character or graphic object at the indicated position in ...
bool set_wtext(const wstring &wtext)
Accepts a new text string and associated properties structure, and precomputes the wordwrapping layou...
virtual void set_focus(bool focus)
Sets whether the PGItem currently has keyboard focus.
void set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets up a scissor region on the nodes rendered at this level and below.
int get_state() const
Returns the "state" of this particular PGItem.
This is a 4-by-4 transform matrix.
double get_frame_time(Thread *current_thread=Thread::get_current_thread()) const
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a)
Sets the dominant color of the frame.
void set_num_lines(int num_lines)
Sets the number of lines of text the PGEntry will use.
virtual void cursormove()
This is a callback hook function, called whenever the cursor moves.
bool get_active() const
Returns whether the PGItem is currently active for mouse events.
This class is not normally used directly by user code, but is used by the TextNode to lay out a block...
int get_keycode() const
Returns the keycode associated with this event.
static TextNode * get_text_node()
Returns the TextNode object that will be used by all PGItems to generate default labels given a strin...
bool has_button() const
Returns true if this parameter has an associated mouse or keyboard button, false otherwise.
wstring decode_text(const string &text) const
Returns the given wstring decoded to a single-byte string, via the current encoding system...
wstring get_wtext() const
Returns a wstring that represents the contents of the text.
static LVector3f right(CoordinateSystem cs=CS_default)
Returns the right vector for the given coordinate system.
bool set_wsubstr(const wstring &wtext, int start, int count)
Replaces the 'count' characters from 'start' of the current text with the indicated replacement text...
bool set_text(const string &text)
Changes the text currently displayed within the entry.
virtual void keystroke(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever the user types a key.
Similar to MutexHolder, but for a light reentrant mutex.
virtual void set_focus(bool focus)
Toggles the focus state of the entry.
bool get_overflow_mode() const
Specifies whether overflow mode is enabled.
void draw_to(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Draws a line segment from the pen's last position (the last call to move_to or draw_to) to the indica...
const wstring & get_candidate_string() const
Returns the candidate string associated with this event.
void setup(PN_stdfloat width, int num_lines)
Sets up the entry for normal use.
This is the base class for all three-component vectors and points.
void set_max_rows(int max_rows)
If max_rows is greater than zero, no more than max_rows will be accepted.
virtual void candidate(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever the user selects an item from the IME menu...
void set_state(int state)
Sets the "state" of this particular PGItem.
int flatten_strong()
The strongest possible flattening.
void set_text_def(int state, TextNode *node)
Changes the TextNode that will be used to render the text within the entry when the entry is in the i...
NodePath get_cursor_def()
Returns the Node that will be rendered to represent the cursor.
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
static LPoint3f rfu(float right, float fwd, float up, CoordinateSystem cs=CS_default)
Returns a point described by right, forward, up displacements from the origin, wherever that maps to ...
The primary interface to this module.
This defines the set of visual properties that may be assigned to the individual characters of the te...
size_t get_highlight_end() const
Returns one more than the last highlighted character in the candidate string.
bool is_empty() const
Returns true if the NodePath contains no nodes.
void set_mat(const LMatrix4 &mat)
Directly sets an arbitrary 4x4 transform matrix.
virtual void candidate(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever the user highlights an option in the IME window...
virtual void keystroke(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever the user presses a key.
PN_stdfloat get_ypos(int r, int c) const
Returns the y position of the origin of all of the characters or graphic objects in the indicated row...
virtual void type(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the user extends the text by typing.
size_t get_cursor_pos() const
Returns the position of the user's edit cursor within the candidate string.
TypeHandle is the identifier used to differentiate C++ class types.
virtual void set_active(bool active)
Toggles the active/inactive state of the entry.
This is sent along as a parameter to most events generated for a region to indicate the mouse and but...
This defines all of the TextProperties structures that might be referenced by name from an embedded t...
void hide()
Makes the referenced node (and the entire subgraph below this node) invisible to all cameras...
virtual void accept(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the entry is accepted by the user pressing Enter no...
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
string get_accept_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the entry is accepted normally.
void set_max_chars(int max_chars)
Sets the maximum number of characters that may be typed into the entry.
void set_preserve_trailing_whitespace(bool preserve_trailing_whitespace)
Sets the preserve_trailing_whitespace flag.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
bool get_focus() const
Returns whether the PGItem currently has focus for keyboard events.
static LVector3f up(CoordinateSystem cs=CS_default)
Returns the up vector for the given coordinate system.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
virtual void set_active(bool active)
Sets whether the PGItem is active for mouse watching.
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
virtual void press(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever a mouse or keyboard button is depressed while the m...
void ls(ostream &out, int indent_level) const
Lists all the nodes at and below the current path hierarchically.
string get_accept_failed_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the entry cannot accept an input. ...
bool calc_r_c(int &r, int &c, int n) const
Computes the row and column index of the nth character or graphic object in the text.
TextNode * get_text_def(int state) const
Returns the TextNode that will be used to render the text within the entry when the entry is in the i...
bool has_candidate() const
Returns true if this parameter has an associated candidate string, false otherwise.