00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pgEntry.h"
00016 #include "pgMouseWatcherParameter.h"
00017
00018 #include "cullTraverser.h"
00019 #include "cullTraverserData.h"
00020 #include "throw_event.h"
00021 #include "transformState.h"
00022 #include "mouseWatcherParameter.h"
00023 #include "keyboardButton.h"
00024 #include "mouseButton.h"
00025 #include "lineSegs.h"
00026 #include "textEncoder.h"
00027 #include "config_text.h"
00028
00029 #include <math.h>
00030
00031 TypeHandle PGEntry::_type_handle;
00032
00033
00034
00035
00036
00037
00038 PGEntry::
00039 PGEntry(const string &name) :
00040 PGItem(name),
00041 _text(get_text_node()),
00042 _obscure_text(get_text_node())
00043 {
00044 set_cull_callback();
00045
00046 _cursor_position = 0;
00047 _cursor_stale = true;
00048 _candidate_highlight_start = 0;
00049 _candidate_highlight_end = 0;
00050 _candidate_cursor_pos = 0;
00051 _max_chars = 0;
00052 _max_width = 0.0f;
00053 _num_lines = 1;
00054 _accept_enabled = true;
00055 _last_text_def = (TextNode *)NULL;
00056 _text_geom_stale = true;
00057 _text_geom_flattened = true;
00058 _blink_start = 0.0f;
00059 _blink_rate = 1.0f;
00060
00061 _text_render_root = NodePath("text_root");
00062
00063 CPT(TransformState) transform = TransformState::make_mat(LMatrix4::convert_mat(CS_default, CS_zup_right));
00064 _text_render_root.set_transform(transform);
00065
00066 _cursor_scale = _text_render_root.attach_new_node("cursor_scale");
00067 _cursor_def = _cursor_scale.attach_new_node("cursor");
00068 _cursor_visible = true;
00069
00070
00071
00072
00073 _candidate_active = "candidate_active";
00074 _candidate_inactive = "candidate_inactive";
00075
00076 _cursor_keys_active = true;
00077 _obscure_mode = false;
00078 _overflow_mode = false;
00079
00080 _current_padding = 0.0f;
00081
00082 set_active(true);
00083 update_state();
00084
00085
00086
00087 setup_minimal(10, 1);
00088 }
00089
00090
00091
00092
00093
00094
00095 PGEntry::
00096 ~PGEntry() {
00097 }
00098
00099
00100
00101
00102
00103
00104 PGEntry::
00105 PGEntry(const PGEntry ©) :
00106 PGItem(copy),
00107 _text(copy._text),
00108 _obscure_text(copy._obscure_text),
00109 _cursor_position(copy._cursor_position),
00110 _cursor_visible(copy._cursor_visible),
00111 _candidate_highlight_start(copy._candidate_highlight_start),
00112 _candidate_highlight_end(copy._candidate_highlight_end),
00113 _candidate_cursor_pos(copy._candidate_cursor_pos),
00114 _max_chars(copy._max_chars),
00115 _max_width(copy._max_width),
00116 _num_lines(copy._num_lines),
00117 _accept_enabled(copy._accept_enabled),
00118 _candidate_active(copy._candidate_active),
00119 _candidate_inactive(copy._candidate_inactive),
00120 _text_defs(copy._text_defs),
00121 _blink_start(copy._blink_start),
00122 _blink_rate(copy._blink_rate),
00123 _cursor_keys_active(copy._cursor_keys_active),
00124 _obscure_mode(copy._obscure_mode),
00125 _overflow_mode(copy._overflow_mode)
00126 {
00127 _cursor_stale = true;
00128 _last_text_def = (TextNode *)NULL;
00129 _text_geom_stale = true;
00130 _text_geom_flattened = true;
00131
00132 _text_render_root = NodePath("text_root");
00133 _cursor_scale = _text_render_root.attach_new_node("cursor_scale");
00134 _cursor_scale.set_transform(copy._cursor_scale.get_transform());
00135 _cursor_def = copy._cursor_def.copy_to(_cursor_scale);
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 PandaNode *PGEntry::
00147 make_copy() const {
00148 LightReMutexHolder holder(_lock);
00149 return new PGEntry(*this);
00150 }
00151
00152
00153
00154
00155
00156
00157
00158
00159 void PGEntry::
00160 xform(const LMatrix4 &mat) {
00161 LightReMutexHolder holder(_lock);
00162 PGItem::xform(mat);
00163 _text_render_root.set_mat(_text_render_root.get_mat() * mat);
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 bool PGEntry::
00192 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00193 LightReMutexHolder holder(_lock);
00194 PGItem::cull_callback(trav, data);
00195 update_text();
00196 update_cursor();
00197
00198
00199 CullTraverserData next_data(data, _text_render_root.node());
00200 trav->traverse(next_data);
00201
00202
00203 return true;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213 void PGEntry::
00214 press(const MouseWatcherParameter ¶m, bool background) {
00215 LightReMutexHolder holder(_lock);
00216 if (get_active()) {
00217 if (param.has_button()) {
00218
00219 update_text();
00220
00221 bool overflow_mode = get_overflow_mode() && _num_lines == 1;
00222
00223 ButtonHandle button = param.get_button();
00224
00225 if (button == MouseButton::one() ||
00226 button == MouseButton::two() ||
00227 button == MouseButton::three() ||
00228 button == MouseButton::four() ||
00229 button == MouseButton::five()) {
00230
00231 set_focus(true);
00232
00233 } else if ((!background && get_focus()) ||
00234 (background && get_background_focus())) {
00235
00236 if (!_candidate_wtext.empty()) {
00237 _candidate_wtext = wstring();
00238 _text_geom_stale = true;
00239 }
00240
00241 _cursor_position = min(_cursor_position, _text.get_num_characters());
00242 _blink_start = ClockObject::get_global_clock()->get_frame_time();
00243 if (button == KeyboardButton::enter()) {
00244
00245 if (_accept_enabled) {
00246 accept(param);
00247 }
00248 else {
00249 accept_failed(param);
00250 }
00251
00252 } else if (button == KeyboardButton::backspace()) {
00253
00254 if (_cursor_position > 0) {
00255 _text.set_wsubstr(wstring(), _cursor_position - 1, 1);
00256 _cursor_position--;
00257 _cursor_stale = true;
00258 _text_geom_stale = true;
00259 erase(param);
00260 }
00261
00262 } else if (button == KeyboardButton::del()) {
00263
00264 if (_cursor_position < _text.get_num_characters()) {
00265 _text.set_wsubstr(wstring(), _cursor_position, 1);
00266 _text_geom_stale = true;
00267 erase(param);
00268 }
00269
00270 } else if (button == KeyboardButton::left()) {
00271 if (_cursor_keys_active) {
00272
00273 --_cursor_position;
00274 if (_cursor_position < 0) {
00275 _cursor_position = 0;
00276 overflow(param);
00277 } else {
00278 type(param);
00279 }
00280 _cursor_stale = true;
00281 if (overflow_mode){
00282 _text_geom_stale = true;
00283 }
00284 }
00285
00286 } else if (button == KeyboardButton::right()) {
00287 if (_cursor_keys_active) {
00288
00289 ++_cursor_position;
00290 if (_cursor_position > _text.get_num_characters()) {
00291 _cursor_position = _text.get_num_characters();
00292 overflow(param);
00293 } else {
00294 type(param);
00295 }
00296 _cursor_stale = true;
00297 if (overflow_mode){
00298 _text_geom_stale = true;
00299 }
00300 }
00301
00302 } else if (button == KeyboardButton::home()) {
00303 if (_cursor_keys_active) {
00304
00305 _cursor_position = 0;
00306 _cursor_stale = true;
00307 if (overflow_mode){
00308 _text_geom_stale = true;
00309 }
00310 type(param);
00311 }
00312
00313 } else if (button == KeyboardButton::end()) {
00314 if (_cursor_keys_active) {
00315
00316 _cursor_position = _text.get_num_characters();
00317 _cursor_stale = true;
00318 if (overflow_mode){
00319 _text_geom_stale = true;
00320 }
00321 type(param);
00322 }
00323 }
00324 }
00325 }
00326 }
00327 PGItem::press(param, background);
00328 }
00329
00330
00331
00332
00333
00334
00335
00336 void PGEntry::
00337 keystroke(const MouseWatcherParameter ¶m, bool background) {
00338 LightReMutexHolder holder(_lock);
00339 if (get_active()) {
00340 if (param.has_keycode()) {
00341
00342 update_text();
00343
00344 int keycode = param.get_keycode();
00345
00346 if (!isascii(keycode) || isprint(keycode)) {
00347
00348
00349 if (!_candidate_wtext.empty()) {
00350 _candidate_wtext = wstring();
00351 _text_geom_stale = true;
00352 }
00353 wstring new_char(1, (wchar_t)keycode);
00354
00355 if (get_max_chars() > 0 && _text.get_num_characters() >= get_max_chars()) {
00356
00357
00358
00359 overflow(param);
00360
00361 } else {
00362 _cursor_position = min(_cursor_position, _text.get_num_characters());
00363 bool too_long = !_text.set_wsubstr(new_char, _cursor_position, 0);
00364 bool overflow_mode = get_overflow_mode() && _num_lines == 1;
00365 if(overflow_mode){
00366 too_long = false;
00367 }
00368 if (_obscure_mode) {
00369 too_long = !_obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
00370 } else {
00371 if (!too_long && (_text.get_num_rows() == _num_lines) && !overflow_mode) {
00372
00373
00374
00375
00376 int r = _num_lines - 1;
00377 int c = _text.get_num_cols(r);
00378 PN_stdfloat last_line_width =
00379 _text.get_xpos(r, c) - _text.get_xpos(r, 0);
00380 too_long = (last_line_width > _max_width);
00381 }
00382
00383 if (!too_long && keycode == ' ' && !overflow_mode) {
00384
00385
00386
00387
00388
00389 int r, c;
00390 _text.calc_r_c(r, c, _cursor_position);
00391 if (_text.get_num_cols(r) == c + 1) {
00392
00393
00394
00395
00396
00397 if (c - 1 >= 0 && _text.get_character(r, c - 1) == ' ') {
00398
00399
00400
00401 PN_stdfloat current_line_width =
00402 _text.get_xpos(r, c + 1) - _text.get_xpos(r, 0);
00403 if (current_line_width > _max_width) {
00404
00405
00406 _text.set_wsubstr(wstring(), _cursor_position, 1);
00407
00408
00409
00410
00411
00412 if (_cursor_position < _text.get_num_characters() &&
00413 _text.get_character(_cursor_position) == ' ') {
00414 _cursor_position++;
00415 _cursor_stale = true;
00416 }
00417 return;
00418 }
00419 }
00420 }
00421 }
00422 }
00423
00424 if (too_long) {
00425 _text.set_wsubstr(wstring(), _cursor_position, 1);
00426 overflow(param);
00427
00428 } else {
00429 _cursor_position += new_char.length();
00430 _cursor_stale = true;
00431 _text_geom_stale = true;
00432 type(param);
00433 }
00434 }
00435 }
00436 }
00437 }
00438 PGItem::keystroke(param, background);
00439 }
00440
00441
00442
00443
00444
00445
00446
00447 void PGEntry::
00448 candidate(const MouseWatcherParameter ¶m, bool background) {
00449 LightReMutexHolder holder(_lock);
00450 if (get_active()) {
00451 if (param.has_candidate()) {
00452
00453 _candidate_wtext = param.get_candidate_string();
00454 _candidate_highlight_start = param.get_highlight_start();
00455 _candidate_highlight_end = param.get_highlight_end();
00456 _candidate_cursor_pos = param.get_cursor_pos();
00457 _text_geom_stale = true;
00458 if (!_candidate_wtext.empty()) {
00459 type(param);
00460 }
00461 }
00462 }
00463 PGItem::candidate(param, background);
00464 }
00465
00466
00467
00468
00469
00470
00471
00472 void PGEntry::
00473 accept(const MouseWatcherParameter ¶m) {
00474 LightReMutexHolder holder(_lock);
00475 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
00476 string event = get_accept_event(param.get_button());
00477 play_sound(event);
00478 throw_event(event, EventParameter(ep));
00479 set_focus(false);
00480 }
00481
00482
00483
00484
00485
00486
00487
00488 void PGEntry::
00489 accept_failed(const MouseWatcherParameter ¶m) {
00490 LightReMutexHolder holder(_lock);
00491 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
00492 string event = get_accept_failed_event(param.get_button());
00493 play_sound(event);
00494 throw_event(event, EventParameter(ep));
00495
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 void PGEntry::
00507 overflow(const MouseWatcherParameter ¶m) {
00508 LightReMutexHolder holder(_lock);
00509 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
00510 string event = get_overflow_event();
00511 play_sound(event);
00512 throw_event(event, EventParameter(ep));
00513 }
00514
00515
00516
00517
00518
00519
00520
00521 void PGEntry::
00522 type(const MouseWatcherParameter ¶m) {
00523 LightReMutexHolder holder(_lock);
00524 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
00525 string event = get_type_event();
00526 play_sound(event);
00527 throw_event(event, EventParameter(ep));
00528 }
00529
00530
00531
00532
00533
00534
00535
00536 void PGEntry::
00537 erase(const MouseWatcherParameter ¶m) {
00538 LightReMutexHolder holder(_lock);
00539 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
00540 string event = get_erase_event();
00541 play_sound(event);
00542 throw_event(event, EventParameter(ep));
00543 }
00544
00545
00546
00547
00548
00549
00550
00551 void PGEntry::
00552 cursormove() {
00553 LightReMutexHolder holder(_lock);
00554 string event = get_cursormove_event();
00555 throw_event(event, EventParameter(_cursor_def.get_x()), EventParameter(_cursor_def.get_y()));
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567 void PGEntry::
00568 setup(PN_stdfloat width, int num_lines) {
00569 LightReMutexHolder holder(_lock);
00570 setup_minimal(width, num_lines);
00571
00572 TextNode *text_node = get_text_def(S_focus);
00573 PN_stdfloat line_height = text_node->get_line_height();
00574
00575
00576 float bottom = -0.3f * line_height - (line_height * (num_lines - 1));
00577
00578 LMatrix4 mat = text_node->get_transform();
00579 LPoint3 ll = LPoint3::rfu(0.0f, 0.0f, bottom) * mat;
00580 LPoint3 ur = LPoint3::rfu(width, 0.0f, line_height) * mat;
00581 LPoint3 lr = LPoint3::rfu(width, 0.0f, bottom) * mat;
00582 LPoint3 ul = LPoint3::rfu(0.0f, 0.0f, line_height) * mat;
00583
00584 LVector3 up = LVector3::up();
00585 int up_axis;
00586 if (up[1]) {
00587 up_axis = 1;
00588 }
00589 else if (up[2]) {
00590 up_axis = 2;
00591 }
00592 else {
00593 up_axis = 0;
00594 }
00595 LVector3 right = LVector3::right();
00596 int right_axis;
00597 if (right[0]) {
00598 right_axis = 0;
00599 }
00600 else if (right[2]) {
00601 right_axis = 2;
00602 }
00603 else {
00604 right_axis = 1;
00605 }
00606
00607
00608
00609
00610 LVecBase4 frame;
00611 frame[0] = min(min(ll[right_axis], ur[right_axis]), min(lr[right_axis], ul[right_axis]));
00612 frame[1] = max(max(ll[right_axis], ur[right_axis]), max(lr[right_axis], ul[right_axis]));
00613 frame[2] = min(min(ll[up_axis], ur[up_axis]), min(lr[up_axis], ul[up_axis]));
00614 frame[3] = max(max(ll[up_axis], ur[up_axis]), max(lr[up_axis], ul[up_axis]));
00615
00616 switch (text_node->get_align()) {
00617 case TextNode::A_left:
00618 case TextNode::A_boxed_left:
00619
00620 break;
00621
00622 case TextNode::A_center:
00623 case TextNode::A_boxed_center:
00624 frame[0] = -width / 2.0;
00625 frame[1] = width / 2.0;
00626 break;
00627
00628 case TextNode::A_right:
00629 case TextNode::A_boxed_right:
00630 frame[0] = -width;
00631 frame[1] = 0.0f;
00632 break;
00633 }
00634
00635 set_frame(frame[0] - 0.15f, frame[1] + 0.15f, frame[2], frame[3]);
00636
00637 PGFrameStyle style;
00638 style.set_width(0.1f, 0.1f);
00639 style.set_type(PGFrameStyle::T_bevel_in);
00640 style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
00641
00642 set_frame_style(S_no_focus, style);
00643
00644 style.set_color(0.9f, 0.9f, 0.9f, 1.0f);
00645 set_frame_style(S_focus, style);
00646
00647 style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
00648 set_frame_style(S_inactive, style);
00649 }
00650
00651
00652
00653
00654
00655
00656
00657 void PGEntry::
00658 setup_minimal(PN_stdfloat width, int num_lines) {
00659 LightReMutexHolder holder(_lock);
00660 set_text(string());
00661 _cursor_position = 0;
00662 set_max_chars(0);
00663 set_max_width(width);
00664 set_num_lines(num_lines);
00665 update_text();
00666
00667 _accept_enabled = true;
00668
00669 TextNode *text_node = get_text_def(S_focus);
00670 PN_stdfloat line_height = text_node->get_line_height();
00671
00672
00673 clear_cursor_def();
00674
00675 LineSegs ls;
00676 ls.set_color(text_node->get_text_color());
00677 ls.move_to(0.0f, 0.0f, -0.15f * line_height);
00678 ls.draw_to(0.0f, 0.0f, 0.70f * line_height);
00679 get_cursor_def().attach_new_node(ls.create());
00680
00681
00682
00683
00684
00685
00686 }
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697 void PGEntry::
00698 set_text_def(int state, TextNode *node) {
00699 LightReMutexHolder holder(_lock);
00700 nassertv(state >= 0 && state < 1000);
00701 if (node == (TextNode *)NULL && state >= (int)_text_defs.size()) {
00702
00703 return;
00704 }
00705 slot_text_def(state);
00706
00707 _text_defs[state] = node;
00708 }
00709
00710
00711
00712
00713
00714
00715
00716
00717 TextNode *PGEntry::
00718 get_text_def(int state) const {
00719 LightReMutexHolder holder(_lock);
00720 if (state < 0 || state >= (int)_text_defs.size()) {
00721
00722 return get_text_node();
00723 }
00724 if (_text_defs[state] == (TextNode *)NULL) {
00725 return get_text_node();
00726 }
00727 return _text_defs[state];
00728 }
00729
00730
00731
00732
00733
00734
00735
00736
00737 void PGEntry::
00738 set_active(bool active) {
00739 LightReMutexHolder holder(_lock);
00740 PGItem::set_active(active);
00741 update_state();
00742 }
00743
00744
00745
00746
00747
00748
00749
00750 void PGEntry::
00751 set_focus(bool focus) {
00752 LightReMutexHolder holder(_lock);
00753 PGItem::set_focus(focus);
00754 _blink_start = ClockObject::get_global_clock()->get_frame_time();
00755 update_state();
00756 }
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766 bool PGEntry::
00767 is_wtext() const {
00768 LightReMutexHolder holder(_lock);
00769 for (int i = 0; i < _text.get_num_characters(); ++i) {
00770 wchar_t ch = _text.get_character(i);
00771 if ((ch & ~0x7f) != 0) {
00772 return true;
00773 }
00774 }
00775
00776 return false;
00777 }
00778
00779
00780
00781
00782
00783
00784
00785 void PGEntry::
00786 slot_text_def(int state) {
00787 while (state >= (int)_text_defs.size()) {
00788 _text_defs.push_back((TextNode *)NULL);
00789 }
00790 }
00791
00792
00793
00794
00795
00796
00797
00798 void PGEntry::
00799 update_text() {
00800 TextNode *node = get_text_def(get_state());
00801 nassertv(node != (TextNode *)NULL);
00802
00803 if (_text_geom_stale || node != _last_text_def) {
00804 TextProperties props = *node;
00805 props.set_wordwrap(_max_width);
00806 props.set_preserve_trailing_whitespace(true);
00807 _text.set_properties(props);
00808 _text.set_max_rows(_num_lines);
00809
00810 if (node != _last_text_def) {
00811
00812
00813 _text.set_wtext(_text.get_wtext());
00814 _last_text_def = node;
00815 }
00816
00817 _text.set_multiline_mode (!(get_overflow_mode() && _num_lines == 1));
00818
00819 PT(PandaNode) assembled;
00820 if (_obscure_mode) {
00821 _obscure_text.set_properties(props);
00822 _obscure_text.set_max_rows(_num_lines);
00823 _obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
00824 assembled = _obscure_text.assemble_text();
00825
00826 } else if (_candidate_wtext.empty()) {
00827
00828
00829 assembled = _text.assemble_text();
00830
00831 } else {
00832 TextPropertiesManager *tp_mgr = TextPropertiesManager::get_global_ptr();
00833 TextProperties inactive = tp_mgr->get_properties(_candidate_inactive);
00834 TextProperties active = tp_mgr->get_properties(_candidate_active);
00835
00836
00837
00838
00839 wstring cseq;
00840 cseq += wstring(1, (wchar_t)text_push_properties_key);
00841 cseq += node->decode_text(_candidate_inactive);
00842 cseq += wstring(1, (wchar_t)text_push_properties_key);
00843 cseq += _candidate_wtext.substr(0, _candidate_highlight_start);
00844 cseq += wstring(1, (wchar_t)text_push_properties_key);
00845 cseq += node->decode_text(_candidate_active);
00846 cseq += wstring(1, (wchar_t)text_push_properties_key);
00847 cseq += _candidate_wtext.substr(_candidate_highlight_start,
00848 _candidate_highlight_end - _candidate_highlight_start);
00849 cseq += wstring(1, (wchar_t)text_pop_properties_key);
00850 cseq += _candidate_wtext.substr(_candidate_highlight_end);
00851 cseq += wstring(1, (wchar_t)text_pop_properties_key);
00852
00853
00854 TextAssembler ctext(_text);
00855 ctext.set_wsubstr(cseq, _cursor_position, 0);
00856 assembled = ctext.assemble_text();
00857 }
00858
00859 if (!_current_text.is_empty()) {
00860 _current_text.remove_node();
00861 }
00862
00863 _current_text =
00864 _text_render_root.attach_new_node(assembled);
00865
00866 _current_text.set_mat(node->get_transform());
00867
00868 if (get_overflow_mode() && _num_lines == 1){
00869
00870 PN_stdfloat cursor_graphic_pos = _text.get_xpos(0, _cursor_position);
00871 PN_stdfloat min_padding = (cursor_graphic_pos - _max_width);
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891 if (_current_padding < min_padding || _current_padding > cursor_graphic_pos){
00892 _current_padding = min_padding + (cursor_graphic_pos - min_padding) * 0.5;
00893 }
00894
00895 if (_current_padding < 0){
00896 _current_padding = 0;
00897 }
00898
00899 _current_text.set_x(_current_text.get_x() - _current_padding);
00900 _current_text.set_scissor(NodePath(this),
00901 LPoint3::rfu(0, 0, -0.5), LPoint3::rfu(_max_width, 0, -0.5),
00902 LPoint3::rfu(_max_width, 0, 1.5), LPoint3::rfu(0, 0, 1.5));
00903 }
00904
00905 _text_geom_stale = false;
00906 _text_geom_flattened = false;
00907 _cursor_stale = true;
00908 }
00909
00910
00911
00912 if (!get_focus() && !_text_geom_flattened) {
00913 _current_text.flatten_strong();
00914 _text_geom_flattened = true;
00915 }
00916 }
00917
00918
00919
00920
00921
00922
00923 void PGEntry::
00924 update_cursor() {
00925 TextNode *node = get_text_def(get_state());
00926 nassertv(node != (TextNode *)NULL);
00927 _cursor_scale.set_mat(node->get_transform());
00928 _cursor_scale.set_color(node->get_text_color());
00929
00930 if (_cursor_stale || node != _last_text_def) {
00931 update_text();
00932
00933 _cursor_position = min(_cursor_position, _text.get_num_characters());
00934
00935
00936 int row, column;
00937 PN_stdfloat xpos, ypos;
00938 if (_obscure_mode) {
00939 _obscure_text.calc_r_c(row, column, _cursor_position);
00940 xpos = _obscure_text.get_xpos(row, column);
00941 ypos = _obscure_text.get_ypos(row, column);
00942 } else {
00943 _text.calc_r_c(row, column, _cursor_position);
00944 xpos = _text.get_xpos(row, column);
00945 ypos = _text.get_ypos(row, column);
00946 }
00947
00948 _cursor_def.set_pos(xpos - _current_padding, 0.0f, ypos);
00949 _cursor_stale = false;
00950 cursormove();
00951
00952 }
00953
00954
00955 if (!get_focus() || !_candidate_wtext.empty()) {
00956 show_hide_cursor(false);
00957 } else {
00958 double elapsed_time =
00959 ClockObject::get_global_clock()->get_frame_time() - _blink_start;
00960 int cycle = (int)(elapsed_time * _blink_rate * 2.0f);
00961 bool visible = ((cycle & 1) == 0);
00962 show_hide_cursor(visible);
00963 }
00964 }
00965
00966
00967
00968
00969
00970
00971
00972 void PGEntry::
00973 show_hide_cursor(bool visible) {
00974 if (visible != _cursor_visible) {
00975 if (visible) {
00976 _cursor_scale.show();
00977 } else {
00978 _cursor_scale.hide();
00979 }
00980 _cursor_visible = visible;
00981 }
00982 }
00983
00984
00985
00986
00987
00988
00989
00990 void PGEntry::
00991 update_state() {
00992 if (get_active()) {
00993 if (get_focus()) {
00994 set_state(S_focus);
00995 } else {
00996 set_state(S_no_focus);
00997 }
00998 } else {
00999 set_state(S_inactive);
01000 }
01001 }