diff options
Diffstat (limited to 'indra/llui/lltextbase.h')
-rw-r--r-- | indra/llui/lltextbase.h | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h new file mode 100644 index 0000000000..e5dfecad54 --- /dev/null +++ b/indra/llui/lltextbase.h @@ -0,0 +1,569 @@ +/** + * @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 "llstyle.h" +#include "llkeywords.h" +#include "llpanel.h" + +#include <string> +#include <vector> +#include <set> + +#include <boost/signals2.hpp> + +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(); + + virtual bool getDimensions(S32 first_char, S32 num_chars, S32& 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) const; + virtual void updateLayout(const class LLTextBase& editor); + virtual F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& 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*/ 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); + ~LLNormalTextSegment(); + + /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& 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) const; + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& 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, LLRect rect); + +protected: + class LLTextBase& mEditor; + LLStyleConstSP mStyle; + S32 mFontHeight; + LLKeywordToken* mToken; + std::string mTooltip; + boost::signals2::connection mImageLoadedConnection; +}; + +// 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 LLRect& 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 getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; + /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; + /*virtual*/ void updateLayout(const class LLTextBase& editor); + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& 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(); + bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; + S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; + F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); + +private: + S32 mFontHeight; +}; + +class LLImageTextSegment : public LLTextSegment +{ +public: + LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor); + ~LLImageTextSegment(); + bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; + S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; + F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); + +private: + class LLTextBase& mEditor; + LLStyleConstSP mStyle; +}; + +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: + friend class LLTextSegment; + friend class LLNormalTextSegment; + + struct LineSpacingParams : public LLInitParam::Choice<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, + 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, + allow_scroll, + plain_text, + wrap, + use_ellipses, + parse_urls, + parse_highlights, + clip_partial; + + 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 handleVisibilityChange( BOOL new_visibility ); + + /*virtual*/ void setValue(const LLSD& value ); + /*virtual*/ LLTextViewModel* getViewModel() const; + + // LLEditMenuHandler interface + /*virtual*/ BOOL canDeselect() const; + /*virtual*/ void deselect(); + + // used by LLTextSegment layout code + bool getWordWrap() { return mWordWrap; } + bool getUseEllipses() { return mUseEllipses; } + bool truncate(); // returns true of truncation occurred + + // 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; } + + // 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()); + // force reflow of text + void needsReflow(S32 index = 0); + + S32 getLength() const { return getWText().length(); } + S32 getLineCount() const { return mLineInfoList.size(); } + + void addDocumentChild(LLView* view); + void removeDocumentChild(LLView* view); + const LLView* getDocumentView() const { return mDocumentView; } + LLRect getVisibleTextRect() { 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* getDefaultFont() const { return mDefaultFont; } + + 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); + +protected: + // helper structs + struct compare_bottom; + struct compare_top; + 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; + + // 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; + + // member functions + LLTextBase(const Params &p); + virtual ~LLTextBase(); + void initFromParams(const Params& p); + virtual void onValueChange(S32 start, S32 end); + + // draw methods + 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 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& getDefaultStyleParams(); + + // 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; } + void replaceUrlLabel(const std::string &url, const std::string &label); + + 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); + + +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 mDefaultStyle; + bool mStyleDirty; + const LLFontGL* const mDefaultFont; // font that is used when none specified, can only be set by constructor + const LLFontGL::ShadowType mFontShadow; // shadow style, can only be set by constructor + + // colors + LLUIColor mCursorColor; + LLUIColor mFgColor; + LLUIColor mReadOnlyFgColor; + 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; + + BOOL mIsSelecting; // Are we in the middle of a drag-select? + + // 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 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 mClipPartial; // false if we show lines that are partially inside bounding rect + bool mPlainText; // didn't use Image or Icon segments + S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes + + // support widgets + LLContextMenu* mPopupMenu; + LLView* mDocumentView; + class 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; + +}; + +#endif |