Commit cfd59072 authored by twanvl's avatar twanvl

improved cursor handling in text editor

parent 54659c21
...@@ -195,15 +195,20 @@ button: ...@@ -195,15 +195,20 @@ button:
# Card select # Card select
select all: Select &All select all: Select &All
select none: Select &None select none: Select &None
# Update checker
close: &Close
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
magic set editor: Magic Set Editor magic set editor: Magic Set Editor
about: About Magic Set Editor about: About Magic Set Editor
symbol editor: Symbol Editor
# dialogs # dialogs
open set: Open Set open set: Open Set
save set: Save Set As save set: Save Set As
save image: Save Image save image: Save Image
updates availible: Updates Availible
#preferences #preferences
preferences: Preferences preferences: Preferences
display: Display display: Display
......
...@@ -94,11 +94,11 @@ SetWindow::SetWindow(Window* parent, const SetP& set) ...@@ -94,11 +94,11 @@ SetWindow::SetWindow(Window* parent, const SetP& set)
menuBar->Append(menuHelp, _MENU_("help")); menuBar->Append(menuHelp, _MENU_("help"));
SetMenuBar(menuBar); SetMenuBar(menuBar);
// status bar // status bar
CreateStatusBar(); CreateStatusBar();
SetStatusText(_("Welcome to Magic Set Editor")); SetStatusText(_("Welcome to Magic Set Editor"));
// tool bar // tool bar
wxToolBar* tb = CreateToolBar(wxTB_FLAT | wxNO_BORDER | wxTB_HORIZONTAL); wxToolBar* tb = CreateToolBar(wxTB_FLAT | wxNO_BORDER | wxTB_HORIZONTAL);
tb->SetToolBitmapSize(wxSize(18,18)); tb->SetToolBitmapSize(wxSize(18,18));
......
...@@ -48,7 +48,7 @@ SymbolWindow::SymbolWindow(Window* parent, const SymbolValueP& value, const SetP ...@@ -48,7 +48,7 @@ SymbolWindow::SymbolWindow(Window* parent, const SymbolValueP& value, const SetP
} }
void SymbolWindow::init(Window* parent, SymbolP symbol) { void SymbolWindow::init(Window* parent, SymbolP symbol) {
Create(parent, wxID_ANY, _("Symbol Editor"), wxDefaultPosition, wxSize(600,600), wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE); Create(parent, wxID_ANY, _TITLE_("symbol editor"), wxDefaultPosition, wxSize(600,600), wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
inSelectionEvent = false; inSelectionEvent = false;
// Menu bar // Menu bar
......
...@@ -120,11 +120,11 @@ struct HtmlWindowToBrowser : public wxHtmlWindow { ...@@ -120,11 +120,11 @@ struct HtmlWindowToBrowser : public wxHtmlWindow {
void show_update_dialog(Window* parent) { void show_update_dialog(Window* parent) {
if (!update_available()) return; // we already have the latest version if (!update_available()) return; // we already have the latest version
// Show update dialog // Show update dialog
wxDialog* dlg = new wxDialog(parent, wxID_ANY, _("Updates availible"), wxDefaultPosition); wxDialog* dlg = new wxDialog(parent, wxID_ANY, _TITLE_("updates availible"), wxDefaultPosition);
// controls // controls
wxHtmlWindow* html = new HtmlWindowToBrowser(dlg, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO | wxSUNKEN_BORDER); wxHtmlWindow* html = new HtmlWindowToBrowser(dlg, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO | wxSUNKEN_BORDER);
html->SetPage(update_version_data->description); html->SetPage(update_version_data->description);
wxButton* close = new wxButton(dlg, wxID_OK, _("&Close")); wxButton* close = new wxButton(dlg, wxID_OK, _BUTTON_("close"));
close->SetDefault(); close->SetDefault();
// layout // layout
wxSizer* s = new wxBoxSizer(wxVERTICAL); wxSizer* s = new wxBoxSizer(wxVERTICAL);
......
This diff is collapsed.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/tagged_string.hpp> // for Movement
#include <gui/value/editor.hpp> #include <gui/value/editor.hpp>
#include <render/value/text.hpp> #include <render/value/text.hpp>
...@@ -17,11 +18,9 @@ class TextValueEditorScrollBar; ...@@ -17,11 +18,9 @@ class TextValueEditorScrollBar;
// ----------------------------------------------------------------------------- : TextValueEditor // ----------------------------------------------------------------------------- : TextValueEditor
/// Directions of cursor movement enum IndexType
enum Movement { TYPE_CURSOR ///< Positions are cursor positions
{ MOVE_LEFT ///< Always move the cursor to the left , TYPE_INDEX ///< Positions are character indices
, MOVE_MID ///< Move in whichever direction the distance to move is shorter (TODO: define shorter)
, MOVE_RIGHT ///< Always move the cursor to the right
}; };
/// An editor 'control' for editing TextValues /// An editor 'control' for editing TextValues
...@@ -83,16 +82,19 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -83,16 +82,19 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
// --------------------------------------------------- : Data // --------------------------------------------------- : Data
private: private:
size_t selection_start, selection_end; ///< Cursor position/selection (if any) size_t selection_start, selection_end; ///< Cursor position/selection (if any), cursor positions
size_t selection_start_i, selection_end_i; ///< Cursor position/selection, character indices
TextValueEditorScrollBar* scrollbar; ///< Scrollbar for multiline fields in native look TextValueEditorScrollBar* scrollbar; ///< Scrollbar for multiline fields in native look
bool select_words; ///< Select whole words when dragging the mouse? bool select_words; ///< Select whole words when dragging the mouse?
// --------------------------------------------------- : Selection / movement // --------------------------------------------------- : Selection / movement
/// Move the selection to a new location, clears the previously drawn selection /// Move the selection to a new location, clears the previously drawn selection.
void moveSelection(size_t new_end, bool also_move_start=true, Movement dir = MOVE_MID); /** t specifies what kind of position new_end is */
/// Move the selection to a new location, but does not redraw void moveSelection(IndexType t, size_t new_end, bool also_move_start=true, Movement dir = MOVE_MID);
void moveSelectionNoRedraw(size_t new_end, bool also_move_start=true, Movement dir = MOVE_MID); /// Move the selection to a new location, but does not redraw.
/** t specifies what kind of position new_end is */
void moveSelectionNoRedraw(IndexType t, size_t new_end, bool also_move_start=true, Movement dir = MOVE_MID);
/// Replace the current selection with 'replacement', name the action /// Replace the current selection with 'replacement', name the action
void replaceSelection(const String& replacement, const String& name); void replaceSelection(const String& replacement, const String& name);
...@@ -104,7 +106,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -104,7 +106,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
* *
* When correcting the selection, move in the given direction * When correcting the selection, move in the given direction
*/ */
void fixSelection(Movement dir = MOVE_MID); void fixSelection(IndexType t = TYPE_CURSOR, Movement dir = MOVE_MID);
/// Return a position resulting from moving pos outside the range [start...end), in the direction dir /// Return a position resulting from moving pos outside the range [start...end), in the direction dir
static size_t move(size_t pos, size_t start, size_t end, Movement dir); static size_t move(size_t pos, size_t start, size_t end, Movement dir);
...@@ -113,11 +115,13 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -113,11 +115,13 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
void showCaret(); void showCaret();
/// Position of previous visible & selectable character /// Position of previous visible & selectable character
/** Uses cursor positions */
size_t prevCharBoundry(size_t pos) const; size_t prevCharBoundry(size_t pos) const;
size_t nextCharBoundry(size_t pos) const; size_t nextCharBoundry(size_t pos) const;
/// Front of previous word, used witch Ctrl+Left/right /// Front of previous word, used witch Ctrl+Left/right
size_t prevWordBoundry(size_t pos) const; /** Uses character indices */
size_t nextWordBoundry(size_t pos) const; size_t prevWordBoundry(size_t pos_i) const;
size_t nextWordBoundry(size_t pos_i) const;
// --------------------------------------------------- : Scrolling // --------------------------------------------------- : Scrolling
......
...@@ -64,7 +64,7 @@ void WelcomeWindow::draw(DC& dc) { ...@@ -64,7 +64,7 @@ void WelcomeWindow::draw(DC& dc) {
} }
void WelcomeWindow::onOpenSet(wxCommandEvent&) { void WelcomeWindow::onOpenSet(wxCommandEvent&) {
wxFileDialog dlg(this, _("Open a set"), wxEmptyString, wxEmptyString, import_formats(), wxOPEN); wxFileDialog dlg(this, _TITLE_("open set"), wxEmptyString, wxEmptyString, import_formats(), wxOPEN);
if (dlg.ShowModal() == wxID_OK) { if (dlg.ShowModal() == wxID_OK) {
close(import_set(dlg.GetPath())); close(import_set(dlg.GetPath()));
} }
......
...@@ -130,7 +130,7 @@ class FontTextElement : public SimpleTextElement { ...@@ -130,7 +130,7 @@ class FontTextElement : public SimpleTextElement {
: SimpleTextElement(text, start, end) : SimpleTextElement(text, start, end)
, font(font) , font(font)
{} {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const; virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const; virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const; virtual double minScale() const;
...@@ -146,7 +146,7 @@ class SymbolTextElement : public SimpleTextElement { ...@@ -146,7 +146,7 @@ class SymbolTextElement : public SimpleTextElement {
: SimpleTextElement(text, start, end) : SimpleTextElement(text, start, end)
, font(font), ctx(*ctx) , font(font), ctx(*ctx)
{} {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const; virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const; virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const; virtual double minScale() const;
...@@ -162,9 +162,22 @@ class CompoundTextElement : public TextElement { ...@@ -162,9 +162,22 @@ class CompoundTextElement : public TextElement {
public: public:
CompoundTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {} CompoundTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const;
TextElements elements; ///< the elements TextElements elements; ///< the elements
}; };
/// A TextElement drawn using a grey background
class AtomTextElement : public CompoundTextElement {
public:
AtomTextElement(const String& text, size_t start ,size_t end) : CompoundTextElement(text, start, end) {}
virtual void draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
};
// ----------------------------------------------------------------------------- : Other text elements // ----------------------------------------------------------------------------- : Other text elements
/// A text element that displays a horizontal separator line /// A text element that displays a horizontal separator line
......
...@@ -81,7 +81,7 @@ class TextViewer { ...@@ -81,7 +81,7 @@ class TextViewer {
/// Is the character at the given index visible? /// Is the character at the given index visible?
bool isVisible(size_t index) const; bool isVisible(size_t index) const;
/// Find the first character index that is at/before/after the given index, and which has a nonzero width /// Find the first character index that is at/before/after the given index, and which has a nonzero width
/** More precisely: it returns a position so that no character after it has zero width /** More precisely: it returns a position so that the character after it in the direction delta has nonzero width
*/ */
size_t firstVisibleChar(size_t index, int delta) const; size_t firstVisibleChar(size_t index, int delta) const;
......
...@@ -159,6 +159,80 @@ String anti_tag(const String& tag) { ...@@ -159,6 +159,80 @@ String anti_tag(const String& tag) {
else return _("</") + tag + _(">"); else return _("</") + tag + _(">");
} }
// ----------------------------------------------------------------------------- : Cursor position
size_t index_to_cursor(const String& str, size_t index, Movement dir) {
size_t cursor = 0;
size_t start = 0, end = 0;
index = min(index, str.size());
// find the range [start...end) with the same cursor value, that contains index
// after the loop, cursor corresponds to index end
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
if (c == _('<')) {
// a tag
if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) {
// skip tag contents, tag counts as a single 'character'
i = skip_tag(str, match_close_tag(str, i));
cursor++;
start = end;
end = i;
if (end > index) break;
} else {
i = skip_tag(str, i);
end = i;
}
} else {
cursor++;
i++;
start = end;
end = i;
if (end > index) break;
}
}
if (cursor == 0) return 0;
if (i == str.size()) return cursor;
if (dir == MOVE_LEFT) return cursor - 1;
if (dir == MOVE_RIGHT) return cursor - (start == index);
// which is nearer? start or end?
return cursor - ((int)(index - start) <= (int)(end - index));
}
void cursor_to_index_range(const String& str, size_t cursor, size_t& start, size_t& end) {
start = end = 0;
size_t cur = 0;
size_t i = 0;
while (cur <= cursor && i < str.size()) {
Char c = str.GetChar(i);
if (c == _('<')) {
// a tag
if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) {
// skip tag contents, tag counts as a single 'character'
i = skip_tag(str, match_close_tag(str, i));
cur++;
if (cur == cursor) start = i;
} else {
i = skip_tag(str, i);
}
} else {
cur++;
i++;
if (cur == cursor) start = i;
}
}
end = min(i, str.size());
if (cur < cursor) start = end = str.size();
}
size_t cursor_to_index(const String& str, size_t cursor) {
size_t start, end;
cursor_to_index_range(str, cursor, start, end);
// TODO: If at i there is <tag></tag> return a position inside the tags
// This allows formating to be enabled without a selection
return start;
}
// ----------------------------------------------------------------------------- : Global operations // ----------------------------------------------------------------------------- : Global operations
String remove_tag(const String& str, const String& tag) { String remove_tag(const String& str, const String& tag) {
......
...@@ -80,6 +80,29 @@ String close_tag(const String& tag); ...@@ -80,6 +80,29 @@ String close_tag(const String& tag);
/// The matching close tag for an open tag and vice versa /// The matching close tag for an open tag and vice versa
String anti_tag(const String& tag); String anti_tag(const String& tag);
// ----------------------------------------------------------------------------- : Cursor position
/// Directions of cursor movement
enum Movement
{ MOVE_LEFT = -1 ///< Always move the cursor to the left
, MOVE_MID = 0 ///< Move in whichever direction the distance to move is shorter (TODO: define shorter)
, MOVE_RIGHT = 1 ///< Always move the cursor to the right
};
/// Find the cursor position corresponding to the given character index.
/** A cursor position always corresponds to a valid place to type text.
* The cursor position is rounded to the direction dir.
*/
size_t index_to_cursor(const String& str, size_t index, Movement dir = MOVE_MID);
/// Find the range of character indeces corresponding to the given cursor position
/** The output parameters will correspond to the range [start...end) which are all valid character indices.
*/
void cursor_to_index_range(const String& str, size_t cursor, size_t& begin, size_t& end);
/// Find the character index corresponding to the given cursor position
size_t cursor_to_index(const String& str, size_t cursor);
// ----------------------------------------------------------------------------- : Global operations // ----------------------------------------------------------------------------- : Global operations
/// Remove all instances of a tag and its close tag, but keep the contents. /// Remove all instances of a tag and its close tag, but keep the contents.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment