2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
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 "LineStyle.h" // for LineStyle
29 #include "snappingrange.h"
30 #include "SWFRect.h" // for inlines
32 // Forward declarations
35 class DefineEditTextTag
;
44 /// An instance of a DefineEditTextTag
45 class TextField
: public InteractiveObject
50 typedef std::vector
<size_t> LineStarts
;
52 /// Text alignment values
61 /// Text format display values
62 enum TextFormatDisplay
68 /// Possible autoSize values
71 /// Do not automatically resize TextField as text grow/shrink
74 /// Expand TextField, anchor the top-left side
77 /// Expand TextField, anchor the horizontal center
80 /// Expand TextField, anchor the top-right side
84 /// Possible type values
90 /// Do not accept input, text is only changed by variable name
91 /// or assigning to the .text member
98 /// Constructs a TextField as specified in a DefineEditText tag.
99 TextField(as_object
* object
, DisplayObject
* parent
,
100 const SWF::DefineEditTextTag
& def
);
102 /// Constructs a TextField with default values and the specified bounds.
104 /// Notably, the default textHeight is 12pt (240 twips).
105 /// @param parent A pointer to the DisplayObject parent of this TextField
106 /// @param bounds A SWFRect specifying the bounds of this TextField
107 TextField(as_object
* object
, DisplayObject
* parent
, const SWFRect
& bounds
);
112 // TODO: should this return isSelectable() ?
113 /// Returns true for now, TextField is always "Mouse-Enabled"
114 bool mouseEnabled() const { return true; }
116 /// Returns a pointer to the topmost InteractiveObject at (x,y)
118 /// @param x x-coordinate
119 /// @param y y-coordinate
120 InteractiveObject
* topmostMouseEntity(boost::int32_t x
, boost::int32_t y
);
122 /// Return the version of the SWF this was parsed from.
124 /// TODO: work out what this means for dynamic TextFields.
125 virtual int getDefinitionVersion() const;
127 /// This function is called as a user-input handler
128 void notifyEvent(const event_id
& id
);
130 const std::string
& getVariableName() const
132 return _variable_name
;
135 /// Set the name of a variable associated to this
136 /// TextField's displayed text.
138 /// Calling this function will override any previous
139 /// setting for the variable name.
141 void set_variable_name(const std::string
& newname
);
143 /// \brief Set our text to the given string by effect of an update of a
144 /// registered variable name
146 /// This call only updates the text and is only meant to be called
147 /// by ourselves or by MovieClip when a registered TextVariable is
149 void updateText(const std::string
& s
);
151 /// Return value of our text.
152 std::string
get_text_value() const;
154 /// Return value of our htmlText.
155 std::string
get_htmltext_value() const;
157 /// Return true if text is defined
158 bool getTextDefined() const { return _textDefined
; }
160 size_t getCaretIndex() const {
164 /// Get a std::pair of size_t with start/end of selection
166 /// Both start and end should invariably be within the
167 /// range of the text.
168 const std::pair
<size_t, size_t>& getSelection() const {
172 /// Replace the current selection with the new text.
174 /// @param replace String to replace the current selection
175 void replaceSelection(const std::string
& replace
);
177 /// Set the current selection
179 /// @param start The index of the beginning of the selection.
180 /// @param end The index of the end of the selection.
182 /// If start is greater than end, the values are swapped, ensuring
183 /// end is never less than start.
184 void setSelection(int start
, int end
);
186 /// Override of DisplayObject::setWidth
188 /// TextField width currently behaves differently from MovieClip width
189 virtual void setWidth(double width
);
191 /// Override of DisplayObject::setHeight
193 /// TextField height currently behaves differently from MovieClip height
194 virtual void setHeight(double height
);
196 /// Draw the dynamic string.
197 virtual void display(Renderer
& renderer
, const Transform
& xform
);
199 void add_invalidated_bounds(InvalidatedRanges
& ranges
, bool force
);
201 /// Get bounding SWFRect of this TextField
202 virtual SWFRect
getBounds() const
207 // See dox in DisplayObject.h
208 bool pointInShape(boost::int32_t x
, boost::int32_t y
) const;
210 /// Return true if the 'background' should be drawn
211 bool getDrawBackground() const;
213 /// Specify whether to draw the background
215 /// @param draw If true the background of this TextField will be drawn
216 void setDrawBackground(bool draw
);
218 /// \brief Return color of the background
219 rgba
getBackgroundColor() const;
221 /// Set color of the background
223 /// Use setDrawBackground to actually use this value.
224 /// @param col RGBA Object with color information. TextField
225 /// background will be drawn in this color
226 void setBackgroundColor(const rgba
& col
);
228 /// Return true if this TextField should have its border visible
229 bool getDrawBorder() const;
231 /// Specify whether to draw the border
233 /// @param draw If true the border of this TextField will be drawn
234 void setDrawBorder(bool draw
);
236 /// Return color of the border
237 rgba
getBorderColor() const;
239 /// Set color of the border
241 /// Use setDrawBorder to actually use this value.
242 /// @param col RGBA Object with color information. TextField border
243 /// will be drawn in this color.
244 void setBorderColor(const rgba
& col
);
246 /// Return color of the text
247 const rgba
& getTextColor() const
252 /// Set color of the text
254 /// @param col RGBA Object with color information. Text in this TextField
255 /// will be displayed in this color.
256 void setTextColor(const rgba
& col
);
259 /// Return true if this TextField should use embedded font glyphs,
260 /// false if it should use device font glyphs
261 bool getEmbedFonts() const {
265 /// Get the current maxChars setting of the TextField
266 boost::int32_t maxChars() const {
270 /// Set the current maxChars setting of the TextField
272 /// @param max The maximum number of characters that can be
273 /// input by the user (Does not restrict Scripts)
274 void maxChars(boost::int32_t max
) {
278 /// Get the current multiline setting of the TextField
279 bool multiline() const {
283 /// Set the current multiline setting of the TextField
285 /// @param b If true "Enter" key will be recognized (Does not
286 /// restrict Scripts)
287 void multiline(bool b
) {
291 /// Get the current password setting of the TextField
292 bool password() const {
296 /// Set the current password setting of the TextField
298 /// @param b If true characters in the TextField will be displayed
300 void password(bool b
) {
304 /// Set whether this TextField should use embedded font glyphs,
305 /// or use device font glyphs
308 void setEmbedFonts(bool use
);
310 /// Get autoSize value
311 AutoSize
getAutoSize() const
316 /// Return text TextAlignment
317 TextAlignment
getTextAlignment();
319 /// Set autoSize value
322 /// The AutoSize to use
324 void setAutoSize(AutoSize val
);
326 /// Set type (input or dynamic)
329 /// The TypeValue to use, no-op if typeInvalid.
331 void setType(TypeValue val
) { if (val
!= typeInvalid
) _type
=val
; }
333 /// Get type (input, dynamic or invalid)
334 TypeValue
getType() const
339 /// Return true if this TextField is read-only
340 bool isReadOnly() const { return _type
!= typeInput
; }
342 /// Parse type string value
345 /// Type value as a string (one of input or dynamic)
347 /// @return an TypeValue identifier. typeInvalid if invalid.
349 static TypeValue
parseTypeValue(const std::string
& val
);
351 /// Return type value as a string
354 /// Type value (enum)
356 /// @return a C-string representation of the type value.
357 /// The returns is *never* NULL.
359 static const char* typeValueName(TypeValue val
);
362 /// Return true if text should continue to next available line
363 /// when hitting end of bounding box.
365 bool doWordWrap() const {
369 /// Set wordWrap parameter
372 /// If true text hitting bounding box limits will continue
374 /// If false, either text will be truncated or bounding box
375 /// expanded, depending on autoSize (see getAutoSize)
377 void setWordWrap(bool on
);
379 /// Return true if HTML markup in text should be rendered.
380 bool doHtml() const {
384 /// Set html parameter
387 /// If true HTML tags in the text will be parsed and rendered
388 void setHtml(bool on
) {
392 /// Return true if the TextField text is selectable
393 bool isSelectable() const
398 /// Set 'selectable' parameter
401 /// If true text in this TextField will be selectable
402 void setSelectable(bool v
)
407 // See DisplayObject::isActiveTextField
408 /// Return true if the TextField text is selectable
409 virtual bool isSelectableTextField() const
411 return isSelectable();
414 /// Remove this textfield from the stage
416 /// This is to implement TextField.removeTextField, will
417 /// basically forward the request to its parent.
418 /// Eventually this and MovieClip::removeMovieClip
419 /// will be merged in a single function to be later used
420 /// also for AS3 removeChild().
422 void removeTextField();
424 /// Set our font, return previously set one.
427 /// Will be stored in an intrusive_ptr
429 boost::intrusive_ptr
<const Font
> setFont(
430 boost::intrusive_ptr
<const Font
> newfont
);
432 const Font
* getFont() { return _font
.get(); }
435 boost::uint16_t getFontHeight() const
440 void setFontHeight(boost::uint16_t h
);
442 boost::uint16_t getLeftMargin() const
447 void setLeftMargin(boost::uint16_t h
);
449 boost::uint16_t getRightMargin() const
454 void setRightMargin(boost::uint16_t h
);
456 boost::uint16_t getIndent() const
461 void setIndent(boost::uint16_t h
);
463 boost::uint16_t getBlockIndent() const
468 void setBlockIndent(boost::uint16_t h
);
470 TextAlignment
getAlignment() const
475 void setAlignment(TextAlignment h
);
477 boost::int16_t getLeading() const
482 void setLeading(boost::int16_t h
);
484 bool getUnderlined() const
489 TextFormatDisplay
getDisplay() const
494 bool getBullet() const
499 const std::vector
<int>& getTabStops() const
504 bool isRestrict() const
506 return _restrictDefined
;
509 const std::string
& getRestrict() const
514 size_t getScroll() const
519 size_t getMaxScroll() const
524 size_t getHScroll() const
529 size_t getMaxHScroll() const
534 size_t getBottomScroll() const
536 return _bottomScroll
;
539 void setUnderlined(bool v
);
540 void setTabStops(const std::vector
<int>& tabStops
);
541 void setBullet(bool b
);
542 void setURL(std::string url
);
543 void setTarget(std::string target
);
544 void setRestrict(const std::string
& restrict
);
545 void setDisplay(TextFormatDisplay display
);
546 void setScroll(size_t scroll
) {
550 void setMaxScroll(size_t maxScroll
) {
551 _maxScroll
= maxScroll
;
554 void setHScroll(size_t hScroll
) {
558 void setMaxHScroll(size_t maxHScroll
) {
559 _maxHScroll
= maxHScroll
;
562 void setbottomScroll(size_t bottomScroll
) {
563 _bottomScroll
= bottomScroll
;
567 /// Returns the number of the record that the cursor is in
569 size_t cursorRecord();
571 void setTextFormat(TextFormat_as
& tf
);
573 const SWFRect
& getTextBoundingBox() const {
574 return m_text_bounding_box
;
577 /// Set our text to the given string.
579 /// This function will also update any registered variable
581 void setTextValue(const std::wstring
& wstr
);
587 /// \brief Set our text to the given string by effect of an update of a
588 /// registered variable name
590 /// This call only updates the text and is only meant to be called
591 /// by ourselves or by MovieClip when a registered TextVariable is
593 void updateText(const std::wstring
& s
);
595 void updateHtmlText(const std::wstring
& s
);
597 void insertTab(SWF::TextRecord
& rec
, boost::int32_t& x
, float scale
);
599 /// What happens when setFocus() is called on this TextField.
601 /// @return true if focus was set. A TextField can always receive focus,
602 /// so this always returns true.
603 virtual bool handleFocus();
606 virtual void killFocus();
608 /// Call this function when willing to invoke the onChanged event handler
611 /// Reset our text bounding box to the given point.
612 void reset_bounding_box(boost::int32_t x
, boost::int32_t y
)
614 m_text_bounding_box
.set_to_point(x
, y
);
617 /// Convert the DisplayObjects in _text into a series of
618 /// text_glyph_records to be rendered.
621 /// Move viewable lines based on m_cursor
624 /// Handles a new line, this will be called several times, so this
625 /// will hopefully make code cleaner
626 void newLine(boost::int32_t& x
, boost::int32_t& y
,
627 SWF::TextRecord
& rec
, int& last_space_glyph
,
628 LineStarts::value_type
& last_line_start_record
, float div
);
630 /// De-reference and do appropriate action for character iterator
631 void handleChar(std::wstring::const_iterator
& it
,
632 const std::wstring::const_iterator
& e
, boost::int32_t& x
,
633 boost::int32_t& y
, SWF::TextRecord
& rec
, int& last_code
,
634 int& last_space_glyph
,
635 LineStarts::value_type
& last_line_start_record
);
637 /// Extracts an HTML tag.
639 /// @param tag This string is filled with the extracted HTML tag.
640 /// @param attributes This is a map of attribute names and values
641 /// @param it An iterator pointing to the first DisplayObject of the
642 /// HTML tag. It is left pointing to the DisplayObject after the
643 /// closing tag or the end of the string.
644 /// @param e An iterator pointing to the end of the string.
645 /// @return Whether the tag is complete or not (i.e. whether a '>'
647 bool parseHTML(std::wstring
& tag
,
648 std::map
<std::string
, std::string
>& attributes
,
649 std::wstring::const_iterator
& it
,
650 const std::wstring::const_iterator
& e
,
651 bool& selfclosing
) const;
653 /// Does LEFT/CENTER/RIGHT alignment on the records in
654 /// m_text_glyph_records[], starting with
655 /// last_line_start_record and going through the end of
656 /// m_text_glyph_records.
657 float align_line(TextAlignment align
, int last_line_start_record
, float x
);
659 /// Associate a variable to the text of this DisplayObject
661 /// Setting the associated variable actually changes the
662 /// displayed text. Getting the variable would return the
665 /// If the given variable already exist use it to set
666 /// current text before overriding it.
668 /// Since the variable target may be undefined at time
669 /// of instantiation of this EditText DisplayObject, the
670 /// class keeps track of wheter it succeeded registering
671 /// the variable and this function will do nothing in this
672 /// case. Thus it is safe to call it multiple time, using
673 /// an as-needed policy (will be called from get_text_value and
676 void registerTextVariable();
678 typedef std::pair
<as_object
*, ObjectURI
> VariableRef
;
681 /// Parse the given variable name
682 /// into sprite and a string_table::key components
684 VariableRef
parseTextVariableRef(const std::string
& variableName
) const;
686 /// Called in display(), sets the cursor using m_cursor and _textRecords
690 void show_cursor(Renderer
& renderer
, const SWFMatrix
& mat
);
692 /// The immutable definition of our TextField
694 /// This is NULL for dynamic TextFields.
695 boost::intrusive_ptr
<const SWF::DefineEditTextTag
> _tag
;
699 /// Because we have to deal with non-ascii DisplayObjects (129-255), this
700 /// is a wide string; the cursor position and the position within the
701 /// string are then the same, which makes manipulating the string much
705 /// The html representation of our text
707 std::wstring _htmlText
;
709 /// bounds of dynamic text, as laid out
710 SWFRect m_text_bounding_box
;
712 typedef std::vector
<SWF::TextRecord
> TextRecords
;
713 TextRecords _textRecords
;
715 std::vector
<size_t> _recordStarts
;
717 TextRecords _displayRecords
;
721 std::string _restrict
;
722 std::set
<wchar_t> _restrictedchars
;
723 TextFormatDisplay _display
;
724 std::vector
<int> _tabStops
;
725 LineStarts _line_starts
;
727 /// The text variable name
729 /// This is stored here, and not just in the definition,
730 /// because it can be changed programmatically, by setting
731 /// 'TextFields.variable'
732 std::string _variable_name
;
734 rgba _backgroundColor
;
740 TextAlignment _alignment
;
742 boost::intrusive_ptr
<const Font
> _font
;
749 size_t _bottomScroll
;
750 size_t _linesindisplay
;
752 /// Corresponds to the maxChars property.
759 /// Area in which the text is drawn.
761 /// This area encloses all the text, can be automatically
762 /// extended to fit text or hide text overflowing it.
763 /// See the setAutoSize() method to change that.
767 /// Represents the selected part of the text. The second element must
768 /// never be less than the first.
769 std::pair
<size_t, size_t> _selection
;
771 boost::int16_t _leading
;
772 boost::uint16_t _indent
;
774 /// Indentation for every line (including the ones created by
775 /// effect of a word-wrap.
776 boost::uint16_t _blockIndent
;
778 boost::uint16_t _leftMargin
;
780 boost::uint16_t _rightMargin
;
782 boost::uint16_t _fontHeight
;
784 /// This flag will be true as soon as the TextField
785 /// is assigned a text value. Only way to be false is
786 /// when definition has the hasText flag set to false
787 /// and no actionscript added text.
790 bool _restrictDefined
;
797 /// Corresponds to the multiline property.
800 /// Corresponds to the password property.
803 /// The flag keeping status of TextVariable registration
805 /// It will be set to true if there's no need to register
806 /// a text variable (ie. non-specified in the SWF)
808 bool _text_variable_registered
;
810 bool _drawBackground
;