OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / win / win32 / mhstatus.c
1 /* NetHack 3.6  mhstatus.c      $NHDT-Date: 1432512810 2015/05/25 00:13:30 $  $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */
2 /* Copyright (C) 2001 by Alex Kompel     */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include <assert.h>
6 #include "winMS.h"
7 #include "mhstatus.h"
8 #include "mhmsg.h"
9 #include "mhfont.h"
10
11 #define NHSW_LINES 2
12 #define MAXWINDOWTEXT BUFSZ
13
14 extern COLORREF nhcolor_to_RGB(int c); /* from mhmap */
15
16 typedef struct back_buffer {
17     HWND hWnd;
18     HDC hdc;
19     HBITMAP bm;
20     HBITMAP orig_bm;
21     int width;
22     int height;
23 } back_buffer_t;
24
25 void back_buffer_free(back_buffer_t * back_buffer)
26 {
27     if (back_buffer->bm != NULL) {
28         SelectObject(back_buffer->hdc, back_buffer->orig_bm);
29         DeleteObject(back_buffer->bm);
30         back_buffer->bm = NULL;
31     }
32 }
33
34 void back_buffer_allocate(back_buffer_t * back_buffer, int width, int height)
35 {
36     HDC hdc = GetDC(back_buffer->hWnd);
37     back_buffer->bm = CreateCompatibleBitmap(hdc, width, height);
38     back_buffer->orig_bm =  SelectObject(back_buffer->hdc, back_buffer->bm);
39     back_buffer->width = width;
40     back_buffer->height = height;
41     ReleaseDC(back_buffer->hWnd, hdc);
42 }
43
44 void back_buffer_size(back_buffer_t * back_buffer, int width, int height)
45 {
46     if (back_buffer->bm == NULL || back_buffer->width != width
47                                 || back_buffer->height != height) {
48         back_buffer_free(back_buffer);
49         back_buffer_allocate(back_buffer, width, height);
50     }
51 }
52
53 void back_buffer_init(back_buffer_t * back_buffer, HWND hWnd, int width, int height)
54 {
55     back_buffer->hWnd = hWnd;
56     back_buffer->hdc = CreateCompatibleDC(NULL);
57     back_buffer->bm = NULL;
58
59     back_buffer_size(back_buffer, width, height);
60 }
61
62 typedef struct mswin_nethack_status_window {
63     int index;
64     char window_text[NHSW_LINES][MAXWINDOWTEXT + 1];
65     int n_fields;
66     const char **vals;
67     boolean *activefields;
68     int *percents;
69     int *colors;
70     back_buffer_t back_buffer;
71 } NHStatusWindow, *PNHStatusWindow;
72
73 static int fieldorder1[] = { BL_TITLE, BL_STR, BL_DX,    BL_CO,    BL_IN,
74                              BL_WI,    BL_CH,  BL_ALIGN, BL_SCORE, -1 };
75 static int fieldorder2[] = { BL_LEVELDESC, BL_GOLD,      BL_HP,   BL_HPMAX,
76                              BL_ENE,       BL_ENEMAX,    BL_AC,   BL_XP,
77                              BL_EXP,       BL_HD,        BL_TIME, BL_HUNGER,
78                              BL_CAP,       BL_CONDITION, -1 };
79 static int *fieldorders[] = { fieldorder1, fieldorder2, NULL };
80
81 static TCHAR szStatusWindowClass[] = TEXT("MSNHStatusWndClass");
82 LRESULT CALLBACK StatusWndProc(HWND, UINT, WPARAM, LPARAM);
83 static void register_status_window_class(void);
84 static LRESULT onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam);
85
86 #define DEFAULT_COLOR_BG_STATUS COLOR_WINDOW
87 #define DEFAULT_COLOR_FG_STATUS COLOR_WINDOWTEXT
88
89 HWND
90 mswin_init_status_window()
91 {
92     static int run_once = 0;
93     HWND ret;
94     NHStatusWindow *data;
95     RECT rt;
96     int width, height;
97
98     if (!run_once) {
99         register_status_window_class();
100         run_once = 1;
101     }
102
103     /* get window position */
104     if (GetNHApp()->bAutoLayout) {
105         SetRect(&rt, 0, 0, 0, 0);
106     } else {
107         mswin_get_window_placement(NHW_STATUS, &rt);
108     }
109
110     /* create status window object */
111     width = rt.right - rt.left;
112     height = rt.bottom - rt.top;
113     ret = CreateWindow(szStatusWindowClass, NULL,
114                        WS_CHILD | WS_CLIPSIBLINGS | WS_SIZEBOX,
115                        rt.left, /* horizontal position of window */
116                        rt.top,  /* vertical position of window */
117                        width,   /* window width */
118                        height,  /* window height */
119                        GetNHApp()->hMainWnd, NULL, GetNHApp()->hApp, NULL);
120     if (!ret)
121         panic("Cannot create status window");
122
123     /* Set window caption */
124     SetWindowText(ret, "Status");
125
126     /* create window data */
127     data = (PNHStatusWindow) malloc(sizeof(NHStatusWindow));
128     if (!data)
129         panic("out of memory");
130
131     ZeroMemory(data, sizeof(NHStatusWindow));
132     SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data);
133
134     back_buffer_init(&data->back_buffer, ret, width, height);
135
136     mswin_apply_window_style(ret);
137
138     if (status_bg_brush == NULL) {
139         status_bg_color = (COLORREF)GetSysColor(DEFAULT_COLOR_BG_STATUS);
140         status_bg_brush = CreateSolidBrush(status_bg_color);
141     }
142
143     if (status_fg_brush == NULL) {
144         status_fg_color = (COLORREF)GetSysColor(DEFAULT_COLOR_FG_STATUS);
145         status_fg_brush = CreateSolidBrush(status_fg_color);
146     }
147
148     return ret;
149 }
150
151 void
152 register_status_window_class()
153 {
154     WNDCLASS wcex;
155     ZeroMemory(&wcex, sizeof(wcex));
156
157     wcex.style = CS_NOCLOSE;
158     wcex.lpfnWndProc = (WNDPROC) StatusWndProc;
159     wcex.cbClsExtra = 0;
160     wcex.cbWndExtra = 0;
161     wcex.hInstance = GetNHApp()->hApp;
162     wcex.hIcon = NULL;
163     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
164     wcex.hbrBackground = NULL;
165     wcex.lpszMenuName = NULL;
166     wcex.lpszClassName = szStatusWindowClass;
167
168     RegisterClass(&wcex);
169 }
170
171 LRESULT CALLBACK
172 StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
173 {
174     PNHStatusWindow data;
175
176     data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
177     switch (message) {
178     case WM_MSNH_COMMAND: {
179         switch (wParam) {
180         case MSNH_MSG_PUTSTR: {
181             PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam;
182             strncpy(data->window_text[data->index], msg_data->text,
183                     MAXWINDOWTEXT);
184             data->index = (data->index + 1) % NHSW_LINES;
185             InvalidateRect(hWnd, NULL, TRUE);
186         } break;
187
188         case MSNH_MSG_CLEAR_WINDOW: {
189             data->index = 0;
190             ZeroMemory(data->window_text, sizeof(data->window_text));
191             InvalidateRect(hWnd, NULL, TRUE);
192         } break;
193
194         case MSNH_MSG_GETTEXT: {
195             PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam;
196 #ifdef STATUS_HILITES
197             int **fop;
198             int *f;
199
200             msg_data->buffer[0] = '\0';
201             if (data->n_fields > 0) {
202                 for (fop = fieldorders; *fop; fop++) {
203                     for (f = *fop; *f != -1; f++) {
204                         if (data->activefields[*f])
205                             strncat(msg_data->buffer, data->vals[*f],
206                                     msg_data->max_size
207                                     - strlen(msg_data->buffer));
208                     }
209                     strncat(msg_data->buffer, "\r\n",
210                             msg_data->max_size - strlen(msg_data->buffer));
211                 }
212             }
213 #else
214             strncpy(msg_data->buffer, data->window_text[0],
215                     msg_data->max_size);
216             strncat(msg_data->buffer, "\r\n",
217                     msg_data->max_size - strlen(msg_data->buffer));
218             strncat(msg_data->buffer, data->window_text[1],
219                     msg_data->max_size - strlen(msg_data->buffer));
220 #endif
221         } break;
222
223         case MSNH_MSG_UPDATE_STATUS: {
224             PMSNHMsgUpdateStatus msg_data = (PMSNHMsgUpdateStatus) lParam;
225             data->n_fields = msg_data->n_fields;
226             data->vals = msg_data->vals;
227             data->activefields = msg_data->activefields;
228             data->percents = msg_data->percents;
229             data->colors = msg_data->colors;
230             InvalidateRect(hWnd, NULL, TRUE);
231         } break;
232         } /* end switch( wParam ) { */
233     } break;
234
235     case WM_PAINT:
236         return onWMPaint(hWnd, wParam, lParam);
237
238     case WM_SIZE: {
239         RECT rt;
240         GetWindowRect(hWnd, &rt);
241         ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
242         ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
243         mswin_update_window_placement(NHW_STATUS, &rt);
244     }
245         return FALSE;
246
247     case WM_MOVE: {
248         RECT rt;
249         GetWindowRect(hWnd, &rt);
250         ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
251         ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
252         mswin_update_window_placement(NHW_STATUS, &rt);
253     }
254         return FALSE;
255
256     case WM_DESTROY:
257         free(data);
258         SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
259         break;
260
261     case WM_SETFOCUS:
262         SetFocus(GetNHApp()->hMainWnd);
263         break;
264
265     default:
266         return DefWindowProc(hWnd, message, wParam, lParam);
267     }
268     return 0;
269 }
270
271 #ifdef STATUS_HILITES
272 static LRESULT
273 onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
274 {
275     int hpbar_percent = 100;
276     int hpbar_color = NO_COLOR;
277     int *f;
278     int **fop;
279     SIZE sz;
280     HGDIOBJ normalFont, boldFont;
281     TCHAR wbuf[BUFSZ];
282     RECT rt;
283     PAINTSTRUCT ps;
284     HDC hdc;
285     PNHStatusWindow data;
286     int width, height;
287     RECT clear_rect;
288     HDC front_buffer_hdc;
289
290     data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
291
292     front_buffer_hdc = BeginPaint(hWnd, &ps);
293     GetClientRect(hWnd, &rt);
294
295     width = rt.right - rt.left;
296     height = rt.bottom - rt.top;
297
298     back_buffer_size(&data->back_buffer, width, height);
299
300     hdc = data->back_buffer.hdc;
301
302     normalFont = mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE);
303     boldFont = mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, FALSE);
304
305     SelectObject(hdc, normalFont);
306
307     SetBkColor(hdc, status_bg_color);
308     SetTextColor(hdc, status_fg_color);
309
310     if (iflags.wc2_hitpointbar && BL_HP < data->n_fields
311         && data->activefields[BL_HP]) {
312         hpbar_percent = data->percents[BL_HP];
313         hpbar_color = data->colors[BL_HP] & 0x00ff;
314     }
315
316     clear_rect.left = 0;
317     clear_rect.top = 0;
318     clear_rect.right = width;
319     clear_rect.bottom = height;
320
321     FillRect(hdc, &clear_rect, status_bg_brush);
322
323     for (fop = fieldorders; *fop; fop++) {
324         LONG left = rt.left;
325         LONG cy = 0;
326         int vlen;
327         for (f = *fop; *f != -1; f++) {
328             int clr, atr;
329             int fntatr = ATR_NONE;
330             HGDIOBJ fnt;
331             COLORREF nFg, nBg;
332
333             if (((*f) >= data->n_fields) || (!data->activefields[*f]))
334                 continue;
335             clr = data->colors[*f] & 0x00ff;
336             atr = (data->colors[*f] & 0xff00) >> 8;
337             vlen = strlen(data->vals[*f]);
338             NH_A2W(data->vals[*f], wbuf, SIZE(wbuf));
339
340             if (atr & HL_BOLD)
341                 fntatr = ATR_BOLD;
342             else if (atr & HL_INVERSE)
343                 fntatr = ATR_INVERSE;
344             else if (atr & HL_ULINE)
345                 fntatr = ATR_ULINE;
346             else if (atr & HL_BLINK)
347                 fntatr = ATR_BLINK;
348             else if (atr & HL_DIM)
349                 fntatr = ATR_DIM;
350             fnt = mswin_get_font(NHW_STATUS, fntatr, hdc, FALSE);
351             nFg = (clr == NO_COLOR ? status_fg_color
352                    : ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr)
353                       : status_fg_color));
354             nBg = status_bg_color;
355
356             sz.cy = -1;
357             if (*f == BL_TITLE && iflags.wc2_hitpointbar) {
358                 HBRUSH back_brush = CreateSolidBrush(nhcolor_to_RGB(hpbar_color));
359                 RECT barrect;
360
361                 /* prepare for drawing */
362                 SelectObject(hdc, fnt);
363                 SetBkMode(hdc, OPAQUE);
364                 SetBkColor(hdc, status_bg_color);
365                 SetTextColor(hdc, nhcolor_to_RGB(hpbar_color));
366
367                 /* get bounding rectangle */
368                 GetTextExtentPoint32(hdc, wbuf, vlen, &sz);
369
370                 /* first draw title normally */
371                 DrawText(hdc, wbuf, vlen, &rt, DT_LEFT);
372
373                 /* calc bar length */
374                 barrect.left = rt.left;
375                 barrect.top = rt.top;
376                 barrect.bottom = sz.cy;
377                 if (hpbar_percent > 0)
378                     barrect.right = (int)((hpbar_percent * sz.cx) / 100);
379                 else
380                     barrect.right = sz.cx;
381
382                 /* then draw hpbar on top of title */
383                 FillRect(hdc, &barrect, back_brush);
384                 SetBkMode(hdc, TRANSPARENT);
385                 SetTextColor(hdc, nBg);
386                 DrawText(hdc, wbuf, vlen, &barrect, DT_LEFT);
387
388                 DeleteObject(back_brush);
389             } else {
390                 if (atr & HL_INVERSE) {
391                     COLORREF tmp = nFg;
392                     nFg = nBg;
393                     nBg = tmp;
394                 }
395
396                 /* prepare for drawing */
397                 SelectObject(hdc, fnt);
398                 SetBkMode(hdc, OPAQUE);
399                 SetBkColor(hdc, nBg);
400                 SetTextColor(hdc, nFg);
401
402                 /* get bounding rectangle */
403                 GetTextExtentPoint32(hdc, wbuf, vlen, &sz);
404
405                 /* draw */
406                 DrawText(hdc, wbuf, vlen, &rt, DT_LEFT);
407             }
408             assert(sz.cy >= 0);
409
410             rt.left += sz.cx;
411             cy = max(cy, sz.cy);
412         }
413
414         rt.left = left;
415         rt.top += cy;
416     }
417
418     BitBlt(front_buffer_hdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
419
420     EndPaint(hWnd, &ps);
421
422     return 0;
423 }
424 #else
425 static LRESULT
426 onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
427 {
428     int i;
429     SIZE sz;
430     HGDIOBJ oldFont;
431     TCHAR wbuf[BUFSZ];
432     COLORREF OldBg, OldFg;
433     RECT rt;
434     PAINTSTRUCT ps;
435     HDC hdc;
436     PNHStatusWindow data;
437
438     data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
439
440     hdc = BeginPaint(hWnd, &ps);
441     GetClientRect(hWnd, &rt);
442
443     oldFont =
444         SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE));
445
446     OldBg = SetBkColor(hdc, status_bg_brush ? status_bg_color
447                                             : (COLORREF) GetSysColor(
448                                                   DEFAULT_COLOR_BG_STATUS));
449     OldFg = SetTextColor(hdc, status_fg_brush ? status_fg_color
450                                               : (COLORREF) GetSysColor(
451                                                     DEFAULT_COLOR_FG_STATUS));
452
453     for (i = 0; i < NHSW_LINES; i++) {
454         int wlen = strlen(data->window_text[i]);
455         NH_A2W(data->window_text[i], wbuf, SIZE(wbuf));
456         GetTextExtentPoint32(hdc, wbuf, wlen, &sz);
457         DrawText(hdc, wbuf, wlen, &rt, DT_LEFT | DT_END_ELLIPSIS);
458         rt.top += sz.cy;
459     }
460
461     SelectObject(hdc, oldFont);
462     SetTextColor(hdc, OldFg);
463     SetBkColor(hdc, OldBg);
464     EndPaint(hWnd, &ps);
465
466     return 0;
467 }
468 #endif /* !STATUS_HILITES */
469
470 void
471 mswin_status_window_size(HWND hWnd, LPSIZE sz)
472 {
473     TEXTMETRIC tm;
474     HGDIOBJ saveFont;
475     HDC hdc;
476     PNHStatusWindow data;
477     RECT rt;
478     SIZE text_sz;
479
480     GetClientRect(hWnd, &rt);
481
482     data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
483     if (data) {
484         hdc = GetDC(hWnd);
485         saveFont = SelectObject(
486             hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE));
487         GetTextExtentPoint32(hdc, _T("W"), 1, &text_sz);
488         GetTextMetrics(hdc, &tm);
489
490         rt.bottom = rt.top + text_sz.cy * NHSW_LINES;
491
492         SelectObject(hdc, saveFont);
493         ReleaseDC(hWnd, hdc);
494     }
495     AdjustWindowRect(&rt, GetWindowLong(hWnd, GWL_STYLE), FALSE);
496     sz->cx = rt.right - rt.left;
497     sz->cy = rt.bottom - rt.top;
498 }