From 42ab8c84c0f6e3fd962e4578807be161393d9279 Mon Sep 17 00:00:00 2001 From: twanvl Date: Thu, 12 Apr 2007 17:35:00 +0000 Subject: [PATCH] Fixed TextCtrl to work for keyword properties; Added wrapping of <> around parameters to TextElement; Added colors for keyword parameters; Added menu & toolbar for keyword panel; Fixed bug in package, save/save-as was the wrong way around; Added third quality setting to RotatedDC: using SetUserScale, this gets you more precise positioning. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@250 0fc631ac-6414-0410-93d0-97cfa31319b6 --- data/en.mse-locale/locale | 15 ++++ data/magic.mse-game/game | 2 + src/data/field/multiple_choice.cpp | 7 +- src/data/field/multiple_choice.hpp | 4 - src/data/field/text.cpp | 17 +++- src/data/field/text.hpp | 11 ++- src/data/font.cpp | 5 +- src/data/font.hpp | 2 +- src/data/keyword.cpp | 3 +- src/data/keyword.hpp | 1 + src/gui/control/card_editor.hpp | 11 +++ src/gui/control/graph.cpp | 2 +- src/gui/control/native_look_editor.cpp | 2 +- src/gui/control/text_ctrl.cpp | 99 ++++++++++++--------- src/gui/control/text_ctrl.hpp | 17 +++- src/gui/image_slice_window.cpp | 2 +- src/gui/set/cards_panel.cpp | 2 +- src/gui/set/cards_panel.hpp | 2 +- src/gui/set/keywords_panel.cpp | 114 +++++++++++++++++++++++-- src/gui/set/keywords_panel.hpp | 17 ++++ src/gui/value/editor.hpp | 11 +++ src/gui/value/text.cpp | 4 +- src/gui/value/text.hpp | 18 ++++ src/render/card/viewer.cpp | 4 +- src/render/text/element.cpp | 52 +++++++++-- src/render/text/element.hpp | 5 +- src/render/text/font.cpp | 13 +-- src/render/text/symbol.cpp | 4 +- src/render/text/viewer.cpp | 30 +++++++ src/render/value/image.cpp | 2 +- src/render/value/multiple_choice.cpp | 9 +- src/util/alignment.cpp | 21 +++++ src/util/alignment.hpp | 12 +++ src/util/io/package.cpp | 2 +- src/util/rotation.cpp | 47 +++++++--- src/util/rotation.hpp | 15 +++- 36 files changed, 468 insertions(+), 116 deletions(-) diff --git a/data/en.mse-locale/locale b/data/en.mse-locale/locale index acb9ed9f..2a38ed29 100644 --- a/data/en.mse-locale/locale +++ b/data/en.mse-locale/locale @@ -41,6 +41,12 @@ menu: rotate 180: Rotated 180°, &Up Side Down card list columns: C&ard List Columns... + keywords: &Keywords + previous keyword: Select &Previous Keyword PgUp + next keyword: Select &Next Keyword PgDn + add keyword: &Add Keyword Ctrl++ + remove keyword: &Remove Select Keyword Del + format: &Format bold: &Bold Ctrl+B italic: &Italic Ctrl+I @@ -123,6 +129,12 @@ help: rotate 180: Display the card up side down card list columns: Select what columns should be shown and in what order. + keywords: + previous keyword: Selects the previous keyword in the list + next keyword: Selects the next keyword in the list + add keyword: Add a new keyword to this set + remove keyword: Delete the selected keyword from this set + format: bold: Makes the selected text bold italic: Makes the selected text italic @@ -266,6 +278,9 @@ tooltip: remove card: Remove selected card rotate card: Rotate card + add keyword: Add keyword + remove keyword: Remove selected keyword + bold: Bold italic: Italic symbols: Symbols diff --git a/data/magic.mse-game/game b/data/magic.mse-game/game index 48deafcc..c0e54000 100644 --- a/data/magic.mse-game/game +++ b/data/magic.mse-game/game @@ -285,6 +285,7 @@ set field: choice: core choice: expert choice: custom + initial: old, core, export, custom description: Should reminder text be added to keywords by default? Note: you can enable/disable reminder text by right clicking the keyword. set field: type: boolean @@ -902,6 +903,7 @@ keyword mode: name: expert description: Expert level keywords (Cycling, Vanishing, etc.) keyword mode: + is default: true name: custom description: Custom keywords diff --git a/src/data/field/multiple_choice.cpp b/src/data/field/multiple_choice.cpp index 6e619070..e2607a5b 100644 --- a/src/data/field/multiple_choice.cpp +++ b/src/data/field/multiple_choice.cpp @@ -31,15 +31,10 @@ IMPLEMENT_REFLECTION(MultipleChoiceField) { MultipleChoiceStyle::MultipleChoiceStyle(const MultipleChoiceFieldP& field) : ChoiceStyle(field) - , direction(HORIZONTAL) + , direction(LEFT_TO_RIGHT) , spacing(0) {} -IMPLEMENT_REFLECTION_ENUM(Direction) { - VALUE_N("horizontal", HORIZONTAL); - VALUE_N("vertical", VERTICAL); -} - IMPLEMENT_REFLECTION(MultipleChoiceStyle) { REFLECT_BASE(ChoiceStyle); REFLECT(direction); diff --git a/src/data/field/multiple_choice.hpp b/src/data/field/multiple_choice.hpp index 78905454..f26eb96a 100644 --- a/src/data/field/multiple_choice.hpp +++ b/src/data/field/multiple_choice.hpp @@ -32,10 +32,6 @@ class MultipleChoiceField : public ChoiceField { // ----------------------------------------------------------------------------- : MultipleChoiceStyle -enum Direction { - HORIZONTAL, VERTICAL -}; - /// The Style for a MultipleChoiceField class MultipleChoiceStyle : public ChoiceStyle { public: diff --git a/src/data/field/text.cpp b/src/data/field/text.cpp index b5a10c56..8f79ade3 100644 --- a/src/data/field/text.cpp +++ b/src/data/field/text.cpp @@ -86,6 +86,7 @@ IMPLEMENT_REFLECTION(TextStyle) { REFLECT(line_height_hard); REFLECT(line_height_line); REFLECT_N("mask", mask_filename); + REFLECT(direction); } // ----------------------------------------------------------------------------- : TextValue @@ -108,15 +109,27 @@ IMPLEMENT_REFLECTION_NAMELESS(TextValue) { // ----------------------------------------------------------------------------- : FakeTextValue +FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool untagged) + : TextValue(field), underlying(underlying) + , untagged(untagged) +{ + if (underlying) { + value.assign(untagged ? escape(*underlying) : *underlying); + } +} + void FakeTextValue::onAction(Action& a, bool undone) { - *underlying = value; + if (underlying) { + *underlying = untagged ? untag(value) : value; + } } bool FakeTextValue::equals(const Value* that) { if (this == that) return true; + if (!underlying) return false; const FakeTextValue* thatT = dynamic_cast(that); if (!thatT || underlying != thatT->underlying) return false; // update the value - value = *underlying; + value.assign(untagged ? escape(*underlying) : *underlying); return true; } diff --git a/src/data/field/text.hpp b/src/data/field/text.hpp index df1f585a..cd0f4e7e 100644 --- a/src/data/field/text.hpp +++ b/src/data/field/text.hpp @@ -65,7 +65,8 @@ class TextStyle : public Style { double line_height_hard; ///< Line height for hard linebreaks double line_height_line; ///< Line height for tags String mask_filename; ///< Filename of the mask - ContourMask mask; ///< Mask to fit the text to (may be null) + ContourMask mask; ///< Mask to fit the text to (may be null) + Direction direction; ///< In what direction is text layed out? virtual bool update(Context&); virtual void initDependencies(Context&, const Dependency&) const; @@ -104,10 +105,12 @@ class TextValue : public Value { /** Used by TextCtrl */ class FakeTextValue : public TextValue { public: - inline FakeTextValue(const TextFieldP& field, String* underlying) - : TextValue(field), underlying(underlying) {} + /// Initialize the fake text value + /** underlying can be nullptr, in that case there is no underlying value */ + FakeTextValue(const TextFieldP& field, String* underlying, bool untagged); - String* const underlying; ///< The underlying actual value + String* const underlying; ///< The underlying actual value, can be null + bool const untagged; ///< The underlying value is untagged /// Update underlying data virtual void onAction(Action& a, bool undone); diff --git a/src/data/font.cpp b/src/data/font.cpp index 2d119c0d..51ccee30 100644 --- a/src/data/font.cpp +++ b/src/data/font.cpp @@ -27,7 +27,7 @@ void Font::initDependencies(Context& ctx, const Dependency& dep) const { shadow_color.initDependencies(ctx, dep); } -FontP Font::make(bool bold, bool italic, bool placeholder_color) const { +FontP Font::make(bool bold, bool italic, bool placeholder_color, Color* other_color) const { FontP f(new Font(*this)); if (bold) f->font.SetWeight(wxBOLD); if (italic) { @@ -41,6 +41,9 @@ FontP Font::make(bool bold, bool italic, bool placeholder_color) const { f->color = f->separator_color; f->shadow_displacement = RealSize(0,0); // no shadow } + if (other_color) { + f->color = *other_color; + } return f; } diff --git a/src/data/font.hpp b/src/data/font.hpp index 2d97833f..3dfdb906 100644 --- a/src/data/font.hpp +++ b/src/data/font.hpp @@ -41,7 +41,7 @@ class Font { inline bool hasShadow() { return shadow_displacement.width != 0 || shadow_displacement.height != 0; } /// Make a bold/italic/placeholder version of this font - FontP make(bool bold, bool italic, bool placeholder_color) const; + FontP make(bool bold, bool italic, bool placeholder_color, Color* other_color) const; private: DECLARE_REFLECTION(); diff --git a/src/data/keyword.cpp b/src/data/keyword.cpp index 2deb5578..7cf6a144 100644 --- a/src/data/keyword.cpp +++ b/src/data/keyword.cpp @@ -34,6 +34,7 @@ IMPLEMENT_REFLECTION(KeywordParam) { IMPLEMENT_REFLECTION(KeywordMode) { REFLECT(name); REFLECT(description); + REFLECT(is_default); } // backwards compatability @@ -376,7 +377,7 @@ String KeywordDatabase::expand(const String& text, String param = untagged.substr(start_u, len_u); // untagged version if (param.empty()) { // placeholder - param = _("‹") + (kwp.placeholder.empty() ? kwp.name : kwp.placeholder) + _("›"); + param = _("") + (kwp.placeholder.empty() ? kwp.name : kwp.placeholder) + _(""); part = part + param; // keep tags } else if (kw->parameters[j/2-1]->script) { // apply parameter script diff --git a/src/data/keyword.hpp b/src/data/keyword.hpp index 2d4ad29c..c56c542d 100644 --- a/src/data/keyword.hpp +++ b/src/data/keyword.hpp @@ -41,6 +41,7 @@ class KeywordParam { class KeywordMode { String name; ///< Name of the mode String description; ///< Description of the type + bool is_default; ///< This is the default mode for new keywords DECLARE_REFLECTION(); }; diff --git a/src/gui/control/card_editor.hpp b/src/gui/control/card_editor.hpp index 4a4c69e8..3d9cdf1b 100644 --- a/src/gui/control/card_editor.hpp +++ b/src/gui/control/card_editor.hpp @@ -13,6 +13,7 @@ #include class ValueEditor; +class FindInfo; // ----------------------------------------------------------------------------- : DataEditor @@ -58,6 +59,16 @@ class DataEditor : public CardViewer { /// A menu item from getMenu was selected void onCommand(int id); + // --------------------------------------------------- : Search/replace + + /// Do a search or replace action for the given FindInfo + /** If from_start == false: searches only from the current selection onward (or backward) + * If from_start == true: searches everything + * + * Returns true when more searching is needed. + */ + bool search(FindInfo& find, bool from_start); + // --------------------------------------------------- : ValueViewers protected: diff --git a/src/gui/control/graph.cpp b/src/gui/control/graph.cpp index 8dc4aedd..01eec494 100644 --- a/src/gui/control/graph.cpp +++ b/src/gui/control/graph.cpp @@ -246,7 +246,7 @@ void GraphControl::setData(const GraphDataP& data) { void GraphControl::onPaint(wxPaintEvent&) { wxBufferedPaintDC dc(this); wxSize cs = GetClientSize(); - RotatedDC rdc(dc, 0, RealRect(RealPoint(0,0),cs), 1, false); + RotatedDC rdc(dc, 0, RealRect(RealPoint(0,0),cs), 1, QUALITY_LOW); rdc.SetPen(*wxTRANSPARENT_PEN); rdc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); rdc.DrawRectangle(rdc.getInternalRect()); diff --git a/src/gui/control/native_look_editor.cpp b/src/gui/control/native_look_editor.cpp index 697d84b1..387c9026 100644 --- a/src/gui/control/native_look_editor.cpp +++ b/src/gui/control/native_look_editor.cpp @@ -26,7 +26,7 @@ Rotation NativeLookEditor::getRotation() const { } void NativeLookEditor::draw(DC& dc) { - RotatedDC rdc(dc, getRotation(), false); + RotatedDC rdc(dc, getRotation(), QUALITY_LOW); DataViewer::draw(rdc, wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); } void NativeLookEditor::drawViewer(RotatedDC& dc, ValueViewer& v) { diff --git a/src/gui/control/text_ctrl.cpp b/src/gui/control/text_ctrl.cpp index 92677599..6aa7c967 100644 --- a/src/gui/control/text_ctrl.cpp +++ b/src/gui/control/text_ctrl.cpp @@ -16,9 +16,10 @@ DECLARE_TYPEOF_COLLECTION(ValueViewerP); // ----------------------------------------------------------------------------- : TextCtrl -TextCtrl::TextCtrl(Window* parent, int id, long style) +TextCtrl::TextCtrl(Window* parent, int id, bool multi_line, long style) : DataEditor(parent, id, style) , value(nullptr) + , multi_line(multi_line) {} Rotation TextCtrl::getRotation() const { @@ -26,44 +27,37 @@ Rotation TextCtrl::getRotation() const { } void TextCtrl::draw(DC& dc) { - RotatedDC rdc(dc, getRotation(), false); + RotatedDC rdc(dc, getRotation(), QUALITY_LOW); DataViewer::draw(rdc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); } -void TextCtrl::setValue(String* value) { - this->value = value; - if (viewers.empty() && value) { - // create a field, style and value - TextFieldP field(new TextField); - TextStyleP style(new TextStyle(field)); - TextValueP value(new FakeTextValue(field, this->value)); - // set stuff - field->index = 0; - field->multi_line = true; - style->width = 100; - style->height = 20; - style->left = style->top = 1; - value->value.assign(*this->value); - // assign to this control - IndexMap styles; styles.add(field, style); - IndexMap values; values.add(field, value); - setStyles(set->stylesheet, styles); - setData(values); - // determine size - wxSize cs = GetClientSize(); - style->width = cs.GetWidth() - 2; - style->height = cs.GetHeight() - 2; - viewers.front()->getEditor()->determineSize(true); - // We don't wan to change the window size - //SetMinSize(RealSize(style->width + 6, style->height + 6)); - } else if (value) { +TextStyle& TextCtrl::getStyle() { + assert(!viewers.empty()); + return static_cast(*viewers.front()->getStyle()); +} +TextField& TextCtrl::getField() { + assert(!viewers.empty()); + return static_cast(*viewers.front()->getField()); +} +void TextCtrl::updateSize() { + wxSize cs = GetClientSize(); + Style& style = getStyle(); + style.width = cs.GetWidth() - 2; + style.height = cs.GetHeight() - 2; + viewers.front()->getEditor()->determineSize(true); +} + +void TextCtrl::setValue(String* value, bool untagged) { + if (value != this->value) { + this->value = value; // create a new value, for a different underlying actual value - ValueViewer& viewer = *viewers.front(); - TextValueP new_value(new FakeTextValue(static_pointer_cast(viewer.getField()), this->value)); + ValueViewer& viewer = *viewers.front(); + TextValueP new_value(new FakeTextValue(static_pointer_cast(viewer.getField()), this->value, untagged)); viewer.setValue(new_value); + updateSize(); + valueChanged(); } - valueChanged(); } void TextCtrl::valueChanged() { if (!viewers.empty()) { @@ -87,7 +81,29 @@ void TextCtrl::onAction(const Action& action, bool undone) { } void TextCtrl::onChangeSet() { DataEditor::onChangeSet(); - setValue(nullptr); + // initialize + if (viewers.empty()) { + // create a field, style and value + TextFieldP field(new TextField); + TextStyleP style(new TextStyle(field)); + TextValueP value(new FakeTextValue(field, nullptr, false)); + // set stuff + field->index = 0; + field->multi_line = multi_line; + style->width = 100; + style->height = 20; + style->left = style->top = 1; + style->font.color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + // assign to this control + IndexMap styles; styles.add(field, style); + IndexMap values; values.add(field, value); + setStyles(set->stylesheet, styles); + setData(values); + updateSize(); + onChange(); + } else { + setValue(nullptr); + } } void TextCtrl::onInit() { @@ -99,16 +115,19 @@ void TextCtrl::onInit() { void TextCtrl::onSize(wxSizeEvent&) { if (!viewers.empty()) { - wxSize cs = GetClientSize(); - Style& style = *viewers.front()->getStyle(); - style.width = cs.GetWidth() - 2; - style.height = cs.GetHeight() - 2; - viewers.front()->getEditor()->determineSize(true); + updateSize(); + onChange(); } - onChange(); } wxSize TextCtrl::DoGetBestSize() const { - return wxSize(1,1); + if (multi_line || viewers.empty()) { + // flexible size + return wxSize(1,1); + } else { + wxSize ws = GetSize(), cs = GetClientSize(); + Style& style = *viewers.front()->getStyle(); + return wxSize(style.width, style.height) + ws - cs; + } } BEGIN_EVENT_TABLE(TextCtrl, DataEditor) diff --git a/src/gui/control/text_ctrl.hpp b/src/gui/control/text_ctrl.hpp index 86102bb8..6c418e0a 100644 --- a/src/gui/control/text_ctrl.hpp +++ b/src/gui/control/text_ctrl.hpp @@ -12,6 +12,9 @@ #include #include +class TextField; +class TextStyle; + // ----------------------------------------------------------------------------- : TextCtrl /// A control for editing a String @@ -25,13 +28,20 @@ */ class TextCtrl : public DataEditor { public: - TextCtrl(Window* parent, int id, long style = 0); + TextCtrl(Window* parent, int id, bool multi_line, long style = 0); /// Set the value that is being edited - void setValue(String* value); + void setValue(String* value, bool untagged = false); /// Notification that the value has changed outside this control void valueChanged(); + /// Get access to the field used by the control + TextField& getField(); + /// Get access to the style used by the control + TextStyle& getStyle(); + /// Update the size, for example after changing the style + void updateSize(); + /// Uses a native look virtual bool nativeLook() const { return true; } virtual bool drawBorders() const { return false; } @@ -48,7 +58,8 @@ class TextCtrl : public DataEditor { virtual wxSize DoGetBestSize() const; private: - String* value; ///< Value to edit + String* value; ///< Value to edit + bool multi_line; ///< Multi line text control? DECLARE_EVENT_TABLE(); diff --git a/src/gui/image_slice_window.cpp b/src/gui/image_slice_window.cpp index 35ad3ba1..51af533e 100644 --- a/src/gui/image_slice_window.cpp +++ b/src/gui/image_slice_window.cpp @@ -367,7 +367,7 @@ void ImageSlicePreview::draw(DC& dc) { wxMemoryDC mdc; mdc.SelectObject(bitmap); // draw checker pattern behind image RealRect rect = GetClientSize(); - RotatedDC rdc(mdc, 0, rect, 1, false); + RotatedDC rdc(mdc, 0, rect, 1, QUALITY_LOW); draw_checker(rdc, rect); rdc.DrawImage(image, RealPoint(0,0)); mdc.SelectObject(wxNullBitmap); diff --git a/src/gui/set/cards_panel.cpp b/src/gui/set/cards_panel.cpp index 689464e9..e4cc0cb0 100644 --- a/src/gui/set/cards_panel.cpp +++ b/src/gui/set/cards_panel.cpp @@ -31,7 +31,7 @@ CardsPanel::CardsPanel(Window* parent, int id) splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); card_list = new ImageCardList(splitter, ID_CARD_LIST); notesP = new Panel(splitter, wxID_ANY); - notes = new TextCtrl(notesP, ID_NOTES); + notes = new TextCtrl(notesP, ID_NOTES, true); collapse_notes = new HoverButton(notesP, ID_COLLAPSE_NOTES, _("btn_collapse"), wxNullColour); collapse_notes->SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES); // init sizer for notes panel diff --git a/src/gui/set/cards_panel.hpp b/src/gui/set/cards_panel.hpp index 317724b0..8e382076 100644 --- a/src/gui/set/cards_panel.hpp +++ b/src/gui/set/cards_panel.hpp @@ -27,7 +27,7 @@ class CardsPanel : public SetWindowPanel { CardsPanel(Window* parent, int id); ~CardsPanel(); - void onChangeSet(); + virtual void onChangeSet(); // --------------------------------------------------- : UI diff --git a/src/gui/set/keywords_panel.cpp b/src/gui/set/keywords_panel.cpp index 4b488fc3..b183543d 100644 --- a/src/gui/set/keywords_panel.cpp +++ b/src/gui/set/keywords_panel.cpp @@ -9,7 +9,11 @@ #include #include #include +#include +#include #include +#include +#include #include #include @@ -19,16 +23,17 @@ KeywordsPanel::KeywordsPanel(Window* parent, int id) : SetWindowPanel(parent, id) { // init controls - Panel* panel; splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); list = new KeywordList(splitter, wxID_ANY); panel = new Panel(splitter, wxID_ANY); - keyword = new TextCtrl(panel, wxID_ANY); - match = new TextCtrl(panel, wxID_ANY); - reminder = new TextCtrl(panel, wxID_ANY); - rules = new TextCtrl(panel, wxID_ANY); + keyword = new TextCtrl(panel, wxID_ANY, false); + match = new TextCtrl(panel, wxID_ANY, false); + reminder = new TextCtrl(panel, wxID_ANY, false); + rules = new TextCtrl(panel, wxID_ANY, true); // init sizer for panel wxSizer* sp = new wxBoxSizer(wxVERTICAL); + sp->Add(new wxStaticText(panel, wxID_ANY, _("This is a standard $game keyword, you can not edit it. ") + _("If you make a copy of the keyword your copy will take precedent.")), 0, wxALL, 6); sp->Add(new wxStaticText(panel, wxID_ANY, _("Keyword:")), 0, wxALL, 6); sp->Add(keyword, 0, wxEXPAND | wxALL & ~wxTOP, 6); wxSizer* s2 = new wxStaticBoxSizer(wxVERTICAL, panel, _("Match")); @@ -38,13 +43,14 @@ KeywordsPanel::KeywordsPanel(Window* parent, int id) sp->Add(s2, 0, wxEXPAND | wxALL, 6); sp->Add(new wxStaticText(panel, wxID_ANY, _("Reminder:")), 0, wxALL, 6); sp->Add(reminder, 0, wxEXPAND | wxALL & ~wxTOP, 6); + sp->Add(new wxStaticText(panel, wxID_ANY, _("Example:")), 0, wxALL, 6); sp->Add(new wxStaticText(panel, wxID_ANY, _("Rules:")), 0, wxALL, 6); - sp->Add(rules, 0, wxEXPAND | wxALL & ~wxTOP, 6); + sp->Add(rules, 1, wxEXPAND | wxALL & ~wxTOP, 6); panel->SetSizer(sp); // init splitter splitter->SetMinimumPaneSize(100); splitter->SetSashGravity(0.5); - splitter->SplitVertically(list, panel, -200); + splitter->SplitVertically(list, panel); // init sizer wxSizer* s = new wxBoxSizer(wxHORIZONTAL); s->Add(splitter, 1, wxEXPAND); @@ -55,8 +61,102 @@ KeywordsPanel::KeywordsPanel(Window* parent, int id) /* wxSizer* s2 = new wxBoxSizer(wxVERTICAL); s2->Add(list_active, 1, wxEXPAND); s2->Add(list_inactive, 1, wxEXPAND);*/ + + // init menus + menuKeyword = new IconMenu(); + menuKeyword->Append(ID_KEYWORD_PREV, _MENU_("previous keyword"), _HELP_("previous keyword")); + menuKeyword->Append(ID_KEYWORD_NEXT, _MENU_("next keyword"), _HELP_("next keyword")); + menuKeyword->AppendSeparator(); + menuKeyword->Append(ID_KEYWORD_ADD, _("keyword_add"), _MENU_("add keyword"), _HELP_("add keyword")); + // NOTE: space after "Del" prevents wx from making del an accellerator + // otherwise we delete a card when delete is pressed inside the editor + menuKeyword->Append(ID_KEYWORD_REMOVE, _("keyword_del"), _MENU_("remove keyword")+_(" "),_HELP_("remove keyword")); } +KeywordsPanel::~KeywordsPanel() { + delete menuKeyword; +} + +// ----------------------------------------------------------------------------- : UI + + +void KeywordsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) { + // Toolbar + tb->AddTool(ID_KEYWORD_ADD, _(""), load_resource_tool_image(_("keyword_add")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("add keyword"), _HELP_("add keyword")); + tb->AddTool(ID_KEYWORD_REMOVE, _(""), load_resource_tool_image(_("keyword_del")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("remove keyword"),_HELP_("remove keyword")); + tb->Realize(); + // Menus + mb->Insert(2, menuKeyword, _MENU_("keywords")); +} + +void KeywordsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) { + // Toolbar + tb->DeleteTool(ID_KEYWORD_ADD); + tb->DeleteTool(ID_KEYWORD_REMOVE); + // Menus + mb->Remove(2); +} + +void KeywordsPanel::onUpdateUI(wxUpdateUIEvent& ev) { + switch (ev.GetId()) { + case ID_KEYWORD_PREV: ev.Enable(list->canSelectPrevious()); break; + case ID_KEYWORD_NEXT: ev.Enable(list->canSelectNext()); break; + case ID_KEYWORD_REMOVE: ev.Enable(list->getKeyword() && !list->getKeyword()->fixed); break; + } +} + +void KeywordsPanel::onCommand(int id) { + switch (id) { + case ID_KEYWORD_PREV: + list->selectPrevious(); + break; + case ID_KEYWORD_NEXT: + list->selectNext(); + break; + case ID_KEYWORD_ADD: +// set->actions.add(new AddKeywordAction(*set)); + break; + case ID_KEYWORD_REMOVE: +// set->actions.add(new RemoveKeywordAction(*set, list->getKeyword())); + break; + } +} + + +// ----------------------------------------------------------------------------- : Events + void KeywordsPanel::onChangeSet() { list->setSet(set); + // init text controls + keyword ->setSet(set); + keyword ->getStyle().font.size = 16; + keyword ->getStyle().font.font.SetPointSize(16); + keyword ->getStyle().padding_bottom = 1; + keyword ->updateSize(); + match ->setSet(set); + match ->getStyle().font.size = 12; + match ->getStyle().font.font.SetPointSize(12); + match ->getStyle().padding_bottom = 1; + match ->updateSize(); + reminder->setSet(set); + reminder->getStyle().padding_bottom = 2; + reminder->updateSize(); + rules ->setSet(set); + // re-layout + panel->Layout(); } + +void KeywordsPanel::onKeywordSelect(KeywordSelectEvent& ev) { + if (ev.keyword) { + panel->Enable(!ev.keyword->fixed); + keyword->setValue(&ev.keyword->keyword, true); + match ->setValue(&ev.keyword->match); + rules ->setValue(&ev.keyword->rules); + } else { + panel->Enable(false); + } +} + +BEGIN_EVENT_TABLE(KeywordsPanel, wxPanel) + EVT_KEYWORD_SELECT(wxID_ANY, KeywordsPanel::onKeywordSelect) +END_EVENT_TABLE() diff --git a/src/gui/set/keywords_panel.hpp b/src/gui/set/keywords_panel.hpp index 79145f9b..4b2f0f9f 100644 --- a/src/gui/set/keywords_panel.hpp +++ b/src/gui/set/keywords_panel.hpp @@ -15,6 +15,8 @@ class wxSplitterWindow; class KeywordList; class TextCtrl; +class IconMenu; +struct KeywordSelectEvent; // ----------------------------------------------------------------------------- : KeywordsPanel @@ -22,17 +24,32 @@ class TextCtrl; class KeywordsPanel : public SetWindowPanel { public: KeywordsPanel(Window* parent, int id); + ~KeywordsPanel(); virtual void onChangeSet(); + // --------------------------------------------------- : UI + + virtual void initUI (wxToolBar* tb, wxMenuBar* mb); + virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb); + virtual void onUpdateUI(wxUpdateUIEvent&); + virtual void onCommand(int id); + private: + DECLARE_EVENT_TABLE(); + // --------------------------------------------------- : Controls wxSplitterWindow* splitter; + wxPanel* panel; KeywordList* list; TextCtrl* keyword; TextCtrl* match; TextCtrl* reminder; TextCtrl* rules; + IconMenu* menuKeyword; + + // --------------------------------------------------- : Events + void onKeywordSelect(KeywordSelectEvent& ev); }; // ----------------------------------------------------------------------------- : EOF diff --git a/src/gui/value/editor.hpp b/src/gui/value/editor.hpp index 22cd3b3f..a5daa7a3 100644 --- a/src/gui/value/editor.hpp +++ b/src/gui/value/editor.hpp @@ -94,6 +94,17 @@ class ValueEditor { virtual size_t selectionStart() const { return 0; } virtual size_t selectionEnd() const { return 0; } + // --------------------------------------------------- : Search / replace + + /// Do a search or replace action for the given FindInfo + /** If from_start == false: searches only from the current selection onward (or backward), + * excluding the sellection itself. + * If from_start == true: searches everything + * + * Returns true when more searching is needed. + */ + bool search(FindInfo& find, bool from_start); + // --------------------------------------------------- : Other /// The cursor type to use when the mouse is over this control diff --git a/src/gui/value/text.cpp b/src/gui/value/text.cpp index 6b7ba833..9dbb0a92 100644 --- a/src/gui/value/text.cpp +++ b/src/gui/value/text.cpp @@ -529,7 +529,7 @@ void TextValueEditor::moveSelection(IndexType t, size_t new_end, bool also_move_ { // Move selection shared_ptr dc = editor().overdrawDC(); - RotatedDC rdc(*dc, viewer.getRotation(), false); + RotatedDC rdc(*dc, viewer.getRotation(), QUALITY_LOW); if (nativeLook()) { // clip the dc to the region of this control rdc.SetClippingRegion(style().getRect()); @@ -659,7 +659,7 @@ void TextValueEditor::determineSize(bool force_fit) { Bitmap bmp(1,1); dc.SelectObject(bmp); dc.SetFont(style().font.font); - style().height = dc.GetCharHeight() + 2; + style().height = dc.GetCharHeight() + 2 + style().padding_top + style().padding_bottom; } } diff --git a/src/gui/value/text.hpp b/src/gui/value/text.hpp index 88246bc1..eed78a71 100644 --- a/src/gui/value/text.hpp +++ b/src/gui/value/text.hpp @@ -15,6 +15,24 @@ #include class TextValueEditorScrollBar; +class wxFindReplaceData; +DECLARE_POINTER_TYPE(Card); + +// ----------------------------------------------------------------------------- : Search/replace + +/// Information for search/replace +class FindInfo { + public: + FindInfo(wxFindReplaceData& what) : what(what) {} + virtual ~FindInfo() {} + + /// Handle that a match was found. + /** Should return whether more searching is needed. + */ + virtual bool handle(const CardP& card, const TextValueP& value, size_t start, size_t end) = 0; + + wxFindReplaceData& what; ///< What to search for, the direction to search in +}; // ----------------------------------------------------------------------------- : TextValueEditor diff --git a/src/render/card/viewer.cpp b/src/render/card/viewer.cpp index 200cbf7f..81da0492 100644 --- a/src/render/card/viewer.cpp +++ b/src/render/card/viewer.cpp @@ -27,7 +27,9 @@ DECLARE_TYPEOF_NO_REV(IndexMap); void DataViewer::draw(DC& dc) { StyleSheetSettings& ss = settings.stylesheetSettingsFor(*stylesheet); - RotatedDC rdc(dc, ss.card_angle(), stylesheet->getCardRect(), ss.card_zoom(), ss.card_anti_alias() && !nativeLook(), true); + RotatedDC rdc(dc, ss.card_angle(), stylesheet->getCardRect(), ss.card_zoom(), + nativeLook() ? QUALITY_LOW : (ss.card_anti_alias() ? QUALITY_AA : QUALITY_SUB_PIXEL), + true); draw(rdc, stylesheet->card_background); } void DataViewer::draw(RotatedDC& dc, const Color& background) { diff --git a/src/render/text/element.cpp b/src/render/text/element.cpp index c9e523f2..22720cb7 100644 --- a/src/render/text/element.cpp +++ b/src/render/text/element.cpp @@ -11,6 +11,7 @@ #include DECLARE_TYPEOF_COLLECTION(TextElementP); +DECLARE_POINTER_TYPE(FontTextElement); // ----------------------------------------------------------------------------- : TextElements @@ -56,14 +57,26 @@ double TextElements::scaleStep() const { return m; } +// Colors for tags +Color param_colors[] = + { Color(0,170,0) + , Color(0,0,200) + , Color(200,0,100) + , Color(200,200,0) + , Color(0,170,170) + , Color(200,0,0) + }; + // Helper class for TextElements::fromString, to allow persistent formating state accross recusive calls struct TextElementsFromString { // What formatting is enabled? int bold, italic, symbol; - int soft, kwpph, line; + int soft, kwpph, param, line; + int param_id; + bool bracket; TextElementsFromString() - : bold(0), italic(0), symbol(0), soft(0), kwpph(0), line(0) {} + : bold(0), italic(0), symbol(0), soft(0), kwpph(0), param(0), line(0), param_id(0), bracket(false) {} // read TextElements from a string void fromString(TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) { @@ -84,6 +97,8 @@ struct TextElementsFromString { else if (is_substr(text, tag_start, _("(te.elements.back().get()); - if (e && e->end == pos) { - e->end = pos + 1; // just move the end, no need to make a new element + if (e && e->end == (bracket ? pos + 1 : pos)) { + e->end = bracket ? pos + 2 : pos + 1; // just move the end, no need to make a new element + e->content += c; + if (bracket) { + // content is "g" should be "" + swap(e->content[e->content.size() - 2], e->content[e->content.size() - 1]); + } } else { // add a new element for this text if (symbol > 0 && style.symbol_font.valid()) { - te.elements.push_back(new_shared5(text, pos, pos + 1, style.symbol_font, &ctx)); + e = new SymbolTextElement(text, pos, pos + 1, style.symbol_font, &ctx); + bracket = false; } else { - te.elements.push_back(new_shared6 (text, pos, pos + 1, - style.font.make(bold > 0, italic > 0, soft > 0 || kwpph > 0), - soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL, - line > 0 ? BREAK_LINE : BREAK_HARD)); + FontP font = style.font.make(bold > 0, italic > 0, soft > 0 || kwpph > 0, + param > 0 ? ¶m_colors[(param_id++) % (sizeof(param_colors)/sizeof(param_colors[0]))] : nullptr); + bracket = kwpph > 0 || param > 0; + e = new FontTextElement( + text, + bracket ? pos - 1 : pos, + bracket ? pos + 2 : pos + 1, + font, + soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL, + line > 0 ? BREAK_LINE : BREAK_HARD); } + if (bracket) { + e->content = String(_("‹")) + c + _("›"); + } else { + e->content = c; + } + te.elements.push_back(TextElementP(e)); } pos += 1; } diff --git a/src/render/text/element.hpp b/src/render/text/element.hpp index 7ab47689..578b00c1 100644 --- a/src/render/text/element.hpp +++ b/src/render/text/element.hpp @@ -100,7 +100,10 @@ class TextElements : public vector { /// A text element that just shows text class SimpleTextElement : public TextElement { public: - SimpleTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {} + SimpleTextElement(const String& text, size_t start, size_t end) + : TextElement(text, start, end), content(text.substr(start,end-start)) + {} + String content; ///< Text to show }; /// A text element that uses a normal font diff --git a/src/render/text/font.cpp b/src/render/text/font.cpp index a2ecb5c2..34603cd7 100644 --- a/src/render/text/font.cpp +++ b/src/render/text/font.cpp @@ -14,15 +14,18 @@ void FontTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const { if ((what & draw_as) != draw_as) return; // don't draw dc.SetFont(font->font, font->size * scale); - if (end != start && text.substr(end-1, 1) == _("\n")) end -= 1; // don't draw the newline character at the end // draw shadow + String text = content.substr(start - this->start, end - start); + if (!text.empty() && text.GetChar(text.size() - 1) == _('\n')) { + text = text.substr(0, text.size() - 1); // don't draw last \n + } if (font->hasShadow()) { dc.SetTextForeground(font->shadow_color); - dc.DrawText(text.substr(start, end - start), rect.position() + font->shadow_displacement); + dc.DrawText(text, rect.position() + font->shadow_displacement); } // draw dc.SetTextForeground(font->color); - dc.DrawText(text.substr(start, end - start), rect.position()); + dc.DrawText(text, rect.position()); } void FontTextElement::getCharInfo(RotatedDC& dc, double scale, vector& out) const { @@ -31,8 +34,8 @@ void FontTextElement::getCharInfo(RotatedDC& dc, double scale, vector& // find sizes & breaks double prev_width = 0; for (size_t i = start ; i < end ; ++i) { - Char c = text.GetChar(i); - RealSize s = dc.GetTextExtent(text.substr(start, i - start + 1)); + Char c = content.GetChar(i - this->start); + RealSize s = dc.GetTextExtent(content.substr(start - this->start, i - start + 1)); out.push_back(CharInfo(RealSize(s.width - prev_width, s.height), c == _('\n') ? break_style : c == _(' ') ? BREAK_SOFT : BREAK_NO diff --git a/src/render/text/symbol.cpp b/src/render/text/symbol.cpp index 6182986c..bdee8795 100644 --- a/src/render/text/symbol.cpp +++ b/src/render/text/symbol.cpp @@ -13,13 +13,13 @@ void SymbolTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const { if (font.font) { - font.font->draw(dc, ctx, rect, font.size * scale, font.alignment, text.substr(start, end-start)); + font.font->draw(dc, ctx, rect, font.size * scale, font.alignment, content.substr(start - this->start, end-start)); } } void SymbolTextElement::getCharInfo(RotatedDC& dc, double scale, vector& out) const { if (font.font) { - font.font->getCharInfo(dc, ctx, font.size * scale, text.substr(start, end-start), out); + font.font->getCharInfo(dc, ctx, font.size * scale, content.substr(start - this->start, end-start), out); } } diff --git a/src/render/text/viewer.cpp b/src/render/text/viewer.cpp index f8140409..86926cf9 100644 --- a/src/render/text/viewer.cpp +++ b/src/render/text/viewer.cpp @@ -325,6 +325,36 @@ void TextViewer::prepareLines(RotatedDC& dc, const String& text, const TextStyle scale = next_scale; } + /* + double scale_1 = 1. + double fit_1 = fitLines(dc, text, style, scale_1); + if (fit_1 <= 0 || scale_1 >= scale_2) { + // ok + } else { + // find best text size, using the 'false position' root finding method + double scale_2 = elements.minScale(); + double fit_2 = fitLines(dc, text, style, scale_2); + if (fit_2 > 0) { + // still doesn't fit at smallest size + } else { + // invariant: fit_1 > 0 && fit_2 <= 0 + while (abs(scale_2 - scale_1) > 0.01) { + double scale_3 = scale_2 - fit_2 * (scale_2 - scale_1)/(fit_2 - fit_1); + double fit_3 = fitLines(dc, text, style, scale_3); + if (fit_3 > 0) { + scale_2 = scale_3; + fit_2 = fit_3; + } else { + scale_2 = scale_3; + fit_2 = fit_3; + } + } + } + } + + // returns negative values if it fits, positive if it doesn't + */ + // no text, find a dummy height for the single line we have if (lines.size() == 1 && lines[0].width() < 0.0001) { if (style.always_symbol && style.symbol_font.valid()) { diff --git a/src/render/value/image.cpp b/src/render/value/image.cpp index 2fa69235..a978c2db 100644 --- a/src/render/value/image.cpp +++ b/src/render/value/image.cpp @@ -88,7 +88,7 @@ Bitmap ImageValueViewer::imagePlaceholder(const Rotation& rot, UInt w, UInt h, b wxMemoryDC mdc; mdc.SelectObject(bmp); RealRect rect(0,0,w,h); - RotatedDC dc(mdc, 0, rect, 1.0, true); + RotatedDC dc(mdc, 0, rect, 1.0, QUALITY_AA); // Draw checker background draw_checker(dc, rect); // Draw text diff --git a/src/render/value/multiple_choice.cpp b/src/render/value/multiple_choice.cpp index 7abb4833..9e5e4203 100644 --- a/src/render/value/multiple_choice.cpp +++ b/src/render/value/multiple_choice.cpp @@ -18,7 +18,7 @@ DECLARE_TYPEOF_COLLECTION(String); void MultipleChoiceValueViewer::draw(RotatedDC& dc) { drawFieldBorder(dc); if (style().render_style & RENDER_HIDDEN) return; - RealPoint pos = style().getPos(); + RealPoint pos = align_in_rect(style().alignment, RealSize(0,0), style().getRect()); // selected choices vector selected; value().get(selected); @@ -66,9 +66,6 @@ void MultipleChoiceValueViewer::drawChoice(RotatedDC& dc, RealPoint& pos, const RealRect(pos + RealSize(size.width + 1, 0), RealSize(0,size.height)))); size = add_horizontal(size, text_size); } - if (style().direction == HORIZONTAL) { - pos.x += size.width + style().spacing; - } else { - pos.y += size.height + style().spacing; - } + // next position + pos = move_in_direction(style().direction, pos, size, style().spacing); } diff --git a/src/util/alignment.cpp b/src/util/alignment.cpp index 38550bba..3d5fc208 100644 --- a/src/util/alignment.cpp +++ b/src/util/alignment.cpp @@ -79,3 +79,24 @@ template <> void Writer::handle(const Alignment& align) { template <> void GetDefaultMember::handle(const Alignment& align) { handle(to_string(align)); } + +// ----------------------------------------------------------------------------- : Direction + +IMPLEMENT_REFLECTION_ENUM(Direction) { + VALUE_N("left to right", LEFT_TO_RIGHT); + VALUE_N("right to left", RIGHT_TO_LEFT); + VALUE_N("top to bottom", TOP_TO_BOTTOM); + VALUE_N("bottom to top", BOTTOM_TO_TOP); + VALUE_N("horizontal", LEFT_TO_RIGHT); + VALUE_N("vertical", TOP_TO_BOTTOM); +} + +RealPoint move_in_direction(Direction dir, const RealPoint& point, const RealSize to_move, double spacing) { + switch (dir) { + case LEFT_TO_RIGHT: return RealPoint(point.x + to_move.width + spacing, point.y); + case RIGHT_TO_LEFT: return RealPoint(point.x - to_move.width - spacing, point.y); + case TOP_TO_BOTTOM: return RealPoint(point.x, point.y + to_move.height + spacing); + case BOTTOM_TO_TOP: return RealPoint(point.x, point.y - to_move.height - spacing); + default: return point; // should not happen + } +} diff --git a/src/util/alignment.hpp b/src/util/alignment.hpp index 856bbbb1..f897ea76 100644 --- a/src/util/alignment.hpp +++ b/src/util/alignment.hpp @@ -52,5 +52,17 @@ double align_delta_y(Alignment align, double box_height, double obj_height); */ RealPoint align_in_rect(Alignment align, const RealSize& to_align, const RealRect& outer); +// ----------------------------------------------------------------------------- : Direction + +/// Direction to place something in +enum Direction { + LEFT_TO_RIGHT, RIGHT_TO_LEFT, + TOP_TO_BOTTOM, BOTTOM_TO_TOP +}; + +/// Move a point in a direction +/** If the direction is horizontal the to_move.width is used, otherwise to_move.height */ +RealPoint move_in_direction(Direction dir, const RealPoint& point, const RealSize to_move, double spacing = 0); + // ----------------------------------------------------------------------------- : EOF #endif diff --git a/src/util/io/package.cpp b/src/util/io/package.cpp index 57e26150..45e2d631 100644 --- a/src/util/io/package.cpp +++ b/src/util/io/package.cpp @@ -41,7 +41,7 @@ bool Package::isOpened() const { return !filename.empty(); } bool Package::needSaveAs() const { - return !filename.empty(); + return filename.empty(); } String Package::name() const { // wxFileName is too slow (profiled) diff --git a/src/util/rotation.cpp b/src/util/rotation.cpp index f2e972a4..417c9c2a 100644 --- a/src/util/rotation.cpp +++ b/src/util/rotation.cpp @@ -111,24 +111,31 @@ Rotater::~Rotater() { // ----------------------------------------------------------------------------- : RotatedDC -RotatedDC::RotatedDC(DC& dc, int angle, const RealRect& rect, double zoom, bool high_quality, bool is_internal) +RotatedDC::RotatedDC(DC& dc, int angle, const RealRect& rect, double zoom, RenderQuality quality, bool is_internal) : Rotation(angle, rect, zoom, is_internal) - , dc(dc), high_quality(high_quality) + , dc(dc), quality(quality) {} -RotatedDC::RotatedDC(DC& dc, const Rotation& rotation, bool high_quality) +RotatedDC::RotatedDC(DC& dc, const Rotation& rotation, RenderQuality quality) : Rotation(rotation) - , dc(dc), high_quality(high_quality&&false) + , dc(dc), quality(quality) {} // ----------------------------------------------------------------------------- : RotatedDC : Drawing void RotatedDC::DrawText (const String& text, const RealPoint& pos) { if (text.empty()) return; - if (high_quality) { + if (quality == QUALITY_AA) { RealRect r(pos, GetTextExtent(text)); RealRect r_ext = trNoNeg(r); draw_resampled_text(dc, r_ext, revX(), revY(), angle, text); + } else if (quality == QUALITY_SUB_PIXEL) { + RealPoint p_ext = tr(pos)*text_scaling; + double usx,usy; + dc.GetUserScale(&usx, &usy); + dc.SetUserScale(usx/text_scaling, usy/text_scaling); + dc.DrawRotatedText(text, (int) p_ext.x, (int) p_ext.y, angle); + dc.SetUserScale(usx, usy); } else { RealPoint p_ext = tr(pos); dc.DrawRotatedText(text, (int) p_ext.x, (int) p_ext.y, angle); @@ -172,24 +179,44 @@ void RotatedDC::SetTextForeground(const Color& color) { dc.SetTextForeground(col void RotatedDC::SetLogicalFunction(int function) { dc.SetLogicalFunction(function); } void RotatedDC::SetFont(const wxFont& font) { - SetFont(font, font.GetPointSize()); + if (quality == QUALITY_LOW) { + dc.SetFont(font); + } else { + SetFont(font, font.GetPointSize()); + } } void RotatedDC::SetFont(wxFont font, double size) { - font.SetPointSize((int) (trS(size) * (high_quality ? text_scaling : 1))); + if (quality == QUALITY_LOW) { + font.SetPointSize((int) trS(size)); + } else { + font.SetPointSize((int) (trS(size) * text_scaling)); + } dc.SetFont(font); } double RotatedDC::getFontSizeStep() const { - return 1. / (high_quality ? text_scaling : 1); + if (quality == QUALITY_LOW) { + return 1; + } else { + return 1. / text_scaling; + } } RealSize RotatedDC::GetTextExtent(const String& text) const { int w, h; dc.GetTextExtent(text, &w, &h); - return RealSize(w,h) / zoom / (high_quality ? text_scaling : 1); + if (quality == QUALITY_LOW) { + return RealSize(w,h) / zoom; + } else { + return RealSize(w,h) / zoom / text_scaling; + } } double RotatedDC::GetCharHeight() const { - return dc.GetCharHeight() / zoom / (high_quality ? text_scaling : 1); + if (quality == QUALITY_LOW) { + return dc.GetCharHeight() / zoom; + } else { + return dc.GetCharHeight() / zoom / text_scaling; + } } void RotatedDC::SetClippingRegion(const RealRect& rect) { diff --git a/src/util/rotation.hpp b/src/util/rotation.hpp index b89d3843..c8187760 100644 --- a/src/util/rotation.hpp +++ b/src/util/rotation.hpp @@ -119,13 +119,20 @@ class Rotater { // ----------------------------------------------------------------------------- : RotatedDC +/// Render quality of text +enum RenderQuality { + QUALITY_AA, ///< Our own anti aliassing + QUALITY_SUB_PIXEL, ///< Sub-pixel positioning + QUALITY_LOW, ///< Normal +}; + /// A DC with rotation applied /** All draw** functions take internal coordinates. */ class RotatedDC : public Rotation { public: - RotatedDC(DC& dc, int angle, const RealRect& rect, double zoom, bool high_quality, bool is_internal = false); - RotatedDC(DC& dc, const Rotation& rotation, bool high_quality); + RotatedDC(DC& dc, int angle, const RealRect& rect, double zoom, RenderQuality quality, bool is_internal = false); + RotatedDC(DC& dc, const Rotation& rotation, RenderQuality quality); // --------------------------------------------------- : Drawing @@ -165,8 +172,8 @@ class RotatedDC : public Rotation { inline wxDC& getDC() { return dc; } private: - wxDC& dc; ///< The actual dc - bool high_quality; ///< Drawing using our own anti aliassing? + wxDC& dc; ///< The actual dc + RenderQuality quality; ///< Quality of the text }; // ----------------------------------------------------------------------------- : EOF