1 /*******************************************************************************
2  * pvtext.cpp
3  *
4  * This module implements message and message display routines for Windows.
5  *
6  * Author: Christopher J. Cason.
7  *
8  * ---------------------------------------------------------------------------
9  * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
10  * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
11  *
12  * POV-Ray is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU Affero General Public License as
14  * published by the Free Software Foundation, either version 3 of the
15  * License, or (at your option) any later version.
16  *
17  * POV-Ray is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Affero General Public License for more details.
21  *
22  * You should have received a copy of the GNU Affero General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  * ---------------------------------------------------------------------------
25  * POV-Ray is based on the popular DKB raytracer version 2.12.
26  * DKBTrace was originally written by David K. Buck.
27  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
28  * ---------------------------------------------------------------------------
29  * $File: //depot/public/povray/3.x/windows/pvtext.cpp $
30  * $Revision: #1 $
31  * $Change: 6069 $
32  * $DateTime: 2013/11/06 11:59:40 $
33  * $Author: chrisc $
34  *******************************************************************************/
35 
36 #define POVWIN_FILE
37 #define _WIN32_IE COMMONCTRL_VERSION
38 
39 #include <windows.h>
40 #include <commctrl.h>
41 #include <setjmp.h>
42 #include <string.h>
43 
44 #include "pvengine.h"
45 #include "resource.h"
46 #include "pvguiext.h"
47 #include "pvedit.h"
48 
49 // this must be the last file included
50 #include "syspovdebug.h"
51 
52 namespace povwin
53 {
54 
55 #define MAX_SEEK_INDEX            1024
56 
57 typedef struct
58 {
59   unsigned              Line ;
60   unsigned short        Offset ;
61 } seekStruct ;
62 
63 typedef struct
64 {
65   int         id ;
66   int         resid ;
67   int         flags ;
68   char        *text ;
69 } toolbarStruct ;
70 
71 int                     message_xchar ;
72 int                     message_ychar ;
73 int                     listbox_xchar ;
74 int                     listbox_ychar ;
75 int                     top_message_row ;
76 int                     message_scroll_pos_x ;
77 int                     message_scroll_pos_y ;
78 int                     message_count ;
79 int                     message_cols ;
80 int                     message_rows ;
81 int                     EditFileCount ;
82 int                     toolbar_cmdline_width ;
83 int                     toolbar_combobox_width ;
84 int                     bandWidths [8] ;
85 int                     message_output_x = -1 ;
86 char                    *message_buffer [MAX_MESSAGE] ;
87 char                    **first_message ;
88 char                    **next_message ;
89 char                    **last_message ;
90 char                    str_buffer [2048] ;
91 char                    message_font_name [256] ;
92 char                    listbox_font_name [] = "Lucida Console" ;
93 char                    line_buffer [2048] ;
94 char                    *EditFiles [MAX_EDIT_FILES] ;
95 bool                    mem_warned ;
96 unsigned                message_font_size ;
97 unsigned                message_font_weight ;
98 unsigned                listbox_font_size = 8 ;
99 unsigned                listbox_font_weight = FW_NORMAL ;
100 unsigned                editor_line_number ;
101 unsigned                editor_char_pos ;
102 unsigned                editor_offset ;
103 unsigned                seek_entry_count ;
104 RECT                    current_rect ;
105 bool                    keep_messages ;
106 HFONT                   message_font ;
107 HFONT                   listbox_font ;
108 HFONT                   tab_font ;
109 char                    sbToolText[512];
110 TOOLINFO                sbToolInfo;
111 seekStruct              seek_entries [MAX_SEEK_INDEX] ;
112 HIMAGELIST              ToolImages1 ;
113 HIMAGELIST              ToolImages2 ;
114 
115 extern int              statistics_count ;
116 extern int              delay_next_status ;
117 extern int              seconds_for_last_line ;
118 extern char             tool_help [MAX_TOOLCMD] [MAX_TOOLHELPTEXT] ;
119 extern char             requested_render_file [] ;
120 extern char             source_file_name [] ;
121 extern char             NetworkAddress [] ;
122 extern char             PovStatusPanelWinClass [] ;
123 extern char             *EditDLLPath ;
124 extern bool             ListenMode ;
125 extern bool             ControlMode ;
126 extern void             *CurrentEditor ;
127 extern time_t           quit ;
128 extern unsigned         background_width ;
129 extern unsigned         background_height ;
130 extern unsigned         window_count ;
131 extern unsigned         statusheight ;
132 extern unsigned         screen_depth ;
133 extern unsigned         render_width ;
134 extern unsigned         ThreadCount ;
135 extern HWND             main_window ;
136 extern HWND             message_window ;
137 extern HWND             hToolComboBox ;
138 extern HWND             window_list [MAX_WINDOWS] ;
139 extern HWND             toolbar_combobox ;
140 extern HWND             aux_toolbar_window ;
141 extern HWND             statuspanel ;
142 extern HWND             StatusWindow ;
143 extern HWND             StatusTooltip ;
144 extern HWND             toolbar_cmdline ;
145 extern bool             IsWin32 ;
146 extern bool             fast_scroll ;
147 extern bool             tile_background ;
148 extern bool             IsW95UserInterface ;
149 extern bool             use_toolbar ;
150 extern bool             resizing ;
151 extern bool             exit_after_render ;
152 extern bool             demo_mode ;
153 extern bool             debugging ;
154 extern bool             render_requested ;
155 extern bool             noexec ;
156 extern bool             NoRestore ;
157 extern bool             rendering ;
158 extern bool             run_renderer ;
159 extern bool             rendering_animation ;
160 extern bool             no_status_output ;
161 extern bool             stop_rendering ;
162 extern bool             benchmark_mode;
163 extern HBITMAP          hBmpBackground ;
164 extern HBITMAP          hBmpRendering ;
165 extern COLORREF         background_colour ;
166 extern COLORREF         background_shade ;
167 extern COLORREF         text_colours[3] ;
168 extern HPALETTE         hPalApp ;
169 extern CRITICAL_SECTION critical_section ;
170 
171 int                     toolbar_ids [] = {
172                                           CM_FILENEW,
173                                           CM_FILEOPEN,
174                                           CM_FILESAVE,
175                                           CM_FILEQUEUE,
176                                           CM_RENDERSHOW,
177                                           CM_COMMANDLINE,
178                                           CM_SOURCEFILE,
179                                           CM_FILERENDER,
180                                           CM_RENDERSLEEP | 0x8000,
181                                          } ;
182 
183 #define MAX_TOOLS       (sizeof (toolbar_ids) / sizeof (int))
184 
185 toolbarStruct           maintools [] =
186                         {
187                           {CM_FILENEW,       BMP_TOOLFILENEW,              0x00, "New"},
188                           {CM_FILEOPEN,      BMP_TOOLFILEOPEN,             0x00, "Open"},
189                           {CM_FILESAVE,      BMP_TOOLFILESAVE,             0x00, "Save"},
190                           {CM_FILECLOSE,     BMP_TOOLFILECLOSE,            0x00, "Close"},
191                           {CM_FILEQUEUE,     BMP_TOOLFILEQUEUE,            0x00, "Queue"},
192                           {CM_RENDERSHOW,    BMP_TOOLRENDERSHOW,           0x00, "Show"},
193                           {CM_RENDERCLOSE,   BMP_TOOLRENDERCLOSE,          0x02, "Hide"},
194                           {CM_COMMANDLINE,   BMP_TOOLCMDLINE,              0x00, "Ini"},
195                           {CM_SOURCEFILE,    BMP_TOOLSOURCEFILE,           0x00, "Sel-Run"},
196                           {CM_FILERENDER,    BMP_TOOLFILERENDER,           0x00, "Run"},
197                           {CM_STOPRENDER,    BMP_TOOLSTOPRENDER,           0x02, "Stop"},
198                           {CM_RENDERSLEEP,   BMP_TOOLSLEEP,                0x01, "Pause"},
199                           {CM_SHOWMAINWINDOW,BMP_TOOLSYSTRAY,              0x00, "Tray"},
200                           {0,                0,                            0x00, NULL}
201                         } ;
202 
203 #define MAX_MAIN_TOOLS  (sizeof (maintools) / sizeof (toolbarStruct) - 1)
204 
205 toolbarStruct           auxtools [] =
206                         {
207                           {CM_HELPPOVWIN,    BMP_TOOLHELPCONT,             0x00, "POV-Win"},
208                           {CM_HELPSCENE,     BMP_TOOLHELPPOVRAY,           0x00, "Scene"},
209                           {CM_GOPOVRAYORG,   BMP_TOOLGOPOVRAY,             0x00, "POV Site"},
210                           {0,                0,                            0x00, NULL}
211                         } ;
212 
213 #define MAX_AUX_TOOLS   (sizeof (auxtools) / sizeof (toolbarStruct) - 1)
214 
is_horz_line(char * s)215 bool is_horz_line (char *s)
216 {
217   if (strlen (s) < 70)
218     return (false) ;
219 
220   while (*s)
221     if (*s++ != '-')
222       return (false) ;
223 
224   return (true) ;
225 }
226 
buffer_str(const char * s,lftype * lf)227 const char *buffer_str (const char *s, lftype *lf)
228 {
229   char                  *ptr ;
230 
231   if (s == NULL)
232   {
233     message_output_x = -1 ;
234     return (NULL) ;
235   }
236   *lf = None ;
237   if (message_output_x == -1)
238   {
239     message_output_x = 0 ;
240     memset (str_buffer, 0, sizeof (str_buffer)) ;
241   }
242   ptr = str_buffer + message_output_x ;
243   while (*s)
244   {
245     switch (*s)
246     {
247       case '\r' : message_output_x = 0 ;
248                   ptr = str_buffer ;
249                   *lf = CR ;
250                   break ;
251       case '\n' : message_output_x = -1 ;
252                   *lf = LF ;
253                   return (++s) ;
254       case '\f' : if (message_output_x != -1)
255                   {
256                     message_output_x = -1 ;
257                     *lf = LF ;
258                     return (++s) ;
259                   }
260                   s++ ;
261                   break ;
262       case '\b' : if (message_output_x > 0)
263                   {
264                     --message_output_x ;
265                     *--ptr = '\0' ;
266                   }
267                   break ;
268       default   : if (isprint (*s) && message_output_x < sizeof (str_buffer) - 1)
269                   {
270                     message_output_x++ ;
271                     *ptr++ = *s ;
272                   }
273                   break ;
274     }
275     s++ ;
276   }
277   return (s) ;
278 }
279 
update_message_display(lftype lf)280 int update_message_display (lftype lf)
281 {
282   RECT        rect ;
283 
284   if (message_window == NULL)
285     return (0) ;
286   GetClientRect (message_window, &rect) ;
287   message_cols = rect.right / message_xchar ;
288   message_rows = rect.bottom / message_ychar ;
289   if (lf == None || lf == LF)
290   {
291     EnterCriticalSection (&critical_section) ;
292     top_message_row = message_count > message_rows ? message_count - message_rows : 0 ;
293     LeaveCriticalSection (&critical_section) ;
294     SetScrollRange (message_window, SB_HORZ, 0, need_hscroll (), false) ;
295     SetScrollPos (message_window, SB_HORZ, message_scroll_pos_x, true) ;
296     SetScrollRange (message_window, SB_VERT, 0, top_message_row, false) ;
297     SetScrollPos (message_window, SB_VERT, message_scroll_pos_y, true) ;
298   }
299   if (lf == None)
300     return (message_rows) ;
301   if (lf == LF)
302   {
303     EnterCriticalSection (&critical_section) ;
304     // is there room for another row ?
305     if (current_rect.bottom + message_ychar <= rect.bottom)
306     {
307       // yes there is
308       current_rect.top += message_ychar ;
309       current_rect.bottom += message_ychar ;
310     }
311     else
312       ScrollWindow (message_window, 0, -message_ychar, NULL, &rect) ;
313     message_scroll_pos_y = top_message_row ;
314     SetScrollPos (message_window, SB_VERT, message_scroll_pos_y, true) ;
315     LeaveCriticalSection (&critical_section) ;
316   }
317   PovInvalidateRect (message_window, &current_rect, true) ;
318   if (!fast_scroll && !rendering_animation && IsWindowVisible (message_window))
319     UpdateWindow (message_window) ;
320   return (message_rows) ;
321 }
322 
buffer_message(msgtype message_type,const char * s,bool addLF)323 void buffer_message (msgtype message_type, const char *s, bool addLF)
324 {
325   char                  *s1 ;
326   lftype                lf ;
327 
328   ExternalBufferMessage (message_type, (LPSTR) s) ;
329 
330   EnterCriticalSection (&critical_section) ;
331 
332   while (*s)
333   {
334     s1 = (char *)s ;
335     s = buffer_str (s, &lf) ;
336     if (lf == None)
337       continue ;
338 
339     if ((s1 = (char *) malloc (strlen (str_buffer) + 2)) == NULL)
340     {
341       LeaveCriticalSection (&critical_section) ;
342       if (rendering)
343       {
344         if (!mem_warned)
345           PovMessageBox ("Failed to allocate memory for message string", "Fatal Error") ;
346         stop_rendering = true ;
347       }
348       else
349         if (!mem_warned)
350           PovMessageBox ("Failed to allocate memory for message string", "Error") ;
351       mem_warned = true ;
352       return ;
353     }
354 
355     if (is_horz_line (str_buffer))
356       message_type = mHorzLine ;
357 
358     strcpy (s1 + 1, str_buffer) ;
359     *s1 = (uchar) message_type ;
360 
361     if (lf == CR)
362     {
363       if (*last_message)
364         free (*last_message) ;
365       *last_message = s1 ;
366       LeaveCriticalSection (&critical_section) ;
367       update_message_display (CR) ;
368       EnterCriticalSection (&critical_section) ;
369     }
370     else
371     {
372       if (*next_message)
373       {
374         free (*next_message) ;
375         *next_message = NULL ;
376         if (++first_message == message_buffer + MAX_MESSAGE)
377           first_message = message_buffer ;
378       }
379       else
380         message_count++ ;
381       *next_message = s1 ;
382       last_message = next_message ;
383       if (++next_message == message_buffer + MAX_MESSAGE)
384         next_message = message_buffer ;
385       LeaveCriticalSection (&critical_section) ;
386       update_message_display (LF) ;
387       EnterCriticalSection (&critical_section) ;
388     }
389   }
390 
391   if (addLF)
392     buffer_message (message_type, "\n", false) ;
393   LeaveCriticalSection (&critical_section) ;
394 }
395 
add_single_line(msgtype message_type,const char * str)396 void add_single_line (msgtype message_type, const char *str)
397 {
398   char                  *s1 ;
399   RECT                  rect ;
400 
401   if (message_type == mWarning && strncmp (str, "File: ", 6) == 0)
402     add_single_line (mDivider, "") ;
403   if (message_type == mStatistics)
404     if (strcmp (str, "Scene Statistics") == 0 || strcmp (str, "Render Statistics") == 0)
405       add_single_line (mDivider, "") ;
406 
407   if (strncmp (str, "---------------", 15) == 0)
408   {
409     str = "" ;
410     message_type = mDivider ;
411   }
412 
413   if (message_type == mDivider || message_type == mHorzLine)
414     if (last_message != NULL && (**last_message == mDivider || **last_message == mHorzLine))
415       return ;
416 
417   if ((s1 = (char *) malloc (strlen (str) + 2)) == NULL)
418   {
419     if (rendering)
420     {
421       if (!mem_warned)
422         PovMessageBox ("Failed to allocate memory for message string", "Fatal Error") ;
423       stop_rendering = true ;
424     }
425     else
426       if (!mem_warned)
427         PovMessageBox ("Failed to allocate memory for message string", "Error") ;
428     mem_warned = true ;
429     return ;
430   }
431 
432   strcpy (s1 + 1, str) ;
433   *s1 = (uchar) message_type ;
434 
435   if (*next_message)
436   {
437     free (*next_message) ;
438     *next_message = NULL ;
439     if (++first_message == message_buffer + MAX_MESSAGE)
440       first_message = message_buffer ;
441   }
442   else
443     message_count++ ;
444   *next_message = s1 ;
445   last_message = next_message ;
446   if (++next_message == message_buffer + MAX_MESSAGE)
447     next_message = message_buffer ;
448 
449   GetClientRect (message_window, &rect) ;
450   message_cols = rect.right / message_xchar ;
451   message_rows = rect.bottom / message_ychar ;
452   top_message_row = message_count > message_rows ? message_count - message_rows : 0 ;
453   SetScrollRange (message_window, SB_HORZ, 0, need_hscroll (), false) ;
454   SetScrollPos (message_window, SB_HORZ, message_scroll_pos_x, true) ;
455   SetScrollRange (message_window, SB_VERT, 0, top_message_row, false) ;
456   SetScrollPos (message_window, SB_VERT, message_scroll_pos_y, true) ;
457   // is there room for another row ?
458   if (current_rect.bottom + message_ychar <= rect.bottom)
459   {
460     // yes there is
461     current_rect.top += message_ychar ;
462     current_rect.bottom += message_ychar ;
463   }
464   else
465     ScrollWindow (message_window, 0, -message_ychar, NULL, &rect) ;
466   message_scroll_pos_y = top_message_row ;
467   SetScrollPos (message_window, SB_VERT, message_scroll_pos_y, true) ;
468   PovInvalidateRect (message_window, &current_rect, true) ;
469   if (!fast_scroll && !rendering_animation && IsWindowVisible (message_window))
470     UpdateWindow (message_window) ;
471 }
472 
wrap_message(const char * str,int width,msgtype message_type)473 void wrap_message (const char *str, int width, msgtype message_type)
474 {
475   int         col = 1 ;
476   char        buffer [2048] ;
477   char        *bp = buffer ;
478   char        *ws_b = NULL ;
479   const char  *wd_b = NULL ;
480   const char  *s = str ;
481 
482   if (width < 80)
483     width = 80 ;
484   while (*s)
485   {
486     if (*s == '\r' || *s == '\n')
487     {
488       while (*s == '\r' && (s [1] == '\r' || s [1] == '\n'))
489         s++ ;
490       *bp = '\0' ;
491       add_single_line (message_type, buffer) ;
492       ws_b = NULL ;
493       wd_b = NULL ;
494       bp = buffer ;
495       col = 1 ;
496       s++ ;
497       continue ;
498     }
499 
500     col++ ;
501     if (*s == ' ' || *s == '\t')
502     {
503       if (ws_b == NULL || ws_b < wd_b)
504         ws_b = bp ;
505       wd_b = NULL ;
506       *bp++ = *s++ ;
507       continue ;
508     }
509 
510     if (wd_b == NULL)
511       wd_b = bp ;
512     *bp++ = *s++ ;
513 
514     if (col > width && ws_b != NULL)
515     {
516       *ws_b = '\0' ;
517       add_single_line (message_type, buffer) ;
518       if (wd_b)
519       {
520         col = bp - wd_b ;
521         memcpy (buffer, wd_b, col) ;
522         bp = buffer + col ;
523         wd_b = buffer ;
524         ws_b = NULL ;
525       }
526       else
527       {
528         col = 1 ;
529         bp = buffer ;
530         ws_b = NULL ;
531         wd_b = NULL ;
532         while (*s == ' ' || *s == '\t')
533           s++ ;
534       }
535     }
536   }
537   if (ws_b != NULL && wd_b == NULL)
538     bp = ws_b ;
539   *bp = '\0' ;
540   add_single_line (message_type, buffer) ;
541 }
542 
buffer_stream_message(msgtype message_type,const char * s)543 void buffer_stream_message (msgtype message_type, const char *s)
544 {
545   RECT        rect ;
546 
547   if (message_type == mUnknown)
548   {
549 	  if (strncmp (s, "File: ", 6) == 0)
550 		message_type = mWarning;
551 	  else if (strncmp (s, "Shutdown", 8) == 0)
552 		message_type = mWarning;
553   }
554 
555   // since the POVMS streams don't try fancy stuff with CR's and backspaces
556   // we can simplify the above code (and also handle wordwrap). all data
557   // data passed to us is implicitly terminated by an LF. embedded LF's are
558   // permitted and a terminating LF implies two LF's (due to above).
559   ExternalBufferMessage (message_type, (LPSTR) s) ;
560   ExternalBufferMessage (message_type, "\n") ;
561 
562   GetClientRect (message_window, &rect) ;
563   message_cols = rect.right / message_xchar ;
564 
565   EnterCriticalSection (&critical_section) ;
566 
567   // we don't want to wrap debug text - we assume the scene author wants to control this.
568   wrap_message (s, message_type == mDebug ? 9999 : message_cols - 2, message_type) ;
569   LeaveCriticalSection (&critical_section) ;
570 }
571 
message_printf(const char * format,...)572 void message_printf (const char *format, ...)
573 {
574   char                  str [2048] ;
575   char                  *s ;
576   time_t                t ;
577   va_list               arg_ptr ;
578 
579   if (strlen (format) > sizeof (str) - 256)
580     return ;
581   if (debugging)
582   {
583     time (&t) ;
584     s = ctime (&t) ;
585     memcpy (str, s + 11, 9) ;
586     va_start (arg_ptr, format) ;
587     vsprintf (str + 9, format, arg_ptr) ;
588     va_end (arg_ptr) ;
589     OutputDebugString (str) ;
590   }
591   va_start (arg_ptr, format) ;
592   vsprintf (str, format, arg_ptr) ;
593   va_end (arg_ptr) ;
594   buffer_message (mIDE, str) ;
595 }
596 
wrapped_printf(const char * format,...)597 void wrapped_printf (const char *format, ...)
598 {
599   char                  str [2048] ;
600   char                  *s ;
601   time_t                t ;
602   va_list               arg_ptr ;
603 
604   if (strlen (format) > sizeof (str) - 256)
605     return ;
606   if (debugging)
607   {
608     time (&t) ;
609     s = ctime (&t) ;
610     memcpy (str, s + 11, 9) ;
611     va_start (arg_ptr, format) ;
612     vsprintf (str + 9, format, arg_ptr) ;
613     va_end (arg_ptr) ;
614     OutputDebugString (str) ;
615   }
616   va_start (arg_ptr, format) ;
617   vsprintf (str, format, arg_ptr) ;
618   va_end (arg_ptr) ;
619   s = str + strlen (str) - 1 ;
620   if (*s == '\n')
621     *s = '\0' ;
622   buffer_stream_message (mIDE, str) ;
623 }
624 
status_printf(int nSection,const char * format,...)625 void status_printf (int nSection, const char *format, ...)
626 {
627   char                  str [2048] ;
628   va_list               arg_ptr ;
629 
630   va_start (arg_ptr, format) ;
631   vsprintf (str, format, arg_ptr) ;
632   va_end (arg_ptr) ;
633   say_status_message (nSection, str) ;
634 }
635 
clean_str(const char * s)636 char *clean_str (const char *s)
637 {
638   char        *s1 ;
639   static char str [512] ;
640 
641   if (strlen (s) > 511)
642     return ("Internal error : string too long in clean_str") ;
643   EnterCriticalSection (&critical_section) ;
644   for (s1 = str ; *s ; s++)
645     if (*s >= ' ')
646       *s1++ = *s ;
647   *s1 = '\0' ;
648   LeaveCriticalSection (&critical_section) ;
649   return (str) ;
650 }
651 
erase_display_window(HDC hdc,int xoffset,int yoffset)652 void erase_display_window (HDC hdc, int xoffset, int yoffset)
653 {
654   int         x, y ;
655   HDC         hdcMemory ;
656   RECT        rect ;
657   HBRUSH      hbr ;
658   HBITMAP     oldBmp ;
659 
660   if (message_window == NULL)
661     return ;
662   GetClientRect (message_window, &rect) ;
663   if (tile_background)
664   {
665     hdcMemory = CreateCompatibleDC (hdc) ;
666     oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpBackground) ;
667     xoffset %= background_width ;
668     yoffset %= background_height ;
669     for (y = -yoffset ; y < rect.bottom ; y += background_height)
670       for (x = -xoffset ; x < rect.right ; x += background_width)
671         BitBlt (hdc, x, y, background_width, background_height, hdcMemory, 0, 0, SRCCOPY) ;
672     SelectObject (hdcMemory, oldBmp) ;
673     DeleteDC (hdcMemory) ;
674   }
675   else
676   {
677     hbr = CreateSolidBrush (background_colour) ;
678     FillRect (hdc, &rect, hbr) ;
679     DeleteObject (hbr) ;
680   }
681 }
682 
paint_display_window(HDC hdc)683 void paint_display_window (HDC hdc)
684 {
685   int           x, y ;
686   int           message_number ;
687   int           oldMode ;
688   int           dividerStep ;
689   int           xoffset ;
690   int           yoffset ;
691   char          **message = first_message ;
692   bool          erased = false ;
693   RECT          rect ;
694   HPEN          hpen1 ;
695   HPEN          hpen2 ;
696   HPEN          hpenOld ;
697   HFONT         oldFont ;
698   COLORREF      oldColour ;
699   COLORREF      oldBkColour ;
700   unsigned char lastType = 255;
701   static RECT   oldRect ;
702 
703   EnterCriticalSection (&critical_section) ;
704   GetClientRect (message_window, &rect) ;
705   current_rect.left = 0 ;
706   current_rect.right = rect.right ;
707   current_rect.top = -message_ychar ;
708   current_rect.bottom = 0 ;
709   xoffset = (unsigned) message_scroll_pos_x * message_xchar ;
710   yoffset = (unsigned) (first_message - message_buffer) * message_ychar ;
711 
712   if (*message == NULL || resizing || (EditGetFlags () & EDIT_DRAG_ACTIVE) != 0)
713   {
714     erase_display_window (hdc, xoffset, yoffset) ;
715     LeaveCriticalSection (&critical_section) ;
716     oldRect = rect ;
717     return ;
718   }
719 
720   oldRect = rect ;
721 
722   if (tile_background)
723   {
724     hpen1 = CreatePen (PS_SOLID, 1, RGB (192,192,192)) ;
725     hpen2 = CreatePen (PS_SOLID, 1, RGB (64,64,64)) ;
726   }
727   else
728   {
729     int red = background_colour & 0xff;
730     int green = (background_colour >> 8) & 0xff;
731     int blue = (background_colour >> 16) & 0xff;
732 
733     hpen1 = CreatePen (PS_SOLID, 1, text_colours[0]) ;
734     hpen2 = CreatePen (PS_SOLID, 1, RGB(red / 2, green / 2, blue / 2)) ;
735   }
736 
737   hpenOld = (HPEN) SelectObject (hdc, hpen2) ;
738   oldFont = (HFONT) SelectObject (hdc, message_font) ;
739   oldMode = SetBkMode (hdc, TRANSPARENT) ;
740   oldColour = SetTextColor (hdc, text_colours[0]) ;
741   oldBkColour = SetBkColor (hdc, background_shade) ;
742   x = message_scroll_pos_x * -message_xchar + message_xchar ;
743   for (message_number = y = 0 ; y < rect.bottom ; message_number++)
744   {
745     if (*message == NULL)
746       break ;
747     if (message_number >= message_scroll_pos_y)
748     {
749       if (!erased)
750       {
751         erase_display_window (hdc, xoffset, yoffset) ;
752         erased = true ;
753       }
754       if (**message != lastType)
755       {
756         lastType = **message;
757         switch (**message)
758         {
759           case mDebug:
760           case mWarning:
761             SetTextColor (hdc, text_colours[1]);
762             break;
763 
764           case mFatal:
765             SetTextColor (hdc, text_colours[2]);
766             break;
767 
768           default:
769             SetTextColor (hdc, text_colours[0]);
770             break;
771         }
772       }
773       current_rect.top += message_ychar ;
774       current_rect.bottom += message_ychar ;
775       if (**message == mDivider || **message == mHorzLine)
776       {
777         if (background_shade != RGB (1, 1, 1) && tile_background)
778           DRAWFASTRECT (hdc, &current_rect) ;
779         SelectObject (hdc, hpen2) ;
780         if (tile_background)
781         {
782           dividerStep = message_ychar / 3;
783           MoveToEx (hdc, current_rect.left + message_xchar, y + message_ychar - dividerStep, NULL) ;
784           LineTo (hdc, current_rect.left + message_xchar, y + dividerStep) ;
785           LineTo (hdc, current_rect.right - message_xchar, y + dividerStep) ;
786           SelectObject (hdc, hpen1) ;
787           LineTo (hdc, current_rect.right - message_xchar, y + message_ychar - dividerStep) ;
788           LineTo (hdc, current_rect.left + message_xchar, y + message_ychar - dividerStep) ;
789         }
790         else
791         {
792           MoveToEx (hdc, current_rect.left + message_xchar, y + message_ychar / 2, NULL) ;
793           LineTo (hdc, current_rect.right - message_xchar, y + message_ychar / 2) ;
794           SelectObject (hdc, hpen1) ;
795           MoveToEx (hdc, current_rect.left + message_xchar, y + message_ychar / 2 + 1, NULL) ;
796           LineTo (hdc, current_rect.right - message_xchar, y + message_ychar / 2 + 1) ;
797         }
798       }
799       else
800         ExtTextOut (hdc, x, y, ETO_CLIPPED, &current_rect, *message + 1, (int) strlen (*message + 1), NULL) ;
801       y += message_ychar ;
802     }
803     if (message == last_message)
804       break ;
805     if (++message == message_buffer + MAX_MESSAGE)
806       message = message_buffer ;
807     yoffset += message_ychar ;
808   }
809   if (!erased)
810     erase_display_window (hdc, xoffset, yoffset) ;
811   SetTextColor (hdc, oldColour) ;
812   SetBkColor (hdc, oldBkColour) ;
813   SetBkMode (hdc, oldMode) ;
814   SelectObject (hdc, oldFont) ;
815   SelectObject (hdc, hpenOld) ;
816   DeleteObject (hpen1) ;
817   DeleteObject (hpen2) ;
818   LeaveCriticalSection (&critical_section) ;
819 }
820 
get_logfont(HDC hdc,LOGFONT * lf)821 void get_logfont (HDC hdc, LOGFONT *lf)
822 {
823   memset (lf, 0, sizeof (LOGFONT)) ;
824   lf->lfHeight = -MulDiv (message_font_size, GetDeviceCaps (hdc, LOGPIXELSY), 72) ;
825   lf->lfWeight = message_font_weight ;
826   lf->lfPitchAndFamily = FIXED_PITCH | FF_MODERN ;
827   lf->lfCharSet = DEFAULT_CHARSET ;
828   lf->lfQuality = PROOF_QUALITY ;
829   strncpy (lf->lfFaceName, message_font_name, sizeof (lf->lfFaceName) - 1) ;
830 }
831 
get_lblogfont(HDC hdc,LOGFONT * lf)832 void get_lblogfont (HDC hdc, LOGFONT *lf)
833 {
834   memset (lf, 0, sizeof (LOGFONT)) ;
835   lf->lfHeight = -MulDiv (listbox_font_size, GetDeviceCaps (hdc, LOGPIXELSY), 72) ;
836   lf->lfWeight = listbox_font_weight ;
837   lf->lfPitchAndFamily = FIXED_PITCH | FF_MODERN ;
838   lf->lfCharSet = DEFAULT_CHARSET ;
839   lf->lfQuality = PROOF_QUALITY ;
840   strncpy (lf->lfFaceName, listbox_font_name, sizeof (lf->lfFaceName) - 1) ;
841 }
842 
create_message_font(HDC hdc,LOGFONT * lf)843 int create_message_font (HDC hdc, LOGFONT *lf)
844 {
845   HFONT       hfontOld ;
846   TEXTMETRIC  tm ;
847 
848   if ((message_font = CreateFontIndirect (lf)) == NULL)
849     return (1) ;
850   hfontOld = (HFONT) SelectObject (hdc, message_font) ;
851   GetTextMetrics (hdc, &tm) ;
852   message_xchar = tm.tmAveCharWidth ;
853   message_ychar = tm.tmHeight + tm.tmExternalLeading ;
854   SelectObject (hdc, hfontOld) ;
855   return (0) ;
856 }
857 
create_listbox_font(HDC hdc,LOGFONT * lf)858 int create_listbox_font (HDC hdc, LOGFONT *lf)
859 {
860   HFONT       hfontOld ;
861   TEXTMETRIC  tm ;
862 
863   if ((listbox_font = CreateFontIndirect (lf)) == NULL)
864     return (1) ;
865   hfontOld = (HFONT)SelectObject (hdc, listbox_font) ;
866   GetTextMetrics (hdc, &tm) ;
867   listbox_xchar = tm.tmAveCharWidth ;
868   listbox_ychar = tm.tmHeight + tm.tmExternalLeading ;
869   SelectObject (hdc, hfontOld) ;
870   return (0) ;
871 }
872 
initialise_message_display(void)873 int initialise_message_display (void)
874 {
875   HDC         hdc ;
876   LOGFONT     lf ;
877 
878   if (message_window == NULL)
879   {
880     PovMessageBox ("Message Window does not exist", "Initialize Message Display - Fatal Error") ;
881     return (1) ;
882   }
883   hdc = GetDC (message_window) ;
884   get_logfont (hdc, &lf) ;
885   if (create_message_font (hdc, &lf) != 0)
886   {
887     PovMessageBox ("Failed to create message font", "Initialize Message Display - Fatal Error") ;
888     ReleaseDC (message_window, hdc) ;
889     return (1) ;
890   }
891   get_lblogfont (hdc, &lf) ;
892   if (create_listbox_font (hdc, &lf) != 0)
893   {
894     strcpy (lf.lfFaceName, "Courier New") ;
895     if (create_listbox_font (hdc, &lf) != 0)
896       PovMessageBox ("Failed to create listbox font", "Initialize Message Display") ;
897   }
898   first_message = next_message = message_buffer ;
899   last_message = NULL ;
900   buffer_str (NULL, NULL) ;
901   top_message_row = message_count = message_scroll_pos_x = message_scroll_pos_y = 0 ;
902   current_rect.left = current_rect.bottom = current_rect.right = 0 ;
903   current_rect.top = -message_ychar ;
904   ReleaseDC (message_window, hdc) ;
905   return (0) ;
906 }
907 
clear_messages(bool print)908 void clear_messages (bool print)
909 {
910   int         i ;
911   char        **p ;
912 
913   EnterCriticalSection (&critical_section) ;
914   buffer_str (NULL, NULL) ;
915   // free any buffered lines still around from a previous run of the renderer
916   for (p = message_buffer, i = 0 ; i < MAX_MESSAGE ; p++, i++)
917   {
918     if (*p)
919       free (*p) ;
920     *p = NULL ;
921   }
922   first_message = next_message = message_buffer ;
923   last_message = NULL ;
924   top_message_row = message_count = message_scroll_pos_x = message_scroll_pos_y = 0 ;
925   current_rect.left = current_rect.bottom = current_rect.right = 0 ;
926   current_rect.top = -message_ychar ;
927   LeaveCriticalSection (&critical_section) ;
928   if (print)
929     message_printf ("Messages cleared.\n") ;
930 }
931 
need_hscroll(void)932 int need_hscroll (void)
933 {
934   int         x ;
935   int         xchars ;
936   int         width = 0 ;
937   char        **message = first_message ;
938   RECT        rect ;
939 
940   /* modified to return the scroll range if ANY line is long enough */
941   if (message_window == NULL || *message == NULL)
942     return (0) ;
943   GetClientRect (message_window, &rect) ;
944   xchars = rect.right / message_xchar - 1 ;
945   while (*message)
946   {
947     x = (int) strlen (*message + 1) ;
948     if (x >= xchars)
949       if (x - xchars > width)
950         width = x - xchars ;
951     if (message == next_message)
952       break ;
953     if (++message == message_buffer + MAX_MESSAGE)
954       message = message_buffer ;
955   }
956   return (width) ;
957 }
958 
copy_text_to_clipboard(const char * text)959 bool copy_text_to_clipboard(const char *text)
960 {
961   char        *s ;
962   HGLOBAL     hText ;
963 
964   if (!OpenClipboard(NULL))
965     return false;
966   if ((hText = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, strlen(text) + 1)) == NULL)
967     return false;
968   if ((s = (char *) GlobalLock (hText)) == NULL)
969   {
970     GlobalFree(hText);
971     return false;
972   }
973   strcpy(s, text);
974   GlobalUnlock(hText);
975   EmptyClipboard() ;
976   bool result = SetClipboardData(CF_TEXT, hText) != NULL;
977   CloseClipboard() ;
978   return result;
979 }
980 
dump_pane_to_clipboard(void)981 void dump_pane_to_clipboard (void)
982 {
983   int         y ;
984   int         message_number ;
985   int         length = 0 ;
986   char        **message = first_message ;
987   char        *s ;
988   RECT        rect ;
989   HGLOBAL     hText ;
990   static char *_s ;
991 
992   if (message_window == NULL || *message == NULL)
993     return ;
994   if (OpenClipboard (message_window) == false)
995   {
996     PovMessageBox ("Could not open clipboard", "Error") ;
997     return ;
998   }
999   if ((hText = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, 33000)) == NULL)
1000     return ;
1001   if ((s = (char *) GlobalLock (hText)) == NULL)
1002   {
1003     GlobalFree(hText);
1004     CloseClipboard () ;
1005     return ;
1006   }
1007   _s = s ;
1008   GetClientRect (message_window, &rect) ;
1009   for (message_number = y = 0 ; y < rect.bottom ; message_number++)
1010   {
1011     if (*message == NULL)
1012       break ;
1013     if (message_number >= message_scroll_pos_y)
1014     {
1015       length += (int) strlen (*message + 1) + 2 ;
1016       if (length >= 32767)
1017         break ;
1018       s += sprintf (s, "%s\r\n", *message + 1) ;
1019       y += message_ychar ;
1020     }
1021     if (++message == message_buffer + MAX_MESSAGE)
1022       message = message_buffer ;
1023     if (message == next_message)
1024       break ;
1025   }
1026   GlobalUnlock (hText) ;
1027   GlobalReAlloc (hText, length + 1, GMEM_MOVEABLE | GMEM_DDESHARE) ;
1028   EmptyClipboard () ;
1029   SetClipboardData (CF_TEXT, hText) ;
1030   CloseClipboard () ;
1031 }
1032 
draw_ordinary_listbox(DRAWITEMSTRUCT * d,bool fitpath)1033 void draw_ordinary_listbox (DRAWITEMSTRUCT *d, bool fitpath)
1034 {
1035   int         oldMode ;
1036   int         dividerStep ;
1037   int         width ;
1038   int         length ;
1039   char        str [MAX_PATH] ;
1040   RECT        rect ;
1041   HPEN        hpen1 ;
1042   HPEN        hpen2 ;
1043   HPEN        hpenOld ;
1044   HFONT       oldFont ;
1045   COLORREF    oldBackground ;
1046   COLORREF    oldForeground ;
1047 
1048   if (d->itemID == -1)
1049     return ;
1050   hpen1 = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNHIGHLIGHT)) ;
1051   hpen2 = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNSHADOW)) ;
1052   hpenOld = (HPEN) SelectObject (d->hDC, hpen2) ;
1053   oldFont = (HFONT) SelectObject (d->hDC, listbox_font) ;
1054   oldMode = SetBkMode (d->hDC, TRANSPARENT) ;
1055   oldForeground = SetTextColor (d->hDC, GetSysColor (d->itemState & ODS_SELECTED ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)) ;
1056   oldBackground = SetBkColor (d->hDC, GetSysColor (d->itemState & ODS_SELECTED ? COLOR_HIGHLIGHT : COLOR_WINDOW)) ;
1057   dividerStep = listbox_ychar / 2 - 1 ;
1058 
1059   rect = d->rcItem ;
1060   rect.left += listbox_xchar ;
1061   rect.right -= listbox_xchar ;
1062   width = (rect.right - rect.left) / listbox_xchar ;
1063   SendMessage (d->hwndItem, LB_GETTEXT, d->itemID, (LPARAM) str) ;
1064   if (strncmp (str, "----------------", 16) == 0)
1065   {
1066     MoveToEx (d->hDC, rect.left, rect.top + listbox_ychar - dividerStep, NULL) ;
1067     SelectObject (d->hDC, hpen2) ;
1068     LineTo (d->hDC, rect.left, rect.top + dividerStep) ;
1069     LineTo (d->hDC, rect.right - listbox_xchar, rect.top + dividerStep) ;
1070     SelectObject (d->hDC, hpen1) ;
1071     LineTo (d->hDC, rect.right - listbox_xchar, rect.top + listbox_ychar - dividerStep) ;
1072     LineTo (d->hDC, rect.left, rect.top + listbox_ychar - dividerStep) ;
1073   }
1074   else
1075   {
1076     if (fitpath)
1077     {
1078       length = (int) strlen (str) ;
1079       if (length > width)
1080       {
1081         if (str [1] == ':' && isPathSeparator(str [2]))
1082         {
1083           memcpy (str + 3, "...", 3) ;
1084           strcpy (str + 6, str + length - width + 6) ;
1085         }
1086       }
1087     }
1088     ExtTextOut (d->hDC, rect.left, rect.top, ETO_CLIPPED | ETO_OPAQUE, &rect, str, (int) strlen (str), NULL) ;
1089   }
1090 
1091   SetBkColor (d->hDC, oldBackground) ;
1092   SetTextColor (d->hDC, oldForeground) ;
1093   SetBkMode (d->hDC, oldMode) ;
1094   SelectObject (d->hDC, oldFont) ;
1095   SelectObject (d->hDC, hpenOld) ;
1096   DeleteObject (hpen1) ;
1097   DeleteObject (hpen2) ;
1098 }
1099 
write_wrapped_text(HDC hdc,RECT * rect,const char * text)1100 void write_wrapped_text (HDC hdc, RECT *rect, const char *text)
1101 {
1102   int         oldMode ;
1103   HFONT       hFont ;
1104   HFONT       hFontOld ;
1105   LOGFONT     lf ;
1106   COLORREF    oldForeground ;
1107 
1108   memset (&lf, 0, sizeof (LOGFONT)) ;
1109   lf.lfHeight = -MulDiv (8, GetDeviceCaps (hdc, LOGPIXELSY), 72) ;
1110   lf.lfWeight = FW_NORMAL ;
1111   lf.lfPitchAndFamily = VARIABLE_PITCH ;
1112   lf.lfCharSet = DEFAULT_CHARSET ;
1113   strcpy (lf.lfFaceName, "MS Sans Serif") ;
1114   if ((hFont = CreateFontIndirect (&lf)) != NULL)
1115   {
1116     hFontOld = (HFONT) SelectObject (hdc, hFont) ;
1117     oldMode = SetBkMode (hdc, TRANSPARENT) ;
1118     oldForeground = SetTextColor (hdc, RGB (0, 0, 0)) ;
1119     DrawText (hdc, text, -1, rect, DT_WORDBREAK | DT_EXPANDTABS) ;
1120     SetTextColor (hdc, oldForeground) ;
1121     SetBkMode (hdc, oldMode) ;
1122     SelectObject (hdc, hFontOld) ;
1123     DeleteObject (hFont) ;
1124   }
1125 }
1126 
tip_of_the_day(HDC hdc,RECT * rect,char * text)1127 void tip_of_the_day (HDC hdc, RECT *rect, char *text)
1128 {
1129   int         oldMode ;
1130   RECT        rc ;
1131   HFONT       hFont ;
1132   HFONT       hFontOld ;
1133   LOGFONT     lf ;
1134   COLORREF    oldForeground ;
1135 
1136   rc = *rect ;
1137   memset (&lf, 0, sizeof (LOGFONT)) ;
1138   lf.lfHeight = -MulDiv (9, GetDeviceCaps (hdc, LOGPIXELSY), 72) ;
1139   lf.lfWeight = FW_BOLD ;
1140   lf.lfPitchAndFamily = VARIABLE_PITCH ;
1141   lf.lfCharSet = DEFAULT_CHARSET ;
1142   strcpy (lf.lfFaceName, "MS Sans Serif") ;
1143   if ((hFont = CreateFontIndirect (&lf)) != NULL)
1144   {
1145 //  hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_BULB)) ;
1146 //  DrawIcon (hdc, rc.left, rc.top, hIcon) ;
1147 //  DestroyIcon (hIcon) ;
1148     hFontOld = (HFONT) SelectObject (hdc, hFont) ;
1149     oldMode = SetBkMode (hdc, TRANSPARENT) ;
1150     oldForeground = SetTextColor (hdc, RGB (0, 0, 0)) ;
1151     ExtTextOut (hdc, rc.left, rc.top, ETO_CLIPPED, &rc, "Did you know ... ? ", 19, NULL) ;
1152     rc.top += 25 ;
1153     SetTextColor (hdc, oldForeground) ;
1154     SetBkMode (hdc, oldMode) ;
1155     SelectObject (hdc, hFontOld) ;
1156     DeleteObject (hFont) ;
1157     write_wrapped_text (hdc, &rc, text) ;
1158   }
1159 }
1160 
handle_menu_select(WPARAM wParam,LPARAM lParam)1161 void handle_menu_select (WPARAM wParam, LPARAM lParam)
1162 {
1163   char        str [128] ;
1164   static int  nLastID = -1 ;
1165 
1166   wParam = LOWORD (wParam) ;
1167   if (wParam != nLastID)
1168   {
1169     nLastID = wParam ;
1170     if (wParam >= CM_FIRSTGUIEXT && wParam <= CM_LASTGUIEXT)
1171     {
1172       say_status_message (StatusMessage, ExternalMenuTip (wParam)) ;
1173       return ;
1174     }
1175     if (wParam < CM_FIRSTTOOL || wParam > CM_LASTTOOL)
1176     {
1177       if (LoadString (hInstance, wParam, str, sizeof (str)) != 0)
1178         say_status_message (StatusMessage, str) ;
1179       else
1180         say_status_message (StatusMessage, "") ;
1181     }
1182     else
1183       say_status_message (StatusMessage, tool_help [wParam - CM_FIRSTTOOL]) ;
1184   }
1185 }
1186 
resize_windows(unsigned left,unsigned top,unsigned width,unsigned height)1187 void resize_windows (unsigned left, unsigned top, unsigned width, unsigned height)
1188 {
1189   MoveWindow (message_window, left, top, width, height, false) ;
1190 }
1191 
editor_stream_init(void)1192 FILE *editor_stream_init (void)
1193 {
1194   editor_line_number = 0 ;
1195   editor_char_pos = 0 ;
1196   editor_offset = 0 ;
1197   seek_entry_count = 0 ;
1198   line_buffer [0] = '\0' ;
1199   return (POV_INTERNAL_STREAM) ;
1200 }
1201 
editor_ftell(void)1202 int editor_ftell (void)
1203 {
1204   if (seek_entry_count >= MAX_SEEK_INDEX)
1205   {
1206     PovMessageBox ("Seek index overflow ; render scene from outside editor", "Error") ;
1207     if (!quit)
1208       quit = time (NULL) ;
1209     return (-1) ;
1210   }
1211   if (editor_char_pos)
1212   {
1213     seek_entries [seek_entry_count].Line = editor_line_number ;
1214     seek_entries [seek_entry_count++].Offset = editor_char_pos - 1 ;
1215   }
1216   seek_entries [seek_entry_count].Line = editor_line_number ;
1217   seek_entries [seek_entry_count].Offset = editor_char_pos ;
1218   return (seek_entry_count++) ;
1219 }
1220 
editor_fseek(long offset,int whence)1221 int editor_fseek (long offset, int whence)
1222 {
1223   if (whence != 0)
1224     return (-1) ;
1225   editor_line_number = seek_entries [offset].Line ;
1226   editor_char_pos = seek_entries [offset].Offset ;
1227 // FIXME
1228 //if (Edit.GetLine (CurrentEditor, editor_line_number, line_buffer, sizeof (line_buffer) - 1) == false)
1229 //{
1230 //  PovMessageBox ("Seek index error ; render scene from outside editor", "Error") ;
1231 //  if (!quit)
1232 //    quit = time (NULL) ;
1233 //  return (-1) ;
1234 //}
1235   return (0) ;
1236 }
1237 
editor_getc(void)1238 int editor_getc (void)
1239 {
1240   if (line_buffer [editor_char_pos] == '\0')
1241   {
1242 // FIXME
1243 //  if (Edit.GetLine (CurrentEditor, ++editor_line_number, line_buffer, sizeof (line_buffer) - 2) == false)
1244 //    return (EOF) ;
1245     editor_char_pos = 0 ;
1246     strcat (line_buffer, "\n") ;
1247   }
1248   return (line_buffer [editor_char_pos++]) ;
1249 }
1250 
pov_fopen(const char * filename,const char * mode)1251 FILE *pov_fopen (const char *filename, const char *mode)
1252 {
1253   if (filename == NULL)
1254     return (editor_stream_init ()) ;
1255   else
1256     return (fopen (filename, mode)) ;
1257 }
1258 
pov_fclose(FILE * stream)1259 int pov_fclose (FILE *stream)
1260 {
1261   if (stream != POV_INTERNAL_STREAM)
1262     return (fclose (stream)) ;
1263   else
1264     return (0) ;
1265 }
1266 
pov_getc(FILE * stream)1267 int pov_getc (FILE *stream)
1268 {
1269   return (stream == POV_INTERNAL_STREAM ? editor_getc () : getc (stream)) ;
1270 }
1271 
pov_fseek(FILE * stream,long offset,int whence)1272 int pov_fseek (FILE *stream, long offset, int whence)
1273 {
1274   return (stream == POV_INTERNAL_STREAM ? editor_fseek (offset, whence) : fseek (stream, offset, whence)) ;
1275 }
1276 
pov_ftell(FILE * stream)1277 int pov_ftell (FILE *stream)
1278 {
1279   return (stream == POV_INTERNAL_STREAM ? editor_ftell () : ftell (stream)) ;
1280 }
1281 
add_edit_file(char * file)1282 void add_edit_file (char *file)
1283 {
1284   if (strlen (file) == 0)
1285   {
1286     PovMessageBox ("Empty filename after /EDIT", "Edit File") ;
1287     return ;
1288   }
1289   if (EditFileCount == MAX_EDIT_FILES)
1290     return ;
1291   if (strpbrk (file, "*?") != NULL)
1292   {
1293     PovMessageBox ("Filename may not contain wildcards", "Edit File") ;
1294     return ;
1295   }
1296   EditFiles [EditFileCount++] = _strdup (file) ;
1297 }
1298 
add_render_file(char * file)1299 void add_render_file (char *file)
1300 {
1301   static bool first = true ;
1302 
1303   if (strlen (file) == 0)
1304   {
1305     PovMessageBox ("Empty filename after /RENDER", "Render File") ;
1306     return ;
1307   }
1308   if (!first)
1309   {
1310     PovMessageBox ("Only one /RENDER file may be specified", "Render File") ;
1311     return ;
1312   }
1313   if (strpbrk (file, "*?") != NULL)
1314   {
1315     PovMessageBox ("Filename may not contain wildcards", "Render File") ;
1316     return ;
1317   }
1318   first = false ;
1319   strcpy (requested_render_file, file) ;
1320   render_requested = true ;
1321 }
1322 
extract_file(char * filename,char * s)1323 char *extract_file (char *filename, char *s)
1324 {
1325   bool        startsWithQuote = false ;
1326   bool        inDoubleQuote = false ;
1327 
1328   while (*s == ' ' || *s == '\t')
1329     s++ ;
1330   // a single quote is a legitimate part of a filename under windows, so we
1331   // treat it as a special case only if the first character is one.
1332   if (*s == '\'')
1333   {
1334     startsWithQuote = true;
1335     s++;
1336   }
1337   while (*s)
1338   {
1339     switch (*s)
1340     {
1341       case '"' :
1342            if (inDoubleQuote)
1343            {
1344              *filename = '\0' ;
1345              return (++s) ;
1346            }
1347            inDoubleQuote = true ;
1348            break ;
1349 
1350       case '\'' :
1351            if (startsWithQuote && (s[1] == ' ' || s[1] == '\t' || s[1] == '\0'))
1352            {
1353              *filename  = '\0' ;
1354              return (++s) ;
1355            }
1356            *filename++ = *s ;
1357            break ;
1358 
1359       case ' ' :
1360       case '\t' :
1361            if (!inDoubleQuote && !startsWithQuote)
1362            {
1363              *filename  = '\0' ;
1364              return (s) ;
1365            }
1366            *filename++ = *s ;
1367            break ;
1368 
1369       default :
1370            *filename++ = *s ;
1371            break ;
1372     }
1373     s++ ;
1374   }
1375   *filename  = '\0' ;
1376   return (s) ;
1377 }
1378 
preparse_commandline(char * s)1379 char *preparse_commandline (char *s)
1380 {
1381   char        *out ;
1382   char        *command ;
1383   char        last = ' ' ;
1384   char        commandstr [256] ;
1385   char        filename [_MAX_PATH] ;
1386   static char outstr [_MAX_PATH * 3] ;
1387 
1388   out = outstr ;
1389   while (*s)
1390   {
1391     if (*s == '/' && (last == ' ' || last == '\t'))
1392     {
1393       command = commandstr ;
1394       while (*++s)
1395       {
1396         if (*s == ' ' || *s == '\t')
1397           break ;
1398         *command++ = *s ;
1399       }
1400       *command = '\0' ;
1401       last = *s ;
1402       if (strlen (commandstr) == 0)
1403       {
1404         PovMessageBox ("Empty command on commandline", "Commandline processing error") ;
1405         return (NULL) ;
1406       }
1407       if (_stricmp (commandstr, "EXIT") == 0)
1408       {
1409         exit_after_render = true ;
1410         while (*s == ' ')
1411           s++ ;
1412         continue ;
1413       }
1414       if (_stricmp (commandstr, "DEMO") == 0)
1415       {
1416         demo_mode = true ;
1417         while (*s == ' ')
1418           s++ ;
1419         continue ;
1420       }
1421       if (_stricmp (commandstr, "DEBUG") == 0)
1422       {
1423         debugging = true ;
1424         while (*s == ' ')
1425           s++ ;
1426         continue ;
1427       }
1428       if (_stricmp (commandstr, "EDIT") == 0)
1429       {
1430         s = extract_file (filename, s) ;
1431         add_edit_file (filename) ;
1432         while (*s == ' ')
1433           s++ ;
1434         continue ;
1435       }
1436       if (_stricmp (commandstr, "RENDER") == 0)
1437       {
1438         s = extract_file (filename, s) ;
1439         add_render_file (filename) ;
1440         while (*s == ' ')
1441           s++ ;
1442         continue ;
1443       }
1444       if (_stricmp (commandstr, "EDITDLLPATH") == 0)
1445       {
1446         s = extract_file (filename, s) ;
1447         appendPathSeparator (filename);
1448         EditDLLPath = _strdup(filename);
1449         while (*s == ' ')
1450           s++ ;
1451         continue ;
1452       }
1453       if (_stricmp (commandstr, "NOEXEC") == 0)
1454       {
1455         noexec = true ;
1456         while (*s == ' ')
1457           s++ ;
1458         continue ;
1459       }
1460       if (_stricmp (commandstr, "NORESTORE") == 0 || _stricmp (commandstr, "NR") == 0)
1461       {
1462         NoRestore = true ;
1463         while (*s == ' ')
1464           s++ ;
1465         continue ;
1466       }
1467       if (_stricmp (commandstr, "THREADS") == 0)
1468       {
1469         int n ;
1470         while (*s == ' ')
1471           s++ ;
1472         if (sscanf (s, "%d", &n) != 1)
1473         {
1474           PovMessageBox ("Invalid numerical value following '/THREADS'", "Commandline processing error") ;
1475           return (NULL) ;
1476         }
1477         if (n < 1 || n > 255)
1478         {
1479           PovMessageBox ("Invalid value for thread count (range 1-255)", "Commandline processing error") ;
1480           return (NULL) ;
1481         }
1482         ThreadCount = n ;
1483         while (isdigit (*s))
1484           s++ ;
1485         while (*s == ' ')
1486           s++ ;
1487         continue ;
1488       }
1489       if (_stricmp (commandstr, "BENCHMARK") == 0)
1490       {
1491         benchmark_mode = true ;
1492         while (*s == ' ')
1493           s++ ;
1494         continue ;
1495       }
1496 #ifdef POVMS_NETWORK_SUPPORT
1497       if (_stricmp (commandstr, "LISTEN") == 0)
1498       {
1499         ListenMode = true ;
1500         s = extract_file (NetworkAddress, s) ;
1501         while (*s == ' ')
1502           s++ ;
1503         continue ;
1504       }
1505       if (_stricmp (commandstr, "CONTROL") == 0)
1506       {
1507         ControlMode = true ;
1508         s = extract_file (NetworkAddress, s) ;
1509         while (*s == ' ')
1510           s++ ;
1511         continue ;
1512       }
1513 #endif
1514       sprintf (outstr, "Unrecognized command '%s' on commandline", commandstr) ;
1515       PovMessageBox (outstr, "Commandline processing error") ;
1516       return (NULL) ;
1517     }
1518     last = *out++ = *s++ ;
1519   }
1520   return (outstr) ;
1521 }
1522 
preparse_instance_commandline(char * s)1523 char *preparse_instance_commandline (char *s)
1524 {
1525   char        *out ;
1526   char        *command ;
1527   char        last = ' ' ;
1528   char        commandstr [256] ;
1529   char        filename [_MAX_PATH] ;
1530   static char outstr [_MAX_PATH * 3] ;
1531 
1532   out = outstr ;
1533   while (*s)
1534   {
1535     if (*s == '/' && (last == ' ' || last == '\t'))
1536     {
1537       command = commandstr ;
1538       while (*++s)
1539       {
1540         if (*s == ' ' || *s == '\t')
1541           break ;
1542         *command++ = *s ;
1543       }
1544       *command = '\0' ;
1545       last = *s ;
1546       if (strlen (commandstr) == 0)
1547       {
1548         PovMessageBox ("Empty command on commandline", "Commandline processing error") ;
1549         return (NULL) ;
1550       }
1551       if (_stricmp (commandstr, "EXIT") == 0)
1552       {
1553         PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
1554         return (NULL) ;
1555       }
1556       if (_stricmp (commandstr, "DEMO") == 0)
1557       {
1558         PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
1559         return (NULL) ;
1560       }
1561       if (_stricmp (commandstr, "DEBUG") == 0)
1562       {
1563         PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
1564         return (NULL) ;
1565       }
1566       if (_stricmp (commandstr, "NOEXEC") == 0)
1567       {
1568         PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
1569         return (NULL) ;
1570       }
1571       if (_stricmp (commandstr, "THREADS") == 0)
1572       {
1573         PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
1574         return (NULL) ;
1575       }
1576       if (_stricmp (commandstr, "EDIT") == 0)
1577       {
1578         s = extract_file (filename, s) ;
1579         add_edit_file (filename) ;
1580         while (*s == ' ')
1581           s++ ;
1582         continue ;
1583       }
1584       if (_stricmp (commandstr, "RENDER") == 0)
1585       {
1586         s = extract_file (filename, s) ;
1587         add_render_file (filename) ;
1588         while (*s == ' ')
1589           s++ ;
1590         continue ;
1591       }
1592       if (_stricmp (commandstr, "NORESTORE") == 0 || _stricmp (commandstr, "NR") == 0)
1593       {
1594         while (*s == ' ')
1595           s++ ;
1596         continue ;
1597       }
1598       sprintf (outstr, "Unrecognized command '%s' on commandline", commandstr) ;
1599       PovMessageBox (outstr, "Commandline processing error") ;
1600       return (NULL) ;
1601     }
1602     last = *out++ = *s++ ;
1603   }
1604   return (outstr) ;
1605 }
1606 
1607 INT_PTR CALLBACK PovStatusPanelDialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
1608 
create_toolbar(HWND hwndParent)1609 HWND create_toolbar (HWND hwndParent)
1610 {
1611   int                   fontWidth ;
1612   int                   fontHeight ;
1613   HDC                   hdc ;
1614   HWND                  hwnd ;
1615   RECT                  rect ;
1616   HFONT                 hFontOld ;
1617   HFONT                 hParentFont ;
1618   HBITMAP               hbmp ;
1619   TBBUTTON              main_tbb [MAX_MAIN_TOOLS] ;
1620   TBBUTTON              aux_tbb [MAX_AUX_TOOLS] ;
1621   TBBUTTON              *dt ;
1622   TEXTMETRIC            tm ;
1623   toolbarStruct         *st ;
1624   REBARBANDINFO         rbBand ;
1625 
1626   hParentFont = (HFONT) SendMessage (hwndParent, WM_GETFONT, 0, 0) ;
1627   hdc = GetDC (hwndParent) ;
1628   hFontOld = (HFONT) SelectObject (hdc, hParentFont) ;
1629   GetTextMetrics (hdc, &tm) ;
1630   SelectObject (hdc, hFontOld) ;
1631   ReleaseDC (hwndParent, hdc) ;
1632 
1633   fontWidth = tm.tmAveCharWidth ;
1634   fontHeight = tm.tmHeight ;
1635 
1636   toolbar_combobox_width = fontWidth * 30 ;
1637   toolbar_cmdline_width = fontWidth * 20 ;
1638 
1639   // Initialize REBARBANDINFO for all rebar bands
1640   rbBand.cbSize = sizeof (REBARBANDINFO) ;
1641   rbBand.clrFore = GetSysColor (COLOR_BTNTEXT) ;
1642   rbBand.clrBack = GetSysColor (COLOR_BTNFACE) ;
1643   rbBand.hbmBack = LoadBitmap (hInstance, MAKEINTRESOURCE (BMP_REBAR)) ;
1644 
1645   hwnd = CreateWindow (TOOLBARCLASSNAME,
1646                        "",
1647                        WS_CHILD | WS_VISIBLE | CCS_TOP | TBSTYLE_TOOLTIPS |
1648                        TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | WS_CLIPCHILDREN |
1649                        WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_ADJUSTABLE,
1650                        0,
1651                        0,
1652                        256,
1653                        50,
1654                        hwndParent,
1655                        NULL,
1656                        hInstance,
1657                        NULL) ;
1658   if (hwnd == NULL)
1659     return (NULL) ;
1660   SendMessage (hwnd, TB_BUTTONSTRUCTSIZE, sizeof (TBBUTTON), 0) ;
1661   SendMessage (hwnd, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG (38, 21)) ;
1662   SendMessage (hwnd, TB_SETBUTTONSIZE, 0, (LPARAM) MAKELONG (38, 21)) ;
1663 
1664   if ((ToolImages1 = ImageList_Create (38, 21, (screen_depth < 8 ? ILC_COLOR4 : ILC_COLOR24) | ILC_MASK, 0, 16)) == NULL)
1665     return (NULL) ;
1666   for (dt = main_tbb, st = maintools ; st->text != NULL ; st++, dt++)
1667   {
1668     dt->iBitmap = ImageList_AddMasked (ToolImages1, hbmp = LoadBitmap (hInstance, MAKEINTRESOURCE (st->resid)), RGB (255, 0, 255)) ;
1669     dt->iString = SendMessage (hwnd, TB_ADDSTRING, 0, (LPARAM) st->text) ;
1670     dt->idCommand = st->id ;
1671     dt->fsState = TBSTATE_ENABLED ;
1672     dt->fsStyle = st->flags & 0x01 ? TBSTYLE_CHECK : TBSTYLE_BUTTON ;
1673     dt->fsState = st->flags & 0x02 ? TBSTATE_HIDDEN | TBSTATE_ENABLED : TBSTATE_ENABLED ;
1674     dt->dwData = 0 ;
1675     DeleteObject (hbmp) ;
1676   }
1677   SendMessage (hwnd, TB_SETIMAGELIST, 0, (LPARAM) ToolImages1) ;
1678   SendMessage (hwnd, TB_ADDBUTTONS, MAX_MAIN_TOOLS, (LPARAM) main_tbb) ;
1679   SendMessage (hwnd, TB_AUTOSIZE, 0, 0) ;
1680 
1681   rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
1682   rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_GRIPPERALWAYS ;
1683   rbBand.hwndChild = hwnd ;
1684   SendMessage (hwnd, TB_GETITEMRECT, MAX_MAIN_TOOLS - 1, (LPARAM) &rect) ;
1685   rbBand.cxMinChild = 1 ;
1686   rbBand.cyMinChild = rect.bottom ;
1687   rbBand.cx = rect.right + 15 ;
1688   rbBand.wID = 0 ;
1689   SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) (LPREBARBANDINFO) &rbBand) ;
1690   DeleteObject (hbmp) ;
1691 
1692   statuspanel = CreateDialog (hInstance, MAKEINTRESOURCE (IDD_STATUSPANEL), hwnd, PovStatusPanelDialogProc) ;
1693   rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
1694   rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDSIZE ;
1695   rbBand.hwndChild = statuspanel ;
1696   rbBand.cx = 200 ;
1697   rbBand.cxMinChild = 200 ;
1698   rbBand.cyMinChild = 42 ;
1699   rbBand.wID++;
1700   SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) (LPREBARBANDINFO) &rbBand) ;
1701 
1702   toolbar_combobox = CreateWindow ("COMBOBOX", // WC_COMBOBOXEX,
1703                                    "",
1704                                    WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP |
1705                                    WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NORESIZE,
1706                                    0,
1707                                    0,
1708                                    toolbar_combobox_width,
1709                                    fontHeight * 20,
1710                                    hwndParent,
1711                                    NULL,
1712                                    hInstance,
1713                                    NULL) ;
1714 
1715   SendMessage (toolbar_combobox, WM_SETFONT, (WPARAM) hParentFont, true) ;
1716   rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
1717   rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_GRIPPERALWAYS | RBBS_BREAK ;
1718   rbBand.hwndChild = toolbar_combobox ;
1719   GetWindowRect (toolbar_combobox, &rect) ;
1720   rbBand.cx = rect.right - rect.left ;
1721   rbBand.cxMinChild = rbBand.cx / 2 ;
1722   rbBand.cyMinChild = rect.bottom - rect.top ;
1723   rbBand.wID++;
1724   if (bandWidths[rbBand.wID] > 10)
1725     rbBand.cx = bandWidths[rbBand.wID] ;
1726   SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) (LPREBARBANDINFO) &rbBand) ;
1727 
1728   toolbar_cmdline = CreateWindowEx (WS_EX_CLIENTEDGE,
1729                                     "EDIT",
1730                                     "",
1731                                     WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
1732                                     0,
1733                                     0,
1734                                     toolbar_cmdline_width + GetSystemMetrics (SM_CXEDGE) * 2,
1735                                     fontHeight + GetSystemMetrics (SM_CYEDGE) * 2 + 3,
1736                                     hwndParent,
1737                                     NULL,
1738                                     hInstance,
1739                                     NULL) ;
1740 
1741   SendMessage (toolbar_cmdline, EM_LIMITTEXT, _MAX_PATH, 0) ;
1742   SendMessage (toolbar_cmdline, WM_SETFONT, (WPARAM) hParentFont, true) ;
1743   GetWindowRect (toolbar_cmdline, &rect) ;
1744   rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
1745   rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_GRIPPERALWAYS ;
1746   rbBand.hwndChild = toolbar_cmdline ;
1747   rbBand.cx = rect.right - rect.left ;
1748   rbBand.cxMinChild = rbBand.cx / 2 ;
1749   rbBand.cyMinChild = rect.bottom - rect.top ;
1750   rbBand.wID++;
1751   if (bandWidths[rbBand.wID] > 10)
1752     rbBand.cx = bandWidths[rbBand.wID] ;
1753   SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) &rbBand) ;
1754 
1755   HWND tt ;
1756   if ((tt = (HWND) SendMessage (hwnd, TB_GETTOOLTIPS, 0, 0)) != NULL)
1757   {
1758     // we borrow the toolbar's tooltip rather than create a new one
1759     TOOLINFO ti ;
1760     memset (&ti, 0, sizeof (TOOLINFO)) ;
1761     ti.cbSize = sizeof (TOOLINFO) ;
1762     ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
1763     ti.hwnd = hwndParent ;
1764     ti.uId = (UINT_PTR) toolbar_cmdline ;
1765     ti.lpszText = "Command line (overrides preset render options)" ;
1766     SendMessage (tt, TTM_ADDTOOL, 0, (LPARAM) &ti) ;
1767     ti.uId = (UINT_PTR) toolbar_combobox ;
1768     ti.lpszText = "Preset render options" ;
1769     SendMessage (tt, TTM_ADDTOOL, 0, (LPARAM) &ti) ;
1770   }
1771 
1772   aux_toolbar_window = CreateWindow (TOOLBARCLASSNAME,
1773                                      "",
1774                                      WS_CHILD | WS_VISIBLE | CCS_TOP | TBSTYLE_TOOLTIPS |
1775                                      TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT |
1776                                      WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE,
1777                                      0,
1778                                      0,
1779                                      256,
1780                                      50,
1781                                      hwndParent,
1782                                      NULL,
1783                                      hInstance,
1784                                      NULL) ;
1785   if (aux_toolbar_window == NULL)
1786     return (NULL) ;
1787 
1788   SendMessage (aux_toolbar_window, TB_BUTTONSTRUCTSIZE, sizeof (TBBUTTON), 0) ;
1789   SendMessage (aux_toolbar_window, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG (14, 14)) ;
1790   SendMessage (aux_toolbar_window, TB_SETBUTTONSIZE, 0, (LPARAM) MAKELONG (14, 14)) ;
1791 
1792   if ((ToolImages2 = ImageList_Create (14, 14, (screen_depth < 8 ? ILC_COLOR4 : ILC_COLOR24) | ILC_MASK, 0, 8)) == NULL)
1793     return (hwnd) ;
1794   for (dt = aux_tbb, st = auxtools ; st->text != NULL ; st++, dt++)
1795   {
1796     dt->iBitmap = ImageList_AddMasked (ToolImages2, hbmp = LoadBitmap (hInstance, MAKEINTRESOURCE (st->resid)), RGB (255, 0, 255)) ;
1797     dt->iString = SendMessage (aux_toolbar_window, TB_ADDSTRING, 0, (LPARAM) st->text) ;
1798     dt->idCommand = st->id ;
1799     dt->fsState = TBSTATE_ENABLED ;
1800     dt->fsStyle = st->flags & 0x01 ? TBSTYLE_CHECK : TBSTYLE_BUTTON ;
1801     dt->dwData = 0 ;
1802     DeleteObject (hbmp) ;
1803   }
1804   SendMessage (aux_toolbar_window, TB_SETIMAGELIST, 0, (LPARAM) ToolImages2) ;
1805   SendMessage (aux_toolbar_window, TB_ADDBUTTONS, MAX_AUX_TOOLS, (LPARAM) aux_tbb) ;
1806   SendMessage (aux_toolbar_window, TB_AUTOSIZE, 0, 0) ;
1807 
1808   rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
1809   rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_GRIPPERALWAYS ;
1810   rbBand.hwndChild = aux_toolbar_window ;
1811   SendMessage (aux_toolbar_window, TB_GETITEMRECT, MAX_AUX_TOOLS - 1, (LPARAM) &rect) ;
1812   rbBand.cxMinChild = 1 ;
1813   rbBand.cyMinChild = rect.bottom ;
1814   rbBand.cx = rect.right + 15 ;
1815   rbBand.wID++;
1816   if (bandWidths[rbBand.wID] > 10)
1817     rbBand.cx = bandWidths[rbBand.wID] ;
1818   SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) (LPREBARBANDINFO) &rbBand) ;
1819 
1820   return (hwnd) ;
1821 }
1822 
create_rebar(HWND hwndParent)1823 HWND create_rebar (HWND hwndParent)
1824 {
1825   HWND                            hwnd ;
1826   INITCOMMONCONTROLSEX            icex ;
1827 
1828   icex.dwSize = sizeof (INITCOMMONCONTROLSEX) ;
1829   icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES ;
1830   InitCommonControlsEx (&icex) ;
1831   hwnd = CreateWindowEx (0L,
1832                          REBARCLASSNAME,
1833                          NULL,
1834                          WS_VISIBLE | WS_BORDER | WS_CHILD | WS_CLIPCHILDREN |
1835                          /*CCS_NOPARENTALIGN |*/ CCS_NODIVIDER | WS_CLIPSIBLINGS |
1836                          RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_DBLCLKTOGGLE,
1837                          0,
1838                          0,
1839                          800,
1840                          128,
1841                          hwndParent,
1842                          (HMENU) ID_REBAR,
1843                          hInstance,
1844                          NULL) ;
1845   return (hwnd) ;
1846 }
1847 
CreateStatusbar(HWND hwndParent)1848 HWND CreateStatusbar (HWND hwndParent)
1849 {
1850   HWND                            hwnd ;
1851   RECT                            rect ;
1852 
1853   hwnd = CreateWindowEx (0L,
1854                          STATUSCLASSNAME,
1855                          NULL,
1856                          WS_CHILD | SBARS_SIZEGRIP | WS_VISIBLE,
1857                          0,
1858                          0,
1859                          0,
1860                          0,
1861                          hwndParent,
1862                          (HMENU) ID_STATUS,
1863                          hInstance,
1864                          NULL) ;
1865   GetClientRect (hwnd, &rect) ;
1866   statusheight = rect.bottom - rect.top ;
1867 
1868   StatusTooltip = CreateWindowEx(NULL,
1869                                  TOOLTIPS_CLASS,
1870                                  NULL,
1871                                  WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
1872                                  CW_USEDEFAULT,
1873                                  CW_USEDEFAULT,
1874                                  CW_USEDEFAULT,
1875                                  CW_USEDEFAULT,
1876                                  hwndParent,
1877                                  NULL,
1878                                  hInstance,
1879                                  NULL);
1880   SetWindowPos(StatusTooltip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1881 
1882   memset (&sbToolInfo, 0, sizeof (TOOLINFO)) ;
1883   sbToolInfo.cbSize = sizeof (TOOLINFO) ;
1884   sbToolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
1885   sbToolInfo.hwnd = hwndParent ;
1886   sbToolInfo.uId = (UINT_PTR) hwnd ;
1887   sbToolInfo.lpszText = LPSTR_TEXTCALLBACK;
1888   SendMessage (StatusTooltip, TTM_ADDTOOL, 0, (LPARAM) &sbToolInfo) ;
1889 
1890   return (hwnd) ;
1891 }
1892 
1893 // should really query the statusbar and get the font size, then
1894 // work out the section sizes from that.
ResizeStatusBar(HWND hwnd)1895 void ResizeStatusBar (HWND hwnd)
1896 {
1897   int                   parts [] = {0, 0, 0, 0, 0, 0, 0, 0} ;
1898   int                   i ;
1899   int                   total = 0 ;
1900   RECT                  rect ;
1901   static const int      widths [] = {0, 65, 50, 50, 50, 50, 95, 135} ;
1902   static const int      all = 495 ;
1903 
1904   GetClientRect (hwnd, &rect) ;
1905   rect.right -= all ;
1906   for (i = 0 ; i < sizeof (parts) / sizeof (int) ; i++)
1907   {
1908     total += widths [i] ;
1909     parts [i] = total + rect.right ;
1910   }
1911   SendMessage (hwnd, SB_SETPARTS, sizeof (parts) / sizeof (int), (LPARAM) parts) ;
1912 }
1913 
HandleStatusTooltip(NMHDR * nmh)1914 bool HandleStatusTooltip(NMHDR *nmh)
1915 {
1916   int                   parts[32];
1917   int                   count;
1918   int                   off;
1919   char                  str[512];
1920   char                  *s;
1921   RECT                  rect ;
1922   POINT                 pos;
1923   NMTTDISPINFO          *di;
1924 
1925   switch (nmh->code)
1926   {
1927      case TTN_NEEDTEXT :
1928           di = (NMTTDISPINFO *) nmh;
1929           if ((count = SendMessage(StatusWindow, SB_GETPARTS, 32, (LPARAM) parts)) == 0)
1930             return false;
1931           GetCursorPos (&pos) ;
1932           GetWindowRect(StatusWindow, &rect);
1933           if (pos.x < rect.left || pos.y > rect.right)
1934             return false;
1935           off = pos.x - rect.left;
1936           di->hinst = hInstance ;
1937           di->lpszText = sbToolText;
1938           sbToolText[0] = '\0';
1939           for (int i = 0; i < count; i++)
1940           {
1941             if (parts[i] == -1 || off < parts[i])
1942             {
1943               SendMessage(StatusWindow, SB_GETTEXT, i, (LPARAM) str);
1944               if (str[0] == '\0')
1945                 return true;
1946               switch (i)
1947               {
1948                 case StatusMessage :
1949                      strcpy(sbToolText, str);
1950                      break ;
1951 
1952                 case StatusMem :
1953                      sprintf(sbToolText, "Current memory usage: %s", str);
1954                      break ;
1955 
1956                 case StatusLine:
1957                      sprintf(sbToolText, "Line: %s", str + 3);
1958                      break ;
1959 
1960                 case StatusCol:
1961                      sprintf(sbToolText, "Column: %s", str + 3);
1962                      break ;
1963 
1964                 case StatusIns:
1965                      strcpy(sbToolText, str[1] == 'I' ? "Insert mode" : "Overwrite mode");
1966                      break ;
1967 
1968                 case StatusModified:
1969                      strcpy(sbToolText, "File has been modified");
1970                      break ;
1971 
1972                 case StatusPPS :
1973                      if ((s = strchr(str, ' ')) == NULL)
1974                        break;
1975                      *s = '\0';
1976                      sprintf(sbToolText, "%s Pixels per Second", str);
1977                      break ;
1978 
1979                 case StatusRendertime :
1980                      sprintf(sbToolText, "Elapsed Time: %s", str);
1981                      break ;
1982               }
1983               break;
1984             }
1985           }
1986           return true;
1987   }
1988   return false;
1989 }
1990 
say_status_message(int section,const char * message)1991 void say_status_message (int section, const char *message)
1992 {
1993   char        str [256] = "\t" ;
1994 
1995   switch (section)
1996   {
1997     case StatusMessage :
1998          SendMessage (StatusWindow, SB_SETTEXT, StatusMessage, (LPARAM) message) ;
1999          break ;
2000 
2001     case StatusMem :
2002          SendMessage (StatusWindow, SB_SETTEXT, StatusMem, (LPARAM) message) ;
2003          break ;
2004 
2005     case StatusPPS :
2006          strncat (str, message, sizeof (str) - strlen (str) - 1) ;
2007          SendMessage (StatusWindow, SB_SETTEXT, StatusPPS, (LPARAM) str) ;
2008          break ;
2009 
2010     case StatusRendertime :
2011          SendMessage (StatusWindow, SB_SETTEXT, StatusRendertime, (LPARAM) message) ;
2012          break ;
2013   }
2014 }
2015 
2016 }
2017