]> git.saurik.com Git - wxWidgets.git/commitdiff
Added field implementation
authorJulian Smart <julian@anthemion.co.uk>
Wed, 9 May 2012 11:06:04 +0000 (11:06 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Wed, 9 May 2012 11:06:04 +0000 (11:06 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71379 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/richtext/richtextbuffer.h
include/wx/richtext/richtextctrl.h
interface/wx/richtext/richtextbuffer.h
interface/wx/richtext/richtextctrl.h
src/richtext/richtextbuffer.cpp
src/richtext/richtextctrl.cpp
src/richtext/richtextxml.cpp

index 40788167be94edb3d2a8909caab7908883d19ec1..e2ea3f0e855ecd7e724c43f791fb0b1c18b26147 100644 (file)
@@ -527,7 +527,7 @@ All (GUI):
 - Fix WXK_MENU handling in wxStyledTextCtrl under wxGTK (cantabile).
 - Added wxAcceleratorEntry::ToRawString() (Armel Asselin).
 - Added wxDataViewEvent::SetDragFlags() and GetDropEffect() (Friedrich).
-
+- Added support for fields and virtual attributes to wxRichTextCtrl.
 
 GTK:
 
index e6465bbb77876e16ff41e05532e9bfbdfcc707c7..24656faa51875f0e0ed0a9913717e05bb16f8a60 100644 (file)
@@ -131,6 +131,8 @@ class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextLine;
 class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextParagraph;
 class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextFileHandler;
 class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextDrawingHandler;
+class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextField;
+class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextFieldType;
 class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextStyleSheet;
 class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextListStyleDefinition;
 class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextEvent;
@@ -193,7 +195,10 @@ enum wxRichTextHitTestFlags
     wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS = 0x20,
 
     // Ignore floating objects
-    wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS = 0x40
+    wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS = 0x40,
+
+    // Don't recurse into objects marked as atomic
+    wxRICHTEXT_HITTEST_HONOUR_ATOMIC = 0x80
 };
 
 /**
@@ -2407,10 +2412,16 @@ public:
     wxRichTextRange GetOwnRangeIfTopLevel() const { return IsTopLevel() ? m_ownRange : m_range; }
 
     /**
-        Returns @true if this object this composite.
+        Returns @true if this object is composite.
     */
     virtual bool IsComposite() const { return false; }
 
+    /**
+        Returns @true if no user editing can be done inside the object. This returns @true for simple objects,
+        @false for most composite objects, but @true for fields, which if composite, should not be user-edited.
+    */
+    virtual bool IsAtomic() const { return true; }
+
     /**
         Returns a pointer to the parent object.
     */
@@ -2498,7 +2509,7 @@ public:
     wxRichTextAttr& GetAttributes() { return m_attributes; }
 
     /**
-        Sets the object's properties.
+        Returns the object's properties.
     */
     wxRichTextProperties& GetProperties() { return m_properties; }
 
@@ -2508,7 +2519,7 @@ public:
     const wxRichTextProperties& GetProperties() const { return m_properties; }
 
     /**
-        Returns the object's properties.
+        Sets the object's properties.
     */
     void SetProperties(const wxRichTextProperties& props) { m_properties = props; }
 
@@ -2726,6 +2737,12 @@ public:
     */
     virtual bool IsComposite() const { return true; }
 
+    /**
+        Returns @true if no user editing can be done inside the object. This returns @true for simple objects,
+        @false for most composite objects, but @true for fields, which if composite, should not be user-edited.
+    */
+    virtual bool IsAtomic() const { return false; }
+
     /**
         Returns true if the buffer is empty.
     */
@@ -2879,6 +2896,16 @@ public:
     bool InsertImageWithUndo(wxRichTextBuffer* buffer, long pos, const wxRichTextImageBlock& imageBlock,
                                                         wxRichTextCtrl* ctrl, int flags, const wxRichTextAttr& textAttr);
 
+    /**
+        Submits a command to insert the given field. Field data can be included in properties.
+
+        @see wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+    */
+    wxRichTextField* InsertFieldWithUndo(wxRichTextBuffer* buffer, long pos, const wxString& fieldType,
+                                                        const wxRichTextProperties& properties,
+                                                        wxRichTextCtrl* ctrl, int flags,
+                                                        const wxRichTextAttr& textAttr);
+
     /**
         Returns the style that is appropriate for a new paragraph at this position.
         If the previous paragraph has a paragraph style name, looks up the next-paragraph
@@ -3418,6 +3445,470 @@ public:
 protected:
 };
 
+/**
+    @class wxRichTextField
+
+    This class implements the general concept of a field, an object that represents
+    additional functionality such as a footnote, a bookmark, a page number, a table
+    of contents, and so on. Extra information (such as a bookmark name) can be stored
+    in the object properties.
+
+    Drawing, layout, and property editing is delegated to classes derived
+    from wxRichTextFieldType, such as instances of wxRichTextFieldTypeStandard; this makes
+    the use of fields an efficient method of introducing extra functionality, since
+    most of the information required to draw a field (such as a bitmap) is kept centrally
+    in a single field type definition.
+
+    The FieldType property, accessed by SetFieldType/GetFieldType, is used to retrieve
+    the field type definition. So be careful not to overwrite this property.
+
+    wxRichTextField is derived from wxRichTextParagraphLayoutBox, which means that it
+    can contain its own read-only content, refreshed when the application calls the UpdateField
+    function. Whether a field is treated as a composite or a single graphic is determined
+    by the field type definition. If using wxRichTextFieldTypeStandard, passing the display
+    type wxRICHTEXT_FIELD_STYLE_COMPOSITE to the field type definition causes the field
+    to behave like a composite; the other display styles display a simple graphic.
+    When implementing a composite field, you will still need to derive from wxRichTextFieldTypeStandard
+    or wxRichTextFieldType, if only to implement UpdateField to refresh the field content
+    appropriately. wxRichTextFieldTypeStandard is only one possible implementation, but
+    covers common needs especially for simple, static fields using text or a bitmap.
+
+    Register field types on application initialisation with the static function
+    wxRichTextParagraphLayoutBox::AddFieldType. They will be deleted automatically
+    on application exit.
+
+    An application can write a field to a control with wxRichTextCtrl::WriteField,
+    taking a field type, the properties for the field, and optional attributes.
+
+    @library{wxrichtext}
+    @category{richtext}
+
+    @see wxRichTextFieldTypeStandard, wxRichTextFieldType, wxRichTextParagraphLayoutBox, wxRichTextProperties, wxRichTextCtrl
+*/
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextField: public wxRichTextParagraphLayoutBox
+{
+    DECLARE_DYNAMIC_CLASS(wxRichTextField)
+public:
+// Constructors
+
+    /**
+        Default constructor; optionally pass the parent object.
+    */
+
+    wxRichTextField(const wxString& fieldType = wxEmptyString, wxRichTextObject* parent = NULL);
+
+    /**
+        Copy constructor.
+    */
+
+    wxRichTextField(const wxRichTextField& obj): wxRichTextParagraphLayoutBox() { Copy(obj); }
+
+// Overridables
+
+    virtual bool Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
+
+    virtual bool Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style);
+
+    virtual bool GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position = wxPoint(0,0), wxArrayInt* partialExtents = NULL) const;
+
+    virtual wxString GetXMLNodeName() const { return wxT("field"); }
+
+    virtual bool CanEditProperties() const;
+
+    virtual bool EditProperties(wxWindow* parent, wxRichTextBuffer* buffer);
+
+    virtual wxString GetPropertiesMenuLabel() const;
+
+    virtual bool AcceptsFocus() const { return false; }
+
+    virtual void CalculateRange(long start, long& end);
+
+    /**
+        If a field has children, we don't want the user to be able to edit it.
+    */
+    virtual bool IsAtomic() const { return true; }
+
+    virtual bool IsEmpty() const { return false; }
+
+    virtual bool IsTopLevel() const;
+
+// Accessors
+
+    void SetFieldType(const wxString& fieldType) { GetProperties().SetProperty(wxT("FieldType"), fieldType); }
+    wxString GetFieldType() const { return GetProperties().GetPropertyString(wxT("FieldType")); }
+
+// Operations
+
+    /**
+        Update the field; delegated to the associated field type. This would typically expand the field to its value,
+        if this is a dynamically changing and/or composite field.
+     */
+    virtual bool UpdateField();
+
+    virtual wxRichTextObject* Clone() const { return new wxRichTextField(*this); }
+
+    void Copy(const wxRichTextField& obj);
+
+protected:
+};
+
+/**
+    @class wxRichTextFieldType
+
+    The base class for custom field types. Each type definition handles one
+    field type. Override functions to provide drawing, layout, updating and
+    property editing functionality for a field.
+
+    Register field types on application initialisation with the static function
+    wxRichTextParagraphLayoutBox::AddFieldType. They will be deleted automatically
+    on application exit.
+
+    @library{wxrichtext}
+    @category{richtext}
+
+    @see wxRichTextFieldTypeStandard, wxRichTextField, wxRichTextCtrl
+*/
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextFieldType: public wxObject
+{
+    DECLARE_CLASS(wxRichTextFieldType)
+public:
+    /**
+        Creates a field type definition.
+    */
+    wxRichTextFieldType(const wxString& name = wxEmptyString)
+        : m_name(name)
+        { }
+
+    /**
+        Copy constructor.
+    */
+    wxRichTextFieldType(const wxRichTextFieldType& fieldType) { Copy(fieldType); }
+
+    void Copy(const wxRichTextFieldType& fieldType) { m_name = fieldType.m_name; }
+
+    /**
+        Draw the item, within the given range. Some objects may ignore the range (for
+        example paragraphs) while others must obey it (lines, to implement wrapping)
+    */
+    virtual bool Draw(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style) = 0;
+
+    /**
+        Lay the item out at the specified position with the given size constraint.
+        Layout must set the cached size. @rect is the available space for the object,
+        and @a parentRect is the container that is used to determine a relative size
+        or position (for example if a text box must be 50% of the parent text box).
+    */
+    virtual bool Layout(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style) = 0;
+
+    /**
+        Returns the object size for the given range. Returns @false if the range
+        is invalid for this object.
+    */
+    virtual bool GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position = wxPoint(0,0), wxArrayInt* partialExtents = NULL) const = 0;
+
+    /**
+        Returns @true if we can edit the object's properties via a GUI.
+    */
+    virtual bool CanEditProperties(wxRichTextField* WXUNUSED(obj)) const { return false; }
+
+    /**
+        Edits the object's properties via a GUI.
+    */
+    virtual bool EditProperties(wxRichTextField* WXUNUSED(obj), wxWindow* WXUNUSED(parent), wxRichTextBuffer* WXUNUSED(buffer)) { return false; }
+
+    /**
+        Returns the label to be used for the properties context menu item.
+    */
+    virtual wxString GetPropertiesMenuLabel(wxRichTextField* WXUNUSED(obj)) const { return wxEmptyString; }
+
+    /**
+        Update the field. This would typically expand the field to its value,
+        if this is a dynamically changing and/or composite field.
+     */
+    virtual bool UpdateField(wxRichTextField* WXUNUSED(obj)) { return false; }
+
+    /**
+        Returns @true if this object is top-level, i.e. contains its own paragraphs, such as a text box.
+    */
+    virtual bool IsTopLevel(wxRichTextField* WXUNUSED(obj)) const { return true; }
+
+    /**
+        Sets the field type name. There should be a unique name per field type object.
+    */
+    void SetName(const wxString& name) { m_name = name; }
+
+    /**
+        Returns the field type name. There should be a unique name per field type object.
+    */
+    wxString GetName() const { return m_name; }
+
+protected:
+
+    wxString  m_name;
+};
+
+WX_DECLARE_STRING_HASH_MAP(wxRichTextFieldType*, wxRichTextFieldTypeHashMap);
+
+/**
+    @class wxRichTextFieldTypeStandard
+
+    A field type that can handle fields with text or bitmap labels, with a small range
+    of styles for implementing rectangular fields and fields that can be used for start
+    and end tags.
+
+    The border, text and background colours can be customised; the default is
+    white text on a black background.
+
+    The following display styles can be used.
+
+    @beginStyleTable
+    @style{wxRICHTEXT_FIELD_STYLE_COMPOSITE}
+           Creates a composite field; you will probably need to derive a new class to implement UpdateField.
+    @style{wxRICHTEXT_FIELD_STYLE_RECTANGLE}
+           Shows a rounded rectangle background.
+    @style{wxRICHTEXT_FIELD_STYLE_NO_BORDER}
+           Suppresses the background and border; mostly used with a bitmap label.
+    @style{wxRICHTEXT_FIELD_STYLE_START_TAG}
+           Shows a start tag background, with the pointy end facing right.
+    @style{wxRICHTEXT_FIELD_STYLE_END_TAG}
+           Shows an end tag background, with the pointy end facing left.
+    @endStyleTable
+
+    @library{wxrichtext}
+    @category{richtext}
+
+    @see wxRichTextFieldType, wxRichTextField, wxRichTextBuffer, wxRichTextCtrl
+*/
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextFieldTypeStandard: public wxRichTextFieldType
+{
+    DECLARE_CLASS(wxRichTextFieldTypeStandard)
+public:
+
+    // Display style types
+    enum { wxRICHTEXT_FIELD_STYLE_COMPOSITE = 0x01,
+           wxRICHTEXT_FIELD_STYLE_RECTANGLE = 0x02,
+           wxRICHTEXT_FIELD_STYLE_NO_BORDER = 0x04,
+           wxRICHTEXT_FIELD_STYLE_START_TAG = 0x08,
+           wxRICHTEXT_FIELD_STYLE_END_TAG = 0x10
+         };
+
+    /**
+        Constructor, creating a field type definition with a text label.
+
+        @param parent
+            The name of the type definition. This must be unique, and is the type
+            name used when adding a field to a control.
+        @param label
+            The text label to be shown on the field.
+        @param displayStyle
+            The display style: one of wxRICHTEXT_FIELD_STYLE_RECTANGLE,
+            wxRICHTEXT_FIELD_STYLE_NO_BORDER, wxRICHTEXT_FIELD_STYLE_START_TAG,
+            wxRICHTEXT_FIELD_STYLE_END_TAG.
+
+    */
+    wxRichTextFieldTypeStandard(const wxString& name, const wxString& label, int displayStyle = wxRICHTEXT_FIELD_STYLE_RECTANGLE);
+
+    /**
+        Constructor, creating a field type definition with a bitmap label.
+
+        @param parent
+            The name of the type definition. This must be unique, and is the type
+            name used when adding a field to a control.
+        @param label
+            The bitmap label to be shown on the field.
+        @param displayStyle
+            The display style: one of wxRICHTEXT_FIELD_STYLE_RECTANGLE,
+            wxRICHTEXT_FIELD_STYLE_NO_BORDER, wxRICHTEXT_FIELD_STYLE_START_TAG,
+            wxRICHTEXT_FIELD_STYLE_END_TAG.
+
+    */
+    wxRichTextFieldTypeStandard(const wxString& name, const wxBitmap& bitmap, int displayStyle = wxRICHTEXT_FIELD_STYLE_NO_BORDER);
+
+    /**
+        The default constructor.
+
+    */
+    wxRichTextFieldTypeStandard() { Init(); }
+
+    /**
+        The copy constructor.
+
+    */
+    wxRichTextFieldTypeStandard(const wxRichTextFieldTypeStandard& field) { Copy(field); }
+
+    /**
+        Initialises the object.
+    */
+    void Init();
+
+    /**
+        Copies the object.
+    */
+    void Copy(const wxRichTextFieldTypeStandard& field);
+
+    /**
+        The assignment operator.
+    */
+    void operator=(const wxRichTextFieldTypeStandard& field) { Copy(field); }
+
+    /**
+        Draw the item, within the given range. Some objects may ignore the range (for
+        example paragraphs) while others must obey it (lines, to implement wrapping)
+    */
+    virtual bool Draw(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
+
+    /**
+        Lay the item out at the specified position with the given size constraint.
+        Layout must set the cached size. @rect is the available space for the object,
+        and @a parentRect is the container that is used to determine a relative size
+        or position (for example if a text box must be 50% of the parent text box).
+    */
+    virtual bool Layout(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style);
+
+    /**
+        Returns the object size for the given range. Returns @false if the range
+        is invalid for this object.
+    */
+    virtual bool GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position = wxPoint(0,0), wxArrayInt* partialExtents = NULL) const;
+
+    /**
+        Get the size of the field, given the label, font size, and so on.
+    */
+    wxSize GetSize(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, int style) const;
+
+    /**
+        Returns @true if the display type is wxRICHTEXT_FIELD_STYLE_COMPOSITE, @false otherwise.
+    */
+    virtual bool IsTopLevel(wxRichTextField* WXUNUSED(obj)) const { return (GetDisplayStyle() & wxRICHTEXT_FIELD_STYLE_COMPOSITE) != 0; }
+
+    /**
+        Sets the text label for fields of this type.
+    */
+    void SetLabel(const wxString& label) { m_label = label; }
+
+    /**
+        Returns the text label for fields of this type.
+    */
+    const wxString& GetLabel() const { return m_label; }
+
+    /**
+        Sets the bitmap label for fields of this type.
+    */
+    void SetBitmap(const wxBitmap& bitmap) { m_bitmap = bitmap; }
+
+    /**
+        Gets the bitmap label for fields of this type.
+    */
+    const wxBitmap& GetBitmap() const { return m_bitmap; }
+
+    /**
+        Gets the display style for fields of this type.
+    */
+    int GetDisplayStyle() const { return m_displayStyle; }
+
+    /**
+        Sets the display style for fields of this type.
+    */
+    void SetDisplayStyle(int displayStyle) { m_displayStyle = displayStyle; }
+
+    /**
+        Gets the font used for drawing the text label.
+    */
+    const wxFont& GetFont() const { return m_font; }
+
+    /**
+        Sets the font used for drawing the text label.
+    */
+    void SetFont(const wxFont& font) { m_font = font; }
+
+    /**
+        Gets the colour used for drawing the text label.
+    */
+    const wxColour& GetTextColour() const { return m_textColour; }
+
+    /**
+        Sets the colour used for drawing the text label.
+    */
+    void SetTextColour(const wxColour& colour) { m_textColour = colour; }
+
+    /**
+        Gets the colour used for drawing the field border.
+    */
+    const wxColour& GetBorderColour() const { return m_borderColour; }
+
+    /**
+        Sets the colour used for drawing the field border.
+    */
+    void SetBorderColour(const wxColour& colour) { m_borderColour = colour; }
+
+    /**
+        Gets the colour used for drawing the field background.
+    */
+    const wxColour& GetBackgroundColour() const { return m_backgroundColour; }
+
+    /**
+        Sets the colour used for drawing the field background.
+    */
+    void SetBackgroundColour(const wxColour& colour) { m_backgroundColour = colour; }
+
+    /**
+        Sets the vertical padding (the distance between the border and the text).
+    */
+    void SetVerticalPadding(int padding) { m_verticalPadding = padding; }
+
+    /**
+        Gets the vertical padding (the distance between the border and the text).
+    */
+    int GetVerticalPadding() const { return m_verticalPadding; }
+
+    /**
+        Sets the horizontal padding (the distance between the border and the text).
+    */
+    void SetHorizontalPadding(int padding) { m_horizontalPadding = padding; }
+
+    /**
+        Sets the horizontal padding (the distance between the border and the text).
+    */
+    int GetHorizontalPadding() const { return m_horizontalPadding; }
+
+    /**
+        Sets the horizontal margin surrounding the field object.
+    */
+    void SetHorizontalMargin(int margin) { m_horizontalMargin = margin; }
+
+    /**
+        Gets the horizontal margin surrounding the field object.
+    */
+    int GetHorizontalMargin() const { return m_horizontalMargin; }
+
+    /**
+        Sets the vertical margin surrounding the field object.
+    */
+    void SetVerticalMargin(int margin) { m_verticalMargin = margin; }
+
+    /**
+        Gets the vertical margin surrounding the field object.
+    */
+    int GetVerticalMargin() const { return m_verticalMargin; }
+
+protected:
+
+    wxString    m_label;
+    int         m_displayStyle;
+    wxFont      m_font;
+    wxColour    m_textColour;
+    wxColour    m_borderColour;
+    wxColour    m_backgroundColour;
+    int         m_verticalPadding;
+    int         m_horizontalPadding;
+    int         m_horizontalMargin;
+    int         m_verticalMargin;
+    wxBitmap    m_bitmap;
+};
+
 /**
     @class wxRichTextLine
 
@@ -4750,6 +5241,38 @@ public:
     */
     static void CleanUpDrawingHandlers();
 
