/***************************************************************************
 *   crwx-ng                                                               *
 *   Copyright (C) 2007-2009,2012 Vadim Lopatin <coolreader.org@gmail.com> *
 *   Copyright (C) 2018 Sergey Torokhov <torokhov-s-a@yandex.ru>           *
 *   Copyright (C) 2020,2023,2024 Aleksey Chernov <valexlin@gmail.com>     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License           *
 *   as published by the Free Software Foundation; either version 2        *
 *   of the License, or (at your option) any later version.                *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the Free Software           *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,            *
 *   MA 02110-1301, USA.                                                   *
 ***************************************************************************/

// options dialog, implementation
#include <wx/wx.h>
#include <wx/colordlg.h>
#include <wx/spinctrl.h>

#include <crengine.h>

#include "optdlg.h"
#include "utils.h"
#include "app-props.h"

class CheckBoxOption: public PropOption
{
private:
    bool _defvalue;
public:
    CheckBoxOption(wxCheckBox* control, const char* option, bool defvalue)
            : PropOption(control, option)
            , _defvalue(defvalue) { }
    virtual void ControlToOption(CRPropRef props) {
        props->setBool(_option, ((wxCheckBox*)_control)->IsChecked());
    }
    virtual void OptionToControl(CRPropRef props) {
        ((wxCheckBox*)_control)->SetValue(props->getBoolDef(_option, _defvalue));
    }
    virtual wxString getControlValue() const {
        return ((wxCheckBox*)_control)->IsChecked() ? wxT("1") : wxT("0");
    }
};

class ComboBoxOption: public PropOption
{
private:
    wxString _defValue;
    wxArrayString _choices;
    wxArrayString _values;
public:
    ComboBoxOption(wxComboBox* control, const char* option, const wxString& defValue, const wxArrayString& choices,
                   const wxArrayString& values)
            : PropOption(control, option)
            , _defValue(defValue)
            , _choices(choices)
            , _values(values) { }
    virtual void ControlToOption(CRPropRef props) {
        int idx = ((wxComboBox*)_control)->GetCurrentSelection();
        wxString v = (idx >= 0 && idx < _values.GetCount()) ? _values[idx] : _defValue;
        props->setString(_option, wx2cr(v));
    }
    virtual void OptionToControl(CRPropRef props) {
        int idx = 0; // if item not found use first
        lString32 s32 = props->getStringDef(_option, LCSTR(wx2cr(_defValue)));
        wxString v = cr2wx(s32);
        for (size_t i = 0; i < _values.GetCount(); i++) {
            if (v == _values[i]) {
                idx = (int)i;
                break;
            }
        }
        ((wxComboBox*)_control)->SetValue(_choices[idx]);
    }
    virtual wxString getControlValue() const {
        int idx = ((wxComboBox*)_control)->GetCurrentSelection();
        return (idx >= 0 && idx < _values.GetCount()) ? _values[idx] : _defValue;
    }
};

class NumberOption: public PropOption
{
private:
    int _defvalue;
    int _min;
    int _max;
public:
    NumberOption(wxSpinCtrl* control, const char* option, int defvalue, int min, int max)
            : PropOption(control, option)
            , _defvalue(defvalue)
            , _min(min)
            , _max(max) {
        control->SetRange(min, max);
    }
    virtual void ControlToOption(CRPropRef props) {
        props->setInt(_option, ((wxSpinCtrl*)_control)->GetValue());
    }
    virtual void OptionToControl(CRPropRef props) {
        int value = props->getIntDef(_option, _defvalue);
        if (value < _min)
            value = _min;
        if (value > _max)
            value = _max;
        ((wxSpinCtrl*)_control)->SetValue(value);
    }
    virtual wxString getControlValue() const {
        return wxString::Format(wxT("%d"), ((wxSpinCtrl*)_control)->GetValue());
    }
};

