need to include wx/imaglist.h even when using PCH
[wxWidgets.git] / src / richtext / richtextformatdlg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/richtext/richtextformatdlg.cpp
3 // Purpose: Formatting dialog for wxRichTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 2006-10-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_RICHTEXT
20
21 #ifndef WX_PRECOMP
22 #include "wx/listbox.h"
23 #include "wx/combobox.h"
24 #include "wx/textctrl.h"
25 #include "wx/sizer.h"
26 #include "wx/stattext.h"
27 #include "wx/statline.h"
28 #include "wx/radiobut.h"
29 #include "wx/icon.h"
30 #include "wx/bitmap.h"
31 #include "wx/dcclient.h"
32 #include "wx/frame.h"
33 #include "wx/checkbox.h"
34 #include "wx/button.h"
35 #endif // WX_PRECOMP
36
37 #include "wx/bookctrl.h"
38 #include "wx/colordlg.h"
39 #include "wx/fontenum.h"
40 #include "wx/settings.h"
41 #include "wx/module.h"
42 #include "wx/imaglist.h"
43
44 #include "wx/richtext/richtextformatdlg.h"
45 #include "wx/richtext/richtextctrl.h"
46 #include "wx/richtext/richtextstyles.h"
47
48 #include "richtextfontpage.cpp"
49 #include "richtextindentspage.cpp"
50 #include "richtexttabspage.cpp"
51 #include "richtextbulletspage.cpp"
52 #include "richtextstylepage.cpp"
53
54 #ifdef __WXMAC__
55 #define wxRICHTEXT_USE_TOOLBOOK true
56 #else
57 #define wxRICHTEXT_USE_TOOLBOOK false
58 #endif
59
60 IMPLEMENT_CLASS(wxRichTextFormattingDialog, wxPropertySheetDialog)
61
62 BEGIN_EVENT_TABLE(wxRichTextFormattingDialog, wxPropertySheetDialog)
63 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxRichTextFormattingDialog::OnTabChanged)
64 END_EVENT_TABLE()
65
66 wxRichTextFormattingDialogFactory* wxRichTextFormattingDialog::ms_FormattingDialogFactory = NULL;
67
68 void wxRichTextFormattingDialog::Init()
69 {
70 m_imageList = NULL;
71 m_styleDefinition = NULL;
72 m_styleSheet = NULL;
73 }
74
75 wxRichTextFormattingDialog::~wxRichTextFormattingDialog()
76 {
77 delete m_imageList;
78 delete m_styleDefinition;
79 }
80
81 bool wxRichTextFormattingDialog::Create(long flags, wxWindow* parent, const wxString& title, wxWindowID id,
82 const wxPoint& pos, const wxSize& sz, long style)
83 {
84 SetExtraStyle(wxDIALOG_EX_CONTEXTHELP|wxWS_EX_VALIDATE_RECURSIVELY);
85
86 int resizeBorder = wxRESIZE_BORDER;
87
88 GetFormattingDialogFactory()->SetSheetStyle(this);
89
90 wxPropertySheetDialog::Create(parent, id, title, pos, sz,
91 style | (int)wxPlatform::IfNot(wxWinCE, resizeBorder)
92 );
93
94 GetFormattingDialogFactory()->CreateButtons(this);
95 GetFormattingDialogFactory()->CreatePages(flags, this);
96
97 LayoutDialog();
98
99 return true;
100 }
101
102 /// Get attributes from the given range
103 bool wxRichTextFormattingDialog::GetStyle(wxRichTextCtrl* ctrl, const wxRichTextRange& range)
104 {
105 if (ctrl->GetBuffer().GetStyleForRange(range.ToInternal(), m_attributes))
106 return UpdateDisplay();
107 else
108 return false;
109 }
110
111 /// Apply attributes to the given range, only applying if necessary (wxRICHTEXT_SETSTYLE_OPTIMIZE)
112 bool wxRichTextFormattingDialog::ApplyStyle(wxRichTextCtrl* ctrl, const wxRichTextRange& range, int flags)
113 {
114 return ctrl->SetStyleEx(range, m_attributes, flags);
115 }
116
117 /// Set the attributes and optionally update the display
118 bool wxRichTextFormattingDialog::SetStyle(const wxTextAttrEx& style, bool update)
119 {
120 m_attributes = style;
121 if (update)
122 UpdateDisplay();
123 return true;
124 }
125
126 /// Set the style definition and optionally update the display
127 bool wxRichTextFormattingDialog::SetStyleDefinition(const wxRichTextStyleDefinition& styleDef, wxRichTextStyleSheet* sheet, bool update)
128 {
129 m_styleSheet = sheet;
130
131 if (m_styleDefinition)
132 delete m_styleDefinition;
133 m_styleDefinition = styleDef.Clone();
134
135 return SetStyle(m_styleDefinition->GetStyle(), update);
136 }
137
138 /// Transfers the data and from to the window
139 bool wxRichTextFormattingDialog::TransferDataToWindow()
140 {
141 if (m_styleDefinition)
142 m_attributes = m_styleDefinition->GetStyle();
143
144 if (!wxPropertySheetDialog::TransferDataToWindow())
145 return false;
146
147 return true;
148 }
149
150 bool wxRichTextFormattingDialog::TransferDataFromWindow()
151 {
152 if (!wxPropertySheetDialog::TransferDataFromWindow())
153 return false;
154
155 if (m_styleDefinition)
156 m_styleDefinition->GetStyle() = m_attributes;
157
158 return true;
159 }
160
161 /// Update the display
162 bool wxRichTextFormattingDialog::UpdateDisplay()
163 {
164 return TransferDataToWindow();
165 }
166
167 /// Apply the styles when a different tab is selected, so the previews are
168 /// up to date
169 void wxRichTextFormattingDialog::OnTabChanged(wxNotebookEvent& event)
170 {
171 if (GetBookCtrl() != event.GetEventObject())
172 {
173 event.Skip();
174 return;
175 }
176
177 int oldPageId = event.GetOldSelection();
178 if (oldPageId != -1)
179 {
180 wxWindow* page = GetBookCtrl()->GetPage(oldPageId);
181 if (page)
182 page->TransferDataFromWindow();
183 }
184
185 int pageId = event.GetSelection();
186 if (pageId != -1)
187 {
188 wxWindow* page = GetBookCtrl()->GetPage(pageId);
189 if (page)
190 page->TransferDataToWindow();
191 }
192 }
193
194 void wxRichTextFormattingDialog::SetFormattingDialogFactory(wxRichTextFormattingDialogFactory* factory)
195 {
196 if (ms_FormattingDialogFactory)
197 delete ms_FormattingDialogFactory;
198 ms_FormattingDialogFactory = factory;
199 }
200
201 /*!
202 * Factory for formatting dialog
203 */
204
205 /// Create all pages, under the dialog's book control, also calling AddPage
206 bool wxRichTextFormattingDialogFactory::CreatePages(long pages, wxRichTextFormattingDialog* dialog)
207 {
208 if (dialog->GetImageList())
209 dialog->GetBookCtrl()->SetImageList(dialog->GetImageList());
210
211 int availablePageCount = GetPageIdCount();
212 int i;
213 for (i = 0; i < availablePageCount; i ++)
214 {
215 int pageId = GetPageId(i);
216 if (pageId != -1 && (pages & pageId))
217 {
218 wxString title;
219 wxPanel* panel = CreatePage(pageId, title, dialog);
220 wxASSERT( panel != NULL );
221 if (panel)
222 {
223 int imageIndex = GetPageImage(pageId);
224 dialog->GetBookCtrl()->AddPage(panel, title, false, imageIndex);
225 }
226 }
227 }
228 return true;
229 }
230
231 /// Create a page, given a page identifier
232 wxPanel* wxRichTextFormattingDialogFactory::CreatePage(int page, wxString& title, wxRichTextFormattingDialog* dialog)
233 {
234 if (page == wxRICHTEXT_FORMAT_STYLE_EDITOR)
235 {
236 wxRichTextStylePage* page = new wxRichTextStylePage(dialog->GetBookCtrl(), wxID_ANY);
237 title = _("Style");
238 return page;
239 }
240 else if (page == wxRICHTEXT_FORMAT_FONT)
241 {
242 wxRichTextFontPage* page = new wxRichTextFontPage(dialog->GetBookCtrl(), wxID_ANY);
243 title = _("Font");
244 return page;
245 }
246 else if (page == wxRICHTEXT_FORMAT_INDENTS_SPACING)
247 {
248 wxRichTextIndentsSpacingPage* page = new wxRichTextIndentsSpacingPage(dialog->GetBookCtrl(), wxID_ANY);
249 title = _("Indents && Spacing");
250 return page;
251 }
252 else if (page == wxRICHTEXT_FORMAT_TABS)
253 {
254 wxRichTextTabsPage* page = new wxRichTextTabsPage(dialog->GetBookCtrl(), wxID_ANY);
255 title = _("Tabs");
256 return page;
257 }
258 else if (page == wxRICHTEXT_FORMAT_BULLETS)
259 {
260 wxRichTextBulletsPage* page = new wxRichTextBulletsPage(dialog->GetBookCtrl(), wxID_ANY);
261 title = _("Bullets");
262 return page;
263 }
264 else
265 return NULL;
266 }
267
268 /// Enumerate all available page identifiers
269 int wxRichTextFormattingDialogFactory::GetPageId(int i) const
270 {
271 int pages[] = {
272 wxRICHTEXT_FORMAT_STYLE_EDITOR,
273 wxRICHTEXT_FORMAT_FONT,
274 wxRICHTEXT_FORMAT_INDENTS_SPACING,
275 wxRICHTEXT_FORMAT_BULLETS,
276 wxRICHTEXT_FORMAT_TABS };
277
278 if (i < 0 || i > 4)
279 return -1;
280
281 return pages[i];
282 }
283
284 /// Get the number of available page identifiers
285 int wxRichTextFormattingDialogFactory::GetPageIdCount() const
286 {
287 return 5;
288 }
289
290 /// Set the sheet style, called at the start of wxRichTextFormattingDialog::Create
291 bool wxRichTextFormattingDialogFactory::SetSheetStyle(wxRichTextFormattingDialog* dialog)
292 {
293 bool useToolBook = wxRICHTEXT_USE_TOOLBOOK;
294 if (useToolBook)
295 {
296 int sheetStyle = wxPROPSHEET_SHRINKTOFIT;
297 #ifdef __WXMAC__
298 sheetStyle |= wxPROPSHEET_BUTTONTOOLBOOK;
299 #else
300 sheetStyle |= wxPROPSHEET_TOOLBOOK;
301 #endif
302
303 dialog->SetSheetStyle(sheetStyle);
304 dialog->SetSheetInnerBorder(0);
305 dialog->SetSheetOuterBorder(0);
306 }
307
308 return true;
309 }
310
311 /// Create the main dialog buttons
312 bool wxRichTextFormattingDialogFactory::CreateButtons(wxRichTextFormattingDialog* dialog)
313 {
314 bool useToolBook = wxRICHTEXT_USE_TOOLBOOK;
315
316 // If using a toolbook, also follow Mac style and don't create buttons
317 int flags = wxOK|wxCANCEL;
318 #ifndef __WXWINCE__
319 flags |= wxHELP;
320 #endif
321
322 if (!useToolBook)
323 dialog->CreateButtons(flags);
324
325 return true;
326 }
327
328 /*
329 * Module to initialise and clean up handlers
330 */
331
332 class wxRichTextFormattingDialogModule: public wxModule
333 {
334 DECLARE_DYNAMIC_CLASS(wxRichTextFormattingDialogModule)
335 public:
336 wxRichTextFormattingDialogModule() {}
337 bool OnInit() { wxRichTextFormattingDialog::SetFormattingDialogFactory(new wxRichTextFormattingDialogFactory); return true; };
338 void OnExit() { wxRichTextFormattingDialog::SetFormattingDialogFactory(NULL); };
339 };
340
341 IMPLEMENT_DYNAMIC_CLASS(wxRichTextFormattingDialogModule, wxModule)
342
343 /*
344 * Font preview control
345 */
346
347 BEGIN_EVENT_TABLE(wxRichTextFontPreviewCtrl, wxWindow)
348 EVT_PAINT(wxRichTextFontPreviewCtrl::OnPaint)
349 END_EVENT_TABLE()
350
351 void wxRichTextFontPreviewCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
352 {
353 wxPaintDC dc(this);
354
355 wxSize size = GetSize();
356 wxFont font = GetFont();
357
358 if ( font.Ok() )
359 {
360 dc.SetFont(font);
361 // Calculate vertical and horizontal centre
362 long w = 0, h = 0;
363
364 wxString text(_("ABCDEFGabcdefg12345"));
365
366 dc.GetTextExtent( text, &w, &h);
367 int cx = wxMax(2, (size.x/2) - (w/2));
368 int cy = wxMax(2, (size.y/2) - (h/2));
369
370 dc.SetTextForeground(GetForegroundColour());
371 dc.SetClippingRegion(2, 2, size.x-4, size.y-4);
372 dc.DrawText(text, cx, cy);
373 dc.DestroyClippingRegion();
374 }
375 }
376
377 // Helper for pages to get the top-level dialog
378 wxRichTextFormattingDialog* wxRichTextFormattingDialog::GetDialog(wxWindow* win)
379 {
380 wxWindow* p = win->GetParent();
381 while (p && !p->IsKindOf(CLASSINFO(wxRichTextFormattingDialog)))
382 p = p->GetParent();
383 wxRichTextFormattingDialog* dialog = wxDynamicCast(p, wxRichTextFormattingDialog);
384 return dialog;
385 }
386
387
388 // Helper for pages to get the attributes
389 wxTextAttrEx* wxRichTextFormattingDialog::GetDialogAttributes(wxWindow* win)
390 {
391 wxRichTextFormattingDialog* dialog = GetDialog(win);
392 if (dialog)
393 return & dialog->GetAttributes();
394 else
395 return NULL;
396 }
397
398 // Helper for pages to get the style
399 wxRichTextStyleDefinition* wxRichTextFormattingDialog::GetDialogStyleDefinition(wxWindow* win)
400 {
401 wxRichTextFormattingDialog* dialog = GetDialog(win);
402 if (dialog)
403 return dialog->GetStyleDefinition();
404 else
405 return NULL;
406 }
407
408 /*
409 * A control for displaying a small preview of a colour or bitmap
410 */
411
412 BEGIN_EVENT_TABLE(wxRichTextColourSwatchCtrl, wxControl)
413 EVT_MOUSE_EVENTS(wxRichTextColourSwatchCtrl::OnMouseEvent)
414 END_EVENT_TABLE()
415
416 IMPLEMENT_CLASS(wxRichTextColourSwatchCtrl, wxControl)
417
418 wxRichTextColourSwatchCtrl::wxRichTextColourSwatchCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style):
419 wxControl(parent, id, pos, size, style)
420 {
421 SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
422 SetBackgroundStyle(wxBG_STYLE_COLOUR);
423 }
424
425 wxRichTextColourSwatchCtrl::~wxRichTextColourSwatchCtrl()
426 {
427 }
428
429 void wxRichTextColourSwatchCtrl::OnMouseEvent(wxMouseEvent& event)
430 {
431 if (event.LeftDown())
432 {
433 wxWindow* parent = GetParent();
434 while (parent != NULL && !parent->IsKindOf(CLASSINFO(wxDialog)) && !parent->IsKindOf(CLASSINFO(wxFrame)))
435 parent = parent->GetParent();
436
437 wxColourData data;
438 data.SetChooseFull(true);
439 data.SetColour(m_colour);
440 wxColourDialog *dialog = new wxColourDialog(parent, &data);
441 // Crashes on wxMac (no m_peer)
442 #ifndef __WXMAC__
443 dialog->SetTitle(_("Background colour"));
444 #endif
445 if (dialog->ShowModal() == wxID_OK)
446 {
447 wxColourData retData = dialog->GetColourData();
448 m_colour = retData.GetColour();
449 SetBackgroundColour(m_colour);
450 }
451 dialog->Destroy();
452 Refresh();
453
454 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
455 GetEventHandler()->ProcessEvent(event);
456 }
457 }
458
459 #if wxUSE_HTML
460
461 /*!
462 * wxRichTextFontListBox class declaration
463 * A listbox to display styles.
464 */
465
466 IMPLEMENT_CLASS(wxRichTextFontListBox, wxHtmlListBox)
467
468 BEGIN_EVENT_TABLE(wxRichTextFontListBox, wxHtmlListBox)
469 END_EVENT_TABLE()
470
471 wxRichTextFontListBox::wxRichTextFontListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos,
472 const wxSize& size, long style)
473 {
474 Init();
475 Create(parent, id, pos, size, style);
476 }
477
478 bool wxRichTextFontListBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
479 const wxSize& size, long style)
480 {
481 return wxHtmlListBox::Create(parent, id, pos, size, style);
482 }
483
484 wxRichTextFontListBox::~wxRichTextFontListBox()
485 {
486 }
487
488 /// Returns the HTML for this item
489 wxString wxRichTextFontListBox::OnGetItem(size_t n) const
490 {
491 if (m_faceNames.GetCount() == 0)
492 return wxEmptyString;
493
494 wxString str = CreateHTML(m_faceNames[n]);
495 return str;
496 }
497
498 /// Get font name for index
499 wxString wxRichTextFontListBox::GetFaceName(size_t i) const
500 {
501 return m_faceNames[i];
502 }
503
504 /// Set selection for string, returning the index.
505 int wxRichTextFontListBox::SetFaceNameSelection(const wxString& name)
506 {
507 int i = m_faceNames.Index(name);
508 SetSelection(i);
509
510 return i;
511 }
512
513 /// Updates the font list
514 void wxRichTextFontListBox::UpdateFonts()
515 {
516 wxFontEnumerator enumerator;
517 enumerator.EnumerateFacenames();
518 wxArrayString facenames = enumerator.GetFacenames();
519 m_faceNames = facenames;
520 m_faceNames.Sort();
521
522 SetItemCount(m_faceNames.GetCount());
523 Refresh();
524 }
525
526 #if 0
527 // Convert a colour to a 6-digit hex string
528 static wxString ColourToHexString(const wxColour& col)
529 {
530 wxString hex;
531
532 hex += wxDecToHex(col.Red());
533 hex += wxDecToHex(col.Green());
534 hex += wxDecToHex(col.Blue());
535
536 return hex;
537 }
538 #endif
539
540 /// Creates a suitable HTML fragment for a definition
541 wxString wxRichTextFontListBox::CreateHTML(const wxString& facename) const
542 {
543 wxString str = wxT("<font");
544
545 str << wxT(" size=\"+2\"");;
546
547 if (!facename.IsEmpty() && facename != _("(none)"))
548 str << wxT(" face=\"") << facename << wxT("\"");
549 /*
550 if (def->GetStyle().GetTextColour().Ok())
551 str << wxT(" color=\"#") << ColourToHexString(def->GetStyle().GetTextColour()) << wxT("\"");
552 */
553
554 str << wxT(">");
555
556 bool hasBold = false;
557
558 if (hasBold)
559 str << wxT("<b>");
560
561 str += facename;
562
563 if (hasBold)
564 str << wxT("</b>");
565
566 str << wxT("</font>");
567
568 return str;
569 }
570
571 #endif
572 // wxUSE_HTML
573
574
575 #endif
576 // wxUSE_RICHTEXT
577