2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifndef GNASH_TEXTFIELD_H
20 #define GNASH_TEXTFIELD_H
22 #include <boost/intrusive_ptr.hpp>
27 #include "InteractiveObject.h" // for inheritance
28 #include "snappingrange.h"
29 #include "SWFRect.h" // for inlines
31 #include "RGBA.h" // for rgba
33 // Forward declarations
36 class DefineEditTextTag
;
47 ,std::char_traits
<wchar_t>
48 ,std::allocator
<wchar_t> >
55 /// An instance of a DefineEditTextTag
56 class DSOTEXPORT TextField
: public InteractiveObject
61 typedef std::vector
<size_t> LineStarts
;
63 /// Text alignment values
72 /// Text format display values
73 enum TextFormatDisplay
79 /// Possible autoSize values
82 /// Do not automatically resize TextField as text grow/shrink
85 /// Expand TextField, anchor the top-left side
88 /// Expand TextField, anchor the horizontal center
91 /// Expand TextField, anchor the top-right side
95 /// Possible type values
101 /// Do not accept input, text is only changed by variable name
102 /// or assigning to the .text member
105 /// Accept user input
109 /// Constructs a TextField as specified in a DefineEditText tag.
110 TextField(as_object
* object
, DisplayObject
* parent
,
111 const SWF::DefineEditTextTag
& def
);
113 /// Constructs a TextField with default values and the specified bounds.
115 /// Notably, the default textHeight is 12pt (240 twips).
116 /// @param parent A pointer to the DisplayObject parent of this TextField
117 /// @param bounds A SWFRect specifying the bounds of this TextField
118 TextField(as_object
* object
, DisplayObject
* parent
, SWFRect bounds
);
123 // TODO: should this return isSelectable() ?
124 /// Returns true for now, TextField is always "Mouse-Enabled"
125 bool mouseEnabled() const { return true; }
127 /// Returns a pointer to the topmost InteractiveObject at (x,y)
129 /// @param x x-coordinate
130 /// @param y y-coordinate
131 InteractiveObject
* topmostMouseEntity(std::int32_t x
, std::int32_t y
);
133 /// Return the version of the SWF this was parsed from.
135 /// TODO: work out what this means for dynamic TextFields.
136 virtual int getDefinitionVersion() const;
138 /// This function is called as a user-input handler
139 void mouseEvent(const event_id
& id
);
141 /// Handle user input from a key press.
142 void keyInput(key::code k
);
144 const std::string
& getVariableName() const
146 return _variable_name
;
149 /// Set the name of a variable associated to this
150 /// TextField's displayed text.
152 /// Calling this function will override any previous
153 /// setting for the variable name.
155 void set_variable_name(const std::string
& newname
);
157 /// \brief Set our text to the given string by effect of an update of a
158 /// registered variable name
160 /// This call only updates the text and is only meant to be called
161 /// by ourselves or by MovieClip when a registered TextVariable is
163 void updateText(const std::string
& s
);
165 /// Return value of our text.
166 std::string
get_text_value() const;
168 /// Return value of our htmlText.
169 std::string
get_htmltext_value() const;
171 /// Return true if text is defined
172 bool getTextDefined() const { return _textDefined
; }
174 size_t getCaretIndex() const {
178 /// Get a std::pair of size_t with start/end of selection
180 /// Both start and end should invariably be within the
181 /// range of the text.
182 const std::pair
<size_t, size_t>& getSelection() const {
186 /// Replace the current selection with the new text.
188 /// @param replace String to replace the current selection
189 void replaceSelection(const std::string
& replace
);
191 /// Set the current selection
193 /// @param start The index of the beginning of the selection.
194 /// @param end The index of the end of the selection.
196 /// If start is greater than end, the values are swapped, ensuring
197 /// end is never less than start.
198 void setSelection(int start
, int end
);
200 /// Override of DisplayObject::setWidth
202 /// TextField width currently behaves differently from MovieClip width
203 virtual void setWidth(double width
);
205 /// Override of DisplayObject::setHeight
207 /// TextField height currently behaves differently from MovieClip height
208 virtual void setHeight(double height
);
210 /// Draw the dynamic string.
211 virtual void display(Renderer
& renderer
, const Transform
& xform
);
213 void add_invalidated_bounds(InvalidatedRanges
& ranges
, bool force
);
215 /// Get bounding SWFRect of this TextField
216 virtual SWFRect
getBounds() const
221 // See dox in DisplayObject.h
222 bool pointInShape(std::int32_t x
, std::int32_t y
) const;
224 /// Return true if the 'background' should be drawn
225 bool getDrawBackground() const;
227 /// Specify whether to draw the background
229 /// @param draw If true the background of this TextField will be drawn
230 void setDrawBackground(bool draw
);
232 /// \brief Return color of the background
233 rgba
getBackgroundColor() const;
235 /// Set color of the background
237 /// Use setDrawBackground to actually use this value.
238 /// @param col RGBA Object with color information. TextField
239 /// background will be drawn in this color
240 void setBackgroundColor(const rgba
& col
);
242 /// Return true if this TextField should have its border visible
243 bool getDrawBorder() const;
245 /// Specify whether to draw the border
247 /// @param draw If true the border of this TextField will be drawn
248 void setDrawBorder(bool draw
);
250 /// Return color of the border
251 rgba
getBorderColor() const;
253 /// Set color of the border
255 /// Use setDrawBorder to actually use this value.
256 /// @param col RGBA Object with color information. TextField border
257 /// will be drawn in this color.
258 void setBorderColor(const rgba
& col
);
260 /// Return color of the text
261 const rgba
& getTextColor() const
266 /// Set color of the text
268 /// @param col RGBA Object with color information. Text in this TextField
269 /// will be displayed in this color.
270 void setTextColor(const rgba
& col
);
273 /// Return true if this TextField should use embedded font glyphs,
274 /// false if it should use device font glyphs
275 bool getEmbedFonts() const {
279 /// Get the current maxChars setting of the TextField
280 std::int32_t maxChars() const {
284 /// Set the current maxChars setting of the TextField
286 /// @param max The maximum number of characters that can be
287 /// input by the user (Does not restrict Scripts)
288 void maxChars(std::int32_t max
) {
292 /// Get the current multiline setting of the TextField
293 bool multiline() const {
297 /// Set the current multiline setting of the TextField
299 /// @param b If true "Enter" key will be recognized (Does not
300 /// restrict Scripts)
301 void multiline(bool b
) {
305 /// Get the current password setting of the TextField
306 bool password() const {
310 /// Set the current password setting of the TextField
312 /// @param b If true characters in the TextField will be displayed
314 void password(bool b
) {
318 /// Set whether this TextField should use embedded font glyphs,
319 /// or use device font glyphs
322 void setEmbedFonts(bool use
);
324 /// Get autoSize value
325 AutoSize
getAutoSize() const
330 /// Return text TextAlignment
331 TextAlignment
getTextAlignment();
333 /// Set autoSize value
336 /// The AutoSize to use
338 void setAutoSize(AutoSize val
);
340 /// Set type (input or dynamic)
343 /// The TypeValue to use, no-op if typeInvalid.
345 void setType(TypeValue val
) { if (val
!= typeInvalid
) _type
=val
; }
347 /// Get type (input, dynamic or invalid)
348 TypeValue
getType() const
353 /// Return true if this TextField is read-only
354 bool isReadOnly() const { return _type
!= typeInput
; }
356 /// Parse type string value
359 /// Type value as a string (one of input or dynamic)
361 /// @return an TypeValue identifier. typeInvalid if invalid.
363 static TypeValue
parseTypeValue(const std::string
& val
);
365 /// Return type value as a string
368 /// Type value (enum)
370 /// @return a C-string representation of the type value.
371 /// The returns is *never* NULL.
373 static const char* typeValueName(TypeValue val
);
376 /// Return true if text should continue to next available line
377 /// when hitting end of bounding box.
379 bool doWordWrap() const {
383 /// Set wordWrap parameter
386 /// If true text hitting bounding box limits will continue
388 /// If false, either text will be truncated or bounding box
389 /// expanded, depending on autoSize (see getAutoSize)
391 void setWordWrap(bool on
);
393 /// Return true if HTML markup in text should be rendered.
394 bool doHtml() const {
398 /// Set html parameter
401 /// If true HTML tags in the text will be parsed and rendered
402 void setHtml(bool on
) {
406 /// Return true if the TextField text is selectable
407 bool isSelectable() const
412 /// Set 'selectable' parameter
415 /// If true text in this TextField will be selectable
416 void setSelectable(bool v
)
421 // See DisplayObject::isActiveTextField
422 /// Return true if the TextField text is selectable
423 virtual bool isSelectableTextField() const
425 return isSelectable();
428 /// Remove this textfield from the stage
430 /// This is to implement TextField.removeTextField, will
431 /// basically forward the request to its parent.
432 /// Eventually this and MovieClip::removeMovieClip
433 /// will be merged in a single function to be later used
434 /// also for AS3 removeChild().
436 void removeTextField();
438 /// Set our font, return previously set one.
441 /// Will be stored in an intrusive_ptr
443 boost::intrusive_ptr
<const Font
> setFont(
444 boost::intrusive_ptr
<const Font
> newfont
);
446 const Font
* getFont() { return _font
.get(); }
449 std::uint16_t getFontHeight() const
454 void setFontHeight(std::uint16_t h
);
456 std::uint16_t getLeftMargin() const
461 void setLeftMargin(std::uint16_t h
);
463 std::uint16_t getRightMargin() const
468 void setRightMargin(std::uint16_t h
);
470 std::uint16_t getIndent() const
475 void setIndent(std::uint16_t h
);
477 std::uint16_t getBlockIndent() const
482 void setBlockIndent(std::uint16_t h
);
484 TextAlignment
getAlignment() const
489 void setAlignment(TextAlignment h
);
491 std::int16_t getLeading() const
496 void setLeading(std::int16_t h
);
498 bool getUnderlined() const
503 TextFormatDisplay
getDisplay() const
508 bool getBullet() const
513 const std::vector
<int>& getTabStops() const
518 bool isRestrict() const
520 return _restrictDefined
;
523 const std::string
& getRestrict() const
528 size_t getScroll() const
533 size_t getMaxScroll() const
538 size_t getHScroll() const
543 size_t getMaxHScroll() const
548 size_t getBottomScroll() const
550 return _bottomScroll
;
553 void setUnderlined(bool v
);
554 void setTabStops(const std::vector
<int>& tabStops
);
555 void setBullet(bool b
);
556 void setURL(std::string url
);
557 void setTarget(std::string target
);
558 void setRestrict(const std::string
& restrict
);
559 void setDisplay(TextFormatDisplay display
);
560 void setScroll(size_t scroll
) {
564 void setMaxScroll(size_t maxScroll
) {
565 _maxScroll
= maxScroll
;
568 void setHScroll(size_t hScroll
) {
572 void setMaxHScroll(size_t maxHScroll
) {
573 _maxHScroll
= maxHScroll
;
576 void setbottomScroll(size_t bottomScroll
) {
577 _bottomScroll
= bottomScroll
;
581 /// Returns the number of the record that the cursor is in
583 size_t cursorRecord();
585 void setTextFormat(TextFormat_as
& tf
);
587 const SWFRect
& getTextBoundingBox() const {
588 return m_text_bounding_box
;
591 /// Set our text to the given string.
593 /// This function will also update any registered variable
595 void setTextValue(const std::wstring
& wstr
);
601 /// \brief Set our text to the given string by effect of an update of a
602 /// registered variable name
604 /// This call only updates the text and is only meant to be called
605 /// by ourselves or by MovieClip when a registered TextVariable is
607 void updateText(const std::wstring
& s
);
609 void updateHtmlText(const std::wstring
& s
);
611 void insertTab(SWF::TextRecord
& rec
, std::int32_t& x
, float scale
);
613 /// What happens when setFocus() is called on this TextField.
615 /// @return true if focus was set. A TextField can always receive focus,
616 /// so this always returns true.
617 virtual bool handleFocus();
620 virtual void killFocus();
622 /// Call this function when willing to invoke the onChanged event handler
625 /// Reset our text bounding box to the given point.
626 void reset_bounding_box(std::int32_t x
, std::int32_t y
)
628 m_text_bounding_box
.set_to_point(x
, y
);
631 /// Convert the DisplayObjects in _text into a series of
632 /// text_glyph_records to be rendered.
635 /// Move viewable lines based on m_cursor
638 /// Handles a new line, this will be called several times, so this
639 /// will hopefully make code cleaner
640 void newLine(std::int32_t& x
, std::int32_t& y
,
641 SWF::TextRecord
& rec
, int& last_space_glyph
,
642 LineStarts::value_type
& last_line_start_record
, float div
);
644 /// De-reference and do appropriate action for character iterator
645 void handleChar(std::wstring::const_iterator
& it
,
646 const std::wstring::const_iterator
& e
, std::int32_t& x
,
647 std::int32_t& y
, SWF::TextRecord
& rec
, int& last_code
,
648 int& last_space_glyph
,
649 LineStarts::value_type
& last_line_start_record
);
651 /// Extracts an HTML tag.
653 /// @param tag This string is filled with the extracted HTML tag.
654 /// @param attributes This is a map of attribute names and values
655 /// @param it An iterator pointing to the first DisplayObject of the
656 /// HTML tag. It is left pointing to the DisplayObject after the
657 /// closing tag or the end of the string.
658 /// @param e An iterator pointing to the end of the string.
659 /// @return Whether the tag is complete or not (i.e. whether a '>'
661 bool parseHTML(std::wstring
& tag
,
662 std::map
<std::string
, std::string
>& attributes
,
663 std::wstring::const_iterator
& it
,
664 const std::wstring::const_iterator
& e
,
665 bool& selfclosing
) const;
667 /// Does LEFT/CENTER/RIGHT alignment on the records in
668 /// m_text_glyph_records[], starting with
669 /// last_line_start_record and going through the end of
670 /// m_text_glyph_records.
671 float align_line(TextAlignment align
, int last_line_start_record
, float x
);
673 /// Associate a variable to the text of this DisplayObject
675 /// Setting the associated variable actually changes the
676 /// displayed text. Getting the variable would return the
679 /// If the given variable already exist use it to set
680 /// current text before overriding it.
682 /// Since the variable target may be undefined at time
683 /// of instantiation of this EditText DisplayObject, the
684 /// class keeps track of wheter it succeeded registering
685 /// the variable and this function will do nothing in this
686 /// case. Thus it is safe to call it multiple time, using
687 /// an as-needed policy (will be called from get_text_value and
690 void registerTextVariable();
692 typedef std::pair
<as_object
*, ObjectURI
> VariableRef
;
695 /// Parse the given variable name
696 /// into sprite and a string_table::key components
698 VariableRef
parseTextVariableRef(const std::string
& variableName
) const;
700 /// Called in display(), sets the cursor using m_cursor and _textRecords
704 void show_cursor(Renderer
& renderer
, const SWFMatrix
& mat
);
706 /// The immutable definition of our TextField
708 /// This is NULL for dynamic TextFields.
709 boost::intrusive_ptr
<const SWF::DefineEditTextTag
> _tag
;
713 /// Because we have to deal with non-ascii DisplayObjects (129-255), this
714 /// is a wide string; the cursor position and the position within the
715 /// string are then the same, which makes manipulating the string much
719 /// The html representation of our text
721 std::wstring _htmlText
;
723 /// bounds of dynamic text, as laid out
724 SWFRect m_text_bounding_box
;
726 typedef std::vector
<SWF::TextRecord
> TextRecords
;
727 TextRecords _textRecords
;
729 std::vector
<size_t> _recordStarts
;
731 TextRecords _displayRecords
;
735 std::string _restrict
;
736 std::set
<wchar_t> _restrictedchars
;
737 TextFormatDisplay _display
;
738 std::vector
<int> _tabStops
;
739 LineStarts _line_starts
;
741 /// The text variable name
743 /// This is stored here, and not just in the definition,
744 /// because it can be changed programmatically, by setting
745 /// 'TextFields.variable'
746 std::string _variable_name
;
748 rgba _backgroundColor
;
754 TextAlignment _alignment
;
756 boost::intrusive_ptr
<const Font
> _font
;
763 size_t _bottomScroll
;
764 size_t _linesindisplay
;
766 /// Corresponds to the maxChars property.
773 /// Area in which the text is drawn.
775 /// This area encloses all the text, can be automatically
776 /// extended to fit text or hide text overflowing it.
777 /// See the setAutoSize() method to change that.
781 /// Represents the selected part of the text. The second element must
782 /// never be less than the first.
783 std::pair
<size_t, size_t> _selection
;
785 std::int16_t _leading
;
786 std::uint16_t _indent
;
788 /// Indentation for every line (including the ones created by
789 /// effect of a word-wrap.
790 std::uint16_t _blockIndent
;
792 std::uint16_t _leftMargin
;
794 std::uint16_t _rightMargin
;
796 std::uint16_t _fontHeight
;
798 /// This flag will be true as soon as the TextField
799 /// is assigned a text value. Only way to be false is
800 /// when definition has the hasText flag set to false
801 /// and no actionscript added text.
804 bool _restrictDefined
;
811 /// Corresponds to the multiline property.
814 /// Corresponds to the password property.
817 /// The flag keeping status of TextVariable registration
819 /// It will be set to true if there's no need to register
820 /// a text variable (ie. non-specified in the SWF)
822 bool _text_variable_registered
;
824 bool _drawBackground
;