X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/02761f6cd478e3c2c97cf6f93442747f7b029833..daca43d84796aebb064d9c39bbcdf268cd799eb0:/src/richtext/richtextstyles.cpp diff --git a/src/richtext/richtextstyles.cpp b/src/richtext/richtextstyles.cpp index 309a110176..e0bad0c3ad 100644 --- a/src/richtext/richtextstyles.cpp +++ b/src/richtext/richtextstyles.cpp @@ -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