1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
|
/**
* @file lltextbase.h
* @author Martin Reddy
* @brief The base class of text box/editor, providing Url handling support
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLTEXTBASE_H
#define LL_LLTEXTBASE_H
#include "v4color.h"
#include "lleditmenuhandler.h"
#include "llspellcheckmenuhandler.h"
#include "llstyle.h"
#include "llkeywords.h"
#include "llpanel.h"
#include <string>
#include <vector>
#include <set>
#include <boost/signals2.hpp>
class LLScrollContainer;
class LLContextMenu;
class LLUrlMatch;
///
/// A text segment is used to specify a subsection of a text string
/// that should be formatted differently, such as a hyperlink. It
/// includes a start/end offset from the start of the string, a
/// style to render with, an optional tooltip, etc.
///
class LLTextSegment
: public LLRefCount,
public LLMouseHandler
{
public:
LLTextSegment(S32 start, S32 end)
: mStart(start),
mEnd(end)
{}
virtual ~LLTextSegment();
bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
virtual bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
/**
* Get number of chars that fit into free part of current line.
*
* @param num_pixels - maximum width of rect
* @param segment_offset - symbol in segment we start processing line from
* @param line_offset - symbol in line after which segment starts
* @param max_chars - limit of symbols that will fit in current line
* @param line_ind - index of not word-wrapped string inside segment for multi-line segments.
* Two string separated by word-wrap will have same index.
* @return number of chars that will fit into current line
*/
virtual S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const;
virtual void updateLayout(const class LLTextBase& editor);
virtual F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
virtual bool canEdit() const;
virtual void unlinkFromDocument(class LLTextBase* editor);
virtual void linkToDocument(class LLTextBase* editor);
virtual const LLUIColor& getColor() const;
//virtual void setColor(const LLUIColor &color);
virtual LLStyleConstSP getStyle() const;
virtual void setStyle(LLStyleConstSP style);
virtual void setToken( LLKeywordToken* token );
virtual LLKeywordToken* getToken() const;
virtual void setToolTip(const std::string& tooltip);
virtual void dump() const;
// LLMouseHandler interface
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMiddleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMiddleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleRightMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleScrollWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ bool handleScrollHWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ bool handleToolTip(S32 x, S32 y, MASK mask);
/*virtual*/ const std::string& getName() const;
/*virtual*/ void onMouseCaptureLost();
/*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
/*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
/*virtual*/ bool hasMouseCapture();
S32 getStart() const { return mStart; }
void setStart(S32 start) { mStart = start; }
S32 getEnd() const { return mEnd; }
void setEnd( S32 end ) { mEnd = end; }
protected:
S32 mStart;
S32 mEnd;
};
class LLNormalTextSegment : public LLTextSegment
{
public:
LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor );
LLNormalTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true);
virtual ~LLNormalTextSegment();
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
/*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
/*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const;
/*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
/*virtual*/ bool canEdit() const { return true; }
/*virtual*/ const LLUIColor& getColor() const { return mStyle->getColor(); }
/*virtual*/ LLStyleConstSP getStyle() const { return mStyle; }
/*virtual*/ void setStyle(LLStyleConstSP style) { mStyle = style; }
/*virtual*/ void setToken( LLKeywordToken* token ) { mToken = token; }
/*virtual*/ LLKeywordToken* getToken() const { return mToken; }
/*virtual*/ bool getToolTip( std::string& msg ) const;
/*virtual*/ void setToolTip(const std::string& tooltip);
/*virtual*/ void dump() const;
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleToolTip(S32 x, S32 y, MASK mask);
protected:
F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRectf rect);
virtual const LLWString& getWText() const;
virtual const S32 getLength() const;
protected:
class LLTextBase& mEditor;
LLStyleConstSP mStyle;
S32 mFontHeight;
LLKeywordToken* mToken;
std::string mTooltip;
boost::signals2::connection mImageLoadedConnection;
};
// This text segment is the same as LLNormalTextSegment, the only difference
// is that LLNormalTextSegment draws value of LLTextBase (LLTextBase::getWText()),
// but LLLabelTextSegment draws label of the LLTextBase (LLTextBase::mLabel)
class LLLabelTextSegment : public LLNormalTextSegment
{
public:
LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor );
LLLabelTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true);
protected:
/*virtual*/ const LLWString& getWText() const;
/*virtual*/ const S32 getLength() const;
};
// Text segment that represents a single emoji character that has a different style (=font size) than the rest of
// the document it belongs to
class LLEmojiTextSegment : public LLNormalTextSegment
{
public:
LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor);
LLEmojiTextSegment(const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true);
bool canEdit() const override { return false; }
bool handleToolTip(S32 x, S32 y, MASK mask) override;
};
// Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment)
class LLOnHoverChangeableTextSegment : public LLNormalTextSegment
{
public:
LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor );
/*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask);
protected:
// Style used for text when mouse pointer is over segment
LLStyleConstSP mHoveredStyle;
// Style used for text when mouse pointer is outside segment
LLStyleConstSP mNormalStyle;
};
class LLIndexSegment : public LLTextSegment
{
public:
LLIndexSegment() : LLTextSegment(0, 0) {}
};
class LLInlineViewSegment : public LLTextSegment
{
public:
struct Params : public LLInitParam::Block<Params>
{
Mandatory<LLView*> view;
Optional<bool> force_newline;
Optional<S32> left_pad,
right_pad,
bottom_pad,
top_pad;
};
LLInlineViewSegment(const Params& p, S32 start, S32 end);
~LLInlineViewSegment();
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
/*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const;
/*virtual*/ void updateLayout(const class LLTextBase& editor);
/*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
/*virtual*/ bool canEdit() const { return false; }
/*virtual*/ void unlinkFromDocument(class LLTextBase* editor);
/*virtual*/ void linkToDocument(class LLTextBase* editor);
private:
S32 mLeftPad;
S32 mRightPad;
S32 mTopPad;
S32 mBottomPad;
LLView* mView;
bool mForceNewLine;
};
class LLLineBreakTextSegment : public LLTextSegment
{
public:
LLLineBreakTextSegment(LLStyleConstSP style,S32 pos);
LLLineBreakTextSegment(S32 pos);
~LLLineBreakTextSegment();
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const;
F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
private:
S32 mFontHeight;
};
class LLImageTextSegment : public LLTextSegment
{
public:
LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor);
~LLImageTextSegment();
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 char_offset, S32 max_chars, S32 line_ind) const;
F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
/*virtual*/ bool handleToolTip(S32 x, S32 y, MASK mask);
/*virtual*/ void setToolTip(const std::string& tooltip);
private:
class LLTextBase& mEditor;
LLStyleConstSP mStyle;
protected:
std::string mTooltip;
};
typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
///
/// The LLTextBase class provides a base class for all text fields, such
/// as LLTextEditor and LLTextBox. It implements shared functionality
/// such as Url highlighting and opening.
///
class LLTextBase
: public LLUICtrl,
protected LLEditMenuHandler,
public LLSpellCheckMenuHandler,
public ll::ui::SearchableControl
{
public:
friend class LLTextSegment;
friend class LLNormalTextSegment;
friend class LLUICtrlFactory;
typedef boost::signals2::signal<bool (const LLUUID& user_id)> is_friend_signal_t;
typedef boost::signals2::signal<bool (const LLUUID& blocked_id, const std::string from)> is_blocked_signal_t;
struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams>
{
Alternative<F32> multiple;
Alternative<S32> pixels;
LineSpacingParams();
};
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<LLUIColor> cursor_color,
text_color,
text_readonly_color,
text_tentative_color,
bg_readonly_color,
bg_writeable_color,
bg_focus_color,
text_selected_color,
bg_selected_color;
Optional<bool> bg_visible,
border_visible,
track_end,
read_only,
skip_link_underline,
spellcheck,
allow_scroll,
plain_text,
wrap,
use_ellipses,
use_emoji,
use_color,
parse_urls,
force_urls_external,
parse_highlights,
clip,
clip_partial,
trusted_content,
always_show_icons;
Optional<S32> v_pad,
h_pad;
Optional<LineSpacingParams>
line_spacing;
Optional<S32> max_text_length;
Optional<LLFontGL::ShadowType> font_shadow;
Optional<LLFontGL::VAlign> text_valign;
Params();
};
// LLMouseHandler interface
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleMiddleMouseDown(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleMiddleMouseUp(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleRightMouseUp(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleScrollWheel(S32 x, S32 y, S32 clicks) override;
/*virtual*/ bool handleToolTip(S32 x, S32 y, MASK mask) override;
// LLView interface
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true) override;
/*virtual*/ void draw() override;
// LLUICtrl interface
/*virtual*/ bool acceptsTextInput() const override { return !mReadOnly; }
/*virtual*/ void setColor(const LLUIColor& c) override;
virtual void setReadOnlyColor(const LLUIColor& c);
/*virtual*/ void onVisibilityChange(bool new_visibility) override;
/*virtual*/ void setValue(const LLSD& value) override;
/*virtual*/ LLTextViewModel* getViewModel() const override;
// LLEditMenuHandler interface
/*virtual*/ bool canDeselect() const override;
/*virtual*/ void deselect() override;
virtual void onFocusReceived() override;
virtual void onFocusLost() override;
void setParseHTML(bool parse_html) { mParseHTML = parse_html; }
// LLSpellCheckMenuHandler overrides
/*virtual*/ bool getSpellCheck() const override;
/*virtual*/ const std::string& getSuggestion(U32 index) const override;
/*virtual*/ U32 getSuggestionCount() const override;
/*virtual*/ void replaceWithSuggestion(U32 index) override;
/*virtual*/ void addToDictionary() override;
/*virtual*/ bool canAddToDictionary() const override;
/*virtual*/ void addToIgnore() override;
/*virtual*/ bool canAddToIgnore() const override;
// Spell checking helper functions
std::string getMisspelledWord(U32 pos) const;
bool isMisspelledWord(U32 pos) const;
void onSpellCheckSettingsChange();
virtual void onSpellCheckPerformed(){}
// used by LLTextSegment layout code
bool getWordWrap() const { return mWordWrap; }
bool getUseEllipses() const { return mUseEllipses; }
bool getUseEmoji() const { return mUseEmoji; }
void setUseEmoji(bool value) { mUseEmoji = value; }
bool getUseColor() const { return mUseColor; }
void setUseColor(bool value) { mUseColor = value; }
bool truncate(); // returns true of truncation occurred
bool isContentTrusted() const { return mTrustedContent; }
void setContentTrusted(bool trusted_content) { mTrustedContent = trusted_content; }
// TODO: move into LLTextSegment?
void createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url
// Text accessors
// TODO: add optional style parameter
virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style
/*virtual*/ const std::string& getText() const override;
void setMaxTextLength(S32 length) { mMaxTextByteLength = length; }
S32 getMaxTextLength() { return mMaxTextByteLength; }
// wide-char versions
void setWText(const LLWString& text);
const LLWString& getWText() const;
void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params());
void setLabel(const LLStringExplicit& label);
/*virtual*/ bool setLabelArg(const std::string& key, const LLStringExplicit& text) override;
const std::string& getLabel() { return mLabel.getString(); }
const LLWString& getWlabel() { return mLabel.getWString();}
void setLastSegmentToolTip(const std::string &tooltip);
/**
* If label is set, draws text label (which is LLLabelTextSegment)
* that is visible when no user text provided
*/
void resetLabel();
void setFont(const LLFontGL* font);
// force reflow of text
void needsReflow(S32 index = 0);
S32 getLength() const { return static_cast<S32>(getWText().length()); }
S32 getLineCount() const { return static_cast<S32>(mLineInfoList.size()); }
S32 removeFirstLine(); // returns removed length
void addDocumentChild(LLView* view);
void removeDocumentChild(LLView* view);
const LLView* getDocumentView() const { return mDocumentView; }
LLRect getVisibleTextRect() const { return mVisibleTextRect; }
LLRect getTextBoundingRect();
LLRect getVisibleDocumentRect() const;
S32 getVPad() { return mVPad; }
S32 getHPad() { return mHPad; }
F32 getLineSpacingMult() { return mLineSpacingMult; }
S32 getLineSpacingPixels() { return mLineSpacingPixels; } // only for multiline
S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, bool round, bool hit_past_end_of_line = true) const;
LLRect getLocalRectFromDocIndex(S32 pos) const;
LLRect getDocRectFromDocIndex(S32 pos) const;
void setReadOnly(bool read_only) { mReadOnly = read_only; }
bool getReadOnly() { return mReadOnly; }
void setSkipLinkUnderline(bool skip_link_underline) { mSkipLinkUnderline = skip_link_underline; }
bool getSkipLinkUnderline() { return mSkipLinkUnderline; }
void setParseURLs(bool parse_urls) { mParseHTML = parse_urls; }
void setPlainText(bool value) { mPlainText = value;}
bool getPlainText() const { return mPlainText; }
// cursor manipulation
bool setCursor(S32 row, S32 column);
bool setCursorPos(S32 cursor_pos, bool keep_cursor_offset = false);
void startOfLine();
void endOfLine();
void startOfDoc();
void endOfDoc();
void changePage( S32 delta );
void changeLine( S32 delta );
bool scrolledToStart();
bool scrolledToEnd();
const LLFontGL* getFont() const override { return mFont; }
virtual void appendLineBreakSegment(const LLStyle::Params& style_params);
virtual void appendImageSegment(const LLStyle::Params& style_params);
virtual void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);
boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb);
boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb);
boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb);
void setWordWrap(bool wrap);
LLScrollContainer* getScrollContainer() const { return mScroller; }
protected:
// protected member variables
// List of offsets and segment index of the start of each line. Always has at least one node (0).
struct line_info
{
line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num);
S32 mDocIndexStart;
S32 mDocIndexEnd;
LLRect mRect;
S32 mLineNum; // actual line count (ignoring soft newlines due to word wrap)
};
typedef std::vector<line_info> line_list_t;
// helper structs
struct compare_bottom
{
bool operator()(const S32& a, const line_info& b) const;
bool operator()(const line_info& a, const S32& b) const;
bool operator()(const line_info& a, const line_info& b) const;
};
struct compare_top
{
bool operator()(const S32& a, const line_info& b) const;
bool operator()(const line_info& a, const S32& b) const;
bool operator()(const line_info& a, const line_info& b) const;
};
struct line_end_compare;
typedef std::vector<LLTextSegmentPtr> segment_vec_t;
// Abstract inner base class representing an undoable editor command.
// Concrete sub-classes can be defined for operations such as insert, remove, etc.
// Used as arguments to the execute() method below.
class TextCmd
{
public:
TextCmd( S32 pos, bool group_with_next, LLTextSegmentPtr segment = LLTextSegmentPtr() )
: mPos(pos),
mGroupWithNext(group_with_next)
{
if (segment.notNull())
{
mSegments.push_back(segment);
}
}
virtual ~TextCmd() {}
virtual bool execute(LLTextBase* editor, S32* delta) = 0;
virtual S32 undo(LLTextBase* editor) = 0;
virtual S32 redo(LLTextBase* editor) = 0;
virtual bool canExtend(S32 pos) const { return false; }
virtual void blockExtensions() {}
virtual bool extendAndExecute( LLTextBase* editor, S32 pos, llwchar c, S32* delta ) { llassert(0); return 0; }
virtual bool hasExtCharValue( llwchar value ) const { return false; }
// Defined here so they can access protected LLTextEditor editing methods
S32 insert(LLTextBase* editor, S32 pos, const LLWString &wstr) { return editor->insertStringNoUndo( pos, wstr, &mSegments ); }
S32 remove(LLTextBase* editor, S32 pos, S32 length) { return editor->removeStringNoUndo( pos, length ); }
S32 overwrite(LLTextBase* editor, S32 pos, llwchar wc) { return editor->overwriteCharNoUndo(pos, wc); }
S32 getPosition() const { return mPos; }
bool groupWithNext() const { return mGroupWithNext; }
protected:
const S32 mPos;
bool mGroupWithNext;
segment_vec_t mSegments;
};
struct compare_segment_end
{
bool operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const;
};
typedef std::multiset<LLTextSegmentPtr, compare_segment_end> segment_set_t;
// member functions
LLTextBase(const Params &p);
virtual ~LLTextBase();
void initFromParams(const Params& p);
virtual void beforeValueChange();
virtual void onValueChange(S32 start, S32 end);
virtual bool useLabel() const;
// draw methods
virtual void drawSelectionBackground(); // draws the black box behind the selected text
void drawCursor();
void drawText();
// modify contents
S32 insertStringNoUndo(S32 pos, const LLWString &wstr, segment_vec_t* segments = NULL); // returns num of chars actually inserted
S32 removeStringNoUndo(S32 pos, S32 length);
S32 overwriteCharNoUndo(S32 pos, llwchar wc);
void appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& stylep, bool underline_on_hover_only = false);
// manage segments
void getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const;
void getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp );
LLTextSegmentPtr getSegmentAtLocalPos( S32 x, S32 y, bool hit_past_end_of_line = true);
segment_set_t::iterator getEditableSegIterContaining(S32 index);
segment_set_t::const_iterator getEditableSegIterContaining(S32 index) const;
segment_set_t::iterator getSegIterContaining(S32 index);
segment_set_t::const_iterator getSegIterContaining(S32 index) const;
void clearSegments();
void createDefaultSegment();
virtual void updateSegments();
void insertSegment(LLTextSegmentPtr segment_to_insert);
const LLStyle::Params& getStyleParams();
// manage lines
S32 getLineStart( S32 line ) const;
S32 getLineEnd( S32 line ) const;
S32 getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap = true) const;
S32 getLineOffsetFromDocIndex( S32 doc_index, bool include_wordwrap = true) const;
S32 getFirstVisibleLine() const;
std::pair<S32, S32> getVisibleLines(bool fully_visible = false);
S32 getLeftOffset(S32 width);
void reflow();
// cursor
void updateCursorXPos();
void setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool keep_cursor_offset=false );
S32 getEditableIndex(S32 index, bool increasing_direction); // constraint cursor to editable segments of document
void resetCursorBlink() { mCursorBlinkTimer.reset(); }
void updateScrollFromCursor();
// text selection
bool hasSelection() const { return (mSelectionStart !=mSelectionEnd); }
void startSelection();
void endSelection();
// misc
void updateRects();
void needsScroll() { mScrollNeeded = true; }
struct URLLabelCallback;
// Replace a URL with a new icon and label, for example, when
// avatar names are looked up.
void replaceUrl(const std::string &url, const std::string &label, const std::string& icon);
void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params());
void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false);
S32 normalizeUri(std::string& uri);
protected:
// virtual
std::string _getSearchText() const override
{
return mLabel.getString() + getToolTip();
}
std::vector<LLRect> getSelectionRects();
protected:
// text segmentation and flow
segment_set_t mSegments;
line_list_t mLineInfoList;
LLRect mVisibleTextRect; // The rect in which text is drawn. Excludes borders.
LLRect mTextBoundingRect;
// default text style
LLStyle::Params mStyle;
bool mStyleDirty;
const LLFontGL* mFont;
const LLFontGL::ShadowType mFontShadow;
// colors
LLUIColor mCursorColor;
LLUIColor mFgColor;
LLUIColor mReadOnlyFgColor;
LLUIColor mTentativeFgColor;
LLUIColor mWriteableBgColor;
LLUIColor mReadOnlyBgColor;
LLUIColor mFocusBgColor;
LLUIColor mTextSelectedColor;
LLUIColor mSelectedBGColor;
// cursor
S32 mCursorPos; // I-beam is just after the mCursorPos-th character.
S32 mDesiredXPixel; // X pixel position where the user wants the cursor to be
LLFrameTimer mCursorBlinkTimer; // timer that controls cursor blinking
// selection
S32 mSelectionStart;
S32 mSelectionEnd;
LLTimer mTripleClickTimer;
bool mIsSelecting; // Are we in the middle of a drag-select?
// spell checking
bool mSpellCheck;
S32 mSpellCheckStart;
S32 mSpellCheckEnd;
LLTimer mSpellCheckTimer;
std::list<std::pair<U32, U32> > mMisspellRanges;
std::vector<std::string> mSuggestionList;
// configuration
S32 mHPad; // padding on left of text
S32 mVPad; // padding above text
LLFontGL::HAlign mHAlign; // horizontal alignment of the document in its entirety
LLFontGL::VAlign mVAlign; // vertical alignment of the document in its entirety
LLFontGL::VAlign mTextVAlign; // vertical alignment of a text segment within a single line of text
F32 mLineSpacingMult; // multiple of line height used as space for a single line of text (e.g. 1.5 to get 50% padding)
S32 mLineSpacingPixels; // padding between lines
bool mBorderVisible;
bool mParseHTML; // make URLs interactive
bool mForceUrlsExternal; // URLs from this textbox will be opened in external browser
bool mParseHighlights; // highlight user-defined keywords
bool mWordWrap;
bool mUseEllipses;
bool mUseEmoji;
bool mUseColor;
bool mTrackEnd; // if true, keeps scroll position at end of document during resize
bool mReadOnly;
bool mBGVisible; // render background?
bool mClip; // clip text to widget rect
bool mClipPartial; // false if we show lines that are partially inside bounding rect
bool mTrustedContent; // if false, does not allow to execute SURL links from this editor
bool mPlainText; // didn't use Image or Icon segments
bool mAutoIndent;
S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
bool mSkipTripleClick;
bool mAlwaysShowIcons;
bool mSkipLinkUnderline;
// support widgets
LLHandle<LLContextMenu> mPopupMenuHandle;
LLView* mDocumentView;
LLScrollContainer* mScroller;
// transient state
S32 mReflowIndex; // index at which to start reflow. S32_MAX indicates no reflow needed.
bool mScrollNeeded; // need to change scroll region because of change to cursor position
S32 mScrollIndex; // index of first character to keep visible in scroll region
// Fired when a URL link is clicked
commit_signal_t* mURLClickSignal;
// Used to check if user with given ID is avatar's friend
is_friend_signal_t* mIsFriendSignal;
is_blocked_signal_t* mIsObjectBlockedSignal;
LLUIString mLabel; // text label that is visible when no user text provided
};
#endif
|