1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/richtext/richtextformatdlg.cpp 
   3 // Purpose:     Formatting dialog for wxRichTextCtrl 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  21 #include "wx/richtext/richtextformatdlg.h" 
  24     #include "wx/listbox.h" 
  25     #include "wx/combobox.h" 
  26     #include "wx/textctrl.h" 
  28     #include "wx/stattext.h" 
  29     #include "wx/statline.h" 
  30     #include "wx/radiobut.h" 
  32     #include "wx/bitmap.h" 
  33     #include "wx/dcclient.h" 
  35     #include "wx/checkbox.h" 
  36     #include "wx/button.h" 
  39 #include "wx/bookctrl.h" 
  40 #include "wx/colordlg.h" 
  41 #include "wx/fontenum.h" 
  42 #include "wx/settings.h" 
  43 #include "wx/module.h" 
  44 #include "wx/imaglist.h" 
  46 #include "wx/richtext/richtextctrl.h" 
  47 #include "wx/richtext/richtextstyles.h" 
  49 #include "richtextfontpage.cpp" 
  50 #include "richtextindentspage.cpp" 
  51 #include "richtexttabspage.cpp" 
  52 #include "richtextbulletspage.cpp" 
  53 #include "richtextstylepage.cpp" 
  56 #define wxRICHTEXT_USE_TOOLBOOK true 
  58 #define wxRICHTEXT_USE_TOOLBOOK false 
  61 IMPLEMENT_CLASS(wxRichTextFormattingDialog
, wxPropertySheetDialog
) 
  63 BEGIN_EVENT_TABLE(wxRichTextFormattingDialog
, wxPropertySheetDialog
) 
  64     EVT_NOTEBOOK_PAGE_CHANGED(-1, wxRichTextFormattingDialog::OnTabChanged
) 
  67 wxRichTextFormattingDialogFactory
* wxRichTextFormattingDialog::ms_FormattingDialogFactory 
= NULL
; 
  69 void wxRichTextFormattingDialog::Init() 
  72     m_styleDefinition 
= NULL
; 
  76 wxRichTextFormattingDialog::~wxRichTextFormattingDialog() 
  79     delete m_styleDefinition
; 
  82 bool wxRichTextFormattingDialog::Create(long flags
, wxWindow
* parent
, const wxString
& title
, wxWindowID id
, 
  83         const wxPoint
& pos
, const wxSize
& sz
, long style
) 
  85     SetExtraStyle(wxDIALOG_EX_CONTEXTHELP
|wxWS_EX_VALIDATE_RECURSIVELY
); 
  87     int resizeBorder 