+    /**
+        Returns the field types.
+    */
+    static wxRichTextFieldTypeHashMap& GetFieldTypes() { return sm_fieldTypes; }
+
+    /**
+        Adds a field type.
+
+        @see RemoveFieldType(), FindFieldType(), wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+
+    */
+    static void AddFieldType(wxRichTextFieldType *fieldType);
+
+    /**
+        Removes a field type by name.
+
+        @see AddFieldType(), FindFieldType(), wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+    */
+    static bool RemoveFieldType(const wxString& name);
+
+    /**
+        Finds a field type by name.
+
+        @see RemoveFieldType(), AddFieldType(), wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+    */
+    static wxRichTextFieldType *FindFieldType(const wxString& name);
+
+    /**
+        Cleans up field types.
+    */
+    static void CleanUpFieldTypes();
+
     /**
         Returns the renderer object.
     */
@@ -4836,6 +5359,9 @@ protected:
     /// Drawing handlers
     static wxList           sm_drawingHandlers;
 
+    /// Field types
+    static wxRichTextFieldTypeHashMap sm_fieldTypes;
+
     /// Renderer
     static wxRichTextRenderer* sm_renderer;
 
@@ -5501,12 +6027,12 @@ public:
     virtual void SetVisible(bool visible) { m_visible = visible; }
 
     /**
-        Sets the name of the nandler.
+        Sets the name of the handler.
     */
     void SetName(const wxString& name) { m_name = name; }
 
     /**
-        Returns the name of the nandler.
+        Returns the name of the handler.
     */
     wxString GetName() const { return m_name; }
 
