/* ------------- editbox.c ------------ */ #include "dflat32/dflat.h" #define EditBufLen(wnd) (isMultiLine(wnd) ? EDITLEN : ENTRYLEN) #define SetLinePointer(wnd, ln) (wnd->CurrLine = ln) #define isWhite(c) ((c)==' '||(c)=='\n') /* ---------- local prototypes ----------- */ static void SaveDeletedText(DFWINDOW, char *, int); static void Forward(DFWINDOW); static void Backward(DFWINDOW); static void End(DFWINDOW); static void Home(DFWINDOW); static void Downward(DFWINDOW); static void Upward(DFWINDOW); static void StickEnd(DFWINDOW); static void NextWord(DFWINDOW); static void PrevWord(DFWINDOW); static void ModTextPointers(DFWINDOW, int, int); static void SetAnchor(DFWINDOW, int, int); /* -------- local variables -------- */ static BOOL KeyBoardMarking, ButtonDown; static BOOL TextMarking; static int ButtonX, ButtonY; static int PrevY = -1; /* ----------- CREATE_WINDOW Message ---------- */ static int CreateWindowMsg(DFWINDOW wnd) { int rtn = BaseWndProc(EDITBOX, wnd, CREATE_WINDOW, 0, 0); wnd->MaxTextLength = MAXTEXTLEN+1; wnd->textlen = EditBufLen(wnd); wnd->InsertMode = TRUE; DfSendMessage(wnd, CLEARTEXT, 0, 0); return rtn; } /* ----------- SETTEXT Message ---------- */ static int SetTextMsg(DFWINDOW wnd, PARAM p1) { int rtn = FALSE; if (strlen((char *)p1) <= wnd->MaxTextLength) rtn = BaseWndProc(EDITBOX, wnd, SETTEXT, p1, 0); return rtn; } /* ----------- CLEARTEXT Message ------------ */ static int ClearTextMsg(DFWINDOW wnd) { int rtn = BaseWndProc(EDITBOX, wnd, CLEARTEXT, 0, 0); unsigned blen = EditBufLen(wnd)+2; wnd->text = DFrealloc(wnd->text, blen); memset(wnd->text, 0, blen); wnd->wlines = 0; wnd->CurrLine = 0; wnd->CurrCol = 0; wnd->WndRow = 0; wnd->wleft = 0; wnd->wtop = 0; wnd->textwidth = 0; wnd->TextChanged = FALSE; return rtn; } /* ----------- ADDTEXT Message ---------- */ static int AddTextMsg(DFWINDOW wnd, PARAM p1, PARAM p2) { int rtn = FALSE; if (strlen((char *)p1)+wnd->textlen <= wnd->MaxTextLength) { rtn = BaseWndProc(EDITBOX, wnd, ADDTEXT, p1, p2); if (rtn != FALSE) { if (!isMultiLine(wnd)) { wnd->CurrLine = 0; wnd->CurrCol = strlen((char *)p1); if (wnd->CurrCol >= ClientWidth(wnd)) { wnd->wleft = wnd->CurrCol-ClientWidth(wnd); wnd->CurrCol -= wnd->wleft; } wnd->BlkEndCol = wnd->CurrCol; DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); } } } return rtn; } /* ----------- GETTEXT Message ---------- */ static int GetTextMsg(DFWINDOW wnd, PARAM p1, PARAM p2) { char *cp1 = (char *)p1; char *cp2 = wnd->text; if (cp2 != NULL) { while (p2-- && *cp2 && *cp2 != '\n') *cp1++ = *cp2++; *cp1 = '\0'; return TRUE; } return FALSE; } /* ----------- SETTEXTLENGTH Message ---------- */ static int SetTextLengthMsg(DFWINDOW wnd, unsigned int len) { if (++len < MAXTEXTLEN) { wnd->MaxTextLength = len; if (len < wnd->textlen) { wnd->text=DFrealloc(wnd->text, len+2); wnd->textlen = len; *((wnd->text)+len) = '\0'; *((wnd->text)+len+1) = '\0'; BuildTextPointers(wnd); } return TRUE; } return FALSE; } /* ----------- KEYBOARD_CURSOR Message ---------- */ static void KeyboardCursorMsg(DFWINDOW wnd, PARAM p1, PARAM p2) { wnd->CurrCol = (int)p1 + wnd->wleft; wnd->WndRow = (int)p2; wnd->CurrLine = (int)p2 + wnd->wtop; if (wnd == inFocus) { if (CharInView(wnd, (int)p1, (int)p2)) DfSendMessage(NULL, SHOW_CURSOR, (wnd->InsertMode && !TextMarking), 0); else DfSendMessage(NULL, HIDE_CURSOR, 0, 0); } } /* ----------- SIZE Message ---------- */ int SizeMsg(DFWINDOW wnd, PARAM p1, PARAM p2) { int rtn = BaseWndProc(EDITBOX, wnd, DFM_SIZE, 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); } DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return rtn; } /* ----------- SCROLL Message ---------- */ static int ScrollMsg(DFWINDOW wnd, PARAM p1) { int rtn = FALSE; if (isMultiLine(wnd)) { rtn = BaseWndProc(EDITBOX,wnd,SCROLL,p1,0); if (rtn != FALSE) { if (p1) { /* -------- scrolling up --------- */ if (wnd->WndRow == 0) { wnd->CurrLine++; StickEnd(wnd); } else --wnd->WndRow; } else { /* -------- scrolling down --------- */ if (wnd->WndRow == ClientHeight(wnd)-1) { if (wnd->CurrLine > 0) --wnd->CurrLine; StickEnd(wnd); } else wnd->WndRow++; } DfSendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow); } } return rtn; } /* ----------- HORIZSCROLL Message ---------- */ static int HorizScrollMsg(DFWINDOW wnd, PARAM p1) { int rtn = FALSE; char *currchar = CurrChar; if (!(p1 && wnd->CurrCol == wnd->wleft && *currchar == '\n')) { rtn = BaseWndProc(EDITBOX, wnd, HORIZSCROLL, p1, 0); if (rtn != FALSE) { if (wnd->CurrCol < wnd->wleft) wnd->CurrCol++; else if (WndCol == ClientWidth(wnd)) --wnd->CurrCol; DfSendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow); } } return rtn; } /* ----------- SCROLLPAGE Message ---------- */ static int ScrollPageMsg(DFWINDOW wnd, PARAM p1) { int rtn = FALSE; if (isMultiLine(wnd)) { rtn = BaseWndProc(EDITBOX, wnd, SCROLLPAGE, p1, 0); SetLinePointer(wnd, wnd->wtop+wnd->WndRow); StickEnd(wnd); DfSendMessage(wnd, KEYBOARD_CURSOR,WndCol, wnd->WndRow); } return rtn; } /* ----------- HORIZSCROLLPAGE Message ---------- */ static int HorizPageMsg(DFWINDOW wnd, PARAM p1) { int rtn = BaseWndProc(EDITBOX, wnd, HORIZPAGE, p1, 0); if ((int) p1 == FALSE) { if (wnd->CurrCol > wnd->wleft+ClientWidth(wnd)-1) wnd->CurrCol = wnd->wleft+ClientWidth(wnd)-1; } else if (wnd->CurrCol < wnd->wleft) wnd->CurrCol = wnd->wleft; DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return rtn; } /* ----- Extend the marked block to the new x,y position ---- */ static void ExtendBlock(DFWINDOW wnd, int x, int y) { int bbl, bel; int ptop = min(wnd->BlkBegLine, wnd->BlkEndLine); int pbot = max(wnd->BlkBegLine, wnd->BlkEndLine); char *lp = TextLine(wnd, wnd->wtop+y); int len = (int) (strchr(lp, '\n') - lp); x = max(0, min(x, len)); y = max(0, y); wnd->BlkEndCol = min(len, x+wnd->wleft); wnd->BlkEndLine = y+wnd->wtop; DfSendMessage(wnd, KEYBOARD_CURSOR, wnd->BlkEndCol, wnd->BlkEndLine); bbl = min(wnd->BlkBegLine, wnd->BlkEndLine); bel = max(wnd->BlkBegLine, wnd->BlkEndLine); while (ptop < bbl) { WriteTextLine(wnd, NULL, ptop, FALSE); ptop++; } for (y = bbl; y <= bel; y++) WriteTextLine(wnd, NULL, y, FALSE); while (pbot > bel) { WriteTextLine(wnd, NULL, pbot, FALSE); --pbot; } } /* ----------- LEFT_BUTTON Message ---------- */ static int LeftButtonMsg(DFWINDOW wnd, PARAM p1, PARAM p2) { int MouseX = (int) p1 - GetClientLeft(wnd); int MouseY = (int) p2 - GetClientTop(wnd); DFRECT rc = ClientRect(wnd); char *lp; int len; if (KeyBoardMarking) return TRUE; if (WindowMoving || WindowSizing) return FALSE; if (isMultiLine(wnd)) { if (TextMarking) { if (!InsideRect(p1, p2, rc)) { int x = MouseX, y = MouseY; int dir; DFMESSAGE msg = 0; if ((int)p2 == GetTop(wnd)) y++, dir = FALSE, msg = SCROLL; else if ((int)p2 == GetBottom(wnd)) --y, dir = TRUE, msg = SCROLL; else if ((int)p1 == GetLeft(wnd)) --x, dir = FALSE, msg = HORIZSCROLL; else if ((int)p1 == GetRight(wnd)) x++, dir = TRUE, msg = HORIZSCROLL; if (msg != 0) { if (DfSendMessage(wnd, msg, dir, 0)) ExtendBlock(wnd, x, y); DfSendMessage(wnd, PAINT, 0, 0); } } return TRUE; } if (!InsideRect(p1, p2, rc)) return FALSE; if (TextBlockMarked(wnd)) { ClearTextBlock(wnd); DfSendMessage(wnd, PAINT, 0, 0); } if (wnd->wlines) { if (MouseY > wnd->wlines-1) return TRUE; lp = TextLine(wnd, MouseY+wnd->wtop); len = (int) (strchr(lp, '\n') - lp); MouseX = min(MouseX, len); if (MouseX < wnd->wleft) { MouseX = 0; DfSendMessage(wnd, KEYBOARD, HOME, 0); } ButtonDown = TRUE; ButtonX = MouseX; ButtonY = MouseY; } else MouseX = MouseY = 0; wnd->WndRow = MouseY; SetLinePointer(wnd, MouseY+wnd->wtop); } if (isMultiLine(wnd) || (!TextBlockMarked(wnd) && (int)(MouseX+wnd->wleft) < (int)strlen(wnd->text))) wnd->CurrCol = MouseX+wnd->wleft; DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return TRUE; } /* ----------- MOUSE_MOVED Message ---------- */ static int MouseMovedMsg(DFWINDOW wnd, PARAM p1, PARAM p2) { int MouseX = (int) p1 - GetClientLeft(wnd); int MouseY = (int) p2 - GetClientTop(wnd); DFRECT rc = ClientRect(wnd); if (!InsideRect(p1, p2, rc)) return FALSE; if (MouseY > wnd->wlines-1) return FALSE; if (ButtonDown) { SetAnchor(wnd, ButtonX+wnd->wleft, ButtonY+wnd->wtop); TextMarking = TRUE; rc = WindowRect(wnd); DfSendMessage(NULL,MOUSE_TRAVEL,(PARAM) &rc, 0); ButtonDown = FALSE; } if (TextMarking && !(WindowMoving || WindowSizing)) { ExtendBlock(wnd, MouseX, MouseY); return TRUE; } return FALSE; } static void StopMarking(DFWINDOW wnd) { 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); } /* ----------- BUTTON_RELEASED Message ---------- */ static int ButtonReleasedMsg(DFWINDOW wnd) { if (isMultiLine(wnd)) { ButtonDown = FALSE; if (TextMarking && !(WindowMoving || WindowSizing)) { /* release the mouse ouside the edit box */ DfSendMessage(NULL, MOUSE_TRAVEL, 0, 0); StopMarking(wnd); return TRUE; } else PrevY = -1; } return FALSE; } /* ---- Process text block keys for multiline text box ---- */ static void DoMultiLines(DFWINDOW wnd, int c, PARAM p2) { if (isMultiLine(wnd) && !KeyBoardMarking) { if ((int)p2 & (LEFTSHIFT | RIGHTSHIFT)) { switch (c) { case HOME: case CTRL_HOME: case CTRL_BS: case PGUP: case CTRL_PGUP: case UP: case BS: case END: case CTRL_END: case PGDN: case CTRL_PGDN: case DN: case FWD: case CTRL_FWD: KeyBoardMarking = TextMarking = TRUE; SetAnchor(wnd, wnd->CurrCol, wnd->CurrLine); break; default: break; } } } } /* ---------- page/scroll keys ----------- */ static int DoScrolling(DFWINDOW wnd, int c, PARAM p2) { switch (c) { case PGUP: case PGDN: if (isMultiLine(wnd)) BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2); break; case CTRL_PGUP: case CTRL_PGDN: BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2); 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)) { DfSendMessage(wnd, SCROLLDOC, TRUE, 0); wnd->CurrLine = 0; wnd->WndRow = 0; } Home(wnd); break; case CTRL_END: if (isMultiLine(wnd) && wnd->WndRow+wnd->wtop+1 < wnd->wlines && wnd->wlines > 0) { DfSendMessage(wnd, SCROLLDOC, FALSE, 0); SetLinePointer(wnd, wnd->wlines-1); wnd->WndRow = min(ClientHeight(wnd)-1, wnd->wlines-1); Home(wnd); } End(wnd); break; case UP: if (isMultiLine(wnd)) Upward(wnd); break; case DN: if (isMultiLine(wnd)) Downward(wnd); break; case FWD: Forward(wnd); break; case BS: Backward(wnd); break; default: return FALSE; } if (!KeyBoardMarking && TextBlockMarked(wnd)) { ClearTextBlock(wnd); DfSendMessage(wnd, PAINT, 0, 0); } DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); return TRUE; } /* -------------- Del key ---------------- */ static void DelKey(DFWINDOW wnd) { char *currchar = CurrChar; int repaint = *currchar == '\n'; if (TextBlockMarked(wnd)) { DfSendMessage(wnd, DFM_COMMAND, ID_DELETETEXT, 0); DfSendMessage(wnd, PAINT, 0, 0); return; } if (isMultiLine(wnd) && *currchar == '\n' && *(currchar+1) == '\0') return; strcpy(currchar, currchar+1); if (repaint) { BuildTextPointers(wnd); DfSendMessage(wnd, PAINT, 0, 0); } else { ModTextPointers(wnd, wnd->CurrLine+1, -1); WriteTextLine(wnd, NULL, wnd->WndRow+wnd->wtop, FALSE); } wnd->TextChanged = TRUE; } /* ------------ Tab key ------------ */ static void TabKey(DFWINDOW wnd, PARAM p2) { if (isMultiLine(wnd)) { int insmd = wnd->InsertMode; do { char *cc = CurrChar+1; if (!insmd && *cc == '\0') break; if (wnd->textlen == wnd->MaxTextLength) break; DfSendMessage(wnd,KEYBOARD,insmd ? ' ' : FWD,0); } while (wnd->CurrCol % cfg.Tabs); } else DfPostMessage(GetParent(wnd), KEYBOARD, '\t', p2); } /* ------------ Shift+Tab key ------------ */ static void ShiftTabKey(DFWINDOW wnd, PARAM p2) { if (isMultiLine(wnd)) { do { if (CurrChar == GetText(wnd)) break; DfSendMessage(wnd,KEYBOARD,BS,0); } while (wnd->CurrCol % cfg.Tabs); } else DfPostMessage(GetParent(wnd), KEYBOARD, SHIFT_HT, p2); } /* --------- All displayable typed keys ------------- */ static void KeyTyped(DFWINDOW wnd, int c) { char *currchar = CurrChar; if ((c != '\n' && c < ' ') || (c & 0x1000)) /* ---- not recognized by editor --- */ return; if (!isMultiLine(wnd) && TextBlockMarked(wnd)) { DfSendMessage(wnd, CLEARTEXT, 0, 0); currchar = CurrChar; } /* ---- test typing at end of text ---- */ if (currchar == wnd->text+wnd->MaxTextLength) { /* ---- typing at the end of maximum buffer ---- */ beep(); return; } if (*currchar == '\0') { /* --- insert a newline at end of text --- */ *currchar = '\n'; *(currchar+1) = '\0'; BuildTextPointers(wnd); } /* --- displayable char or newline --- */ if (c == '\n' || wnd->InsertMode || *currchar == '\n') { /* ------ inserting the keyed character ------ */ if (wnd->text[wnd->textlen-1] != '\0') { /* --- the current text buffer is full --- */ if (wnd->textlen == wnd->MaxTextLength) { /* --- text buffer is at maximum size --- */ beep(); return; } /* ---- increase the text buffer size ---- */ wnd->textlen += GROWLENGTH; /* --- but not above maximum size --- */ if (wnd->textlen > wnd->MaxTextLength) wnd->textlen = wnd->MaxTextLength; wnd->text = DFrealloc(wnd->text, wnd->textlen+2); wnd->text[wnd->textlen-1] = '\0'; currchar = CurrChar; } memmove(currchar+1, currchar, strlen(currchar)+1); ModTextPointers(wnd, wnd->CurrLine+1, 1); if (isMultiLine(wnd) && wnd->wlines > 1) wnd->textwidth = max(wnd->textwidth, (int) (TextLine(wnd, wnd->CurrLine+1)- TextLine(wnd, wnd->CurrLine))); else wnd->textwidth = max((int)wnd->textwidth, (int)strlen(wnd->text)); WriteTextLine(wnd, NULL, wnd->wtop+wnd->WndRow, FALSE); } /* ----- put the char in the buffer ----- */ *currchar = c; wnd->TextChanged = TRUE; if (c == '\n') { wnd->wleft = 0; BuildTextPointers(wnd); End(wnd); Forward(wnd); DfSendMessage(wnd, PAINT, 0, 0); return; } /* ---------- test end of window --------- */ if (WndCol == ClientWidth(wnd)-1) { if (!isMultiLine(wnd)) { if (!(currchar == wnd->text+wnd->MaxTextLength-2)) DfSendMessage(wnd, HORIZSCROLL, TRUE, 0); } else { char *cp = currchar; while (*cp != ' ' && cp != TextLine(wnd, wnd->CurrLine)) --cp; if (cp == TextLine(wnd, wnd->CurrLine) || !wnd->WordWrapMode) DfSendMessage(wnd, HORIZSCROLL, TRUE, 0); else { int dif = 0; if (c != ' ') { dif = (int) (currchar - cp); wnd->CurrCol -= dif; DfSendMessage(wnd, KEYBOARD, DEL, 0); --dif; } DfSendMessage(wnd, KEYBOARD, '\n', 0); currchar = CurrChar; wnd->CurrCol = dif; if (c == ' ') return; } } } /* ------ display the character ------ */ SetStandardColor(wnd); PutWindowChar(wnd, c, WndCol, wnd->WndRow); /* ----- advance the pointers ------ */ wnd->CurrCol++; } /* ------------ screen changing key strokes ------------- */ static void DoKeyStroke(DFWINDOW wnd, int c, PARAM p2) { switch (c) { case RUBOUT: if (wnd->CurrCol == 0 && wnd->CurrLine == 0) break; Backward(wnd); case DEL: DelKey(wnd); break; case SHIFT_HT: ShiftTabKey(wnd, p2); break; case '\t': TabKey(wnd, p2); break; case '\r': if (!isMultiLine(wnd)) { DfPostMessage(GetParent(wnd), KEYBOARD, c, p2); break; } c = '\n'; default: if (TextBlockMarked(wnd)) { DfSendMessage(wnd, DFM_COMMAND, ID_DELETETEXT, 0); DfSendMessage(wnd, PAINT, 0, 0); } KeyTyped(wnd, c); break; } } /* ----------- KEYBOARD Message ---------- */ static int KeyboardMsg(DFWINDOW wnd, PARAM p1, PARAM p2) { int c = (int) p1; if (WindowMoving || WindowSizing || ((int)p2 & ALTKEY)) return FALSE; switch (c) { /* these keys get processed by lower classes */ case ESC: case F1: case F2: case F3: case F4: case F5: case F6: case F7: case F8: case F9: case F10: case INS: case SHIFT_INS: case SHIFT_DEL: return FALSE; /* these keys get processed here */ case CTRL_FWD: case CTRL_BS: case CTRL_HOME: case CTRL_END: case CTRL_PGUP: case CTRL_PGDN: break; default: /* other ctrl keys get processed by lower classes */ if ((int)p2 & CTRLKEY) return FALSE; /* all other keys get processed here */ break; } DoMultiLines(wnd, c, p2); if (DoScrolling(wnd, c, p2)) { if (KeyBoardMarking) ExtendBlock(wnd, WndCol, wnd->WndRow); } else if (!TestAttribute(wnd, READONLY)) { DoKeyStroke(wnd, c, p2); DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); } else beep(); return TRUE; } /* ----------- SHIFT_CHANGED Message ---------- */ static void ShiftChangedMsg(DFWINDOW wnd, PARAM p1) { if (!((int)p1 & (LEFTSHIFT | RIGHTSHIFT)) && KeyBoardMarking) { StopMarking(wnd); KeyBoardMarking = FALSE; } } /* ----------- ID_DELETETEXT Command ---------- */ static void DeleteTextCmd(DFWINDOW wnd) { if (TextBlockMarked(wnd)) { char *bbl=TextLine(wnd,wnd->BlkBegLine)+wnd->BlkBegCol; char *bel=TextLine(wnd,wnd->BlkEndLine)+wnd->BlkEndCol; int len = (int) (bel - bbl); SaveDeletedText(wnd, bbl, len); wnd->TextChanged = TRUE; strcpy(bbl, bel); wnd->CurrLine = TextLineNumber(wnd, bbl-wnd->BlkBegCol); wnd->CurrCol = wnd->BlkBegCol; wnd->WndRow = wnd->BlkBegLine - wnd->wtop; if (wnd->WndRow < 0) { wnd->wtop = wnd->BlkBegLine; wnd->WndRow = 0; } DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); ClearTextBlock(wnd); BuildTextPointers(wnd); } } /* ----------- ID_CLEAR Command ---------- */ static void ClearCmd(DFWINDOW wnd) { if (TextBlockMarked(wnd)) { char *bbl=TextLine(wnd,wnd->BlkBegLine)+wnd->BlkBegCol; char *bel=TextLine(wnd,wnd->BlkEndLine)+wnd->BlkEndCol; int len = (int) (bel - bbl); SaveDeletedText(wnd, bbl, len); wnd->CurrLine = TextLineNumber(wnd, bbl); wnd->CurrCol = wnd->BlkBegCol; wnd->WndRow = wnd->BlkBegLine - wnd->wtop; if (wnd->WndRow < 0) { wnd->WndRow = 0; wnd->wtop = wnd->BlkBegLine; } /* ------ change all text lines in block to \n ----- */ while (bbl < bel) { char *cp = strchr(bbl, '\n'); if (cp > bel) cp = bel; strcpy(bbl, cp); bel -= (int) (cp - bbl); bbl++; } ClearTextBlock(wnd); BuildTextPointers(wnd); DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); wnd->TextChanged = TRUE; } } /* ----------- ID_UNDO Command ---------- */ static void UndoCmd(DFWINDOW wnd) { if (wnd->DeletedText != NULL) { PasteText(wnd, wnd->DeletedText, wnd->DeletedLength); free(wnd->DeletedText); wnd->DeletedText = NULL; wnd->DeletedLength = 0; DfSendMessage(wnd, PAINT, 0, 0); } } /* ----------- ID_PARAGRAPH Command ---------- */ static void ParagraphCmd(DFWINDOW wnd) { int bc, fl; char *bl, *bbl, *bel, *bb; ClearTextBlock(wnd); /* ---- forming paragraph from cursor position --- */ fl = wnd->wtop + wnd->WndRow; bbl = bel = bl = TextLine(wnd, wnd->CurrLine); if ((bc = wnd->CurrCol) >= ClientWidth(wnd)) bc = 0; Home(wnd); /* ---- 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) { DfSendMessage(wnd, KEYBOARD, DN, 0); return; } if (*bel == '\0') --bel; if (*bel == '\n') --bel; /* --- change all newlines in block to spaces --- */ while (CurrChar < bel) { if (*CurrChar == '\n') { *CurrChar = ' '; wnd->CurrLine++; wnd->CurrCol = 0; } 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'; bb = bbl+1; } } BuildTextPointers(wnd); /* --- put cursor back at beginning --- */ wnd->CurrLine = TextLineNumber(wnd, bl); wnd->CurrCol = bc; if (fl < wnd->wtop) wnd->wtop = fl; wnd->WndRow = fl - wnd->wtop; DfSendMessage(wnd, PAINT, 0, 0); DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); wnd->TextChanged = TRUE; BuildTextPointers(wnd); } /* ----------- COMMAND Message ---------- */ static int CommandMsg(DFWINDOW wnd, PARAM p1) { switch ((int)p1) { case ID_DELETETEXT: DeleteTextCmd(wnd); return TRUE; case ID_CLEAR: ClearCmd(wnd); return TRUE; case ID_UNDO: UndoCmd(wnd); return TRUE; case ID_PARAGRAPH: ParagraphCmd(wnd); return TRUE; default: break; } return FALSE; } /* ---------- CLOSE_WINDOW Message ----------- */ static int CloseWindowMsg(DFWINDOW wnd, PARAM p1, PARAM p2) { int rtn; DfSendMessage(NULL, HIDE_CURSOR, 0, 0); if (wnd->DeletedText != NULL) free(wnd->DeletedText); if (wnd->text != NULL) { free(wnd->text); wnd->text = NULL; } rtn = BaseWndProc(EDITBOX, wnd, CLOSE_WINDOW, p1, p2); return rtn; } /* ------- Window processing module for EDITBOX class ------ */ int EditBoxProc(DFWINDOW wnd, DFMESSAGE msg, PARAM p1, PARAM p2) { int rtn; switch (msg) { case CREATE_WINDOW: return CreateWindowMsg(wnd); case ADDTEXT: return AddTextMsg(wnd, p1, p2); case SETTEXT: return SetTextMsg(wnd, p1); case CLEARTEXT: return ClearTextMsg(wnd); case GETTEXT: return GetTextMsg(wnd, p1, p2); case SETTEXTLENGTH: return SetTextLengthMsg(wnd, (unsigned) p1); case KEYBOARD_CURSOR: KeyboardCursorMsg(wnd, p1, p2); return TRUE; case SETFOCUS: if (!(int)p1) DfSendMessage(NULL, HIDE_CURSOR, 0, 0); case PAINT: case MOVE: rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2); DfSendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow); return rtn; case DFM_SIZE: return SizeMsg(wnd, p1, p2); case SCROLL: return ScrollMsg(wnd, p1); case HORIZSCROLL: return HorizScrollMsg(wnd, p1); case SCROLLPAGE: return ScrollPageMsg(wnd, p1); case HORIZPAGE: return HorizPageMsg(wnd, p1); case LEFT_BUTTON: if (LeftButtonMsg(wnd, p1, p2)) return TRUE; break; case MOUSE_MOVED: if (MouseMovedMsg(wnd, p1, p2)) return TRUE; break; case DFM_BUTTON_RELEASED: if (ButtonReleasedMsg(wnd)) return TRUE; break; case KEYBOARD: if (KeyboardMsg(wnd, p1, p2)) return TRUE; break; case SHIFT_CHANGED: ShiftChangedMsg(wnd, p1); break; case DFM_COMMAND: if (CommandMsg(wnd, p1)) return TRUE; break; case CLOSE_WINDOW: return CloseWindowMsg(wnd, p1, p2); default: break; } return BaseWndProc(EDITBOX, wnd, msg, p1, p2); } /* ------ save deleted text for the Undo command ------ */ static void SaveDeletedText(DFWINDOW wnd, char *bbl, int len) { wnd->DeletedLength = len; wnd->DeletedText=DFrealloc(wnd->DeletedText,len); memmove(wnd->DeletedText, bbl, len); } /* ---- cursor right key: right one character position ---- */ static void Forward(DFWINDOW wnd) { char *cc = CurrChar+1; if (*cc == '\0') return; if (*CurrChar == '\n') { Home(wnd); Downward(wnd); } else { wnd->CurrCol++; if (WndCol == ClientWidth(wnd)) DfSendMessage(wnd, HORIZSCROLL, TRUE, 0); } } /* ----- stick the moving cursor to the end of the line ---- */ static void StickEnd(DFWINDOW wnd) { char *cp = TextLine(wnd, wnd->CurrLine); char *cp1 = strchr(cp, '\n'); int len = cp1 ? (int) (cp1 - cp) : 0; wnd->CurrCol = min(len, wnd->CurrCol); if (wnd->wleft > wnd->CurrCol) { wnd->wleft = max(0, wnd->CurrCol - 4); DfSendMessage(wnd, PAINT, 0, 0); } else if (wnd->CurrCol-wnd->wleft >= ClientWidth(wnd)) { wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1); DfSendMessage(wnd, PAINT, 0, 0); } } /* --------- cursor down key: down one line --------- */ static void Downward(DFWINDOW wnd) { if (isMultiLine(wnd) && wnd->WndRow+wnd->wtop+1 < wnd->wlines) { wnd->CurrLine++; if (wnd->WndRow == ClientHeight(wnd)-1) BaseWndProc(EDITBOX, wnd, SCROLL, TRUE, 0); else wnd->WndRow++; StickEnd(wnd); } } /* -------- cursor up key: up one line ------------ */ static void Upward(DFWINDOW wnd) { if (isMultiLine(wnd) && wnd->CurrLine != 0) { --wnd->CurrLine; if (wnd->WndRow == 0) BaseWndProc(EDITBOX, wnd, SCROLL, FALSE, 0); else --wnd->WndRow; StickEnd(wnd); } } /* ---- cursor left key: left one character position ---- */ static void Backward(DFWINDOW wnd) { if (wnd->CurrCol) { --wnd->CurrCol; if (wnd->CurrCol < wnd->wleft) DfSendMessage(wnd, HORIZSCROLL, FALSE, 0); } else if (isMultiLine(wnd) && wnd->CurrLine != 0) { Upward(wnd); End(wnd); } } /* -------- End key: to end of line ------- */ static void End(DFWINDOW wnd) { while (*CurrChar && *CurrChar != '\n') ++wnd->CurrCol; if (WndCol >= ClientWidth(wnd)) { wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1); DfSendMessage(wnd, PAINT, 0, 0); } } /* -------- Home key: to beginning of line ------- */ static void Home(DFWINDOW wnd) { wnd->CurrCol = 0; if (wnd->wleft != 0) { wnd->wleft = 0; DfSendMessage(wnd, PAINT, 0, 0); } } /* -- Ctrl+cursor right key: to beginning of next word -- */ static void NextWord(DFWINDOW wnd) { int savetop = wnd->wtop; int saveleft = wnd->wleft; ClearVisible(wnd); while (!isWhite(*CurrChar)) { char *cc = CurrChar+1; if (*cc == '\0') break; Forward(wnd); } while (isWhite(*CurrChar)) { char *cc = CurrChar+1; if (*cc == '\0') break; Forward(wnd); } SetVisible(wnd); DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); if (wnd->wtop != savetop || wnd->wleft != saveleft) DfSendMessage(wnd, PAINT, 0, 0); } /* -- Ctrl+cursor left key: to beginning of previous word -- */ static void PrevWord(DFWINDOW wnd) { int savetop = wnd->wtop; int saveleft = wnd->wleft; ClearVisible(wnd); Backward(wnd); while (isWhite(*CurrChar)) { if (wnd->CurrLine == 0 && wnd->CurrCol == 0) break; Backward(wnd); } while (wnd->CurrCol != 0 && !isWhite(*CurrChar)) Backward(wnd); if (isWhite(*CurrChar)) Forward(wnd); SetVisible(wnd); if (wnd->wleft != saveleft) if (wnd->CurrCol >= saveleft) if (wnd->CurrCol - saveleft < ClientWidth(wnd)) wnd->wleft = saveleft; DfSendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow); if (wnd->wtop != savetop || wnd->wleft != saveleft) DfSendMessage(wnd, PAINT, 0, 0); } /* ----- modify text pointers from a specified position by a specified plus or minus amount ----- */ static void ModTextPointers(DFWINDOW wnd, int lineno, int var) { while (lineno < wnd->wlines) *((wnd->TextPointers) + lineno++) += var; } /* ----- set anchor point for marking text block ----- */ static void SetAnchor(DFWINDOW wnd, int mx, int my) { ClearTextBlock(wnd); /* ------ set the anchor ------ */ wnd->BlkBegLine = wnd->BlkEndLine = my; wnd->BlkBegCol = wnd->BlkEndCol = mx; DfSendMessage(wnd, PAINT, 0, 0); } /* EOF */