Panda3D
pgEntry.I
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.I
10  * @author drose
11  * @date 2002-03-13
12  */
13 
14 /**
15  * Changes the text currently displayed within the entry. This uses the
16  * Unicode encoding currently specified for the "focus" TextNode; therefore,
17  * the TextNode must exist before calling set_text().
18  *
19  * The return value is true if all the text is accepted, or false if some was
20  * truncated (see set_max_width(), etc.).
21  */
22 INLINE bool PGEntry::
23 set_text(const std::string &text) {
24  LightReMutexHolder holder(_lock);
25  TextNode *text_node = get_text_def(S_focus);
26  nassertr(text_node != nullptr, false);
27  return set_wtext(text_node->decode_text(text));
28 }
29 
30 /**
31  * Returns the text currently displayed within the entry, without any embedded
32  * properties characters.
33  *
34  * This uses the Unicode encoding currently specified for the "focus"
35  * TextNode; therefore, the TextNode must exist before calling get_text().
36  */
37 INLINE std::string PGEntry::
38 get_plain_text() const {
39  LightReMutexHolder holder(_lock);
40  TextNode *text_node = get_text_def(S_focus);
41  nassertr(text_node != nullptr, std::string());
42  return text_node->encode_wtext(get_plain_wtext());
43 }
44 
45 /**
46  * Returns the text currently displayed within the entry. This uses the
47  * Unicode encoding currently specified for the "focus" TextNode; therefore,
48  * the TextNode must exist before calling get_text().
49  */
50 INLINE std::string PGEntry::
51 get_text() const {
52  LightReMutexHolder holder(_lock);
53  TextNode *text_node = get_text_def(S_focus);
54  nassertr(text_node != nullptr, std::string());
55  return text_node->encode_wtext(get_wtext());
56 }
57 
58 /**
59  * Returns the number of characters of text in the entry. This is the actual
60  * number of visible characters, not counting implicit newlines due to
61  * wordwrapping, or formatted characters for text properties changes. If
62  * there is an embedded TextGraphic object, it counts as one character.
63  *
64  * This is also the length of the string returned by get_plain_text().
65  */
66 INLINE int PGEntry::
68  LightReMutexHolder holder(_lock);
69  return _text.get_num_characters();
70 }
71 
72 /**
73  * Returns the character at the indicated position in the entry. If the
74  * object at this position is a graphic object instead of a character, returns
75  * 0.
76  */
77 INLINE wchar_t PGEntry::
78 get_character(int n) const {
79  LightReMutexHolder holder(_lock);
80  return _text.get_character(n);
81 }
82 
83 /**
84  * Returns the graphic object at the indicated position in the pre-wordwrapped
85  * string. If the object at this position is a character instead of a graphic
86  * object, returns NULL.
87  */
88 INLINE const TextGraphic *PGEntry::
89 get_graphic(int n) const {
90  LightReMutexHolder holder(_lock);
91  return _text.get_graphic(n);
92 }
93 
94 /**
95  * Returns the TextProperties in effect for the object at the indicated
96  * position in the pre-wordwrapped string.
97  */
98 INLINE const TextProperties &PGEntry::
99 get_properties(int n) const {
100  LightReMutexHolder holder(_lock);
101  return _text.get_properties(n);
102 }
103 
104 /**
105  * Sets the current position of the cursor. This is the position within the
106  * text at which the next letter typed by the user will be inserted; normally
107  * it is the same as the length of the text.
108  */
109 INLINE void PGEntry::
110 set_cursor_position(int position) {
111  LightReMutexHolder holder(_lock);
112  if (_cursor_position != position) {
113  _cursor_position = position;
114  _cursor_stale = true;
115  _blink_start = ClockObject::get_global_clock()->get_frame_time();
116  }
117 }
118 
119 /**
120  * Returns the current position of the cursor.
121  */
122 INLINE int PGEntry::
124  LightReMutexHolder holder(_lock);
125  return _cursor_position;
126 }
127 
128 /**
129  * Returns the node position x of the cursor
130  */
131 
132 INLINE PN_stdfloat PGEntry::
133 get_cursor_X() const {
134  LightReMutexHolder holder(_lock);
135  return _cursor_def.get_x();
136 }
137 
138 /**
139  * Returns the node position y of the cursor
140  */
141 
142 INLINE PN_stdfloat PGEntry::
143 get_cursor_Y() const {
144  LightReMutexHolder holder(_lock);
145  return _cursor_def.get_y();
146 }
147 
148 
149 /**
150  * Sets the maximum number of characters that may be typed into the entry.
151  * This is a limit on the number of characters, as opposed to the width of the
152  * entry; see also set_max_width().
153  *
154  * If this is 0, there is no limit.
155  */
156 INLINE void PGEntry::
157 set_max_chars(int max_chars) {
158  LightReMutexHolder holder(_lock);
159  _max_chars = max_chars;
160 }
161 
162 /**
163  * Returns the current maximum number of characters that may be typed into the
164  * entry, or 0 if there is no limit. See set_max_chars().
165  */
166 INLINE int PGEntry::
167 get_max_chars() const {
168  LightReMutexHolder holder(_lock);
169  return _max_chars;
170 }
171 
172 /**
173  * Sets the maximum width of all characters that may be typed into the entry.
174  * This is a limit on the width of the formatted text, not a fixed limit on
175  * the number of characters; also set_max_chars().
176  *
177  * If this is 0, there is no limit.
178  *
179  * If _num_lines is more than 1, rather than being a fixed width on the whole
180  * entry, this becomes instead the wordwrap width (and the width limit on the
181  * entry is essentially _max_width * _num_lines).
182  */
183 INLINE void PGEntry::
184 set_max_width(PN_stdfloat max_width) {
185  LightReMutexHolder holder(_lock);
186  _max_width = max_width;
187  _text_geom_stale = true;
188 }
189 
190 /**
191  * Returns the current maximum width of the characters that may be typed into
192  * the entry, or 0 if there is no limit. See set_max_width().
193  */
194 INLINE PN_stdfloat PGEntry::
195 get_max_width() const {
196  LightReMutexHolder holder(_lock);
197  return _max_width;
198 }
199 
200 /**
201  * Sets the number of lines of text the PGEntry will use. This only has
202  * meaning if _max_width is not 0; _max_width indicates the wordwrap width of
203  * each line.
204  */
205 INLINE void PGEntry::
206 set_num_lines(int num_lines) {
207  LightReMutexHolder holder(_lock);
208  nassertv(num_lines >= 1);
209  _num_lines = num_lines;
210  _text_geom_stale = true;
211  update_text();
212 }
213 
214 /**
215  * Returns the number of lines of text the PGEntry will use, if _max_width is
216  * not 0. See set_num_lines().
217  */
218 INLINE int PGEntry::
219 get_num_lines() const {
220  LightReMutexHolder holder(_lock);
221  return _num_lines;
222 }
223 
224 /**
225  * Sets the number of times per second the cursor will blink while the entry
226  * has keyboard focus.
227  *
228  * If this is 0, the cursor does not blink, but is held steady.
229  */
230 INLINE void PGEntry::
231 set_blink_rate(PN_stdfloat blink_rate) {
232  LightReMutexHolder holder(_lock);
233  _blink_rate = blink_rate;
234 }
235 
236 /**
237  * Returns the number of times per second the cursor will blink, or 0 if the
238  * cursor is not to blink.
239  */
240 INLINE PN_stdfloat PGEntry::
241 get_blink_rate() const {
242  LightReMutexHolder holder(_lock);
243  return _blink_rate;
244 }
245 
246 /**
247  * Returns the Node that will be rendered to represent the cursor. You can
248  * attach suitable cursor geometry to this node.
249  */
250 INLINE NodePath PGEntry::
252  LightReMutexHolder holder(_lock);
253  return _cursor_def;
254 }
255 
256 /**
257  * Removes all the children from the cursor_def node, in preparation for
258  * adding a new definition.
259  */
260 INLINE void PGEntry::
262  LightReMutexHolder holder(_lock);
263  _cursor_def.remove_node();
264  _cursor_def = _cursor_scale.attach_new_node("cursor");
265 }
266 
267 /**
268  * Sets whether the arrow keys (and home/end) control movement of the cursor.
269  * If true, they are active; if false, they are ignored.
270  */
271 INLINE void PGEntry::
273  LightReMutexHolder holder(_lock);
274  _cursor_keys_active = flag;
275 }
276 
277 /**
278  * Returns whether the arrow keys are currently set to control movement of the
279  * cursor; see set_cursor_keys_active().
280  */
281 INLINE bool PGEntry::
283  LightReMutexHolder holder(_lock);
284  return _cursor_keys_active;
285 }
286 
287 /**
288  * Specifies whether obscure mode should be enabled. In obscure mode, a
289  * string of asterisks is displayed instead of the literal text, e.g. for
290  * entering passwords.
291  *
292  * In obscure mode, the width of the text is computed based on the width of
293  * the string of asterisks, not on the width of the actual text. This has
294  * implications on the maximum length of text that may be entered if max_width
295  * is in effect.
296  */
297 INLINE void PGEntry::
298 set_obscure_mode(bool flag) {
299  LightReMutexHolder holder(_lock);
300  if (_obscure_mode != flag) {
301  _obscure_mode = flag;
302  _text_geom_stale = true;
303  }
304 }
305 
306 /**
307  * Specifies whether obscure mode is enabled. See set_obscure_mode().
308  */
309 INLINE bool PGEntry::
311  LightReMutexHolder holder(_lock);
312  return _obscure_mode;
313 }
314 
315 /**
316  * Specifies whether overflow mode should be enabled. In overflow mode, text
317  * can overflow the boundaries of the Entry element horizontally.
318  *
319  * Overflow mode only works when the number of lines is 1.
320  */
321 INLINE void PGEntry::
322 set_overflow_mode(bool flag) {
323  LightReMutexHolder holder(_lock);
324  if (_overflow_mode != flag) {
325  _overflow_mode = flag;
326  _text_geom_stale = true;
327  _cursor_stale = true;
328  }
329 }
330 
331 /**
332  * Specifies whether overflow mode is enabled. See set_overflow_mode().
333  */
334 INLINE bool PGEntry::
336  LightReMutexHolder holder(_lock);
337  return _overflow_mode;
338 }
339 
340 /**
341  * Specifies the name of the TextProperties structure added to the
342  * TextPropertiesManager that will be used to render candidate strings from
343  * the IME, used for typing characters in east Asian languages. Each
344  * candidate string represents one possible way to interpret the sequence of
345  * keys the user has just entered; it should not be considered typed yet, but
346  * it is important for the user to be able to see what he is considering
347  * entering.
348  *
349  * This particular method sets the properties for the subset of the current
350  * candidate string that the user can actively scroll through.
351  */
352 INLINE void PGEntry::
353 set_candidate_active(const std::string &candidate_active) {
354  LightReMutexHolder holder(_lock);
355  _candidate_active = candidate_active;
356 }
357 
358 /**
359  * See set_candidate_active().
360  */
361 INLINE const std::string &PGEntry::
363  LightReMutexHolder holder(_lock);
364  return _candidate_active;
365 }
366 
367 /**
368  * Specifies the name of the TextProperties structure added to the
369  * TextPropertiesManager that will be used to render candidate strings from
370  * the IME, used for typing characters in east Asian languages. Each
371  * candidate string represents one possible way to interpret the sequence of
372  * keys the user has just entered; it should not be considered typed yet, but
373  * it is important for the user to be able to see what he is considering
374  * entering.
375  *
376  * This particular method sets the properties for the subset of the current
377  * candidate string that the user is not actively scrolling through.
378  */
379 INLINE void PGEntry::
380 set_candidate_inactive(const std::string &candidate_inactive) {
381  LightReMutexHolder holder(_lock);
382  _candidate_inactive = candidate_inactive;
383 }
384 
385 /**
386  * See set_candidate_inactive().
387  */
388 INLINE const std::string &PGEntry::
390  LightReMutexHolder holder(_lock);
391  return _candidate_inactive;
392 }
393 
394 /**
395  * Returns the prefix that is used to define the accept event for all
396  * PGEntries. The accept event is the concatenation of this string followed
397  * by get_id().
398  */
399 INLINE std::string PGEntry::
401  return "accept-";
402 }
403 
404 /**
405  * Returns the prefix that is used to define the accept failed event for all
406  * PGEntries. This event is the concatenation of this string followed by
407  * get_id().
408  */
409 INLINE std::string PGEntry::
411  return "acceptfailed-";
412 }
413 
414 /**
415  * Returns the prefix that is used to define the overflow event for all
416  * PGEntries. The overflow event is the concatenation of this string followed
417  * by get_id().
418  */
419 INLINE std::string PGEntry::
421  return "overflow-";
422 }
423 
424 /**
425  * Returns the prefix that is used to define the type event for all PGEntries.
426  * The type event is the concatenation of this string followed by get_id().
427  */
428 INLINE std::string PGEntry::
430  return "type-";
431 }
432 
433 /**
434  * Returns the prefix that is used to define the erase event for all
435  * PGEntries. The erase event is the concatenation of this string followed by
436  * get_id().
437  */
438 INLINE std::string PGEntry::
440  return "erase-";
441 }
442 
443 /**
444  * Returns the prefix that is used to define the cursor event for all
445  * PGEntries. The cursor event is the concatenation of this string followed
446  * by get_id().
447  */
448 INLINE std::string PGEntry::
450  return "cursormove-";
451 }
452 
453 /**
454  * Returns the event name that will be thrown when the entry is accepted
455  * normally.
456  */
457 INLINE std::string PGEntry::
458 get_accept_event(const ButtonHandle &button) const {
459  return get_accept_prefix() + button.get_name() + "-" + get_id();
460 }
461 
462 /**
463  * Returns the event name that will be thrown when the entry cannot accept an
464  * input
465  */
466 INLINE std::string PGEntry::
467 get_accept_failed_event(const ButtonHandle &button) const {
468  return get_accept_failed_prefix() + button.get_name() + "-" + get_id();
469 }
470 
471 /**
472  * Returns the event name that will be thrown when too much text is attempted
473  * to be entered into the PGEntry, exceeding either the limit set via
474  * set_max_chars() or via set_max_width().
475  */
476 INLINE std::string PGEntry::
478  return get_overflow_prefix() + get_id();
479 }
480 
481 /**
482  * Returns the event name that will be thrown whenever the user extends the
483  * text by typing.
484  */
485 INLINE std::string PGEntry::
486 get_type_event() const {
487  return get_type_prefix() + get_id();
488 }
489 
490 /**
491  * Returns the event name that will be thrown whenever the user erases
492  * characters in the text.
493  */
494 INLINE std::string PGEntry::
496  return get_erase_prefix() + get_id();
497 }
498 
499 /**
500  * Returns the event name that will be thrown whenever the cursor moves
501  */
502 INLINE std::string PGEntry::
504  return get_cursormove_prefix() + get_id();
505 }
506 
507 /**
508  * Changes the text currently displayed within the entry.
509  *
510  * The return value is true if all the text is accepted, or false if some was
511  * truncated (see set_max_width(), etc.).
512  */
513 INLINE bool PGEntry::
514 set_wtext(const std::wstring &wtext) {
515  LightReMutexHolder holder(_lock);
516  bool ret = _text.set_wtext(wtext);
517  if (_obscure_mode) {
518  ret = _obscure_text.set_wtext(std::wstring(_text.get_num_characters(), '*'));
519  }
520  _text_geom_stale = true;
521  set_cursor_position(std::min(_cursor_position, _text.get_num_characters()));
522  return ret;
523 }
524 
525 /**
526  * Returns the text currently displayed within the entry, without any embedded
527  * properties characters.
528  */
529 INLINE std::wstring PGEntry::
531  LightReMutexHolder holder(_lock);
532  return _text.get_plain_wtext();
533 }
534 
535 /**
536  * Returns the text currently displayed within the entry.
537  */
538 INLINE std::wstring PGEntry::
539 get_wtext() const {
540  LightReMutexHolder holder(_lock);
541  return _text.get_wtext();
542 }
543 
544 /**
545  * Sets whether the input may be accepted--use to disable submission by the
546  * user
547  */
548 INLINE void PGEntry::
549 set_accept_enabled(bool enabled) {
550  LightReMutexHolder holder(_lock);
551  _accept_enabled = enabled;
552 }
std::string get_plain_text() const
Returns the text currently displayed within the entry, without any embedded properties characters.
Definition: pgEntry.I:38
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
PN_stdfloat get_cursor_Y() const
Returns the node position y of the cursor.
Definition: pgEntry.I:143
static std::string get_accept_prefix()
Returns the prefix that is used to define the accept event for all PGEntries.
Definition: pgEntry.I:400
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:184
std::string get_cursormove_event() const
Returns the event name that will be thrown whenever the cursor moves.
Definition: pgEntry.I:503
const TextGraphic * get_graphic(int n) const
Returns the graphic object at the indicated position in the pre-wordwrapped string.
void set_candidate_inactive(const std::string &candidate_inactive)
Specifies the name of the TextProperties structure added to the TextPropertiesManager that will be us...
Definition: pgEntry.I:380
int get_num_characters() const
Returns the number of characters of text, before wordwrapping.
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:467
PN_stdfloat get_cursor_X() const
Returns the node position x of the cursor.
Definition: pgEntry.I:133
void clear_cursor_def()
Removes all the children from the cursor_def node, in preparation for adding a new definition.
Definition: pgEntry.I:261
int get_max_chars() const
Returns the current maximum number of characters that may be typed into the entry,...
Definition: pgEntry.I:167
static std::string get_type_prefix()
Returns the prefix that is used to define the type event for all PGEntries.
Definition: pgEntry.I:429
void set_candidate_active(const std::string &candidate_active)
Specifies the name of the TextProperties structure added to the TextPropertiesManager that will be us...
Definition: pgEntry.I:353
wchar_t get_character(int n) const
Returns the character at the indicated position in the pre-wordwrapped string.
void set_cursor_keys_active(bool flag)
Sets whether the arrow keys (and home/end) control movement of the cursor.
Definition: pgEntry.I:272
void set_accept_enabled(bool enabled)
Sets whether the input may be accepted–use to disable submission by the user.
Definition: pgEntry.I:549
bool get_obscure_mode() const
Specifies whether obscure mode is enabled.
Definition: pgEntry.I:310
bool set_wtext(const std::wstring &wtext)
Accepts a new text string and associated properties structure, and precomputes the wordwrapping layou...
int get_cursor_position() const
Returns the current position of the cursor.
Definition: pgEntry.I:123
std::wstring get_plain_wtext() const
Returns the text currently displayed within the entry, without any embedded properties characters.
Definition: pgEntry.I:530
const std::string & get_id() const
Returns the unique ID assigned to this PGItem.
Definition: pgItem.I:224
get_properties
Returns the default TextProperties that are applied to the text in the absence of any nested property...
const std::string & get_candidate_active() const
See set_candidate_active().
Definition: pgEntry.I:362
static std::string get_cursormove_prefix()
Returns the prefix that is used to define the cursor event for all PGEntries.
Definition: pgEntry.I:449
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:26
bool get_overflow_mode() const
Specifies whether overflow mode is enabled.
Definition: pgEntry.I:335
int get_num_characters() const
Returns the number of characters of text in the entry.
Definition: pgEntry.I:67
PN_stdfloat get_max_width() const
Returns the current maximum width of the characters that may be typed into the entry,...
Definition: pgEntry.I:195
bool get_cursor_keys_active() const
Returns whether the arrow keys are currently set to control movement of the cursor; see set_cursor_ke...
Definition: pgEntry.I:282
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
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:563
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:458
void set_num_lines(int num_lines)
Sets the number of lines of text the PGEntry will use.
Definition: pgEntry.I:206
static std::string get_overflow_prefix()
Returns the prefix that is used to define the overflow event for all PGEntries.
Definition: pgEntry.I:420
void set_blink_rate(PN_stdfloat blink_rate)
Sets the number of times per second the cursor will blink while the entry has keyboard focus.
Definition: pgEntry.I:231
int get_num_lines() const
Returns the number of lines of text the PGEntry will use, if _max_width is not 0.
Definition: pgEntry.I:219
Similar to MutexHolder, but for a light reentrant mutex.
std::string encode_wtext(const std::wstring &wtext) const
Encodes a wide-text string into a single-char string, according to the current encoding.
Definition: textEncoder.I:481
std::wstring get_wtext() const
Returns the text currently displayed within the entry.
Definition: pgEntry.I:539
static std::string get_accept_failed_prefix()
Returns the prefix that is used to define the accept failed event for all PGEntries.
Definition: pgEntry.I:410
NodePath get_cursor_def()
Returns the Node that will be rendered to represent the cursor.
Definition: pgEntry.I:251
get_name
Returns the name of the button.
Definition: buttonHandle.h:61
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:591
The primary interface to this module.
Definition: textNode.h:48
This defines the set of visual properties that may be assigned to the individual characters of the te...
void set_cursor_position(int position)
Sets the current position of the cursor.
Definition: pgEntry.I:110
bool set_wtext(const std::wstring &wtext)
Changes the text currently displayed within the entry.
Definition: pgEntry.I:514
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:495
std::wstring get_wtext() const
Returns a wstring that represents the contents of the text.
const TextGraphic * get_graphic(int n) const
Returns the graphic object at the indicated position in the pre-wordwrapped string.
Definition: pgEntry.I:89
void set_overflow_mode(bool flag)
Specifies whether overflow mode should be enabled.
Definition: pgEntry.I:322
const std::string & get_candidate_inactive() const
See set_candidate_inactive().
Definition: pgEntry.I:389
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 * 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:664
std::wstring get_plain_wtext() const
Returns a wstring that represents the contents of the text, without any embedded properties character...
void set_max_chars(int max_chars)
Sets the maximum number of characters that may be typed into the entry.
Definition: pgEntry.I:157
bool set_text(const std::string &text)
Changes the text currently displayed within the entry.
Definition: pgEntry.I:23
const TextProperties & get_properties(int n) const
Returns the TextProperties in effect for the object at the indicated position in the pre-wordwrapped ...
Definition: pgEntry.I:99
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
void set_obscure_mode(bool flag)
Specifies whether obscure mode should be enabled.
Definition: pgEntry.I:298
This defines a special model that has been constructed for the purposes of embedding an arbitrary gra...
Definition: textGraphic.h:37
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:477
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:486
PN_stdfloat get_blink_rate() const
Returns the number of times per second the cursor will blink, or 0 if the cursor is not to blink.
Definition: pgEntry.I:241
std::string get_text() const
Returns the text currently displayed within the entry.
Definition: pgEntry.I:51
static std::string get_erase_prefix()
Returns the prefix that is used to define the erase event for all PGEntries.
Definition: pgEntry.I:439
wchar_t get_character(int n) const
Returns the character at the indicated position in the entry.
Definition: pgEntry.I:78