/* ------------- textbox.c ------------ */ #include #include #include #include #include "dflat.h" static char *GetTextLine(WINDOW wnd, int selection); static int HScrolling = FALSE; static int VScrolling = FALSE; int TextBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2) { int mx = (int) p1 - GetLeft(wnd); int my = (int) p2 - GetTop(wnd); switch (msg) { case CREATE_WINDOW: wnd->wlines = wnd->wtop = wnd->wleft = wnd->textlen = wnd->textwidth = 0; wnd->text = NULL; wnd->HScrollBox = wnd->VScrollBox = 1; ClearBlock(wnd); break; case ADDTEXT: { /* ======== need to assure that length !> 64K ======= */ int adln = strlen((char *)p1)+2; if (wnd->text != NULL) { int txln = strlen(wnd->text); if (txln+adln > wnd->textlen) { wnd->text = realloc(wnd->text, txln+adln); wnd->textlen = txln+adln-1; } } else { wnd->text = malloc(adln); *wnd->text = '\0'; wnd->textlen = adln-1; } strcat(wnd->text, (char*) p1); strcat(wnd->text, "\n"); wnd->wlines++; wnd->textwidth = max(adln, wnd->textwidth); break; } case SETTEXT: { char *cp, *cp1; SendMessage(wnd, CLEARTEXT, 0, 0); wnd->text = cp = cp1 = (void *) p1; wnd->textlen = max(strlen(cp)+1, (int) p2); while ((cp = strchr(cp, '\n')) != NULL) { wnd->wlines++; cp++; wnd->textwidth = max(wnd->textwidth, (int)(cp-cp1)); cp1 = cp; } break; } case CLEARTEXT: if (wnd->text != NULL) free(wnd->text); wnd->text = NULL; wnd->textlen = 0; wnd->wlines = 0; wnd->textwidth = 0; wnd->wtop = wnd->wleft = 0; ClearBlock(wnd); break; case SETFOCUS: if (!p1 && isMultiLine(wnd)) ClearBlock(wnd); break; case KEYBOARD: if (WindowMoving || WindowSizing) break; switch ((int) p1) { case UP: if (wnd->wtop) SendMessage(wnd, SCROLL, FALSE, 0); return TRUE; case DN: if (wnd->wtop+ClientHeight(wnd) < wnd->wlines) SendMessage(wnd, SCROLL, TRUE, 0); return TRUE; case FWD: SendMessage(wnd, HORIZSCROLL, TRUE, 0); return TRUE; case BS: SendMessage(wnd, HORIZSCROLL, FALSE, 0); return TRUE; case PGUP: if (wnd->wtop) { wnd->wtop -= ClientHeight(wnd); if (wnd->wtop < 0) wnd->wtop = 0; SendMessage(wnd, PAINT, 0, 0); return TRUE; } return TRUE; case PGDN: if (wnd->wtop+ClientHeight(wnd) < wnd->wlines) { wnd->wtop += ClientHeight(wnd); if (wnd->wtop > wnd->wlines-ClientHeight(wnd)) wnd->wtop = wnd->wlines-ClientHeight(wnd); SendMessage(wnd, PAINT, 0, 0); return TRUE; } return TRUE; case HOME: if (wnd->wtop || wnd->wleft) { wnd->wtop = wnd->wleft = 0; SendMessage(wnd, PAINT, 0, 0); } return TRUE; case END: if (wnd->wtop+ClientHeight(wnd) < wnd->wlines) { wnd->wtop = wnd->wlines-ClientHeight(wnd); wnd->wleft = 0; SendMessage(wnd, PAINT, 0, 0); } return TRUE; default: break; } break; case LEFT_BUTTON: if (WindowSizing || WindowMoving) return FALSE; if (TestAttribute(wnd, VSCROLLBAR) && (VScrolling || mx == WindowWidth(wnd)-1)) { /* -------- in the right border ------- */ if (my == 0 || my == ClientHeight(wnd)+1) /* ------ above or below the scroll bar ---- */ break; /* ---------- in the scroll bar ----------- */ VScrolling = TRUE; if (my == 1) { /* -------- top scroll button --------- */ SendMessage(wnd, SCROLL, FALSE, 0); return TRUE; } if (my == ClientHeight(wnd)) { /* -------- bottom scroll button --------- */ SendMessage(wnd, SCROLL, TRUE, 0); return TRUE; } if (my-1 != wnd->VScrollBox) { int dir = my-1 > wnd->VScrollBox; while (dir ? (my-1 > wnd->VScrollBox) : (my-1 < wnd->VScrollBox)) { if (!SendMessage(NULLWND, TESTMOUSE, 0, 0)) break; SendMessage(wnd, SCROLL, dir, 0); } return TRUE; } } if (TestAttribute(wnd, HSCROLLBAR) && (HScrolling || my == WindowHeight(wnd)-1)) { /* -------- in the bottom border ------- */ if (mx == 0 || my == ClientWidth(wnd)+1) /* ------ outside the scroll bar ---- */ break; HScrolling = TRUE; if (mx == 1) { SendMessage(wnd, HORIZSCROLL, FALSE, 0); return TRUE; } if (mx == WindowWidth(wnd)-2) { SendMessage(wnd, HORIZSCROLL, TRUE, 0); return TRUE; } if (mx-1 != wnd->HScrollBox) { int dir = mx-1 > wnd->HScrollBox; while (dir ? (mx-1 > wnd->HScrollBox) : (mx-1 < wnd->HScrollBox)) { if (!SendMessage(NULLWND, TESTMOUSE, 0, 0)) break; SendMessage(wnd, HORIZSCROLL, dir, 0); } return TRUE; } } break; case BUTTON_RELEASED: HScrolling = VScrolling = FALSE; break; case SCROLL: if (isVisible(wnd)) { if (p1 == 0) { if (wnd->wtop == 0) return FALSE; } else if (wnd->wtop+ClientHeight(wnd) >= wnd->wlines) return FALSE; if (p1) wnd->wtop++; else --wnd->wtop; SendMessage(wnd, PAINT, 0, 0); return TRUE; } break; case HORIZSCROLL: if (p1 == 0 && wnd->wleft == 0) return FALSE; if (p1) { if (wnd->wleft + ClientWidth(wnd)-1 >= wnd->textwidth) return FALSE; wnd->wleft++; } else --wnd->wleft; SendMessage(wnd, PAINT, 0, 0); return TRUE; case PAINT: if (isVisible(wnd) && wnd->wlines) { RECT rc; int y; if ((RECT *)p1 == NULL) rc = SetRect(0, 0, ClientWidth(wnd)-1, ClientHeight(wnd)-1); else rc = *(RECT *)p1; for (y = RectTop(rc); y <= RectBottom(rc); y++) { if (y < wnd->wlines-wnd->wtop) WriteTextLine(wnd, &rc, y, FALSE); else { char line[SCREENWIDTH]; memset(line, ' ', sizeof line); line[RectRight(rc)+1] = '\0'; SetStandardColor(wnd); writeline(wnd, line+RectLeft(rc), RectLeft(rc), y, FALSE); } } if (TestAttribute(wnd, VSCROLLBAR)) { int pagelen = wnd->wlines - ClientHeight(wnd); int barlen = ClientHeight(wnd)-2; int lines_tick; if (pagelen < 1 || barlen < 1) wnd->VScrollBox = 1; else { if (pagelen > barlen) lines_tick = pagelen / barlen; else lines_tick = barlen / pagelen; wnd->VScrollBox = 1 + (wnd->wtop / lines_tick); if (wnd->VScrollBox > ClientHeight(wnd)-2 || wnd->wtop + ClientHeight(wnd) >= wnd->wlines) wnd->VScrollBox = ClientHeight(wnd)-2; } SendMessage(wnd, BORDER, p1, 0); } if (TestAttribute(wnd, HSCROLLBAR)) { int pagewidth = wnd->textwidth - ClientWidth(wnd); int barlen = ClientWidth(wnd)-2; int chars_tick; if (pagewidth < 1 || barlen < 1) wnd->HScrollBox = 1; else { if (pagewidth > barlen) chars_tick = pagewidth / barlen; else chars_tick = barlen / pagewidth; wnd->HScrollBox = 1 + (wnd->wleft / chars_tick); if (wnd->HScrollBox > ClientWidth(wnd)-2 || wnd->wleft + ClientWidth(wnd) >= wnd->textwidth) wnd->HScrollBox = ClientWidth(wnd)-2; } SendMessage(wnd, BORDER, p1, 0); } return FALSE; } break; case CLOSE_WINDOW: SendMessage(wnd, CLEARTEXT, 0, 0); break; default: break; } return BaseWndProc(TEXTBOX, wnd, msg, p1, p2); } char *TextLine(WINDOW wnd, int selection) { char *cp = wnd->text; if (selection == -1) return NULL; while (selection--) { while (*cp != '\n') cp++; cp++; } return cp; } static char *GetTextLine(WINDOW wnd, int selection) { char *line; int len = 0; char *cp, *cp1; cp = cp1 = TextLine(wnd, selection); while (*cp && *cp != '\n') { len++; cp++; } line = malloc(len+6); if (line != NULL) { memmove(line, cp1, len); line[len] = '\0'; } return line; } void WriteTextLine(WINDOW wnd, RECT *rcc, int y, int reverse) { int len = 0; int dif = 0; char line[100]; RECT rc; char *lp, *svlp; int lnlen; int i; int trunc = FALSE; lp = svlp = GetTextLine(wnd, wnd->wtop+y); lnlen = LineLength(lp); /* -------- insert block color change controls ------- */ if (BlockMarked(wnd)) { int bbl = wnd->BlkBegLine; int bel = wnd->BlkEndLine; int bbc = wnd->BlkBegCol; int bec = wnd->BlkEndCol; int by = y+wnd->wtop; if (bbl > bel) { swap(bbl, bel); swap(bbc, bec); } if (bbl == bel && bbc > bec) swap(bbc, bec); if (by >= bbl && by <= bel) { /* ------ the block includes this line ----- */ int blkbeg = 0; int blkend = lnlen; if (!(by > bbl && by < bel)) { /* --- the entire line is not in the block --- */ if (by == bbl) /* ---- the block begins on this line ---- */ blkbeg = bbc; if (by == bel) /* ---- the block ends on this line ---- */ blkend = bec; } memmove(lp+blkend+1, lp+blkend, strlen(lp+blkend)+1); lp[blkend] = RESETCOLOR; memmove(lp+blkbeg+3, lp+blkbeg, strlen(lp+blkbeg)+1); lp[blkbeg] = CHANGECOLOR; SetReverseColor(wnd); lp[blkbeg+1] = foreground | 0x80; lp[blkbeg+2] = background | 0x80; lnlen += 4; } } for (i = 0; i < wnd->wleft+3; i++) if (*(unsigned char *)(lp + i) == RESETCOLOR) break; if (i < wnd->wleft+3) { if (wnd->wleft+4 > lnlen) trunc = TRUE; else lp += 4; } else { for (i = 0; i < wnd->wleft; i++) { if (*(unsigned char *)(lp + i) == CHANGECOLOR) { *(lp+wnd->wleft+2) = *(lp+i+2); *(lp+wnd->wleft+1) = *(lp+i+1); *(lp+wnd->wleft) = *(lp+i); break; } } } if (!trunc) { if (lnlen < wnd->wleft) lnlen = 0; else lp += wnd->wleft; if (rcc == NULL) rc = SetRect(0, 0, ClientWidth(wnd)-1, ClientHeight(wnd)-1); else rc = *rcc; if (y < rc.tp || y > rc.bt) return; if (lnlen > RectLeft(rc)) { lp += RectLeft(rc); lnlen = LineLength(lp); len = min(lnlen, RectWidth(rc)); lnlen = LineLength(lp); dif = strlen(lp) - lnlen; len += dif; if (len > 0) strncpy(line, lp, len); } } while (len < RectWidth(rc)+dif) line[len++] = ' '; line[len] = '\0'; dif = 0; if (reverse) { char *cp = line; SetReverseColor(wnd); while ((cp = strchr(cp, CHANGECOLOR)) != NULL) { cp += 2; *cp++ = background | 0x80; } if (*(unsigned char *)line == CHANGECOLOR) dif = 3; } else SetStandardColor(wnd); writeline(wnd, line+dif, RectLeft(rc), y, FALSE); if (svlp != NULL) free(svlp); } void SetTextBlock(WINDOW wnd, int l1, int c1, int l2, int c2) { wnd->BlkBegLine = l1; wnd->BlkBegCol = c1; wnd->BlkEndLine = l2; wnd->BlkEndCol = c2; }