@@ -5619,7 +6145,7 @@ protected:
     @class wxRichTextDrawingHandler
 
     The base class for custom drawing handlers.
-    Currently, drawing handlers can provide virtual handlers.
+    Currently, drawing handlers can provide virtual attributes.
 
     @library{wxrichtext}
     @category{richtext}
@@ -5649,12 +6175,12 @@ public:
     virtual bool GetVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const = 0;
 
     /**
-        Sets the name of the nandler.
+        Sets the name of the handler.
     */
     void SetName(const wxString& name) { m_name = name; }
 
     /**
-        Returns the name of the nandler.
+        Returns the name of the handler.
     */
     wxString GetName() const { return m_name; }
 
index 0c572c6047f8cc1f3c7fb8fccdc1ec0334e611dd..2ced2cdb7bcdf93332574ee3fec29a4065fe0d0e 100644 (file)
@@ -1060,6 +1060,21 @@ public:
     */
     virtual wxRichTextBox* WriteTextBox(const wxRichTextAttr& textAttr = wxRichTextAttr());
 
+    /**
+        Writes a field at the current insertion point.
+
+        @param fieldType
+            The field type, matching an existing field type definition.
+        @param properties
+            Extra data for the field.
+        @param textAttr
+            Optional attributes.
+
+        @see wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+    */
+    virtual wxRichTextField* WriteField(const wxString& fieldType, const wxRichTextProperties& properties,
+                            const wxRichTextAttr& textAttr = wxRichTextAttr());
+
     /**
         Write a table at the current insertion point, returning the table.
         You can then call SetFocusObject() to set the focus to the new object.
index 8227a7b63c74c67ec1379ab9fbeb7f7aa807b53d..f5edca39abd2f5ee8b2b3703fcce99803e4dd126 100644 (file)
@@ -77,7 +77,10 @@ enum wxRichTextHitTestFlags
     wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS = 0x20,
 
     // Ignore floating objects
-    wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS = 0x40
+    wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS = 0x40,
+
+    // Don't recurse into objects marked as atomic
+    wxRICHTEXT_HITTEST_HONOUR_ATOMIC = 0x80
 };
 
 /**
@@ -2286,10 +2289,16 @@ public:
     wxRichTextRange GetOwnRangeIfTopLevel() const { return IsTopLevel() ? m_ownRange : m_range; }
 
     /**
-        Returns @true if this object this composite.
+        Returns @true if this object is composite.
     */
     virtual bool IsComposite() const { return false; }
 
+    /**
+        Returns @true if no user editing can be done inside the object. This returns @true for simple objects,
+        @false for most composite objects, but @true for fields, which if composite, should not be user-edited.
+    */
+    virtual bool IsAtomic() const { return true; }
+
     /**
         Returns a pointer to the parent object.
     */
@@ -2605,6 +2614,12 @@ public:
     */
     virtual bool IsComposite() const { return true; }
 
+    /**
+        Returns @true if no user editing can be done inside the object. This returns @true for simple objects,
+        @false for most composite objects, but @true for fields, which if composite, should not be user-edited.
+    */
+    virtual bool IsAtomic() const { return false; }
+
     /**
         Returns true if the buffer is empty.
     */
@@ -2759,6 +2774,16 @@ public:
                                                         wxRichTextCtrl* ctrl, int flags,
                                                         const wxRichTextAttr& textAttr);
 
