Style listbox now shows current style

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
This commit is contained in:
Julian Smart
2006-09-12 10:19:45 +00:00
parent 03703fc0af
commit e637208a32
3 changed files with 389 additions and 19 deletions

View File

@@ -2,9 +2,9 @@
// Name: richtextstyles.h // Name: richtextstyles.h
// Purpose: Style management for wxRichTextCtrl // Purpose: Style management for wxRichTextCtrl
// Author: Julian Smart // Author: Julian Smart
// Modified by: // Modified by:
// Created: 2005-09-30 // Created: 2005-09-30
// RCS-ID: // RCS-ID:
// Copyright: (c) Julian Smart // Copyright: (c) Julian Smart
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@@ -24,6 +24,10 @@
#include "wx/htmllbox.h" #include "wx/htmllbox.h"
#endif #endif
#if wxUSE_COMBOCTRL
#include "wx/combo.h"
#endif
/*! /*!
* Forward declarations * Forward declarations
*/ */
@@ -188,10 +192,23 @@ class WXDLLIMPEXP_RICHTEXT wxRichTextStyleListBox: public wxHtmlListBox
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
public: public:
wxRichTextStyleListBox()
{
Init();
}
wxRichTextStyleListBox(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, wxRichTextStyleListBox(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = 0); const wxSize& size = wxDefaultSize, long style = 0);
virtual ~wxRichTextStyleListBox(); 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 /// Creates a suitable HTML fragment for a definition
wxString CreateHTML(wxRichTextStyleDefinition* def) const; wxString CreateHTML(wxRichTextStyleDefinition* def) const;
@@ -203,26 +220,42 @@ public:
void SetRichTextCtrl(wxRichTextCtrl* ctrl) { m_richTextCtrl = ctrl; } void SetRichTextCtrl(wxRichTextCtrl* ctrl) { m_richTextCtrl = ctrl; }
wxRichTextCtrl* GetRichTextCtrl() const { return m_richTextCtrl; } wxRichTextCtrl* GetRichTextCtrl() const { return m_richTextCtrl; }
// Get style for index /// Get style for index
wxRichTextStyleDefinition* GetStyle(size_t i) const ; 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 /// Updates the list
void UpdateStyles(); void UpdateStyles();
/// Do selection
void DoSelection(int i);
/// React to selection /// React to selection
void OnSelect(wxCommandEvent& event); void OnSelect(wxCommandEvent& event);
/// Left click /// Left click
void OnLeftDown(wxMouseEvent& event); void OnLeftDown(wxMouseEvent& event);
/// Auto-select from style under caret in idle time
void OnIdle(wxIdleEvent& event);
#if 0 #if 0
virtual wxColour GetSelectedTextColour(const wxColour& colFg) const; virtual wxColour GetSelectedTextColour(const wxColour& colFg) const;
virtual wxColour GetSelectedTextBgColour(const wxColour& colBg) const; virtual wxColour GetSelectedTextBgColour(const wxColour& colBg) const;
#endif #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; 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: protected:
/// Returns the HTML for this item /// Returns the HTML for this item
virtual wxString OnGetItem(size_t n) const; virtual wxString OnGetItem(size_t n) const;
@@ -232,7 +265,117 @@ private:
wxRichTextStyleSheet* m_styleSheet; wxRichTextStyleSheet* m_styleSheet;
wxRichTextCtrl* m_richTextCtrl; 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 #endif
// wxUSE_COMBOCTRL
#endif
// wxUSE_HTML
#endif #endif
// wxUSE_RICHTEXT // wxUSE_RICHTEXT

View File

@@ -490,6 +490,9 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
toolBar->AddSeparator(); toolBar->AddSeparator();
toolBar->AddTool(ID_FORMAT_FONT, wxBitmap(font_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Font")); 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(); toolBar->Realize();
wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, GetClientSize(), wxSP_NO_XP_THEME|wxSP_3D|wxSP_LIVE_UPDATE); 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); m_richTextCtrl->SetFont(font);
combo->SetStyleSheet(wxGetApp().GetStyleSheet());
combo->SetRichTextCtrl(m_richTextCtrl);
combo->UpdateStyles();
wxRichTextStyleListBox* styleListBox = new wxRichTextStyleListBox(splitter, wxID_ANY); wxRichTextStyleListBox* styleListBox = new wxRichTextStyleListBox(splitter, wxID_ANY);
wxSize display = wxGetDisplaySize(); wxSize display = wxGetDisplaySize();

View File

@@ -100,13 +100,20 @@ IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox)
BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox) BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox)
EVT_LISTBOX(wxID_ANY, wxRichTextStyleListBox::OnSelect) EVT_LISTBOX(wxID_ANY, wxRichTextStyleListBox::OnSelect)
EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown) EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown)
EVT_IDLE(wxRichTextStyleListBox::OnIdle)
END_EVENT_TABLE() END_EVENT_TABLE()
wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos, 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; Init();
m_richTextCtrl = NULL; 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() 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 // Convert a colour to a 6-digit hex string
static wxString ColourToHexString(const wxColour& col) static wxString ColourToHexString(const wxColour& col)
{ {
@@ -269,24 +307,62 @@ void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
wxVListBox::OnLeftDown(event); wxVListBox::OnLeftDown(event);
int item = HitTest(event.GetPosition()); int item = HitTest(event.GetPosition());
if (item != wxNOT_FOUND)
DoSelection(item);
}
/// Auto-select from style under caret in idle time
void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
{
if (CanAutoSetSelection() && 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())
{
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();
}
int sel = GetSelection();
if (!styleName.IsEmpty())
{
// Don't do the selection if it's already set
if (sel == GetIndexForStyle(styleName))
return;
SetStyleSelection(styleName);
}
else if (sel != -1)
SetSelection(-1);
}
event.Skip();
}
/// Do selection
void wxRichTextStyleListBox::DoSelection(int item)
{
if ( item != wxNOT_FOUND ) if ( item != wxNOT_FOUND )
{ {
wxRichTextStyleDefinition* def = GetStyle(item); wxRichTextStyleDefinition* def = GetStyle(item);
if (def && GetRichTextCtrl()) if (def && GetRichTextCtrl())
{ {
wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint()); GetRichTextCtrl()->ApplyStyle(def);
GetRichTextCtrl()->SetFocus();
// Flags are defined within each definition, so only certain
// attributes are applied.
wxRichTextAttr attr(def->GetStyle());
if (m_richTextCtrl->HasSelection())
m_richTextCtrl->SetStyle(m_richTextCtrl->GetSelectionRange(), attr);
else
m_richTextCtrl->SetDefaultStyle(attr);
m_richTextCtrl->SetFocus();
} }
} }
} }
@@ -303,6 +379,150 @@ wxColour wxRichTextStyleListBox::GetSelectedTextBgColour(const wxColour& colBg)
} }
#endif #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 #endif
// wxUSE_HTML // wxUSE_HTML