Replace standard message boxes with my own, which will word-wrap

consistently across multiple versionf of Windows, and perhaps not
be immediately ignored by the user.

[git-p4: depot-paths = "//depot/solvespace/": change = 2108]
This commit is contained in:
Jonathan Westhues 2010-01-16 01:22:44 -08:00
parent 342729d9a4
commit aaf0984882
6 changed files with 209 additions and 33 deletions

View File

@ -176,7 +176,7 @@ void SolveSpace::ExportViewOrWireframeTo(char *filename, bool wireframe) {
out); out);
} }
if(!out->HasCanvasSize()) { if(out && !out->HasCanvasSize()) {
// These file formats don't have a canvas size, so they just // These file formats don't have a canvas size, so they just
// get exported in the raw coordinate system. So indicate what // get exported in the raw coordinate system. So indicate what
// that was on-screen. // that was on-screen.

View File

@ -789,7 +789,8 @@ void SolveSpace::MenuHelp(int id) {
Message("This is SolveSpace version 1.6.\r\n\r\n" Message("This is SolveSpace version 1.6.\r\n\r\n"
"For more information, see http://solvespace.com/\r\n\r\n" "For more information, see http://solvespace.com/\r\n\r\n"
"Built " __TIME__ " " __DATE__ ".\r\n\r\n" "Built " __TIME__ " " __DATE__ ".\r\n\r\n"
"Copyright 2008-2010 Useful Subset, LLC. All Rights Reserved."); "Copyright 2008-2010 Useful Subset, LLC.\r\n"
"All Rights Reserved.");
break; break;
case GraphicsWindow::MNU_LICENSE: { case GraphicsWindow::MNU_LICENSE: {

View File

@ -152,8 +152,7 @@ void dbp(char *str, ...);
CO((tri).a), CO((tri).b), CO((tri).c)) CO((tri).a), CO((tri).b), CO((tri).c))
void SetWindowTitle(char *str); void SetWindowTitle(char *str);
void Message(char *str, ...); void DoMessageBox(char *str, int rows, int cols, BOOL error);
void Error(char *str, ...);
void SetTimerFor(int milliseconds); void SetTimerFor(int milliseconds);
void ExitNow(void); void ExitNow(void);
@ -235,6 +234,8 @@ void MakePathRelative(char *base, char *path);
void MakePathAbsolute(char *base, char *path); void MakePathAbsolute(char *base, char *path);
bool StringAllPrintable(char *str); bool StringAllPrintable(char *str);
bool StringEndsIn(char *str, char *ending); bool StringEndsIn(char *str, char *ending);
void Message(char *str, ...);
void Error(char *str, ...);
class System { class System {
public: public:

View File

@ -125,6 +125,81 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
mat[15] = a44; mat[15] = a44;
} }
//-----------------------------------------------------------------------------
// Word-wrap the string for our message box appropriately, and then display
// that string.
//-----------------------------------------------------------------------------
static void DoStringForMessageBox(char *str, va_list f, bool error)
{
char inBuf[1024*50];
vsprintf(inBuf, str, f);
char outBuf[1024*50];
int i = 0, j = 0, len = 0, longestLen = 47;
int rows = 0, cols = 0;
// Count the width of the longest line that starts with spaces; those
// are list items, that should not be split in the middle.
bool listLine = false;
while(inBuf[i]) {
if(inBuf[i] == '\r') {
// ignore these
} else if(inBuf[i] == ' ' && len == 0) {
listLine = true;
} else if(inBuf[i] == '\n') {
if(listLine) longestLen = max(longestLen, len);
len = 0;
} else {
len++;
}
i++;
}
if(listLine) longestLen = max(longestLen, len);
// Word wrap according to our target line length longestLen.
len = 0;
i = 0;
while(inBuf[i]) {
if(inBuf[i] == '\r') {
// ignore these
} else if(inBuf[i] == '\n') {
outBuf[j++] = '\n';
if(len == 0) rows++;
len = 0;
} else if(inBuf[i] == ' ' && len > longestLen) {
outBuf[j++] = '\n';
len = 0;
} else {
outBuf[j++] = inBuf[i];
// Count rows when we draw the first character; so an empty
// row doesn't end up counting.
if(len == 0) rows++;
len++;
}
cols = max(cols, len);
i++;
}
outBuf[j++] = '\0';
// And then display the text with our actual longest line length.
DoMessageBox(outBuf, rows, cols, error);
}
void Error(char *str, ...)
{
va_list f;
va_start(f, str);
DoStringForMessageBox(str, f, true);
va_end(f);
}
void Message(char *str, ...)
{
va_list f;
va_start(f, str);
DoStringForMessageBox(str, f, false);
va_end(f);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Solve a mostly banded matrix. In a given row, there are LEFT_OF_DIAG // Solve a mostly banded matrix. In a given row, there are LEFT_OF_DIAG
// elements to the left of the diagonal element, and RIGHT_OF_DIAG elements to // elements to the left of the diagonal element, and RIGHT_OF_DIAG elements to

View File

@ -58,42 +58,141 @@ HFONT FixedFont, LinkFont;
// The 6-DOF input device. // The 6-DOF input device.
SiHdl SpaceNavigator = SI_NO_HANDLE; SiHdl SpaceNavigator = SI_NO_HANDLE;
static void DoMessageBox(char *str, va_list f, BOOL error) //-----------------------------------------------------------------------------
{ // Routines to display message boxes on screen. Do our own, instead of using
char buf[1024*50]; // MessageBox, because that is not consistent from version to version and
vsprintf(buf, str, f); // there's word wrap problems.
//-----------------------------------------------------------------------------
HWND MessageWnd, OkButton;
BOOL MessageDone;
char *MessageString;
static LRESULT CALLBACK MessageProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch (msg) {
case WM_COMMAND:
if((HWND)lParam == OkButton && wParam == BN_CLICKED) {
MessageDone = TRUE;
}
break;
case WM_CLOSE:
case WM_DESTROY:
MessageDone = TRUE;
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
int row = 0, col = 0, i;
SelectObject(hdc, FixedFont);
SetTextColor(hdc, RGB(0, 0, 0));
SetBkMode(hdc, TRANSPARENT);
for(i = 0; MessageString[i]; i++) {
if(MessageString[i] == '\n') {
col = 0;
row++;
} else {
TextOut(hdc, col*TEXT_WIDTH + 10, row*TEXT_HEIGHT + 10,
&(MessageString[i]), 1);
col++;
}
}
EndPaint(hwnd, &ps);
break;
}
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 1;
}
HWND CreateWindowClient(DWORD exStyle, char *className, char *windowName,
DWORD style, int x, int y, int width, int height, HWND parent,
HMENU menu, HINSTANCE instance, void *param)
{
HWND h = CreateWindowEx(exStyle, className, windowName, style, x, y,
width, height, parent, menu, instance, param);
RECT r;
GetClientRect(h, &r);
width = width - (r.right - width);
height = height - (r.bottom - height);
SetWindowPos(h, HWND_TOP, x, y, width, height, 0);
return h;
}
void DoMessageBox(char *str, int rows, int cols, BOOL error)
{
EnableWindow(GraphicsWnd, FALSE); EnableWindow(GraphicsWnd, FALSE);
EnableWindow(TextWnd, FALSE); EnableWindow(TextWnd, FALSE);
int flags;
if(error) {
flags = MB_OK | MB_ICONERROR;
} else {
flags = MB_OK | MB_ICONINFORMATION;
}
HWND h = GetForegroundWindow(); HWND h = GetForegroundWindow();
MessageBox(h, buf, "SolveSpace", flags);
// Register the window class for our dialog.
WNDCLASSEX wc;
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)MessageProc;
wc.hInstance = Instance;
wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
wc.lpszClassName = "MessageWnd";
wc.lpszMenuName = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = (HICON)LoadImage(Instance, MAKEINTRESOURCE(4000),
IMAGE_ICON, 32, 32, 0);
wc.hIconSm = (HICON)LoadImage(Instance, MAKEINTRESOURCE(4000),
IMAGE_ICON, 16, 16, 0);
RegisterClassEx(&wc);
// Create the window.
MessageString = str;
RECT r;
GetWindowRect(GraphicsWnd, &r);
char *title = error ? "SolveSpace - Error" : "SolveSpace - Message";
int width = cols*TEXT_WIDTH + 20, height = rows*TEXT_HEIGHT + 60;
MessageWnd = CreateWindowClient(0, "MessageWnd", title,
WS_OVERLAPPED | WS_SYSMENU,
r.left + 100, r.top + 100, width, height, NULL, NULL, Instance, NULL);
OkButton = CreateWindowEx(0, WC_BUTTON, "OK",
WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS | WS_VISIBLE | BS_DEFPUSHBUTTON,
(width - 70)/2, rows*TEXT_HEIGHT + 20,
70, 25, MessageWnd, NULL, Instance, NULL);
SendMessage(OkButton, WM_SETFONT, (WPARAM)FixedFont, TRUE);
ShowWindow(MessageWnd, TRUE);
SetFocus(OkButton);
MSG msg;
DWORD ret;
MessageDone = FALSE;
while((ret = GetMessage(&msg, NULL, 0, 0)) && !MessageDone) {
if((msg.message == WM_KEYDOWN &&
(msg.wParam == VK_RETURN ||
msg.wParam == VK_ESCAPE)) ||
(msg.message == WM_KEYUP &&
(msg.wParam == VK_SPACE)))
{
MessageDone = TRUE;
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
MessageString = NULL;
EnableWindow(TextWnd, TRUE); EnableWindow(TextWnd, TRUE);
EnableWindow(GraphicsWnd, TRUE); EnableWindow(GraphicsWnd, TRUE);
SetForegroundWindow(GraphicsWnd); SetForegroundWindow(GraphicsWnd);
} DestroyWindow(MessageWnd);
void Error(char *str, ...)
{
va_list f;
va_start(f, str);
DoMessageBox(str, f, TRUE);
va_end(f);
}
void Message(char *str, ...)
{
va_list f;
va_start(f, str);
DoMessageBox(str, f, FALSE);
va_end(f);
} }
void AddContextMenuItem(char *label, int id) void AddContextMenuItem(char *label, int id)

View File

@ -1,4 +1,4 @@
better Error() and Message() dialog boxes replace show/hide links with icons?
lock point where dragged constraint lock point where dragged constraint
projected and signed distance constraints projected and signed distance constraints