+    /**
+        Submits a command to insert the given field. Field data can be included in properties.
+
+        @see wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+    */
+    wxRichTextField* InsertFieldWithUndo(wxRichTextBuffer* buffer, long pos, const wxString& fieldType,
+                                                        const wxRichTextProperties& properties,
+                                                        wxRichTextCtrl* ctrl, int flags,
+                                                        const wxRichTextAttr& textAttr);
+
     /**
         Returns the style that is appropriate for a new paragraph at this position.
         If the previous paragraph has a paragraph style name, looks up the next-paragraph
@@ -3298,6 +3323,470 @@ public:
 protected:
 };
 
+/**
+    @class wxRichTextField
+
+    This class implements the general concept of a field, an object that represents
+    additional functionality such as a footnote, a bookmark, a page number, a table
+    of contents, and so on. Extra information (such as a bookmark name) can be stored
+    in the object properties.
+
+    Drawing, layout, and property editing is delegated to classes derived
+    from wxRichTextFieldType, such as instances of wxRichTextFieldTypeStandard; this makes
+    the use of fields an efficient method of introducing extra functionality, since
+    most of the information required to draw a field (such as a bitmap) is kept centrally
+    in a single field type definition.
+
+    The FieldType property, accessed by SetFieldType/GetFieldType, is used to retrieve
+    the field type definition. So be careful not to overwrite this property.
+
+    wxRichTextField is derived from wxRichTextParagraphLayoutBox, which means that it
+    can contain its own read-only content, refreshed when the application calls the UpdateField
+    function. Whether a field is treated as a composite or a single graphic is determined
+    by the field type definition. If using wxRichTextFieldTypeStandard, passing the display
+    type wxRICHTEXT_FIELD_STYLE_COMPOSITE to the field type definition causes the field
+    to behave like a composite; the other display styles display a simple graphic.
+    When implementing a composite field, you will still need to derive from wxRichTextFieldTypeStandard
+    or wxRichTextFieldType, if only to implement UpdateField to refresh the field content
+    appropriately. wxRichTextFieldTypeStandard is only one possible implementation, but
+    covers common needs especially for simple, static fields using text or a bitmap.
+
+    Register field types on application initialisation with the static function
+    wxRichTextParagraphLayoutBox::AddFieldType. They will be deleted automatically
+    on application exit.
+
+    An application can write a field to a control with wxRichTextCtrl::WriteField,
+    taking a field type, the properties for the field, and optional attributes.
+
+    @library{wxrichtext}
+    @category{richtext}
+
+    @see wxRichTextFieldTypeStandard, wxRichTextFieldType, wxRichTextParagraphLayoutBox, wxRichTextProperties, wxRichTextCtrl
+*/
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextField: public wxRichTextParagraphLayoutBox
+{
+    DECLARE_DYNAMIC_CLASS(wxRichTextField)
+public:
+// Constructors
+
+    /**
+        Default constructor; optionally pass the parent object.
+    */
+
+    wxRichTextField(const wxString& fieldType = wxEmptyString, wxRichTextObject* parent = NULL);
+
+    /**
+        Copy constructor.
+    */
+
+    wxRichTextField(const wxRichTextField& obj): wxRichTextParagraphLayoutBox() { Copy(obj); }
+
+// Overridables
+
+    virtual bool Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
+
+    virtual bool Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style);
+
+    virtual bool GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position = wxPoint(0,0), wxArrayInt* partialExtents = NULL) const;
+
+    virtual wxString GetXMLNodeName() const { return wxT("field"); }
+
+    virtual bool CanEditProperties() const;
+
+    virtual bool EditProperties(wxWindow* parent, wxRichTextBuffer* buffer);
+
+    virtual wxString GetPropertiesMenuLabel() const;
+
+    virtual bool AcceptsFocus() const { return false; }
+
+    virtual void CalculateRange(long start, long& end);
+
+    /**
+        If a field has children, we don't want the user to be able to edit it.
+    */
+    virtual bool IsAtomic() const { return true; }
+
+    virtual bool IsEmpty() const { return false; }
+
+    virtual bool IsTopLevel() const;
+
+// Accessors
+
+    void SetFieldType(const wxString& fieldType) { GetProperties().SetProperty(wxT("FieldType"), fieldType); }
+    wxString GetFieldType() const { return GetProperties().GetPropertyString(wxT("FieldType")); }
+
+// Operations
+
+    /**
+        Update the field; delegated to the associated field type. This would typically expand the field to its value,
+        if this is a dynamically changing and/or composite field.
+     */
+    virtual bool UpdateField();
+
+    virtual wxRichTextObject* Clone() const { return new wxRichTextField(*this); }
+
+    void Copy(const wxRichTextField& obj);
+
+protected:
+};
+
+/**
+    @class wxRichTextFieldType
+
+    The base class for custom field types. Each type definition handles one
+    field type. Override functions to provide drawing, layout, updating and
+    property editing functionality for a field.
+
+    Register field types on application initialisation with the static function
+    wxRichTextParagraphLayoutBox::AddFieldType. They will be deleted automatically
+    on application exit.
+
+    @library{wxrichtext}
+    @category{richtext}
+
+    @see wxRichTextFieldTypeStandard, wxRichTextField, wxRichTextCtrl
+*/
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextFieldType: public wxObject
+{
+    DECLARE_CLASS(wxRichTextFieldType)
+public:
+    /**
+        Creates a field type definition.
+    */
+    wxRichTextFieldType(const wxString& name = wxEmptyString)
+        : m_name(name)
+        { }
+
+    /**
+        Copy constructor.
+    */
+    wxRichTextFieldType(const wxRichTextFieldType& fieldType) { Copy(fieldType); }
+
+    void Copy(const wxRichTextFieldType& fieldType) { m_name = fieldType.m_name; }
+
+    /**
+        Draw the item, within the given range. Some objects may ignore the range (for
+        example paragraphs) while others must obey it (lines, to implement wrapping)
+    */
+    virtual bool Draw(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style) = 0;
+
+    /**
+        Lay the item out at the specified position with the given size constraint.
+        Layout must set the cached size. @rect is the available space for the object,
+        and @a parentRect is the container that is used to determine a relative size
+        or position (for example if a text box must be 50% of the parent text box).
+    */
+    virtual bool Layout(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style) = 0;
+
+    /**
+        Returns the object size for the given range. Returns @false if the range
+        is invalid for this object.
+    */
+    virtual bool GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position = wxPoint(0,0), wxArrayInt* partialExtents = NULL) const = 0;
+
+    /**
+        Returns @true if we can edit the object's properties via a GUI.
+    */
+    virtual bool CanEditProperties(wxRichTextField* WXUNUSED(obj)) const { return false; }
+
+    /**
+        Edits the object's properties via a GUI.
+    */
+    virtual bool EditProperties(wxRichTextField* WXUNUSED(obj), wxWindow* WXUNUSED(parent), wxRichTextBuffer* WXUNUSED(buffer)) { return false; }
+
+    /**
+        Returns the label to be used for the properties context menu item.
+    */
+    virtual wxString GetPropertiesMenuLabel(wxRichTextField* WXUNUSED(obj)) const { return wxEmptyString; }
+
+    /**
+        Update the field. This would typically expand the field to its value,
+        if this is a dynamically changing and/or composite field.
+     */
+    virtual bool UpdateField(wxRichTextField* WXUNUSED(obj)) { return false; }
+
+    /**
+        Returns @true if this object is top-level, i.e. contains its own paragraphs, such as a text box.
+    */
+    virtual bool IsTopLevel(wxRichTextField* WXUNUSED(obj)) const { return true; }
+
+    /**
+        Sets the field type name. There should be a unique name per field type object.
+    */
+    void SetName(const wxString& name) { m_name = name; }
+
+    /**
+        Returns the field type name. There should be a unique name per field type object.
+    */
+    wxString GetName() const { return m_name; }
+
+protected:
+
+    wxString  m_name;
+};
+
+WX_DECLARE_STRING_HASH_MAP(wxRichTextFieldType*, wxRichTextFieldTypeHashMap);
+
+/**
+    @class wxRichTextFieldTypeStandard
+
+    A field type that can handle fields with text or bitmap labels, with a small range
+    of styles for implementing rectangular fields and fields that can be used for start
+    and end tags.
+
+    The border, text and background colours can be customised; the default is
+    white text on a black background.
+
+    The following display styles can be used.
+
+    @beginStyleTable
+    @style{wxRICHTEXT_FIELD_STYLE_COMPOSITE}
+           Creates a composite field; you will probably need to derive a new class to implement UpdateField.
+    @style{wxRICHTEXT_FIELD_STYLE_RECTANGLE}
+           Shows a rounded rectangle background.
+    @style{wxRICHTEXT_FIELD_STYLE_NO_BORDER}
+           Suppresses the background and border; mostly used with a bitmap label.
+    @style{wxRICHTEXT_FIELD_STYLE_START_TAG}
+           Shows a start tag background, with the pointy end facing right.
+    @style{wxRICHTEXT_FIELD_STYLE_END_TAG}
+           Shows an end tag background, with the pointy end facing left.
+    @endStyleTable
+
+    @library{wxrichtext}
+    @category{richtext}
+
+    @see wxRichTextFieldType, wxRichTextField, wxRichTextBuffer, wxRichTextCtrl
+*/
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextFieldTypeStandard: public wxRichTextFieldType
+{
+    DECLARE_CLASS(wxRichTextFieldTypeStandard)
+public:
+
+    // Display style types
+    enum { wxRICHTEXT_FIELD_STYLE_COMPOSITE = 0x01,
+           wxRICHTEXT_FIELD_STYLE_RECTANGLE = 0x02,
+           wxRICHTEXT_FIELD_STYLE_NO_BORDER = 0x04,
+           wxRICHTEXT_FIELD_STYLE_START_TAG = 0x08,
+           wxRICHTEXT_FIELD_STYLE_END_TAG = 0x10
+         };
+
+    /**
+        Constructor, creating a field type definition with a text label.
+
+        @param parent
+            The name of the type definition. This must be unique, and is the type
+            name used when adding a field to a control.
+        @param label
+            The text label to be shown on the field.
+        @param displayStyle
+            The display style: one of wxRICHTEXT_FIELD_STYLE_RECTANGLE,
+            wxRICHTEXT_FIELD_STYLE_NO_BORDER, wxRICHTEXT_FIELD_STYLE_START_TAG,
+            wxRICHTEXT_FIELD_STYLE_END_TAG.
+
+    */
+    wxRichTextFieldTypeStandard(const wxString& name, const wxString& label, int displayStyle = wxRICHTEXT_FIELD_STYLE_RECTANGLE);
+
+    /**
+        Constructor, creating a field type definition with a bitmap label.
+
+        @param parent
+            The name of the type definition. This must be unique, and is the type
+            name used when adding a field to a control.
+        @param label
+            The bitmap label to be shown on the field.
+        @param displayStyle
+            The display style: one of wxRICHTEXT_FIELD_STYLE_RECTANGLE,
+            wxRICHTEXT_FIELD_STYLE_NO_BORDER, wxRICHTEXT_FIELD_STYLE_START_TAG,
+            wxRICHTEXT_FIELD_STYLE_END_TAG.
+
+    */
+    wxRichTextFieldTypeStandard(const wxString& name, const wxBitmap& bitmap, int displayStyle = wxRICHTEXT_FIELD_STYLE_NO_BORDER);
+
+    /**
+        The default constructor.
+
+    */
+    wxRichTextFieldTypeStandard() { Init(); }
+
+    /**
+        The copy constructor.
+
+    */
+    wxRichTextFieldTypeStandard(const wxRichTextFieldTypeStandard& field) { Copy(field); }
+
+    /**
+        Initialises the object.
+    */
+    void Init();
+
+    /**
+        Copies the object.
+    */
+    void Copy(const wxRichTextFieldTypeStandard& field);
+
+    /**
+        The assignment operator.
+    */
+    void operator=(const wxRichTextFieldTypeStandard& field) { Copy(field); }
+
+    /**
+        Draw the item, within the given range. Some objects may ignore the range (for
+        example paragraphs) while others must obey it (lines, to implement wrapping)
+    */
+    virtual bool Draw(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style);
+
+    /**
+        Lay the item out at the specified position with the given size constraint.
+        Layout must set the cached size. @rect is the available space for the object,
+        and @a parentRect is the container that is used to determine a relative size
+        or position (for example if a text box must be 50% of the parent text box).
+    */
+    virtual bool Layout(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style);
+
+    /**
+        Returns the object size for the given range. Returns @false if the range
+        is invalid for this object.
+    */
+    virtual bool GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position = wxPoint(0,0), wxArrayInt* partialExtents = NULL) const;
+
+    /**
+        Get the size of the field, given the label, font size, and so on.
+    */
+    wxSize GetSize(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, int style) const;
+
+    /**
+        Returns @true if the display type is wxRICHTEXT_FIELD_STYLE_COMPOSITE, @false otherwise.
+    */
+    virtual bool IsTopLevel(wxRichTextField* WXUNUSED(obj)) const { return (GetDisplayStyle() & wxRICHTEXT_FIELD_STYLE_COMPOSITE) != 0; }
+
+    /**
+        Sets the text label for fields of this type.
+    */
+    void SetLabel(const wxString& label) { m_label = label; }
+
+    /**
+        Returns the text label for fields of this type.
+    */
+    const wxString& GetLabel() const { return m_label; }
+
+    /**
+        Sets the bitmap label for fields of this type.
+    */
+    void SetBitmap(const wxBitmap& bitmap) { m_bitmap = bitmap; }
+
+    /**
+        Gets the bitmap label for fields of this type.
+    */
+    const wxBitmap& GetBitmap() const { return m_bitmap; }
+
+    /**
+        Gets the display style for fields of this type.
+    */
+    int GetDisplayStyle() const { return m_displayStyle; }
+
+    /**
+        Sets the display style for fields of this type.
+    */
+    void SetDisplayStyle(int displayStyle) { m_displayStyle = displayStyle; }
+
+    /**
+        Gets the font used for drawing the text label.
+    */
+    const wxFont& GetFont() const { return m_font; }
+
+    /**
+        Sets the font used for drawing the text label.
+    */
+    void SetFont(const wxFont& font) { m_font = font; }
+
+    /**
+        Gets the colour used for drawing the text label.
+    */
+    const wxColour& GetTextColour() const { return m_textColour; }
+
+    /**
+        Sets the colour used for drawing the text label.
+    */
+    void SetTextColour(const wxColour& colour) { m_textColour = colour; }
+
+    /**
+        Gets the colour used for drawing the field border.
+    */
+    const wxColour& GetBorderColour() const { return m_borderColour; }
+
+    /**
+        Sets the colour used for drawing the field border.
+    */
+    void SetBorderColour(const wxColour& colour) { m_borderColour = colour; }
+
+    /**
+        Gets the colour used for drawing the field background.
+    */
+    const wxColour& GetBackgroundColour() const { return m_backgroundColour; }
+
+    /**
+        Sets the colour used for drawing the field background.
+    */
+    void SetBackgroundColour(const wxColour& colour) { m_backgroundColour = colour; }
+
+    /**
+        Sets the vertical padding (the distance between the border and the text).
+    */
+    void SetVerticalPadding(int padding) { m_verticalPadding = padding; }
+
+    /**
+        Gets the vertical padding (the distance between the border and the text).
+    */
+    int GetVerticalPadding() const { return m_verticalPadding; }
+
+    /**
+        Sets the horizontal padding (the distance between the border and the text).
+    */
+    void SetHorizontalPadding(int padding) { m_horizontalPadding = padding; }
+
+    /**
+        Sets the horizontal padding (the distance between the border and the text).
+    */
+    int GetHorizontalPadding() const { return m_horizontalPadding; }
+
+    /**
+        Sets the horizontal margin surrounding the field object.
+    */
+    void SetHorizontalMargin(int margin) { m_horizontalMargin = margin; }
+
+    /**
+        Gets the horizontal margin surrounding the field object.
+    */
+    int GetHorizontalMargin() const { return m_horizontalMargin; }
+
+    /**
+        Sets the vertical margin surrounding the field object.
+    */
+    void SetVerticalMargin(int margin) { m_verticalMargin = margin; }
+
+    /**
+        Gets the vertical margin surrounding the field object.
+    */
+    int GetVerticalMargin() const { return m_verticalMargin; }
+
+protected:
+
+    wxString    m_label;
+    int         m_displayStyle;
+    wxFont      m_font;
+    wxColour    m_textColour;
+    wxColour    m_borderColour;
+    wxColour    m_backgroundColour;
+    int         m_verticalPadding;
+    int         m_horizontalPadding;
+    int         m_horizontalMargin;
+    int         m_verticalMargin;
+    wxBitmap    m_bitmap;
+};
+
 /**
     @class wxRichTextLine
 
@@ -4624,6 +5113,38 @@ public:
     */
     static void CleanUpDrawingHandlers();
 
