Panda3D
pgEntry.cxx
1 // Filename: pgEntry.cxx
2 // Created by: drose (13Mar02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pgEntry.h"
16 #include "pgMouseWatcherParameter.h"
17 
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"
25 #include "lineSegs.h"
26 #include "textEncoder.h"
27 #include "config_text.h"
28 
29 #include <math.h>
30 
31 TypeHandle PGEntry::_type_handle;
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: PGEntry::Constructor
35 // Access: Published
36 // Description:
37 ////////////////////////////////////////////////////////////////////
38 PGEntry::
39 PGEntry(const string &name) :
40  PGItem(name),
41  _text(get_text_node()),
42  _obscure_text(get_text_node())
43 {
44  set_cull_callback();
45 
46  _cursor_position = 0;
47  _cursor_stale = true;
48  _candidate_highlight_start = 0;
49  _candidate_highlight_end = 0;
50  _candidate_cursor_pos = 0;
51  _max_chars = 0;
52  _max_width = 0.0f;
53  _num_lines = 1;
54  _accept_enabled = true;
55  _last_text_def = (TextNode *)NULL;
56  _text_geom_stale = true;
57  _text_geom_flattened = true;
58  _blink_start = 0.0f;
59  _blink_rate = 1.0f;
60 
61  _text_render_root = NodePath("text_root");
62 
63  CPT(TransformState) transform = TransformState::make_mat(LMatrix4::convert_mat(CS_default, CS_zup_right));
64  _text_render_root.set_transform(transform);
65 
66  _cursor_scale = _text_render_root.attach_new_node("cursor_scale");
67  _cursor_def = _cursor_scale.attach_new_node("cursor");
68  _cursor_visible = true;
69 
70  // These strings are used to specify the TextProperties to apply to
71  // candidate strings generated from the IME (for entering text in an
72  // east Asian language).
73  _candidate_active = "candidate_active";
74  _candidate_inactive = "candidate_inactive";
75 
76  _cursor_keys_active = true;
77  _obscure_mode = false;
78  _overflow_mode = false;
79 
80  _current_padding = 0.0f;
81 
82  set_active(true);
83  update_state();
84 
85  // Some default parameters so it doesn't crash hard if no one calls
86  // setup().
87  setup_minimal(10, 1);
88 }
89 
90 ////////////////////////////////////////////////////////////////////
91 // Function: PGEntry::Destructor
92 // Access: Public, Virtual
93 // Description:
94 ////////////////////////////////////////////////////////////////////
95 PGEntry::
96 ~PGEntry() {
97 }
98 
99 ////////////////////////////////////////////////////////////////////
100 // Function: PGEntry::Copy Constructor
101 // Access: Protected
102 // Description:
103 ////////////////////////////////////////////////////////////////////
104 PGEntry::
105 PGEntry(const PGEntry &copy) :
106  PGItem(copy),
107  _text(copy._text),
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)
126 {
127  _cursor_stale = true;
128  _last_text_def = (TextNode *)NULL;
129  _text_geom_stale = true;
130  _text_geom_flattened = true;
131 
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);
136 }
137 
138 ////////////////////////////////////////////////////////////////////
139 // Function: PGEntry::make_copy
140 // Access: Public, Virtual
141 // Description: Returns a newly-allocated Node that is a shallow copy
142 // of this one. It will be a different Node pointer,
143 // but its internal data may or may not be shared with
144 // that of the original Node.
145 ////////////////////////////////////////////////////////////////////
147 make_copy() const {
148  LightReMutexHolder holder(_lock);
149  return new PGEntry(*this);
150 }
151 
152 ////////////////////////////////////////////////////////////////////
153 // Function: PGEntry::xform
154 // Access: Public, Virtual
155 // Description: Transforms the contents of this node by the indicated
156 // matrix, if it means anything to do so. For most
157 // kinds of nodes, this does nothing.
158 ////////////////////////////////////////////////////////////////////
159 void PGEntry::
160 xform(const LMatrix4 &mat) {
161  LightReMutexHolder holder(_lock);
162  PGItem::xform(mat);
163  _text_render_root.set_mat(_text_render_root.get_mat() * mat);
164 }
165 
166 ////////////////////////////////////////////////////////////////////
167 // Function: PGEntry::cull_callback
168 // Access: Protected, Virtual
169 // Description: This function will be called during the cull
170 // traversal to perform any additional operations that
171 // should be performed at cull time. This may include
172 // additional manipulation of render state or additional
173 // visible/invisible decisions, or any other arbitrary
174 // operation.
175 //
176 // Note that this function will *not* be called unless
177 // set_cull_callback() is called in the constructor of
178 // the derived class. It is necessary to call
179 // set_cull_callback() to indicated that we require
180 // cull_callback() to be called.
181 //
182 // By the time this function is called, the node has
183 // already passed the bounding-volume test for the
184 // viewing frustum, and the node's transform and state
185 // have already been applied to the indicated
186 // CullTraverserData object.
187 //
188 // The return value is true if this node should be
189 // visible, or false if it should be culled.
190 ////////////////////////////////////////////////////////////////////
191 bool PGEntry::
193  LightReMutexHolder holder(_lock);
194  PGItem::cull_callback(trav, data);
195  update_text();
196  update_cursor();
197 
198  // Now render the text.
199  CullTraverserData next_data(data, _text_render_root.node());
200  trav->traverse(next_data);
201 
202  // Now continue to render everything else below this node.
203  return true;
204 }
205 
206 ////////////////////////////////////////////////////////////////////
207 // Function: PGEntry::press
208 // Access: Public, Virtual
209 // Description: This is a callback hook function, called whenever a
210 // mouse or keyboard entry is depressed while the mouse
211 // is within the region.
212 ////////////////////////////////////////////////////////////////////
213 void PGEntry::
214 press(const MouseWatcherParameter &param, bool background) {
215  LightReMutexHolder holder(_lock);
216  if (get_active()) {
217  if (param.has_button()) {
218  // Make sure _text is initialized properly.
219  update_text();
220 
221  bool overflow_mode = get_overflow_mode() && _num_lines == 1;
222 
223  ButtonHandle button = param.get_button();
224 
225  if (button == MouseButton::one() ||
226  button == MouseButton::two() ||
227  button == MouseButton::three() ||
228  button == MouseButton::four() ||
229  button == MouseButton::five()) {
230  // Mouse button; set focus.
231  set_focus(true);
232 
233  } else if ((!background && get_focus()) ||
234  (background && get_background_focus())) {
235  // Keyboard button.
236  if (!_candidate_wtext.empty()) {
237  _candidate_wtext = wstring();
238  _text_geom_stale = true;
239  }
240 
241  _cursor_position = min(_cursor_position, _text.get_num_characters());
242  _blink_start = ClockObject::get_global_clock()->get_frame_time();
243  if (button == KeyboardButton::enter()) {
244  // Enter. Accept the entry.
245  if (_accept_enabled) {
246  accept(param);
247  }
248  else {
249  accept_failed(param);
250  }
251 
252  } else if (button == KeyboardButton::backspace()) {
253  // Backspace. Remove the character to the left of the cursor.
254  if (_cursor_position > 0) {
255  _text.set_wsubstr(wstring(), _cursor_position - 1, 1);
256  _cursor_position--;
257  _cursor_stale = true;
258  _text_geom_stale = true;
259  erase(param);
260  }
261 
262  } else if (button == KeyboardButton::del()) {
263  // Delete. Remove the character to the right of the cursor.
264  if (_cursor_position < _text.get_num_characters()) {
265  _text.set_wsubstr(wstring(), _cursor_position, 1);
266  _text_geom_stale = true;
267  erase(param);
268  }
269 
270  } else if (button == KeyboardButton::left()) {
271  if (_cursor_keys_active) {
272  // Left arrow. Move the cursor position to the left.
273  --_cursor_position;
274  if (_cursor_position < 0) {
275  _cursor_position = 0;
276  overflow(param);
277  } else {
278  type(param);
279  }
280  _cursor_stale = true;
281  if (overflow_mode){
282  _text_geom_stale = true;
283  }
284  }
285 
286  } else if (button == KeyboardButton::right()) {
287  if (_cursor_keys_active) {
288  // Right arrow. Move the cursor position to the right.
289  ++_cursor_position;
290  if (_cursor_position > _text.get_num_characters()) {
291  _cursor_position = _text.get_num_characters();
292  overflow(param);
293  } else {
294  type(param);
295  }
296  _cursor_stale = true;
297  if (overflow_mode){
298  _text_geom_stale = true;
299  }
300  }
301 
302  } else if (button == KeyboardButton::home()) {
303  if (_cursor_keys_active) {
304  // Home. Move the cursor position to the beginning.
305  _cursor_position = 0;
306  _cursor_stale = true;
307  if (overflow_mode){
308  _text_geom_stale = true;
309  }
310  type(param);
311  }
312 
313  } else if (button == KeyboardButton::end()) {
314  if (_cursor_keys_active) {
315  // End. Move the cursor position to the end.
316  _cursor_position = _text.get_num_characters();
317  _cursor_stale = true;
318  if (overflow_mode){
319  _text_geom_stale = true;
320  }
321  type(param);
322  }
323  }
324  }
325  }
326  }
327  PGItem::press(param, background);
328 }
329 
330 ////////////////////////////////////////////////////////////////////
331 // Function: PGEntry::keystroke
332 // Access: Public, Virtual
333 // Description: This is a callback hook function, called whenever
334 // the user types a key.
335 ////////////////////////////////////////////////////////////////////
336 void PGEntry::
337 keystroke(const MouseWatcherParameter &param, bool background) {
338  LightReMutexHolder holder(_lock);
339  if (get_active()) {
340  if (param.has_keycode()) {
341  // Make sure _text is initialized properly.
342  update_text();
343 
344  int keycode = param.get_keycode();
345 
346  if (!isascii(keycode) || isprint(keycode)) {
347  // A normal visible character. Add a new character to the
348  // text entry, if there's room.
349  if (!_candidate_wtext.empty()) {
350  _candidate_wtext = wstring();
351  _text_geom_stale = true;
352  }
353  wstring new_char(1, (wchar_t)keycode);
354 
355  if (get_max_chars() > 0 && _text.get_num_characters() >= get_max_chars()) {
356  // In max_chars mode, we consider it an overflow after we
357  // have exceeded a fixed number of characters, irrespective
358  // of the formatted width of those characters.
359  overflow(param);
360 
361  } else {
362  _cursor_position = min(_cursor_position, _text.get_num_characters());
363  bool too_long = !_text.set_wsubstr(new_char, _cursor_position, 0);
364  bool overflow_mode = get_overflow_mode() && _num_lines == 1;
365  if(overflow_mode){
366  too_long = false;
367  }
368  if (_obscure_mode) {
369  too_long = !_obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
370  } else {
371  if (!too_long && (_text.get_num_rows() == _num_lines) && !overflow_mode) {
372  // If we've filled up all of the available lines, we
373  // must also ensure that the last line is not too long
374  // (it might be, because of additional whitespace on
375  // the end).
376  int r = _num_lines - 1;
377  int c = _text.get_num_cols(r);
378  PN_stdfloat last_line_width =
379  _text.get_xpos(r, c) - _text.get_xpos(r, 0);
380  too_long = (last_line_width > _max_width);
381  }
382 
383  if (!too_long && keycode == ' ' && !overflow_mode) {
384  // Even if we haven't filled up all of the available
385  // lines, we should reject a space that's typed at the
386  // end of the current line if it would make that line
387  // exceed the maximum width, just so we don't allow an
388  // infinite number of spaces to accumulate.
389  int r, c;
390  _text.calc_r_c(r, c, _cursor_position);
391  if (_text.get_num_cols(r) == c + 1) {
392  // The user is typing at the end of the line. But we
393  // must allow at least one space at the end of the
394  // line, so we only make any of the following checks
395  // if there are already multiple spaces at the end of
396  // the line.
397  if (c - 1 >= 0 && _text.get_character(r, c - 1) == ' ') {
398  // Ok, the user is putting multiple spaces on the
399  // end of a line; we need to make sure the line does
400  // not grow too wide. Measure the line's width.
401  PN_stdfloat current_line_width =
402  _text.get_xpos(r, c + 1) - _text.get_xpos(r, 0);
403  if (current_line_width > _max_width) {
404  // We have to reject the space, but we don't treat
405  // it as an overflow condition.
406  _text.set_wsubstr(wstring(), _cursor_position, 1);
407  // If the user is typing over existing space
408  // characters, we act as if the right-arrow key
409  // were pressed instead, and advance the cursor to
410  // the next position. Otherwise, we just quietly
411  // eat the space character.
412  if (_cursor_position < _text.get_num_characters() &&
413  _text.get_character(_cursor_position) == ' ') {
414  _cursor_position++;
415  _cursor_stale = true;
416  }
417  return;
418  }
419  }
420  }
421  }
422  }
423 
424  if (too_long) {
425  _text.set_wsubstr(wstring(), _cursor_position, 1);
426  overflow(param);
427 
428  } else {
429  _cursor_position += new_char.length();
430  _cursor_stale = true;
431  _text_geom_stale = true;
432  type(param);
433  }
434  }
435  }
436  }
437  }
438  PGItem::keystroke(param, background);
439 }
440 
441 ////////////////////////////////////////////////////////////////////
442 // Function: PGEntry::candidate
443 // Access: Public, Virtual
444 // Description: This is a callback hook function, called whenever
445 // the user selects an item from the IME menu.
446 ////////////////////////////////////////////////////////////////////
447 void PGEntry::
448 candidate(const MouseWatcherParameter &param, bool background) {
449  LightReMutexHolder holder(_lock);
450  if (get_active()) {
451  if (param.has_candidate()) {
452  // Save the candidate string so it can be displayed.
453  _candidate_wtext = param.get_candidate_string();
454  _candidate_highlight_start = param.get_highlight_start();
455  _candidate_highlight_end = param.get_highlight_end();
456  _candidate_cursor_pos = param.get_cursor_pos();
457  _text_geom_stale = true;
458  if (!_candidate_wtext.empty()) {
459  type(param);
460  }
461  }
462  }
463  PGItem::candidate(param, background);
464 }
465 
466 ////////////////////////////////////////////////////////////////////
467 // Function: PGEntry::accept
468 // Access: Public, Virtual
469 // Description: This is a callback hook function, called whenever the
470 // entry is accepted by the user pressing Enter normally.
471 ////////////////////////////////////////////////////////////////////
472 void PGEntry::
474  LightReMutexHolder holder(_lock);
476  string event = get_accept_event(param.get_button());
477  play_sound(event);
478  throw_event(event, EventParameter(ep));
479  set_focus(false);
480 }
481 
482 ////////////////////////////////////////////////////////////////////
483 // Function: PGEntry::accept_failed
484 // Access: Public, Virtual
485 // Description: This is a callback hook function, called whenever the
486 // user presses Enter but we can't accept the input.
487 ////////////////////////////////////////////////////////////////////
488 void PGEntry::
490  LightReMutexHolder holder(_lock);
492  string event = get_accept_failed_event(param.get_button());
493  play_sound(event);
494  throw_event(event, EventParameter(ep));
495  //set_focus(false);
496 }
497 
498 ////////////////////////////////////////////////////////////////////
499 // Function: PGEntry::overflow
500 // Access: Public, Virtual
501 // Description: This is a callback hook function, called whenever the
502 // entry is overflowed because the user attempts to type
503 // too many characters, exceeding either set_max_chars()
504 // or set_max_width().
505 ////////////////////////////////////////////////////////////////////
506 void PGEntry::
508  LightReMutexHolder holder(_lock);
510  string event = get_overflow_event();
511  play_sound(event);
512  throw_event(event, EventParameter(ep));
513 }
514 
515 ////////////////////////////////////////////////////////////////////
516 // Function: PGEntry::type
517 // Access: Public, Virtual
518 // Description: This is a callback hook function, called whenever the
519 // user extends the text by typing.
520 ////////////////////////////////////////////////////////////////////
521 void PGEntry::
523  LightReMutexHolder holder(_lock);
525  string event = get_type_event();
526  play_sound(event);
527  throw_event(event, EventParameter(ep));
528 }
529 
530 ////////////////////////////////////////////////////////////////////
531 // Function: PGEntry::erase
532 // Access: Public, Virtual
533 // Description: This is a callback hook function, called whenever the
534 // user erase characters in the text.
535 ////////////////////////////////////////////////////////////////////
536 void PGEntry::
538  LightReMutexHolder holder(_lock);
540  string event = get_erase_event();
541  play_sound(event);
542  throw_event(event, EventParameter(ep));
543 }
544 
545 ////////////////////////////////////////////////////////////////////
546 // Function: PGEntry::cursormove
547 // Access: Public, Virtual
548 // Description: This is a callback hook function, called whenever the
549 // cursor moves.
550 ////////////////////////////////////////////////////////////////////
551 void PGEntry::
553  LightReMutexHolder holder(_lock);
554  string event = get_cursormove_event();
555  throw_event(event, EventParameter(_cursor_def.get_x()), EventParameter(_cursor_def.get_y()));
556 }
557 
558 ////////////////////////////////////////////////////////////////////
559 // Function: PGEntry::setup
560 // Access: Published
561 // Description: Sets up the entry for normal use. The width is the
562 // maximum width of characters that will be typed, and
563 // num_lines is the integer number of lines of text of
564 // the entry. Both of these together determine the size
565 // of the entry, based on the TextNode in effect.
566 ////////////////////////////////////////////////////////////////////
567 void PGEntry::
568 setup(PN_stdfloat width, int num_lines) {
569  LightReMutexHolder holder(_lock);
570  setup_minimal(width, num_lines);
571 
572  TextNode *text_node = get_text_def(S_focus);
573  PN_stdfloat line_height = text_node->get_line_height();
574 
575  // Determine the four corners of the frame.
576  float bottom = -0.3f * line_height - (line_height * (num_lines - 1));
577  // Transform each corner by the TextNode's transform.
578  LMatrix4 mat = text_node->get_transform();
579  LPoint3 ll = LPoint3::rfu(0.0f, 0.0f, bottom) * mat;
580  LPoint3 ur = LPoint3::rfu(width, 0.0f, line_height) * mat;
581  LPoint3 lr = LPoint3::rfu(width, 0.0f, bottom) * mat;
582  LPoint3 ul = LPoint3::rfu(0.0f, 0.0f, line_height) * mat;
583 
584  LVector3 up = LVector3::up();
585  int up_axis;
586  if (up[1]) {
587  up_axis = 1;
588  }
589  else if (up[2]) {
590  up_axis = 2;
591  }
592  else {
593  up_axis = 0;
594  }
595  LVector3 right = LVector3::right();
596  int right_axis;
597  if (right[0]) {
598  right_axis = 0;
599  }
600  else if (right[2]) {
601  right_axis = 2;
602  }
603  else {
604  right_axis = 1;
605  }
606 
607  // And get the new minmax to define the frame. We do all this work
608  // instead of just using the lower-left and upper-right corners,
609  // just in case the text was rotated.
610  LVecBase4 frame;
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]));
615 
616  switch (text_node->get_align()) {
617  case TextNode::A_left:
618  case TextNode::A_boxed_left:
619  // The default case.
620  break;
621 
622  case TextNode::A_center:
623  case TextNode::A_boxed_center:
624  frame[0] = -width / 2.0;
625  frame[1] = width / 2.0;
626  break;
627 
628  case TextNode::A_right:
629  case TextNode::A_boxed_right:
630  frame[0] = -width;
631  frame[1] = 0.0f;
632  break;
633  }
634 
635  set_frame(frame[0] - 0.15f, frame[1] + 0.15f, frame[2], frame[3]);
636 
637  PGFrameStyle style;
638  style.set_width(0.1f, 0.1f);
639  style.set_type(PGFrameStyle::T_bevel_in);
640  style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
641 
642  set_frame_style(S_no_focus, style);
643 
644  style.set_color(0.9f, 0.9f, 0.9f, 1.0f);
645  set_frame_style(S_focus, style);
646 
647  style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
648  set_frame_style(S_inactive, style);
649 }
650 
651 ////////////////////////////////////////////////////////////////////
652 // Function: PGEntry::setup_minimal
653 // Access: Published
654 // Description: Sets up the entry without creating any frame or other
655 // decoration.
656 ////////////////////////////////////////////////////////////////////
657 void PGEntry::
658 setup_minimal(PN_stdfloat width, int num_lines) {
659  LightReMutexHolder holder(_lock);
660  set_text(string());
661  _cursor_position = 0;
662  set_max_chars(0);
663  set_max_width(width);
664  set_num_lines(num_lines);
665  update_text();
666 
667  _accept_enabled = true;
668 
669  TextNode *text_node = get_text_def(S_focus);
670  PN_stdfloat line_height = text_node->get_line_height();
671 
672  // Set up a default cursor: a vertical bar.
674 
675  LineSegs ls;
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);
680 
681  /*
682  // An underscore cursor would work too.
683  text_node->set_text("_");
684  get_cursor_def().attach_new_node(text_node->generate());
685  */
686 }
687 
688 ////////////////////////////////////////////////////////////////////
689 // Function: PGEntry::set_text_def
690 // Access: Published
691 // Description: Changes the TextNode that will be used to render the
692 // text within the entry when the entry is in the
693 // indicated state. The default if nothing is specified
694 // is the same TextNode returned by
695 // PGItem::get_text_node().
696 ////////////////////////////////////////////////////////////////////
697 void PGEntry::
698 set_text_def(int state, TextNode *node) {
699  LightReMutexHolder holder(_lock);
700  nassertv(state >= 0 && state < 1000); // Sanity check.
701  if (node == (TextNode *)NULL && state >= (int)_text_defs.size()) {
702  // If we're setting it to NULL, we don't need to slot a new one.
703  return;
704  }
705  slot_text_def(state);
706 
707  _text_defs[state] = node;
708 }
709 
710 ////////////////////////////////////////////////////////////////////
711 // Function: PGEntry::get_text_def
712 // Access: Published
713 // Description: Returns the TextNode that will be used to render the
714 // text within the entry when the entry is in the
715 // indicated state. See set_text_def().
716 ////////////////////////////////////////////////////////////////////
718 get_text_def(int state) const {
719  LightReMutexHolder holder(_lock);
720  if (state < 0 || state >= (int)_text_defs.size()) {
721  // If we don't have a definition, use the global one.
722  return get_text_node();
723  }
724  if (_text_defs[state] == (TextNode *)NULL) {
725  return get_text_node();
726  }
727  return _text_defs[state];
728 }
729 
730 ////////////////////////////////////////////////////////////////////
731 // Function: PGEntry::set_active
732 // Access: Published, Virtual
733 // Description: Toggles the active/inactive state of the entry. In
734 // the case of a PGEntry, this also changes its visual
735 // appearance.
736 ////////////////////////////////////////////////////////////////////
737 void PGEntry::
738 set_active(bool active) {
739  LightReMutexHolder holder(_lock);
740  PGItem::set_active(active);
741  update_state();
742 }
743 
744 ////////////////////////////////////////////////////////////////////
745 // Function: PGEntry::set_focus
746 // Access: Published, Virtual
747 // Description: Toggles the focus state of the entry. In the case of
748 // a PGEntry, this also changes its visual appearance.
749 ////////////////////////////////////////////////////////////////////
750 void PGEntry::
751 set_focus(bool focus) {
752  LightReMutexHolder holder(_lock);
753  PGItem::set_focus(focus);
754  _blink_start = ClockObject::get_global_clock()->get_frame_time();
755  update_state();
756 }
757 
758 ////////////////////////////////////////////////////////////////////
759 // Function: PGEntry::is_wtext
760 // Access: Published
761 // Description: Returns true if any of the characters in the string
762 // returned by get_wtext() are out of the range of an
763 // ASCII character (and, therefore, get_wtext() should
764 // be called in preference to get_text()).
765 ////////////////////////////////////////////////////////////////////
766 bool PGEntry::
767 is_wtext() const {
768  LightReMutexHolder holder(_lock);
769  for (int i = 0; i < _text.get_num_characters(); ++i) {
770  wchar_t ch = _text.get_character(i);
771  if ((ch & ~0x7f) != 0) {
772  return true;
773  }
774  }
775 
776  return false;
777 }
778 
779 ////////////////////////////////////////////////////////////////////
780 // Function: PGEntry::slot_text_def
781 // Access: Private
782 // Description: Ensures there is a slot in the array for the given
783 // text definition.
784 ////////////////////////////////////////////////////////////////////
785 void PGEntry::
786 slot_text_def(int state) {
787  while (state >= (int)_text_defs.size()) {
788  _text_defs.push_back((TextNode *)NULL);
789  }
790 }
791 
792 ////////////////////////////////////////////////////////////////////
793 // Function: PGEntry::update_text
794 // Access: Private
795 // Description: Causes the PGEntry to recompute its text, if
796 // necessary.
797 ////////////////////////////////////////////////////////////////////
798 void PGEntry::
799 update_text() {
800  TextNode *node = get_text_def(get_state());
801  nassertv(node != (TextNode *)NULL);
802 
803  if (_text_geom_stale || node != _last_text_def) {
804  TextProperties props = *node;
805  props.set_wordwrap(_max_width);
807  _text.set_properties(props);
808  _text.set_max_rows(_num_lines);
809 
810  if (node != _last_text_def) {
811  // Make sure the default properties are applied to all the
812  // characters in the text.
813  _text.set_wtext(_text.get_wtext());
814  _last_text_def = node;
815  }
816 
817  _text.set_multiline_mode (!(get_overflow_mode() && _num_lines == 1));
818 
819  PT(PandaNode) assembled;
820  if (_obscure_mode) {
821  _obscure_text.set_properties(props);
822  _obscure_text.set_max_rows(_num_lines);
823  _obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
824  assembled = _obscure_text.assemble_text();
825 
826  } else if (_candidate_wtext.empty()) {
827  // If we're not trying to display a candidate string, it's easy:
828  // just display the current text contents.
829  assembled = _text.assemble_text();
830 
831  } else {
833  TextProperties inactive = tp_mgr->get_properties(_candidate_inactive);
834  TextProperties active = tp_mgr->get_properties(_candidate_active);
835 
836  // Insert the complex sequence of characters required to show
837  // the candidate string in a different color. This gets
838  // inserted at the current cursor position.
839  wstring cseq;
840  cseq += wstring(1, (wchar_t)text_push_properties_key);
841  cseq += node->decode_text(_candidate_inactive);
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);
845  cseq += node->decode_text(_candidate_active);
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);
852 
853  // Create a special TextAssembler to insert the candidate string.
854  TextAssembler ctext(_text);
855  ctext.set_wsubstr(cseq, _cursor_position, 0);
856  assembled = ctext.assemble_text();
857  }
858 
859  if (!_current_text.is_empty()) {
860  _current_text.remove_node();
861  }
862 
863  _current_text =
864  _text_render_root.attach_new_node(assembled);
865 
866  _current_text.set_mat(node->get_transform());
867 
868  if (get_overflow_mode() && _num_lines == 1){
869  // We determine the minimum required padding:
870  PN_stdfloat cursor_graphic_pos = _text.get_xpos(0, _cursor_position);
871  PN_stdfloat min_padding = (cursor_graphic_pos - _max_width);
872 
873  // If the current padding would produce a caret outside the text entry,
874  // we relocate it.
875  // Here we also have to make a jump towards the center when the caret
876  // is going outside the visual area and there's enough text ahead for
877  // increased usability.
878  //
879  // The amount that the caret is moved for hinting depends on the OS,
880  // and the specific behavior under certain circunstances in different
881  // Operating Systems is very complicated (the implementation would need
882  // to "remember" the original typing starting point). For the moment we are
883  // gonna use an unconditional 50% jump, this behavior is found in some
884  // Mac dialogs, and it's the easiest to implement by far, while
885  // providing proven usability.
886  // PROS: Reduces the amount of scrolling while both writing and navigating
887  // with arrow keys, which is desirable.
888  // CONS: The user needs to remember that he/she has exceeded the boundaries,
889  // but this happens with all implementations to some degree.
890 
891  if (_current_padding < min_padding || _current_padding > cursor_graphic_pos){
892  _current_padding = min_padding + (cursor_graphic_pos - min_padding) * 0.5;
893  }
894 
895  if (_current_padding < 0){ // Caret virtual position doesn't exceed boundaries
896  _current_padding = 0;
897  }
898 
899  _current_text.set_x(_current_text.get_x() - _current_padding);
900  _current_text.set_scissor(NodePath(this),
901  LPoint3::rfu(0, 0, -0.5), LPoint3::rfu(_max_width, 0, -0.5),
902  LPoint3::rfu(_max_width, 0, 1.5), LPoint3::rfu(0, 0, 1.5));
903  }
904 
905  _text_geom_stale = false;
906  _text_geom_flattened = false;
907  _cursor_stale = true;
908  }
909 
910  // We'll flatten the text geometry only if we don't have focus.
911  // Otherwise, we assume the user may be changing it frequently.
912  if (!get_focus() && !_text_geom_flattened) {
913  _current_text.flatten_strong();
914  _text_geom_flattened = true;
915  }
916 }
917 
918 ////////////////////////////////////////////////////////////////////
919 // Function: PGEntry::update_cursor
920 // Access: Private
921 // Description: Moves the cursor to its correct position.
922 ////////////////////////////////////////////////////////////////////
923 void PGEntry::
924 update_cursor() {
925  TextNode *node = get_text_def(get_state());
926  nassertv(node != (TextNode *)NULL);
927  _cursor_scale.set_mat(node->get_transform());
928  _cursor_scale.set_color(node->get_text_color());
929 
930  if (_cursor_stale || node != _last_text_def) {
931  update_text();
932 
933  _cursor_position = min(_cursor_position, _text.get_num_characters());
934 
935  // Determine the row and column of the cursor.
936  int row, column;
937  PN_stdfloat xpos, ypos;
938  if (_obscure_mode) {
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);
942  } else {
943  _text.calc_r_c(row, column, _cursor_position);
944  xpos = _text.get_xpos(row, column);
945  ypos = _text.get_ypos(row, column);
946  }
947 
948  _cursor_def.set_pos(xpos - _current_padding, 0.0f, ypos);
949  _cursor_stale = false;
950  cursormove();
951 
952  }
953 
954  // Should the cursor be visible?
955  if (!get_focus() || !_candidate_wtext.empty()) {
956  show_hide_cursor(false);
957  } else {
958  double elapsed_time =
959  ClockObject::get_global_clock()->get_frame_time() - _blink_start;
960  int cycle = (int)(elapsed_time * _blink_rate * 2.0f);
961  bool visible = ((cycle & 1) == 0);
962  show_hide_cursor(visible);
963  }
964 }
965 
966 ////////////////////////////////////////////////////////////////////
967 // Function: PGEntry::show_hide_cursor
968 // Access: Private
969 // Description: Makes the cursor visible or invisible, e.g. during a
970 // blink cycle.
971 ////////////////////////////////////////////////////////////////////
972 void PGEntry::
973 show_hide_cursor(bool visible) {
974  if (visible != _cursor_visible) {
975  if (visible) {
976  _cursor_scale.show();
977  } else {
978  _cursor_scale.hide();
979  }
980  _cursor_visible = visible;
981  }
982 }
983 
984 ////////////////////////////////////////////////////////////////////
985 // Function: PGEntry::update_state
986 // Access: Private
987 // Description: Determines what the correct state for the PGEntry
988 // should be.
989 ////////////////////////////////////////////////////////////////////
990 void PGEntry::
991 update_state() {
992  if (get_active()) {
993  if (get_focus()) {
994  set_state(S_focus);
995  } else {
996  set_state(S_no_focus);
997  }
998  } else {
999  set_state(S_inactive);
1000  }
1001 }
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:271
void setup_minimal(PN_stdfloat width, int num_lines)
Sets up the entry without creating any frame or other decoration.
Definition: pgEntry.cxx:658
int get_num_cols(int r) const
Returns the number of characters and/or graphic objects in the nth row.
bool get_background_focus() const
Returns whether background_focus is currently enabled.
Definition: pgItem.I:223
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
void set_max_width(PN_stdfloat max_width)
Sets the maximum width of all characters that may be typed into the entry.
Definition: pgEntry.I:228
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.
void set_width(PN_stdfloat x, PN_stdfloat y)
Sets the width parameter, which has meaning only for certain frame types.
Definition: pgFrameStyle.I:172
int get_num_characters() const
Returns the number of characters of text, before wordwrapping.
static ButtonHandle three()
Returns the ButtonHandle associated with the third mouse button.
Definition: mouseButton.cxx:72
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
Definition: pgItem.cxx:386
static ButtonHandle two()
Returns the ButtonHandle associated with the second mouse button.
Definition: mouseButton.cxx:61
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...
Definition: pgEntry.I:591
virtual void overflow(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the entry is overflowed because the user attempts t...
Definition: pgEntry.cxx:507
This is the base class for all the various kinds of gui widget objects.
Definition: pgItem.h:58
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Definition: pgEntry.cxx:147
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
Definition: pgEntry.cxx:160
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...
Definition: pgEntry.I:321
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.
Definition: pgEntry.I:207
int get_state() const
Returns the "state" of this particular PGItem.
Definition: pgItem.I:187
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:236
bool get_active() const
Returns whether the PGItem is currently active for mouse events.
Definition: pgItem.I:199
int get_keycode() const
Returns the keycode associated with this event.
This is a particular kind of PGItem that handles simple one-line or short multi-line text entries...
Definition: pgEntry.h:42
wchar_t get_character(int n) const
Returns the character at the indicated position in the pre-wordwrapped string.
wstring decode_text(const string &text) const
Returns the given wstring decoded to a single-byte string, via the current encoding system...
Definition: textEncoder.I:568
string get_erase_event() const
Returns the event name that will be thrown whenever the user erases characters in the text...
Definition: pgEntry.I:613
void set_type(Type type)
Sets the basic type of frame.
Definition: pgFrameStyle.I:76
void set_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets the bounding rectangle of the item, in local coordinates.
Definition: pgItem.I:100
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
Definition: pgEntry.cxx:192
This collects together the pieces of data that are accumulated for each node while walking the scene ...
static ButtonHandle one()
Returns the ButtonHandle associated with the first mouse button.
Definition: mouseButton.cxx:50
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...
GeomNode * create(bool dynamic=false)
Creates a new GeomNode that will render the series of line segments and points described via calls to...
Definition: lineSegs.I:137
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
virtual void press(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever a mouse or keyboard entry is depressed while the mo...
Definition: pgEntry.cxx:214
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
int get_num_rows() const
Returns the number of rows of text after it has all been wordwrapped and assembled.
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.
Definition: nodePath.cxx:2270
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 ...
Definition: clockObject.I:48
static const LMatrix4f & convert_mat(CoordinateSystem from, CoordinateSystem to)
Returns a matrix that transforms from the indicated coordinate system to the indicated coordinate sys...
Definition: lmatrix.cxx:656
void show()
Undoes the effect of a previous hide() on this node: makes the referenced node (and the entire subgra...
Definition: nodePath.I:2202
string get_accept_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the entry is accepted normally.
Definition: pgEntry.I:567
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.
Definition: textAssembler.I:99
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.
static ButtonHandle four()
Returns the ButtonHandle associated with the fourth mouse button.
Definition: mouseButton.cxx:83
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Changes the complete transform object on this node.
Definition: nodePath.I:718
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:28
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...
Definition: pgEntry.cxx:767
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 ...
Definition: lineSegs.I:68
bool get_overflow_mode() const
Specifies whether overflow mode is enabled.
Definition: pgEntry.I:415
virtual void erase(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the user erase characters in the text...
Definition: pgEntry.cxx:537
void move_to(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Moves the pen to the given point without drawing a line.
Definition: lineSegs.I:105
virtual void accept_failed(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the user presses Enter but we can&#39;t accept the inpu...
Definition: pgEntry.cxx:489
bool has_button() const
Returns true if this parameter has an associated mouse or keyboard button, false otherwise.
Encapsulates creation of a series of connected or disconnected line segments or points, for drawing paths or rays.
Definition: lineSegs.h:36
void set_frame_style(int state, const PGFrameStyle &style)
Changes the kind of frame that will be drawn behind the item when it is in the indicated state...
Definition: pgItem.cxx:1102
void set_wordwrap(PN_stdfloat wordwrap)
Sets the text up to automatically wordwrap when it exceeds the indicated width.
ButtonHandle get_button() const
Returns the mouse or keyboard button associated with this event.
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.
Definition: pgItem.cxx:917
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.
Definition: nodePath.cxx:3143
string get_cursormove_event() const
Returns the event name that will be thrown whenever the cursor moves.
Definition: pgEntry.I:624
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...
Definition: nodePath.cxx:723
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a)
Sets the dominant color of the frame.
Definition: pgFrameStyle.I:96
void set_num_lines(int num_lines)
Sets the number of lines of text the PGEntry will use.
Definition: pgEntry.I:255
virtual void cursormove()
This is a callback hook function, called whenever the cursor moves.
Definition: pgEntry.cxx:552
This class is not normally used directly by user code, but is used by the TextNode to lay out a block...
Definition: textAssembler.h:46
size_t get_cursor_pos() const
Returns the position of the user&#39;s edit cursor within the candidate string.
static TextNode * get_text_node()
Returns the TextNode object that will be used by all PGItems to generate default labels given a strin...
Definition: pgItem.cxx:1177
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 ...
string get_type_event() const
Returns the event name that will be thrown whenever the user extends the text by typing.
Definition: pgEntry.I:602
bool get_focus() const
Returns whether the PGItem currently has focus for keyboard events.
Definition: pgItem.I:211
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...
Definition: nodePath.cxx:691
static ButtonHandle five()
Returns the ButtonHandle associated with the fifth mouse button.
Definition: mouseButton.cxx:94
static LVector3f right(CoordinateSystem cs=CS_default)
Returns the right vector for the given coordinate system.
Definition: lvector3.h:568
bool set_wsubstr(const wstring &wtext, int start, int count)
Replaces the &#39;count&#39; characters from &#39;start&#39; of the current text with the indicated replacement text...
bool set_text(const string &text)
Changes the text currently displayed within the entry.
Definition: pgEntry.I:29
const wstring & get_candidate_string() const
Returns the candidate string associated with this event.
virtual void keystroke(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever the user types a key.
Definition: pgEntry.cxx:337
Similar to MutexHolder, but for a light reentrant mutex.
virtual void set_focus(bool focus)
Toggles the focus state of the entry.
Definition: pgEntry.cxx:751
void draw_to(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Draws a line segment from the pen&#39;s last position (the last call to move_to or draw_to) to the indica...
Definition: lineSegs.I:119
bool has_candidate() const
Returns true if this parameter has an associated candidate string, false otherwise.
void setup(PN_stdfloat width, int num_lines)
Sets up the entry for normal use.
Definition: pgEntry.cxx:568
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
void set_max_rows(int max_rows)
If max_rows is greater than zero, no more than max_rows will be accepted.
Definition: textAssembler.I:54
virtual void candidate(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever the user selects an item from the IME menu...
Definition: pgEntry.cxx:448
void set_state(int state)
Sets the "state" of this particular PGItem.
Definition: pgItem.I:175
int flatten_strong()
The strongest possible flattening.
Definition: nodePath.cxx:6337
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.
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...
Definition: pgEntry.cxx:698
NodePath get_cursor_def()
Returns the Node that will be rendered to represent the cursor.
Definition: pgEntry.I:309
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:757
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 ...
Definition: lpoint3.h:463
size_t get_highlight_start() const
Returns the first highlighted character in the candidate string.
The primary interface to this module.
Definition: textNode.h:52
This defines the set of visual properties that may be assigned to the individual characters of the te...
void set_mat(const LMatrix4 &mat)
Directly sets an arbitrary 4x4 transform matrix.
Definition: nodePath.cxx:1517
virtual void candidate(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever the user highlights an option in the IME window...
Definition: pgItem.cxx:778
virtual void keystroke(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever the user presses a key.
Definition: pgItem.cxx:752
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
Definition: nodePath.I:965
wstring get_wtext() const
Returns a wstring that represents the contents of the text.
PN_stdfloat get_line_height() const
Returns the number of units high each line of text is.
Definition: textNode.I:26
virtual void type(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the user extends the text by typing.
Definition: pgEntry.cxx:522
string get_accept_failed_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the entry cannot accept an input. ...
Definition: pgEntry.I:578
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
virtual void set_active(bool active)
Toggles the active/inactive state of the entry.
Definition: pgEntry.cxx:738
This is sent along as a parameter to most events generated for a region to indicate the mouse and but...
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:925
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...
Definition: pgEntry.cxx:718
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...
Definition: nodePath.I:2270
virtual void accept(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the entry is accepted by the user pressing Enter no...
Definition: pgEntry.cxx:473
void set_max_chars(int max_chars)
Sets the maximum number of characters that may be typed into the entry.
Definition: pgEntry.I:194
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...
Definition: nodePath.h:165
static LVector3f up(CoordinateSystem cs=CS_default)
Returns the up vector for the given coordinate system.
Definition: lvector3.h:541
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
size_t get_highlight_end() const
Returns one more than the last highlighted character in the candidate string.
virtual void set_active(bool active)
Sets whether the PGItem is active for mouse watching.
Definition: pgItem.cxx:890
virtual void press(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever a mouse or keyboard button is depressed while the m...
Definition: pgItem.cxx:694
bool has_keycode() const
Returns true if this parameter has an associated keycode, false otherwise.