= wxRESIZE_BORDER
; 
  89     GetFormattingDialogFactory()->SetSheetStyle(this); 
  91     wxPropertySheetDialog::Create(parent
, id
, title
, pos
, sz
, 
  92         style 
| (int)wxPlatform::IfNot(wxOS_WINDOWS_CE
, resizeBorder
) 
  95     GetFormattingDialogFactory()->CreateButtons(this); 
  96     GetFormattingDialogFactory()->CreatePages(flags
, this); 
 103 /// Get attributes from the given range 
 104 bool wxRichTextFormattingDialog::GetStyle(wxRichTextCtrl
* ctrl
, const wxRichTextRange
& range
) 
 106     if (ctrl
->GetBuffer().GetStyleForRange(range
.ToInternal(), m_attributes
)) 
 107         return UpdateDisplay(); 
 112 /// Apply attributes to the given range, only applying if necessary (wxRICHTEXT_SETSTYLE_OPTIMIZE) 
 113 bool wxRichTextFormattingDialog::ApplyStyle(wxRichTextCtrl
* ctrl
, const wxRichTextRange
& range
, int flags
) 
 115     return ctrl
->SetStyleEx(range
, m_attributes
, flags
); 
 118 /// Set the attributes and optionally update the display 
 119 bool wxRichTextFormattingDialog::SetStyle(const wxTextAttrEx
& style
, bool update
) 
 121     m_attributes 
= style
; 
 127 /// Set the style definition and optionally update the display 
 128 bool wxRichTextFormattingDialog::SetStyleDefinition(const wxRichTextStyleDefinition
& styleDef
, wxRichTextStyleSheet
* sheet
, bool update
) 
 130     m_styleSheet 
= sheet
; 
 132     if (m_styleDefinition
) 
 133         delete m_styleDefinition
; 
 134     m_styleDefinition 
= styleDef
.Clone(); 
 136     return SetStyle(m_styleDefinition
->GetStyle(), update
); 
 139 /// Transfers the data and from to the window 
 140 bool wxRichTextFormattingDialog::TransferDataToWindow() 
 142     if (m_styleDefinition
) 
 143         m_attributes 
= m_styleDefinition
->GetStyle(); 
 145     if (!wxPropertySheetDialog::TransferDataToWindow()) 
 151 bool wxRichTextFormattingDialog::TransferDataFromWindow() 
 153     if (!wxPropertySheetDialog::TransferDataFromWindow()) 
 156     if (m_styleDefinition
) 
 157         m_styleDefinition
->GetStyle() = m_attributes
; 
 162 /// Update the display 
 163 bool wxRichTextFormattingDialog::UpdateDisplay() 
 165     return TransferDataToWindow(); 
 168 /// Apply the styles when a different tab is selected, so the previews are 
 170 void wxRichTextFormattingDialog::OnTabChanged(wxNotebookEvent
& event
) 
 172     if (GetBookCtrl() != event
.GetEventObject()) 
 178     int oldPageId 
= event
.GetOldSelection(); 
 181         wxWindow
* page 
= GetBookCtrl()->GetPage(oldPageId
); 
 183             page
->TransferDataFromWindow(); 
 186     int pageId 
= event
.GetSelection(); 
 189         wxWindow
* page 
= GetBookCtrl()->GetPage(pageId
); 
 191             page
->TransferDataToWindow(); 
 195 void wxRichTextFormattingDialog::SetFormattingDialogFactory(wxRichTextFormattingDialogFactory
* factory
) 
 197     if (ms_FormattingDialogFactory
) 
 198         delete ms_FormattingDialogFactory
; 
 199     ms_FormattingDialogFactory 
= factory
; 
 203  * Factory for formatting dialog 
 206 /// Create all pages, under the dialog's book control, also calling AddPage 
 207 bool wxRichTextFormattingDialogFactory::CreatePages(long pages
, wxRichTextFormattingDialog
* dialog
) 
 209     if (dialog
->GetImageList()) 
 210         dialog
->GetBookCtrl()->SetImageList(dialog
->GetImageList()); 
 212     int availablePageCount 
= GetPageIdCount(); 
 214     for (i 
= 0; i 
< availablePageCount
; i 
++) 
 216         int pageId 
= GetPageId(i
); 
 217         if (pageId 
!= -1 && (pages 
& pageId
)) 
 220             wxPanel
* panel 
= CreatePage(pageId
, title
, dialog
); 
 221             wxASSERT( panel 
!= NULL 
); 
 224                 int imageIndex 
= GetPageImage(pageId
); 
 225                 dialog
->GetBookCtrl()->AddPage(panel
, title
, false, imageIndex
); 
 232 /// Create a page, given a page identifier 
 233 wxPanel
* wxRichTextFormattingDialogFactory::CreatePage(int page
, wxString
& title
, wxRichTextFormattingDialog
* dialog
) 
 235     if (page 
== wxRICHTEXT_FORMAT_STYLE_EDITOR
) 
 237         wxRichTextStylePage
* page 
= new wxRichTextStylePage(dialog
->GetBookCtrl(), wxID_ANY
); 
 241     else if (page 
== wxRICHTEXT_FORMAT_FONT
) 
 243         wxRichTextFontPage
* page 
= new wxRichTextFontPage(dialog
->GetBookCtrl(), wxID_ANY
); 
 247     else if (page 
== wxRICHTEXT_FORMAT_INDENTS_SPACING
) 
 249         wxRichTextIndentsSpacingPage
* page 
= new wxRichTextIndentsSpacingPage(dialog
->GetBookCtrl(), wxID_ANY
); 
 250         title 
= _("Indents && Spacing"); 
 253     else if (page 
== wxRICHTEXT_FORMAT_TABS
) 
 255         wxRichTextTabsPage
* page 
= new wxRichTextTabsPage(dialog
->GetBookCtrl(), wxID_ANY
); 
 259     else if (page 
== wxRICHTEXT_FORMAT_BULLETS
) 
 261         wxRichTextBulletsPage
* page 
= new wxRichTextBulletsPage(dialog
->GetBookCtrl(), wxID_ANY
); 
 262         title 
= _("Bullets"); 
 269 /// Enumerate all available page identifiers 
 270 int wxRichTextFormattingDialogFactory::GetPageId(int i
) const 
 273         wxRICHTEXT_FORMAT_STYLE_EDITOR
, 
 274         wxRICHTEXT_FORMAT_FONT
, 
 275         wxRICHTEXT_FORMAT_INDENTS_SPACING
, 
 276         wxRICHTEXT_FORMAT_BULLETS
, 
 277         wxRICHTEXT_FORMAT_TABS 
}; 
 285 /// Get the number of available page identifiers 
 286 int wxRichTextFormattingDialogFactory::GetPageIdCount() const 
 291 /// Set the sheet style, called at the start of wxRichTextFormattingDialog::Create 
 292 bool wxRichTextFormattingDialogFactory::SetSheetStyle(wxRichTextFormattingDialog
* dialog
) 
 294     bool useToolBook 
= wxRICHTEXT_USE_TOOLBOOK
; 
 297         int sheetStyle 
= wxPROPSHEET_SHRINKTOFIT
; 
 299         sheetStyle 
|= wxPROPSHEET_BUTTONTOOLBOOK
; 
 301         sheetStyle 
|= wxPROPSHEET_TOOLBOOK
; 
 304         dialog
->SetSheetStyle(sheetStyle
); 
 305         dialog
->SetSheetInnerBorder(0); 
 306         dialog
->SetSheetOuterBorder(0); 
 312 /// Create the main dialog buttons 
 313 bool wxRichTextFormattingDialogFactory::CreateButtons(wxRichTextFormattingDialog
* dialog
) 
 315     bool useToolBook 
= wxRICHTEXT_USE_TOOLBOOK
; 
 317     // If using a toolbook, also follow Mac style and don't create buttons 
 318     int flags 
= wxOK
|wxCANCEL
; 
 324         dialog
->CreateButtons(flags
); 
 330  * Module to initialise and clean up handlers 
 333 class wxRichTextFormattingDialogModule
: public wxModule
 
 335 DECLARE_DYNAMIC_CLASS(wxRichTextFormattingDialogModule
) 
 337     wxRichTextFormattingDialogModule() {} 
 338     bool OnInit() { wxRichTextFormattingDialog::SetFormattingDialogFactory(new wxRichTextFormattingDialogFactory
); return true; }; 
 339     void OnExit() { wxRichTextFormattingDialog::SetFormattingDialogFactory(NULL
); }; 
 342 IMPLEMENT_DYNAMIC_CLASS(wxRichTextFormattingDialogModule
, wxModule
) 
 345  * Font preview control 
 348 BEGIN_EVENT_TABLE(wxRichTextFontPreviewCtrl
, wxWindow
) 
 349     EVT_PAINT(wxRichTextFontPreviewCtrl::OnPaint
) 
 352 void wxRichTextFontPreviewCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 356     wxSize size 
= GetSize(); 
 357     wxFont font 
= GetFont(); 
 362         // Calculate vertical and horizontal centre 
 365         wxString 
text(_("ABCDEFGabcdefg12345")); 
 367         dc
.GetTextExtent( text
, &w
, &h
); 
 368         int cx 
= wxMax(2, (size
.x
/2) - (w
/2)); 
 369         int cy 
= wxMax(2, (size
.y
/2) - (h
/2)); 
 371         dc
.SetTextForeground(GetForegroundColour()); 
 372         dc
.SetClippingRegion(2, 2, size
.x
-4, size
.y
-4); 
 373         dc
.DrawText(text
, cx
, cy
); 
 374         dc
.DestroyClippingRegion(); 
 378 // Helper for pages to get the top-level dialog 
 379 wxRichTextFormattingDialog
* wxRichTextFormattingDialog::GetDialog(wxWindow
* win
) 
 381     wxWindow
* p 
= win
->GetParent(); 
 382     while (p 
&& !p
->IsKindOf(CLASSINFO(wxRichTextFormattingDialog
))) 
 384     wxRichTextFormattingDialog
* dialog 
= wxDynamicCast(p
, wxRichTextFormattingDialog
); 
 389 // Helper for pages to get the attributes 
 390 wxTextAttrEx
* wxRichTextFormattingDialog::GetDialogAttributes(wxWindow
* win
) 
 392     wxRichTextFormattingDialog
* dialog 
= GetDialog(win
); 
 394         return & dialog
->GetAttributes(); 
 399 // Helper for pages to get the style 
 400 wxRichTextStyleDefinition
* wxRichTextFormattingDialog::GetDialogStyleDefinition(wxWindow
* win
) 
 402     wxRichTextFormattingDialog
* dialog 
= GetDialog(win
); 
 404         return dialog
