// 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
*/
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;
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;
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
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()
}
}
+// 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)
{
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();
}
}
}
}
#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