/* ------------- editbox.c ------------ */ #include #include #include #include #include "dflat.h" #define EDITBUFFERLENGTH 4096 #define ENTRYBUFFERLENGTH 1024 #define GROWLENGTH 1024 #define EditBufLen(wnd) (isMultiLine(wnd) ? EDITBUFFERLENGTH : ENTRYBUFFERLENGTH) #define WndCol (wnd->CurrCol-wnd->wleft) #define CurrChar (wnd->CurrLine+wnd->CurrCol) static void PasteText(WINDOW, char *, int); static void SaveDeletedText(WINDOW, char *, int); static void SetAnchor(WINDOW, int, int); static void Forward(WINDOW); static void Backward(WINDOW); static void End(WINDOW); static void Home(WINDOW); static void Downward(WINDOW); static void Upward(WINDOW); static char *FindLinePointer(WINDOW, int); static void StickEnd(WINDOW); static void UpLine(WINDOW); static void DownLine(WINDOW); static void NextWord(WINDOW); static void PrevWord(WINDOW); static void ResetEditBox(WINDOW); #define SetLinePointer(wnd, ln) (wnd->CurrLine = FindLinePointer(wnd, ln)) static int KeyBoardMarking; int TextMarking; static int dragcount = -1; char *Clipboard; int ClipboardLength; int EditBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2) { int rtn; static int py = -1; int kx = (int) p1 - GetLeft(wnd); int ky = (int) p2 - GetTop(wnd); int c; RECT rc = ClientRect(wnd); char *lp; int len; int mx; int my; switch (msg) { case CREATE_WINDOW: rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2); wnd->text = malloc(EditBufLen(wnd)); wnd->textlen = EditBufLen(wnd); ResetEditBox(wnd); return rtn; case ADDTEXT: rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2); if (!isMultiLine(wnd)) { wnd->CurrLine = wnd->text; wnd->CurrCol = strlen((char *)p1); if (wnd->CurrCol >= ClientWidth(wnd)) { wnd->wleft = wnd->CurrCol - ClientWidth(wnd); wnd->CurrCol -= wnd->wleft; } wnd->BlkEndCol = wnd->CurrCol; PostMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); } return rtn; case SETTEXT: rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2); wnd->CurrLine = wnd->text; return rtn; case CLEARTEXT: ResetEditBox(wnd); break; case EB_GETTEXT: { char *cp1 = (char *)p1; char *cp2 = wnd->text; while (p2-- && *cp2 && *cp2 != '\n') *cp1++ = *cp2++; *cp1 = '\0'; return TRUE; } case EB_PUTTEXT: SendMessage(wnd, CLEARTEXT, 0, 0); SendMessage(wnd, ADDTEXT, p1, p2); return TRUE; case SETFOCUS: rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2); if (p1) { SendMessage(NULLWND, SHOW_CURSOR, GetCommandToggle(ID_INSERT), 0); SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); } else SendMessage(NULLWND, HIDE_CURSOR, 0, 0); return rtn; case SHIFT_CHANGED: if (!(p1 & (LEFTSHIFT | RIGHTSHIFT)) && KeyBoardMarking) { SendMessage(wnd, BUTTON_RELEASED, 0, 0); KeyBoardMarking = FALSE; } break; case DOUBLE_CLICK: if (KeyBoardMarking) return TRUE; break; case LEFT_BUTTON: if (KeyBoardMarking || TextMarking) return TRUE; if (WindowMoving || WindowSizing) break; if (!InsideRect(p1, p2, rc)) break; mx = (int) p1 - GetClientLeft(wnd); my = (int) p2 - GetClientTop(wnd); if (isMultiLine(wnd)) { if (BlockMarked(wnd)) { ClearBlock(wnd); SendMessage(wnd, PAINT, 0, 0); } if (wnd->wlines) { if (my > wnd->wlines-1) break; lp = TextLine(wnd, my); len = (int) (strchr(lp, '\n') - lp); mx = min(mx, len); if (mx < wnd->wleft) { mx = 0; SendMessage(wnd, KEYBOARD, HOME, 0); } } else mx = my = 0; if (dragcount == -1) dragcount = 2; if (--dragcount == 0) { SetAnchor(wnd, mx+wnd->wleft, my+wnd->wtop); TextMarking = TRUE; SendMessage(wnd, CAPTURE_MOUSE, TRUE, 0); return TRUE; } wnd->WndRow = my; SetLinePointer(wnd, my+wnd->wtop); } if (isMultiLine(wnd) || !BlockMarked(wnd)) wnd->CurrCol = mx+wnd->wleft; PostMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return TRUE; case MOUSE_MOVED: mx = (int) p1 - GetClientLeft(wnd); my = (int) p2 - GetClientTop(wnd); if (my > wnd->wlines-1) break; if (TextMarking && !(WindowMoving || WindowSizing)) { int ptop; int pbot; char *lp; int len; int y; int bbl, bel; RECT rc = ClientRect(wnd); if (!InsideRect(p1, p2, rc)) { if (p1 < GetClientLeft(wnd)) p1 = GetClientLeft(wnd); if (p1 > GetClientRight(wnd)) p1 = GetClientRight(wnd); if (p2 < GetClientTop(wnd)) p2 = GetClientTop(wnd); if (p2 > GetClientBottom(wnd)) p2 = GetClientBottom(wnd); SendMessage(NULLWND, MOUSE_CURSOR, p1, p2); } ptop = min(wnd->BlkBegLine, wnd->BlkEndLine); pbot = max(wnd->BlkBegLine, wnd->BlkEndLine); lp = TextLine(wnd, wnd->wtop+my); len = (int) (strchr(lp, '\n') - lp); mx = min(mx, len-wnd->wleft); wnd->BlkEndCol = mx+wnd->wleft; wnd->BlkEndLine = my+wnd->wtop; bbl = min(wnd->BlkBegLine, wnd->BlkEndLine); bel = max(wnd->BlkBegLine, wnd->BlkEndLine); while (ptop < bbl) { WriteTextLine(wnd, NULL, ptop-wnd->wtop, FALSE); ptop++; } for (y = bbl; y <= bel; y++) WriteTextLine(wnd, NULL, y-wnd->wtop, FALSE); while (pbot > bel) { WriteTextLine(wnd, NULL, pbot-wnd->wtop, FALSE); --pbot; } return FALSE; } break; case BUTTON_RELEASED: if (!isMultiLine(wnd)) break; dragcount = -1; if (TextMarking && !(WindowMoving || WindowSizing)) { PostMessage(wnd, RELEASE_MOUSE, 0, 0); TextMarking = FALSE; if (wnd->BlkBegLine > wnd->BlkEndLine) { swap(wnd->BlkBegLine, wnd->BlkEndLine); swap(wnd->BlkBegCol, wnd->BlkEndCol); } if (wnd->BlkBegLine == wnd->BlkEndLine && wnd->BlkBegCol > wnd->BlkEndCol) swap(wnd->BlkBegCol, wnd->BlkEndCol); return TRUE; } else py = -1; break; case SCROLL: if (!isMultiLine(wnd)) break; if ((rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2)) != FALSE) { if (p1) { /* -------- scrolling up --------- */ if (wnd->WndRow == 0) { DownLine(wnd); StickEnd(wnd); } else --wnd->WndRow; } else { /* -------- scrolling down --------- */ if (wnd->WndRow == ClientHeight(wnd)-1) { UpLine(wnd); StickEnd(wnd); } else wnd->WndRow++; } SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); } return rtn; case HORIZSCROLL: if (p1 && wnd->CurrCol == wnd->wleft && *CurrChar == '\n') return FALSE; if ((rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2)) != FALSE) { if (wnd->CurrCol < wnd->wleft) wnd->CurrCol++; else if (WndCol == ClientWidth(wnd)) --wnd->CurrCol; SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); } return rtn; case MOVE: rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2); SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return rtn; case SIZE: rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2); if (WndCol > ClientWidth(wnd)-1) wnd->CurrCol = ClientWidth(wnd)-1 + wnd->wleft; if (wnd->WndRow > ClientHeight(wnd)-1) { wnd->WndRow = ClientHeight(wnd)-1; SetLinePointer(wnd, wnd->WndRow+wnd->wtop); } SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return rtn; case KEYBOARD: if (WindowMoving || WindowSizing) break; c = (int) p1; if ((p2 & ALTKEY) || c == SHIFT_INS || c == SHIFT_DEL) break; if ((p2 & CTRLKEY) && c != CTRL_FWD && c != CTRL_BS && c != CTRL_HOME && c != CTRL_END) break; if (c == ESC) break; if (isMultiLine(wnd)) { if (p2 & (LEFTSHIFT | RIGHTSHIFT)) { SendMessage(NULLWND, CURRENT_KEYBOARD_CURSOR, (PARAM) &kx, (PARAM)&ky); kx -= GetClientLeft(wnd); ky -= GetClientTop(wnd); switch (c) { case HOME: case END: case PGUP: case PGDN: case UP: case DN: case FWD: case BS: case CTRL_FWD: case CTRL_BS: if (!KeyBoardMarking) { if (BlockMarked(wnd)) { ClearBlock(wnd); SendMessage(wnd, PAINT, 0, 0); } KeyBoardMarking = TextMarking = TRUE; SetAnchor(wnd, kx+wnd->wleft, ky+wnd->wtop); } break; default: break; } } else if (((c != DEL && c != RUBOUT) || !isMultiLine(wnd)) && BlockMarked(wnd)) { ClearBlock(wnd); SendMessage(wnd, PAINT, 0, 0); } } switch (c) { case PGUP: case PGDN: if (!isMultiLine(wnd)) break; BaseWndProc(EDITBOX, wnd, msg, p1, p2); SetLinePointer(wnd, wnd->wtop+wnd->WndRow); StickEnd(wnd); SendMessage(wnd, KEYBOARD_CURSOR,WndCol, wnd->WndRow); break; case HOME: Home(wnd); break; case END: End(wnd); break; case CTRL_FWD: NextWord(wnd); break; case CTRL_BS: PrevWord(wnd); break; case CTRL_HOME: if (!isMultiLine(wnd)) { Home(wnd); break; } rtn = BaseWndProc(EDITBOX, wnd, msg, HOME, p2); Home(wnd); wnd->CurrLine = wnd->text; wnd->WndRow = 0; SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return rtn; case CTRL_END: if (!isMultiLine(wnd)) { End(wnd); break; } Home(wnd); rtn = BaseWndProc(EDITBOX, wnd, msg, END, p2); SetLinePointer(wnd, wnd->wlines-1); wnd->WndRow = min(ClientHeight(wnd)-1, wnd->wlines-1); End(wnd); SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return rtn; case UP: if (!isMultiLine(wnd)) break; Upward(wnd); break; case DN: if (!isMultiLine(wnd)) break; Downward(wnd); break; case FWD: Forward(wnd); break; case BS: Backward(wnd); break; } if (KeyBoardMarking) { SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); SendMessage(NULLWND, CURRENT_KEYBOARD_CURSOR, (PARAM) &kx, (PARAM)&ky); SendMessage(wnd, MOUSE_MOVED, kx, ky); return TRUE; } if (!TestAttribute(wnd, READONLY)) { switch (c) { case HOME: case END: case PGUP: case PGDN: case UP: case DN: case FWD: case BS: case CTRL_FWD: case CTRL_BS: case CTRL_HOME: case CTRL_END: case RUBOUT: if (!isMultiLine(wnd) && BlockMarked(wnd)) { ClearBlock(wnd); SendMessage(wnd, PAINT, 0, 0); } if (c != RUBOUT) break; if (wnd->CurrLine == wnd->text && wnd->CurrCol == 0) break; Backward(wnd); SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); case DEL: if (BlockMarked(wnd)) { SendMessage(wnd, COMMAND, ID_DELETETEXT, 0); return TRUE; } if (*(CurrChar+1) == '\0') return TRUE; if (isMultiLine(wnd) && *CurrChar == '\n') --wnd->wlines; if (*(CurrChar+1)) { int repaint = *CurrChar == '\n'; strcpy(CurrChar, CurrChar+1); if (repaint) SendMessage(wnd, PAINT, 0, 0); else WriteTextLine(wnd, NULL, wnd->WndRow, FALSE); } wnd->TextChanged = TRUE; break; case INS: InvertCommandToggle(ID_INSERT); SendMessage(NULLWND, SHOW_CURSOR, GetCommandToggle(ID_INSERT), 0); break; case '\r': if (isMultiLine(wnd)) c = '\n'; default: if (c == '\t') { int insmd = GetCommandToggle(ID_INSERT); if (!isMultiLine(wnd)) PostMessage(GetParent(wnd), msg, p1, p2); else do { if (!insmd && *(CurrChar+1) == '\0') break; SendMessage(wnd, KEYBOARD, insmd ? ' ' : FWD, 0); } while (wnd->CurrCol % cfg.Tabs); return TRUE; } if ((c != '\n' && c < ' ') || (c & 0x1000)) /* ---- not recognized by editor --- */ break; if (!isMultiLine(wnd) && BlockMarked(wnd)) { ResetEditBox(wnd); ClearBlock(wnd); } if (*CurrChar == '\0') { *CurrChar = '\n'; *(CurrChar+1) = '\0'; wnd->wlines++; } /* --- displayable char or newline --- */ if (c == '\n' || GetCommandToggle(ID_INSERT) || *CurrChar == '\n') { char *cp = wnd->CurrLine; while (*cp && *cp != '\n') cp++; wnd->textwidth = max(wnd->textwidth, (int) (cp-wnd->CurrLine+1)); /* ------ insert mode ------ */ memmove(CurrChar+1, CurrChar, strlen(CurrChar)+1); WriteTextLine(wnd, NULL, wnd->WndRow, FALSE); if (strlen(wnd->text) == wnd->textlen) { int dif = (int) (wnd->CurrLine - wnd->text); wnd->textlen += GROWLENGTH; wnd->text = realloc(wnd->text, wnd->textlen); wnd->CurrLine = wnd->text + dif; } } /* ----- put the char in the buffer ----- */ *CurrChar = c; wnd->TextChanged = TRUE; if (c == '\n') { wnd->wleft = 0; wnd->wlines++; End(wnd); Forward(wnd); SendMessage(wnd, PAINT, 0, 0); break; } /* ---------- test end of window --------- */ if (WndCol == ClientWidth(wnd)-1) { int dif; char *cp = CurrChar; while (*cp != ' ' && cp != wnd->CurrLine) --cp; if (!isMultiLine(wnd) || cp == wnd->CurrLine || !GetCommandToggle(ID_WRAP)) SendMessage(wnd, HORIZSCROLL, TRUE, 0); else { dif = 0; if (c != ' ') { dif = (int) (CurrChar - cp); wnd->CurrCol -= dif; SendMessage(wnd, KEYBOARD, DEL, 0); --dif; } SendMessage(wnd, KEYBOARD, '\r', 0); wnd->CurrCol = dif; if (c == ' ') break; } } /* ------ display the character ------ */ SetStandardColor(wnd); PutWindowChar(wnd, WndCol, wnd->WndRow, c); /* ----- advance the pointers ------ */ wnd->CurrCol++; break; } } SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return TRUE; case COMMAND: { char *bbl, *bel, *bb; int len; if (BlockMarked(wnd)) { bbl = FindLinePointer(wnd, wnd->BlkBegLine) + wnd->BlkBegCol; bel = FindLinePointer(wnd, wnd->BlkEndLine) + wnd->BlkEndCol; len = (int) (bel - bbl); } switch ((int)p1) { case ID_CUT: case ID_COPY: ClipboardLength = len; Clipboard = realloc(Clipboard, ClipboardLength); if (Clipboard != NULL) memmove(Clipboard, bbl, ClipboardLength); case ID_DELETETEXT: if (p1 != ID_COPY) { if (p1 != ID_CUT) SaveDeletedText(wnd, bbl, len); wnd->TextChanged = TRUE; strcpy(bbl, bel); wnd->CurrLine = bbl - wnd->BlkBegCol; wnd->CurrCol = wnd->BlkBegCol; wnd->WndRow = wnd->BlkBegLine - wnd->wtop; if (wnd->WndRow < 0) { wnd->wtop = wnd->BlkBegLine; wnd->WndRow = 0; } wnd->wlines -= wnd->BlkEndLine - wnd-> BlkBegLine; SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); } ClearBlock(wnd); SendMessage(wnd, PAINT, 0, 0); return TRUE; case ID_CLEAR: SaveDeletedText(wnd, bbl, len); wnd->CurrLine = bbl; wnd->CurrCol = wnd->BlkBegCol; wnd->WndRow = wnd->BlkBegLine - wnd->wtop; if (wnd->WndRow < 0) { wnd->WndRow = 0; wnd->wtop = wnd->BlkBegLine; } while (bbl < bel) { char *cp = strchr(bbl, '\n'); if (cp > bel) cp = bel; strcpy(bbl, cp); bel -= (int) (cp - bbl); bbl++; } ClearBlock(wnd); SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); SendMessage(wnd, PAINT, 0, 0); wnd->TextChanged = TRUE; return TRUE; case ID_PASTE: if (Clipboard != NULL) { PasteText(wnd, Clipboard, ClipboardLength); wnd->TextChanged = TRUE; } return TRUE; case ID_UNDO: if (wnd->DeletedText != NULL) { PasteText(wnd, wnd->DeletedText, wnd->DeletedLength); free(wnd->DeletedText); wnd->DeletedText = NULL; } return TRUE; case ID_PARAGRAPH: { char *bl; int bc, ec; int fl, el; int Blocked; el = wnd->BlkEndLine; ec = wnd->BlkEndCol; if (!BlockMarked(wnd)) { Blocked = FALSE; /* ---- forming paragraph from cursor position --- */ fl = wnd->wtop + wnd->WndRow; bl = wnd->CurrLine; bc = wnd->CurrCol; Home(wnd); bbl = bel = bl; if (bc >= ClientWidth(wnd)) bc = 0; /* ---- locate the end of the paragraph ---- */ while (*bel) { int blank = TRUE; char *bll = bel; /* --- blank line marks end of paragraph --- */ while (*bel && *bel != '\n') { if (*bel != ' ') blank = FALSE; bel++; } if (blank) { bel = bll; break; } if (*bel) bel++; } if (bel == bbl) { SendMessage(wnd, KEYBOARD, DN, 0); return TRUE; } if (*bel == '\0') --bel; if (*bel == '\n') --bel; } else { Blocked = TRUE; /* ---- forming paragraph from marked block --- */ fl = wnd->BlkBegLine; bc = wnd->CurrCol = wnd->BlkBegCol; wnd->CurrLine = FindLinePointer(wnd, fl); if (fl < wnd->wtop) wnd->wtop = fl; wnd->WndRow = fl - wnd->wtop; SendMessage(wnd, KEYBOARD, '\r', 0); el++, fl++; if (bc != 0) { SendMessage(wnd, KEYBOARD, '\r', 0); el++, fl ++; } bc = 0; bl = wnd->CurrLine = FindLinePointer(wnd, fl); bbl = bl + bc; bel = FindLinePointer(wnd, el) + ec; } /* --- change all newlines in block to spaces --- */ while (CurrChar < bel) { if (*CurrChar == '\n') { *CurrChar = ' '; wnd->CurrLine = CurrChar + 1; wnd->CurrCol = 0; --wnd->wlines; } else wnd->CurrCol++; } /* ---- insert newlines at new margin boundaries ---- */ bb = bbl; while (bbl < bel) { bbl++; if ((int)(bbl - bb) == ClientWidth(wnd)-1) { while (*bbl != ' ' && bbl > bb) --bbl; if (*bbl != ' ') { bbl = strchr(bbl, ' '); if (bbl == NULL || bbl >= bel) break; } *bbl = '\n'; wnd->textwidth = max(wnd->textwidth, (int) (bbl-bb)); wnd->wlines++; bb = bbl+1; } } ec = (int)(bel - bb); if (Blocked) { /* ---- position cursor at end of new paragraph ---- */ if (el < wnd->wtop || wnd->wtop + ClientHeight(wnd) < el) wnd->wtop = el-ClientHeight(wnd); if (wnd->wtop < 0) wnd->wtop = 0; wnd->WndRow = el - wnd->wtop; wnd->CurrLine = FindLinePointer(wnd, el); wnd->CurrCol = ec; SendMessage(wnd, KEYBOARD, '\r', 0); SendMessage(wnd, KEYBOARD, '\r', 0); } else { /* --- put cursor back at beginning --- */ wnd->CurrLine = bl; wnd->CurrCol = bc; if (fl < wnd->wtop) wnd->wtop = fl; wnd->WndRow = fl - wnd->wtop; } SendMessage(wnd, PAINT, 0, 0); SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); wnd->TextChanged = TRUE; return TRUE; } default: break; } break; } case CLOSE_WINDOW: SendMessage(NULLWND, HIDE_CURSOR, 0, 0); if (wnd->DeletedText != NULL) free(wnd->DeletedText); break; default: break; } return BaseWndProc(EDITBOX, wnd, msg, p1, p2); } static void PasteText(WINDOW wnd, char *SaveTo, int len) { int plen = strlen(wnd->text) + len + 1; char *bl = CurrChar; char *el = bl+len; if (plen > wnd->textlen) { wnd->text = realloc(wnd->text, plen); wnd->textlen = plen; } memmove(el, bl, strlen(bl)+1); memmove(bl, SaveTo, len); while (bl < el) if (*bl++ == '\n') wnd->wlines++; SendMessage(wnd, PAINT, 0, 0); } static void SaveDeletedText(WINDOW wnd, char *bbl, int len) { wnd->DeletedLength = len; if ((wnd->DeletedText = realloc(wnd->DeletedText, len)) != NULL) memmove(wnd->DeletedText, bbl, len); } static void SetAnchor(WINDOW wnd, int mx, int my) { if (BlockMarked(wnd)) { ClearBlock(wnd); SendMessage(wnd, PAINT, 0, 0); } dragcount = -1; /* ------ set the anchor ------ */ wnd->BlkBegLine = wnd->BlkEndLine = my; wnd->BlkBegCol = wnd->BlkEndCol = mx; WriteTextLine(wnd, NULL, my, FALSE); } static void Forward(WINDOW wnd) { if (*(CurrChar+1) == '\0') return; if (*CurrChar == '\n') { Home(wnd); Downward(wnd); } else { wnd->CurrCol++; if (WndCol == ClientWidth(wnd)) { wnd->wleft++; SendMessage(wnd, PAINT, 0, 0); } } } static void StickEnd(WINDOW wnd) { int len = (int) (strchr(wnd->CurrLine, '\n') - wnd->CurrLine); wnd->CurrCol = min(len, wnd->CurrCol); if (wnd->wleft > wnd->CurrCol) { wnd->wleft = max(0, wnd->CurrCol - 4); SendMessage(wnd, PAINT, 0, 0); } else if (wnd->CurrCol-wnd->wleft >= ClientWidth(wnd)) { wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1); SendMessage(wnd, PAINT, 0, 0); } } static void Downward(WINDOW wnd) { if (isMultiLine(wnd) && wnd->WndRow+wnd->wtop+1 < wnd->wlines) { DownLine(wnd); if (wnd->WndRow == ClientHeight(wnd)-1) { if (wnd->wtop+ClientHeight(wnd) <= wnd->wlines) { wnd->wtop++; SendMessage(wnd, PAINT, 0, 0); } } else wnd->WndRow++; StickEnd(wnd); } } static void DownLine(WINDOW wnd) { wnd->CurrLine = strchr(wnd->CurrLine, '\n'); wnd->CurrLine++; } static void UpLine(WINDOW wnd) { --wnd->CurrLine; if (wnd->CurrLine != wnd->text) { --wnd->CurrLine; while (wnd->CurrLine != wnd->text && *wnd->CurrLine != '\n') --wnd->CurrLine; if (*wnd->CurrLine == '\n') wnd->CurrLine++; } } static void Upward(WINDOW wnd) { if (isMultiLine(wnd) && wnd->CurrLine != wnd->text) { UpLine(wnd); if (wnd->WndRow == 0) { if (wnd->wtop) { --wnd->wtop; SendMessage(wnd, PAINT, 0, 0); } } else --wnd->WndRow; StickEnd(wnd); } } static void Backward(WINDOW wnd) { if (wnd->CurrCol) { if (wnd->CurrCol-- <= wnd->wleft) { if (wnd->wleft != 0) { --wnd->wleft; SendMessage(wnd, PAINT, 0, 0); return; } } else return ; } if (isMultiLine(wnd) && wnd->CurrLine != wnd->text) { Upward(wnd); End(wnd); } } static void End(WINDOW wnd) { while (*CurrChar != '\n') ++wnd->CurrCol; if (WndCol >= ClientWidth(wnd)) { wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1); SendMessage(wnd, PAINT, 0, 0); } } static void Home(WINDOW wnd) { wnd->CurrCol = 0; if (wnd->wleft != 0) { wnd->wleft = 0; SendMessage(wnd, PAINT, 0, 0); } } static char *FindLinePointer(WINDOW wnd, int ln) { char *cp = wnd->text; while (ln--) { cp = strchr(cp, '\n'); cp++; } return cp; } #define isWhite(c) ((c) == ' ' || (c) == '\n') static void NextWord(WINDOW wnd) { int savetop = wnd->wtop; int saveleft = wnd->wleft; ClearVisible(wnd); while (!isWhite(*CurrChar)) { if (*(CurrChar+1) == '\0') break; Forward(wnd); } while (isWhite(*CurrChar)) { if (*(CurrChar+1) == '\0') break; Forward(wnd); } SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); SetVisible(wnd); if (wnd->wtop != savetop || wnd->wleft != saveleft) SendMessage(wnd, PAINT, 0, 0); } static void PrevWord(WINDOW wnd) { int savetop = wnd->wtop; int saveleft = wnd->wleft; ClearVisible(wnd); Backward(wnd); while (isWhite(*CurrChar)) { if (wnd->CurrLine == wnd->text && wnd->CurrCol == 0) break; Backward(wnd); } while (!isWhite(*CurrChar)) { if (wnd->CurrLine == wnd->text && wnd->CurrCol == 0) break; Backward(wnd); } if (isWhite(*CurrChar)) Forward(wnd); if (wnd->wleft != saveleft) if (wnd->CurrCol >= saveleft) if (wnd->CurrCol - saveleft < ClientWidth(wnd)) wnd->wleft = saveleft; SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); SetVisible(wnd); if (wnd->wtop != savetop || wnd->wleft != saveleft) SendMessage(wnd, PAINT, 0, 0); } static void ResetEditBox(WINDOW wnd) { *wnd->text = '\0'; wnd->wlines = 0; wnd->CurrLine = wnd->text; wnd->CurrCol = 0; wnd->WndRow = 0; wnd->TextChanged = FALSE; wnd->wleft = 0; }