/* Copyright (C) 1996-2001 Ghostgum Software Pty Ltd. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /* $Id: dwtext.c,v 1.5.2.1.2.1 2003/01/17 00:49:00 giles Exp $ */ /* Microsoft Windows text window for Ghostscript. #include #include /* use only far items */ #include #define STRICT #include #include #include #include #include "dwtext.h" /* Define min and max, but make sure to use the identical definition */ /* to the one that all the compilers seem to have.... */ #ifndef min # define min(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef max # define max(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifndef EOF #define EOF (-1) #endif /* sysmenu */ #define M_COPY_CLIP 1 #define M_PASTE_CLIP 2 LRESULT CALLBACK WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static void text_error(char *message); static void text_new_line(TW *tw); static void text_update_text(TW *tw, int count); static void text_drag_drop(TW *tw, HDROP hdrop); static void text_copy_to_clipboard(TW *tw); static void text_paste_from_clipboard(TW *tw); static const char* TextWinClassName = "rjlTextWinClass"; static const POINT TextWinMinSize = {16, 4}; static void text_error(char *message) { MessageBox((HWND)NULL,message,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL); } /* Bring Cursor into text window */ void text_to_cursor(TW *tw) { int nXinc=0; int nYinc=0; int cxCursor; int cyCursor; cyCursor = tw->CursorPos.y * tw->CharSize.y; if ( (cyCursor + tw->CharSize.y > tw->ScrollPos.y + tw->ClientSize.y) /* || (cyCursor < tw->ScrollPos.y) ) { */ /* change to scroll to end of window instead of just making visible */ /* so that ALL of error message can be seen */ || (cyCursor < tw->ScrollPos.y+tw->ClientSize.y) ) { nYinc = max(0, cyCursor + tw->CharSize.y - tw->ClientSize.y) - tw->ScrollPos.y; nYinc = min(nYinc, tw->ScrollMax.y - tw->ScrollPos.y); } cxCursor = tw->CursorPos.x * tw->CharSize.x; if ( (cxCursor + tw->CharSize.x > tw->ScrollPos.x + tw->ClientSize.x) || (cxCursor < tw->ScrollPos.x) ) { nXinc = max(0, cxCursor + tw->CharSize.x - tw->ClientSize.x/2) - tw->ScrollPos.x; nXinc = min(nXinc, tw->ScrollMax.x - tw->ScrollPos.x); } if (nYinc || nXinc) { tw->ScrollPos.y += nYinc; tw->ScrollPos.x += nXinc; ScrollWindow(tw->hwnd,-nXinc,-nYinc,NULL,NULL); SetScrollPos(tw->hwnd,SB_VERT,tw->ScrollPos.y,TRUE); SetScrollPos(tw->hwnd,SB_HORZ,tw->ScrollPos.x,TRUE); UpdateWindow(tw->hwnd); } } static void text_new_line(TW *tw) { tw->CursorPos.x = 0; tw->CursorPos.y++; if (tw->CursorPos.y >= tw->ScreenSize.y) { int i = tw->ScreenSize.x * (tw->ScreenSize.y - 1); memmove(tw->ScreenBuffer, tw->ScreenBuffer+tw->ScreenSize.x, i); memset(tw->ScreenBuffer + i, ' ', tw->ScreenSize.x); tw->CursorPos.y--; ScrollWindow(tw->hwnd,0,-tw->CharSize.y,NULL,NULL); UpdateWindow(tw->hwnd); } if (tw->CursorFlag) text_to_cursor(tw); /* TextMessage(); */ } /* Update count characters in window at cursor position */ /* Updates cursor position */ static void text_update_text(TW *tw, int count) { HDC hdc; int xpos, ypos; xpos = tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x; ypos = tw->CursorPos.y*tw->CharSize.y - tw->ScrollPos.y; hdc = GetDC(tw->hwnd); SelectFont(hdc, tw->hfont); TextOut(hdc,xpos,ypos, (LPSTR)(tw->ScreenBuffer + tw->CursorPos.y*tw->ScreenSize.x + tw->CursorPos.x), count); (void)ReleaseDC(tw->hwnd,hdc); tw->CursorPos.x += count; if (tw->CursorPos.x >= tw->ScreenSize.x) text_new_line(tw); } void text_size(TW *tw, int width, int height) { tw->ScreenSize.x = max(width, TextWinMinSize.x); tw->ScreenSize.y = max(height, TextWinMinSize.y); } void text_font(TW *tw, const char *name, int size) { /* make a new font */ LOGFONT lf; TEXTMETRIC tm; LPSTR p; HDC hdc; /* reject inappropriate arguments */ if (name == NULL) return; if (size < 4) return; /* set new name and size */ if (tw->fontname) free(tw->fontname); tw->fontname = (char *)malloc(strlen(name)+1); if (tw->fontname == NULL) return; strcpy(tw->fontname, name); tw->fontsize = size; /* if window not open, hwnd == 0 == HWND_DESKTOP */ hdc = GetDC(tw->hwnd); memset(&lf, 0, sizeof(LOGFONT)); strncpy(lf.lfFaceName,tw->fontname,LF_FACESIZE); lf.lfHeight = -MulDiv(tw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72); lf.lfPitchAndFamily = FIXED_PITCH; lf.lfCharSet = DEFAULT_CHARSET; if ( (p = strstr(tw->fontname," Italic")) != (LPSTR)NULL ) { lf.lfFaceName[ (unsigned int)(p-tw->fontname) ] = '\0'; lf.lfItalic = TRUE; } if ( (p = strstr(tw->fontname," Bold")) != (LPSTR)NULL ) { lf.lfFaceName[ (unsigned int)(p-tw->fontname) ] = '\0'; lf.lfWeight = FW_BOLD; } if (tw->hfont) DeleteFont(tw->hfont); tw->hfont = CreateFontIndirect((LOGFONT FAR *)&lf); /* get text size */ SelectFont(hdc, tw->hfont); GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm); tw->CharSize.y = tm.tmHeight; tw->CharSize.x = tm.tmAveCharWidth; tw->CharAscent = tm.tmAscent; if (tw->bFocus) CreateCaret(tw->hwnd, 0, tw->CharSize.x, 2+tw->CaretHeight); ReleaseDC(tw->hwnd, hdc); /* redraw window if necessary */ if (tw->hwnd != HWND_DESKTOP) { /* INCOMPLETE */ } } /* Set drag strings */ void text_drag(TW *tw, const char *pre, const char *post) { /* remove old strings */ if (tw->DragPre) free((char *)tw->DragPre); tw->DragPre = NULL; if (tw->DragPost) free((char *)tw->DragPost); tw->DragPost = NULL; /* add new strings */ tw->DragPre = malloc(strlen(pre)+1); if (tw->DragPre) strcpy(tw->DragPre, pre); tw->DragPost = malloc(strlen(post)+1); if (tw->DragPost) strcpy(tw->DragPost, post); } /* Set the window position and size */ void text_setpos(TW *tw, int x, int y, int cx, int cy) { tw->x = x; tw->y = y; tw->cx = cx; tw->cy = cy; } /* Get the window position and size */ int text_getpos(TW *tw, int *px, int *py, int *pcx, int *pcy) { *px = tw->x; *py = tw->y; *pcx = tw->cx; *pcy = tw->cy; return 0; } /* Allocate new text window */ TW * text_new(void) { TW *tw; tw = (TW *)malloc(sizeof(TW)); if (tw == NULL) return NULL; /* make sure everything is null */ memset(tw, 0, sizeof(TW)); /* set some defaults */ text_font(tw, "Courier New", 10); text_size(tw, 80, 24); tw->KeyBufSize = 2048; tw->CursorFlag = 1; /* scroll to cursor after \n or \r */ tw->hwnd = HWND_DESKTOP; tw->line_end = 0; tw->line_start = 0; tw->line_complete = FALSE; tw->line_eof = FALSE; tw->x = CW_USEDEFAULT; tw->y = CW_USEDEFAULT; tw->cx = CW_USEDEFAULT; tw->cy = CW_USEDEFAULT; return tw; } /* Destroy window and deallocate text window structure */ void text_destroy(TW *tw) { if (tw->hwnd) DestroyWindow(tw->hwnd); tw->hwnd = HWND_DESKTOP; if (tw->hfont) DeleteFont(tw->hfont); tw->hfont = NULL; if (tw->KeyBuf) free((char *)tw->KeyBuf); tw->KeyBuf = NULL; if (tw->ScreenBuffer) free((char *)tw->ScreenBuffer); tw->ScreenBuffer = NULL; if (tw->DragPre) free((char *)tw->DragPre); tw->DragPre = NULL; if (tw->DragPost) free((char *)tw->DragPost); tw->DragPost = NULL; if (tw->fontname) free((char *)tw->fontname); tw->fontname = NULL; } /* register the window class */ int text_register_class(TW *tw, HICON hicon) { WNDCLASS wndclass; HINSTANCE hInstance = GetModuleHandle(NULL); tw->hIcon = hicon; /* register window class */ wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndTextProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = sizeof(void *); wndclass.hInstance = hInstance; wndclass.hIcon = tw->hIcon ? tw->hIcon : LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = GetStockBrush(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = TextWinClassName; return RegisterClass(&wndclass); } /* Show the window */ int text_create(TW *tw, const char *app_name, int show_cmd) { HMENU sysmenu; HINSTANCE hInstance = GetModuleHandle(NULL); tw->Title = app_name; tw->nCmdShow = show_cmd; tw->quitnow = FALSE; /* make sure we have some sensible defaults */ if (tw->KeyBufSize < 256) tw->KeyBufSize = 256; tw->CursorPos.x = tw->CursorPos.y = 0; tw->bFocus = FALSE; tw->bGetCh = FALSE; tw->CaretHeight = 0; /* allocate buffers */ tw->KeyBufIn = tw->KeyBufOut = tw->KeyBuf = malloc(tw->KeyBufSize); if (tw->KeyBuf == NULL) { text_error("Out of memory"); return 1; } tw->ScreenBuffer = malloc(tw->ScreenSize.x * tw->ScreenSize.y); if (tw->ScreenBuffer == NULL) { text_error("Out of memory"); return 1; } memset(tw->ScreenBuffer, ' ', tw->ScreenSize.x * tw->ScreenSize.y); tw->hwnd = CreateWindow(TextWinClassName, tw->Title, WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, tw->x, tw->y, tw->cx, tw->cy, NULL, NULL, hInstance, tw); if (tw->hwnd == NULL) { MessageBox((HWND)NULL,"Couldn't open text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL); return 1; } ShowWindow(tw->hwnd, tw->nCmdShow); sysmenu = GetSystemMenu(tw->hwnd,0); /* get the sysmenu */ AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL); AppendMenu(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board"); AppendMenu(sysmenu, MF_STRING, M_PASTE_CLIP, "&Paste"); return 0; } int text_putch(TW *tw, int ch) { int pos; int n; if (tw->quitnow) return ch; /* don't write error message as we shut down */ switch(ch) { case '\r': tw->CursorPos.x = 0; if (tw->CursorFlag) text_to_cursor(tw); break; case '\n': text_new_line(tw); break; case 7: MessageBeep(-1); if (tw->CursorFlag) text_to_cursor(tw); break; case '\t': { for (n = 8 - (tw->CursorPos.x % 8); n>0; n-- ) text_putch(tw, ' '); } break; case 0x08: case 0x7f: tw->CursorPos.x--; if (tw->CursorPos.x < 0) { tw->CursorPos.x = tw->ScreenSize.x - 1; tw->CursorPos.y--; } if (tw->CursorPos.y < 0) tw->CursorPos.y = 0; break; default: pos = tw->CursorPos.y*tw->ScreenSize.x + tw->CursorPos.x; tw->ScreenBuffer[pos] = ch; text_update_text(tw, 1); } return ch; } void text_write_buf(TW *tw, const char *str, int cnt) { BYTE *p; int count, limit; int n; if (tw->quitnow) return; /* don't write error message as we shut down */ while (cnt>0) { p = tw->ScreenBuffer + tw->CursorPos.y*tw->ScreenSize.x + tw->CursorPos.x; limit = tw->ScreenSize.x - tw->CursorPos.x; for (count=0; (count < limit) && (cnt>0) && (isprint(*str) || *str=='\t'); count++) { if (*str=='\t') { for (n = 8 - ((tw->CursorPos.x+count) % 8); (count < limit) & (n>0); n--, count++ ) *p++ = ' '; str++; count--; } else { *p++ = *str++; } cnt--; } if (count>0) { text_update_text(tw, count); } if (cnt > 0) { if (*str=='\n') { text_new_line(tw); str++; cnt--; } else if (!isprint(*str) && *str!='\t') { text_putch(tw, *str++); cnt--; } } } } /* Put string to window */ void text_puts(TW *tw, const char *str) { text_write_buf(tw, str, strlen(str)); } /* TRUE if key hit, FALSE if no key */ int text_kbhit(TW *tw) { return (tw->KeyBufIn != tw->KeyBufOut); } /* get character from keyboard, no echo */ /* need to add extended codes */ int text_getch(TW *tw) { MSG msg; int ch; text_to_cursor(tw); tw->bGetCh = TRUE; if (tw->bFocus) { SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x, tw->CursorPos.y*tw->CharSize.y + tw->CharAscent - tw->CaretHeight - tw->ScrollPos.y); ShowCaret(tw->hwnd); } while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_NOREMOVE)) { if (GetMessage(&msg, (HWND)NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } if (tw->quitnow) return EOF; /* window closed */ while (!text_kbhit(tw)) { if (!tw->quitnow) { if (GetMessage(&msg, (HWND)NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } else return EOF; /* window closed */ } ch = *tw->KeyBufOut++; if (ch=='\r') ch = '\n'; if (tw->KeyBufOut - tw->KeyBuf >= tw->KeyBufSize) tw->KeyBufOut = tw->KeyBuf; /* wrap around */ if (tw->bFocus) HideCaret(tw->hwnd); tw->bGetCh = FALSE; return ch; } /* Read line from keyboard using buffered input * Return at most 'len' characters * Does NOT add null terminating character * This is NOT the same as fgets() * Do not mix this with calls to text_getch() */ int text_read_line(TW *tw, char *line, int len) { int ch; if (tw->line_eof) return 0; while (!tw->line_complete) { /* we have not yet collected a full line */ ch = text_getch(tw); switch(ch) { case EOF: case 26: /* ^Z == EOF */ tw->line_eof = TRUE; tw->line_complete = TRUE; break; case '\b': /* ^H */ case 0x7f: /* DEL */ if (tw->line_end) { text_putch(tw, '\b'); text_putch(tw, ' '); text_putch(tw, '\b'); --(tw->line_end); } break; case 21: /* ^U */ while (tw->line_end) { text_putch(tw, '\b'); text_putch(tw, ' '); text_putch(tw, '\b'); --(tw->line_end); } break; case '\r': case '\n': tw->line_complete = TRUE; /* fall through */ default: tw->line_buf[tw->line_end++] = ch; text_putch(tw, ch); break; } if (tw->line_end >= sizeof(tw->line_buf)) tw->line_complete = TRUE; } if (tw->quitnow) return -1; if (tw->line_complete) { /* We either filled the buffer or got CR, LF or EOF */ int count = min(len, tw->line_end - tw->line_start); memcpy(line, tw->line_buf + tw->line_start, count); tw->line_start += count; if (tw->line_start == tw->line_end) { tw->line_start = tw->line_end = 0; tw->line_complete = FALSE; } return count; } return 0; } /* Read a string from the keyboard, of up to len characters */ /* (not including trailing NULL) */ int text_gets(TW *tw, char *line, int len) { LPSTR dest = line; LPSTR limit = dest + len; /* don't leave room for '\0' */ int ch; do { if (dest >= limit) break; ch = text_getch(tw); switch(ch) { case 26: /* ^Z == EOF */ return 0; case '\b': /* ^H */ case 0x7f: /* DEL */ if (dest > line) { text_putch(tw, '\b'); text_putch(tw, ' '); text_putch(tw, '\b'); --dest; } break; case 21: /* ^U */ while (dest > line) { text_putch(tw, '\b'); text_putch(tw, ' '); text_putch(tw, '\b'); --dest; } break; default: *dest++ = ch; text_putch(tw, ch); break; } } while (ch != '\n'); *dest = '\0'; return (dest-line); } /* Windows 3.1 drag-drop feature */ void text_drag_drop(TW *tw, HDROP hdrop) { char szFile[256]; int i, cFiles; const char *p; if ( (tw->DragPre==NULL) || (tw->DragPost==NULL) ) return; cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPSTR)NULL, 0); for (i=0; iDragPre; *p; p++) SendMessage(tw->hwnd,WM_CHAR,*p,1L); for (p=szFile; *p; p++) { if (*p == '\\') SendMessage(tw->hwnd,WM_CHAR,'/',1L); else SendMessage(tw->hwnd,WM_CHAR,*p,1L); } for (p=tw->DragPost; *p; p++) SendMessage(tw->hwnd,WM_CHAR,*p,1L); } DragFinish(hdrop); } void text_copy_to_clipboard(TW *tw) { int size, count; HGLOBAL hGMem; LPSTR cbuf, cp; TEXTMETRIC tm; UINT type; HDC hdc; int i; size = tw->ScreenSize.y * (tw->ScreenSize.x + 2) + 1; hGMem = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)size); cbuf = cp = (LPSTR)GlobalLock(hGMem); if (cp == (LPSTR)NULL) return; for (i=0; iScreenSize.y; i++) { count = tw->ScreenSize.x; memcpy(cp, tw->ScreenBuffer + tw->ScreenSize.x*i, count); /* remove trailing spaces */ for (count=count-1; count>=0; count--) { if (cp[count]!=' ') break; cp[count] = '\0'; } cp[++count] = '\r'; cp[++count] = '\n'; cp[++count] = '\0'; cp += count; } size = strlen(cbuf) + 1; GlobalUnlock(hGMem); hGMem = GlobalReAlloc(hGMem, (DWORD)size, GHND | GMEM_SHARE); /* find out what type to put into clipboard */ hdc = GetDC(tw->hwnd); SelectFont(hdc, tw->hfont); GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm); if (tm.tmCharSet == OEM_CHARSET) type = CF_OEMTEXT; else type = CF_TEXT; ReleaseDC(tw->hwnd, hdc); /* give buffer to clipboard */ OpenClipboard(tw->hwnd); EmptyClipboard(); SetClipboardData(type, hGMem); CloseClipboard(); } void text_paste_from_clipboard(TW *tw) { HGLOBAL hClipMemory; BYTE *p; long count; OpenClipboard(tw->hwnd); if (IsClipboardFormatAvailable(CF_TEXT)) { hClipMemory = GetClipboardData(CF_TEXT); p = GlobalLock(hClipMemory); while (*p) { /* transfer to keyboard circular buffer */ count = tw->KeyBufIn - tw->KeyBufOut; if (count < 0) count += tw->KeyBufSize; if (count < tw->KeyBufSize-1) { *tw->KeyBufIn++ = *p; if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize) tw->KeyBufIn = tw->KeyBuf; /* wrap around */ } p++; } GlobalUnlock(hClipMemory); } CloseClipboard(); } /* text window */ LRESULT CALLBACK WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; int nYinc, nXinc; TW *tw; if (message == WM_CREATE) { /* Object is stored in window extra data. * Nothing must try to use the object before WM_CREATE * initializes it here. */ tw = (TW *)(((CREATESTRUCT FAR *)lParam)->lpCreateParams); SetWindowLong(hwnd, 0, (LONG)tw); } tw = (TW *)GetWindowLong(hwnd, 0); switch(message) { case WM_SYSCOMMAND: switch(LOWORD(wParam)) { case M_COPY_CLIP: text_copy_to_clipboard(tw); return 0; case M_PASTE_CLIP: text_paste_from_clipboard(tw); return 0; } break; case WM_SETFOCUS: tw->bFocus = TRUE; CreateCaret(hwnd, 0, tw->CharSize.x, 2+tw->CaretHeight); SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x, tw->CursorPos.y*tw->CharSize.y + tw->CharAscent - tw->CaretHeight - tw->ScrollPos.y); if (tw->bGetCh) ShowCaret(hwnd); break; case WM_KILLFOCUS: DestroyCaret(); tw->bFocus = FALSE; break; case WM_MOVE: if (!IsIconic(hwnd) && !IsZoomed(hwnd)) { GetWindowRect(hwnd, &rect); tw->x = rect.left; tw->y = rect.top; } break; case WM_SIZE: if (wParam == SIZE_MINIMIZED) return(0); /* remember current window size */ if (wParam != SIZE_MAXIMIZED) { GetWindowRect(hwnd, &rect); tw->cx = rect.right - rect.left; tw->cy = rect.bottom - rect.top; tw->x = rect.left; tw->y = rect.top; } tw->ClientSize.y = HIWORD(lParam); tw->ClientSize.x = LOWORD(lParam); tw->ScrollMax.y = max(0, tw->CharSize.y*tw->ScreenSize.y - tw->ClientSize.y); tw->ScrollPos.y = min(tw->ScrollPos.y, tw->ScrollMax.y); SetScrollRange(hwnd, SB_VERT, 0, tw->ScrollMax.y, FALSE); SetScrollPos(hwnd, SB_VERT, tw->ScrollPos.y, TRUE); tw->ScrollMax.x = max(0, tw->CharSize.x*tw->ScreenSize.x - tw->ClientSize.x); tw->ScrollPos.x = min(tw->ScrollPos.x, tw->ScrollMax.x); SetScrollRange(hwnd, SB_HORZ, 0, tw->ScrollMax.x, FALSE); SetScrollPos(hwnd, SB_HORZ, tw->ScrollPos.x, TRUE); if (tw->bFocus && tw->bGetCh) { SetCaretPos(tw->CursorPos.x*tw->CharSize.x - tw->ScrollPos.x, tw->CursorPos.y*tw->CharSize.y + tw->CharAscent - tw->CaretHeight - tw->ScrollPos.y); ShowCaret(hwnd); } return(0); case WM_VSCROLL: switch(LOWORD(wParam)) { case SB_TOP: nYinc = -tw->ScrollPos.y; break; case SB_BOTTOM: nYinc = tw->ScrollMax.y - tw->ScrollPos.y; break; case SB_LINEUP: nYinc = -tw->CharSize.y; break; case SB_LINEDOWN: nYinc = tw->CharSize.y; break; case SB_PAGEUP: nYinc = min(-1,-tw->ClientSize.y); break; case SB_PAGEDOWN: nYinc = max(1,tw->ClientSize.y); break; case SB_THUMBPOSITION: nYinc = HIWORD(wParam) - tw->ScrollPos.y; break; default: nYinc = 0; } if ( (nYinc = max(-tw->ScrollPos.y, min(nYinc, tw->ScrollMax.y - tw->ScrollPos.y))) != 0 ) { tw->ScrollPos.y += nYinc; ScrollWindow(hwnd,0,-nYinc,NULL,NULL); SetScrollPos(hwnd,SB_VERT,tw->ScrollPos.y,TRUE); UpdateWindow(hwnd); } return(0); case WM_HSCROLL: switch(LOWORD(wParam)) { case SB_LINEUP: nXinc = -tw->CharSize.x; break; case SB_LINEDOWN: nXinc = tw->CharSize.x; break; case SB_PAGEUP: nXinc = min(-1,-tw->ClientSize.x); break; case SB_PAGEDOWN: nXinc = max(1,tw->ClientSize.x); break; case SB_THUMBPOSITION: nXinc = HIWORD(wParam) - tw->ScrollPos.x; break; default: nXinc = 0; } if ( (nXinc = max(-tw->ScrollPos.x, min(nXinc, tw->ScrollMax.x - tw->ScrollPos.x))) != 0 ) { tw->ScrollPos.x += nXinc; ScrollWindow(hwnd,-nXinc,0,NULL,NULL); SetScrollPos(hwnd,SB_HORZ,tw->ScrollPos.x,TRUE); UpdateWindow(hwnd); } return(0); case WM_KEYDOWN: if (GetKeyState(VK_SHIFT) < 0) { switch(wParam) { case VK_HOME: SendMessage(hwnd, WM_VSCROLL, SB_TOP, (LPARAM)0); break; case VK_END: SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, (LPARAM)0); break; case VK_PRIOR: SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)0); break; case VK_NEXT: SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)0); break; case VK_UP: SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)0); break; case VK_DOWN: SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)0); break; case VK_LEFT: SendMessage(hwnd, WM_HSCROLL, SB_LINEUP, (LPARAM)0); break; case VK_RIGHT: SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, (LPARAM)0); break; } } else { switch(wParam) { case VK_HOME: case VK_END: case VK_PRIOR: case VK_NEXT: case VK_UP: case VK_DOWN: case VK_LEFT: case VK_RIGHT: case VK_DELETE: { /* store key in circular buffer */ long count = tw->KeyBufIn - tw->KeyBufOut; if (count < 0) count += tw->KeyBufSize; if (count < tw->KeyBufSize-2) { *tw->KeyBufIn++ = 0; if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize) tw->KeyBufIn = tw->KeyBuf; /* wrap around */ *tw->KeyBufIn++ = HIWORD(lParam) & 0xff; if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize) tw->KeyBufIn = tw->KeyBuf; /* wrap around */ } } } } break; case WM_CHAR: { /* store key in circular buffer */ long count = tw->KeyBufIn - tw->KeyBufOut; if (count < 0) count += tw->KeyBufSize; if (count < tw->KeyBufSize-1) { *tw->KeyBufIn++ = wParam; if (tw->KeyBufIn - tw->KeyBuf >= tw->KeyBufSize) tw->KeyBufIn = tw->KeyBuf; /* wrap around */ } } return(0); case WM_PAINT: { POINT source, width, dest; hdc = BeginPaint(hwnd, &ps); SelectFont(hdc, tw->hfont); SetMapMode(hdc, MM_TEXT); SetBkMode(hdc,OPAQUE); GetClientRect(hwnd, &rect); source.x = (rect.left + tw->ScrollPos.x) / tw->CharSize.x; /* source */ source.y = (rect.top + tw->ScrollPos.y) / tw->CharSize.y; dest.x = source.x * tw->CharSize.x - tw->ScrollPos.x; /* destination */ dest.y = source.y * tw->CharSize.y - tw->ScrollPos.y; width.x = ((rect.right + tw->ScrollPos.x + tw->CharSize.x - 1) / tw->CharSize.x) - source.x; /* width */ width.y = ((rect.bottom + tw->ScrollPos.y + tw->CharSize.y - 1) / tw->CharSize.y) - source.y; if (source.x < 0) source.x = 0; if (source.y < 0) source.y = 0; if (source.x+width.x > tw->ScreenSize.x) width.x = tw->ScreenSize.x - source.x; if (source.y+width.y > tw->ScreenSize.y) width.y = tw->ScreenSize.y - source.y; /* for each line */ while (width.y>0) { TextOut(hdc,dest.x,dest.y, (LPSTR)(tw->ScreenBuffer + source.y*tw->ScreenSize.x + source.x), width.x); dest.y += tw->CharSize.y; source.y++; width.y--; } EndPaint(hwnd, &ps); return 0; } case WM_DROPFILES: text_drag_drop(tw, (HDROP)wParam); break; case WM_CREATE: { RECT crect, wrect; int cx, cy; tw->hwnd = hwnd; /* make window no larger than screen buffer */ GetWindowRect(hwnd, &wrect); GetClientRect(hwnd, &crect); cx = min(tw->CharSize.x*tw->ScreenSize.x, crect.right); cy = min(tw->CharSize.y*tw->ScreenSize.y, crect.bottom); MoveWindow(hwnd, wrect.left, wrect.top, wrect.right-wrect.left + (cx - crect.right), wrect.bottom-wrect.top + (cy - crect.bottom), TRUE); if ( (tw->DragPre!=(LPSTR)NULL) && (tw->DragPost!=(LPSTR)NULL) ) DragAcceptFiles(hwnd, TRUE); } break; case WM_CLOSE: /* Tell user that we heard them */ if (!tw->quitnow) { char title[256]; int count = GetWindowText(hwnd, title, sizeof(title)-11); strcpy(title+count, " - closing"); SetWindowText(hwnd, title); } tw->quitnow = TRUE; /* wait until Ghostscript exits before destroying window */ return 0; case WM_DESTROY: DragAcceptFiles(hwnd, FALSE); if (tw->hfont) DeleteFont(tw->hfont); tw->hfont = (HFONT)0; tw->quitnow = TRUE; PostQuitMessage(0); break; } return DefWindowProc(hwnd, message, wParam, lParam); } HWND text_get_handle(TW *tw) { return tw->hwnd; } #ifdef NOTUSED /* test program */ #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { /* make a test window */ tw = text_new(); if (!hPrevInstance) { HICON hicon = LoadIcon(NULL, IDI_APPLICATION); text_register_class(hicon); } text_font(tw, "Courier New", 10); text_size(tw, 80, 80); text_drag(tw, "(", ") run\r"); /* show the text window */ if (!text_create(tw, "Application Name", nCmdShow)) { /* do the real work here */ /* TESTING */ int ch; int len; char *line = new char[256]; while ( (len = text_read_line(tw, line, 256-1)) != 0 ) { text_write_buf(tw, line, len); } /* while ( text_gets(tw, line, 256-1) ) { text_puts(tw, line); } */ /* while ( (ch = text_getch(tw, )) != 4 ) text_putch(tw, ch); */ } else { } /* clean up */ text_destroy(tw); /* end program */ return 0; } #endif