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>");