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