41PGEntry(
const string &name) :
43 _text(get_text_node()),
44 _obscure_text(get_text_node())
50 _candidate_highlight_start = 0;
51 _candidate_highlight_end = 0;
52 _candidate_cursor_pos = 0;
56 _accept_enabled =
true;
57 _last_text_def =
nullptr;
58 _text_geom_stale =
true;
59 _text_geom_flattened =
true;
63 _text_render_root =
NodePath(
"text_root");
65 CPT(
TransformState) transform = TransformState::make_mat(LMatrix4::convert_mat(CS_default, CS_zup_right));
66 _text_render_root.set_transform(transform);
68 _cursor_scale = _text_render_root.attach_new_node(
"cursor_scale");
69 _cursor_def = _cursor_scale.attach_new_node(
"cursor");
70 _cursor_visible =
true;
75 _candidate_active =
"candidate_active";
76 _candidate_inactive =
"candidate_inactive";
78 _cursor_keys_active =
true;
79 _obscure_mode =
false;
80 _overflow_mode =
false;
82 _current_padding = 0.0f;
105 _obscure_text(copy._obscure_text),
106 _cursor_position(copy._cursor_position),
107 _cursor_visible(copy._cursor_visible),
108 _candidate_highlight_start(copy._candidate_highlight_start),
109 _candidate_highlight_end(copy._candidate_highlight_end),
110 _candidate_cursor_pos(copy._candidate_cursor_pos),
111 _max_chars(copy._max_chars),
112 _max_width(copy._max_width),
113 _num_lines(copy._num_lines),
114 _accept_enabled(copy._accept_enabled),
115 _candidate_active(copy._candidate_active),
116 _candidate_inactive(copy._candidate_inactive),
117 _text_defs(copy._text_defs),
118 _blink_start(copy._blink_start),
119 _blink_rate(copy._blink_rate),
120 _cursor_keys_active(copy._cursor_keys_active),
121 _obscure_mode(copy._obscure_mode),
122 _overflow_mode(copy._overflow_mode)
124 _cursor_stale =
true;
125 _last_text_def =
nullptr;
126 _text_geom_stale =
true;
127 _text_geom_flattened =
true;
129 _text_render_root =
NodePath(
"text_root");
130 _cursor_scale = _text_render_root.attach_new_node(
"cursor_scale");
131 _cursor_scale.set_transform(copy._cursor_scale.
get_transform());
132 _cursor_def = copy._cursor_def.
copy_to(_cursor_scale);
143 return new PGEntry(*
this);
151xform(
const LMatrix4 &mat) {
154 _text_render_root.set_mat(_text_render_root.get_mat() * mat);
178 PGItem::cull_callback(trav, data);
185 CullTraverserData next_data(data, _text_render_root.node());
216 }
else if ((!background &&
get_focus()) ||
219 if (!_candidate_wtext.empty()) {
220 _candidate_wtext = wstring();
221 _text_geom_stale =
true;
224 _cursor_position = min(_cursor_position, _text.get_num_characters());
226 if (button == KeyboardButton::enter()) {
228 if (_accept_enabled) {
235 }
else if (button == KeyboardButton::backspace()) {
237 if (_cursor_position > 0) {
238 _text.set_wsubstr(wstring(), _cursor_position - 1, 1);
240 _cursor_stale =
true;
241 _text_geom_stale =
true;
245 }
else if (button == KeyboardButton::del()) {
247 if (_cursor_position < _text.get_num_characters()) {
248 _text.set_wsubstr(wstring(), _cursor_position, 1);
249 _text_geom_stale =
true;
253 }
else if (button == KeyboardButton::left()) {
254 if (_cursor_keys_active) {
257 if (_cursor_position < 0) {
258 _cursor_position = 0;
263 _cursor_stale =
true;
265 _text_geom_stale =
true;
269 }
else if (button == KeyboardButton::right()) {
270 if (_cursor_keys_active) {
273 if (_cursor_position > _text.get_num_characters()) {
274 _cursor_position = _text.get_num_characters();
279 _cursor_stale =
true;
281 _text_geom_stale =
true;
285 }
else if (button == KeyboardButton::home()) {
286 if (_cursor_keys_active) {
288 _cursor_position = 0;
289 _cursor_stale =
true;
291 _text_geom_stale =
true;
296 }
else if (button == KeyboardButton::end()) {
297 if (_cursor_keys_active) {
299 _cursor_position = _text.get_num_characters();
300 _cursor_stale =
true;
302 _text_geom_stale =
true;
312#ifdef THREADED_PIPELINE
314 if (_text_geom_stale) {
337 if ((!isascii(keycode) || isprint(keycode)) && keycode !=
'\t') {
340 if (!_candidate_wtext.empty()) {
341 _candidate_wtext = wstring();
342 _text_geom_stale =
true;
344 wstring new_char(1, (
wchar_t)keycode);
353 _cursor_position = min(_cursor_position, _text.get_num_characters());
354 bool too_long = !_text.set_wsubstr(new_char, _cursor_position, 0);
360 too_long = !_obscure_text.set_wtext(wstring(_text.get_num_characters(),
'*'));
362 if (!too_long && (_text.get_num_rows() == _num_lines) && !overflow_mode) {
366 int r = _num_lines - 1;
367 int c = _text.get_num_cols(r);
368 PN_stdfloat last_line_width =
369 _text.get_xpos(r, c) - _text.get_xpos(r, 0);
370 too_long = (last_line_width > _max_width);
373 if (!too_long && keycode ==
' ' && !overflow_mode) {
380 _text.calc_r_c(r, c, _cursor_position);
381 if (_text.get_num_cols(r) == c + 1) {
386 if (c - 1 >= 0 && _text.get_character(r, c - 1) ==
' ') {
390 PN_stdfloat current_line_width =
391 _text.get_xpos(r, c + 1) - _text.get_xpos(r, 0);
392 if (current_line_width > _max_width) {
395 _text.set_wsubstr(wstring(), _cursor_position, 1);
400 if (_cursor_position < _text.get_num_characters() &&
401 _text.get_character(_cursor_position) ==
' ') {
403 _cursor_stale =
true;
413 _text.set_wsubstr(wstring(), _cursor_position, 1);
417 _cursor_position += new_char.length();
418 _cursor_stale =
true;
419 _text_geom_stale =
true;
428#ifdef THREADED_PIPELINE
430 if (_text_geom_stale) {
454 _text_geom_stale =
true;
455 if (!_candidate_wtext.empty()) {
462#ifdef THREADED_PIPELINE
464 if (_text_geom_stale) {
559setup(PN_stdfloat width,
int num_lines) {
567 float bottom = -0.3f * line_height - (line_height * (num_lines - 1));
569 LMatrix4 mat = text_node->get_transform();
570 LPoint3 ll = LPoint3::rfu(0.0f, 0.0f, bottom) * mat;
571 LPoint3 ur = LPoint3::rfu(width, 0.0f, line_height) * mat;
572 LPoint3 lr = LPoint3::rfu(width, 0.0f, bottom) * mat;
573 LPoint3 ul = LPoint3::rfu(0.0f, 0.0f, line_height) * mat;
575 LVector3 up = LVector3::up();
586 LVector3 right = LVector3::right();
602 frame[0] = min(min(ll[right_axis], ur[right_axis]), min(lr[right_axis], ul[right_axis]));
603 frame[1] = max(max(ll[right_axis], ur[right_axis]), max(lr[right_axis], ul[right_axis]));
604 frame[2] = min(min(ll[up_axis], ur[up_axis]), min(lr[up_axis], ul[up_axis]));
605 frame[3] = max(max(ll[up_axis], ur[up_axis]), max(lr[up_axis], ul[up_axis]));
607 switch (text_node->get_align()) {
608 case TextNode::A_left:
609 case TextNode::A_boxed_left:
613 case TextNode::A_center:
614 case TextNode::A_boxed_center:
615 frame[0] = -width / 2.0;
616 frame[1] = width / 2.0;
619 case TextNode::A_right:
620 case TextNode::A_boxed_right:
626 set_frame(frame[0] - 0.15f, frame[1] + 0.15f, frame[2], frame[3]);
630 style.
set_type(PGFrameStyle::T_bevel_in);
649 _cursor_position = 0;
655 _accept_enabled =
true;
664 ls.
set_color(text_node->get_text_color());
665 ls.move_to(0.0f, 0.0f, -0.15f * line_height);
666 ls.draw_to(0.0f, 0.0f, 0.70f * line_height);
684 nassertv(state >= 0 && state < 1000);
685 if (node ==
nullptr && state >= (
int)_text_defs.size()) {
689 slot_text_def(state);
691 _text_defs[state] = node;
701 if (state < 0 || state >= (
int)_text_defs.size()) {
705 if (_text_defs[state] ==
nullptr) {
708 return _text_defs[state];
742 for (
int i = 0; i < _text.get_num_characters(); ++i) {
743 wchar_t ch = _text.get_character(i);
744 if ((ch & ~0x7f) != 0) {
756slot_text_def(
int state) {
757 while (state >= (
int)_text_defs.size()) {
758 _text_defs.push_back(
nullptr);
768 nassertv(node !=
nullptr);
770 if (_text_geom_stale || node != _last_text_def) {
771 TextProperties props = *node;
774 _text.set_properties(props);
775 _text.set_max_rows(_num_lines);
777 if (node != _last_text_def) {
780 _text.set_wtext(_text.get_wtext());
781 _last_text_def = node;
786 PT(PandaNode) assembled;
788 _obscure_text.set_properties(props);
789 _obscure_text.set_max_rows(_num_lines);
790 _obscure_text.set_wtext(wstring(_text.get_num_characters(),
'*'));
791 assembled = _obscure_text.assemble_text();
793 }
else if (_candidate_wtext.empty()) {
796 assembled = _text.assemble_text();
800 TextProperties inactive = tp_mgr->
get_properties(_candidate_inactive);
801 TextProperties active = tp_mgr->
get_properties(_candidate_active);
807 cseq += wstring(1, (
wchar_t)text_push_properties_key);
809 cseq += wstring(1, (
wchar_t)text_push_properties_key);
810 cseq += _candidate_wtext.substr(0, _candidate_highlight_start);
811 cseq += wstring(1, (
wchar_t)text_push_properties_key);
813 cseq += wstring(1, (
wchar_t)text_push_properties_key);
814 cseq += _candidate_wtext.substr(_candidate_highlight_start,
815 _candidate_highlight_end - _candidate_highlight_start);
816 cseq += wstring(1, (
wchar_t)text_pop_properties_key);
817 cseq += _candidate_wtext.substr(_candidate_highlight_end);
818 cseq += wstring(1, (
wchar_t)text_pop_properties_key);
821 TextAssembler ctext(_text);
822 ctext.set_wsubstr(cseq, _cursor_position, 0);
823 assembled = ctext.assemble_text();
826 if (!_current_text.is_empty()) {
827 _current_text.remove_node();
831 _text_render_root.attach_new_node(assembled);
833 _current_text.set_mat(node->get_transform());
837 PN_stdfloat cursor_graphic_pos = _text.get_xpos(0, _cursor_position);
838 PN_stdfloat min_padding = (cursor_graphic_pos - _max_width);
856 if (_current_padding < min_padding || _current_padding > cursor_graphic_pos){
857 _current_padding = min_padding + (cursor_graphic_pos - min_padding) * 0.5;
860 if (_current_padding < 0){
861 _current_padding = 0;
864 _current_text.set_x(_current_text.get_x() - _current_padding);
865 _current_text.set_scissor(NodePath(
this),
866 LPoint3::rfu(0, 0, -0.5), LPoint3::rfu(_max_width, 0, -0.5),
867 LPoint3::rfu(_max_width, 0, 1.5), LPoint3::rfu(0, 0, 1.5));
870 _text_geom_stale =
false;
871 _text_geom_flattened =
false;
872 _cursor_stale =
true;
877 if (!
get_focus() && !_text_geom_flattened) {
878 _current_text.flatten_strong();
879 _text_geom_flattened =
true;
889 nassertv(node !=
nullptr);
890 _cursor_scale.set_mat(node->get_transform());
891 _cursor_scale.set_color(node->get_text_color());
893 if (_cursor_stale || node != _last_text_def) {
896 _cursor_position = min(_cursor_position, _text.get_num_characters());
900 PN_stdfloat xpos, ypos;
902 _obscure_text.calc_r_c(row, column, _cursor_position);
903 xpos = _obscure_text.get_xpos(row, column);
904 ypos = _obscure_text.get_ypos(row, column);
906 _text.calc_r_c(row, column, _cursor_position);
907 if (_cursor_position > 0 && _text.get_character(_cursor_position - 1) ==
'\n') {
911 xpos = _text.get_xpos(row, column);
912 ypos = _text.get_ypos(row, column);
915 _cursor_def.set_pos(xpos - _current_padding, 0.0f, ypos);
916 _cursor_stale =
false;
922 if (!
get_focus() || !_candidate_wtext.empty()) {
923 show_hide_cursor(
false);
925 double elapsed_time =
927 int cycle = (int)(elapsed_time * _blink_rate * 2.0f);
928 bool visible = ((cycle & 1) == 0);
929 show_hide_cursor(visible);
937show_hide_cursor(
bool visible) {
938 if (visible != _cursor_visible) {
940 _cursor_scale.show();
942 _cursor_scale.hide();
944 _cursor_visible = visible;
962#ifdef THREADED_PIPELINE
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
An optional parameter associated with an event.
Similar to MutexHolder, but for a light reentrant mutex.
Encapsulates creation of a series of connected or disconnected line segments or points,...
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 ...
This is sent along as a parameter to most events generated for a region to indicate the mouse and but...
bool has_candidate() const
Returns true if this parameter has an associated candidate string, false otherwise.
const std::wstring & get_candidate_string() const
Returns the candidate string associated with this event.
ButtonHandle get_button() const
Returns the mouse or keyboard button associated with this event.
size_t get_highlight_end() const
Returns one more than the last highlighted character in the candidate string.
bool has_keycode() const
Returns true if this parameter has an associated keycode, false otherwise.
size_t get_highlight_start() const
Returns the first highlighted character in the candidate string.
size_t get_cursor_pos() const
Returns the position of the user's edit cursor within the candidate string.
bool has_button() const
Returns true if this parameter has an associated mouse or keyboard button, false otherwise.
int get_keycode() const
Returns the keycode associated with this event.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
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...
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...
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
This is a particular kind of PGItem that handles simple one-line or short multi-line text entries,...
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...
std::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...
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so.
virtual void type(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the user extends the text by typing.
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...
std::string get_type_event() const
Returns the event name that will be thrown whenever the user extends the text by typing.
NodePath get_cursor_def()
Returns the Node that will be rendered to represent the cursor.
void set_max_chars(int max_chars)
Sets the maximum number of characters that may be typed into the entry.
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...
std::string get_accept_failed_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the entry cannot accept an input.
void set_num_lines(int num_lines)
Sets the number of lines of text the PGEntry will use.
void setup_minimal(PN_stdfloat width, int num_lines)
Sets up the entry without creating any frame or other decoration.
virtual void erase(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the user erase characters in the text.
std::string get_cursormove_event() const
Returns the event name that will be thrown whenever the cursor moves.
virtual void cursormove()
This is a callback hook function, called whenever the cursor moves.
virtual void set_active(bool active)
Toggles the active/inactive state of the entry.
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_max_width(PN_stdfloat max_width)
Sets the maximum width of all characters that may be typed into the entry.
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
void setup(PN_stdfloat width, int num_lines)
Sets up the entry for normal use.
virtual void accept(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the entry is accepted by the user pressing Enter no...
std::string get_erase_event() const
Returns the event name that will be thrown whenever the user erases characters in the text.
bool get_overflow_mode() const
Specifies whether overflow mode is enabled.
bool set_text(const std::string &text)
Changes the text currently displayed within the entry.
virtual void set_focus(bool focus)
Toggles the focus state of the entry.
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...
virtual void overflow(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the entry is overflowed because the user attempts t...
std::string get_accept_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the entry is accepted normally.
virtual void keystroke(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever the user types a key.
int get_max_chars() const
Returns the current maximum number of characters that may be typed into the entry,...
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
void clear_cursor_def()
Removes all the children from the cursor_def node, in preparation for adding a new definition.
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...
void set_type(Type type)
Sets the basic type of frame.
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a)
Sets the dominant color of the frame.
void set_width(PN_stdfloat x, PN_stdfloat y)
Sets the width parameter, which has meaning only for certain frame types.
This is the base class for all the various kinds of gui widget objects.
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...
bool get_active() const
Returns whether the PGItem is currently active for mouse events.
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_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets the bounding rectangle of the item, in local coordinates.
static TextNode * get_text_node()
Returns the TextNode object that will be used by all PGItems to generate default labels given a strin...
bool get_focus() const
Returns whether the PGItem currently has focus for keyboard events.
bool get_background_focus() const
Returns whether background_focus is currently enabled.
int get_state() const
Returns the "state" of this particular PGItem.
virtual void keystroke(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever the user presses a key.
virtual void set_focus(bool focus)
Sets whether the PGItem currently has keyboard focus.
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 set_active(bool active)
Sets whether the PGItem is active for mouse watching.
This specialization on MouseWatcherParameter allows us to tag on additional elements to events for th...
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
static Pipeline * get_render_pipeline()
Returns a pointer to the global render pipeline.
std::wstring decode_text(const std::string &text) const
Returns the given wstring decoded to a single-byte string, via the current encoding system.
The primary interface to this module.
PN_stdfloat get_line_height() const
Returns the number of units high each line of text is.
TextProperties get_properties(const std::string &name)
Returns the TextProperties associated with the indicated name.
static TextPropertiesManager * get_global_ptr()
Returns the pointer to the global TextPropertiesManager object.
set_wordwrap
Sets the text up to automatically wordwrap when it exceeds the indicated width.
set_preserve_trailing_whitespace
Sets the preserve_trailing_whitespace flag.
get_current_pipeline_stage
Returns the integer pipeline stage associated with the current thread.
TypeHandle is the identifier used to differentiate C++ class types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.