Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
magicseteditor
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
magicseteditor
Commits
cfd59072
Commit
cfd59072
authored
Dec 19, 2006
by
twanvl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
improved cursor handling in text editor
parent
54659c21
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
247 additions
and
96 deletions
+247
-96
data/en.mse-locale/locale
data/en.mse-locale/locale
+5
-0
src/gui/set/window.cpp
src/gui/set/window.cpp
+2
-2
src/gui/symbol/window.cpp
src/gui/symbol/window.cpp
+1
-1
src/gui/update_checker.cpp
src/gui/update_checker.cpp
+2
-2
src/gui/value/text.cpp
src/gui/value/text.cpp
+106
-74
src/gui/value/text.hpp
src/gui/value/text.hpp
+17
-13
src/gui/welcome_window.cpp
src/gui/welcome_window.cpp
+1
-1
src/render/text/element.hpp
src/render/text/element.hpp
+15
-2
src/render/text/viewer.hpp
src/render/text/viewer.hpp
+1
-1
src/util/tagged_string.cpp
src/util/tagged_string.cpp
+74
-0
src/util/tagged_string.hpp
src/util/tagged_string.hpp
+23
-0
No files found.
data/en.mse-locale/locale
View file @
cfd59072
...
...
@@ -195,15 +195,20 @@ button:
#
Card
select
select
all
:
Select
&
All
select
none
:
Select
&
None
#
Update
checker
close
:
&
Close
##############################################################
Titles
in
the
GUI
title
:
magic
set
editor
:
Magic
Set
Editor
about
:
About
Magic
Set
Editor
symbol
editor
:
Symbol
Editor
#
dialogs
open
set
:
Open
Set
save
set
:
Save
Set
As
save
image
:
Save
Image
updates
availible
:
Updates
Availible
#
preferences
preferences
:
Preferences
display
:
Display
...
...
src/gui/set/window.cpp
View file @
cfd59072
...
...
@@ -94,11 +94,11 @@ SetWindow::SetWindow(Window* parent, const SetP& set)
menuBar
->
Append
(
menuHelp
,
_MENU_
(
"help"
));
SetMenuBar
(
menuBar
);
// status bar
CreateStatusBar
();
SetStatusText
(
_
(
"Welcome to Magic Set Editor"
));
// tool bar
wxToolBar
*
tb
=
CreateToolBar
(
wxTB_FLAT
|
wxNO_BORDER
|
wxTB_HORIZONTAL
);
tb
->
SetToolBitmapSize
(
wxSize
(
18
,
18
));
...
...
src/gui/symbol/window.cpp
View file @
cfd59072
...
...
@@ -48,7 +48,7 @@ SymbolWindow::SymbolWindow(Window* parent, const SymbolValueP& value, const SetP
}
void
SymbolWindow
::
init
(
Window
*
parent
,
SymbolP
symbol
)
{
Create
(
parent
,
wxID_ANY
,
_
(
"Symbol E
ditor"
),
wxDefaultPosition
,
wxSize
(
600
,
600
),
wxDEFAULT_FRAME_STYLE
|
wxNO_FULL_REPAINT_ON_RESIZE
);
Create
(
parent
,
wxID_ANY
,
_
TITLE_
(
"symbol e
ditor"
),
wxDefaultPosition
,
wxSize
(
600
,
600
),
wxDEFAULT_FRAME_STYLE
|
wxNO_FULL_REPAINT_ON_RESIZE
);
inSelectionEvent
=
false
;
// Menu bar
...
...
src/gui/update_checker.cpp
View file @
cfd59072
...
...
@@ -120,11 +120,11 @@ struct HtmlWindowToBrowser : public wxHtmlWindow {
void
show_update_dialog
(
Window
*
parent
)
{
if
(
!
update_available
())
return
;
// we already have the latest version
// Show update dialog
wxDialog
*
dlg
=
new
wxDialog
(
parent
,
wxID_ANY
,
_
(
"U
pdates availible"
),
wxDefaultPosition
);
wxDialog
*
dlg
=
new
wxDialog
(
parent
,
wxID_ANY
,
_
TITLE_
(
"u
pdates availible"
),
wxDefaultPosition
);
// controls
wxHtmlWindow
*
html
=
new
HtmlWindowToBrowser
(
dlg
,
wxID_ANY
,
wxDefaultPosition
,
wxDefaultSize
,
wxHW_SCROLLBAR_AUTO
|
wxSUNKEN_BORDER
);
html
->
SetPage
(
update_version_data
->
description
);
wxButton
*
close
=
new
wxButton
(
dlg
,
wxID_OK
,
_
(
"&C
lose"
));
wxButton
*
close
=
new
wxButton
(
dlg
,
wxID_OK
,
_
BUTTON_
(
"c
lose"
));
close
->
SetDefault
();
// layout
wxSizer
*
s
=
new
wxBoxSizer
(
wxVERTICAL
);
...
...
src/gui/value/text.cpp
View file @
cfd59072
...
...
@@ -54,7 +54,8 @@ END_EVENT_TABLE ()
// ----------------------------------------------------------------------------- : TextValueEditor
IMPLEMENT_VALUE_EDITOR
(
Text
)
,
selection_start
(
0
),
selection_end
(
0
)
,
selection_start
(
0
),
selection_end
(
0
)
,
selection_start_i
(
0
),
selection_end_i
(
0
)
,
select_words
(
false
)
,
scrollbar
(
nullptr
)
{}
...
...
@@ -67,7 +68,7 @@ TextValueEditor::~TextValueEditor() {
void
TextValueEditor
::
onLeftDown
(
const
RealPoint
&
pos
,
wxMouseEvent
&
ev
)
{
select_words
=
false
;
moveSelection
(
v
.
indexAt
(
style
().
getRotation
().
trInv
(
pos
)),
!
ev
.
ShiftDown
(),
MOVE_MID
);
moveSelection
(
TYPE_INDEX
,
v
.
indexAt
(
style
().
getRotation
().
trInv
(
pos
)),
!
ev
.
ShiftDown
(),
MOVE_MID
);
}
void
TextValueEditor
::
onLeftUp
(
const
RealPoint
&
pos
,
wxMouseEvent
&
)
{
// TODO: lookup position of click?
...
...
@@ -78,9 +79,9 @@ void TextValueEditor::onMotion(const RealPoint& pos, wxMouseEvent& ev) {
size_t
index
=
v
.
indexAt
(
style
().
getRotation
().
trInv
(
pos
));
if
(
select_words
)
{
// TODO: on the left, swap start and end
moveSelection
(
index
<
selection_start
?
prevWordBoundry
(
index
)
:
nextWordBoundry
(
index
),
false
,
MOVE_MID
);
moveSelection
(
TYPE_INDEX
,
index
<
selection_start_i
?
prevWordBoundry
(
index
)
:
nextWordBoundry
(
index
),
false
,
MOVE_MID
);
}
else
{
moveSelection
(
index
,
false
,
MOVE_MID
);
moveSelection
(
TYPE_INDEX
,
index
,
false
,
MOVE_MID
);
}
}
}
...
...
@@ -88,16 +89,16 @@ void TextValueEditor::onMotion(const RealPoint& pos, wxMouseEvent& ev) {
void
TextValueEditor
::
onLeftDClick
(
const
RealPoint
&
pos
,
wxMouseEvent
&
ev
)
{
select_words
=
true
;
size_t
index
=
v
.
indexAt
(
style
().
getRotation
().
trInv
(
pos
));
moveSelection
(
prevWordBoundry
(
index
),
true
,
MOVE_MID
);
moveSelection
(
nextWordBoundry
(
index
),
false
,
MOVE_MID
);
moveSelection
(
TYPE_INDEX
,
prevWordBoundry
(
index
),
true
,
MOVE_MID
);
moveSelection
(
TYPE_INDEX
,
nextWordBoundry
(
index
),
false
,
MOVE_MID
);
}
void
TextValueEditor
::
onRightDown
(
const
RealPoint
&
pos
,
wxMouseEvent
&
ev
)
{
size_t
index
=
v
.
indexAt
(
style
().
getRotation
().
trInv
(
pos
));
if
(
index
<
min
(
selection_start
,
selection_end
)
||
index
>
max
(
selection_start
,
selection_end
))
{
if
(
index
<
min
(
selection_start
_i
,
selection_end_i
)
||
index
>
max
(
selection_start
_i
,
selection_end_i
))
{
// only move cursor when outside selection
moveSelection
(
index
,
!
ev
.
ShiftDown
(),
MOVE_MID
);
moveSelection
(
TYPE_INDEX
,
index
,
!
ev
.
ShiftDown
(),
MOVE_MID
);
}
}
...
...
@@ -109,48 +110,48 @@ void TextValueEditor::onChar(wxKeyEvent& ev) {
case
WXK_LEFT
:
// move left (selection?)
if
(
ev
.
ControlDown
())
{
moveSelection
(
prevWordBoundry
(
selection_end
),
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
moveSelection
(
TYPE_INDEX
,
prevWordBoundry
(
selection_end_i
),
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
}
else
{
moveSelection
(
prevCharBoundry
(
selection_end
),
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
moveSelection
(
TYPE_CURSOR
,
prevCharBoundry
(
selection_end
),
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
}
break
;
case
WXK_RIGHT
:
// move left (selection?)
if
(
ev
.
ControlDown
())
{
moveSelection
(
nextWordBoundry
(
selection_end
),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
moveSelection
(
TYPE_INDEX
,
nextWordBoundry
(
selection_end_i
),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
}
else
{
moveSelection
(
nextCharBoundry
(
selection_end
),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
moveSelection
(
TYPE_CURSOR
,
nextCharBoundry
(
selection_end
),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
}
break
;
case
WXK_UP
:
moveSelection
(
v
.
moveLine
(
selection_end
,
-
1
),
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
moveSelection
(
TYPE_INDEX
,
v
.
moveLine
(
selection_end_i
,
-
1
),
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
break
;
case
WXK_DOWN
:
moveSelection
(
v
.
moveLine
(
selection_end
,
+
1
),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
moveSelection
(
TYPE_INDEX
,
v
.
moveLine
(
selection_end_i
,
+
1
),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
break
;
case
WXK_HOME
:
// move to begining of line / all (if control)
if
(
ev
.
ControlDown
())
{
moveSelection
(
0
,
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
moveSelection
(
TYPE_INDEX
,
0
,
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
}
else
{
moveSelection
(
v
.
lineStart
(
selection_end
),
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
moveSelection
(
TYPE_INDEX
,
v
.
lineStart
(
selection_end_i
),
!
ev
.
ShiftDown
(),
MOVE_LEFT
);
}
break
;
case
WXK_END
:
// move to end of line / all (if control)
if
(
ev
.
ControlDown
())
{
moveSelection
(
value
().
value
().
size
(),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
moveSelection
(
TYPE_INDEX
,
value
().
value
().
size
(),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
}
else
{
moveSelection
(
v
.
lineEnd
(
selection_end
),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
moveSelection
(
TYPE_INDEX
,
v
.
lineEnd
(
selection_end_i
),
!
ev
.
ShiftDown
(),
MOVE_RIGHT
);
}
break
;
case
WXK_BACK
:
if
(
selection_start
==
selection_end
)
{
// if no selection, select previous character
moveSelectionNoRedraw
(
prevCharBoundry
(
selection_end
),
false
);
moveSelectionNoRedraw
(
TYPE_CURSOR
,
prevCharBoundry
(
selection_end
),
false
);
if
(
selection_start
==
selection_end
)
{
// Walk over a <sep> as if we are the LEFT key
moveSelection
(
prevCharBoundry
(
selection_end
),
true
,
MOVE_LEFT
);
moveSelection
(
TYPE_CURSOR
,
prevCharBoundry
(
selection_end
),
true
,
MOVE_LEFT
);
return
;
}
}
...
...
@@ -159,10 +160,10 @@ void TextValueEditor::onChar(wxKeyEvent& ev) {
case
WXK_DELETE
:
if
(
selection_start
==
selection_end
)
{
// if no selection select next
moveSelectionNoRedraw
(
nextCharBoundry
(
selection_end
),
false
);
moveSelectionNoRedraw
(
TYPE_CURSOR
,
nextCharBoundry
(
selection_end
),
false
);
if
(
selection_start
==
selection_end
)
{
// Walk over a <sep> as if we are the RIGHT key
moveSelection
(
nextCharBoundry
(
selection_end
),
true
,
MOVE_RIGHT
);
moveSelection
(
TYPE_CURSOR
,
nextCharBoundry
(
selection_end
),
true
,
MOVE_RIGHT
);
}
}
replaceSelection
(
wxEmptyString
,
_
(
"Delete"
));
...
...
@@ -193,12 +194,13 @@ void TextValueEditor::onLoseFocus() {
assert
(
caret
);
if
(
caret
->
IsVisible
())
caret
->
Hide
();
// hide selection
selection_start
=
selection_end
=
0
;
selection_start
=
selection_end
=
0
;
selection_start_i
=
selection_end_i
=
0
;
}
bool
TextValueEditor
::
onContextMenu
(
wxMenu
&
m
,
wxContextMenuEvent
&
ev
)
{
// in a keword? => "reminder text" option
size_t
kwpos
=
in_tag
(
value
().
value
(),
_
(
"<kw-"
),
selection_start
,
selection_start
);
size_t
kwpos
=
in_tag
(
value
().
value
(),
_
(
"<kw-"
),
selection_start
_i
,
selection_start_i
);
if
(
kwpos
!=
String
::
npos
)
{
Char
c
=
String
(
value
().
value
()).
GetChar
(
kwpos
+
4
);
m
.
AppendSeparator
();
...
...
@@ -211,7 +213,7 @@ bool TextValueEditor::onContextMenu(wxMenu& m, wxContextMenuEvent& ev) {
void
TextValueEditor
::
onMenu
(
wxCommandEvent
&
ev
)
{
if
(
ev
.
GetId
()
==
ID_FORMAT_REMINDER
)
{
// toggle reminder text
size_t
kwpos
=
in_tag
(
value
().
value
(),
_
(
"<kw-"
),
selection_start
,
selection_start
);
size_t
kwpos
=
in_tag
(
value
().
value
(),
_
(
"<kw-"
),
selection_start
_i
,
selection_start_i
);
if
(
kwpos
!=
String
::
npos
)
{
// getSet().actions.add(new TextToggleReminderAction(value, kwpos));
}
...
...
@@ -225,7 +227,7 @@ void TextValueEditor::onMenu(wxCommandEvent& ev) {
void
TextValueEditor
::
draw
(
RotatedDC
&
dc
)
{
TextValueViewer
::
draw
(
dc
);
if
(
isCurrent
())
{
v
.
drawSelection
(
dc
,
style
(),
selection_start
,
selection_end
);
v
.
drawSelection
(
dc
,
style
(),
selection_start
_i
,
selection_end_i
);
// show caret, onAction() would be a better place
// but it has to be done after the viewer has updated the TextViewer
...
...
@@ -268,15 +270,16 @@ wxCursor TextValueEditor::cursor() const {
void
TextValueEditor
::
onValueChange
()
{
TextValueViewer
::
onValueChange
();
selection_start
=
0
;
selection_
end
=
0
;
selection_start
=
selection_end
=
0
;
selection_
start_i
=
selection_end_i
=
0
;
}
void
TextValueEditor
::
onAction
(
const
ValueAction
&
action
,
bool
undone
)
{
TextValueViewer
::
onAction
(
action
,
undone
);
TYPE_CASE
(
action
,
TextValueAction
)
{
selection_start
=
action
.
selection_start
;
selection_end
=
action
.
selection_end
;
selection_start_i
=
action
.
selection_start
;
selection_end_i
=
action
.
selection_end
;
fixSelection
(
TYPE_INDEX
);
}
}
...
...
@@ -304,10 +307,10 @@ bool TextValueEditor::doPaste() {
bool
TextValueEditor
::
doCopy
()
{
// determine string to store
if
(
selection_start
>
value
().
value
().
size
())
selection_start
=
value
().
value
().
size
();
if
(
selection_end
>
value
().
value
().
size
())
selection_end
=
value
().
value
().
size
();
size_t
start
=
min
(
selection_start
,
selection_end
);
size_t
end
=
max
(
selection_start
,
selection_end
);
if
(
selection_start
_i
>
value
().
value
().
size
())
selection_start_i
=
value
().
value
().
size
();
if
(
selection_end
_i
>
value
().
value
().
size
())
selection_end_i
=
value
().
value
().
size
();
size_t
start
=
min
(
selection_start
_i
,
selection_end_i
);
size_t
end
=
max
(
selection_start
_i
,
selection_end_i
);
String
str
=
untag
(
value
().
value
().
substr
(
start
,
end
-
start
));
if
(
str
.
empty
())
return
false
;
// no data to copy
// set data
...
...
@@ -340,11 +343,11 @@ bool TextValueEditor::canFormat(int type) const {
bool
TextValueEditor
::
hasFormat
(
int
type
)
const
{
switch
(
type
)
{
case
ID_FORMAT_BOLD
:
return
in_tag
(
value
().
value
(),
_
(
"<b"
),
selection_start
,
selection_end
)
!=
String
::
npos
;
return
in_tag
(
value
().
value
(),
_
(
"<b"
),
selection_start
_i
,
selection_end_i
)
!=
String
::
npos
;
case
ID_FORMAT_ITALIC
:
return
in_tag
(
value
().
value
(),
_
(
"<i"
),
selection_start
,
selection_end
)
!=
String
::
npos
;
return
in_tag
(
value
().
value
(),
_
(
"<i"
),
selection_start
_i
,
selection_end_i
)
!=
String
::
npos
;
case
ID_FORMAT_SYMBOL
:
return
in_tag
(
value
().
value
(),
_
(
"<sym"
),
selection_start
,
selection_end
)
!=
String
::
npos
;
return
in_tag
(
value
().
value
(),
_
(
"<sym"
),
selection_start
_i
,
selection_end_i
)
!=
String
::
npos
;
case
ID_FORMAT_REMINDER
:
return
false
;
// TODO
default:
...
...
@@ -355,15 +358,15 @@ bool TextValueEditor::hasFormat(int type) const {
void
TextValueEditor
::
doFormat
(
int
type
)
{
switch
(
type
)
{
case
ID_FORMAT_BOLD
:
{
getSet
().
actions
.
add
(
toggle_format_action
(
valueP
(),
_
(
"b"
),
selection_start
,
selection_end
,
_
(
"Bold"
)));
getSet
().
actions
.
add
(
toggle_format_action
(
valueP
(),
_
(
"b"
),
selection_start
_i
,
selection_end_i
,
_
(
"Bold"
)));
break
;
}
case
ID_FORMAT_ITALIC
:
{
getSet
().
actions
.
add
(
toggle_format_action
(
valueP
(),
_
(
"i"
),
selection_start
,
selection_end
,
_
(
"Italic"
)));
getSet
().
actions
.
add
(
toggle_format_action
(
valueP
(),
_
(
"i"
),
selection_start
_i
,
selection_end_i
,
_
(
"Italic"
)));
break
;
}
case
ID_FORMAT_SYMBOL
:
{
getSet
().
actions
.
add
(
toggle_format_action
(
valueP
(),
_
(
"sym"
),
selection_start
,
selection_end
,
_
(
"Symbols"
)));
getSet
().
actions
.
add
(
toggle_format_action
(
valueP
(),
_
(
"sym"
),
selection_start
_i
,
selection_end_i
,
_
(
"Symbols"
)));
break
;
}
}
...
...
@@ -378,7 +381,7 @@ void TextValueEditor::showCaret() {
// The caret
wxCaret
*
caret
=
editor
().
GetCaret
();
// cursor rectangle
RealRect
cursor
=
v
.
charRect
(
selection_end
);
RealRect
cursor
=
v
.
charRect
(
selection_end
_i
);
cursor
.
width
=
0
;
// height may be 0 near a <line>
// it is not 0 for empty text, because TextRenderer handles that case
...
...
@@ -437,10 +440,10 @@ void TextValueEditor::replaceSelection(const String& replacement, const String&
fixSelection
();
// execute the action before adding it to the stack,
// because we want to run scripts before action listeners see the action
ValueAction
*
action
=
typing_action
(
valueP
(),
selection_start
,
selection_end
,
replacement
,
name
);
ValueAction
*
action
=
typing_action
(
valueP
(),
selection_start
_i
,
selection_end_i
,
replacement
,
name
);
if
(
!
action
)
{
// nothing change
d
, but move the selection anyway
moveSelection
(
selection_start
);
// nothing change
s
, but move the selection anyway
moveSelection
(
TYPE_CURSOR
,
selection_start
);
return
;
}
// perform the action
...
...
@@ -451,12 +454,12 @@ void TextValueEditor::replaceSelection(const String& replacement, const String&
String
val
=
value
().
value
();
Char
typed
=
replacement
.
GetChar
(
0
);
Char
typedU
=
toUpper
(
typed
);
Char
cur
=
val
.
GetChar
(
selection_start
);
Char
cur
=
val
.
GetChar
(
selection_start
_i
);
// the cursor may have moved because of sorting...
// is 'replacement' just after the current cursor?
if
(
selection_start
>=
0
&&
selection_start
<
val
.
size
()
&&
(
cur
==
typed
||
cur
==
typedU
))
{
if
(
selection_start
_i
>=
0
&&
selection_start_i
<
val
.
size
()
&&
(
cur
==
typed
||
cur
==
typedU
))
{
// no need to move cursor in a special way
selection_end
=
selection_start
=
min
(
selection_end
,
selection_start
)
+
1
;
selection_end
_i
=
selection_start_i
=
min
(
selection_end_i
,
selection_start_i
)
+
1
;
}
else
{
// find the last occurence of 'replacement' in the value
size_t
pos
=
val
.
find_last_of
(
typed
);
...
...
@@ -465,22 +468,23 @@ void TextValueEditor::replaceSelection(const String& replacement, const String&
pos
=
val
.
find_last_of
(
typedU
);
}
if
(
pos
!=
String
::
npos
)
{
selection_end
=
selection_start
=
pos
+
1
;
selection_end
_i
=
selection_start_i
=
pos
+
1
;
}
else
{
selection_end
=
selection_start
;
selection_end
_i
=
selection_start_i
;
}
}
}
else
{
selection_end
=
selection_start
=
min
(
selection_end
,
selection_start
)
+
replacement
.
size
();
selection_end
_i
=
selection_start_i
=
min
(
selection_end_i
,
selection_start_i
)
+
replacement
.
size
();
}
fixSelection
(
TYPE_INDEX
,
MOVE_MID
);
// scroll with next update
// scrollWithCursor = true;
}
void
TextValueEditor
::
moveSelection
(
size_t
new_end
,
bool
also_move_start
,
Movement
dir
)
{
void
TextValueEditor
::
moveSelection
(
IndexType
t
,
size_t
new_end
,
bool
also_move_start
,
Movement
dir
)
{
if
(
!
isCurrent
())
{
// selection is only visible for curent editor, we can do a move the simple way
moveSelectionNoRedraw
(
new_end
,
also_move_start
,
dir
);
moveSelectionNoRedraw
(
t
,
new_end
,
also_move_start
,
dir
);
return
;
}
// Hide caret
...
...
@@ -494,9 +498,9 @@ void TextValueEditor::moveSelection(size_t new_end, bool also_move_start, Moveme
rdc
.
SetClippingRegion
(
style
().
getRect
());
}
// clear old selection by drawing it again
v
.
drawSelection
(
rdc
,
style
(),
selection_start
,
selection_end
);
v
.
drawSelection
(
rdc
,
style
(),
selection_start
_i
,
selection_end_i
);
// move
moveSelectionNoRedraw
(
new_end
,
also_move_start
,
dir
);
moveSelectionNoRedraw
(
t
,
new_end
,
also_move_start
,
dir
);
// scroll?
// scrollWithCursor = true;
// if (onMove()) {
...
...
@@ -518,23 +522,53 @@ void TextValueEditor::moveSelection(size_t new_end, bool also_move_start, Moveme
rdc
.
DrawText
(
String
::
Format
(
_
(
"%d - %d"
),
selection_start
,
selection_end
),
RealPoint
(
style
().
width
-
50
,
style
().
height
-
10
));
}
void
TextValueEditor
::
moveSelectionNoRedraw
(
size_t
new_end
,
bool
also_move_start
,
Movement
dir
)
{
selection_end
=
new_end
;
if
(
also_move_start
)
selection_start
=
selection_end
;
fixSelection
(
dir
);
void
TextValueEditor
::
moveSelectionNoRedraw
(
IndexType
t
,
size_t
new_end
,
bool
also_move_start
,
Movement
dir
)
{
if
(
t
==
TYPE_INDEX
)
{
selection_end_i
=
new_end
;
if
(
also_move_start
)
selection_start_i
=
selection_end_i
;
}
else
{
selection_end
=
new_end
;
if
(
also_move_start
)
selection_start
=
selection_end
;
}
fixSelection
(
t
,
dir
);
}
void
TextValueEditor
::
fixSelection
(
Movement
dir
)
{
void
TextValueEditor
::
fixSelection
(
IndexType
t
,
Movement
dir
)
{
const
String
&
val
=
value
().
value
();
// value may have become smaller because of undo/redo
// make sure the selection stays inside the text
size_t
size
=
val
.
size
();
// Which type takes precedent?
if
(
t
==
TYPE_INDEX
)
{
selection_start
=
index_to_cursor
(
value
().
value
(),
selection_start_i
,
dir
);
selection_end
=
index_to_cursor
(
value
().
value
(),
selection_end_i
,
dir
);
}
// make sure the selection is at a valid position inside the text
selection_start_i
=
cursor_to_index
(
val
,
selection_start
);
selection_end_i
=
cursor_to_index
(
val
,
selection_end
);
// start and end must be on the same side of separators
size_t
seppos
=
val
.
find
(
_
(
"<sep"
));
while
(
seppos
!=
String
::
npos
)
{
size_t
sepend
=
skip_tag
(
val
,
match_close_tag
(
val
,
seppos
));
if
((
selection_start_i
<=
seppos
&&
selection_end_i
>
seppos
)
||
(
selection_start_i
>=
sepend
&&
selection_end_i
<
sepend
))
{
// not on same side, move selection end before sep
//selection_end = cursor_to_index(val, index_to_cursor(val, seppos));
selection_end
=
index_to_cursor
(
val
,
seppos
,
dir
);
selection_end_i
=
cursor_to_index
(
val
,
selection_end
);
}
// find next separator
seppos
=
val
.
find
(
_
(
"<sep"
),
seppos
+
1
);
}
// REMOVEME
/*size_t size = val.size();
selection_end = min(size, selection_end);
selection_start = min(size, selection_start);
// start and end must not be inside or between tags
selection_start = v.firstVisibleChar(selection_start, dir == MOVE_LEFT ? -1 : +1);
selection_end = v.firstVisibleChar(selection_end, dir == MOVE_LEFT ? -1 : +1);
// start and end must be on the same side of separators
size_t seppos = val.find(_("<sep"));
while (seppos != String::npos) {
size_t
sepend
=
match_close_tag
(
val
,
seppos
);
size_t sepend =
skip_tag(val,match_close_tag(val, seppos)
);
if (selection_start <= seppos && selection_end > seppos) selection_end = seppos; // not on same side
if (selection_start >= sepend && selection_end < sepend) selection_end = sepend; // not on same side
if (selection_start > seppos && selection_start < sepend) {
...
...
@@ -551,7 +585,7 @@ void TextValueEditor::fixSelection(Movement dir) {
// start or end in an <atom>? if so, move them out
size_t atompos = val.find(_("<atom"));
while (atompos != String::npos) {
size_t
atomend
=
match_close_tag
(
val
,
atompos
);
size_t atomend =
skip_tag(val,match_close_tag(val, atompos)
);
if (selection_start > atompos && selection_start < atomend) { // start inside atom
selection_start = move(selection_start, atompos, atomend, dir);
}
...
...
@@ -561,10 +595,8 @@ void TextValueEditor::fixSelection(Movement dir) {
// find next atom
atompos = val.find(_("<atom"), atompos + 1);
}
// start and end must not be inside or between tags
selection_start
=
v
.
firstVisibleChar
(
selection_start
,
dir
==
MOVE_LEFT
?
-
1
:
+
1
);
selection_end
=
v
.
firstVisibleChar
(
selection_end
,
dir
==
MOVE_LEFT
?
-
1
:
+
1
);
// TODO
*/
// TODO? : More checks?
}
...
...
@@ -572,19 +604,19 @@ size_t TextValueEditor::prevCharBoundry(size_t pos) const {
return
max
(
0
,
(
int
)
pos
-
1
);
}
size_t
TextValueEditor
::
nextCharBoundry
(
size_t
pos
)
const
{
return
min
(
value
().
value
().
size
(),
pos
+
1
)
;
return
pos
+
1
;
}
size_t
TextValueEditor
::
prevWordBoundry
(
size_t
pos
)
const
{
size_t
TextValueEditor
::
prevWordBoundry
(
size_t
pos
_i
)
const
{
const
String
&
val
=
value
().
value
();
size_t
p
=
val
.
find_last_not_of
(
_
(
" ,.:;()
\n
"
),
max
(
0
,
(
int
)
(
pos
-
1
)));
//note: pos-1 might be < 0
size_t
p
=
val
.
find_last_not_of
(
_
(
" ,.:;()
\n
"
),
max
(
0
,
(
int
)
pos_i
-
1
));
if
(
p
==
String
::
npos
)
return
0
;
p
=
val
.
find_last_of
(
_
(
" ,.:;()
\n
"
),
p
);
if
(
p
==
String
::
npos
)
return
0
;
return
p
+
1
;
}
size_t
TextValueEditor
::
nextWordBoundry
(
size_t
pos
)
const
{
size_t
TextValueEditor
::
nextWordBoundry
(
size_t
pos
_i
)
const
{
const
String
&
val
=
value
().
value
();
size_t
p
=
val
.
find_first_of
(
_
(
" ,.:;()
\n
"
),
pos
);
size_t
p
=
val
.
find_first_of
(
_
(
" ,.:;()
\n
"
),
pos
_i
);
if
(
p
==
String
::
npos
)
return
val
.
size
();
p
=
val
.
find_first_not_of
(
_
(
" ,.:;()
\n
"
),
p
);
if
(
p
==
String
::
npos
)
return
val
.
size
();
...
...
src/gui/value/text.hpp
View file @
cfd59072
...
...
@@ -10,6 +10,7 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/tagged_string.hpp> // for Movement
#include <gui/value/editor.hpp>
#include <render/value/text.hpp>
...
...
@@ -17,11 +18,9 @@ class TextValueEditorScrollBar;
// ----------------------------------------------------------------------------- : TextValueEditor
/// Directions of cursor movement
enum
Movement
{
MOVE_LEFT
///< Always move the cursor to the left
,
MOVE_MID
///< Move in whichever direction the distance to move is shorter (TODO: define shorter)
,
MOVE_RIGHT
///< Always move the cursor to the right
enum
IndexType
{
TYPE_CURSOR
///< Positions are cursor positions
,
TYPE_INDEX
///< Positions are character indices
};
/// An editor 'control' for editing TextValues
...
...
@@ -83,16 +82,19 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
// --------------------------------------------------- : Data
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
bool
select_words
;
///< Select whole words when dragging the mouse?
// --------------------------------------------------- : Selection / movement
/// 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
);
/// Move the selection to a new location, but does not redraw
void
moveSelectionNoRedraw
(
size_t
new_end
,
bool
also_move_start
=
true
,
Movement
dir
=
MOVE_MID
);
/// Move the selection to a new location, clears the previously drawn selection.
/** t specifies what kind of position new_end is */
void
moveSelection
(
IndexType
t
,
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
void
replaceSelection
(
const
String
&
replacement
,
const
String
&
name
);
...
...
@@ -104,7 +106,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
*
* 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
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 {
void
showCaret
();
/// Position of previous visible & selectable character
/** Uses cursor positions */
size_t
prevCharBoundry
(
size_t
pos
)
const
;
size_t
nextCharBoundry
(
size_t
pos
)
const
;
/// Front of previous word, used witch Ctrl+Left/right
size_t
prevWordBoundry
(
size_t
pos
)
const
;
size_t
nextWordBoundry
(
size_t
pos
)
const
;
/** Uses character indices */
size_t
prevWordBoundry
(
size_t
pos_i
)
const
;
size_t
nextWordBoundry
(
size_t
pos_i
)
const
;
// --------------------------------------------------- : Scrolling
...
...
src/gui/welcome_window.cpp
View file @
cfd59072
...
...
@@ -64,7 +64,7 @@ void WelcomeWindow::draw(DC& dc) {
}
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
)
{
close
(
import_set
(
dlg
.
GetPath
()));
}
...
...
src/render/text/element.hpp
View file @
cfd59072
...
...
@@ -130,7 +130,7 @@ class FontTextElement : public SimpleTextElement {
:
SimpleTextElement
(
text
,
start
,
end
)
,
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
getCharInfo
(
RotatedDC
&
dc
,
double
scale
,
vector
<
CharInfo
>&
out
)
const
;
virtual
double
minScale
()
const
;
...
...
@@ -146,7 +146,7 @@ class SymbolTextElement : public SimpleTextElement {
:
SimpleTextElement
(
text
,
start
,
end
)
,
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
getCharInfo
(
RotatedDC
&
dc
,
double
scale
,
vector
<
CharInfo
>&
out
)
const
;
virtual
double
minScale
()
const
;
...
...
@@ -162,9 +162,22 @@ class CompoundTextElement : public TextElement {
public:
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
};
/// 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
/// A text element that displays a horizontal separator line
...
...
src/render/text/viewer.hpp
View file @
cfd59072
...
...
@@ -81,7 +81,7 @@ class TextViewer {
/// Is the character at the given index visible?
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
/** 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 non
zero width
*/
size_t
firstVisibleChar
(
size_t
index
,
int
delta
)
const
;
...
...
src/util/tagged_string.cpp
View file @
cfd59072
...
...
@@ -159,6 +159,80 @@ String anti_tag(const String& 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
String
remove_tag
(
const
String
&
str
,
const
String
&
tag
)
{
...
...
src/util/tagged_string.hpp
View file @
cfd59072
...
...
@@ -80,6 +80,29 @@ String close_tag(const String& tag);
/// The matching close tag for an open tag and vice versa
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
/// Remove all instances of a tag and its close tag, but keep the contents.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment