1 // Copyright (c) 2005, Rodrigo Braz Monteiro
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of the Aegisub Group nor the names of its contributors
13 // may be used to endorse or promote products derived from this software
14 // without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 // POSSIBILITY OF SUCH DAMAGE.
27 //
28 // Aegisub Project http://www.aegisub.org/
29
30 /// @file dialog_style_editor.cpp
31 /// @brief Style Editor dialogue box
32 /// @ingroup style_editor
33 ///
34
35 #include "ass_dialogue.h"
36 #include "ass_file.h"
37 #include "ass_style.h"
38 #include "ass_style_storage.h"
39 #include "colour_button.h"
40 #include "compat.h"
41 #include "dialog_style_editor.h"
42 #include "help_button.h"
43 #include "include/aegisub/context.h"
44 #include "libresrc/libresrc.h"
45 #include "options.h"
46 #include "persist_location.h"
47 #include "selection_controller.h"
48 #include "subs_preview.h"
49 #include "utils.h"
50 #include "validators.h"
51
52 #include <libaegisub/of_type_adaptor.h>
53 #include <libaegisub/make_unique.h>
54
55 #include <algorithm>
56
57 #include <wx/bmpbuttn.h>
58 #include <wx/checkbox.h>
59 #include <wx/msgdlg.h>
60 #include <wx/sizer.h>
61 #include <wx/spinctrl.h>
62 #include <wx/stattext.h>
63
64 /// Style rename helper that walks a file searching for a style and optionally
65 /// updating references to it
66 class StyleRenamer {
67 agi::Context *c;
68 bool found_any = false;
69 bool do_replace = false;
70 std::string source_name;
71 std::string new_name;
72
73 /// Process a single override parameter to check if it's \r with this style name
ProcessTag(std::string const & tag,AssOverrideParameter * param,void * userData)74 static void ProcessTag(std::string const& tag, AssOverrideParameter* param, void *userData) {
75 StyleRenamer *self = static_cast<StyleRenamer*>(userData);
76 if (tag == "\\r" && param->GetType() == VariableDataType::TEXT && param->Get<std::string>() == self->source_name) {
77 if (self->do_replace)
78 param->Set(self->new_name);
79 else
80 self->found_any = true;
81 }
82 }
83
Walk(bool replace)84 void Walk(bool replace) {
85 found_any = false;
86 do_replace = replace;
87
88 for (auto& diag : c->ass->Events) {
89 if (diag.Style == source_name) {
90 if (replace)
91 diag.Style = new_name;
92 else
93 found_any = true;
94 }
95
96 auto blocks = diag.ParseTags();
97 for (auto block : blocks | agi::of_type<AssDialogueBlockOverride>())
98 block->ProcessParameters(&StyleRenamer::ProcessTag, this);
99 if (replace)
100 diag.UpdateText(blocks);
101
102 if (found_any) return;
103 }
104 }
105
106 public:
StyleRenamer(agi::Context * c,std::string source_name,std::string new_name)107 StyleRenamer(agi::Context *c, std::string source_name, std::string new_name)
108 : c(c)
109 , source_name(std::move(source_name))
110 , new_name(std::move(new_name))
111 {
112 }
113
114 /// Check if there are any uses of the original style name in the file
NeedsReplace()115 bool NeedsReplace() {
116 Walk(false);
117 return found_any;
118 }
119
120 /// Replace all uses of the original style name with the new one
Replace()121 void Replace() {
122 Walk(true);
123 }
124 };
125
DialogStyleEditor(wxWindow * parent,AssStyle * style,agi::Context * c,AssStyleStorage * store,std::string const & new_name,wxArrayString const & font_list)126 DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Context *c, AssStyleStorage *store, std::string const& new_name, wxArrayString const& font_list)
127 : wxDialog (parent, -1, _("Style Editor"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
128 , c(c)
129 , style(style)
130 , store(store)
131 {
132 if (new_name.size()) {
133 is_new = true;
134 style = this->style = new AssStyle(*style);
135 style->name = new_name;
136 }
137 else if (!style) {
138 is_new = true;
139 style = this->style = new AssStyle;
140 }
141
142 work = agi::make_unique<AssStyle>(*style);
143
144 SetIcon(GETICON(style_toolbutton_16));
145
146 auto add_with_label = [&](wxSizer *sizer, wxString const& label, wxWindow *ctrl) {
147 sizer->Add(new wxStaticText(this, -1, label), wxSizerFlags().Center().Right().Border(wxLEFT | wxRIGHT));
148 sizer->Add(ctrl, wxSizerFlags(1).Left().Expand());
149 };
150
151 auto num_text_ctrl = [&](double *value, double min, double max, double step) -> wxSpinCtrlDouble * {
152 auto scd = new wxSpinCtrlDouble(this, -1, "", wxDefaultPosition,
153 wxSize(75, -1), wxSP_ARROW_KEYS, min, max, *value, step);
154 scd->SetValidator(DoubleSpinValidator(value));
155 scd->Bind(wxEVT_SPINCTRLDOUBLE, [=](wxSpinDoubleEvent &evt) {
156 evt.Skip();
157 if (updating) return;
158
159 bool old = updating;
160 updating = true;
161 scd->GetValidator()->TransferFromWindow();
162 updating = old;
163 SubsPreview->SetStyle(*work);
164 });
165 return scd;
166 };
167
168 // Prepare control values
169 wxString EncodingValue = std::to_wstring(style->encoding);
170 wxString alignValues[9] = { "7", "8", "9", "4", "5", "6", "1", "2", "3" };
171
172 // Encoding options
173 wxArrayString encodingStrings;
174 AssStyle::GetEncodings(encodingStrings);
175
176 // Create sizers
177 wxSizer *NameSizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Style Name"));
178 wxSizer *FontSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Font"));
179 wxSizer *ColorsSizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Colors"));
180 wxSizer *MarginSizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Margins"));
181 wxSizer *OutlineBox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Outline"));
182 wxSizer *MiscBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Miscellaneous"));
183 wxSizer *PreviewBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Preview"));
184
185 // Create controls
186 StyleName = new wxTextCtrl(this, -1, to_wx(style->name));
187 FontName = new wxComboBox(this, -1, to_wx(style->font), wxDefaultPosition, wxSize(150, -1), 0, nullptr, wxCB_DROPDOWN);
188 auto FontSize = num_text_ctrl(&work->fontsize, 0, 10000.0, 1.0);
189 BoxBold = new wxCheckBox(this, -1, _("&Bold"));
190 BoxItalic = new wxCheckBox(this, -1, _("&Italic"));
191 BoxUnderline = new wxCheckBox(this, -1, _("&Underline"));
192 BoxStrikeout = new wxCheckBox(this, -1, _("&Strikeout"));
193 ColourButton *colorButton[] = {
194 new ColourButton(this, wxSize(55, 16), true, style->primary, ColorValidator(&work->primary)),
195 new ColourButton(this, wxSize(55, 16), true, style->secondary, ColorValidator(&work->secondary)),
196 new ColourButton(this, wxSize(55, 16), true, style->outline, ColorValidator(&work->outline)),
197 new ColourButton(this, wxSize(55, 16), true, style->shadow, ColorValidator(&work->shadow))
198 };
199 for (int i = 0; i < 3; i++)
200 margin[i] = new wxSpinCtrl(this, -1, std::to_wstring(style->Margin[i]),
201 wxDefaultPosition, wxSize(60, -1),
202 wxSP_ARROW_KEYS, 0, 9999, style->Margin[i]);
203
204 Alignment = new wxRadioBox(this, -1, _("Alignment"), wxDefaultPosition, wxDefaultSize, 9, alignValues, 3, wxRA_SPECIFY_COLS);
205 auto Outline = num_text_ctrl(&work->outline_w, 0.0, 1000.0, 0.1);
206 auto Shadow = num_text_ctrl(&work->shadow_w, 0.0, 1000.0, 0.1);
207 OutlineType = new wxCheckBox(this, -1, _("&Opaque box"));
208 auto ScaleX = num_text_ctrl(&work->scalex, 0.0, 10000.0, 1.0);
209 auto ScaleY = num_text_ctrl(&work->scaley, 0.0, 10000.0, 1.0);
210 auto Angle = num_text_ctrl(&work->angle, -180.0, 180.0, 1.0);
211 auto Spacing = num_text_ctrl(&work->spacing, 0.0, 1000.0, 0.1);
212 Encoding = new wxComboBox(this, -1, "", wxDefaultPosition, wxDefaultSize, encodingStrings, wxCB_READONLY);
213
214 // Set control tooltips
215 StyleName->SetToolTip(_("Style name"));
216 FontName->SetToolTip(_("Font face"));
217 FontSize->SetToolTip(_("Font size"));
218 colorButton[0]->SetToolTip(_("Choose primary color"));
219 colorButton[1]->SetToolTip(_("Choose secondary color"));
220 colorButton[2]->SetToolTip(_("Choose outline color"));
221 colorButton[3]->SetToolTip(_("Choose shadow color"));
222 margin[0]->SetToolTip(_("Distance from left edge, in pixels"));
223 margin[1]->SetToolTip(_("Distance from right edge, in pixels"));
224 margin[2]->SetToolTip(_("Distance from top/bottom edge, in pixels"));
225 OutlineType->SetToolTip(_("When selected, display an opaque box behind the subtitles instead of an outline around the text"));
226 Outline->SetToolTip(_("Outline width, in pixels"));
227 Shadow->SetToolTip(_("Shadow distance, in pixels"));
228 ScaleX->SetToolTip(_("Scale X, in percentage"));
229 ScaleY->SetToolTip(_("Scale Y, in percentage"));
230 Angle->SetToolTip(_("Angle to rotate in Z axis, in degrees"));
231 Encoding->SetToolTip(_("Encoding, only useful in unicode if the font doesn't have the proper unicode mapping"));
232 Spacing->SetToolTip(_("Character spacing, in pixels"));
233 Alignment->SetToolTip(_("Alignment in screen, in numpad style"));
234
235 // Set up controls
236 BoxBold->SetValue(style->bold);
237 BoxItalic->SetValue(style->italic);
238 BoxUnderline->SetValue(style->underline);
239 BoxStrikeout->SetValue(style->strikeout);
240 OutlineType->SetValue(style->borderstyle == 3);
241 Alignment->SetSelection(AlignToControl(style->alignment));
242 // Fill font face list box
243 FontName->Freeze();
244 FontName->Append(font_list);
245 FontName->SetValue(to_wx(style->font));
246 FontName->Thaw();
247
248 // Set encoding value
249 bool found = false;
250 for (size_t i=0;i<encodingStrings.Count();i++) {
251 if (encodingStrings[i].StartsWith(EncodingValue)) {
252 Encoding->Select(i);
253 found = true;
254 break;
255 }
256 }
257 if (!found) Encoding->Select(0);
258
259 // Style name sizer
260 NameSizer->Add(StyleName, 1, wxALL, 0);
261
262 // Font sizer
263 wxSizer *FontSizerTop = new wxBoxSizer(wxHORIZONTAL);
264 wxSizer *FontSizerBottom = new wxBoxSizer(wxHORIZONTAL);
265 FontSizerTop->Add(FontName, 1, wxALL, 0);
266 FontSizerTop->Add(FontSize, 0, wxLEFT, 5);
267 FontSizerBottom->AddStretchSpacer(1);
268 FontSizerBottom->Add(BoxBold, 0, 0, 0);
269 FontSizerBottom->Add(BoxItalic, 0, wxLEFT, 5);
270 FontSizerBottom->Add(BoxUnderline, 0, wxLEFT, 5);
271 FontSizerBottom->Add(BoxStrikeout, 0, wxLEFT, 5);
272 FontSizerBottom->AddStretchSpacer(1);
273 FontSizer->Add(FontSizerTop, 1, wxALL | wxEXPAND, 0);
274 FontSizer->Add(FontSizerBottom, 1, wxTOP | wxEXPAND, 5);
275
276 // Colors sizer
277 wxString colorLabels[] = { _("Primary"), _("Secondary"), _("Outline"), _("Shadow") };
278 ColorsSizer->AddStretchSpacer(1);
279 for (int i = 0; i < 4; ++i) {
280 auto sizer = new wxBoxSizer(wxVERTICAL);
281 sizer->Add(new wxStaticText(this, -1, colorLabels[i]), 0, wxBOTTOM | wxALIGN_CENTER, 5);
282 sizer->Add(colorButton[i], 0, wxBOTTOM | wxALIGN_CENTER, 5);
283 ColorsSizer->Add(sizer, 0, wxLEFT, i?5:0);
284 }
285 ColorsSizer->AddStretchSpacer(1);
286
287 // Margins
288 wxString marginLabels[] = { _("Left"), _("Right"), _("Vert") };
289 MarginSizer->AddStretchSpacer(1);
290 for (int i=0;i<3;i++) {
291 auto sizer = new wxBoxSizer(wxVERTICAL);
292 sizer->AddStretchSpacer(1);
293 sizer->Add(new wxStaticText(this, -1, marginLabels[i]), 0, wxCENTER, 0);
294 sizer->Add(margin[i], 0, wxTOP | wxCENTER, 5);
295 sizer->AddStretchSpacer(1);
296 MarginSizer->Add(sizer, 0, wxEXPAND | wxLEFT, i?5:0);
297 }
298 MarginSizer->AddStretchSpacer(1);
299
300 // Margins+Alignment
301 wxSizer *MarginAlign = new wxBoxSizer(wxHORIZONTAL);
302 MarginAlign->Add(MarginSizer, 1, wxLEFT | wxEXPAND, 0);
303 MarginAlign->Add(Alignment, 0, wxLEFT | wxEXPAND, 5);
304
305 // Outline
306 add_with_label(OutlineBox, _("Outline:"), Outline);
307 add_with_label(OutlineBox, _("Shadow:"), Shadow);
308 OutlineBox->Add(OutlineType, 0, wxLEFT | wxALIGN_CENTER, 5);
309
310 // Misc
311 auto MiscBoxTop = new wxFlexGridSizer(2, 4, 5, 5);
312 add_with_label(MiscBoxTop, _("Scale X%:"), ScaleX);
313 add_with_label(MiscBoxTop, _("Scale Y%:"), ScaleY);
314 add_with_label(MiscBoxTop, _("Rotation:"), Angle);
315 add_with_label(MiscBoxTop, _("Spacing:"), Spacing);
316
317 wxSizer *MiscBoxBottom = new wxBoxSizer(wxHORIZONTAL);
318 add_with_label(MiscBoxBottom, _("Encoding:"), Encoding);
319
320 MiscBox->Add(MiscBoxTop, wxSizerFlags().Expand().Center());
321 MiscBox->Add(MiscBoxBottom, wxSizerFlags().Expand().Center().Border(wxTOP));
322
323 // Preview
324 auto previewButton = new ColourButton(this, wxSize(45, 16), false, OPT_GET("Colour/Style Editor/Background/Preview")->GetColor());
325 PreviewText = new wxTextCtrl(this, -1, to_wx(OPT_GET("Tool/Style Editor/Preview Text")->GetString()));
326 SubsPreview = new SubtitlesPreview(this, wxSize(100, 60), wxSUNKEN_BORDER, OPT_GET("Colour/Style Editor/Background/Preview")->GetColor());
327
328 SubsPreview->SetToolTip(_("Preview of current style"));
329 SubsPreview->SetStyle(*style);
330 SubsPreview->SetText(from_wx(PreviewText->GetValue()));
331 PreviewText->SetToolTip(_("Text to be used for the preview"));
332 previewButton->SetToolTip(_("Color of preview background"));
333
334 wxSizer *PreviewBottomSizer = new wxBoxSizer(wxHORIZONTAL);
335 PreviewBottomSizer->Add(PreviewText, 1, wxEXPAND | wxRIGHT, 5);
336 PreviewBottomSizer->Add(previewButton, 0, wxEXPAND, 0);
337 PreviewBox->Add(SubsPreview, 1, wxEXPAND | wxBOTTOM, 5);
338 PreviewBox->Add(PreviewBottomSizer, 0, wxEXPAND | wxBOTTOM, 0);
339
340 // Buttons
341 auto ButtonSizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxAPPLY | wxHELP);
342
343 // Left side sizer
344 wxSizer *LeftSizer = new wxBoxSizer(wxVERTICAL);
345 LeftSizer->Add(NameSizer, 0, wxBOTTOM | wxEXPAND, 5);
346 LeftSizer->Add(FontSizer, 0, wxBOTTOM | wxEXPAND, 5);
347 LeftSizer->Add(ColorsSizer, 0, wxBOTTOM | wxEXPAND, 5);
348 LeftSizer->Add(MarginAlign, 0, wxBOTTOM | wxEXPAND, 0);
349
350 // Right side sizer
351 wxSizer *RightSizer = new wxBoxSizer(wxVERTICAL);
352 RightSizer->Add(OutlineBox, wxSizerFlags().Expand().Border(wxBOTTOM));
353 RightSizer->Add(MiscBox, wxSizerFlags().Expand().Border(wxBOTTOM));
354 RightSizer->Add(PreviewBox, wxSizerFlags(1).Expand());
355
356 // Controls Sizer
357 wxSizer *ControlSizer = new wxBoxSizer(wxHORIZONTAL);
358 ControlSizer->Add(LeftSizer, 0, wxEXPAND, 0);
359 ControlSizer->Add(RightSizer, 1, wxLEFT | wxEXPAND, 5);
360
361 // General Layout
362 wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL);
363 MainSizer->Add(ControlSizer, 1, wxALL | wxALIGN_CENTER | wxEXPAND, 5);
364 MainSizer->Add(ButtonSizer, 0, wxBOTTOM | wxEXPAND, 5);
365
366 SetSizerAndFit(MainSizer);
367
368 // Force the style name text field to scroll based on its final size, rather
369 // than its initial size
370 StyleName->SetInsertionPoint(0);
371 StyleName->SetInsertionPoint(-1);
372
373 persist = agi::make_unique<PersistLocation>(this, "Tool/Style Editor", true);
374
375 Bind(wxEVT_CHILD_FOCUS, &DialogStyleEditor::OnChildFocus, this);
376
377 Bind(wxEVT_CHECKBOX, &DialogStyleEditor::OnCommandPreviewUpdate, this);
378 Bind(wxEVT_COMBOBOX, &DialogStyleEditor::OnCommandPreviewUpdate, this);
379 Bind(wxEVT_SPINCTRL, &DialogStyleEditor::OnCommandPreviewUpdate, this);
380
381 previewButton->Bind(EVT_COLOR, &DialogStyleEditor::OnPreviewColourChange, this);
382 FontName->Bind(wxEVT_TEXT_ENTER, &DialogStyleEditor::OnCommandPreviewUpdate, this);
383 PreviewText->Bind(wxEVT_TEXT, &DialogStyleEditor::OnPreviewTextChange, this);
384
385 Bind(wxEVT_BUTTON, std::bind(&DialogStyleEditor::Apply, this, true, true), wxID_OK);
386 Bind(wxEVT_BUTTON, std::bind(&DialogStyleEditor::Apply, this, true, false), wxID_APPLY);
387 Bind(wxEVT_BUTTON, std::bind(&DialogStyleEditor::Apply, this, false, true), wxID_CANCEL);
388 Bind(wxEVT_BUTTON, std::bind(&HelpButton::OpenPage, "Style Editor"), wxID_HELP);
389
390 for (auto const& elem : colorButton)
391 elem->Bind(EVT_COLOR, &DialogStyleEditor::OnSetColor, this);
392 }
393
~DialogStyleEditor()394 DialogStyleEditor::~DialogStyleEditor() {
395 if (is_new)
396 delete style;
397 }
398
GetStyleName() const399 std::string DialogStyleEditor::GetStyleName() const {
400 return style->name;
401 }
402
Apply(bool apply,bool close)403 void DialogStyleEditor::Apply(bool apply, bool close) {
404 if (apply) {
405 std::string new_name = from_wx(StyleName->GetValue());
406
407 // Get list of existing styles
408 std::vector<std::string> styles = store ? store->GetNames() : c->ass->GetStyles();
409
410 // Check if style name is unique
411 AssStyle *existing = store ? store->GetStyle(new_name) : c->ass->GetStyle(new_name);
412 if (existing && existing != style) {
413 wxMessageBox(_("There is already a style with this name. Please choose another name."), _("Style name conflict"), wxOK | wxICON_ERROR | wxCENTER);
414 return;
415 }
416
417 // Style name change
418 bool did_rename = false;
419 if (work->name != new_name) {
420 if (!store && !is_new) {
421 StyleRenamer renamer(c, work->name, new_name);
422 if (renamer.NeedsReplace()) {
423 // See if user wants to update style name through script
424 int answer = wxMessageBox(
425 _("Do you want to change all instances of this style in the script to this new name?"),
426 _("Update script?"),
427 wxYES_NO | wxCANCEL);
428
429 if (answer == wxCANCEL) return;
430
431 if (answer == wxYES) {
432 did_rename = true;
433 renamer.Replace();
434 }
435 }
436 }
437
438 work->name = new_name;
439 }
440
441 UpdateWorkStyle();
442
443 *style = *work;
444 style->UpdateData();
445 if (is_new) {
446 if (store)
447 store->push_back(std::unique_ptr<AssStyle>(style));
448 else
449 c->ass->Styles.push_back(*style);
450 is_new = false;
451 }
452 if (!store)
453 c->ass->Commit(_("style change"), AssFile::COMMIT_STYLES | (did_rename ? AssFile::COMMIT_DIAG_FULL : 0));
454
455 // Update preview
456 if (!close) SubsPreview->SetStyle(*style);
457 }
458
459 if (close) {
460 EndModal(apply);
461 if (PreviewText)
462 OPT_SET("Tool/Style Editor/Preview Text")->SetString(from_wx(PreviewText->GetValue()));
463 }
464 }
465
UpdateWorkStyle()466 void DialogStyleEditor::UpdateWorkStyle() {
467 updating = true;
468 TransferDataFromWindow();
469 updating = false;
470
471 work->font = from_wx(FontName->GetValue());
472
473 long templ = 0;
474 Encoding->GetValue().BeforeFirst('-').ToLong(&templ);
475 work->encoding = templ;
476
477 work->borderstyle = OutlineType->IsChecked() ? 3 : 1;
478
479 work->alignment = ControlToAlign(Alignment->GetSelection());
480
481 for (size_t i = 0; i < 3; ++i)
482 work->Margin[i] = margin[i]->GetValue();
483
484 work->bold = BoxBold->IsChecked();
485 work->italic = BoxItalic->IsChecked();
486 work->underline = BoxUnderline->IsChecked();
487 work->strikeout = BoxStrikeout->IsChecked();
488 }
489
OnSetColor(wxThreadEvent &)490 void DialogStyleEditor::OnSetColor(wxThreadEvent&) {
491 TransferDataFromWindow();
492 SubsPreview->SetStyle(*work);
493 }
494
OnChildFocus(wxChildFocusEvent & event)495 void DialogStyleEditor::OnChildFocus(wxChildFocusEvent &event) {
496 UpdateWorkStyle();
497 SubsPreview->SetStyle(*work);
498 event.Skip();
499 }
500
OnPreviewTextChange(wxCommandEvent & event)501 void DialogStyleEditor::OnPreviewTextChange (wxCommandEvent &event) {
502 SubsPreview->SetText(from_wx(PreviewText->GetValue()));
503 event.Skip();
504 }
505
OnPreviewColourChange(wxThreadEvent & evt)506 void DialogStyleEditor::OnPreviewColourChange(wxThreadEvent &evt) {
507 SubsPreview->SetColour(evt.GetPayload<agi::Color>());
508 OPT_SET("Colour/Style Editor/Background/Preview")->SetColor(evt.GetPayload<agi::Color>());
509 }
510
OnCommandPreviewUpdate(wxCommandEvent & event)511 void DialogStyleEditor::OnCommandPreviewUpdate(wxCommandEvent &event) {
512 UpdateWorkStyle();
513 SubsPreview->SetStyle(*work);
514 event.Skip();
515 }
516
ControlToAlign(int n)517 int DialogStyleEditor::ControlToAlign(int n) {
518 switch (n) {
519 case 0: return 7;
520 case 1: return 8;
521 case 2: return 9;
522 case 3: return 4;
523 case 4: return 5;
524 case 5: return 6;
525 case 6: return 1;
526 case 7: return 2;
527 case 8: return 3;
528 default: return 2;
529 }
530 }
531
AlignToControl(int n)532 int DialogStyleEditor::AlignToControl(int n) {
533 switch (n) {
534 case 7: return 0;
535 case 8: return 1;
536 case 9: return 2;
537 case 4: return 3;
538 case 5: return 4;
539 case 6: return 5;
540 case 1: return 6;
541 case 2: return 7;
542 case 3: return 8;
543 default: return 7;
544 }
545 }
546