]> git.saurik.com Git - wxWidgets.git/commitdiff
Style listbox now shows current style
authorJulian Smart <julian@anthemion.co.uk>
Tue, 12 Sep 2006 10:19:45 +0000 (10:19 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Tue, 12 Sep 2006 10:19:45 +0000 (10:19 +0000)
Added combo control for selecting styles
Updated the sample to show the combo control

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41174 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/richtext/richtextstyles.h
samples/richtext/richtext.cpp
src/richtext/richtextstyles.cpp

index 08ff7e683b7600472d4275ee1bfa5debf20b52b9..997d3e97445963a4ddf2aca0cef759f2c7794ec1 100644 (file)
@@ -2,9 +2,9 @@
 // Name:        richtextstyles.h
 // Purpose:     Style management for wxRichTextCtrl
 // Author:      Julian Smart
-// Modified by: 
+// Modified by:
 // Created:     2005-09-30
-// RCS-ID:      
+// RCS-ID:
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 #include "wx/htmllbox.h"
 #endif
 
+#if wxUSE_COMBOCTRL
+#include "wx/combo.h"
+#endif
+
 /*!
  * Forward declarations
  */
@@ -188,10 +192,23 @@ class WXDLLIMPEXP_RICHTEXT wxRichTextStyleListBox: public wxHtmlListBox
     DECLARE_EVENT_TABLE()
 
 public:
+    wxRichTextStyleListBox()
+    {
+        Init();
+    }
     wxRichTextStyleListBox(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
         const wxSize& size = wxDefaultSize, long style = 0);
     virtual ~wxRichTextStyleListBox();
 
+    void Init()
+    {
+        m_styleSheet = NULL;
+        m_richTextCtrl = NULL;
+    }
+
+    bool Create(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
+        const wxSize& size = wxDefaultSize, long style = 0);
+
     /// Creates a suitable HTML fragment for a definition
     wxString CreateHTML(wxRichTextStyleDefinition* def) const;
 
@@ -203,26 +220,42 @@ public:
     void SetRichTextCtrl(wxRichTextCtrl* ctrl) { m_richTextCtrl = ctrl; }
     wxRichTextCtrl* GetRichTextCtrl() const { return m_richTextCtrl; }
 
-    // Get style for index
+    /// Get style for index
     wxRichTextStyleDefinition* GetStyle(size_t i) const ;
 
+    /// Get index for style name
+    int GetIndexForStyle(const wxString& name) const ;
+
+    /// Set selection for string, returning the index.
+    int SetStyleSelection(const wxString& name);
+
     /// Updates the list
     void UpdateStyles();
 
+    /// Do selection
+    void DoSelection(int i);
+
     /// React to selection
     void OnSelect(wxCommandEvent& event);
 
     /// Left click
     void OnLeftDown(wxMouseEvent& event);
 
+    /// Auto-select from style under caret in idle time
+    void OnIdle(wxIdleEvent& event);
+
 #if 0
     virtual wxColour GetSelectedTextColour(const wxColour& colFg) const;
     virtual wxColour GetSelectedTextBgColour(const wxColour& colBg) const;
 #endif
 
-    // Convert units in tends of a millimetre to device units
+    /// Convert units in tends of a millimetre to device units
     int ConvertTenthsMMToPixels(wxDC& dc, int units) const;
 
+    /// Can we set the selection based on the editor caret position?
+    /// Need to override this if being used in a combobox popup
+    virtual bool CanAutoSetSelection() { return true; }
+
 protected:
     /// Returns the HTML for this item
     virtual wxString OnGetItem(size_t n) const;
@@ -232,7 +265,117 @@ private:
     wxRichTextStyleSheet*   m_styleSheet;
     wxRichTextCtrl*         m_richTextCtrl;
 };
