1 /* Copyright (C) 2003 by Alex Kompel <shurikk@pacbell.net> */
2 /* NetHack may be freely redistributed. See license for details. */
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
15 /*----------------------------------------------------------------*/
16 #define NHTEXT_BUFFER_INCREMENT 10
17 /*----------------------------------------------------------------*/
18 struct text_buffer_line {
25 /*----------------------------------------------------------------*/
26 typedef struct mswin_nethack_text_buffer {
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 /*----------------------------------------------------------------*/
36 PNHTextBuffer mswin_init_text_buffer(BOOL wrap_text)
38 PNHTextBuffer pb = (PNHTextBuffer)malloc(sizeof(NHTextBuffer));
39 if( !pb ) panic("Out of memory");
41 ZeroMemory(pb, sizeof(NHTextBuffer));
42 pb->b_wrap_text = wrap_text;
45 pb->text_buffer_line = NULL;
48 /*----------------------------------------------------------------*/
49 void mswin_free_text_buffer(PNHTextBuffer pb)
55 for(i=0; i<pb->n_used; i++ ) {
56 free(pb->text_buffer_line[i].text);
58 free( pb->text_buffer_line );
61 /*----------------------------------------------------------------*/
62 void mswin_add_text(PNHTextBuffer pb, int attr, const char* text)
65 struct text_buffer_line* new_line;
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");
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++;
84 memmove(new_line->text,
85 new_line->text + new_line->beg_padding,
86 strlen(new_line->text) - new_line->beg_padding + 1
88 for( p = new_line->text+strlen(new_line->text);
89 p>=new_line->text && isspace(*p);
91 new_line->end_padding++;
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);
99 new_line->end_padding = 0;
100 new_line->text[0] = 0;
101 new_line->formatted = FALSE;
105 /*----------------------------------------------------------------*/
106 static TCHAR* nh_append( TCHAR* s, int* size, const char* ap )
110 if( !(ap && *ap) ) return s;
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));
121 if( strcmp(ap, "\r\n")==0 ) {
122 _tcscat(s, TEXT("\r\n"));
124 NH_A2W(ap, s+tlen, strlen(ap));
129 /*----------------------------------------------------------------*/
130 void mswin_render_text(PNHTextBuffer pb, HWND edit_control)
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 */
142 HDC hdcEdit; /* device context for the edit control */
143 HFONT hFont, hOldFont; /* edit control font */
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);
153 /* loop through each line (outer loop) and wrap it around (inner loop) */
154 ZeroMemory(buf, sizeof(buf));
156 for( i=0; i<pb->n_used; i++ ) {
157 if( pb->b_wrap_text ) {
158 p_cur = NHTextLine(pb,i).text;
160 /* insert an line break for the empty string */
161 if( !NHTextLine(pb,i).text[0] ) {
162 pText = nh_append(pText, &pTextSize, "\r\n");
166 /* add margin to the "formatted" line of text */
167 if( NHTextLine(pb,i).formatted ) {
172 /* scroll thourgh the current line of text and wrap it
173 so it fits to width of the edit control */
175 char *p_word_pos = p_buf_cur;
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++;
182 while( *p_cur && !isspace(*p_cur) )
183 *p_buf_cur++ = *p_cur++;
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 ) {
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.
194 if( p_word_pos>buf ) {
195 p_cur -= (p_buf_cur-p_word_pos);
196 p_buf_cur = p_word_pos;
198 *p_buf_cur = 0; /* break the line */
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));
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));
217 } else { /* do not wrap text */
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");
227 if( hFont ) SelectObject(hdcEdit, hOldFont);
228 ReleaseDC(edit_control, hdcEdit);
230 /* update edit control text */
232 SendMessage(edit_control, EM_FMTLINES, 1, 0 );
233 SetWindowText(edit_control, pText);
237 /*----------------------------------------------------------------*/