scummvm/engines/saga2/gtextbox.cpp
2021-07-04 11:54:29 -07:00

1113 lines
30 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* aint32 with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
* Based on the original sources
* Faery Tale II -- The Halls of the Dead
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
*/
#include "saga2/saga2.h"
#include "saga2/cmisc.h"
#include "saga2/fta.h"
#include "saga2/panel.h"
#include "saga2/gtextbox.h"
namespace Saga2 {
// definitions
Rect16 editBaseRect(7,
45,
314,
111);
/* ===================================================================== *
Imports
* ===================================================================== */
// These are all things that need to be moved to their proper places.
extern gFont *mainFont;
extern gMousePointer pointer; // the actual pointer
//-----------------------------------------------------------------------
// init
#define SpecialKey(k) ((k>>8)+0x80)
/****** gtextbox.cpp/gTextBox [class] ******************************
*
* NAME
* gTextBox class -- an editable text string control
*
* FUNCTION
* This class manifests as a "string gadget" or editable text
* box. You supply the buffer of characters to be edited (although
* it will create an undo buffer).
*
* gTextBox has the ability to "pass through" some keystrokes
* to the application (such as ESC and TAB) if desired.
*
* It does not currently support the concept of cut & paste.
*
* This class returns true to the "tabSelect" query indicating
* that it is tab-selectable.
*
* /h2/NOTIFICATIONS
* This class sends a gEventNewValue whenever the text box becomes
* deactivated. If the deactivation occured because of the user
* hitting return, then the value of the event will be 1; In all
* other cases it is zero.
*
* In addition, a gEventAltValue is sent for each character
* typed. (Value is always 0). This is to allow other displays
* to be dynamically updated as the user types.
*
* SEE ALSO
* gControl class
* gTextBox::gTextBox
* gTextBox::setValue
*
**********************************************************************
*/
/****** gtextbox.cpp/gTextBox::gTextBox ******************************
*
* NAME
* gTextBox::gTextBox -- constructor for editable text box
*
* SYNOPSIS
* new gTextBox( list, rect, title, buffer, length, flags, id, cmd );
*
* gTextBox::gTextBox ( gPanelList &, const Rect16 &, char *,
* /c/ char *, uint16, uint16, uint16, AppFunc * = NULL );
*
* FUNCTION
* The constructor for gTextBox initializes the cursor position,
* scroll position, and text buffers. It also allocates a temporary
* undo buffer which is deleted by the destructor.
*
* INPUTS
* list Can be either a gWindow or a gPanelList. The newly
* constructed control will be placed on the contentsList
* of the gWindow or gPanelList. In addition, the panel's
* window pointer will be initialized to the gWindow
* argument, or to the gPanelList's gWindow pointer if
* a gPanelList is passed.
*
* rect Defines the rectangular area of the gControl.
*
* title The title of the text box.
*
* buffer The buffer to place the text in. If the buffer
* contains text initially, that text will be
* shown when the control is drawn.
*
* length The maximum length of the text buffer.
*
* flag Various flags which control operation of the
* text box:
*
* /i/ textBoxAlignRight causes the text to
* be right-justified within the box.
*
* /i/ textBoxAlignCenter causes the text to be centered within the box.
*
* /i/ textBoxNoFilter indicates that non-edit keys
* (such as ESC and TAB) should be passed on to the
* application's AppFunc.
*
* /i/ textBoxStayActive tells the text box not to
* deactivate when the user hits return.
*
* id A 16-bit Application-specific ID for this panel.
*
* cmd [Optional Argument] A pointer to the AppFunction
* for this panel. AppFunctions are application-defined
* callback functions, and should be created using the
* APPFUNC() macro.
*
* RESULT
*
**********************************************************************
*/
gTextBox::gTextBox(
gPanelList &list,
const Rect16 &box,
gFont *font,
int8 height,
int8 FGColor,
int8 BGColor,
int8 HLColor,
byte BGHLColor,
byte CRColor,
const char *title_,
const char *buffer,
char **stringBufs,
uint16 length,
uint16 flg,
uint16 ident,
bool noEditing,
AppFunc *cmd,
AppFunc *cmdEnter,
AppFunc *cmdEscape)
: gControl(list, box, title_, ident, cmd) {
int16 i;
hilit = false;
noUndo = false;
index = 0; // index into string array ( which string )
maxLen = length;
flags = flg;
currentLen[index] = buffer ? strlen(buffer) : 0;
cursorPos = anchorPos = scrollPixels = 0;
undoBuffer = new char[maxLen + 1]();
textFont = font;
fontHeight = height;
fontOffset = fontHeight + 2;
fontColorFore = FGColor;
fontColorBack = BGColor;
fontColorHilite = HLColor;
fontColorBackHilite = BGHLColor;
cursorColor = CRColor;
linesPerPage = (box.height / fontOffset);
endLine = clamp(0, (index + linesPerPage), numEditLines);
oldMark = -1;
displayOnly = noEditing;
editing = false;
editRect = box;
editRect.height = fontHeight;
inDrag = false;
onEnter = cmdEnter;
onEscape = cmdEscape;
isActiveCtl = false;
selected = 0;
parent = &list;
// set the filedStrings pointer
fieldStrings = stringBufs;
// get the size of each string
for (i = 0; i < numEditLines; i++) {
exists[i] = ((stringBufs[i][0] & 0x80) == 0);
stringBufs[i][0] &= 0x7F;
currentLen[i] = MIN<int>(editLen, strlen(stringBufs[i]));
}
internalBuffer = false;
fullRedraw = true;
index = 0;
enSelect(0);
if (!displayOnly) {
cursorPos = 0;
anchorPos = currentLen[index];
}
fullRedraw = true;
}
//-----------------------------------------------------------------------
gTextBox::~gTextBox() {
deSelect();
selected = 0;
if (undoBuffer) {
delete[] undoBuffer;
}
}
/****** gtextbox.cpp/gTextBox::insertText ****************************
*
* NAME
* gTextBox::insertText -- insert text at current cursor position
*
* SYNOPSIS
* success = textBox->insertText( newText, length );
*
* bool gTextBox::insertText( char *, int );
*
* FUNCTION
* This function inserts the text string "newText" into the
* text box at the current cursor position. If a range of
* characters are selected, they will be deleted and replaced
* with the new text. The text box will be redrawn in any case.
*
* INPUTS
* newText The text string to insert.
*
* length How many characters to insert.
*
* RESULT
* true if there was enough room in the buffer to insert the text.
*
**********************************************************************
*/
bool gTextBox::insertText(char *newText, int length) {
int16 selStart = MIN(cursorPos, anchorPos),
selWidth = ABS(cursorPos - anchorPos),
selEnd = selStart + selWidth;
if (length == -1) length = strlen(newText);
// If inserting the text would make the string too long,
// then don't insert it.
if (currentLen[index] - selWidth + length >= maxLen) return false;
// Move the text after the selection to where it will be
// after the insertion.
if (selEnd < currentLen[index]) {
memmove(fieldStrings[index] + selStart + length,
fieldStrings[index] + selEnd,
currentLen[index] - selEnd);
}
// Move the inserted text, if any, to the opening
if (length > 0) {
memmove(fieldStrings[index] + selStart, newText, length);
}
// Set the insertion point to the end of the new text.
cursorPos = anchorPos = selStart + length;
currentLen[index] += (length - selWidth);
fieldStrings[index][currentLen[index]] = '\0';
return true;
}
/****** gtextbox.cpp/gTextBox::setText *******************************
*
* NAME
* gTextBox::setText -- set the text in the text box.
*
* SYNOPSIS
* textBox->setText( newText );
*
* void gTextBox::setText( char * );
*
* FUNCTION
* This function replaces the contents of the text buffer with
* the string "newText" which is assumed to be NULL-terminated.
* The text box is redrawn.
*
* INPUTS
* newText A null terminated string.
*
* RESULT
* none
*
**********************************************************************
*/
void gTextBox::setText(char *newText) {
int16 len = MIN((int)(strlen(newText)), (int)(maxLen - 1));
cursorPos = 0;
anchorPos = currentLen[index];
insertText(newText, len);
cursorPos = anchorPos = 0;
if (window.isOpen()) drawContents();
}
//-----------------------------------------------------------------------
void gTextBox::setEditExtent(const Rect16 &r) {
editRect.x = r.x;
editRect.y = r.y;
editRect.width = r.width;
editRect.height = r.height;
}
//-----------------------------------------------------------------------
bool gTextBox::activate(gEventType why) {
if (why == gEventAltValue) { // momentarily depress
selected = 1;
notify(why, 0); // notify App of successful hit
return true;
}
isActiveCtl = true;
if (!selected) {
enSelect(index);
}
selected = 1;
fullRedraw = true;
draw();
if (why == gEventNone)
return true;
return gPanel::activate(why);
}
//-----------------------------------------------------------------------
void gTextBox::deactivate(void) {
selected = 0;
isActiveCtl = false;
draw();
fullRedraw = true;
gPanel::deactivate();
}
//-----------------------------------------------------------------------
void gTextBox::prepareEdit(int which) {
if (!displayOnly) {
if (undoBuffer) memcpy(undoBuffer, fieldStrings[which], currentLen[which] + 1);
undoLen = currentLen[which];
}
}
//-----------------------------------------------------------------------
bool gTextBox::changed(void) {
if (undoBuffer && editing) {
return memcmp(undoBuffer, fieldStrings[index], currentLen[index] + 1);
}
return false;
}
//-----------------------------------------------------------------------
void gTextBox::commitEdit(void) {
if (undoBuffer && changed()) {
memcpy(undoBuffer, fieldStrings[index], currentLen[index] + 1);
undoLen = currentLen[index];
cursorPos = anchorPos = currentLen[index];
notify(gEventNewValue, 1); // tell app about new value
}
}
//-----------------------------------------------------------------------
void gTextBox::revertEdit(void) {
if (undoBuffer && changed()) {
cursorPos = anchorPos = currentLen[index] = undoLen;
memcpy(fieldStrings[index], undoBuffer, currentLen[index] + 1);
notify(gEventNewValue, 0); // tell app about new value
}
}
//-----------------------------------------------------------------------
// LINE SELECTION
//-----------------------------------------------------------------------
// Choose the part of the list to display & the specific Item in that list
void gTextBox::scroll(int8 req) {
int16 indexReq = req;
int16 oldIndex = index;
int16 visOld = (oldIndex - (endLine - linesPerPage));
int16 visBase = endLine;
int16 visIndex;
indexReq = clamp(0, indexReq, numEditLines);
visIndex = (indexReq - (visBase - linesPerPage));
if (ABS(oldIndex - indexReq) < 2) {
if (visIndex < 0) {
visBase--;
visIndex++;
} else if (visIndex >= linesPerPage) {
visBase++;
visIndex--;
}
} else {
while (visIndex >= linesPerPage) {
visBase = clamp(linesPerPage, visBase + linesPerPage, numEditLines);
visIndex = (indexReq - (visBase - linesPerPage));
}
while (visIndex < 0) {
visBase = clamp(linesPerPage, visBase - linesPerPage, numEditLines);
visIndex = (indexReq - (visBase - linesPerPage));
}
}
if (endLine != visBase) {
fullRedraw = true;
}
endLine = visBase;
if (visIndex != visOld) {
Rect16 textBoxExtent = editRect;
// setup the editing extent
textBoxExtent.y = (fontOffset * visIndex) + extent.y;
setEditExtent(textBoxExtent);
fullRedraw = true;
}
}
//-----------------------------------------------------------------------
void gTextBox::deSelect(bool commit) {
if (index >= 0 && editing) {
if (commit)
commitEdit();
else
revertEdit();
editing = false;
fullRedraw = true;
}
}
//-----------------------------------------------------------------------
void gTextBox::enSelect(int which) {
scroll(which);
index = which;
if (!displayOnly) {
prepareEdit(which);
editing = true;
cursorPos = 0;
anchorPos = currentLen[index];
} else {
hilit = true;
}
}
//-----------------------------------------------------------------------
void gTextBox::reSelect(int which) {
if (which != index) {
deSelect(false);
draw();
enSelect(which);
fullRedraw = true;
}
}
//-----------------------------------------------------------------------
// select a nearby line of text
void gTextBox::selectionMove(int howMany) {
int8 newIndex;
newIndex = clamp(0, index + howMany, numEditLines - 1);
#ifndef ALLOW_BAD_LOADS
if (displayOnly) {
int i = newIndex;
if (howMany > 0) {
while (!exists[i] && i < numEditLines - 1) i++;
if (!exists[i]) {
i = newIndex;
while (!exists[i] && i > 0) i--;
}
if (exists[i])
newIndex = i;
} else {
while (!exists[i] && i > 0) i--;
if (!exists[i]) {
i = newIndex;
while (!exists[i] && i < numEditLines - 1) i++;
}
if (exists[i])
newIndex = i;
}
}
#endif
reSelect(newIndex);
if (!displayOnly) {
cursorPos = 0;
anchorPos = currentLen[index];
}
draw();
//activate(gEventAltValue);
}
//-----------------------------------------------------------------------
void gTextBox::scrollUp(void) {
selectionUp(linesPerPage - 2);
}
//-----------------------------------------------------------------------
void gTextBox::scrollDown(void) {
selectionDown(linesPerPage - 2);
}
//-----------------------------------------------------------------------
// INPUT HANDLING
//-----------------------------------------------------------------------
bool gTextBox::pointerHit(gPanelMessage &msg) {
Point16 pos = msg.pickPos;
int16 newPos;
if (Rect16(0, 0, extent.width, extent.height).ptInside(pos)) {
int8 newIndex;
// get the position of the line
newIndex = clamp(0, pos.y / fontOffset, linesPerPage - 1);
newIndex = (endLine - (linesPerPage - newIndex));
if (index != newIndex)
reSelect(newIndex);
if (editing) {
if (textFont) {
newPos = WhichIChar(textFont, (uint8 *)fieldStrings[index], msg.pickPos.x - 3, currentLen[index]);
} else {
newPos = WhichIChar(mainFont, (uint8 *)fieldStrings[index], msg.pickPos.x - 3, currentLen[index]);
}
if (msg.leftButton) {
if (cursorPos != newPos || anchorPos != newPos) {
anchorPos = newPos;
cursorPos = newPos;
}
}
draw();
}
if (!isActive()) {
makeActive();
}
}
return true; //gControl::activate( gEventMouseDown );
}
//-----------------------------------------------------------------------
// Drag-select the text.
void gTextBox::pointerDrag(gPanelMessage &msg) {
int16 newPos;
if (msg.leftButton) {
if (textFont) {
newPos = WhichIChar(textFont, (uint8 *)fieldStrings[index], msg.pickPos.x - 3, currentLen[index]);
} else {
newPos = WhichIChar(mainFont, (uint8 *)fieldStrings[index], msg.pickPos.x - 3, currentLen[index]);
}
inDrag = true;
if (cursorPos != newPos) {
//if (newPos<cursorPos)
cursorPos = newPos;
//else
// anchorPos = newPos ;
}
draw();
}
}
//-----------------------------------------------------------------------
// Mouse release code
void gTextBox::pointerRelease(gPanelMessage &msg) {
if (!msg.leftButton) {
inDrag = false;
draw();
}
}
//-----------------------------------------------------------------------
bool gTextBox::keyStroke(gPanelMessage &msg) {
gPort &port = window.windowPort;
int16 selStart = MIN(cursorPos, anchorPos),
selWidth = ABS(cursorPos - anchorPos);
uint8 key = msg.key;
// Process the various keystrokes...
if (editing && cursorPos > anchorPos) {
cursorPos = anchorPos;
anchorPos = cursorPos;
}
if (key > 0x80) {
switch (key) {
case SpecialKey(upArrowKey):
selectionUp(1);
return true;
case SpecialKey(downArrowKey):
selectionDown(1);
return true;
case SpecialKey(pageUpKey):
selectionUp(linesPerPage);
return true;
case SpecialKey(pageDownKey):
selectionDown(linesPerPage);
return true;
}
}
if ((key > 0x80) && editing) {
switch (key) {
case SpecialKey(leftArrowKey):
if (anchorPos > 0) anchorPos--;
if (!(msg.qualifier & qualifierShift)) cursorPos = anchorPos;
break;
case SpecialKey(rightArrowKey):
if (anchorPos < currentLen[index]) anchorPos++;
if (!(msg.qualifier & qualifierShift)) cursorPos = anchorPos;
break;
case SpecialKey(homeKey):
cursorPos = 0;
anchorPos = 0;
break;
case SpecialKey(endKey):
cursorPos = currentLen[index];
anchorPos = currentLen[index];
break;
case SpecialKey(deleteKey): // DELETE character
if (selWidth == 0) { // if insertion point
// don't delete if at end
if (selStart >= currentLen[index]) return false;
selWidth = 1; // delete 1 char
}
// Delete N chars
memmove(fieldStrings[index] + selStart,
fieldStrings[index] + selStart + selWidth,
currentLen[index] - (selStart + selWidth));
cursorPos = anchorPos = selStart;// adjust cursor pos
currentLen[index] -= selWidth; // adjust str len
notify(gEventAltValue, 0); // tell app about new value
break;
case SpecialKey(0x2c00): // Alt-Z
if (undoBuffer) {
cursorPos = anchorPos = currentLen[index] = undoLen;
memcpy(fieldStrings[index], undoBuffer, currentLen[index] + 1);
notify(gEventAltValue, 0); // tell app about new value
}
break;
default:
if (flags & textBoxNoFilter) return false;
break;
}
} else if (key == '\r' || key == '\n') { // return key
if (editing) {
commitEdit();
if (!(flags & textBoxStayActive)) {
deactivate(); // deactivate the text box
}
}
if (onEnter != NULL) {
gEvent ev;
ev.eventType = gEventKeyDown ;
ev.value = 1;
ev.panel = parent;
(*onEnter)(ev);
}
return true;
} else if (key == 0x1B) { // escape key
revertEdit();
deactivate(); // deactivate the text box
if (onEscape != NULL) {
gEvent ev;
ev.eventType = gEventKeyDown ;
ev.value = 1;
ev.value = 1;
ev.panel = this; //parent;
(*onEscape)(ev);
}
if (flags & textBoxNoFilter) return false;
return true;
} else if (key == '\b' && editing) { // BACKSPACE
if (selWidth == 0) { // if insertion point
if (selStart < 1) return false; // if at start, do nothing
selStart--; // if I-bar, backup 1 char
selWidth = 1; // delete 1 char
}
// Delete N chars
memmove(fieldStrings[index] + selStart,
fieldStrings[index] + selStart + selWidth,
currentLen[index] - (selStart + selWidth));
cursorPos = anchorPos = selStart; // adjust cursor pos
currentLen[index] -= selWidth; // adjust str len
notify(gEventAltValue, 0); // tell app about new value
} else if (key == SpecialKey(deleteKey) && editing) { // DELETE character
if (selWidth == 0) { // if insertion point
// don't delete if at end
if (selStart >= currentLen[index]) return false;
selWidth = 1; // delete 1 char
}
// Delete N chars
memmove(fieldStrings[index] + selStart,
fieldStrings[index] + selStart + selWidth,
currentLen[index] - (selStart + selWidth));
cursorPos = anchorPos = selStart; // adjust cursor pos
currentLen[index] -= selWidth; // adjust str len
notify(gEventAltValue, 0); // tell app about new value
} else if (key == '\t' && editing) return false; // reprocess keystroke
else if (key == 26 && editing) { // control-z
if (undoBuffer) {
cursorPos = anchorPos = currentLen[index] = undoLen;
memcpy(fieldStrings[index], undoBuffer, currentLen[index] + 1);
notify(gEventAltValue, 0); // tell app about new value
}
} else if (editing) {
// Insert text, if it will fit
if (insertText((char *)&key, 1) == false) return false;
notify(gEventAltValue, 0); // tell app about new value
}
if (editing) {
fieldStrings[index][currentLen[index]] = '\0';
// Now, redraw the contents.
SAVE_GPORT_STATE(port); // save pen color, etc.
pointer.hide(port, extent); // hide mouse pointer
drawContents(); // draw the string
pointer.show(port, extent); // show mouse pointer
return true;
}
return false;
}
//-----------------------------------------------------------------------
// PUBLIC INTERFACE
//-----------------------------------------------------------------------
bool gTextBox::tabSelect(void) {
return true;
}
//-----------------------------------------------------------------------
char *gTextBox::getLine(int8 stringIndex) {
// return the save name
return fieldStrings[stringIndex];
}
//-----------------------------------------------------------------------
char *gTextBox::selectedText(int &length) {
length = ABS(cursorPos - anchorPos);
return fieldStrings[index] + MIN(cursorPos, anchorPos);
}
//-----------------------------------------------------------------------
// DRAWING ROUTINES
void gTextBox::timerTick(gPanelMessage &msg) {
handleTimerTick(gameTime);
}
//-----------------------------------------------------------------------
void gTextBox::handleTimerTick(int32 tick) {
if (selected && !displayOnly && editing && !inDrag) {
if (blinkStart == 0) {
blinkState = 0;
blinkStart = tick;
return;
}
if (tick - blinkStart > blinkTime) {
gPort &port = window.windowPort;
SAVE_GPORT_STATE(port); // save pen color, etc.
pointer.hide(port, extent); // hide mouse pointer
port.setPenMap(port.penMap);
port.setStyle(0);
port.setColor(blinkState ? blinkColor0 : blinkColor1);
port.fillRect(editRect.x + blinkX - ((blinkWide + 1) / 2), editRect.y + 1, blinkWide, editRect.height - 1);
pointer.show(port, extent); // show mouse pointer
blinkState = !blinkState;
blinkStart = tick;
}
}
}
//-----------------------------------------------------------------------
void gTextBox::editRectFill(gPort &fillPort, gPen *pen) {
fillPort.setPenMap(pen);
fillPort.setStyle(0);
fillPort.setColor(fontColorBackHilite);
fillPort.fillRect(0, 0, editRect.width, editRect.height);
}
//-----------------------------------------------------------------------
void gTextBox::drawContents(void) {
int16 cPos, aPos;
assert(textFont);
assert(fontColorBack != -1);
gPort &port = window.windowPort,
tPort;
cPos = MIN(cursorPos, anchorPos);
aPos = MAX(cursorPos, anchorPos);
// Allocate a temporary pixel map and render into it.
if (NewTempPort(tPort, editRect.width, editRect.height)) {
int16 cursorX,
anchorX = 0,
hiliteX,
hiliteWidth,
textHeight_;
textHeight_ = fontHeight;
if (hilit || editing) {
// fill in the editing field's background color
editRectFill(tPort, port.penMap);
}
if (selected) { // if panel is selected
// Determine the pixel position of the cursor and
// anchor positions.
if (!displayOnly) {
if (cPos == aPos) {
// If it's an insertion point, then make the cursor
// 1 pixel wide. (And blink it...)
cursorX = TextWidth(textFont, fieldStrings[index], cPos, 0);
anchorX = cursorX + 1;
} else {
if (cPos == 0) {
cursorX = 0;
} else {
cursorX = TextWidth(textFont, fieldStrings[index], cPos, 0) + 1;
}
if (aPos == 0) {
anchorX = 0;
} else {
anchorX = TextWidth(textFont, fieldStrings[index], aPos, 0) + 1;
}
}
// Adjust the scrolling of the text string
if (scrollPixels > cursorX) {
scrollPixels = cursorX;
} else if (scrollPixels + (editRect.width - 1) < cursorX) {
scrollPixels = cursorX - (editRect.width - 1);
}
// Adjust the cursor positions to match the scroll
cursorX -= scrollPixels;
anchorX -= scrollPixels;
#ifdef BADINTERFACE
// If it's a selection, then check to see if either
// end of the selection is after the last character,
// in which case, also include the blank space after
// the end in the highlight.
if (cPos != aPos) {
if (cPos == currentLen[index]) cursorX = editRect.width;
if (aPos == currentLen[index]) anchorX = editRect.width;
}
#endif
hiliteX = MIN(cursorX, anchorX);
hiliteWidth = MAX(cursorX, anchorX) - hiliteX;
tPort.setColor(cursorColor); // draw the highlight
tPort.fillRect(hiliteX, 0, hiliteWidth, editRect.height);
}
}
// set up the font
tPort.setFont(textFont);
tPort.setColor(fontColorHilite);
tPort.moveTo(-scrollPixels, (editRect.height - textHeight_ + 1) / 2);
tPort.drawText(fieldStrings[index], currentLen[index]);
// Blit the pixelmap to the main screen
port.setMode(drawModeMatte);
port.bltPixels(*tPort.map, 0, 0,
editRect.x + 1, editRect.y + 1,
editRect.width, editRect.height);
blinkStart = 0;
blinkX = anchorX;
DisposeTempPort(tPort); // dispose of temporary pixelmap
}
}
//-----------------------------------------------------------------------
void gTextBox::drawClipped(void) {
gPort &port = window.windowPort;
Rect16 rect = window.getExtent();
#if 0
if (!inDrag && cursorPos > anchorPos) {
int16 t = cursorPos;
cursorPos = anchorPos;
anchorPos = cursorPos;
}
#endif
WriteStatusF(11, "Entry %d[%d] (%d:%d)", index, currentLen[index], cursorPos, anchorPos);
SAVE_GPORT_STATE(port); // save pen color, etc.
pointer.hide(port, extent); // hide mouse pointer
if (fullRedraw) {
drawAll(port, Point16(0, 0), Rect16(0, 0, rect.width, rect.height));
fullRedraw = false;
}
if (editing) {
drawContents(); // draw the string
drawTitle(textPosLeft); // draw the title
} else if (displayOnly && hilit) {
drawContents();
} else {
drawAll(port, Point16(0, 0), Rect16(0, 0, rect.width, rect.height));
}
pointer.show(port, extent); // show mouse pointer
}
//-----------------------------------------------------------------------
void gTextBox::drawAll(gPort &port,
const Point16 &offset,
const Rect16 &) {
assert(textFont);
gPort tempPort;
Rect16 bufRect = Rect16(0, 0, 0, 0);
int16 i;
bufRect.width = editBaseRect.width;
bufRect.height = editBaseRect.height;
// Allocate a temporary pixel map and render into it.
if (NewTempPort(tempPort, bufRect.width, bufRect.height)) {
Rect16 workRect;
workRect = bufRect;
workRect.x -= offset.x;
workRect.y -= offset.y;
if (endLine != oldMark || fullRedraw) {
// setup the tempPort
tempPort.setMode(drawModeMatte);
// if the text is going to change
tempPort.setColor(fontColorBack);
tempPort.fillRect(workRect);
// draw as glyph
tempPort.setMode(drawModeMatte);
// pen color black
tempPort.setColor(fontColorFore);
// font
oldFont = tempPort.font;
tempPort.setFont(textFont);
for (i = (endLine - linesPerPage); i < endLine; i++) {
assert(i >= 0 && i <= numEditLines);
// move to new text pos
tempPort.moveTo(workRect.x, workRect.y);
// pen color black
tempPort.setColor(((i != index) && exists[i]) ? fontColorFore : textDisable);
// draw the text
tempPort.drawText(fieldStrings[i]);
//increment the position
workRect.y += fontOffset;
}
oldMark = endLine;
// reset the old font
tempPort.setFont(oldFont);
// Blit the pixelmap to the main screen
port.setMode(drawModeMatte);
port.bltPixels(*tempPort.map, 0, 0,
extent.x + 1, extent.y + 1,
bufRect.width, bufRect.height);
}
DisposeTempPort(tempPort); // dispose of temporary pixelmap
}
}
} // end of namespace Saga2