+
+#if wxUSE_COMBOCTRL
+
+/*!
+ * Style drop-down for a wxComboCtrl
+ */
+
+class wxRichTextStyleComboPopup : public wxRichTextStyleListBox, public wxComboPopup
+{
+public:
+    virtual void Init()
+    {
+        m_itemHere = -1; // hot item in list
+        m_value = -1;
+    }
+
+    virtual bool Create( wxWindow* parent )
+    {
+        return wxRichTextStyleListBox::Create(parent, wxID_ANY,
+                                  wxPoint(0,0), wxDefaultSize,
+                                  wxSIMPLE_BORDER);
+    }
+
+    virtual wxWindow *GetControl() { return this; }
+
+    virtual void SetStringValue( const wxString& s );
+
+    virtual wxString GetStringValue() const;
+
+    /// Can we set the selection based on the editor caret position?
+    // virtual bool CanAutoSetSelection() { return ((m_combo == NULL) || !m_combo->IsPopupShown()); }
+    virtual bool CanAutoSetSelection() { return false; }
+
+    //
+    // Popup event handlers
+    //
+
+    // Mouse hot-tracking
+    void OnMouseMove(wxMouseEvent& event);
+
+    // On mouse left, set the value and close the popup
+    void OnMouseClick(wxMouseEvent& WXUNUSED(event));
+
+protected:
+
+    int             m_itemHere; // hot item in popup
+    int             m_value;
+
+private:
+    DECLARE_EVENT_TABLE()
+};
+
+/*!
+ * wxRichTextStyleComboCtrl
+ * A combo for applying styles.
+ */
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextStyleComboCtrl: public wxComboCtrl
+{
+    DECLARE_CLASS(wxRichTextStyleComboCtrl)
+    DECLARE_EVENT_TABLE()
+
+public:
+    wxRichTextStyleComboCtrl()
+    {
+        Init();
+    }
+
+    wxRichTextStyleComboCtrl(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
+        const wxSize& size = wxDefaultSize, long style = wxCB_READONLY)
+    {
+        Init();
+        Create(parent, id, pos, size, style);
+    }
+
+    virtual ~wxRichTextStyleComboCtrl() {}
+
+    void Init()
+    {
+        m_stylePopup = NULL;
+    }
+
+    bool Create(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
+        const wxSize& size = wxDefaultSize, long style = 0);
+
+    /// Updates the list
+    void UpdateStyles() { m_stylePopup->UpdateStyles(); }
+
+    /// Associates the control with a style manager
+    void SetStyleSheet(wxRichTextStyleSheet* styleSheet) { m_stylePopup->SetStyleSheet(styleSheet); }
+    wxRichTextStyleSheet* GetStyleSheet() const { return m_stylePopup->GetStyleSheet(); }
+
+    /// Associates the control with a wxRichTextCtrl
+    void SetRichTextCtrl(wxRichTextCtrl* ctrl) { m_stylePopup->SetRichTextCtrl(ctrl); }
+    wxRichTextCtrl* GetRichTextCtrl() const { return m_stylePopup->GetRichTextCtrl(); }
+
+    /// Gets the style popup
+    wxRichTextStyleComboPopup* GetStylePopup() const { return m_stylePopup; }
+
+    /// Auto-select from style under caret in idle time
+    void OnIdle(wxIdleEvent& event);
+
+protected:
+    wxRichTextStyleComboPopup*  m_stylePopup;
+};
+
+#endif
+    // wxUSE_COMBOCTRL
+
 #endif
+    // wxUSE_HTML
 
 #endif
     // wxUSE_RICHTEXT
index 2c8d0a3df6a11cae65c5e60f2df83a58556c99d2..37f0089f6bb892a500c25ada7f294a1805f1a077 100644 (file)
@@ -490,6 +490,9 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
     toolBar->AddSeparator();
     toolBar->AddTool(ID_FORMAT_FONT, wxBitmap(font_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Font"));
 
+    wxRichTextStyleComboCtrl* combo = new wxRichTextStyleComboCtrl(toolBar, wxID_ANY, wxDefaultPosition, wxSize(200, -1));
+    toolBar->AddControl(combo);
+
     toolBar->Realize();
 
     wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, GetClientSize(), wxSP_NO_XP_THEME|wxSP_3D|wxSP_LIVE_UPDATE);
@@ -503,6 +506,10 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
 
     m_richTextCtrl->SetFont(font);
 
+    combo->SetStyleSheet(wxGetApp().GetStyleSheet());
+    combo->SetRichTextCtrl(m_richTextCtrl);
+    combo->UpdateStyles();
+
     wxRichTextStyleListBox* styleListBox = new wxRichTextStyleListBox(splitter, wxID_ANY);
 
     wxSize display = wxGetDisplaySize();
index 309a110176cc231321ae341de18e45f8d2e96302..183daea53a2c4174575064ca874e0f656ec7870d 100644 (file)
@@ -100,13 +100,20 @@ IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox)
 BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox)
     EVT_LISTBOX(wxID_ANY, wxRichTextStyleListBox::OnSelect)
     EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown)
+    EVT_IDLE(wxRichTextStyleListBox::OnIdle)
 END_EVENT_TABLE()
 
 wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos,
-    const wxSize& size, long style): wxHtmlListBox(parent, id, pos, size, style)
+    const wxSize& size, long style)
 {
-    m_styleSheet = NULL;
-    m_richTextCtrl = NULL;
+    Init();
+    Create(parent, id, pos, size, style);
+}
+
+bool wxRichTextStyleListBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
+        const wxSize& size, long style)
+{
+    return wxHtmlListBox::Create(parent, id, pos, size, style);
 }
 
 wxRichTextStyleListBox::~wxRichTextStyleListBox()
@@ -164,6 +171,37 @@ void wxRichTextStyleListBox::UpdateStyles()
     }
 }
 