->GetStyleDefinition(); 
 410  * A control for displaying a small preview of a colour or bitmap 
 413 BEGIN_EVENT_TABLE(wxRichTextColourSwatchCtrl
, wxControl
) 
 414     EVT_MOUSE_EVENTS(wxRichTextColourSwatchCtrl::OnMouseEvent
) 
 417 IMPLEMENT_CLASS(wxRichTextColourSwatchCtrl
, wxControl
) 
 419 wxRichTextColourSwatchCtrl::wxRichTextColourSwatchCtrl(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
, long style
): 
 420     wxControl(parent
, id
, pos
, size
, style
) 
 422     SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 423     SetBackgroundStyle(wxBG_STYLE_COLOUR
); 
 426 wxRichTextColourSwatchCtrl::~wxRichTextColourSwatchCtrl() 
 430 void wxRichTextColourSwatchCtrl::OnMouseEvent(wxMouseEvent
& event
) 
 432     if (event
.LeftDown()) 
 434         wxWindow
* parent 
= GetParent(); 
 435         while (parent 
!= NULL 
&& !parent
->IsKindOf(CLASSINFO(wxDialog
)) && !parent
->IsKindOf(CLASSINFO(wxFrame
))) 
 436             parent 
= parent
->GetParent(); 
 439         data
.SetChooseFull(true); 
 440         data
.SetColour(m_colour
); 
 441         wxColourDialog 
*dialog 
= new wxColourDialog(parent
, &data
); 
 442         // Crashes on wxMac (no m_peer) 
 444         dialog
->SetTitle(_("Background colour")); 
 446         if (dialog
->ShowModal() == wxID_OK
) 
 448             wxColourData retData 
= dialog
->GetColourData(); 
 449             m_colour 
= retData
.GetColour(); 
 450             SetBackgroundColour(m_colour
); 
 455         wxCommandEvent 
event(wxEVT_COMMAND_BUTTON_CLICKED
, GetId()); 
 456         GetEventHandler()->ProcessEvent(event
); 
 463  * wxRichTextFontListBox class declaration 
 464  * A listbox to display styles. 
 467 IMPLEMENT_CLASS(wxRichTextFontListBox
, wxHtmlListBox
) 
 469 BEGIN_EVENT_TABLE(wxRichTextFontListBox
, wxHtmlListBox
) 
 472 wxRichTextFontListBox::wxRichTextFontListBox(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
, 
 473     const wxSize
& size
, long style
) 
 476     Create(parent
, id
, pos
, size
, style
); 
 479 bool wxRichTextFontListBox::Create(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
, 
 480         const wxSize
& size
, long style
) 
 482     return wxHtmlListBox::Create(parent
, id
, pos
, size
, style
); 
 485 wxRichTextFontListBox::~wxRichTextFontListBox() 
 489 /// Returns the HTML for this item 
 490 wxString 
wxRichTextFontListBox::OnGetItem(size_t n
) const 
 492     if (m_faceNames
.GetCount() == 0) 
 493         return wxEmptyString
; 
 495     wxString str 
= CreateHTML(m_faceNames
[n
]); 
 499 /// Get font name for index 
 500 wxString 
wxRichTextFontListBox::GetFaceName(size_t i
) const 
 502     return m_faceNames
[i
]; 
 505 /// Set selection for string, returning the index. 
 506 int wxRichTextFontListBox::SetFaceNameSelection(const wxString
& name
) 
 508     int i 
= m_faceNames
.Index(name
); 
 514 /// Updates the font list 
 515 void wxRichTextFontListBox::UpdateFonts() 
 517     wxFontEnumerator enumerator
; 
 518     enumerator
.EnumerateFacenames(); 
 519     wxArrayString facenames 
= enumerator
.GetFacenames(); 
 520     m_faceNames 
= facenames
; 
 523     SetItemCount(m_faceNames
.GetCount()); 
 528 // Convert a colour to a 6-digit hex string 
 529 static wxString 
ColourToHexString(const wxColour
& col
) 
 533     hex 
+= wxDecToHex(col
.Red()); 
 534     hex 
+= wxDecToHex(col
.Green()); 
 535     hex 
+= wxDecToHex(col
.Blue()); 
 541 /// Creates a suitable HTML fragment for a definition 
 542 wxString 
wxRichTextFontListBox::CreateHTML(const wxString
& facename
) const 
 544     wxString str 
= wxT("<font"); 
 546     str 
<< wxT(" size=\"+2\"");; 
 548     if (!facename
.IsEmpty() && facename 
!= _("(none)")) 
 549         str 
<< wxT(" face=\"") << facename 
<< wxT("\""); 
 551     if (def->GetStyle().GetTextColour().Ok()) 
 552         str << wxT(" color=\"#") << ColourToHexString(def->GetStyle().GetTextColour()) << wxT("\""); 
 557     bool hasBold 
= false; 
 567     str 
<< wxT("</font>");