OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / sys / wince / mhtxtbuf.c
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 /*----------------------------------------------------------------*/
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 /*----------------------------------------------------------------*/
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 /*----------------------------------------------------------------*/
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 /*----------------------------------------------------------------*/
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 /*----------------------------------------------------------------*/
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