+// Get index for style name
+int wxRichTextStyleListBox::GetIndexForStyle(const wxString& name) const
+{
+    if (GetStyleSheet())
+    {
+        int i;
+        for (i = 0; i < (int) GetStyleSheet()->GetParagraphStyleCount(); i++)
+        {
+            wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->GetParagraphStyle(i);
+            if (def->GetName() == name)
+                return i;
+        }
+        for (i = 0; i < (int) GetStyleSheet()->GetCharacterStyleCount(); i++)
+        {
+            wxRichTextCharacterStyleDefinition* def = GetStyleSheet()->GetCharacterStyle(i);
+            if (def->GetName() == name)
+                return i + (int) GetStyleSheet()->GetParagraphStyleCount();
+        }
+    }
+    return -1;
+}
+
+/// Set selection for string
+int wxRichTextStyleListBox::SetStyleSelection(const wxString& name)
+{
+    int i = GetIndexForStyle(name);
+    if (i > -1)
+        SetSelection(i);
+    return i;
+}
+
 // Convert a colour to a 6-digit hex string
 static wxString ColourToHexString(const wxColour& col)
 {
@@ -269,24 +307,62 @@ void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
     wxVListBox::OnLeftDown(event);
 
     int item = HitTest(event.GetPosition());
+    if (item != wxNOT_FOUND)
+        DoSelection(item);
+}
 
-    if ( item != wxNOT_FOUND )
+/// Auto-select from style under caret in idle time
+void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
+{
+    if (CanAutoSetSelection() && GetRichTextCtrl())
     {
-        wxRichTextStyleDefinition* def = GetStyle(item);
-        if (def && GetRichTextCtrl())
+        wxRichTextParagraph* para = GetRichTextCtrl()->GetBuffer().GetParagraphAtPosition(GetRichTextCtrl()->GetCaretPosition());
+        wxRichTextObject* obj = GetRichTextCtrl()->GetBuffer().GetLeafObjectAtPosition(GetRichTextCtrl()->GetCaretPosition());
+
+        wxString styleName;
+
+        // Take into account current default style just chosen by user
+        if (GetRichTextCtrl()->IsDefaultStyleShowing())
         {
-            wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
+            if (!GetRichTextCtrl()->GetDefaultStyleEx().GetCharacterStyleName().IsEmpty())
+                styleName = GetRichTextCtrl()->GetDefaultStyleEx().GetCharacterStyleName();
+            else if (!GetRichTextCtrl()->GetDefaultStyleEx().GetParagraphStyleName().IsEmpty())
+                styleName = GetRichTextCtrl()->GetDefaultStyleEx().GetParagraphStyleName();
+        }
+        else if (obj && !obj->GetAttributes().GetCharacterStyleName().IsEmpty())
+        {
+            styleName = obj->GetAttributes().GetCharacterStyleName();
+        }
+        else if (para && !para->GetAttributes().GetParagraphStyleName().IsEmpty())
+        {
+            styleName = para->GetAttributes().GetParagraphStyleName();
+        }
 
-            // Flags are defined within each definition, so only certain
-            // attributes are applied.
-            wxRichTextAttr attr(def->GetStyle());
+        int sel = GetSelection();
+        if (!styleName.IsEmpty())
+        {
+            // Don't do the selection if it's already set
+            if (sel == GetIndexForStyle(styleName))
+                return;
 
-            if (m_richTextCtrl->HasSelection())
-                m_richTextCtrl->SetStyle(m_richTextCtrl->GetSelectionRange(), attr);
-            else
-                m_richTextCtrl->SetDefaultStyle(attr);
+            SetStyleSelection(styleName);
+        }
+        else if (sel != -1)
+            SetSelection(-1);
+    }
+    event.Skip();
+}
 
-            m_richTextCtrl->SetFocus();
+/// Do selection
+void wxRichTextStyleListBox::DoSelection(int item)
+{
+    if ( item != wxNOT_FOUND )
+    {
+        wxRichTextStyleDefinition* def = GetStyle(item);
+        if (def && GetRichTextCtrl())
+        {
+            GetRichTextCtrl()->ApplyStyle(def);
+            GetRichTextCtrl()->SetFocus();
         }
     }
 }
@@ -303,6 +379,150 @@ wxColour wxRichTextStyleListBox::GetSelectedTextBgColour(const wxColour& colBg)
 }
 #endif
 
