//----------------------------------------------------------------------------- // Copyright 2007 Jonathan Westhues // // This file is part of LDmicro. // // LDmicro is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // LDmicro 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with LDmicro. If not, see . //------ // // Window to show our internal help. Roll my own using a rich edit control so // that I don't have to distribute a separate Windows Help or HTML file; the // manual is compiled in to the exe. Do pretty syntax highlighting style // colours. // Jonathan Westhues, Dec 2004 //----------------------------------------------------------------------------- #include #include #include #include #include #include "ldmicro.h" extern char *HelpText[]; extern char *HelpTextDe[]; extern char *HelpTextFr[]; extern char *HelpTextTr[]; static char *AboutText[] = { "", "ABOUT LDMICRO", "=============", "", "LDmicro is a ladder logic editor, simulator and compiler for 8-bit", "microcontrollers. It can generate native code for Atmel AVR and Microchip", "PIC16 CPUs from a ladder diagram.", "", "This program is free software: you can redistribute it and/or modify it", "under the terms of the GNU General Public License as published by the", "Free Software Foundation, either version 3 of the License, or (at your", "option) any later version.", "", "This program 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 General Public License", "for more details.", "", "You should have received a copy of the GNU General Public License along", "with this program. If not, see .", "", "The source code for LDmicro is available at", "", " http://cq.cx/ladder.pl", "", "Copyright 2005-2010 Jonathan Westhues", "Release 2.2, built " __TIME__ " " __DATE__ ".", "", "Email: user jwesthues, at host cq.cx", "", NULL }; static char **Text[] = { #if defined(LDLANG_EN) || \ defined(LDLANG_ES) || \ defined(LDLANG_IT) || \ defined(LDLANG_PT) HelpText, #elif defined(LDLANG_DE) HelpTextDe, #elif defined(LDLANG_FR) HelpTextFr, #elif defined(LDLANG_TR) HelpTextTr, #else # error "Bad language" #endif // Let's always keep the about text in English. AboutText }; static HWND HelpDialog[2]; static HWND RichEdit[2]; static BOOL HelpWindowOpen[2]; static int TitleHeight; #define RICH_EDIT_HEIGHT(h) \ ((((h) - 3 + (FONT_HEIGHT/2)) / FONT_HEIGHT) * FONT_HEIGHT) static void SizeRichEdit(int a) { RECT r; GetClientRect(HelpDialog[a], &r); SetWindowPos(RichEdit[a], HWND_TOP, 6, 3, r.right - 6, RICH_EDIT_HEIGHT(r.bottom), 0); } static BOOL Resizing(RECT *r, int wParam) { BOOL touched = FALSE; if(r->right - r->left < 650) { int diff = 650 - (r->right - r->left); if(wParam == WMSZ_RIGHT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_BOTTOMRIGHT) { r->right += diff; } else { r->left -= diff; } touched = TRUE; } if(!(wParam == WMSZ_LEFT || wParam == WMSZ_RIGHT)) { int h = r->bottom - r->top - TitleHeight - 5; if(RICH_EDIT_HEIGHT(h) != h) { int diff = h - RICH_EDIT_HEIGHT(h); if(wParam == WMSZ_TOP || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT) { r->top += diff; } else { r->bottom -= diff; } touched = TRUE; } } return !touched; } static void MakeControls(int a) { HMODULE re = LoadLibrary("RichEd20.dll"); if(!re) oops(); RichEdit[a] = CreateWindowEx(0, RICHEDIT_CLASS, "", WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | ES_READONLY | ES_MULTILINE | WS_VSCROLL, 0, 0, 100, 100, HelpDialog[a], NULL, Instance, NULL); SendMessage(RichEdit[a], WM_SETFONT, (WPARAM)FixedWidthFont, TRUE); SendMessage(RichEdit[a], EM_SETBKGNDCOLOR, (WPARAM)0, RGB(0, 0, 0)); SizeRichEdit(a); int i; BOOL nextSubHead = FALSE; for(i = 0; Text[a][i]; i++) { char *s = Text[a][i]; CHARFORMAT cf; cf.cbSize = sizeof(cf); cf.dwMask = CFM_BOLD | CFM_COLOR; cf.dwEffects = 0; if((s[0] == '=') || (Text[a][i+1] && Text[a][i+1][0] == '=')) { cf.crTextColor = RGB(255, 255, 110); } else if(s[3] == '|' && s[4] == '|') { cf.crTextColor = RGB(255, 110, 255); } else if(s[0] == '>' || nextSubHead) { // Need to make a copy because the strings we are passed aren't // mutable. char copy[1024]; if(strlen(s) >= sizeof(copy)) oops(); strcpy(copy, s); int j; for(j = 1; copy[j]; j++) { if(copy[j] == ' ' && copy[j-1] == ' ') break; } BOOL justHeading = (copy[j] == '\0'); copy[j] = '\0'; cf.crTextColor = RGB(110, 255, 110); SendMessage(RichEdit[a], EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); SendMessage(RichEdit[a], EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)copy); SendMessage(RichEdit[a], EM_SETSEL, (WPARAM)-1, (LPARAM)-1); // Special case if there's nothing except title on the line if(!justHeading) { copy[j] = ' '; } s += j; cf.crTextColor = RGB(255, 110, 255); nextSubHead = !nextSubHead; } else { cf.crTextColor = RGB(255, 255, 255); } SendMessage(RichEdit[a], EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); SendMessage(RichEdit[a], EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)s); SendMessage(RichEdit[a], EM_SETSEL, (WPARAM)-1, (LPARAM)-1); if(Text[a][i+1]) { SendMessage(RichEdit[a], EM_REPLACESEL, FALSE, (LPARAM)"\r\n"); SendMessage(RichEdit[a], EM_SETSEL, (WPARAM)-1, (LPARAM)-1); } } SendMessage(RichEdit[a], EM_SETSEL, (WPARAM)0, (LPARAM)0); } //----------------------------------------------------------------------------- // Window proc for the help dialog. //----------------------------------------------------------------------------- static LRESULT CALLBACK HelpProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { int a = (hwnd == HelpDialog[0] ? 0 : 1); switch (msg) { case WM_SIZING: { RECT *r = (RECT *)lParam; return Resizing(r, wParam); break; } case WM_SIZE: SizeRichEdit(a); break; case WM_ACTIVATE: case WM_KEYDOWN: SetFocus(RichEdit[a]); break; case WM_DESTROY: case WM_CLOSE: HelpWindowOpen[a] = FALSE; // fall through default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 1; } //----------------------------------------------------------------------------- // Create the class for the help window. //----------------------------------------------------------------------------- static void MakeClass(void) { WNDCLASSEX wc; memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(wc); wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC | CS_DBLCLKS; wc.lpfnWndProc = (WNDPROC)HelpProc; wc.hInstance = Instance; wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszClassName = "LDmicroHelp"; 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); } void ShowHelpDialog(BOOL about) { int a = about ? 1 : 0; if(HelpWindowOpen[a]) { SetForegroundWindow(HelpDialog[a]); return; } MakeClass(); char *s = about ? "About LDmicro" : "LDmicro Help"; HelpDialog[a] = CreateWindowEx(0, "LDmicroHelp", s, WS_OVERLAPPED | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_SIZEBOX, 100, 100, 650, 300+10*FONT_HEIGHT, NULL, NULL, Instance, NULL); MakeControls(a); ShowWindow(HelpDialog[a], TRUE); SetFocus(RichEdit[a]); HelpWindowOpen[a] = TRUE; RECT r; GetClientRect(HelpDialog[a], &r); TitleHeight = 300 - r.bottom; GetWindowRect(HelpDialog[a], &r); Resizing(&r, WMSZ_TOP); SetWindowPos(HelpDialog[a], HWND_TOP, r.left, r.top, r.right - r.left, r.bottom - r.top, 0); }