diff --git a/ColumnMode/ColumnMode.rc b/ColumnMode/ColumnMode.rc
index 1e1674e..cd66676 100644
--- a/ColumnMode/ColumnMode.rc
+++ b/ColumnMode/ColumnMode.rc
@@ -1,266 +1,268 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#ifndef APSTUDIO_INVOKED
-#include "targetver.h"
-#endif
-#define APSTUDIO_HIDDEN_SYMBOLS
-#include "windows.h"
-#undef APSTUDIO_HIDDEN_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (United States) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_COLUMNMODE ICON "ColumnMode.ico"
-
-IDI_SMALL ICON "small.ico"
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-
-IDC_COLUMNMODE MENU
-BEGIN
- POPUP "&File"
- BEGIN
- MENUITEM "New\tCtrl+N", ID_FILE_NEW
- MENUITEM "Open\tCtrl+O", ID_FILE_OPEN
- MENUITEM "Save\tCtrl+S", ID_FILE_SAVE
- MENUITEM "Save As\tCtrl+Shift+S", ID_FILE_SAVEAS
- MENUITEM "Refresh\tF5", ID_FILE_REFRESH
- MENUITEM "Properties...", ID_FILE_PROPERTIES
- MENUITEM SEPARATOR
- MENUITEM "Print...\tCtrl+P", ID_FILE_PRINT
- MENUITEM SEPARATOR
- MENUITEM "E&xit", IDM_EXIT
- END
- POPUP "Edit"
- BEGIN
- MENUITEM "Undo\tCtrl+Z", ID_EDIT_UNDO, INACTIVE
- MENUITEM SEPARATOR
- MENUITEM "Cut\tCtrl+X", ID_EDIT_CUT
- MENUITEM "Copy\tCtrl+C", ID_EDIT_COPY
- MENUITEM "Paste\tCtrl+V", ID_EDIT_PASTE
- MENUITEM "Delete\tDel", ID_EDIT_DELETE
- MENUITEM "Find\tCtrl+F", ID_EDIT_FIND
- END
- POPUP "Options"
- BEGIN
- MENUITEM "Diagram Mode", ID_OPTIONS_DIAGRAMMODE, CHECKED
- MENUITEM "Text Mode", ID_OPTIONS_TEXTMODE
- POPUP "Themes"
- BEGIN
- MENUITEM "Create New Theme", ID_THEMES_CREATENEWTHEME
- MENUITEM "Rescan", ID_THEMES_RESCAN
- MENUITEM SEPARATOR
- END
- END
- POPUP "Plugins"
- BEGIN
- MENUITEM "Rescan", ID_PLUGINS_RESCAN
- MENUITEM SEPARATOR
- END
- POPUP "&Help"
- BEGIN
- MENUITEM "&About ...", IDM_ABOUT
- END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Accelerator
-//
-
-IDC_COLUMNMODE ACCELERATORS
-BEGIN
- "C", ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
- "X", ID_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT
- VK_DELETE, ID_EDIT_DELETE, VIRTKEY, CONTROL, NOINVERT
- "F", ID_EDIT_FIND, VIRTKEY, CONTROL, NOINVERT
- "V", ID_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
- "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT
- "N", ID_FILE_NEW, VIRTKEY, CONTROL, NOINVERT
- "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
- "P", ID_FILE_PRINT, VIRTKEY, CONTROL, NOINVERT
- VK_F5, ID_FILE_REFRESH, VIRTKEY, NOINVERT
- "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT
- "S", ID_FILE_SAVEAS, VIRTKEY, SHIFT, CONTROL, NOINVERT
- "/", IDM_ABOUT, ASCII, ALT, NOINVERT
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "About ColumnMode"
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
-BEGIN
- ICON IDR_MAINFRAME,IDC_STATIC,14,14,21,20
- LTEXT "ColumnMode, Version 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX
- LTEXT "Copyright (C) 2019",IDC_STATIC,42,26,114,8
- DEFPUSHBUTTON "OK",IDOK,113,41,50,14,WS_GROUP
-END
-
-IDD_DOCUMENTPROPERTIES DIALOGEX 0, 0, 179, 78
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Document Properties"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- DEFPUSHBUTTON "OK",IDOK,64,56,50,14
- PUSHBUTTON "Cancel",IDCANCEL,122,56,50,14
- LTEXT "Line Count:",IDC_STATIC,7,9,38,8
- EDITTEXT IDC_LINECOUNT_EDITBOX,66,7,55,14,ES_AUTOHSCROLL
- LTEXT "Column Count:",IDC_STATIC,7,30,48,8
- EDITTEXT IDC_COLUMNCOUNT_EDITBOX,66,27,55,14,ES_AUTOHSCROLL
-END
-
-IDD_FIND_DIALOG DIALOGEX 0, 0, 179, 53
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Find"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- PUSHBUTTON "Next",ID_NEXT,64,28,50,14
- PUSHBUTTON "Previous",ID_PREVIOUS,122,28,50,14
- LTEXT "Search Text:",-1,7,9,45,8
- EDITTEXT IDC_FIND_EDITBOX,66,7,106,14,ES_AUTOHSCROLL
-END
-
-IDD_THEMENAMEQUERY DIALOGEX 0, 0, 179, 53
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Create New Theme"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- PUSHBUTTON "OK",IDOK,64,28,50,14
- PUSHBUTTON "CANCEL",IDCANCEL,122,28,50,14
- LTEXT "Theme Name:",-1,7,9,45,8
- EDITTEXT IDC_THEMENAME_EDITBOX,66,7,106,14,ES_AUTOHSCROLL
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO
-BEGIN
- IDD_ABOUTBOX, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 163
- TOPMARGIN, 7
- BOTTOMMARGIN, 55
- END
-
- IDD_DOCUMENTPROPERTIES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 172
- TOPMARGIN, 7
- BOTTOMMARGIN, 71
- END
-
- IDD_FIND_DIALOG, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 172
- TOPMARGIN, 7
- BOTTOMMARGIN, 46
- END
-
- IDD_THEMENAMEQUERY, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 172
- TOPMARGIN, 7
- BOTTOMMARGIN, 46
- END
-END
-#endif // APSTUDIO_INVOKED
-
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
- "#ifndef APSTUDIO_INVOKED\r\n"
- "#include ""targetver.h""\r\n"
- "#endif\r\n"
- "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
- "#include ""windows.h""\r\n"
- "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE
-BEGIN
- IDS_APP_TITLE "ColumnMode"
- IDC_COLUMNMODE "COLUMNMODE"
-END
-
-#endif // English (United States) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#ifndef APSTUDIO_INVOKED
+#include "targetver.h"
+#endif
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_COLUMNMODE ICON "ColumnMode.ico"
+
+IDI_SMALL ICON "small.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_COLUMNMODE MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "New\tCtrl+N", ID_FILE_NEW
+ MENUITEM "Open\tCtrl+O", ID_FILE_OPEN
+ MENUITEM "Save\tCtrl+S", ID_FILE_SAVE
+ MENUITEM "Save As\tCtrl+Shift+S", ID_FILE_SAVEAS
+ MENUITEM "Refresh\tF5", ID_FILE_REFRESH
+ MENUITEM "Properties...", ID_FILE_PROPERTIES
+ MENUITEM SEPARATOR
+ MENUITEM "Print...\tCtrl+P", ID_FILE_PRINT
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "Edit"
+ BEGIN
+ MENUITEM "Undo\tCtrl+Z", ID_EDIT_UNDO, INACTIVE
+ MENUITEM SEPARATOR
+ MENUITEM "Cut\tCtrl+X", ID_EDIT_CUT
+ MENUITEM "Copy\tCtrl+C", ID_EDIT_COPY
+ MENUITEM "Paste\tCtrl+V", ID_EDIT_PASTE
+ MENUITEM "Delete\tDel", ID_EDIT_DELETE
+ MENUITEM "Find\tCtrl+F", ID_EDIT_FIND
+ END
+ POPUP "Options"
+ BEGIN
+ MENUITEM "Diagram Mode", ID_OPTIONS_DIAGRAMMODE, CHECKED
+ MENUITEM "Text Mode", ID_OPTIONS_TEXTMODE
+ MENUITEM SEPARATOR
+ POPUP "Themes"
+ BEGIN
+ MENUITEM "Create New Theme", ID_THEMES_CREATENEWTHEME
+ MENUITEM "Edit a Theme", ID_THEMES_EDIT
+ MENUITEM "Rescan", ID_THEMES_RESCAN
+ MENUITEM SEPARATOR
+ END
+ END
+ POPUP "Plugins"
+ BEGIN
+ MENUITEM "Rescan", ID_PLUGINS_RESCAN
+ MENUITEM SEPARATOR
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About ...", IDM_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_COLUMNMODE ACCELERATORS
+BEGIN
+ "C", ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
+ "X", ID_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT
+ VK_DELETE, ID_EDIT_DELETE, VIRTKEY, CONTROL, NOINVERT
+ "F", ID_EDIT_FIND, VIRTKEY, CONTROL, NOINVERT
+ "V", ID_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
+ "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT
+ "N", ID_FILE_NEW, VIRTKEY, CONTROL, NOINVERT
+ "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
+ "P", ID_FILE_PRINT, VIRTKEY, CONTROL, NOINVERT
+ VK_F5, ID_FILE_REFRESH, VIRTKEY, NOINVERT
+ "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT
+ "S", ID_FILE_SAVEAS, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ "/", IDM_ABOUT, ASCII, ALT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About ColumnMode"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ ICON IDR_MAINFRAME,IDC_STATIC,14,14,21,20
+ LTEXT "ColumnMode, Version 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX
+ LTEXT "Copyright (C) 2019",IDC_STATIC,42,26,114,8
+ DEFPUSHBUTTON "OK",IDOK,113,41,50,14,WS_GROUP
+END
+
+IDD_DOCUMENTPROPERTIES DIALOGEX 0, 0, 179, 78
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Document Properties"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,64,56,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,122,56,50,14
+ LTEXT "Line Count:",IDC_STATIC,7,9,38,8
+ EDITTEXT IDC_LINECOUNT_EDITBOX,66,7,55,14,ES_AUTOHSCROLL
+ LTEXT "Column Count:",IDC_STATIC,7,30,48,8
+ EDITTEXT IDC_COLUMNCOUNT_EDITBOX,66,27,55,14,ES_AUTOHSCROLL
+END
+
+IDD_FIND_DIALOG DIALOGEX 0, 0, 179, 53
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Find"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Next",ID_NEXT,64,28,50,14
+ PUSHBUTTON "Previous",ID_PREVIOUS,122,28,50,14
+ LTEXT "Search Text:",-1,7,9,45,8
+ EDITTEXT IDC_FIND_EDITBOX,66,7,106,14,ES_AUTOHSCROLL
+END
+
+IDD_THEMENAMEQUERY DIALOGEX 0, 0, 179, 53
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Create New Theme"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "OK",IDOK,64,28,50,14
+ PUSHBUTTON "CANCEL",IDCANCEL,122,28,50,14
+ LTEXT "Theme Name:",-1,7,9,45,8
+ EDITTEXT IDC_THEMENAME_EDITBOX,66,7,106,14,ES_AUTOHSCROLL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_ABOUTBOX, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 163
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 55
+ END
+
+ IDD_DOCUMENTPROPERTIES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 172
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 71
+ END
+
+ IDD_FIND_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 172
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 46
+ END
+
+ IDD_THEMENAMEQUERY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 172
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 46
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#ifndef APSTUDIO_INVOKED\r\n"
+ "#include ""targetver.h""\r\n"
+ "#endif\r\n"
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_APP_TITLE "ColumnMode"
+ IDC_COLUMNMODE "COLUMNMODE"
+END
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/ColumnMode/ColumnMode.vcxproj b/ColumnMode/ColumnMode.vcxproj
index 4f3131e..cb15e28 100644
--- a/ColumnMode/ColumnMode.vcxproj
+++ b/ColumnMode/ColumnMode.vcxproj
@@ -23,33 +23,33 @@
{6546B3A0-08BA-43DD-A450-B2DE1262820A}
Win32Proj
ColumnMode
- 10.0.17134.0
+ 10.0
ColumnMode
Application
true
- v141
+ v143
Unicode
Application
false
- v141
+ v143
true
Unicode
Application
true
- v141
+ v143
Unicode
Application
false
- v141
+ v143
true
Unicode
@@ -143,6 +143,7 @@
true
NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
true
+ stdcpp17
Windows
diff --git a/ColumnMode/ColumnModePluginApi.h b/ColumnMode/ColumnModePluginApi.h
index fa0c838..635eb26 100644
--- a/ColumnMode/ColumnModePluginApi.h
+++ b/ColumnMode/ColumnModePluginApi.h
@@ -4,7 +4,7 @@
namespace ColumnMode
{
- constexpr UINT c_ColumnModePluginApiVersion = 1;
+ constexpr UINT c_ColumnModePluginApiVersion = 2;
#pragma region ColumnModeCallbacks
@@ -32,6 +32,7 @@ namespace ColumnMode
typedef HRESULT(APIENTRY* PFN_PF_ONOPEN)(HANDLE, LPCWSTR);
typedef HRESULT(APIENTRY* PFN_PF_ONSAVE)(HANDLE, LPCWSTR);
typedef HRESULT(APIENTRY* PFN_PF_ONSAVEAS)(HANDLE, LPCWSTR);
+ typedef HRESULT(APIENTRY* PFN_PF_ONTYPINGCOMPLETE)(HANDLE, const size_t numChars, const WCHAR* pAllText);
//Plugin Life cycle
typedef HRESULT(APIENTRY* PFN_PF_ONLOADCOMPLETED)(HANDLE); //Called after OpenColumnModePlugin
@@ -45,10 +46,19 @@ namespace ColumnMode
PFN_PF_ONLOADCOMPLETED pfnOnLoadCompleted;
PFN_PF_ONSHUTDOWN pfnOnShutdown;
+
+ // API version >= 2
+ PFN_PF_ONTYPINGCOMPLETE pfnOnTypingComplete;
};
#pragma endregion
+ struct PluginDependency
+ {
+ UINT length; // number of WCHARs in pName
+ WCHAR* pName;
+ };
+
struct OpenPluginArgs
{
_In_ UINT apiVersion;
@@ -58,6 +68,20 @@ namespace ColumnMode
};
}
+/*
+Safe to not export if your plugin doesn't have run-time dll dependencies.
+Called in the following pattern:
+1. pCount is a valid pointer to any UINT and pDependencies is nullptr. - Plugin should set pCount to the number of dependencies.
+2. pCount is a valid pointer, pDependencies is a valid pointer, each dependency's pName is nullptr. - Plugin should validate pCount is the right size, then populate the length fields of each dependency struct.
+3. pCount is a valid pointer, pDependencies is a valid pointer, each dependency's pName is a valid pointer - Plugin should validate pCount, then foreach dependency: validate the length and then write the dependency name to the buffer (including extension).
+
+Return value from each step should be S_OK if everything is valid and fields are being written as expected. If pCount or a length value is wrong, return E_INVALIDARG. Else, return E_FAIL.
+
+Note that depenency dlls should be in the same directory as your plugin: %APPDATA%/ColumnMode/Plugins/your_plugin_name/
+*/
+extern "C" HRESULT WINAPI QueryColumnModePluginDependencies(_Inout_ UINT* pCount, _Inout_opt_count_(*pCount) ColumnMode::PluginDependency* pDependencies);
+typedef HRESULT(WINAPI* PFN_QUERYCOLUMNMODEPLUGINDEPENDENCIES)(_Inout_ UINT* pCount, _Inout_opt_count_(*pCount) ColumnMode::PluginDependency* pDependencies);
+// Required export
extern "C" HRESULT WINAPI OpenColumnModePlugin(_Inout_ ColumnMode::OpenPluginArgs* args);
typedef HRESULT(WINAPI* PFN_OPENCOLUMNMODEPLUGIN)(_Inout_ ColumnMode::OpenPluginArgs* args);
\ No newline at end of file
diff --git a/ColumnMode/Main.cpp b/ColumnMode/Main.cpp
index f1db5c4..f4be5a1 100644
--- a/ColumnMode/Main.cpp
+++ b/ColumnMode/Main.cpp
@@ -114,7 +114,7 @@ void MyRegisterClass(HINSTANCE hInstance)
}
{
// Document window
- WNDCLASSEXW wcex;
+ WNDCLASSEXW wcex {};
wcex.cbSize = sizeof(WNDCLASSEX);
@@ -316,6 +316,9 @@ LRESULT CALLBACK TopLevelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
case ID_THEMES_CREATENEWTHEME:
OnCreateTheme(hWnd, hInst);
break;
+ case ID_THEMES_EDIT:
+ OnEditTheme(hWnd, hInst);
+ break;
case ID_FILE_REFRESH:
OnRefresh(g_windowHandles);
break;
diff --git a/ColumnMode/PluginManager.cpp b/ColumnMode/PluginManager.cpp
index 61daaff..0c39e12 100644
--- a/ColumnMode/PluginManager.cpp
+++ b/ColumnMode/PluginManager.cpp
@@ -59,25 +59,124 @@ HRESULT ColumnMode::PluginManager::ScanForPlugins()
return S_OK;
}
+HRESULT LoadLibraryHelper(std::filesystem::path path, HMODULE& out_pluginModule)
+{
+ DWORD flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
+ out_pluginModule = LoadLibraryEx(path.c_str(), NULL, flags);
+ if (out_pluginModule == NULL)
+ {
+ DWORD err = GetLastError();
+ WCHAR buff[1024];
+ std::swprintf(buff, 1024, _T("Plugin not found or DLL failed to load.\nError code: %d\nPath: %s"), err, path.c_str());
+ MessageBox(NULL, buff, L"Error loading plugin DLL", MB_OK | MB_ICONERROR);
+
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+HRESULT LoadPluginDependenciesHelper(PFN_QUERYCOLUMNMODEPLUGINDEPENDENCIES pfnQueryDeps, std::filesystem::path pluginDir, HMODULE pluginModule)
+{
+ UINT numDeps = 0;
+ std::wstring pluginName = pluginDir.filename(); //plugin name is the last part of the pluginDir
+
+ //query num dependencies and create dependency list
+ HRESULT hr = pfnQueryDeps(&numDeps, nullptr);
+ if(FAILED(hr))
+ {
+ MessageBoxHelper_FormattedBody(MB_ICONERROR | MB_OK, L"Failed to get dependencies", L"%s returned failure code %d when calling QueryColumnModePluginDependencies (1st call).", pluginName, hr);
+ return hr;
+ }
+ ColumnMode::PluginDependency defaultInit{ 0, nullptr };
+ std::vector deps = std::vector(numDeps, defaultInit);
+
+ // query sizes of dependency names and allocate space
+ hr = pfnQueryDeps(&numDeps, deps.data());
+ if (FAILED(hr))
+ {
+ MessageBoxHelper_FormattedBody(MB_ICONERROR | MB_OK, L"Failed to get dependencies", L"%s returned failure code %d when calling QueryColumnModePluginDependencies (2nd call).", pluginName, hr);
+ return hr;
+ }
+ for (auto depIt = deps.begin(); depIt != deps.end(); depIt++)
+ {
+ depIt->pName = (WCHAR*)malloc((depIt->length +1) * sizeof(WCHAR)); //add one extra char of padding so that we can ensure null-terminated
+ if (depIt->pName == nullptr)
+ {
+ hr = E_OUTOFMEMORY;
+ goto cleanup_and_exit;
+ }
+ }
+
+ // query dependency names
+ hr = pfnQueryDeps(&numDeps, deps.data());
+ if (FAILED(hr))
+ {
+ MessageBoxHelper_FormattedBody(MB_ICONERROR | MB_OK, L"Failed to get dependencies", L"%s returned failure code %d when calling QueryColumnModePluginDependencies (3rd call).", pluginName, hr);
+ goto cleanup_and_exit;
+ }
+
+ //Now we need to free the plugin library in case it has a load time library that does weird checks for runtime dependencies in dllmain (looking at you dxcompiler.dll)
+ FreeLibrary(pluginModule);
+ //Finally load the requested libraries
+ for (auto depIt = deps.begin(); depIt != deps.end(); depIt++)
+ {
+ depIt->pName[depIt->length] = L'\0'; //ensure null-terminated
+ std::filesystem::path depFullPath = pluginDir / depIt->pName;
+ HMODULE hm;
+ if (FAILED(LoadLibraryHelper(depFullPath, hm)))
+ {
+ hr = E_FAIL;
+ goto cleanup_and_exit;
+ //maybe unload dlls?
+ }
+ }
+
+ cleanup_and_exit:
+ // free allocated strings
+ for (auto depIt = deps.begin(); depIt != deps.end(); depIt++)
+ {
+ if (depIt->pName != nullptr)
+ {
+ free(depIt->pName);
+ depIt->pName = nullptr;
+ }
+ }
+ return hr;
+}
+
HRESULT ColumnMode::PluginManager::LoadPlugin(LPCWSTR pluginName)
{
std::filesystem::path path(m_modulesRootPath);
- path.append(pluginName) //Plugins should be in a folder of the plugin name
- .append(pluginName) //Plugin is a DLL file of the plugin name
+ path.append(pluginName) //Plugins should be in a folder of the plugin name
+ .append(pluginName) //Plugin is a DLL file of the plugin name
.replace_extension(L".dll");
- HMODULE pluginModule = LoadLibrary(path.c_str());
- if (pluginModule == NULL)
+
+
+ HMODULE pluginModule;
+ BAIL_ON_FAIL_HR(LoadLibraryHelper(path, pluginModule));
+
+ PFN_QUERYCOLUMNMODEPLUGINDEPENDENCIES pfnQueryDeps =
+ reinterpret_cast(GetProcAddress(pluginModule, "QueryColumnModePluginDependencies"));
+
+ if (pfnQueryDeps != nullptr)
{
- MessageBox(NULL, path.c_str(), L"Plugin Not Found", MB_OK | MB_ICONERROR);
- return E_INVALIDARG;
+ BAIL_ON_FAIL_HR(LoadPluginDependenciesHelper(pfnQueryDeps, m_modulesRootPath / pluginName, pluginModule));
}
+ BAIL_ON_FAIL_HR(LoadLibraryHelper(path, pluginModule));
PFN_OPENCOLUMNMODEPLUGIN pfnOpenPlugin =
reinterpret_cast(GetProcAddress(pluginModule, "OpenColumnModePlugin"));
- PluginFunctions pluginFuncs = { 0 };
- OpenPluginArgs args;
+ if (pfnOpenPlugin == nullptr)
+ {
+ MessageBoxHelper_FormattedBody(MB_ICONERROR | MB_OK, L"Failed to open plugin", L"%s doesn't export the OpenColumnModePlugin function.", pluginName);
+ return E_FAIL;
+ }
+
+ PluginFunctions pluginFuncs{};
+ ZeroMemory(&pluginFuncs, sizeof(pluginFuncs));
+ OpenPluginArgs args{};
args.apiVersion = c_ColumnModePluginApiVersion;
args.hPlugin = NULL;
args.pPluginFuncs = &pluginFuncs;
diff --git a/ColumnMode/PluginManagerFunctions.inl b/ColumnMode/PluginManagerFunctions.inl
index e593507..e86bf2c 100644
--- a/ColumnMode/PluginManagerFunctions.inl
+++ b/ColumnMode/PluginManagerFunctions.inl
@@ -21,6 +21,7 @@
DECLARE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnOpen, (LPCWSTR))
DECLARE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnSave, (LPCWSTR))
DECLARE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnSaveAs, (LPCWSTR))
+DECLARE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnTypingComplete, (const size_t, const WCHAR*))
#undef DECLARE_PLUGINMANAGER_FUNCTION_CALL_ALL
@@ -39,6 +40,7 @@ DECLARE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnSaveAs, (LPCWSTR))
DEFINE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnOpen, (LPCWSTR fileName), (p.m_hPlugin, fileName))
DEFINE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnSave, (LPCWSTR fileName), (p.m_hPlugin, fileName))
DEFINE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnSaveAs, (LPCWSTR fileName), (p.m_hPlugin, fileName))
+DEFINE_PLUGINMANAGER_FUNCTION_CALL_ALL(OnTypingComplete, (const size_t numChars, const WCHAR* pAllText), (p.m_hPlugin, numChars, pAllText))
#undef DEFINE_PLUGINMANAGER_FUNCTION_CALL_ALL
diff --git a/ColumnMode/Program.cpp b/ColumnMode/Program.cpp
index ff17fa4..0c487c8 100644
--- a/ColumnMode/Program.cpp
+++ b/ColumnMode/Program.cpp
@@ -1,4 +1,6 @@
#include "stdafx.h"
+#include
+
#include "Program.h"
#include "Resource.h"
#include "Verify.h"
@@ -110,6 +112,7 @@ class Status
int m_caretRow;
int m_caretColumn;
Mode m_mode;
+ std::optional m_warning;
void RefreshStatusBar(HWND statusBarLabelHwnd)
{
@@ -118,6 +121,11 @@ class Status
label << L"Row: " << (m_caretRow + 1) << " Col: " << (m_caretColumn + 1);
label << L" Mode: " << (m_mode == Mode::TextMode ? L"Text" : L"Diagram");
+ if (m_warning.has_value())
+ {
+ label << L" WARNING: " << m_warning.value();
+ }
+
Static_SetText(statusBarLabelHwnd, label.str().c_str());
}
@@ -147,6 +155,21 @@ class Status
return m_mode;
}
+ void SetWarning(std::wstring str, HWND statusBarLabelHwnd)
+ {
+ m_warning = str;
+ RefreshStatusBar(statusBarLabelHwnd);
+ }
+
+ void ClearWarning(std::wstring str, HWND statusBarLabelHwnd)
+ {
+ if (m_warning.has_value() && m_warning.value() == str)
+ {
+ m_warning.reset();
+ }
+ RefreshStatusBar(statusBarLabelHwnd);
+ }
+
} g_status;
bool g_isDragging;
@@ -169,6 +192,7 @@ DWRITE_HIT_TEST_METRICS g_caretMetrics;
int g_caretBlinkState;
int g_updatesSinceLastEdit;
+bool g_editMadeSinceLastConfirmationOfEdits = false;
const int g_numUpdatesWithoutEditBeforeConfirmingEdits = 50;
std::wstring g_allText;
@@ -733,7 +757,7 @@ void InitGraphics(WindowHandles windowHandles)
g_isTrackingLeaveClientArea = false;
g_hasTextSelectionRectangle = false;
g_caretBlinkState = 0;
- g_updatesSinceLastEdit = 0;
+ g_updatesSinceLastEdit = g_numUpdatesWithoutEditBeforeConfirmingEdits+1; //init to more than the confirmation value so we don't prematurely confirm
g_isShiftDown = false;
g_hasUnsavedChanges = false;
g_needsDeviceRecreation = false;
@@ -1590,12 +1614,11 @@ void OnKeyDown(WindowHandles windowHandles, WPARAM wParam)
return;
g_caretBlinkState = 0;
- g_updatesSinceLastEdit = 0;
CheckModifierKeys(); // modifiers could be pressed when a message went to a different handler
if (g_keyOutput[wParam].Valid)
{
DisableTextSelectionRectangle(windowHandles);
-
+ g_updatesSinceLastEdit = 0; // only register newly typed characters for calling ConfirmEdits
wchar_t chr = g_isShiftDown ? g_keyOutput[wParam].Uppercase : g_keyOutput[wParam].Lowercase;
if (g_status.GetMode() == Mode::DiagramMode)
@@ -1892,6 +1915,7 @@ void ConfirmEdits()
{
g_themeManager.LoadThemeFromText(g_allText, g_theme);
}
+ g_pluginManager.PF_OnTypingComplete_ALL(g_allText.length(), g_allText.c_str());
}
void Update()
@@ -1993,6 +2017,17 @@ void OpenImpl(WindowHandles windowHandles, LPCWSTR fileName)
EnableMenuItem(windowHandles, ID_FILE_REFRESH);
EnableMenuItem(windowHandles, ID_FILE_SAVE);
g_pluginManager.PF_OnOpen_ALL(fileName);
+
+ std::filesystem::path path = fileName;
+ if (path.extension() == L".cmt")
+ {
+ if (!g_themeManager.LoadTheme(path.filename(), g_theme, false))
+ {
+ WCHAR buff[256];
+ std::swprintf(buff, 256, L"There was an error loading the theme.\nWhen you have fixed the issue, CTRL+S and then select it as the active theme from Options > Themes > %s.", path.filename().replace_extension(L"").c_str());
+ MessageBox(NULL, buff, fileName, MB_OK);
+ }
+ }
}
void OnOpen(WindowHandles windowHandles)
@@ -2031,12 +2066,6 @@ void OnOpen(WindowHandles windowHandles)
if (!!GetOpenFileName(&ofn))
{
OpenImpl(windowHandles, ofn.lpstrFile);
- std::filesystem::path path = ofn.lpstrFile;
- if (path.extension() == L".cmt") {
- if (!g_themeManager.LoadTheme(path.filename(), g_theme, false)) {
- MessageBox(NULL, L"There was an error loading the theme.", ofn.lpstrFile, MB_OK);
- }
- }
}
}
@@ -2940,6 +2969,37 @@ void OnCreateTheme(HWND hwnd, HINSTANCE hInst)
DialogBox(hInst, MAKEINTRESOURCE(IDD_THEMENAMEQUERY), hwnd, ThemeNameQueryCallback);
}
+void OnEditTheme(HWND hwnd, HINSTANCE hInst)
+{
+ std::filesystem::path currentThemePath = g_themeManager.GetThemeFilepath(g_theme);
+
+ OPENFILENAME ofn; // common dialog box structure
+ wchar_t szFile[MAX_PATH];
+
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = g_windowManager.GetWindowHandles().TopLevel;
+ ofn.lpstrFile = szFile;
+
+ // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
+ // use the contents of szFile to initialize itself.
+ ofn.lpstrFile[0] = L'\0';
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFilter = L"*.cmt\0";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = currentThemePath.parent_path().c_str();
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+
+ // Display the Open dialog box.
+
+ if (!!GetOpenFileName(&ofn))
+ {
+ OpenImpl(g_windowManager.GetWindowHandles(), ofn.lpstrFile);
+ }
+}
+
bool OnMaybeDynamicMenuItemSelected(WindowHandles windowHandles, int id)
{
static_assert(ColumnMode::ThemeManager::THEME_MENU_ITEM_START_INDEX > ColumnMode::PluginManager::PLUGIN_MENU_ITEM_START_INDEX);
@@ -3004,7 +3064,17 @@ bool OnMaybeThemeSelected(WindowHandles windowHandles, int id)
int size = GetMenuString(themesMenu, id, buff, 64, MF_BYCOMMAND);
if (size > 0 && g_theme.GetName().compare(buff) != 0)
{
- g_themeManager.LoadTheme(buff, g_theme);
+ if (!g_themeManager.LoadTheme(buff, g_theme))
+ {
+ int dialogResult = MessageBox(NULL, L"There was an error loading the theme.\nOpen it for editing and try to fix the issue?", buff, MB_ICONERROR | MB_YESNO);
+ if (dialogResult == IDYES)
+ {
+ ColumnMode::Theme temp{};
+ temp.SetName(buff);
+ std::wstring path = g_themeManager.GetThemeFilepath(temp);
+ OpenImpl(g_windowManager.GetWindowHandles(), path.c_str());
+ }
+ }
OnThemesRescan(windowHandles, true); // Handle the check marking-ing in probably the worst way
}
return true;
@@ -3306,4 +3376,14 @@ std::wstring& GetAllText()
ColumnMode::FindTool& GetFindTool()
{
return g_findTool;
+}
+
+void SetWarningMessage(std::wstring str)
+{
+ g_status.SetWarning(str, g_windowManager.GetWindowHandles().StatusBarLabel);
+}
+
+void ClearWarningMssage(std::wstring str)
+{
+ g_status.ClearWarning(str, g_windowManager.GetWindowHandles().StatusBarLabel);
}
\ No newline at end of file
diff --git a/ColumnMode/Program.h b/ColumnMode/Program.h
index 3c6ab50..20576ef 100644
--- a/ColumnMode/Program.h
+++ b/ColumnMode/Program.h
@@ -43,6 +43,7 @@ void OnPrint(WindowHandles windowHandles);
void OnPluginRescan(WindowHandles windowHandles, bool skipRescan=false);
void OnThemesRescan(WindowHandles windowHandles, bool skipRescan = false);
void OnCreateTheme(HWND hwnd, HINSTANCE hInst);
+void OnEditTheme(HWND hwnd, HINSTANCE hInst);
bool OnMaybeDynamicMenuItemSelected(WindowHandles windowHandles, int id);
void OnDiagramMode(WindowHandles windowHandles);
void OnTextMode(WindowHandles windowHandles);
@@ -83,4 +84,6 @@ enum class ScrollToStyle
};
void ScrollTo(UINT index, ScrollToStyle scrollStyle = ScrollToStyle::CENTER);
-ColumnMode::FindTool& GetFindTool();
\ No newline at end of file
+ColumnMode::FindTool& GetFindTool();
+void SetWarningMessage(std::wstring str);
+void ClearWarningMssage(std::wstring str);
\ No newline at end of file
diff --git a/ColumnMode/Resource.h b/ColumnMode/Resource.h
index 2c18743..72c29ce 100644
Binary files a/ColumnMode/Resource.h and b/ColumnMode/Resource.h differ
diff --git a/ColumnMode/Theme.cpp b/ColumnMode/Theme.cpp
index 7cc1c02..d8756cd 100644
--- a/ColumnMode/Theme.cpp
+++ b/ColumnMode/Theme.cpp
@@ -1,5 +1,7 @@
#include "stdafx.h"
#include "../External/json.hpp"
+
+#include "Program.h"
#include "Theme.h"
#include "Verify.h"
#include "utf8Conversion.h"
@@ -185,10 +187,18 @@ bool ColumnMode::ThemeManager::LoadThemeFromText(std::wstring jsonString, Theme&
{
json data = json::parse(jsonString);
out = data;
+ themeTextInvalidOnLastLoadFromText = false;
+ ClearWarningMssage(L"Theme JSON invalid!");
return true;
}
catch (...)
{
+ if (!themeTextInvalidOnLastLoadFromText)
+ {
+ MessageBox(NULL, L"Your latest change broke the theme.\nEnsure that your JSON is well formatted and color values are valid floats.", L"Error parsing Theme", MB_ICONERROR | MB_OK);
+ }
+ themeTextInvalidOnLastLoadFromText = true;
+ SetWarningMessage(L"Theme JSON invalid!");
return false;
}
return false;
diff --git a/ColumnMode/Theme.h b/ColumnMode/Theme.h
index 9ed6505..e9bc2a7 100644
--- a/ColumnMode/Theme.h
+++ b/ColumnMode/Theme.h
@@ -78,6 +78,7 @@ namespace ColumnMode
private:
std::filesystem::path m_themesRootPath;
std::vector m_availableThemes;
+ bool themeTextInvalidOnLastLoadFromText = false;
public:
static const int THEME_MENU_ITEM_START_INDEX = 5000;//chosen arbitrarily. hopefully the resource generator doesn't conflict
diff --git a/ColumnMode/Verify.h b/ColumnMode/Verify.h
index 1c896d8..474776c 100644
--- a/ColumnMode/Verify.h
+++ b/ColumnMode/Verify.h
@@ -6,6 +6,8 @@ void inline VerifyHR(HRESULT hr)
__debugbreak();
}
+#define BAIL_ON_FAIL_HR(hrFunc) {HRESULT hr = hrFunc; if(FAILED(hr)) { return hr;}}
+
void inline VerifyBool(BOOL b)
{
if (!b)
diff --git a/ColumnMode/stdafx.h b/ColumnMode/stdafx.h
index 344b9ac..2f18b10 100644
Binary files a/ColumnMode/stdafx.h and b/ColumnMode/stdafx.h differ
diff --git a/Images/themes_UI_annotation.png b/Images/themes_UI_annotation.png
new file mode 100644
index 0000000..f496aac
Binary files /dev/null and b/Images/themes_UI_annotation.png differ
diff --git a/Manual/Themes.md b/Manual/Themes.md
new file mode 100644
index 0000000..7f5b0a8
--- /dev/null
+++ b/Manual/Themes.md
@@ -0,0 +1,29 @@
+# Themes
+Themes allow you to style ColumnMode's color pallet to suit your taste / usage.
+You can find the Themes installed on your system at `%APPDATA%/ColumnMode/Themes` (extension is `.cmt`).
+`.cmt` files are a JSON format pairing colors to theme Ids.
+Opening a `.cmt` file in ColumnMode will allow you to preview your changes in realtime (though some fields are not used by the editor when viewing `.cmt` files. Eventually this may be addressed by a more full-featured theme editor).
+
+You can create a new Theme by going to Options > Themes > Create New Theme.
+Your new theme will be based on the default theme: ColumnModeClassic.
+
+## Theme Ids
+You can think of a theme as a pallet of colors that can be picked from by the Column Mode editor for different uses.
+
+### `UI_`* Theme Ids
+
+
+1. `UI_BACKGROUND`: The empty region of the window that can't be edited.
+1. `UI_PAPER`: The region available for editing.
+1. `UI_PAPER_BORDER`
+1. `UI_MARGIN`
+1. `UI_CURRENT_LINE_HIGHLIGHT`: A color that should be different from `UI_PAPER` to indicate the line bing edited.
+1. `UI_CARET`: The flashing indicator for the character you are about to edit.
+1. `UI_DRAG_RECT`: The solid line that shows the exact selection rectangle you are dragging out.
+1. `UI_SELECTION`: The shaded region of your selection.
+1. `UI_SELECTION_BORDER`: The "marching ants" on the ourside of the effective selection rectangle.
+
+### `TEXT_`* Theme Ids
+Most of these aren't used yet.
+For now just edit `TEXT_DEFAULT` to set the color of the text.
+Other `TEXT_`* colors will be used in the future when plugins are able to handle text colorization.
\ No newline at end of file
diff --git a/README.md b/README.md
index ee2fd2a..7dd36ea 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,8 @@ ColumnMode is a lightweight, column-based text editor.
* Supports copying and pasting
* Supports undo
* Supports print
+* Supports extension via plugins
+* Supports [Themes](Manual/Themes.md) to change the look and feel


diff --git a/SamplePlugin/SamplePlugin.vcxproj b/SamplePlugin/SamplePlugin.vcxproj
index 7c332dd..65fb020 100644
--- a/SamplePlugin/SamplePlugin.vcxproj
+++ b/SamplePlugin/SamplePlugin.vcxproj
@@ -1,178 +1,178 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
- 16.0
- Win32Proj
- {c544b2fb-d327-4011-87b4-f184470bc716}
- SamplePlugin
- 10.0
-
-
-
- DynamicLibrary
- true
- v142
- Unicode
-
-
- DynamicLibrary
- false
- v142
- true
- Unicode
-
-
- DynamicLibrary
- true
- v142
- Unicode
-
-
- DynamicLibrary
- false
- v142
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
- false
-
-
- true
-
-
- false
-
-
-
- Level3
- true
- WIN32;_DEBUG;SAMPLEPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- false
- SamplePlugin.def
-
-
-
-
- Level3
- true
- true
- true
- WIN32;NDEBUG;SAMPLEPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- true
- true
- false
- SamplePlugin.def
-
-
-
-
- Level3
- true
- _DEBUG;SAMPLEPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- false
- SamplePlugin.def
-
-
-
-
- Level3
- true
- true
- true
- NDEBUG;SAMPLEPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- true
- true
- false
- SamplePlugin.def
-
-
-
-
-
-
-
-
-
-
-
- Create
- Create
- Create
- Create
-
-
-
-
-
-
-
-
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {c544b2fb-d327-4011-87b4-f184470bc716}
+ SamplePlugin
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;SAMPLEPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ false
+ SamplePlugin.def
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;SAMPLEPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ true
+ true
+ false
+ SamplePlugin.def
+
+
+
+
+ Level3
+ true
+ _DEBUG;SAMPLEPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ false
+ SamplePlugin.def
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;SAMPLEPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ true
+ true
+ false
+ SamplePlugin.def
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+
+
\ No newline at end of file