#include <utils/common/StdDefs.h>
#include <utils/gui/div/GUIDesigns.h>
#include <fxkeys.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4266)
#endif
#include <FX88591Codec.h>
#include <FXUTF16Codec.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "MFXStaticToolTip.h"
#include "MFXTextFieldIcon.h"
#define JUSTIFY_MASK (JUSTIFY_HZ_APART|JUSTIFY_VT_APART)
#define TEXTFIELD_MASK (TEXTFIELD_PASSWD|TEXTFIELD_INTEGER|TEXTFIELD_REAL|TEXTFIELD_READONLY|TEXTFIELD_ENTER_ONLY|TEXTFIELD_LIMITED|TEXTFIELD_OVERSTRIKE|TEXTFIELD_AUTOHIDE|TEXTFIELD_AUTOGRAY)
#define ICON_SPACING 4
#define ICON_SIZE 16
FXDEFMAP(MFXTextFieldIcon) MFXTextFieldIconMap[] = {
FXMAPFUNC(SEL_CLIPBOARD_GAINED, 0, MFXTextFieldIcon::onClipboardGained),
FXMAPFUNC(SEL_CLIPBOARD_LOST, 0, MFXTextFieldIcon::onClipboardLost),
FXMAPFUNC(SEL_CLIPBOARD_REQUEST, 0, MFXTextFieldIcon::onClipboardRequest),
FXMAPFUNC(SEL_ENTER, 0, MFXTextFieldIcon::onEnter),
FXMAPFUNC(SEL_FOCUS_SELF, 0, MFXTextFieldIcon::onFocusSelf),
FXMAPFUNC(SEL_FOCUSIN, 0, MFXTextFieldIcon::onFocusIn),
FXMAPFUNC(SEL_FOCUSOUT, 0, MFXTextFieldIcon::onFocusOut),
FXMAPFUNC(SEL_KEYPRESS, 0, MFXTextFieldIcon::onKeyPress),
FXMAPFUNC(SEL_KEYRELEASE, 0, MFXTextFieldIcon::onKeyRelease),
FXMAPFUNC(SEL_LEAVE, 0, MFXTextFieldIcon::onLeave),
FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, MFXTextFieldIcon::onLeftBtnPress),
FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, MFXTextFieldIcon::onLeftBtnRelease),
FXMAPFUNC(SEL_MIDDLEBUTTONPRESS, 0, MFXTextFieldIcon::onMiddleBtnPress),
FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE, 0, MFXTextFieldIcon::onMiddleBtnRelease),
FXMAPFUNC(SEL_MOTION, 0, MFXTextFieldIcon::onMotion),
FXMAPFUNC(SEL_PAINT, 0, MFXTextFieldIcon::onPaint),
FXMAPFUNC(SEL_QUERY_HELP, 0, MFXTextFieldIcon::onQueryHelp),
FXMAPFUNC(SEL_QUERY_TIP, 0, MFXTextFieldIcon::onQueryTip),
FXMAPFUNC(SEL_SELECTION_GAINED, 0, MFXTextFieldIcon::onSelectionGained),
FXMAPFUNC(SEL_SELECTION_LOST, 0, MFXTextFieldIcon::onSelectionLost),
FXMAPFUNC(SEL_SELECTION_REQUEST, 0, MFXTextFieldIcon::onSelectionRequest),
FXMAPFUNC(SEL_UPDATE, 0, MFXTextFieldIcon::onUpdate),
FXMAPFUNC(SEL_VERIFY, 0, MFXTextFieldIcon::onVerify),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_BACKSPACE, MFXTextFieldIcon::onCmdBackspace),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_COPY_SEL, MFXTextFieldIcon::onCmdCopySel),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_END, MFXTextFieldIcon::onCmdCursorEnd),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_HOME, MFXTextFieldIcon::onCmdCursorHome),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_LEFT, MFXTextFieldIcon::onCmdCursorLeft),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_RIGHT, MFXTextFieldIcon::onCmdCursorRight),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_END, MFXTextFieldIcon::onCmdCursorWordEnd),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_LEFT, MFXTextFieldIcon::onCmdCursorWordLeft),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_RIGHT, MFXTextFieldIcon::onCmdCursorWordRight),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_START, MFXTextFieldIcon::onCmdCursorWordStart),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CUT_SEL, MFXTextFieldIcon::onCmdCutSel),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_DELETE, MFXTextFieldIcon::onCmdDelete),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_DELETE_ALL, MFXTextFieldIcon::onCmdDeleteAll),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_DELETE_SEL, MFXTextFieldIcon::onCmdDeleteSel),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_DESELECT_ALL, MFXTextFieldIcon::onCmdDeselectAll),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_EXTEND, MFXTextFieldIcon::onCmdExtend),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETHELPSTRING, MFXTextFieldIcon::onCmdGetHelp),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETINTVALUE, MFXTextFieldIcon::onCmdGetIntValue),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETREALVALUE, MFXTextFieldIcon::onCmdGetRealValue),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETSTRINGVALUE, MFXTextFieldIcon::onCmdGetStringValue),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETTIPSTRING, MFXTextFieldIcon::onCmdGetTip),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_INSERT_STRING, MFXTextFieldIcon::onCmdInsertString),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_MARK, MFXTextFieldIcon::onCmdMark),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_OVERST_STRING, MFXTextFieldIcon::onCmdOverstString),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_PASTE_MIDDLE, MFXTextFieldIcon::onCmdPasteMiddle),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_PASTE_SEL, MFXTextFieldIcon::onCmdPasteSel),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SELECT_ALL, MFXTextFieldIcon::onCmdSelectAll),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETHELPSTRING, MFXTextFieldIcon::onCmdSetHelp),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETINTVALUE, MFXTextFieldIcon::onCmdSetIntValue),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETREALVALUE, MFXTextFieldIcon::onCmdSetRealValue),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETSTRINGVALUE, MFXTextFieldIcon::onCmdSetStringValue),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETTIPSTRING, MFXTextFieldIcon::onCmdSetTip),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETVALUE, MFXTextFieldIcon::onCmdSetValue),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_TOGGLE_EDITABLE, MFXTextFieldIcon::onCmdToggleEditable),
FXMAPFUNC(SEL_COMMAND, FXTextField::ID_TOGGLE_OVERSTRIKE, MFXTextFieldIcon::onCmdToggleOverstrike),
FXMAPFUNC(SEL_TIMEOUT, FXTextField::ID_AUTOSCROLL, MFXTextFieldIcon::onAutoScroll),
FXMAPFUNC(SEL_TIMEOUT, FXTextField::ID_BLINK, MFXTextFieldIcon::onBlink),
FXMAPFUNC(SEL_UPDATE, FXTextField::ID_COPY_SEL, MFXTextFieldIcon::onUpdHaveSelection),
FXMAPFUNC(SEL_UPDATE, FXTextField::ID_CUT_SEL, MFXTextFieldIcon::onUpdHaveSelection),
FXMAPFUNC(SEL_UPDATE, FXTextField::ID_DELETE_SEL, MFXTextFieldIcon::onUpdHaveSelection),
FXMAPFUNC(SEL_UPDATE, FXTextField::ID_PASTE_SEL, MFXTextFieldIcon::onUpdYes),
FXMAPFUNC(SEL_UPDATE, FXTextField::ID_SELECT_ALL, MFXTextFieldIcon::onUpdSelectAll),
FXMAPFUNC(SEL_UPDATE, FXTextField::ID_TOGGLE_EDITABLE, MFXTextFieldIcon::onUpdToggleEditable),
FXMAPFUNC(SEL_UPDATE, FXTextField::ID_TOGGLE_OVERSTRIKE, MFXTextFieldIcon::onUpdToggleOverstrike),
};
FXIMPLEMENT(MFXTextFieldIcon, FXFrame, MFXTextFieldIconMap, ARRAYNUMBER(MFXTextFieldIconMap))
MFXTextFieldIcon::MFXTextFieldIcon(FXComposite* p, MFXStaticToolTip* staticToolTip, GUIIcon icon, FXObject* tgt, FXSelector sel,
FXuint opts, FXint x, FXint y, FXint w, FXint h, FXint pl, FXint pr, FXint pt, FXint pb) :
FXFrame(p, opts, x, y, w, h, pl, pr, pt, pb),
myStaticToolTip(staticToolTip) {
if (icon != GUIIcon::EMPTY) {
myIcon = GUIIconSubSys::getIcon(icon);
}
flags |= FLAG_ENABLED;
target = tgt;
message = sel;
if (!(options & JUSTIFY_RIGHT)) {
options |= JUSTIFY_LEFT;
}
defaultCursor = getApp()->getDefaultCursor(DEF_TEXT_CURSOR);
dragCursor = getApp()->getDefaultCursor(DEF_TEXT_CURSOR);
myFont = getApp()->getNormalFont();
backColor = getApp()->getBackColor();
myTextColor = getApp()->getForeColor();
mySelectedBackgroundColor = getApp()->getSelbackColor();
mySelectedTextColor = getApp()->getSelforeColor();
myCursorColor = getApp()->getForeColor();
myVisibleColumns = GUIDesignTextFieldNCol;
}
MFXTextFieldIcon::~MFXTextFieldIcon() {
getApp()->removeTimeout(this, FXTextField::ID_BLINK);
getApp()->removeTimeout(this, ID_AUTOSCROLL);
myFont = (FXFont*) - 1L;
}
void
MFXTextFieldIcon::create() {
FXFrame::create();
if (!textType) {
textType = getApp()->registerDragType(textTypeName);
}
if (!utf8Type) {
utf8Type = getApp()->registerDragType(utf8TypeName);
}
if (!utf16Type) {
utf16Type = getApp()->registerDragType(utf16TypeName);
}
myFont->create();
}
void
MFXTextFieldIcon::setFont(FXFont* fnt) {
if (!fnt) {
fxerror("%s::setFont: NULL font specified.\n", getClassName());
}
if (myFont != fnt) {
myFont = fnt;
recalc();
update();
}
}
FXFont*
MFXTextFieldIcon::getFont() const {
return myFont;
}
void
MFXTextFieldIcon::enable() {
if (!(flags & FLAG_ENABLED)) {
FXFrame::enable();
update();
}
}
void
MFXTextFieldIcon::disable() {
if (flags & FLAG_ENABLED) {
FXFrame::disable();
update();
}
}
FXint
MFXTextFieldIcon::getDefaultWidth() {
return padleft + padright + (border << 1) + myVisibleColumns * myFont->getTextWidth("8", 1);
}
FXint
MFXTextFieldIcon::getDefaultHeight() {
return padtop + padbottom + (border << 1) + myFont->getFontHeight();
}
long
MFXTextFieldIcon::onUpdate(FXObject* sender, FXSelector sel, void* ptr) {
if (!FXFrame::onUpdate(sender, sel, ptr)) {
if (options & TEXTFIELD_AUTOHIDE) {
if (shown()) {
hide();
recalc();
}
}
if (options & TEXTFIELD_AUTOGRAY) {
disable();
}
}
return 1;
}
long
MFXTextFieldIcon::onSelectionGained(FXObject* sender, FXSelector sel, void* ptr) {
FXFrame::onSelectionGained(sender, sel, ptr);
update();
return 1;
}
long
MFXTextFieldIcon::onSelectionLost(FXObject* sender, FXSelector sel, void* ptr) {
FXFrame::onSelectionLost(sender, sel, ptr);
update();
return 1;
}
long
MFXTextFieldIcon::onSelectionRequest(FXObject* sender, FXSelector sel, void* ptr) {
FXEvent* event = (FXEvent*)ptr;
FXString string;
FXuint start;
FXuint len;
FXASSERT(0 <= myAnchorPosition && myAnchorPosition <= contents.length());
FXASSERT(0 <= myCursorPosition && myCursorPosition <= contents.length());
if (FXFrame::onSelectionRequest(sender, sel, ptr)) {
return 1;
}
if (event->target == stringType || event->target == textType || event->target == utf8Type || event->target == utf16Type) {
if (myAnchorPosition < myCursorPosition) {
start = myAnchorPosition;
len = myCursorPosition - myAnchorPosition;
} else {
start = myCursorPosition;
len = myAnchorPosition - myCursorPosition;
}
string = contents.mid(start, len);
if (options & TEXTFIELD_PASSWD) {
string.assign('*', string.count());
}
if (event->target == utf8Type) {
FXTRACE((100, "Request UTF8\n"));
setDNDData(FROM_SELECTION, event->target, string);
return 1;
}
if (event->target == stringType || event->target == textType) {
FX88591Codec ascii;
FXTRACE((100, "Request ASCII\n"));
setDNDData(FROM_SELECTION, event->target, ascii.utf2mb(string));
return 1;
}
if (event->target == utf16Type) {
FXUTF16LECodec unicode;
FXTRACE((100, "Request UTF16\n"));
setDNDData(FROM_SELECTION, event->target, unicode.utf2mb(string));
return 1;
}
}
return 0;
}
long
MFXTextFieldIcon::onClipboardGained(FXObject* sender, FXSelector sel, void* ptr) {
FXFrame::onClipboardGained(sender, sel, ptr);
return 1;
}
long
MFXTextFieldIcon::onClipboardLost(FXObject* sender, FXSelector sel, void* ptr) {
FXFrame::onClipboardLost(sender, sel, ptr);
myClippedText.clear();
return 1;
}
long
MFXTextFieldIcon::onClipboardRequest(FXObject* sender, FXSelector sel, void* ptr) {
FXEvent* event = (FXEvent*)ptr;
FXString string;
if (FXFrame::onClipboardRequest(sender, sel, ptr)) {
return 1;
}
if (event->target == stringType || event->target == textType || event->target == utf8Type || event->target == utf16Type) {
string = myClippedText;
if (options & TEXTFIELD_PASSWD) {
string.assign('*', string.count());
}
if (event->target == utf8Type) {
FXTRACE((100, "Request UTF8\n"));
setDNDData(FROM_CLIPBOARD, event->target, string);
return 1;
}
if (event->target == stringType || event->target == textType) {
FX88591Codec ascii;
FXTRACE((100, "Request ASCII\n"));
setDNDData(FROM_CLIPBOARD, event->target, ascii.utf2mb(string));
return 1;
}
if (event->target == utf16Type) {
FXUTF16LECodec unicode;
FXTRACE((100, "Request UTF16\n"));
setDNDData(FROM_CLIPBOARD, event->target, unicode.utf2mb(string));
return 1;
}
}
return 0;
}
long
MFXTextFieldIcon::onBlink(FXObject*, FXSelector, void*) {
drawCursor(flags ^ FLAG_CARET);
getApp()->addTimeout(this, FXTextField::ID_BLINK, getApp()->getBlinkSpeed());
return 0;
}
long
MFXTextFieldIcon::onFocusIn(FXObject* sender, FXSelector sel, void* ptr) {
FXFrame::onFocusIn(sender, sel, ptr);
if (isEditable()) {
getApp()->addTimeout(this, FXTextField::ID_BLINK, getApp()->getBlinkSpeed());
drawCursor(FLAG_CARET);
}
if (hasSelection()) {
update(border, border, width - (border << 1), height - (border << 1));
}
return 1;
}
long
MFXTextFieldIcon::onFocusOut(FXObject* sender, FXSelector sel, void* ptr) {
FXFrame::onFocusOut(sender, sel, ptr);
getApp()->removeTimeout(this, FXTextField::ID_BLINK);
drawCursor(0);
if (hasSelection()) {
update(border, border, width - (border << 1), height - (border << 1));
}
return 1;
}
long
MFXTextFieldIcon::onFocusSelf(FXObject* sender, FXSelector sel, void* ptr) {
if (FXFrame::onFocusSelf(sender, sel, ptr)) {
FXEvent* event = (FXEvent*)ptr;
if (event->type == SEL_KEYPRESS || event->type == SEL_KEYRELEASE) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_SELECT_ALL), NULL);
}
return 1;
}
return 0;
}
bool
MFXTextFieldIcon::canFocus() const {
return true;
}
void
MFXTextFieldIcon::setFocus() {
FXFrame::setFocus();
setDefault(TRUE);
flags &= ~FLAG_UPDATE;
if (getApp()->hasInputMethod()) {
createComposeContext();
}
}
void
MFXTextFieldIcon::killFocus() {
FXFrame::killFocus();
setDefault(MAYBE);
flags |= FLAG_UPDATE;
if (flags & FLAG_CHANGED) {
flags &= ~FLAG_CHANGED;
if (!(options & TEXTFIELD_ENTER_ONLY)) {
if (target) {
target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)contents.text());
}
}
}
if (getApp()->hasInputMethod()) {
destroyComposeContext();
}
}
long
MFXTextFieldIcon::onCmdSetHelp(FXObject*, FXSelector, void* ptr) {
setHelpText(*((FXString*)ptr));
return 1;
}
long
MFXTextFieldIcon::onCmdGetHelp(FXObject*, FXSelector, void* ptr) {
*((FXString*)ptr) = getHelpText();
return 1;
}
long
MFXTextFieldIcon::onCmdSetTip(FXObject*, FXSelector, void* ptr) {
setTipText(*((FXString*)ptr));
return 1;
}
long
MFXTextFieldIcon::onCmdGetTip(FXObject*, FXSelector, void* ptr) {
*((FXString*)ptr) = getTipText();
return 1;
}
long
MFXTextFieldIcon::onQueryTip(FXObject* sender, FXSelector sel, void* ptr) {
if (FXWindow::onQueryTip(sender, sel, ptr)) {
return 1;
}
if ((flags & FLAG_TIP) && !myTooltipText.empty()) {
sender->handle(this, FXSEL(SEL_COMMAND, ID_SETSTRINGVALUE), (void*)&myTooltipText);
return 1;
}
return 0;
}
long
MFXTextFieldIcon::onQueryHelp(FXObject* sender, FXSelector sel, void* ptr) {
if (FXWindow::onQueryHelp(sender, sel, ptr)) {
return 1;
}
if ((flags & FLAG_HELP) && !myHelpText.empty()) {
sender->handle(this, FXSEL(SEL_COMMAND, ID_SETSTRINGVALUE), (void*)&myHelpText);
return 1;
}
return 0;
}
long
MFXTextFieldIcon::onCmdSetValue(FXObject*, FXSelector, void* ptr) {
setText((const FXchar*)ptr);
return 1;
}
long
MFXTextFieldIcon::onCmdSetIntValue(FXObject*, FXSelector, void* ptr) {
setText(FXStringVal(*((FXint*)ptr)));
return 1;
}
long
MFXTextFieldIcon::onCmdSetRealValue(FXObject*, FXSelector, void* ptr) {
setText(FXStringVal(*((FXdouble*)ptr)));
return 1;
}
long
MFXTextFieldIcon::onCmdSetStringValue(FXObject*, FXSelector, void* ptr) {
setText(*((FXString*)ptr));
return 1;
}
long
MFXTextFieldIcon::onCmdGetIntValue(FXObject*, FXSelector, void* ptr) {
*((FXint*)ptr) = FXIntVal(contents);
return 1;
}
long
MFXTextFieldIcon::onCmdGetRealValue(FXObject*, FXSelector, void* ptr) {
*((FXdouble*)ptr) = FXDoubleVal(contents);
return 1;
}
long
MFXTextFieldIcon::onCmdGetStringValue(FXObject*, FXSelector, void* ptr) {
*((FXString*)ptr) = getText();
return 1;
}
long
MFXTextFieldIcon::onLeftBtnPress(FXObject*, FXSelector, void* ptr) {
FXEvent* ev = (FXEvent*)ptr;
flags &= ~FLAG_TIP;
handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
if (isEnabled()) {
grab();
if (target && target->tryHandle(this, FXSEL(SEL_LEFTBUTTONPRESS, message), ptr)) {
return 1;
}
flags &= ~FLAG_UPDATE;
if (ev->click_count == 1) {
setCursorPos(index(ev->win_x));
if (ev->state & SHIFTMASK) {
extendSelection(myCursorPosition);
} else {
killSelection();
setAnchorPos(myCursorPosition);
}
makePositionVisible(myCursorPosition);
flags |= FLAG_PRESSED;
} else {
setAnchorPos(0);
setCursorPos(contents.length());
extendSelection(contents.length());
makePositionVisible(myCursorPosition);
}
return 1;
}
return 0;
}
long
MFXTextFieldIcon::onLeftBtnRelease(FXObject*, FXSelector, void* ptr) {
if (isEnabled()) {
ungrab();
flags &= ~FLAG_PRESSED;
if (target) {
target->tryHandle(this, FXSEL(SEL_LEFTBUTTONRELEASE, message), ptr);
}
return 1;
}
return 0;
}
long
MFXTextFieldIcon::onMiddleBtnPress(FXObject*, FXSelector, void* ptr) {
FXEvent* ev = (FXEvent*)ptr;
flags &= ~FLAG_TIP;
handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
if (isEnabled()) {
grab();
if (target && target->tryHandle(this, FXSEL(SEL_MIDDLEBUTTONPRESS, message), ptr)) {
return 1;
}
setCursorPos(index(ev->win_x));
setAnchorPos(myCursorPosition);
makePositionVisible(myCursorPosition);
update(border, border, width - (border << 1), height - (border << 1));
flags &= ~FLAG_UPDATE;
return 1;
}
return 0;
}
long
MFXTextFieldIcon::onMiddleBtnRelease(FXObject*, FXSelector, void* ptr) {
if (isEnabled()) {
ungrab();
if (target && target->tryHandle(this, FXSEL(SEL_MIDDLEBUTTONRELEASE, message), ptr)) {
return 1;
}
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_PASTE_MIDDLE), NULL);
}
return 0;
}
long
MFXTextFieldIcon::onMotion(FXObject* sender, FXSelector sel, void* ptr) {
if (myStaticToolTip) {
myStaticToolTip->onUpdate(sender, sel, ptr);
}
FXEvent* event = (FXEvent*)ptr;
FXint t;
if (flags & FLAG_PRESSED) {
if (event->win_x < (border + padleft) || (width - border - padright) < event->win_x) {
if (!getApp()->hasTimeout(this, ID_AUTOSCROLL)) {
getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
}
} else {
getApp()->removeTimeout(this, ID_AUTOSCROLL);
t = index(event->win_x);
if (t != myCursorPosition) {
drawCursor(0);
myCursorPosition = t;
extendSelection(myCursorPosition);
}
}
return 1;
}
return 0;
}
long
MFXTextFieldIcon::onAutoScroll(FXObject*, FXSelector, void* ptr) {
FXEvent* event = (FXEvent*)ptr;
if (flags & FLAG_PRESSED) {
FXint newcursor = myCursorPosition;
FXint ll = border + padleft;
FXint rr = width - border - padright;
FXint ww = rr - ll;
FXint tw;
if (options & TEXTFIELD_PASSWD) {
tw = myFont->getTextWidth("*", 1) * contents.count();
} else {
tw = myFont->getTextWidth(contents.text(), contents.length());
}
if (options & JUSTIFY_RIGHT) {
if (event->win_x < ll) {
if (tw > ww) {
myShiftAmount += ll - event->win_x;
if (ww > tw - myShiftAmount) {
myShiftAmount = tw - ww;
} else {
getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
}
}
newcursor = index(ll);
}
if (rr < event->win_x) {
if (tw > ww) {
myShiftAmount += rr - event->win_x;
if (myShiftAmount <= 0) {
myShiftAmount = 0;
} else {
getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
}
}
newcursor = index(rr);
}
}
else if (options & JUSTIFY_LEFT) {
if (event->win_x < ll) {
if (tw > ww) {
myShiftAmount += ll - event->win_x;
if (myShiftAmount >= 0) {
myShiftAmount = 0;
} else {
getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
}
}
newcursor = index(ll);
}
if (rr < event->win_x) {
if (tw > ww) {
myShiftAmount += rr - event->win_x;
if (myShiftAmount + tw < ww) {
myShiftAmount = ww - tw;
} else {
getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
}
}
newcursor = index(rr);
}
} else {
if (event->win_x < ll) {
if (tw > ww) {
myShiftAmount += ll - event->win_x;
if (myShiftAmount > tw / 2 - ww / 2) {
myShiftAmount = tw / 2 - ww / 2;
} else {
getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
}
}
newcursor = index(ll);
}
if (rr < event->win_x) {
if (tw > ww) {
myShiftAmount += rr - event->win_x;
if (myShiftAmount < (ww - ww / 2) - tw / 2) {
myShiftAmount = (ww - ww / 2) - tw / 2;
} else {
getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
}
}
newcursor = index(rr);
}
}
if (newcursor != myCursorPosition) {
drawCursor(0);
myCursorPosition = newcursor;
extendSelection(myCursorPosition);
}
}
return 1;
}
long
MFXTextFieldIcon::onCmdToggleOverstrike(FXObject*, FXSelector, void*) {
setOverstrike(!isOverstrike());
return 1;
}
long
MFXTextFieldIcon::onUpdToggleOverstrike(FXObject* sender, FXSelector, void*) {
sender->handle(this, isOverstrike() ? FXSEL(SEL_COMMAND, ID_CHECK) : FXSEL(SEL_COMMAND, ID_UNCHECK), NULL);
sender->handle(this, FXSEL(SEL_COMMAND, ID_SHOW), NULL);
sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
return 1;
}
long
MFXTextFieldIcon::onCmdToggleEditable(FXObject*, FXSelector, void*) {
setEditable(!isEditable());
return 1;
}
long
MFXTextFieldIcon::onUpdToggleEditable(FXObject* sender, FXSelector, void*) {
sender->handle(this, isEditable() ? FXSEL(SEL_COMMAND, ID_CHECK) : FXSEL(SEL_COMMAND, ID_UNCHECK), NULL);
sender->handle(this, FXSEL(SEL_COMMAND, ID_SHOW), NULL);
sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
return 1;
}
long
MFXTextFieldIcon::onUpdHaveSelection(FXObject* sender, FXSelector, void* ptr) {
sender->handle(this, hasSelection() ? FXSEL(SEL_COMMAND, ID_ENABLE) : FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
return 1;
}
long
MFXTextFieldIcon::onUpdSelectAll(FXObject* sender, FXSelector, void* ptr) {
sender->handle(this, contents.empty() ? FXSEL(SEL_COMMAND, ID_DISABLE) : FXSEL(SEL_COMMAND, ID_ENABLE), ptr);
return 1;
}
void
MFXTextFieldIcon::setCursorPos(FXint pos) {
pos = contents.validate(FXCLAMP(0, pos, contents.length()));
if (myCursorPosition != pos) {
drawCursor(0);
myCursorPosition = pos;
if (isEditable() && hasFocus()) {
drawCursor(FLAG_CARET);
}
}
}
FXint
MFXTextFieldIcon::getCursorPos() const {
return myCursorPosition;
}
void
MFXTextFieldIcon::setAnchorPos(FXint pos) {
myAnchorPosition = contents.validate(FXCLAMP(0, pos, contents.length()));
}
FXint
MFXTextFieldIcon::getAnchorPos() const {
return myAnchorPosition;
}
void
MFXTextFieldIcon::drawCursor(FXuint state) {
FXint cl, ch, xx, xlo, xhi;
if ((state ^ flags) & FLAG_CARET) {
if (xid) {
FXDCWindow dc(this);
FXASSERT(0 <= myCursorPosition && myCursorPosition <= contents.length());
FXASSERT(0 <= myAnchorPosition && myAnchorPosition <= contents.length());
xx = coord(myCursorPosition) - 1;
if (myIcon) {
xx += ICON_SPACING + ICON_SIZE;
}
xlo = FXMAX(xx - 2, border);
xhi = FXMIN(xx + 3, width - border);
dc.setClipRectangle(xlo, border, xhi - xlo, height - (border << 1));
if (state & FLAG_CARET) {
dc.setForeground(myCursorColor);
dc.fillRectangle(xx, padtop + border, 1, height - padbottom - padtop - (border << 1));
dc.fillRectangle(xx - 2, padtop + border, 5, 1);
dc.fillRectangle(xx - 2, height - border - padbottom - 1, 5, 1);
} else {
dc.setForeground(backColor);
dc.fillRectangle(xx - 2, border, 5, height - (border << 1));
cl = ch = myCursorPosition;
if (0 < cl) {
cl = contents.dec(cl);
if (0 < cl) {
cl = contents.dec(cl);
}
}
if (ch < contents.length()) {
ch = contents.inc(ch);
if (ch < contents.length()) {
ch = contents.inc(ch);
}
}
drawTextRange(dc, cl, ch);
}
}
flags ^= FLAG_CARET;
}
}
void
MFXTextFieldIcon::layout() {
FXint rr = width - border - padright;
FXint ll = border + padleft;
FXint ww = rr - ll;
FXint tw;
if (!xid) {
return;
}
if (options & TEXTFIELD_PASSWD) {
tw = myFont->getTextWidth("*", 1) * contents.count();
} else {
tw = myFont->getTextWidth(contents.text(), contents.length());
}
if (options & JUSTIFY_RIGHT) {
if (ww >= tw) {
myShiftAmount = 0;
} else if (myShiftAmount < 0) {
myShiftAmount = 0;
} else if (myShiftAmount > tw - ww) {
myShiftAmount = tw - ww;
}
} else if (options & JUSTIFY_LEFT) {
if (ww >= tw) {
myShiftAmount = 0;
} else if (myShiftAmount > 0) {
myShiftAmount = 0;
} else if (myShiftAmount < ww - tw) {
myShiftAmount = ww - tw;
}
} else {
if (ww >= tw) {
myShiftAmount = 0;
} else if (myShiftAmount > tw / 2 - ww / 2) {
myShiftAmount = tw / 2 - ww / 2;
} else if (myShiftAmount < (ww - ww / 2) - tw / 2) {
myShiftAmount = (ww - ww / 2) - tw / 2;
}
}
makePositionVisible(myCursorPosition);
update();
flags &= ~(FXuint)FLAG_DIRTY;
}
void
MFXTextFieldIcon::makePositionVisible(FXint pos) {
FXint rr = width - border - padright;
FXint ll = border + padleft;
FXint ww = rr - ll;
FXint oldshift = myShiftAmount;
FXint xx;
if (!xid) {
return;
}
pos = contents.validate(FXCLAMP(0, pos, contents.length()));
if (options & JUSTIFY_RIGHT) {
if (options & TEXTFIELD_PASSWD) {
xx = myFont->getTextWidth("*", 1) * contents.count(pos, contents.length());
} else {
xx = myFont->getTextWidth(&contents[pos], contents.length() - pos);
}
if (myShiftAmount - xx > 0) {
myShiftAmount = xx;
} else if (myShiftAmount - xx < -ww) {
myShiftAmount = xx - ww;
}
} else if (options & JUSTIFY_LEFT) {
if (options & TEXTFIELD_PASSWD) {
xx = myFont->getTextWidth("*", 1) * contents.index(pos);
} else {
xx = myFont->getTextWidth(contents.text(), pos);
}
if (myShiftAmount + xx < 0) {
myShiftAmount = -xx;
} else if (myShiftAmount + xx >= ww) {
myShiftAmount = ww - xx;
}
} else {
if (options & TEXTFIELD_PASSWD) {
xx = myFont->getTextWidth("*", 1) * contents.index(pos) - (myFont->getTextWidth("*", 1) * contents.count()) / 2;
} else {
xx = myFont->getTextWidth(contents.text(), pos) - myFont->getTextWidth(contents.text(), contents.length()) / 2;
}
if (myShiftAmount + ww / 2 + xx < 0) {
myShiftAmount = -ww / 2 - xx;
} else if (myShiftAmount + ww / 2 + xx >= ww) {
myShiftAmount = ww - ww / 2 - xx;
}
}
if (myShiftAmount != oldshift) {
update(border, border, width - (border << 1), height - (border << 1));
}
}
FXint
MFXTextFieldIcon::index(FXint x) const {
FXint rr = width - border - padright;
FXint ll = border + padleft;
FXint mm = (ll + rr) / 2;
FXint pos, xx, cw;
if (options & TEXTFIELD_PASSWD) {
cw = myFont->getTextWidth("*", 1);
if (options & JUSTIFY_RIGHT) {
xx = rr - cw * contents.count();
} else if (options & JUSTIFY_LEFT) {
xx = ll;
} else {
xx = mm - (cw * contents.count()) / 2;
}
xx += myShiftAmount;
pos = contents.offset((x - xx + (cw >> 1)) / cw);
} else {
if (options & JUSTIFY_RIGHT) {
xx = rr - myFont->getTextWidth(contents.text(), contents.length());
} else if (options & JUSTIFY_LEFT) {
xx = ll;
} else {
xx = mm - myFont->getTextWidth(contents.text(), contents.length()) / 2;
}
xx += myShiftAmount;
for (pos = 0; pos < contents.length(); pos = contents.inc(pos)) {
cw = myFont->getTextWidth(&contents[pos], contents.extent(pos));
if (x < (xx + (cw >> 1))) {
break;
}
xx += cw;
}
}
if (pos < 0) {
pos = 0;
}
if (pos > contents.length()) {
pos = contents.length();
}
return pos;
}
FXint
MFXTextFieldIcon::coord(FXint i) const {
FXint rr = width - border - padright;
FXint ll = border + padleft;
FXint mm = (ll + rr) / 2;
FXint pos;
FXASSERT(0 <= i && i <= contents.length());
if (options & JUSTIFY_RIGHT) {
if (options & TEXTFIELD_PASSWD) {
pos = rr - myFont->getTextWidth("*", 1) * (contents.count() - contents.index(i));
} else {
pos = rr - myFont->getTextWidth(&contents[i], contents.length() - i);
}
} else if (options & JUSTIFY_LEFT) {
if (options & TEXTFIELD_PASSWD) {
pos = ll + myFont->getTextWidth("*", 1) * contents.index(i);
} else {
pos = ll + myFont->getTextWidth(contents.text(), i);
}
} else {
if (options & TEXTFIELD_PASSWD) {
pos = mm + myFont->getTextWidth("*", 1) * contents.index(i) - (myFont->getTextWidth("*", 1) * contents.count()) / 2;
} else {
pos = mm + myFont->getTextWidth(contents.text(), i) - myFont->getTextWidth(contents.text(), contents.length()) / 2;
}
}
return pos + myShiftAmount;
}
FXbool
MFXTextFieldIcon::isPosVisible(FXint pos) const {
if (0 <= pos && pos <= contents.length()) {
FXint x = coord(contents.validate(pos));
return border + padleft <= x && x <= width - border - padright;
}
return FALSE;
}
FXbool
MFXTextFieldIcon::isPosSelected(FXint pos) const {
return hasSelection() && FXMIN(myAnchorPosition, myCursorPosition) <= pos && pos <= FXMAX(myAnchorPosition, myCursorPosition);
}
void
MFXTextFieldIcon::drawTextFragment(FXDCWindow& dc, FXint x, FXint y, FXint fm, FXint to) {
x += myFont->getTextWidth(contents.text(), fm);
y += myFont->getFontAscent();
dc.drawText(x, y, &contents[fm], to - fm);
}
void
MFXTextFieldIcon::drawPWDTextFragment(FXDCWindow& dc, FXint x, FXint y, FXint fm, FXint to) {
FXint cw = myFont->getTextWidth("*", 1);
FXint i;
y += myFont->getFontAscent();
x += cw * contents.index(fm);
for (i = fm; i < to; i = contents.inc(i), x += cw) {
dc.drawText(x, y, "*", 1);
}
}
void MFXTextFieldIcon::drawTextRange(FXDCWindow& dc, FXint fm, FXint to) {
FXint sx, ex, xx, yy, cw, hh, ww, si, ei, lx, rx, t;
FXint rr = width - border - padright;
FXint ll = border + padleft;
FXint mm = (ll + rr) / 2;
if (to <= fm) {
return;
}
dc.setFont(myFont);
dc.setForeground(myTextColor);
hh = myFont->getFontHeight();
if (options & JUSTIFY_TOP) {
yy = padtop + border;
} else if (options & JUSTIFY_BOTTOM) {
yy = height - padbottom - border - hh;
} else {
yy = border + padtop + (height - padbottom - padtop - (border << 1) - hh) / 2;
}
if (myAnchorPosition < myCursorPosition) {
si = myAnchorPosition;
ei = myCursorPosition;
} else {
si = myCursorPosition;
ei = myAnchorPosition;
}
if (options & TEXTFIELD_PASSWD) {
cw = myFont->getTextWidth("*", 1);
ww = cw * contents.count();
if (options & JUSTIFY_RIGHT) {
xx = myShiftAmount + rr - ww;
} else if (options & JUSTIFY_LEFT) {
xx = myShiftAmount + ll;
} else {
xx = myShiftAmount + mm - ww / 2;
}
if (myIcon) {
xx += ICON_SPACING + ICON_SIZE;
}
lx = xx + cw * contents.index(fm);
rx = xx + cw * contents.index(to);
while (fm < to) {
if (lx + cw >= 0) {
break;
}
lx += cw;
fm = contents.inc(fm);
}
while (fm < to) {
if (rx - cw < width) {
break;
}
rx -= cw;
to = contents.dec(to);
}
if (si < fm) {
si = fm;
}
if (ei > to) {
ei = to;
}
if (!hasSelection() || to <= si || ei <= fm) {
drawPWDTextFragment(dc, xx, yy, fm, to);
} else {
if (fm < si) {
drawPWDTextFragment(dc, xx, yy, fm, si);
} else {
si = fm;
}
if (ei < to) {
drawPWDTextFragment(dc, xx, yy, ei, to);
} else {
ei = to;
}
if (si < ei) {
sx = xx + cw * contents.index(si);
ex = xx + cw * contents.index(ei);
if (hasFocus()) {
dc.setForeground(mySelectedBackgroundColor);
dc.fillRectangle(sx, padtop + border, ex - sx, height - padtop - padbottom - (border << 1));
dc.setForeground(mySelectedTextColor);
drawPWDTextFragment(dc, xx, yy, si, ei);
} else {
dc.setForeground(baseColor);
dc.fillRectangle(sx, padtop + border, ex - sx, height - padtop - padbottom - (border << 1));
dc.setForeground(myTextColor);
drawPWDTextFragment(dc, xx, yy, si, ei);
}
}
}
} else {
ww = myFont->getTextWidth(contents.text(), contents.length());
if (options & JUSTIFY_RIGHT) {
xx = myShiftAmount + rr - ww;
} else if (options & JUSTIFY_LEFT) {
xx = myShiftAmount + ll;
} else {
xx = myShiftAmount + mm - ww / 2;
}
if (myIcon) {
xx += ICON_SPACING + ICON_SIZE;
}
lx = xx + myFont->getTextWidth(&contents[0], fm);
rx = lx + myFont->getTextWidth(&contents[fm], to - fm);
while (fm < to) {
t = contents.inc(fm);
cw = myFont->getTextWidth(&contents[fm], t - fm);
if (lx + cw >= 0) {
break;
}
lx += cw;
fm = t;
}
while (fm < to) {
t = contents.dec(to);
cw = myFont->getTextWidth(&contents[t], to - t);
if (rx - cw < width) {
break;
}
rx -= cw;
to = t;
}
if (si < fm) {
si = fm;
}
if (ei > to) {
ei = to;
}
if (!hasSelection() || to <= si || ei <= fm) {
drawTextFragment(dc, xx, yy, fm, to);
} else {
if (fm < si) {
drawTextFragment(dc, xx, yy, fm, si);
} else {
si = fm;
}
if (ei < to) {
drawTextFragment(dc, xx, yy, ei, to);
} else {
ei = to;
}
if (si < ei) {
sx = xx + myFont->getTextWidth(contents.text(), si);
ex = xx + myFont->getTextWidth(contents.text(), ei);
if (hasFocus()) {
dc.setForeground(mySelectedBackgroundColor);
dc.fillRectangle(sx, padtop + border, ex - sx, height - padtop - padbottom - (border << 1));
dc.setForeground(mySelectedTextColor);
drawTextFragment(dc, xx, yy, si, ei);
} else {
dc.setForeground(baseColor);
dc.fillRectangle(sx, padtop + border, ex - sx, height - padtop - padbottom - (border << 1));
dc.setForeground(myTextColor);
drawTextFragment(dc, xx, yy, si, ei);
}
}
}
}
}
long
MFXTextFieldIcon::onEnter(FXObject* sender, FXSelector sel, void* ptr) {
if (myStaticToolTip) {
if (!myToolTipText.empty()) {
setTipText(myToolTipText);
myStaticToolTip->showStaticToolTip(getTipText());
} else if (myFont->getTextWidth(contents.text(), contents.length()) > getWidth()) {
setTipText(contents);
myStaticToolTip->showStaticToolTip(getTipText());
}
setHelpText(contents);
}
return FXFrame::onEnter(sender, sel, ptr);
}
long
MFXTextFieldIcon::onLeave(FXObject* sender, FXSelector sel, void* ptr) {
if (myStaticToolTip) {
myStaticToolTip->hideStaticToolTip();
}
return FXFrame::onLeave(sender, sel, ptr);
}
long
MFXTextFieldIcon::onPaint(FXObject*, FXSelector, void* ptr) {
FXEvent* ev = (FXEvent*)ptr;
FXDCWindow dc(this, ev);
drawFrame(dc, 0, 0, width, height);
if (isEnabled()) {
dc.setForeground(backColor);
} else {
dc.setForeground(baseColor);
}
dc.fillRectangle(border, border, width - (border << 1), height - (border << 1));
dc.setClipRectangle(border, border, width - (border << 1), height - (border << 1));
drawTextRange(dc, 0, contents.length());
if (flags & FLAG_CARET) {
int xx = coord(myCursorPosition) - 1;
if (myIcon) {
xx += ICON_SPACING + ICON_SIZE;
}
dc.setForeground(myCursorColor);
dc.fillRectangle(xx, padtop + border, 1, height - padbottom - padtop - (border << 1));
dc.fillRectangle(xx - 2, padtop + border, 5, 1);
dc.fillRectangle(xx - 2, height - border - padbottom - 1, 5, 1);
}
if (myIcon) {
dc.drawIcon(myIcon, ICON_SPACING / 2, border + padtop + (height - padbottom - padtop - (border << 1) - ICON_SIZE) / 2);
}
return 1;
}
long
MFXTextFieldIcon::onCmdCursorHome(FXObject*, FXSelector, void*) {
setCursorPos(0);
makePositionVisible(0);
return 1;
}
long
MFXTextFieldIcon::onCmdCursorEnd(FXObject*, FXSelector, void*) {
setCursorPos(contents.length());
makePositionVisible(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdCursorRight(FXObject*, FXSelector, void*) {
setCursorPos(contents.inc(myCursorPosition));
makePositionVisible(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdCursorLeft(FXObject*, FXSelector, void*) {
setCursorPos(contents.dec(myCursorPosition));
makePositionVisible(myCursorPosition);
return 1;
}
static FXbool
isdelimiter(const FXchar* myTextDelimiter, FXwchar w) {
return w < 128 && strchr(myTextDelimiter, w);
}
FXint
MFXTextFieldIcon::leftWord(FXint pos) const {
FXint pp = pos, p;
FXASSERT(0 <= pos && pos <= contents.length());
while (0 <= (p = contents.dec(pp)) && !Unicode::isSpace(contents.wc(p)) && !isdelimiter(myTextDelimiter, contents.wc(p))) {
pp = p;
}
while (0 <= (p = contents.dec(pp)) && Unicode::isSpace(contents.wc(p))) {
pp = p;
}
if ((pos == pp) && 0 <= (p = contents.dec(pp))) {
pp = p;
}
return pp;
}
FXint
MFXTextFieldIcon::rightWord(FXint pos) const {
FXint pp = pos;
FXASSERT(0 <= pos && pos <= contents.length());
while (pp < contents.length() && !Unicode::isSpace(contents.wc(pp)) && !isdelimiter(myTextDelimiter, contents.wc(pp))) {
pp = contents.inc(pp);
}
while (pp < contents.length() && Unicode::isSpace(contents.wc(pp))) {
pp = contents.inc(pp);
}
if ((pos == pp) && pp < contents.length()) {
pp = contents.inc(pp);
}
return pp;
}
FXint
MFXTextFieldIcon::wordStart(FXint pos) const {
FXint p;
FXASSERT(0 <= pos && pos <= contents.length());
if (pos == contents.length() || Unicode::isSpace(contents.wc(pos))) {
while (0 <= (p = contents.dec(pos)) && Unicode::isSpace(contents.wc(p))) {
pos = p;
}
} else if (isdelimiter(myTextDelimiter, contents.wc(pos))) {
while (0 <= (p = contents.dec(pos)) && isdelimiter(myTextDelimiter, contents.wc(p))) {
pos = p;
}
} else {
while (0 <= (p = contents.dec(pos)) && !isdelimiter(myTextDelimiter, contents.wc(p)) && !Unicode::isSpace(contents.wc(p))) {
pos = p;
}
}
return pos;
}
FXint
MFXTextFieldIcon::wordEnd(FXint pos) const {
FXASSERT(0 <= pos && pos <= contents.length());
if (pos == contents.length() || Unicode::isSpace(contents.wc(pos))) {
while (pos < contents.length() && Unicode::isSpace(contents.wc(pos))) {
pos = contents.inc(pos);
}
} else if (isdelimiter(myTextDelimiter, contents.wc(pos))) {
while (pos < contents.length() && isdelimiter(myTextDelimiter, contents.wc(pos))) {
pos = contents.inc(pos);
}
} else {
while (pos < contents.length() && !isdelimiter(myTextDelimiter, contents.wc(pos)) && !Unicode::isSpace(contents.wc(pos))) {
pos = contents.inc(pos);
}
}
return pos;
}
long
MFXTextFieldIcon::onCmdCursorWordRight(FXObject*, FXSelector, void*) {
setCursorPos(rightWord(myCursorPosition));
makePositionVisible(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdCursorWordLeft(FXObject*, FXSelector, void*) {
setCursorPos(leftWord(myCursorPosition));
makePositionVisible(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdCursorWordStart(FXObject*, FXSelector, void*) {
setCursorPos(wordStart(myCursorPosition));
makePositionVisible(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdCursorWordEnd(FXObject*, FXSelector, void*) {
setCursorPos(wordEnd(myCursorPosition));
makePositionVisible(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdMark(FXObject*, FXSelector, void*) {
setAnchorPos(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdExtend(FXObject*, FXSelector, void*) {
extendSelection(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdSelectAll(FXObject*, FXSelector, void*) {
selectAll();
makePositionVisible(myCursorPosition);
return 1;
}
long
MFXTextFieldIcon::onCmdDeselectAll(FXObject*, FXSelector, void*) {
killSelection();
return 1;
}
long
MFXTextFieldIcon::onCmdCutSel(FXObject*, FXSelector, void*) {
if (isEditable()) {
if (hasSelection()) {
FXDragType types[4];
types[0] = stringType;
types[1] = textType;
types[2] = utf8Type;
types[3] = utf16Type;
if (acquireClipboard(types, 4)) {
if (myAnchorPosition < myCursorPosition) {
myClippedText = contents.mid(myAnchorPosition, myCursorPosition - myAnchorPosition);
} else {
myClippedText = contents.mid(myCursorPosition, myAnchorPosition - myCursorPosition);
}
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE_SEL), NULL);
}
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onCmdCopySel(FXObject*, FXSelector, void*) {
if (hasSelection()) {
FXDragType types[4];
types[0] = stringType;
types[1] = textType;
types[2] = utf8Type;
types[3] = utf16Type;
if (acquireClipboard(types, 4)) {
if (myAnchorPosition < myCursorPosition) {
myClippedText = contents.mid(myAnchorPosition, myCursorPosition - myAnchorPosition);
} else {
myClippedText = contents.mid(myCursorPosition, myAnchorPosition - myCursorPosition);
}
}
}
return 1;
}
long
MFXTextFieldIcon::onCmdPasteSel(FXObject*, FXSelector, void*) {
if (isEditable()) {
FXString string;
if (hasSelection()) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE_SEL), NULL);
}
if (getDNDData(FROM_CLIPBOARD, utf8Type, string)) {
FXTRACE((100, "Paste UTF8\n"));
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)string.text());
return 1;
}
if (getDNDData(FROM_CLIPBOARD, utf16Type, string)) {
FXUTF16LECodec unicode;
FXTRACE((100, "Paste UTF16\n"));
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)unicode.mb2utf(string).text());
return 1;
}
if (getDNDData(FROM_CLIPBOARD, stringType, string)) {
FX88591Codec ascii;
FXTRACE((100, "Paste ASCII\n"));
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)ascii.mb2utf(string).text());
return 1;
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onCmdPasteMiddle(FXObject*, FXSelector, void*) {
if (isEditable()) {
FXString string;
if (getDNDData(FROM_SELECTION, utf8Type, string)) {
FXTRACE((100, "Paste UTF8\n"));
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)string.text());
return 1;
}
if (getDNDData(FROM_SELECTION, utf16Type, string)) {
FXUTF16LECodec unicode;
FXTRACE((100, "Paste UTF16\n"));
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)unicode.mb2utf(string).text());
return 1;
}
if (getDNDData(FROM_SELECTION, stringType, string)) {
FX88591Codec ascii;
FXTRACE((100, "Paste ASCII\n"));
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)ascii.mb2utf(string).text());
return 1;
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onCmdDeleteSel(FXObject*, FXSelector, void*) {
if (isEditable()) {
if (!hasSelection()) {
return 1;
}
FXint st = FXMIN(myAnchorPosition, myCursorPosition);
FXint en = FXMAX(myAnchorPosition, myCursorPosition);
setCursorPos(st);
setAnchorPos(st);
contents.erase(st, en - st);
layout();
makePositionVisible(st);
killSelection();
flags |= FLAG_CHANGED;
if (target) {
target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onCmdDeleteAll(FXObject*, FXSelector, void*) {
if (isEditable()) {
setCursorPos(0);
setAnchorPos(0);
contents.clear();
layout();
makePositionVisible(0);
killSelection();
flags |= FLAG_CHANGED;
if (target) {
target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onCmdOverstString(FXObject*, FXSelector, void* ptr) {
if (isEditable()) {
FXString tentative = contents;
FXint len = (int)strlen((FXchar*)ptr);
FXint reppos = myCursorPosition;
FXint replen = len;
if (hasSelection()) {
reppos = FXMIN(myAnchorPosition, myCursorPosition);
replen = FXMAX(myAnchorPosition, myCursorPosition) - reppos;
}
tentative.replace(reppos, replen, (FXchar*)ptr, len);
if (handle(this, FXSEL(SEL_VERIFY, 0), (void*)tentative.text())) {
getApp()->beep();
return 1;
}
setCursorPos(reppos);
setAnchorPos(reppos);
contents = tentative;
layout();
setCursorPos(reppos + len);
setAnchorPos(reppos + len);
makePositionVisible(reppos + len);
killSelection();
update(border, border, width - (border << 1), height - (border << 1));
flags |= FLAG_CHANGED;
if (target) {
target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onCmdInsertString(FXObject*, FXSelector, void* ptr) {
if (isEditable()) {
FXString tentative = contents;
FXint len = (int)strlen((FXchar*)ptr);
FXint reppos = myCursorPosition;
FXint replen = 0;
if (hasSelection()) {
reppos = FXMIN(myAnchorPosition, myCursorPosition);
replen = FXMAX(myAnchorPosition, myCursorPosition) - reppos;
}
tentative.replace(reppos, replen, (FXchar*)ptr, len);
if (handle(this, FXSEL(SEL_VERIFY, 0), (void*)tentative.text())) {
getApp()->beep();
return 1;
}
setCursorPos(reppos);
setAnchorPos(reppos);
contents = tentative;
layout();
setCursorPos(reppos + len);
setAnchorPos(reppos + len);
makePositionVisible(reppos + len);
killSelection();
update(border, border, width - (border << 1), height - (border << 1));
flags |= FLAG_CHANGED;
if (target) {
target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onCmdBackspace(FXObject*, FXSelector, void*) {
if (isEditable() && 0 < myCursorPosition) {
setCursorPos(contents.dec(myCursorPosition));
setAnchorPos(myCursorPosition);
contents.erase(myCursorPosition, contents.extent(myCursorPosition));
layout();
makePositionVisible(myCursorPosition);
update(border, border, width - (border << 1), height - (border << 1));
flags |= FLAG_CHANGED;
if (target) {
target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onCmdDelete(FXObject*, FXSelector, void*) {
if (isEditable() && myCursorPosition < contents.length()) {
contents.erase(myCursorPosition, contents.extent(myCursorPosition));
layout();
setCursorPos(myCursorPosition);
setAnchorPos(myCursorPosition);
makePositionVisible(myCursorPosition);
update(border, border, width - (border << 1), height - (border << 1));
flags |= FLAG_CHANGED;
if (target) {
target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
}
} else {
getApp()->beep();
}
return 1;
}
long
MFXTextFieldIcon::onVerify(FXObject*, FXSelector, void* ptr) {
FXchar* p = (FXchar*)ptr;
if (options & TEXTFIELD_LIMITED) {
if ((FXint)wcslen(p) > myVisibleColumns) {
return 1;
}
}
if (options & TEXTFIELD_INTEGER) {
while (Ascii::isSpace(*p)) {
p++;
}
if (*p == '-' || *p == '+') {
p++;
}
while (Ascii::isDigit(*p)) {
p++;
}
while (Ascii::isSpace(*p)) {
p++;
}
if (*p != '\0') {
return 1;
}
}
if (options & TEXTFIELD_REAL) {
while (Ascii::isSpace(*p)) {
p++;
}
if (*p == '-' || *p == '+') {
p++;
}
while (Ascii::isDigit(*p)) {
p++;
}
if (*p == '.') {
p++;
}
while (Ascii::isDigit(*p)) {
p++;
}
if (*p == 'E' || *p == 'e') {
p++;
if (*p == '-' || *p == '+') {
p++;
}
while (Ascii::isDigit(*p)) {
p++;
}
}
while (Ascii::isSpace(*p)) {
p++;
}
if (*p != '\0') {
return 1;
}
}
if (target && target->tryHandle(this, FXSEL(SEL_VERIFY, message), ptr)) {
return 1;
}
return 0;
}
long
MFXTextFieldIcon::onKeyPress(FXObject*, FXSelector, void* ptr) {
FXEvent* event = (FXEvent*)ptr;
flags &= ~FLAG_TIP;
if (isEnabled()) {
FXTRACE((200, "%s::onKeyPress keysym = 0x%04x state = %04x\n", getClassName(), event->code, event->state));
if (target && target->tryHandle(this, FXSEL(SEL_KEYPRESS, message), ptr)) {
return 1;
}
flags &= ~FLAG_UPDATE;
switch (event->code) {
case KEY_Right:
case KEY_KP_Right:
if (!(event->state & SHIFTMASK)) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DESELECT_ALL), NULL);
}
if (event->state & CONTROLMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_RIGHT), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_RIGHT), NULL);
}
if (event->state & SHIFTMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_EXTEND), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_MARK), NULL);
}
return 1;
case KEY_Left:
case KEY_KP_Left:
if (!(event->state & SHIFTMASK)) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DESELECT_ALL), NULL);
}
if (event->state & CONTROLMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_LEFT), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_LEFT), NULL);
}
if (event->state & SHIFTMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_EXTEND), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_MARK), NULL);
}
return 1;
case KEY_Home:
case KEY_KP_Home:
if (!(event->state & SHIFTMASK)) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DESELECT_ALL), NULL);
}
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_HOME), NULL);
if (event->state & SHIFTMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_EXTEND), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_MARK), NULL);
}
return 1;
case KEY_End:
case KEY_KP_End:
if (!(event->state & SHIFTMASK)) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DESELECT_ALL), NULL);
}
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_END), NULL);
if (event->state & SHIFTMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_EXTEND), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_MARK), NULL);
}
return 1;
case KEY_Insert:
case KEY_KP_Insert:
if (event->state & CONTROLMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_COPY_SEL), NULL);
} else if (event->state & SHIFTMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_PASTE_SEL), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_TOGGLE_OVERSTRIKE), NULL);
}
return 1;
case KEY_Delete:
case KEY_KP_Delete:
if (hasSelection()) {
if (event->state & SHIFTMASK) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CUT_SEL), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE_SEL), NULL);
}
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE), NULL);
}
return 1;
case KEY_BackSpace:
if (hasSelection()) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE_SEL), NULL);
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_BACKSPACE), NULL);
}
return 1;
case KEY_Return:
case KEY_KP_Enter:
if (isEditable()) {
flags |= FLAG_UPDATE;
flags &= ~FLAG_CHANGED;
if (target) {
target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)contents.text());
}
} else {
getApp()->beep();
}
return 1;
case KEY_a:
if (!(event->state & CONTROLMASK)) {
break;
}
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_SELECT_ALL), NULL);
return 1;
case KEY_x:
if (!(event->state & CONTROLMASK)) {
break;
}
FALLTHROUGH;
case KEY_F20:
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CUT_SEL), NULL);
return 1;
case KEY_c:
if (!(event->state & CONTROLMASK)) {
break;
}
FALLTHROUGH;
case KEY_F16:
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_COPY_SEL), NULL);
return 1;
case KEY_v:
if (!(event->state & CONTROLMASK)) {
break;
}
FALLTHROUGH;
case KEY_F18:
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_PASTE_SEL), NULL);
return 1;
default:
break;
}
if ((event->state & (CONTROLMASK | ALTMASK)) || ((FXuchar)event->text[0] < 32)) {
return 0;
}
if (isOverstrike()) {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_OVERST_STRING), (void*)event->text.text());
} else {
handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)event->text.text());
}
return 1;
}
return 0;
}
long
MFXTextFieldIcon::onKeyRelease(FXObject*, FXSelector, void* ptr) {
FXEvent* event = (FXEvent*)ptr;
if (isEnabled()) {
FXTRACE((200, "%s::onKeyRelease keysym = 0x%04x state = %04x\n", getClassName(), ((FXEvent*)ptr)->code, ((FXEvent*)ptr)->state));
if (target && target->tryHandle(this, FXSEL(SEL_KEYRELEASE, message), ptr)) {
return 1;
}
switch (event->code) {
case KEY_Right:
case KEY_KP_Right:
case KEY_Left:
case KEY_KP_Left:
case KEY_Home:
case KEY_KP_Home:
case KEY_End:
case KEY_KP_End:
case KEY_Insert:
case KEY_KP_Insert:
case KEY_Delete:
case KEY_KP_Delete:
case KEY_BackSpace:
case KEY_Return:
case KEY_F20:
case KEY_F16:
case KEY_F18:
return 1;
case KEY_a:
case KEY_x:
case KEY_c:
case KEY_v:
if (event->state & CONTROLMASK) {
return 1;
}
FALLTHROUGH;
default:
if ((event->state & (CONTROLMASK | ALTMASK)) || ((FXuchar)event->text[0] < 32)) {
return 0;
}
return 1;
}
}
return 0;
}
FXbool
MFXTextFieldIcon::killSelection() {
if (hasSelection()) {
releaseSelection();
update(border, border, width - (border << 1), height - (border << 1));
return TRUE;
}
return FALSE;
}
FXbool
MFXTextFieldIcon::selectAll() {
setAnchorPos(0);
setCursorPos(contents.length());
extendSelection(myCursorPosition);
return TRUE;
}
FXbool
MFXTextFieldIcon::setSelection(FXint pos, FXint len) {
setAnchorPos(pos);
setCursorPos(pos + len);
extendSelection(myCursorPosition);
return TRUE;
}
FXbool
MFXTextFieldIcon::extendSelection(FXint pos) {
FXDragType types[4];
pos = contents.validate(FXCLAMP(0, pos, contents.length()));
if (myAnchorPosition != pos) {
types[0] = stringType;
types[1] = textType;
types[2] = utf8Type;
types[3] = utf16Type;
if (!hasSelection()) {
acquireSelection(types, 4);
}
} else {
if (hasSelection()) {
releaseSelection();
}
}
update(border, border, width - (border << 1), height - (border << 1));
return TRUE;
}
void
MFXTextFieldIcon::setText(const FXString& text, FXbool notify) {
killSelection();
if (contents != text) {
contents = text;
myAnchorPosition = contents.length();
myCursorPosition = contents.length();
if (xid) {
layout();
}
if (notify && target) {
target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)contents.text());
}
}
}
void
MFXTextFieldIcon::setIcon(FXIcon* ic) {
killSelection();
myIcon = ic;
myAnchorPosition = contents.length();
myCursorPosition = contents.length();
if (xid) {
layout();
}
}
FXString
MFXTextFieldIcon::getText() const {
return contents;
}
void
MFXTextFieldIcon::setTextColor(FXColor clr) {
if (myTextColor != clr) {
myTextColor = clr;
update();
}
}
FXColor
MFXTextFieldIcon::getTextColor() const {
return myTextColor;
}
void
MFXTextFieldIcon::setSelBackColor(FXColor clr) {
if (mySelectedBackgroundColor != clr) {
mySelectedBackgroundColor = clr;
update();
}
}
void
MFXTextFieldIcon::setSelTextColor(FXColor clr) {
if (mySelectedTextColor != clr) {
mySelectedTextColor = clr;
update();
}
}
FXColor
MFXTextFieldIcon::getSelTextColor() const {
return mySelectedTextColor;
}
void
MFXTextFieldIcon::setCursorColor(FXColor clr) {
if (clr != myCursorColor) {
myCursorColor = clr;
update();
}
}
FXColor
MFXTextFieldIcon::getCursorColor() const {
return myCursorColor;
}
void
MFXTextFieldIcon::setNumColumns(FXint ncols) {
if (ncols < 0) {
ncols = 0;
}
if (myVisibleColumns != ncols) {
myShiftAmount = 0;
myVisibleColumns = ncols;
layout();
recalc();
update();
}
}
FXint
MFXTextFieldIcon::getNumColumns() const {
return myVisibleColumns;
}
FXbool
MFXTextFieldIcon::isEditable() const {
return (options & TEXTFIELD_READONLY) == 0;
}
void
MFXTextFieldIcon::setEditable(FXbool edit) {
if (edit) {
options &= ~TEXTFIELD_READONLY;
} else {
options |= TEXTFIELD_READONLY;
}
}
FXbool
MFXTextFieldIcon::isOverstrike() const {
return (options & TEXTFIELD_OVERSTRIKE) != 0;
}
void
MFXTextFieldIcon::setOverstrike(FXbool over) {
if (over) {
options |= TEXTFIELD_OVERSTRIKE;
} else {
options &= ~TEXTFIELD_OVERSTRIKE;
}
}
void
MFXTextFieldIcon::setTextStyle(FXuint style) {
FXuint opts = (options & ~TEXTFIELD_MASK) | (style & TEXTFIELD_MASK);
if (options != opts) {
myShiftAmount = 0;
options = opts;
recalc();
update();
}
}
FXuint
MFXTextFieldIcon::getTextStyle() const {
return (options & TEXTFIELD_MASK);
}
void
MFXTextFieldIcon::setJustify(FXuint style) {
FXuint opts = (options & ~JUSTIFY_MASK) | (style & JUSTIFY_MASK);
if (options != opts) {
myShiftAmount = 0;
options = opts;
recalc();
update();
}
}
FXuint
MFXTextFieldIcon::getJustify() const {
return (options & JUSTIFY_MASK);
}
void
MFXTextFieldIcon::setDelimiters(const FXchar* delims) {
myTextDelimiter = delims;
}
const FXchar*
MFXTextFieldIcon::getDelimiters() const {
return myTextDelimiter;
}
void
MFXTextFieldIcon::setHelpText(const FXString& text) {
myHelpText = text;
}
const FXString&
MFXTextFieldIcon::getHelpText() const {
return myHelpText;
}
void
MFXTextFieldIcon::setTipText(const FXString& text) {
myTooltipText = text;
}
const FXString&
MFXTextFieldIcon::getTipText() const {
return myTooltipText;
}
void
MFXTextFieldIcon::setToolTipText(const FXString& toolTip) {
myToolTipText = toolTip;
}
MFXTextFieldIcon::MFXTextFieldIcon() {
flags |= FLAG_ENABLED;
myFont = (FXFont*) - 1L;
}