summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Fl_Text_Buffer.cxx1695
-rw-r--r--src/Fl_Text_Display.cxx578
-rw-r--r--src/Fl_Text_Editor.cxx4
3 files changed, 660 insertions, 1617 deletions
diff --git a/src/Fl_Text_Buffer.cxx b/src/Fl_Text_Buffer.cxx
index 002454462..cdd43e491 100644
--- a/src/Fl_Text_Buffer.cxx
+++ b/src/Fl_Text_Buffer.cxx
@@ -33,97 +33,47 @@
#include <FL/Fl.H>
#include <FL/Fl_Text_Buffer.H>
+
/*
This file is based on a port of NEdit to FLTK many years ago. NEdit at that
point was already stretched beyond the task it was designed for which explains
- why the source code is sometimes pretty convoluted. It still is a nice widget
- for FLTK.
+ why the source code is sometimes pretty convoluted. It still is a very useful
+ widget for FLTK, and we are thankful that the nedit team allowed us to
+ integrate their code.
With the introduction of Unicode and UTF-8, Fl_Text_... has to go into a whole
new generation of code. Originally designed for monspaced fonts only, many
features make les sense in the multibyte and multiwdth world of UTF-8.
- Columns are a good example. There is simply no such thing.
-
- Rectangular selections pose a real problem.
-
- Using multiple spaces to emulate tab stops will no longer work.
+ Columns are a good example. There is simply no such thing. The new Fl_Text_...
+ widget converts columns to pixels by multiplying them with the average
+ character width for a given font
- And constantly recalculating character widths is just much too expensive.
+ Rectangular selections were rearely used (if at all) and make little sense when
+ using variable width fonts. They have been removed.
- But nevertheless, we will get ths widget rolling again ;-)
+ Using multiple spaces to emulate tab stops has been replaced by pixel counting
+ routines. They are slower, but give the expected result for proportional fonts.
+ And constantly recalculating character widths is just much too expensive. Lines
+ of text are now subdivided into blocks of text which are measured at once
+ instead of individual characters.
*/
-/*
- \todo unicode check
- */
-static void insertColInLine(const char *line, char *insLine, int column,
- int insWidth, int tabDist, int useTabs,
- char *outStr, int *outLen,
- int *endOffset);
-
-/*
- \todo unicode check
- */
-static void deleteRectFromLine(const char *line, int rectStart,
- int rectEnd, int tabDist, int useTabs,
- char *outStr,
- int *outLen, int *endOffset);
-
-/*
- \todo unicode check
- */
-static void overlayRectInLine(const char *line, char *insLine,
- int rectStart, int rectEnd, int tabDist,
- int useTabs, char *outStr,
- int *outLen, int *endOffset);
-
-/*
- \todo unicode check
- */
-static void addPadding(char *string, int startIndent, int toIndent,
- int tabDist, int useTabs, int *charsAdded);
-
-/*
- \todo unicode check
- */
-static char *copyLine(const char *text, int *lineLen);
-
-/*
- unicode tested
- */
-static int countLines(const char *string);
-
-/*
- \todo unicode check
- */
-static int textWidth(const char *text, int tabDist);
-
-/*
- \todo unicode check
- */
-static char *realignTabs(const char *text, int origIndent, int newIndent,
- int tabDist, int useTabs, int *newLength);
-
-/*
- \todo unicode check
- */
-static char *expandTabs(const char *text, int startIndent, int tabDist, int *newLen);
+#ifndef min
/*
- \todo unicode check
+ Unicode safe.
*/
-static char *unexpandTabs(char *text, int startIndent, int tabDist, int *newLen);
-
-#ifndef min
-
static int max(int i1, int i2)
{
return i1 >= i2 ? i1 : i2;
}
+/*
+ Unicode safe.
+ */
static int min(int i1, int i2)
{
return i1 <= i2 ? i1 : i2;
@@ -131,12 +81,6 @@ static int min(int i1, int i2)
#endif
-static const char *ControlCodeTable[32] = {
- "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
- "bs", "ht", "nl", "vt", "np", "cr", "so", "si",
- "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
- "can", "em", "sub", "esc", "fs", "gs", "rs", "us"
-};
static char *undobuffer;
static int undobufferlength;
@@ -146,6 +90,10 @@ static int undocut; // number of characters deleted there
static int undoinsert; // number of characters inserted
static int undoyankcut; // length of valid contents of buffer, even if undocut=0
+/*
+ Resize the undo buffer to match at least the requested size.
+ Unicode safe.
+ */
static void undobuffersize(int n)
{
if (n > undobufferlength) {
@@ -162,7 +110,10 @@ static void undobuffersize(int n)
}
-// unicode ok
+/*
+ Initialize all variables.
+ Unicode safe.
+ */
Fl_Text_Buffer::Fl_Text_Buffer(int requestedSize, int preferredGapSize)
{
mLength = 0;
@@ -171,16 +122,12 @@ Fl_Text_Buffer::Fl_Text_Buffer(int requestedSize, int preferredGapSize)
mGapStart = 0;
mGapEnd = mPreferredGapSize;
mTabDist = 8;
- mUseTabs = 1;
mPrimary.mSelected = 0;
- mPrimary.mRectangular = 0;
mPrimary.mStart = mPrimary.mEnd = 0;
mSecondary.mSelected = 0;
mSecondary.mStart = mSecondary.mEnd = 0;
- mSecondary.mRectangular = 0;
mHighlight.mSelected = 0;
mHighlight.mStart = mHighlight.mEnd = 0;
- mHighlight.mRectangular = 0;
mModifyProcs = NULL;
mCbArgs = NULL;
mNModifyProcs = 0;
@@ -189,17 +136,13 @@ Fl_Text_Buffer::Fl_Text_Buffer(int requestedSize, int preferredGapSize)
mPredeleteCbArgs = NULL;
mCursorPosHint = 0;
mCanUndo = 1;
-#ifdef PURIFY
- {
- int i;
- for (i = mGapStart; i < mGapEnd; i++)
- mBuf[i] = '.';
}
-#endif
-}
-// unicode ok
+/*
+ Free all resources.
+ Unicode safe.
+ */
Fl_Text_Buffer::~Fl_Text_Buffer()
{
free(mBuf);
@@ -214,19 +157,24 @@ Fl_Text_Buffer::~Fl_Text_Buffer()
}
-// This function copies verbose whatever is in front and after the gap into a
-// single buffer.
-// - unicode ok
+/*
+ This function copies verbose whatever is in front and after the gap into a
+ single buffer.
+ Unicode safe.
+ */
char *Fl_Text_Buffer::text() const {
char *t = (char *) malloc(mLength + 1);
memcpy(t, mBuf, mGapStart);
- memcpy(&t[mGapStart], &mBuf[mGapEnd], mLength - mGapStart);
+ memcpy(t+mGapStart, mBuf+mGapEnd, mLength - mGapStart);
t[mLength] = '\0';
return t;
}
-// unicode ok, functions called have not been verified yet
+/*
+ Set the text buffer to a new string.
+ Unicode safe.
+ */
void Fl_Text_Buffer::text(const char *t)
{
call_predelete_callbacks(0, length());
@@ -243,13 +191,6 @@ void Fl_Text_Buffer::text(const char *t)
mGapStart = insertedLength;
mGapEnd = mGapStart + mPreferredGapSize;
memcpy(mBuf, t, insertedLength);
-#ifdef PURIFY
- {
- int i;
- for (i = mGapStart; i < mGapEnd; i++)
- mBuf[i] = '.';
- }
-#endif
/* Zero all of the existing selections */
update_selections(0, deletedLength, 0);
@@ -260,8 +201,10 @@ void Fl_Text_Buffer::text(const char *t)
}
-// Creates a new buffer and copies verbose from around the gap.
-// - unicode ok
+/*
+ Creates a range of text to a new buffer and copies verbose from around the gap.
+ Unicode safe.
+ */
char *Fl_Text_Buffer::text_range(int start, int end) const {
char *s = NULL;
@@ -285,22 +228,23 @@ char *Fl_Text_Buffer::text_range(int start, int end) const {
/* Copy the text from the buffer to the returned string */
if (end <= mGapStart) {
- memcpy(s, &mBuf[start], copiedLength);
+ memcpy(s, mBuf + start, copiedLength);
} else if (start >= mGapStart) {
- memcpy(s, &mBuf[start + (mGapEnd - mGapStart)], copiedLength);
+ memcpy(s, mBuf + start + (mGapEnd - mGapStart), copiedLength);
} else {
int part1Length = mGapStart - start;
- memcpy(s, &mBuf[start], part1Length);
- memcpy(&s[part1Length], &mBuf[mGapEnd], copiedLength - part1Length);
+ memcpy(s, mBuf + start, part1Length);
+ memcpy(s + part1Length, mBuf + mGapEnd, copiedLength - part1Length);
}
s[copiedLength] = '\0';
return s;
}
-
-// TODO: we will need the same signature function to get bytes (style buffer)
-// unicode ok
-unsigned int Fl_Text_Buffer::character(int pos) const {
+/*
+ Return a UCS-4 character at the given index.
+ Unicode safe. Pos must be at a character boundary.
+ */
+unsigned int Fl_Text_Buffer::char_at(int pos) const {
if (pos < 0 || pos >= mLength)
return '\0';
const char *src = address(pos);
@@ -308,7 +252,22 @@ unsigned int Fl_Text_Buffer::character(int pos) const {
}
-// unicode ok, dependents not tested
+/*
+ Return the raw byte at the given index.
+ This function ignores all unicode encoding.
+ */
+char Fl_Text_Buffer::byte_at(int pos) const {
+ if (pos < 0 || pos >= mLength)
+ return '\0';
+ const char *src = address(pos);
+ return *src;
+}
+
+
+/*
+ Insert some text at the given index.
+ Unicode safe. Pos must be at a character boundary.
+*/
void Fl_Text_Buffer::insert(int pos, const char *text)
{
/* if pos is not contiguous to existing text, make it */
@@ -327,7 +286,10 @@ void Fl_Text_Buffer::insert(int pos, const char *text)
}
-// unicode ok, dependents not tested
+/*
+ Replace a range of text with new text.
+ Unicode safe. Start and end must be at a character boundary.
+*/
void Fl_Text_Buffer::replace(int start, int end, const char *text)
{
// Range check...
@@ -348,7 +310,10 @@ void Fl_Text_Buffer::replace(int start, int end, const char *text)
}
-// unicode ok, dependents not tested
+/*
+ Remove a range of text.
+ Unicode safe. Start and End must be at a character boundary.
+*/
void Fl_Text_Buffer::remove(int start, int end)
{
/* Make sure the arguments make sense */
@@ -378,6 +343,11 @@ void Fl_Text_Buffer::remove(int start, int end)
free((void *) deletedText);
}
+
+/*
+ Copy a range of text from another text buffer.
+ Unicode safe. FromDtart, fromEnd, and toPos must be at a character boundary.
+ */
void Fl_Text_Buffer::copy(Fl_Text_Buffer * fromBuf, int fromStart,
int fromEnd, int toPos)
{
@@ -398,8 +368,7 @@ void Fl_Text_Buffer::copy(Fl_Text_Buffer * fromBuf, int fromStart,
memcpy(&mBuf[toPos], &fromBuf->mBuf[fromStart], copiedLength);
} else if (fromStart >= fromBuf->mGapStart) {
memcpy(&mBuf[toPos],
- &fromBuf->mBuf[fromStart +
- (fromBuf->mGapEnd - fromBuf->mGapStart)],
+ &fromBuf->mBuf[fromStart + (fromBuf->mGapEnd - fromBuf->mGapStart)],
copiedLength);
} else {
int part1Length = fromBuf->mGapStart - fromStart;
@@ -412,9 +381,15 @@ void Fl_Text_Buffer::copy(Fl_Text_Buffer * fromBuf, int fromStart,
update_selections(toPos, 0, copiedLength);
}
+
+/*
+ Take the previous changes and undo them. Return the previous
+ cursor position in cursorPos. Returns 1 if the undo was applied.
+ Unicode safe. CursorPos will be at a character boundary.
+ */
int Fl_Text_Buffer::undo(int *cursorPos)
{
- if (undowidget != this || (!undocut && !undoinsert && !mCanUndo) )
+ if (undowidget != this || !undocut && !undoinsert && !mCanUndo)
return 0;
int ilen = undocut;
@@ -450,181 +425,27 @@ int Fl_Text_Buffer::undo(int *cursorPos)
}
-// unicode ok
+/*
+ Set a flag is undo function will work.
+ Unicode safe.
+ */
void Fl_Text_Buffer::canUndo(char flag)
{
mCanUndo = flag;
+ // disabeling undo also clears the last undo operation!
+ if (!mCanUndo && undowidget==this)
+ undowidget = 0;
}
-void Fl_Text_Buffer::insert_column(int column, int startPos,
- const char *text, int *charsInserted,
- int *charsDeleted)
-{
- int nLines = countLines(text);
- int lineStartPos = line_start(startPos);
- int nDeleted = line_end(skip_lines(startPos, nLines)) - lineStartPos;
- call_predelete_callbacks(lineStartPos, nDeleted);
- const char *deletedText =
- text_range(lineStartPos, lineStartPos + nDeleted);
- int insertDeleted, nInserted;
- insert_column_(column, lineStartPos, text, &insertDeleted, &nInserted,
- &mCursorPosHint);
- if (nDeleted != insertDeleted)
- Fl::error
- ("Fl_Text_Buffer::insert_column(): internal consistency check ins1 failed");
- call_modify_callbacks(lineStartPos, nDeleted, nInserted, 0, deletedText);
- free((void *) deletedText);
- if (charsInserted != NULL)
- *charsInserted = nInserted;
- if (charsDeleted != NULL)
- *charsDeleted = nDeleted;
-}
-
-void Fl_Text_Buffer::overlay_rectangular(int startPos, int rectStart,
- int rectEnd, const char *text,
- int *charsInserted,
- int *charsDeleted)
-{
-
- int nLines = countLines(text);
- int lineStartPos = line_start(startPos);
- int nDeleted = line_end(skip_lines(startPos, nLines)) - lineStartPos;
- call_predelete_callbacks(lineStartPos, nDeleted);
- const char *deletedText =
- text_range(lineStartPos, lineStartPos + nDeleted);
- int insertDeleted, nInserted;
- overlay_rectangular_(lineStartPos, rectStart, rectEnd, text,
- &insertDeleted, &nInserted, &mCursorPosHint);
- if (nDeleted != insertDeleted)
- Fl::error
- ("Fl_Text_Buffer::overlay_rectangle(): internal consistency check ovly1 failed");
- call_modify_callbacks(lineStartPos, nDeleted, nInserted, 0, deletedText);
- free((void *) deletedText);
- if (charsInserted != NULL)
- *charsInserted = nInserted;
- if (charsDeleted != NULL)
- *charsDeleted = nDeleted;
-}
-
-void Fl_Text_Buffer::replace_rectangular(int start, int end, int rectStart,
- int rectEnd, const char *text)
-{
- char *insText = (char *) "";
- int linesPadded = 0;
-
- /* Make sure start and end refer to complete lines, since the
- columnar delete and insert operations will replace whole lines */
- start = line_start(start);
- end = line_end(end);
-
- call_predelete_callbacks(start, end - start);
-
- /* If more lines will be deleted than inserted, pad the inserted text
- with newlines to make it as long as the number of deleted lines. This
- will indent all of the text to the right of the rectangle to the same
- column. If more lines will be inserted than deleted, insert extra
- lines in the buffer at the end of the rectangle to make room for the
- additional lines in "text" */
- int nInsertedLines = countLines(text);
- int nDeletedLines = count_lines(start, end);
- if (nInsertedLines < nDeletedLines) {
- int insLen = strlen(text);
- insText = (char *) malloc(insLen + nDeletedLines - nInsertedLines + 1);
- strcpy(insText, text);
- char *insPtr = insText + insLen;
- for (int i = 0; i < nDeletedLines - nInsertedLines; i++)
- *insPtr++ = '\n';
- *insPtr = '\0';
- } else if (nDeletedLines < nInsertedLines) {
- linesPadded = nInsertedLines - nDeletedLines;
- for (int i = 0; i < linesPadded; i++)
- insert_(end, "\n");
- }
-
- /* else nDeletedLines == nInsertedLines; */
- /* Save a copy of the text which will be modified for the modify CBs */
- const char *deletedText = text_range(start, end);
-
- /* Delete then insert */
- int insertDeleted, insertInserted, deleteInserted, hint;
- remove_rectangular_(start, end, rectStart, rectEnd, &deleteInserted,
- &hint);
- insert_column_(rectStart, start, insText, &insertDeleted,
- &insertInserted, &mCursorPosHint);
-
- /* Figure out how many chars were inserted and call modify callbacks */
- if (insertDeleted != deleteInserted + linesPadded)
- Fl::error
- ("Fl_Text_Buffer::replace_rectangular(): internal consistency check repl1 failed");
- call_modify_callbacks(start, end - start, insertInserted, 0,
- deletedText);
- free((void *) deletedText);
- if (nInsertedLines < nDeletedLines)
- free((void *) insText);
-}
-
-void Fl_Text_Buffer::remove_rectangular(int start, int end, int rectStart,
- int rectEnd)
-{
-
- start = line_start(start);
- end = line_end(end);
- call_predelete_callbacks(start, end - start);
- const char *deletedText = text_range(start, end);
- int nInserted;
- remove_rectangular_(start, end, rectStart, rectEnd, &nInserted,
- &mCursorPosHint);
- call_modify_callbacks(start, end - start, nInserted, 0, deletedText);
- free((void *) deletedText);
-}
-
-void Fl_Text_Buffer::clear_rectangular(int start, int end, int rectStart,
- int rectEnd)
-{
- int nLines = count_lines(start, end);
- char *newlineString = (char *) malloc(nLines + 1);
- int i;
- for (i = 0; i < nLines; i++)
- newlineString[i] = '\n';
- newlineString[i] = '\0';
- overlay_rectangular(start, rectStart, rectEnd, newlineString,
- NULL, NULL);
- free((void *) newlineString);
-}
-
-char *Fl_Text_Buffer::text_in_rectangle(int start, int end,
- int rectStart,
- int rectEnd) const {
- start = line_start(start);
- end = line_end(end);
- char *textOut = (char *) malloc((end - start) + 1);
- int lineStart = start;
- char *outPtr = textOut;
- int selLeft, selRight;
- while (lineStart <= end)
- {
- rectangular_selection_boundaries(lineStart, rectStart, rectEnd,
- &selLeft, &selRight);
- const char *textIn = text_range(selLeft, selRight);
- int len = selRight - selLeft;
- memcpy(outPtr, textIn, len);
- free((void *) textIn);
- outPtr += len;
- lineStart = line_end(selRight) + 1;
- *outPtr++ = '\n';
- } if (outPtr != textOut)
- outPtr--; /* don't leave trailing newline */
- *outPtr = '\0';
-
- /* If necessary, realign the tabs in the selection as if the text were
- positioned at the left margin */
- int len;
- char *retabbedStr = realignTabs(textOut, rectStart, 0, mTabDist,
- mUseTabs, &len);
- free((void *) textOut);
- return retabbedStr;
-}
+/*
+ Change the tab width. This will cause a couple of callbacks and a complete
+ redisplay.
+ Matt: I am not entirely sure why we need to trigger callbacks because
+ tabs are only a graphical hint, not changing any text at all, but I leave
+ this in here for back compatibility.
+ Unicode safe.
+ */
void Fl_Text_Buffer::tab_distance(int tabDist)
{
/* First call the pre-delete callbacks with the previous tab setting
@@ -641,6 +462,11 @@ void Fl_Text_Buffer::tab_distance(int tabDist)
free((void *) deletedText);
}
+
+/*
+ Select a range of text.
+ Unicode safe. Start and End must be at a character boundary.
+ */
void Fl_Text_Buffer::select(int start, int end)
{
Fl_Text_Selection oldSelection = mPrimary;
@@ -649,6 +475,11 @@ void Fl_Text_Buffer::select(int start, int end)
redisplay_selection(&oldSelection, &mPrimary);
}
+
+/*
+ Clear the primary selection.
+ Unicode safe.
+ */
void Fl_Text_Buffer::unselect()
{
Fl_Text_Selection oldSelection = mPrimary;
@@ -657,42 +488,51 @@ void Fl_Text_Buffer::unselect()
redisplay_selection(&oldSelection, &mPrimary);
}
-void Fl_Text_Buffer::select_rectangular(int start, int end, int rectStart,
- int rectEnd)
-{
- Fl_Text_Selection oldSelection = mPrimary;
- mPrimary.set_rectangular(start, end, rectStart, rectEnd);
- redisplay_selection(&oldSelection, &mPrimary);
-}
-
+/*
+ Return the primary selection range.
+ Unicode safe.
+ */
int Fl_Text_Buffer::selection_position(int *start, int *end)
{
return mPrimary.position(start, end);
}
-int Fl_Text_Buffer::selection_position(int *start, int *end,
- int *isRect, int *rectStart,
- int *rectEnd)
-{
- return mPrimary.position(start, end, isRect, rectStart, rectEnd);
-}
+/*
+ Return a copy of the selected text.
+ Unicode safe.
+ */
char *Fl_Text_Buffer::selection_text()
{
return selection_text_(&mPrimary);
}
+
+/*
+ Remove the selected text.
+ Unicode safe.
+ */
void Fl_Text_Buffer::remove_selection()
{
remove_selection_(&mPrimary);
}
+
+/*
+ Replace the selected text.
+ Unicode safe.
+ */
void Fl_Text_Buffer::replace_selection(const char *text)
{
replace_selection_(&mPrimary, text);
}
+
+/*
+ Select text.
+ Unicode safe. Start and End must be at a character boundary.
+ */
void Fl_Text_Buffer::secondary_select(int start, int end)
{
Fl_Text_Selection oldSelection = mSecondary;
@@ -701,6 +541,11 @@ void Fl_Text_Buffer::secondary_select(int start, int end)
redisplay_selection(&oldSelection, &mSecondary);
}
+
+/*
+ Deselect text.
+ Unicode safe.
+ */
void Fl_Text_Buffer::secondary_unselect()
{
Fl_Text_Selection oldSelection = mSecondary;
@@ -709,44 +554,51 @@ void Fl_Text_Buffer::secondary_unselect()
redisplay_selection(&oldSelection, &mSecondary);
}
-void Fl_Text_Buffer::secondary_select_rectangular(int start, int end,
- int rectStart,
- int rectEnd)
-{
- Fl_Text_Selection oldSelection = mSecondary;
- mSecondary.set_rectangular(start, end, rectStart, rectEnd);
- redisplay_selection(&oldSelection, &mSecondary);
-}
-
+/*
+ Return the selected range.
+ Unicode safe.
+ */
int Fl_Text_Buffer::secondary_selection_position(int *start, int *end)
{
return mSecondary.position(start, end);
}
-int Fl_Text_Buffer::secondary_selection_position(int *start, int *end,
- int *isRect,
- int *rectStart,
- int *rectEnd)
-{
- return mSecondary.position(start, end, isRect, rectStart, rectEnd);
-}
+/*
+ Return a copy of the text in this selection.
+ Unicode safe.
+ */
char *Fl_Text_Buffer::secondary_selection_text()
{
return selection_text_(&mSecondary);
}
+
+/*
+ Remove the selected text.
+ Unicode safe.
+ */
void Fl_Text_Buffer::remove_secondary_selection()
{
remove_selection_(&mSecondary);
}
+
+/*
+ Replace selected text.
+ Unicode safe.
+ */
void Fl_Text_Buffer::replace_secondary_selection(const char *text)
{
replace_selection_(&mSecondary, text);
}
+
+/*
+ Highlight a range of text.
+ Unicode safe. Start and End must be at a character boundary.
+ */
void Fl_Text_Buffer::highlight(int start, int end)
{
Fl_Text_Selection oldSelection = mHighlight;
@@ -755,6 +607,11 @@ void Fl_Text_Buffer::highlight(int start, int end)
redisplay_selection(&oldSelection, &mHighlight);
}
+
+/*
+ Remove text highlighting.
+ Unicode safe.
+ */
void Fl_Text_Buffer::unhighlight()
{
Fl_Text_Selection oldSelection = mHighlight;
@@ -763,32 +620,31 @@ void Fl_Text_Buffer::unhighlight()
redisplay_selection(&oldSelection, &mHighlight);
}
-void Fl_Text_Buffer::highlight_rectangular(int start, int end,
- int rectStart, int rectEnd)
-{
- Fl_Text_Selection oldSelection = mHighlight;
- mHighlight.set_rectangular(start, end, rectStart, rectEnd);
- redisplay_selection(&oldSelection, &mHighlight);
-}
-
+/*
+ Return position of highlight.
+ Unicode safe.
+ */
int Fl_Text_Buffer::highlight_position(int *start, int *end)
{
return mHighlight.position(start, end);
}
-int Fl_Text_Buffer::highlight_position(int *start, int *end,
- int *isRect, int *rectStart,
- int *rectEnd)
-{
- return mHighlight.position(start, end, isRect, rectStart, rectEnd);
-}
+/*
+ Return a copy of highlighted text.
+ Unicode safe.
+ */
char *Fl_Text_Buffer::highlight_text()
{
return selection_text_(&mHighlight);
}
+
+/*
+ Add a callback that is called whenever text is modified.
+ Unicode safe.
+ */
void Fl_Text_Buffer::add_modify_callback(Fl_Text_Modify_Cb bufModifiedCB,
void *cbArg)
{
@@ -810,8 +666,13 @@ void Fl_Text_Buffer::add_modify_callback(Fl_Text_Modify_Cb bufModifiedCB,
mCbArgs = newCBArgs;
}
-void Fl_Text_Buffer::
-remove_modify_callback(Fl_Text_Modify_Cb bufModifiedCB, void *cbArg)
+
+/*
+ Remove a callback.
+ Unicode safe.
+ */
+void Fl_Text_Buffer::remove_modify_callback(Fl_Text_Modify_Cb bufModifiedCB,
+ void *cbArg)
{
int i, toRemove = -1;
@@ -857,8 +718,13 @@ remove_modify_callback(Fl_Text_Modify_Cb bufModifiedCB, void *cbArg)
mCbArgs = newCBArgs;
}
-void Fl_Text_Buffer::
-add_predelete_callback(Fl_Text_Predelete_Cb bufPreDeleteCB, void *cbArg)
+
+/*
+ Add a callback that is called before deleting text.
+ Unicode safe.
+ */
+void Fl_Text_Buffer::add_predelete_callback(Fl_Text_Predelete_Cb bufPreDeleteCB,
+ void *cbArg)
{
Fl_Text_Predelete_Cb *newPreDeleteProcs =
new Fl_Text_Predelete_Cb[mNPredeleteProcs + 1];
@@ -878,8 +744,12 @@ add_predelete_callback(Fl_Text_Predelete_Cb bufPreDeleteCB, void *cbArg)
mPredeleteCbArgs = newCBArgs;
}
-void Fl_Text_Buffer::
-remove_predelete_callback(Fl_Text_Predelete_Cb bufPreDeleteCB, void *cbArg)
+
+/*
+ Remove a callback.
+ Unicode safe.
+ */
+void Fl_Text_Buffer::remove_predelete_callback(Fl_Text_Predelete_Cb bufPreDeleteCB, void *cbArg)
{
int i, toRemove = -1;
/* find the matching callback to remove */
@@ -926,156 +796,99 @@ remove_predelete_callback(Fl_Text_Predelete_Cb bufPreDeleteCB, void *cbArg)
mPredeleteCbArgs = newCBArgs;
}
+
+/*
+ Return a copy of the line that contains a given index.
+ Unicode safe. Pos must be at a character boundary.
+ */
char *Fl_Text_Buffer::line_text(int pos) const {
return text_range(line_start(pos), line_end(pos));
}
-int Fl_Text_Buffer::line_start(int pos) const {
+
+/*
+ Find the beginning of the line.
+ NOT UNICODE SAFE.
+ */
+int Fl_Text_Buffer::line_start(int pos) const
+{
+ // FIXME: this currently works for unicode, but will be very inefficent when findchar_backward is fixed.
if (!findchar_backward(pos, '\n', &pos))
return 0;
return pos + 1;
}
+
+/*
+ Find the end of the line.
+ NOT UNICODE SAFE.
+ */
int Fl_Text_Buffer::line_end(int pos) const {
+ // FIXME: this currently works for unicode, but will be very inefficent when findchar_forward is fixed.
if (!findchar_forward(pos, '\n', &pos))
pos = mLength;
return pos;
}
+
+/*
+ Find the beginning of a word.
+ NOT UNICODE SAFE.
+ */
int Fl_Text_Buffer::word_start(int pos) const {
// FIXME: character is ucs-4
- while (pos && (isalnum(character(pos)) || character(pos) == '_')) {
+ while (pos && (isalnum(char_at(pos)) || char_at(pos) == '_')) {
pos--;
}
// FIXME: character is ucs-4
- if (!(isalnum(character(pos)) || character(pos) == '_'))
+ if (!(isalnum(char_at(pos)) || char_at(pos) == '_'))
pos++;
return pos;
}
+
+/*
+ Find the end of a word.
+ NOT UNICODE SAFE.
+ */
int Fl_Text_Buffer::word_end(int pos) const {
// FIXME: character is ucs-4
- while (pos < length() && (isalnum(character(pos)) || character(pos) == '_'))
+ while (pos < length() && (isalnum(char_at(pos)) || char_at(pos) == '_'))
{
pos++;
} return pos;
}
-// Expand from the byte representation into some readable text.
-// Under unicode, this is not really needed because all characters should
-// be prinatble one way or the other. But since we use this to (badly) simulate
-// tabs, we can leave this here anyway.
-// - unicode ok
-int Fl_Text_Buffer::expand_character(int pos, int indent, char *outStr) const {
- const char *src = address(pos);
- return expand_character(src, indent, outStr, mTabDist);
-}
-
-
-// static function and counterpart to "character_width"
-// - unicode ok
-// FIXME: harmonise with new character_width(char*...) version
-//
-int Fl_Text_Buffer::expand_character(const char *src, int indent, char *outStr, int tabDist)
-{
- char c = *src;
- /* Convert tabs to spaces */
- if (c == '\t') {
- int nSpaces = tabDist - (indent % tabDist);
- for (int i = 0; i < nSpaces; i++)
- outStr[i] = ' ';
- return nSpaces;
- }
-
- /* Convert control codes to readable character sequences */
- if (((unsigned char) c) <= 31) {
- sprintf(outStr, "<%s>", ControlCodeTable[(unsigned char) c]);
- return strlen(outStr);
- } else if (c == 127) {
- sprintf(outStr, "<del>");
- return 5;
- } else if ((c & 0x80) && !(c & 0x40)) {
-#ifdef DEBUG
- fprintf(stderr, "%s:%d - Error in UTF-8 encoding!\n", __FILE__, __LINE__);
-#endif
- *outStr = c;
- return 1;
- } else if (c & 0x80) {
- int i, n = fl_utf8len(c);
- for (i=0; i<n; i++) *outStr++ = *src++;
- return n;
- }
-
- /* Otherwise, just return the character */
- *outStr = c;
- return 1;
-}
-
-
-// This function takes a character and optionally converts it into a little
-// string which will replace the character on screen. This function returns
-// the number of bytes in the replacement string, but *not* the number of
-// bytes in the original character!
-// - unicode ok
-int Fl_Text_Buffer::character_width(const char *src, int indent, int tabDist)
-{
- char c = *src;
- if ((c & 0x80) && (c & 0x40)) { // first byte of UTF-8 sequence
- int len = fl_utf8len(c);
- int ret = 0;
- unsigned int ucs = fl_utf8decode(src, src+len, &ret);
- int width = fl_wcwidth_(ucs); // FIXME
- // fprintf(stderr, "mk_wcwidth(%x) -> %d (%d, %d, %s)\n", ucs, width, len, ret, src);
- return width;
- }
- if ((c & 0x80) && !(c & 0x40)) { // other byte of UTF-8 sequence
- return 0;
- }
- return character_width(c, indent, tabDist);
-}
-
-// FIXME: merge the following with the char* version above.
-// but the question then is: how to reorganise expand_character()?
-//
-int Fl_Text_Buffer::character_width(const char c, int indent, int tabDist)
-{
- /* Note, this code must parallel that in Fl_Text_Buffer::ExpandCharacter */
- if (c == '\t') {
- return tabDist - (indent % tabDist);
- } else if (((unsigned char) c) <= 31) {
- return strlen(ControlCodeTable[(unsigned char) c]) + 2;
- } else if (c == 127) {
- return 5;
- } else if ((c & 0x80) && !(c & 0x40)) {
-#ifdef DEBUG
- fprintf(stderr, "%s:%d - Error in UTF-8 encoding!\n", __FILE__, __LINE__);
-#endif
- return 1;
- } else if (c & 0x80) {
- // return fl_utf8len(c);
- return 1;
- }
- return 1;
-}
-
+/*
+ Matt: I am not sure why we need this function. Does it still make sense in
+ the world of proportional characters?
+ */
int Fl_Text_Buffer::count_displayed_characters(int lineStartPos,
int targetPos) const
{
+ // TODO: is this function still needed? If it is, put this functionality in handle_vline?
int charCount = 0;
- char expandedChar[FL_TEXT_MAX_EXP_CHAR_LEN];
int pos = lineStartPos;
- while (pos < targetPos)
- charCount += expand_character(pos++, charCount, expandedChar);
+ while (pos < targetPos) {
+ int len = fl_utf8len(*address(pos));
+ charCount += 1;
+ pos += len;
+ }
return charCount;
}
+/*
+ Matt: I am not sure why we need this function. Does it still make sense in
+ the world of proportional characters?
+ */
// All values are number of bytes.
-// - unicode ok
+// - unicode ok?
int Fl_Text_Buffer::skip_displayed_characters(int lineStartPos, int nChars)
{
+ // FIXME: is this function still needed?
int pos = lineStartPos;
for (int charCount = 0; charCount < nChars && pos < mLength;) {
@@ -1083,12 +896,17 @@ int Fl_Text_Buffer::skip_displayed_characters(int lineStartPos, int nChars)
char c = *src;
if (c == '\n')
return pos;
- charCount += character_width(src, charCount, mTabDist);
+ charCount++;
pos += fl_utf8len(c);
}
return pos;
}
+
+/*
+ Count the number of newline characters between start and end.
+ Unicode safe. StartPos and endPos must be at a character boundary.
+ */
int Fl_Text_Buffer::count_lines(int startPos, int endPos) const {
int gapLen = mGapEnd - mGapStart;
int lineCount = 0;
@@ -1100,7 +918,8 @@ int Fl_Text_Buffer::count_lines(int startPos, int endPos) const {
return lineCount;
if (mBuf[pos++] == '\n')
lineCount++;
- } while (pos < mLength) {
+ }
+ while (pos < mLength) {
if (pos == endPos)
return lineCount;
if (mBuf[pos++ + gapLen] == '\n')
@@ -1109,6 +928,11 @@ int Fl_Text_Buffer::count_lines(int startPos, int endPos) const {
return lineCount;
}
+
+/*
+ Skip to the first character, n lines ahead.
+ Unicode safe. StartPos must be at a character boundary.
+ */
int Fl_Text_Buffer::skip_lines(int startPos, int nLines)
{
if (nLines == 0)
@@ -1134,6 +958,11 @@ int Fl_Text_Buffer::skip_lines(int startPos, int nLines)
return pos;
}
+
+/*
+ Skip to the first character, n lines back.
+ Unicode safe. StartPos must be at a character boundary.
+ */
int Fl_Text_Buffer::rewind_lines(int startPos, int nLines)
{
int pos = startPos - 1;
@@ -1159,10 +988,15 @@ int Fl_Text_Buffer::rewind_lines(int startPos, int nLines)
return 0;
}
+
+/*
+ Find a matching string in the buffer.
+ NOT TESTED FOR UNICODE.
+ */
int Fl_Text_Buffer::search_forward(int startPos, const char *searchString,
- int *foundPos,
- int matchCase) const
+ int *foundPos, int matchCase) const
{
+ // FIXME: Unicode?
if (!searchString)
return 0;
int bp;
@@ -1176,17 +1010,22 @@ int Fl_Text_Buffer::search_forward(int startPos, const char *searchString,
return 1;
}
// FIXME: character is ucs-4
- } while ((matchCase ? character(bp++) == (unsigned int)*sp++ :
- toupper(character(bp++)) == toupper(*sp++))
+ } while ((matchCase ? char_at(bp++) == *sp++ :
+ toupper(char_at(bp++)) == toupper(*sp++))
&& bp < length());
startPos++;
}
return 0;
}
+
+/*
+ Find a matching string in the buffer.
+ NOT TESTED FOR UNICODE.
+ */
int Fl_Text_Buffer::search_backward(int startPos, const char *searchString,
- int *foundPos,
- int matchCase) const {
+ int *foundPos, int matchCase) const {
+ // FIXME: Unicode?
if (!searchString)
return 0;
int bp;
@@ -1201,17 +1040,22 @@ int Fl_Text_Buffer::search_backward(int startPos, const char *searchString,
return 1;
}
// FIXME: character is ucs-4
- } while ((matchCase ? character(bp--) == (unsigned int)*sp-- :
- toupper(character(bp--)) == toupper(*sp--))
+ } while ((matchCase ? char_at(bp--) == *sp-- :
+ toupper(char_at(bp--)) == toupper(*sp--))
&& bp >= 0);
startPos--;
}
return 0;
}
-int Fl_Text_Buffer::findchars_forward(int startPos,
- const char *searchChars,
+
+/*
+ Find a matching string in the buffer.
+ NOT TESTED FOR UNICODE.
+ */
+int Fl_Text_Buffer::findchars_forward(int startPos, const char *searchChars,
int *foundPos) const {
+ // FIXME: unicode?
int gapLen = mGapEnd - mGapStart;
const char *c;
@@ -1238,9 +1082,14 @@ int Fl_Text_Buffer::findchars_forward(int startPos,
return 0;
}
-int Fl_Text_Buffer::findchars_backward(int startPos,
- const char *searchChars,
+
+/*
+ Find a matching string in the buffer.
+ NOT TESTED FOR UNICODE.
+ */
+int Fl_Text_Buffer::findchars_backward(int startPos, const char *searchChars,
int *foundPos) const {
+ // FIXME: Unicode
int gapLen = mGapEnd - mGapStart;
const char *c;
@@ -1272,6 +1121,11 @@ int Fl_Text_Buffer::findchars_backward(int startPos,
return 0;
}
+
+/*
+ Insert a string into the buffer.
+ Unicode safe. Pos must be at a character boundary. Text must be a correct utf8 string.
+ */
int Fl_Text_Buffer::insert_(int pos, const char *text)
{
int insertedLength = strlen(text);
@@ -1307,6 +1161,11 @@ int Fl_Text_Buffer::insert_(int pos, const char *text)
return insertedLength;
}
+
+/*
+ Remove a string from the buffer.
+ Unicode safe. Start and end must be at a character boundary.
+ */
void Fl_Text_Buffer::remove_(int start, int end)
{
/* if the gap is not contiguous to the area to remove, move it there */
@@ -1354,458 +1213,23 @@ void Fl_Text_Buffer::remove_(int start, int end)
update_selections(start, end - start, 0);
}
-void Fl_Text_Buffer::insert_column_(int column, int startPos,
- const char *insText, int *nDeleted,
- int *nInserted, int *endPos)
-{
- if (column < 0)
- column = 0;
-
- /* Allocate a buffer for the replacement string large enough to hold
- possibly expanded tabs in both the inserted text and the replaced
- area, as well as per line: 1) an additional 2*FL_TEXT_MAX_EXP_CHAR_LEN
- characters for padding where tabs and control characters cross the
- column of the selection, 2) up to "column" additional spaces per
- line for padding out to the position of "column", 3) padding up
- to the width of the inserted text if that must be padded to align
- the text beyond the inserted column. (Space for additional
- newlines if the inserted text extends beyond the end of the buffer
- is counted with the length of insText) */
- int start = line_start(startPos);
- int nLines = countLines(insText) + 1;
- int insWidth = textWidth(insText, mTabDist); // this function probably returns a useless value
- int end = line_end(skip_lines(start, nLines - 1));
- int expReplLen, expInsLen, len, endOffset;
- const char *replText = text_range(start, end);
- char *expText = expandTabs(replText, 0, mTabDist, &expReplLen);
- free((void *) replText);
- free((void *) expText);
- expText = expandTabs(insText, 0, mTabDist, &expInsLen);
- free((void *) expText);
- char *outStr = (char *) malloc(expReplLen + expInsLen +
- nLines * (column + insWidth +
- FL_TEXT_MAX_EXP_CHAR_LEN) + 1);
-
- /* Loop over all lines in the buffer between start and end removing the
- text between rectStart and rectEnd and padding appropriately. Trim
- trailing space from line (whitespace at the ends of lines otherwise
- tends to multiply, since additional padding is added to maintain it */
- char *outPtr = outStr, *insLine;
- const char *insPtr = insText, *line;
- for (int lineStart = start, lineEnd;;) {
- lineEnd = line_end(lineStart);
- line = text_range(lineStart, lineEnd);
- insLine = copyLine(insPtr, &len);
- insPtr += len;
- insertColInLine(line, insLine, column, insWidth, mTabDist,
- mUseTabs, outPtr, &len, &endOffset);
- free((void *) line);
- free((void *) insLine);
- for (const char *c = outPtr + len - 1; c > outPtr && isspace(*c); c--)
- len--;
- outPtr += len;
- *outPtr++ = '\n';
- lineStart = lineEnd < mLength ? lineEnd + 1 : mLength;
- if (*insPtr == '\0')
- break;
- insPtr++;
- }
- if (outPtr != outStr)
- outPtr--; /* trim back off extra newline */
- *outPtr = '\0';
- /* replace the text between start and end with the new stuff */
- remove_(start, end);
- insert_(start, outStr);
- *nInserted = outPtr - outStr;
- *nDeleted = end - start;
- *endPos = start + (outPtr - outStr) - len + endOffset;
- free((void *) outStr);
-}
-
-void Fl_Text_Buffer::remove_rectangular_(int start, int end, int rectStart,
- int rectEnd, int *replaceLen,
- int *endPos)
-{
- /* allocate a buffer for the replacement string large enough to hold
- possibly expanded tabs as well as an additional FL_TEXT_MAX_EXP_CHAR_LEN * 2
- characters per line for padding where tabs and control characters cross
- the edges of the selection */
- start = line_start(start);
- end = line_end(end);
- int nLines = count_lines(start, end) + 1;
- const char *s = text_range(start, end);
- int len;
- char *expText = expandTabs(s, 0, mTabDist, &len);
- free((void *) s);
- free((void *) expText);
- char *outStr =
- (char *) malloc(len + nLines * FL_TEXT_MAX_EXP_CHAR_LEN * 2 + 1);
-
- /* loop over all lines in the buffer between start and end removing
- the text between rectStart and rectEnd and padding appropriately */
- int endOffset = 0;
- char *outPtr = outStr;
- const char *line;
- for (int lineStart = start, lineEnd;
- lineStart <= mLength && lineStart <= end;) {
- lineEnd = line_end(lineStart);
- line = text_range(lineStart, lineEnd);
- deleteRectFromLine(line, rectStart, rectEnd, mTabDist,
- mUseTabs, outPtr, &len, &endOffset);
- free((void *) line);
- outPtr += len;
- *outPtr++ = '\n';
- lineStart = lineEnd + 1;
- }
- if (outPtr != outStr)
- outPtr--; /* trim back off extra newline */
- *outPtr = '\0';
-
- /* replace the text between start and end with the newly created string */
- remove_(start, end);
- insert_(start, outStr);
- *replaceLen = outPtr - outStr;
- *endPos = start + (outPtr - outStr) - len + endOffset;
- free((void *) outStr);
-}
-
-void Fl_Text_Buffer::overlay_rectangular_(int startPos, int rectStart,
- int rectEnd, const char *insText,
- int *nDeleted, int *nInserted,
- int *endPos)
-{
-
- /* Allocate a buffer for the replacement string large enough to hold
- possibly expanded tabs in the inserted text, as well as per line: 1)
- an additional 2*FL_TEXT_MAX_EXP_CHAR_LEN characters for padding where tabs
- and control characters cross the column of the selection, 2) up to
- "column" additional spaces per line for padding out to the position
- of "column", 3) padding up to the width of the inserted text if that
- must be padded to align the text beyond the inserted column. (Space
- for additional newlines if the inserted text extends beyond the end
- of the buffer is counted with the length of insText) */
- int start = line_start(startPos);
- int nLines = countLines(insText) + 1;
- int end = line_end(skip_lines(start, nLines - 1)), expInsLen;
- char *expText = expandTabs(insText, 0, mTabDist, &expInsLen);
- free((void *) expText);
- char *outStr = (char *) malloc(end - start + expInsLen +
- nLines * (rectEnd +
- FL_TEXT_MAX_EXP_CHAR_LEN) + 1);
-
- /* Loop over all lines in the buffer between start and end overlaying the
- text between rectStart and rectEnd and padding appropriately. Trim
- trailing space from line (whitespace at the ends of lines otherwise
- tends to multiply, since additional padding is added to maintain it */
- int len, endOffset;
- char *outPtr = outStr, *insLine;
- const char *insPtr = insText, *line;
- for (int lineStart = start, lineEnd;;) {
- lineEnd = line_end(lineStart);
- line = text_range(lineStart, lineEnd);
- insLine = copyLine(insPtr, &len);
- insPtr += len;
- overlayRectInLine(line, insLine, rectStart, rectEnd, mTabDist,
- mUseTabs, outPtr, &len, &endOffset);
- free((void *) line);
- free((void *) insLine);
- for (const char *c = outPtr + len - 1; c > outPtr && isspace(*c); c--)
- len--;
- outPtr += len;
- *outPtr++ = '\n';
- lineStart = lineEnd < mLength ? lineEnd + 1 : mLength;
- if (*insPtr == '\0')
- break;
- insPtr++;
- }
- if (outPtr != outStr)
- outPtr--; /* trim back off extra newline */
- *outPtr = '\0';
-
- /* replace the text between start and end with the new stuff */
- remove_(start, end);
- insert_(start, outStr);
- *nInserted = outPtr - outStr;
- *nDeleted = end - start;
- *endPos = start + (outPtr - outStr) - len + endOffset;
- free((void *) outStr);
-}
-
/*
- Inserts characters from single-line string \p insLine in single-line string
- \p line at \p column, leaving \p insWidth space before continuing line.
- \p outLen returns the number of characters written to \p outStr, \p endOffset
- returns the number of characters from the beginning of the string to
- the right edge of the inserted text (as a hint for routines which need
- to position the cursor).
+ simple setter.
+ Unicode safe. Start and end must be at a character boundary.
*/
-static void insertColInLine(const char *line, char *insLine, int column,
- int insWidth, int tabDist, int useTabs,
- char *outStr, int *outLen,
- int *endOffset)
-{
- /* copy the line up to "column" */
- char *outPtr = outStr;
- int indent = 0, len;
- const char *linePtr;
-
- for (linePtr = line; *linePtr != '\0'; linePtr++) {
- len = Fl_Text_Buffer::character_width(linePtr, indent, tabDist);
- if (indent + len > column)
- break;
- indent += len;
- *outPtr++ = *linePtr;
- }
-
- /* If "column" falls in the middle of a character, and the character is a
- tab, leave it off and leave the indent short and it will get padded
- later. If it's a control character, insert it and adjust indent
- accordingly. */
- int postColIndent;
- if (indent < column && *linePtr != '\0') {
- postColIndent = indent + len;
- if (*linePtr == '\t')
- linePtr++;
- else {
- *outPtr++ = *linePtr++;
- indent += len;
- }
- } else
- postColIndent = indent;
-
- /* If there's no text after the column and no text to insert, that's all */
- if (*insLine == '\0' && *linePtr == '\0') {
- *outLen = *endOffset = outPtr - outStr;
- return;
- }
-
- /* pad out to column if text is too short */
- if (indent < column) {
- addPadding(outPtr, indent, column, tabDist, useTabs, &len);
- outPtr += len;
- indent = column;
- }
-
- /* Copy the text from "insLine" (if any), recalculating the tabs as if
- the inserted string began at column 0 to its new column destination */
- if (*insLine != '\0') {
- char *retabbedStr = realignTabs(insLine, 0, indent, tabDist, useTabs,
- &len);
- for (const char *c = retabbedStr; *c != '\0'; c++) {
- *outPtr++ = *c;
- len = Fl_Text_Buffer::character_width(c, indent, tabDist);
- indent += len;
- }
- free((void *) retabbedStr);
- }
-
- /* If the original line did not extend past "column", that's all */
- if (*linePtr == '\0') {
- *outLen = *endOffset = outPtr - outStr;
- return;
- }
-
- /* Pad out to column + width of inserted text + (additional original
- offset due to non-breaking character at column) */
- int toIndent = column + insWidth + postColIndent - column;
- addPadding(outPtr, indent, toIndent, tabDist, useTabs, &len);
- outPtr += len;
- indent = toIndent;
-
- /* realign tabs for text beyond "column" and write it out */
- char *retabbedStr = realignTabs(linePtr, postColIndent, indent, tabDist,
- useTabs, &len);
- strcpy(outPtr, retabbedStr);
- free((void *) retabbedStr);
- *endOffset = outPtr - outStr;
- *outLen = (outPtr - outStr) + len;
-}
-
-/**
- Removes characters in single-line string \p line between displayed positions
- \p rectStart and \p rectEnd, and write the result to \p outStr, which is
- assumed to be large enough to hold the returned string. Note that in
- certain cases, it is possible for the string to get longer due to
- expansion of tabs. \p endOffset returns the number of characters from
- the beginning of the string to the point where the characters were
- deleted (as a hint for routines which need to position the cursor).
- */
-static void deleteRectFromLine(const char *line, int rectStart,
- int rectEnd, int tabDist, int useTabs,
- char *outStr,
- int *outLen, int *endOffset)
-{
-
- /* copy the line up to rectStart */
- char *outPtr = outStr;
- int indent = 0, len;
- const char *c;
- for (c = line; *c != '\0'; c++) {
- if (indent > rectStart)
- break;
- len = Fl_Text_Buffer::character_width(c, indent, tabDist);
- if (indent + len > rectStart && (indent == rectStart || *c == '\t'))
- break;
- indent += len;
- *outPtr++ = *c;
- }
- int preRectIndent = indent;
-
- /* skip the characters between rectStart and rectEnd */
- for (; *c != '\0' && indent < rectEnd; c++)
- indent += Fl_Text_Buffer::character_width(c, indent, tabDist);
- int postRectIndent = indent;
-
- /* If the line ended before rectEnd, there's nothing more to do */
- if (*c == '\0') {
- *outPtr = '\0';
- *outLen = *endOffset = outPtr - outStr;
- return;
- }
-
- /* fill in any space left by removed tabs or control characters
- which straddled the boundaries */
- indent = max(rectStart + postRectIndent - rectEnd, preRectIndent);
- addPadding(outPtr, preRectIndent, indent, tabDist, useTabs, &len);
- outPtr += len;
-
- /* Copy the rest of the line. If the indentation has changed, preserve
- the position of non-whitespace characters by converting tabs to
- spaces, then back to tabs with the correct offset */
- char *retabbedStr =
- realignTabs(c, postRectIndent, indent, tabDist, useTabs, &len);
- strcpy(outPtr, retabbedStr);
- free((void *) retabbedStr);
- *endOffset = outPtr - outStr;
- *outLen = (outPtr - outStr) + len;
-}
-
-/**
- Overlay characters from single-line string \p insLine on single-line string
- \p line between displayed character offsets \p rectStart and \p rectEnd.
- \p outLen returns the number of characters written to \p outStr, \p endOffset
- returns the number of characters from the beginning of the string to
- the right edge of the inserted text (as a hint for routines which need
- to position the cursor).
- */
-static void overlayRectInLine(const char *line, char *insLine,
- int rectStart, int rectEnd, int tabDist,
- int useTabs, char *outStr,
- int *outLen, int *endOffset)
-{
- /* copy the line up to "rectStart" */
- char *outPtr = outStr;
- int inIndent = 0, outIndent = 0, len;
- const char *linePtr = line;
-
- for (; *linePtr != '\0'; linePtr++) {
- len = Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
- if (inIndent + len > rectStart)
- break;
- inIndent += len;
- outIndent += len;
- *outPtr++ = *linePtr;
- }
-
- /* If "rectStart" falls in the middle of a character, and the character
- is a tab, leave it off and leave the outIndent short and it will get
- padded later. If it's a control character, insert it and adjust
- outIndent accordingly. */
- if (inIndent < rectStart && *linePtr != '\0') {
- if (*linePtr == '\t') {
- linePtr++;
- inIndent += len;
- } else {
- *outPtr++ = *linePtr++;
- outIndent += len;
- inIndent += len;
- }
- }
-
- /* skip the characters between rectStart and rectEnd */
- int postRectIndent = rectEnd;
- for (; *linePtr != '\0'; linePtr++) {
- inIndent += Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
- if (inIndent >= rectEnd) {
- linePtr++;
- postRectIndent = inIndent;
- break;
- }
- }
-
- /* If there's no text after rectStart and no text to insert, that's all */
- if (*insLine == '\0' && *linePtr == '\0') {
- *outLen = *endOffset = outPtr - outStr;
- return;
- }
-
- /* pad out to rectStart if text is too short */
- if (outIndent < rectStart) {
- addPadding(outPtr, outIndent, rectStart, tabDist, useTabs, &len);
- outPtr += len;
- }
- outIndent = rectStart;
-
- /* Copy the text from "insLine" (if any), recalculating the tabs as if
- the inserted string began at column 0 to its new column destination */
- if (*insLine != '\0') {
- char *retabbedStr =
- realignTabs(insLine, 0, rectStart, tabDist, useTabs, &len);
- for (const char *c = retabbedStr; *c != '\0'; c++) {
- *outPtr++ = *c;
- len = Fl_Text_Buffer::character_width(c, outIndent, tabDist);
- outIndent += len;
- }
- free((void *) retabbedStr);
- }
-
- /* If the original line did not extend past "rectStart", that's all */
- if (*linePtr == '\0') {
- *outLen = *endOffset = outPtr - outStr;
- return;
- }
-
- /* Pad out to rectEnd + (additional original offset
- due to non-breaking character at right boundary) */
- addPadding(outPtr, outIndent, postRectIndent, tabDist, useTabs, &len);
- outPtr += len;
- outIndent = postRectIndent;
-
- /* copy the text beyond "rectEnd" */
- strcpy(outPtr, linePtr);
- *endOffset = outPtr - outStr;
- *outLen = (outPtr - outStr) + strlen(linePtr);
-}
-
-
-// simple setter
-// Unicode safe
void Fl_Text_Selection::set(int startpos, int endpos)
{
mSelected = startpos != endpos;
- mRectangular = 0;
mStart = min(startpos, endpos);
mEnd = max(startpos, endpos);
}
-// simple setter
-// Unicode safe
-void Fl_Text_Selection::set_rectangular(int startpos, int endpos,
- int rectStart, int rectEnd)
-{
- mSelected = rectStart < rectEnd;
- mRectangular = 1;
- mStart = startpos;
- mEnd = endpos;
- mRectStart = rectStart;
- mRectEnd = rectEnd;
-}
-
-
-// simple getter
-// Unicode safe
+/*
+ simple getter.
+ Unicode safe. Start and end will be at a character boundary.
+ */
int Fl_Text_Selection::position(int *startpos, int *endpos) const {
if (!mSelected)
return 0;
@@ -1816,83 +1240,65 @@ int Fl_Text_Selection::position(int *startpos, int *endpos) const {
}
-// simple getter
-// Unicode safe
-int Fl_Text_Selection::position(int *startpos, int *endpos,
- int *isRect, int *rectStart,
- int *rectEnd) const {
- if (!mSelected)
- return 0;
- *isRect = mRectangular;
- *startpos = mStart;
- *endpos = mEnd;
- if (mRectangular)
- {
- *rectStart = mRectStart;
- *rectEnd = mRectEnd;
+/*
+ Return if a position is inside the eselected area.
+ Unicode safe. Pos must be at a character boundary.
+ */
+int Fl_Text_Selection::includes(int pos) const {
+ return (selected() && pos >= start() && pos < end() );
}
- return 1;
-}
-
-// unicode safe
-int Fl_Text_Selection::includes(int pos, int lineStartPos, int dispIndex) const {
- return (selected()
- && ( (!rectangular() && pos >= start() && pos < end())
- || (rectangular() && pos >= start() && lineStartPos <= end()
- && dispIndex >= rect_start() && dispIndex < rect_end()
- )
- )
- );
-}
+/*
+ Return a duplicate of the selected text, or an empty string.
+ Unicode safe.
+ */
char *Fl_Text_Buffer::selection_text_(Fl_Text_Selection * sel) const {
- int start, end, isRect, rectStart, rectEnd;
+ int start, end;
/* If there's no selection, return an allocated empty string */
- if (!sel->position(&start, &end, &isRect, &rectStart, &rectEnd))
+ if (!sel->position(&start, &end))
{
char *s = (char *) malloc(1);
*s = '\0';
return s;
}
- /* If the selection is not rectangular, return the selected range */
- if (isRect)
- return text_in_rectangle(start, end, rectStart, rectEnd);
- else
+ /* Return the selected range */
return text_range(start, end);
}
+
+/*
+ Remove the selected text.
+ Unicode safe.
+ */
void Fl_Text_Buffer::remove_selection_(Fl_Text_Selection * sel)
{
- int start, end, isRect, rectStart, rectEnd;
+ int start, end;
- if (!sel->position(&start, &end, &isRect, &rectStart, &rectEnd))
+ if (!sel->position(&start, &end))
return;
- if (isRect)
- remove_rectangular(start, end, rectStart, rectEnd);
- else {
remove(start, end);
//undoyankcut = undocut;
}
-}
+/*
+ Replace selection with text.
+ Unicode safe.
+ */
void Fl_Text_Buffer::replace_selection_(Fl_Text_Selection * sel,
const char *text)
{
Fl_Text_Selection oldSelection = *sel;
/* If there's no selection, return */
- int start, end, isRect, rectStart, rectEnd;
- if (!sel->position(&start, &end, &isRect, &rectStart, &rectEnd))
+ int start, end;
+ if (!sel->position(&start, &end))
return;
/* Do the appropriate type of replace */
- if (isRect)
- replace_rectangular(start, end, rectStart, rectEnd, text);
- else
replace(start, end, text);
/* Unselect (happens automatically in BufReplace, but BufReplaceRect
@@ -1901,43 +1307,35 @@ void Fl_Text_Buffer::replace_selection_(Fl_Text_Selection * sel,
redisplay_selection(&oldSelection, sel);
}
-static void addPadding(char *string, int startIndent, int toIndent,
- int tabDist, int useTabs, int *charsAdded)
-{
- int indent = startIndent, len;
- char *outPtr = string;
-
- if (useTabs) {
- while (indent < toIndent) {
- //static char t = '\t';
- len = Fl_Text_Buffer::character_width("\t", indent, tabDist);
- if (len > 1 && indent + len <= toIndent) {
- *outPtr++ = '\t';
- indent += len;
- } else {
- *outPtr++ = ' ';
- indent++;
- }
- }
- } else {
- while (indent < toIndent) {
- *outPtr++ = ' ';
- indent++;
- }
- }
- *charsAdded = outPtr - string;
-}
-
+
+/*
+ Call all callbacks.
+ Unicode safe.
+ */
void Fl_Text_Buffer::call_modify_callbacks(int pos, int nDeleted,
int nInserted, int nRestyled,
const char *deletedText) const {
for (int i = 0; i < mNModifyProcs; i++)
(*mModifyProcs[i]) (pos, nInserted, nDeleted, nRestyled,
deletedText, mCbArgs[i]);
-} void Fl_Text_Buffer::call_predelete_callbacks(int pos, int nDeleted) const {
+}
+
+
+/*
+ Call all callbacks.
+ Unicode safe.
+ */
+void Fl_Text_Buffer::call_predelete_callbacks(int pos, int nDeleted) const {
for (int i = 0; i < mNPredeleteProcs; i++)
(*mPredeleteProcs[i]) (pos, nDeleted, mPredeleteCbArgs[i]);
-} void Fl_Text_Buffer::redisplay_selection(Fl_Text_Selection *
+}
+
+
+/*
+ Redisplay a new selected area.
+ Unicode safe.
+ */
+void Fl_Text_Buffer::redisplay_selection(Fl_Text_Selection *
oldSelection,
Fl_Text_Selection *
newSelection) const
@@ -1952,10 +1350,6 @@ void Fl_Text_Buffer::call_modify_callbacks(int pos, int nDeleted,
newStart = newSelection->mStart;
oldEnd = oldSelection->mEnd;
newEnd = newSelection->mEnd;
- if (oldSelection->mRectangular)
- oldEnd++;
- if (newSelection->mRectangular)
- newEnd++;
/* If the old or new selection is unselected, just redisplay the
single area that is (was) selected and return */
@@ -1971,20 +1365,6 @@ void Fl_Text_Buffer::call_modify_callbacks(int pos, int nDeleted,
return;
}
- /* If the selection changed from normal to rectangular or visa versa, or
- if a rectangular selection changed boundaries, redisplay everything */
- if ((oldSelection->mRectangular && !newSelection->mRectangular) ||
- (!oldSelection->mRectangular && newSelection->mRectangular) ||
- (oldSelection->mRectangular && ((oldSelection->mRectStart !=
- newSelection->mRectStart)
- || (oldSelection->mRectEnd !=
- newSelection->mRectEnd)))) {
- call_modify_callbacks(min(oldStart, newStart), 0, 0,
- max(oldEnd, newEnd) - min(oldStart,
- newStart), NULL);
- return;
- }
-
/* If the selections are non-contiguous, do two separate updates
and return */
if (oldEnd < newStart || newEnd < oldStart) {
@@ -2006,6 +1386,11 @@ void Fl_Text_Buffer::call_modify_callbacks(int pos, int nDeleted,
call_modify_callbacks(ch2Start, 0, 0, ch2End - ch2Start, NULL);
}
+
+/*
+ Move the gap around without changing buffer content.
+ Unicode safe. Pos must be at a character boundary.
+ */
void Fl_Text_Buffer::move_gap(int pos)
{
int gapLen = mGapEnd - mGapStart;
@@ -2018,6 +1403,11 @@ void Fl_Text_Buffer::move_gap(int pos)
mGapStart += pos - mGapStart;
}
+
+/*
+ Create a larger gap.
+ Unicode safe. Start must be at a character boundary.
+ */
void Fl_Text_Buffer::reallocate_with_gap(int newGapStart, int newGapLen)
{
char *newBuf = (char *) malloc(mLength + newGapLen);
@@ -2040,15 +1430,13 @@ void Fl_Text_Buffer::reallocate_with_gap(int newGapStart, int newGapLen)
mBuf = newBuf;
mGapStart = newGapStart;
mGapEnd = newGapEnd;
-#ifdef PURIFY
- {
- int i;
- for (i = mGapStart; i < mGapEnd; i++)
- mBuf[i] = '.';
}
-#endif
-}
+
+/*
+ Update selection range if characers were inserted.
+ Unicode safe. Pos must be at a character boundary.
+ */
void Fl_Text_Buffer::update_selections(int pos, int nDeleted,
int nInserted)
{
@@ -2061,6 +1449,7 @@ void Fl_Text_Buffer::update_selections(int pos, int nDeleted,
// unicode safe, assuming the arguments are on character boundaries
void Fl_Text_Selection::update(int pos, int nDeleted, int nInserted)
{
+ // FIXME: check if this is safe when seletion crosses selction boundaries
if (!mSelected || pos > mEnd)
return;
if (pos + nDeleted <= mStart) {
@@ -2080,283 +1469,69 @@ void Fl_Text_Selection::update(int pos, int nDeleted, int nInserted)
}
}
-int Fl_Text_Buffer::findchar_forward(int startPos, char searchChar,
- int *foundPos) const {
- if (startPos < 0 || startPos >= mLength)
+
+/*
+ Find a UCS-4 character.
+ Unicode safe. StartPos must be at a charcter boundary, searchChar is UCS-4 encoded.
+ */
+int Fl_Text_Buffer::findchar_forward(int startPos, unsigned searchChar,
+ int *foundPos) const
+ {
+ if (startPos >= mLength)
{
*foundPos = mLength;
return 0;
}
- int pos = startPos;
- while (pos < mGapStart) {
- if (mBuf[pos] == searchChar) {
- *foundPos = pos;
- return 1;
- }
- pos++;
- }
+ if (startPos<0)
+ startPos = 0;
- for (int gapLen = mGapEnd - mGapStart; pos < mLength; pos++) {
- if (mBuf[pos + gapLen] == searchChar) {
- *foundPos = pos;
+ // TODO: for performance reasons, we can re-insert the ASCII search here which is about three times as fast if searchChar is <128
+
+ for ( ; startPos<mLength; startPos = next_char(startPos)) {
+ if (searchChar == char_at(startPos)) {
+ *foundPos = startPos;
return 1;
}
}
+
*foundPos = mLength;
return 0;
}
-int Fl_Text_Buffer::findchar_backward(int startPos, char searchChar,
- int *foundPos) const {
- if (startPos <= 0 || startPos > mLength)
- {
+/*
+ Find a UCS-4 character.
+ Unicode safe. StartPos must be at a charcter boundary, searchChar is UCS-4 encoded.
+ */
+int Fl_Text_Buffer::findchar_backward(int startPos, unsigned searchChar,
+ int *foundPos) const {
+ if (startPos <= 0) {
*foundPos = 0;
return 0;
}
- int pos = startPos - 1;
- for (int gapLen = mGapEnd - mGapStart; pos >= mGapStart; pos--) {
- if (mBuf[pos + gapLen] == searchChar) {
- *foundPos = pos;
- return 1;
- }
- }
+ if (startPos > mLength)
+ startPos = mLength;
+
+ // TODO: for performance reasons, we can re-insert the ASCII search here which is about three times as fast if searchChar is <128
- for (; pos >= 0; pos--) {
- if (mBuf[pos] == searchChar) {
- *foundPos = pos;
+ for (startPos = prev_char(startPos); startPos>=0; startPos = prev_char(startPos)) {
+ if (searchChar == char_at(startPos)) {
+ *foundPos = startPos;
return 1;
}
}
+
*foundPos = 0;
return 0;
}
-/*
- Copies from \p text to end up to but not including newline (or end of \p text)
- and return the copy as the function value, and the length of the line in
- \p lineLen
- */
-static char *copyLine(const char *text, int *lineLen)
-{
- int len = 0;
-
- for (const char *c = text; *c != '\0' && *c != '\n'; c++)
- len++;
- char *outStr = (char *) malloc(len + 1);
- strlcpy(outStr, text, len + 1);
- *lineLen = len;
- return outStr;
-}
-
-/*
- Counts the number of newlines in a null-terminated text string.
- Unicode tested.
- */
-static int countLines(const char *string)
-{
- int lineCount = 0;
- for (const char *c = string; *c != '\0'; c++)
- if (*c == '\n')
- lineCount++;
- return lineCount;
-}
-
/*
- Measures the width in displayed characters of string \p text
+ Insert text from a file.
+ Unicode safe. Inout must be correct utf8!
*/
-static int textWidth(const char *text, int tabDist)
-{
- int width = 0, maxWidth = 0;
-
- // HUH? Why is "c" incremented? Shouldn't "text" be incrmented?
- // FIXME: increment is wrong!
- for (const char *c = text; *c != '\0'; c++) {
- if (*c == '\n') {
- if (width > maxWidth)
- maxWidth = width;
- width = 0;
- } else
- width += Fl_Text_Buffer::character_width(c, width, tabDist);
- }
- if (width > maxWidth)
- return width;
- return maxWidth;
-}
-
-void Fl_Text_Buffer::rectangular_selection_boundaries(int lineStartPos,
- int rectStart,
- int rectEnd,
- int *selStart,
- int *selEnd) const
-{
- int pos, width, indent = 0;
- char c;
-
- /* find the start of the selection */
- for (pos = lineStartPos; pos < mLength; pos++)
- {
- // FIXME: character is ucs-4
- c = character(pos);
- if (c == '\n')
- break;
- width =
- Fl_Text_Buffer::character_width(&c, indent, mTabDist); // FIXME: c is not unicode
- if (indent + width > rectStart) {
- if (indent != rectStart && c != '\t') {
- pos++;
- indent += width;
- }
- break;
- }
- indent += width;
- }
- *selStart = pos;
-
- /* find the end */
- for (; pos < mLength; pos++) {
- // FIXME: character is ucs-4
- c = character(pos);
- if (c == '\n')
- break;
- width =
- Fl_Text_Buffer::character_width(&c, indent, mTabDist); // FIXME: c is not unicode
- indent += width;
- if (indent > rectEnd) {
- if (indent - width != rectEnd && c != '\t')
- pos++;
- break;
- }
- }
- *selEnd = pos;
-}
-
-/*
- Adjust the space and tab characters from string \p text so that non-white
- characters remain stationary when the text is shifted from starting at
- \p origIndent to starting at \p newIndent. Returns an allocated string
- which must be freed by the caller with XtFree.
- */
-static char *realignTabs(const char *text, int origIndent, int newIndent,
- int tabDist, int useTabs, int *newLength)
-{
- /* If the tabs settings are the same, retain original tabs */
- int len;
- char *outStr;
- if (origIndent % tabDist == newIndent % tabDist) {
- len = strlen(text);
- outStr = (char *) malloc(len + 1);
- strcpy(outStr, text);
- *newLength = len;
- return outStr;
- }
-
- /* If the tab settings are not the same, brutally convert tabs to
- spaces, then back to tabs in the new position */
- char *expStr = expandTabs(text, origIndent, tabDist, &len);
- if (!useTabs) {
- *newLength = len;
- return expStr;
- }
- outStr =
- unexpandTabs(expStr, newIndent, tabDist, newLength);
- free((void *) expStr);
- return outStr;
-}
-
-/*
- Expand tabs to spaces for a block of text. The additional parameter
- \p startIndent if nonzero, indicates that the text is a rectangular selection
- beginning at column \p startIndent
- */
-static char *expandTabs(const char *text, int startIndent, int tabDist, int *newLen)
-{
- /* rehearse the expansion to figure out length for output string */
- int indent = startIndent, len, outLen = 0;
- const char *c;
- for (c = text; *c != '\0'; c++) {
- if (*c == '\t') {
- len =
- Fl_Text_Buffer::character_width(c, indent, tabDist);
- outLen += len;
- indent += len;
- } else if (*c == '\n') {
- indent = startIndent;
- outLen++;
- } else {
- // FIXME: character_width does not return number of bytes for UTF-8!
- indent +=
- Fl_Text_Buffer::character_width(c, indent, tabDist);
- outLen++;
- }
- }
-
- /* do the expansion */
- char *outStr = (char *) malloc(outLen + 1);
- char *outPtr = outStr;
- indent = startIndent;
- for (c = text; *c != '\0'; c++) {
- if (*c == '\t') {
- len =
- Fl_Text_Buffer::expand_character(c, indent, outPtr, tabDist);
- outPtr += len;
- indent += len;
- } else if (*c == '\n') {
- indent = startIndent;
- *outPtr++ = *c;
- } else {
- // FIXME: character_width does not return number of bytes for UTF-8!
- indent +=
- Fl_Text_Buffer::character_width(c, indent, tabDist);
- *outPtr++ = *c;
- }
- }
- outStr[outLen] = '\0';
- *newLen = outLen;
- return outStr;
-}
-
-/*
- Convert sequences of spaces into tabs. The threshold for conversion is
- when 3 or more spaces can be converted into a single tab, this avoids
- converting double spaces after a period withing a block of text.
- */
-static char *unexpandTabs(char *text, int startIndent, int tabDist, int *newLen)
-{
- char expandedChar[FL_TEXT_MAX_EXP_CHAR_LEN];
- char *outStr = (char *) malloc(strlen(text) + 1);
- char *outPtr = outStr;
- int indent = startIndent, len;
-
- for (const char *c = text; *c != '\0';) {
- if (*c == ' ') {
- static char tab = '\t';
- len =
- Fl_Text_Buffer::expand_character(&tab, indent, expandedChar, tabDist);
- if (len >= 3 && !strncmp(c, expandedChar, len)) {
- c += len;
- *outPtr++ = '\t';
- indent += len;
- } else {
- *outPtr++ = *c++;
- indent++;
- }
- } else if (*c == '\n') {
- indent = startIndent;
- *outPtr++ = *c++;
- } else {
- *outPtr++ = *c++;
- indent++;
- }
- }
- *outPtr = '\0';
- *newLen = outPtr - outStr;
- return outStr;
-}
-
int Fl_Text_Buffer::insertfile(const char *file, int pos, int buflen)
{
FILE *fp;
@@ -2374,6 +1549,11 @@ int Fl_Text_Buffer::insertfile(const char *file, int pos, int buflen)
return e;
}
+
+/*
+ Write text to file,
+ Unicode safe.
+ */
int Fl_Text_Buffer::outputfile(const char *file, int start, int end,
int buflen)
{
@@ -2394,6 +1574,39 @@ int Fl_Text_Buffer::outputfile(const char *file, int start, int end,
}
+/*
+ Return the previous character position.
+ Uncode safe.
+ */
+int Fl_Text_Buffer::prev_char(int pos) const
+{
+ if (pos<=0)
+ return 0;
+
+ char c;
+ do {
+ pos--;
+ if (pos==0)
+ return 0;
+ c = byte_at(pos);
+ } while ( (c&0xc0) == 0x80);
+
+ return pos;
+}
+
+/*
+ Return the next character position.
+ Uncode safe.
+ */
+int Fl_Text_Buffer::next_char(int pos) const
+{
+ int n = fl_utf8len(byte_at(pos));
+ pos += n;
+ if (pos>=mLength)
+ return mLength;
+ return pos;
+}
+
//
// End of "$Id$".
//
diff --git a/src/Fl_Text_Display.cxx b/src/Fl_Text_Display.cxx
index 88a2f084f..4fb6352ba 100644
--- a/src/Fl_Text_Display.cxx
+++ b/src/Fl_Text_Display.cxx
@@ -129,7 +129,6 @@ Fl_Text_Display::Fl_Text_Display(int X, int Y, int W, int H, const char* l)
mCursor_color = FL_FOREGROUND_COLOR;
- mFixedFontWidth = -1;
mStyleBuffer = 0;
mStyleTable = 0;
mNStyles = 0;
@@ -211,6 +210,8 @@ void Fl_Text_Display::buffer( Fl_Text_Buffer *buf ) {
(see extendRangeForStyleMods for more information on this protocol).
Style buffers, tables and their associated memory are managed by the caller.
+
+ Styles are ranged from 65 ('A') to 126.
*/
void Fl_Text_Display::highlight_data(Fl_Text_Buffer *styleBuffer,
const Style_Table_Entry *styleTable,
@@ -429,7 +430,7 @@ void Fl_Text_Display::redisplay_range(int startpos, int endpos) {
int ok = 0;
while (!ok && startpos > 0) {
// FIXME: character is ucs-4
- char c = buffer()->character( startpos );
+ char c = buffer()->char_at( startpos );
if (!((c & 0x80) && !(c & 0x40))) {
ok = 1;
} else {
@@ -438,7 +439,7 @@ void Fl_Text_Display::redisplay_range(int startpos, int endpos) {
}
while (!ok && endpos < buffer()->length()) {
// FIXME: character is ucs-4
- char c = buffer()->character( endpos );
+ char c = buffer()->char_at( endpos );
if (!((c & 0x80) && !(c & 0x40))) {
ok = 1;
} else {
@@ -626,7 +627,7 @@ void Fl_Text_Display::overstrike(const char* text) {
startIndent = mBuffer->count_displayed_characters( lineStart, startPos );
indent = startIndent;
for ( c = text; *c != '\0'; c++ )
- indent += Fl_Text_Buffer::character_width( c, indent, buf->tab_distance() );
+ indent++;
endIndent = indent;
/* find which characters to remove, and if necessary generate additional
@@ -636,11 +637,10 @@ void Fl_Text_Display::overstrike(const char* text) {
if ( p == buf->length() )
break;
// FIXME: character is ucs-4
- ch = buf->character( p );
+ ch = buf->char_at( p );
if ( ch == '\n' )
break;
- const char *s = buf->address(p);
- indent += Fl_Text_Buffer::character_width(s, indent, buf->tab_distance() ); // FIXME: not unicode
+ indent++;
if ( indent == endIndent ) {
p++;
break;
@@ -674,32 +674,19 @@ void Fl_Text_Display::overstrike(const char* text) {
*/
int Fl_Text_Display::position_to_xy( int pos, int* X, int* Y ) const {
- int charIndex, lineStartPos, fontHeight, lineLen;
- int visLineNum, charLen, outIndex, xStep, charStyle;
- char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ];
- const char *lineStr;
-
-// printf("position_to_xy(pos=%d, X=%p, Y=%p)\n", pos, X, Y);
+ int lineStartPos, fontHeight, lineLen;
+ int visLineNum;
/* If position is not displayed, return false */
if (pos < mFirstChar || (pos > mLastChar && !empty_vlines())) {
-// printf(" returning 0\n"
-// " mFirstChar=%d, mLastChar=%d, empty_vlines()=0\n",
-// mFirstChar, mLastChar);
return 0;
}
/* Calculate Y coordinate */
if (!position_to_line(pos, &visLineNum)) {
-// puts(" returning 0\n"
-// " position_to_line()=0");
return 0;
}
-
if (visLineNum < 0 || visLineNum > mNBufferLines) {
-// printf(" returning 0\n"
-// " visLineNum=%d, mNBufferLines=%d\n",
-// visLineNum, mNBufferLines);
return 0;
}
@@ -715,25 +702,7 @@ int Fl_Text_Display::position_to_xy( int pos, int* X, int* Y ) const {
return 1;
}
lineLen = vline_length( visLineNum );
- lineStr = mBuffer->text_range( lineStartPos, lineStartPos + lineLen );
-
- /* Step through character positions from the beginning of the line
- to "pos" to calculate the X coordinate */
- xStep = text_area.x - mHorizOffset;
- outIndex = 0;
- for (charIndex = 0;
- charIndex < lineLen && charIndex < pos - lineStartPos;
- charIndex += fl_utf8len(lineStr[charIndex]) )
- {
- charLen = Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar,
- mBuffer->tab_distance());
- charStyle = position_style( lineStartPos, lineLen, charIndex,
- outIndex );
- xStep += string_width( expandedChar, charLen, charStyle );
- outIndex += charLen;
- }
- *X = xStep;
- free((char *)lineStr);
+ *X = text_area.x + handle_vline(GET_WIDTH, lineStartPos, pos-lineStartPos, 0, 0, 0, 0, 0, 0) - mHorizOffset;
return 1;
}
@@ -774,24 +743,10 @@ int Fl_Text_Display::position_to_linecol( int pos, int* lineNum, int* column ) c
Return 1 if position (X, Y) is inside of the primary Fl_Text_Selection
*/
int Fl_Text_Display::in_selection( int X, int Y ) const {
- int row, column, pos = xy_to_position( X, Y, CHARACTER_POS );
+ int pos = xy_to_position( X, Y, CHARACTER_POS );
Fl_Text_Buffer *buf = mBuffer;
- int ok = 0;
- while (!ok) {
- // FIXME: character is ucs-4
- char c = buffer()->character( pos );
- if (!((c & 0x80) && !(c & 0x40))) {
- ok = 1;
- } else {
- pos++;
+ return buf->primary_selection()->includes(pos);
}
- }
-
- xy_to_rowcol( X, Y, &row, &column, CHARACTER_POS );
- if (range_touches_selection(buf->primary_selection(), mFirstChar, mLastChar))
- column = wrapped_column(row, column);
- return buf->primary_selection()->includes(pos, buf->line_start( pos ), column);
-}
/**
Correct a column number based on an unconstrained position (as returned by
@@ -886,33 +841,30 @@ void Fl_Text_Display::show_insert_position() {
/*
Cursor movement functions
*/
-/** Moves the current insert position right one character.*/
+
+/**
+ Moves the current insert position right one character.
+ \return 1 if the cursor moved, 0 if the end of the text was reached
+ */
int Fl_Text_Display::move_right() {
- int ok = 0;
- while (!ok) {
if ( mCursorPos >= mBuffer->length() )
return 0;
- insert_position( mCursorPos + 1 );
- int pos = insert_position();
- // FIXME: character is ucs-4
- char c = buffer()->character( pos );
- if (!((c & 0x80) && !(c & 0x40))) ok = 1;
- }
+ int p = insert_position();
+ int q = buffer()->next_char(p);
+ insert_position(q);
return 1;
}
-/** Moves the current insert position left one character.*/
+/**
+ Moves the current insert position left one character.
+ \return 1 if the cursor moved, 0 if the beginning of the text was reached
+ */
int Fl_Text_Display::move_left() {
- int ok = 0;
- while (!ok) {
if ( mCursorPos <= 0 )
return 0;
- insert_position( mCursorPos - 1 );
- int pos = insert_position();
- // FIXME: character is ucs-4
- char c = buffer()->character( pos );
- if (!((c & 0x80) && !(c & 0x40))) ok = 1;
- }
+ int p = insert_position();
+ int q = buffer()->prev_char(p);
+ insert_position(q);
return 1;
}
@@ -951,7 +903,7 @@ int Fl_Text_Display::move_up() {
while (!ok) {
int pos = insert_position();
// FIXME: character is ucs-4
- char c = buffer()->character( pos );
+ char c = buffer()->char_at( pos );
if (!((c & 0x80) && !(c & 0x40))) {
ok = 1;
} else {
@@ -988,7 +940,7 @@ int Fl_Text_Display::move_down() {
while (!ok) {
int pos = insert_position();
// FIXME: character is ucs-4
- char c = buffer()->character( pos );
+ char c = buffer()->char_at( pos );
if (!((c & 0x80) && !(c & 0x40))) {
ok = 1;
} else {
@@ -1138,11 +1090,11 @@ static inline int fl_isseparator(int c) {
void Fl_Text_Display::next_word() {
int pos = insert_position();
// FIXME: character is ucs-4
- while (pos < buffer()->length() && !fl_isseparator(buffer()->character(pos))) {
+ while (pos < buffer()->length() && !fl_isseparator(buffer()->char_at(pos))) {
pos++;
}
// FIXME: character is ucs-4
- while (pos < buffer()->length() && fl_isseparator(buffer()->character(pos))) {
+ while (pos < buffer()->length() && fl_isseparator(buffer()->char_at(pos))) {
pos++;
}
@@ -1155,15 +1107,15 @@ void Fl_Text_Display::previous_word() {
if (pos==0) return;
pos--;
// FIXME: character is ucs-4
- while (pos && fl_isseparator(buffer()->character(pos))) {
+ while (pos && fl_isseparator(buffer()->char_at(pos))) {
pos--;
}
// FIXME: character is ucs-4
- while (pos && !fl_isseparator(buffer()->character(pos))) {
+ while (pos && !fl_isseparator(buffer()->char_at(pos))) {
pos--;
}
// FIXME: character is ucs-4
- if (fl_isseparator(buffer()->character(pos))) pos++;
+ if (fl_isseparator(buffer()->char_at(pos))) pos++;
insert_position( pos );
}
@@ -1174,8 +1126,7 @@ void Fl_Text_Display::previous_word() {
*/
void Fl_Text_Display::buffer_predelete_cb(int pos, int nDeleted, void *cbArg) {
Fl_Text_Display *textD = (Fl_Text_Display *)cbArg;
- if (textD->mContinuousWrap &&
- (textD->mFixedFontWidth == -1 || textD->mModifyingTabDistance))
+ if (textD->mContinuousWrap)
/* Note: we must perform this measurement, even if there is not a
single character deleted; the number of "deleted" lines is the
number of visual lines spanned by the real line in which the
@@ -1401,6 +1352,125 @@ int Fl_Text_Display::position_to_line( int pos, int *lineNum ) const {
return 0; /* probably never be reached */
}
+// We use a single function that handles all line layout, measuring, and drawing
+// - draw a text range
+// - return the width of a text range in pixels
+// - return the index of a char that is at a pixel position
+//
+// - we need to handle hidden hyphens and tabs here!
+// - we handle all styles and selections
+//
+// needs:
+// mode: draw, find width, find index
+// index of first character
+// size of string in bytes
+// x and y drawing position
+// width and height of drawing rectangle
+//
+// returns:
+// width of drawing in pixels
+// index of last character that fits into the box
+//
+// enum { DRAW_LINE, FIND_INDEX, GET_WIDTH };
+//
+//
+int Fl_Text_Display::handle_vline(
+ int mode,
+ int lineStartPos, int lineLen, int leftChar, int rightChar,
+ int Y, int bottomClip,
+ int leftClip, int rightClip) const
+{
+ // FIXME: we need to allow two modes for FIND_INDEX: one on the edge of the
+ // FIXME: character for selection, and one on the character center for cursors.
+ int i, X, startX, startIndex, style, charStyle;
+ char *lineStr;
+
+ if ( lineStartPos == -1 ) {
+ lineStr = NULL;
+ } else {
+ lineStr = mBuffer->text_range( lineStartPos, lineStartPos + lineLen );
+ }
+
+ if (mode==GET_WIDTH)
+ X = 0;
+ else
+ X = text_area.x - mHorizOffset;
+
+ startX = X;
+ startIndex = 0;
+ if (!lineStr) {
+ // just clear the background
+ if (mode==DRAW_LINE) {
+ style = position_style(lineStartPos, lineLen, -1);
+ draw_string( style|BG_ONLY_MASK, text_area.x, Y, text_area.x+text_area.w, lineStr, lineLen );
+ }
+ if (mode==FIND_INDEX)
+ return lineStartPos;
+ return 0;
+ }
+
+ // draw the line
+ style = position_style(lineStartPos, lineLen, i);
+ for (i=0; i<lineLen; ) {
+ int len = fl_utf8len(lineStr[i]);
+ charStyle = position_style(lineStartPos, lineLen, i);
+ // FIXME: if the character is a tab, we need to do the correct indenting
+ // FIXME: if the character is an optional hyphen, we need to ignore it unless we wrap the text
+ if (charStyle!=style) {
+ // draw a segment whenever the style changes
+ int w = string_width( lineStr+startIndex, i-startIndex, style );
+ if (mode==DRAW_LINE)
+ draw_string( style, startX, Y, startX+w, lineStr+startIndex, i-startIndex );
+ if (mode==FIND_INDEX && startX+w>rightClip) {
+ // find x pos inside block
+ int di = find_x(lineStr+startIndex, i-startIndex, style, rightClip-startX);
+ free(lineStr);
+ return lineStartPos + startIndex + di;
+ }
+ style = charStyle;
+ startX += w;
+ startIndex = i;
+ }
+ i += len;
+ }
+ int w = string_width( lineStr+startIndex, i-startIndex, style );
+ if (mode==DRAW_LINE)
+ draw_string( style, startX, Y, startX+w, lineStr+startIndex, i-startIndex );
+ if (mode==FIND_INDEX) {
+ // find x pos inside block
+ int di = find_x(lineStr+startIndex, i-startIndex, style, rightClip-startX);
+ free(lineStr);
+ return lineStartPos + startIndex + di;
+ }
+ if (mode==GET_WIDTH) {
+ free(lineStr);
+ return startX+w;
+ }
+
+ // clear the rest of the line
+ startX += w;
+ style = position_style(lineStartPos, lineLen, i);
+ if (mode==DRAW_LINE)
+ draw_string( style|BG_ONLY_MASK, startX, Y, text_area.x+text_area.w, lineStr, lineLen );
+
+ free(lineStr);
+ return lineStartPos + lineLen;
+}
+
+int Fl_Text_Display::find_x(const char *s, int len, int style, int x) const {
+ // FIXME: use binary search which is much quicker!
+ int i = 0;
+ while (i<len) {
+ int cl = fl_utf8len(s[i]);
+ int w = string_width(s, i+cl, style);
+ if (w>x)
+ return i;
+ i += cl;
+ }
+ return len;
+}
+
+
/**
Draw the text on a single line represented by "visLineNum" (the
number of lines down from the top of the display), limited by
@@ -1410,14 +1480,8 @@ int Fl_Text_Display::position_to_line( int pos, int *lineNum ) const {
*/
void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip,
int leftCharIndex, int rightCharIndex) {
- Fl_Text_Buffer * buf = mBuffer;
- int i, X, Y, startX, charIndex, lineStartPos, lineLen, fontHeight;
- int stdCharWidth, charWidth, startIndex, charStyle, style;
- int charLen, outStartIndex, outIndex;
- int dispIndexOffset;
- char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ], outStr[ MAX_DISP_LINE_LEN ];
- char *outPtr;
- const char *lineStr;
+ int Y, lineStartPos, lineLen, fontHeight;
+ int stdCharWidth;
// printf("draw_vline(visLineNum=%d, leftClip=%d, rightClip=%d, leftCharIndex=%d, rightCharIndex=%d)\n",
// visLineNum, leftClip, rightClip, leftCharIndex, rightCharIndex);
@@ -1436,10 +1500,8 @@ void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip,
// printf("lineStartPos=%d\n", lineStartPos);
if ( lineStartPos == -1 ) {
lineLen = 0;
- lineStr = NULL;
} else {
lineLen = vline_length( visLineNum );
- lineStr = buf->text_range( lineStartPos, lineStartPos + lineLen );
}
/* Space beyond the end of the line is still counted in units of characters
@@ -1450,7 +1512,6 @@ void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip,
stdCharWidth = TMPFONTWIDTH; //mFontStruct->max_bounds.width;
if ( stdCharWidth <= 0 ) {
Fl::error("Fl_Text_Display::draw_vline(): bad font measurement");
- if (lineStr) free((void *)lineStr);
return;
}
@@ -1458,167 +1519,11 @@ void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip,
leftClip = max( text_area.x, leftClip );
rightClip = min( rightClip, text_area.x + text_area.w );
- /* Rectangular Fl_Text_Selections are based on "real" line starts (after
- a newline or start of buffer). Calculate the difference between the
- last newline position and the line start we're using. Since scanning
- back to find a newline is expensive, only do so if there's actually a
- rectangular Fl_Text_Selection which needs it */
- if (mContinuousWrap &&
- (range_touches_selection(buf->primary_selection(),
- lineStartPos, lineStartPos + lineLen) ||
- range_touches_selection(buf->secondary_selection(),
- lineStartPos, lineStartPos + lineLen) ||
- range_touches_selection(buf->highlight_selection(),
- lineStartPos, lineStartPos + lineLen)))
- {
- dispIndexOffset = buf->count_displayed_characters(
- buf->line_start(lineStartPos), lineStartPos);
- } else
- dispIndexOffset = 0;
-
- /* Step through character positions from the beginning of the line (even if
- that's off the left edge of the displayed area) to find the first
- character position that's not clipped, and the X coordinate for drawing
- that character */
- X = text_area.x - mHorizOffset;
- outIndex = 0;
- for (charIndex = 0;
- ;
- charIndex += lineStr ? fl_utf8len(lineStr[charIndex]) : 1 )
- {
- charLen = charIndex >= lineLen ? 1 :
- Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex,
- expandedChar, buf->tab_distance());
- style = position_style( lineStartPos, lineLen, charIndex,
- outIndex + dispIndexOffset );
- charWidth = charIndex >= lineLen ? stdCharWidth :
- string_width( expandedChar, charLen, style );
- if ( X + charWidth >= leftClip && charIndex >= leftCharIndex ) {
- startIndex = charIndex;
- outStartIndex = outIndex;
- startX = X;
- break;
- }
- X += charWidth;
- outIndex += charLen;
- }
-
- /* Scan character positions from the beginning of the clipping range, and
- draw parts whenever the style changes (also note if the cursor is on
- this line, and where it should be drawn to take advantage of the x
- position which we've gone to so much trouble to calculate) */
- /* since characters between style may overlap, we draw the full
- background first */
- int sX = startX;
- outPtr = outStr;
- outIndex = outStartIndex;
- X = startX;
- for (charIndex = startIndex;
- charIndex < rightCharIndex;
- charIndex += lineStr ? fl_utf8len(lineStr[charIndex]) : 1 )
- {
- charLen = charIndex >= lineLen ? 1 :
- Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar,
- buf->tab_distance());
- charStyle = position_style( lineStartPos, lineLen, charIndex,
- outIndex + dispIndexOffset );
- for ( i = 0; i < charLen; i++ ) { // FIXME: this rips apart the utf-8 sequneces
- if ( i != 0 && charIndex < lineLen && lineStr[ charIndex ] == '\t' )
- charStyle = position_style( lineStartPos, lineLen,
- charIndex, outIndex + dispIndexOffset );
- if ( charStyle != style ) {
- draw_string( style|BG_ONLY_MASK, sX, Y, X, outStr, outPtr - outStr );
- outPtr = outStr;
- sX = X;
- style = charStyle;
- }
- if ( charIndex < lineLen ) {
- *outPtr = expandedChar[ i ];
- int l = 1;
- if (*outPtr & 0x80) {
- l = fl_utf8len(*outPtr);
- if (l<=0) l = 1;
- }
- charWidth = string_width( &expandedChar[ i ], l, charStyle );
- } else
- charWidth = stdCharWidth;
- outPtr++;
- X += charWidth;
- outIndex++;
- }
- if ( outPtr - outStr + FL_TEXT_MAX_EXP_CHAR_LEN >= MAX_DISP_LINE_LEN || X >= rightClip )
- break;
- }
- draw_string( style|BG_ONLY_MASK, sX, Y, X, outStr, outPtr - outStr );
-
- /* now draw the text over the previously erased background */
- outPtr = outStr;
- outIndex = outStartIndex;
- X = startX;
- for (charIndex = startIndex;
- charIndex < rightCharIndex;
- charIndex += lineStr ? fl_utf8len(lineStr[charIndex]) : 0)
- {
- charLen = charIndex >= lineLen ? 1 :
- Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar,
- buf->tab_distance());
- charStyle = position_style( lineStartPos, lineLen, charIndex,
- outIndex + dispIndexOffset );
- for ( i = 0; i < charLen; i++ ) { // FIXME: this rips apart the utf-8 sequneces
- if ( i != 0 && charIndex < lineLen && lineStr[ charIndex ] == '\t' )
- charStyle = position_style( lineStartPos, lineLen,
- charIndex, outIndex + dispIndexOffset );
- if ( charStyle != style ) {
- draw_string( style|TEXT_ONLY_MASK, startX, Y, X, outStr, outPtr - outStr );
- outPtr = outStr;
- startX = X;
- style = charStyle;
- }
- if ( charIndex < lineLen ) {
- *outPtr = expandedChar[ i ];
- int l = 1;
- if (*outPtr & 0x80) {
- l = fl_utf8len(*outPtr);
- if (l<=0) l = 1;
- }
- charWidth = string_width( &expandedChar[ i ], l, charStyle );
- } else
- charWidth = stdCharWidth;
- outPtr++;
- X += charWidth;
- outIndex++;
- }
- if ( outPtr - outStr + FL_TEXT_MAX_EXP_CHAR_LEN >= MAX_DISP_LINE_LEN || X >= rightClip )
- break;
- }
-
- /* Draw the remaining style segment */
- draw_string( style|TEXT_ONLY_MASK, startX, Y, X, outStr, outPtr - outStr );
-
- /* Draw the cursor if part of it appeared on the redisplayed part of
- this line. Also check for the cases which are not caught as the
- line is scanned above: when the cursor appears at the very end
- of the redisplayed section. */
- /* CET - FIXME
- if ( mCursorOn )
- {
- if ( hasCursor )
- draw_cursor( cursorX, Y );
- else if ( charIndex < lineLen && ( lineStartPos + charIndex + 1 == cursorPos )
- && X == rightClip )
- {
- if ( cursorPos >= buf->length() )
- draw_cursor( X - 1, Y );
- else
- {
- draw_cursor( X - 1, Y );
- }
- }
+ handle_vline(DRAW_LINE,
+ lineStartPos, lineLen, leftCharIndex, rightCharIndex,
+ Y, Y+fontHeight, leftClip, rightClip);
+ return;
}
- */
- if ( lineStr != NULL )
- free((void *)lineStr);
-}
/**
Draw a string or blank area according to parameter "style", using the
@@ -1628,8 +1533,9 @@ void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip,
rectangle where text would have drawn from X to toX and from Y to
the maximum Y extent of the current font(s).
*/
-void Fl_Text_Display::draw_string( int style, int X, int Y, int toX,
- const char *string, int nChars ) {
+void Fl_Text_Display::draw_string(int style,
+ int X, int Y, int toX,
+ const char *string, int nChars) const {
const Style_Table_Entry * styleRec;
/* Draw blank area rather than text, if that was the request */
@@ -1712,8 +1618,9 @@ void Fl_Text_Display::draw_string( int style, int X, int Y, int toX,
/**
Clear a rectangle with the appropriate background color for "style"
*/
-void Fl_Text_Display::clear_rect( int style, int X, int Y,
- int width, int height ) {
+void Fl_Text_Display::clear_rect(int style,
+ int X, int Y,
+ int width, int height) const {
/* A width of zero means "clear to end of window" to XClearArea */
if ( width == 0 )
return;
@@ -1821,8 +1728,8 @@ void Fl_Text_Display::draw_cursor( int X, int Y ) {
Note that style is a somewhat incorrect name, drawing method would
be more appropriate.
*/
-int Fl_Text_Display::position_style( int lineStartPos,
- int lineLen, int lineIndex, int dispIndex ) const {
+int Fl_Text_Display::position_style( int lineStartPos, int lineLen, int lineIndex) const
+{
Fl_Text_Buffer * buf = mBuffer;
Fl_Text_Buffer *styleBuf = mStyleBuffer;
int pos, style = 0;
@@ -1835,20 +1742,18 @@ int Fl_Text_Display::position_style( int lineStartPos,
if ( lineIndex >= lineLen )
style = FILL_MASK;
else if ( styleBuf != NULL ) {
- // FIXME: character is ucs-4
- style = ( unsigned char ) styleBuf->character( pos );
+ style = ( unsigned char ) styleBuf->byte_at( pos );
if (style == mUnfinishedStyle && mUnfinishedHighlightCB) {
/* encountered "unfinished" style, trigger parsing */
(mUnfinishedHighlightCB)( pos, mHighlightCBArg);
- // FIXME: character is ucs-4
- style = (unsigned char) styleBuf->character( pos);
+ style = (unsigned char) styleBuf->byte_at( pos);
}
}
- if (buf->primary_selection()->includes(pos, lineStartPos, dispIndex))
+ if (buf->primary_selection()->includes(pos))
style |= PRIMARY_MASK;
- if (buf->highlight_selection()->includes(pos, lineStartPos, dispIndex))
+ if (buf->highlight_selection()->includes(pos))
style |= HIGHLIGHT_MASK;
- if (buf->secondary_selection()->includes(pos, lineStartPos, dispIndex))
+ if (buf->secondary_selection()->includes(pos))
style |= SECONDARY_MASK;
return style;
}
@@ -1884,10 +1789,8 @@ int Fl_Text_Display::string_width( const char *string, int length, int style ) c
closest to (X, Y).
*/
int Fl_Text_Display::xy_to_position( int X, int Y, int posType ) const {
- int charIndex, lineStart, lineLen, fontHeight;
- int charWidth, charLen, charStyle, visLineNum, xStep, outIndex;
- char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ];
- const char *lineStr;
+ int lineStart, lineLen, fontHeight;
+ int visLineNum;
/* Find the visible line number corresponding to the Y coordinate */
fontHeight = mMaxsize;
@@ -1906,33 +1809,12 @@ int Fl_Text_Display::xy_to_position( int X, int Y, int posType ) const {
/* Get the line text and its length */
lineLen = vline_length( visLineNum );
- lineStr = mBuffer->text_range( lineStart, lineStart + lineLen );
-
- /* Step through character positions from the beginning of the line
- to find the character position corresponding to the X coordinate */
- xStep = text_area.x - mHorizOffset;
- outIndex = 0;
- for (charIndex = 0;
- charIndex < lineLen;
- charIndex += fl_utf8len(lineStr[charIndex]) )
- {
- charLen = Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar,
- mBuffer->tab_distance());
- charStyle = position_style( lineStart, lineLen, charIndex, outIndex );
- charWidth = string_width( expandedChar, charLen, charStyle );
- if ( X < xStep + ( posType == CURSOR_POS ? charWidth / 2 : charWidth ) ) {
- free((char *)lineStr);
- return lineStart + charIndex;
- }
- xStep += charWidth;
- outIndex += charLen;
- }
- /* If the X position was beyond the end of the line, return the position
- of the newline at the end of the line */
- free((char *)lineStr);
- return lineStart + lineLen;
-}
+ return handle_vline(FIND_INDEX,
+ lineStart, lineLen, 0, 0,
+ 0, 0,
+ text_area.x, X);
+ }
/**
Translate window coordinates to the nearest row and column number for
@@ -2341,42 +2223,12 @@ static int countlines( const char *string ) {
Return the width in pixels of the displayed line pointed to by "visLineNum"
*/
int Fl_Text_Display::measure_vline( int visLineNum ) const {
- int i, width = 0, len, style, lineLen = vline_length( visLineNum );
- int charCount = 0, lineStartPos = mLineStarts[ visLineNum ];
- char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ];
-
+ // FIXME: the horizontal scroll bar is still messed up. Clicking the right container is not possible.
+ int lineLen = vline_length( visLineNum );
+ int lineStartPos = mLineStarts[ visLineNum ];
if (lineStartPos < 0 || lineLen == 0) return 0;
- if ( mStyleBuffer == NULL ) {
- for ( i = 0; i < lineLen; i++ ) {
- len = mBuffer->expand_character( lineStartPos + i,
- charCount, expandedChar );
-
- fl_font( textfont(), textsize() );
-
- width += ( int ) fl_width( expandedChar, len );
-
- charCount += len;
- }
- } else {
- for ( i = 0; i < lineLen; i++ ) {
- len = mBuffer->expand_character( lineStartPos + i,
- charCount, expandedChar );
- // FIXME: character is ucs-4
- style = ( unsigned char ) mStyleBuffer->character(
- lineStartPos + i ) - 'A';
-
- if (style < 0) style = 0;
- else if (style >= mNStyles) style = mNStyles - 1;
-
- fl_font( mStyleTable[ style ].font, mStyleTable[ style ].size );
-
- width += ( int ) fl_width( expandedChar, len );
-
- charCount += len;
+ return handle_vline(GET_WIDTH, lineStartPos, lineLen, 0, 0, 0, 0, 0, 0);
}
- }
- return width;
-}
/**
Return true if there are lines visible with no corresponding buffer text
@@ -2471,7 +2323,7 @@ void Fl_Text_Display::find_wrap_range(const char *deletedText, int pos,
nLines++;
if (lineStart > pos + nInserted &&
// FIXME: character is ucs-4
- buf->character(lineStart-1) == '\n') {
+ buf->char_at(lineStart-1) == '\n') {
countTo = lineStart;
*modRangeEnd = lineStart;
break;
@@ -2617,7 +2469,7 @@ void Fl_Text_Display::measure_deleted_lines(int pos, int nDeleted) {
nLines++;
if (lineStart > pos + nDeleted &&
// FIXME: character is ucs-4
- buf->character(lineStart-1) == '\n') {
+ buf->char_at(lineStart-1) == '\n') {
break;
}
@@ -2662,16 +2514,17 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
int lineStart, newLineStart = 0, b, p, colNum, wrapMargin;
int maxWidth, i, foundBreak, width;
bool countPixels;
- int nLines = 0, tabDist = buffer()->tab_distance();
+ int nLines = 0;
unsigned char c;
/* If the font is fixed, or there's a wrap margin set, it's more efficient
to measure in columns, than to count pixels. Determine if we can count
in columns (countPixels == False) or must count pixels (countPixels ==
True), and set the wrap target for either pixels or columns */
- if (mFixedFontWidth != -1 || mWrapMargin != 0) {
+ if (mWrapMargin != 0) {
+ // FIXME: the warp margin is actually a pixel boundary, so we have to measure nevertheless!
countPixels = false;
- wrapMargin = mWrapMargin ? mWrapMargin : text_area.w / (mFixedFontWidth + 1);
+ wrapMargin = mWrapMargin;
maxWidth = INT_MAX;
} else {
countPixels = true;
@@ -2688,14 +2541,14 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
/*
** Loop until position exceeds maxPos or line count exceeds maxLines.
- ** (actually, contines beyond maxPos to end of line containing maxPos,
+ ** (actually, continues beyond maxPos to end of line containing maxPos,
** in case later characters cause a word wrap back before maxPos)
*/
colNum = 0;
width = 0;
for (p=lineStart; p<buf->length(); p++) {
// FIXME: character is ucs-4
- c = (unsigned char)buf->character(p);
+ c = (unsigned char)buf->char_at(p);
/* If the character was a newline, count the line and start over,
otherwise, add it to the width and column counts */
@@ -2720,7 +2573,7 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
width = 0;
} else {
const char *s = buf->address(p);
- colNum += Fl_Text_Buffer::character_width(s, colNum, tabDist); // FIXME: unicode
+ colNum++;
if (countPixels)
width += measure_proportional_character(s, colNum, p+styleBufOffset);
}
@@ -2731,7 +2584,7 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
foundBreak = false;
for (b=p; b>=lineStart; b--) {
// FIXME: character is ucs-4
- c = (unsigned char)buf->character(b);
+ c = (unsigned char)buf->char_at(b);
if (c == '\t' || c == ' ') {
newLineStart = b + 1;
if (countPixels) {
@@ -2753,7 +2606,7 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
if (!foundBreak) { /* no whitespace, just break at margin */
newLineStart = max(p, lineStart+1);
const char *s = buf->address(b);
- colNum = Fl_Text_Buffer::character_width(s, colNum, tabDist); // FIXME: unicode
+ colNum++;
if (countPixels)
width = measure_proportional_character(s, colNum, p+styleBufOffset);
}
@@ -2800,27 +2653,14 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
insertion/deletion, though static display and wrapping and resizing
should now be solid because they are now used for online help display.
*/
-
int Fl_Text_Display::measure_proportional_character(const char *s, int colNum, int pos) const {
- int charLen, style;
- char expChar[ FL_TEXT_MAX_EXP_CHAR_LEN ];
- Fl_Text_Buffer *styleBuf = mStyleBuffer;
-
- charLen = Fl_Text_Buffer::expand_character(s, colNum, expChar, buffer()->tab_distance()); // FIXME: unicode
- if (styleBuf == 0) {
- style = 0;
- } else {
- // FIXME: character is ucs-4
- style = (unsigned char)styleBuf->character(pos);
- if (style == mUnfinishedStyle && mUnfinishedHighlightCB) {
- /* encountered "unfinished" style, trigger parsing */
- (mUnfinishedHighlightCB)(pos, mHighlightCBArg);
- // FIXME: character is ucs-4
- style = (unsigned char)styleBuf->character(pos);
+ int charLen = fl_utf8len(*s), style = 0;
+ if (mStyleBuffer) {
+ const char *b = mStyleBuffer->address(pos);
+ style = *b;
}
+ return string_width(s, charLen, style);
}
- return string_width(expChar, charLen, style);
-}
/**
Finds both the end of the current line and the start of the next line. Why?
@@ -2873,22 +2713,12 @@ int Fl_Text_Display::wrap_uses_character(int lineEndPos) const {
return 1;
// FIXME: character is ucs-4
- c = buffer()->character(lineEndPos);
+ c = buffer()->char_at(lineEndPos);
return c == '\n' || ((c == '\t' || c == ' ') &&
lineEndPos + 1 != buffer()->length());
}
/**
- Return true if the selection "sel" is rectangular, and touches a
- buffer position withing "rangeStart" to "rangeEnd"
-*/
-int Fl_Text_Display::range_touches_selection(const Fl_Text_Selection *sel,
- int rangeStart, int rangeEnd) const {
- return sel->selected() && sel->rectangular() && sel->end() >= rangeStart &&
- sel->start() <= rangeEnd;
-}
-
-/**
Extend the range of a redraw request (from *start to *end) with additional
redraw requests resulting from changes to the attached style buffer (which
contains auxiliary information for coloring or styling text).
@@ -2921,7 +2751,7 @@ void Fl_Text_Display::extend_range_for_styles( int *startpos, int *endpos ) {
/* If the Fl_Text_Selection was extended due to a style change, and some of the
fonts don't match in spacing, extend redraw area to end of line to
redraw characters exposed by possible font size changes */
- if ( mFixedFontWidth == -1 && extended )
+ if ( extended )
*endpos = mBuffer->line_end( *endpos ) + 1;
}
@@ -3153,7 +2983,7 @@ int Fl_Text_Display::handle(int event) {
int ok = 0;
while (!ok) {
// FIXME: character is ucs-4
- char c = buffer()->character( pos );
+ char c = buffer()->char_at( pos );
if (!((c & 0x80) && !(c & 0x40))) {
ok = 1;
} else {
@@ -3219,7 +3049,7 @@ int Fl_Text_Display::handle(int event) {
int ok = 0;
while (!ok) {
// FIXME: character is ucs-4
- char c = buffer()->character( pos );
+ char c = buffer()->char_at( pos );
if (!((c & 0x80) && !(c & 0x40))) {
ok = 1;
} else {
diff --git a/src/Fl_Text_Editor.cxx b/src/Fl_Text_Editor.cxx
index 76ce92ddd..dc4730fe2 100644
--- a/src/Fl_Text_Editor.cxx
+++ b/src/Fl_Text_Editor.cxx
@@ -255,7 +255,7 @@ int Fl_Text_Editor::kf_backspace(int, Fl_Text_Editor* e) {
if (!e->buffer()->selected() && e->move_left()) {
int l = 1;
// FIXME: character is ucs-4
- char c = e->buffer()->character(e->insert_position());
+ char c = e->buffer()->char_at(e->insert_position());
if (c & 0x80 && c & 0x40) {
l = fl_utf8len(c);
}
@@ -451,7 +451,7 @@ int Fl_Text_Editor::kf_delete(int, Fl_Text_Editor* e) {
if (!e->buffer()->selected()) {
int l = 1;
// FIXME: character is ucs-4
- char c = e->buffer()->character(e->insert_position());
+ char c = e->buffer()->char_at(e->insert_position());
if (c & 0x80 && c & 0x40) {
l = fl_utf8len(c);
}