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 "InteractiveObject.h" // for inheritance
23 #include "LineStyle.h" // for LineStyle
24 #include "snappingrange.h"
25 #include "SWFRect.h" // for inlines
27 #include <boost/intrusive_ptr.hpp>
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 void updateHtmlText(const std::string
& s
);
153 /// Return value of our text.
154 std::string
get_text_value() const;
156 /// Return value of our htmlText.
157 std::string
get_htmltext_value() const;
159 /// Return true if text is defined
160 bool getTextDefined() const { return _textDefined
; }
162 size_t getCaretIndex() const {
166 /// Get a std::pair of size_t with start/end of selection
167 const std::pair
<size_t, size_t>& getSelection() const {
171 /// Replace the current selection with the new text.
173 /// @param replace String to replace the current selection
174 void replaceSelection(const std::string
& replace
);
176 /// Set the current selection
178 /// @param start The index of the beginning of the selection.
179 /// @param end The index of the end of the selection.
181 /// If start is greater than end, the values are swapped, ensuring
182 /// end is never less than start.
183 void setSelection(int start
, int end
);
185 /// Override of DisplayObject::setWidth
187 /// TextField width currently behaves differently from MovieClip width
188 virtual void setWidth(double width
);
190 /// Override of DisplayObject::setHeight
192 /// TextField height currently behaves differently from MovieClip height
193 virtual void setHeight(double height
);
195 /// Draw the dynamic string.
196 virtual void display(Renderer
& renderer
, const Transform
& xform
);
198 void add_invalidated_bounds(InvalidatedRanges
& ranges
, bool force
);
200 /// Get bounding SWFRect of this TextField
201 virtual SWFRect
getBounds() const
206 // See dox in DisplayObject.h
207 bool pointInShape(boost::int32_t x
, boost::int32_t y
) const;
209 /// Return true if the 'background' should be drawn
210 bool getDrawBackground() const;
212 /// Specify whether to draw the background
214 /// @param draw If true the background of this TextField will be drawn
215 void setDrawBackground(bool draw
);
217 /// \brief Return color of the background
218 rgba
getBackgroundColor() const;
220 /// Set color of the background
222 /// Use setDrawBackground to actually use this value.
223 /// @param col RGBA Object with color information. TextField
224 /// background will be drawn in this color
225 void setBackgroundColor(const rgba
& col
);
227 /// Return true if this TextField should have its border visible
228 bool getDrawBorder() const;
230 /// Specify whether to draw the border
232 /// @param draw If true the border of this TextField will be drawn
233 void setDrawBorder(bool draw
);
235 /// Return color of the border
236 rgba
getBorderColor() const;
238 /// Set color of the border
240 /// Use setDrawBorder to actually use this value.
241 /// @param col RGBA Object with color information. TextField border
242 /// will be drawn in this color.
243 void setBorderColor(const rgba
& col
);
245 /// Return color of the text
246 const rgba
& getTextColor() const
251 /// Set color of the text
253 /// @param col RGBA Object with color information. Text in this TextField
254 /// will be displayed in this color.
255 void setTextColor(const rgba
& col
);
258 /// Return true if this TextField should use embedded font glyphs,
259 /// false if it should use device font glyphs
260 bool getEmbedFonts() const {
264 /// Get the current maxChars setting of the TextField
265 boost::int32_t maxChars() const {
269 /// Set the current maxChars setting of the TextField
271 /// @param max The maximum number of characters that can be
272 /// input by the user (Does not restrict Scripts)
273 void maxChars(boost::int32_t max
) {
277 /// Get the current multiline setting of the TextField
278 bool multiline() const {
282 /// Set the current multiline setting of the TextField
284 /// @param b If true "Enter" key will be recognized (Does not
285 /// restrict Scripts)
286 void multiline(bool b
) {
290 /// Get the current password setting of the TextField
291 bool password() const {
295 /// Set the current password setting of the TextField
297 /// @param b If true characters in the TextField will be displayed
299 void password(bool b
) {
303 /// Set whether this TextField should use embedded font glyphs,
304 /// or use device font glyphs
307 void setEmbedFonts(bool use
);
309 /// Get autoSize value
310 AutoSize
getAutoSize() const
315 /// Return text TextAlignment
316 TextAlignment
getTextAlignment();
318 /// Set autoSize value
321 /// The AutoSize to use
323 void setAutoSize(AutoSize val
);
325 /// Set type (input or dynamic)
328 /// The TypeValue to use, no-op if typeInvalid.
330 void setType(TypeValue val
) { if (val
!= typeInvalid
) _type
=val
; }
332 /// Get type (input, dynamic or invalid)
333 TypeValue
getType() const
338 /// Return true if this TextField is read-only
339 bool isReadOnly() const { return _type
!= typeInput
; }
341 /// Parse type string value
344 /// Type value as a string (one of input or dynamic)
346 /// @return an TypeValue identifier. typeInvalid if invalid.
348 static TypeValue
parseTypeValue(const std::string
& val
);
350 /// Return type value as a string
353 /// Type value (enum)
355 /// @return a C-string representation of the type value.
356 /// The returns is *never* NULL.
358 static const char* typeValueName(TypeValue val
);
361 /// Return true if text should continue to next available line
362 /// when hitting end of bounding box.
364 bool doWordWrap() const {
368 /// Set wordWrap parameter
371 /// If true text hitting bounding box limits will continue
373 /// If false, either text will be truncated or bounding box
374 /// expanded, depending on autoSize (see getAutoSize)
376 void setWordWrap(bool on
);
378 /// Return true if HTML markup in text should be rendered.
379 bool doHtml() const {
383 /// Set html parameter
386 /// If true HTML tags in the text will be parsed and rendered
387 void setHtml(bool on
) {
391 /// Return true if the TextField text is selectable
392 bool isSelectable() const
397 /// Set 'selectable' parameter
400 /// If true text in this TextField will be selectable
401 void setSelectable(bool v
)
406 // See DisplayObject::isActiveTextField
407 /// Return true if the TextField text is selectable
408 virtual bool isSelectableTextField() const
410 return isSelectable();
413 /// Remove this textfield from the stage
415 /// This is to implement TextField.removeTextField, will
416 /// basically forward the request to its parent.
417 /// Eventually this and MovieClip::removeMovieClip
418 /// will be merged in a single function to be later used
419 /// also for AS3 removeChild().
421 void removeTextField();
423 /// Set our font, return previously set one.
426 /// Will be stored in an intrusive_ptr
428 boost::intrusive_ptr
<const Font
> setFont(
429 boost::intrusive_ptr
<const Font
> newfont
);
431 const Font
* getFont() { return _font
.get(); }
434 boost::uint16_t getFontHeight() const
439 void setFontHeight(boost::uint16_t h
);
441 boost::uint16_t getLeftMargin() const
446 void setLeftMargin(boost::uint16_t h
);
448 boost::uint16_t getRightMargin() const
453 void setRightMargin(boost::uint16_t h
);
455 boost::uint16_t getIndent() const
460 void setIndent(boost::uint16_t h
);
462 boost::uint16_t getBlockIndent() const
467 void setBlockIndent(boost::uint16_t h
);
469 TextAlignment
getAlignment() const
474 void setAlignment(TextAlignment h
);
476 boost::int16_t getLeading() const
481 void setLeading(boost::int16_t h
);
483 bool getUnderlined() const
488 TextFormatDisplay
getDisplay() const
493 bool getBullet() const
498 const std::vector
<int>& getTabStops() const
503 bool isRestrict() const
505 return _restrictDefined
;
508 const std::string
& getRestrict() const
513 size_t getScroll() const
518 size_t getMaxScroll() const
523 size_t getHScroll() const
528 size_t getMaxHScroll() const
533 size_t getBottomScroll() const
535 return _bottomScroll
;
538 void setUnderlined(bool v
);
539 void setTabStops(const std::vector
<int>& tabStops
);
540 void setBullet(bool b
);
541 void setURL(std::string url
);
542 void setTarget(std::string target
);
543 void setRestrict(const std::string
& restrict
);
544 void setDisplay(TextFormatDisplay display
);
545 void setScroll(size_t scroll
) {
549 void setMaxScroll(size_t maxScroll
) {
550 _maxScroll
= maxScroll
;
553 void setHScroll(size_t hScroll
) {
557 void setMaxHScroll(size_t maxHScroll
) {
558 _maxHScroll
= maxHScroll
;
561 void setbottomScroll(size_t bottomScroll
) {
562 _bottomScroll
= bottomScroll
;
566 /// Returns the number of the record that the cursor is in
568 size_t cursorRecord();
570 void setTextFormat(TextFormat_as
& tf
);
572 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
);
583 /// Set our htmlText to the given string.
585 void setHtmlTextValue(const std::wstring
& wstr
);
591 /// \brief Set our text to the given string by effect of an update of a
592 /// registered variable name
594 /// This call only updates the text and is only meant to be called
595 /// by ourselves or by MovieClip when a registered TextVariable is
597 void updateText(const std::wstring
& s
);
599 void updateHtmlText(const std::wstring
& s
);
601 void insertTab(SWF::TextRecord
& rec
, boost::int32_t& x
, float scale
);
603 /// What happens when setFocus() is called on this TextField.
605 /// @return true if focus was set. A TextField can always receive focus,
606 /// so this always returns true.
607 virtual bool handleFocus();
610 virtual void killFocus();
612 /// Call this function when willing to invoke the onChanged event handler
615 /// Reset our text bounding box to the given point.
616 void reset_bounding_box(boost::int32_t x
, boost::int32_t y
)
618 m_text_bounding_box
.set_to_point(x
, y
);
621 /// Convert the DisplayObjects in _text into a series of
622 /// text_glyph_records to be rendered.
625 /// Move viewable lines based on m_cursor
628 /// Handles a new line, this will be called several times, so this
629 /// will hopefully make code cleaner
630 void newLine(boost::int32_t& x
, boost::int32_t& y
,
631 SWF::TextRecord
& rec
, int& last_space_glyph
,
632 LineStarts::value_type
& last_line_start_record
, float div
);
634 /// De-reference and do appropriate action for character iterator
635 void handleChar(std::wstring::const_iterator
& it
,
636 const std::wstring::const_iterator
& e
, boost::int32_t& x
,
637 boost::int32_t& y
, SWF::TextRecord
& rec
, int& last_code
,
638 int& last_space_glyph
,
639 LineStarts::value_type
& last_line_start_record
);
641 /// Extracts an HTML tag.
643 /// @param tag This string is filled with the extracted HTML tag.
644 /// @param attributes This is a map of attribute names and values
645 /// @param it An iterator pointing to the first DisplayObject of the
646 /// HTML tag. It is left pointing to the DisplayObject after the
647 /// closing tag or the end of the string.
648 /// @param e An iterator pointing to the end of the string.
649 /// @return Whether the tag is complete or not (i.e. whether a '>'
651 bool parseHTML(std::wstring
& tag
,
652 std::map
<std::string
, std::string
>& attributes
,
653 std::wstring::const_iterator
& it
,
654 const std::wstring::const_iterator
& e
,
655 bool& selfclosing
) const;
657 /// Does LEFT/CENTER/RIGHT alignment on the records in
658 /// m_text_glyph_records[], starting with
659 /// last_line_start_record and going through the end of
660 /// m_text_glyph_records.
661 float align_line(TextAlignment align
, int last_line_start_record
, float x
);
663 /// Associate a variable to the text of this DisplayObject
665 /// Setting the associated variable actually changes the
666 /// displayed text. Getting the variable would return the
669 /// If the given variable already exist use it to set
670 /// current text before overriding it.
672 /// Since the variable target may be undefined at time
673 /// of instantiation of this EditText DisplayObject, the
674 /// class keeps track of wheter it succeeded registering
675 /// the variable and this function will do nothing in this
676 /// case. Thus it is safe to call it multiple time, using
677 /// an as-needed policy (will be called from get_text_value and
680 void registerTextVariable();
682 typedef std::pair
<as_object
*, string_table::key
> VariableRef
;
685 /// Parse the given variable name
686 /// into sprite and a string_table::key components
688 VariableRef
parseTextVariableRef(const std::string
& variableName
) const;
690 /// Called in display(), sets the cursor using m_cursor and _textRecords
694 void show_cursor(Renderer
& renderer
, const SWFMatrix
& mat
);
696 /// The immutable definition of our TextField
698 /// This is NULL for dynamic TextFields.
699 boost::intrusive_ptr
<const SWF::DefineEditTextTag
> _tag
;
703 /// Because we have to deal with non-ascii DisplayObjects (129-255), this
704 /// is a wide string; the cursor position and the position within the
705 /// string are then the same, which makes manipulating the string much
709 /// The html representation of our text
711 std::wstring _htmlText
;
713 /// bounds of dynamic text, as laid out
714 SWFRect m_text_bounding_box
;
716 typedef std::vector
<SWF::TextRecord
> TextRecords
;
717 TextRecords _textRecords
;
719 std::vector
<size_t> _recordStarts
;
721 TextRecords _displayRecords
;
725 std::string _restrict
;
726 std::set
<wchar_t> _restrictedchars
;
727 TextFormatDisplay _display
;
728 std::vector
<int> _tabStops
;
729 LineStarts _line_starts
;
731 /// The text variable name
733 /// This is stored here, and not just in the definition,
734 /// because it can be changed programmatically, by setting
735 /// 'TextFields.variable'
736 std::string _variable_name
;
738 rgba _backgroundColor
;
744 TextAlignment _alignment
;
746 boost::intrusive_ptr
<const Font
> _font
;
753 size_t _bottomScroll
;
754 size_t _linesindisplay
;
756 /// Corresponds to the maxChars property.
763 /// Area in which the text is drawn.
765 /// This area encloses all the text, can be automatically
766 /// extended to fit text or hide text overflowing it.
767 /// See the setAutoSize() method to change that.
771 /// Represents the selected part of the text. The second element must
772 /// never be less than the first.
773 std::pair
<size_t, size_t> _selection
;
775 boost::int16_t _leading
;
776 boost::uint16_t _indent
;
778 /// Indentation for every line (including the ones created by
779 /// effect of a word-wrap.
780 boost::uint16_t _blockIndent
;
782 boost::uint16_t _leftMargin
;
784 boost::uint16_t _rightMargin
;
786 boost::uint16_t _fontHeight
;
788 /// This flag will be true as soon as the TextField
789 /// is assigned a text value. Only way to be false is
790 /// when definition has the hasText flag set to false
791 /// and no actionscript added text.
794 bool _htmlTextDefined
;
796 bool _restrictDefined
;
803 /// Corresponds to the multiline property.
806 /// Corresponds to the password property.
809 /// The flag keeping status of TextVariable registration
811 /// It will be set to true if there's no need to register
812 /// a text variable (ie. non-specified in the SWF)
814 bool _text_variable_registered
;
816 bool _drawBackground
;