]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextstyles.cpp
fixing coordinate conversions
[wxWidgets.git] / src / richtext / richtextstyles.cpp
index 309a110176cc231321ae341de18e45f8d2e96302..e0bad0c3adca78d507d9679fb4ad0534d4c87ee4 100644 (file)
@@ -13,7 +13,7 @@
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-    #pragma hdrstop
+  #pragma hdrstop
 #endif
 
 #if wxUSE_RICHTEXT
@@ -21,8 +21,7 @@
 #include "wx/richtext/richtextstyles.h"
 
 #ifndef WX_PRECOMP
-    #include "wx/dcclient.h"
-    #include "wx/module.h"
+  #include "wx/wx.h"
 #endif
 
 #include "wx/filename.h"
@@ -35,6 +34,38 @@ IMPLEMENT_CLASS(wxRichTextStyleDefinition, wxObject)
 IMPLEMENT_CLASS(wxRichTextCharacterStyleDefinition, wxRichTextStyleDefinition)
 IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition)
 
+/*!
+ * A definition
+ */
+
+void wxRichTextStyleDefinition::Copy(const wxRichTextStyleDefinition& def)
+{
+    m_name = def.m_name;
+    m_baseStyle = def.m_baseStyle;
+    m_style = def.m_style;
+}
+
+bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition& def) const
+{
+    return (m_name == def.m_name && m_baseStyle == def.m_baseStyle && m_style == def.m_style);
+}
+
+/*!
+ * Paragraph style definition
+ */
+
+void wxRichTextParagraphStyleDefinition::Copy(const wxRichTextParagraphStyleDefinition& def)
+{
+    wxRichTextStyleDefinition::Copy(def);
+
+    m_nextStyle = def.m_nextStyle;
+}
+
+bool wxRichTextParagraphStyleDefinition::operator ==(const wxRichTextParagraphStyleDefinition& def) const
+{
+    return (Eq(def) && m_nextStyle == def.m_nextStyle);
+}
+
 /*!
  * The style manager
  */
@@ -89,6 +120,48 @@ void wxRichTextStyleSheet::DeleteStyles()
     WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions);
 }
 
+/// Add a definition to the character style list
+bool wxRichTextStyleSheet::AddCharacterStyle(wxRichTextCharacterStyleDefinition* def)
+{
+    def->GetStyle().SetCharacterStyleName(def->GetName());
+    return AddStyle(m_characterStyleDefinitions, def);
+}
+
+/// Add a definition to the paragraph style list
+bool wxRichTextStyleSheet::AddParagraphStyle(wxRichTextParagraphStyleDefinition* def)
+{
+    def->GetStyle().SetParagraphStyleName(def->GetName());
+    return AddStyle(m_paragraphStyleDefinitions, def);
+}
+
+/// Copy
+void wxRichTextStyleSheet::Copy(const wxRichTextStyleSheet& sheet)
+{
+    DeleteStyles();
+
+    wxList::compatibility_iterator node;
+
+    for (node = sheet.m_characterStyleDefinitions.GetFirst(); node; node = node->GetNext())
+    {
+        wxRichTextCharacterStyleDefinition* def = (wxRichTextCharacterStyleDefinition*) node->GetData();
+        AddCharacterStyle(new wxRichTextCharacterStyleDefinition(*def));
+    }
+
+    for (node = sheet.m_paragraphStyleDefinitions.GetFirst(); node; node = node->GetNext())
+    {
+        wxRichTextParagraphStyleDefinition* def = (wxRichTextParagraphStyleDefinition*) node->GetData();
+        AddParagraphStyle(new wxRichTextParagraphStyleDefinition(*def));
+    }
+}
+
+/// Equality
+bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const
+{
+    // TODO
+    return false;
+}
+
+
 #if wxUSE_HTML
 /*!
  * wxRichTextStyleListBox class declaration
@@ -100,13 +173,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 +244,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 +380,64 @@ void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
     wxVListBox::OnLeftDown(event);
 
     int item = HitTest(event.GetPosition());
+    if (item != wxNOT_FOUND && GetApplyOnSelection())
+        ApplyStyle(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())
+        int adjustedCaretPos = GetRichTextCtrl()->GetAdjustedCaretPosition(GetRichTextCtrl()->GetCaretPosition());
+
+        wxRichTextParagraph* para = GetRichTextCtrl()->GetBuffer().GetParagraphAtPosition(adjustedCaretPos);
+        wxRichTextObject* obj = GetRichTextCtrl()->GetBuffer().GetLeafObjectAtPosition(adjustedCaretPos);
+
+        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::ApplyStyle(int item)
+{
+    if ( item != wxNOT_FOUND )
+    {
+        wxRichTextStyleDefinition* def = GetStyle(item);
+        if (def && GetRichTextCtrl())
+        {
+            GetRichTextCtrl()->ApplyStyle(def);
+            GetRichTextCtrl()->SetFocus();
         }
     }
 }
@@ -303,6 +454,152 @@ 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 ApplyStyle
+    Dismiss();
+
+    if (m_itemHere >= 0)
+        wxRichTextStyleListBox::ApplyStyle(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())
+    {
+        int adjustedCaretPos = GetRichTextCtrl()->GetAdjustedCaretPosition(GetRichTextCtrl()->GetCaretPosition());
+
+        wxRichTextParagraph* para = GetRichTextCtrl()->GetBuffer().GetParagraphAtPosition(adjustedCaretPos);
+        wxRichTextObject* obj = GetRichTextCtrl()->GetBuffer().GetLeafObjectAtPosition(adjustedCaretPos);
+
+        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