home *** CD-ROM | disk | FTP | other *** search
- /* The routines in this file provide display support under
- the Microsoft Windows environment on an IBM-PC or compatible
- computer.
-
- Must be compiled with Borland C++ 2.0.
-
- It should not be compiled if the WINDOW_MSWIN symbol is not set */
-
- /* The functions in this module are mostly concerned with the mapping
- between character cells and client coordinates. */
-
- #include "estruct.h"
- #include "elang.h"
- #include <stdio.h>
- #include <time.h>
- #include "eproto.h"
- #include "edef.h"
-
- #include "mswin.h"
-
- #if COLOR
- /* palette table. It is initialized for the default colors, but can be
- changed by the spal function */
- static COLORREF EmacsPalette [16] = {
- 0x00000000, /* black */
- 0x00000080, /* red */
- 0x00008000, /* green */
- 0x0000FFFF, /* yellow */
- 0x00800000, /* blue */
- 0x00800080, /* magenta */
- 0x00808000, /* cyan */
- 0x00C0C0C0, /* grey (light) */
- 0x00808080, /* gray (dark) */
- 0x000000FF, /* light red */
- 0x0000FF00, /* light green */
- 0x0080FFFF, /* light yellow*/
- 0x00FF0000, /* light blue */
- 0x00800080, /* light magenta*/
- 0x00FFFF00, /* light cyan */
- 0x00FFFFFF /* white */
- };
- #endif
-
- static HWND hCaretWnd = 0; /* window where the caret belongs */
- static int CaretVisible = 0; /* the caret should be visible if not 0 */
- static int CaretCol, CaretRow; /* caret position */
- /* Text Metrics values (from the CellMetrics structure) are used as follows:
-
- -------------------------------- Client area upper boundary
- | ^
- | OffsetY
- | v
- | ^
- | HalfLeadingY
- | v
- | ---------- ----------
- |<---->| | | ^
- OffsetX | cell | cell | | . . .
- | | 0,0 | 1,0 | SizeY
- | | | | |
- | | | | v
- | ---------- ----------
- | ^
- | <- SizeX-> LeadingY = 2 * HalfLeadingY
- | v
- | ---------- ----------
- | | | |
- | | cell | cell |
- | | 0,1 | 1,1 |
- | | | |
- |
- | ...
- |
- Client area left boundary
- */
-
- /* BuildCellMetrics: fills a CellMetrics structure from a font description */
- /* ================ */
-
- void far pascal BuildCellMetrics (CellMetrics *cm, HFONT hFont)
- {
- HDC hDC;
- TEXTMETRIC Metrics;
- HANDLE hPrevFont;
-
- hDC = GetDC (hFrameWnd);
- hPrevFont = SelectFont (hDC, hFont);
- GetTextMetrics (hDC, &Metrics);
- SelectObject (hDC, hPrevFont);
- ReleaseDC (hFrameWnd, hDC);
- cm->SizeX = Metrics.tmAveCharWidth;
- cm->SizeY = Metrics.tmHeight;
- cm->HalfLeadingY = Metrics.tmExternalLeading / 2;
- cm->OffsetX = cm->SizeX / 4;
- if ((cm->OffsetY = (cm->SizeY / 8) - cm->HalfLeadingY) < 0) {
- cm->OffsetY = 0;
- /* for a reasonable upper boundary separation, we want
- (SizeY / 8) <= OffsetY + HalfLeadingY */
- }
- cm->LeadingY = 2 * cm->HalfLeadingY;
- cm->MLHeight = cm->SizeY + cm->LeadingY + (2 * cm->OffsetY) +
- GetSystemMetrics(SM_CYBORDER);
- } /* BuildCellMetrics */
-
- /* InvalidateCells: marks character cells for repaint */
- /* =============== */
-
- void far pascal InvalidateCells (HWND hWnd, int leftcol, int toprow,
- int rightcol, int bottomrow)
- {
- RECT Rect; /* used for Cell and Client coordinates */
- RECT ClientRect; /* MDI window client area */
- POINT MaxBottomRight; /* Cell coordinates of bottom right of MDI
- window */
-
- GetClientRect (hWnd, &ClientRect);
- ClientToCell (hWnd, *(POINT *)&ClientRect.right, &MaxBottomRight);
-
- Rect.left = leftcol;
- Rect.top = toprow;
- CellToClient (hWnd, *(POINT *)&Rect.left, (POINT *)&Rect.left);
- if (leftcol == 0) Rect.left = 0;
- if (toprow == 0) Rect.top = 0;
-
- Rect.right = rightcol + 1;
- Rect.bottom = bottomrow + 1;
- CellToClient (hWnd, *(POINT *)&Rect.right, (POINT *)&Rect.right);
- if (rightcol + 1 >= MaxBottomRight.x) Rect.right = ClientRect.right;
- if (bottomrow + 1 >= MaxBottomRight.y) Rect.bottom = ClientRect.bottom;
-
- InvalidateRect (hWnd, &Rect, FALSE);
- /* the background does not need erasing since Paint will
- completely fill the invalid rectangle */
- } /* InvalidateCells */
-
- /* MinimumClientSize: computes the minimum client area size */
- /* ================= */
-
- void far pascal MinimumClientSize (HWND hWnd, int NCols, int NRows,
- int *Width, int *Height)
-
- /* The values pointed by Height and Width are set to the smallest value
- that allows displaying NRows rows and NCols columns. A NULL pointer
- disables the computing of the associated value */
- {
- if (Height) *Height = (2 * EmacsCM.OffsetY) +
- (NRows * (EmacsCM.SizeY + EmacsCM.LeadingY));
- if (Width) *Width = (2 * EmacsCM.OffsetX) + (NCols * EmacsCM.SizeX);
- } /* MinimumClientSize */
-
- /* DisplayableRows: returns the number of rows displayable in the client area */
- /* =============== */
-
- int far pascal DisplayableRows (HWND hWnd, int Height, CellMetrics *cm)
-
- /* Heigh is the hypothetic heigh of the client area. If this parameter
- is 0, the real client area is measured. If it is negative, the
- maximal client area (maximized child in a maximized frame) is used.
- */
- {
- RECT Rect;
- int x;
-
- if (Height == 0) GetClientRect (hWnd, &Rect);
- else {
- if (Height > 0) {
- Rect.bottom = Height;
- }
- else {
- Rect.bottom = GetSystemMetrics (SM_CYFULLSCREEN) -
- (GetSystemMetrics (SM_CYMENU) + cm->MLHeight);
- }
- }
- x = (Rect.bottom - (2 * cm->OffsetY)) / (cm->SizeY + cm->LeadingY);
- if (x < 0) return 0;
- return x;
- } /* DisplayableRows */
-
- /* DisplayableColumns: returns the number of columns displayable in the client area */
- /* ================== */
-
- int far pascal DisplayableColumns (HWND hWnd, int Width, CellMetrics *cm)
-
- /* Width is the hypothetic width of the client area. If this parameter
- is 0, the real client area is measured. If it is negative, the
- maximal client area (maximized child in a maximized frame) is used.
- */
- {
- RECT Rect;
- int x;
-
- if (Width== 0) GetClientRect (hWnd, &Rect);
- else {
- if (Width > 0) {
- Rect.right = Width;
- }
- else {
- Rect.right = GetSystemMetrics (SM_CXFULLSCREEN);
- }
- }
- x = (Rect.right - (2 * cm->OffsetX)) / cm->SizeX;
- if (x < 0) return 0;
- return x;
- } /* DisplayableColumns */
-
- /* UpdateEmacsCaretPos: position the caret according to CaretCol/CaretRow */
- /* =================== */
-
- static void pascal near UpdateEmacsCaretPos (void)
- {
- POINT pt;
-
- pt.x = CaretCol;
- pt.y = CaretRow;
- CellToClient (hCaretWnd, pt, &pt);
- SetCaretPos (pt.x, pt.y + EmacsCM.HalfLeadingY);
- } /* UpdateEmacsCaretPos */
-
- /* EmacsCaret: Creates or destroys the caret */
- /* ========== */
-
- void far pascal EmacsCaret (BOOL Show)
-
- /* the Show parameter is TRUE if the caret should be created and FALSE
- if it should be destroyed */
- {
- if (Show) {
- if (hCaretWnd == 0) return;
- if (hFrameWnd == GetActiveWindow ()) {
- if (!IsWindow (hCaretWnd)) {
- /* this may happen in some transient cases when closing
- down a screen */
- hCaretWnd = 0;
- return;
- }
- CreateCaret (hCaretWnd, NULL,
- hCaretWnd == hFrameWnd ?
- GetSystemMetrics (SM_CXBORDER) :
- #if BLOCKCARET
- EmacsCM.SizeX,
- #else
- EmacsCM.SizeX / 4,
- #endif
- EmacsCM.SizeY);
- UpdateEmacsCaretPos ();
- if (CaretVisible && !IsIconic (hCaretWnd)) ShowCaret (hCaretWnd);
- }
- }
- else {
- /* destroy the caret */
- DestroyCaret ();
- }
- } /* EmacsCaret */
-
- /* MoveEmacsCaret: updates the caret position */
- /* ============== */
-
- void far pascal MoveEmacsCaret (HWND hWnd, int col, int row)
- {
- CaretCol = col;
- CaretRow = row;
- if (hWnd != hCaretWnd) {
- hCaretWnd = hWnd;
- EmacsCaret (TRUE);
- }
- else {
- hCaretWnd = hWnd;
- UpdateEmacsCaretPos ();
- }
- } /* MoveEmacsCaret */
-
- /* ShowEmacsCaret: shows or hides the caret used by emacs */
- /* ============== */
-
- void far pascal ShowEmacsCaret (BOOL Show)
-
- /* this function is used to make the caret visible only when waiting for
- user input */
- {
- if (Show) {
- if (!CaretVisible) {
- if (!IsIconic (hCaretWnd)) ShowCaret (hCaretWnd);
- }
- ++CaretVisible;
- }
- else {
- --CaretVisible;
- if (!CaretVisible) {
- HideCaret (NULL);
- }
- }
- } /* ShowEmacsCaret */
-
- /* InMessageLine: non-zero if caret currently in the message line */
- /* ============= */
-
- BOOL far pascal InMessageLine (void)
- {
- return (hCaretWnd == hFrameWnd);
- } /* InMessageLine */
-
- /* CellToClient: converts character cell coordinates into client coordinates */
- /* ============ */
-
- void far pascal CellToClient (HWND hWnd, POINT Cell, LPPOINT Client)
-
- /* The resulting Client coordinates indicate the upper left pixel one
- HalfLeadingY above the character cell */
- {
- Client->x = (Cell.x * EmacsCM.SizeX) + EmacsCM.OffsetX;
- if (hWnd == hFrameWnd ) {
- RECT Rect;
-
- GetClientRect (hWnd, &Rect);
- Client->y = (Rect.bottom - EmacsCM.MLHeight) + EmacsCM.OffsetY +
- GetSystemMetrics (SM_CYBORDER);
- }
- else Client->y = (Cell.y * (EmacsCM.SizeY + EmacsCM.LeadingY)) +
- EmacsCM.OffsetY;
- } /* CellToClient */
-
- /* ClientToCell: converts client coordinates into character cell coordinates */
- /* ============ */
-
- void far pascal ClientToCell (HWND hWnd, POINT Client, LPPOINT Cell)
-
- /* The area associated with a Cell is the character cell itself, plus
- the HalfLeadingY-high areas above and under the cell */
- {
- int MaxCol, MaxRow;
-
- if (hWnd == hFrameWnd) { /* message line case */
- MaxCol = MLSIZE - 1;
- MaxRow = 0;
- }
- else { /* screen case */
- register SCREEN *sp;
-
- sp = (SCREEN*)GetWindowLong (hWnd, GWL_SCRPTR);
- MaxCol = sp->s_ncol - 1;
- MaxRow = sp->s_nrow - 1;
- }
- if ((Cell->x = (Client.x - EmacsCM.OffsetX) /
- EmacsCM.SizeX) < 0) Cell->x = 0;
- else Cell->x = min (Cell->x, MaxCol);
- if ((Cell->y = (Client.y - EmacsCM.OffsetY) /
- (EmacsCM.SizeY + EmacsCM.LeadingY)) < 0) Cell->y = 0;
- else Cell->y = min (Cell->y, MaxRow);
- } /* ClientToCell */
-
- /* GetMinMaxInfo: processes the WM_GETMINMAXINFO message for a screen */
- /* ============= */
-
- void far pascal GetMinMaxInfo (HWND hWnd, LPPOINT rgpt)
- {
- if (InternalRequest) return; /* none of our business */
-
- if (notquiescent) {
- /* forbid all size changes */
- RECT Rect;
-
- GetWindowRect (hWnd, &Rect);
- rgpt[1].x = Rect.right - Rect.left;
- rgpt[1].y = Rect.bottom - Rect.top;
- rgpt[2] = *(POINT*)&Rect.left;
- rgpt[3] = rgpt[1];
- rgpt[4] = rgpt[1];
- }
- else { /* compute minimum tracking size */
- int X, Y;
-
- /* minimum displayed text width = 3 */
- /* minimum displayed text height = 10 */
- MinimumClientSize (hWnd, term.t_margin, 2, &X, &Y);
- rgpt[3].x = X + (2 * GetSystemMetrics (SM_CXFRAME));
- rgpt[3].y = Y + GetSystemMetrics (SM_CYCAPTION) +
- (2 * GetSystemMetrics (SM_CYFRAME));
- }
- } /* GetMinMaxInfo */
-
- /* ScrReSize: processes the WM_SIZE message */
- /* ========= */
-
- BOOL far pascal ScrReSize (HWND hWnd, WORD wParam, WORD cx, WORD cy)
-
- /* returns TRUE only if real resizing performed */
- {
- BOOL ChgWidth, ChgHeight;
-
- if ((wParam != SIZENORMAL) && (wParam != SIZEFULLSCREEN)) {
- return FALSE;
- }
- ChgWidth = (cx != GetWindowWord (hWnd, GWW_SCRCX));
- ChgHeight = (cy != GetWindowWord (hWnd, GWW_SCRCY));
- if (!ChgWidth && !ChgHeight) return FALSE;
-
- SetWindowWord (hWnd, GWW_SCRCX, cx);
- SetWindowWord (hWnd, GWW_SCRCY, cy);
- if (!InternalRequest) {
- SCREEN *TopScreen;
-
- InternalRequest = TRUE;
- TopScreen = first_screen;
- select_screen ((SCREEN *)GetWindowLong (hWnd, GWL_SCRPTR), FALSE);
- if (ChgWidth) {
- newwidth (TRUE, DisplayableColumns (hWnd, cx, &EmacsCM));
- }
- if (ChgHeight) {
- newsize (TRUE, DisplayableRows (hWnd, cy, &EmacsCM));
- }
- select_screen (TopScreen, FALSE);
- update (FALSE);
- InternalRequest = FALSE;
- }
- return TRUE;
- } /* ScrReSize */
-
- /* ScrPaint: processes WM_PAINT messages for emacs screens */
- /* ======== */
-
- void far pascal ScrPaint (HWND hWnd)
- {
- SCREEN *sp;
- PAINTSTRUCT ps;
- HANDLE hPrevFont;
- RECT Rect;
- int Row, BottomRow;
- int Col;
- int Length;
-
- /* note that if the WM_PAINT is not passed through the message loop
- (as would hapen with use of UpdateWindow), it is possible to
- attempt repainting while defferupdate is TRUE which means update
- has been deffered */
-
- BeginPaint (hWnd, &ps);
- sp = (SCREEN*)GetWindowLong (hWnd, GWL_SCRPTR);
-
- /*-calculate the row/col loop control variables and normalize the
- coordinates of the first line's rectangle into Rect */
- CopyRect (&Rect, &ps.rcPaint);
- ClientToCell (hWnd, *(POINT *)&Rect.left, (POINT *)&Rect.left);
- Col = Rect.left;
- Row = Rect.top;
- --Rect.right; /* in rectangle conventions, */
- --Rect.bottom; /* the lower/right border is excluded */
- ClientToCell (hWnd, *(POINT *)&Rect.right, (POINT *)&Rect.right);
- ++Rect.right;
- Length = Rect.right - Col;
- BottomRow = Rect.bottom;
- Rect.bottom = Rect.top + 1;
- CellToClient (hWnd, *(POINT *)&Rect.left, (POINT *)&Rect.left);
- CellToClient (hWnd, *(POINT *)&Rect.right, (POINT *)&Rect.right);
- /* Rect now contains a bounding rectangle for the 1st row. This will
- be used to paint the row's background and will be moved down one
- row's height at each iteration of the painting loop */
-
- /*-loop from top to bottom, writing one line at a time */
- hPrevFont = SelectFont (ps.hdc, hEmacsFont);
- do {
- VIDEO *vp;
- COLORREF FColor, BColor;
- RECT BoundingRect;
-
- vp = sp->s_physical[Row];
- if (!(vp->v_flag & VFNEW)) { /* valid contents */
- #if COLOR
- if (ColorDisplay) {
- FColor = EmacsPalette[vp->v_flag & VFREV ?
- vp->v_bcolor : vp->v_fcolor];
- BColor = EmacsPalette[vp->v_flag & VFREV ?
- vp->v_fcolor : vp->v_bcolor];
- }
- else { /* monochrome display */
- #else
- {
- #endif
- if (vp->v_flag & VFREV) {
- FColor = GetSysColor (COLOR_HIGHLIGHTTEXT);
- BColor = GetSysColor (COLOR_HIGHLIGHT);
- }
- else {
- FColor = GetSysColor (COLOR_WINDOWTEXT);
- BColor = GetSysColor (COLOR_WINDOW);
- }
- }
- SetBkColor (ps.hdc, BColor);
- SetTextColor (ps.hdc, FColor);
- CopyRect (&BoundingRect, &ps.rcPaint);
- if (Row > 0) BoundingRect.top = Rect.top;
- if (Row < BottomRow) BoundingRect.bottom = Rect.bottom;
- ExtTextOut (ps.hdc,
- Rect.left, Rect.top + EmacsCM.HalfLeadingY,
- ETO_OPAQUE, &BoundingRect,
- &vp->v_text[Col],
- Length, NULL);
- }
- Rect.top = Rect.bottom;
- Rect.bottom += EmacsCM.SizeY + EmacsCM.LeadingY;
- } while (++Row <= BottomRow);
-
- SelectObject (ps.hdc, hPrevFont);
- EndScrPaint:
- EndPaint (hWnd, &ps);
- } /* ScrPaint */
-
- /* MLPaint: processes WM_PAINT messages for the Message Line */
- /* ======= */
-
- void far pascal MLPaint (void)
- {
- PAINTSTRUCT ps;
- HANDLE hPrev, hPen;
- RECT Rect;
- POINT Client;
-
- BeginPaint (hFrameWnd, &ps);
-
- /*-draw the text portion targetted for repaint */
- hPrev = SelectFont (ps.hdc, hEmacsFont);
- ClientToCell (hFrameWnd, *(POINT*)&ps.rcPaint.left, (POINT*)&Rect.left);
- ClientToCell (hFrameWnd, *(POINT*)&ps.rcPaint.right, (POINT*)&Rect.right);
- CellToClient (hFrameWnd, *(POINT*)&Rect.left, &Client);
- ExtTextOut (ps.hdc,
- Client.x, Client.y + EmacsCM.HalfLeadingY,
- ETO_OPAQUE, &ps.rcPaint,
- &MLBuf[Rect.left],
- Rect.right - Rect.left + 1, NULL);
- SelectObject (ps.hdc, hPrev);
-
- /*-draw the separation line at top of message line */
- hPen = CreatePen (PS_SOLID, GetSystemMetrics (SM_CYBORDER), RGB(0,0,0));
- hPrev = SelectObject (ps.hdc, hPen);
- GetClientRect (hFrameWnd, &Rect);
- Rect.top = Rect.bottom - EmacsCM.MLHeight;
- MoveTo (ps.hdc, 0, Rect.top);
- LineTo (ps.hdc, Rect.right, Rect.top);
- SelectObject (ps.hdc, hPrev);
- DeleteObject (hPen);
-
- EndPaint (hFrameWnd, &ps);
- } /* MLPaint */
-
- /* spal: set palette from $palette string */
- /* ==== */
-
- PASCAL spal (char *pstr)
- {
- #if COLOR
- int pal; /* current palette position */
-
- for (pal = 0; pal < 16; pal++) {
- DWORD clr; /* current color value */
- int i;
- unsigned char n;
-
- if (*pstr== 0) break;
- clr = 0;
- for (i = 0; i < 3; i++) if (*pstr) {
- n = *pstr++ - '0';
- if (n >= 8) n = 255;
- else n *= 32;
- clr |= (DWORD)n << (i * 8);
- }
- EmacsPalette[pal] = clr;
- }
- #endif
- return 0;
- } /* spal */
-