📄 atbeditor.c
字号:
}
/*******************************************************************************
$Function: ATB_edit_GetCasePref
$Description: Returns the preferred case for the current position in the editor
$Returns: ED_CASEPREF_NUM - Any numeric character
ED_CASEPREF_ALPHA_UC - Any symbolic or alphabetic uppercase
character
ED_CASEPREF_ALPHA_LC - Any symbolic or alphabetic lowercase
character
ED_CASEPREF_ALPHANUM - Any symbolic, numeric, or alphabetic
character
ED_CASEPREF_ALPHANUM_UC - Any symbolic, numeric, or alphabetic
uppercase character
ED_CASEPREF_ALPHANUM_LC - Any symbolic, numeric, or alphabetic
lowercase character
$Arguments: editor - The editor data
*******************************************************************************/
T_ED_CASE_PREF ATB_edit_GetCasePref(T_ED_DATA *editor)
{
T_ED_CASE_PREF casePref;
char formatchar;
char *format;
/* FORMATTED MODE */
if (ATB_edit_Mode(editor, ED_MODE_FORMATTED))
{
format = editor->attr->FormatString;
formatchar = format[editor->formatIndex];
if ((formatchar>'0' && formatchar<='9') || formatchar=='*') // Delimiter for format field
{
editor->formatIndex++;
editor->fieldIndex = 0;
formatchar = format[editor->formatIndex]; // Next character is the format for the field
}
switch(formatchar)
{
case 'X': /* Uppercase alphanumeric */
casePref = ED_CASEPREF_ALPHANUM_UC;
break;
case 'x':
casePref = ED_CASEPREF_ALPHANUM_LC; /* Lowercase alphanumeric */
break;
case 'A': /* Uppercase alphabetic */
casePref = ED_CASEPREF_ALPHA_UC;
break;
case 'a': /* Lowercase alphabetic */
casePref = ED_CASEPREF_ALPHA_LC;
break;
case 'M':
casePref = ED_CASEPREF_ALPHANUM;
break;
case 'm':
casePref = ED_CASEPREF_ALPHANUM;
break;
case 'N':
casePref = ED_CASEPREF_NUM;
break;
default:
casePref = ED_CASEPREF_NONE;
break;
}
}
/* NORMAL MODE */
else
{
if (ATB_edit_Mode(editor, ED_MODE_ALPHA))
casePref = ED_CASEPREF_ALPHANUM;
else
casePref = ED_CASEPREF_NUM;
}
return casePref;
}
/*******************************************************************************
$Function: ATB_edit_OutTextLines
$Description: Draw the visible lines of text onto the screen
$Returns: None
$Arguments: editor - The editor data
*******************************************************************************/
static void ATB_edit_OutTextLines (T_ED_DATA *editor)
{
USHORT editX = editor->attr->win_size.px; /* X position in editor */
USHORT editY = editor->attr->win_size.py; /* Y position in editor */
USHORT editWidth = editor->attr->win_size.sx; /* Height of the editor */
USHORT editHeight = editor->attr->win_size.sy; /* Height of the editor */
USHORT lineNo;
USHORT heightOnScreen; /* Height of lines shown so far */
USHORT offsetX; /* X offset of line */
T_DS_TEXTFORMAT tempFormat; /* Temporary storage for format attributes */
T_ED_LINE *line; /* Current line attributes */
T_ATB_TEXT currentLine; /* Current line */
TRACE_FUNCTION("ATB_edit_OutTextLines()");
if (editor == NULL)
return;
heightOnScreen = 0;
line = ATB_edit_LineGet(editor, editor->winStartLine);
for (lineNo = editor->winStartLine; lineNo < editor->numLines && heightOnScreen<=editHeight; lineNo++)
{
heightOnScreen += line->height; /* Add this height to the total height so far... */
if (editor->display && heightOnScreen <= editHeight) /* and make sure this fits onto the screen */
{
currentLine.len = line->next->pos - line->pos; /* End of line is the first character of the next line */
currentLine.dcs = editor->attr->text.dcs;
currentLine.data = &editor->attr->text.data[line->pos*ATB_string_Size(¤tLine)];
offsetX = 0;
if (line->format.attr & DS_ALIGN_RIGHT)
{
offsetX = editWidth-ATB_display_StringWidth(¤tLine, &line->format);
}
else if (line->format.attr & DS_ALIGN_CENTRE)
{
offsetX = (editWidth-ATB_display_StringWidth(¤tLine, &line->format))/2;
}
ATB_display_CopyFormat(&tempFormat, &line->format); /* So format of lines doesn't change */
ATB_display_Text(offsetX+editX, editY, &tempFormat, ¤tLine);
}
editY += line->height; /* Move down by line height, ready for the next one */
line = line->next; /* Get next line */
}
return;
}
/*******************************************************************************
$Function: ATB_edit_Update
$Description: Update editor (without displaying), moving cursor up or down by 'dy' lines.
This function goes through the text, word-wraps it with the help of ATB_edit_WordWrap,
and works out the start position of text on-screen and the X and Y pixel positions
of the cursor (with the help of ATB_edit_UpdateCursorPos). The character position of
the start of each line within the string is stored, so that ATB_edit_OutTextLines can
quickly display the editor contents without further calculation.
$Returns: ED_BAD_HANDLE - Editor data pointer is null
ED_OK - OK
$Arguments: editor - The editor data
dy - number of lines (+ or -) that the cursor must scroll
up or down.
*******************************************************************************/
static ED_RES ATB_edit_Update (T_ED_DATA *editor, int dy)
{
USHORT cursorCharPos; /* New cursor character position */
USHORT linePos; /* Char pos in string of current line. */
USHORT lineNo; /* Line being considered */
USHORT editComplete; /* Flag indicating cursor position found/updated or end of line reached. */
USHORT character; /* Current unicode char. */
T_ED_LINE *line; /* Pointer to current entry in line chain */
USHORT cursorColumn; /* Column cursor is in - always multiple of 8 pixels */
TRACE_FUNCTION("ATB_edit_Update()");
/* Make sure the editor exists and has text in it */
if (!editor)
return ED_BAD_HANDLE;
/* For non read-only modes, or on first process, perform word wrap */
if (!ATB_edit_Mode(editor, ED_MODE_READONLY) || editor->initialised==FALSE)
{
editor->viewStartPos = 0;
editor->viewHeight = 0;
editor->totalHeight = 0;
editor->startOfLine = TRUE; /* We're at the start of a line */
editor->endOfText = FALSE;
editor->precedingEOL = FALSE; /* Used to detect if preceding character was CR/LF */
editor->thischar.lineWidth = 0; /* Width of current line */
editor->cursor.line = 0; /* Line that the cursor is on */
editor->space.pos = 0; /* Possible position for soft linebreak - none as yet */
/* Set up data if this is the first time... */
if (!editor->initialised)
{
editor->thischar.pos = 0;
editor->numLines = 0; /* total number of lines in editor, start at 0 */
line = ATB_edit_LineGet(editor, 0);
line->pos = 0; /* first line starts at start of buffer */
line->height = 0; /* Height of first line */
ATB_display_CopyFormat(&line->format, &editor->attr->startFormat); /* Start with this text formatting */
ATB_display_CopyFormat(&editor->thischar.format, &editor->attr->startFormat); // Start with this text formatting
editor->winStartLine = 0; /* First line to be displayed in window */
editor->initialised = TRUE;
}
/* Set up data if this is NOT the first time */
else
{
/* We only need to word wrap text that might have been changed by user text entry.
* The user can affect the previous line (by inserting a space or deleting, so the word is
* wrapped to a previous line) and all subsequent lines. Therefore if we start word wrapping
* on the line previous to where the cursor is, we can encompass all changes. */
line = ATB_edit_LineGet(editor, 0);
for (lineNo = 0; lineNo<editor->numLines && editor->cursor.pos>=line->pos; lineNo++)
{
line = line->next;
}
if (lineNo>0)
lineNo--;
if (lineNo>0)
lineNo--;
line = ATB_edit_LineGet(editor, lineNo);
editor->thischar.pos = line->pos; /* Start looking at this line */
editor->numLines = lineNo; /* This no. of lines so far */
ATB_display_CopyFormat(&editor->thischar.format, &line->format); /* Start with this text formatting */
line->height = 0; /* Height of first line */
}
/* Set up some values */
cursorCharPos = editor->cursor.pos; /* Cursor position in the string */
linePos = 0; // Position on the current line
/* Word wrap the text into separate lines, storing the start position and height of each.
* Also, find the cursor and work out its X position. */
while(!editor->endOfText) // Go through from first character to last character
{
ATB_edit_WordWrap(editor); // What is the character? What's its width?
if (editor->endOfLine) // Newline, or current char will not fit on previous line.
{
editor->numLines++; // We've got another line
editor->startOfLine = TRUE; // New line is starting
}
if (editor->startOfLine)
{
line = ATB_edit_LineGet(editor, editor->numLines);
line->pos = editor->startPos;
line->height = editor->thischar.height; // Height of line set to that of first character
ATB_display_CopyFormat(&line->format,&editor->thischar.format);
/* Formatting at start of line to that of 1st character */
editor->thischar.lineWidth = 0;
line = ATB_edit_LineGet(editor, editor->winStartLine);
if (editor->startPos <= line->pos) /* Is this the first line to be displayed in the editor? */
{
editor->winStartLine = editor->numLines; /* If so, set this line to the start window line */
}
editor->startOfLine = FALSE;
}
if (editor->endOfText) /* If it's a unicode terminator... */
{
if (cursorCharPos > editor->thischar.pos) /* Cursor is past end of text - move to char before end of line. */
cursorCharPos = editor->thischar.pos;
}
if (editor->startPos == cursorCharPos) // We've found the cursor
{
editor->cursor.line = editor->numLines; // Store the line it's on
editor->cursor.width = editor->thischar.width; // Set the width of the cursor
editor->cursor.x = editor->thischar.lineWidth; // And its position
editor->cursor.attr = editor->thischar.format.attr; // Save the format attribute
}
editor->thischar.lineWidth += editor->thischar.width;
editor->thischar.pos++;
} // End while
editor->numLines++; // Number of lines is one more than the last line
line = ATB_edit_LineGet(editor, editor->numLines);
line->pos = editor->thischar.pos; // End of last line
ATB_edit_UpdateCursorPos(editor); // Update, but if dy!=0 we may have to change this
}
/* We now have the start position of each line and its height stored in an array.
* We also have the cursor's current X position on its line (but its line may be offscreen) */
if (dy) // If we're sending the cursor up/down some lines...
{
editor->cursor.line = editor->cursor.line+dy; // Change cursor line
if (editor->cursor.line >= editor->numLines ) // Make sure line cursor is on doesn't go beyond...
editor->cursor.line = editor->numLines-1; // ...last line of editor...
if (editor->cursor.line < 0) // ...or above...
editor->cursor.line = 0; // ...first line of editor
/* In read-only mode, stop scrolling down when the bottom line of the text
* is visible at the bottom of the window */
if (ATB_edit_Mode(editor,ED_MODE_READONLY))
{
if (editor->numLines>=editor->linesPerScreen
&& editor->cursor.line >= (editor->numLines - editor->linesPerScreen))
{
editor->cursor.line = (editor->numLines - editor->linesPerScreen);
}
editor->winStartLine = editor->cursor.line;
}
}
/* Reset all our horizontal variables */
editor->thischar.pos = 0;
editor->thischar.lineWidth = 0;
editComplete = TRUE;
editor->endOfText = FALSE;
editor->space.pos = 0;
/* Work out how many lines fit on the current screen */
ATB_edit_UpdateCursorPos(editor);
lineNo = 0;
/* Update the line where we start showing the text on the window */
if (editor->cursor.line < editor->winStartLine) //cursor is on a line before current window screen
{
editor->winStartLine = editor->cursor.line;
editComplete = FALSE;
}
else if (editor->cursor.line >= (editor->winStartLine+editor->linesPerScreen)) //cursor is below the bottom of the screen
{
editor->winStartLine = editor->cursor.line-(editor->linesPerScreen-1);
editComplete = FALSE;
}
if (dy!= 0) /* If we're moving up or down */
{
editComplete = FALSE;
}
if (!editComplete) /* Calculate new cursor X and Y positions */
{
if (dy!=0) /* If we've changed line, find new X position */
{
line = ATB_edit_LineGet(editor, editor->cursor.line);
editor->thischar.lineWidth = 0;
linePos = line->pos; // Start of current line
ATB_display_CopyFormat(&editor->thischar.format, &line->format); // Format attributes of 1st character
/* Get column - is always a multiple of the maximum character width. Makes sure cursor doesn't wander
* left or right too much when moving up or down by lines */
cursorColumn = editor->cursor.x - (editor->cursor.x % ATB_display_GetMaxCharWidth(&editor->thischar.format));
/* Search until we're in the column or at the end of the line */
while (editor->thischar.lineWidth<cursorColumn && linePos < (line->next->pos-1))
{
character = ATB_string_GetChar(&editor->attr->text, linePos);
editor->thischar.width = ATB_display_GetCharWidth(character, &editor->thischar.format); // Character width
editor->thischar.lineWidth += editor->thischar.width;
linePos++;
}
/* Set the new cursor X position */
cursorCharPos = linePos; // New cursor position in buffer
editor->cursor.width = editor->thischar.width; // Set the width of the cursor
editor->cursor.x = editor->thischar.lineWidth; // And its position
editor->cursor.attr = editor->thischar.format.attr; // Save the format attribute
}
ATB_edit_UpdateCursorPos(editor);
}
/* Change cursor position */
editor->cursor.pos = cursorCharPos;
return ED_OK;
}
/*******************************************************************************
$Function: ATB_edit_WordWrap
$Description: Main word wrap function. Takes in the characters of the string
one by one, calculating the total width displayed on screen and setting flags
when a string should be wrapped, a carriage return is encountered, the end
of string has been reached.
Tracks the last space character and goes back there when a word runs over
the edge of the screen. Also works out the height of the current line, based on
the maximum character height found.
$Returns: None
$Arguments: editor - The editor data
*******************************************************************************/
static void ATB_edit_WordWrap(T_ED_DATA *editor)
{
USHORT character;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -