├── .gitignore ├── Initial.Txt ├── LICENCE.TXT ├── Neatpad.dsw ├── Neatpad ├── NeatUtils.c ├── Neatpad.c ├── Neatpad.dsp ├── Neatpad.exe.manifest ├── Neatpad.h ├── OpenSave.c ├── Options.c ├── OptionsDisplay.c ├── OptionsFont.c ├── OptionsMisc.c ├── Printing.c ├── Search.c ├── ThemeUtils.c ├── Toolbars.c ├── bitmap1.bmp ├── bitmap2.bmp ├── bitmap3.bmp ├── bitmap4.bmp ├── icon0.ico ├── icon1.ico ├── icon2.ico ├── icon3.ico ├── icon4.ico ├── resource.h └── resource.rc ├── TextView ├── TextDocument.cpp ├── TextDocument.h ├── TextView.cpp ├── TextView.dsp ├── TextView.h ├── TextViewClipboard.cpp ├── TextViewFile.cpp ├── TextViewFont.cpp ├── TextViewInternal.h ├── TextViewKeyInput.cpp ├── TextViewKeyNav.cpp ├── TextViewMouse.cpp ├── TextViewPaint.cpp ├── TextViewParser.cpp ├── TextViewScroll.cpp ├── TextViewSyntax.cpp ├── Unicode.c ├── Unicode.h ├── codepages.h ├── racursor.h ├── sequence.cpp └── sequence.h ├── UspLib ├── USPDLL.dsp ├── USPDLL.dsw ├── UspCtrl.c ├── UspLib.c ├── UspLib.dsp ├── UspMain.c ├── UspMouse.c ├── UspPaint.c └── usplib.h └── readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore all files of types: 2 | *.aps 3 | *.bsc 4 | *.cache 5 | *.exe 6 | *.idb 7 | *.map 8 | *.lib 9 | *.ncb 10 | *.obj 11 | *.old 12 | *.opensdf 13 | *.pdb 14 | *.res 15 | *.sbr 16 | *.sdf 17 | *.suo 18 | *.user 19 | *.zip 20 | 21 | # ignore the following files: 22 | BuildLog.htm 23 | 24 | # ignore the following directories - they can occur 25 | # anywhere under the repo 26 | Unicode_Debug/ 27 | Unicode_Release/ 28 | Debug/ 29 | Release/ 30 | ipch/ 31 | -------------------------------------------------------------------------------- /Initial.Txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Initial.Txt -------------------------------------------------------------------------------- /LICENCE.TXT: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 James Brown 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Neatpad.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "Neatpad"=.\Neatpad\Neatpad.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | Begin Project Dependency 15 | Project_Dep_Name TextView 16 | End Project Dependency 17 | Begin Project Dependency 18 | Project_Dep_Name UspLib 19 | End Project Dependency 20 | }}} 21 | 22 | ############################################################################### 23 | 24 | Project: "TextView"=.\TextView\TextView.dsp - Package Owner=<4> 25 | 26 | Package=<5> 27 | {{{ 28 | }}} 29 | 30 | Package=<4> 31 | {{{ 32 | Begin Project Dependency 33 | Project_Dep_Name UspLib 34 | End Project Dependency 35 | }}} 36 | 37 | ############################################################################### 38 | 39 | Project: "UspLib"=.\UspLib\UspLib.dsp - Package Owner=<4> 40 | 41 | Package=<5> 42 | {{{ 43 | }}} 44 | 45 | Package=<4> 46 | {{{ 47 | }}} 48 | 49 | ############################################################################### 50 | 51 | Global: 52 | 53 | Package=<5> 54 | {{{ 55 | }}} 56 | 57 | Package=<3> 58 | {{{ 59 | }}} 60 | 61 | ############################################################################### 62 | 63 | -------------------------------------------------------------------------------- /Neatpad/NeatUtils.c: -------------------------------------------------------------------------------- 1 | // 2 | // Helper routines for Neatpad 3 | // 4 | // www.catch22.net 5 | // 6 | 7 | #define STRICT 8 | #define WIN32_LEAN_AND_MEAN 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "neatpad.h" 17 | 18 | #define WINPOS_FILESPEC _T("%s:Neatpad.Settings") 19 | 20 | typedef HMONITOR (WINAPI * MFR_PROC)(LPCRECT, DWORD); 21 | 22 | BOOL CheckMenuCommand(HMENU hMenu, int nCommandId, BOOL fChecked) 23 | { 24 | if(fChecked) 25 | { 26 | CheckMenuItem(hMenu, nCommandId, MF_CHECKED | MF_BYCOMMAND); 27 | return TRUE; 28 | } 29 | else 30 | { 31 | CheckMenuItem(hMenu, nCommandId, MF_UNCHECKED | MF_BYCOMMAND); 32 | return FALSE; 33 | } 34 | } 35 | 36 | BOOL ToggleMenuItem(HMENU hmenu, UINT menuid) 37 | { 38 | if(MF_CHECKED & GetMenuState(hmenu, menuid, MF_BYCOMMAND)) 39 | { 40 | CheckMenuItem(hmenu, menuid, MF_UNCHECKED | MF_BYCOMMAND); 41 | return FALSE; 42 | } 43 | else 44 | { 45 | CheckMenuItem(hmenu, menuid, MF_CHECKED | MF_BYCOMMAND); 46 | return TRUE; 47 | } 48 | } 49 | 50 | BOOL EnableMenuCommand(HMENU hmenu, int nCommandId, BOOL fEnable) 51 | { 52 | if(fEnable) 53 | { 54 | EnableMenuItem(hmenu, nCommandId, MF_ENABLED | MF_BYCOMMAND); 55 | return TRUE; 56 | } 57 | else 58 | { 59 | EnableMenuItem(hmenu, nCommandId, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND); 60 | return FALSE; 61 | } 62 | } 63 | 64 | BOOL EnableDlgItem(HWND hDlg, UINT nCommandId, BOOL fEnable) 65 | { 66 | return EnableWindow(GetDlgItem(hDlg, nCommandId), fEnable); 67 | } 68 | 69 | // 70 | // Ensure that the specified window is on a visible monitor 71 | // 72 | void ForceVisibleDisplay(HWND hwnd) 73 | { 74 | RECT rect; 75 | HMODULE hUser32; 76 | MFR_PROC pMonitorFromRect; 77 | 78 | GetWindowRect(hwnd, &rect); 79 | 80 | hUser32 = GetModuleHandle(_T("USER32.DLL")); 81 | 82 | pMonitorFromRect = (MFR_PROC)GetProcAddress(hUser32, "MonitorFromRect"); 83 | 84 | if(pMonitorFromRect != 0) 85 | { 86 | if(NULL == pMonitorFromRect(&rect, MONITOR_DEFAULTTONULL)) 87 | { 88 | // force window onto primary display if it is not visible 89 | rect.left %= GetSystemMetrics(SM_CXSCREEN); 90 | rect.top %= GetSystemMetrics(SM_CYSCREEN); 91 | 92 | SetWindowPos(hwnd, 0, rect.left, rect.top, 0, 0, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE); 93 | } 94 | } 95 | } 96 | 97 | // 98 | // Save window-position for the specified file 99 | // 100 | BOOL SaveFileData(TCHAR *szPath, HWND hwnd) 101 | { 102 | WINDOWPLACEMENT wp = { sizeof(wp) }; 103 | 104 | TCHAR szStream[MAX_PATH]; 105 | HANDLE hFile; 106 | DWORD len; 107 | BOOL restoretime = FALSE; 108 | FILETIME ctm, atm, wtm; 109 | 110 | if(szPath == 0 || szPath[0] == 0) 111 | return FALSE; 112 | 113 | wsprintf(szStream, WINPOS_FILESPEC, szPath); 114 | 115 | if(!GetWindowPlacement(hwnd, &wp)) 116 | return FALSE; 117 | 118 | // 119 | // Get the file time-stamp. Try the stream first - if that doesn't exist 120 | // get the time from the 'base' file 121 | // 122 | if((hFile = CreateFile(szStream, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)) != INVALID_HANDLE_VALUE || 123 | (hFile = CreateFile(szPath, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)) != INVALID_HANDLE_VALUE) 124 | { 125 | if(GetFileTime(hFile, &ctm, &atm, &wtm)) 126 | restoretime = TRUE; 127 | 128 | CloseHandle(hFile); 129 | } 130 | 131 | // 132 | // Now open the stream for writing 133 | // 134 | if((hFile = CreateFile(szStream, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) 135 | return FALSE; 136 | 137 | WriteFile(hFile, &wp, sizeof(wp), &len, 0); 138 | 139 | // 140 | // Restore timestamp if necessary 141 | // 142 | if(restoretime == TRUE) 143 | SetFileTime(hFile, &ctm, &atm, &wtm); 144 | 145 | CloseHandle(hFile); 146 | 147 | return TRUE; 148 | } 149 | 150 | // 151 | // Restore the last window-position for the specified file 152 | // 153 | BOOL LoadFileData(TCHAR *szPath, HWND hwnd) 154 | { 155 | WINDOWPLACEMENT wp = { sizeof(wp) }; 156 | 157 | TCHAR szStream[MAX_PATH]; 158 | HANDLE hFile; 159 | DWORD len; 160 | 161 | if(szPath == 0 || szPath[0] == 0) 162 | return FALSE; 163 | 164 | wsprintf(szStream, WINPOS_FILESPEC, szPath); 165 | 166 | // 167 | // Can only set the window-position if the alternate-data-stream exists 168 | // 169 | if((hFile = CreateFile(szStream, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) 170 | return FALSE; 171 | 172 | if(!ReadFile(hFile, &wp, sizeof(wp), &len, 0)) 173 | return FALSE; 174 | 175 | // 176 | // Only set the window-position if we read a valid WINDOWPLACEMENT structure!! 177 | // 178 | if(len == sizeof(wp) && wp.length == sizeof(wp)) 179 | { 180 | wp.flags = SW_HIDE; 181 | SetWindowPlacement(hwnd, &wp); 182 | ForceVisibleDisplay(hwnd); 183 | } 184 | 185 | CloseHandle(hFile); 186 | return TRUE; 187 | } 188 | 189 | // 190 | // Resolve a ShellLink (i.e. c:\path\shortcut.lnk) to a real path 191 | // Refactored from MFC source 192 | // 193 | BOOL ResolveShortcut(TCHAR *pszShortcut, TCHAR *pszFilePath, int nPathLen) 194 | { 195 | IShellLink * psl; 196 | SHFILEINFO info = { 0 }; 197 | IPersistFile *ppf; 198 | 199 | *pszFilePath = 0; // assume failure 200 | 201 | // retrieve file's shell-attributes 202 | if((SHGetFileInfo(pszShortcut, 0, &info, sizeof(info), SHGFI_ATTRIBUTES) == 0)) 203 | return FALSE; 204 | 205 | // not a shortcut? 206 | if(!(info.dwAttributes & SFGAO_LINK)) 207 | { 208 | lstrcpyn(pszFilePath, pszShortcut, nPathLen); 209 | return TRUE; 210 | } 211 | 212 | // obtain the IShellLink interface 213 | if(FAILED(CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID*)&psl))) 214 | return FALSE; 215 | 216 | if (SUCCEEDED(psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf))) 217 | { 218 | if (SUCCEEDED(ppf->lpVtbl->Load(ppf, pszShortcut, STGM_READ))) 219 | { 220 | // Resolve the link, this may post UI to find the link 221 | if (SUCCEEDED(psl->lpVtbl->Resolve(psl, 0, SLR_NO_UI ))) 222 | { 223 | psl->lpVtbl->GetPath(psl, pszFilePath, nPathLen, NULL, 0); 224 | ppf->lpVtbl->Release(ppf); 225 | psl->lpVtbl->Release(psl); 226 | return TRUE; 227 | } 228 | } 229 | 230 | ppf->lpVtbl->Release(ppf); 231 | } 232 | 233 | psl->lpVtbl->Release(psl); 234 | return FALSE; 235 | } 236 | 237 | 238 | // 239 | // Convert 'points' to logical-units suitable for CreateFont 240 | // 241 | int PointsToLogical(int nPointSize) 242 | { 243 | HDC hdc = GetDC(0); 244 | int nLogSize = -MulDiv(nPointSize, GetDeviceCaps(hdc, LOGPIXELSY), 72); 245 | ReleaseDC(0, hdc); 246 | 247 | return nLogSize; 248 | } 249 | 250 | // 251 | // Simple wrapper around CreateFont 252 | // 253 | HFONT EasyCreateFont(int nPointSize, BOOL fBold, DWORD dwQuality, TCHAR *szFace) 254 | { 255 | return CreateFont(PointsToLogical(nPointSize), 256 | 0, 0, 0, 257 | fBold ? FW_BOLD : 0, 258 | 0,0,0,DEFAULT_CHARSET,0,0, 259 | dwQuality, 260 | 0, 261 | szFace); 262 | } 263 | 264 | // 265 | // Return a BOLD version of whatever font the 266 | // specified window is using 267 | // 268 | HFONT CreateBoldFontFromHwnd(HWND hwnd) 269 | { 270 | HFONT hFont; 271 | LOGFONT logfont; 272 | 273 | // get the font information 274 | hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); 275 | GetObject(hFont, sizeof(logfont), &logfont); 276 | 277 | // create it with the 'bold' attribute 278 | logfont.lfWeight = FW_BOLD; 279 | return CreateFontIndirect(&logfont); 280 | } 281 | 282 | int RectWidth(RECT *rect) 283 | { 284 | return rect->right - rect->left; 285 | } 286 | 287 | int RectHeight(RECT *rect) 288 | { 289 | return rect->bottom - rect->top; 290 | } 291 | 292 | // 293 | // Center the specified window relative to it's parent 294 | // 295 | void CenterWindow(HWND hwnd) 296 | { 297 | HWND hwndParent = GetParent(hwnd); 298 | RECT rcChild; 299 | RECT rcParent; 300 | int x, y; 301 | 302 | GetWindowRect(hwnd, &rcChild); 303 | GetWindowRect(hwndParent, &rcParent); 304 | 305 | x = rcParent.left + (RectWidth(&rcParent) - RectWidth(&rcChild)) / 2; 306 | y = rcParent.top + (RectHeight(&rcParent) - RectHeight(&rcChild)) / 2; 307 | 308 | MoveWindow(hwnd, max(0, x), max(0, y), RectWidth(&rcChild), RectHeight(&rcChild), TRUE); 309 | } 310 | 311 | 312 | // 313 | // Copied from uxtheme.h 314 | // If you have this new header, then delete these and 315 | // #include instead! 316 | // 317 | /*#define ETDT_DISABLE 0x00000001 318 | #define ETDT_ENABLE 0x00000002 319 | #define ETDT_USETABTEXTURE 0x00000004 320 | #define ETDT_ENABLETAB (ETDT_ENABLE | ETDT_USETABTEXTURE) 321 | */ 322 | // 323 | 324 | // 325 | // Try to call EnableThemeDialogTexture, if uxtheme.dll is present 326 | // 327 | BOOL EnableDialogTheme(HWND hwnd) 328 | { 329 | HMODULE hUXTheme; 330 | typedef HRESULT (WINAPI * ETDTProc) (HWND, DWORD); 331 | ETDTProc fnEnableThemeDialogTexture; 332 | 333 | hUXTheme = GetModuleHandle(_T("uxtheme.dll")); 334 | 335 | if(hUXTheme) 336 | { 337 | fnEnableThemeDialogTexture = 338 | (ETDTProc)GetProcAddress(hUXTheme, "EnableThemeDialogTexture"); 339 | 340 | if(fnEnableThemeDialogTexture) 341 | { 342 | fnEnableThemeDialogTexture(hwnd, ETDT_ENABLETAB); 343 | return TRUE; 344 | } 345 | else 346 | { 347 | // Failed to locate API! 348 | return FALSE; 349 | } 350 | } 351 | else 352 | { 353 | // Not running under XP? Just fail gracefully 354 | return FALSE; 355 | } 356 | } 357 | 358 | 359 | // 360 | // WM_NCCALCSIZE handler for top-level windows. Prevents the 361 | // flickering observed during a 'top-left' window resize by adjusting 362 | // the source+dest BitBlt rectangles 363 | // 364 | // hwnd - must have WS_CLIPCHILDREN turned OFF 365 | // 366 | /*UINT NcCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam) 367 | { 368 | ULONG ret = DefWindowProc(hwnd, WM_NCCALCSIZE, wParam, lParam); 369 | 370 | if(wParam == TRUE) 371 | { 372 | NCCALCSIZE_PARAMS *nccsp = (NCCALCSIZE_PARAMS *)lParam; 373 | RECT rc; 374 | int sbheight = 0; 375 | 376 | GetWindowRect(g_hwndStatusbar, &rc); 377 | sbheight = g_fShowStatusbar ? rc.bottom-rc.top : 0; 378 | 379 | nccsp->rgrc[1] = nccsp->rgrc[0]; 380 | nccsp->rgrc[1].right -= GetSystemMetrics(SM_CXVSCROLL) + 50; 381 | nccsp->rgrc[1].bottom -= GetSystemMetrics(SM_CYHSCROLL) + sbheight + 50; 382 | 383 | return WVR_VALIDRECTS; 384 | } 385 | else 386 | { 387 | return ret; 388 | } 389 | }*/ -------------------------------------------------------------------------------- /Neatpad/Neatpad.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="Neatpad" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Application" 0x0101 6 | 7 | CFG=Neatpad - Win32 Unicode Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "Neatpad.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "Neatpad.mak" CFG="Neatpad - Win32 Unicode Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "Neatpad - Win32 Release" (based on "Win32 (x86) Application") 21 | !MESSAGE "Neatpad - Win32 Debug" (based on "Win32 (x86) Application") 22 | !MESSAGE "Neatpad - Win32 Unicode Debug" (based on "Win32 (x86) Application") 23 | !MESSAGE "Neatpad - Win32 Unicode Release" (based on "Win32 (x86) Application") 24 | !MESSAGE 25 | 26 | # Begin Project 27 | # PROP AllowPerConfigDependencies 0 28 | # PROP Scc_ProjName "" 29 | # PROP Scc_LocalPath "" 30 | CPP=cl.exe 31 | MTL=midl.exe 32 | RSC=rc.exe 33 | 34 | !IF "$(CFG)" == "Neatpad - Win32 Release" 35 | 36 | # PROP BASE Use_MFC 0 37 | # PROP BASE Use_Debug_Libraries 0 38 | # PROP BASE Output_Dir "Release" 39 | # PROP BASE Intermediate_Dir "Release" 40 | # PROP BASE Target_Dir "" 41 | # PROP Use_MFC 0 42 | # PROP Use_Debug_Libraries 0 43 | # PROP Output_Dir "..\Release" 44 | # PROP Intermediate_Dir "Release" 45 | # PROP Ignore_Export_Lib 0 46 | # PROP Target_Dir "" 47 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c 48 | # ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /c 49 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 50 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 51 | # ADD BASE RSC /l 0x809 /d "NDEBUG" 52 | # ADD RSC /l 0x809 /d "NDEBUG" 53 | BSC32=bscmake.exe 54 | # ADD BASE BSC32 /nologo 55 | # ADD BSC32 /nologo 56 | LINK32=link.exe 57 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 58 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 59 | # SUBTRACT LINK32 /profile 60 | 61 | !ELSEIF "$(CFG)" == "Neatpad - Win32 Debug" 62 | 63 | # PROP BASE Use_MFC 0 64 | # PROP BASE Use_Debug_Libraries 1 65 | # PROP BASE Output_Dir "Debug" 66 | # PROP BASE Intermediate_Dir "Debug" 67 | # PROP BASE Target_Dir "" 68 | # PROP Use_MFC 0 69 | # PROP Use_Debug_Libraries 1 70 | # PROP Output_Dir "..\Debug" 71 | # PROP Intermediate_Dir "Debug" 72 | # PROP Ignore_Export_Lib 0 73 | # PROP Target_Dir "" 74 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c 75 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /GZ /c 76 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 77 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 78 | # ADD BASE RSC /l 0x809 /d "_DEBUG" 79 | # ADD RSC /l 0x809 /d "_DEBUG" 80 | BSC32=bscmake.exe 81 | # ADD BASE BSC32 /nologo 82 | # ADD BSC32 /nologo 83 | LINK32=link.exe 84 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept 85 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 86 | # SUBTRACT LINK32 /profile 87 | 88 | !ELSEIF "$(CFG)" == "Neatpad - Win32 Unicode Debug" 89 | 90 | # PROP BASE Use_MFC 0 91 | # PROP BASE Use_Debug_Libraries 1 92 | # PROP BASE Output_Dir "Neatpad___Win32_Unicode_Debug" 93 | # PROP BASE Intermediate_Dir "Neatpad___Win32_Unicode_Debug" 94 | # PROP BASE Ignore_Export_Lib 0 95 | # PROP BASE Target_Dir "" 96 | # PROP Use_MFC 0 97 | # PROP Use_Debug_Libraries 1 98 | # PROP Output_Dir "..\Unicode_Debug" 99 | # PROP Intermediate_Dir "Unicode_Debug" 100 | # PROP Ignore_Export_Lib 0 101 | # PROP Target_Dir "" 102 | # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /GZ /c 103 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "_WINDOWS" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /FR /YX /FD /GZ /c 104 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 105 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 106 | # ADD BASE RSC /l 0x809 /d "_DEBUG" 107 | # ADD RSC /l 0x809 /d "_DEBUG" 108 | BSC32=bscmake.exe 109 | # ADD BASE BSC32 /nologo 110 | # ADD BSC32 /nologo 111 | LINK32=link.exe 112 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 113 | # SUBTRACT BASE LINK32 /profile 114 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /profile /map /debug /machine:I386 115 | 116 | !ELSEIF "$(CFG)" == "Neatpad - Win32 Unicode Release" 117 | 118 | # PROP BASE Use_MFC 0 119 | # PROP BASE Use_Debug_Libraries 0 120 | # PROP BASE Output_Dir "Neatpad___Win32_Unicode_Release" 121 | # PROP BASE Intermediate_Dir "Neatpad___Win32_Unicode_Release" 122 | # PROP BASE Ignore_Export_Lib 0 123 | # PROP BASE Target_Dir "" 124 | # PROP Use_MFC 0 125 | # PROP Use_Debug_Libraries 0 126 | # PROP Output_Dir "..\Unicode_Release" 127 | # PROP Intermediate_Dir "Unicode_Release" 128 | # PROP Ignore_Export_Lib 0 129 | # PROP Target_Dir "" 130 | # ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /c 131 | # ADD CPP /nologo /MD /W3 /O1 /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /FR /YX /FD /c 132 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 133 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 134 | # ADD BASE RSC /l 0x809 /d "NDEBUG" 135 | # ADD RSC /l 0x809 /d "NDEBUG" 136 | BSC32=bscmake.exe 137 | # ADD BASE BSC32 /nologo 138 | # ADD BSC32 /nologo 139 | LINK32=link.exe 140 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 141 | # SUBTRACT BASE LINK32 /profile 142 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /map /machine:I386 143 | # SUBTRACT LINK32 /profile 144 | 145 | !ENDIF 146 | 147 | # Begin Target 148 | 149 | # Name "Neatpad - Win32 Release" 150 | # Name "Neatpad - Win32 Debug" 151 | # Name "Neatpad - Win32 Unicode Debug" 152 | # Name "Neatpad - Win32 Unicode Release" 153 | # Begin Group "Source Files" 154 | 155 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 156 | # Begin Source File 157 | 158 | SOURCE=.\Neatpad.c 159 | # End Source File 160 | # Begin Source File 161 | 162 | SOURCE=.\NeatUtils.c 163 | # End Source File 164 | # Begin Source File 165 | 166 | SOURCE=.\OpenSave.c 167 | # End Source File 168 | # Begin Source File 169 | 170 | SOURCE=.\Options.c 171 | # End Source File 172 | # Begin Source File 173 | 174 | SOURCE=.\OptionsDisplay.c 175 | # End Source File 176 | # Begin Source File 177 | 178 | SOURCE=.\OptionsFont.c 179 | # End Source File 180 | # Begin Source File 181 | 182 | SOURCE=.\OptionsMisc.c 183 | # End Source File 184 | # Begin Source File 185 | 186 | SOURCE=.\Printing.c 187 | # End Source File 188 | # Begin Source File 189 | 190 | SOURCE=.\resource.rc 191 | # End Source File 192 | # Begin Source File 193 | 194 | SOURCE=.\Search.c 195 | # End Source File 196 | # Begin Source File 197 | 198 | SOURCE=.\Toolbars.c 199 | # End Source File 200 | # End Group 201 | # Begin Group "Resource Files" 202 | 203 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 204 | # Begin Source File 205 | 206 | SOURCE=.\bitmap1.bmp 207 | # End Source File 208 | # Begin Source File 209 | 210 | SOURCE=.\bitmap2.bmp 211 | # End Source File 212 | # Begin Source File 213 | 214 | SOURCE=.\bitmap3.bmp 215 | # End Source File 216 | # Begin Source File 217 | 218 | SOURCE=.\bitmap4.bmp 219 | # End Source File 220 | # Begin Source File 221 | 222 | SOURCE=.\icon1.ico 223 | # End Source File 224 | # Begin Source File 225 | 226 | SOURCE=.\icon2.ico 227 | # End Source File 228 | # Begin Source File 229 | 230 | SOURCE=.\icon3.ico 231 | # End Source File 232 | # Begin Source File 233 | 234 | SOURCE=.\icon4.ico 235 | # End Source File 236 | # End Group 237 | # Begin Group "Header Files" 238 | 239 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 240 | # Begin Source File 241 | 242 | SOURCE=.\Neatpad.h 243 | # End Source File 244 | # Begin Source File 245 | 246 | SOURCE=.\resource.h 247 | # End Source File 248 | # End Group 249 | # Begin Source File 250 | 251 | SOURCE=.\Neatpad.exe.manifest 252 | # End Source File 253 | # End Target 254 | # End Project 255 | -------------------------------------------------------------------------------- /Neatpad/Neatpad.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | Neatpad text editor. 10 | 11 | 12 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Neatpad/Neatpad.h: -------------------------------------------------------------------------------- 1 | #ifndef NEATPAD_INCLUDED 2 | #define NEATPAD_INCLUDED 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | 9 | #define APP_TITLE _T("Neatpad") 10 | #define REGLOC _T("SOFTWARE\\Catch22\\Neatpad") 11 | 12 | #define WEBSITE_STR _T("www.catch22.net") 13 | #define WEBSITE_URL _T("http://") WEBSITE_STR 14 | #define SYSLINK_STR _T("Updates available at ") WEBSITE_STR _T("") 15 | 16 | 17 | // 18 | // Global variables used for Neatpad settings 19 | // 20 | extern LONG g_nFontSize; 21 | extern BOOL g_fFontBold; 22 | extern TCHAR g_szFontName[]; 23 | extern LONG g_nFontSmoothing; 24 | extern BOOL g_fLineNumbers; 25 | extern BOOL g_fLongLines; 26 | extern BOOL g_fSelMargin; 27 | extern BOOL g_fSaveOnExit; 28 | extern int g_nLongLineLimit; 29 | extern BOOL g_nHLCurLine; 30 | extern BOOL g_fAddToExplorer; 31 | extern BOOL g_fReplaceNotepad; 32 | extern BOOL g_fShowStatusbar; 33 | 34 | extern LONG g_nPaddingAbove; 35 | extern LONG g_nPaddingBelow; 36 | extern LONG g_fPaddingFlags; 37 | extern COLORREF g_rgbColourList[]; 38 | extern COLORREF g_rgbCustColours[]; 39 | 40 | 41 | #define COURIERNEW 1 42 | #define LUCIDACONS 2 43 | 44 | // Global runtime variables 45 | extern HWND g_hwndTextView; 46 | extern HWND g_hwndMain; 47 | extern HFONT g_hFont; 48 | extern TCHAR g_szFileName[]; 49 | extern TCHAR g_szFileTitle[]; 50 | extern BOOL g_fFileChanged; 51 | extern HINSTANCE g_hResourceModule; 52 | 53 | // 54 | // Global functions 55 | // 56 | void SetWindowFileName(HWND hwnd, TCHAR *szFileName, BOOL fModified); 57 | HFONT EasyCreateFont(int nPointSize, BOOL fBold, DWORD dwQuality, TCHAR *szFace); 58 | HDC ShowPrintDlg(HWND hwndParent); 59 | 60 | // 61 | // Options.c functions 62 | // 63 | void ShowOptions(HWND hwndParent); 64 | void ApplyRegSettings(); 65 | void LoadRegSettings(); 66 | void SaveRegSettings(); 67 | void LoadRegSysSettings(); 68 | void SaveRegSysSettings(); 69 | BOOL SetExplorerContextMenu(BOOL fAddToMenu); 70 | BOOL SetImageFileExecutionOptions(BOOL fReplaceWithCurrentApp); 71 | 72 | 73 | // 74 | // OpenSave.c functions 75 | // 76 | BOOL DoOpenFile(HWND hwndMain, TCHAR *szFileName, TCHAR *szFileTitle); 77 | BOOL DoSaveFile(HWND hwndMain, TCHAR *szFileName, TCHAR *szFileTitle); 78 | BOOL ShowOpenFileDlg(HWND hwnd, TCHAR *pstrFileName, TCHAR *pstrTitleName); 79 | BOOL ShowSaveFileDlg(HWND hwnd, TCHAR *pstrFileName, TCHAR *pstrTitleName); 80 | void HandleDropFiles(HWND hwnd, HDROP hDrop); 81 | void NeatpadOpenFile(HWND hwnd, TCHAR *szFile); 82 | 83 | // 84 | // NeatUtils.c functions 85 | // 86 | BOOL ResolveShortcut(TCHAR *pszShortcut, TCHAR *pszFilePath, int nPathLen); 87 | BOOL SaveFileData(TCHAR *szPath, HWND hwnd); 88 | BOOL LoadFileData(TCHAR *szPath, HWND hwnd); 89 | 90 | BOOL CheckMenuCommand(HMENU hMenu, int nCommandId, BOOL fChecked); 91 | BOOL EnableMenuCommand(HMENU hmenu, int nCommandId, BOOL fEnable); 92 | BOOL EnableDlgItem(HWND hDlg, UINT nCommandId, BOOL fEnable); 93 | void CenterWindow(HWND hwnd); 94 | BOOL EnableDialogTheme(HWND hwnd); 95 | 96 | 97 | HFONT EasyCreateFont(int nPointSize, BOOL fBold, DWORD dwQuality, TCHAR *szFace); 98 | int PointsToLogical(int nPointSize); 99 | HFONT CreateBoldFontFromHwnd(HWND hwnd); 100 | 101 | // 102 | // Search.c functions 103 | // 104 | #define FIND_PAGE 0 105 | #define REPLACE_PAGE 1 106 | #define GOTO_PAGE 2 107 | HWND ShowFindDlg(HWND hwndParent, UINT nPage); 108 | 109 | 110 | // 111 | // Toolbars.c functions 112 | // 113 | HWND CreateStatusBar (HWND hwndParent); 114 | void SetStatusBarParts(HWND hwndSB); 115 | int StatusBarMenuSelect(HWND hwnd, HWND hwndSB, WPARAM wParam, LPARAM lParam); 116 | void SetStatusBarText(HWND hwndSB, UINT nPart, UINT uStyle, TCHAR *fmt, ...); 117 | 118 | #ifdef __cplusplus 119 | } 120 | #endif 121 | 122 | #endif -------------------------------------------------------------------------------- /Neatpad/OpenSave.c: -------------------------------------------------------------------------------- 1 | // 2 | // OpenSave.c 3 | // 4 | // Open+Save dialog support for Neatpad 5 | // 6 | // www.catch22.net 7 | // Written by J Brown 2004 8 | // 9 | // 10 | #define _CRT_SECURE_NO_DEPRECATE 11 | #define _CRT_NON_CONFORMING_SWPRINTFS 12 | #define _WIN32_WINNT 0x501 13 | #define STRICT 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "Neatpad.h" 21 | #include "..\TextView\TextView.h" 22 | #include "resource.h" 23 | 24 | static BOOL g_fFirstTime = TRUE; 25 | 26 | typedef struct 27 | { 28 | TCHAR szFile[MAX_PATH]; 29 | HWND hwndNotify; 30 | HANDLE hQuitEvent; 31 | UINT uMsg; 32 | } NOTIFY_DATA; 33 | 34 | DWORD WINAPI ChangeNotifyThread(NOTIFY_DATA *pnd) 35 | { 36 | HANDLE hChange; 37 | DWORD dwResult; 38 | TCHAR szDirectory[MAX_PATH]; 39 | 40 | lstrcpy(szDirectory, pnd->szFile); 41 | 42 | // get the directory name from filename 43 | if(GetFileAttributes(szDirectory) != FILE_ATTRIBUTE_DIRECTORY) 44 | { 45 | TCHAR *slash = _tcsrchr(szDirectory, _T('\\')); 46 | if(slash) *slash = '\0'; 47 | } 48 | 49 | // watch the specified directory for changes 50 | hChange = FindFirstChangeNotification(szDirectory, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE); 51 | 52 | do 53 | { 54 | HANDLE hEventList[2] = { hChange, pnd->hQuitEvent }; 55 | 56 | if((dwResult = WaitForMultipleObjects(1, hEventList, FALSE, INFINITE)) == WAIT_OBJECT_0) 57 | { 58 | PostMessage(pnd->hwndNotify, pnd->uMsg, 0, (LPARAM)pnd); 59 | } 60 | 61 | FindNextChangeNotification(hChange); 62 | } 63 | while(dwResult == WAIT_OBJECT_0); 64 | 65 | // cleanup 66 | FindCloseChangeNotification(hChange); 67 | free(pnd); 68 | 69 | return 0; 70 | } 71 | 72 | BOOL NotifyFileChange(TCHAR *szPathName, HWND hwndNotify, HANDLE hQuitEvent) 73 | { 74 | NOTIFY_DATA *pnd = malloc(sizeof(NOTIFY_DATA)); 75 | 76 | pnd->hQuitEvent = 0; 77 | pnd->hwndNotify = hwndNotify; 78 | pnd->uMsg = WM_USER; 79 | lstrcpy(pnd->szFile, szPathName); 80 | 81 | CreateThread(0, 0, ChangeNotifyThread, pnd, 0, 0); 82 | 83 | return TRUE; 84 | } 85 | 86 | 87 | // 88 | // Hook procedure for the Open dialog, 89 | // used to center the dialog on 1st invokation 90 | // 91 | UINT_PTR CALLBACK OpenHookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 92 | { 93 | switch(msg) 94 | { 95 | case WM_INITDIALOG: 96 | 97 | if(g_fFirstTime) 98 | { 99 | CenterWindow(GetParent(hwnd)); 100 | g_fFirstTime = FALSE; 101 | } 102 | 103 | return TRUE; 104 | } 105 | 106 | return 0; 107 | } 108 | 109 | // 110 | // Show the GetOpenFileName common dialog 111 | // 112 | BOOL ShowOpenFileDlg(HWND hwnd, TCHAR *pstrFileName, TCHAR *pstrTitleName) 113 | { 114 | TCHAR *szFilter = _T("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0"); 115 | 116 | OPENFILENAME ofn = { sizeof(ofn) }; 117 | 118 | ofn.hwndOwner = hwnd; 119 | ofn.hInstance = g_hResourceModule; 120 | ofn.lpstrFilter = szFilter; 121 | ofn.lpstrFile = pstrFileName; 122 | ofn.lpstrFileTitle = pstrTitleName; 123 | ofn.lpfnHook = OpenHookProc; 124 | 125 | ofn.nFilterIndex = 1; 126 | ofn.nMaxFile = _MAX_PATH; 127 | ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT; 128 | 129 | // flags to control appearance of open-file dialog 130 | ofn.Flags = OFN_EXPLORER | 131 | OFN_ENABLESIZING | 132 | OFN_ALLOWMULTISELECT | 133 | OFN_FILEMUSTEXIST | 134 | 0;//OFN_ENABLEHOOK ; 135 | 136 | return GetOpenFileName(&ofn); 137 | } 138 | 139 | // 140 | // Hook procedure for the SaveAs dialog, 141 | // used to center the dialog on 1st invokation and manage the 'encoding' combobox 142 | // 143 | UINT_PTR CALLBACK SaveHookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 144 | { 145 | HWND hwndCombo; 146 | RECT rect; 147 | 148 | switch(msg) 149 | { 150 | case WM_INITDIALOG: 151 | 152 | if(g_fFirstTime) 153 | { 154 | CenterWindow(GetParent(hwnd)); 155 | g_fFirstTime = FALSE; 156 | } 157 | 158 | SendDlgItemMessage(hwnd, IDC_ENCODINGLIST, CB_ADDSTRING, 0, (LPARAM)_T("Ascii")); 159 | SendDlgItemMessage(hwnd, IDC_ENCODINGLIST, CB_ADDSTRING, 0, (LPARAM)_T("Unicode (UTF-8)")); 160 | SendDlgItemMessage(hwnd, IDC_ENCODINGLIST, CB_ADDSTRING, 0, (LPARAM)_T("Unicode (UTF-16)")); 161 | SendDlgItemMessage(hwnd, IDC_ENCODINGLIST, CB_ADDSTRING, 0, (LPARAM)_T("Unicode (UTF-16, Big Endian)")); 162 | SendDlgItemMessage(hwnd, IDC_ENCODINGLIST, CB_SETCURSEL, 0, 0); 163 | 164 | SendDlgItemMessage(hwnd, IDC_LINEFMTLIST, CB_ADDSTRING, 0, (LPARAM)_T("Keep Existing")); 165 | SendDlgItemMessage(hwnd, IDC_LINEFMTLIST, CB_ADDSTRING, 0, (LPARAM)_T("Windows (CR/LF)")); 166 | SendDlgItemMessage(hwnd, IDC_LINEFMTLIST, CB_ADDSTRING, 0, (LPARAM)_T("Unix (LF)")); 167 | SendDlgItemMessage(hwnd, IDC_LINEFMTLIST, CB_ADDSTRING, 0, (LPARAM)_T("Mac (CR)")); 168 | SendDlgItemMessage(hwnd, IDC_LINEFMTLIST, CB_ADDSTRING, 0, (LPARAM)_T("Unicode (LT)")); 169 | SendDlgItemMessage(hwnd, IDC_LINEFMTLIST, CB_SETCURSEL, 0, 0); 170 | 171 | 172 | return TRUE; 173 | 174 | case WM_SIZE: 175 | 176 | // Get the coordinates of the 'Save As Type' combo 177 | hwndCombo = GetDlgItem(GetParent(hwnd), 0x470); 178 | 179 | if(hwndCombo) 180 | { 181 | GetWindowRect(hwndCombo, &rect); 182 | ScreenToClient(hwnd, (POINT *)&rect.left); 183 | ScreenToClient(hwnd, (POINT*)&rect.right); 184 | 185 | // Resize our 'Line Format' combo to be the same width 186 | hwndCombo = GetDlgItem(hwnd, IDC_LINEFMTLIST); 187 | SetWindowPos(hwndCombo, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 188 | SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); 189 | 190 | // Resize our 'Encoding' combo to be the same width 191 | hwndCombo = GetDlgItem(hwnd, IDC_ENCODINGLIST); 192 | SetWindowPos(hwndCombo, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 193 | SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); 194 | } 195 | 196 | return 0; 197 | 198 | default: 199 | break; 200 | } 201 | 202 | return 0; 203 | } 204 | 205 | // 206 | // Show the GetSaveFileName common dialog 207 | // 208 | BOOL ShowSaveFileDlg(HWND hwnd, TCHAR *pstrFileName, TCHAR *pstrTitleName) 209 | { 210 | TCHAR *szFilter = _T("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0"); 211 | 212 | OPENFILENAME ofn = { sizeof(ofn) }; 213 | 214 | ofn.hwndOwner = hwnd; 215 | ofn.hInstance = g_hResourceModule; 216 | ofn.lpstrFilter = szFilter; 217 | ofn.lpstrFile = pstrFileName; 218 | ofn.lpstrFileTitle = pstrTitleName; 219 | ofn.lpTemplateName = MAKEINTRESOURCE(IDD_SAVEFILE); 220 | ofn.lpfnHook = SaveHookProc; 221 | 222 | ofn.nFilterIndex = 1; 223 | ofn.nMaxFile = _MAX_PATH; 224 | ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT; 225 | 226 | // flags to control appearance of open-file dialog 227 | ofn.Flags = OFN_EXPLORER | 228 | OFN_ENABLESIZING | 229 | OFN_OVERWRITEPROMPT | 230 | OFN_ENABLETEMPLATE | 231 | OFN_ENABLEHOOK ; 232 | 233 | return GetSaveFileName(&ofn); 234 | } 235 | 236 | UINT FmtErrorMsg(HWND hwnd, DWORD dwMsgBoxType, DWORD dwError, TCHAR *szFmt, ...) 237 | { 238 | TCHAR *lpMsgBuf; 239 | TCHAR *ptr; 240 | UINT msgboxerr; 241 | va_list varg; 242 | 243 | va_start(varg, szFmt); 244 | 245 | FormatMessage( 246 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 247 | NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 248 | (LPTSTR) &lpMsgBuf, 0, NULL 249 | ); 250 | 251 | ptr = LocalAlloc(LPTR, LocalSize(lpMsgBuf) + 1000 * sizeof(TCHAR)); 252 | _vstprintf(ptr, szFmt, varg); 253 | _tcscat(ptr, lpMsgBuf); 254 | 255 | msgboxerr = MessageBox(hwnd, ptr, APP_TITLE, dwMsgBoxType); 256 | 257 | LocalFree( lpMsgBuf ); 258 | LocalFree( ptr ); 259 | va_end(varg); 260 | 261 | return msgboxerr; 262 | } 263 | 264 | // 265 | // Open the specified file 266 | // 267 | BOOL DoOpenFile(HWND hwndMain, TCHAR *szFileName, TCHAR *szFileTitle) 268 | { 269 | int fmt, fmtlook[] = 270 | { 271 | IDM_VIEW_ASCII, IDM_VIEW_UTF8, IDM_VIEW_UTF16, IDM_VIEW_UTF16BE 272 | }; 273 | 274 | if(TextView_OpenFile(g_hwndTextView, szFileName)) 275 | { 276 | SetWindowFileName(hwndMain, szFileTitle, FALSE); 277 | g_fFileChanged = FALSE; 278 | 279 | fmt = TextView_GetFormat(g_hwndTextView); 280 | 281 | CheckMenuRadioItem(GetMenu(hwndMain), 282 | IDM_VIEW_ASCII, IDM_VIEW_UTF16BE, 283 | fmtlook[fmt], MF_BYCOMMAND); 284 | 285 | NotifyFileChange(szFileName, hwndMain, 0); 286 | return TRUE; 287 | } 288 | else 289 | { 290 | FmtErrorMsg(hwndMain, MB_OK|MB_ICONWARNING, GetLastError(), _T("Error opening \'%s\'\r\n\r\n"), szFileName); 291 | //FormatMessage 292 | //MessageBox(hwndMain, _T("Error opening file"), APP_TITLE, MB_ICONEXCLAMATION); 293 | return FALSE; 294 | } 295 | } 296 | 297 | void NeatpadOpenFile(HWND hwnd, TCHAR *szFile) 298 | { 299 | TCHAR *name; 300 | 301 | // save current file's position! 302 | SaveFileData(g_szFileName, hwnd); 303 | 304 | _tcscpy(g_szFileName, szFile); 305 | 306 | name = _tcsrchr(g_szFileName, '\\'); 307 | _tcscpy(g_szFileTitle, name ? name+1 : szFile); 308 | 309 | DoOpenFile(hwnd, g_szFileName, g_szFileTitle); 310 | } 311 | 312 | // 313 | // How to process WM_DROPFILES 314 | // 315 | void HandleDropFiles(HWND hwnd, HDROP hDrop) 316 | { 317 | TCHAR buf[MAX_PATH]; 318 | 319 | if(DragQueryFile(hDrop, 0, buf, MAX_PATH)) 320 | { 321 | TCHAR tmp[MAX_PATH]; 322 | 323 | if(ResolveShortcut(buf, tmp, MAX_PATH)) 324 | lstrcpy(buf,tmp); 325 | 326 | NeatpadOpenFile(hwnd, buf); 327 | } 328 | 329 | DragFinish(hDrop); 330 | } 331 | -------------------------------------------------------------------------------- /Neatpad/Options.c: -------------------------------------------------------------------------------- 1 | // 2 | // Neatpad 3 | // Options.c 4 | // 5 | // www.catch22.net 6 | // 7 | 8 | #define STRICT 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "resource.h" 15 | #include "Neatpad.h" 16 | #include "..\TextView\TextView.h" 17 | 18 | #pragma comment(lib, "comctl32.lib") 19 | 20 | #define CONTEXT_CMD_LOC _T("*\\shell\\Open with Neatpad\\command") 21 | #define CONTEXT_APP_LOC _T("*\\shell\\Open with Neatpad") 22 | 23 | #define IMAGEFILE_XOPT _T("Software\\Microsoft\\Windows NT\\CurrentVersion")\ 24 | _T("\\Image File Execution Options\\Notepad.exe") 25 | 26 | 27 | 28 | BOOL CALLBACK FontOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 29 | BOOL CALLBACK MiscOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 30 | BOOL CALLBACK DisplayOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 31 | 32 | LONG g_nFontSize; 33 | BOOL g_fFontBold; 34 | TCHAR g_szFontName[LF_FACESIZE]; 35 | LONG g_nFontSmoothing; 36 | 37 | LONG g_nPaddingAbove; 38 | LONG g_nPaddingBelow; 39 | LONG g_fPaddingFlags; 40 | BOOL g_fLineNumbers; 41 | BOOL g_fLongLines; 42 | BOOL g_fSelMargin; 43 | BOOL g_fSaveOnExit; 44 | int g_nLongLineLimit; 45 | BOOL g_nHLCurLine; 46 | BOOL g_fShowStatusbar; 47 | BOOL g_fAddToExplorer = 0; 48 | BOOL g_fReplaceNotepad = 0; 49 | 50 | COLORREF g_rgbColourList[TXC_MAX_COLOURS]; 51 | COLORREF g_rgbCustColours[16]; 52 | extern COLORREF g_rgbAutoColourList[]; 53 | 54 | // Get a binary buffer from the registry 55 | BOOL GetSettingBin(HKEY hkey, TCHAR szKeyName[], PVOID pBuffer, LONG nLength) 56 | { 57 | ZeroMemory(pBuffer, nLength); 58 | return !RegQueryValueEx(hkey, szKeyName, 0, 0, (BYTE *)pBuffer, &nLength); 59 | } 60 | 61 | // Get an integer value from the registry 62 | BOOL GetSettingInt(HKEY hkey, TCHAR szKeyName[], LONG *pnReturnVal, LONG nDefault) 63 | { 64 | ULONG len = sizeof(nDefault); 65 | 66 | *pnReturnVal = nDefault; 67 | 68 | return !RegQueryValueEx(hkey, szKeyName, 0, 0, (BYTE *)pnReturnVal, &len); 69 | } 70 | 71 | // Get a string buffer from the registry 72 | BOOL GetSettingStr(HKEY hkey, TCHAR szKeyName[], TCHAR pszReturnStr[], DWORD nLength, TCHAR szDefault[]) 73 | { 74 | ULONG len = nLength * sizeof(TCHAR); 75 | 76 | lstrcpyn(pszReturnStr, szDefault, nLength); 77 | 78 | return !RegQueryValueEx(hkey, szKeyName, 0, 0, (BYTE *)pszReturnStr, &len); 79 | } 80 | 81 | // Write a binary value from the registry 82 | BOOL WriteSettingBin(HKEY hkey, TCHAR szKeyName[], PVOID pData, ULONG nLength) 83 | { 84 | return !RegSetValueEx(hkey, szKeyName, 0, REG_BINARY, (BYTE *)pData, nLength); 85 | } 86 | 87 | // Write an integer value from the registry 88 | BOOL WriteSettingInt(HKEY hkey, TCHAR szKeyName[], LONG nValue) 89 | { 90 | return !RegSetValueEx(hkey, szKeyName, 0, REG_DWORD, (BYTE *)&nValue, sizeof(nValue)); 91 | } 92 | 93 | // Get a string buffer from the registry 94 | BOOL WriteSettingStr(HKEY hkey, TCHAR szKeyName[], TCHAR szString[]) 95 | { 96 | return !RegSetValueEx(hkey, szKeyName, 0, REG_SZ, (BYTE *)szString, (lstrlen(szString) + 1) * sizeof(TCHAR)); 97 | } 98 | 99 | // 100 | // Add or remove Neatpad from the Explorer context-menu 101 | // 102 | BOOL SetExplorerContextMenu(BOOL fAddToMenu) 103 | { 104 | HRESULT hr; 105 | 106 | if(fAddToMenu) 107 | { 108 | TCHAR szAppPath[MAX_PATH]; 109 | TCHAR szDefaultStr[MAX_PATH]; 110 | 111 | GetModuleFileName(0, szAppPath, MAX_PATH); 112 | 113 | wsprintf(szDefaultStr, _T("\"%s\" \"%%1\""), szAppPath); 114 | 115 | hr = RegSetValue(HKEY_CLASSES_ROOT, CONTEXT_CMD_LOC, REG_SZ, szDefaultStr, lstrlen(szDefaultStr) * sizeof(TCHAR)); 116 | } 117 | else 118 | { 119 | hr = RegDeleteKey(HKEY_CLASSES_ROOT, CONTEXT_CMD_LOC); 120 | 121 | if(hr == ERROR_SUCCESS) 122 | hr = RegDeleteKey(HKEY_CLASSES_ROOT, CONTEXT_APP_LOC); 123 | } 124 | 125 | return (hr == ERROR_SUCCESS) ? TRUE : FALSE; 126 | } 127 | 128 | // 129 | // Replace/Restore Notepad (with Neatpad) as the default text editor, by 130 | // manipulating the Image-File-Execution-Options debugger setting for NOTEPAD.EXE 131 | // 132 | BOOL SetImageFileExecutionOptions(BOOL fReplaceWithCurrentApp) 133 | { 134 | HKEY hKey; 135 | HRESULT hr; 136 | TCHAR szPath[MAX_PATH]; 137 | 138 | // create an 'ImageFileExecutionOptions' entry for the standard Notepad app 139 | hr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, IMAGEFILE_XOPT, 0, 0, 0, KEY_WRITE, 0, &hKey, 0); 140 | 141 | if(hr != ERROR_SUCCESS) 142 | return FALSE; 143 | 144 | // get path of current exe 145 | GetModuleFileName(0, szPath+1, MAX_PATH); 146 | 147 | // enclose it in double-quotes 148 | szPath[0] = '\"'; 149 | lstrcat(szPath, _T("\"")); 150 | lstrcat(szPath, _T(" -ifeo")); 151 | 152 | // set the 'debugger' key so that whenever notepad.exe is executed, neatpad runs instead 153 | if(fReplaceWithCurrentApp) 154 | WriteSettingStr(hKey, _T("Debugger"), szPath); 155 | else 156 | RegDeleteValue(hKey, _T("Debugger")); 157 | 158 | RegCloseKey(hKey); 159 | return TRUE; 160 | } 161 | 162 | void LoadRegSettings() 163 | { 164 | HKEY hKey, hColKey; 165 | 166 | // open registry location for reading 167 | RegCreateKeyEx(HKEY_CURRENT_USER, REGLOC, 0, 0, 0, KEY_READ, 0, &hKey, 0); 168 | 169 | GetSettingInt(hKey, _T("FontSize"), &g_nFontSize, 10); 170 | GetSettingInt(hKey, _T("FontBold"), &g_fFontBold, FALSE); 171 | GetSettingStr(hKey, _T("FontName"), g_szFontName, LF_FACESIZE, _T("Courier New")); 172 | GetSettingInt(hKey, _T("FontSmooth"), &g_nFontSmoothing, DEFAULT_QUALITY); 173 | 174 | GetSettingInt(hKey, _T("PaddingAbove"), &g_nPaddingAbove, 0); 175 | GetSettingInt(hKey, _T("PaddingBelow"), &g_nPaddingBelow, 1); 176 | GetSettingInt(hKey, _T("PaddingFlags"), &g_fPaddingFlags, COURIERNEW|LUCIDACONS); 177 | 178 | GetSettingInt(hKey, _T("SelMargin"), &g_fSelMargin, TRUE); 179 | GetSettingInt(hKey, _T("LineNumbers"), &g_fLineNumbers, FALSE); 180 | GetSettingInt(hKey, _T("LongLines"), &g_fLongLines, TRUE); 181 | GetSettingInt(hKey, _T("LongLineLimit"), &g_nLongLineLimit, 80); 182 | GetSettingInt(hKey, _T("SaveOnExit"), &g_fSaveOnExit, TRUE); 183 | GetSettingInt(hKey, _T("HLCurLine"), &g_nHLCurLine, FALSE); 184 | 185 | GetSettingInt(hKey, _T("AddExplorer"), &g_fAddToExplorer, FALSE); 186 | GetSettingInt(hKey, _T("ReplaceNotepad"), &g_fReplaceNotepad, FALSE); 187 | GetSettingInt(hKey, _T("ShowStatusbar"), &g_fShowStatusbar, FALSE); 188 | 189 | // read the display colours 190 | RegCreateKeyEx(hKey, _T("Colours"), 0, 0, 0, KEY_READ, 0, &hColKey, 0); 191 | 192 | GetSettingInt(hColKey, _T("Foreground"), &g_rgbColourList[TXC_FOREGROUND], g_rgbAutoColourList[TXC_FOREGROUND] ); 193 | GetSettingInt(hColKey, _T("Background"), &g_rgbColourList[TXC_BACKGROUND], g_rgbAutoColourList[TXC_BACKGROUND] ); 194 | GetSettingInt(hColKey, _T("SelFG"), &g_rgbColourList[TXC_HIGHLIGHTTEXT], g_rgbAutoColourList[TXC_HIGHLIGHTTEXT] ); 195 | GetSettingInt(hColKey, _T("SelBG"), &g_rgbColourList[TXC_HIGHLIGHT], g_rgbAutoColourList[TXC_HIGHLIGHT] ); 196 | GetSettingInt(hColKey, _T("SelFG2"), &g_rgbColourList[TXC_HIGHLIGHTTEXT2], g_rgbAutoColourList[TXC_HIGHLIGHTTEXT2] ); 197 | GetSettingInt(hColKey, _T("SelBG2"), &g_rgbColourList[TXC_HIGHLIGHT2], g_rgbAutoColourList[TXC_HIGHLIGHT2] ); 198 | GetSettingInt(hColKey, _T("Margin1"), &g_rgbColourList[TXC_SELMARGIN1], g_rgbAutoColourList[TXC_SELMARGIN1] ); 199 | GetSettingInt(hColKey, _T("Margin2"), &g_rgbColourList[TXC_SELMARGIN2], g_rgbAutoColourList[TXC_SELMARGIN2] ); 200 | GetSettingInt(hColKey, _T("LinenoText"), &g_rgbColourList[TXC_LINENUMBERTEXT], g_rgbAutoColourList[TXC_LINENUMBERTEXT] ); 201 | GetSettingInt(hColKey, _T("Lineno"), &g_rgbColourList[TXC_LINENUMBER], g_rgbAutoColourList[TXC_LINENUMBER] ); 202 | GetSettingInt(hColKey, _T("LongLineText"), &g_rgbColourList[TXC_LONGLINETEXT], g_rgbAutoColourList[TXC_LONGLINETEXT] ); 203 | GetSettingInt(hColKey, _T("LongLine"), &g_rgbColourList[TXC_LONGLINE], g_rgbAutoColourList[TXC_LONGLINE] ); 204 | GetSettingInt(hColKey, _T("CurlineText"), &g_rgbColourList[TXC_CURRENTLINETEXT], g_rgbAutoColourList[TXC_CURRENTLINETEXT] ); 205 | GetSettingInt(hColKey, _T("Curline"), &g_rgbColourList[TXC_CURRENTLINE], g_rgbAutoColourList[TXC_CURRENTLINE] ); 206 | 207 | GetSettingBin(hColKey, _T("Custom"), g_rgbCustColours, sizeof(g_rgbCustColours)); 208 | 209 | RegCloseKey(hColKey); 210 | RegCloseKey(hKey); 211 | } 212 | 213 | void LoadRegSysSettings() 214 | { 215 | HKEY hKey; 216 | 217 | RegCreateKeyEx(HKEY_CURRENT_USER, REGLOC, 0, 0, 0, KEY_READ, 0, &hKey, 0); 218 | GetSettingInt(hKey, _T("AddExplorer"), &g_fAddToExplorer, FALSE); 219 | GetSettingInt(hKey, _T("ReplaceNotepad"), &g_fReplaceNotepad, FALSE); 220 | RegCloseKey(hKey); 221 | } 222 | 223 | void SaveRegSysSettings() 224 | { 225 | HKEY hKey; 226 | 227 | RegCreateKeyEx(HKEY_CURRENT_USER, REGLOC, 0, 0, 0, KEY_WRITE, 0, &hKey, 0); 228 | WriteSettingInt(hKey, _T("AddExplorer"), g_fAddToExplorer); 229 | WriteSettingInt(hKey, _T("ReplaceNotepad"), g_fReplaceNotepad); 230 | RegCloseKey(hKey); 231 | } 232 | 233 | void SaveRegSettings() 234 | { 235 | HKEY hKey, hColKey; 236 | 237 | // open registry location for writing 238 | RegCreateKeyEx(HKEY_CURRENT_USER, REGLOC, 0, 0, 0, KEY_WRITE, 0, &hKey, 0); 239 | 240 | WriteSettingInt(hKey, _T("FontSize"), g_nFontSize); 241 | WriteSettingInt(hKey, _T("FontBold"), g_fFontBold); 242 | WriteSettingStr(hKey, _T("FontName"), g_szFontName); 243 | WriteSettingInt(hKey, _T("FontSmooth"), g_nFontSmoothing); 244 | 245 | WriteSettingInt(hKey, _T("PaddingAbove"), g_nPaddingAbove); 246 | WriteSettingInt(hKey, _T("PaddingBelow"), g_nPaddingBelow); 247 | WriteSettingInt(hKey, _T("PaddingFlags"), g_fPaddingFlags); 248 | 249 | WriteSettingInt(hKey, _T("SelMargin"), g_fSelMargin); 250 | WriteSettingInt(hKey, _T("LineNumbers"), g_fLineNumbers); 251 | WriteSettingInt(hKey, _T("LongLines"), g_fLongLines); 252 | WriteSettingInt(hKey, _T("SaveOnExit"), g_fSaveOnExit); 253 | WriteSettingInt(hKey, _T("LongLineLimit"),g_nLongLineLimit); 254 | WriteSettingInt(hKey, _T("HLCurLine"), g_nHLCurLine); 255 | 256 | WriteSettingInt(hKey, _T("AddExplorer"), g_fAddToExplorer); 257 | WriteSettingInt(hKey, _T("ReplaceNotepad"), g_fReplaceNotepad); 258 | WriteSettingInt(hKey, _T("ShowStatusbar"), g_fShowStatusbar); 259 | 260 | // write the display colours 261 | RegCreateKeyEx(hKey, _T("Colours"), 0, 0, 0, KEY_WRITE, 0, &hColKey, 0); 262 | 263 | WriteSettingInt(hColKey, _T("Foreground"), g_rgbColourList[TXC_FOREGROUND]); 264 | WriteSettingInt(hColKey, _T("Background"), g_rgbColourList[TXC_BACKGROUND]); 265 | WriteSettingInt(hColKey, _T("SelFG"), g_rgbColourList[TXC_HIGHLIGHTTEXT]); 266 | WriteSettingInt(hColKey, _T("SelBG"), g_rgbColourList[TXC_HIGHLIGHT]); 267 | WriteSettingInt(hColKey, _T("SelFG2"), g_rgbColourList[TXC_HIGHLIGHTTEXT2]); 268 | WriteSettingInt(hColKey, _T("SelBG2"), g_rgbColourList[TXC_HIGHLIGHT2]); 269 | 270 | WriteSettingInt(hColKey, _T("Margin1"), g_rgbColourList[TXC_SELMARGIN1]); 271 | WriteSettingInt(hColKey, _T("Margin2"), g_rgbColourList[TXC_SELMARGIN2]); 272 | WriteSettingInt(hColKey, _T("LinenoText"), g_rgbColourList[TXC_LINENUMBERTEXT]); 273 | WriteSettingInt(hColKey, _T("Lineno"), g_rgbColourList[TXC_LINENUMBER]); 274 | WriteSettingInt(hColKey, _T("LongLineText"),g_rgbColourList[TXC_LONGLINETEXT]); 275 | WriteSettingInt(hColKey, _T("LongLine"), g_rgbColourList[TXC_LONGLINE]); 276 | 277 | WriteSettingInt(hColKey, _T("CurlineText"), g_rgbColourList[TXC_CURRENTLINETEXT]); 278 | WriteSettingInt(hColKey, _T("Curline"), g_rgbColourList[TXC_CURRENTLINE]); 279 | 280 | 281 | WriteSettingBin(hColKey, _T("Custom"), g_rgbCustColours, sizeof(g_rgbCustColours)); 282 | 283 | RegCloseKey(hColKey); 284 | RegCloseKey(hKey); 285 | } 286 | 287 | void ApplyRegSettings() 288 | { 289 | int i; 290 | 291 | if(g_hFont) 292 | DeleteObject(g_hFont); 293 | 294 | g_hFont = EasyCreateFont(g_nFontSize, g_fFontBold, g_nFontSmoothing, g_szFontName); 295 | 296 | TextView_SetLineSpacing(g_hwndTextView, g_nPaddingAbove, g_nPaddingBelow); 297 | 298 | TextView_SetStyleBool(g_hwndTextView, TXS_SELMARGIN, g_fSelMargin); 299 | TextView_SetStyleBool(g_hwndTextView, TXS_LINENUMBERS, g_fLineNumbers); 300 | TextView_SetStyleBool(g_hwndTextView, TXS_LONGLINES, g_fLongLines); 301 | 302 | TextView_SetStyleBool(g_hwndTextView, TXS_HIGHLIGHTCURLINE, g_nHLCurLine); 303 | 304 | TextView_SetCaretWidth(g_hwndTextView, 2); 305 | TextView_SetLongLine(g_hwndTextView, g_nLongLineLimit); 306 | 307 | SendMessage(g_hwndTextView, WM_SETFONT, (WPARAM)g_hFont, 0); 308 | 309 | for(i = 0; i < TXC_MAX_COLOURS; i++) 310 | { 311 | TextView_SetColor(g_hwndTextView, i, g_rgbColourList[i]); 312 | } 313 | 314 | // 315 | // System-wide options require Administrator access. On Vista we 316 | // need to elevate using the UAC prompt. Only do this if the settings have actually 317 | // changed 318 | // 319 | //SetExplorerContextMenu(g_fAddToExplorerContextMenu); 320 | //SetImageFileExecutionOptions(g_fReplaceNotepad); 321 | } 322 | 323 | void ShowOptions(HWND hwndParent) 324 | { 325 | PROPSHEETHEADER psh = { sizeof(psh) }; 326 | PROPSHEETPAGE psp[3] = { { sizeof(psp[0]) }, 327 | { sizeof(psp[1]) }, 328 | { sizeof(psp[2]) }, 329 | }; 330 | 331 | CoInitialize(0); 332 | 333 | // configure property sheet 334 | psh.dwFlags = PSH_PROPSHEETPAGE; 335 | psh.hwndParent = hwndParent; 336 | psh.nPages = sizeof(psp) / sizeof(psp[0]); 337 | psh.ppsp = psp; 338 | psh.pszCaption = _T("Options"); 339 | 340 | // configure property sheet page(1) 341 | psp[0].dwFlags = PSP_USETITLE; 342 | psp[0].hInstance = g_hResourceModule;//GetModuleHandle(0); 343 | psp[0].pfnDlgProc = FontOptionsDlgProc; 344 | psp[0].pszTemplate = MAKEINTRESOURCE(IDD_FONT); 345 | psp[0].pszTitle = _T("Font"); 346 | 347 | // configure property sheet page(2) 348 | psp[1].dwFlags = PSP_USETITLE; 349 | psp[1].hInstance = g_hResourceModule;//GetModuleHandle(0); 350 | psp[1].pfnDlgProc = DisplayOptionsDlgProc; 351 | psp[1].pszTemplate = MAKEINTRESOURCE(IDD_DISPLAY); 352 | psp[1].pszTitle = _T("Display"); 353 | 354 | // configure property sheet page(3) 355 | psp[2].dwFlags = PSP_USETITLE; 356 | psp[2].hInstance = g_hResourceModule;//GetModuleHandle(0); 357 | psp[2].pfnDlgProc = MiscOptionsDlgProc; 358 | psp[2].pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); 359 | psp[2].pszTitle = _T("Settings"); 360 | 361 | if(PropertySheet(&psh)) 362 | { 363 | ApplyRegSettings(); 364 | } 365 | 366 | CoUninitialize(); 367 | } 368 | -------------------------------------------------------------------------------- /Neatpad/OptionsDisplay.c: -------------------------------------------------------------------------------- 1 | // 2 | // Neatpad 3 | // OptionsDisplay.c 4 | // 5 | // www.catch22.net 6 | // 7 | 8 | #define STRICT 9 | #define WIN32_LEAN_AND_MEAN 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "Neatpad.h" 16 | #include "resource.h" 17 | 18 | // 19 | // Dialogbox procedure for the FONT pane 20 | // 21 | BOOL CALLBACK DisplayOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 22 | { 23 | PSHNOTIFY *pshn; 24 | 25 | switch(msg) 26 | { 27 | case WM_INITDIALOG: 28 | 29 | SendDlgItemMessage(hwnd, IDC_LONGLINEMODE, CB_ADDSTRING, 0, (LPARAM)_T("No Highlighting")); 30 | SendDlgItemMessage(hwnd, IDC_LONGLINEMODE, CB_ADDSTRING, 0, (LPARAM)_T("Highlight long lines")); 31 | 32 | SendDlgItemMessage(hwnd, IDC_LONGLINEMODE, CB_SETCURSEL, g_fLongLines, 0); 33 | 34 | SetDlgItemInt(hwnd, IDC_LONGLINELIM, g_nLongLineLimit, FALSE); 35 | EnableDlgItem(hwnd, IDC_LONGLINELIM, g_fLongLines); 36 | 37 | CheckDlgButton(hwnd, IDC_LINENOS, g_fLineNumbers); 38 | CheckDlgButton(hwnd, IDC_SELMARGIN, g_fSelMargin); 39 | 40 | CheckDlgButton(hwnd, IDC_HIGHLIGHTCURLINE, g_nHLCurLine); 41 | 42 | return TRUE; 43 | 44 | case WM_CLOSE: 45 | return TRUE; 46 | 47 | case WM_NOTIFY: 48 | 49 | pshn = (PSHNOTIFY *)lParam; 50 | 51 | if(pshn->hdr.code == PSN_APPLY) 52 | { 53 | g_fLineNumbers = IsDlgButtonChecked(hwnd, IDC_LINENOS); 54 | g_fSelMargin = IsDlgButtonChecked(hwnd, IDC_SELMARGIN); 55 | g_fLongLines = SendDlgItemMessage(hwnd, IDC_LONGLINEMODE, CB_GETCURSEL, 0, 0); 56 | g_nLongLineLimit = GetDlgItemInt(hwnd, IDC_LONGLINELIM, 0, FALSE); 57 | g_nHLCurLine = IsDlgButtonChecked(hwnd, IDC_HIGHLIGHTCURLINE); 58 | 59 | return TRUE; 60 | } 61 | 62 | return FALSE; 63 | 64 | case WM_COMMAND: 65 | 66 | switch(LOWORD(wParam)) 67 | { 68 | case IDC_LONGLINEMODE: 69 | 70 | if(HIWORD(wParam) == CBN_SELCHANGE) 71 | { 72 | int idx = SendDlgItemMessage(hwnd, IDC_LONGLINEMODE, CB_GETCURSEL, 0, 0); 73 | EnableDlgItem(hwnd, IDC_LONGLINELIM, idx); 74 | } 75 | 76 | return TRUE; 77 | 78 | case IDCANCEL: 79 | return TRUE; 80 | } 81 | 82 | return FALSE; 83 | } 84 | 85 | return FALSE; 86 | } 87 | -------------------------------------------------------------------------------- /Neatpad/OptionsMisc.c: -------------------------------------------------------------------------------- 1 | // 2 | // Neatpad 3 | // OptionsMisc.c 4 | // 5 | // Use the following registry key to replace 'notepad' with 'neatpad' 6 | // 7 | // "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Notepad" 8 | // REG_SZ "Debugger"="C:\path\Neatpad.exe" 9 | // 10 | // 11 | // www.catch22.net 12 | // 13 | 14 | #define STRICT 15 | #define WIN32_LEAN_AND_MEAN 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "Neatpad.h" 22 | #include "resource.h" 23 | 24 | BOOL ElevateToAdmin(HWND hwnd, BOOL fChecked1, BOOL fChecked2)//TCHAR *szParams) 25 | { 26 | //// http://codefromthe70s.org/vistatutorial.asp 27 | SHELLEXECUTEINFO sei = { sizeof(sei) }; 28 | TCHAR szFile[MAX_PATH]; 29 | TCHAR szParams[32]; 30 | 31 | BOOL success = FALSE; 32 | 33 | wsprintf(szParams, _T("-uac %d %d"), fChecked1, fChecked2); 34 | 35 | GetModuleFileName(0, szFile, MAX_PATH); 36 | 37 | sei.hwnd = hwnd; 38 | sei.lpVerb = L"runas"; 39 | sei.lpFile = szFile; 40 | sei.lpParameters = szParams;//L"oof"; 41 | sei.fMask = SEE_MASK_NOCLOSEPROCESS; 42 | sei.nShow = SW_SHOWNORMAL; 43 | 44 | if(ShellExecuteEx(&sei)) 45 | { 46 | WaitForSingleObject(sei.hProcess, INFINITE); 47 | GetExitCodeProcess(sei.hProcess, &success); 48 | CloseHandle(sei.hProcess); 49 | success = !success; 50 | } 51 | 52 | return success; 53 | } 54 | 55 | void ApplyAdminSettings(HWND hwnd) 56 | { 57 | BOOL fChecked1; 58 | BOOL fChecked2; 59 | 60 | fChecked1 = IsDlgButtonChecked(hwnd, IDC_ADDCONTEXT); 61 | fChecked2 = IsDlgButtonChecked(hwnd, IDC_REPLACENOTEPAD); 62 | 63 | // do we need to elevate? 64 | if(g_fAddToExplorer != fChecked1 || g_fReplaceNotepad != fChecked2) 65 | { 66 | // spawn ourselves to set the HKLM registry keys 67 | ElevateToAdmin(hwnd, fChecked1, fChecked2); 68 | 69 | // the spawned process will do a SaveRegSysSettings if 70 | // it was successful - so do a 'Load' to refresh our own state 71 | LoadRegSysSettings(); 72 | } 73 | } 74 | 75 | // 76 | // Dialogbox procedure for the FONT pane 77 | // 78 | BOOL CALLBACK MiscOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 79 | { 80 | PSHNOTIFY *pshn; 81 | HICON hShield; 82 | 83 | switch(msg) 84 | { 85 | 86 | case WM_INITDIALOG: 87 | 88 | //oof(hwnd); 89 | 90 | // load the 'vista shield icon' 91 | hShield = LoadImage(0, MAKEINTRESOURCE(106), IMAGE_ICON, 32, 32, LR_CREATEDIBSECTION);//IDI_SHIELD)); 92 | 93 | // display the next-best-thing if not running on Vista 94 | if(hShield == 0) 95 | { 96 | hShield = LoadIcon(0, MAKEINTRESOURCE(IDI_INFORMATION)); 97 | } 98 | 99 | SendDlgItemMessage(hwnd, IDC_SHIELD, STM_SETICON, (WPARAM)hShield, 0); 100 | 101 | CheckDlgButton(hwnd, IDC_ADDCONTEXT, g_fAddToExplorer); 102 | CheckDlgButton(hwnd, IDC_REPLACENOTEPAD, g_fReplaceNotepad); 103 | 104 | // disable 'replace notepad' option for Win9x 105 | EnableDlgItem(hwnd, IDC_REPLACENOTEPAD, (GetVersion() & 0x80000000) ? FALSE : TRUE); 106 | return TRUE; 107 | 108 | case WM_CLOSE: 109 | return TRUE; 110 | 111 | case WM_NOTIFY: 112 | 113 | pshn = (PSHNOTIFY *)lParam; 114 | 115 | if(pshn->hdr.code == PSN_APPLY) 116 | { 117 | ApplyAdminSettings(hwnd); 118 | return TRUE; 119 | } 120 | 121 | return FALSE; 122 | 123 | case WM_COMMAND: 124 | 125 | switch(LOWORD(wParam)) 126 | { 127 | case IDCANCEL: 128 | return TRUE; 129 | } 130 | 131 | return FALSE; 132 | } 133 | 134 | return FALSE; 135 | } 136 | -------------------------------------------------------------------------------- /Neatpad/Printing.c: -------------------------------------------------------------------------------- 1 | // 2 | // Neatpad 3 | // 4 | // Printing.c 5 | // 6 | // Not currently used but might be in the future 7 | // 8 | // www.catch22.net 9 | // 10 | 11 | #define STRICT 12 | 13 | #include 14 | #include 15 | 16 | static HANDLE g_hDevMode = NULL; 17 | static HANDLE g_hDevNames = NULL; 18 | extern HWND g_hwndTextView; 19 | static int g_nPrinterWidth = 0; 20 | 21 | int GetPrinterWidth(HDC hdcPrn); 22 | 23 | #pragma comment(lib, "DelayImp.lib") 24 | #pragma comment(linker, "/DELAYLOAD:Comdlg32.dll") 25 | 26 | HDC ShowPrintDlg(HWND hwndParent) 27 | { 28 | // if Windows 2000 and above 29 | if((GetVersion() & 0xff) >= 5) 30 | { 31 | PRINTDLGEX pdlgx = { sizeof(pdlgx), hwndParent, g_hDevMode, g_hDevNames }; 32 | pdlgx.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOCURRENTPAGE | PD_NOWARNING | PD_HIDEPRINTTOFILE; 33 | pdlgx.nStartPage = START_PAGE_GENERAL; 34 | 35 | if(S_OK == PrintDlgEx(&pdlgx) && pdlgx.dwResultAction != PD_RESULT_CANCEL) 36 | { 37 | g_hDevMode = pdlgx.hDevMode; 38 | g_hDevNames = pdlgx.hDevNames; 39 | g_nPrinterWidth = GetPrinterWidth(pdlgx.hDC); 40 | 41 | return pdlgx.hDC; 42 | } 43 | } 44 | // Win9x and WinNT need the old-style print dialog 45 | else 46 | { 47 | PRINTDLG pdlg = { sizeof(pdlg), hwndParent, g_hDevMode, g_hDevNames }; 48 | pdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE; 49 | 50 | if(PrintDlg(&pdlg)) 51 | { 52 | g_hDevMode = pdlg.hDevMode; 53 | g_hDevNames = pdlg.hDevNames; 54 | g_nPrinterWidth = GetPrinterWidth(pdlg.hDC); 55 | 56 | return pdlg.hDC; 57 | } 58 | } 59 | 60 | return NULL; 61 | } 62 | 63 | HDC GetDefaultPrinterDC() 64 | { 65 | PRINTDLG pdlg = { sizeof(pdlg), 0, 0, 0 }; 66 | pdlg.Flags = PD_RETURNDC|PD_RETURNDEFAULT; 67 | 68 | if(PrintDlg(&pdlg)) 69 | { 70 | g_hDevMode = pdlg.hDevMode; 71 | g_hDevNames = pdlg.hDevNames; 72 | 73 | return pdlg.hDC; 74 | } 75 | else 76 | { 77 | return NULL; 78 | } 79 | } 80 | 81 | int GetPrinterWidth(HDC hdcPrn) 82 | { 83 | HDC hdcScr = GetDC(0); 84 | 85 | int nPrinterDPI = GetDeviceCaps(hdcPrn, LOGPIXELSX); 86 | int nPrinterWidth = GetDeviceCaps(hdcPrn, HORZRES); 87 | int nScreenDPI = GetDeviceCaps(hdcScr, LOGPIXELSX); 88 | 89 | ReleaseDC(0, hdcScr); 90 | 91 | return nPrinterWidth * nScreenDPI / nPrinterDPI; 92 | } 93 | 94 | 95 | int GetCurrentPrinterWidth() 96 | { 97 | if(g_nPrinterWidth == 0) 98 | { 99 | HDC hdcPrn = GetDefaultPrinterDC(); 100 | g_nPrinterWidth = GetPrinterWidth(hdcPrn); 101 | 102 | DeleteDC(hdcPrn); 103 | } 104 | 105 | return g_nPrinterWidth; 106 | } -------------------------------------------------------------------------------- /Neatpad/Search.c: -------------------------------------------------------------------------------- 1 | // 2 | // Neatpad - Simple Text Editor application 3 | // 4 | // www.catch22.net 5 | // Written by J Brown 2004 6 | // 7 | #define _CRT_SECURE_NO_DEPRECATE 8 | #define _WIN32_WINNT 0x501 9 | #define STRICT 10 | 11 | #include 12 | #include 13 | #include 14 | #include "Neatpad.h" 15 | #include "..\TextView\TextView.h" 16 | #include "resource.h" 17 | 18 | extern HWND g_hwndSearchDlg; 19 | extern HWND g_hwndSearchBar; 20 | 21 | #define MAX_FIND_PANES 3 22 | #define FINDBORDER 6 23 | 24 | #define SWP_SIZEONLY (SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE) 25 | #define SWP_MOVEONLY (SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE) 26 | #define SWP_ZONLY (SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE) 27 | #define SWP_SHOWONLY (SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE | SWP_SHOWWINDOW) 28 | #define SWP_HIDEONLY (SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE | SWP_HIDEWINDOW) 29 | 30 | 31 | HWND g_hwndFindPane[MAX_FIND_PANES]; 32 | 33 | BOOL CALLBACK FindHexDlg(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 34 | { 35 | switch(msg) 36 | { 37 | case WM_INITDIALOG: 38 | EnableDialogTheme(hwnd); 39 | return FALSE; 40 | 41 | case WM_COMMAND: 42 | 43 | switch(LOWORD(wParam)) 44 | { 45 | case IDCANCEL: 46 | DestroyWindow(GetParent(hwnd)); 47 | return TRUE; 48 | } 49 | 50 | if(HIWORD(wParam) == BN_CLICKED) 51 | { 52 | //g_fFindInSelection = IsDlgButtonChecked(hwnd, IDC_SCOPE_SEL); 53 | //g_fSearchBackwards = IsDlgButtonChecked(hwnd, IDC_SEARCHBACK); 54 | //g_fKeepVisible = IsDlgButtonChecked(hwnd, IDC_KEEPVISIBLE); 55 | return TRUE; 56 | } 57 | 58 | return FALSE; 59 | 60 | case WM_CLOSE: 61 | DestroyWindow(GetParent(hwnd)); 62 | return TRUE; 63 | } 64 | return FALSE; 65 | } 66 | 67 | 68 | void AddSearchTabs(HWND hwnd) 69 | { 70 | TCITEM tcitem; 71 | RECT rect; 72 | int i; 73 | 74 | HWND hwndTab = GetDlgItem(hwnd, IDC_TAB1); 75 | 76 | tcitem.mask = TCIF_TEXT; 77 | tcitem.pszText = _T("Find"); 78 | TabCtrl_InsertItem(hwndTab, 0, &tcitem); 79 | 80 | tcitem.mask = TCIF_TEXT; 81 | tcitem.pszText = _T("Replace"); 82 | TabCtrl_InsertItem(hwndTab, 1, &tcitem); 83 | 84 | tcitem.mask = TCIF_TEXT; 85 | tcitem.pszText = _T("Goto"); 86 | TabCtrl_InsertItem(hwndTab, 2, &tcitem); 87 | 88 | ///tcitem.mask = TCIF_TEXT; 89 | ///tcitem.pszText = _T("Replace"); 90 | //TabCtrl_InsertItem(hwndTab, 3, &tcitem); 91 | 92 | // GetClient 93 | // TabCtrl_GetItemRect(hwndTab, 0, &rect); 94 | 95 | //for(i = MAX_FIND_PANES-1; i >= 0; i--) 96 | //{ 97 | 98 | g_hwndFindPane[0] = CreateDialog(g_hResourceModule, MAKEINTRESOURCE(IDD_FINDPANE), hwnd, FindHexDlg); 99 | g_hwndFindPane[1] = CreateDialog(g_hResourceModule, MAKEINTRESOURCE(IDD_REPLACEPANE), hwnd, FindHexDlg); 100 | g_hwndFindPane[2] = CreateDialog(g_hResourceModule, MAKEINTRESOURCE(IDD_GOTOPANE), hwnd, FindHexDlg); 101 | 102 | //ShowWindow(g_hwndFindPane[0], SW_SHOW); 103 | //} 104 | 105 | // work out how big tab control needs to be to hold the pane 106 | //for(i = 0; i < MAX_FIND_PANES; i++) 107 | i = 0; 108 | { 109 | GetClientRect(g_hwndFindPane[i], &rect); 110 | MapWindowPoints(g_hwndFindPane[i], hwnd, (POINT *)&rect, 2); 111 | TabCtrl_AdjustRect(hwndTab, TRUE, &rect); 112 | 113 | // break; 114 | } 115 | 116 | // move tab control into position 117 | MoveWindow(hwndTab, FINDBORDER, FINDBORDER, rect.right-rect.left, rect.bottom-rect.top, FALSE); 118 | 119 | // adjust the find dialog size 120 | AdjustWindowRectEx(&rect, GetWindowLong(hwnd, GWL_STYLE), FALSE, GetWindowLong(hwnd, GWL_EXSTYLE)); 121 | InflateRect(&rect, FINDBORDER, FINDBORDER); 122 | SetWindowPos(hwnd, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top-2, SWP_SIZEONLY); 123 | 124 | // now find out the tab control's client display area 125 | GetWindowRect(hwndTab, &rect); 126 | MapWindowPoints(0, hwnd, (POINT *)&rect, 2); 127 | TabCtrl_AdjustRect(hwndTab, FALSE, &rect); 128 | 129 | // move find pane into position 130 | for(i = 0; i < MAX_FIND_PANES; i++) 131 | { 132 | MoveWindow(g_hwndFindPane[i], rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, FALSE); 133 | } 134 | 135 | // ShowWindow(g_hwndFindPane[0], SW_SHOW); 136 | } 137 | 138 | BOOL CALLBACK SearchDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 139 | { 140 | NMHDR *nmhdr; 141 | static BOOL fMouseDown = FALSE; 142 | 143 | switch(msg) 144 | { 145 | case WM_INITDIALOG: 146 | AddSearchTabs(hwnd); 147 | return FALSE; 148 | 149 | case WM_NOTIFY: 150 | nmhdr = (NMHDR *)lParam; 151 | 152 | if(nmhdr->code == TCN_SELCHANGE) 153 | { 154 | int i; 155 | int idx = TabCtrl_GetCurSel(nmhdr->hwndFrom); 156 | HWND hwndPanel; 157 | 158 | for(i = 0; i < MAX_FIND_PANES; i++) 159 | { 160 | if(i != idx) 161 | { 162 | //DelStyle(g_hwndFindPane[i], WS_VISIBLE); 163 | ShowWindow(g_hwndFindPane[i], SW_HIDE); 164 | } 165 | } 166 | 167 | hwndPanel = g_hwndFindPane[idx]; 168 | 169 | SetWindowPos(g_hwndFindPane[idx], HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_SHOWWINDOW); 170 | 171 | if(fMouseDown) 172 | { 173 | SetFocus(GetDlgItem(hwndPanel, IDC_COMBO1)); 174 | PostMessage(hwndPanel, WM_NEXTDLGCTL, IDC_COMBO1, TRUE); 175 | } 176 | 177 | return TRUE; 178 | } 179 | else if(nmhdr->code == TCN_SELCHANGING) 180 | { 181 | fMouseDown = (GetKeyState(VK_LBUTTON) & 0x80000000) ? TRUE : FALSE; 182 | } 183 | else if(nmhdr->code == NM_RELEASEDCAPTURE) 184 | { 185 | fMouseDown = FALSE; 186 | } 187 | break; 188 | 189 | case WM_COMMAND: 190 | 191 | switch(LOWORD(wParam)) 192 | { 193 | case IDCANCEL: 194 | DestroyWindow(hwnd); 195 | return TRUE; 196 | } 197 | 198 | return TRUE; 199 | 200 | case WM_CLOSE: 201 | DestroyWindow(hwnd); 202 | return TRUE; 203 | 204 | case WM_DESTROY: 205 | g_hwndSearchDlg = 0; 206 | return TRUE; 207 | } 208 | return FALSE; 209 | } 210 | 211 | // 212 | // Show the find/replace/goto dialog 213 | // 214 | HWND ShowFindDlg(HWND hwndParent, UINT nPage) 215 | { 216 | HWND hwndTab; 217 | NMHDR nmhdr; 218 | 219 | // 220 | // Create the dialog if it hasn't been already 221 | // 222 | if(g_hwndSearchDlg == 0) 223 | { 224 | g_hwndSearchDlg = CreateDialog(g_hResourceModule, MAKEINTRESOURCE(IDD_FIND), hwndParent, SearchDlgProc); 225 | 226 | 227 | CenterWindow(g_hwndSearchDlg); 228 | ShowWindow(g_hwndSearchDlg, SW_SHOW); 229 | } 230 | 231 | SetForegroundWindow(g_hwndSearchDlg); 232 | 233 | // 234 | // Simulate the user clicking one of the TABs in order to 235 | // set the desired page 236 | // 237 | hwndTab = GetDlgItem(g_hwndSearchDlg, IDC_TAB1); 238 | nmhdr.hwndFrom = hwndTab; 239 | nmhdr.code = TCN_SELCHANGE; 240 | nmhdr.idFrom = IDC_TAB1; 241 | 242 | TabCtrl_SetCurSel(hwndTab, nPage); 243 | SendMessage(g_hwndSearchDlg, WM_NOTIFY, IDC_TAB1, (LPARAM)&nmhdr); 244 | 245 | // Set focus to 1st control in dialog 246 | SetFocus(GetDlgItem(g_hwndFindPane[nPage], IDC_COMBO1)); 247 | PostMessage(g_hwndFindPane[nPage], WM_NEXTDLGCTL, IDC_COMBO1, TRUE); 248 | 249 | return g_hwndSearchDlg; 250 | } 251 | 252 | /* 253 | void AddBlankSpace(HWND hwndTB, int width) 254 | { 255 | TBBUTTON tbb = { width, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0,0, 0 }; 256 | SendMessage(hwndTB, TB_ADDBUTTONS, 1, (LPARAM) &tbb); 257 | } 258 | 259 | 260 | void AddButton(HWND hwndTB, UINT uCmdId, UINT uImageIdx, UINT uStyle, TCHAR *szText) 261 | { 262 | //uStyle |= BTNS_SHOWTEXT; 263 | TBBUTTON tbb = { uImageIdx, uCmdId, TBSTATE_ENABLED, uStyle|BTNS_SHOWTEXT, 0, 0,0, (INT_PTR)szText }; 264 | 265 | //SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM)"Hello\0"); 266 | 267 | SendMessage(hwndTB, TB_ADDBUTTONS, 1, (LPARAM) &tbb); 268 | } 269 | 270 | static DWORD TOOLBAR_STYLE =WS_CHILD | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | 271 | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | 272 | CCS_NOPARENTALIGN | 273 | CCS_NORESIZE| 274 | CCS_NODIVIDER; 275 | 276 | HWND CreateEmptyToolbar(HWND hwndParent, int nBitmapIdx, int nBitmapWidth, int nCtrlId, DWORD dwExtraStyle) 277 | { 278 | HWND hwndTB; 279 | HIMAGELIST hImgList; 280 | 281 | hwndTB = CreateToolbarEx (hwndParent, 282 | TOOLBAR_STYLE|dwExtraStyle, 283 | nCtrlId, 0, 284 | 0, 285 | 0, 286 | NULL, 287 | 0, 288 | 0, 0, 0, 0, 289 | sizeof(TBBUTTON) ); 290 | 291 | hImgList = ImageList_LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(nBitmapIdx), 292 | nBitmapWidth, 16, RGB(255,0,255), 293 | IMAGE_BITMAP, LR_CREATEDIBSECTION); 294 | 295 | SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)hImgList); 296 | return hwndTB; 297 | } 298 | 299 | 300 | LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 301 | { 302 | WNDPROC oldproc = (WNDPROC)GetWindowLong(hwnd, GWL_USERDATA); 303 | RECT *prect, rect; 304 | LRESULT retval; 305 | 306 | static HICON hIcon; 307 | HDC hdc; 308 | 309 | if(hIcon == 0) 310 | { 311 | hIcon = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON4), 312 | IMAGE_ICON,16,16,LR_CREATEDIBSECTION); 313 | } 314 | 315 | switch(msg) 316 | { 317 | case WM_NCCALCSIZE: 318 | prect = (RECT *)lParam; 319 | 320 | retval = CallWindowProc(oldproc, hwnd, msg, wParam, lParam); 321 | prect->right -= 16; 322 | return retval; 323 | 324 | case WM_NCPAINT: 325 | 326 | retval = CallWindowProc(oldproc, hwnd, msg, wParam, lParam); 327 | 328 | GetWindowRect(hwnd, &rect); 329 | OffsetRect(&rect, -rect.left, -rect.top); 330 | 331 | if(wParam <= 1) 332 | hdc = GetWindowDC(hwnd); 333 | else 334 | hdc = (HDC)wParam; 335 | 336 | rect.left = rect.right - 18; 337 | rect.right -= 2; 338 | rect.top += 2; 339 | rect.bottom -= 2; 340 | FillRect(hdc, &rect, GetSysColorBrush(COLOR_WINDOW)); 341 | DrawIconEx(hdc, rect.left, rect.top + (rect.bottom-rect.top-16)/2, hIcon, 16, 16, 0, 0, DI_NORMAL); 342 | 343 | if(wParam <= 1) 344 | ReleaseDC(hwnd, hdc); 345 | 346 | return retval; 347 | 348 | } 349 | 350 | return CallWindowProc(oldproc, hwnd, msg, wParam, lParam); 351 | } 352 | 353 | BOOL CALLBACK SearchBarProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 354 | { 355 | NMHDR *nmhdr; 356 | HTHEME hTheme; 357 | RECT rect; 358 | static HWND hwndTB; 359 | HWND hwndEdit; 360 | WNDPROC oldproc; 361 | 362 | switch(msg) 363 | { 364 | case WM_INITDIALOG: 365 | //CreateWindowEx(0, WC_TOOLBAR, 0, WS_VISIBLE|WS_CHILD, 366 | InitCommonControls(); 367 | 368 | GetWindowRect(GetDlgItem(hwnd, IDC_EDIT1), &rect); 369 | ScreenToClient(hwnd, (POINT *)&rect.left); 370 | ScreenToClient(hwnd, (POINT *)&rect.right); 371 | 372 | hwndTB = //CreateWindowEx(0, TOOLBARCLASSNAME,0,WS_VISIBLE|WS_CHILD|TBSTYLE_FLAT|CCS_NORESIZE|CCS_NODIVIDER, 373 | CreateEmptyToolbar(hwnd, IDB_BITMAP3, 18, 0, TBSTYLE_LIST); 374 | 375 | SendMessage(hwndTB, WM_SETFONT, (WPARAM)SendMessage(hwnd, WM_GETFONT, 0, 0), 0); 376 | 377 | MoveWindow(hwndTB, rect.right + 8, rect.top, 400, rect.bottom-rect.top, TRUE); 378 | 379 | SendMessage(hwndTB, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS|TBSTYLE_EX_DRAWDDARROWS ); 380 | 381 | AddButton(hwndTB, 0, 0, TBSTYLE_BUTTON, _T("Find &Next")); 382 | AddButton(hwndTB, 0, 1, TBSTYLE_BUTTON, _T("Find &Previous")); 383 | AddButton(hwndTB, 0, 3, TBSTYLE_BUTTON|TBSTYLE_CHECK, _T("Highlight &all")); 384 | 385 | hwndEdit = GetDlgItem(hwnd, IDC_EDIT1); 386 | oldproc = (WNDPROC)GetWindowLong(hwndEdit, GWL_WNDPROC); 387 | SetWindowLong(hwndEdit, GWL_USERDATA, (LONG)oldproc); 388 | SetWindowLong(hwndEdit, GWL_WNDPROC, (LONG)EditSubclassProc); 389 | 390 | SetWindowPos(hwndEdit, 0, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED); 391 | 392 | return TRUE; 393 | 394 | default: 395 | return FALSE; 396 | } 397 | } 398 | 399 | HWND ShowSearchBar(HWND hwndParent) 400 | { 401 | if(g_hwndSearchBar == 0) 402 | { 403 | g_hwndSearchBar = CreateDialog(g_hResourceModule, MAKEINTRESOURCE(IDD_SEARCHBAR), hwndParent, SearchBarProc); 404 | } 405 | 406 | return g_hwndSearchBar; 407 | }*/ -------------------------------------------------------------------------------- /Neatpad/ThemeUtils.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/ThemeUtils.c -------------------------------------------------------------------------------- /Neatpad/Toolbars.c: -------------------------------------------------------------------------------- 1 | // 2 | // Neatpad - Simple Text Editor application 3 | // 4 | // www.catch22.net 5 | // Written by J Brown 2004-2006 6 | // 7 | 8 | #define STRICT 9 | #define _CRT_SECURE_NO_DEPRECATE 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "neatpad.h" 16 | 17 | 18 | 19 | DWORD dwStatusBarStyles = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | 20 | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NOMOVEY | //| CCS_NORESIZE 21 | SBT_NOBORDERS | SBARS_SIZEGRIP 22 | ; 23 | 24 | 25 | #define MAX_STATUS_PARTS 3 26 | 27 | // 28 | // Process WM_MENUSELECT message to display menu-item hints in statusbar 29 | // 30 | int StatusBarMenuSelect(HWND hwnd, HWND hwndSB, WPARAM wParam, LPARAM lParam) 31 | { 32 | UINT lookup[] = { 0, 0 }; 33 | 34 | // Display helpful text in status bar 35 | MenuHelp(WM_MENUSELECT, wParam, lParam, GetMenu(hwnd), g_hResourceModule, 36 | hwndSB, (UINT *)lookup); 37 | 38 | return 0; 39 | } 40 | 41 | // 42 | // Create each menubar pane. Must be called whenever the statusbar changes size, 43 | // so call each time the main-window gets a WM_SIZE 44 | // 45 | void SetStatusBarParts(HWND hwndSB) 46 | { 47 | RECT r; 48 | HWND hwndParent = GetParent(hwndSB); 49 | int parts[MAX_STATUS_PARTS]; 50 | int parentwidth; 51 | 52 | GetClientRect(hwndParent, &r); 53 | 54 | parentwidth = r.right < 400 ? 400 : r.right; 55 | parts[0] = parentwidth - 250; 56 | parts[1] = parentwidth - 70; 57 | parts[2] = parentwidth;//-1; 58 | 59 | // Tell the status bar to create the window parts. 60 | SendMessage(hwndSB, SB_SETPARTS, MAX_STATUS_PARTS, (LPARAM)parts); 61 | } 62 | 63 | // 64 | // sprintf-style wrapper for setting statubar pane text 65 | // 66 | void SetStatusBarText(HWND hwndSB, UINT nPart, UINT uStyle, TCHAR *fmt, ...) 67 | { 68 | TCHAR tmpbuf[100]; 69 | va_list argp; 70 | 71 | va_start(argp, fmt); 72 | _vsntprintf(tmpbuf, 100, fmt, argp); 73 | va_end(argp); 74 | 75 | //cannot use PostMessage, as the panel type is not set correctly 76 | SendMessage(hwndSB, SB_SETTEXT, (WPARAM)(nPart | uStyle), (LPARAM)tmpbuf); 77 | } 78 | 79 | // 80 | // Create Neatpad's statusbar 81 | // 82 | HWND CreateStatusBar (HWND hwndParent) 83 | { 84 | HWND hwndSB; 85 | 86 | hwndSB = CreateStatusWindow(dwStatusBarStyles, _T(""), hwndParent, 2); 87 | 88 | SetStatusBarParts(hwndSB); 89 | 90 | SetStatusBarText(hwndSB, 0, 1, _T("")); 91 | SetStatusBarText(hwndSB, 1, 0, _T(" Ln %d, Col %d"), 1, 1); 92 | SetStatusBarText(hwndSB, 2, 0, _T(" INS")); 93 | 94 | return hwndSB ; 95 | } 96 | -------------------------------------------------------------------------------- /Neatpad/bitmap1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/bitmap1.bmp -------------------------------------------------------------------------------- /Neatpad/bitmap2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/bitmap2.bmp -------------------------------------------------------------------------------- /Neatpad/bitmap3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/bitmap3.bmp -------------------------------------------------------------------------------- /Neatpad/bitmap4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/bitmap4.bmp -------------------------------------------------------------------------------- /Neatpad/icon0.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/icon0.ico -------------------------------------------------------------------------------- /Neatpad/icon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/icon1.ico -------------------------------------------------------------------------------- /Neatpad/icon2.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/icon2.ico -------------------------------------------------------------------------------- /Neatpad/icon3.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/icon3.ico -------------------------------------------------------------------------------- /Neatpad/icon4.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/icon4.ico -------------------------------------------------------------------------------- /Neatpad/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Developer Studio generated include file. 3 | // Used by resource.rc 4 | // 5 | #define IDC_REPLACEALL 3 6 | #define IDR_MENU1 101 7 | #define IDI_ICON1 102 8 | #define IDR_ACCELERATOR1 103 9 | #define IDD_OPTIONS1 104 10 | #define IDD_OPTIONS 104 11 | #define IDI_ICON2 105 12 | #define IDD_SPACING 106 13 | #define IDD_DIALOG1 107 14 | #define IDD_FONT 107 15 | #define IDD_DIALOG2 108 16 | #define IDD_FONTEXTRA 112 17 | #define IDD_DISPLAY 113 18 | #define IDD_ABOUT 114 19 | #define IDB_BITMAP1 115 20 | #define IDB_BITMAP2 116 21 | #define IDI_ICON3 118 22 | #define IDD_SAVEFILE 121 23 | #define IDD_FIND 122 24 | #define IDD_FINDPANE 123 25 | #define IDD_REPLACEPANE 124 26 | #define IDD_GOTOPANE 125 27 | #define IDR_MENU2 126 28 | #define IDD_SEARCHBAR 127 29 | #define IDB_BITMAP3 128 30 | #define IDI_ICON4 129 31 | #define IDB_BITMAP4 130 32 | #define IDC_COMBO1 1000 33 | #define IDC_FONTLIST 1000 34 | #define IDC_COMBO2 1001 35 | #define IDC_SIZELIST 1001 36 | #define IDC_CHECK1 1002 37 | #define IDC_COMBO3 1003 38 | #define IDC_EDIT1 1003 39 | #define IDC_COMBO4 1004 40 | #define IDC_EDIT2 1004 41 | #define IDC_SPIN1 1005 42 | #define IDC_SPIN2 1006 43 | #define IDC_PREVIEW 1009 44 | #define IDC_LIST1 1010 45 | #define IDC_ITEMLIST 1010 46 | #define IDC_COMBO5 1011 47 | #define IDC_BUTTON1 1012 48 | #define IDC_BGCOLCOMBO 1012 49 | #define IDC_BUTTON2 1014 50 | #define IDC_CUSTBUT1 1014 51 | #define IDC_BUTTON3 1015 52 | #define IDC_DISPLAYITEMLIST 1015 53 | #define IDC_CUSTBUT2 1015 54 | #define IDC_FGCOLCOMBO 1016 55 | #define IDC_DEFAULTS 1017 56 | #define IDC_BOLD 1018 57 | #define IDC_PADDINGA 1019 58 | #define IDC_PADDINGB 1020 59 | #define IDC_ADVANCED 1021 60 | #define IDC_CHECK2 1022 61 | #define IDC_CHECK3 1023 62 | #define IDC_ADDCONTEXT 1023 63 | #define IDC_CHECK4 1024 64 | #define IDC_REPLACENOTEPAD 1024 65 | #define IDC_PROGRESS1 1025 66 | #define IDC_CHECK10 1025 67 | #define IDC_RADIO1 1026 68 | #define IDC_RADIO2 1027 69 | #define IDC_CHECK5 1028 70 | #define IDC_CHECK6 1029 71 | #define IDC_CHECK7 1030 72 | #define IDC_CHECK8 1031 73 | #define IDC_CHECK9 1032 74 | #define IDC_EDIT3 1033 75 | #define IDC_EDIT4 1034 76 | #define IDC_LONGLINELIM 1034 77 | #define IDC_BANNER 1035 78 | #define IDC_SPIN3 1037 79 | #define IDC_HEADER 1038 80 | #define IDC_HEADER2 1039 81 | #define IDC_LINENOSFIRST 1040 82 | #define IDC_LINENOS 1041 83 | #define IDC_SELMARGIN 1042 84 | #define IDC_LONGLINEMODE 1043 85 | #define IDC_SELMARGIN2 1044 86 | #define IDC_HIGHLIGHTCURLINE 1044 87 | #define IDC_MEMWINPOS 1044 88 | #define IDC_MEMWINPOSFILE 1045 89 | #define IDC_HEADER1 1046 90 | #define IDC_ABOUT_APPNAME 1047 91 | #define IDC_ABOUT_URL 1048 92 | #define IDC_ENCODINGLIST 1049 93 | #define IDC_INCLUDEBOM 1050 94 | #define IDC_TAB1 1051 95 | #define IDC_LINEFMTLIST 1051 96 | #define IDC_FIND 1052 97 | #define IDC_REPLACE 1053 98 | #define IDC_SHIELD 1054 99 | #define IDM_FILE_NEW 40001 100 | #define IDM_FILE_OPEN 40002 101 | #define IDM_FILE_EXIT 40003 102 | #define IDM_HELP_ABOUT 40004 103 | #define IDM_VIEW_FONT 40005 104 | #define IDM_VIEW_LINENUMBERS 40006 105 | #define IDM_VIEW_LONGLINES 40007 106 | #define IDM_VIEW_SAVENOW 40008 107 | #define IDM_VIEW_SAVEEXIT 40009 108 | #define IDM_FILE_PRINT 40010 109 | #define IDM_VIEW_ASCII 40012 110 | #define IDM_VIEW_UTF8 40013 111 | #define IDM_VIEW_UTF16 40014 112 | #define IDM_VIEW_UTF16BE 40015 113 | #define IDM_EDIT_UNDO 40016 114 | #define IDM_EDIT_REDO 40017 115 | #define IDM_EDIT_CUT 40018 116 | #define IDM_EDIT_COPY 40019 117 | #define IDM_EDIT_PASTE 40020 118 | #define IDM_EDIT_DELETE 40021 119 | #define IDM_EDIT_SELECTALL 40022 120 | #define IDM_VIEW_STATUSBAR 40023 121 | #define IDM_VIEW_OPTIONS 40024 122 | #define IDM_FILE_SAVE 40025 123 | #define IDM_FILE_SAVEAS 40026 124 | #define IDM_EDIT_FIND 40027 125 | #define IDM_EDIT_FINDNEXT 40028 126 | #define IDM_EDIT_REPLACE 40029 127 | #define IDM_EDIT_GOTO 40030 128 | #define IDM_SCHEME_NORMAL 40032 129 | #define IDM_SCHEME_SAVE 40033 130 | 131 | // Next default values for new objects 132 | // 133 | #ifdef APSTUDIO_INVOKED 134 | #ifndef APSTUDIO_READONLY_SYMBOLS 135 | #define _APS_NEXT_RESOURCE_VALUE 131 136 | #define _APS_NEXT_COMMAND_VALUE 40034 137 | #define _APS_NEXT_CONTROL_VALUE 1055 138 | #define _APS_NEXT_SYMED_VALUE 101 139 | #endif 140 | #endif 141 | -------------------------------------------------------------------------------- /Neatpad/resource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strobejb/Neatpad/439820300e025a1b770ca008b1d59ade8f267945/Neatpad/resource.rc -------------------------------------------------------------------------------- /TextView/TextDocument.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTDOC_INCLUDED 2 | #define TEXTDOC_INCLUDED 3 | 4 | #include "codepages.h" 5 | #include "sequence.h" 6 | 7 | class TextIterator; 8 | 9 | class TextDocument 10 | { 11 | friend class TextIterator; 12 | friend class TextView; 13 | 14 | public: 15 | TextDocument(); 16 | ~TextDocument(); 17 | 18 | bool init(HANDLE hFile); 19 | bool init(TCHAR *filename); 20 | 21 | bool clear(); 22 | bool EmptyDoc(); 23 | 24 | bool Undo(ULONG *offset_start, ULONG *offset_end); 25 | bool Redo(ULONG *offset_start, ULONG *offset_end); 26 | 27 | // UTF-16 text-editing interface 28 | ULONG insert_text(ULONG offset_chars, TCHAR *text, ULONG length); 29 | ULONG replace_text(ULONG offset_chars, TCHAR *text, ULONG length, ULONG erase_len); 30 | ULONG erase_text(ULONG offset_chars, ULONG length); 31 | 32 | ULONG lineno_from_offset(ULONG offset); 33 | ULONG offset_from_lineno(ULONG lineno); 34 | 35 | bool lineinfo_from_offset(ULONG offset_chars, ULONG *lineno, ULONG *lineoff_chars, ULONG *linelen_chars, ULONG *lineoff_bytes, ULONG *linelen_bytes); 36 | bool lineinfo_from_lineno(ULONG lineno, ULONG *lineoff_chars, ULONG *linelen_chars, ULONG *lineoff_bytes, ULONG *linelen_bytes); 37 | 38 | TextIterator iterate(ULONG offset); 39 | TextIterator iterate_line(ULONG lineno, ULONG *linestart = 0, ULONG *linelen = 0); 40 | TextIterator iterate_line_offset(ULONG offset_chars, ULONG *lineno, ULONG *linestart = 0); 41 | 42 | ULONG getdata(ULONG offset, BYTE *buf, size_t len); 43 | ULONG getline(ULONG nLineNo, TCHAR *buf, ULONG buflen, ULONG *off_chars); 44 | 45 | int getformat(); 46 | ULONG linecount(); 47 | ULONG longestline(int tabwidth); 48 | ULONG size(); 49 | 50 | private: 51 | 52 | bool init_linebuffer(); 53 | 54 | ULONG charoffset_to_byteoffset(ULONG offset_chars); 55 | ULONG byteoffset_to_charoffset(ULONG offset_bytes); 56 | 57 | ULONG count_chars(ULONG offset_bytes, ULONG length_chars); 58 | 59 | size_t utf16_to_rawdata(TCHAR *utf16str, size_t utf16len, BYTE *rawdata, size_t *rawlen); 60 | size_t rawdata_to_utf16(BYTE *rawdata, size_t rawlen, TCHAR *utf16str, size_t *utf16len); 61 | 62 | int detect_file_format(int *headersize); 63 | ULONG gettext(ULONG offset, ULONG lenbytes, TCHAR *buf, ULONG *len); 64 | int getchar(ULONG offset, ULONG lenbytes, ULONG *pch32); 65 | 66 | // UTF-16 text-editing interface 67 | ULONG insert_raw(ULONG offset_bytes, TCHAR *text, ULONG length); 68 | ULONG replace_raw(ULONG offset_bytes, TCHAR *text, ULONG length, ULONG erase_len); 69 | ULONG erase_raw(ULONG offset_bytes, ULONG length); 70 | 71 | 72 | sequence m_seq; 73 | 74 | ULONG m_nDocLength_chars; 75 | ULONG m_nDocLength_bytes; 76 | 77 | ULONG *m_pLineBuf_byte; 78 | ULONG *m_pLineBuf_char; 79 | ULONG m_nNumLines; 80 | 81 | int m_nFileFormat; 82 | int m_nHeaderSize; 83 | }; 84 | 85 | class TextIterator 86 | { 87 | public: 88 | // default constructor sets all members to zero 89 | TextIterator() 90 | : text_doc(0), off_bytes(0), len_bytes(0) 91 | { 92 | } 93 | 94 | TextIterator(ULONG off, ULONG len, TextDocument *td) 95 | : text_doc(td), off_bytes(off), len_bytes(len) 96 | { 97 | 98 | } 99 | 100 | // default copy-constructor 101 | TextIterator(const TextIterator &ti) 102 | : text_doc(ti.text_doc), off_bytes(ti.off_bytes), len_bytes(ti.len_bytes) 103 | { 104 | } 105 | 106 | // assignment operator 107 | TextIterator & operator= (TextIterator &ti) 108 | { 109 | text_doc = ti.text_doc; 110 | off_bytes = ti.off_bytes; 111 | len_bytes = ti.len_bytes; 112 | return *this; 113 | } 114 | 115 | ULONG gettext(TCHAR *buf, ULONG buflen) 116 | { 117 | if(text_doc) 118 | { 119 | // get text from the TextDocument at the specified byte-offset 120 | ULONG len = text_doc->gettext(off_bytes, len_bytes, buf, &buflen); 121 | 122 | // adjust the iterator's internal position 123 | off_bytes += len; 124 | len_bytes -= len; 125 | 126 | return buflen; 127 | } 128 | else 129 | { 130 | return 0; 131 | } 132 | } 133 | 134 | /*int insert_text(TCHAR *buf, int buflen) 135 | { 136 | if(text_doc) 137 | { 138 | // get text from the TextDocument at the specified byte-offset 139 | int len = text_doc->insert(off_bytes, buf, buflen); 140 | 141 | // adjust the iterator's internal position 142 | off_bytes += len; 143 | return buflen; 144 | } 145 | else 146 | { 147 | return 0; 148 | } 149 | } 150 | 151 | int replace_text(TCHAR *buf, int buflen) 152 | { 153 | if(text_doc) 154 | { 155 | // get text from the TextDocument at the specified byte-offset 156 | int len = text_doc->replace(off_bytes, buf, buflen); 157 | 158 | // adjust the iterator's internal position 159 | off_bytes += len; 160 | return buflen; 161 | } 162 | else 163 | { 164 | return 0; 165 | } 166 | } 167 | 168 | int erase_text(int length) 169 | { 170 | if(text_doc) 171 | { 172 | // get text from the TextDocument at the specified byte-offset 173 | int len = text_doc->erase(off_bytes, length); 174 | 175 | // adjust the iterator's internal position 176 | off_bytes += len; 177 | return len; 178 | } 179 | else 180 | { 181 | return 0; 182 | } 183 | }*/ 184 | 185 | 186 | operator bool() 187 | { 188 | return text_doc ? true : false; 189 | } 190 | 191 | private: 192 | 193 | TextDocument *text_doc; 194 | 195 | ULONG off_bytes; 196 | ULONG len_bytes; 197 | }; 198 | 199 | class LineIterator 200 | { 201 | public: 202 | LineIterator(); 203 | 204 | private: 205 | TextDocument *m_pTextDoc; 206 | }; 207 | 208 | struct _BOM_LOOKUP 209 | { 210 | DWORD bom; 211 | ULONG len; 212 | int type; 213 | }; 214 | 215 | #endif -------------------------------------------------------------------------------- /TextView/TextView.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextView.cpp 3 | // 4 | // PURPOSE: Implementation of the TextView control 5 | // 6 | // NOTES: www.catch22.net 7 | // 8 | #define _WIN32_WINNT 0x501 9 | #define STRICT 10 | #define WIN32_LEAN_AND_MEAN 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | // for the EM_xxx message constants 17 | #include 18 | 19 | #include "TextView.h" 20 | #include "TextViewInternal.h" 21 | #include "racursor.h" 22 | 23 | #if !defined(UNICODE) 24 | #error "Please build as Unicode only!" 25 | #endif 26 | 27 | #if !defined(GetWindowLongPtr) 28 | #error "Latest Platform SDK is required to build Neatpad - try PSDK-Feb-2003 29 | #endif 30 | 31 | #pragma comment(lib, "comctl32.lib") 32 | 33 | // 34 | // Constructor for TextView class 35 | // 36 | TextView::TextView(HWND hwnd) 37 | { 38 | m_hWnd = hwnd; 39 | 40 | m_hTheme = OpenThemeData(hwnd, L"edit"); 41 | 42 | // Font-related data 43 | m_nNumFonts = 1; 44 | m_nHeightAbove = 0; 45 | m_nHeightBelow = 0; 46 | 47 | // File-related data 48 | m_nLineCount = 0; 49 | m_nLongestLine = 0; 50 | 51 | 52 | // Scrollbar related data 53 | m_nVScrollPos = 0; 54 | m_nHScrollPos = 0; 55 | m_nVScrollMax = 0; 56 | m_nHScrollMax = 0; 57 | 58 | // Display-related data 59 | m_nTabWidthChars = 4; 60 | m_uStyleFlags = 0; 61 | m_nCaretWidth = 0; 62 | m_nLongLineLimit = 80; 63 | m_nLineInfoCount = 0; 64 | m_nCRLFMode = TXL_CRLF;//ALL; 65 | 66 | // allocate the USPDATA cache 67 | m_uspCache = new USPCACHE[USP_CACHE_SIZE]; 68 | 69 | for(int i = 0; i < USP_CACHE_SIZE; i++) 70 | { 71 | m_uspCache[i].usage = 0; 72 | m_uspCache[i].lineno = 0; 73 | m_uspCache[i].uspData = UspAllocate(); 74 | } 75 | 76 | SystemParametersInfo(SPI_GETCARETWIDTH, 0, &m_nCaretWidth, 0); 77 | 78 | if(m_nCaretWidth == 0) 79 | m_nCaretWidth = 2; 80 | 81 | // Default display colours 82 | m_rgbColourList[TXC_FOREGROUND] = SYSCOL(COLOR_WINDOWTEXT); 83 | m_rgbColourList[TXC_BACKGROUND] = SYSCOL(COLOR_WINDOW); // RGB(34,54,106) 84 | m_rgbColourList[TXC_HIGHLIGHTTEXT] = SYSCOL(COLOR_HIGHLIGHTTEXT); 85 | m_rgbColourList[TXC_HIGHLIGHT] = SYSCOL(COLOR_HIGHLIGHT); 86 | m_rgbColourList[TXC_HIGHLIGHTTEXT2] = SYSCOL(COLOR_WINDOWTEXT);//INACTIVECAPTIONTEXT); 87 | m_rgbColourList[TXC_HIGHLIGHT2] = SYSCOL(COLOR_3DFACE);//INACTIVECAPTION); 88 | m_rgbColourList[TXC_SELMARGIN1] = SYSCOL(COLOR_3DFACE); 89 | m_rgbColourList[TXC_SELMARGIN2] = SYSCOL(COLOR_3DHIGHLIGHT); 90 | m_rgbColourList[TXC_LINENUMBERTEXT] = SYSCOL(COLOR_3DSHADOW); 91 | m_rgbColourList[TXC_LINENUMBER] = SYSCOL(COLOR_3DFACE); 92 | m_rgbColourList[TXC_LONGLINETEXT] = SYSCOL(COLOR_3DSHADOW); 93 | m_rgbColourList[TXC_LONGLINE] = SYSCOL(COLOR_3DFACE); 94 | m_rgbColourList[TXC_CURRENTLINETEXT] = SYSCOL(COLOR_WINDOWTEXT); 95 | m_rgbColourList[TXC_CURRENTLINE] = RGB(230,240,255); 96 | 97 | 98 | // Runtime data 99 | m_nSelectionMode = SEL_NONE; 100 | m_nEditMode = MODE_INSERT; 101 | m_nScrollTimer = 0; 102 | m_fHideCaret = false; 103 | m_hUserMenu = 0; 104 | m_hImageList = 0; 105 | 106 | m_nSelectionStart = 0; 107 | m_nSelectionEnd = 0; 108 | m_nSelectionType = SEL_NONE; 109 | m_nCursorOffset = 0; 110 | m_nCurrentLine = 0; 111 | 112 | m_nLinenoWidth = 0; 113 | m_nCaretPosX = 0; 114 | m_nAnchorPosX = 0; 115 | 116 | //SetRect(&m_rcBorder, 2, 2, 2, 2); 117 | 118 | m_pTextDoc = new TextDocument(); 119 | 120 | m_hMarginCursor = CreateCursor(GetModuleHandle(0), 21, 5, 32, 32, XORMask, ANDMask); 121 | 122 | // 123 | // The TextView state must be fully initialized before we 124 | // start calling member-functions 125 | // 126 | 127 | memset(m_uspFontList, 0, sizeof(m_uspFontList)); 128 | 129 | // Set the default font 130 | OnSetFont((HFONT)GetStockObject(ANSI_FIXED_FONT)); 131 | 132 | UpdateMetrics(); 133 | UpdateMarginWidth(); 134 | } 135 | 136 | // 137 | // Destructor for TextView class 138 | // 139 | TextView::~TextView() 140 | { 141 | if(m_pTextDoc) 142 | delete m_pTextDoc; 143 | 144 | DestroyCursor(m_hMarginCursor); 145 | 146 | for(int i = 0; i < USP_CACHE_SIZE; i++) 147 | UspFree(m_uspCache[i].uspData); 148 | 149 | CloseThemeData(m_hTheme); 150 | } 151 | 152 | ULONG TextView::NotifyParent(UINT nNotifyCode, NMHDR *optional) 153 | { 154 | UINT nCtrlId = GetWindowLong(m_hWnd, GWL_ID); 155 | NMHDR nmhdr = { m_hWnd, nCtrlId, nNotifyCode }; 156 | NMHDR *nmptr = &nmhdr; 157 | 158 | if(optional) 159 | { 160 | nmptr = optional; 161 | *nmptr = nmhdr; 162 | } 163 | 164 | return SendMessage(GetParent(m_hWnd), WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)nmptr); 165 | } 166 | 167 | VOID TextView::UpdateMetrics() 168 | { 169 | RECT rect; 170 | GetClientRect(m_hWnd, &rect); 171 | 172 | OnSize(0, rect.right, rect.bottom); 173 | RefreshWindow(); 174 | 175 | RepositionCaret(); 176 | } 177 | 178 | LONG TextView::OnSetFocus(HWND hwndOld) 179 | { 180 | CreateCaret(m_hWnd, (HBITMAP)NULL, m_nCaretWidth, m_nLineHeight); 181 | RepositionCaret(); 182 | 183 | ShowCaret(m_hWnd); 184 | RefreshWindow(); 185 | return 0; 186 | } 187 | 188 | LONG TextView::OnKillFocus(HWND hwndNew) 189 | { 190 | // if we are making a selection when we lost focus then 191 | // stop the selection logic 192 | if(m_nSelectionMode != SEL_NONE) 193 | { 194 | OnLButtonUp(0, 0, 0); 195 | } 196 | 197 | HideCaret(m_hWnd); 198 | DestroyCaret(); 199 | RefreshWindow(); 200 | return 0; 201 | } 202 | 203 | ULONG TextView::SetStyle(ULONG uMask, ULONG uStyles) 204 | { 205 | ULONG oldstyle = m_uStyleFlags; 206 | 207 | m_uStyleFlags = (m_uStyleFlags & ~uMask) | uStyles; 208 | 209 | ResetLineCache(); 210 | 211 | // update display here 212 | UpdateMetrics(); 213 | RefreshWindow(); 214 | 215 | return oldstyle; 216 | } 217 | 218 | ULONG TextView::SetVar(ULONG nVar, ULONG nValue) 219 | { 220 | return 0;//oldval; 221 | } 222 | 223 | ULONG TextView::GetVar(ULONG nVar) 224 | { 225 | return 0; 226 | } 227 | 228 | ULONG TextView::GetStyleMask(ULONG uMask) 229 | { 230 | return m_uStyleFlags & uMask; 231 | } 232 | 233 | bool TextView::CheckStyle(ULONG uMask) 234 | { 235 | return (m_uStyleFlags & uMask) ? true : false; 236 | } 237 | 238 | int TextView::SetCaretWidth(int nWidth) 239 | { 240 | int oldwidth = m_nCaretWidth; 241 | m_nCaretWidth = nWidth; 242 | 243 | return oldwidth; 244 | } 245 | 246 | BOOL TextView::SetImageList(HIMAGELIST hImgList) 247 | { 248 | m_hImageList = hImgList; 249 | return TRUE; 250 | } 251 | 252 | LONG TextView::SetLongLine(int nLength) 253 | { 254 | int oldlen = m_nLongLineLimit; 255 | m_nLongLineLimit = nLength; 256 | return oldlen; 257 | } 258 | 259 | int CompareLineInfo(LINEINFO *elem1, LINEINFO *elem2) 260 | { 261 | if(elem1->nLineNo < elem2->nLineNo) 262 | return -1; 263 | if(elem1->nLineNo > elem2->nLineNo) 264 | return 1; 265 | else 266 | return 0; 267 | } 268 | 269 | int TextView::SetLineImage(ULONG nLineNo, ULONG nImageIdx) 270 | { 271 | LINEINFO *linfo = GetLineInfo(nLineNo); 272 | 273 | // if already a line with an image 274 | if(linfo) 275 | { 276 | linfo->nImageIdx = nImageIdx; 277 | } 278 | else 279 | { 280 | linfo = &m_LineInfo[m_nLineInfoCount++]; 281 | linfo->nLineNo = nLineNo; 282 | linfo->nImageIdx = nImageIdx; 283 | 284 | // sort the array 285 | qsort( 286 | m_LineInfo, 287 | m_nLineInfoCount, 288 | sizeof(LINEINFO), 289 | (COMPAREPROC)CompareLineInfo 290 | ); 291 | 292 | } 293 | return 0; 294 | } 295 | 296 | LINEINFO* TextView::GetLineInfo(ULONG nLineNo) 297 | { 298 | LINEINFO key = { nLineNo, 0 }; 299 | 300 | // perform the binary search 301 | return (LINEINFO *) bsearch( 302 | &key, 303 | m_LineInfo, 304 | m_nLineInfoCount, 305 | sizeof(LINEINFO), 306 | (COMPAREPROC)CompareLineInfo 307 | ); 308 | } 309 | 310 | ULONG TextView::SelectionSize() 311 | { 312 | ULONG s1 = min(m_nSelectionStart, m_nSelectionEnd); 313 | ULONG s2 = max(m_nSelectionStart, m_nSelectionEnd); 314 | return s2 - s1; 315 | } 316 | 317 | ULONG TextView::SelectAll() 318 | { 319 | m_nSelectionStart = 0; 320 | m_nSelectionEnd = m_pTextDoc->size(); 321 | m_nCursorOffset = m_nSelectionEnd; 322 | 323 | Smeg(TRUE); 324 | RefreshWindow(); 325 | return 0; 326 | } 327 | 328 | // 329 | // Public memberfunction 330 | // 331 | LONG WINAPI TextView::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) 332 | { 333 | switch(msg) 334 | { 335 | // Draw contents of TextView whenever window needs updating 336 | case WM_ERASEBKGND: 337 | return 1; 338 | 339 | // Need to custom-draw the border for XP/Vista themes 340 | case WM_NCPAINT: 341 | return OnNcPaint((HRGN)wParam); 342 | 343 | case WM_PAINT: 344 | return OnPaint(); 345 | 346 | // Set a new font 347 | case WM_SETFONT: 348 | return OnSetFont((HFONT)wParam); 349 | 350 | case WM_SIZE: 351 | return OnSize(wParam, LOWORD(lParam), HIWORD(lParam)); 352 | 353 | case WM_VSCROLL: 354 | return OnVScroll(LOWORD(wParam), HIWORD(wParam)); 355 | 356 | case WM_HSCROLL: 357 | return OnHScroll(LOWORD(wParam), HIWORD(wParam)); 358 | 359 | case WM_MOUSEACTIVATE: 360 | return OnMouseActivate((HWND)wParam, LOWORD(lParam), HIWORD(lParam)); 361 | 362 | case WM_CONTEXTMENU: 363 | return OnContextMenu((HWND)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam)); 364 | 365 | case WM_MOUSEWHEEL: 366 | return OnMouseWheel((short)HIWORD(wParam)); 367 | 368 | case WM_SETFOCUS: 369 | return OnSetFocus((HWND)wParam); 370 | 371 | case WM_KILLFOCUS: 372 | return OnKillFocus((HWND)wParam); 373 | 374 | // make sure we get arrow-keys, enter, tab, etc when hosted inside a dialog 375 | case WM_GETDLGCODE: 376 | return DLGC_WANTALLKEYS; 377 | 378 | case WM_LBUTTONDOWN: 379 | return OnLButtonDown(wParam, (short)LOWORD(lParam), (short)HIWORD(lParam)); 380 | 381 | case WM_LBUTTONUP: 382 | return OnLButtonUp(wParam, (short)LOWORD(lParam), (short)HIWORD(lParam)); 383 | 384 | case WM_LBUTTONDBLCLK: 385 | return OnLButtonDblClick(wParam, (short)LOWORD(lParam), (short)HIWORD(lParam)); 386 | 387 | case WM_MOUSEMOVE: 388 | return OnMouseMove(wParam, (short)LOWORD(lParam), (short)HIWORD(lParam)); 389 | 390 | case WM_KEYDOWN: 391 | return OnKeyDown(wParam, lParam); 392 | 393 | case WM_UNDO: case TXM_UNDO: case EM_UNDO: 394 | return Undo(); 395 | 396 | case TXM_REDO: case EM_REDO: 397 | return Redo(); 398 | 399 | case TXM_CANUNDO: case EM_CANUNDO: 400 | return CanUndo(); 401 | 402 | case TXM_CANREDO: case EM_CANREDO: 403 | return CanRedo(); 404 | 405 | case WM_CHAR: 406 | return OnChar(wParam, lParam); 407 | 408 | case WM_SETCURSOR: 409 | 410 | if(LOWORD(lParam) == HTCLIENT) 411 | return TRUE; 412 | 413 | break; 414 | 415 | case WM_COPY: 416 | return OnCopy(); 417 | 418 | case WM_CUT: 419 | return OnCut(); 420 | 421 | case WM_PASTE: 422 | return OnPaste(); 423 | 424 | case WM_CLEAR: 425 | return OnClear(); 426 | 427 | case WM_GETTEXT: 428 | return 0; 429 | 430 | case WM_TIMER: 431 | return OnTimer(wParam); 432 | 433 | // 434 | case TXM_OPENFILE: 435 | return OpenFile((TCHAR *)lParam); 436 | 437 | case TXM_CLEAR: 438 | return ClearFile(); 439 | 440 | case TXM_SETLINESPACING: 441 | return SetLineSpacing(wParam, lParam); 442 | 443 | case TXM_ADDFONT: 444 | return AddFont((HFONT)wParam); 445 | 446 | case TXM_SETCOLOR: 447 | return SetColour(wParam, lParam); 448 | 449 | case TXM_SETSTYLE: 450 | return SetStyle(wParam, lParam); 451 | 452 | case TXM_SETCARETWIDTH: 453 | return SetCaretWidth(wParam); 454 | 455 | case TXM_SETIMAGELIST: 456 | return SetImageList((HIMAGELIST)wParam); 457 | 458 | case TXM_SETLONGLINE: 459 | return SetLongLine(lParam); 460 | 461 | case TXM_SETLINEIMAGE: 462 | return SetLineImage(wParam, lParam); 463 | 464 | case TXM_GETFORMAT: 465 | return m_pTextDoc->getformat(); 466 | 467 | case TXM_GETSELSIZE: 468 | return SelectionSize(); 469 | 470 | case TXM_SETSELALL: 471 | return SelectAll(); 472 | 473 | case TXM_GETCURPOS: 474 | return m_nCursorOffset; 475 | 476 | case TXM_GETCURLINE: 477 | return m_nCurrentLine; 478 | 479 | case TXM_GETCURCOL: 480 | ULONG nOffset; 481 | GetUspData(0, m_nCurrentLine, &nOffset); 482 | return m_nCursorOffset - nOffset; 483 | 484 | case TXM_GETEDITMODE: 485 | return m_nEditMode; 486 | 487 | case TXM_SETEDITMODE: 488 | lParam = m_nEditMode; 489 | m_nEditMode = wParam; 490 | return lParam; 491 | 492 | case TXM_SETCONTEXTMENU: 493 | m_hUserMenu = (HMENU)wParam; 494 | return 0; 495 | 496 | default: 497 | break; 498 | } 499 | 500 | return DefWindowProc(m_hWnd, msg, wParam, lParam); 501 | } 502 | 503 | // 504 | // Win32 TextView window procedure stub 505 | // 506 | LRESULT WINAPI TextViewWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 507 | { 508 | TextView *ptv = (TextView *)GetWindowLongPtr(hwnd, 0); 509 | 510 | switch(msg) 511 | { 512 | // First message received by any window - make a new TextView object 513 | // and store pointer to it in our extra-window-bytes 514 | case WM_NCCREATE: 515 | 516 | if((ptv = new TextView(hwnd)) == 0) 517 | return FALSE; 518 | 519 | SetWindowLongPtr(hwnd, 0, (LONG)ptv); 520 | return TRUE; 521 | 522 | // Last message received by any window - delete the TextView object 523 | case WM_NCDESTROY: 524 | delete ptv; 525 | SetWindowLongPtr(hwnd, 0, 0); 526 | return 0; 527 | 528 | // Pass everything to the TextView window procedure 529 | default: 530 | if(ptv) 531 | return ptv->WndProc(msg, wParam, lParam); 532 | else 533 | return 0; 534 | } 535 | } 536 | 537 | // 538 | // Register the TextView window class 539 | // 540 | BOOL InitTextView() 541 | { 542 | WNDCLASSEX wcx; 543 | 544 | //Window class for the main application parent window 545 | wcx.cbSize = sizeof(wcx); 546 | wcx.style = CS_DBLCLKS; 547 | wcx.lpfnWndProc = TextViewWndProc; 548 | wcx.cbClsExtra = 0; 549 | wcx.cbWndExtra = sizeof(TextView *); 550 | wcx.hInstance = GetModuleHandle(0); 551 | wcx.hIcon = 0; 552 | wcx.hCursor = LoadCursor (NULL, IDC_IBEAM); 553 | wcx.hbrBackground = (HBRUSH)0; //NO FLICKERING FOR US!! 554 | wcx.lpszMenuName = 0; 555 | wcx.lpszClassName = TEXTVIEW_CLASS; 556 | wcx.hIconSm = 0; 557 | 558 | return RegisterClassEx(&wcx) ? TRUE : FALSE; 559 | } 560 | 561 | // 562 | // Create a TextView control! 563 | // 564 | HWND CreateTextView(HWND hwndParent) 565 | { 566 | return CreateWindowEx(WS_EX_CLIENTEDGE, 567 | // L"EDIT", L"", 568 | TEXTVIEW_CLASS, _T(""), 569 | WS_VSCROLL |WS_HSCROLL | WS_CHILD | WS_VISIBLE, 570 | 0, 0, 0, 0, 571 | hwndParent, 572 | 0, 573 | GetModuleHandle(0), 574 | 0); 575 | } 576 | 577 | -------------------------------------------------------------------------------- /TextView/TextView.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="TextView" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Static Library" 0x0104 6 | 7 | CFG=TextView - Win32 Unicode Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "TextView.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "TextView.mak" CFG="TextView - Win32 Unicode Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "TextView - Win32 Release" (based on "Win32 (x86) Static Library") 21 | !MESSAGE "TextView - Win32 Debug" (based on "Win32 (x86) Static Library") 22 | !MESSAGE "TextView - Win32 Unicode Debug" (based on "Win32 (x86) Static Library") 23 | !MESSAGE "TextView - Win32 Unicode Release" (based on "Win32 (x86) Static Library") 24 | !MESSAGE 25 | 26 | # Begin Project 27 | # PROP AllowPerConfigDependencies 0 28 | # PROP Scc_ProjName "" 29 | # PROP Scc_LocalPath "" 30 | CPP=cl.exe 31 | RSC=rc.exe 32 | 33 | !IF "$(CFG)" == "TextView - Win32 Release" 34 | 35 | # PROP BASE Use_MFC 0 36 | # PROP BASE Use_Debug_Libraries 0 37 | # PROP BASE Output_Dir "Release" 38 | # PROP BASE Intermediate_Dir "Release" 39 | # PROP BASE Target_Dir "" 40 | # PROP Use_MFC 0 41 | # PROP Use_Debug_Libraries 0 42 | # PROP Output_Dir "Release" 43 | # PROP Intermediate_Dir "Release" 44 | # PROP Target_Dir "" 45 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c 46 | # ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /c 47 | # ADD BASE RSC /l 0x809 /d "NDEBUG" 48 | # ADD RSC /l 0x809 /d "NDEBUG" 49 | BSC32=bscmake.exe 50 | # ADD BASE BSC32 /nologo 51 | # ADD BSC32 /nologo 52 | LIB32=link.exe -lib 53 | # ADD BASE LIB32 /nologo 54 | # ADD LIB32 /nologo 55 | 56 | !ELSEIF "$(CFG)" == "TextView - Win32 Debug" 57 | 58 | # PROP BASE Use_MFC 0 59 | # PROP BASE Use_Debug_Libraries 1 60 | # PROP BASE Output_Dir "Debug" 61 | # PROP BASE Intermediate_Dir "Debug" 62 | # PROP BASE Target_Dir "" 63 | # PROP Use_MFC 0 64 | # PROP Use_Debug_Libraries 1 65 | # PROP Output_Dir "Debug" 66 | # PROP Intermediate_Dir "Debug" 67 | # PROP Target_Dir "" 68 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 69 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c 70 | # ADD BASE RSC /l 0x809 /d "_DEBUG" 71 | # ADD RSC /l 0x809 /d "_DEBUG" 72 | BSC32=bscmake.exe 73 | # ADD BASE BSC32 /nologo 74 | # ADD BSC32 /nologo 75 | LIB32=link.exe -lib 76 | # ADD BASE LIB32 /nologo 77 | # ADD LIB32 /nologo 78 | 79 | !ELSEIF "$(CFG)" == "TextView - Win32 Unicode Debug" 80 | 81 | # PROP BASE Use_MFC 0 82 | # PROP BASE Use_Debug_Libraries 1 83 | # PROP BASE Output_Dir "TextView___Win32_Unicode_Debug" 84 | # PROP BASE Intermediate_Dir "TextView___Win32_Unicode_Debug" 85 | # PROP BASE Target_Dir "" 86 | # PROP Use_MFC 0 87 | # PROP Use_Debug_Libraries 1 88 | # PROP Output_Dir "Unicode_Debug" 89 | # PROP Intermediate_Dir "Unicode_Debug" 90 | # PROP Target_Dir "" 91 | # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c 92 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "_LIB" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /FR /YX /FD /GZ /c 93 | # ADD BASE RSC /l 0x809 /d "_DEBUG" 94 | # ADD RSC /l 0x809 /d "_DEBUG" 95 | BSC32=bscmake.exe 96 | # ADD BASE BSC32 /nologo 97 | # ADD BSC32 /nologo 98 | LIB32=link.exe -lib 99 | # ADD BASE LIB32 /nologo 100 | # ADD LIB32 /nologo 101 | 102 | !ELSEIF "$(CFG)" == "TextView - Win32 Unicode Release" 103 | 104 | # PROP BASE Use_MFC 0 105 | # PROP BASE Use_Debug_Libraries 0 106 | # PROP BASE Output_Dir "TextView___Win32_Unicode_Release" 107 | # PROP BASE Intermediate_Dir "TextView___Win32_Unicode_Release" 108 | # PROP BASE Target_Dir "" 109 | # PROP Use_MFC 0 110 | # PROP Use_Debug_Libraries 0 111 | # PROP Output_Dir "Unicode_Release" 112 | # PROP Intermediate_Dir "Unicode_Release" 113 | # PROP Target_Dir "" 114 | # ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /c 115 | # ADD CPP /nologo /MD /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /FR /YX /FD /c 116 | # ADD BASE RSC /l 0x809 /d "NDEBUG" 117 | # ADD RSC /l 0x809 /d "NDEBUG" 118 | BSC32=bscmake.exe 119 | # ADD BASE BSC32 /nologo 120 | # ADD BSC32 /nologo 121 | LIB32=link.exe -lib 122 | # ADD BASE LIB32 /nologo 123 | # ADD LIB32 /nologo 124 | 125 | !ENDIF 126 | 127 | # Begin Target 128 | 129 | # Name "TextView - Win32 Release" 130 | # Name "TextView - Win32 Debug" 131 | # Name "TextView - Win32 Unicode Debug" 132 | # Name "TextView - Win32 Unicode Release" 133 | # Begin Group "Source Files" 134 | 135 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 136 | # Begin Source File 137 | 138 | SOURCE=.\sequence.cpp 139 | # End Source File 140 | # Begin Source File 141 | 142 | SOURCE=.\TextDocument.cpp 143 | # End Source File 144 | # Begin Source File 145 | 146 | SOURCE=.\TextView.cpp 147 | # End Source File 148 | # Begin Source File 149 | 150 | SOURCE=.\TextViewClipboard.cpp 151 | # End Source File 152 | # Begin Source File 153 | 154 | SOURCE=.\TextViewFile.cpp 155 | # End Source File 156 | # Begin Source File 157 | 158 | SOURCE=.\TextViewFont.cpp 159 | # End Source File 160 | # Begin Source File 161 | 162 | SOURCE=.\TextViewKeyInput.cpp 163 | # End Source File 164 | # Begin Source File 165 | 166 | SOURCE=.\TextViewKeyNav.cpp 167 | # End Source File 168 | # Begin Source File 169 | 170 | SOURCE=.\TextViewMouse.cpp 171 | # End Source File 172 | # Begin Source File 173 | 174 | SOURCE=.\TextViewPaint.cpp 175 | # End Source File 176 | # Begin Source File 177 | 178 | SOURCE=.\TextViewScroll.cpp 179 | # End Source File 180 | # Begin Source File 181 | 182 | SOURCE=.\TextViewSyntax.cpp 183 | # End Source File 184 | # Begin Source File 185 | 186 | SOURCE=.\Unicode.c 187 | # End Source File 188 | # End Group 189 | # Begin Group "Header Files" 190 | 191 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 192 | # Begin Source File 193 | 194 | SOURCE=.\codepages.h 195 | # End Source File 196 | # Begin Source File 197 | 198 | SOURCE=.\sequence.h 199 | # End Source File 200 | # Begin Source File 201 | 202 | SOURCE=.\TextDocument.h 203 | # End Source File 204 | # Begin Source File 205 | 206 | SOURCE=.\TextView.h 207 | # End Source File 208 | # Begin Source File 209 | 210 | SOURCE=.\TextViewInternal.h 211 | # End Source File 212 | # Begin Source File 213 | 214 | SOURCE=.\Unicode.h 215 | # End Source File 216 | # End Group 217 | # End Target 218 | # End Project 219 | -------------------------------------------------------------------------------- /TextView/TextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TextView public interface - include this file 3 | // when you want a TextView edit control 4 | // 5 | #ifndef TEXTVIEW_INCLUDED 6 | #define TEXTVIEW_INCLUDED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #ifndef UNICODE 13 | #pragma message("Warning: UNICODE is not defined\n") 14 | #endif 15 | 16 | // 17 | // TextView API declared here 18 | // 19 | BOOL InitTextView(); 20 | HWND CreateTextView(HWND hwndParent); 21 | COLORREF RealizeColour(COLORREF col); 22 | 23 | 24 | // 25 | // currently supported Neatpad Codepages 26 | // 27 | #define NCP_ASCII 0 28 | #define NCP_UTF8 1 29 | #define NCP_UTF16 2 30 | #define NCP_UTF16BE 3 31 | #define NCP_UTF32 4 32 | #define NCP_UTF32BE 5 33 | 34 | // 35 | // TextView edit modes 36 | // 37 | #define MODE_READONLY 0 38 | #define MODE_INSERT 1 39 | #define MODE_OVERWRITE 2 40 | 41 | // 42 | // TextView Window Messages defined here 43 | // 44 | #define TXM_BASE (WM_USER) 45 | #define TXM_OPENFILE (TXM_BASE + 0) 46 | #define TXM_CLEAR (TXM_BASE + 1) 47 | #define TXM_SETLINESPACING (TXM_BASE + 2) 48 | #define TXM_ADDFONT (TXM_BASE + 3) 49 | #define TXM_SETCOLOR (TXM_BASE + 4) 50 | #define TXM_GETCOLOR (TXM_BASE + 5) 51 | #define TXM_SETSTYLE (TXM_BASE + 6) 52 | #define TXM_GETSTYLE (TXM_BASE + 7) 53 | #define TXM_SETCARETWIDTH (TXM_BASE + 8) 54 | #define TXM_SETIMAGELIST (TXM_BASE + 9) 55 | #define TXM_SETLONGLINE (TXM_BASE + 10) 56 | #define TXM_SETLINEIMAGE (TXM_BASE + 11) 57 | #define TXM_GETFORMAT (TXM_BASE + 12) 58 | #define TXM_UNDO (TXM_BASE + 13) 59 | #define TXM_REDO (TXM_BASE + 14) 60 | #define TXM_CANUNDO (TXM_BASE + 15) 61 | #define TXM_CANREDO (TXM_BASE + 16) 62 | #define TXM_GETSELSIZE (TXM_BASE + 17) 63 | #define TXM_SETSELALL (TXM_BASE + 18) 64 | #define TXM_GETCURPOS (TXM_BASE + 19) 65 | #define TXM_GETCURLINE (TXM_BASE + 20) 66 | #define TXM_GETCURCOL (TXM_BASE + 21) 67 | #define TXM_SETEDITMODE (TXM_BASE + 22) 68 | #define TXM_GETEDITMODE (TXM_BASE + 23) 69 | #define TXM_SETCONTEXTMENU (TXM_BASE + 24) 70 | 71 | // 72 | // TextView Notification Messages defined here - 73 | // sent via the WM_NOTIFY message 74 | // 75 | #define TVN_BASE (WM_USER) 76 | #define TVN_CURSOR_CHANGE (TVN_BASE + 0) 77 | #define TVN_SELECTION_CHANGE (TVN_BASE + 1) 78 | #define TVN_EDITMODE_CHANGE (TVN_BASE + 2) 79 | #define TVN_CHANGED (TVN_BASE + 3) 80 | 81 | typedef struct 82 | { 83 | NMHDR hdr; 84 | ULONG nLineNo; 85 | ULONG nColumnNo; 86 | ULONG nOffset; 87 | } TVNCURSORINFO; 88 | 89 | // 90 | // TextView Window Styles defined here 91 | // (set using TXM_SETSTYLE) 92 | // 93 | #define TXS_SELMARGIN 1 94 | #define TXS_LINENUMBERS 2 95 | #define TXS_TREECTRL 4 96 | #define TXS_LONGLINES 8 97 | #define TXS_HIGHLIGHTCURLINE 16 98 | 99 | // 100 | // End-of-line mode 101 | // 102 | #define TXL_LF 1 // line-feed 103 | #define TXL_CR 2 // carriage-return 104 | #define TXL_CRLF 4 // carriage-return, line-feed (default) 105 | #define TXL_ALL 7 // allow all forms regardless 106 | 107 | // 108 | // TextView Macros defined here 109 | // 110 | #define TEXTVIEW_CLASS _T("TextView32") 111 | 112 | // 113 | // TextView colours 114 | // 115 | #define TXC_FOREGROUND 0 // normal foreground colour 116 | #define TXC_BACKGROUND 1 // normal background colour 117 | #define TXC_HIGHLIGHTTEXT 2 // normal text highlight colour 118 | #define TXC_HIGHLIGHT 3 // normal background highlight colour 119 | #define TXC_HIGHLIGHTTEXT2 4 // inactive text highlight colour 120 | #define TXC_HIGHLIGHT2 5 // inactive background highlight colour 121 | #define TXC_SELMARGIN1 6 // selection margin colour#1 122 | #define TXC_SELMARGIN2 7 // selection margin colour#2 123 | #define TXC_LINENUMBERTEXT 8 // line number text 124 | #define TXC_LINENUMBER 9 // line number background 125 | #define TXC_LONGLINETEXT 10 // long-line text 126 | #define TXC_LONGLINE 11 // long-line background 127 | #define TXC_CURRENTLINETEXT 12 // active line text 128 | #define TXC_CURRENTLINE 13 // active line background 129 | #define TXC_MAX_COLOURS 14 // keep this updated! 130 | 131 | #define SYSCOL(COLOR_IDX) ( 0x80000000 | COLOR_IDX ) 132 | #define MIXED_SYSCOL(COLOR_IDX1, COLOR_IDX2) ( 0xC0000000 | (COLOR_IDX2 << 8) | COLOR_IDX1 ) 133 | #define MIXED_SYSCOL2(COLOR_IDX1, COLOR_IDX2) ( 0xE0000000 | (COLOR_IDX2 << 8) | COLOR_IDX1 ) 134 | 135 | #define SYSCOLIDX(COLREF) ( 0x00FFFFFF & COLREF ) 136 | #define REALIZE_SYSCOL(col) (RealizeColour(col)) 137 | 138 | 139 | // 140 | // TextView Message Macros defined here 141 | // 142 | #define TextView_OpenFile(hwndTV, szFile) \ 143 | SendMessage((hwndTV), TXM_OPENFILE, 0, (LPARAM)(TCHAR *)(szFile)) 144 | 145 | #define TextView_Clear(hwndTV) \ 146 | SendMessage((hwndTV), TXM_CLEAR, 0, 0) 147 | 148 | #define TextView_SetLineSpacing(hwndTV, nAbove, nBelow) \ 149 | SendMessage((hwndTV), TXM_SETLINESPACING, (int)(nAbove), (int)(nBelow)) 150 | 151 | #define TextView_AddFont(hwndTV, hFont) \ 152 | SendMessage((hwndTV), TXM_ADDFONT, (WPARAM)(HFONT)(hFont), 0) 153 | 154 | #define TextView_SetColor(hwndTV, nIdx, rgbColor) \ 155 | SendMessage((hwndTV), TXM_SETCOLOR, (WPARAM)(nIdx), (LPARAM)(rgbColor)) 156 | 157 | #define TextView_SetStyle(hwndTV, uMask, uStyles) \ 158 | SendMessage((hwndTV), TXM_SETSTYLE, (WPARAM)(uMask), (LPARAM)(uStyles)) 159 | 160 | #define TextView_SetStyleBool(hwndTV, uStyle, fBoolean) \ 161 | SendMessage((hwndTV), TXM_SETSTYLE, (WPARAM)(uStyle), (LPARAM)(fBoolean ? uStyle : 0)) 162 | 163 | #define TextView_SetCaretWidth(hwndTV, nWidth) \ 164 | SendMessage((hwndTV), TXM_SETCARETWIDTH, (WPARAM)(nWidth), 0) 165 | 166 | #define TextView_SetImageList(hwndTV, hImgList) \ 167 | SendMessage((hwndTV), TXM_SETIMAGELIST, (WPARAM)(HIMAGELIST)(hImgList), 0) 168 | 169 | #define TextView_SetLongLine(hwndTV, nLength) \ 170 | SendMessage((hwndTV), TXM_SETLONGLINE, (WPARAM)(0), (LPARAM)(nLength)) 171 | 172 | #define TextView_SetLineImage(hwndTV, nLineNo, nImageIdx) \ 173 | SendMessage((hwndTV), TXM_SETLINEIMAGE, (WPARAM)(ULONG)(nLineNo), (LPARAM)(ULONG)nImageIdx) 174 | 175 | #define TextView_GetFormat(hwndTV) \ 176 | SendMessage((hwndTV), TXM_GETFORMAT, 0, 0) 177 | 178 | #define TextView_Undo(hwndTV) \ 179 | SendMessage((hwndTV), TXM_UNDO, 0, 0) 180 | 181 | #define TextView_Redo(hwndTV) \ 182 | SendMessage((hwndTV), TXM_REDO, 0, 0) 183 | 184 | #define TextView_CanUndo(hwndTV) \ 185 | SendMessage((hwndTV), TXM_CANUNDO, 0, 0) 186 | 187 | #define TextView_CanRedo(hwndTV) \ 188 | SendMessage((hwndTV), TXM_CANREDO, 0, 0) 189 | 190 | #define TextView_GetSelSize(hwndTV) \ 191 | SendMessage((hwndTV), TXM_GETSELSIZE, 0, 0) 192 | 193 | #define TextView_SelectAll(hwndTV) \ 194 | SendMessage((hwndTV), TXM_SETSELALL, 0, 0) 195 | 196 | #define TextView_GetCurPos(hwndTV) \ 197 | SendMessage((hwndTV), TXM_GETCURPOS, 0, 0) 198 | 199 | #define TextView_GetCurLine(hwndTV) \ 200 | SendMessage((hwndTV), TXM_GETCURLINE, 0, 0) 201 | 202 | #define TextView_GetCurCol(hwndTV) \ 203 | SendMessage((hwndTV), TXM_GETCURCOL, 0, 0) 204 | 205 | #define TextView_SetEditMode(hwndTV, nEditMode) \ 206 | SendMessage((hwndTV), TXM_SETEDITMODE, (WPARAM)(nEditMode), 0) 207 | 208 | #define TextView_GetEditMode(hwndTV) \ 209 | SendMessage((hwndTV), TXM_GETEDITMODE, 0, 0) 210 | 211 | #define TextView_SetContextMenu(hwndTV, hPopupMenu) \ 212 | SendMessage((hwndTV), TXM_SETCONTEXTMENU, (WPARAM)(hPopupMenu), 0) 213 | 214 | #define TextView_SetFont(hwndTV, hFont) \ 215 | SendMessage((hwndTV), WM_SETFONT, (WPARAM)(HFONT)(hFont), 0) 216 | 217 | #ifdef __cplusplus 218 | } 219 | #endif 220 | 221 | #endif -------------------------------------------------------------------------------- /TextView/TextViewClipboard.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextViewClipboard.cpp 3 | // 4 | // PURPOSE: Basic clipboard support for TextView 5 | // Just uses GetClipboardData/SetClipboardData until I migrate 6 | // to the OLE code from my drag+drop tutorials 7 | // 8 | // NOTES: www.catch22.net 9 | // 10 | 11 | #define STRICT 12 | #define WIN32_LEAN_AND_MEAN 13 | 14 | #include 15 | #include 16 | #include "TextView.h" 17 | #include "TextViewInternal.h" 18 | 19 | #ifdef UNICODE 20 | #define CF_TCHARTEXT CF_UNICODETEXT 21 | #else 22 | #define CF_TCHARTEXT CF_TEXT 23 | #endif 24 | 25 | // 26 | // Paste any CF_TEXT/CF_UNICODE text from the clipboard 27 | // 28 | BOOL TextView::OnPaste() 29 | { 30 | BOOL success = FALSE; 31 | 32 | if(m_nEditMode == MODE_READONLY) 33 | return FALSE; 34 | 35 | if(OpenClipboard(m_hWnd)) 36 | { 37 | HANDLE hMem = GetClipboardData(CF_TCHARTEXT); 38 | TCHAR *szText = (TCHAR *)GlobalLock(hMem); 39 | 40 | if(szText) 41 | { 42 | ULONG textlen = lstrlen(szText); 43 | EnterText(szText, textlen); 44 | 45 | if(textlen > 1) 46 | m_pTextDoc->m_seq.breakopt(); 47 | 48 | GlobalUnlock(hMem); 49 | 50 | success = TRUE; 51 | } 52 | 53 | CloseClipboard(); 54 | } 55 | 56 | return success; 57 | } 58 | 59 | // 60 | // Retrieve the specified range of text and copy it to supplied buffer 61 | // szDest must be big enough to hold nLength characters 62 | // nLength includes the terminating NULL 63 | // 64 | ULONG TextView::GetText(TCHAR *szDest, ULONG nStartOffset, ULONG nLength) 65 | { 66 | ULONG copied = 0; 67 | 68 | if(nLength > 1) 69 | { 70 | TextIterator itor = m_pTextDoc->iterate(nStartOffset); 71 | copied = itor.gettext(szDest, nLength - 1); 72 | 73 | // null-terminate 74 | szDest[copied] = 0; 75 | } 76 | 77 | return copied; 78 | } 79 | 80 | // 81 | // Copy the currently selected text to the clipboard as CF_TEXT/CF_UNICODE 82 | // 83 | BOOL TextView::OnCopy() 84 | { 85 | ULONG selstart = min(m_nSelectionStart, m_nSelectionEnd); 86 | ULONG sellen = SelectionSize(); 87 | BOOL success = FALSE; 88 | 89 | if(sellen == 0) 90 | return FALSE; 91 | 92 | if(OpenClipboard(m_hWnd)) 93 | { 94 | HANDLE hMem; 95 | TCHAR *ptr; 96 | 97 | if((hMem = GlobalAlloc(GPTR, (sellen + 1) * sizeof(TCHAR))) != 0) 98 | { 99 | if((ptr = (TCHAR *)GlobalLock(hMem)) != 0) 100 | { 101 | EmptyClipboard(); 102 | 103 | GetText(ptr, selstart, sellen + 1); 104 | 105 | SetClipboardData(CF_TCHARTEXT, hMem); 106 | success = TRUE; 107 | 108 | GlobalUnlock(hMem); 109 | } 110 | } 111 | 112 | CloseClipboard(); 113 | } 114 | 115 | return success; 116 | } 117 | 118 | // 119 | // Remove current selection and copy to the clipboard 120 | // 121 | BOOL TextView::OnCut() 122 | { 123 | BOOL success = FALSE; 124 | 125 | if(m_nEditMode == MODE_READONLY) 126 | return FALSE; 127 | 128 | if(SelectionSize() > 0) 129 | { 130 | // copy selected text to clipboard then erase current selection 131 | success = OnCopy(); 132 | success = success && ForwardDelete(); 133 | } 134 | 135 | return success; 136 | } 137 | 138 | // 139 | // Remove the current selection 140 | // 141 | BOOL TextView::OnClear() 142 | { 143 | BOOL success = FALSE; 144 | 145 | if(m_nEditMode == MODE_READONLY) 146 | return FALSE; 147 | 148 | if(SelectionSize() > 0) 149 | { 150 | ForwardDelete(); 151 | success = TRUE; 152 | } 153 | 154 | return success; 155 | } 156 | 157 | -------------------------------------------------------------------------------- /TextView/TextViewFile.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextViewFile.cpp 3 | // 4 | // PURPOSE: TextView file input routines 5 | // 6 | // NOTES: www.catch22.net 7 | // 8 | 9 | #define STRICT 10 | #define WIN32_LEAN_AND_MEAN 11 | 12 | #include 13 | #include 14 | #include "TextView.h" 15 | #include "TextViewInternal.h" 16 | 17 | // 18 | // 19 | // 20 | LONG TextView::OpenFile(TCHAR *szFileName) 21 | { 22 | ClearFile(); 23 | 24 | if(m_pTextDoc->init(szFileName)) 25 | { 26 | m_nLineCount = m_pTextDoc->linecount(); 27 | m_nLongestLine = m_pTextDoc->longestline(m_nTabWidthChars); 28 | 29 | m_nVScrollPos = 0; 30 | m_nHScrollPos = 0; 31 | 32 | m_nSelectionStart = 0; 33 | m_nSelectionEnd = 0; 34 | m_nCursorOffset = 0; 35 | 36 | UpdateMarginWidth(); 37 | UpdateMetrics(); 38 | ResetLineCache(); 39 | return TRUE; 40 | } 41 | 42 | return FALSE; 43 | } 44 | 45 | // 46 | // 47 | // 48 | LONG TextView::ClearFile() 49 | { 50 | if(m_pTextDoc) 51 | { 52 | m_pTextDoc->clear(); 53 | m_pTextDoc->EmptyDoc(); 54 | } 55 | 56 | ResetLineCache(); 57 | 58 | m_nLineCount = m_pTextDoc->linecount(); 59 | m_nLongestLine = m_pTextDoc->longestline(m_nTabWidthChars); 60 | 61 | m_nVScrollPos = 0; 62 | m_nHScrollPos = 0; 63 | 64 | m_nSelectionStart = 0; 65 | m_nSelectionEnd = 0; 66 | m_nCursorOffset = 0; 67 | 68 | m_nCurrentLine = 0; 69 | m_nCaretPosX = 0; 70 | 71 | UpdateMetrics(); 72 | 73 | 74 | 75 | return TRUE; 76 | } 77 | -------------------------------------------------------------------------------- /TextView/TextViewFont.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextViewFont.cpp 3 | // 4 | // PURPOSE: Font support for the TextView control 5 | // 6 | // NOTES: www.catch22.net 7 | // 8 | 9 | #define STRICT 10 | #define WIN32_LEAN_AND_MEAN 11 | 12 | #include 13 | #include 14 | #include "TextView.h" 15 | #include "TextViewInternal.h" 16 | 17 | // 18 | // TextView:: 19 | // 20 | int TextView::NeatTextYOffset(USPFONT *font) 21 | { 22 | return m_nMaxAscent + m_nHeightAbove - font->tm.tmAscent; 23 | } 24 | 25 | int TextView::TextWidth(HDC hdc, TCHAR *buf, int len) 26 | { 27 | SIZE sz; 28 | if(len == -1) 29 | len = lstrlen(buf); 30 | GetTextExtentPoint32(hdc, buf, len, &sz); 31 | return sz.cx; 32 | } 33 | 34 | // 35 | // Update the lineheight based on current font settings 36 | // 37 | VOID TextView::RecalcLineHeight() 38 | { 39 | m_nLineHeight = 0; 40 | m_nMaxAscent = 0; 41 | 42 | // find the tallest font in the TextView 43 | for(int i = 0; i < m_nNumFonts; i++) 44 | { 45 | // always include a font's external-leading 46 | int fontheight = m_uspFontList[i].tm.tmHeight + 47 | m_uspFontList[i].tm.tmExternalLeading; 48 | 49 | m_nLineHeight = max(m_nLineHeight, fontheight); 50 | m_nMaxAscent = max(m_nMaxAscent, m_uspFontList[i].tm.tmAscent); 51 | } 52 | 53 | // add on the above+below spacings 54 | m_nLineHeight += m_nHeightAbove + m_nHeightBelow; 55 | 56 | // force caret resize if we've got the focus 57 | if(GetFocus() == m_hWnd) 58 | { 59 | OnKillFocus(0); 60 | OnSetFocus(0); 61 | } 62 | } 63 | 64 | // 65 | // Set a font for the TextView 66 | // 67 | LONG TextView::SetFont(HFONT hFont, int idx) 68 | { 69 | USPFONT *uspFont = &m_uspFontList[idx]; 70 | 71 | // need a DC to query font data 72 | HDC hdc = GetDC(m_hWnd); 73 | 74 | // Initialize the font for USPLIB 75 | UspFreeFont(uspFont); 76 | UspInitFont(uspFont, hdc, hFont); 77 | 78 | ReleaseDC(m_hWnd, hdc); 79 | 80 | // calculate new line metrics 81 | m_nFontWidth = m_uspFontList[0].tm.tmAveCharWidth; 82 | 83 | RecalcLineHeight(); 84 | UpdateMarginWidth(); 85 | 86 | ResetLineCache(); 87 | 88 | return 0; 89 | } 90 | 91 | // 92 | // Add a secondary font to the TextView 93 | // 94 | LONG TextView::AddFont(HFONT hFont) 95 | { 96 | int idx = m_nNumFonts++; 97 | 98 | SetFont(hFont, idx); 99 | UpdateMetrics(); 100 | 101 | return 0; 102 | } 103 | 104 | // 105 | // WM_SETFONT handler: set a new default font 106 | // 107 | LONG TextView::OnSetFont(HFONT hFont) 108 | { 109 | // default font is always #0 110 | SetFont(hFont, 0); 111 | UpdateMetrics(); 112 | 113 | return 0; 114 | } 115 | 116 | // 117 | // Set spacing (in pixels) above and below each line - 118 | // this is in addition to the external-leading of a font 119 | // 120 | LONG TextView::SetLineSpacing(int nAbove, int nBelow) 121 | { 122 | m_nHeightAbove = nAbove; 123 | m_nHeightBelow = nBelow; 124 | RecalcLineHeight(); 125 | return TRUE; 126 | } 127 | -------------------------------------------------------------------------------- /TextView/TextViewInternal.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTVIEW_INTERNAL_INCLUDED 2 | #define TEXTVIEW_INTERNAL_INCLUDED 3 | 4 | #define TEXTBUFSIZE 128 5 | #define LINENO_FMT _T(" %2d ") 6 | #define LINENO_PAD 8 7 | 8 | #include 9 | #include 10 | 11 | /*HTHEME (WINAPI * OpenThemeData_Proc)(HWND hwnd, LPCWSTR pszClassList); 12 | BOOL (WINAPI * CloseThemeData_Proc)(HTHEME hTheme); 13 | HRESULT (WINAPI * DrawThemeBackground_Proc)(HTHEME hTheme, HDC hdc, int, int, const RECT*, const RECT*); 14 | */ 15 | 16 | 17 | #include "TextDocument.h" 18 | 19 | #include "..\UspLib\usplib.h" 20 | 21 | typedef struct 22 | { 23 | USPDATA *uspData; 24 | ULONG lineno; // line# 25 | ULONG offset; // offset (in WCHAR's) of this line 26 | ULONG usage; // cache-count 27 | 28 | int length; // length in chars INCLUDING CR/LF 29 | int length_CRLF; // length in chars EXCLUDING CR/LF 30 | 31 | } USPCACHE; 32 | 33 | typedef const SCRIPT_LOGATTR CSCRIPT_LOGATTR; 34 | 35 | #define USP_CACHE_SIZE 200 36 | 37 | // 38 | // LINEINFO - information about a specific line 39 | // 40 | typedef struct 41 | { 42 | ULONG nLineNo; 43 | int nImageIdx; 44 | 45 | // more here in the future? 46 | 47 | } LINEINFO; 48 | 49 | typedef int (__cdecl * COMPAREPROC) (const void *, const void *); 50 | 51 | // maximum number of lines that we can hold info for at one time 52 | #define MAX_LINE_INFO 128 53 | 54 | // maximum fonts that a TextView can hold 55 | #define MAX_FONTS 32 56 | 57 | enum SELMODE { SEL_NONE, SEL_NORMAL, SEL_MARGIN, SEL_BLOCK }; 58 | 59 | typedef struct 60 | { 61 | ULONG line; 62 | ULONG xpos; 63 | 64 | } CURPOS; 65 | 66 | // 67 | // TextView - internal window implementation 68 | // 69 | class TextView 70 | { 71 | public: 72 | 73 | TextView(HWND hwnd); 74 | ~TextView(); 75 | 76 | LONG WINAPI WndProc(UINT msg, WPARAM wParam, LPARAM lParam); 77 | 78 | private: 79 | 80 | // 81 | // Message handlers 82 | // 83 | LONG OnPaint(); 84 | LONG OnNcPaint(HRGN hrgnUpdate); 85 | LONG OnSetFont(HFONT hFont); 86 | LONG OnSize(UINT nFlags, int width, int height); 87 | LONG OnVScroll(UINT nSBCode, UINT nPos); 88 | LONG OnHScroll(UINT nSBCode, UINT nPos); 89 | LONG OnMouseWheel(int nDelta); 90 | LONG OnTimer(UINT nTimer); 91 | 92 | LONG OnMouseActivate(HWND hwndTop, UINT nHitTest, UINT nMessage); 93 | LONG OnContextMenu(HWND wParam, int x, int y); 94 | 95 | LONG OnLButtonDown(UINT nFlags, int x, int y); 96 | LONG OnLButtonUp(UINT nFlags, int x, int y); 97 | LONG OnLButtonDblClick(UINT nFlags, int x, int y); 98 | LONG OnMouseMove(UINT nFlags, int x, int y); 99 | 100 | LONG OnKeyDown(UINT nKeyCode, UINT nFlags); 101 | LONG OnChar(UINT nChar, UINT nFlags); 102 | 103 | LONG OnSetFocus(HWND hwndOld); 104 | LONG OnKillFocus(HWND hwndNew); 105 | 106 | BOOL OnCut(); 107 | BOOL OnCopy(); 108 | BOOL OnPaste(); 109 | BOOL OnClear(); 110 | 111 | private: 112 | 113 | // 114 | // Internal private functions 115 | // 116 | LONG OpenFile(TCHAR *szFileName); 117 | LONG ClearFile(); 118 | void ResetLineCache(); 119 | ULONG GetText(TCHAR *szDest, ULONG nStartOffset, ULONG nLength); 120 | 121 | // 122 | // Cursor/Selection 123 | // 124 | ULONG SelectionSize(); 125 | ULONG SelectAll(); 126 | 127 | //void Toggle 128 | 129 | 130 | // 131 | // Painting support 132 | // 133 | void RefreshWindow(); 134 | void PaintLine(HDC hdc, ULONG line, int x, int y, HRGN hrgnUpdate); 135 | void PaintText(HDC hdc, ULONG nLineNo, int x, int y, RECT *bounds); 136 | int PaintMargin(HDC hdc, ULONG line, int x, int y); 137 | 138 | LONG InvalidateRange(ULONG nStart, ULONG nFinish); 139 | LONG InvalidateLine(ULONG nLineNo, bool forceAnalysis); 140 | VOID UpdateLine(ULONG nLineNo); 141 | 142 | 143 | int ApplyTextAttributes(ULONG nLineNo, ULONG offset, ULONG &nColumn, TCHAR *szText, int nTextLen, ATTR *attr); 144 | int ApplySelection(USPDATA *uspData, ULONG nLineNo, ULONG nOffset, ULONG nTextLen); 145 | int SyntaxColour(TCHAR *szText, ULONG nTextLen, ATTR *attr); 146 | int StripCRLF(TCHAR *szText, ATTR *attrList, int nLength, bool fAllow); 147 | void MarkCRLF(USPDATA *uspData, TCHAR *szText, int nLength, ATTR *attr); 148 | int CRLF_size(TCHAR *szText, int nLength); 149 | 150 | // 151 | // Font support 152 | // 153 | LONG AddFont(HFONT); 154 | LONG SetFont(HFONT, int idx); 155 | LONG SetLineSpacing(int nAbove, int nBelow); 156 | LONG SetLongLine(int nLength); 157 | 158 | // 159 | // 160 | // 161 | int NeatTextYOffset(USPFONT *font); 162 | int TextWidth(HDC hdc, TCHAR *buf, int len); 163 | //int TabWidth(); 164 | int LeftMarginWidth(); 165 | void UpdateMarginWidth(); 166 | int SetCaretWidth(int nWidth); 167 | BOOL SetImageList(HIMAGELIST hImgList); 168 | int SetLineImage(ULONG nLineNo, ULONG nImageIdx); 169 | LINEINFO * GetLineInfo(ULONG nLineNo); 170 | 171 | // 172 | // Caret/Cursor positioning 173 | // 174 | BOOL MouseCoordToFilePos(int x, int y, ULONG *pnLineNo, ULONG *pnFileOffset, int *px);//, ULONG *pnLineLen=0); 175 | VOID RepositionCaret(); 176 | //VOID MoveCaret(int x, int y); 177 | VOID UpdateCaretXY(int x, ULONG lineno); 178 | VOID UpdateCaretOffset(ULONG offset, BOOL fTrailing, int *outx=0, ULONG *outlineno=0); 179 | VOID Smeg(BOOL fAdvancing); 180 | 181 | VOID MoveWordPrev(); 182 | VOID MoveWordNext(); 183 | VOID MoveWordStart(); 184 | VOID MoveWordEnd(); 185 | VOID MoveCharPrev(); 186 | VOID MoveCharNext(); 187 | VOID MoveLineUp(int numLines); 188 | VOID MoveLineDown(int numLines); 189 | VOID MovePageUp(); 190 | VOID MovePageDown(); 191 | VOID MoveLineStart(ULONG lineNo); 192 | VOID MoveLineEnd(ULONG lineNo); 193 | VOID MoveFileStart(); 194 | VOID MoveFileEnd(); 195 | 196 | // 197 | // Editing 198 | // 199 | BOOL Undo(); 200 | BOOL Redo(); 201 | BOOL CanUndo(); 202 | BOOL CanRedo(); 203 | BOOL ForwardDelete(); 204 | BOOL BackDelete(); 205 | ULONG EnterText(TCHAR *szText, ULONG nLength); 206 | 207 | // 208 | // Scrolling 209 | // 210 | HRGN ScrollRgn(int dx, int dy, bool fReturnUpdateRgn); 211 | void Scroll(int dx, int dy); 212 | void ScrollToCaret(); 213 | void ScrollToPosition(int xpos, ULONG lineno); 214 | VOID SetupScrollbars(); 215 | VOID UpdateMetrics(); 216 | VOID RecalcLineHeight(); 217 | bool PinToBottomCorner(); 218 | 219 | // 220 | // TextView configuration 221 | // 222 | ULONG SetStyle(ULONG uMask, ULONG uStyles); 223 | ULONG SetVar(ULONG nVar, ULONG nValue); 224 | ULONG GetVar(ULONG nVar); 225 | ULONG GetStyleMask(ULONG uMask); 226 | bool CheckStyle(ULONG uMask); 227 | 228 | COLORREF SetColour(UINT idx, COLORREF rgbColour); 229 | COLORREF GetColour(UINT idx); 230 | COLORREF LineColour(ULONG nLineNo); 231 | COLORREF LongColour(ULONG nLineNo); 232 | 233 | // 234 | // Miscallaneous 235 | // 236 | HMENU CreateContextMenu(); 237 | ULONG NotifyParent(UINT nNotifyCode, NMHDR *optional = 0); 238 | 239 | 240 | 241 | // 242 | // ------ Internal TextView State ------ 243 | // 244 | 245 | HWND m_hWnd; 246 | HTHEME m_hTheme; 247 | ULONG m_uStyleFlags; 248 | 249 | // File-related data 250 | ULONG m_nLineCount; 251 | 252 | // Font-related data 253 | USPFONT m_uspFontList[MAX_FONTS]; 254 | int m_nNumFonts; 255 | int m_nFontWidth; 256 | int m_nMaxAscent; 257 | int m_nLineHeight; 258 | int m_nHeightAbove; 259 | int m_nHeightBelow; 260 | 261 | // Scrollbar-related data 262 | ULONG m_nVScrollPos; 263 | ULONG m_nVScrollMax; 264 | int m_nHScrollPos; 265 | int m_nHScrollMax; 266 | 267 | int m_nLongestLine; 268 | int m_nWindowLines; 269 | int m_nWindowColumns; 270 | 271 | // Cursor/Caret position 272 | ULONG m_nCurrentLine; 273 | ULONG m_nSelectionStart; 274 | ULONG m_nSelectionEnd; 275 | ULONG m_nCursorOffset; 276 | ULONG m_nSelMarginOffset1; 277 | ULONG m_nSelMarginOffset2; 278 | int m_nCaretPosX; 279 | int m_nAnchorPosX; 280 | 281 | SELMODE m_nSelectionMode; 282 | SELMODE m_nSelectionType; 283 | CURPOS m_cpBlockStart; 284 | CURPOS m_cpBlockEnd; 285 | UINT m_nEditMode; 286 | 287 | // Display-related data 288 | int m_nTabWidthChars; 289 | DWORD m_nCaretWidth; 290 | int m_nLongLineLimit; 291 | int m_nCRLFMode; 292 | 293 | LINEINFO m_LineInfo[MAX_LINE_INFO]; 294 | int m_nLineInfoCount; 295 | 296 | // Margin information 297 | int m_nLinenoWidth; 298 | HCURSOR m_hMarginCursor; 299 | //RECT m_rcBorder; 300 | 301 | COLORREF m_rgbColourList[TXC_MAX_COLOURS]; 302 | 303 | // Runtime data 304 | UINT m_nScrollTimer; 305 | int m_nScrollCounter; 306 | bool m_fHideCaret; 307 | //bool m_fTransparent; 308 | HIMAGELIST m_hImageList; 309 | HMENU m_hUserMenu; 310 | 311 | // Cache for USPDATA objects 312 | USPCACHE *m_uspCache; 313 | USPDATA *GetUspData(HDC hdc, ULONG nLineNo, ULONG *nOffset=0); 314 | USPCACHE *GetUspCache(HDC hdc, ULONG nLineNo, ULONG *nOffset=0); 315 | bool GetLogAttr(ULONG nLineNo, USPCACHE **puspCache, CSCRIPT_LOGATTR **plogAttr=0, ULONG *pnOffset=0); 316 | 317 | TextDocument *m_pTextDoc; 318 | }; 319 | 320 | #endif -------------------------------------------------------------------------------- /TextView/TextViewKeyInput.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextViewKeyInput.cpp 3 | // 4 | // PURPOSE: Keyboard input for TextView 5 | // 6 | // NOTES: www.catch22.net 7 | // 8 | 9 | #define STRICT 10 | #define WIN32_LEAN_AND_MEAN 11 | 12 | #include 13 | #include 14 | #include "TextView.h" 15 | #include "TextViewInternal.h" 16 | 17 | // 18 | // TextView::EnterText 19 | // 20 | // Import the specified text into the TextView at the current 21 | // cursor position, replacing any text-selection in the process 22 | // 23 | ULONG TextView::EnterText(TCHAR *szText, ULONG nLength) 24 | { 25 | ULONG selstart = min(m_nSelectionStart, m_nSelectionEnd); 26 | ULONG selend = max(m_nSelectionStart, m_nSelectionEnd); 27 | 28 | BOOL fReplaceSelection = (selstart == selend) ? FALSE : TRUE; 29 | ULONG erase_len = nLength; 30 | 31 | switch(m_nEditMode) 32 | { 33 | case MODE_READONLY: 34 | return 0; 35 | 36 | case MODE_INSERT: 37 | 38 | // if there is a selection then remove it 39 | if(fReplaceSelection) 40 | { 41 | // group this erase with the insert/replace operation 42 | m_pTextDoc->m_seq.group(); 43 | m_pTextDoc->erase_text(selstart, selend-selstart); 44 | m_nCursorOffset = selstart; 45 | } 46 | 47 | if(!m_pTextDoc->insert_text(m_nCursorOffset, szText, nLength)) 48 | return 0; 49 | 50 | if(fReplaceSelection) 51 | m_pTextDoc->m_seq.ungroup(); 52 | 53 | break; 54 | 55 | case MODE_OVERWRITE: 56 | 57 | if(fReplaceSelection) 58 | { 59 | erase_len = selend - selstart; 60 | m_nCursorOffset = selstart; 61 | } 62 | else 63 | { 64 | ULONG lineoff; 65 | USPCACHE *uspCache = GetUspCache(0, m_nCurrentLine, &lineoff); 66 | 67 | // single-character overwrite - must behave like 'forward delete' 68 | // and remove a whole character-cluster (i.e. maybe more than 1 char) 69 | if(nLength == 1) 70 | { 71 | ULONG oldpos = m_nCursorOffset; 72 | MoveCharNext(); 73 | erase_len = m_nCursorOffset - oldpos; 74 | m_nCursorOffset = oldpos; 75 | } 76 | 77 | // if we are at the end of a line (just before the CRLF) then we must 78 | // not erase any text - instead we act like a regular insertion 79 | if(m_nCursorOffset == lineoff + uspCache->length_CRLF) 80 | erase_len = 0; 81 | 82 | 83 | } 84 | 85 | if(!m_pTextDoc->replace_text(m_nCursorOffset, szText, nLength, erase_len)) 86 | return 0; 87 | 88 | break; 89 | 90 | default: 91 | return 0; 92 | } 93 | 94 | // update cursor+selection positions 95 | m_nCursorOffset += nLength; 96 | m_nSelectionStart = m_nCursorOffset; 97 | m_nSelectionEnd = m_nCursorOffset; 98 | 99 | // we altered the document, recalculate line+scrollbar information 100 | ResetLineCache(); 101 | RefreshWindow(); 102 | 103 | Smeg(TRUE); 104 | NotifyParent(TVN_CURSOR_CHANGE); 105 | 106 | return nLength; 107 | } 108 | 109 | BOOL TextView::ForwardDelete() 110 | { 111 | ULONG selstart = min(m_nSelectionStart, m_nSelectionEnd); 112 | ULONG selend = max(m_nSelectionStart, m_nSelectionEnd); 113 | 114 | if(selstart != selend) 115 | { 116 | m_pTextDoc->erase_text(selstart, selend-selstart); 117 | m_nCursorOffset = selstart; 118 | 119 | m_pTextDoc->m_seq.breakopt(); 120 | } 121 | else 122 | { 123 | BYTE tmp[2]; 124 | //USPCACHE * uspCache; 125 | //CSCRIPT_LOGATTR * logAttr; 126 | //ULONG lineOffset; 127 | //ULONG index; 128 | 129 | m_pTextDoc->m_seq.render(m_nCursorOffset, tmp, 2); 130 | 131 | /*GetLogAttr(m_nCurrentLine, &uspCache, &logAttr, &lineOffset); 132 | 133 | index = m_nCursorOffset - lineOffset; 134 | 135 | do 136 | { 137 | m_pTextDoc->seq.erase(m_nCursorOffset, 1); 138 | index++; 139 | } 140 | while(!logAttr[index].fCharStop);*/ 141 | 142 | ULONG oldpos = m_nCursorOffset; 143 | MoveCharNext(); 144 | 145 | m_pTextDoc->erase_text(oldpos, m_nCursorOffset - oldpos); 146 | m_nCursorOffset = oldpos; 147 | 148 | 149 | //if(tmp[0] == '\r') 150 | // m_pTextDoc->erase_text(m_nCursorOffset, 2); 151 | //else 152 | // m_pTextDoc->erase_text(m_nCursorOffset, 1); 153 | } 154 | 155 | m_nSelectionStart = m_nCursorOffset; 156 | m_nSelectionEnd = m_nCursorOffset; 157 | 158 | ResetLineCache(); 159 | RefreshWindow(); 160 | Smeg(FALSE); 161 | 162 | return TRUE; 163 | } 164 | 165 | BOOL TextView::BackDelete() 166 | { 167 | ULONG selstart = min(m_nSelectionStart, m_nSelectionEnd); 168 | ULONG selend = max(m_nSelectionStart, m_nSelectionEnd); 169 | 170 | // if there's a selection then delete it 171 | if(selstart != selend) 172 | { 173 | m_pTextDoc->erase_text(selstart, selend-selstart); 174 | m_nCursorOffset = selstart; 175 | m_pTextDoc->m_seq.breakopt(); 176 | } 177 | // otherwise do a back-delete 178 | else if(m_nCursorOffset > 0) 179 | { 180 | //m_nCursorOffset--; 181 | ULONG oldpos = m_nCursorOffset; 182 | MoveCharPrev(); 183 | //m_pTextDoc->erase_text(m_nCursorOffset, 1); 184 | m_pTextDoc->erase_text(m_nCursorOffset, oldpos - m_nCursorOffset); 185 | } 186 | 187 | m_nSelectionStart = m_nCursorOffset; 188 | m_nSelectionEnd = m_nCursorOffset; 189 | 190 | ResetLineCache(); 191 | RefreshWindow(); 192 | Smeg(FALSE); 193 | 194 | return TRUE; 195 | } 196 | 197 | void TextView::Smeg(BOOL fAdvancing) 198 | { 199 | m_pTextDoc->init_linebuffer(); 200 | 201 | m_nLineCount = m_pTextDoc->linecount(); 202 | 203 | UpdateMetrics(); 204 | UpdateMarginWidth(); 205 | SetupScrollbars(); 206 | 207 | UpdateCaretOffset(m_nCursorOffset, fAdvancing, &m_nCaretPosX, &m_nCurrentLine); 208 | 209 | m_nAnchorPosX = m_nCaretPosX; 210 | ScrollToPosition(m_nCaretPosX, m_nCurrentLine); 211 | RepositionCaret(); 212 | } 213 | 214 | BOOL TextView::Undo() 215 | { 216 | if(m_nEditMode == MODE_READONLY) 217 | return FALSE; 218 | 219 | if(!m_pTextDoc->Undo(&m_nSelectionStart, &m_nSelectionEnd)) 220 | return FALSE; 221 | 222 | m_nCursorOffset = m_nSelectionEnd; 223 | 224 | ResetLineCache(); 225 | RefreshWindow(); 226 | 227 | Smeg(m_nSelectionStart != m_nSelectionEnd); 228 | 229 | return TRUE; 230 | } 231 | 232 | BOOL TextView::Redo() 233 | { 234 | if(m_nEditMode == MODE_READONLY) 235 | return FALSE; 236 | 237 | if(!m_pTextDoc->Redo(&m_nSelectionStart, &m_nSelectionEnd)) 238 | return FALSE; 239 | 240 | m_nCursorOffset = m_nSelectionEnd; 241 | 242 | ResetLineCache(); 243 | RefreshWindow(); 244 | Smeg(m_nSelectionStart != m_nSelectionEnd); 245 | 246 | return TRUE; 247 | } 248 | 249 | BOOL TextView::CanUndo() 250 | { 251 | return m_pTextDoc->m_seq.canundo() ? TRUE : FALSE; 252 | } 253 | 254 | BOOL TextView::CanRedo() 255 | { 256 | return m_pTextDoc->m_seq.canredo() ? TRUE : FALSE; 257 | } 258 | 259 | LONG TextView::OnChar(UINT nChar, UINT nFlags) 260 | { 261 | WCHAR ch = (WCHAR)nChar; 262 | 263 | if(nChar < 32 && nChar != '\t' && nChar != '\r' && nChar != '\n') 264 | return 0; 265 | 266 | // change CR into a CR/LF sequence 267 | if(nChar == '\r') 268 | PostMessage(m_hWnd, WM_CHAR, '\n', 1); 269 | 270 | if(EnterText(&ch, 1)) 271 | { 272 | if(nChar == '\n') 273 | m_pTextDoc->m_seq.breakopt(); 274 | 275 | NotifyParent(TVN_CHANGED); 276 | } 277 | 278 | return 0; 279 | } 280 | -------------------------------------------------------------------------------- /TextView/TextViewKeyNav.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextViewKeyNav.cpp 3 | // 4 | // PURPOSE: Keyboard navigation for TextView 5 | // 6 | // NOTES: www.catch22.net 7 | // 8 | 9 | #define STRICT 10 | #define WIN32_LEAN_AND_MEAN 11 | 12 | #include 13 | #include 14 | #include "TextView.h" 15 | #include "TextViewInternal.h" 16 | 17 | /*struct SCRIPT_LOGATTR 18 | { 19 | BYTE fSoftBreak :1; 20 | BYTE fWhiteSpace :1; 21 | BYTE fCharStop :1; 22 | BYTE fWordStop :1; 23 | BYTE fInvalid :1; 24 | BYTE fReserved :3; 25 | };*/ 26 | 27 | 28 | bool IsKeyPressed(UINT nVirtKey) 29 | { 30 | return GetKeyState(nVirtKey) < 0 ? true : false; 31 | } 32 | 33 | // 34 | // Get the UspCache and logical attributes for specified line 35 | // 36 | bool TextView::GetLogAttr(ULONG nLineNo, USPCACHE **puspCache, CSCRIPT_LOGATTR **plogAttr, ULONG *pnOffset) 37 | { 38 | if((*puspCache = GetUspCache(0, nLineNo, pnOffset)) == 0) 39 | return false; 40 | 41 | if(plogAttr && (*plogAttr = UspGetLogAttr((*puspCache)->uspData)) == 0) 42 | return false; 43 | 44 | return true; 45 | } 46 | 47 | // 48 | // Move caret up specified number of lines 49 | // 50 | VOID TextView::MoveLineUp(int numLines) 51 | { 52 | USPDATA * uspData; 53 | ULONG lineOffset; 54 | 55 | int charPos; 56 | BOOL trailing; 57 | 58 | m_nCurrentLine -= min(m_nCurrentLine, (unsigned)numLines); 59 | 60 | // get Uniscribe data for prev line 61 | uspData = GetUspData(0, m_nCurrentLine, &lineOffset); 62 | 63 | // move up to character nearest the caret-anchor positions 64 | UspXToOffset(uspData, m_nAnchorPosX, &charPos, &trailing, 0); 65 | 66 | m_nCursorOffset = lineOffset + charPos + trailing; 67 | } 68 | 69 | // 70 | // Move caret down specified number of lines 71 | // 72 | VOID TextView::MoveLineDown(int numLines) 73 | { 74 | USPDATA * uspData; 75 | ULONG lineOffset; 76 | 77 | int charPos; 78 | BOOL trailing; 79 | 80 | m_nCurrentLine += min(m_nLineCount-m_nCurrentLine-1, (unsigned)numLines); 81 | 82 | // get Uniscribe data for prev line 83 | uspData = GetUspData(0, m_nCurrentLine, &lineOffset); 84 | 85 | // move down to character nearest the caret-anchor position 86 | UspXToOffset(uspData, m_nAnchorPosX, &charPos, &trailing, 0); 87 | 88 | m_nCursorOffset = lineOffset + charPos + trailing; 89 | } 90 | 91 | // 92 | // Move to start of previous word (to the left) 93 | // 94 | VOID TextView::MoveWordPrev() 95 | { 96 | USPCACHE * uspCache; 97 | CSCRIPT_LOGATTR * logAttr; 98 | ULONG lineOffset; 99 | int charPos; 100 | 101 | // get Uniscribe data for current line 102 | if(!GetLogAttr(m_nCurrentLine, &uspCache, &logAttr, &lineOffset)) 103 | return; 104 | 105 | // move 1 character to left 106 | charPos = m_nCursorOffset - lineOffset - 1; 107 | 108 | // skip to end of *previous* line if necessary 109 | if(charPos < 0) 110 | { 111 | charPos = 0; 112 | 113 | if(m_nCurrentLine > 0) 114 | { 115 | MoveLineEnd(m_nCurrentLine-1); 116 | return; 117 | } 118 | } 119 | 120 | // skip preceding whitespace 121 | while(charPos > 0 && logAttr[charPos].fWhiteSpace) 122 | charPos--; 123 | 124 | // skip whole characters until we hit a word-break/more whitespace 125 | for( ; charPos > 0 ; charPos--) 126 | { 127 | if(logAttr[charPos].fWordStop || logAttr[charPos-1].fWhiteSpace) 128 | break; 129 | } 130 | 131 | m_nCursorOffset = lineOffset + charPos; 132 | } 133 | 134 | // 135 | // Move to start of next word 136 | // 137 | VOID TextView::MoveWordNext() 138 | { 139 | USPCACHE * uspCache; 140 | CSCRIPT_LOGATTR * logAttr; 141 | ULONG lineOffset; 142 | int charPos; 143 | 144 | // get Uniscribe data for current line 145 | if(!GetLogAttr(m_nCurrentLine, &uspCache, &logAttr, &lineOffset)) 146 | return; 147 | 148 | charPos = m_nCursorOffset - lineOffset; 149 | 150 | // if already at end-of-line, skip to next line 151 | if(charPos == uspCache->length_CRLF) 152 | { 153 | if(m_nCurrentLine + 1 < m_nLineCount) 154 | MoveLineStart(m_nCurrentLine+1); 155 | 156 | return; 157 | } 158 | 159 | // if already on a word-break, go to next char 160 | if(logAttr[charPos].fWordStop) 161 | charPos++; 162 | 163 | // skip whole characters until we hit a word-break/more whitespace 164 | for( ; charPos < uspCache->length_CRLF; charPos++) 165 | { 166 | if(logAttr[charPos].fWordStop || logAttr[charPos].fWhiteSpace) 167 | break; 168 | } 169 | 170 | // skip trailing whitespace 171 | while(charPos < uspCache->length_CRLF && logAttr[charPos].fWhiteSpace) 172 | charPos++; 173 | 174 | m_nCursorOffset = lineOffset + charPos; 175 | } 176 | 177 | // 178 | // Move to start of current word 179 | // 180 | VOID TextView::MoveWordStart() 181 | { 182 | USPCACHE * uspCache; 183 | CSCRIPT_LOGATTR * logAttr; 184 | ULONG lineOffset; 185 | int charPos; 186 | 187 | // get Uniscribe data for current line 188 | if(!GetLogAttr(m_nCurrentLine, &uspCache, &logAttr, &lineOffset)) 189 | return; 190 | 191 | charPos = m_nCursorOffset - lineOffset; 192 | 193 | while(charPos > 0 && !logAttr[charPos-1].fWhiteSpace) 194 | charPos--; 195 | 196 | m_nCursorOffset = lineOffset + charPos; 197 | } 198 | 199 | // 200 | // Move to end of current word 201 | // 202 | VOID TextView::MoveWordEnd() 203 | { 204 | USPCACHE * uspCache; 205 | CSCRIPT_LOGATTR * logAttr; 206 | ULONG lineOffset; 207 | int charPos; 208 | 209 | // get Uniscribe data for current line 210 | if(!GetLogAttr(m_nCurrentLine, &uspCache, &logAttr, &lineOffset)) 211 | return; 212 | 213 | charPos = m_nCursorOffset - lineOffset; 214 | 215 | while(charPos < uspCache->length_CRLF && !logAttr[charPos].fWhiteSpace) 216 | charPos++; 217 | 218 | m_nCursorOffset = lineOffset + charPos; 219 | } 220 | 221 | // 222 | // Move to previous character 223 | // 224 | VOID TextView::MoveCharPrev() 225 | { 226 | USPCACHE * uspCache; 227 | CSCRIPT_LOGATTR * logAttr; 228 | ULONG lineOffset; 229 | int charPos; 230 | 231 | // get Uniscribe data for current line 232 | if(!GetLogAttr(m_nCurrentLine, &uspCache, &logAttr, &lineOffset)) 233 | return; 234 | 235 | charPos = m_nCursorOffset - lineOffset; 236 | 237 | // find the previous valid character-position 238 | for( --charPos; charPos >= 0; charPos--) 239 | { 240 | if(logAttr[charPos].fCharStop) 241 | break; 242 | } 243 | 244 | // move up to end-of-last line if necessary 245 | if(charPos < 0) 246 | { 247 | charPos = 0; 248 | 249 | if(m_nCurrentLine > 0) 250 | { 251 | MoveLineEnd(m_nCurrentLine-1); 252 | return; 253 | } 254 | } 255 | 256 | // update cursor position 257 | m_nCursorOffset = lineOffset + charPos; 258 | } 259 | 260 | // 261 | // Move to next character 262 | // 263 | VOID TextView::MoveCharNext() 264 | { 265 | USPCACHE * uspCache; 266 | CSCRIPT_LOGATTR * logAttr; 267 | ULONG lineOffset; 268 | int charPos; 269 | 270 | // get Uniscribe data for specified line 271 | if(!GetLogAttr(m_nCurrentLine, &uspCache, &logAttr, &lineOffset)) 272 | return; 273 | 274 | charPos = m_nCursorOffset - lineOffset; 275 | 276 | // find the next valid character-position 277 | for( ++charPos; charPos <= uspCache->length_CRLF; charPos++) 278 | { 279 | if(logAttr[charPos].fCharStop) 280 | break; 281 | } 282 | 283 | // skip to beginning of next line if we hit the CR/LF 284 | if(charPos > uspCache->length_CRLF) 285 | { 286 | if(m_nCurrentLine + 1 < m_nLineCount) 287 | MoveLineStart(m_nCurrentLine+1); 288 | } 289 | // otherwise advance the character-position 290 | else 291 | { 292 | m_nCursorOffset = lineOffset + charPos; 293 | } 294 | } 295 | 296 | // 297 | // Move to start of specified line 298 | // 299 | VOID TextView::MoveLineStart(ULONG lineNo) 300 | { 301 | ULONG lineOffset; 302 | USPCACHE * uspCache; 303 | CSCRIPT_LOGATTR * logAttr; 304 | int charPos; 305 | 306 | // get Uniscribe data for current line 307 | if(!GetLogAttr(lineNo, &uspCache, &logAttr, &lineOffset)) 308 | return; 309 | 310 | charPos = m_nCursorOffset - lineOffset; 311 | 312 | // if already at start of line, skip *forwards* past any whitespace 313 | if(m_nCursorOffset == lineOffset) 314 | { 315 | // skip whitespace 316 | while(logAttr[m_nCursorOffset - lineOffset].fWhiteSpace) 317 | m_nCursorOffset++; 318 | } 319 | // if not at start, goto start 320 | else 321 | { 322 | m_nCursorOffset = lineOffset; 323 | } 324 | } 325 | 326 | // 327 | // Move to end of specified line 328 | // 329 | VOID TextView::MoveLineEnd(ULONG lineNo) 330 | { 331 | USPCACHE *uspCache; 332 | 333 | if((uspCache = GetUspCache(0, lineNo)) == 0) 334 | return; 335 | 336 | m_nCursorOffset = uspCache->offset + uspCache->length_CRLF; 337 | } 338 | 339 | // 340 | // Move to start of file 341 | // 342 | VOID TextView::MoveFileStart() 343 | { 344 | m_nCursorOffset = 0; 345 | } 346 | 347 | // 348 | // Move to end of file 349 | // 350 | VOID TextView::MoveFileEnd() 351 | { 352 | m_nCursorOffset = m_pTextDoc->size(); 353 | } 354 | 355 | 356 | // 357 | // Process keyboard-navigation keys 358 | // 359 | LONG TextView::OnKeyDown(UINT nKeyCode, UINT nFlags) 360 | { 361 | bool fCtrlDown = IsKeyPressed(VK_CONTROL); 362 | bool fShiftDown = IsKeyPressed(VK_SHIFT); 363 | BOOL fAdvancing = FALSE; 364 | 365 | // 366 | // Process the key-press. Cursor movement is different depending 367 | // on if is held down or not, so act accordingly 368 | // 369 | switch(nKeyCode) 370 | { 371 | case VK_SHIFT: case VK_CONTROL: 372 | return 0; 373 | 374 | // CTRL+Z undo 375 | case 'z': case 'Z': 376 | 377 | if(fCtrlDown && Undo()) 378 | NotifyParent(TVN_CHANGED); 379 | 380 | return 0; 381 | 382 | // CTRL+Y redo 383 | case 'y': case 'Y': 384 | 385 | if(fCtrlDown && Redo()) 386 | NotifyParent(TVN_CHANGED); 387 | 388 | return 0; 389 | 390 | // Change insert mode / clipboard copy&paste 391 | case VK_INSERT: 392 | 393 | if(fCtrlDown) 394 | { 395 | OnCopy(); 396 | NotifyParent(TVN_CHANGED); 397 | } 398 | else if(fShiftDown) 399 | { 400 | OnPaste(); 401 | NotifyParent(TVN_CHANGED); 402 | } 403 | else 404 | { 405 | if(m_nEditMode == MODE_INSERT) 406 | m_nEditMode = MODE_OVERWRITE; 407 | 408 | else if(m_nEditMode == MODE_OVERWRITE) 409 | m_nEditMode = MODE_INSERT; 410 | 411 | NotifyParent(TVN_EDITMODE_CHANGE); 412 | } 413 | 414 | return 0; 415 | 416 | case VK_DELETE: 417 | 418 | if(m_nEditMode != MODE_READONLY) 419 | { 420 | if(fShiftDown) 421 | OnCut(); 422 | else 423 | ForwardDelete(); 424 | 425 | NotifyParent(TVN_CHANGED); 426 | } 427 | return 0; 428 | 429 | case VK_BACK: 430 | 431 | if(m_nEditMode != MODE_READONLY) 432 | { 433 | BackDelete(); 434 | fAdvancing = FALSE; 435 | 436 | NotifyParent(TVN_CHANGED); 437 | } 438 | return 0; 439 | 440 | case VK_LEFT: 441 | 442 | if(fCtrlDown) MoveWordPrev(); 443 | else MoveCharPrev(); 444 | 445 | fAdvancing = FALSE; 446 | break; 447 | 448 | case VK_RIGHT: 449 | 450 | if(fCtrlDown) MoveWordNext(); 451 | else MoveCharNext(); 452 | 453 | fAdvancing = TRUE; 454 | break; 455 | 456 | case VK_UP: 457 | if(fCtrlDown) Scroll(0, -1); 458 | else MoveLineUp(1); 459 | break; 460 | 461 | case VK_DOWN: 462 | if(fCtrlDown) Scroll(0, 1); 463 | else MoveLineDown(1); 464 | break; 465 | 466 | case VK_PRIOR: 467 | if(!fCtrlDown) MoveLineUp(m_nWindowLines); 468 | break; 469 | 470 | case VK_NEXT: 471 | if(!fCtrlDown) MoveLineDown(m_nWindowLines); 472 | break; 473 | 474 | case VK_HOME: 475 | if(fCtrlDown) MoveFileStart(); 476 | else MoveLineStart(m_nCurrentLine); 477 | break; 478 | 479 | case VK_END: 480 | if(fCtrlDown) MoveFileEnd(); 481 | else MoveLineEnd(m_nCurrentLine); 482 | break; 483 | 484 | default: 485 | return 0; 486 | } 487 | 488 | // Extend selection if is down 489 | if(fShiftDown) 490 | { 491 | InvalidateRange(m_nSelectionEnd, m_nCursorOffset); 492 | m_nSelectionEnd = m_nCursorOffset; 493 | } 494 | // Otherwise clear the selection 495 | else 496 | { 497 | if(m_nSelectionStart != m_nSelectionEnd) 498 | InvalidateRange(m_nSelectionStart, m_nSelectionEnd); 499 | 500 | m_nSelectionEnd = m_nCursorOffset; 501 | m_nSelectionStart = m_nCursorOffset; 502 | } 503 | 504 | // update caret-location (xpos, line#) from the offset 505 | UpdateCaretOffset(m_nCursorOffset, fAdvancing, &m_nCaretPosX, &m_nCurrentLine); 506 | 507 | // maintain the caret 'anchor' position *except* for up/down actions 508 | if(nKeyCode != VK_UP && nKeyCode != VK_DOWN) 509 | { 510 | m_nAnchorPosX = m_nCaretPosX; 511 | 512 | // scroll as necessary to keep caret within viewport 513 | ScrollToPosition(m_nCaretPosX, m_nCurrentLine); 514 | } 515 | else 516 | { 517 | // scroll as necessary to keep caret within viewport 518 | if(!fCtrlDown) 519 | ScrollToPosition(m_nCaretPosX, m_nCurrentLine); 520 | } 521 | 522 | NotifyParent(TVN_CURSOR_CHANGE); 523 | 524 | return 0; 525 | } 526 | -------------------------------------------------------------------------------- /TextView/TextViewParser.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextViewParser.cpp 3 | // 4 | // PURPOSE: Parser for the Syntax-Description-Language 5 | // 6 | // NOTES: www.catch22.net 7 | // 8 | 9 | #define STRICT 10 | #define WIN32_LEAN_AND_MEAN 11 | 12 | #include 13 | #include 14 | #include "TextView.h" 15 | #include "TextViewInternal.h" 16 | 17 | struct Rule 18 | { 19 | TCHAR ruleName[32]; 20 | COLORREF fg; 21 | COLORREF bg; 22 | }; 23 | 24 | enum TEST { testNone, testEqual, testNotEqual, testInRange, testOutRange }; 25 | 26 | struct State 27 | { 28 | TCHAR arg1; 29 | TCHAR arg2; 30 | TEST test; 31 | int next; 32 | }; 33 | 34 | bool Init(TCHAR *buf, int len) 35 | { 36 | return true; 37 | } 38 | 39 | void Machine(TCHAR *str, int len, int initialState) 40 | { 41 | State machine[] = 42 | { 43 | { 'a', 0, testEqual }, 44 | { 'b', 0, testEqual } 45 | }; 46 | 47 | int state = initialState; 48 | 49 | // match string character-by-character 50 | for(int i = 0; i < len; i++) 51 | { 52 | TEST status = testNone; 53 | 54 | switch(machine[state].test) 55 | { 56 | case testEqual: 57 | if(str[i] == machine[state].arg1) 58 | status = testEqual; 59 | 60 | break; 61 | 62 | case testNotEqual: 63 | if(str[i] != machine[state].arg1) 64 | status = testNotEqual; 65 | break; 66 | 67 | case testInRange: 68 | if(str[i] >= machine[state].arg1 && str[i] <= machine[state].arg2) 69 | status = testInRange; 70 | 71 | break; 72 | 73 | case testOutRange: 74 | if(str[i] < machine[state].arg1 || str[i] > machine[state].arg2) 75 | status = testOutRange; 76 | 77 | break; 78 | } 79 | 80 | if(status == testNone) 81 | state++; 82 | else 83 | state = machine[state].test; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /TextView/TextViewScroll.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextView.cpp 3 | // 4 | // PURPOSE: Implementation of the TextView control 5 | // 6 | // NOTES: www.catch22.net 7 | // 8 | 9 | #define STRICT 10 | #define WIN32_LEAN_AND_MEAN 11 | 12 | #include 13 | #include 14 | #include "TextView.h" 15 | #include "TextViewInternal.h" 16 | 17 | bool IsKeyPressed(UINT nVirtKey); 18 | 19 | // 20 | // Set scrollbar positions and range 21 | // 22 | VOID TextView::SetupScrollbars() 23 | { 24 | SCROLLINFO si = { sizeof(si) }; 25 | 26 | si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL; 27 | 28 | // 29 | // Vertical scrollbar 30 | // 31 | si.nPos = m_nVScrollPos; // scrollbar thumb position 32 | si.nPage = m_nWindowLines; // number of lines in a page 33 | si.nMin = 0; 34 | si.nMax = m_nLineCount - 1; // total number of lines in file 35 | 36 | SetScrollInfo(m_hWnd, SB_VERT, &si, TRUE); 37 | 38 | // 39 | // Horizontal scrollbar 40 | // 41 | si.nPos = m_nHScrollPos; // scrollbar thumb position 42 | si.nPage = m_nWindowColumns; // number of lines in a page 43 | si.nMin = 0; 44 | si.nMax = m_nLongestLine - 1; // total number of lines in file 45 | 46 | SetScrollInfo(m_hWnd, SB_HORZ, &si, TRUE); 47 | 48 | // adjust our interpretation of the max scrollbar range to make 49 | // range-checking easier. The scrollbars don't use these values, they 50 | // are for our own use. 51 | m_nVScrollMax = m_nLineCount - m_nWindowLines; 52 | m_nHScrollMax = m_nLongestLine - m_nWindowColumns; 53 | } 54 | 55 | // 56 | // Ensure that we never scroll off the end of the file 57 | // 58 | bool TextView::PinToBottomCorner() 59 | { 60 | bool repos = false; 61 | 62 | if(m_nHScrollPos + m_nWindowColumns > m_nLongestLine) 63 | { 64 | m_nHScrollPos = m_nLongestLine - m_nWindowColumns; 65 | repos = true; 66 | } 67 | 68 | if(m_nVScrollPos + m_nWindowLines > m_nLineCount) 69 | { 70 | m_nVScrollPos = m_nLineCount - m_nWindowLines; 71 | repos = true; 72 | } 73 | 74 | return repos; 75 | } 76 | 77 | // 78 | // The window has changed size - update the scrollbars 79 | // 80 | LONG TextView::OnSize(UINT nFlags, int width, int height) 81 | { 82 | int margin = LeftMarginWidth(); 83 | 84 | m_nWindowLines = min((unsigned)height / m_nLineHeight, m_nLineCount); 85 | m_nWindowColumns = min((width - margin) / m_nFontWidth, m_nLongestLine); 86 | 87 | if(PinToBottomCorner()) 88 | { 89 | RefreshWindow(); 90 | RepositionCaret(); 91 | } 92 | 93 | SetupScrollbars(); 94 | 95 | return 0; 96 | } 97 | 98 | // 99 | // ScrollRgn 100 | // 101 | // Scrolls the viewport in specified direction. If fReturnUpdateRgn is true, 102 | // then a HRGN is returned which holds the client-region that must be redrawn 103 | // manually. This region must be deleted by the caller using DeleteObject. 104 | // 105 | // Otherwise ScrollRgn returns NULL and updates the entire window 106 | // 107 | HRGN TextView::ScrollRgn(int dx, int dy, bool fReturnUpdateRgn) 108 | { 109 | RECT clip; 110 | 111 | GetClientRect(m_hWnd, &clip); 112 | 113 | // 114 | // make sure that dx,dy don't scroll us past the edge of the document! 115 | // 116 | 117 | // scroll up 118 | if(dy < 0) 119 | { 120 | dy = -(int)min((ULONG)-dy, m_nVScrollPos); 121 | clip.top = -dy * m_nLineHeight; 122 | } 123 | // scroll down 124 | else if(dy > 0) 125 | { 126 | dy = min((ULONG)dy, m_nVScrollMax-m_nVScrollPos); 127 | clip.bottom = (m_nWindowLines -dy) * m_nLineHeight; 128 | } 129 | 130 | 131 | // scroll left 132 | if(dx < 0) 133 | { 134 | dx = -(int)min(-dx, m_nHScrollPos); 135 | clip.left = -dx * m_nFontWidth * 4; 136 | } 137 | // scroll right 138 | else if(dx > 0) 139 | { 140 | dx = min((unsigned)dx, (unsigned)m_nHScrollMax-m_nHScrollPos); 141 | clip.right = (m_nWindowColumns - dx - 4) * m_nFontWidth ; 142 | } 143 | 144 | // adjust the scrollbar thumb position 145 | m_nHScrollPos += dx; 146 | m_nVScrollPos += dy; 147 | 148 | // ignore clipping rectangle if its a whole-window scroll 149 | if(fReturnUpdateRgn == false) 150 | GetClientRect(m_hWnd, &clip); 151 | 152 | // take margin into account 153 | clip.left += LeftMarginWidth(); 154 | 155 | // perform the scroll 156 | if(dx != 0 || dy != 0) 157 | { 158 | // do the scroll! 159 | ScrollWindowEx( 160 | m_hWnd, 161 | -dx * m_nFontWidth, // scale up to pixel coords 162 | -dy * m_nLineHeight, 163 | NULL, // scroll entire window 164 | &clip, // clip the non-scrolling part 165 | 0, 166 | 0, 167 | SW_INVALIDATE 168 | ); 169 | 170 | SetupScrollbars(); 171 | 172 | if(fReturnUpdateRgn) 173 | { 174 | RECT client; 175 | 176 | GetClientRect(m_hWnd, &client); 177 | 178 | //clip.left -= LeftMarginWidth(); 179 | 180 | HRGN hrgnClient = CreateRectRgnIndirect(&client); 181 | HRGN hrgnUpdate = CreateRectRgnIndirect(&clip); 182 | 183 | // create a region that represents the area outside the 184 | // clipping rectangle (i.e. the part that is never scrolled) 185 | CombineRgn(hrgnUpdate, hrgnClient, hrgnUpdate, RGN_XOR); 186 | 187 | DeleteObject(hrgnClient); 188 | 189 | return hrgnUpdate; 190 | } 191 | } 192 | 193 | if(dy != 0) 194 | { 195 | GetClientRect(m_hWnd, &clip); 196 | clip.right = LeftMarginWidth(); 197 | //ScrollWindow(m_hWnd, 0, -dy * m_nLineHeight, 0, &clip); 198 | InvalidateRect(m_hWnd, &clip, 0); 199 | } 200 | 201 | return NULL; 202 | } 203 | 204 | // 205 | // Scroll viewport in specified direction 206 | // 207 | VOID TextView::Scroll(int dx, int dy) 208 | { 209 | // do a "normal" scroll - don't worry about invalid regions, 210 | // just scroll the whole window 211 | ScrollRgn(dx, dy, false); 212 | } 213 | 214 | // 215 | // Ensure that the specified file-location is visible within 216 | // the window-viewport, Scrolling the viewport as necessary 217 | // 218 | VOID TextView::ScrollToPosition(int xpos, ULONG lineno) 219 | { 220 | bool fRefresh = false; 221 | RECT rect; 222 | int marginWidth = LeftMarginWidth(); 223 | 224 | GetClientRect(m_hWnd, &rect); 225 | 226 | xpos -= m_nHScrollPos * m_nFontWidth; 227 | xpos += marginWidth; 228 | 229 | if(xpos < marginWidth) 230 | { 231 | m_nHScrollPos -= (marginWidth - xpos) / m_nFontWidth; 232 | fRefresh = true; 233 | } 234 | 235 | if(xpos >= rect.right) 236 | { 237 | m_nHScrollPos += (xpos - rect.right) / m_nFontWidth + 1; 238 | fRefresh = true; 239 | } 240 | 241 | if(lineno < m_nVScrollPos) 242 | { 243 | m_nVScrollPos = lineno; 244 | fRefresh = true; 245 | } 246 | else if(lineno > m_nVScrollPos + m_nWindowLines - 1) 247 | { 248 | m_nVScrollPos = lineno - m_nWindowLines + 1; 249 | fRefresh = true; 250 | } 251 | 252 | 253 | if(fRefresh) 254 | { 255 | SetupScrollbars(); 256 | RefreshWindow(); 257 | RepositionCaret(); 258 | } 259 | } 260 | 261 | VOID TextView::ScrollToCaret() 262 | { 263 | ScrollToPosition(m_nCaretPosX, m_nCurrentLine); 264 | } 265 | 266 | LONG GetTrackPos32(HWND hwnd, int nBar) 267 | { 268 | SCROLLINFO si = { sizeof(si), SIF_TRACKPOS }; 269 | GetScrollInfo(hwnd, nBar, &si); 270 | return si.nTrackPos; 271 | } 272 | 273 | // 274 | // Vertical scrollbar support 275 | // 276 | LONG TextView::OnVScroll(UINT nSBCode, UINT nPos) 277 | { 278 | ULONG oldpos = m_nVScrollPos; 279 | 280 | switch(nSBCode) 281 | { 282 | case SB_TOP: 283 | m_nVScrollPos = 0; 284 | RefreshWindow(); 285 | break; 286 | 287 | case SB_BOTTOM: 288 | m_nVScrollPos = m_nVScrollMax; 289 | RefreshWindow(); 290 | break; 291 | 292 | case SB_LINEUP: 293 | Scroll(0, -1); 294 | break; 295 | 296 | case SB_LINEDOWN: 297 | Scroll(0, 1); 298 | break; 299 | 300 | case SB_PAGEDOWN: 301 | Scroll(0, m_nWindowLines); 302 | break; 303 | 304 | case SB_PAGEUP: 305 | Scroll(0, -m_nWindowLines); 306 | break; 307 | 308 | case SB_THUMBPOSITION: 309 | case SB_THUMBTRACK: 310 | 311 | m_nVScrollPos = GetTrackPos32(m_hWnd, SB_VERT); 312 | RefreshWindow(); 313 | 314 | break; 315 | } 316 | 317 | if(oldpos != m_nVScrollPos) 318 | { 319 | SetupScrollbars(); 320 | RepositionCaret(); 321 | } 322 | 323 | 324 | return 0; 325 | } 326 | 327 | // 328 | // Horizontal scrollbar support 329 | // 330 | LONG TextView::OnHScroll(UINT nSBCode, UINT nPos) 331 | { 332 | int oldpos = m_nHScrollPos; 333 | 334 | switch(nSBCode) 335 | { 336 | case SB_LEFT: 337 | m_nHScrollPos = 0; 338 | RefreshWindow(); 339 | break; 340 | 341 | case SB_RIGHT: 342 | m_nHScrollPos = m_nHScrollMax; 343 | RefreshWindow(); 344 | break; 345 | 346 | case SB_LINELEFT: 347 | Scroll(-1, 0); 348 | break; 349 | 350 | case SB_LINERIGHT: 351 | Scroll(1, 0); 352 | break; 353 | 354 | case SB_PAGELEFT: 355 | Scroll(-m_nWindowColumns, 0); 356 | break; 357 | 358 | case SB_PAGERIGHT: 359 | Scroll(m_nWindowColumns, 0); 360 | break; 361 | 362 | case SB_THUMBPOSITION: 363 | case SB_THUMBTRACK: 364 | 365 | m_nHScrollPos = GetTrackPos32(m_hWnd, SB_HORZ); 366 | RefreshWindow(); 367 | break; 368 | } 369 | 370 | if(oldpos != m_nHScrollPos) 371 | { 372 | SetupScrollbars(); 373 | RepositionCaret(); 374 | } 375 | 376 | return 0; 377 | } 378 | 379 | LONG TextView::OnMouseWheel(int nDelta) 380 | { 381 | #ifndef SPI_GETWHEELSCROLLLINES 382 | #define SPI_GETWHEELSCROLLLINES 104 383 | #endif 384 | 385 | if(!IsKeyPressed(VK_SHIFT)) 386 | { 387 | int nScrollLines; 388 | 389 | SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0); 390 | 391 | if(nScrollLines <= 1) 392 | nScrollLines = 3; 393 | 394 | Scroll(0, (-nDelta/120) * nScrollLines); 395 | RepositionCaret(); 396 | } 397 | 398 | return 0; 399 | } 400 | -------------------------------------------------------------------------------- /TextView/TextViewSyntax.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MODULE: TextView.cpp 3 | // 4 | // PURPOSE: Implementation of the TextView control 5 | // 6 | // NOTES: www.catch22.net 7 | // 8 | 9 | #define STRICT 10 | #define WIN32_LEAN_AND_MEAN 11 | 12 | #include 13 | #include 14 | #include "TextView.h" 15 | #include "TextViewInternal.h" 16 | 17 | #define COOKIE_BEGIN 0 18 | #define COOKIE_END 1 19 | 20 | //typedef struct LEX; 21 | 22 | typedef struct 23 | { 24 | ATTR attr; 25 | ULONG type; 26 | 27 | } TYPE; 28 | 29 | typedef struct LEX _LEX; 30 | struct LEX 31 | { 32 | TYPE *type; 33 | 34 | int num_branches; 35 | _LEX *branch[1]; 36 | }; 37 | 38 | LEX firstchar[256]; 39 | 40 | ULONG lexer(ULONG cookie, TCHAR *buf, ULONG len, ATTR *attr) 41 | { 42 | LEX *state = 0; 43 | int i = 0; 44 | ULONG ch = buf[i++]; 45 | 46 | // start at the correct place in our state machine 47 | LEX *node = &state[cookie]; 48 | 49 | // look for a match against the current character 50 | // for(i = 0; i < node->num_branches; i++) 51 | // { 52 | // if(node->branch[i]. 53 | // } 54 | 55 | 56 | if(ch < 256) 57 | { 58 | 59 | } 60 | 61 | 62 | //switc 63 | return COOKIE_END; 64 | } 65 | 66 | TCHAR *gettok(TCHAR *ptr, TCHAR *buf, int buflen) 67 | { 68 | int ch = *ptr++; 69 | int i = 0; 70 | 71 | if(buf == 0) 72 | return 0; 73 | 74 | // end of string? 75 | if(ptr == 0 || ch == 0) 76 | { 77 | buf[0] = '\0'; 78 | return 0; 79 | } 80 | 81 | // strip any leading whitespace 82 | // whitspace: { | | } 83 | while(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') 84 | { 85 | if(*ptr == 0) 86 | return 0; 87 | 88 | ch = *ptr++; 89 | } 90 | 91 | // found a quote - skip to matching pair 92 | /* if(ch == '\"') 93 | { 94 | ch = *ptr++; 95 | while(i < buflen && ch != '\0' && ch != '\"' && ch != '\n' && ch != '\r') 96 | { 97 | buf[i++] = ch; 98 | ch = *ptr++; 99 | } 100 | } 101 | else*/ 102 | { 103 | while(i < buflen && ch) 104 | { 105 | if(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')// || ch == '\"') 106 | break; 107 | 108 | buf[i++] = ch; 109 | 110 | 111 | if(ch = *ptr) ptr++; 112 | 113 | 114 | } 115 | } 116 | 117 | buf[i] = 0; 118 | 119 | return ptr; 120 | } 121 | 122 | void xSetStyle(ATTR *attr, ULONG nPos, ULONG nLen, COLORREF fg, COLORREF bg, int bold=0) 123 | { 124 | for(ULONG i = nPos; i < nPos+nLen; i++) 125 | { 126 | attr[i].fg = fg; 127 | //attr[i].bg = bg; 128 | 129 | //if(bold) 130 | // attr[i].font = 1; 131 | } 132 | } 133 | 134 | typedef struct 135 | { 136 | TCHAR firstchar[256]; 137 | 138 | } SYNTAX_NODE; 139 | 140 | int TextView::SyntaxColour(TCHAR *szText, ULONG nTextLen, ATTR *attr) 141 | { 142 | TCHAR tok[128]; 143 | 144 | TCHAR *ptr1 = szText; 145 | TCHAR *ptr2; 146 | 147 | if(nTextLen == 0) 148 | return 0; 149 | 150 | szText[nTextLen]=0; 151 | 152 | while((ptr2 = gettok(ptr1, tok, 128)) != 0) 153 | { 154 | if(isdigit(tok[0])) 155 | { 156 | //xSetStyle(attr, ptr1 - szText, ptr2-ptr1, RGB(200,0,0), RGB(255,255,255), 0); 157 | xSetStyle(attr, ptr1 - szText, ptr2-ptr1, RGB(255,80,80), RGB(255,255,255), 0); 158 | } 159 | else if(memcmp(tok, _T("if"), 2) == 0 || 160 | memcmp(tok, _T("for"), 3) == 0) 161 | { 162 | //xSetStyle(attr, ptr1 - szText, ptr2-ptr1, RGB(0,0,128), RGB(255,255,255), 1); 163 | xSetStyle(attr, ptr1 - szText, ptr2-ptr1, RGB(240,240,240), RGB(255,255,255), 1); 164 | } 165 | else if(tok[0] == '\"' || tok[0] == '<' || tok[0] == '\'') 166 | { 167 | //xSetStyle(attr, ptr1 - szText, ptr2-ptr1, RGB(128,0,128), RGB(255,255,255)); 168 | xSetStyle(attr, ptr1 - szText, ptr2-ptr1, RGB(200,100,200), RGB(255,255,255)); 169 | } 170 | else if(tok[0] == '#')//lstrcmp(tok, _T("#include")) == 0) 171 | { 172 | //SetStyle(attr, ptr1 - szText, ptr2 - ptr1, RGB(255,255,0), RGB(255,0,0)); 173 | //xSetStyle(attr, ptr1 - szText, ptr2-ptr1, RGB(65,102,190), RGB(255,255,255)); 174 | xSetStyle(attr, ptr1 - szText, ptr2-ptr1, RGB(100,150,200), RGB(255,255,255)); 175 | } 176 | else if(lstrcmp(tok, _T("ULONG")) == 0) 177 | { 178 | xSetStyle(attr, ptr1 - szText, ptr2 - ptr1, RGB(100,200,255), RGB(255,255,255)); 179 | } 180 | else if(lstrcmp(tok, _T("//")) == 0) 181 | { 182 | //xSetStyle(attr, ptr1 - szText, nTextLen - (ptr1-szText), RGB(128,90,20), RGB(255,255,255)); 183 | xSetStyle(attr, ptr1 - szText, nTextLen - (ptr1-szText), RGB(128,110,90), RGB(255,255,255)); 184 | break; 185 | } 186 | else 187 | { 188 | //xSetStyle(attr, ptr1 - szText, nTextLen - (ptr1-szText), RGB(200,200,200), RGB(255,255,255)); 189 | } 190 | 191 | ptr1 = ptr2; 192 | } 193 | 194 | return 0; 195 | } 196 | -------------------------------------------------------------------------------- /TextView/Unicode.h: -------------------------------------------------------------------------------- 1 | #ifndef UNICODE_LIB_INCLUDED 2 | #define UNICODE_LIB_INCLUDED 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | // Define the basic types for storing Unicode 9 | typedef unsigned long UTF32; 10 | typedef unsigned short UTF16; 11 | typedef unsigned char UTF8; 12 | 13 | // Some fundamental constants 14 | #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD 15 | #define UNI_MAX_BMP (UTF32)0x0000FFFF 16 | #define UNI_MAX_UTF16 (UTF32)0x0010FFFF 17 | #define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF 18 | #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF 19 | 20 | #define UNI_SUR_HIGH_START (UTF32)0xD800 21 | #define UNI_SUR_HIGH_END (UTF32)0xDBFF 22 | #define UNI_SUR_LOW_START (UTF32)0xDC00 23 | #define UNI_SUR_LOW_END (UTF32)0xDFFF 24 | 25 | #define SWAPWORD(val) (((UTF16)(val) << 8) | ((UTF16)(val) >> 8)) 26 | 27 | // 28 | // Conversions between UTF-8 and a single UTF-32 value 29 | // 30 | size_t utf8_to_utf32(UTF8 *utf8str, size_t utf8len, UTF32 *pcp32); 31 | size_t utf32_to_utf8(UTF8 *utf8str, size_t utf8len, UTF32 ch32); 32 | 33 | // 34 | // Conversions between UTF-16 and UTF-8 strings 35 | // 36 | size_t utf8_to_utf16(UTF8 *utf8str, size_t utf8len, UTF16 *utf16str, size_t *utf16len); 37 | size_t utf16_to_utf8(UTF16 *utf16str, size_t utf16len, UTF8 *utf8str, size_t *utf8len); 38 | 39 | // 40 | // Conversions between UTF-16 and UTF-32 strings 41 | // 42 | size_t utf16_to_utf32(UTF16 *utf16str, size_t utf16len, UTF32 *utf32str, size_t *utf32len); 43 | size_t utf32_to_utf16(UTF32 *utf32str, size_t utf32len, UTF16 *utf16str, size_t *utf16len); 44 | size_t utf16be_to_utf32(UTF16 *utf16str, size_t utf16len, UTF32 *utf32str, size_t *utf32len); 45 | 46 | 47 | // 48 | // Conversions between ASCII/ANSI and UTF-16 strings 49 | // 50 | size_t ascii_to_utf16(UTF8 *asciistr, size_t asciilen, UTF16 *utf16str, size_t *utf16len); 51 | size_t utf16_to_ascii(UTF16 *utf16str, size_t utf16len, UTF8 *asciistr, size_t *asciilen); 52 | 53 | // 54 | // Miscallaneaous 55 | // 56 | size_t copy_utf16(UTF16 *src, size_t srclen, UTF16 *dest, size_t *destlen); 57 | size_t swap_utf16(UTF16 *src, size_t srclen, UTF16 *dest, size_t *destlen); 58 | 59 | 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | 65 | #endif -------------------------------------------------------------------------------- /TextView/codepages.h: -------------------------------------------------------------------------------- 1 | #ifndef CODEPAGES_INCLUDED 2 | #define CODEPAGES_INCLUDED 3 | 4 | #endif -------------------------------------------------------------------------------- /TextView/racursor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Right-arrow cursor raw bytes 3 | // 4 | 5 | #pragma once 6 | 7 | /* Generated by HexEdit */ 8 | static BYTE XORMask[128] = 9 | { 10 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 11 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xc3, 0xff, 12 | 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xfc, 0x03, 0xff, 13 | 0xff, 0xf8, 0x03, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x03, 0xff, 14 | 0xff, 0xfc, 0x03, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xf8, 0x63, 0xff, 0xff, 0xf8, 0x73, 0xff, 15 | 0xff, 0xf0, 0xfb, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 16 | 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 17 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 18 | }; 19 | 20 | /* Generated by HexEdit */ 21 | static BYTE ANDMask[128] = 22 | { 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 25 | 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 26 | 0x00, 0x03, 0xf8, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 27 | 0x00, 0x01, 0xb8, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 28 | 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 31 | }; 32 | -------------------------------------------------------------------------------- /TextView/sequence.h: -------------------------------------------------------------------------------- 1 | #ifndef SEQUENCE_INCLUDED 2 | #define SEQUENCE_INCLUDED 3 | 4 | #include 5 | 6 | // 7 | // Define the underlying string/character type of the sequence. 8 | // 9 | // 'seqchar' can be redefined to BYTE, WCHAR, ULONG etc 10 | // depending on what kind of string you want your sequence to hold 11 | // 12 | typedef unsigned char seqchar; 13 | 14 | #ifdef SEQUENCE64 15 | typedef unsigned __int64 size_w; 16 | #else 17 | typedef unsigned long size_w; 18 | #endif 19 | 20 | const size_w MAX_SEQUENCE_LENGTH = ((size_w)(-1) / sizeof(seqchar)); 21 | 22 | // 23 | // sequence class! 24 | // 25 | class sequence 26 | { 27 | public: 28 | // forward declare the nested helper-classes 29 | class span; 30 | class span_range; 31 | class buffer_control; 32 | class iterator; 33 | class ref; 34 | enum action; 35 | 36 | public: 37 | 38 | // sequence construction 39 | sequence(); 40 | ~sequence(); 41 | 42 | // 43 | // initialize with a file 44 | // 45 | bool init(); 46 | bool open(TCHAR *filename, bool readonly); 47 | bool clear(); 48 | 49 | // 50 | // initialize from an in-memory buffer 51 | // 52 | bool init(const seqchar *buffer, size_t length); 53 | 54 | // 55 | // sequence statistics 56 | // 57 | size_w size() const; 58 | 59 | // 60 | // sequence manipulation 61 | // 62 | bool insert (size_w index, const seqchar *buf, size_w length); 63 | bool insert (size_w index, const seqchar val, size_w count); 64 | bool insert (size_w index, const seqchar val); 65 | bool replace(size_w index, const seqchar *buf, size_w length, size_w erase_length); 66 | bool replace(size_w index, const seqchar *buf, size_w length); 67 | bool replace(size_w index, const seqchar val, size_w count); 68 | bool replace(size_w index, const seqchar val); 69 | bool erase (size_w index, size_w len); 70 | bool erase (size_w index); 71 | bool append (const seqchar *buf, size_w len); 72 | bool append (const seqchar val); 73 | void breakopt(); 74 | 75 | // 76 | // undo/redo support 77 | // 78 | bool undo(); 79 | bool redo(); 80 | bool canundo() const; 81 | bool canredo() const; 82 | void group(); 83 | void ungroup(); 84 | size_w event_index() const { return undoredo_index; } 85 | size_w event_length() const { return undoredo_length; } 86 | 87 | // print out the sequence 88 | void debug1(); 89 | void debug2(); 90 | 91 | // 92 | // access and iteration 93 | // 94 | size_w render(size_w index, seqchar *buf, size_w len) const; 95 | seqchar peek(size_w index) const; 96 | bool poke(size_w index, seqchar val); 97 | 98 | seqchar operator[] (size_w index) const; 99 | ref operator[] (size_w index); 100 | 101 | private: 102 | 103 | typedef std::vector eventstack; 104 | typedef std::vector bufferlist; 105 | template void clear_vector(type &source); 106 | 107 | // 108 | // Span-table management 109 | // 110 | void deletefromsequence(span **sptr); 111 | span * spanfromindex(size_w index, size_w *spanindex) const; 112 | void scan(span *sptr); 113 | size_w sequence_length; 114 | span * head; 115 | span * tail; 116 | span * frag1; 117 | span * frag2; 118 | 119 | 120 | // 121 | // Undo and redo stacks 122 | // 123 | span_range * initundo(size_w index, size_w length, action act); 124 | void restore_spanrange(span_range *range, bool undo_or_redo); 125 | void swap_spanrange(span_range *src, span_range *dest); 126 | bool undoredo(eventstack &source, eventstack &dest); 127 | void clearstack(eventstack &source); 128 | span_range * stackback(eventstack &source, size_t idx); 129 | 130 | eventstack undostack; 131 | eventstack redostack; 132 | size_t group_id; 133 | size_t group_refcount; 134 | size_w undoredo_index; 135 | size_w undoredo_length; 136 | 137 | // 138 | // File and memory buffer management 139 | // 140 | buffer_control *alloc_buffer(size_t size); 141 | buffer_control *alloc_modifybuffer(size_t size); 142 | bool import_buffer(const seqchar *buf, size_t len, size_t *buffer_offset); 143 | 144 | bufferlist buffer_list; 145 | int modifybuffer_id; 146 | int modifybuffer_pos; 147 | 148 | // 149 | // Sequence manipulation 150 | // 151 | bool insert_worker (size_w index, const seqchar *buf, size_w len, action act); 152 | bool erase_worker (size_w index, size_w len, action act); 153 | bool can_optimize (action act, size_w index); 154 | void record_action (action act, size_w index); 155 | 156 | size_w lastaction_index; 157 | action lastaction; 158 | bool can_quicksave; 159 | 160 | void LOCK(); 161 | void UNLOCK(); 162 | 163 | 164 | }; 165 | 166 | 167 | // 168 | // sequence::action 169 | // 170 | // enumeration of the type of 'edit actions' our sequence supports. 171 | // only important when we try to 'optimize' repeated operations on the 172 | // sequence by coallescing them into a single span. 173 | // 174 | enum sequence::action 175 | { 176 | action_invalid, 177 | action_insert, 178 | action_erase, 179 | action_replace 180 | }; 181 | 182 | // 183 | // sequence::span 184 | // 185 | // private class to the sequence 186 | // 187 | class sequence::span 188 | { 189 | friend class sequence; 190 | friend class span_range; 191 | 192 | public: 193 | // constructor 194 | span(size_w off, size_w len, int buf, span *nx = 0, span *pr = 0) 195 | : 196 | next(nx), 197 | prev(pr), 198 | offset(off), 199 | length(len), 200 | buffer(buf) 201 | { 202 | static int count=-2; 203 | id = count++; 204 | } 205 | 206 | 207 | private: 208 | 209 | span *next; 210 | span *prev; // double-link-list 211 | 212 | size_w offset; 213 | size_w length; 214 | int buffer; 215 | 216 | int id; 217 | }; 218 | 219 | 220 | 221 | // 222 | // sequence::span_range 223 | // 224 | // private class to the sequence. Used to represent a contiguous range of spans. 225 | // used by the undo/redo stacks to store state. A span-range effectively represents 226 | // the range of spans affected by an event (operation) on the sequence 227 | // 228 | // 229 | class sequence::span_range 230 | { 231 | friend class sequence; 232 | 233 | public: 234 | 235 | // constructor 236 | span_range( size_w seqlen = 0, 237 | size_w idx = 0, 238 | size_w len = 0, 239 | action a = action_invalid, 240 | bool qs = false, 241 | size_t id = 0 242 | ) 243 | : 244 | first(0), 245 | last(0), 246 | boundary(true), 247 | sequence_length(seqlen), 248 | index(idx), 249 | length(len), 250 | act(a), 251 | quicksave(qs), 252 | group_id(id) 253 | { 254 | } 255 | 256 | // destructor does nothing - because sometimes we don't want 257 | // to free the contents when the span_range is deleted. e.g. when 258 | // the span_range is just a temporary helper object. The contents 259 | // must be deleted manually with span_range::free 260 | ~span_range() 261 | { 262 | } 263 | 264 | // separate 'destruction' used when appropriate 265 | void free() 266 | { 267 | span *sptr, *next, *term; 268 | 269 | if(boundary == false) 270 | { 271 | // delete the range of spans 272 | for(sptr = first, term = last->next; sptr && sptr != term; sptr = next) 273 | { 274 | next = sptr->next; 275 | delete sptr; 276 | } 277 | } 278 | } 279 | 280 | // add a span into the range 281 | void append(span *sptr) 282 | { 283 | if(sptr != 0) 284 | { 285 | // first time a span has been added? 286 | if(first == 0) 287 | { 288 | first = sptr; 289 | } 290 | // otherwise chain the spans together. 291 | else 292 | { 293 | last->next = sptr; 294 | sptr->prev = last; 295 | } 296 | 297 | last = sptr; 298 | boundary = false; 299 | } 300 | } 301 | 302 | // join two span-ranges together 303 | void append(span_range *range) 304 | { 305 | if(range->boundary == false) 306 | { 307 | if(boundary) 308 | { 309 | first = range->first; 310 | last = range->last; 311 | boundary = false; 312 | } 313 | else 314 | { 315 | range->first->prev = last; 316 | last->next = range->first; 317 | last = range->last; 318 | } 319 | } 320 | } 321 | 322 | // join two span-ranges together. used only for 'back-delete' 323 | void prepend(span_range *range) 324 | { 325 | if(range->boundary == false) 326 | { 327 | if(boundary) 328 | { 329 | first = range->first; 330 | last = range->last; 331 | boundary = false; 332 | } 333 | else 334 | { 335 | range->last->next = first; 336 | first->prev = range->last; 337 | first = range->first; 338 | } 339 | } 340 | } 341 | 342 | // An 'empty' range is represented by storing pointers to the 343 | // spans ***either side*** of the span-boundary position. Input is 344 | // always the span following the boundary. 345 | void spanboundary(span *before, span *after) 346 | { 347 | first = before; 348 | last = after; 349 | boundary = true; 350 | } 351 | 352 | 353 | private: 354 | 355 | // the span range 356 | span *first; 357 | span *last; 358 | bool boundary; 359 | 360 | // sequence state 361 | size_w sequence_length; 362 | size_w index; 363 | size_w length; 364 | action act; 365 | bool quicksave; 366 | size_t group_id; 367 | }; 368 | 369 | // 370 | // sequence::ref 371 | // 372 | // temporary 'reference' to the sequence, used for 373 | // non-const array access with sequence::operator[] 374 | // 375 | class sequence::ref 376 | { 377 | public: 378 | ref(sequence *s, size_w i) 379 | : 380 | seq(s), 381 | index(i) 382 | { 383 | } 384 | 385 | operator seqchar() const 386 | { 387 | return seq->peek(index); 388 | } 389 | 390 | ref & operator= (seqchar rhs) 391 | { 392 | seq->poke(index, rhs); 393 | return *this; 394 | } 395 | 396 | private: 397 | size_w index; 398 | sequence * seq; 399 | }; 400 | 401 | // 402 | // buffer_control 403 | // 404 | class sequence::buffer_control 405 | { 406 | public: 407 | seqchar *buffer; 408 | size_w length; 409 | size_w maxsize; 410 | int id; 411 | }; 412 | 413 | class sequence::iterator 414 | { 415 | public: 416 | 417 | }; 418 | 419 | #endif -------------------------------------------------------------------------------- /UspLib/USPDLL.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="USPDLL" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 6 | 7 | CFG=USPDLL - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "USPDLL.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "USPDLL.mak" CFG="USPDLL - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "USPDLL - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") 21 | !MESSAGE "USPDLL - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | MTL=midl.exe 30 | RSC=rc.exe 31 | 32 | !IF "$(CFG)" == "USPDLL - Win32 Release" 33 | 34 | # PROP BASE Use_MFC 0 35 | # PROP BASE Use_Debug_Libraries 0 36 | # PROP BASE Output_Dir "Release" 37 | # PROP BASE Intermediate_Dir "Release" 38 | # PROP BASE Target_Dir "" 39 | # PROP Use_MFC 0 40 | # PROP Use_Debug_Libraries 0 41 | # PROP Output_Dir "Release" 42 | # PROP Intermediate_Dir "Release" 43 | # PROP Ignore_Export_Lib 0 44 | # PROP Target_Dir "" 45 | # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USPDLL_EXPORTS" /YX /FD /c 46 | # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USPDLL_EXPORTS" /YX /FD /c 47 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 48 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 49 | # ADD BASE RSC /l 0x809 /d "NDEBUG" 50 | # ADD RSC /l 0x809 /d "NDEBUG" 51 | BSC32=bscmake.exe 52 | # ADD BASE BSC32 /nologo 53 | # ADD BSC32 /nologo 54 | LINK32=link.exe 55 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 56 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/usplib.dll" 57 | 58 | !ELSEIF "$(CFG)" == "USPDLL - Win32 Debug" 59 | 60 | # PROP BASE Use_MFC 0 61 | # PROP BASE Use_Debug_Libraries 1 62 | # PROP BASE Output_Dir "Debug" 63 | # PROP BASE Intermediate_Dir "Debug" 64 | # PROP BASE Target_Dir "" 65 | # PROP Use_MFC 0 66 | # PROP Use_Debug_Libraries 1 67 | # PROP Output_Dir "Debug" 68 | # PROP Intermediate_Dir "Debug" 69 | # PROP Target_Dir "" 70 | # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USPDLL_EXPORTS" /YX /FD /GZ /c 71 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "USPDLL_EXPORTS" /YX /FD /GZ /c 72 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 73 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 74 | # ADD BASE RSC /l 0x809 /d "_DEBUG" 75 | # ADD RSC /l 0x809 /d "_DEBUG" 76 | BSC32=bscmake.exe 77 | # ADD BASE BSC32 /nologo 78 | # ADD BSC32 /nologo 79 | LINK32=link.exe 80 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept 81 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept 82 | 83 | !ENDIF 84 | 85 | # Begin Target 86 | 87 | # Name "USPDLL - Win32 Release" 88 | # Name "USPDLL - Win32 Debug" 89 | # Begin Group "Source Files" 90 | 91 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 92 | # Begin Source File 93 | 94 | SOURCE=.\UspCtrl.c 95 | # End Source File 96 | # Begin Source File 97 | 98 | SOURCE=.\UspLib.c 99 | # End Source File 100 | # Begin Source File 101 | 102 | SOURCE=.\UspMain.c 103 | # End Source File 104 | # Begin Source File 105 | 106 | SOURCE=.\UspMouse.c 107 | # End Source File 108 | # Begin Source File 109 | 110 | SOURCE=.\UspPaint.c 111 | # End Source File 112 | # End Group 113 | # Begin Group "Header Files" 114 | 115 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 116 | # Begin Source File 117 | 118 | SOURCE=.\usplib.h 119 | # End Source File 120 | # End Group 121 | # Begin Group "Resource Files" 122 | 123 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 124 | # End Group 125 | # End Target 126 | # End Project 127 | -------------------------------------------------------------------------------- /UspLib/USPDLL.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "USPDLL"=.\USPDLL.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Global: 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<3> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | -------------------------------------------------------------------------------- /UspLib/UspCtrl.c: -------------------------------------------------------------------------------- 1 | // 2 | // UspCtrl.c 3 | // 4 | // Contains support routines for painting control-characters 5 | // 6 | // Written by J Brown 2006 7 | // www.catch22.net 8 | // 9 | 10 | #define _WIN32_WINNT 0x501 11 | 12 | #ifndef _UNICODE 13 | #define _UNICODE 14 | #endif 15 | 16 | #ifndef UNICODE 17 | #error "Please build as Unicode only!" 18 | #define UNICODE 19 | #endif 20 | 21 | #define STRICT 22 | #define WIN32_LEAN_AND_MEAN 23 | 24 | #include 25 | #include 26 | #include 27 | #include "usplib.h" 28 | 29 | #if _MSC_VER == 1200 30 | #define swprintf _snwprintf 31 | #endif 32 | 33 | // 'ASCII' control characters U+0000 - U+001F 34 | static const WCHAR *asciireps[] = 35 | { 36 | L"NUL", L"SOH", L"STX", L"ETX", L"EOT", L"ENQ", L"ACK", L"BEL", 37 | L"BS", L"HT", L"LF", L"VT", L"FF", L"CR", L"SO", L"SI", 38 | L"DLE", L"DC1", L"DC2", L"DC3", L"DC4", L"NAK", L"SYN", L"ETB", 39 | L"CAN", L"EM", L"SUB", L"ESC", L"FS", L"GS", L"RS", L"US" 40 | }; 41 | 42 | // C1 control characters U+0080 - U+00A0 43 | static const WCHAR *c1controls[] = 44 | { 45 | L"80", L"81", L"BPH", L"NBH", L"IND", L"NEL", L"SSA", L"ESA", 46 | L"HTS", L"HTJ", L"VTS", L"PLD", L"PLU", L"RI", L"SS2", L"SS3", 47 | L"DCS", L"PU1", L"PU2", L"STS", L"CCH", L"MW", L"SPA", L"EPA", 48 | L"SOS", L"99", L"SCI", L"CSI", L"ST", L"OSC", L"PM", L"APC", 49 | L"NBSP", 50 | L"SHY", // 0xAD 51 | }; 52 | 53 | static 54 | const WCHAR * CtrlStrRep(DWORD ch) 55 | { 56 | if(ch < 0x20) 57 | return asciireps[ch]; 58 | 59 | if(ch >= 0x80 && ch < 0xA0) 60 | return c1controls[ch-0x80]; 61 | 62 | switch(ch) 63 | { 64 | // Arabic control-characters 65 | case 0x0600: return L"ANS"; // Arabic Number Sign 66 | case 0x0601: return L"ASS"; // Arabic Sign Sanah 67 | case 0x0602: return L"ANSN"; // Arabic Number Sign 68 | case 0x0603: return L"ASNS"; // Arabic Sign Safha 69 | case 0x06DD: return L"AEY"; // Arabic End Of Ayah 70 | 71 | // tag characters 72 | case 0xE0001: return L"LTAG"; // Language Tag 73 | case 0xE007F: return L"CTAG"; // Cancel Tag 74 | 75 | case 0x0085: return L"NEL"; // Next Line (EBCDIC) 76 | case 0x00A0: return L"NBSP"; // No Break Space 77 | case 0x034F: return L"CGJ"; // Combining Grapheme Joiner 78 | 79 | // general punc 80 | case 0x2000: return L"NQSP"; // EnQuad 81 | case 0x2001: return L"MQSP"; // EmQuad 82 | case 0x2002: return L"ENSP"; // EnSpace 83 | case 0x2003: return L"NQSP"; // EmSpace 84 | case 0x2004: return L"3MSP"; // 3 per em Space 85 | case 0x2005: return L"4MSP"; // 4 per em Space 86 | case 0x2006: return L"6MPS"; // 6 per em Space 87 | case 0x2007: return L"FSP"; // Figure space 88 | case 0x2008: return L"PSP"; // Punctuation Space 89 | case 0x2009: return L"THSP"; // Thin Space 90 | case 0x200A: return L"HSP"; // Hair Space 91 | case 0x200B: return L"ZWSP"; // Zero Width Space 92 | case 0x200C: return L"ZWNJ"; // Zero Width Non Joiner 93 | case 0x200D: return L"ZWJ"; // Zero width Joiner 94 | case 0x200E: return L"LRM"; // Left Right Mark 95 | case 0x200F: return L"RLM"; // Right Left Mark 96 | case 0x2010: return L"HYP"; // Hyphen 97 | case 0x2011: return L"NB"; // Non Break Hyphen 98 | case 0x2015: return L"HB"; // Horizontal Bar 99 | case 0x2028: return L"LSEP"; // Line Separator 100 | case 0x2029: return L"PSEP"; // Paragraph Separator 101 | case 0x202A: return L"LRE"; // Left to Right Embedding 102 | case 0x202B: return L"RLE"; // Right to Left Embedding 103 | case 0x202C: return L"PDF"; // Pop Directional Formatting 104 | case 0x202D: return L"LRO"; // Left to Right Override 105 | case 0x202E: return L"RLO"; // Right to Left Override 106 | case 0x202F: return L"NNMSP"; // Narrow No Break Space 107 | case 0x205F: return L"MMSP"; // Medium Mathematical Space 108 | case 0x2060: return L"WJ"; // Word Joiner 109 | case 0x2061: return L"F()"; // Function Application 110 | case 0x2062: return L"X"; // Invisible Times 111 | case 0x2063: return L","; // Invisible Separator 112 | case 0x206A: return L"ISS"; // Inhibit Symmetric Swapping 113 | case 0x206B: return L"ASS"; // Activate Symmetric Swapping 114 | case 0x206C: return L"IAFS"; // Inhibit Arabic Form Shaping 115 | case 0x206D: return L"AAFS"; // Activate Arabic Form Shaping 116 | case 0x206E: return L"NADS"; // National Digit Shapes 117 | case 0x206F: return L"NODS"; // Nominal Digit Shapes 118 | 119 | case 0xFEFF: return L"ZWNBS"; // Zero Width No Break Space 120 | case 0xFFA0: return L"HWHF"; // halfwidth hangul filler 121 | case 0xFFF9: return L"ILAA"; // Interlinear Annotation Anchor 122 | case 0xFFFA: return L"ILAS"; // Interlinear Annotation Separator 123 | case 0xFFFB: return L"ILAT"; // Interlinear Annotation Terminator 124 | case 0xFFFC: return L"OBJ"; // Object Replacement Character 125 | case 0xFFFD: return L"REP"; // Replacement Character 126 | case 0: return L"RS"; // Record Separator 127 | case 2: return L"US"; // Unit Separator 128 | 129 | case 0x070F: return L"SAM"; // syriac abbreviation mark (SAM) 130 | case 0x0F0C: return L"NB"; // Tibetan-Mark-Delimeter-Tsheg-Bstar (NB) 131 | case 0x115F: return L"HCF"; // Hangul-Choseong-Filler (HCF) 132 | case 0x1160: return L"HJF"; // Hangul-Jungseong-Filler (HCF) 133 | case 0x17B4: return L"KIVAQ"; // Khmer-Vowel-Inherent AQ (KIVAQ) 134 | case 0x17B5: return L"KIVAA"; // Khmer-Vowel-Inherent AA (KIVAA) 135 | case 0x180B: return L"FVS1"; // Mongolian-Free-Variation-Selector-One (FVS1) 136 | case 0x180C: return L"FVS2"; // Mongolian-Free-Variation-Selector-Two (FVS2) 137 | case 0x180D: return L"FVS3"; // Mongolian-Free-Variation-Selector-Three (FVS3) 138 | case 0x180E: return L"MVS"; // Mongolian-Vowel-Separator (MVS) 139 | 140 | case 0x1D159: return L"MSNNH"; // Music Symbol Null Note Head 141 | case 0x1D173: return L"MSBB"; // Music Symbol begin beam 142 | case 0x1D174: return L"MSEB"; // Music Symbol end beam 143 | case 0x1D175: return L"MSBT"; // Music Symbol begin tie 144 | case 0x1D176: return L"MSET"; // Music Symbol end tie 145 | case 0x1D177: return L"MSBS"; // Music Symbol begin slur 146 | case 0x1D178: return L"MSES"; // Music Symbol end slur 147 | case 0x1D179: return L"MSBP"; // Music Symbol begin phrase 148 | case 0x1D17A: return L"MSEP"; // Music Symbol end phrase 149 | default: return NULL; 150 | } 151 | 152 | // control-pictures (2400+) 153 | 154 | // 3000 Ideographic-Space (IDSP) 155 | 156 | // 3164 Hangul-filler(HF) 157 | 158 | // variation-selectors (FE00 - FE0F, VS1-VS16) 159 | // tags (E0001 - E007f) 160 | // variation-selector-supplement (e0100-e01ef , 'vs17 - vs256) 161 | } 162 | 163 | 164 | 165 | 166 | static 167 | WCHAR * CtrlStr(DWORD ch, int mode, WCHAR *buf, size_t len) 168 | { 169 | const WCHAR *ctrlstr; 170 | 171 | switch(mode) 172 | { 173 | case USP_CTLCHR_ASC: 174 | ctrlstr = CtrlStrRep(ch); 175 | 176 | if(ctrlstr) swprintf(buf, len, L"%s", ctrlstr); 177 | else swprintf(buf, len, L"%02X", ch); 178 | break; 179 | 180 | case USP_CTLCHR_DEC: 181 | swprintf(buf, len, L"%02d", ch); 182 | break; 183 | 184 | case USP_CTLCHR_HEX: 185 | swprintf(buf, len, L"%02X", ch); 186 | break; 187 | } 188 | 189 | return buf; 190 | } 191 | 192 | int CtrlCharWidth(USPFONT *uspFont, HDC hdc, ULONG chValue) 193 | { 194 | SIZE size; 195 | WCHAR str[16]; 196 | int mode = USP_CTLCHR_HEX;//ASC; 197 | 198 | CtrlStr(chValue, mode, str, 16); 199 | GetTextExtentPoint32(hdc, str, wcslen(str), &size); 200 | 201 | return size.cx+uspFont->xborder*2 + uspFont->yborder; 202 | } 203 | 204 | 205 | void InitCtrlChar(HDC hdc, USPFONT *uspFont) 206 | { 207 | int x, y; 208 | 209 | // create a temporary off-screen bitmap 210 | HDC hdcTemp = CreateCompatibleDC(hdc); 211 | HBITMAP hbmTemp = CreateBitmap(uspFont->tm.tmAveCharWidth, uspFont->tm.tmHeight, 1, 1, 0); 212 | HANDLE hbmOld = SelectObject(hdcTemp, hbmTemp); 213 | HANDLE hfnOld = SelectObject(hdcTemp, uspFont->hFont); 214 | 215 | // black-on-white text 216 | SetTextColor(hdcTemp, RGB(0,0,0)); 217 | SetBkColor(hdcTemp, RGB(255,255,255)); 218 | SetBkMode(hdcTemp, OPAQUE); 219 | 220 | // give default values just in case the scan fails 221 | uspFont->capheight = uspFont->tm.tmAscent - uspFont->tm.tmInternalLeading; 222 | 223 | TextOut(hdcTemp, 0, 0, _T("E"), 1); 224 | 225 | // scan downwards looking for the top of the letter 'E' 226 | for(y = 0; y < uspFont->tm.tmHeight; y++) 227 | { 228 | for(x = 0; x < uspFont->tm.tmAveCharWidth; x++) 229 | { 230 | COLORREF col; 231 | 232 | if((col = GetPixel(hdcTemp, x, y)) == RGB(0,0,0)) 233 | { 234 | uspFont->capheight = uspFont->tm.tmAscent - y; 235 | y = uspFont->tm.tmHeight; 236 | break; 237 | } 238 | } 239 | } 240 | 241 | TextOut(hdcTemp, 0, 0, _T("0"), 1); 242 | 243 | // do the same for numbers (0) in case they are taller/shorter 244 | for(y = 0; y < uspFont->tm.tmHeight; y++) 245 | { 246 | for(x = 0; x < uspFont->tm.tmAveCharWidth; x++) 247 | { 248 | COLORREF col; 249 | 250 | if((col = GetPixel(hdcTemp, x, y)) == RGB(0,0,0)) 251 | { 252 | uspFont->numheight = uspFont->tm.tmAscent - y; 253 | y = uspFont->tm.tmHeight; 254 | break; 255 | } 256 | } 257 | } 258 | 259 | // calculate border-size - 15% of total height 260 | uspFont->yborder = uspFont->capheight * 15 / 100; 261 | uspFont->yborder = max(1, uspFont->yborder); // minimum of 1-pixel 262 | uspFont->xborder = max(2, uspFont->yborder); // same as yborder, but min 2-pixel 263 | 264 | // cleanup 265 | SelectObject(hdcTemp, hbmOld); 266 | SelectObject(hdcTemp, hfnOld); 267 | DeleteDC(hdcTemp); 268 | DeleteObject(hbmTemp); 269 | } 270 | 271 | static 272 | void PaintRect(HDC hdc, RECT *rect, COLORREF fill) 273 | { 274 | fill = SetBkColor(hdc, fill); 275 | ExtTextOut(hdc, 0, 0, ETO_OPAQUE, rect, 0, 0, 0); 276 | SetBkColor(hdc, fill); 277 | } 278 | 279 | static 280 | int PaintCtrlChar(USPFONT *uspFont, HDC hdc, int xpos, int ypos, ULONG chValue, COLORREF fg, COLORREF bg) 281 | { 282 | WCHAR str[8]; 283 | RECT rect; 284 | SIZE size; 285 | int mode = USP_CTLCHR_HEX; 286 | int height; 287 | 288 | // get the textual representation of the control-character 289 | CtrlStr(chValue, mode, str, 8); 290 | 291 | // get the text dimension (only need width) 292 | GetTextExtentPoint32(hdc, str, wcslen(str), &size); 293 | 294 | // center the control-character "glyph" 295 | xpos += uspFont->yborder/2 + 1; 296 | 297 | if(mode == USP_CTLCHR_ASC || mode == USP_CTLCHR_HEX) 298 | height = max(uspFont->capheight, uspFont->numheight); 299 | else 300 | height = uspFont->numheight; 301 | 302 | SetRect( 303 | &rect, 304 | xpos + 1, 305 | ypos + uspFont->tm.tmAscent - height - uspFont->yborder, 306 | xpos + size.cx + uspFont->xborder * 2 - 2, 307 | ypos + uspFont->tm.tmAscent + uspFont->yborder 308 | ); 309 | 310 | //if(rect.top < ypos+1) 311 | // rect.top = ypos+1; 312 | 313 | // prepare the background 'round' rectangle 314 | PaintRect(hdc, &rect, bg); 315 | InflateRect(&rect, 1,-1); 316 | PaintRect(hdc, &rect, bg); 317 | 318 | // finally paint the text 319 | SetTextColor(hdc, fg); 320 | TextOut(hdc, xpos + uspFont->xborder, ypos, str, wcslen(str)); 321 | 322 | return 0; 323 | } 324 | 325 | // 326 | // Note there is only 1 control-character per run so the loop below isn't really necessary 327 | // 328 | void PaintCtrlCharRun(USPDATA *uspData, USPFONT *uspFont, ITEM_RUN *itemRun, HDC hdc, int xpos, int ypos) 329 | { 330 | int i; 331 | 332 | for(i = 0; i < itemRun->glyphCount; i++) 333 | { 334 | ATTR attr = uspData->attrList[itemRun->charPos+i]; 335 | 336 | if(attr.sel) 337 | PaintCtrlChar(uspFont, hdc, xpos, ypos, itemRun->chcode, uspData->selBG, uspData->selFG); 338 | else 339 | PaintCtrlChar(uspFont, hdc, xpos, ypos, itemRun->chcode, attr.bg, attr.fg); 340 | 341 | xpos += uspData->widthList[itemRun->glyphPos+i]; 342 | } 343 | } -------------------------------------------------------------------------------- /UspLib/UspLib.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="UspLib" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Static Library" 0x0104 6 | 7 | CFG=UspLib - Win32 Unicode Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "UspLib.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "UspLib.mak" CFG="UspLib - Win32 Unicode Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "UspLib - Win32 Release" (based on "Win32 (x86) Static Library") 21 | !MESSAGE "UspLib - Win32 Debug" (based on "Win32 (x86) Static Library") 22 | !MESSAGE "UspLib - Win32 Unicode Debug" (based on "Win32 (x86) Static Library") 23 | !MESSAGE "UspLib - Win32 Unicode Release" (based on "Win32 (x86) Static Library") 24 | !MESSAGE 25 | 26 | # Begin Project 27 | # PROP AllowPerConfigDependencies 0 28 | # PROP Scc_ProjName "" 29 | # PROP Scc_LocalPath "" 30 | CPP=cl.exe 31 | RSC=rc.exe 32 | 33 | !IF "$(CFG)" == "UspLib - Win32 Release" 34 | 35 | # PROP BASE Use_MFC 0 36 | # PROP BASE Use_Debug_Libraries 0 37 | # PROP BASE Output_Dir "Release" 38 | # PROP BASE Intermediate_Dir "Release" 39 | # PROP BASE Target_Dir "" 40 | # PROP Use_MFC 0 41 | # PROP Use_Debug_Libraries 0 42 | # PROP Output_Dir "Release" 43 | # PROP Intermediate_Dir "Release" 44 | # PROP Target_Dir "" 45 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c 46 | # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c 47 | # ADD BASE RSC /l 0x809 /d "NDEBUG" 48 | # ADD RSC /l 0x809 /d "NDEBUG" 49 | BSC32=bscmake.exe 50 | # ADD BASE BSC32 /nologo 51 | # ADD BSC32 /nologo 52 | LIB32=link.exe -lib 53 | # ADD BASE LIB32 /nologo 54 | # ADD LIB32 /nologo 55 | 56 | !ELSEIF "$(CFG)" == "UspLib - Win32 Debug" 57 | 58 | # PROP BASE Use_MFC 0 59 | # PROP BASE Use_Debug_Libraries 1 60 | # PROP BASE Output_Dir "Debug" 61 | # PROP BASE Intermediate_Dir "Debug" 62 | # PROP BASE Target_Dir "" 63 | # PROP Use_MFC 0 64 | # PROP Use_Debug_Libraries 1 65 | # PROP Output_Dir "Debug" 66 | # PROP Intermediate_Dir "Debug" 67 | # PROP Target_Dir "" 68 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 69 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 70 | # ADD BASE RSC /l 0x809 /d "_DEBUG" 71 | # ADD RSC /l 0x809 /d "_DEBUG" 72 | BSC32=bscmake.exe 73 | # ADD BASE BSC32 /nologo 74 | # ADD BSC32 /nologo 75 | LIB32=link.exe -lib 76 | # ADD BASE LIB32 /nologo 77 | # ADD LIB32 /nologo 78 | 79 | !ELSEIF "$(CFG)" == "UspLib - Win32 Unicode Debug" 80 | 81 | # PROP BASE Use_MFC 0 82 | # PROP BASE Use_Debug_Libraries 1 83 | # PROP BASE Output_Dir "Unicode Debug" 84 | # PROP BASE Intermediate_Dir "Unicode Debug" 85 | # PROP BASE Target_Dir "" 86 | # PROP Use_MFC 0 87 | # PROP Use_Debug_Libraries 1 88 | # PROP Output_Dir "Unicode_Debug" 89 | # PROP Intermediate_Dir "Unicode_Debug" 90 | # PROP Target_Dir "" 91 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 92 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_LIB" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c 93 | # ADD BASE RSC /l 0x809 /d "_DEBUG" 94 | # ADD RSC /l 0x809 /d "_DEBUG" 95 | BSC32=bscmake.exe 96 | # ADD BASE BSC32 /nologo 97 | # ADD BSC32 /nologo 98 | LIB32=link.exe -lib 99 | # ADD BASE LIB32 /nologo 100 | # ADD LIB32 /nologo 101 | 102 | !ELSEIF "$(CFG)" == "UspLib - Win32 Unicode Release" 103 | 104 | # PROP BASE Use_MFC 0 105 | # PROP BASE Use_Debug_Libraries 0 106 | # PROP BASE Output_Dir "Unicode Release" 107 | # PROP BASE Intermediate_Dir "Unicode Release" 108 | # PROP BASE Target_Dir "" 109 | # PROP Use_MFC 0 110 | # PROP Use_Debug_Libraries 0 111 | # PROP Output_Dir "Unicode_Release" 112 | # PROP Intermediate_Dir "Unicode_Release" 113 | # PROP Target_Dir "" 114 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c 115 | # ADD CPP /nologo /MD /W3 /GX- /O1 /D "WIN32" /D "NDEBUG" /D "_LIB" /D "_UNICODE" /D "UNICODE" /YX /FD /c 116 | # ADD BASE RSC /l 0x809 /d "NDEBUG" 117 | # ADD RSC /l 0x809 /d "NDEBUG" 118 | BSC32=bscmake.exe 119 | # ADD BASE BSC32 /nologo 120 | # ADD BSC32 /nologo 121 | LIB32=link.exe -lib 122 | # ADD BASE LIB32 /nologo 123 | # ADD LIB32 /nologo 124 | 125 | !ENDIF 126 | 127 | # Begin Target 128 | 129 | # Name "UspLib - Win32 Release" 130 | # Name "UspLib - Win32 Debug" 131 | # Name "UspLib - Win32 Unicode Debug" 132 | # Name "UspLib - Win32 Unicode Release" 133 | # Begin Group "Source Files" 134 | 135 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 136 | # Begin Source File 137 | 138 | SOURCE=.\UspCtrl.c 139 | # End Source File 140 | # Begin Source File 141 | 142 | SOURCE=.\UspLib.c 143 | # End Source File 144 | # Begin Source File 145 | 146 | SOURCE=.\UspMouse.c 147 | # End Source File 148 | # Begin Source File 149 | 150 | SOURCE=.\UspPaint.c 151 | # End Source File 152 | # End Group 153 | # Begin Group "Header Files" 154 | 155 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 156 | # Begin Source File 157 | 158 | SOURCE=.\usplib.h 159 | # End Source File 160 | # End Group 161 | # End Target 162 | # End Project 163 | -------------------------------------------------------------------------------- /UspLib/UspMain.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #pragma comment(linker, "/opt:nowin98") 4 | 5 | #pragma comment(linker, "/export:UspAnalyze=_UspAnalyze@40") 6 | #pragma comment(linker, "/export:UspFree=_UspFree@4") 7 | #pragma comment(linker, "/export:UspAllocate=_UspAllocate@0") 8 | #pragma comment(linker, "/export:UspApplyAttributes=_UspApplyAttributes@8") 9 | #pragma comment(linker, "/export:UspApplySelection=_UspApplySelection@12") 10 | #pragma comment(linker, "/export:UspTextOut=_UspTextOut@28") 11 | #pragma comment(linker, "/export:UspSnapXToOffset=_UspSnapXToOffset@20") 12 | #pragma comment(linker, "/export:UspXToOffset=_UspXToOffset@20") 13 | #pragma comment(linker, "/export:UspOffsetToX=_UspOffsetToX@16") 14 | #pragma comment(linker, "/export:UspSetSelColor=_UspSetSelColor@12") 15 | #pragma comment(linker, "/export:UspInitFont=_UspInitFont@12") 16 | #pragma comment(linker, "/export:UspFreeFont=_UspFreeFont@4") 17 | #pragma comment(linker, "/export:UspGetSize=_UspGetSize@8") 18 | #pragma comment(linker, "/export:UspGetLogAttr=_UspGetLogAttr@4") 19 | #pragma comment(linker, "/export:UspBuildAttr=_UspBuildAttr@32") 20 | 21 | BOOL CALLBACK DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved) 22 | { 23 | return TRUE; 24 | } -------------------------------------------------------------------------------- /UspLib/UspMouse.c: -------------------------------------------------------------------------------- 1 | // 2 | // UspMouse.c 3 | // 4 | // Contains routines useful for converting between 5 | // mouse-coordinates and character-positions, designed 6 | // to emulate the functionality provided by the 7 | // ScriptStringXtoCP and ScriptStringCPToX 8 | // 9 | // UspSnapXToOffset 10 | // UspXToOffset 11 | // UspOffsetToX 12 | // 13 | // Written by J Brown 2006 14 | // www.catch22.net 15 | // 16 | #define _WIN32_WINNT 0x501 17 | 18 | #ifndef _UNICODE 19 | #define _UNICODE 20 | #endif 21 | 22 | #ifndef UNICODE 23 | #define UNICODE 24 | #endif 25 | 26 | #define STRICT 27 | #define WIN32_LEAN_AND_MEAN 28 | 29 | #include 30 | #include 31 | #include "usplib.h" 32 | 33 | ITEM_RUN *GetItemRun(USPDATA *uspData, int visualIdx); 34 | 35 | // 36 | // Translate the specified screen-x-coordinate (usually the mouse position) 37 | // into a character-offset within the specified line. Calling this function 38 | // is preferable to using UspXToOffset and UspOffsetToX separately as it 39 | // gives more natural results for mouse-placement. 40 | // 41 | // The adjusted x-coordinate is also returned after it has been snapped to 42 | // the nearest cluster boundary, in *snappedX. 43 | // 44 | // The script direction is returned (right/left) in *fRTL 45 | // 46 | BOOL WINAPI UspSnapXToOffset ( 47 | USPDATA * uspData, 48 | int xpos, 49 | int * snappedX, // out, optional 50 | int * charPos, // out 51 | BOOL * fRTL // out, optional 52 | ) 53 | { 54 | int i, cp, trailing, runx = 0; 55 | int runCount = uspData->itemRunCount; 56 | 57 | if(charPos) *charPos = 0; 58 | if(snappedX) *snappedX = 0; 59 | if(fRTL) *fRTL = 0; 60 | 61 | if(xpos < 0) 62 | xpos = 0; 63 | 64 | // don't allow mouse to move into the CR-LF sequence. This is incorrect 65 | // for RTL and mixed LTR/RTL runs!!! 66 | for(i = runCount-1; i >= 0; i--) 67 | { 68 | if(uspData->itemRunList[i].eol) 69 | runCount--; 70 | } 71 | 72 | //if(runCount > 0 && uspData->itemRunList[runCount-1].eol) 73 | // runCount--; 74 | 75 | // 76 | // process each "run" or span of text in visual order 77 | // 78 | for(i = 0; i < runCount; i++) 79 | { 80 | ITEM_RUN *itemRun; 81 | 82 | // get width of this span of text 83 | if((itemRun = GetItemRun(uspData, i)) == 0) 84 | break; 85 | 86 | if(itemRun->eol) 87 | { 88 | runx += itemRun->width; 89 | continue; 90 | } 91 | 92 | // does the mouse fall within this run of text? 93 | if((i == runCount - 1) || xpos >= runx && xpos < runx + itemRun->width) 94 | { 95 | // get the character position 96 | ScriptXtoCP(xpos - runx, 97 | itemRun->len, 98 | itemRun->glyphCount, 99 | uspData->clusterList + itemRun->charPos, 100 | uspData->svaList + itemRun->glyphPos, 101 | uspData->widthList + itemRun->glyphPos, 102 | &itemRun->analysis, 103 | &cp, 104 | &trailing 105 | ); 106 | 107 | // convert this character position back to a x-coord 108 | if(snappedX) 109 | { 110 | ScriptCPtoX(cp+trailing, 111 | FALSE, 112 | itemRun->len, 113 | itemRun->glyphCount, 114 | uspData->clusterList + itemRun->charPos, 115 | uspData->svaList + itemRun->glyphPos, 116 | uspData->widthList + itemRun->glyphPos, 117 | &itemRun->analysis, 118 | snappedX 119 | ); 120 | 121 | // return the adjusted x-coordinate 122 | *snappedX += runx; 123 | } 124 | 125 | // return the character-offset 126 | *charPos = cp + trailing + itemRun->charPos; 127 | 128 | // return script-direction for this run 129 | if(fRTL) 130 | *fRTL = itemRun->analysis.fRTL; 131 | 132 | return TRUE; 133 | } 134 | 135 | // advance xpos to next run 136 | runx += itemRun->width; 137 | } 138 | 139 | return FALSE; 140 | } 141 | 142 | // 143 | // Translate the specified screen-x-coordinate (usually the mouse position) 144 | // into a character-offset within the specified line. This is function 145 | // duplicates the behaviour of ScriptStringXToCP 146 | // 147 | // The script direction is also returned (right/left) in *fRTL 148 | // 149 | BOOL WINAPI UspXToOffset ( 150 | USPDATA * uspData, 151 | int xpos, 152 | int * charPos, // out 153 | BOOL * trailing, // out 154 | BOOL * fRTL // out, optional 155 | ) 156 | { 157 | int i, runx = 0; 158 | int runCount = uspData->itemRunCount; 159 | 160 | if(xpos < 0) 161 | xpos = 0; 162 | 163 | if(runCount > 0 && uspData->itemRunList[runCount-1].eol) 164 | runCount--; 165 | 166 | // 167 | // process each "run" or span of text 168 | // 169 | for(i = 0; i < runCount; i++) 170 | { 171 | ITEM_RUN *itemRun; 172 | 173 | // get width of this span of text 174 | if((itemRun = GetItemRun(uspData, i)) == 0) 175 | break; 176 | 177 | // does the mouse fall within this run of text? 178 | if((i == runCount - 1) || xpos >= runx && xpos < runx + itemRun->width) 179 | { 180 | // get the character position 181 | ScriptXtoCP(xpos - runx, 182 | itemRun->len, 183 | itemRun->glyphCount, 184 | uspData->clusterList + itemRun->charPos, 185 | uspData->svaList + itemRun->glyphPos, 186 | uspData->widthList + itemRun->glyphPos, 187 | &itemRun->analysis, 188 | charPos, 189 | trailing 190 | ); 191 | 192 | *charPos += itemRun->charPos; 193 | 194 | // return script-direction for this run 195 | if(fRTL) 196 | *fRTL = itemRun->analysis.fRTL; 197 | 198 | return TRUE; 199 | } 200 | 201 | // advance xpos to next run 202 | runx += itemRun->width; 203 | } 204 | 205 | *trailing = 0; 206 | *charPos = 0; 207 | if(fRTL) *fRTL = 0; 208 | return FALSE; 209 | } 210 | 211 | // 212 | // Translate the specified character-position to a pixel-based 213 | // coordinate, relative to the start of the string 214 | // Duplicates the behaviour of ScriptStringCPToX 215 | // 216 | BOOL WINAPI UspOffsetToX ( 217 | USPDATA * uspData, 218 | int charPos, 219 | BOOL trailing, // out 220 | int * px // out 221 | ) 222 | { 223 | int i; 224 | int xpos = 0; 225 | ITEM_RUN *itemRun; 226 | 227 | *px = 0; 228 | 229 | // 230 | // process each "run" or span of text in visual order 231 | // 232 | for(i = 0; i < uspData->itemRunCount; i++) 233 | { 234 | // get width of this span of text 235 | if((itemRun = GetItemRun(uspData, i)) == 0) 236 | break; 237 | 238 | // does the mouse fall within this run of text? 239 | if((i == uspData->itemRunCount - 1) || 240 | charPos >= itemRun->charPos && charPos < itemRun->charPos + itemRun->len) 241 | { 242 | ScriptCPtoX(charPos - itemRun->charPos, 243 | trailing, 244 | itemRun->len, 245 | itemRun->glyphCount, 246 | uspData->clusterList + itemRun->charPos, 247 | uspData->svaList + itemRun->glyphPos, 248 | uspData->widthList + itemRun->glyphPos, 249 | &itemRun->analysis, 250 | px 251 | ); 252 | 253 | *px += xpos; 254 | return TRUE; 255 | } 256 | 257 | xpos += itemRun->width; 258 | } 259 | 260 | return FALSE; 261 | } -------------------------------------------------------------------------------- /UspLib/usplib.h: -------------------------------------------------------------------------------- 1 | #ifndef USPLIB_INCLUDED 2 | #define USPLIB_INCLUDED 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #pragma comment(lib, "usp10.lib") 10 | 11 | // 12 | // ATTR - use to define the attributes of a single run of text 13 | // 14 | typedef struct _ATTR 15 | { 16 | COLORREF fg; 17 | COLORREF bg; 18 | int len : 16; // length of this run (in code-units) 19 | int font : 7; // font-index 20 | int sel : 1; // selection flag (yes/no) 21 | int ctrl : 1; // show as an isolated control-character 22 | int eol : 1; // when set, prevents cursor from selecting character. only valid for last char in line 23 | int reserved : 6; // possible underline/other styles (must be NULL) 24 | 25 | } ATTR, *PATTR; 26 | 27 | // 28 | // USPFONT - use to provide UspAnalyze with font. 29 | // Only the yoffset member can be modified by the caller - after 30 | // UspInitFont has been called 31 | // 32 | typedef struct _USPFONT 33 | { 34 | HFONT hFont; // handle to FONT 35 | SCRIPT_CACHE scriptCache; // must be initialized to NULL 36 | TEXTMETRIC tm; // 37 | int yoffset; // height-adjustment when drawing font (set to zero) 38 | 39 | // reserved for internal use 40 | int capheight; // height of capital letters 41 | int numheight; // height of numeric characters 42 | int xborder; 43 | int yborder; 44 | 45 | } USPFONT, *PUSPFONT; 46 | 47 | // 48 | // ITEM_RUN - private to USPLIB 49 | // 50 | typedef struct _ITEM_RUN 51 | { 52 | SCRIPT_ANALYSIS analysis; 53 | int charPos; 54 | int len; // length of run in WCHARs 55 | int font; // font index 56 | 57 | int width; // total width in pixels of this run 58 | int glyphPos; // position within USPDATA's lists 59 | int glyphCount; // number of glyphs in this run 60 | 61 | int chcode : 21; // codepoint (only used when ::ctrl is TRUE) 62 | int tab : 1; // run is a single tab-character 63 | int ctrl : 1; // run is a single control-character 64 | int eol : 1; // prevents cursor from selecting character (only sensible for last char) 65 | int selstate : 2; // whole run selection state (0=none, 1=all, 2=partial) 66 | 67 | } ITEM_RUN, *PITEM_RUN; 68 | 69 | 70 | // 71 | // USPDATA - opaque data structure, do not assume 72 | // anything about the internal layout of this structure 73 | // 74 | typedef struct _USPDATA 75 | { 76 | // 77 | // Array of merged SCRIPT_ITEM runs 78 | // 79 | int itemRunCount; 80 | int itemRunAllocLen; 81 | ITEM_RUN * itemRunList; 82 | int * visualToLogicalList; 83 | BYTE * bidiLevels; 84 | 85 | SCRIPT_ITEM * tempItemList; // only used during string-analysis 86 | int tempItemAllocLen; 87 | 88 | // 89 | // Logical character/cluster information (1 unit per original WCHAR) 90 | // 91 | int stringLen; // length of current string (in WCHARs) 92 | int stringAllocLen; // actual allocation count of string and arrays: 93 | WORD * clusterList; // logical cluster info 94 | ATTR * attrList; // flattened attribute-list 95 | SCRIPT_LOGATTR * breakList; // holds results of script-break 96 | 97 | // 98 | // Glyph information for the entire paragraph 99 | // Each ITEM_RUN references a position within these lists: 100 | // 101 | int glyphCount; // count of glyphs currently stored 102 | int glyphAllocLen; // actual allocated length of buffers 103 | WORD * glyphList; 104 | int * widthList; 105 | GOFFSET * offsetList; 106 | SCRIPT_VISATTR * svaList; 107 | 108 | SIZE size; 109 | 110 | // colours of the selection-highlight 111 | COLORREF selFG; 112 | COLORREF selBG; 113 | 114 | // stored flags from UspAnalyze 115 | UINT analyzeFlags; 116 | 117 | // 118 | // external, user-maintained font-table 119 | // 120 | USPFONT * uspFontList; 121 | USPFONT defaultFont; // if no user-list 122 | 123 | } USPDATA, *PUSPDATA; 124 | 125 | // 126 | // UspAnalyze flags 127 | // 128 | #define USP_CTLCHR_DEC 0x10 129 | #define USP_CTLCHR_HEX 0x20 130 | #define USP_CTLCHR_ASC 0x40 131 | 132 | 133 | USPDATA * WINAPI UspAllocate ( 134 | ); 135 | 136 | VOID WINAPI UspFree ( 137 | USPDATA *uspData 138 | ); 139 | 140 | BOOL WINAPI UspAnalyze ( 141 | USPDATA * uspData, 142 | HDC hdc, 143 | WCHAR * wstr, 144 | int wlen, 145 | ATTR * attrRunList, 146 | UINT flags, 147 | USPFONT * uspFont, 148 | SCRIPT_CONTROL * scriptControl, 149 | SCRIPT_STATE * scriptState, 150 | SCRIPT_TABDEF * scriptTabDef 151 | ); 152 | 153 | VOID WINAPI UspApplyAttributes ( 154 | USPDATA * uspData, 155 | ATTR * attrRunList 156 | ); 157 | 158 | VOID WINAPI UspApplySelection ( 159 | USPDATA * uspData, 160 | int selStart, 161 | int selEnd 162 | ); 163 | 164 | int WINAPI UspTextOut ( 165 | USPDATA * uspData, 166 | HDC hdc, 167 | int xpos, 168 | int ypos, 169 | int lineHeight, 170 | int lineAdjustY, 171 | RECT * rect 172 | ); 173 | 174 | BOOL WINAPI UspSnapXToOffset ( 175 | USPDATA * uspData, 176 | int xpos, 177 | int * snappedX, // out, optional 178 | int * charPos, // out 179 | BOOL * fRTL // out, optional 180 | ); 181 | 182 | BOOL WINAPI UspXToOffset ( 183 | USPDATA * uspData, 184 | int xpos, 185 | int * charPos, // out 186 | BOOL * trailing, // out 187 | BOOL * fRTL // out, optional 188 | ); 189 | 190 | BOOL WINAPI UspOffsetToX ( 191 | USPDATA * uspData, 192 | int offset, 193 | BOOL trailing, 194 | int * xpos // out 195 | ); 196 | 197 | VOID WINAPI UspSetSelColor ( 198 | USPDATA * uspData, 199 | COLORREF fg, 200 | COLORREF bg 201 | ); 202 | 203 | VOID WINAPI UspInitFont ( 204 | USPFONT * uspFont, // in/out 205 | HDC hdc, // in 206 | HFONT hFont // in 207 | ); 208 | 209 | VOID WINAPI UspFreeFont ( 210 | USPFONT * uspFont 211 | ); 212 | 213 | BOOL WINAPI UspGetSize ( 214 | USPDATA * uspData, 215 | SIZE * size 216 | ); 217 | 218 | BOOL WINAPI UspBuildAttr ( 219 | ATTR * attr, 220 | COLORREF colfg, 221 | COLORREF colbg, 222 | int len, 223 | int font, 224 | int sel, 225 | int ctrl, 226 | int eol 227 | ); 228 | 229 | SCRIPT_LOGATTR * WINAPI UspGetLogAttr ( 230 | USPDATA * uspData 231 | ); 232 | 233 | #ifdef __cplusplus 234 | } 235 | #endif 236 | 237 | #endif -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | NEATPAD - a simple win32 text editor with full source 2 | 3 | Visit www.catch22.net/tuts for more information 4 | 5 | Written by J Brown 2005 6 | --------------------------------------------------------------------------------