+    /**
+        Returns the field types.
+    */
+    static wxRichTextFieldTypeHashMap& GetFieldTypes() { return sm_fieldTypes; }
+
+    /**
+        Adds a field type.
+
+        @see RemoveFieldType(), FindFieldType(), wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+
+    */
+    static void AddFieldType(wxRichTextFieldType *fieldType);
+
+    /**
+        Removes a field type by name.
+
+        @see AddFieldType(), FindFieldType(), wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+    */
+    static bool RemoveFieldType(const wxString& name);
+
+    /**
+        Finds a field type by name.
+
+        @see RemoveFieldType(), AddFieldType(), wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+    */
+    static wxRichTextFieldType *FindFieldType(const wxString& name);
+
+    /**
+        Cleans up field types.
+    */
+    static void CleanUpFieldTypes();
+
     /**
         Returns the renderer object.
     */
@@ -4710,6 +5231,9 @@ protected:
     /// Drawing handlers
     static wxList           sm_drawingHandlers;
 
+    /// Field types
+    static wxRichTextFieldTypeHashMap sm_fieldTypes;
+
     /// Renderer
     static wxRichTextRenderer* sm_renderer;
 
@@ -5374,12 +5898,12 @@ public:
     virtual void SetVisible(bool visible) { m_visible = visible; }
 
     /**
-        Sets the name of the nandler.
+        Sets the name of the handler.
     */
     void SetName(const wxString& name) { m_name = name; }
 
     /**
-        Returns the name of the nandler.
+        Returns the name of the handler.
     */
     wxString GetName() const { return m_name; }
 
@@ -5492,7 +6016,7 @@ protected:
     @class wxRichTextDrawingHandler
 
     The base class for custom drawing handlers.
-    Currently, drawing handlers can provide virtual handlers.
+    Currently, drawing handlers can provide virtual attributes.
 
     @library{wxrichtext}
     @category{richtext}
@@ -5522,12 +6046,12 @@ public:
     virtual bool GetVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const = 0;
 
     /**
-        Sets the name of the nandler.
+        Sets the name of the handler.
     */
     void SetName(const wxString& name) { m_name = name; }
 
     /**
-        Returns the name of the nandler.
+        Returns the name of the handler.
     */
     wxString GetName() const { return m_name; }
 
index d94323a203ee44ea4312fc5c4720ed0d744d8cae..cceb0c85f3bec3eb5b56a7c2feadf567099e3906 100644 (file)
@@ -1019,6 +1019,21 @@ public:
     */
     virtual wxRichTextBox* WriteTextBox(const wxRichTextAttr& textAttr = wxRichTextAttr());
 
