OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / sys / wince / mhtxtbuf.c
1 /* NetHack 3.6  mhtxtbuf.c      $NHDT-Date: 1432512803 2015/05/25 00:13:23 $  $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */
2 /* Copyright (C) 2003 by Alex Kompel     */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "mhtxtbuf.h"
6
7 /* Collect Nethack text messages and render text into edit box.
8    Wrap text if necessary.
9    Recognize formatted lines as having more that 4 consecutive.
10    spaces inside the string.
11    Strip leading and trailing spaces.
12    Always break at the original line end (do not merge text that comes
13    from NetHack engine)
14 */
15
16 /*----------------------------------------------------------------*/
17 #define NHTEXT_BUFFER_INCREMENT 10
18 /*----------------------------------------------------------------*/
19 struct text_buffer_line {
20     int attr;
21     short beg_padding;
22     short end_padding;
23     BOOL formatted;
24     char *text;
25 };
26 /*----------------------------------------------------------------*/
27 typedef struct mswin_nethack_text_buffer {
28     BOOL b_wrap_text;
29     int n_size;
30     int n_used;
31     struct text_buffer_line *text_buffer_line;
32 } NHTextBuffer, *PNHTextBuffer;
33 /*----------------------------------------------------------------*/
34 #define NHTextLine(pb, i) ((pb)->text_buffer_line[(i)])
35 static TCHAR *nh_append(TCHAR *s, int *size, const char *ap);
36 /*----------------------------------------------------------------*/
37 PNHTextBuffer
38 mswin_init_text_buffer(BOOL wrap_text)
39 {
40     PNHTextBuffer pb = (PNHTextBuffer) malloc(sizeof(NHTextBuffer));
41     if (!pb)
42         panic("Out of memory");
43
44     ZeroMemory(pb, sizeof(NHTextBuffer));
45     pb->b_wrap_text = wrap_text;
46     pb->n_size = 0;
47     pb->n_used = 0;
48     pb->text_buffer_line = NULL;
49     return pb;
50 }
51 /*----------------------------------------------------------------*/
52 void
53 mswin_free_text_buffer(PNHTextBuffer pb)
54 {
55     int i;
56
57     if (!pb)
58         return;
59
60     for (i = 0; i < pb->n_used; i++) {
61         free(pb->text_buffer_line[i].text);
62     }
63     free(pb->text_buffer_line);
64     free(pb);
65 }
66 /*----------------------------------------------------------------*/
67 void
68 mswin_add_text(PNHTextBuffer pb, int attr, const char *text)
69 {
70     char *p;
71     struct text_buffer_line *new_line;
72
73     /* grow buffer */
74     if (pb->n_used >= pb->n_size) {
75         pb->n_size += NHTEXT_BUFFER_INCREMENT;
76         pb->text_buffer_line = (struct text_buffer_line *) realloc(
77             pb->text_buffer_line,
78             pb->n_size * sizeof(struct text_buffer_line));
79         if (!pb->text_buffer_line)
80             panic("Memory allocation error");
81     }
82
83     /* analyze the new line of text */
84     new_line = &NHTextLine(pb, pb->n_used);
85     new_line->attr = attr;
86     new_line->beg_padding = 0;
87     new_line->text = strdup(text);
88     for (p = new_line->text; *p && isspace(*p); p++) {
89         new_line->beg_padding++;
90     }
91     if (*p) {
92         memmove(new_line->text, new_line->text + new_line->beg_padding,
93                 strlen(new_line->text) - new_line->beg_padding + 1);
94         for (p = new_line->text + strlen(new_line->text);
95              p >= new_line->text && isspace(*p); p--) {
96             new_line->end_padding++;
97             *p = 0;
98         }
99
100         /* if there are 3 (or more) consecutive spaces inside the string
101            consider it formatted */
102         new_line->formatted = (strstr(new_line->text, "   ") != NULL)
103                               || (new_line->beg_padding > 8);
104     } else {
105         new_line->end_padding = 0;
106         new_line->text[0] = 0;
107         new_line->formatted = FALSE;
108     }
109     pb->n_used++;
110 }
111 /*----------------------------------------------------------------*/
112 void
113 mswin_set_text_wrap(PNHTextBuffer pb, BOOL wrap_text)
114 {
115     pb->b_wrap_text = wrap_text;
116 }
117 /*----------------------------------------------------------------*/
118 BOOL
119 mswin_get_text_wrap(PNHTextBuffer pb)
120 {
121     return pb->b_wrap_text;
122 }
123 /*----------------------------------------------------------------*/
124 static TCHAR *
125 nh_append(TCHAR *s, int *size, const char *ap)
126 {
127     int tlen, tnewlen;
128
129     if (!(ap && *ap))
130         return s;
131
132     /* append the calculated line to the text buffer */
133     tlen = s ? _tcslen(s) : 0;
134     tnewlen = tlen + strlen(ap);
135     if (tnewlen >= *size) {
136         *size = max(tnewlen, *size + BUFSZ);
137         s = (TCHAR *) realloc(s, *size * sizeof(TCHAR));
138         if (!s)
139             panic("Out of memory");
140         ZeroMemory(s + tlen, (*size - tlen) * sizeof(TCHAR));
141     }
142     if (strcmp(ap, "\r\n") == 0) {
143         _tcscat(s, TEXT("\r\n"));
144     } else {
145         NH_A2W(ap, s + tlen, strlen(ap));
146         s[tnewlen] = 0;
147     }
148     return s;
149 }
150 /*----------------------------------------------------------------*/
151 void
152 mswin_render_text(PNHTextBuffer pb, HWND edit_control)
153 {
154     RECT rt_client;    /* boundaries of the client area of the edit control */
155     SIZE size_text;    /* size of the edit control */
156     RECT rt_text;      /* calculated text rectangle for the visible line */
157     char buf[BUFSZ];   /* buffer for the visible line */
158     TCHAR tbuf[BUFSZ]; /* temp buffer for DrawText */
159     TCHAR *pText = NULL;    /* resulting text (formatted) */
160     int pTextSize = 0;      /* resulting text size */
161     char *p_cur = NULL;     /* current position in the
162                                NHTextBuffer->text_buffer_line->text */
163     char *p_buf_cur = NULL; /* current position in the visible line buffer */
164     int i;
165     HDC hdcEdit;           /* device context for the edit control */
166     HFONT hFont, hOldFont; /* edit control font */
167
168     GetClientRect(edit_control, &rt_client);
169     size_text.cx = rt_client.right - rt_client.left;
170     size_text.cy = rt_client.bottom - rt_client.top;
171     size_text.cx -=
172         GetSystemMetrics(SM_CXVSCROLL); /* add a slight right margin - the
173                                            text looks better that way */
174     hdcEdit = GetDC(edit_control);
175     hFont = (HFONT) SendMessage(edit_control, WM_GETFONT, 0, 0);
176     if (hFont)
177         hOldFont = SelectObject(hdcEdit, hFont);
178
179     /* loop through each line (outer loop) and wrap it around (inner loop) */
180     ZeroMemory(buf, sizeof(buf));
181     p_buf_cur = buf;
182     for (i = 0; i < pb->n_used; i++) {
183         if (pb->b_wrap_text) {
184             p_cur = NHTextLine(pb, i).text;
185
186             /* insert an line break for the empty string */
187             if (!NHTextLine(pb, i).text[0]) {
188                 pText = nh_append(pText, &pTextSize, "\r\n");
189                 continue;
190             }
191
192             /* add margin to the "formatted" line of text */
193             if (NHTextLine(pb, i).formatted) {
194                 strcpy(buf, "   ");
195                 p_buf_cur += 3;
196             }
197
198             /* scroll thourgh the current line of text and wrap it
199                so it fits to width of the edit control */
200             while (*p_cur) {
201                 char *p_word_pos = p_buf_cur;
202
203                 /* copy one word into the buffer */
204                 while (*p_cur && isspace(*p_cur))
205                     if (p_buf_cur != buf)
206                         *p_buf_cur++ = *p_cur++;
207                     else
208                         p_cur++;
209
210                 while (*p_cur && !isspace(*p_cur))
211                     *p_buf_cur++ = *p_cur++;
212
213                 /* check if it fits */
214                 SetRect(&rt_text, 0, 0, size_text.cx, size_text.cy);
215                 DrawText(hdcEdit, NH_A2W(buf, tbuf, p_buf_cur - buf),
216                          p_buf_cur - buf, &rt_text,
217                          DT_CALCRECT | DT_LEFT | DT_SINGLELINE | DT_NOCLIP);
218                 if ((rt_text.right - rt_text.left) >= size_text.cx) {
219                     /* Backtrack.
220                        Only backtrack if the last word caused the overflow -
221                        do not backtrack if the entire current line does not
222                        fit the visible area.
223                        Otherwise it is a infinite loop.
224                     */
225                     if (p_word_pos > buf) {
226                         p_cur -= (p_buf_cur - p_word_pos);
227                         p_buf_cur = p_word_pos;
228                     }
229                     *p_buf_cur = 0; /* break the line */
230
231                     /* append the calculated line to the text buffer */
232                     pText = nh_append(pText, &pTextSize, buf);
233                     pText = nh_append(pText, &pTextSize, "\r\n");
234                     ZeroMemory(buf, sizeof(buf));
235                     p_buf_cur = buf;
236                 }
237             }
238
239             /* always break the line at the end of the buffer text */
240             if (p_buf_cur != buf) {
241                 /* flush the current buffrer */
242                 *p_buf_cur = 0; /* break the line */
243                 pText = nh_append(pText, &pTextSize, buf);
244                 pText = nh_append(pText, &pTextSize, "\r\n");
245                 ZeroMemory(buf, sizeof(buf));
246                 p_buf_cur = buf;
247             }
248         } else { /* do not wrap text */
249             int j;
250             for (j = 0; j < NHTextLine(pb, i).beg_padding; j++)
251                 pText = nh_append(pText, &pTextSize, " ");
252             pText = nh_append(pText, &pTextSize, NHTextLine(pb, i).text);
253             pText = nh_append(pText, &pTextSize, "\r\n");
254         }
255     }
256
257     /* cleanup */
258     if (hFont)
259         SelectObject(hdcEdit, hOldFont);
260     ReleaseDC(edit_control, hdcEdit);
261
262     /* update edit control text */
263     if (pText) {
264         SendMessage(edit_control, EM_FMTLINES, 1, 0);
265         SetWindowText(edit_control, pText);
266         free(pText);
267     }
268 }
269 /*----------------------------------------------------------------*/