summaryrefslogtreecommitdiff
path: root/indra/llui/lltextbase.h
blob: 6913374bac9254fb2a5d1ded7051e51feb7123a9 (plain)
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
/** 
 * @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 LLColor4&		getColor() const;
	//virtual void 				setColor(const LLColor4 &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			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 LLColor4& 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 LLColor4&		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 LLColor4& 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 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:
	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,
								spellcheck,
								allow_scroll,
								plain_text,
								wrap,
								use_ellipses,
								parse_urls,
								force_urls_external,
								parse_highlights,
								clip,
								clip_partial,
								trusted_content;
								
		Optional<S32>			v_pad,
								h_pad;


		Optional<LineSpacingParams>
								line_spacing;

		Optional<S32>			max_text_length;

		Optional<LLFontGL::ShadowType>	font_shadow;

		Params();
	};

	// 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		handleToolTip(S32 x, S32 y, MASK mask);

	// LLView interface
	/*virtual*/ void		reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
	/*virtual*/ void		draw();

	// LLUICtrl interface
	/*virtual*/ BOOL		acceptsTextInput() const { return !mReadOnly; }
	/*virtual*/ void		setColor( const LLColor4& c );
	virtual     void 		setReadOnlyColor(const LLColor4 &c);
	virtual	    void		onVisibilityChange( BOOL new_visibility );

	/*virtual*/ void		setValue(const LLSD& value );
	/*virtual*/ LLTextViewModel* getViewModel() const;

	// LLEditMenuHandler interface
	/*virtual*/ BOOL		canDeselect() const;
	/*virtual*/ void		deselect();

	virtual void	onFocusReceived();
	virtual void	onFocusLost();

	// LLSpellCheckMenuHandler overrides
	/*virtual*/ bool		getSpellCheck() const;

	/*virtual*/ const std::string& getSuggestion(U32 index) const;
	/*virtual*/ U32			getSuggestionCount() const;
	/*virtual*/ void		replaceWithSuggestion(U32 index);

	/*virtual*/ void		addToDictionary();
	/*virtual*/ bool		canAddToDictionary() const;

	/*virtual*/ void		addToIgnore();
	/*virtual*/ bool		canAddToIgnore() const;

	// 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() { return mWordWrap; }
	bool					getUseEllipses() { return mUseEllipses; }
	bool					truncate(); // returns true of truncation occurred

	bool					isContentTrusted() {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 std::string		getText() const;
	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 );

	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 getWText().length(); }
	S32						getLineCount() const { return 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; }

	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					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					{ 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:
	// 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;
	LLFontGL::VAlign			mVAlign;
	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						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

	// 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