+    /**
+        Writes a field at the current insertion point.
+
+        @param fieldType
+            The field type, matching an existing field type definition.
+        @param properties
+            Extra data for the field.
+        @param textAttr
+            Optional attributes.
+
+        @see wxRichTextField, wxRichTextFieldType, wxRichTextFieldTypeStandard
+    */
+    virtual wxRichTextField* WriteField(const wxString& fieldType, const wxRichTextProperties& properties,
+                            const wxRichTextAttr& textAttr = wxRichTextAttr());
+
     /**
         Write a table at the current insertion point, returning the table.
         You can then call SetFocusObject() to set the focus to the new object.
index c4086d5dce1db065182c8d543fa04d546209e8d4..663336f03006e8a40b66fbd8d3002c7b23f877c4 100644 (file)
@@ -3542,7 +3542,6 @@ void wxRichTextParagraphLayoutBox::PrepareContent(wxRichTextParagraphLayoutBox&
         buffer->GetRichTextCtrl()->PrepareContent(container);
 }
 
-
 /// Set character or paragraph properties
 bool wxRichTextParagraphLayoutBox::SetProperties(const wxRichTextRange& range, const wxRichTextProperties& properties, int flags)
 {
@@ -4611,7 +4610,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
 
         node = node->GetNext();
     }
-
 #endif
 
     // Split up lines
@@ -4724,7 +4722,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
             wxRect oldAvailableRect = availableRect;
 
             // Available width depends on the floating objects and the line height.
-            // Note: the floating objects may be placed vertically along the two side of
+            // Note: the floating objects may be placed vertically along the two sides of
             // buffer, so we may have different available line widths with different
             // [startY, endY]. So, we can't determine how wide the available
             // space is until we know the exact line height.
@@ -4740,7 +4738,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                 lineAscent = wxMax(childSize.y-childDescent, maxAscent);
             }
             lineHeight = wxMax(lineHeight, (lineDescent + lineAscent));
-
             wxRect floatAvailableRect = collector->GetAvailableRect(rect.y + currentPosition.y, rect.y + currentPosition.y + lineHeight);
 
             // Adjust availableRect to the space that is available when taking floating objects into account.
@@ -4764,7 +4761,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                 {
                     wxSize oldSize = child->GetCachedSize();
 
-                    //child->SetCachedSize(wxDefaultSize);
                     // Lays out the object first with a given amount of space, and then if no width was specified in attr,
                     // lays out the object again using the minimum size
                     child->Invalidate(wxRICHTEXT_ALL);
@@ -4772,7 +4768,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                                 attr, child->GetAttributes(), availableRect, parentRect, style);
                     childSize = child->GetCachedSize();
                     childDescent = child->GetDescent();
-                    //child->SetPosition(availableRect.GetPosition());
 
                     if (oldSize != child->GetCachedSize())
                     {
@@ -4999,7 +4994,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         SetMinSize(marginRect.GetSize());
     }
 
-
 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
 #if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
     // Use the text extents to calculate the size of each fragment in each line
@@ -5177,7 +5171,6 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
         wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
         while (node)
         {
-
             wxRichTextObject* child = node->GetData();
             if (!child->GetRange().IsOutside(range))
             {
@@ -5203,7 +5196,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                     rangeToUse.LimitTo(child->GetRange());
                     int childDescent = 0;
 
-                    // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we're already cached the size,
+                    // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we've already cached the size,
                     // but it's only going to be used after caching has taken place.
                     if ((flags & wxRICHTEXT_HEIGHT_ONLY) && child->GetCachedSize().y != 0)
                     {
@@ -5372,7 +5365,6 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                             maxLineHeight = wxMax(maxLineHeight, (maxAscent + maxDescent));
                             maxLineWidth += childSize.x;
                         }
-                        descent = wxMax(descent, childDescent);
                     }
 
                     node2 = node2->GetNext();
@@ -5511,7 +5503,11 @@ int wxRichTextParagraph::HitTest(wxDC& dc, wxRichTextDrawingContext& context, co
     while (objNode)
     {
         wxRichTextObject* child = objNode->GetData();
-        if (child->IsTopLevel() && ((flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS) == 0))
+        // Don't recurse if we have wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS,
+        // and also, if this seems composite but actually is marked as atomic,
+        // don't recurse.
+        if (child->IsTopLevel() && ((flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS) == 0) &&
+            (! (((flags & wxRICHTEXT_HITTEST_HONOUR_ATOMIC) != 0) && child->IsAtomic())))
         {
             {
                 int hitTest = child->HitTest(dc, context, pt, textPosition, obj, contextObj);
@@ -6506,8 +6502,8 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxRichTextAttr& attr,
 
         x += w;
     }
-    return true;
 
+    return true;
 }
 
 /// Lay the item out
@@ -6833,11 +6829,12 @@ long wxRichTextPlainText::GetFirstLineBreakPosition(long pos)
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextBuffer, wxRichTextParagraphLayoutBox)
 
-wxList                  wxRichTextBuffer::sm_handlers;
-wxList                  wxRichTextBuffer::sm_drawingHandlers;
-wxRichTextRenderer*     wxRichTextBuffer::sm_renderer = NULL;
-int                     wxRichTextBuffer::sm_bulletRightMargin = 20;
-float                   wxRichTextBuffer::sm_bulletProportion = (float) 0.3;
+wxList                      wxRichTextBuffer::sm_handlers;
+wxList                      wxRichTextBuffer::sm_drawingHandlers;
+wxRichTextFieldTypeHashMap  wxRichTextBuffer::sm_fieldTypes;
+wxRichTextRenderer*         wxRichTextBuffer::sm_renderer = NULL;
+int                         wxRichTextBuffer::sm_bulletRightMargin = 20;
+float                       wxRichTextBuffer::sm_bulletProportion = (float) 0.3;
 
 /// Initialisation
 void wxRichTextBuffer::Init()
@@ -7153,6 +7150,47 @@ wxRichTextObject* wxRichTextParagraphLayoutBox::InsertObjectWithUndo(wxRichTextB
     return obj;
 }
 
+wxRichTextField* wxRichTextParagraphLayoutBox::InsertFieldWithUndo(wxRichTextBuffer* buffer, long pos, const wxString& fieldType,
+                                                        const wxRichTextProperties& properties,
+                                                        wxRichTextCtrl* ctrl, int flags,
+                                                        const wxRichTextAttr& textAttr)
+{
+    wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Field"), wxRICHTEXT_INSERT, buffer, this, ctrl, false);
+
+    wxRichTextAttr* p = NULL;
+    wxRichTextAttr paraAttr;
+    if (flags & wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE)
+    {
+        paraAttr = GetStyleForNewParagraph(buffer, pos);
+        if (!paraAttr.IsDefault())
+            p = & paraAttr;
+    }
+
+    wxRichTextAttr attr(buffer->GetDefaultStyle());
+
+    wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
+    if (p)
+        newPara->SetAttributes(*p);
+
+    wxRichTextField* fieldObject = new wxRichTextField();
+    fieldObject->wxRichTextObject::SetProperties(properties);
+    fieldObject->SetFieldType(fieldType);
+    fieldObject->SetAttributes(textAttr);
+    newPara->AppendChild(fieldObject);
+    action->GetNewParagraphs().AppendChild(newPara);
+    action->GetNewParagraphs().UpdateRanges();
+    action->GetNewParagraphs().SetPartialParagraph(true);
+    action->SetPosition(pos);
+
+    // Set the range we'll need to delete in Undo
+    action->SetRange(wxRichTextRange(pos, pos));
+
+    buffer->SubmitAction(action);
+
+    wxRichTextField* obj = wxDynamicCast(GetLeafObjectAtPosition(pos), wxRichTextField);
+    return obj;
+}
+
 /// Get the style that is appropriate for a new paragraph at this position.
 /// If the previous paragraph has a paragraph style name, look up the next-paragraph
 /// style.
@@ -8298,6 +8336,345 @@ bool wxRichTextBox::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
         return false;
 }
 
+/*!
+ * wxRichTextField
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextField, wxRichTextParagraphLayoutBox)
+
+wxRichTextField::wxRichTextField(const wxString& fieldType, wxRichTextObject* parent):
+    wxRichTextParagraphLayoutBox(parent)
+{
+    SetFieldType(fieldType);
+}
+
+/// Draw the item
+bool wxRichTextField::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+{
+    if (!IsShown())
+        return true;
+
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType && fieldType->Draw(this, dc, context, range, selection, rect, descent, style))
+        return true;
+
+    // Fallback; but don't draw guidelines.
+    style &= ~wxRICHTEXT_DRAW_GUIDELINES;
+    return wxRichTextParagraphLayoutBox::Draw(dc, context, range, selection, rect, descent, style);
+}
+
+bool wxRichTextField::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style)
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType && fieldType->Layout(this, dc, context, rect, parentRect, style))
+        return true;
+
+    // Fallback
+    return wxRichTextParagraphLayoutBox::Layout(dc, context, rect, parentRect, style);
+}
+
+bool wxRichTextField::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->GetRangeSize((wxRichTextField*) this, range, size, descent, dc, context, flags, position, partialExtents);
+
+    return wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position, partialExtents);
+}
+
+/// Calculate range
+void wxRichTextField::CalculateRange(long start, long& end)
+{
+    if (IsTopLevel())
+        wxRichTextParagraphLayoutBox::CalculateRange(start, end);
+    else
+        wxRichTextObject::CalculateRange(start, end);
+}
+
+/// Copy
+void wxRichTextField::Copy(const wxRichTextField& obj)
+{
+    wxRichTextParagraphLayoutBox::Copy(obj);
+
+    UpdateField();
+}
+
+// Edit properties via a GUI
+bool wxRichTextField::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->EditProperties(this, parent, buffer);
+
+    return false;
+}
+
+bool wxRichTextField::CanEditProperties() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->CanEditProperties((wxRichTextField*) this);
+
+    return false;
+}
+
+wxString wxRichTextField::GetPropertiesMenuLabel() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->GetPropertiesMenuLabel((wxRichTextField*) this);
+
+    return wxEmptyString;
+}
+
+bool wxRichTextField::UpdateField()
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->UpdateField((wxRichTextField*) this);
+
+    return false;
+}
+
+bool wxRichTextField::IsTopLevel() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->IsTopLevel((wxRichTextField*) this);
+
+    return true;
+}
+
+IMPLEMENT_CLASS(wxRichTextFieldType, wxObject)
+
+IMPLEMENT_CLASS(wxRichTextFieldTypeStandard, wxRichTextFieldType)
+
+wxRichTextFieldTypeStandard::wxRichTextFieldTypeStandard(const wxString& name, const wxString& label, int displayStyle)
+{
+    Init();
+
+    SetName(name);
+    SetLabel(label);
+    SetDisplayStyle(displayStyle);
+}
+
+wxRichTextFieldTypeStandard::wxRichTextFieldTypeStandard(const wxString& name, const wxBitmap& bitmap, int displayStyle)
+{
+    Init();
+
+    SetName(name);
+    SetBitmap(bitmap);
+    SetDisplayStyle(displayStyle);
+}
+
+void wxRichTextFieldTypeStandard::Init()
+{
+    m_displayStyle = wxRICHTEXT_FIELD_STYLE_RECTANGLE;
+    m_font = wxFont(6, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+    m_textColour = *wxWHITE;
+    m_borderColour = *wxBLACK;
+    m_backgroundColour = *wxBLACK;
+    m_verticalPadding = 1;
+    m_horizontalPadding = 3;
+    m_horizontalMargin = 2;
+    m_verticalMargin = 0;
+}
+
+void wxRichTextFieldTypeStandard::Copy(const wxRichTextFieldTypeStandard& field)
+{
+    wxRichTextFieldType::Copy(field);
+
+    m_label = field.m_label;
+    m_displayStyle = field.m_displayStyle;
+    m_font = field.m_font;
+    m_textColour = field.m_textColour;
+    m_borderColour = field.m_borderColour;
+    m_backgroundColour = field.m_backgroundColour;
+    m_verticalPadding = field.m_verticalPadding;
+    m_horizontalPadding = field.m_horizontalPadding;
+    m_horizontalMargin = field.m_horizontalMargin;
+    m_bitmap = field.m_bitmap;
+}
+
+bool wxRichTextFieldTypeStandard::Draw(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& WXUNUSED(context), const wxRichTextRange& WXUNUSED(range), const wxRichTextSelection& selection, const wxRect& rect, int descent, int WXUNUSED(style))
+{
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_COMPOSITE)
+        return false; // USe default composite drawing
+    else // if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_RECTANGLE || m_displayStyle == wxRICHTEXT_FIELD_STYLE_NOBORDER)
+    {
+        int borderSize = 1;
+
+        wxPen borderPen(m_borderColour, 1, wxSOLID);
+        wxBrush backgroundBrush(m_backgroundColour);
+        wxColour textColour(m_textColour);
+
+        if (selection.WithinSelection(obj->GetRange().GetStart(), obj))
+        {
+            wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
+            wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
+
+            borderPen = wxPen(highlightTextColour, 1, wxSOLID);
+            backgroundBrush = wxBrush(highlightColour);
+
+            wxCheckSetBrush(dc, backgroundBrush);
+            wxCheckSetPen(dc, wxPen(highlightColour, 1, wxSOLID));
+            dc.DrawRectangle(rect);
+        }
+
+        if (m_displayStyle != wxRICHTEXT_FIELD_STYLE_NO_BORDER)
+            borderSize = 0;
+
+        // objectRect is the area where the content is drawn, after margins around it have been taken into account
+        wxRect objectRect = wxRect(wxPoint(rect.x + m_horizontalMargin, rect.y + wxMax(0, rect.height - descent - obj->GetCachedSize().y)),
+            wxSize(obj->GetCachedSize().x - 2*m_horizontalMargin - borderSize, obj->GetCachedSize().y));
+
+        // clientArea is where the text is actually written
+        wxRect clientArea = objectRect;
+
+        if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_RECTANGLE)
+        {
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawRoundedRectangle(objectRect, 4.0);
+        }
+        else if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_START_TAG)
+        {
+            int arrowLength = objectRect.height/2;
+            clientArea.width -= (arrowLength - m_horizontalPadding);
+
+            wxPoint pts[5];
+            pts[0].x = objectRect.x; pts[0].y = objectRect.y;
+            pts[1].x = objectRect.x + objectRect.width - arrowLength; pts[1].y = objectRect.y;
+            pts[2].x = objectRect.x + objectRect.width; pts[2].y = objectRect.y + (objectRect.height/2);
+            pts[3].x = objectRect.x + objectRect.width - arrowLength; pts[3].y = objectRect.y + objectRect.height;
+            pts[4].x = objectRect.x; pts[4].y = objectRect.y + objectRect.height;
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawPolygon(5, pts);
+        }
+        else if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_END_TAG)
+        {
+            int arrowLength = objectRect.height/2;
+            clientArea.width -= (arrowLength - m_horizontalPadding);
+            clientArea.x += (arrowLength - m_horizontalPadding);
+
+            wxPoint pts[5];
+            pts[0].x = objectRect.x + objectRect.width; pts[0].y = objectRect.y;
+            pts[1].x = objectRect.x + arrowLength; pts[1].y = objectRect.y;
+            pts[2].x = objectRect.x; pts[2].y = objectRect.y + (objectRect.height/2);
+            pts[3].x = objectRect.x + arrowLength; pts[3].y = objectRect.y + objectRect.height;
+            pts[4].x = objectRect.x + objectRect.width; pts[4].y = objectRect.y + objectRect.height;
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawPolygon(5, pts);
+        }
+
+        if (m_bitmap.IsOk())
+        {
+            int x = clientArea.x + (clientArea.width - m_bitmap.GetWidth())/2;
+            int y = clientArea.y + m_verticalPadding;
+            dc.DrawBitmap(m_bitmap, x, y, true);
+
+            if (selection.WithinSelection(obj->GetRange().GetStart(), obj))
+            {
+                wxCheckSetBrush(dc, *wxBLACK_BRUSH);
+                wxCheckSetPen(dc, *wxBLACK_PEN);
+                dc.SetLogicalFunction(wxINVERT);
+                dc.DrawRectangle(wxRect(x, y, m_bitmap.GetWidth(), m_bitmap.GetHeight()));
+                dc.SetLogicalFunction(wxCOPY);
+            }
+        }
+        else
+        {
+            wxString label(m_label);
+            if (label.IsEmpty())
+                label = wxT("??");
+            int w, h, maxDescent;
+            dc.SetFont(m_font);
+            dc.GetTextExtent(m_label, & w, &h, & maxDescent);
+            dc.SetTextForeground(textColour);
+
+            int x = clientArea.x + (clientArea.width - w)/2;
+            int y = clientArea.y + (clientArea.height - (h - maxDescent))/2;
+            dc.DrawText(m_label, x, y);
+        }
+    }
+
+    return true;
+}
+
+bool wxRichTextFieldTypeStandard::Layout(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& WXUNUSED(rect), const wxRect& WXUNUSED(parentRect), int style)
+{
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_COMPOSITE)
+        return false; // USe default composite layout
+
+    wxSize size = GetSize(obj, dc, context, style);
+    obj->SetCachedSize(size);
+    obj->SetMinSize(size);
+    obj->SetMaxSize(size);
+    return true;
+}
+
+bool wxRichTextFieldTypeStandard::GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+{
+    if (IsTopLevel(obj))
+        return obj->wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position);
+    else
+    {
+        wxSize sz = GetSize(obj, dc, context, 0);
+        if (partialExtents)
+        {
+            int lastSize;
+            if (partialExtents->GetCount() > 0)
+                lastSize = (*partialExtents)[partialExtents->GetCount()-1];
+            else
+                lastSize = 0;
+            partialExtents->Add(lastSize + sz.x);
+        }
+        size = sz;
+       return true;
+    }
+}
+
+wxSize wxRichTextFieldTypeStandard::GetSize(wxRichTextField* WXUNUSED(obj), wxDC& dc, wxRichTextDrawingContext& WXUNUSED(context), int WXUNUSED(style)) const
+{
+    int borderSize = 1;
+    int w = 0, h = 0, maxDescent = 0;
+
+    wxSize sz;
+    if (m_bitmap.IsOk())
+    {
+        w = m_bitmap.GetWidth();
+        h = m_bitmap.GetHeight();
+
+        sz = wxSize(w + m_horizontalMargin*2, h + m_verticalMargin*2);
+    }
+    else
+    {
+        wxString label(m_label);
+        if (label.IsEmpty())
+            label = wxT("??");
+        dc.SetFont(m_font);
+        dc.GetTextExtent(label, & w, &h, & maxDescent);
+
+        sz = wxSize(w + m_horizontalPadding*2 + m_horizontalMargin*2, h + m_verticalPadding *2 + m_verticalMargin*2);
+    }
+
+    if (m_displayStyle != wxRICHTEXT_FIELD_STYLE_NO_BORDER)
+    {
+        sz.x += borderSize*2;
+        sz.y += borderSize*2;
+    }
+
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_START_TAG || m_displayStyle == wxRICHTEXT_FIELD_STYLE_END_TAG)
+    {
+        // Add space for the arrow
+        sz.x += (sz.y/2 - m_horizontalPadding);
+    }
+
+    return sz;
+}
+
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextCell, wxRichTextBox)
 
 wxRichTextCell::wxRichTextCell(wxRichTextObject* parent):
@@ -8484,7 +8861,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
     wxArrayInt absoluteColWidths;
     absoluteColWidths.Add(0, m_colCount);
-    // wxArrayInt absoluteColWidthsSpanning(m_colCount);
+
     wxArrayInt percentageColWidths;
     percentageColWidths.Add(0, m_colCount);
     // wxArrayInt percentageColWidthsSpanning(m_colCount);
@@ -9484,6 +9861,7 @@ public:
     {
         wxRichTextBuffer::CleanUpHandlers();
         wxRichTextBuffer::CleanUpDrawingHandlers();
+        wxRichTextBuffer::CleanUpFieldTypes();
         wxRichTextDecimalToRoman(-1);
         wxRichTextParagraph::ClearDefaultTabs();
         wxRichTextCtrl::ClearAvailableFontNames();
@@ -9851,6 +10229,7 @@ bool wxRichTextAction::Undo()
 
             container->DeleteRange(GetRange());
             container->UpdateRanges();
+
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             container->InvalidateHierarchy(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
@@ -9882,6 +10261,7 @@ bool wxRichTextAction::Undo()
 
             container->InsertFragment(GetRange().GetStart(), m_oldParagraphs);
             container->UpdateRanges();
+
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             container->InvalidateHierarchy(GetRange());
@@ -11166,7 +11546,6 @@ void wxRichTextFontTable::Clear()
 
 // wxTextBoxAttr
 
-
 void wxTextBoxAttr::Reset()
 {
     m_flags = 0;
@@ -12718,5 +13097,45 @@ void wxRichTextBuffer::CleanUpDrawingHandlers()
     sm_drawingHandlers.Clear();
 }
 
+void wxRichTextBuffer::AddFieldType(wxRichTextFieldType *fieldType)
+{
+    sm_fieldTypes[fieldType->GetName()] = fieldType;
+}
+
+bool wxRichTextBuffer::RemoveFieldType(const wxString& name)
+{
+    wxRichTextFieldTypeHashMap::iterator it = sm_fieldTypes.find(name);
+    if (it == sm_fieldTypes.end())
+        return false;
+    else
+    {
+        wxRichTextFieldType* fieldType = it->second;
+        sm_fieldTypes.erase(it);
+        delete fieldType;
+        return true;
+    }
+}
+
+wxRichTextFieldType *wxRichTextBuffer::FindFieldType(const wxString& name)
+{
+    wxRichTextFieldTypeHashMap::iterator it = sm_fieldTypes.find(name);
+    if (it == sm_fieldTypes.end())
+        return NULL;
+    else
+        return it->second;
+}
+
+void wxRichTextBuffer::CleanUpFieldTypes()
+{
+    wxRichTextFieldTypeHashMap::iterator it;
+    for( it = sm_fieldTypes.begin(); it != sm_fieldTypes.end(); ++it )
+    {
+        wxRichTextFieldType* fieldType = it->second;
+        delete fieldType;
+    }
+
+    sm_fieldTypes.clear();
+}
+
 #endif
     // wxUSE_RICHTEXT
index 7468172126a8ece82323600037e154e0f7e0409b..30e9fa2ce41d28276c1534098c3607cbba9d0386 100644 (file)
@@ -576,7 +576,7 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event)
     wxRichTextObject* hitObj = NULL;
     wxRichTextObject* contextObj = NULL;
     wxRichTextDrawingContext context(& GetBuffer());
-    int hit = GetBuffer().HitTest(dc, context, event.GetLogicalPosition(dc), position, & hitObj, & contextObj);
+    int hit = GetBuffer().HitTest(dc, context, event.GetLogicalPosition(dc), position, & hitObj, & contextObj, wxRICHTEXT_HITTEST_HONOUR_ATOMIC);
 
 #if wxUSE_DRAG_AND_DROP
     // If there's no selection, or we're not inside it, this isn't an attempt to initiate Drag'n'Drop
@@ -644,7 +644,7 @@ void wxRichTextCtrl::OnLeftUp(wxMouseEvent& event)
         wxRichTextObject* contextObj = NULL;
         wxRichTextDrawingContext context(& GetBuffer());
         // Only get objects at this level, not nested, because otherwise we couldn't swipe text at a single level.
-        int hit = GetFocusObject()->HitTest(dc, context, logicalPt, position, & hitObj, & contextObj, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS);
+        int hit = GetFocusObject()->HitTest(dc, context, logicalPt, position, & hitObj, & contextObj, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS|wxRICHTEXT_HITTEST_HONOUR_ATOMIC);
 
 #if wxUSE_DRAG_AND_DROP
         if (m_preDrag)
@@ -656,7 +656,7 @@ void wxRichTextCtrl::OnLeftUp(wxMouseEvent& event)
             long position = 0;
             wxRichTextObject* hitObj = NULL;
             wxRichTextObject* contextObj = NULL;
-            int hit = GetBuffer().HitTest(dc, context, event.GetLogicalPosition(dc), position, & hitObj, & contextObj);
+            int hit = GetBuffer().HitTest(dc, context, event.GetLogicalPosition(dc), position, & hitObj, & contextObj, wxRICHTEXT_HITTEST_HONOUR_ATOMIC);
             wxRichTextParagraphLayoutBox* oldFocusObject = GetFocusObject();
             wxRichTextParagraphLayoutBox* container = wxDynamicCast(contextObj, wxRichTextParagraphLayoutBox);
             if (container && container != GetFocusObject() && container->AcceptsFocus())
@@ -957,7 +957,7 @@ void wxRichTextCtrl::OnRightClick(wxMouseEvent& event)
     wxRichTextObject* hitObj = NULL;
     wxRichTextObject* contextObj = NULL;
     wxRichTextDrawingContext context(& GetBuffer());
-    int hit = GetFocusObject()->HitTest(dc, context, logicalPt, position, & hitObj, & contextObj);
+    int hit = GetFocusObject()->HitTest(dc, context, logicalPt, position, & hitObj, & contextObj, wxRICHTEXT_HITTEST_HONOUR_ATOMIC);
 
     if (hitObj && hitObj->GetContainer() != GetFocusObject())
     {
@@ -1183,7 +1183,6 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
             ScrollIntoView(m_caretPosition, WXK_LEFT);
 
             // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion.
-            //if (deletions > 0)
             {
                 wxRichTextEvent cmdEvent(
                     wxEVT_COMMAND_RICHTEXT_DELETE,
@@ -1322,7 +1321,6 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
         ScrollIntoView(m_caretPosition, WXK_LEFT);
 
         // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion.
-        //if (deletions > 0)
         {
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_DELETE,
@@ -1396,7 +1394,6 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
         ScrollIntoView(m_caretPosition, WXK_LEFT);
 
         // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion.
-        //if (deletions > 0)
         {
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_DELETE,
@@ -2092,7 +2089,7 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags)
     }
 
     wxRichTextParagraphLayoutBox* container = GetFocusObject();
-    int hitTestFlags = wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS|wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS;
+    int hitTestFlags = wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS|wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS|wxRICHTEXT_HITTEST_HONOUR_ATOMIC;
 
     if (notInThisObject)
     {
@@ -3004,6 +3001,13 @@ wxRichTextBox* wxRichTextCtrl::WriteTextBox(const wxRichTextAttr& textAttr)
     return box;
 }
 
+wxRichTextField* wxRichTextCtrl::WriteField(const wxString& fieldType, const wxRichTextProperties& properties,
+                            const wxRichTextAttr& textAttr)
+{
+    return GetFocusObject()->InsertFieldWithUndo(& GetBuffer(), m_caretPosition+1, fieldType, properties,
+                this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE, textAttr);
+}
+
 // Write a table at the current insertion point, returning the table.
 wxRichTextTable* wxRichTextCtrl::WriteTable(int rows, int cols, const wxRichTextAttr& tableAttr, const wxRichTextAttr& cellAttr)
 {
@@ -4576,7 +4580,6 @@ void wxRichTextCtrl::EnableVerticalScrollbar(bool enable)
     SetupScrollbars();
 }
 
-
 #if wxRICHTEXT_USE_OWN_CARET
 
 // ----------------------------------------------------------------------------
index e798ee5935a5349537038e3f5fe5315fc3b9acf3..2d8acafb8274e8909b81ae95d5795f57abb99403 100644 (file)
@@ -172,6 +172,8 @@ wxRichTextObject* wxRichTextXMLHandler::CreateObjectForXMLName(wxRichTextObject*
         return new wxRichTextCell;
     else if (name == wxT("table"))
         return new wxRichTextTable;
+    else if (name == wxT("field"))
+        return new wxRichTextField;
     else
         return NULL;
 }
@@ -1085,6 +1087,7 @@ bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream& stream, wxRichT
         OutputString(stream, wxT("</boxstyle>"));
     }
 
+    WriteProperties(stream, def->GetProperties(), level);
 
     return true;
 }