OSDN Git Service

upgrade to 3.6.2
[jnethack/source.git] / sys / wince / mhmsgwnd.c
1 /* NetHack 3.6  mhmsgwnd.c      $NHDT-Date: 1432512802 2015/05/25 00:13:22 $  $NHDT-Branch: master $:$NHDT-Revision: 1.20 $ */
2 /* Copyright (C) 2001 by Alex Kompel     */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "winMS.h"
6 #include "mhmsgwnd.h"
7 #include "mhmsg.h"
8 #include "mhcmd.h"
9 #include "mhfont.h"
10 #include "mhcolor.h"
11
12 #define MSG_WRAP_TEXT
13
14 #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2)
15 #define MAX_MSG_LINES 32
16 #define MSG_LINES (int) min(iflags.msg_history, MAX_MSG_LINES)
17 #define MAXWINDOWTEXT 200
18
19 struct window_line {
20     int attr;
21     char text[MAXWINDOWTEXT];
22 };
23
24 typedef struct mswin_nethack_message_window {
25     size_t max_text;
26     struct window_line window_text[MAX_MSG_LINES];
27
28     int xChar;           /* horizontal scrolling unit */
29     int yChar;           /* vertical scrolling unit */
30     int xUpper;          /* average width of uppercase letters */
31     int xPos;            /* current horizontal scrolling position */
32     int yPos;            /* current vertical scrolling position */
33     int xMax;            /* maximum horizontal scrolling position */
34     int yMax;            /* maximum vertical scrolling position */
35     int xPage;           /* page size of horizontal scroll bar */
36     int lines_last_turn; /* lines added during the last turn */
37     int dont_care; /* flag the user does not care if messages are lost */
38 } NHMessageWindow, *PNHMessageWindow;
39
40 static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass");
41 LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM);
42 static void register_message_window_class();
43 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
44 static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
45 #ifndef MSG_WRAP_TEXT
46 static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
47 #endif
48 static COLORREF setMsgTextColor(HDC hdc, int gray);
49 static void onPaint(HWND hWnd);
50 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
51
52 #ifdef USER_SOUNDS
53 extern void play_sound_for_message(const char *str);
54 #endif
55
56 HWND
57 mswin_init_message_window()
58 {
59     static int run_once = 0;
60     HWND ret;
61     DWORD style;
62
63     if (!run_once) {
64         register_message_window_class();
65         run_once = 1;
66     }
67
68 #ifdef MSG_WRAP_TEXT
69     style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL;
70 #else
71     style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL;
72 #endif
73
74     ret = CreateWindow(
75         szMessageWindowClass, /* registered class name */
76         NULL,                 /* window name */
77         style,                /* window style */
78         0,                    /* horizontal position of window */
79         0,                    /* vertical position of window */
80         0,                    /* window width */
81         0,                    /* window height - set it later */
82         GetNHApp()->hMainWnd, /* handle to parent or owner window */
83         NULL,                 /* menu handle or child identifier */
84         GetNHApp()->hApp,     /* handle to application instance */
85         NULL);                /* window-creation data */
86
87     if (!ret)
88         panic("Cannot create message window");
89
90     return ret;
91 }
92
93 void
94 register_message_window_class()
95 {
96     WNDCLASS wcex;
97     ZeroMemory(&wcex, sizeof(wcex));
98
99     wcex.style = CS_NOCLOSE;
100     wcex.lpfnWndProc = (WNDPROC) NHMessageWndProc;
101     wcex.cbClsExtra = 0;
102     wcex.cbWndExtra = 0;
103     wcex.hInstance = GetNHApp()->hApp;
104     wcex.hIcon = NULL;
105     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
106     wcex.hbrBackground = mswin_get_brush(NHW_MESSAGE, MSWIN_COLOR_BG);
107     wcex.lpszMenuName = NULL;
108     wcex.lpszClassName = szMessageWindowClass;
109
110     RegisterClass(&wcex);
111 }
112
113 LRESULT CALLBACK
114 NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
115 {
116     switch (message) {
117     case WM_CREATE:
118         onCreate(hWnd, wParam, lParam);
119         break;
120
121     case WM_MSNH_COMMAND:
122         onMSNHCommand(hWnd, wParam, lParam);
123         break;
124
125     case WM_PAINT:
126         onPaint(hWnd);
127         break;
128
129     case WM_SETFOCUS:
130         SetFocus(GetNHApp()->hMainWnd);
131         break;
132
133 #ifndef MSG_WRAP_TEXT
134     case WM_HSCROLL:
135         onMSNH_HScroll(hWnd, wParam, lParam);
136         break;
137 #endif
138
139     case WM_VSCROLL:
140         onMSNH_VScroll(hWnd, wParam, lParam);
141         break;
142
143     case WM_DESTROY: {
144         PNHMessageWindow data;
145         data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
146         free(data);
147         SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0);
148     } break;
149
150     case WM_SIZE: {
151         SCROLLINFO si;
152         int xNewSize;
153         int yNewSize;
154         PNHMessageWindow data;
155
156         data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
157
158         xNewSize = LOWORD(lParam);
159         yNewSize = HIWORD(lParam);
160
161         if (xNewSize > 0 || yNewSize > 0) {
162 #ifndef MSG_WRAP_TEXT
163             data->xPage = xNewSize / data->xChar;
164             data->xMax = max(0, (int) (1 + data->max_text - data->xPage));
165             data->xPos = min(data->xPos, data->xMax);
166
167             ZeroMemory(&si, sizeof(si));
168             si.cbSize = sizeof(si);
169             si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
170             si.nMin = 0;
171             si.nMax = data->max_text;
172             si.nPage = data->xPage;
173             si.nPos = data->xPos;
174             SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
175 #endif
176
177             data->yMax = MSG_LINES - 1;
178             data->yPos = min(data->yPos, data->yMax);
179
180             ZeroMemory(&si, sizeof(si));
181             si.cbSize = sizeof(si);
182             si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
183             si.nMin = MSG_VISIBLE_LINES;
184             si.nMax = data->yMax + MSG_VISIBLE_LINES - 1;
185             si.nPage = MSG_VISIBLE_LINES;
186             si.nPos = data->yPos;
187             SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
188         }
189     } break;
190
191     default:
192         return DefWindowProc(hWnd, message, wParam, lParam);
193     }
194     return 0;
195 }
196
197 void
198 onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
199 {
200     PNHMessageWindow data;
201
202     data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
203     switch (wParam) {
204     case MSNH_MSG_PUTSTR: {
205         PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam;
206         SCROLLINFO si;
207         char *p;
208
209         if (msg_data->append) {
210             strncat(data->window_text[MSG_LINES - 1].text, msg_data->text,
211                     MAXWINDOWTEXT
212                         - strlen(data->window_text[MSG_LINES - 1].text));
213         } else {
214             /* check if the string is empty */
215             for (p = data->window_text[MSG_LINES - 1].text; *p && isspace(*p);
216                  p++)
217                 ;
218
219             if (*p) {
220                 /* last string is not empty - scroll up */
221                 memmove(&data->window_text[0], &data->window_text[1],
222                         (MSG_LINES - 1) * sizeof(data->window_text[0]));
223             }
224
225             /* append new text to the end of the array */
226             data->window_text[MSG_LINES - 1].attr = msg_data->attr;
227             strncpy(data->window_text[MSG_LINES - 1].text, msg_data->text,
228                     MAXWINDOWTEXT);
229         }
230
231         /* reset V-scroll position to display new text */
232         data->yPos = data->yMax;
233
234         ZeroMemory(&si, sizeof(si));
235         si.cbSize = sizeof(si);
236         si.fMask = SIF_POS;
237         si.nPos = data->yPos;
238         SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
239
240         /* deal with overflows */
241         data->lines_last_turn++;
242         if (!data->dont_care && data->lines_last_turn >= MSG_LINES - 2) {
243             char c;
244             BOOL done;
245
246             /* append "--More--" to the message window text (cannot call
247                putstr
248                here - infinite recursion) */
249             memmove(&data->window_text[0], &data->window_text[1],
250                     (MSG_LINES - 1) * sizeof(data->window_text[0]));
251             data->window_text[MSG_LINES - 1].attr = ATR_NONE;
252             strncpy(data->window_text[MSG_LINES - 1].text, "--More--",
253                     MAXWINDOWTEXT);
254
255             /* update window content */
256             InvalidateRect(hWnd, NULL, TRUE);
257
258 #if defined(WIN_CE_SMARTPHONE)
259             NHSPhoneSetKeypadFromString("\033- <>");
260 #endif
261
262             done = FALSE;
263             while (!done) {
264                 int x, y, mod;
265                 c = mswin_nh_poskey(&x, &y, &mod);
266                 switch (c) {
267                 /* ESC indicates that we can safely discard any further
268                  * messages during this turn */
269                 case '\033':
270                     data->dont_care = 1;
271                     done = TRUE;
272                     break;
273
274                 case '<':
275                     SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0),
276                                 (LPARAM) NULL);
277                     break;
278
279                 case '>':
280                     SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0),
281                                 (LPARAM) NULL);
282                     break;
283
284                 /* continue scrolling on any key */
285                 default:
286                     data->lines_last_turn = 0;
287                     done = TRUE;
288                     break;
289                 }
290             }
291
292 #if defined(WIN_CE_SMARTPHONE)
293             NHSPhoneSetKeypadDefault();
294 #endif
295             /* remove "--More--" from the message window text */
296             data->window_text[MSG_LINES - 1].attr = ATR_NONE;
297             strncpy(data->window_text[MSG_LINES - 1].text, " ",
298                     MAXWINDOWTEXT);
299         }
300
301         /* update window content */
302         InvalidateRect(hWnd, NULL, TRUE);
303
304 #ifdef USER_SOUNDS
305         play_sound_for_message(msg_data->text);
306 #endif
307     } break;
308
309     case MSNH_MSG_CLEAR_WINDOW:
310         data->lines_last_turn = 0;
311         data->dont_care = 0;
312         break;
313     }
314 }
315
316 void
317 onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
318 {
319     PNHMessageWindow data;
320     SCROLLINFO si;
321     int yInc;
322
323     /* get window data */
324     data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
325
326     ZeroMemory(&si, sizeof(si));
327     si.cbSize = sizeof(si);
328     si.fMask = SIF_PAGE | SIF_POS;
329     GetScrollInfo(hWnd, SB_VERT, &si);
330
331     switch (LOWORD(wParam)) {
332     // User clicked the shaft above the scroll box.
333
334     case SB_PAGEUP:
335         yInc = -(int) si.nPage;
336         break;
337
338     // User clicked the shaft below the scroll box.
339
340     case SB_PAGEDOWN:
341         yInc = si.nPage;
342         break;
343
344     // User clicked the top arrow.
345
346     case SB_LINEUP:
347         yInc = -1;
348         break;
349
350     // User clicked the bottom arrow.
351
352     case SB_LINEDOWN:
353         yInc = 1;
354         break;
355
356     // User dragged the scroll box.
357
358     case SB_THUMBTRACK:
359         yInc = HIWORD(wParam) - data->yPos;
360         break;
361
362     default:
363         yInc = 0;
364     }
365
366     // If applying the vertical scrolling increment does not
367     // take the scrolling position out of the scrolling range,
368     // increment the scrolling position, adjust the position
369     // of the scroll box, and update the window. UpdateWindow
370     // sends the WM_PAINT message.
371
372     if (yInc = max(MSG_VISIBLE_LINES - data->yPos,
373                    min(yInc, data->yMax - data->yPos))) {
374         data->yPos += yInc;
375         /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc,
376                 (CONST RECT *) NULL, (CONST RECT *) NULL,
377                 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
378         */
379         InvalidateRect(hWnd, NULL, TRUE);
380
381         ZeroMemory(&si, sizeof(si));
382         si.cbSize = sizeof(si);
383         si.fMask = SIF_POS;
384         si.nPos = data->yPos;
385         SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
386
387         UpdateWindow(hWnd);
388     }
389 }
390
391 #ifndef MSG_WRAP_TEXT
392 void
393 onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
394 {
395     PNHMessageWindow data;
396     SCROLLINFO si;
397     int xInc;
398
399     /* get window data */
400     data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
401
402     ZeroMemory(&si, sizeof(si));
403     si.cbSize = sizeof(si);
404     si.fMask = SIF_PAGE;
405     GetScrollInfo(hWnd, SB_HORZ, &si);
406
407     switch (LOWORD(wParam)) {
408     // User clicked shaft left of the scroll box.
409
410     case SB_PAGEUP:
411         xInc = -(int) si.nPage;
412         break;
413
414     // User clicked shaft right of the scroll box.
415
416     case SB_PAGEDOWN:
417         xInc = si.nPage;
418         break;
419
420     // User clicked the left arrow.
421
422     case SB_LINEUP:
423         xInc = -1;
424         break;
425
426     // User clicked the right arrow.
427
428     case SB_LINEDOWN:
429         xInc = 1;
430         break;
431
432     // User dragged the scroll box.
433
434     case SB_THUMBTRACK:
435         xInc = HIWORD(wParam) - data->xPos;
436         break;
437
438     default:
439         xInc = 0;
440     }
441
442     // If applying the horizontal scrolling increment does not
443     // take the scrolling position out of the scrolling range,
444     // increment the scrolling position, adjust the position
445     // of the scroll box, and update the window.
446
447     if (xInc = max(-data->xPos, min(xInc, data->xMax - data->xPos))) {
448         data->xPos += xInc;
449         ScrollWindowEx(hWnd, -data->xChar * xInc, 0, (CONST RECT *) NULL,
450                        (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
451                        SW_INVALIDATE | SW_ERASE);
452
453         ZeroMemory(&si, sizeof(si));
454         si.cbSize = sizeof(si);
455         si.fMask = SIF_POS;
456         si.nPos = data->xPos;
457         SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
458         UpdateWindow(hWnd);
459     }
460 }
461 #endif // MSG_WRAP_TEXT
462
463 COLORREF
464 setMsgTextColor(HDC hdc, int gray)
465 {
466     COLORREF fg, color1, color2;
467     if (gray) {
468         color1 = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG);
469         color2 = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG);
470         /* Make a "gray" color by taking the average of the individual R,G,B
471            components of two colors. Thanks to Jonathan del Strother */
472         fg = RGB((GetRValue(color1) + GetRValue(color2)) / 2,
473                  (GetGValue(color1) + GetGValue(color2)) / 2,
474                  (GetBValue(color1) + GetBValue(color2)) / 2);
475     } else {
476         fg = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG);
477     }
478
479     return SetTextColor(hdc, fg);
480 }
481
482 void
483 onPaint(HWND hWnd)
484 {
485     PAINTSTRUCT ps;
486     HDC hdc;
487     PNHMessageWindow data;
488     RECT client_rt, draw_rt;
489     int FirstLine, LastLine;
490     int i, x, y;
491     HGDIOBJ oldFont;
492     TCHAR wbuf[MAXWINDOWTEXT + 2];
493     size_t wlen;
494     COLORREF OldBg, OldFg;
495
496     hdc = BeginPaint(hWnd, &ps);
497
498     OldBg = SetBkColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG));
499     OldFg = setMsgTextColor(hdc, 0);
500
501     data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
502
503     GetClientRect(hWnd, &client_rt);
504
505     if (!IsRectEmpty(&ps.rcPaint)) {
506         FirstLine = max(
507             0, data->yPos - (client_rt.bottom - ps.rcPaint.top) / data->yChar
508                    + 1);
509         LastLine =
510             min(MSG_LINES - 1,
511                 data->yPos
512                     - (client_rt.bottom - ps.rcPaint.bottom) / data->yChar);
513         y = min(ps.rcPaint.bottom, client_rt.bottom - 2);
514         for (i = LastLine; i >= FirstLine; i--) {
515             if (i == MSG_LINES - 1) {
516                 x = data->xChar * (2 - data->xPos);
517             } else {
518                 x = data->xChar * (4 - data->xPos);
519             }
520
521             if (strlen(data->window_text[i].text) > 0) {
522                 /* convert to UNICODE */
523                 NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf));
524                 wlen = _tcslen(wbuf);
525
526                 /* calculate text height */
527                 draw_rt.left = x;
528                 draw_rt.right = client_rt.right;
529                 draw_rt.top = y - data->yChar;
530                 draw_rt.bottom = y;
531
532                 oldFont = SelectObject(
533                     hdc,
534                     mswin_get_font(NHW_MESSAGE, data->window_text[i].attr,
535                                    hdc, FALSE));
536
537                 setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn));
538 #ifdef MSG_WRAP_TEXT
539                 DrawText(hdc, wbuf, wlen, &draw_rt,
540                          DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
541                 draw_rt.top = y - (draw_rt.bottom - draw_rt.top);
542                 draw_rt.bottom = y;
543                 DrawText(hdc, wbuf, wlen, &draw_rt,
544                          DT_NOPREFIX | DT_WORDBREAK);
545 #else
546                 DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX);
547 #endif
548                 SelectObject(hdc, oldFont);
549
550                 y -= draw_rt.bottom - draw_rt.top;
551             } else {
552                 y -= data->yChar;
553             }
554         }
555     }
556
557     SetTextColor(hdc, OldFg);
558     SetBkColor(hdc, OldBg);
559     EndPaint(hWnd, &ps);
560 }
561
562 void
563 onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
564 {
565     HDC hdc;
566     TEXTMETRIC tm;
567     PNHMessageWindow data;
568     HGDIOBJ saveFont;
569
570     /* set window data */
571     data = (PNHMessageWindow) malloc(sizeof(NHMessageWindow));
572     if (!data)
573         panic("out of memory");
574     ZeroMemory(data, sizeof(NHMessageWindow));
575     data->max_text = MAXWINDOWTEXT;
576     SetWindowLong(hWnd, GWL_USERDATA, (LONG) data);
577
578     /* Get the handle to the client area's device context. */
579     hdc = GetDC(hWnd);
580     saveFont =
581         SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE));
582
583     /* Extract font dimensions from the text metrics. */
584     GetTextMetrics(hdc, &tm);
585     data->xChar = tm.tmAveCharWidth;
586     data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar / 2;
587     data->yChar = tm.tmHeight + tm.tmExternalLeading;
588     data->xPage = 1;
589
590     /* Free the device context.  */
591     SelectObject(hdc, saveFont);
592     ReleaseDC(hWnd, hdc);
593
594     /* create command pad (keyboard emulator) */
595     if (!GetNHApp()->hCmdWnd)
596         GetNHApp()->hCmdWnd = mswin_init_command_window();
597 }
598
599 void
600 mswin_message_window_size(HWND hWnd, LPSIZE sz)
601 {
602     PNHMessageWindow data;
603     RECT rt, client_rt;
604
605     GetWindowRect(hWnd, &rt);
606
607     sz->cx = rt.right - rt.left;
608     sz->cy = rt.bottom - rt.top;
609
610     data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA);
611     if (data) {
612         /* set size to accomodate MSG_VISIBLE_LINES, highligh rectangle and
613            horizontal scroll bar (difference between window rect and client
614            rect */
615         GetClientRect(hWnd, &client_rt);
616         sz->cy = sz->cy - (client_rt.bottom - client_rt.top)
617                  + data->yChar * MSG_VISIBLE_LINES + 4;
618     }
619 }