/*******************************************************************************
* pvtext.cpp
*
* This module implements message and message display routines for Windows.
*
* Author: Christopher J. Cason.
*
* ---------------------------------------------------------------------------
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
* Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
*
* POV-Ray is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* POV-Ray is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
* ---------------------------------------------------------------------------
* POV-Ray is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
* ---------------------------------------------------------------------------
* $File: //depot/public/povray/3.x/windows/pvtext.cpp $
* $Revision: #1 $
* $Change: 6069 $
* $DateTime: 2013/11/06 11:59:40 $
* $Author: chrisc $
*******************************************************************************/
#define POVWIN_FILE
#define _WIN32_IE COMMONCTRL_VERSION
#include
#include
#include
#include
#include "pvengine.h"
#include "resource.h"
#include "pvguiext.h"
#include "pvedit.h"
// this must be the last file included
#include "syspovdebug.h"
namespace povwin
{
#define MAX_SEEK_INDEX 1024
typedef struct
{
unsigned Line ;
unsigned short Offset ;
} seekStruct ;
typedef struct
{
int id ;
int resid ;
int flags ;
char *text ;
} toolbarStruct ;
int message_xchar ;
int message_ychar ;
int listbox_xchar ;
int listbox_ychar ;
int top_message_row ;
int message_scroll_pos_x ;
int message_scroll_pos_y ;
int message_count ;
int message_cols ;
int message_rows ;
int EditFileCount ;
int toolbar_cmdline_width ;
int toolbar_combobox_width ;
int bandWidths [8] ;
int message_output_x = -1 ;
char *message_buffer [MAX_MESSAGE] ;
char **first_message ;
char **next_message ;
char **last_message ;
char str_buffer [2048] ;
char message_font_name [256] ;
char listbox_font_name [] = "Lucida Console" ;
char line_buffer [2048] ;
char *EditFiles [MAX_EDIT_FILES] ;
bool mem_warned ;
unsigned message_font_size ;
unsigned message_font_weight ;
unsigned listbox_font_size = 8 ;
unsigned listbox_font_weight = FW_NORMAL ;
unsigned editor_line_number ;
unsigned editor_char_pos ;
unsigned editor_offset ;
unsigned seek_entry_count ;
RECT current_rect ;
bool keep_messages ;
HFONT message_font ;
HFONT listbox_font ;
HFONT tab_font ;
char sbToolText[512];
TOOLINFO sbToolInfo;
seekStruct seek_entries [MAX_SEEK_INDEX] ;
HIMAGELIST ToolImages1 ;
HIMAGELIST ToolImages2 ;
extern int statistics_count ;
extern int delay_next_status ;
extern int seconds_for_last_line ;
extern char tool_help [MAX_TOOLCMD] [MAX_TOOLHELPTEXT] ;
extern char requested_render_file [] ;
extern char source_file_name [] ;
extern char NetworkAddress [] ;
extern char PovStatusPanelWinClass [] ;
extern char *EditDLLPath ;
extern bool ListenMode ;
extern bool ControlMode ;
extern void *CurrentEditor ;
extern time_t quit ;
extern unsigned background_width ;
extern unsigned background_height ;
extern unsigned window_count ;
extern unsigned statusheight ;
extern unsigned screen_depth ;
extern unsigned render_width ;
extern unsigned ThreadCount ;
extern HWND main_window ;
extern HWND message_window ;
extern HWND hToolComboBox ;
extern HWND window_list [MAX_WINDOWS] ;
extern HWND toolbar_combobox ;
extern HWND aux_toolbar_window ;
extern HWND statuspanel ;
extern HWND StatusWindow ;
extern HWND StatusTooltip ;
extern HWND toolbar_cmdline ;
extern bool IsWin32 ;
extern bool fast_scroll ;
extern bool tile_background ;
extern bool IsW95UserInterface ;
extern bool use_toolbar ;
extern bool resizing ;
extern bool exit_after_render ;
extern bool demo_mode ;
extern bool debugging ;
extern bool render_requested ;
extern bool noexec ;
extern bool NoRestore ;
extern bool rendering ;
extern bool run_renderer ;
extern bool rendering_animation ;
extern bool no_status_output ;
extern bool stop_rendering ;
extern bool benchmark_mode;
extern HBITMAP hBmpBackground ;
extern HBITMAP hBmpRendering ;
extern COLORREF background_colour ;
extern COLORREF background_shade ;
extern COLORREF text_colours[3] ;
extern HPALETTE hPalApp ;
extern CRITICAL_SECTION critical_section ;
int toolbar_ids [] = {
CM_FILENEW,
CM_FILEOPEN,
CM_FILESAVE,
CM_FILEQUEUE,
CM_RENDERSHOW,
CM_COMMANDLINE,
CM_SOURCEFILE,
CM_FILERENDER,
CM_RENDERSLEEP | 0x8000,
} ;
#define MAX_TOOLS (sizeof (toolbar_ids) / sizeof (int))
toolbarStruct maintools [] =
{
{CM_FILENEW, BMP_TOOLFILENEW, 0x00, "New"},
{CM_FILEOPEN, BMP_TOOLFILEOPEN, 0x00, "Open"},
{CM_FILESAVE, BMP_TOOLFILESAVE, 0x00, "Save"},
{CM_FILECLOSE, BMP_TOOLFILECLOSE, 0x00, "Close"},
{CM_FILEQUEUE, BMP_TOOLFILEQUEUE, 0x00, "Queue"},
{CM_RENDERSHOW, BMP_TOOLRENDERSHOW, 0x00, "Show"},
{CM_RENDERCLOSE, BMP_TOOLRENDERCLOSE, 0x02, "Hide"},
{CM_COMMANDLINE, BMP_TOOLCMDLINE, 0x00, "Ini"},
{CM_SOURCEFILE, BMP_TOOLSOURCEFILE, 0x00, "Sel-Run"},
{CM_FILERENDER, BMP_TOOLFILERENDER, 0x00, "Run"},
{CM_STOPRENDER, BMP_TOOLSTOPRENDER, 0x02, "Stop"},
{CM_RENDERSLEEP, BMP_TOOLSLEEP, 0x01, "Pause"},
{CM_SHOWMAINWINDOW,BMP_TOOLSYSTRAY, 0x00, "Tray"},
{0, 0, 0x00, NULL}
} ;
#define MAX_MAIN_TOOLS (sizeof (maintools) / sizeof (toolbarStruct) - 1)
toolbarStruct auxtools [] =
{
{CM_HELPPOVWIN, BMP_TOOLHELPCONT, 0x00, "POV-Win"},
{CM_HELPSCENE, BMP_TOOLHELPPOVRAY, 0x00, "Scene"},
{CM_GOPOVRAYORG, BMP_TOOLGOPOVRAY, 0x00, "POV Site"},
{0, 0, 0x00, NULL}
} ;
#define MAX_AUX_TOOLS (sizeof (auxtools) / sizeof (toolbarStruct) - 1)
bool is_horz_line (char *s)
{
if (strlen (s) < 70)
return (false) ;
while (*s)
if (*s++ != '-')
return (false) ;
return (true) ;
}
const char *buffer_str (const char *s, lftype *lf)
{
char *ptr ;
if (s == NULL)
{
message_output_x = -1 ;
return (NULL) ;
}
*lf = None ;
if (message_output_x == -1)
{
message_output_x = 0 ;
memset (str_buffer, 0, sizeof (str_buffer)) ;
}
ptr = str_buffer + message_output_x ;
while (*s)
{
switch (*s)
{
case '\r' : message_output_x = 0 ;
ptr = str_buffer ;
*lf = CR ;
break ;
case '\n' : message_output_x = -1 ;
*lf = LF ;
return (++s) ;
case '\f' : if (message_output_x != -1)
{
message_output_x = -1 ;
*lf = LF ;
return (++s) ;
}
s++ ;
break ;
case '\b' : if (message_output_x > 0)
{
--message_output_x ;
*--ptr = '\0' ;
}
break ;
default : if (isprint (*s) && message_output_x < sizeof (str_buffer) - 1)
{
message_output_x++ ;
*ptr++ = *s ;
}
break ;
}
s++ ;
}
return (s) ;
}
int update_message_display (lftype lf)
{
RECT rect ;
if (message_window == NULL)
return (0) ;
GetClientRect (message_window, &rect) ;
message_cols = rect.right / message_xchar ;
message_rows = rect.bottom / message_ychar ;
if (lf == None || lf == LF)
{
EnterCriticalSection (&critical_section) ;
top_message_row = message_count > message_rows ? message_count - message_rows : 0 ;
LeaveCriticalSection (&critical_section) ;
SetScrollRange (message_window, SB_HORZ, 0, need_hscroll (), false) ;
SetScrollPos (message_window, SB_HORZ, message_scroll_pos_x, true) ;
SetScrollRange (message_window, SB_VERT, 0, top_message_row, false) ;
SetScrollPos (message_window, SB_VERT, message_scroll_pos_y, true) ;
}
if (lf == None)
return (message_rows) ;
if (lf == LF)
{
EnterCriticalSection (&critical_section) ;
// is there room for another row ?
if (current_rect.bottom + message_ychar <= rect.bottom)
{
// yes there is
current_rect.top += message_ychar ;
current_rect.bottom += message_ychar ;
}
else
ScrollWindow (message_window, 0, -message_ychar, NULL, &rect) ;
message_scroll_pos_y = top_message_row ;
SetScrollPos (message_window, SB_VERT, message_scroll_pos_y, true) ;
LeaveCriticalSection (&critical_section) ;
}
PovInvalidateRect (message_window, ¤t_rect, true) ;
if (!fast_scroll && !rendering_animation && IsWindowVisible (message_window))
UpdateWindow (message_window) ;
return (message_rows) ;
}
void buffer_message (msgtype message_type, const char *s, bool addLF)
{
char *s1 ;
lftype lf ;
ExternalBufferMessage (message_type, (LPSTR) s) ;
EnterCriticalSection (&critical_section) ;
while (*s)
{
s1 = (char *)s ;
s = buffer_str (s, &lf) ;
if (lf == None)
continue ;
if ((s1 = (char *) malloc (strlen (str_buffer) + 2)) == NULL)
{
LeaveCriticalSection (&critical_section) ;
if (rendering)
{
if (!mem_warned)
PovMessageBox ("Failed to allocate memory for message string", "Fatal Error") ;
stop_rendering = true ;
}
else
if (!mem_warned)
PovMessageBox ("Failed to allocate memory for message string", "Error") ;
mem_warned = true ;
return ;
}
if (is_horz_line (str_buffer))
message_type = mHorzLine ;
strcpy (s1 + 1, str_buffer) ;
*s1 = (uchar) message_type ;
if (lf == CR)
{
if (*last_message)
free (*last_message) ;
*last_message = s1 ;
LeaveCriticalSection (&critical_section) ;
update_message_display (CR) ;
EnterCriticalSection (&critical_section) ;
}
else
{
if (*next_message)
{
free (*next_message) ;
*next_message = NULL ;
if (++first_message == message_buffer + MAX_MESSAGE)
first_message = message_buffer ;
}
else
message_count++ ;
*next_message = s1 ;
last_message = next_message ;
if (++next_message == message_buffer + MAX_MESSAGE)
next_message = message_buffer ;
LeaveCriticalSection (&critical_section) ;
update_message_display (LF) ;
EnterCriticalSection (&critical_section) ;
}
}
if (addLF)
buffer_message (message_type, "\n", false) ;
LeaveCriticalSection (&critical_section) ;
}
void add_single_line (msgtype message_type, const char *str)
{
char *s1 ;
RECT rect ;
if (message_type == mWarning && strncmp (str, "File: ", 6) == 0)
add_single_line (mDivider, "") ;
if (message_type == mStatistics)
if (strcmp (str, "Scene Statistics") == 0 || strcmp (str, "Render Statistics") == 0)
add_single_line (mDivider, "") ;
if (strncmp (str, "---------------", 15) == 0)
{
str = "" ;
message_type = mDivider ;
}
if (message_type == mDivider || message_type == mHorzLine)
if (last_message != NULL && (**last_message == mDivider || **last_message == mHorzLine))
return ;
if ((s1 = (char *) malloc (strlen (str) + 2)) == NULL)
{
if (rendering)
{
if (!mem_warned)
PovMessageBox ("Failed to allocate memory for message string", "Fatal Error") ;
stop_rendering = true ;
}
else
if (!mem_warned)
PovMessageBox ("Failed to allocate memory for message string", "Error") ;
mem_warned = true ;
return ;
}
strcpy (s1 + 1, str) ;
*s1 = (uchar) message_type ;
if (*next_message)
{
free (*next_message) ;
*next_message = NULL ;
if (++first_message == message_buffer + MAX_MESSAGE)
first_message = message_buffer ;
}
else
message_count++ ;
*next_message = s1 ;
last_message = next_message ;
if (++next_message == message_buffer + MAX_MESSAGE)
next_message = message_buffer ;
GetClientRect (message_window, &rect) ;
message_cols = rect.right / message_xchar ;
message_rows = rect.bottom / message_ychar ;
top_message_row = message_count > message_rows ? message_count - message_rows : 0 ;
SetScrollRange (message_window, SB_HORZ, 0, need_hscroll (), false) ;
SetScrollPos (message_window, SB_HORZ, message_scroll_pos_x, true) ;
SetScrollRange (message_window, SB_VERT, 0, top_message_row, false) ;
SetScrollPos (message_window, SB_VERT, message_scroll_pos_y, true) ;
// is there room for another row ?
if (current_rect.bottom + message_ychar <= rect.bottom)
{
// yes there is
current_rect.top += message_ychar ;
current_rect.bottom += message_ychar ;
}
else
ScrollWindow (message_window, 0, -message_ychar, NULL, &rect) ;
message_scroll_pos_y = top_message_row ;
SetScrollPos (message_window, SB_VERT, message_scroll_pos_y, true) ;
PovInvalidateRect (message_window, ¤t_rect, true) ;
if (!fast_scroll && !rendering_animation && IsWindowVisible (message_window))
UpdateWindow (message_window) ;
}
void wrap_message (const char *str, int width, msgtype message_type)
{
int col = 1 ;
char buffer [2048] ;
char *bp = buffer ;
char *ws_b = NULL ;
const char *wd_b = NULL ;
const char *s = str ;
if (width < 80)
width = 80 ;
while (*s)
{
if (*s == '\r' || *s == '\n')
{
while (*s == '\r' && (s [1] == '\r' || s [1] == '\n'))
s++ ;
*bp = '\0' ;
add_single_line (message_type, buffer) ;
ws_b = NULL ;
wd_b = NULL ;
bp = buffer ;
col = 1 ;
s++ ;
continue ;
}
col++ ;
if (*s == ' ' || *s == '\t')
{
if (ws_b == NULL || ws_b < wd_b)
ws_b = bp ;
wd_b = NULL ;
*bp++ = *s++ ;
continue ;
}
if (wd_b == NULL)
wd_b = bp ;
*bp++ = *s++ ;
if (col > width && ws_b != NULL)
{
*ws_b = '\0' ;
add_single_line (message_type, buffer) ;
if (wd_b)
{
col = bp - wd_b ;
memcpy (buffer, wd_b, col) ;
bp = buffer + col ;
wd_b = buffer ;
ws_b = NULL ;
}
else
{
col = 1 ;
bp = buffer ;
ws_b = NULL ;
wd_b = NULL ;
while (*s == ' ' || *s == '\t')
s++ ;
}
}
}
if (ws_b != NULL && wd_b == NULL)
bp = ws_b ;
*bp = '\0' ;
add_single_line (message_type, buffer) ;
}
void buffer_stream_message (msgtype message_type, const char *s)
{
RECT rect ;
if (message_type == mUnknown)
{
if (strncmp (s, "File: ", 6) == 0)
message_type = mWarning;
else if (strncmp (s, "Shutdown", 8) == 0)
message_type = mWarning;
}
// since the POVMS streams don't try fancy stuff with CR's and backspaces
// we can simplify the above code (and also handle wordwrap). all data
// data passed to us is implicitly terminated by an LF. embedded LF's are
// permitted and a terminating LF implies two LF's (due to above).
ExternalBufferMessage (message_type, (LPSTR) s) ;
ExternalBufferMessage (message_type, "\n") ;
GetClientRect (message_window, &rect) ;
message_cols = rect.right / message_xchar ;
EnterCriticalSection (&critical_section) ;
// we don't want to wrap debug text - we assume the scene author wants to control this.
wrap_message (s, message_type == mDebug ? 9999 : message_cols - 2, message_type) ;
LeaveCriticalSection (&critical_section) ;
}
void message_printf (const char *format, ...)
{
char str [2048] ;
char *s ;
time_t t ;
va_list arg_ptr ;
if (strlen (format) > sizeof (str) - 256)
return ;
if (debugging)
{
time (&t) ;
s = ctime (&t) ;
memcpy (str, s + 11, 9) ;
va_start (arg_ptr, format) ;
vsprintf (str + 9, format, arg_ptr) ;
va_end (arg_ptr) ;
OutputDebugString (str) ;
}
va_start (arg_ptr, format) ;
vsprintf (str, format, arg_ptr) ;
va_end (arg_ptr) ;
buffer_message (mIDE, str) ;
}
void wrapped_printf (const char *format, ...)
{
char str [2048] ;
char *s ;
time_t t ;
va_list arg_ptr ;
if (strlen (format) > sizeof (str) - 256)
return ;
if (debugging)
{
time (&t) ;
s = ctime (&t) ;
memcpy (str, s + 11, 9) ;
va_start (arg_ptr, format) ;
vsprintf (str + 9, format, arg_ptr) ;
va_end (arg_ptr) ;
OutputDebugString (str) ;
}
va_start (arg_ptr, format) ;
vsprintf (str, format, arg_ptr) ;
va_end (arg_ptr) ;
s = str + strlen (str) - 1 ;
if (*s == '\n')
*s = '\0' ;
buffer_stream_message (mIDE, str) ;
}
void status_printf (int nSection, const char *format, ...)
{
char str [2048] ;
va_list arg_ptr ;
va_start (arg_ptr, format) ;
vsprintf (str, format, arg_ptr) ;
va_end (arg_ptr) ;
say_status_message (nSection, str) ;
}
char *clean_str (const char *s)
{
char *s1 ;
static char str [512] ;
if (strlen (s) > 511)
return ("Internal error : string too long in clean_str") ;
EnterCriticalSection (&critical_section) ;
for (s1 = str ; *s ; s++)
if (*s >= ' ')
*s1++ = *s ;
*s1 = '\0' ;
LeaveCriticalSection (&critical_section) ;
return (str) ;
}
void erase_display_window (HDC hdc, int xoffset, int yoffset)
{
int x, y ;
HDC hdcMemory ;
RECT rect ;
HBRUSH hbr ;
HBITMAP oldBmp ;
if (message_window == NULL)
return ;
GetClientRect (message_window, &rect) ;
if (tile_background)
{
hdcMemory = CreateCompatibleDC (hdc) ;
oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpBackground) ;
xoffset %= background_width ;
yoffset %= background_height ;
for (y = -yoffset ; y < rect.bottom ; y += background_height)
for (x = -xoffset ; x < rect.right ; x += background_width)
BitBlt (hdc, x, y, background_width, background_height, hdcMemory, 0, 0, SRCCOPY) ;
SelectObject (hdcMemory, oldBmp) ;
DeleteDC (hdcMemory) ;
}
else
{
hbr = CreateSolidBrush (background_colour) ;
FillRect (hdc, &rect, hbr) ;
DeleteObject (hbr) ;
}
}
void paint_display_window (HDC hdc)
{
int x, y ;
int message_number ;
int oldMode ;
int dividerStep ;
int xoffset ;
int yoffset ;
char **message = first_message ;
bool erased = false ;
RECT rect ;
HPEN hpen1 ;
HPEN hpen2 ;
HPEN hpenOld ;
HFONT oldFont ;
COLORREF oldColour ;
COLORREF oldBkColour ;
unsigned char lastType = 255;
static RECT oldRect ;
EnterCriticalSection (&critical_section) ;
GetClientRect (message_window, &rect) ;
current_rect.left = 0 ;
current_rect.right = rect.right ;
current_rect.top = -message_ychar ;
current_rect.bottom = 0 ;
xoffset = (unsigned) message_scroll_pos_x * message_xchar ;
yoffset = (unsigned) (first_message - message_buffer) * message_ychar ;
if (*message == NULL || resizing || (EditGetFlags () & EDIT_DRAG_ACTIVE) != 0)
{
erase_display_window (hdc, xoffset, yoffset) ;
LeaveCriticalSection (&critical_section) ;
oldRect = rect ;
return ;
}
oldRect = rect ;
if (tile_background)
{
hpen1 = CreatePen (PS_SOLID, 1, RGB (192,192,192)) ;
hpen2 = CreatePen (PS_SOLID, 1, RGB (64,64,64)) ;
}
else
{
int red = background_colour & 0xff;
int green = (background_colour >> 8) & 0xff;
int blue = (background_colour >> 16) & 0xff;
hpen1 = CreatePen (PS_SOLID, 1, text_colours[0]) ;
hpen2 = CreatePen (PS_SOLID, 1, RGB(red / 2, green / 2, blue / 2)) ;
}
hpenOld = (HPEN) SelectObject (hdc, hpen2) ;
oldFont = (HFONT) SelectObject (hdc, message_font) ;
oldMode = SetBkMode (hdc, TRANSPARENT) ;
oldColour = SetTextColor (hdc, text_colours[0]) ;
oldBkColour = SetBkColor (hdc, background_shade) ;
x = message_scroll_pos_x * -message_xchar + message_xchar ;
for (message_number = y = 0 ; y < rect.bottom ; message_number++)
{
if (*message == NULL)
break ;
if (message_number >= message_scroll_pos_y)
{
if (!erased)
{
erase_display_window (hdc, xoffset, yoffset) ;
erased = true ;
}
if (**message != lastType)
{
lastType = **message;
switch (**message)
{
case mDebug:
case mWarning:
SetTextColor (hdc, text_colours[1]);
break;
case mFatal:
SetTextColor (hdc, text_colours[2]);
break;
default:
SetTextColor (hdc, text_colours[0]);
break;
}
}
current_rect.top += message_ychar ;
current_rect.bottom += message_ychar ;
if (**message == mDivider || **message == mHorzLine)
{
if (background_shade != RGB (1, 1, 1) && tile_background)
DRAWFASTRECT (hdc, ¤t_rect) ;
SelectObject (hdc, hpen2) ;
if (tile_background)
{
dividerStep = message_ychar / 3;
MoveToEx (hdc, current_rect.left + message_xchar, y + message_ychar - dividerStep, NULL) ;
LineTo (hdc, current_rect.left + message_xchar, y + dividerStep) ;
LineTo (hdc, current_rect.right - message_xchar, y + dividerStep) ;
SelectObject (hdc, hpen1) ;
LineTo (hdc, current_rect.right - message_xchar, y + message_ychar - dividerStep) ;
LineTo (hdc, current_rect.left + message_xchar, y + message_ychar - dividerStep) ;
}
else
{
MoveToEx (hdc, current_rect.left + message_xchar, y + message_ychar / 2, NULL) ;
LineTo (hdc, current_rect.right - message_xchar, y + message_ychar / 2) ;
SelectObject (hdc, hpen1) ;
MoveToEx (hdc, current_rect.left + message_xchar, y + message_ychar / 2 + 1, NULL) ;
LineTo (hdc, current_rect.right - message_xchar, y + message_ychar / 2 + 1) ;
}
}
else
ExtTextOut (hdc, x, y, ETO_CLIPPED, ¤t_rect, *message + 1, (int) strlen (*message + 1), NULL) ;
y += message_ychar ;
}
if (message == last_message)
break ;
if (++message == message_buffer + MAX_MESSAGE)
message = message_buffer ;
yoffset += message_ychar ;
}
if (!erased)
erase_display_window (hdc, xoffset, yoffset) ;
SetTextColor (hdc, oldColour) ;
SetBkColor (hdc, oldBkColour) ;
SetBkMode (hdc, oldMode) ;
SelectObject (hdc, oldFont) ;
SelectObject (hdc, hpenOld) ;
DeleteObject (hpen1) ;
DeleteObject (hpen2) ;
LeaveCriticalSection (&critical_section) ;
}
void get_logfont (HDC hdc, LOGFONT *lf)
{
memset (lf, 0, sizeof (LOGFONT)) ;
lf->lfHeight = -MulDiv (message_font_size, GetDeviceCaps (hdc, LOGPIXELSY), 72) ;
lf->lfWeight = message_font_weight ;
lf->lfPitchAndFamily = FIXED_PITCH | FF_MODERN ;
lf->lfCharSet = DEFAULT_CHARSET ;
lf->lfQuality = PROOF_QUALITY ;
strncpy (lf->lfFaceName, message_font_name, sizeof (lf->lfFaceName) - 1) ;
}
void get_lblogfont (HDC hdc, LOGFONT *lf)
{
memset (lf, 0, sizeof (LOGFONT)) ;
lf->lfHeight = -MulDiv (listbox_font_size, GetDeviceCaps (hdc, LOGPIXELSY), 72) ;
lf->lfWeight = listbox_font_weight ;
lf->lfPitchAndFamily = FIXED_PITCH | FF_MODERN ;
lf->lfCharSet = DEFAULT_CHARSET ;
lf->lfQuality = PROOF_QUALITY ;
strncpy (lf->lfFaceName, listbox_font_name, sizeof (lf->lfFaceName) - 1) ;
}
int create_message_font (HDC hdc, LOGFONT *lf)
{
HFONT hfontOld ;
TEXTMETRIC tm ;
if ((message_font = CreateFontIndirect (lf)) == NULL)
return (1) ;
hfontOld = (HFONT) SelectObject (hdc, message_font) ;
GetTextMetrics (hdc, &tm) ;
message_xchar = tm.tmAveCharWidth ;
message_ychar = tm.tmHeight + tm.tmExternalLeading ;
SelectObject (hdc, hfontOld) ;
return (0) ;
}
int create_listbox_font (HDC hdc, LOGFONT *lf)
{
HFONT hfontOld ;
TEXTMETRIC tm ;
if ((listbox_font = CreateFontIndirect (lf)) == NULL)
return (1) ;
hfontOld = (HFONT)SelectObject (hdc, listbox_font) ;
GetTextMetrics (hdc, &tm) ;
listbox_xchar = tm.tmAveCharWidth ;
listbox_ychar = tm.tmHeight + tm.tmExternalLeading ;
SelectObject (hdc, hfontOld) ;
return (0) ;
}
int initialise_message_display (void)
{
HDC hdc ;
LOGFONT lf ;
if (message_window == NULL)
{
PovMessageBox ("Message Window does not exist", "Initialize Message Display - Fatal Error") ;
return (1) ;
}
hdc = GetDC (message_window) ;
get_logfont (hdc, &lf) ;
if (create_message_font (hdc, &lf) != 0)
{
PovMessageBox ("Failed to create message font", "Initialize Message Display - Fatal Error") ;
ReleaseDC (message_window, hdc) ;
return (1) ;
}
get_lblogfont (hdc, &lf) ;
if (create_listbox_font (hdc, &lf) != 0)
{
strcpy (lf.lfFaceName, "Courier New") ;
if (create_listbox_font (hdc, &lf) != 0)
PovMessageBox ("Failed to create listbox font", "Initialize Message Display") ;
}
first_message = next_message = message_buffer ;
last_message = NULL ;
buffer_str (NULL, NULL) ;
top_message_row = message_count = message_scroll_pos_x = message_scroll_pos_y = 0 ;
current_rect.left = current_rect.bottom = current_rect.right = 0 ;
current_rect.top = -message_ychar ;
ReleaseDC (message_window, hdc) ;
return (0) ;
}
void clear_messages (bool print)
{
int i ;
char **p ;
EnterCriticalSection (&critical_section) ;
buffer_str (NULL, NULL) ;
// free any buffered lines still around from a previous run of the renderer
for (p = message_buffer, i = 0 ; i < MAX_MESSAGE ; p++, i++)
{
if (*p)
free (*p) ;
*p = NULL ;
}
first_message = next_message = message_buffer ;
last_message = NULL ;
top_message_row = message_count = message_scroll_pos_x = message_scroll_pos_y = 0 ;
current_rect.left = current_rect.bottom = current_rect.right = 0 ;
current_rect.top = -message_ychar ;
LeaveCriticalSection (&critical_section) ;
if (print)
message_printf ("Messages cleared.\n") ;
}
int need_hscroll (void)
{
int x ;
int xchars ;
int width = 0 ;
char **message = first_message ;
RECT rect ;
/* modified to return the scroll range if ANY line is long enough */
if (message_window == NULL || *message == NULL)
return (0) ;
GetClientRect (message_window, &rect) ;
xchars = rect.right / message_xchar - 1 ;
while (*message)
{
x = (int) strlen (*message + 1) ;
if (x >= xchars)
if (x - xchars > width)
width = x - xchars ;
if (message == next_message)
break ;
if (++message == message_buffer + MAX_MESSAGE)
message = message_buffer ;
}
return (width) ;
}
bool copy_text_to_clipboard(const char *text)
{
char *s ;
HGLOBAL hText ;
if (!OpenClipboard(NULL))
return false;
if ((hText = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, strlen(text) + 1)) == NULL)
return false;
if ((s = (char *) GlobalLock (hText)) == NULL)
{
GlobalFree(hText);
return false;
}
strcpy(s, text);
GlobalUnlock(hText);
EmptyClipboard() ;
bool result = SetClipboardData(CF_TEXT, hText) != NULL;
CloseClipboard() ;
return result;
}
void dump_pane_to_clipboard (void)
{
int y ;
int message_number ;
int length = 0 ;
char **message = first_message ;
char *s ;
RECT rect ;
HGLOBAL hText ;
static char *_s ;
if (message_window == NULL || *message == NULL)
return ;
if (OpenClipboard (message_window) == false)
{
PovMessageBox ("Could not open clipboard", "Error") ;
return ;
}
if ((hText = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, 33000)) == NULL)
return ;
if ((s = (char *) GlobalLock (hText)) == NULL)
{
GlobalFree(hText);
CloseClipboard () ;
return ;
}
_s = s ;
GetClientRect (message_window, &rect) ;
for (message_number = y = 0 ; y < rect.bottom ; message_number++)
{
if (*message == NULL)
break ;
if (message_number >= message_scroll_pos_y)
{
length += (int) strlen (*message + 1) + 2 ;
if (length >= 32767)
break ;
s += sprintf (s, "%s\r\n", *message + 1) ;
y += message_ychar ;
}
if (++message == message_buffer + MAX_MESSAGE)
message = message_buffer ;
if (message == next_message)
break ;
}
GlobalUnlock (hText) ;
GlobalReAlloc (hText, length + 1, GMEM_MOVEABLE | GMEM_DDESHARE) ;
EmptyClipboard () ;
SetClipboardData (CF_TEXT, hText) ;
CloseClipboard () ;
}
void draw_ordinary_listbox (DRAWITEMSTRUCT *d, bool fitpath)
{
int oldMode ;
int dividerStep ;
int width ;
int length ;
char str [MAX_PATH] ;
RECT rect ;
HPEN hpen1 ;
HPEN hpen2 ;
HPEN hpenOld ;
HFONT oldFont ;
COLORREF oldBackground ;
COLORREF oldForeground ;
if (d->itemID == -1)
return ;
hpen1 = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNHIGHLIGHT)) ;
hpen2 = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNSHADOW)) ;
hpenOld = (HPEN) SelectObject (d->hDC, hpen2) ;
oldFont = (HFONT) SelectObject (d->hDC, listbox_font) ;
oldMode = SetBkMode (d->hDC, TRANSPARENT) ;
oldForeground = SetTextColor (d->hDC, GetSysColor (d->itemState & ODS_SELECTED ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)) ;
oldBackground = SetBkColor (d->hDC, GetSysColor (d->itemState & ODS_SELECTED ? COLOR_HIGHLIGHT : COLOR_WINDOW)) ;
dividerStep = listbox_ychar / 2 - 1 ;
rect = d->rcItem ;
rect.left += listbox_xchar ;
rect.right -= listbox_xchar ;
width = (rect.right - rect.left) / listbox_xchar ;
SendMessage (d->hwndItem, LB_GETTEXT, d->itemID, (LPARAM) str) ;
if (strncmp (str, "----------------", 16) == 0)
{
MoveToEx (d->hDC, rect.left, rect.top + listbox_ychar - dividerStep, NULL) ;
SelectObject (d->hDC, hpen2) ;
LineTo (d->hDC, rect.left, rect.top + dividerStep) ;
LineTo (d->hDC, rect.right - listbox_xchar, rect.top + dividerStep) ;
SelectObject (d->hDC, hpen1) ;
LineTo (d->hDC, rect.right - listbox_xchar, rect.top + listbox_ychar - dividerStep) ;
LineTo (d->hDC, rect.left, rect.top + listbox_ychar - dividerStep) ;
}
else
{
if (fitpath)
{
length = (int) strlen (str) ;
if (length > width)
{
if (str [1] == ':' && isPathSeparator(str [2]))
{
memcpy (str + 3, "...", 3) ;
strcpy (str + 6, str + length - width + 6) ;
}
}
}
ExtTextOut (d->hDC, rect.left, rect.top, ETO_CLIPPED | ETO_OPAQUE, &rect, str, (int) strlen (str), NULL) ;
}
SetBkColor (d->hDC, oldBackground) ;
SetTextColor (d->hDC, oldForeground) ;
SetBkMode (d->hDC, oldMode) ;
SelectObject (d->hDC, oldFont) ;
SelectObject (d->hDC, hpenOld) ;
DeleteObject (hpen1) ;
DeleteObject (hpen2) ;
}
void write_wrapped_text (HDC hdc, RECT *rect, const char *text)
{
int oldMode ;
HFONT hFont ;
HFONT hFontOld ;
LOGFONT lf ;
COLORREF oldForeground ;
memset (&lf, 0, sizeof (LOGFONT)) ;
lf.lfHeight = -MulDiv (8, GetDeviceCaps (hdc, LOGPIXELSY), 72) ;
lf.lfWeight = FW_NORMAL ;
lf.lfPitchAndFamily = VARIABLE_PITCH ;
lf.lfCharSet = DEFAULT_CHARSET ;
strcpy (lf.lfFaceName, "MS Sans Serif") ;
if ((hFont = CreateFontIndirect (&lf)) != NULL)
{
hFontOld = (HFONT) SelectObject (hdc, hFont) ;
oldMode = SetBkMode (hdc, TRANSPARENT) ;
oldForeground = SetTextColor (hdc, RGB (0, 0, 0)) ;
DrawText (hdc, text, -1, rect, DT_WORDBREAK | DT_EXPANDTABS) ;
SetTextColor (hdc, oldForeground) ;
SetBkMode (hdc, oldMode) ;
SelectObject (hdc, hFontOld) ;
DeleteObject (hFont) ;
}
}
void tip_of_the_day (HDC hdc, RECT *rect, char *text)
{
int oldMode ;
RECT rc ;
HFONT hFont ;
HFONT hFontOld ;
LOGFONT lf ;
COLORREF oldForeground ;
rc = *rect ;
memset (&lf, 0, sizeof (LOGFONT)) ;
lf.lfHeight = -MulDiv (9, GetDeviceCaps (hdc, LOGPIXELSY), 72) ;
lf.lfWeight = FW_BOLD ;
lf.lfPitchAndFamily = VARIABLE_PITCH ;
lf.lfCharSet = DEFAULT_CHARSET ;
strcpy (lf.lfFaceName, "MS Sans Serif") ;
if ((hFont = CreateFontIndirect (&lf)) != NULL)
{
// hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_BULB)) ;
// DrawIcon (hdc, rc.left, rc.top, hIcon) ;
// DestroyIcon (hIcon) ;
hFontOld = (HFONT) SelectObject (hdc, hFont) ;
oldMode = SetBkMode (hdc, TRANSPARENT) ;
oldForeground = SetTextColor (hdc, RGB (0, 0, 0)) ;
ExtTextOut (hdc, rc.left, rc.top, ETO_CLIPPED, &rc, "Did you know ... ? ", 19, NULL) ;
rc.top += 25 ;
SetTextColor (hdc, oldForeground) ;
SetBkMode (hdc, oldMode) ;
SelectObject (hdc, hFontOld) ;
DeleteObject (hFont) ;
write_wrapped_text (hdc, &rc, text) ;
}
}
void handle_menu_select (WPARAM wParam, LPARAM lParam)
{
char str [128] ;
static int nLastID = -1 ;
wParam = LOWORD (wParam) ;
if (wParam != nLastID)
{
nLastID = wParam ;
if (wParam >= CM_FIRSTGUIEXT && wParam <= CM_LASTGUIEXT)
{
say_status_message (StatusMessage, ExternalMenuTip (wParam)) ;
return ;
}
if (wParam < CM_FIRSTTOOL || wParam > CM_LASTTOOL)
{
if (LoadString (hInstance, wParam, str, sizeof (str)) != 0)
say_status_message (StatusMessage, str) ;
else
say_status_message (StatusMessage, "") ;
}
else
say_status_message (StatusMessage, tool_help [wParam - CM_FIRSTTOOL]) ;
}
}
void resize_windows (unsigned left, unsigned top, unsigned width, unsigned height)
{
MoveWindow (message_window, left, top, width, height, false) ;
}
FILE *editor_stream_init (void)
{
editor_line_number = 0 ;
editor_char_pos = 0 ;
editor_offset = 0 ;
seek_entry_count = 0 ;
line_buffer [0] = '\0' ;
return (POV_INTERNAL_STREAM) ;
}
int editor_ftell (void)
{
if (seek_entry_count >= MAX_SEEK_INDEX)
{
PovMessageBox ("Seek index overflow ; render scene from outside editor", "Error") ;
if (!quit)
quit = time (NULL) ;
return (-1) ;
}
if (editor_char_pos)
{
seek_entries [seek_entry_count].Line = editor_line_number ;
seek_entries [seek_entry_count++].Offset = editor_char_pos - 1 ;
}
seek_entries [seek_entry_count].Line = editor_line_number ;
seek_entries [seek_entry_count].Offset = editor_char_pos ;
return (seek_entry_count++) ;
}
int editor_fseek (long offset, int whence)
{
if (whence != 0)
return (-1) ;
editor_line_number = seek_entries [offset].Line ;
editor_char_pos = seek_entries [offset].Offset ;
// FIXME
//if (Edit.GetLine (CurrentEditor, editor_line_number, line_buffer, sizeof (line_buffer) - 1) == false)
//{
// PovMessageBox ("Seek index error ; render scene from outside editor", "Error") ;
// if (!quit)
// quit = time (NULL) ;
// return (-1) ;
//}
return (0) ;
}
int editor_getc (void)
{
if (line_buffer [editor_char_pos] == '\0')
{
// FIXME
// if (Edit.GetLine (CurrentEditor, ++editor_line_number, line_buffer, sizeof (line_buffer) - 2) == false)
// return (EOF) ;
editor_char_pos = 0 ;
strcat (line_buffer, "\n") ;
}
return (line_buffer [editor_char_pos++]) ;
}
FILE *pov_fopen (const char *filename, const char *mode)
{
if (filename == NULL)
return (editor_stream_init ()) ;
else
return (fopen (filename, mode)) ;
}
int pov_fclose (FILE *stream)
{
if (stream != POV_INTERNAL_STREAM)
return (fclose (stream)) ;
else
return (0) ;
}
int pov_getc (FILE *stream)
{
return (stream == POV_INTERNAL_STREAM ? editor_getc () : getc (stream)) ;
}
int pov_fseek (FILE *stream, long offset, int whence)
{
return (stream == POV_INTERNAL_STREAM ? editor_fseek (offset, whence) : fseek (stream, offset, whence)) ;
}
int pov_ftell (FILE *stream)
{
return (stream == POV_INTERNAL_STREAM ? editor_ftell () : ftell (stream)) ;
}
void add_edit_file (char *file)
{
if (strlen (file) == 0)
{
PovMessageBox ("Empty filename after /EDIT", "Edit File") ;
return ;
}
if (EditFileCount == MAX_EDIT_FILES)
return ;
if (strpbrk (file, "*?") != NULL)
{
PovMessageBox ("Filename may not contain wildcards", "Edit File") ;
return ;
}
EditFiles [EditFileCount++] = _strdup (file) ;
}
void add_render_file (char *file)
{
static bool first = true ;
if (strlen (file) == 0)
{
PovMessageBox ("Empty filename after /RENDER", "Render File") ;
return ;
}
if (!first)
{
PovMessageBox ("Only one /RENDER file may be specified", "Render File") ;
return ;
}
if (strpbrk (file, "*?") != NULL)
{
PovMessageBox ("Filename may not contain wildcards", "Render File") ;
return ;
}
first = false ;
strcpy (requested_render_file, file) ;
render_requested = true ;
}
char *extract_file (char *filename, char *s)
{
bool startsWithQuote = false ;
bool inDoubleQuote = false ;
while (*s == ' ' || *s == '\t')
s++ ;
// a single quote is a legitimate part of a filename under windows, so we
// treat it as a special case only if the first character is one.
if (*s == '\'')
{
startsWithQuote = true;
s++;
}
while (*s)
{
switch (*s)
{
case '"' :
if (inDoubleQuote)
{
*filename = '\0' ;
return (++s) ;
}
inDoubleQuote = true ;
break ;
case '\'' :
if (startsWithQuote && (s[1] == ' ' || s[1] == '\t' || s[1] == '\0'))
{
*filename = '\0' ;
return (++s) ;
}
*filename++ = *s ;
break ;
case ' ' :
case '\t' :
if (!inDoubleQuote && !startsWithQuote)
{
*filename = '\0' ;
return (s) ;
}
*filename++ = *s ;
break ;
default :
*filename++ = *s ;
break ;
}
s++ ;
}
*filename = '\0' ;
return (s) ;
}
char *preparse_commandline (char *s)
{
char *out ;
char *command ;
char last = ' ' ;
char commandstr [256] ;
char filename [_MAX_PATH] ;
static char outstr [_MAX_PATH * 3] ;
out = outstr ;
while (*s)
{
if (*s == '/' && (last == ' ' || last == '\t'))
{
command = commandstr ;
while (*++s)
{
if (*s == ' ' || *s == '\t')
break ;
*command++ = *s ;
}
*command = '\0' ;
last = *s ;
if (strlen (commandstr) == 0)
{
PovMessageBox ("Empty command on commandline", "Commandline processing error") ;
return (NULL) ;
}
if (_stricmp (commandstr, "EXIT") == 0)
{
exit_after_render = true ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "DEMO") == 0)
{
demo_mode = true ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "DEBUG") == 0)
{
debugging = true ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "EDIT") == 0)
{
s = extract_file (filename, s) ;
add_edit_file (filename) ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "RENDER") == 0)
{
s = extract_file (filename, s) ;
add_render_file (filename) ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "EDITDLLPATH") == 0)
{
s = extract_file (filename, s) ;
appendPathSeparator (filename);
EditDLLPath = _strdup(filename);
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "NOEXEC") == 0)
{
noexec = true ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "NORESTORE") == 0 || _stricmp (commandstr, "NR") == 0)
{
NoRestore = true ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "THREADS") == 0)
{
int n ;
while (*s == ' ')
s++ ;
if (sscanf (s, "%d", &n) != 1)
{
PovMessageBox ("Invalid numerical value following '/THREADS'", "Commandline processing error") ;
return (NULL) ;
}
if (n < 1 || n > 255)
{
PovMessageBox ("Invalid value for thread count (range 1-255)", "Commandline processing error") ;
return (NULL) ;
}
ThreadCount = n ;
while (isdigit (*s))
s++ ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "BENCHMARK") == 0)
{
benchmark_mode = true ;
while (*s == ' ')
s++ ;
continue ;
}
#ifdef POVMS_NETWORK_SUPPORT
if (_stricmp (commandstr, "LISTEN") == 0)
{
ListenMode = true ;
s = extract_file (NetworkAddress, s) ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "CONTROL") == 0)
{
ControlMode = true ;
s = extract_file (NetworkAddress, s) ;
while (*s == ' ')
s++ ;
continue ;
}
#endif
sprintf (outstr, "Unrecognized command '%s' on commandline", commandstr) ;
PovMessageBox (outstr, "Commandline processing error") ;
return (NULL) ;
}
last = *out++ = *s++ ;
}
return (outstr) ;
}
char *preparse_instance_commandline (char *s)
{
char *out ;
char *command ;
char last = ' ' ;
char commandstr [256] ;
char filename [_MAX_PATH] ;
static char outstr [_MAX_PATH * 3] ;
out = outstr ;
while (*s)
{
if (*s == '/' && (last == ' ' || last == '\t'))
{
command = commandstr ;
while (*++s)
{
if (*s == ' ' || *s == '\t')
break ;
*command++ = *s ;
}
*command = '\0' ;
last = *s ;
if (strlen (commandstr) == 0)
{
PovMessageBox ("Empty command on commandline", "Commandline processing error") ;
return (NULL) ;
}
if (_stricmp (commandstr, "EXIT") == 0)
{
PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
return (NULL) ;
}
if (_stricmp (commandstr, "DEMO") == 0)
{
PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
return (NULL) ;
}
if (_stricmp (commandstr, "DEBUG") == 0)
{
PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
return (NULL) ;
}
if (_stricmp (commandstr, "NOEXEC") == 0)
{
PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
return (NULL) ;
}
if (_stricmp (commandstr, "THREADS") == 0)
{
PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
return (NULL) ;
}
if (_stricmp (commandstr, "EDIT") == 0)
{
s = extract_file (filename, s) ;
add_edit_file (filename) ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "RENDER") == 0)
{
s = extract_file (filename, s) ;
add_render_file (filename) ;
while (*s == ' ')
s++ ;
continue ;
}
if (_stricmp (commandstr, "NORESTORE") == 0 || _stricmp (commandstr, "NR") == 0)
{
while (*s == ' ')
s++ ;
continue ;
}
sprintf (outstr, "Unrecognized command '%s' on commandline", commandstr) ;
PovMessageBox (outstr, "Commandline processing error") ;
return (NULL) ;
}
last = *out++ = *s++ ;
}
return (outstr) ;
}
INT_PTR CALLBACK PovStatusPanelDialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
HWND create_toolbar (HWND hwndParent)
{
int fontWidth ;
int fontHeight ;
HDC hdc ;
HWND hwnd ;
RECT rect ;
HFONT hFontOld ;
HFONT hParentFont ;
HBITMAP hbmp ;
TBBUTTON main_tbb [MAX_MAIN_TOOLS] ;
TBBUTTON aux_tbb [MAX_AUX_TOOLS] ;
TBBUTTON *dt ;
TEXTMETRIC tm ;
toolbarStruct *st ;
REBARBANDINFO rbBand ;
hParentFont = (HFONT) SendMessage (hwndParent, WM_GETFONT, 0, 0) ;
hdc = GetDC (hwndParent) ;
hFontOld = (HFONT) SelectObject (hdc, hParentFont) ;
GetTextMetrics (hdc, &tm) ;
SelectObject (hdc, hFontOld) ;
ReleaseDC (hwndParent, hdc) ;
fontWidth = tm.tmAveCharWidth ;
fontHeight = tm.tmHeight ;
toolbar_combobox_width = fontWidth * 30 ;
toolbar_cmdline_width = fontWidth * 20 ;
// Initialize REBARBANDINFO for all rebar bands
rbBand.cbSize = sizeof (REBARBANDINFO) ;
rbBand.clrFore = GetSysColor (COLOR_BTNTEXT) ;
rbBand.clrBack = GetSysColor (COLOR_BTNFACE) ;
rbBand.hbmBack = LoadBitmap (hInstance, MAKEINTRESOURCE (BMP_REBAR)) ;
hwnd = CreateWindow (TOOLBARCLASSNAME,
"",
WS_CHILD | WS_VISIBLE | CCS_TOP | TBSTYLE_TOOLTIPS |
TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | WS_CLIPCHILDREN |
WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_ADJUSTABLE,
0,
0,
256,
50,
hwndParent,
NULL,
hInstance,
NULL) ;
if (hwnd == NULL)
return (NULL) ;
SendMessage (hwnd, TB_BUTTONSTRUCTSIZE, sizeof (TBBUTTON), 0) ;
SendMessage (hwnd, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG (38, 21)) ;
SendMessage (hwnd, TB_SETBUTTONSIZE, 0, (LPARAM) MAKELONG (38, 21)) ;
if ((ToolImages1 = ImageList_Create (38, 21, (screen_depth < 8 ? ILC_COLOR4 : ILC_COLOR24) | ILC_MASK, 0, 16)) == NULL)
return (NULL) ;
for (dt = main_tbb, st = maintools ; st->text != NULL ; st++, dt++)
{
dt->iBitmap = ImageList_AddMasked (ToolImages1, hbmp = LoadBitmap (hInstance, MAKEINTRESOURCE (st->resid)), RGB (255, 0, 255)) ;
dt->iString = SendMessage (hwnd, TB_ADDSTRING, 0, (LPARAM) st->text) ;
dt->idCommand = st->id ;
dt->fsState = TBSTATE_ENABLED ;
dt->fsStyle = st->flags & 0x01 ? TBSTYLE_CHECK : TBSTYLE_BUTTON ;
dt->fsState = st->flags & 0x02 ? TBSTATE_HIDDEN | TBSTATE_ENABLED : TBSTATE_ENABLED ;
dt->dwData = 0 ;
DeleteObject (hbmp) ;
}
SendMessage (hwnd, TB_SETIMAGELIST, 0, (LPARAM) ToolImages1) ;
SendMessage (hwnd, TB_ADDBUTTONS, MAX_MAIN_TOOLS, (LPARAM) main_tbb) ;
SendMessage (hwnd, TB_AUTOSIZE, 0, 0) ;
rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_GRIPPERALWAYS ;
rbBand.hwndChild = hwnd ;
SendMessage (hwnd, TB_GETITEMRECT, MAX_MAIN_TOOLS - 1, (LPARAM) &rect) ;
rbBand.cxMinChild = 1 ;
rbBand.cyMinChild = rect.bottom ;
rbBand.cx = rect.right + 15 ;
rbBand.wID = 0 ;
SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) (LPREBARBANDINFO) &rbBand) ;
DeleteObject (hbmp) ;
statuspanel = CreateDialog (hInstance, MAKEINTRESOURCE (IDD_STATUSPANEL), hwnd, PovStatusPanelDialogProc) ;
rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDSIZE ;
rbBand.hwndChild = statuspanel ;
rbBand.cx = 200 ;
rbBand.cxMinChild = 200 ;
rbBand.cyMinChild = 42 ;
rbBand.wID++;
SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) (LPREBARBANDINFO) &rbBand) ;
toolbar_combobox = CreateWindow ("COMBOBOX", // WC_COMBOBOXEX,
"",
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NORESIZE,
0,
0,
toolbar_combobox_width,
fontHeight * 20,
hwndParent,
NULL,
hInstance,
NULL) ;
SendMessage (toolbar_combobox, WM_SETFONT, (WPARAM) hParentFont, true) ;
rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_GRIPPERALWAYS | RBBS_BREAK ;
rbBand.hwndChild = toolbar_combobox ;
GetWindowRect (toolbar_combobox, &rect) ;
rbBand.cx = rect.right - rect.left ;
rbBand.cxMinChild = rbBand.cx / 2 ;
rbBand.cyMinChild = rect.bottom - rect.top ;
rbBand.wID++;
if (bandWidths[rbBand.wID] > 10)
rbBand.cx = bandWidths[rbBand.wID] ;
SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) (LPREBARBANDINFO) &rbBand) ;
toolbar_cmdline = CreateWindowEx (WS_EX_CLIENTEDGE,
"EDIT",
"",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
0,
0,
toolbar_cmdline_width + GetSystemMetrics (SM_CXEDGE) * 2,
fontHeight + GetSystemMetrics (SM_CYEDGE) * 2 + 3,
hwndParent,
NULL,
hInstance,
NULL) ;
SendMessage (toolbar_cmdline, EM_LIMITTEXT, _MAX_PATH, 0) ;
SendMessage (toolbar_cmdline, WM_SETFONT, (WPARAM) hParentFont, true) ;
GetWindowRect (toolbar_cmdline, &rect) ;
rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_GRIPPERALWAYS ;
rbBand.hwndChild = toolbar_cmdline ;
rbBand.cx = rect.right - rect.left ;
rbBand.cxMinChild = rbBand.cx / 2 ;
rbBand.cyMinChild = rect.bottom - rect.top ;
rbBand.wID++;
if (bandWidths[rbBand.wID] > 10)
rbBand.cx = bandWidths[rbBand.wID] ;
SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) &rbBand) ;
HWND tt ;
if ((tt = (HWND) SendMessage (hwnd, TB_GETTOOLTIPS, 0, 0)) != NULL)
{
// we borrow the toolbar's tooltip rather than create a new one
TOOLINFO ti ;
memset (&ti, 0, sizeof (TOOLINFO)) ;
ti.cbSize = sizeof (TOOLINFO) ;
ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
ti.hwnd = hwndParent ;
ti.uId = (UINT_PTR) toolbar_cmdline ;
ti.lpszText = "Command line (overrides preset render options)" ;
SendMessage (tt, TTM_ADDTOOL, 0, (LPARAM) &ti) ;
ti.uId = (UINT_PTR) toolbar_combobox ;
ti.lpszText = "Preset render options" ;
SendMessage (tt, TTM_ADDTOOL, 0, (LPARAM) &ti) ;
}
aux_toolbar_window = CreateWindow (TOOLBARCLASSNAME,
"",
WS_CHILD | WS_VISIBLE | CCS_TOP | TBSTYLE_TOOLTIPS |
TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE,
0,
0,
256,
50,
hwndParent,
NULL,
hInstance,
NULL) ;
if (aux_toolbar_window == NULL)
return (NULL) ;
SendMessage (aux_toolbar_window, TB_BUTTONSTRUCTSIZE, sizeof (TBBUTTON), 0) ;
SendMessage (aux_toolbar_window, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG (14, 14)) ;
SendMessage (aux_toolbar_window, TB_SETBUTTONSIZE, 0, (LPARAM) MAKELONG (14, 14)) ;
if ((ToolImages2 = ImageList_Create (14, 14, (screen_depth < 8 ? ILC_COLOR4 : ILC_COLOR24) | ILC_MASK, 0, 8)) == NULL)
return (hwnd) ;
for (dt = aux_tbb, st = auxtools ; st->text != NULL ; st++, dt++)
{
dt->iBitmap = ImageList_AddMasked (ToolImages2, hbmp = LoadBitmap (hInstance, MAKEINTRESOURCE (st->resid)), RGB (255, 0, 255)) ;
dt->iString = SendMessage (aux_toolbar_window, TB_ADDSTRING, 0, (LPARAM) st->text) ;
dt->idCommand = st->id ;
dt->fsState = TBSTATE_ENABLED ;
dt->fsStyle = st->flags & 0x01 ? TBSTYLE_CHECK : TBSTYLE_BUTTON ;
dt->dwData = 0 ;
DeleteObject (hbmp) ;
}
SendMessage (aux_toolbar_window, TB_SETIMAGELIST, 0, (LPARAM) ToolImages2) ;
SendMessage (aux_toolbar_window, TB_ADDBUTTONS, MAX_AUX_TOOLS, (LPARAM) aux_tbb) ;
SendMessage (aux_toolbar_window, TB_AUTOSIZE, 0, 0) ;
rbBand.fMask = RBBIM_COLORS | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE ;
rbBand.fStyle = RBBS_NOVERT | RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_GRIPPERALWAYS ;
rbBand.hwndChild = aux_toolbar_window ;
SendMessage (aux_toolbar_window, TB_GETITEMRECT, MAX_AUX_TOOLS - 1, (LPARAM) &rect) ;
rbBand.cxMinChild = 1 ;
rbBand.cyMinChild = rect.bottom ;
rbBand.cx = rect.right + 15 ;
rbBand.wID++;
if (bandWidths[rbBand.wID] > 10)
rbBand.cx = bandWidths[rbBand.wID] ;
SendMessage (hwndParent, RB_INSERTBAND, (UINT) -1, (LPARAM) (LPREBARBANDINFO) &rbBand) ;
return (hwnd) ;
}
HWND create_rebar (HWND hwndParent)
{
HWND hwnd ;
INITCOMMONCONTROLSEX icex ;
icex.dwSize = sizeof (INITCOMMONCONTROLSEX) ;
icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES ;
InitCommonControlsEx (&icex) ;
hwnd = CreateWindowEx (0L,
REBARCLASSNAME,
NULL,
WS_VISIBLE | WS_BORDER | WS_CHILD | WS_CLIPCHILDREN |
/*CCS_NOPARENTALIGN |*/ CCS_NODIVIDER | WS_CLIPSIBLINGS |
RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_DBLCLKTOGGLE,
0,
0,
800,
128,
hwndParent,
(HMENU) ID_REBAR,
hInstance,
NULL) ;
return (hwnd) ;
}
HWND CreateStatusbar (HWND hwndParent)
{
HWND hwnd ;
RECT rect ;
hwnd = CreateWindowEx (0L,
STATUSCLASSNAME,
NULL,
WS_CHILD | SBARS_SIZEGRIP | WS_VISIBLE,
0,
0,
0,
0,
hwndParent,
(HMENU) ID_STATUS,
hInstance,
NULL) ;
GetClientRect (hwnd, &rect) ;
statusheight = rect.bottom - rect.top ;
StatusTooltip = CreateWindowEx(NULL,
TOOLTIPS_CLASS,
NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hwndParent,
NULL,
hInstance,
NULL);
SetWindowPos(StatusTooltip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
memset (&sbToolInfo, 0, sizeof (TOOLINFO)) ;
sbToolInfo.cbSize = sizeof (TOOLINFO) ;
sbToolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
sbToolInfo.hwnd = hwndParent ;
sbToolInfo.uId = (UINT_PTR) hwnd ;
sbToolInfo.lpszText = LPSTR_TEXTCALLBACK;
SendMessage (StatusTooltip, TTM_ADDTOOL, 0, (LPARAM) &sbToolInfo) ;
return (hwnd) ;
}
// should really query the statusbar and get the font size, then
// work out the section sizes from that.
void ResizeStatusBar (HWND hwnd)
{
int parts [] = {0, 0, 0, 0, 0, 0, 0, 0} ;
int i ;
int total = 0 ;
RECT rect ;
static const int widths [] = {0, 65, 50, 50, 50, 50, 95, 135} ;
static const int all = 495 ;
GetClientRect (hwnd, &rect) ;
rect.right -= all ;
for (i = 0 ; i < sizeof (parts) / sizeof (int) ; i++)
{
total += widths [i] ;
parts [i] = total + rect.right ;
}
SendMessage (hwnd, SB_SETPARTS, sizeof (parts) / sizeof (int), (LPARAM) parts) ;
}
bool HandleStatusTooltip(NMHDR *nmh)
{
int parts[32];
int count;
int off;
char str[512];
char *s;
RECT rect ;
POINT pos;
NMTTDISPINFO *di;
switch (nmh->code)
{
case TTN_NEEDTEXT :
di = (NMTTDISPINFO *) nmh;
if ((count = SendMessage(StatusWindow, SB_GETPARTS, 32, (LPARAM) parts)) == 0)
return false;
GetCursorPos (&pos) ;
GetWindowRect(StatusWindow, &rect);
if (pos.x < rect.left || pos.y > rect.right)
return false;
off = pos.x - rect.left;
di->hinst = hInstance ;
di->lpszText = sbToolText;
sbToolText[0] = '\0';
for (int i = 0; i < count; i++)
{
if (parts[i] == -1 || off < parts[i])
{
SendMessage(StatusWindow, SB_GETTEXT, i, (LPARAM) str);
if (str[0] == '\0')
return true;
switch (i)
{
case StatusMessage :
strcpy(sbToolText, str);
break ;
case StatusMem :
sprintf(sbToolText, "Current memory usage: %s", str);
break ;
case StatusLine:
sprintf(sbToolText, "Line: %s", str + 3);
break ;
case StatusCol:
sprintf(sbToolText, "Column: %s", str + 3);
break ;
case StatusIns:
strcpy(sbToolText, str[1] == 'I' ? "Insert mode" : "Overwrite mode");
break ;
case StatusModified:
strcpy(sbToolText, "File has been modified");
break ;
case StatusPPS :
if ((s = strchr(str, ' ')) == NULL)
break;
*s = '\0';
sprintf(sbToolText, "%s Pixels per Second", str);
break ;
case StatusRendertime :
sprintf(sbToolText, "Elapsed Time: %s", str);
break ;
}
break;
}
}
return true;
}
return false;
}
void say_status_message (int section, const char *message)
{
char str [256] = "\t" ;
switch (section)
{
case StatusMessage :
SendMessage (StatusWindow, SB_SETTEXT, StatusMessage, (LPARAM) message) ;
break ;
case StatusMem :
SendMessage (StatusWindow, SB_SETTEXT, StatusMem, (LPARAM) message) ;
break ;
case StatusPPS :
strncat (str, message, sizeof (str) - strlen (str) - 1) ;
SendMessage (StatusWindow, SB_SETTEXT, StatusPPS, (LPARAM) str) ;
break ;
case StatusRendertime :
SendMessage (StatusWindow, SB_SETTEXT, StatusRendertime, (LPARAM) message) ;
break ;
}
}
}