mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
correct cursor movement accross lines & zero width things
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@108 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+36
-1
@@ -55,6 +55,7 @@ END_EVENT_TABLE ()
|
|||||||
|
|
||||||
IMPLEMENT_VALUE_EDITOR(Text)
|
IMPLEMENT_VALUE_EDITOR(Text)
|
||||||
, selection_start(0), selection_end(0)
|
, selection_start(0), selection_end(0)
|
||||||
|
, select_words(false)
|
||||||
, scrollbar(nullptr)
|
, scrollbar(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ TextValueEditor::~TextValueEditor() {
|
|||||||
// ----------------------------------------------------------------------------- : Mouse
|
// ----------------------------------------------------------------------------- : Mouse
|
||||||
|
|
||||||
void TextValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) {
|
void TextValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) {
|
||||||
|
select_words = false;
|
||||||
moveSelection(v.indexAt(style().getRotation().trInv(pos)), !ev.ShiftDown(), MOVE_MID);
|
moveSelection(v.indexAt(style().getRotation().trInv(pos)), !ev.ShiftDown(), MOVE_MID);
|
||||||
}
|
}
|
||||||
void TextValueEditor::onLeftUp(const RealPoint& pos, wxMouseEvent&) {
|
void TextValueEditor::onLeftUp(const RealPoint& pos, wxMouseEvent&) {
|
||||||
@@ -73,11 +75,18 @@ void TextValueEditor::onLeftUp(const RealPoint& pos, wxMouseEvent&) {
|
|||||||
|
|
||||||
void TextValueEditor::onMotion(const RealPoint& pos, wxMouseEvent& ev) {
|
void TextValueEditor::onMotion(const RealPoint& pos, wxMouseEvent& ev) {
|
||||||
if (ev.LeftIsDown()) {
|
if (ev.LeftIsDown()) {
|
||||||
moveSelection(v.indexAt(style().getRotation().trInv(pos)), false, MOVE_MID);
|
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);
|
||||||
|
} else {
|
||||||
|
moveSelection(index, false, MOVE_MID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextValueEditor::onLeftDClick(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));
|
size_t index = v.indexAt(style().getRotation().trInv(pos));
|
||||||
moveSelection(prevWordBoundry(index), true, MOVE_MID);
|
moveSelection(prevWordBoundry(index), true, MOVE_MID);
|
||||||
moveSelection(nextWordBoundry(index), false, MOVE_MID);
|
moveSelection(nextWordBoundry(index), false, MOVE_MID);
|
||||||
@@ -216,6 +225,24 @@ void TextValueEditor::onMenu(wxCommandEvent& ev) {
|
|||||||
void TextValueEditor::draw(RotatedDC& dc) {
|
void TextValueEditor::draw(RotatedDC& dc) {
|
||||||
TextValueViewer::draw(dc);
|
TextValueViewer::draw(dc);
|
||||||
v.drawSelection(dc, style(), selection_start, selection_end);
|
v.drawSelection(dc, style(), selection_start, selection_end);
|
||||||
|
// DEBUG, TODO: REMOVEME
|
||||||
|
Rotater r(dc, style().getRotation());
|
||||||
|
/*dc.SetPen(*wxRED_PEN);
|
||||||
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||||
|
dc.SetTextForeground(*wxGREEN);
|
||||||
|
dc.SetFont(wxFont(6,wxFONTFAMILY_SWISS,wxNORMAL,wxNORMAL));
|
||||||
|
for (size_t i = 0 ; i < value().value().size() ; i += 10) {
|
||||||
|
RealRect r = v.charRect(i);
|
||||||
|
r.width = max(r.width,1.);
|
||||||
|
dc.DrawRectangle(r);
|
||||||
|
dc.DrawText(String()<<(int)i, r.position()+RealSize(1,5));
|
||||||
|
}*/
|
||||||
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
|
dc.SetBrush(*wxWHITE_BRUSH);
|
||||||
|
dc.SetTextForeground(*wxBLUE);
|
||||||
|
dc.SetFont(wxFont(6,wxFONTFAMILY_SWISS,wxNORMAL,wxNORMAL));
|
||||||
|
dc.DrawRectangle(RealRect(style().width-50,style().height-10,50,10));
|
||||||
|
dc.DrawText(String::Format(_("%d - %d"),selection_start, selection_end), RealPoint(style().width-50,style().height-10));
|
||||||
}
|
}
|
||||||
|
|
||||||
wxCursor rotated_ibeam;
|
wxCursor rotated_ibeam;
|
||||||
@@ -473,6 +500,14 @@ void TextValueEditor::moveSelection(size_t new_end, bool also_move_start, Moveme
|
|||||||
v.drawSelection(rdc, style(), selection_start, selection_end);
|
v.drawSelection(rdc, style(), selection_start, selection_end);
|
||||||
// }
|
// }
|
||||||
showCaret();
|
showCaret();
|
||||||
|
// TODO; DEBUG!!
|
||||||
|
Rotater r(rdc, style().getRotation());
|
||||||
|
rdc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
|
rdc.SetBrush(*wxWHITE_BRUSH);
|
||||||
|
rdc.SetTextForeground(*wxBLUE);
|
||||||
|
rdc.SetFont(wxFont(6,wxFONTFAMILY_SWISS,wxNORMAL,wxNORMAL));
|
||||||
|
rdc.DrawRectangle(RealRect(style().width-50,style().height-10,50,10));
|
||||||
|
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) {
|
void TextValueEditor::moveSelectionNoRedraw(size_t new_end, bool also_move_start, Movement dir) {
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
|
|||||||
private:
|
private:
|
||||||
size_t selection_start, selection_end; ///< Cursor position/selection (if any)
|
size_t selection_start, selection_end; ///< Cursor position/selection (if any)
|
||||||
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?
|
||||||
|
|
||||||
// --------------------------------------------------- : Selection / movement
|
// --------------------------------------------------- : Selection / movement
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ size_t TextViewer::Line::posToIndex(double x) const {
|
|||||||
// largest index with pos <= x
|
// largest index with pos <= x
|
||||||
vector<double>::const_iterator it2 = lower_bound(positions.begin(), positions.end(), x);
|
vector<double>::const_iterator it2 = lower_bound(positions.begin(), positions.end(), x);
|
||||||
if (it2 == positions.begin()) return start;
|
if (it2 == positions.begin()) return start;
|
||||||
|
if (it2 == positions.end()) --it2; // we don't want to find the position beyond the end
|
||||||
// first index with pos > x
|
// first index with pos > x
|
||||||
vector<double>::const_iterator it1 = it2 - 1;
|
vector<double>::const_iterator it1 = it2 - 1;
|
||||||
if (x - *it1 <= *it2 - x) return it1 - positions.begin() + start; // it1 is closer
|
if (x - *it1 <= *it2 - x) return it1 - positions.begin() + start; // it1 is closer
|
||||||
@@ -95,8 +96,8 @@ void TextViewer::drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel
|
|||||||
void TextViewer::Line::drawSelection(RotatedDC& dc, size_t sel_start, size_t sel_end) {
|
void TextViewer::Line::drawSelection(RotatedDC& dc, size_t sel_start, size_t sel_end) {
|
||||||
if (!visible(dc)) return;
|
if (!visible(dc)) return;
|
||||||
if (sel_start < end() && sel_end > start) {
|
if (sel_start < end() && sel_end > start) {
|
||||||
double x1 = positions[sel_start - start];
|
double x1 = positions[max(start, sel_start) - start];
|
||||||
double x2 = positions[min(end(), sel_end) - start];
|
double x2 = positions[min(end(), sel_end) - start];
|
||||||
dc.DrawRectangle(RealRect(x1, top, x2 - x1, line_height));
|
dc.DrawRectangle(RealRect(x1, top, x2 - x1, line_height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +111,7 @@ void TextViewer::reset() {
|
|||||||
|
|
||||||
const TextViewer::Line& TextViewer::findLine(size_t index) const {
|
const TextViewer::Line& TextViewer::findLine(size_t index) const {
|
||||||
FOR_EACH_CONST(l, lines) {
|
FOR_EACH_CONST(l, lines) {
|
||||||
if (l.end() > index) return l;
|
if (l.end() >= index) return l;
|
||||||
}
|
}
|
||||||
return lines.front();
|
return lines.front();
|
||||||
}
|
}
|
||||||
@@ -176,13 +177,22 @@ bool TextViewer::isVisible(size_t index) const {
|
|||||||
}
|
}
|
||||||
size_t TextViewer::firstVisibleChar(size_t index, int delta) const {
|
size_t TextViewer::firstVisibleChar(size_t index, int delta) const {
|
||||||
if (lines.empty()) return index;
|
if (lines.empty()) return index;
|
||||||
const Line& l = findLine(index);
|
const Line* l = &findLine(index);
|
||||||
int pos = (int)(index - l.start);
|
while (true) {
|
||||||
while (pos + delta > 0 && (size_t)pos + delta + 1 < l.positions.size()) {
|
int pos = (int)(index - l->start);
|
||||||
if (l.positions[pos + 1] - l.positions[pos] > 0.0001) break;
|
while (index == l->end() || (pos + delta >= 0 && (size_t)pos + delta < l->positions.size())) {
|
||||||
pos += delta;
|
if (index == l->end() || l->positions[pos + 1] - l->positions[pos] > 0.0001) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
pos += delta;
|
||||||
|
index += delta;
|
||||||
|
}
|
||||||
|
// move to another line, if not at start/end
|
||||||
|
if (l + delta < &lines.front()) return 0;
|
||||||
|
if (l + delta > &lines.back()) return l->end();
|
||||||
|
index += delta;
|
||||||
|
l += delta;
|
||||||
}
|
}
|
||||||
return pos + l.start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double TextViewer::heightOfLastLine() const {
|
double TextViewer::heightOfLastLine() const {
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ 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
|
||||||
|
*/
|
||||||
size_t firstVisibleChar(size_t index, int delta) const;
|
size_t firstVisibleChar(size_t index, int delta) const;
|
||||||
|
|
||||||
/// Return the height of the last line
|
/// Return the height of the last line
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class RealSize {
|
|||||||
|
|
||||||
/// Can be converted to a wxSize, with integer components
|
/// Can be converted to a wxSize, with integer components
|
||||||
inline operator wxSize() {
|
inline operator wxSize() {
|
||||||
return wxSize(realRound(width), realRound(height));
|
return wxSize(to_int(width), to_int(height));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,7 +161,14 @@ class RealRect : private RealPoint, private RealSize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline operator wxRect() const {
|
inline operator wxRect() const {
|
||||||
return wxRect(x, y, width, height);
|
// Prevent rounding errors, for example if
|
||||||
|
// x = 0.6 and width = 0.6
|
||||||
|
// the right = 1.2
|
||||||
|
// so we want a rectangle from 0 to 1
|
||||||
|
// not from 0 to 0
|
||||||
|
int i_l = to_int(x), i_r = to_int(right());
|
||||||
|
int i_t = to_int(y), i_b = to_int(bottom());
|
||||||
|
return wxRect(i_l, i_t, i_r - i_l, i_b - i_t);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,11 @@
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Rounding
|
// ----------------------------------------------------------------------------- : Rounding
|
||||||
|
|
||||||
// Rounding function for converting doubles to integers
|
/// Rounding function for converting doubles to integers,
|
||||||
inline int realRound(double d) {
|
/** Intentionally uses slightly less then 0.5, to give a more consistent result
|
||||||
return d > 0 ? d + 0.5 : d - 0.5;
|
* when for instance something like "x/2" is used. */
|
||||||
|
inline int to_int(double d) {
|
||||||
|
return d > 0 ? d + 0.4999995 : d - 0.4999995;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Vector2D
|
// ----------------------------------------------------------------------------- : Vector2D
|
||||||
@@ -110,7 +112,7 @@ class Vector2D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline operator wxPoint() const {
|
inline operator wxPoint() const {
|
||||||
return wxPoint(realRound(x), realRound(y));
|
return wxPoint(to_int(x), to_int(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vector at infinity
|
// Vector at infinity
|
||||||
|
|||||||
Reference in New Issue
Block a user