OSDN Git Service

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