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