class MyColorBox: public wxControl
{
private:
    wxColour _color;
public:
    MyColorBox(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition,
               const wxSize& size = wxDefaultSize)
            : wxControl(parent, id, pos, size, wxBORDER_NONE) {
        _color = wxColour(0, 0, 0);
    }
    void SetColour(const wxColour& c) {
        _color = c;
        Refresh(false);
    }
protected:
    void OnPaint(wxPaintEvent& event) {
        wxPaintDC dc(this);
        int w, h;
        GetClientSize(&w, &h);
        wxPen pen(_color);
        wxBrush brush(_color);
        dc.SetPen(pen);
        dc.SetBrush(brush);
        dc.DrawRectangle(0, 0, w, h);
        dc.SetPen(wxNullPen);
        dc.SetBrush(wxNullBrush);
    }
    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(MyColorBox, wxControl)
    EVT_PAINT(MyColorBox::OnPaint)
END_EVENT_TABLE()

class ColorOption: public PropOption
{
private:
    lvColor _value;
    int _buttonId;
public:
    ColorOption(MyColorBox* control, const char* option, lUInt32 value, int buttonId)
            : PropOption(control, option)
            , _value(value)
            , _buttonId(buttonId) { }
    virtual void ControlToOption(CRPropRef props) {
        props->setHex(_option, _value.get());
    }
    virtual void OptionToControl(CRPropRef props) {
        lvColor cl = props->getIntDef(_option, _value);
        _value = cl;
        ((MyColorBox*)_control)->SetColour(wxColor(cl.r(), cl.g(), cl.b()));
    }
    virtual wxString getControlValue() const {
        return wxString::Format(wxT("0x%02X%02X%02X"), _value.r(), _value.g(), _value.b());
    }
    virtual int getActionId() {
        return _buttonId;
    }
    virtual void onAction() {
        wxColourData data;
        data.SetColour(wxColor(_value.r(), _value.g(), _value.b()));
        wxColourDialog dlg(_control, &data);
        if (dlg.ShowModal() == wxID_OK) {
            wxColourData& data = dlg.GetColourData();
            wxColor cl = data.GetColour();
            lvColor lvcl(cl.Red(), cl.Green(), cl.Blue());
            _value = lvcl;
            ((MyColorBox*)_control)->SetColour(wxColor(_value.r(), _value.g(), _value.b()));
        }
    }
};

OptPanel::OptPanel() : _sizer(NULL) { }

void OptPanel::Create(wxWindow* parent, wxWindowID id, wxString title) {
    wxPanel::Create(parent, id, wxDefaultPosition, wxSize(350, 300), wxTAB_TRAVERSAL, title);
    _sizer = new wxStaticBoxSizer(wxVERTICAL, this, title);
    CreateControls();
    SetSizer(_sizer);
    //InitDialog();
}

void OptPanel::PropsToControls(CRPropRef props) {
    for (int i = 0; i < _opts.length(); i++) {
        _opts[i]->OptionToControl(props);
        const char* option = _opts[i]->getOption();
        OnOptionControlChanged(option, cr2wx(props->getStringDef(option, "")));
    }
}

void OptPanel::ControlsToProps(CRPropRef props) {
    for (int i = 0; i < _opts.length(); i++) {
        _opts[i]->ControlToOption(props);
    }
}

wxControl* OptPanel::AddColor(const char* option, wxString caption, lvColor defValue, int buttonId) {
    wxSize emSize = GetTextExtent("M");
    wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    sizer->Add(new wxStaticText(this, wxID_ANY, caption),
               0, // make vertically unstretchable
               wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4);
    wxButton* btn = new wxButton(this, buttonId, wxString(wxT("Change")));
    sizer->Add(btn,
               0, // make vertically unstretchable
               wxALIGN_CENTER_VERTICAL | wxALL, 4);
    MyColorBox* control = new MyColorBox(this, wxID_ANY);
    control->SetMinSize(wxSize(emSize.y, emSize.y));
    sizer->Add(control,
               0, // make vertically unstretchable
               wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4);

    _sizer->Add(sizer,
                0, // make vertically unstretchable
                wxALIGN_LEFT | wxALL, 4);
    _opts.add(new ColorOption(control, option, defValue, buttonId));
    return control;
}

wxComboBox* OptPanel::AddFontFaceCombobox(const char* option, wxString caption) {
    lString32Collection list;
    fontMan->getFaceList(list);
    wxArrayString titles;
    wxArrayString values;
    wxString defValue = "";
    for (int i = 0; i < list.length(); i++) {
        wxString item = cr2wx(list[i]);
        if (list[i] == "Arial")
            defValue = item;
        titles.Add(item);
        values.Add(item);
    }
    if (defValue.Length() == 0 && !values.IsEmpty())
        defValue = values[0];
    wxComboBox* res = AddCombobox(option, caption, titles, values, defValue);
    return res;
}

wxComboBox* OptPanel::AddCombobox(const char* option, wxString caption, const wxArrayString& option_titles,
                                  const wxArrayString& option_values, const wxString& defValue) {
    wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    sizer->Add(new wxStaticText(this, wxID_ANY, caption),
               0, // make vertically unstretchable
               wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4);
    wxComboBox* control = new wxComboBox(this, wxID_ANY, defValue, wxDefaultPosition, wxDefaultSize, option_titles,
                                         wxCB_READONLY | wxCB_DROPDOWN);
    sizer->Add(control,
               0, // make vertically unstretchable
               wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4);
    _sizer->Add(sizer,
                0, // make vertically unstretchable
                wxALIGN_LEFT | wxALL, 4);
    _opts.add(new ComboBoxOption(control, option, defValue, option_titles, option_values));
    return control;
}

wxCheckBox* OptPanel::AddCheckbox(const char* option, wxString caption, bool defValue) {
    wxCheckBox* control = new wxCheckBox(this, wxID_ANY, caption);
    _sizer->Add(control,
                0, // make vertically unstretchable
                wxALIGN_LEFT | wxALL, 8);
    _opts.add(new CheckBoxOption(control, option, defValue));
    return control;
}

wxSpinCtrl* OptPanel::AddNumberBox(const char* option, wxString caption, int defValue, int min, int max) {
    wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    sizer->Add(new wxStaticText(this, wxID_ANY, caption),
               0, // make vertically unstretchable
               wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4);
    wxSpinCtrl* control = new wxSpinCtrl(this);
    sizer->Add(control,
               0, // make vertically unstretchable
               wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4);
    _sizer->Add(sizer,
                0, // make vertically unstretchable
                wxALIGN_LEFT | wxALL, 4);
    _opts.add(new NumberOption(control, option, defValue, min, max));
    return control;
}

const static wxString choices_toolbar_size_titles[] = {
    wxT("Hide Toolbar"),
    wxT("Small buttons"),
    wxT("Medium buttons"),
    wxT("Large buttons"),
};
const static wxString choices_toolbar_size_values[] = {
    wxT("0"),
    wxT("1"),
    wxT("2"),
    wxT("3"),
};

const static wxString choices_toolbar_position_titles[] = {
    wxT("Top"),
    wxT("Left"),
    wxT("Right"),
    wxT("Bottom"),
};
const static wxString choices_toolbar_position_values[] = {
    wxT("0"),
    wxT("1"),
    wxT("2"),
    wxT("3"),
};

const static wxString choices_font_aa_titles[] = { wxT("No antialiasing"),  wxT("Gray"),
                                                   wxT("LCD RGB"),          wxT("LCD BGR"),
                                                   wxT("LCD Vertical RGB"), wxT("LCD Vertical BGR") };
const static wxString choices_font_aa_values[] = { wxT("0"), wxT("2"), wxT("4"), wxT("5"), wxT("8"), wxT("9") };

const static wxString choices_page_titles[] = { wxT("Scroll view"), wxT("1 Book page"), wxT("2 Book pages") };
const static wxString choices_page_values[] = { wxT("0"), wxT("1"), wxT("2") };

const static wxString choices_shaping_titles[] = { wxT("Simple (Fast)"), wxT("Light (Optimal)"),
                                                   wxT("Full (With ligatures)") };
const static wxString choices_shaping_values[] = { wxT("0"), wxT("1"), wxT("2") };

const static wxString choices_hinting_titles[] = { wxT("Disabled"), wxT("Bytecode"), wxT("Auto hinting") };
const static wxString choices_hinting_values[] = { wxT("0"), wxT("1"), wxT("2") };

const static wxString choices_linespacing_titles[] = { "75 %",  "80 %",  "85 %",  "90 %",  "95 %",
                                                       "100 %", "110 %", "120 %", "140 %", "150 %" };
const static wxString choices_linespacing_values[] = {
    "75", "80", "85", "90", "95", "100", "110", "120", "140", "150"
};

const static wxString choices_minspace_width_titles[] = { "50 %", "60 %", "70 %", "80 %", "90 %", "100 %" };
const static wxString choices_minspace_width_values[] = { "50", "60", "70", "80", "90", "100" };

class OptPanelWindow: public OptPanel
{
public:
    OptPanelWindow(wxWindow* parent) {
        OptPanel::Create(parent, ID_OPTIONS_WINDOW, wxT("Window options"));
    }
    virtual void CreateControls() {
        AddCombobox(PROP_APP_WINDOW_TOOLBAR_SIZE, wxT("Toolbar size"), wxArrayString(4, choices_toolbar_size_titles),
                    wxArrayString(4, choices_toolbar_size_values), choices_toolbar_size_values[2]);
        AddCombobox(PROP_APP_WINDOW_TOOLBAR_POSITION, wxT("Toolbar position"),
                    wxArrayString(4, choices_toolbar_position_titles),
                    wxArrayString(4, choices_toolbar_position_values), choices_toolbar_position_values[0]);
        AddCheckbox(PROP_APP_WINDOW_SHOW_MENU, wxT("Show menu"), true);
        AddCheckbox(PROP_APP_WINDOW_SHOW_STATUSBAR, wxT("Show statusbar"), true);
    }
};

class OptPanelApp: public OptPanel
{
public:
    OptPanelApp(wxWindow* parent) {
        OptPanel::Create(parent, wxID_ANY, wxT("Application options"));
    }
    virtual void CreateControls() {
        AddCheckbox(PROP_APP_OPEN_LAST_BOOK, wxT("Open last book on start"), true);
    }
};

class OptPanelPageHeader: public OptPanel
{
public:
    OptPanelPageHeader(wxWindow* parent) {
        OptPanel::Create(parent, wxID_ANY, wxT("Page header options"));
    }
    virtual void CreateControls() {
        AddCheckbox(PROP_STATUS_LINE, wxT("Enable page header"), true);
        AddCheckbox(PROP_SHOW_TITLE, wxT("Show author and title"), true);
        AddCheckbox(PROP_STATUS_CHAPTER_MARKS, wxT("Show chapter marks"), true);
        AddCheckbox(PROP_SHOW_PAGE_COUNT, wxT("Show page count"), true);
        AddCheckbox(PROP_SHOW_PAGE_NUMBER, wxT("Show page number"), true);
        AddCheckbox(PROP_SHOW_TIME, wxT("Show clock"), true);
        AddCheckbox(PROP_SHOW_BATTERY, wxT("Show battery indicator"), true);
        AddFontFaceCombobox(PROP_STATUS_FONT_FACE, wxT("Header font face"));
        AddNumberBox(PROP_STATUS_FONT_SIZE, wxT("Header font size"), 14, 10, 72);
    }
};

enum
{
    Btn_View_Text_Color = OPTION_DIALOG_BUTTON_START,
    Btn_View_Background_Color,
};

BEGIN_EVENT_TABLE(OptPanel, wxPanel)
    EVT_COMMAND_RANGE(Btn_View_Text_Color, Btn_View_Background_Color, wxEVT_COMMAND_BUTTON_CLICKED,
                      OptPanel::OnButtonClicked)
    EVT_COMBOBOX(wxID_ANY, OptPanel::OnComboBoxItemSelected)
    EVT_CHECKBOX(wxID_ANY, OptPanel::OnCheckBoxClicked)
    EVT_SPINCTRL(wxID_ANY, OptPanel::OnSpinCtrlUpdated)
END_EVENT_TABLE()

void OptPanel::OnButtonClicked(wxCommandEvent& event) {
    for (int i = 0; i < _opts.length(); i++)
        if (_opts[i]->getActionId() == event.GetId())
            _opts[i]->onAction();
}

void OptPanel::OnComboBoxItemSelected(wxCommandEvent& event) {
    for (int i = 0; i < _opts.length(); i++)
        if (_opts[i]->getControl() == event.GetEventObject()) {
            wxString controlValue = _opts[i]->getControlValue();
            OnOptionControlChanged(_opts[i]->getOption(), controlValue);
        }
}

void OptPanel::OnCheckBoxClicked(wxCommandEvent& event) {
    for (int i = 0; i < _opts.length(); i++)
        if (_opts[i]->getControl() == event.GetEventObject()) {
            wxString controlValue = _opts[i]->getControlValue();
            OnOptionControlChanged(_opts[i]->getOption(), controlValue);
        }
}

void OptPanel::OnSpinCtrlUpdated(wxSpinEvent& event) {
    for (int i = 0; i < _opts.length(); i++)
        if (_opts[i]->getControl() == event.GetEventObject()) {
            wxString controlValue = _opts[i]->getControlValue();
            OnOptionControlChanged(_opts[i]->getOption(), controlValue);
        }
}

class OptPanelView: public OptPanel
{
public:
    OptPanelView(wxWindow* parent) {
        OptPanel::Create(parent, wxID_ANY, wxT("View options"));
    }
    virtual void CreateControls() {
        AddCombobox(PROP_APP_PAGE_VIEW_MODE, wxT("View mode"), wxArrayString(3, choices_page_titles),
                    wxArrayString(3, choices_page_values), choices_page_values[1]);
        AddColor(PROP_FONT_COLOR, wxT("Text color"), 0x000000, Btn_View_Text_Color);
        AddColor(PROP_BACKGROUND_COLOR, wxT("Background color"), 0xFFFFFF, Btn_View_Background_Color);
        AddCheckbox(PROP_FLOATING_PUNCTUATION, wxT("Hanging punctuation"), true);
        AddCombobox(PROP_INTERLINE_SPACE, wxT("Line spacing"), wxArrayString(10, choices_linespacing_titles),
                    wxArrayString(10, choices_linespacing_values), choices_linespacing_values[5]);
        AddCombobox(PROP_FORMAT_MIN_SPACE_CONDENSING_PERCENT, wxT("Minimum space width"),
                    wxArrayString(6, choices_minspace_width_titles), wxArrayString(6, choices_minspace_width_values),
                    choices_minspace_width_values[2]);
        AddCheckbox(PROP_FOOTNOTES, wxT("Show footnotes at bottom of page"), true);
        AddCheckbox(PROP_EMBEDDED_STYLES, wxT("EPUB: allow inline styles"), true);
        AddCheckbox(PROP_EMBEDDED_FONTS, wxT("EPUB: allow embedded fonts"), true);
    }
};

class OptPanelFont: public OptPanel
{
public:
    OptPanelFont(wxWindow* parent) {
        OptPanel::Create(parent, wxID_ANY, wxT("Font options"));
    }
    virtual void CreateControls() {
        AddFontFaceCombobox(PROP_FONT_FACE, wxT("Font face"));
        AddNumberBox(PROP_FONT_SIZE, wxT("Font size"), 18, 14, 72);
        AddCombobox(PROP_FONT_ANTIALIASING, wxT("Font antialiasing"), wxArrayString(6, choices_font_aa_titles),
                    wxArrayString(6, choices_font_aa_values), choices_font_aa_values[1]);
        AddCombobox(PROP_FONT_SHAPING, wxT("Text shaping"), wxArrayString(3, choices_shaping_titles),
                    wxArrayString(3, choices_shaping_values), choices_shaping_values[1]);
        AddCombobox(PROP_FONT_HINTING, wxT("Font hinting"), wxArrayString(3, choices_hinting_titles),
                    wxArrayString(3, choices_hinting_values), choices_hinting_values[1]);
        AddCheckbox(PROP_FONT_KERNING_ENABLED, wxT("Font kerning"), true);
    }
};

class OptPanelLang: public OptPanel
{
    bool _enableMultiLang;
    wxCheckBox* _enableHyphensBox;
    wxComboBox* _hyphenDictsBox;
public:
    OptPanelLang(wxWindow* parent) {
        OptPanel::Create(parent, wxID_ANY, wxT("Language options"));
        _enableMultiLang = false;
    }
    virtual void CreateControls() {
        AddCheckbox(PROP_TEXTLANG_EMBEDDED_LANGS_ENABLED, wxT("Support for multilingual documents"), true);
        _enableHyphensBox = AddCheckbox(PROP_TEXTLANG_HYPHENATION_ENABLED, wxT("Allow hyphenations"), true);
        wxArrayString titles;
        wxArrayString values;
        wxString defValue = "";
        for (int i = 0; i < HyphMan::getDictList()->length(); i++) {
            HyphDictionary* item = HyphMan::getDictList()->get(i);
            wxString s = cr2wx(item->getTitle());
            if (item->getType() == HDT_NONE)
                s = wxT("[No hyphenation]");
            else if (item->getType() == HDT_ALGORITHM) {
                s = wxT("[Algorithmic hyphenation]");
                defValue = s;
            }
            titles.Add(s);
            values.Add(cr2wx(item->getId()));
        }
        if (defValue.Length() == 0 && !values.IsEmpty())
            defValue = values[0];
        _hyphenDictsBox = AddCombobox(PROP_HYPHENATION_DICT, wxT("Hyphenation dictionary"), titles, values, defValue);
    }
    virtual void OnOptionControlChanged(const wxString& option, const wxString& controlValue) {
        bool prevMultiLang = _enableMultiLang;
        if (option == PROP_TEXTLANG_EMBEDDED_LANGS_ENABLED) {
            _enableMultiLang = (controlValue == wxT("1"));
        }
        if (prevMultiLang != _enableMultiLang) {
            _enableHyphensBox->Enable(_enableMultiLang);
            _hyphenDictsBox->Enable(!_enableMultiLang);
        }
    }
};

CR3OptionsDialog::CR3OptionsDialog(CRPropRef props) : wxDialog(), _notebook(NULL), _opt_window(NULL), _oldprops(props) {
    _props = _oldprops->clone();
}

CR3OptionsDialog::~CR3OptionsDialog() {
    if (_notebook) {
        delete _notebook;
        _notebook = NULL;
    }
}

void CR3OptionsDialog::PropsToControls() {
    for (unsigned i = 0; i < _notebook->GetPageCount(); i++) {
        OptPanel* page = (OptPanel*)_notebook->GetPage(i);
        page->PropsToControls(_props);
    }
}

void CR3OptionsDialog::ControlsToProps() {
    for (unsigned i = 0; i < _notebook->GetPageCount(); i++) {
        OptPanel* page = (OptPanel*)_notebook->GetPage(i);
        page->ControlsToProps(_props);
    }
}

bool CR3OptionsDialog::Create(wxWindow* parent, wxWindowID id) {
    wxSize wsize = parent->GetTextExtent("M");
    wsize.x *= 40;
    wsize.y *= 25;
    bool res = wxDialog::Create(parent, id, wxT("crwx options"), wxDefaultPosition, wsize,
                                wxRESIZE_BORDER | wxCLOSE_BOX | wxCAPTION, wxString(wxT("dialogBox")));
    if (res) {
        _notebook = new wxTreebook(this, ID_OPTIONS_TREEBOOK);
        _notebook->Hide();
        wxSizer* btnSizer = CreateButtonSizer(wxOK | wxCANCEL);
        wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
        sizer->Add(_notebook,
                   1,             // make vertically stretchable
                   wxEXPAND |     // make horizontally stretchable
                           wxALL, //   and make border all around
                   10);           // set border width to 10

        sizer->Add(btnSizer,
                   0, // make vertically unstretchable
                   wxALIGN_CENTER | wxALL, 4);

        _opt_window = new OptPanelWindow(_notebook);
        _notebook->InsertPage(0, _opt_window, wxT("Window"));

        _opt_view = new OptPanelView(_notebook);
        _notebook->InsertPage(1, _opt_view, wxT("View"));

        _opt_font = new OptPanelFont(_notebook);
        _notebook->InsertPage(2, _opt_font, wxT("Font"));

        _opt_lang = new OptPanelLang(_notebook);
        _notebook->InsertPage(3, _opt_lang, wxT("Language"));

        _opt_page = new OptPanelPageHeader(_notebook);
        _notebook->InsertPage(4, _opt_page, wxT("Page header"));

        _opt_app = new OptPanelApp(_notebook);
        _notebook->InsertPage(5, _opt_app, wxT("Application"));

        SetSizer(sizer);
#ifdef _WIN32
        // For some reason SetSizeHints() doesn't work here.
        SetMinSize(wsize);
#else
        sizer->SetSizeHints(this);
#endif
        PropsToControls();
        _notebook->Show();
        InitDialog();
    }
    return res;
}
