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"
15 #include "pgMouseWatcherParameter.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 */
140 PandaNode *PGEntry::
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 */
150 void PGEntry::
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 */
175 bool PGEntry::
176 cull_callback(CullTraverser *trav, CullTraverserData &data) {
177 LightReMutexHolder holder(_lock);
178 PGItem::cull_callback(trav, data);
179 if (Thread::get_current_pipeline_stage() == 0) {
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 */
196 void PGEntry::
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 */
327 void PGEntry::
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 */
444 void PGEntry::
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 */
478 void PGEntry::
479 accept(const MouseWatcherParameter &param) {
480 LightReMutexHolder holder(_lock);
481 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
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 */
492 void PGEntry::
493 accept_failed(const MouseWatcherParameter &param) {
494 LightReMutexHolder holder(_lock);
495 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
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 */
507 void PGEntry::
508 overflow(const MouseWatcherParameter &param) {
509 LightReMutexHolder holder(_lock);
510 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
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 */
520 void PGEntry::
521 type(const MouseWatcherParameter &param) {
522 LightReMutexHolder holder(_lock);
523 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
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 */
533 void PGEntry::
534 erase(const MouseWatcherParameter &param) {
535 LightReMutexHolder holder(_lock);
536 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
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 */
545 void PGEntry::
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 */
558 void PGEntry::
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 */
645 void PGEntry::
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.
661 clear_cursor_def();
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);
667 get_cursor_def().attach_new_node(ls.create());
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 */
681 void PGEntry::
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 */
698 TextNode *PGEntry::
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 */
715 void PGEntry::
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 */
726 void PGEntry::
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 */
739 bool PGEntry::
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);
773 props.set_preserve_trailing_whitespace(true);
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 {
799 TextPropertiesManager *tp_mgr = TextPropertiesManager::get_global_ptr();
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 }
ButtonHandle
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:26
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
ClockObject::get_global_clock
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
CullTraverser::traverse
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
Definition: cullTraverser.cxx:106
EventParameter
An optional parameter associated with an event.
Definition: eventParameter.h:35
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
LineSegs
Encapsulates creation of a series of connected or disconnected line segments or points,...
Definition: lineSegs.h:33
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
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
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
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
MouseButton::four
static ButtonHandle four()
Returns the ButtonHandle associated with the fourth mouse button.
Definition: mouseButton.cxx:67
MouseButton::one
static ButtonHandle one()
Returns the ButtonHandle associated with the first mouse button.
Definition: mouseButton.cxx:43
MouseButton::five
static ButtonHandle five()
Returns the ButtonHandle associated with the fifth mouse button.
Definition: mouseButton.cxx:75
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
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
MouseWatcherParameter::has_candidate
bool has_candidate() const
Returns true if this parameter has an associated candidate string, false otherwise.
Definition: mouseWatcherParameter.I:183
MouseWatcherParameter::get_candidate_string
const std::wstring & get_candidate_string() const
Returns the candidate string associated with this event.
Definition: mouseWatcherParameter.I:192
MouseWatcherParameter::get_button
ButtonHandle get_button() const
Returns the mouse or keyboard button associated with this event.
Definition: mouseWatcherParameter.I:148
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
MouseWatcherParameter::has_keycode
bool has_keycode() const
Returns true if this parameter has an associated keycode, false otherwise.
Definition: mouseWatcherParameter.I:165
MouseWatcherParameter::get_highlight_start
size_t get_highlight_start() const
Returns the first highlighted character in the candidate string.
Definition: mouseWatcherParameter.I:218
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
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
MouseWatcherParameter::get_keycode
int get_keycode() const
Returns the keycode associated with this event.
Definition: mouseWatcherParameter.I:174
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
NodePath::set_x
void set_x(PN_stdfloat x)
Sets the X component of the position transform, leaving other components untouched.
Definition: nodePath.cxx:968
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
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:2772
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:1796
NodePath::set_mat
void set_mat(const LMatrix4 &mat)
Directly sets an arbitrary 4x4 transform matrix.
Definition: nodePath.cxx:1355
NodePath::hide
void hide()
Makes the referenced node (and the entire subgraph below this node) invisible to all cameras.
Definition: nodePath.I:1853
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
NodePath::is_empty
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
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
NodePath::node
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
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:2015
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
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
NodePath::flatten_strong
int flatten_strong()
The strongest possible flattening.
Definition: nodePath.cxx:5631
PGEntry
This is a particular kind of PGItem that handles simple one-line or short multi-line text entries,...
Definition: pgEntry.h:38
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_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
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
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::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
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
PGEntry::get_cursor_def
NodePath get_cursor_def()
Returns the Node that will be rendered to represent the cursor.
Definition: pgEntry.I:272
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
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
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
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::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
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
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
PGEntry::cursormove
virtual void cursormove()
This is a callback hook function, called whenever the cursor moves.
Definition: pgEntry.cxx:546
PGEntry::set_active
virtual void set_active(bool active)
Toggles the active/inactive state of the entry.
Definition: pgEntry.cxx:716
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::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
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
PGEntry::setup
void setup(PN_stdfloat width, int num_lines)
Sets up the entry for normal use.
Definition: pgEntry.cxx:559
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
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
PGEntry::get_overflow_mode
bool get_overflow_mode() const
Specifies whether overflow mode is enabled.
Definition: pgEntry.I:370
PGEntry::set_text
bool set_text(const std::string &text)
Changes the text currently displayed within the entry.
Definition: pgEntry.I:23
PGEntry::set_focus
virtual void set_focus(bool focus)
Toggles the focus state of the entry.
Definition: pgEntry.cxx:727
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::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::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
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
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
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::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::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
PGFrameStyle
Definition: pgFrameStyle.h:29
PGFrameStyle::set_type
void set_type(Type type)
Sets the basic type of frame.
Definition: pgFrameStyle.I:64
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
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
PGItem
This is the base class for all the various kinds of gui widget objects.
Definition: pgItem.h:53
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:674
PGItem::get_active
bool get_active() const
Returns whether the PGItem is currently active for mouse events.
Definition: pgItem.I:160
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:1007
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
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:1079
PGItem::get_focus
bool get_focus() const
Returns whether the PGItem currently has focus for keyboard events.
Definition: pgItem.I:170
PGItem::get_background_focus
bool get_background_focus() const
Returns whether background_focus is currently enabled.
Definition: pgItem.I:180
PGItem::get_state
int get_state() const
Returns the "state" of this particular PGItem.
Definition: pgItem.I:150
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:726
PGItem::set_focus
virtual void set_focus(bool focus)
Sets whether the PGItem currently has keyboard focus.
Definition: pgItem.cxx:860
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:750
PGItem::set_active
virtual void set_active(bool active)
Sets whether the PGItem is active for mouse watching.
Definition: pgItem.cxx:837
PGMouseWatcherParameter
This specialization on MouseWatcherParameter allows us to tag on additional elements to events for th...
Definition: pgMouseWatcherParameter.h:27
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
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
Pipeline::get_render_pipeline
static Pipeline * get_render_pipeline()
Returns a pointer to the global render pipeline.
Definition: pipeline.I:18
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
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
TextAssembler::set_multiline_mode
set_multiline_mode
Sets the multiline mode flag.
Definition: textAssembler.h:111
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::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
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_wtext
std::wstring get_wtext() const
Returns a wstring that represents the contents of the text.
Definition: textAssembler.cxx:295
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
TextAssembler::get_num_characters
int get_num_characters() const
Returns the number of characters of text, before wordwrapping.
Definition: textAssembler.I:162
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
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
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
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::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
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
TextNode
The primary interface to this module.
Definition: textNode.h:48
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
TextPropertiesManager
This defines all of the TextProperties structures that might be referenced by name from an embedded t...
Definition: textPropertiesManager.h:44
TextPropertiesManager::get_properties
TextProperties get_properties(const std::string &name)
Returns the TextProperties associated with the indicated name.
Definition: textPropertiesManager.cxx:62
TextPropertiesManager::get_global_ptr
static TextPropertiesManager * get_global_ptr()
Returns the pointer to the global TextPropertiesManager object.
Definition: textPropertiesManager.cxx:197
TextProperties
This defines the set of visual properties that may be assigned to the individual characters of the te...
Definition: textProperties.h:41
TextProperties::set_wordwrap
set_wordwrap
Sets the text up to automatically wordwrap when it exceeds the indicated width.
Definition: textProperties.h:190
TextProperties::set_preserve_trailing_whitespace
set_preserve_trailing_whitespace
Sets the preserve_trailing_whitespace flag.
Definition: textProperties.h:193
Thread::get_current_pipeline_stage
get_current_pipeline_stage
Returns the integer pipeline stage associated with the current thread.
Definition: thread.h:110
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
config_text.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullTraverserData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
keyboardButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lineSegs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mouseButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mouseWatcherParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pgEntry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pgMouseWatcherParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
textEncoder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
throw_event.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
transformState.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.