+#if wxUSE_COMBOCTRL
+
+/*!
+ * Style drop-down for a wxComboCtrl
+ */
+
+
+BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup, wxRichTextStyleListBox)
+    EVT_MOTION(wxRichTextStyleComboPopup::OnMouseMove)
+    EVT_LEFT_DOWN(wxRichTextStyleComboPopup::OnMouseClick)
+END_EVENT_TABLE()
+
+void wxRichTextStyleComboPopup::SetStringValue( const wxString& s )
+{
+    m_value = SetStyleSelection(s);
+}
+
+wxString wxRichTextStyleComboPopup::GetStringValue() const
+{
+    int sel = m_value;
+    if (sel > -1)
+    {
+        wxRichTextStyleDefinition* def = GetStyle(sel);
+        if (def)
+            return def->GetName();
+    }
+    return wxEmptyString;
+}
+
+//
+// Popup event handlers
+//
+
+// Mouse hot-tracking
+void wxRichTextStyleComboPopup::OnMouseMove(wxMouseEvent& event)
+{
+    // Move selection to cursor if it is inside the popup
+
+    int itemHere = wxRichTextStyleListBox::HitTest(event.GetPosition());
+    if ( itemHere >= 0 )
+    {
+        wxRichTextStyleListBox::SetSelection(itemHere);
+        m_itemHere = itemHere;
+    }
+    event.Skip();
+}
+
+// On mouse left, set the value and close the popup
+void wxRichTextStyleComboPopup::OnMouseClick(wxMouseEvent& WXUNUSED(event))
+{
+    if (m_itemHere >= 0)
+        m_value = m_itemHere;
+
+    // Ordering is important, so we don't dismiss this popup accidentally
+    // by setting the focus elsewhere e.g. in DoSelection
+    Dismiss();
+
+    if (m_itemHere >= 0)
+        wxRichTextStyleListBox::DoSelection(m_itemHere);
+}
+
+/*!
+ * wxRichTextStyleComboCtrl
+ * A combo for applying styles.
+ */
+
+IMPLEMENT_CLASS(wxRichTextStyleComboCtrl, wxComboCtrl)
+
+BEGIN_EVENT_TABLE(wxRichTextStyleComboCtrl, wxComboCtrl)
+    EVT_IDLE(wxRichTextStyleComboCtrl::OnIdle)
+END_EVENT_TABLE()
+
+bool wxRichTextStyleComboCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
+        const wxSize& size, long style)
+{
+    if (!wxComboCtrl::Create(parent, id, wxEmptyString, pos, size, style))
+        return false;
+
+    SetPopupMaxHeight(400);
+
+    m_stylePopup = new wxRichTextStyleComboPopup;
+
+    SetPopupControl(m_stylePopup);
+
+    return true;
+}
+
+/// Auto-select from style under caret in idle time
+
+// TODO: must be able to show italic, bold, combinations
+// in style box. Do we have a concept of automatic, temporary
+// styles that are added whenever we wish to show a style
+// that doesn't exist already? E.g. "Bold, Italic, Underline".
+// Word seems to generate these things on the fly.
+// If there's a named style already, it uses e.g. Heading1 + Bold, Italic
+// If you unembolden text in a style that has bold, it uses the
+// term "Not bold".
+// TODO: order styles alphabetically. This means indexes can change,
+// so need a different way to specify selections, i.e. by name.
+
+void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent& event)
+{
+    if (GetRichTextCtrl() && !IsPopupShown())
+    {
+        wxRichTextParagraph* para = GetRichTextCtrl()->GetBuffer().GetParagraphAtPosition(GetRichTextCtrl()->GetCaretPosition());
+        wxRichTextObject* obj = GetRichTextCtrl()->GetBuffer().GetLeafObjectAtPosition(GetRichTextCtrl()->GetCaretPosition());
+
+        wxString styleName;
+
+        // Take into account current default style just chosen by user
+        if (GetRichTextCtrl()->IsDefaultStyleShowing())
+        {
+            if (!GetRichTextCtrl()->GetDefaultStyleEx().GetCharacterStyleName().IsEmpty())
+                styleName = GetRichTextCtrl()->GetDefaultStyleEx().GetCharacterStyleName();
+            else if (!GetRichTextCtrl()->GetDefaultStyleEx().GetParagraphStyleName().IsEmpty())
+                styleName = GetRichTextCtrl()->GetDefaultStyleEx().GetParagraphStyleName();
+        }
+        else if (obj && !obj->GetAttributes().GetCharacterStyleName().IsEmpty())
+        {
+            styleName = obj->GetAttributes().GetCharacterStyleName();
+        }
+        else if (para && !para->GetAttributes().GetParagraphStyleName().IsEmpty())
+        {
+            styleName = para->GetAttributes().GetParagraphStyleName();
+        }
+
+        wxString currentValue = GetValue();
+        if (!styleName.IsEmpty())
+        {
+            // Don't do the selection if it's already set
+            if (currentValue == styleName)
+                return;
+
+            SetValue(styleName);
+        }
+        else if (!currentValue.IsEmpty())
+            SetValue(wxEmptyString);
+    }
+    event.Skip();
+}
+
+#endif
+    // wxUSE_COMBOCTRL
+
 #endif
     // wxUSE_HTML