X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5d7836c47de679f03b1b7e738c77164c11bd3689..37702a44db52f188c1ea5df89f857c797b7fc297:/src/richtext/richtextstyles.cpp diff --git a/src/richtext/richtextstyles.cpp b/src/richtext/richtextstyles.cpp index e1dd06b17e..e40229b843 100644 --- a/src/richtext/richtextstyles.cpp +++ b/src/richtext/richtextstyles.cpp @@ -1,10 +1,10 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: richtextstyles.cpp +// Name: src/richtext/richtextstyles.cpp // Purpose: Style management for wxRichTextCtrl // Author: Julian Smart -// Modified by: +// Modified by: // Created: 2005-09-30 -// RCS-ID: +// RCS-ID: $Id$ // Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -16,25 +16,198 @@ #pragma hdrstop #endif +#if wxUSE_RICHTEXT + +#include "wx/richtext/richtextstyles.h" + #ifndef WX_PRECOMP #include "wx/wx.h" #endif -#include "wx/image.h" - -#if wxUSE_RICHTEXT - #include "wx/filename.h" #include "wx/clipbrd.h" #include "wx/wfstream.h" -#include "wx/module.h" +#include "wx/settings.h" -#include "wx/richtext/richtextstyles.h" #include "wx/richtext/richtextctrl.h" IMPLEMENT_CLASS(wxRichTextStyleDefinition, wxObject) IMPLEMENT_CLASS(wxRichTextCharacterStyleDefinition, wxRichTextStyleDefinition) IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition) +IMPLEMENT_CLASS(wxRichTextListStyleDefinition, wxRichTextParagraphStyleDefinition) + +/*! + * 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); +} + +/*! + * List style definition + */ + +void wxRichTextListStyleDefinition::Copy(const wxRichTextListStyleDefinition& def) +{ + wxRichTextParagraphStyleDefinition::Copy(def); + + int i; + for (i = 0; i < 10; i++) + m_levelStyles[i] = def.m_levelStyles[i]; +} + +bool wxRichTextListStyleDefinition::operator ==(const wxRichTextListStyleDefinition& def) const +{ + if (!Eq(def)) + return false; + int i; + for (i = 0; i < 10; i++) + if (!(m_levelStyles[i] == def.m_levelStyles[i])) + return false; + + return true; +} + +/// Sets/gets the attributes for the given level +void wxRichTextListStyleDefinition::SetLevelAttributes(int i, const wxTextAttrEx& attr) +{ + wxASSERT( (i >= 0 && i < 10) ); + if (i >= 0 && i < 10) + m_levelStyles[i] = attr; +} + +const wxTextAttrEx* wxRichTextListStyleDefinition::GetLevelAttributes(int i) const +{ + wxASSERT( (i >= 0 && i < 10) ); + if (i >= 0 && i < 10) + return & m_levelStyles[i]; + else + return NULL; +} + +wxTextAttrEx* wxRichTextListStyleDefinition::GetLevelAttributes(int i) +{ + wxASSERT( (i >= 0 && i < 10) ); + if (i >= 0 && i < 10) + return & m_levelStyles[i]; + else + return NULL; +} + +/// Convenience function for setting the major attributes for a list level specification +void wxRichTextListStyleDefinition::SetAttributes(int i, int leftIndent, int leftSubIndent, int bulletStyle, const wxString& bulletSymbol) +{ + wxASSERT( (i >= 0 && i < 10) ); + if (i >= 0 && i < 10) + { + wxTextAttrEx attr; + + attr.SetBulletStyle(bulletStyle); + attr.SetLeftIndent(leftIndent, leftSubIndent); + + if (!bulletSymbol.IsEmpty()) + attr.SetBulletSymbol(bulletSymbol[0]); + + m_levelStyles[i] = attr; + } +} + +/// Finds the level corresponding to the given indentation +int wxRichTextListStyleDefinition::FindLevelForIndent(int indent) const +{ + int i; + for (i = 0; i < 10; i++) + { + if (indent < m_levelStyles[i].GetLeftIndent()) + { + if (i > 0) + return i - 1; + else + return 0; + } + } + return 9; +} + +/// Combine the list style with a paragraph style, using the given indent (from which +/// an appropriate level is found) +wxTextAttrEx wxRichTextListStyleDefinition::CombineWithParagraphStyle(int indent, const wxTextAttrEx& paraStyle) +{ + int listLevel = FindLevelForIndent(indent); + + wxTextAttrEx attr(*GetLevelAttributes(listLevel)); + int oldLeftIndent = attr.GetLeftIndent(); + int oldLeftSubIndent = attr.GetLeftSubIndent(); + + // First apply the overall paragraph style, if any + wxRichTextApplyStyle(attr, GetStyle()); + + // Then apply paragraph style, e.g. from paragraph style definition + wxRichTextApplyStyle(attr, paraStyle); + + // We override the indents according to the list definition + attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent); + + return attr; +} + +/// Combine the base and list style, using the given indent (from which +/// an appropriate level is found) +wxTextAttrEx wxRichTextListStyleDefinition::GetCombinedStyle(int indent) +{ + int listLevel = FindLevelForIndent(indent); + return GetCombinedStyleForLevel(listLevel); +} + +/// Combine the base and list style, using the given indent (from which +/// an appropriate level is found) +wxTextAttrEx wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel) +{ + wxTextAttrEx attr(*GetLevelAttributes(listLevel)); + int oldLeftIndent = attr.GetLeftIndent(); + int oldLeftSubIndent = attr.GetLeftSubIndent(); + + // Apply the overall paragraph style, if any + wxRichTextApplyStyle(attr, GetStyle()); + + // We override the indents according to the list definition + attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent); + + return attr; +} + +/// Is this a numbered list? +bool wxRichTextListStyleDefinition::IsNumbered(int i) const +{ + return (0 != (GetLevelAttributes(i)->GetFlags() & + (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER|wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER| + wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER|wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER))); +} /*! * The style manager @@ -42,9 +215,25 @@ IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition) IMPLEMENT_CLASS(wxRichTextStyleSheet, wxObject) +wxRichTextStyleSheet::~wxRichTextStyleSheet() +{ + DeleteStyles(); + + if (m_nextSheet) + m_nextSheet->m_previousSheet = m_previousSheet; + + if (m_previousSheet) + m_previousSheet->m_nextSheet = m_nextSheet; + + m_previousSheet = NULL; + m_nextSheet = NULL; +} + /// Initialisation void wxRichTextStyleSheet::Init() { + m_previousSheet = NULL; + m_nextSheet = NULL; } /// Add a definition to one of the style lists @@ -58,11 +247,11 @@ bool wxRichTextStyleSheet::AddStyle(wxList& list, wxRichTextStyleDefinition* def /// Remove a style bool wxRichTextStyleSheet::RemoveStyle(wxList& list, wxRichTextStyleDefinition* def, bool deleteStyle) { - wxNode* node = list.Find(def); + wxList::compatibility_iterator node = list.Find(def); if (node) { wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData(); - delete node; + list.Erase(node); if (deleteStyle) delete def; return true; @@ -72,15 +261,19 @@ bool wxRichTextStyleSheet::RemoveStyle(wxList& list, wxRichTextStyleDefinition* } /// Find a definition by name -wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxList& list, const wxString& name) const +wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxList& list, const wxString& name, bool recurse) const { - for (wxNode* node = list.GetFirst(); node; node = node->GetNext()) + for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) { wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData(); if (def->GetName().Lower() == name.Lower()) return def; } - return NULL; + + if (m_nextSheet && recurse) + return m_nextSheet->FindStyle(list, name, recurse); + + return NULL; } /// Delete all styles @@ -88,26 +281,130 @@ void wxRichTextStyleSheet::DeleteStyles() { WX_CLEAR_LIST(wxList, m_characterStyleDefinitions); WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions); + WX_CLEAR_LIST(wxList, m_listStyleDefinitions); +} + +/// Insert into list of style sheets +bool wxRichTextStyleSheet::InsertSheet(wxRichTextStyleSheet* before) +{ + m_previousSheet = before->m_previousSheet; + m_nextSheet = before; + + before->m_previousSheet = this; + return true; +} + +/// Append to list of style sheets +bool wxRichTextStyleSheet::AppendSheet(wxRichTextStyleSheet* after) +{ + wxRichTextStyleSheet* last = after; + while (last && last->m_nextSheet) + { + last = last->m_nextSheet; + } + + if (last) + { + m_previousSheet = last; + last->m_nextSheet = this; + + return true; + } + else + return false; +} + +/// Unlink from the list of style sheets +void wxRichTextStyleSheet::Unlink() +{ + if (m_previousSheet) + m_previousSheet->m_nextSheet = m_nextSheet; + if (m_nextSheet) + m_nextSheet->m_previousSheet = m_previousSheet; + + m_previousSheet = NULL; + m_nextSheet = NULL; +} + +/// 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); } +/// Add a definition to the list style list +bool wxRichTextStyleSheet::AddListStyle(wxRichTextListStyleDefinition* def) +{ + def->GetStyle().SetListStyleName(def->GetName()); + return AddStyle(m_listStyleDefinitions, 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)); + } + + for (node = sheet.m_listStyleDefinitions.GetFirst(); node; node = node->GetNext()) + { + wxRichTextListStyleDefinition* def = (wxRichTextListStyleDefinition*) node->GetData(); + AddListStyle(new wxRichTextListStyleDefinition(*def)); + } +} + +/// Equality +bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const +{ + // TODO + return false; +} + + #if wxUSE_HTML /*! - * wxRichTextStyleListBox class declaration - * A listbox to display styles. + * wxRichTextStyleListBox: a listbox to display styles. */ IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox) BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox) - EVT_LISTBOX(wxID_ANY, wxRichTextStyleListBox::OnSelect) EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown) + EVT_LEFT_DCLICK(wxRichTextStyleListBox::OnLeftDoubleClick) + 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) +{ + Init(); + Create(parent, id, pos, size, style); +} + +bool wxRichTextStyleListBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long style) { - m_styleSheet = NULL; - m_richTextCtrl = NULL; + return wxHtmlListBox::Create(parent, id, pos, size, style); } wxRichTextStyleListBox::~wxRichTextStyleListBox() @@ -120,22 +417,10 @@ wxString wxRichTextStyleListBox::OnGetItem(size_t n) const if (!GetStyleSheet()) return wxEmptyString; - // First paragraph styles, then character - if (n < GetStyleSheet()->GetParagraphStyleCount()) - { - wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->GetParagraphStyle(n); - - wxString str = CreateHTML(def); - return str; - } - - if ((n - GetStyleSheet()->GetParagraphStyleCount()) < GetStyleSheet()->GetCharacterStyleCount()) - { - wxRichTextCharacterStyleDefinition* def = GetStyleSheet()->GetCharacterStyle(n - GetStyleSheet()->GetParagraphStyleCount()); + wxRichTextStyleDefinition* def = GetStyle(n); + if (def) + return CreateHTML(def); - wxString str = CreateHTML(def); - return str; - } return wxEmptyString; } @@ -145,12 +430,30 @@ wxRichTextStyleDefinition* wxRichTextStyleListBox::GetStyle(size_t i) const if (!GetStyleSheet()) return NULL; - // First paragraph styles, then character - if (i < GetStyleSheet()->GetParagraphStyleCount()) - return GetStyleSheet()->GetParagraphStyle(i); + if (GetStyleType() == wxRICHTEXT_STYLE_ALL) + { + // First paragraph styles, then character, then list + if (i < GetStyleSheet()->GetParagraphStyleCount()) + return GetStyleSheet()->GetParagraphStyle(i); - if ((i - GetStyleSheet()->GetParagraphStyleCount()) < GetStyleSheet()->GetCharacterStyleCount()) - return GetStyleSheet()->GetCharacterStyle(i - GetStyleSheet()->GetParagraphStyleCount()); + if ((i - GetStyleSheet()->GetParagraphStyleCount()) < GetStyleSheet()->GetCharacterStyleCount()) + return GetStyleSheet()->GetCharacterStyle(i - GetStyleSheet()->GetParagraphStyleCount()); + + if ((i - GetStyleSheet()->GetParagraphStyleCount() - GetStyleSheet()->GetCharacterStyleCount()) < GetStyleSheet()->GetListStyleCount()) + return GetStyleSheet()->GetListStyle(i - GetStyleSheet()->GetParagraphStyleCount() - GetStyleSheet()->GetCharacterStyleCount()); + } + else if ((GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH) && (i < GetStyleSheet()->GetParagraphStyleCount())) + { + return GetStyleSheet()->GetParagraphStyle(i); + } + else if ((GetStyleType() == wxRICHTEXT_STYLE_CHARACTER) && (i < GetStyleSheet()->GetCharacterStyleCount())) + { + return GetStyleSheet()->GetCharacterStyle(i); + } + else if ((GetStyleType() == wxRICHTEXT_STYLE_LIST) && (i < GetStyleSheet()->GetListStyleCount())) + { + return GetStyleSheet()->GetListStyle(i); + } return NULL; } @@ -160,11 +463,54 @@ void wxRichTextStyleListBox::UpdateStyles() { if (GetStyleSheet()) { - SetItemCount(GetStyleSheet()->GetParagraphStyleCount()+GetStyleSheet()->GetCharacterStyleCount()); + SetSelection(wxNOT_FOUND); + + if (GetStyleType() == wxRICHTEXT_STYLE_ALL) + SetItemCount(GetStyleSheet()->GetParagraphStyleCount()+GetStyleSheet()->GetCharacterStyleCount()+GetStyleSheet()->GetListStyleCount()); + else if (GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH) + SetItemCount(GetStyleSheet()->GetParagraphStyleCount()); + else if (GetStyleType() == wxRICHTEXT_STYLE_CHARACTER) + SetItemCount(GetStyleSheet()->GetCharacterStyleCount()); + else if (GetStyleType() == wxRICHTEXT_STYLE_LIST) + SetItemCount(GetStyleSheet()->GetListStyleCount()); + Refresh(); + + if (GetItemCount() > 0) + { + SetSelection(0); + SendSelectedEvent(); + } } } +// Get index for style name +int wxRichTextStyleListBox::GetIndexForStyle(const wxString& name) const +{ + if (GetStyleSheet()) + { + int count = GetItemCount(); + + int i; + for (i = 0; i < (int) count; i++) + { + wxRichTextStyleDefinition* def = GetStyle(i); + if (def->GetName() == name) + return i; + } + } + 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) { @@ -180,21 +526,32 @@ static wxString ColourToHexString(const wxColour& col) /// Creates a suitable HTML fragment for a definition wxString wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition* def) const { + // TODO: indicate list format for list style types + wxString str(wxT("")); if (def->GetStyle().GetLeftIndent() > 0) { wxClientDC dc((wxWindow*) this); - str << wxT(""); + str << wxT(""); } str << wxT("
"); - int size = 5; +#ifdef __WXMSW__ + int size = 3; +#else + int size = 4; +#endif + + int stdFontSize = 12; + int thisFontSize = ((def->GetStyle().GetFlags() & wxTEXT_ATTR_FONT_SIZE) != 0) ? def->GetStyle().GetFontSize() : stdFontSize; - // Standard size is 12, say - size += 12 - def->GetStyle().GetFontSize(); + if (thisFontSize < stdFontSize) + size ++; + else if (thisFontSize > stdFontSize) + size --; str += wxT("GetName()); - } -#endif + wxVListBox::OnLeftDown(event); + + int item = HitTest(event.GetPosition()); + if (item != wxNOT_FOUND && GetApplyOnSelection()) + ApplyStyle(item); } -void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event) +void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent& event) { wxVListBox::OnLeftDown(event); int item = HitTest(event.GetPosition()); + if (item != wxNOT_FOUND && !GetApplyOnSelection()) + ApplyStyle(item); +} + +/// Helper for listbox and combo control +wxString wxRichTextStyleListBox::GetStyleToShowInIdleTime(wxRichTextCtrl* ctrl, wxRichTextStyleType styleType) +{ + int adjustedCaretPos = ctrl->GetAdjustedCaretPosition(ctrl->GetCaretPosition()); + + wxRichTextParagraph* para = ctrl->GetBuffer().GetParagraphAtPosition(adjustedCaretPos); + wxRichTextObject* obj = ctrl->GetBuffer().GetLeafObjectAtPosition(adjustedCaretPos); + + wxString styleName; + + // Take into account current default style just chosen by user + if (ctrl->IsDefaultStyleShowing()) + { + if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) && + !ctrl->GetDefaultStyleEx().GetCharacterStyleName().IsEmpty()) + styleName = ctrl->GetDefaultStyleEx().GetCharacterStyleName(); + else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) && + !ctrl->GetDefaultStyleEx().GetParagraphStyleName().IsEmpty()) + styleName = ctrl->GetDefaultStyleEx().GetParagraphStyleName(); + else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) && + !ctrl->GetDefaultStyleEx().GetListStyleName().IsEmpty()) + styleName = ctrl->GetDefaultStyleEx().GetListStyleName(); + } + else if (obj && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) && + !obj->GetAttributes().GetCharacterStyleName().IsEmpty()) + { + styleName = obj->GetAttributes().GetCharacterStyleName(); + } + else if (para && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) && + !para->GetAttributes().GetParagraphStyleName().IsEmpty()) + { + styleName = para->GetAttributes().GetParagraphStyleName(); + } + else if (para && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) && + !para->GetAttributes().GetListStyleName().IsEmpty()) + { + styleName = para->GetAttributes().GetListStyleName(); + } + + return styleName; +} +/// Auto-select from style under caret in idle time +void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event) +{ + if (CanAutoSetSelection() && GetRichTextCtrl() && wxWindow::FindFocus() != this) + { + wxString styleName = GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType()); + + 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::ApplyStyle(int item) +{ if ( item != wxNOT_FOUND ) { wxRichTextStyleDefinition* def = GetStyle(item); if (def && GetRichTextCtrl()) { - wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint()); - - // 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(); + GetRichTextCtrl()->ApplyStyle(def); + GetRichTextCtrl()->SetFocus(); } } } -#if 0 -wxColour wxRichTextStyleListBox::GetSelectedTextColour(const wxColour& colFg) const +/*! + * wxRichTextStyleListCtrl class: manages a listbox and a choice control to + * switch shown style types + */ + +IMPLEMENT_CLASS(wxRichTextStyleListCtrl, wxControl) + +BEGIN_EVENT_TABLE(wxRichTextStyleListCtrl, wxControl) + EVT_CHOICE(wxID_ANY, wxRichTextStyleListCtrl::OnChooseType) + EVT_SIZE(wxRichTextStyleListCtrl::OnSize) +END_EVENT_TABLE() + +wxRichTextStyleListCtrl::wxRichTextStyleListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long style) +{ + Init(); + Create(parent, id, pos, size, style); +} + +bool wxRichTextStyleListCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long style) +{ + wxControl::Create(parent, id, pos, size, style); + + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + if (size != wxDefaultSize) + SetBestFittingSize(size); + + bool showSelector = ((style & wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR) == 0); + + m_styleListBox = new wxRichTextStyleListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, showSelector ? wxSIMPLE_BORDER : wxNO_BORDER); + + wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL); + + if (showSelector) + { + wxArrayString choices; + choices.Add(_("All styles")); + choices.Add(_("Paragraph styles")); + choices.Add(_("Character styles")); + choices.Add(_("List styles")); + + m_styleChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices); + + boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 5); + boxSizer->Add(m_styleChoice, 0, wxALL|wxEXPAND, 5); + } + else + { + boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 0); + } + + SetSizer(boxSizer); + Layout(); + + m_dontUpdate = true; + + if (m_styleChoice) + { + int i = StyleTypeToIndex(m_styleListBox->GetStyleType()); + m_styleChoice->SetSelection(i); + } + + m_dontUpdate = false; + + return true; +} + +wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl() +{ + +} + +/// React to style type choice +void wxRichTextStyleListCtrl::OnChooseType(wxCommandEvent& event) +{ + if (event.GetEventObject() != m_styleChoice) + event.Skip(); + else + { + if (m_dontUpdate) + return; + + wxRichTextStyleListBox::wxRichTextStyleType styleType = StyleIndexToType(event.GetSelection()); + m_styleListBox->SetStyleType(styleType); + } +} + +/// Lay out the controls +void wxRichTextStyleListCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + if (GetAutoLayout()) + Layout(); +} + +/// Get the choice index for style type +int wxRichTextStyleListCtrl::StyleTypeToIndex(wxRichTextStyleListBox::wxRichTextStyleType styleType) +{ + if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL) + { + return 0; + } + else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH) + { + return 1; + } + else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER) + { + return 2; + } + else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST) + { + return 3; + } + return 0; +} + +/// Get the style type for choice index +wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::StyleIndexToType(int i) +{ + if (i == 1) + return wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH; + else if (i == 2) + return wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER; + else if (i == 3) + return wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST; + + return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL; +} + +/// Associates the control with a style manager +void wxRichTextStyleListCtrl::SetStyleSheet(wxRichTextStyleSheet* styleSheet) +{ + if (m_styleListBox) + m_styleListBox->SetStyleSheet(styleSheet); +} + +wxRichTextStyleSheet* wxRichTextStyleListCtrl::GetStyleSheet() const +{ + if (m_styleListBox) + return m_styleListBox->GetStyleSheet(); + else + return NULL; +} + +/// Associates the control with a wxRichTextCtrl +void wxRichTextStyleListCtrl::SetRichTextCtrl(wxRichTextCtrl* ctrl) +{ + if (m_styleListBox) + m_styleListBox->SetRichTextCtrl(ctrl); +} + +wxRichTextCtrl* wxRichTextStyleListCtrl::GetRichTextCtrl() const +{ + if (m_styleListBox) + return m_styleListBox->GetRichTextCtrl(); + else + return NULL; +} + +/// Set/get the style type to display +void wxRichTextStyleListCtrl::SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType) +{ + if (m_styleListBox) + m_styleListBox->SetStyleType(styleType); + + m_dontUpdate = true; + + if (m_styleChoice) + { + int i = StyleTypeToIndex(m_styleListBox->GetStyleType()); + m_styleChoice->SetSelection(i); + } + + m_dontUpdate = false; +} + +wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::GetStyleType() const { - return *wxBLACK; + if (m_styleListBox) + return m_styleListBox->GetStyleType(); + else + return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL; } -wxColour wxRichTextStyleListBox::GetSelectedTextBgColour(const wxColour& colBg) const +/// Updates the style list box +void wxRichTextStyleListCtrl::UpdateStyles() { - return *wxWHITE; + if (m_styleListBox) + m_styleListBox->UpdateStyles(); } + +#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() && m_stylePopup && wxWindow::FindFocus() != this) + { + wxString styleName = wxRichTextStyleListBox::GetStyleToShowInIdleTime(GetRichTextCtrl(), m_stylePopup->GetStyleType()); + + 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 #endif // wxUSE_RICHTEXT -