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, ¤t_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, ¤t_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, ¤t_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, ¤t_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