Notepad3/src/Notepad3.c

13076 lines
443 KiB
C

// encoding: UTF-8
/******************************************************************************
* *
* *
* Notepad3 *
* *
* Notepad3.c *
* Main application window functionality *
* Based on code from Notepad2, (c) Florian Balmer 1996-2011 *
* *
* (c) Rizonesoft 2008-2024 *
* https://rizonesoft.com *
* *
* *
*******************************************************************************/
#include "Helpers.h"
#if (defined(_DEBUG) || defined(DEBUG)) && !defined(NDEBUG)
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif
#include <commctrl.h>
#include <uxtheme.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <shellapi.h>
#include <commdlg.h>
#include <stdio.h>
#include <string.h>
#include <process.h>
#include <vsstyle.h>
//#include <ShellScalingApi.h>
#include "PathLib.h"
#include "Edit.h"
#include "Styles.h"
#include "Dialogs.h"
#include "crypto/crypto.h"
#include "uthash/utarray.h"
#include "uthash/utlist.h"
#include "tinyexpr/tinyexpr.h"
//#include "tinyexprcpp/tinyexpr_cif.h"
#include "Encoding.h"
#include "VersionEx.h"
#include "MuiLanguage.h"
#include "Notepad3.h"
#include "Config/Config.h"
#include "DarkMode/DarkMode.h"
#include "StyleLexers/EditLexer.h"
#if (defined(_DEBUG) || defined(DEBUG)) && !defined(NDEBUG)
#if defined(WIN32) && !defined(_WIN64)
#pragma comment(linker, "/defaultlib:clang_rt.asan-i386.lib")
#endif // _WIN64
#endif // DEBUG
// ============================================================================
//
// Local and global Variables for Notepad3.c
//
// ============================================================================
LPCWSTR WordBookMarks[MARKER_NP3_BOOKMARK] = {
/*0*/ L"back:#0000", // OCC MARKER
/*1*/ L"back:#FF0000",
/*2*/ L"back:#00FF00",
/*3*/ L"back:#0000FF",
/*4*/ L"back:#FF8000",
/*5*/ L"back:#0080FF",
/*6*/ L"back:#FF00FF",
/*7*/ L"back:#408040",
/*8*/ L"back:#C080C0"
};
#define RELAUNCH_ELEVATED_BUF_ARG L"tmpfbuf="
CONSTANTS_T const Constants = {
2 // StdDefaultLexerID
, L"minipath.exe" // FileBrowserMiniPath
, L"grepWinNP3.exe" // FileSearchGrepWin
, L"Settings" // Inifile Section "Settings"
, L"Settings2" // Inifile Section "Settings2"
, L"Window" // Inifile Section "Window"
, L"Styles" // Inifile Section "Styles"
, L"Suppressed Messages" // Inifile Section "SuppressedMessages"
};
FLAGS_T Flags = { 0 };
FLAGS_T DefaultFlags = { 0 };
GLOBALS_T Globals = { 0 };
SETTINGS_T Settings = { 0 };
SETTINGS_T Defaults = { 0 };
SETTINGS2_T Settings2 = { 0 };
PATHS_T Paths = { 0 };
FOCUSEDVIEW_T FocusedView = { 0 };
FILEWATCHING_T FileWatching = { 0 };
// set by InitScintillaHandle()
HWND g_hwndEditWindow = NULL;
HANDLE g_hndlScintilla = NULL;
// window positioning
WININFO g_IniWinInfo = INIT_WININFO;
WININFO g_DefWinInfo = INIT_WININFO;
COLORREF g_colorCustom[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
prefix_t g_mxSBPrefix[STATUS_SECTOR_COUNT] = { L'\0' };
prefix_t g_mxSBPostfix[STATUS_SECTOR_COUNT] = { L'\0' };
int g_flagMatchText = 0;
bool g_iStatusbarVisible[STATUS_SECTOR_COUNT] = SBS_INIT_ZERO;
int g_iStatusbarWidthSpec[STATUS_SECTOR_COUNT] = SBS_INIT_ZERO;
int g_vSBSOrder[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
HPATHL g_tchToolbarBitmap = NULL;
HPATHL g_tchToolbarBitmapHot = NULL;
HPATHL g_tchToolbarBitmapDisabled = NULL;
WCHAR Default_PreferredLanguageLocaleName[LOCALE_NAME_MAX_LENGTH + 1] = { L'\0' };
// ------------------------------------
HPATHL s_hpthRelaunchElevatedFile = NULL;
static bool s_bInitAppDone = false;
static bool s_bIsProcessElevated = false;
static bool s_bIsUserInAdminGroup = false;
static bool s_bIsRunAsAdmin = false;
static bool s_flagSaveOnRelaunch = false;
static bool s_IsThisAnElevatedRelaunch = false;
static WCHAR s_wchWndClass[64] = { L'\0' };
static HWND s_hwndEditFrame = NULL;
static HWND s_hwndNextCBChain = NULL;
static int s_WinCurrentWidth = 0;
#define FILE_LIST_SIZE 32
static LPWSTR s_lpFileList[FILE_LIST_SIZE] = { NULL };
static int s_cFileList = 0;
static int s_cchiFileList = 0;
static int s_iSortOptions = 0;
static int s_iAlignMode = 0;
static bool s_bIsAppThemed = true;
static UINT s_msgTaskbarCreated = 0;
static WCHAR s_wchTitleExcerpt[MIDSZ_BUFFER] = { L'\0' };
static LONG64 s_iLastCopyTime = 0;
static bool s_bLastCopyFromMe = false;
static bool s_bInMultiEditMode = false;
static bool s_bCallTipEscDisabled = false;
static int s_iInitialLine = 0;
static int s_iInitialColumn = 0;
static int s_iInitialLexer = 0;
static int s_cyReBar = 0;
static int s_cyReBarFrame = 0;
static int s_cxEditFrame = 0;
static int s_cyEditFrame = 0;
static bool s_bUndoRedoScroll = false;
// for tiny expression calculation
static double s_dExpression = 0.0;
static te_int_t s_iExprError = -1;
static char* s_SelectionBuffer = NULL;
//~static CONST WCHAR *const s_ToolbarWndClassName = L"NP3_TOOLBAR_CLASS";
static int const INISECTIONBUFCNT = 32; // .ini file load buffer in KB
// ----------------------------------------------------------------------------
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// (!) ENSURE IDT_FILE_NEW -> IDT_VIEW_NEW_WINDOW corresponds to order of Toolbar.bmp
#define NUMTOOLBITMAPS (31)
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
static TBBUTTON s_tbbMainWnd[] = {
{ 0, IDT_FILE_NEW, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 31, IDT_VIEW_NEW_WINDOW, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 1, IDT_FILE_OPEN, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 3, IDT_FILE_SAVE, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 2, IDT_FILE_BROWSE, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 27, IDT_FILE_RECENT, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 4, IDT_EDIT_UNDO, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 5, IDT_EDIT_REDO, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 6, IDT_EDIT_CUT, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 7, IDT_EDIT_COPY, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 8, IDT_EDIT_PASTE, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 9, IDT_EDIT_FIND, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 10, IDT_EDIT_REPLACE, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 29, IDT_GREP_WIN_TOOL, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 11, IDT_VIEW_WORDWRAP, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 23, IDT_VIEW_TOGGLEFOLDS, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 25, IDT_VIEW_TOGGLE_VIEW, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 21, IDT_FILE_OPENFAV, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 22, IDT_FILE_ADDTOFAV, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 12, IDT_VIEW_ZOOMIN, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 30, IDT_VIEW_RESETZOOM, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 13, IDT_VIEW_ZOOMOUT, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 14, IDT_VIEW_SCHEME, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 24, IDT_FILE_LAUNCH, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 28, IDT_VIEW_PIN_ON_TOP, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 16, IDT_FILE_EXIT, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
{ 15, IDT_VIEW_SCHEMECONFIG, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 17, IDT_FILE_SAVEAS, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 18, IDT_FILE_SAVECOPY, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 19, IDT_EDIT_CLEAR, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 20, IDT_FILE_PRINT, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 },
{ 26, IDT_VIEW_CHASING_DOCTAIL, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 }
};
// don't show buttons beyond this TBBUTTON[] index:
#define TBBUTTON_LAST_DEFAULT (39)
WCHAR TBBUTTON_DEFAULT_IDS[256] = { L'\0' }; // filled in _InitGlobals()
const WCHAR* const TBBUTTON_DEFAULT_IDS_OLD = L"1 32 2 4 3 28 0 5 6 0 7 8 9 0 10 11 0 30 0 12 0 24 26 0 22 23 0 13 14 0 27 0 15 0 25 0 17";
// ----------------------------------------------------------------------------
const char chr_currency[6] = { '$', 0x80, 0xA2, 0xA3, 0xA5, '\0' }; // "$€¢£¥" CP-1252
//==============================================================================
//
// Save Needed Flag
//
static bool s_NeedSavingForced = false; // dirty-flag
static inline bool IsSaveNeeded()
{
return SciCall_GetModify() || s_NeedSavingForced;
}
static inline void SetSaveNeeded(const bool bSetFlagForced)
{
AutoSaveStart(!s_NeedSavingForced);
if (bSetFlagForced) {
s_NeedSavingForced = true;
}
if (IsWindow(Globals.hwndDlgFindReplace)) {
PostWMCommand(Globals.hwndDlgFindReplace, IDC_DOC_MODIFIED);
}
UpdateToolbar();
}
static inline void SetSavePoint()
{
SciCall_SetSavePoint();
UpdateToolbar();
}
void SetSaveDone()
{
s_NeedSavingForced = false;
SetSavePoint();
}
//==============================================================================
// current find pattern
static HSTRINGW s_hstrCurrentFindPattern = NULL;
// undo / redo selections
static UT_icd UndoRedoSelElement_icd = { sizeof(DocPos), NULL, NULL, NULL };
static void InitUndoRedoSelection(void* elt)
{
UndoRedoSelection_t* selection = (UndoRedoSelection_t*)elt;
if (selection != NULL) {
selection->selMode_undo = SC_SEL_STREAM;
selection->anchorPos_undo = NULL;
selection->curPos_undo = NULL;
selection->anchorVS_undo = NULL;
selection->curVS_undo = NULL;
selection->selMode_redo = SC_SEL_STREAM;
selection->anchorPos_redo = NULL;
selection->curPos_redo = NULL;
selection->anchorVS_redo = NULL;
selection->curVS_redo = NULL;
}
}
static void DelUndoRedoSelection(void* elt)
{
UndoRedoSelection_t* selection = (UndoRedoSelection_t*)elt;
if (selection != NULL)
{
selection->selMode_undo = SC_SEL_STREAM;
selection->selMode_redo = SC_SEL_STREAM;
if (selection->anchorPos_undo != NULL) {
utarray_free(selection->anchorPos_undo);
selection->anchorPos_undo = NULL;
}
if (selection->curPos_undo != NULL) {
utarray_free(selection->curPos_undo);
selection->curPos_undo = NULL;
}
if (selection->anchorVS_undo != NULL) {
utarray_free(selection->anchorVS_undo);
selection->anchorVS_undo = NULL;
}
if (selection->curVS_undo != NULL) {
utarray_free(selection->curVS_undo);
selection->curVS_undo = NULL;
}
if (selection->anchorPos_redo != NULL) {
utarray_free(selection->anchorPos_redo);
selection->anchorPos_redo = NULL;
}
if (selection->curPos_redo != NULL) {
utarray_free(selection->curPos_redo);
selection->curPos_redo = NULL;
}
if (selection->anchorVS_redo != NULL) {
utarray_free(selection->anchorVS_redo);
selection->anchorVS_redo = NULL;
}
if (selection->curVS_redo != NULL) {
utarray_free(selection->curVS_redo);
selection->curVS_redo = NULL;
}
}
}
static void CopyUndoRedoSelection(void* dst, const void* src)
{
UndoRedoSelection_t* dst_sel = (UndoRedoSelection_t*)dst;
const UndoRedoSelection_t* src_sel = (UndoRedoSelection_t*)src;
DocPos* pPos = NULL;
InitUndoRedoSelection(dst);
dst_sel->selMode_undo = (src_sel) ? src_sel->selMode_undo : SC_SEL_STREAM;
utarray_new(dst_sel->anchorPos_undo, &UndoRedoSelElement_icd);
if (src_sel) {
while ((pPos = (DocPos*)utarray_next(src_sel->anchorPos_undo, pPos)) != NULL) {
utarray_push_back(dst_sel->anchorPos_undo, pPos);
}
}
utarray_new(dst_sel->curPos_undo, &UndoRedoSelElement_icd);
if (src_sel) {
while ((pPos = (DocPos*)utarray_next(src_sel->curPos_undo, pPos)) != NULL) {
utarray_push_back(dst_sel->curPos_undo, pPos);
}
}
utarray_new(dst_sel->anchorVS_undo, &UndoRedoSelElement_icd);
if (src_sel) {
while ((pPos = (DocPos*)utarray_next(src_sel->anchorVS_undo, pPos)) != NULL) {
utarray_push_back(dst_sel->anchorVS_undo, pPos);
}
}
utarray_new(dst_sel->curVS_undo, &UndoRedoSelElement_icd);
if (src_sel) {
while ((pPos = (DocPos*)utarray_next(src_sel->curVS_undo, pPos)) != NULL) {
utarray_push_back(dst_sel->curVS_undo, pPos);
}
}
dst_sel->selMode_redo = (src_sel) ? src_sel->selMode_redo : SC_SEL_STREAM;
utarray_new(dst_sel->anchorPos_redo, &UndoRedoSelElement_icd);
if (src_sel) {
while ((pPos = (DocPos*)utarray_next(src_sel->anchorPos_redo, pPos)) != NULL) {
utarray_push_back(dst_sel->anchorPos_redo, pPos);
}
}
utarray_new(dst_sel->curPos_redo, &UndoRedoSelElement_icd);
if (src_sel) {
while ((pPos = (DocPos*)utarray_next(src_sel->curPos_redo, pPos)) != NULL) {
utarray_push_back(dst_sel->curPos_redo, pPos);
}
}
utarray_new(dst_sel->anchorVS_redo, &UndoRedoSelElement_icd);
if (src_sel) {
while ((pPos = (DocPos*)utarray_next(src_sel->anchorVS_redo, pPos)) != NULL) {
utarray_push_back(dst_sel->anchorVS_redo, pPos);
}
}
utarray_new(dst_sel->curVS_redo, &UndoRedoSelElement_icd);
if (src_sel) {
while ((pPos = (DocPos*)utarray_next(src_sel->curVS_redo, pPos)) != NULL) {
utarray_push_back(dst_sel->curVS_redo, pPos);
}
}
}
static UT_icd UndoRedoSelection_icd = { sizeof(UndoRedoSelection_t), InitUndoRedoSelection, CopyUndoRedoSelection, DelUndoRedoSelection };
static UT_array* UndoRedoSelectionUTArray = NULL;
static void _SaveRedoSelection(const LONG token, const bool bAddAction);
static LONG _SaveUndoSelection();
static LONG _UndoRedoActionMap(const LONG token, const UndoRedoSelection_t** selection);
// => UndoTransActionBegin();
// => EndUndoTransAction();
static volatile int UndoRedoActionStackCount = 0;
__forceinline bool _InUndoRedoTransaction()
{
return (UndoRedoActionStackCount > 0);
}
static inline void _SplitUndoTransaction()
{
if (_InUndoRedoTransaction()) {
SciCall_EndUndoAction();
SciCall_BeginUndoAction();
}
else {
SciCall_BeginUndoAction();
SciCall_EndUndoAction();
}
}
// ----------------------------------------------------------------------------
static void _DelayClearCallTip(const LONG64 delay);
static void _DelaySplitUndoTransaction(const LONG64 delay);
static void _RestoreActionSelection(const LONG token, DoAction doAct);
// ----------------------------------------------------------------------------
#if 0
static HANDLE s_hEvent = INVALID_HANDLE_VALUE;
// SetEvent(s_hEvent);
// ResetEvent(s_hEvent);
static __forceinline bool IsEventSignaled() {
return (WaitForSingleObject(s_hEvent, 0) == WAIT_OBJECT_0);
}
#endif
// ----------------------------------------------------------------------------
__forceinline bool NotifyDocChanged()
{
return ((SciCall_GetModEventMask() & EVM_Default) == EVM_Default);
}
int DisableDocChangeNotification()
{
int const currentMask = SciCall_GetModEventMask();
SciCall_SetModEventMask(EVM_None);
return currentMask;
}
void EnableDocChangeNotification(const int evm)
{
SciCall_SetModEventMask(evm);
if (NotifyDocChanged()) {
EditUpdateVisibleIndicators();
UpdateStatusbar(false);
}
}
//=============================================================================
//
// Delay Message Queue Handling (TODO: MultiThreading)
//
static CmdMessageQueue_t* MessageQueue = NULL;
// ----------------------------------------------------------------------------
static int msgcmp(void* mqc1, void* mqc2)
{
const CmdMessageQueue_t* const pMQC1 = (CmdMessageQueue_t*)mqc1;
const CmdMessageQueue_t* const pMQC2 = (CmdMessageQueue_t*)mqc2;
if ((pMQC1->cmd == pMQC2->cmd)
&& (pMQC1->hwnd == pMQC2->hwnd)
&& (pMQC1->wparam == pMQC2->wparam) // command
&& (pMQC1->lparam == pMQC2->lparam) // true/false
) {
return 0; // equal
}
return 1;
}
//~static int sortcmp(void *mqc1, void *mqc2) {
//~
//~ const CmdMessageQueue_t *const pMQC1 = (CmdMessageQueue_t *)mqc1;
//~ const CmdMessageQueue_t *const pMQC2 = (CmdMessageQueue_t *)mqc2;
//~
//~ return (pMQC1->delay - pMQC2->delay);
//~}
// ----------------------------------------------------------------------------
#define _MQ_TIMER_CYCLE (USER_TIMER_MINIMUM << 1) // 20ms cycle
#define _MQ_IMMEDIATE (USER_TIMER_MINIMUM >> 1)
#define _MQ_FAST (_MQ_TIMER_CYCLE << 1)
#define _MQ_STD (_MQ_TIMER_CYCLE << 2)
#define _MQ_LAZY (_MQ_TIMER_CYCLE << 3)
#define _MQ_ms2cycl(T) (((T) + USER_TIMER_MINIMUM) / _MQ_TIMER_CYCLE)
static void _MQ_AppendCmd(CmdMessageQueue_t* const pMsgQCmd, LONG64 cycles)
{
if (!pMsgQCmd) { return; }
cycles = clampll(cycles, 0, _MQ_ms2cycl(60000));
CmdMessageQueue_t* pmqc = NULL;
DL_SEARCH(MessageQueue, pmqc, pMsgQCmd, msgcmp);
if (!pmqc) { // NOT found, create one
pmqc = AllocMem(sizeof(CmdMessageQueue_t), HEAP_ZERO_MEMORY);
if (pmqc) {
*pmqc = *pMsgQCmd;
pmqc->delay = cycles;
DL_APPEND(MessageQueue, pmqc);
}
} else {
if ((pmqc->delay > 0) && (cycles > 0)) {
pmqc->delay = (pmqc->delay + cycles) >> 1; // median delay
} else {
pmqc->delay = cycles;
}
}
if (0 == cycles) {
PostMessage(pMsgQCmd->hwnd, pMsgQCmd->cmd, pMsgQCmd->wparam, pMsgQCmd->lparam);
}
//~DL_SORT(MessageQueue, sortcmp); // next scheduled first
}
// ----------------------------------------------------------------------------
/* not used yet
static void _MQ_DropAll()
{
CmdMessageQueue_t *pmqc = NULL;
DL_FOREACH(MessageQueue, pmqc)
{
pmqc->delay = -1;
}
}
*/
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
//
// called by Timer(IDT_TIMER_MRKALL)
//
// TIMERPROC
static void CALLBACK MQ_ExecuteNext(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
UNREFERENCED_PARAMETER(hwnd); // must be main window handle
UNREFERENCED_PARAMETER(uMsg); // must be WM_TIMER
UNREFERENCED_PARAMETER(idEvent); // must be IDT_TIMER_MRKALL
UNREFERENCED_PARAMETER(dwTime); // This is the value returned by the GetTickCount() function
CmdMessageQueue_t* pmqc;
DL_FOREACH(MessageQueue, pmqc) {
if (pmqc->delay >= 0) {
--(pmqc->delay); // count down
}
if (pmqc->delay == 0) {
PostMessage(pmqc->hwnd, pmqc->cmd, pmqc->wparam, pmqc->lparam);
}
}
}
//=============================================================================
//
// IsFileReadOnly
//
static bool IsFileReadOnly()
{
return (Path_IsNotEmpty(Paths.CurrentFile) ? IsReadOnly(Path_GetFileAttributes(Paths.CurrentFile)) : false);
}
//=============================================================================
//
// HasCurrentFileChanged
//
static FCOBSRVDATA_T s_FileChgObsvrData = INIT_FCOBSRV_T;
// ----------------------------------------------------------------------------
static inline bool IsFileChangedFlagSet() {
return (WaitForSingleObject(s_FileChgObsvrData.hEventFileChanged, 0) != WAIT_TIMEOUT);
}
static inline bool IsFileDeletedFlagSet() {
return (WaitForSingleObject(s_FileChgObsvrData.hEventFileDeleted, 0) != WAIT_TIMEOUT);
}
static inline bool RaiseFlagIfCurrentFileChanged() {
if (Path_IsEmpty(Paths.CurrentFile)) {
return false;
}
WIN32_FIND_DATA fdUpdated = { 0 };
if (!GetFileAttributesExW(Path_Get(Paths.CurrentFile), GetFileExInfoStandard, &fdUpdated)) {
// The current file has been removed
if (IsFileDeletedFlagSet()) {
return false;
}
SetEvent(s_FileChgObsvrData.hEventFileChanged);
SetEvent(s_FileChgObsvrData.hEventFileDeleted);
return true;
}
if (IsFileDeletedFlagSet()) {
// The current file has been restored
ResetEvent(s_FileChgObsvrData.hEventFileDeleted);
}
bool const changed = (s_FileChgObsvrData.fdCurFile.nFileSizeLow != fdUpdated.nFileSizeLow) || (s_FileChgObsvrData.fdCurFile.nFileSizeHigh != fdUpdated.nFileSizeHigh)
//~|| (CompareFileTime(&(s_FileChgObsvrData.fdCurFile.ftLastWriteTime), &fdUpdated.ftLastWriteTime) != 0)
|| (s_FileChgObsvrData.fdCurFile.ftLastWriteTime.dwLowDateTime != fdUpdated.ftLastWriteTime.dwLowDateTime)
|| (s_FileChgObsvrData.fdCurFile.ftLastWriteTime.dwHighDateTime != fdUpdated.ftLastWriteTime.dwHighDateTime);
if (changed) {
SetEvent(s_FileChgObsvrData.hEventFileChanged);
}
return changed;
}
// ----------------------------------------------------------------------------
static inline void ResetFileObservationData(const bool bResetEvt) {
if (bResetEvt) {
ResetEvent(s_FileChgObsvrData.hEventFileChanged);
ResetEvent(s_FileChgObsvrData.hEventFileDeleted);
}
if (Path_IsNotEmpty(Paths.CurrentFile)) {
if (!GetFileAttributesEx(Path_Get(Paths.CurrentFile), GetFileExInfoStandard, &(s_FileChgObsvrData.fdCurFile)))
{
ZeroMemory(&(s_FileChgObsvrData.fdCurFile), sizeof(WIN32_FIND_DATA));
}
}
}
// ----------------------------------------------------------------------------
#define TE_ZERO (1.0E-8)
#define TE_FMTA "%.8G"
#define TE_FMTW L"%.8G"
void TinyExprToStringA(LPSTR pszDest, size_t cchDest, const double dExprEval)
{
double idbl = 0.0;
double const fracpart = fabs(modf(dExprEval, &idbl));
double const intpart = fabs(idbl);
if ((fracpart < TE_ZERO) && (intpart < 1.0E+21)) {
StringCchPrintfA(pszDest, cchDest, "%.21G", intpart); // integer full number display
}
else {
StringCchPrintfA(pszDest, cchDest, TE_FMTA, dExprEval);
}
}
// ----------------------------------------------------------------------------
void TinyExprToString(LPWSTR pszDest, size_t cchDest, const double dExprEval)
{
double idbl = 0.0;
double const fracpart = fabs(modf(dExprEval, &idbl));
double const intpart = fabs(idbl);
if ((fracpart < TE_ZERO) && (intpart < 1.0E+21)) {
StringCchPrintf(pszDest, cchDest, L"%.21G", intpart); // integer full number display
}
else {
StringCchPrintf(pszDest, cchDest, TE_FMTW, dExprEval);
}
}
// ----------------------------------------------------------------------------
//=============================================================================
//
// InvalidateStyleRedraw
//
static inline void InvalidateStyleRedraw()
{
SciCall_SetViewEOL(Settings.ViewEOLs);
}
//=============================================================================
//
// CommandLine Parsing Flags
//
static LPWSTR s_lpSchemeArg = NULL;
static LPWSTR s_lpOrigFileArg = NULL;
static HPATHL s_pthArgFilePath = NULL;
static HPATHL s_pthCheckFilePath = NULL;
static cpi_enc_t s_flagSetEncoding = CPI_NONE;
static int s_flagSetEOLMode = 0;
static bool s_flagStartAsTrayIcon = false;
static bool s_flagKeepTitleExcerpt = false;
static bool s_flagNewFromClipboard = false;
static bool s_flagPasteBoard = false;
static bool s_flagJumpTo = false;
static FILE_WATCHING_MODE s_flagChangeNotify = FWM_NO_INIT;
static bool s_flagQuietCreate = false;
static bool s_flagLexerSpecified = false;
static bool s_flagDisplayHelp = false;
static int s_iCaretPolicyV = CARET_EVEN;
//==============================================================================
static volatile HANDLE s_hEventAppIsClosing = INVALID_HANDLE_VALUE;
static __forceinline bool IsAppClosing() {
return (WaitForSingleObject(s_hEventAppIsClosing, 0) == WAIT_OBJECT_0);
}
//==============================================================================
// static forward declarations
static void _UpdateStatusbarDelayed(bool bForceRedraw);
static void _UpdateToolbarDelayed();
static void _UpdateTitlebarDelayed(const HWND hwnd);
//==============================================================================
static void _InitGlobals()
{
Globals.hLngResContainer = NULL;
Globals.hDlgIcon256 = NULL;
Globals.hDlgIcon128 = NULL;
Globals.hDlgIconBig = NULL;
Globals.hDlgIconSmall = NULL;
Globals.hDlgIconPrefs256 = NULL;
Globals.hDlgIconPrefs128 = NULL;
Globals.hDlgIconPrefs64 = NULL;
Globals.hMainMenu = NULL;
Globals.pFileMRU = NULL;
Globals.pMRUfind = NULL;
Globals.pMRUreplace = NULL;
Globals.uAvailLngCount = 1;
Globals.iWrapCol = 80;
Globals.CmdLnFlag_PosParam = false;
Globals.CmdLnFlag_AlwaysOnTop = 0;
Globals.CmdLnFlag_WindowPos = 0;
Globals.CmdLnFlag_ReuseWindow = 0;
Globals.CmdLnFlag_SingleFileInstance = 0;
Globals.CmdLnFlag_MultiFileArg = 0;
Globals.CmdLnFlag_ShellUseSystemMRU = 0;
Globals.CmdLnFlag_PrintFileAndLeave = 0;
Globals.DOSEncoding = CPI_NONE;
Globals.bZeroBasedColumnIndex = false;
Globals.bZeroBasedCharacterCount = false;
Globals.iReplacedOccurrences = 0;
Globals.iSelectionMarkNumber = 0;
Globals.iMarkOccurrencesCount = 0;
Globals.bUseLimitedAutoCCharSet = false;
Globals.bIsCJKInputCodePage = false;
Globals.bIniFileFromScratch = false;
Globals.bFindReplCopySelOrClip = true;
Globals.bReplaceInitialized = false;
Globals.FindReplaceMatchFoundState = FND_NOP;
Globals.bDocHasInconsistentEOLs = false;
Globals.pStdDarkModeIniStyles = NULL;
Globals.bMinimizedToTray = false;
Globals.uCurrentThemeIndex = 0;
Flags.bHugeFileLoadState = DefaultFlags.bHugeFileLoadState = false;
Flags.bDevDebugMode = DefaultFlags.bDevDebugMode = false;
Flags.bStickyWindowPosition = DefaultFlags.bStickyWindowPosition = false;
Flags.bReuseWindow = DefaultFlags.bReuseWindow = false;
Flags.bSingleFileInstance = DefaultFlags.bSingleFileInstance = true;
Flags.MultiFileArg = DefaultFlags.MultiFileArg = false;
Flags.RelativeFileMRU = DefaultFlags.RelativeFileMRU = true;
Flags.PortableMyDocs = DefaultFlags.PortableMyDocs = Flags.RelativeFileMRU;
Flags.NoFadeHidden = DefaultFlags.NoFadeHidden = false;
Flags.ToolbarLook = DefaultFlags.ToolbarLook = IsWindowsXPSP3OrGreater() ? 1 : 2;
Flags.SimpleIndentGuides = DefaultFlags.SimpleIndentGuides = false;
Flags.NoHTMLGuess =DefaultFlags.NoHTMLGuess = false;
Flags.NoCGIGuess = DefaultFlags.NoCGIGuess = false;
Flags.NoFileVariables = DefaultFlags.NoFileVariables = false;
Flags.SaveBlankNewFile = DefaultFlags.SaveBlankNewFile = true;
Flags.ShellUseSystemMRU = DefaultFlags.ShellUseSystemMRU = true;
Flags.PrintFileAndLeave = DefaultFlags.PrintFileAndLeave = 0;
Flags.bPreserveFileModTime = DefaultFlags.bPreserveFileModTime = false;
Flags.bDoRelaunchElevated = DefaultFlags.bDoRelaunchElevated = false;
Flags.bSearchPathIfRelative = DefaultFlags.bSearchPathIfRelative = false;
Flags.bSettingsFileSoftLocked = DefaultFlags.bSettingsFileSoftLocked = false;
Settings.EFR_Data.chFindPattern = StrgCreate(NULL);
Settings.EFR_Data.chReplaceTemplate = StrgCreate(NULL);
Defaults.EFR_Data.chFindPattern = StrgCreate(NULL);
Defaults.EFR_Data.chReplaceTemplate = StrgCreate(NULL);
Settings.OpenWithDir = Path_Allocate(NULL);
Defaults.OpenWithDir = Path_Allocate(NULL);
Settings.FavoritesDir = Path_Allocate(NULL);
Defaults.FavoritesDir = Path_Allocate(NULL);
Settings2.DefaultDirectory = Path_Allocate(NULL);
Settings2.FileBrowserPath = Path_Allocate(NULL);
Settings2.GrepWinPath = Path_Allocate(NULL);
Settings2.AdministrationTool = Path_Allocate(NULL);
Settings2.WebTemplate1 = StrgCreate(NULL);
Settings2.WebTemplate2 = StrgCreate(NULL);
Settings2.HyperlinkShellExURLWithApp = StrgCreate(NULL);
Settings2.HyperlinkShellExURLCmdLnArgs = StrgCreate(NULL);
Settings2.FileDlgFilters = StrgCreate(NULL);
FocusedView.HideNonMatchedLines = false;
FocusedView.CodeFoldingAvailable = false;
FocusedView.ShowCodeFolding = true;
FileWatching.FileWatchingMode = FWM_DONT_CARE;
FileWatching.MonitoringLog = false;
Paths.CurrentFile = Path_Allocate(NULL);
Paths.ModuleDirectory = Path_Allocate(NULL);
Paths.WorkingDirectory = Path_Allocate(NULL);
Paths.IniFile = Path_Allocate(NULL);
Paths.IniFileDefault = Path_Allocate(NULL);
// --- unstructured globals ---
g_tchToolbarBitmap = Path_Allocate(NULL);
g_tchToolbarBitmapHot = Path_Allocate(NULL);
g_tchToolbarBitmapDisabled = Path_Allocate(NULL);
// --- dynamicly created globals ---
WCHAR tchIndex[16] = { L'\0' };
StringCchPrintf(tchIndex, COUNTOF(tchIndex), L"%i", s_tbbMainWnd[0].iBitmap + 1);
StringCchCopy(TBBUTTON_DEFAULT_IDS, COUNTOF(TBBUTTON_DEFAULT_IDS), tchIndex);
assert(TBBUTTON_LAST_DEFAULT <= COUNTOF(s_tbbMainWnd));
for (int i = 1; i < TBBUTTON_LAST_DEFAULT; ++i) {
if (s_tbbMainWnd[i].idCommand) {
StringCchPrintf(tchIndex, COUNTOF(tchIndex), L" %i", s_tbbMainWnd[i].iBitmap + 1);
StringCchCat(TBBUTTON_DEFAULT_IDS, COUNTOF(TBBUTTON_DEFAULT_IDS), tchIndex);
} else {
StringCchCat(TBBUTTON_DEFAULT_IDS, COUNTOF(TBBUTTON_DEFAULT_IDS), L" 0");
}
}
// --- static locals ---
s_hpthRelaunchElevatedFile = Path_Allocate(NULL);
ThemesItems_Init();
s_hstrCurrentFindPattern = StrgCreate(NULL);
s_pthArgFilePath = Path_Allocate(NULL);
s_pthCheckFilePath = Path_Allocate(NULL);
// don't allow empty extensions settings => use default ext
Style_InitFileExtensions();
}
//=============================================================================
//
// _CleanUpResources()
//
static _invalid_parameter_handler _hOldInvalidParamHandler = NULL;
static void _CleanUpResources(const HWND hwnd, bool bIsInitialized)
{
if (hwnd) {
KillTimer(hwnd, IDT_TIMER_MRKALL);
}
if (Globals.pStdDarkModeIniStyles) {
FreeMem(Globals.pStdDarkModeIniStyles);
Globals.pStdDarkModeIniStyles = NULL;
}
CmdMessageQueue_t* pmqc = NULL;
CmdMessageQueue_t* dummy;
DL_FOREACH_SAFE(MessageQueue, pmqc, dummy) {
DL_DELETE(MessageQueue, pmqc);
FreeMem(pmqc);
}
if (UndoRedoSelectionUTArray != NULL) {
utarray_free(UndoRedoSelectionUTArray);
UndoRedoSelectionUTArray = NULL;
}
if (IS_VALID_HANDLE(s_FileChgObsvrData.hEventFileChanged)) {
CloseHandle(s_FileChgObsvrData.hEventFileChanged);
s_FileChgObsvrData.hEventFileChanged = INVALID_HANDLE_VALUE;
}
if (IS_VALID_HANDLE(s_FileChgObsvrData.hEventFileDeleted)) {
CloseHandle(s_FileChgObsvrData.hEventFileDeleted);
s_FileChgObsvrData.hEventFileDeleted = INVALID_HANDLE_VALUE;
}
BackgroundWorker_Destroy(&(s_FileChgObsvrData.worker));
// ---------------------------------------------
if (s_SelectionBuffer) {
FreeMem(s_SelectionBuffer);
s_SelectionBuffer = NULL;
}
// ---------------------------------------------
// Save Settings should be done elsewhere before
// ---------------------------------------------
if (Globals.hMainMenu) {
DestroyMenu(Globals.hMainMenu);
}
#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS)
FreeLanguageResources();
#endif
CleanupDlgResources();
Scintilla_ReleaseResources();
if (bIsInitialized) {
//~UnregisterClass(s_ToolbarWndClassName, Globals.hInstance);
UnregisterClass(s_wchWndClass, Globals.hInstance);
}
ReleaseDarkMode();
// --- free allocated memory ---
if (s_lpOrigFileArg) {
FreeMem(s_lpOrigFileArg);
s_lpOrigFileArg = NULL;
}
MRU_Destroy(Globals.pFileMRU);
MRU_Destroy(Globals.pMRUfind);
MRU_Destroy(Globals.pMRUreplace);
StrgDestroy(Settings2.FileDlgFilters);
StrgDestroy(Settings2.HyperlinkShellExURLCmdLnArgs);
StrgDestroy(Settings2.HyperlinkShellExURLWithApp);
StrgDestroy(Settings2.WebTemplate2);
StrgDestroy(Settings2.WebTemplate1);
Path_Release(Settings2.AdministrationTool);
Path_Release(Settings2.GrepWinPath);
Path_Release(Settings2.FileBrowserPath);
Path_Release(Settings2.DefaultDirectory);
Path_Release(Settings.FavoritesDir);
Path_Release(Defaults.FavoritesDir);
Path_Release(Settings.OpenWithDir);
Path_Release(Defaults.OpenWithDir);
ReleaseEFR(&(Defaults.EFR_Data));
ReleaseEFR(&(Settings.EFR_Data));
Path_Release(Paths.CurrentFile);
Path_Release(Paths.ModuleDirectory);
Path_Release(Paths.WorkingDirectory);
Path_Release(Paths.IniFileDefault);
Path_Release(Paths.IniFile);
Path_Release(g_tchToolbarBitmapDisabled);
Path_Release(g_tchToolbarBitmapHot);
Path_Release(g_tchToolbarBitmap);
Path_Release(s_pthArgFilePath);
Path_Release(s_pthCheckFilePath);
StrgDestroy(s_hstrCurrentFindPattern);
ThemesItems_Release();
Path_Release(s_hpthRelaunchElevatedFile);
// ---------------------------------------------
if (Globals.hDlgIcon256) {
DestroyIcon(Globals.hDlgIcon256);
}
if (Globals.hDlgIcon128) {
DestroyIcon(Globals.hDlgIcon128);
}
if (Globals.hDlgIconBig) {
DestroyIcon(Globals.hDlgIconBig);
}
if (Globals.hDlgIconSmall) {
DestroyIcon(Globals.hDlgIconSmall);
}
if (Globals.hDlgIconPrefs256) {
DestroyIcon(Globals.hDlgIconPrefs256);
}
if (Globals.hDlgIconPrefs128) {
DestroyIcon(Globals.hDlgIconPrefs128);
}
if (Globals.hDlgIconPrefs64) {
DestroyIcon(Globals.hDlgIconPrefs64);
}
if (Globals.hIconMsgUser) {
DestroyIcon(Globals.hIconMsgUser);
}
if (Globals.hIconMsgInfo) {
DestroyIcon(Globals.hIconMsgInfo);
}
if (Globals.hIconMsgWarn) {
DestroyIcon(Globals.hIconMsgWarn);
}
if (Globals.hIconMsgError) {
DestroyIcon(Globals.hIconMsgError);
}
if (Globals.hIconMsgQuest) {
DestroyIcon(Globals.hIconMsgQuest);
}
if (Globals.hIconMsgShield) {
DestroyIcon(Globals.hIconMsgShield);
}
if (Globals.hIconMsgWinCmd) {
DestroyIcon(Globals.hIconMsgWinCmd);
}
if (Globals.hIconGrepWinNP3) {
DestroyIcon(Globals.hIconGrepWinNP3);
}
// install previous handler
if (_hOldInvalidParamHandler) {
_set_invalid_parameter_handler(_hOldInvalidParamHandler);
}
CoUninitialize();
OleUninitialize();
}
//=============================================================================
//
// InvalidParameterHandler()
//
void InvalidParameterHandler(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t pReserved)
{
UNREFERENCED_PARAMETER(expression);
UNREFERENCED_PARAMETER(function);
UNREFERENCED_PARAMETER(file);
UNREFERENCED_PARAMETER(line);
UNREFERENCED_PARAMETER(pReserved);
#if (defined(_DEBUG) || defined(DEBUG)) && !defined(NDEBUG)
WCHAR msg[256];
StringCchPrintf(msg, COUNTOF(msg),
L"Invalid Parameter in function '%s()' - File:'%s' Line:%i !",
function, file, line);
MsgBoxLastError(msg, ERROR_INVALID_PARAMETER);
#endif
}
//=============================================================================
//
// WinMain()
//
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd)
{
UNREFERENCED_PARAMETER(lpCmdLine);
_invalid_parameter_handler const hNewInvalidParamHandler = InvalidParameterHandler;
_hOldInvalidParamHandler= _set_invalid_parameter_handler(hNewInvalidParamHandler);
#if (defined(_DEBUG) || defined(DEBUG)) && !defined(NDEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_CRT_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_ASSERT, 0); // Disable the message box for assertions.
#endif
_InitGlobals();
InitDarkMode();
// Windows Class name
StringCchCopy(s_wchWndClass, COUNTOF(s_wchWndClass), _W(SAPPNAME));
// Set global variable Globals.hInstance
Globals.hInstance = hInstance;
Globals.hPrevInst = hPrevInstance;
Globals.hndlProcessHeap = GetProcessHeap();
// now using AllocMen() methods
s_SelectionBuffer = (char*)AllocMem(128, HEAP_ZERO_MEMORY);
Path_GetAppDirectory(Paths.ModuleDirectory);
if (!Path_GetCurrentDirectory(Paths.WorkingDirectory)) {
Path_Reset(Paths.WorkingDirectory, Path_Get(Paths.ModuleDirectory));
}
// Don't keep working directory locked
SetCurrentDirectoryW(Path_Get(Paths.ModuleDirectory));
SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
// check if running at least on Windows 7 (SP1)
if (!IsWindows7SP1OrGreater()) {
MsgBoxLastError(L"Application Initialization", ERROR_OLD_WIN_VERSION);
return 1; // exit
}
//~SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
//~SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
// Check if running with elevated privileges
s_bIsProcessElevated = IsProcessElevated();
s_bIsUserInAdminGroup = IsUserInAdminGroup();
s_bIsRunAsAdmin = IsRunAsAdmin();
// Adapt window class name
if (s_bIsProcessElevated) {
StringCchCat(s_wchWndClass, COUNTOF(s_wchWndClass), L"U");
}
// Default Encodings (may already be used for command line parsing)
Encoding_InitDefaults();
// Command Line, Ini File and Flags
ParseCommandLine();
// Adapt window class name
if (s_flagPasteBoard) {
StringCchCat(s_wchWndClass, COUNTOF(s_wchWndClass), L"B");
}
// INI File Handling
FindIniFile();
TestIniFile();
DWORD dwFileSize = 0UL;
Globals.bCanSaveIniFile = CreateIniFile(Paths.IniFile, &dwFileSize);
Globals.bIniFileFromScratch = (dwFileSize == 0UL);
if (Globals.bIniFileFromScratch && Globals.bCanSaveIniFile) {
// Set at least Application Name Section
IniFileSetString(Paths.IniFile, _W(SAPPNAME), NULL, NULL);
}
LoadSettings();
// Autoload recent file on close
CheckAutoLoadMostRecent();
PrivateSetCurrentProcessExplicitAppUserModelID(Settings2.AppUserModelID);
(void)CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY);
(void)OleInitialize(NULL);
INITCOMMONCONTROLSEX icex = { sizeof(INITCOMMONCONTROLSEX) };
icex.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES | ICC_COOL_CLASSES | ICC_NATIVEFNTCTL_CLASS | ICC_STANDARD_CLASSES;
InitCommonControlsEx(&icex);
Scintilla_RegisterClasses(hInstance);
#ifdef D_NP3_WIN10_DARK_MODE
SetDarkMode(IsDarkModeSupported() && IsSettingDarkMode()); // settings
#endif
HRSRC const hRes = FindResourceEx(hInstance, RT_RCDATA, MAKEINTRESOURCE(IDR_STD_DARKMODE_THEME),
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
if (hRes) {
HGLOBAL const hMem = LoadResource(hInstance, hRes);
if (hMem) {
const char* const resText = (const char*)LockResource(hMem);
DWORD const size = SizeofResource(hInstance, hRes);
Globals.pStdDarkModeIniStyles = (char*)AllocMem(((size_t)size + 1), 0);
if (Globals.pStdDarkModeIniStyles) {
CopyMemory(Globals.pStdDarkModeIniStyles, resText, size);
Globals.pStdDarkModeIniStyles[size] = '\0'; // zero termination
}
FreeResource(hMem);
}
}
Style_ImportTheme(-1); // init (!)
Style_ImportTheme(Globals.uCurrentThemeIndex);
//SetProcessDPIAware(); // ->.manifest
//SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
//~Scintilla_LoadDpiForWindow(); done in Sci::Platform_Initialize();
// ----------------------------------------------------
// MultiLingual
//
#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS)
SetMuiLanguage(LoadLanguageResources(Settings2.PreferredLanguageLocaleName));
#else
SetMuiLanguage(GetMUILanguageIndexByLocaleName(MUI_BASE_LNG_ID));
#endif
// ----------------------------------------------------
// ICON_BIG (32x32)
int const cxb = GetSystemMetrics(SM_CXICON);
int const cyb = GetSystemMetrics(SM_CYICON);
// ICON_SMALL (16x16)
int const cxs = GetSystemMetrics(SM_CXSMICON);
int const cys = GetSystemMetrics(SM_CYSMICON);
UINT const fuLoad = LR_DEFAULTCOLOR | LR_SHARED;
if (!Globals.hDlgIcon256) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDR_MAINWND), 256, 256, &(Globals.hDlgIcon256))))
Globals.hDlgIcon256 = LoadImage(hInstance, MAKEINTRESOURCE(IDR_MAINWND), IMAGE_ICON, 256, 256, fuLoad);
}
if (!Globals.hDlgIcon128) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDR_MAINWND), 128, 128, &(Globals.hDlgIcon128))))
Globals.hDlgIcon128 = LoadImage(hInstance, MAKEINTRESOURCE(IDR_MAINWND), IMAGE_ICON, 128, 128, fuLoad);
}
if (!Globals.hDlgIconBig) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDR_MAINWND), cxb, cyb, &(Globals.hDlgIconBig))))
Globals.hDlgIconBig = LoadImage(hInstance, MAKEINTRESOURCE(IDR_MAINWND), IMAGE_ICON, cxb, cyb, fuLoad);
}
if (!Globals.hDlgIconSmall) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDR_MAINWND), cxs, cys, &(Globals.hDlgIconSmall))))
Globals.hDlgIconSmall = LoadImage(hInstance, MAKEINTRESOURCE(IDR_MAINWND), IMAGE_ICON, cxs, cys, fuLoad);
}
if (!Globals.hDlgIconPrefs256) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDI_MUI_STYLES), 256, 256, &(Globals.hDlgIconPrefs256))))
Globals.hDlgIconPrefs256 = LoadImage(hInstance, MAKEINTRESOURCE(IDI_MUI_STYLES), IMAGE_ICON, 256, 256, fuLoad);
}
if (!Globals.hDlgIconPrefs128) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDI_MUI_STYLES), 128, 128, &(Globals.hDlgIconPrefs128))))
Globals.hDlgIconPrefs128 = LoadImage(hInstance, MAKEINTRESOURCE(IDI_MUI_STYLES), IMAGE_ICON, 128, 128, fuLoad);
}
if (!Globals.hDlgIconPrefs64) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDI_MUI_STYLES), 64, 64, &(Globals.hDlgIconPrefs64))))
Globals.hDlgIconPrefs64 = LoadImage(hInstance, MAKEINTRESOURCE(IDI_MUI_STYLES), IMAGE_ICON, 64, 64, fuLoad);
}
if (!Globals.hIconMsgUser) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDR_MAINWND), cxb, cyb, &(Globals.hIconMsgUser))))
Globals.hIconMsgUser = LoadImage(hInstance, MAKEINTRESOURCE(IDR_MAINWND), IMAGE_ICON, cxb, cyb, fuLoad);
}
if (!Globals.hIconMsgInfo) {
if (FAILED(LoadIconWithScaleDown(NULL, IDI_INFORMATION, cxb, cyb, &(Globals.hIconMsgInfo))))
Globals.hIconMsgInfo = LoadImage(NULL, IDI_INFORMATION, IMAGE_ICON, cxb, cyb, fuLoad);
}
if (!Globals.hIconMsgWarn) {
if (FAILED(LoadIconWithScaleDown(NULL, IDI_WARNING, cxb, cyb, &(Globals.hIconMsgWarn))))
Globals.hIconMsgWarn = LoadImage(NULL, IDI_WARNING, IMAGE_ICON, cxb, cyb, fuLoad);
}
if (!Globals.hIconMsgError) {
if (FAILED(LoadIconWithScaleDown(NULL, IDI_ERROR, cxb, cyb, &(Globals.hIconMsgError))))
Globals.hIconMsgError = LoadImage(NULL, IDI_ERROR, IMAGE_ICON, cxb, cyb, fuLoad);
}
if (!Globals.hIconMsgQuest) {
if (FAILED(LoadIconWithScaleDown(NULL, IDI_QUESTION, cxb, cyb, &(Globals.hIconMsgQuest))))
Globals.hIconMsgQuest = LoadImage(NULL, IDI_QUESTION, IMAGE_ICON, cxb, cyb, fuLoad);
}
if (!Globals.hIconMsgShield) {
if (FAILED(LoadIconWithScaleDown(NULL, IDI_SHIELD, cxb, cyb, &(Globals.hIconMsgShield))))
Globals.hIconMsgShield = LoadImage(NULL, IDI_SHIELD, IMAGE_ICON, cxb, cyb, fuLoad);
}
if (!Globals.hIconMsgWinCmd) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDI_MUI_RUN), cxb, cyb, &(Globals.hIconMsgWinCmd))))
Globals.hIconMsgWinCmd = LoadImage(hInstance, MAKEINTRESOURCE(IDI_MUI_RUN), IMAGE_ICON, cxb, cyb, fuLoad);
}
if (!Globals.hIconGrepWinNP3) {
if (FAILED(LoadIconWithScaleDown(hInstance, MAKEINTRESOURCE(IDI_MUI_GREPWINNP3), cxs, cys, &(Globals.hIconGrepWinNP3))))
Globals.hIconGrepWinNP3 = LoadImage(hInstance, MAKEINTRESOURCE(IDI_MUI_GREPWINNP3), IMAGE_ICON, cxs, cys, fuLoad);
}
if (s_IsThisAnElevatedRelaunch && !IsRunAsAdmin()) {
InfoBoxLng(MB_ICONSHIELD, NULL, IDS_MUI_ERR_ELEVATED_RIGHTS);
s_flagSaveOnRelaunch = false;
}
// Try to Relaunch with elevated privileges
if (RelaunchElevated(NULL)) {
return FALSE;
}
// Try to run multiple instances
if (RelaunchMultiInst()) {
return FALSE;
}
// Try to activate another window
if (ActivatePrevInst()) {
return FALSE;
}
// Command Line Help Dialog
if (s_flagDisplayHelp) {
DisplayCmdLineHelp(NULL);
_CleanUpResources(NULL, false);
return FALSE;
}
s_msgTaskbarCreated = RegisterWindowMessage(L"TaskbarCreated");
Globals.hMainMenu = LoadMenu(Globals.hLngResContainer, MAKEINTRESOURCE(IDR_MUI_MAINMENU));
if (!Globals.hMainMenu) {
MsgBoxLastError(L"LoadMenu()", 0);
_CleanUpResources(NULL, false);
return 1;
}
#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS)
InsertLanguageMenu(Globals.hMainMenu);
#endif
Style_InsertThemesMenu(Globals.hMainMenu);
if (!InitApplication(Globals.hInstance)) {
_CleanUpResources(NULL, false);
return 1;
}
HWND const hwnd = InitInstance(Globals.hInstance, nShowCmd);
if (!hwnd) {
_CleanUpResources(hwnd, true);
return 1;
}
DrawMenuBar(hwnd);
HACCEL const hAccMain = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_MAINWND));
HACCEL const hAccFindReplace = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCFINDREPLACE));
HACCEL const hAccCoustomizeSchemes = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCCUSTOMSCHEMES));
SetTimer(hwnd, IDT_TIMER_MRKALL, _MQ_TIMER_CYCLE, MQ_ExecuteNext);
// clear caches
ResetTmpCache();
ResetIniFileCache();
// drag-n-drop into elevated process even does not work using:
///ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);
///ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);
///ChangeWindowMessageFilter(0x0049, MSGFLT_ADD);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (IsWindow(Globals.hwndDlgFindReplace) && ((msg.hwnd == Globals.hwndDlgFindReplace) || IsChild(Globals.hwndDlgFindReplace, msg.hwnd))) {
const int iTr = TranslateAccelerator(Globals.hwndDlgFindReplace, hAccFindReplace, &msg);
if (iTr || IsDialogMessage(Globals.hwndDlgFindReplace, &msg)) {
continue;
}
}
if (IsWindow(Globals.hwndDlgCustomizeSchemes) && ((msg.hwnd == Globals.hwndDlgCustomizeSchemes) || IsChild(Globals.hwndDlgCustomizeSchemes, msg.hwnd))) {
const int iTr = TranslateAccelerator(Globals.hwndDlgCustomizeSchemes, hAccCoustomizeSchemes, &msg);
if (iTr || IsDialogMessage(Globals.hwndDlgCustomizeSchemes, &msg)) {
continue;
}
}
if (!TranslateAccelerator(hwnd, hAccMain, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
_CleanUpResources(hwnd, true);
#ifdef _DEBUG
_CrtDumpMemoryLeaks();
#endif
return (int)(msg.wParam);
}
//=============================================================================
//
// GetFactoryDefaultWndPos()
//
//
WININFO GetFactoryDefaultWndPos(HWND hwnd, const int flagsPos)
{
hwnd = hwnd ? hwnd : GetDesktopWindow();
unsigned int const dpi = Scintilla_GetWindowDPI(hwnd);
RECT rc = { 0 };
GetWindowRect(hwnd, &rc);
MONITORINFO mi;
GetMonitorInfoFromRect(&rc, &mi);
rc = mi.rcWork;
//~RelAdjustRectForDPI(&rc, USER_DEFAULT_SCREEN_DPI, dpi);
WININFO winfo = INIT_WININFO;
winfo.y = rc.top;
winfo.cy = rc.bottom - rc.top;
winfo.cx = (rc.right - rc.left) / 2;
winfo.x = (flagsPos == 3) ? rc.left : winfo.cx;
winfo.max = 0;
winfo.zoom = 100;
winfo.dpi = dpi;
return winfo;
}
// ----------------------------------------------------------------------------
//=============================================================================
//
// _GetDefaultWinInfoByStrg()
//
static void _IniFileWriteDefaultWindowPosition(WININFO wi)
{
WCHAR tchScrnDim[64] = { L'\0' };
StringCchPrintf(tchScrnDim, COUNTOF(tchScrnDim), L"%ix%i " DEF_WIN_POSITION_STRG,
GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
StringCchPrintf(Settings2.DefaultWindowPosition, COUNTOF(Settings2.DefaultWindowPosition),
WINDOWPOS_STRGFORMAT, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, wi.max);
IniFileSetString(Paths.IniFile, Constants.Window_Section, tchScrnDim, Settings2.DefaultWindowPosition);
IniFileDelete(Paths.IniFile, Constants.Settings2_Section, DEF_WIN_POSITION_STRG, true);
}
static WININFO _GetDefaultWinInfoByStrg(HWND hwnd, LPCWSTR strDefaultWinPos)
{
hwnd = hwnd ? hwnd : GetDesktopWindow();
WININFO const wiDef = GetFactoryDefaultWndPos(hwnd, 2); // std. default position
if (StrIsEmpty(strDefaultWinPos)) {
return wiDef;
}
WININFO wi = wiDef;
int bMaxi = 0;
int const itok = swscanf_s(Settings2.DefaultWindowPosition, WINDOWPOS_STRGFORMAT,
&wi.x, &wi.y, &wi.cx, &wi.cy, &wi.dpi, &bMaxi);
if (itok == 4 || itok == 5 || itok == 6) { // scan successful
if (itok == 4) {
wi.dpi = USER_DEFAULT_SCREEN_DPI;
wi.max = false;
}
else if (itok == 5) { // maybe DPI or Maxi (old)
if (wi.dpi < (USER_DEFAULT_SCREEN_DPI >> 2)) {
wi.max = wi.dpi ? true : false;
wi.dpi = USER_DEFAULT_SCREEN_DPI;
}
else {
wi.max = false;
}
}
else {
wi.max = bMaxi ? true : false;
}
}
else {
wi = wiDef;
// overwrite bad defined default position
_IniFileWriteDefaultWindowPosition(wi);
}
return wi;
}
//=============================================================================
//
// GetWinInfoByFlag()
//
//
WININFO GetWinInfoByFlag(HWND hwnd, const int flagsPos)
{
hwnd = hwnd ? hwnd : GetDesktopWindow();
if ((g_DefWinInfo.x == CW_USEDEFAULT) || (g_DefWinInfo.y == CW_USEDEFAULT)) {
g_DefWinInfo = _GetDefaultWinInfoByStrg(hwnd, Settings2.DefaultWindowPosition);
}
WININFO winfo = INIT_WININFO;
if (flagsPos < 0) {
winfo = GetMyWindowPlacement(hwnd, NULL, 0, false); // current window position
} else if (flagsPos == 0) {
winfo = g_IniWinInfo; // initial window position
} else if (flagsPos == 1) {
winfo.x = winfo.y = winfo.cx = winfo.cy = CW_USEDEFAULT;
winfo.max = false;
winfo.zoom = 100;
} else if (flagsPos == 2) {
winfo = g_DefWinInfo; // NP3 default window position
} else if (flagsPos == 3) {
winfo = GetFactoryDefaultWndPos(hwnd, flagsPos);
} else if ((flagsPos >= 4) && (flagsPos < 256)) {
RECT rc = { 0 };
GetWindowRect(hwnd, &rc);
MONITORINFO mi;
GetMonitorInfoFromRect(&rc, &mi);
rc = mi.rcWork;
int const width = (rc.right - rc.left);
int const height = (rc.bottom - rc.top);
if (flagsPos & 8) {
winfo.x = rc.left + (width >> 1);
} else {
winfo.x = rc.left;
}
if (flagsPos & (4 | 8)) {
winfo.cx = (width >> 1);
} else {
winfo.cx = width;
}
if (flagsPos & 32) {
winfo.y = rc.top + (height >> 1);
} else {
winfo.y = rc.top;
}
if (flagsPos & (16 | 32)) {
winfo.cy = (height >> 1);
} else {
winfo.cy = height;
}
if (flagsPos & 64) {
winfo.x = rc.left;
winfo.y = rc.top;
winfo.cx = width;
winfo.cy = height;
}
if (flagsPos & 128) {
winfo = g_DefWinInfo;
winfo.max = true;
winfo.zoom = 100;
}
winfo.dpi = Scintilla_GetWindowDPI(hwnd);
} else { // ( > 256) restore window, move upper left corner to Work Area
RECT rc = { 0 };
RectFromWinInfo(&winfo, &rc);
MONITORINFO mi;
GetMonitorInfoFromRect(&rc, &mi);
rc = mi.rcWork;
WININFO wi = winfo;
wi.cx = wi.cy = 16; // really small
FitIntoMonitorGeometry(&rc, &wi, SCR_NORMAL, false);
winfo.x = wi.x;
winfo.y = wi.y;
}
return winfo;
}
//=============================================================================
//
// _EnumWndProc : find other Notepad3 window
//
static BOOL CALLBACK _EnumWndProc(HWND hwnd, LPARAM lParam)
{
BOOL bContinue = TRUE;
WCHAR szClassName[128] = { L'\0' };
if (GetClassName(hwnd, szClassName, COUNTOF(szClassName))) {
if (StrCmpW(szClassName, s_wchWndClass) == 0) {
UINT const iReuseLock = GetDlgItemInt(hwnd, IDC_REUSELOCK, NULL, FALSE);
if ((GetTicks_ms() - iReuseLock) >= REUSEWINDOWLOCKTIMEOUT) {
*(HWND*)lParam = hwnd;
if (IsWindowEnabled(hwnd)) {
bContinue = FALSE;
}
}
}
}
return bContinue;
}
//=============================================================================
//
// _EnumWndProc2 : find other Notepad3 window w/ same file loaded
//
static BOOL CALLBACK _EnumWndProc2(HWND hwnd, LPARAM lParam)
{
BOOL bContinue = TRUE;
WCHAR szClassName[128] = { L'\0' };
if (GetClassName(hwnd, szClassName, COUNTOF(szClassName))) {
if (StrCmpW(szClassName, s_wchWndClass) == 0) {
UINT const iReuseLock = GetDlgItemInt(hwnd, IDC_REUSELOCK, NULL, FALSE);
if ((GetTicks_ms() - iReuseLock) >= REUSEWINDOWLOCKTIMEOUT) {
if (IsWindowEnabled(hwnd)) {
bContinue = FALSE;
}
}
WCHAR wchFileName[INTERNET_MAX_URL_LENGTH] = { L'\0' };
GetDlgItemText(hwnd, IDC_FILENAME, wchFileName, COUNTOF(wchFileName));
if (StringCchCompareXI(wchFileName, Path_Get(s_pthCheckFilePath)) == 0) {
*(HWND*)lParam = hwnd;
bContinue = FALSE;
}
}
}
return bContinue;
}
//=============================================================================
//
// _StatusCalcTextSize()
//
static SIZE _StatusCalcTextSize(HWND hwnd, LPCWSTR lpsz)
{
HDC const hdc = GetDC(hwnd);
HGDIOBJ const hfont = (HGDIOBJ)SendMessage(hwnd, WM_GETFONT, 0, 0);
HGDIOBJ const hfold = SelectObject(hdc, hfont);
int const mmode = SetMapMode(hdc, MM_TEXT);
SIZE size = { 0L, 0L };
GetTextExtentPoint32(hdc, lpsz, (int)StringCchLen(lpsz, 0), &size);
SetMapMode(hdc, mmode);
SelectObject(hdc, hfold);
ReleaseDC(hwnd, hdc);
return size;
}
//=============================================================================
//
// Set/Get FindPattern()
//
bool IsFindPatternEmpty()
{
return StrgIsEmpty(s_hstrCurrentFindPattern);
}
//=============================================================================
//
// GetFindPatternMB()
//
LPCWSTR GetFindPattern()
{
return StrgGet(s_hstrCurrentFindPattern);
}
//=============================================================================
//
// GetFindPatternMB()
//
void GetFindPatternMB(LPSTR chPattern, int cch)
{
StrgGetAsUTF8(s_hstrCurrentFindPattern, chPattern, cch);
}
//=============================================================================
//
// SetFindPattern()
//
void SetFindPattern(LPCWSTR wchFindPattern)
{
StrgReset(s_hstrCurrentFindPattern, StrIsNotEmpty(wchFindPattern) ? wchFindPattern : L"");
}
//=============================================================================
//
// SetFindPatternMB()
//
void SetFindPatternMB(LPCSTR chFindPattern)
{
StrgResetFromUTF8(s_hstrCurrentFindPattern, !StrIsEmptyA(chFindPattern) ? chFindPattern : "");
}
//=============================================================================
//
// LengthOfFindPattern()
//
size_t LengthOfFindPattern()
{
return StrgGetLength(s_hstrCurrentFindPattern);
}
//=============================================================================
//
// LengthOfFindPatternMB()
//
size_t LengthOfFindPatternMB()
{
return (size_t)StrgGetAsUTF8(s_hstrCurrentFindPattern, NULL, 0);
}
// ----------------------------------------------------------------------------
static EDITFINDREPLACE s_FindReplaceData = INIT_EFR_DATA;
//=============================================================================
//
// SetFindReplaceData()
//
static void SetFindReplaceData()
{
// init find pattern with current
if (!IsFindPatternEmpty()) {
StrgReset(Settings.EFR_Data.chFindPattern, GetFindPattern());
}
// copy settings to working data
DuplicateEFR(&s_FindReplaceData, &(Settings.EFR_Data));
if (g_flagMatchText) { // cmd line
if (g_flagMatchText & 4) {
s_FindReplaceData.fuFlags = (SCFIND_REGEXP | SCFIND_POSIX);
}
if (g_flagMatchText & 8) {
s_FindReplaceData.fuFlags |= SCFIND_MATCHCASE;
}
if (g_flagMatchText & 16) {
s_FindReplaceData.fuFlags |= SCFIND_DOT_MATCH_ALL;
}
if (g_flagMatchText & 32) {
s_FindReplaceData.bTransformBS = true;
}
s_FindReplaceData.bRegExprSearch = (s_FindReplaceData.fuFlags & SCFIND_REGEXP);
s_FindReplaceData.bWildcardSearch = false;
s_FindReplaceData.bReplaceClose = false;
}
}
//=============================================================================
//
// SetCurrentSelAsFindReplaceData()
//
static bool SetCurrentSelAsFindReplaceData(LPEDITFINDREPLACE lpefr)
{
if (SciCall_IsSelectionEmpty()) {
EditSelectWordAtPos(SciCall_GetCurrentPos(), true);
}
size_t const cchSelection = SciCall_GetSelText(NULL);
if (0 < cchSelection) {
char* const szSelection = AllocMem((cchSelection + 1), HEAP_ZERO_MEMORY);
if (szSelection) {
SciCall_GetSelText(szSelection);
SetFindPatternMB(szSelection);
SetFindReplaceData(); // s_FindReplaceData
if (lpefr) {
StrgReset(lpefr->chFindPattern, GetFindPattern());
}
FreeMem(szSelection);
return true;
}
}
return false;
}
//=============================================================================
//
// InitApplication()
//
//
bool InitApplication(const HINSTANCE hInstance)
{
WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
wc.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = Globals.hDlgIcon256;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
#ifdef D_NP3_WIN10_DARK_MODE
wc.hbrBackground = UseDarkMode() ? Globals.hbrDarkModeBkgBrush : (HBRUSH)(COLOR_WINDOW + 1);
#else
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
#endif
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MUI_MAINMENU);
wc.lpszClassName = s_wchWndClass;
return RegisterClassEx(&wc);
}
#if 0
//=============================================================================
//
// InitToolbarWndClass()
//
bool InitWndClass(const HINSTANCE hInstance, LPCWSTR lpszWndClassName, LPCWSTR lpszCopyFromWC, bool bUnregisterFirst)
{
if (bUnregisterFirst) {
UnregisterClass(lpszWndClassName, hInstance);
}
WNDCLASSEX wcx = { sizeof(WNDCLASSEX) };
GetClassInfoEx(hInstance, lpszCopyFromWC, &wcx); // copy members
//wcx.lpfnWndProc = (WNDPROC)TBWndProc; ~ don't do that
wcx.hInstance = hInstance; // done already
wcx.hCursor = LoadCursor(NULL, IDC_HAND);
wcx.hbrBackground = UseDarkMode() ? Globals.hbrDarkModeBkgBrush : (HBRUSH)(COLOR_WINDOW + 1);
wcx.lpszClassName = lpszWndClassName;
return RegisterClassEx(&wcx);
}
#endif
//=============================================================================
//
// InitInstance() - DarkMode already initialized !
//
HWND InitInstance(const HINSTANCE hInstance, int nCmdShow)
{
// manual (not automatic) reset & initial state: not signaled (TRUE, FALSE)
s_hEventAppIsClosing = CreateEvent(NULL, TRUE, FALSE, NULL);
// init w/o hwnd
g_IniWinInfo = GetWinInfoByFlag(NULL, Globals.CmdLnFlag_WindowPos);
if (Settings2.LaunchInstanceFullVisible) {
RECT rc = { 0 };
RectFromWinInfo(&g_IniWinInfo, &rc);
FitIntoMonitorGeometry(&rc, &g_IniWinInfo, SCR_NORMAL, false);
}
// get monitor coordinates from g_IniWinInfo
WININFO srcninfo = g_IniWinInfo;
WinInfoToScreenCoord(&srcninfo);
Globals.hwndMain = NULL;
// initialy hidden/not visible
DWORD const dwStyle = ((WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN) & ~WS_VISIBLE); // | (g_IniWinInfo.max ? WS_MAXIMIZE : 0);
HWND const hwndMain = CreateWindowEx(
WS_EX_ACCEPTFILES,
s_wchWndClass,
_W(SAPPNAME),
dwStyle,
srcninfo.x,
srcninfo.y,
srcninfo.cx,
srcninfo.cy,
NULL,
NULL,
hInstance,
NULL);
InitWindowCommon(hwndMain, true);
SetDialogIconNP3(hwndMain);
// correct infos based on hwnd
g_DefWinInfo = _GetDefaultWinInfoByStrg(hwndMain, Settings2.DefaultWindowPosition);
s_WinCurrentWidth = g_IniWinInfo.cx;
if (g_IniWinInfo.max) {
nCmdShow = SW_SHOWMAXIMIZED;
}
// manual (not automatic) reset & initial state: not signaled (TRUE, FALSE)
s_FileChgObsvrData.hEventFileChanged = CreateEvent(NULL, TRUE, FALSE, NULL);
s_FileChgObsvrData.hEventFileDeleted = CreateEvent(NULL, TRUE, FALSE, NULL);
if (Settings.TransparentMode) {
SetWindowTransparentMode(hwndMain, true, Settings2.OpacityLevel);
}
SetMenu(hwndMain, (Settings.ShowMenubar ? Globals.hMainMenu : NULL));
DrawMenuBar(hwndMain);
Globals.hwndMain = hwndMain; // make main window globaly available
HPATHL hfile_pth = Path_Copy(s_pthArgFilePath);
FileLoadFlags fLoadFlags = FLF_None;
// Source Encoding
Encoding_Forced(s_flagSetEncoding);
switch (s_flagChangeNotify) {
case FWM_DONT_CARE:
case FWM_INDICATORSILENT:
case FWM_MSGBOX:
case FWM_AUTORELOAD:
case FWM_EXCLUSIVELOCK:
FileWatching.FileWatchingMode = s_flagChangeNotify;
break;
case FWM_NO_INIT:
default:
FileWatching.FileWatchingMode = Settings.FileWatchingMode;
break;
}
// initial set text in front of ShowWindow()
EditSetNewText(Globals.hwndEdit, "", 0, false, false);
GetSetDoAnimateMinimize(Settings2.DrawAnimatedWindow ? 1 : 0);
ShowWindowAsync(s_hwndEditFrame, SW_SHOWDEFAULT);
ShowWindowAsync(Globals.hwndEdit, SW_SHOWDEFAULT);
//~SnapToWinInfoPos(hwndMain, g_IniWinInfo, SCR_NORMAL, SW_HIDE); ~ instead set all needed properties here:
SetWindowPos(hwndMain, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
if (!s_flagStartAsTrayIcon) {
UpdateWindow(hwndMain);
if (!Settings.ShowTitlebar) {
SetWindowLong(hwndMain, GWL_STYLE, GetWindowLong(hwndMain, GWL_STYLE) & ~WS_CAPTION);
}
}
else {
if (Settings.MinimizeToTray) {
MinimizeWndToTray(hwndMain);
}
else {
nCmdShow = SW_MINIMIZE;
}
ShowNotifyIcon(hwndMain, true);
SetNotifyIconTitle(hwndMain);
}
ShowWindow(hwndMain, nCmdShow);
bool bOpened = false;
// Pathname parameter
if (s_IsThisAnElevatedRelaunch || (Path_IsNotEmpty(s_pthArgFilePath) /*&& !g_flagNewFromClipboard*/))
{
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
// Open from Directory
Path_CanonicalizeEx(hfile_pth, Paths.WorkingDirectory);
if (!s_IsThisAnElevatedRelaunch && Path_IsExistingDirectory(hfile_pth)) {
if (OpenFileDlg(Globals.hwndMain, hfile_pth, hfile_pth)) {
bOpened = FileLoad(hfile_pth, fLoadFlags);
}
} else {
HPATHL const hpthFileToOpen = s_IsThisAnElevatedRelaunch ? s_hpthRelaunchElevatedFile : hfile_pth;
bOpened = FileLoad(hpthFileToOpen, fLoadFlags);
if (bOpened) {
if (s_IsThisAnElevatedRelaunch) {
if (Path_IsNotEmpty(hfile_pth)) {
Path_Reset(Paths.CurrentFile, Path_Get(hfile_pth));
} else {
Path_Empty(Paths.CurrentFile, false);
}
if (!s_flagLexerSpecified) {
Style_SetLexerFromFile(Globals.hwndEdit, Paths.CurrentFile);
}
// check for temp file and delete
if (s_IsThisAnElevatedRelaunch && Path_IsExistingFile(s_hpthRelaunchElevatedFile)) {
DeleteFileW(Path_Get(s_hpthRelaunchElevatedFile));
// delete possible .tmp guard
Path_RenameExtension(s_hpthRelaunchElevatedFile, L".tmp");
if (Path_IsExistingFile(s_hpthRelaunchElevatedFile)) {
DeleteFileW(Path_Get(s_hpthRelaunchElevatedFile));
}
SetSaveNeeded(true);
}
if (Path_IsNotEmpty(Paths.CurrentFile)) {
if (s_flagSaveOnRelaunch) {
FileSave(FSF_SaveAlways); // issued from elevation instances
}
}
}
else if (s_flagChangeNotify == FWM_AUTORELOAD) {
FileWatching.MonitoringLog = false; // will be reset in IDM_VIEW_CHASING_DOCTAIL
PostWMCommand(hwndMain, IDM_VIEW_CHASING_DOCTAIL);
}
}
}
Path_Empty(s_pthArgFilePath, false);
} else {
cpi_enc_t const forcedEncoding = Encoding_Forced(CPI_GET);
if (Encoding_IsValid(forcedEncoding)) {
Encoding_Current(forcedEncoding);
}
}
if (!bOpened) {
Path_Reset(hfile_pth, L"");
fLoadFlags = FLF_DontSave | FLF_New | FLF_SkipUnicodeDetect | FLF_SkipANSICPDetection;
FileLoad(hfile_pth, fLoadFlags); // init editor frame
}
// reset
Encoding_Forced(CPI_NONE);
s_flagQuietCreate = false;
s_flagKeepTitleExcerpt = false;
// undo / redo selections
if (UndoRedoSelectionUTArray != NULL) {
utarray_free(UndoRedoSelectionUTArray);
UndoRedoSelectionUTArray = NULL;
}
utarray_new(UndoRedoSelectionUTArray, &UndoRedoSelection_icd);
utarray_reserve(UndoRedoSelectionUTArray,256);
// Check for /c [if no file is specified] -- even if a file is specified
if (s_flagNewFromClipboard) {
if (SciCall_CanPaste()) {
bool bAutoIndent2 = Settings.AutoIndent;
Settings.AutoIndent = 0;
EditJumpTo(-1, 0);
UndoTransActionBegin();
if (!Sci_IsDocEmpty()) {
SciCall_NewLine();
}
SciCall_Paste();
SciCall_NewLine();
EndUndoTransAction();
Settings.AutoIndent = bAutoIndent2;
if (s_flagJumpTo) {
SciCall_SetYCaretPolicy(s_iCaretPolicyV | CARET_JUMPS, Settings2.CurrentLineVerticalSlop);
EditJumpTo(s_iInitialLine, s_iInitialColumn);
SciCall_SetYCaretPolicy(s_iCaretPolicyV, Settings2.CurrentLineVerticalSlop);
} else {
Sci_ScrollSelectionToView();
}
}
}
else {
if (s_flagJumpTo) { // Jump to position
SciCall_SetYCaretPolicy(s_iCaretPolicyV | CARET_JUMPS, Settings2.CurrentLineVerticalSlop);
EditJumpTo(s_iInitialLine, s_iInitialColumn);
SciCall_SetYCaretPolicy(s_iCaretPolicyV, Settings2.CurrentLineVerticalSlop);
}
else {
Sci_ScrollSelectionToView();
}
}
// Encoding
if (s_flagSetEncoding != CPI_NONE) {
SendMessage(Globals.hwndMain, WM_COMMAND, (WPARAM)MAKELONG(IDM_ENCODING_SELECT, IDM_ENCODING_SELECT + s_flagSetEncoding), 0);
s_flagSetEncoding = CPI_NONE;
}
// EOL mode
if (s_flagSetEOLMode != 0) {
SendWMCommand(Globals.hwndMain, IDM_LINEENDINGS_CRLF + s_flagSetEOLMode - 1);
s_flagSetEOLMode = 0;
}
// Match Text
if (g_flagMatchText && !IsFindPatternEmpty()) {
if (!Sci_IsDocEmpty()) {
SetFindReplaceData(); // s_FindReplaceData
if (g_flagMatchText & 2) {
if (!s_flagJumpTo) {
Sci_SetCaretScrollDocEnd();
}
EditFindPrev(Globals.hwndEdit, &s_FindReplaceData, false, false, false);
} else {
if (!s_flagJumpTo) {
SciCall_DocumentStart();
}
EditFindNext(Globals.hwndEdit, &s_FindReplaceData, false, false, false);
}
}
}
// Check for Paste Board option -- after loading files
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
s_hwndNextCBChain = SetClipboardViewer(Globals.hwndMain);
s_bLastCopyFromMe = false;
s_iLastCopyTime = 0;
SetTimer(Globals.hwndMain, ID_PASTEBOARDTIMER, 100, PasteBoardTimerProc);
}
// check if a lexer was specified from the command line
if (s_flagLexerSpecified) {
if (s_lpSchemeArg) {
Style_SetLexerFromName(Globals.hwndEdit, Paths.CurrentFile, s_lpSchemeArg);
LocalFree(s_lpSchemeArg); // StrDup()
s_lpSchemeArg = NULL;
} else if ((s_iInitialLexer >= 0) && (s_iInitialLexer < Style_NumOfLexers())) {
Style_SetLexerFromID(Globals.hwndEdit, s_iInitialLexer);
}
s_flagLexerSpecified = false;
}
// If start as tray icon, set current filename as tooltip
if (s_flagStartAsTrayIcon) {
SetNotifyIconTitle(Globals.hwndMain);
}
Globals.iSelectionMarkNumber = Globals.iMarkOccurrencesCount = Globals.iReplacedOccurrences = 0;
ResetMouseDWellTime();
// print file immediately and quit
if (Globals.CmdLnFlag_PrintFileAndLeave) {
WCHAR tchPageFmt[32] = { L'\0' };
WCHAR szDisplayName[MAX_PATH_EXPLICIT>>1];
GetLngString(IDS_MUI_UNTITLED, szDisplayName, COUNTOF(szDisplayName));
Path_GetDisplayName(szDisplayName, COUNTOF(szDisplayName), Paths.CurrentFile, NULL, true);
GetLngString(IDS_MUI_PRINT_PAGENUM, tchPageFmt, COUNTOF(tchPageFmt));
if (!EditPrint(Globals.hwndEdit, szDisplayName, tchPageFmt)) {
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_PRINT_ERROR, szDisplayName);
}
}
if (Globals.CmdLnFlag_PrintFileAndLeave || IsAppClosing()) {
CloseApplication();
}
Path_Release(hfile_pth);
s_bInitAppDone = true;
return Globals.hwndMain;
}
//=============================================================================
//
// MainWndProc()
//
// Messages are distributed to the MsgXXX-handlers
//
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
switch(umsg) {
case WM_CREATE:
return MsgCreate(hwnd, wParam, lParam);
case WM_SETFOCUS:
SetFocus(Globals.hwndEdit);
break;
case WM_CLOSE:
SetEvent(s_hEventAppIsClosing);
InstallFileWatching(false);
if (FileSave(FSF_Ask)) {
DestroyWindow(Globals.hwndMain);
}
else {
ResetEvent(s_hEventAppIsClosing);
InstallFileWatching(true);
}
break;
case WM_QUERYENDSESSION:
if (Settings.AutoSaveOptions & ASB_Shutdown) {
AutoSaveDoWork(FSF_EndSession);
}
else if (FileSave(FSF_Ask | FSF_EndSession)) {
return TRUE;
}
break;
case WM_POWERBROADCAST:
if (wParam == PBT_APMSUSPEND) {
// we only have 2 seconds to save current file
if (Settings.AutoSaveOptions & ASB_Suspend) {
AutoSaveDoWork(FSF_None);
}
}
break;
case WM_DESTROY:
case WM_ENDSESSION:
return MsgEndSession(hwnd, umsg, wParam, lParam);
case WM_SYSCOLORCHANGE:
// update Scintilla colors
SendMessage(Globals.hwndEdit, WM_SYSCOLORCHANGE, wParam, lParam);
// [[FallThrough]]
// Reinitialize theme-dependent values and resize windows
case WM_THEMECHANGED:
return MsgThemeChanged(hwnd, wParam, lParam);
case WM_DPICHANGED:
return MsgDPIChanged(hwnd, wParam, lParam);
case WM_SIZE:
return MsgSize(hwnd, wParam, lParam);
#ifdef D_NP3_WIN10_DARK_MODE
case WM_SETTINGCHANGE: {
if (IsColorSchemeChangeMessage(lParam)) {
RefreshTitleBarThemeColor(hwnd);
SendMessage(Globals.hwndEdit, WM_THEMECHANGED, 0, 0);
}
}
break;
#endif
case WM_DRAWITEM:
return MsgDrawItem(hwnd, wParam, lParam);
case WM_DROPFILES:
// see SCN_URIDROPPED
return MsgDropFiles(hwnd, wParam, lParam);
case WM_COPYDATA:
return MsgCopyData(hwnd, wParam, lParam);
case WM_CONTEXTMENU:
case WM_NCRBUTTONDOWN:
MsgContextMenu(hwnd, umsg, wParam, lParam);
break;
case WM_ENTERMENULOOP:
return MsgEnterMenuLoop(hwnd, wParam);
case WM_INITMENU:
return MsgInitMenu(hwnd, wParam, lParam);
case WM_EXITMENULOOP:
return MsgExitMenuLoop(hwnd, wParam);
case WM_NOTIFY:
return MsgNotify(hwnd, wParam, lParam);
//~case WM_KEYDOWN:
//~ return MsgKeyDown(hwnd, wParam, lParam);
case WM_FILECHANGEDNOTIFY:
return MsgFileChangeNotify(hwnd, wParam, lParam);
case WM_RESTORE_UNDOREDOACTION:
_RestoreActionSelection((LONG)lParam, (DoAction)wParam);
break;
//case WM_PARENTNOTIFY:
// if (iLoWParam & WM_DESTROY) {
// if (IsWindow(hDlgFindReplace) && (hDlgFindReplace == (HWND)lParam)) {
// hDlgFindReplace = NULL;
// }
// }
// break;
case WM_COMMAND:
return MsgCommand(hwnd, umsg, wParam, lParam);
case WM_TRAYMESSAGE:
return MsgTrayMessage(hwnd, wParam, lParam);
//// This message is posted before Notepad3 reactivates itself
//case WM_CHANGENOTIFYCLEAR:
// bPendingChangeNotify = false;
// break;
case WM_DRAWCLIPBOARD:
if (!s_bLastCopyFromMe) {
s_iLastCopyTime = GetTicks_ms();
} else {
s_bLastCopyFromMe = false;
}
if (s_hwndNextCBChain) {
SendMessage(s_hwndNextCBChain,WM_DRAWCLIPBOARD,wParam,lParam);
}
break;
case WM_CHANGECBCHAIN:
if ((HWND)wParam == s_hwndNextCBChain) {
s_hwndNextCBChain = (HWND)lParam;
}
if (s_hwndNextCBChain) {
SendMessage(s_hwndNextCBChain,WM_CHANGECBCHAIN,lParam,wParam);
}
break;
case WM_SYSCOMMAND:
return MsgSysCommand(hwnd, umsg, wParam, lParam);
case WM_MBUTTONDOWN: {
DocPos const pos = SciCall_CharPositionFromPointClose(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
if (pos >= 0) {
HandleHotSpotURLClicked(pos, OPEN_WITH_BROWSER);
}
}
break;
//case WM_LBUTTONDBLCLK:
// //return DefWindowProc(hwnd, umsg, wParam, lParam);
// break;
case WM_MOUSEWHEEL:
if (wParam & MK_CONTROL) {
ShowZoomCallTip();
} else if (wParam & MK_RBUTTON) {
// Hold RIGHT MOUSE BUTTON and SCROLL to cycle through UNDO history
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) {
s_bUndoRedoScroll = true;
//LimitNotifyEvents(EVM_UndoRedo);
SciCall_Redo();
//RestoreNotifyEvents();
} else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) {
s_bUndoRedoScroll = true;
//LimitNotifyEvents(EVM_UndoRedo);
SciCall_Undo();
//RestoreNotifyEvents();
}
}
break;
case WM_INPUTLANGCHANGE:
Globals.bIsCJKInputCodePage = IsDBCSCodePage(Scintilla_InputCodePage());
break;
case WM_UAHINITMENU:
case WM_UAHDRAWMENU:
case WM_UAHDRAWMENUITEM:
case WM_UAHDESTROYWINDOW:
case WM_UAHMEASUREMENUITEM:
case WM_UAHNCPAINTMENUPOPUP:
return MsgUahMenuBar(hwnd, umsg, wParam, lParam);
case WM_NCACTIVATE:
case WM_NCPAINT: {
LRESULT const res = DefWindowProc(hwnd, umsg, wParam, lParam);
if (UseDarkMode()) {
// handle dark menu bottom line
MsgUahMenuBar(hwnd, umsg, wParam, lParam);
}
return res;
}
default:
if (umsg == s_msgTaskbarCreated) {
if (!IsWindowVisible(hwnd)) {
ShowNotifyIcon(hwnd, true);
}
SetNotifyIconTitle(hwnd);
}
return DefWindowProc(hwnd, umsg, wParam, lParam);
}
return FALSE;
}
//=============================================================================
//
// _SetWrapStartIndent()
//
static void _SetWrapStartIndent()
{
int i = 0;
switch (Settings.WordWrapIndent) {
case 1:
i = 1;
break;
case 2:
i = 2;
break;
case 3:
i = (Globals.fvCurFile.iIndentWidth) ? 1 * Globals.fvCurFile.iIndentWidth : 1 * Globals.fvCurFile.iTabWidth;
break;
case 4:
i = (Globals.fvCurFile.iIndentWidth) ? 2 * Globals.fvCurFile.iIndentWidth : 2 * Globals.fvCurFile.iTabWidth;
break;
default:
break;
}
SciCall_SetWrapStartIndent(i);
}
//=============================================================================
//
// _SetWrapIndentMode()
//
static void _SetWrapIndentMode()
{
BeginWaitCursorUID(Flags.bHugeFileLoadState, IDS_MUI_SB_WRAP_LINES);
Sci_SetWrapModeEx(GET_WRAP_MODE());
if (Settings.WordWrapIndent == 5) {
SciCall_SetWrapIndentMode(SC_WRAPINDENT_SAME);
} else if (Settings.WordWrapIndent == 6) {
SciCall_SetWrapIndentMode(SC_WRAPINDENT_INDENT);
} else if (Settings.WordWrapIndent == 7) {
SciCall_SetWrapIndentMode(SC_WRAPINDENT_DEEPINDENT);
} else {
_SetWrapStartIndent();
SciCall_SetWrapIndentMode(SC_WRAPINDENT_FIXED);
}
EndWaitCursor();
}
//=============================================================================
//
// _SetWrapVisualFlags()
//
static void _SetWrapVisualFlags(HWND hwndEditCtrl)
{
UNREFERENCED_PARAMETER(hwndEditCtrl);
if (Settings.ShowWordWrapSymbols) {
int wrapVisualFlags = 0;
int wrapVisualFlagsLocation = 0;
if (Settings.WordWrapSymbols == 0) {
Settings.WordWrapSymbols = 22;
}
switch (Settings.WordWrapSymbols % 10) {
case 1:
wrapVisualFlags |= SC_WRAPVISUALFLAG_END;
wrapVisualFlagsLocation |= SC_WRAPVISUALFLAGLOC_END_BY_TEXT;
break;
case 2:
wrapVisualFlags |= SC_WRAPVISUALFLAG_END;
break;
}
switch (((Settings.WordWrapSymbols % 100) - (Settings.WordWrapSymbols % 10)) / 10) {
case 1:
wrapVisualFlags |= SC_WRAPVISUALFLAG_START;
wrapVisualFlagsLocation |= SC_WRAPVISUALFLAGLOC_START_BY_TEXT;
break;
case 2:
wrapVisualFlags |= SC_WRAPVISUALFLAG_START;
break;
}
SciCall_SetWrapVisualFlags(wrapVisualFlags);
SciCall_SetWrapVisualFlagsLocation(wrapVisualFlagsLocation);
} else {
SciCall_SetWrapVisualFlags(0);
}
}
//=============================================================================
//
// InitializeSciEditCtrl()
//
static void _InitializeSciEditCtrl(HWND hwndEditCtrl)
{
InitWindowCommon(hwndEditCtrl, true);
SciCall_SetTechnology(Settings.RenderingTechnology);
Settings.RenderingTechnology = SciCall_GetTechnology();
SciCall_SetBidirectional(Settings.Bidirectional); // experimental
Settings.Bidirectional = SciCall_GetBidirectional();
if (SciCall_SupportsFeature(SC_SUPPORTS_THREAD_SAFE_MEASURE_WIDTHS)) {
SciCall_SetLayoutThreads(max_dw(2, GetNumberOfProcessors())); // MultiThreading Layout (SCI v5.2.0)
}
//~SciCall_SetPhasesDraw(SC_PHASES_TWO); // (= default)
SciCall_SetPhasesDraw(SC_PHASES_MULTIPLE);
SciCall_SetLayoutCache(SC_CACHE_PAGE); //~ SC_CACHE_DOCUMENT ~ beware of memory consumption !
// Idle Styling (very large text)
SciCall_SetIdleStyling(SC_IDLESTYLING_NONE); // needed for focused view
SciCall_SetModEventMask(EVM_Default);
SciCall_SetCommandEvents(false); // speedup folding
SciCall_StyleSetCharacterSet(SC_CHARSET_DEFAULT);
SciCall_SetCodePage(SC_CP_UTF8); // fixed internal UTF-8 (Sci:default)
SciCall_SetMargins(NUMBER_OF_MARGINS);
SciCall_SetMarginTypeN(MARGIN_SCI_LINENUM, SC_MARGIN_NUMBER);
SciCall_SetMarginTypeN(MARGIN_SCI_BOOKMRK, SC_MARGIN_SYMBOL);
SciCall_SetMarginMaskN(MARGIN_SCI_BOOKMRK, ~SC_MASK_FOLDERS & ~MARGIN_MARK_HISTORY_MASK);
SciCall_SetMarginTypeN(MARGIN_SCI_CHGHIST, SC_MARGIN_SYMBOL);
SciCall_SetMarginMaskN(MARGIN_SCI_CHGHIST, MARGIN_MARK_HISTORY_MASK);
SciCall_SetMarginTypeN(MARGIN_SCI_FOLDING, SC_MARGIN_COLOUR);
SciCall_SetMarginMaskN(MARGIN_SCI_FOLDING, SC_MASK_FOLDERS);
SciCall_SetEOLMode(Settings.DefaultEOLMode);
SciCall_SetPasteConvertEndings(true);
SciCall_UsePopUp(SC_POPUP_TEXT);
SciCall_SetScrollWidthTracking(true);
// SciCall_SetScrollWidth(2000);
SciCall_SetMultipleSelection(true);
SciCall_SetMultiPaste(SC_MULTIPASTE_EACH); // paste into rectangular selection
SciCall_SetAdditionalSelectionTyping(true);
SciCall_SetMouseSelectionRectangularSwitch(true);
SciCall_SetVirtualSpaceOptions(NP3_VIRTUAL_SPACE_ACCESS_OPTIONS);
SciCall_AutoCSetMulti(SC_MULTIAUTOC_EACH);
SciCall_SetAdditionalCaretsBlink(true);
SciCall_SetAdditionalCaretsVisible(true);
// assign command keys
SciCall_AssignCmdKey(SCK_NEXT + (SCMOD_CTRL << 16), SCI_PARADOWN);
SciCall_AssignCmdKey(SCK_PRIOR + (SCMOD_CTRL << 16), SCI_PARAUP);
SciCall_AssignCmdKey(SCK_NEXT + ((SCMOD_CTRL | SCMOD_SHIFT) << 16), SCI_PARADOWNEXTEND);
SciCall_AssignCmdKey(SCK_PRIOR + ((SCMOD_CTRL | SCMOD_SHIFT) << 16), SCI_PARAUPEXTEND);
SciCall_AssignCmdKey(SCK_HOME + (0 << 16), SCI_VCHOMEWRAP);
SciCall_AssignCmdKey(SCK_END + (0 << 16), SCI_LINEENDWRAP);
SciCall_AssignCmdKey(SCK_HOME + (SCMOD_SHIFT << 16), SCI_VCHOMEWRAPEXTEND);
SciCall_AssignCmdKey(SCK_END + (SCMOD_SHIFT << 16), SCI_LINEENDWRAPEXTEND);
// set indicator styles (foreground and alpha maybe overridden by style settings)
SciCall_IndicSetStyle(INDIC_NP3_MATCH_BRACE, INDIC_FULLBOX);
SciCall_IndicSetFore(INDIC_NP3_MATCH_BRACE, RGB(0x00, 0xFF, 0x00));
SciCall_IndicSetAlpha(INDIC_NP3_MATCH_BRACE, 120);
SciCall_IndicSetOutlineAlpha(INDIC_NP3_MATCH_BRACE, 120);
SciCall_IndicSetStyle(INDIC_NP3_BAD_BRACE, INDIC_FULLBOX);
SciCall_IndicSetFore(INDIC_NP3_BAD_BRACE, RGB(0xFF, 0x00, 0x00));
SciCall_IndicSetAlpha(INDIC_NP3_BAD_BRACE, 120);
SciCall_IndicSetOutlineAlpha(INDIC_NP3_BAD_BRACE, 120);
if (!Settings2.UseOldStyleBraceMatching) {
SciCall_BraceHighLightIndicator(true, INDIC_NP3_MATCH_BRACE);
SciCall_BraceBadLightIndicator(true, INDIC_NP3_BAD_BRACE);
}
SciCall_IndicSetStyle(INDIC_NP3_MARK_OCCURANCE, INDIC_ROUNDBOX);
SciCall_IndicSetFore(INDIC_NP3_MARK_OCCURANCE, RGB(0x00, 0x00, 0xFF));
SciCall_IndicSetAlpha(INDIC_NP3_MARK_OCCURANCE, 10);
SciCall_IndicSetOutlineAlpha(INDIC_NP3_MARK_OCCURANCE, 10);
SciCall_IndicSetStyle(INDIC_NP3_HYPERLINK, INDIC_TEXTFORE);
SciCall_IndicSetFore(INDIC_NP3_HYPERLINK, RGB(0x00, 0x00, 0xA0));
SciCall_IndicSetStyle(INDIC_NP3_HYPERLINK_U, INDIC_COMPOSITIONTHIN);
SciCall_IndicSetFore(INDIC_NP3_HYPERLINK_U, RGB(0x00, 0x00, 0xA0));
SciCall_IndicSetHoverStyle(INDIC_NP3_HYPERLINK, INDIC_TEXTFORE);
SciCall_IndicSetHoverFore(INDIC_NP3_HYPERLINK, RGB(0x00, 0x00, 0xFF));
SciCall_IndicSetHoverStyle(INDIC_NP3_HYPERLINK_U, INDIC_COMPOSITIONTHICK);
SciCall_IndicSetHoverFore(INDIC_NP3_HYPERLINK_U, RGB(0x00, 0x00, 0xFF));
SciCall_IndicSetStyle(INDIC_NP3_COLOR_DEF, INDIC_COMPOSITIONTHIN /*INDIC_HIDDEN*/); // MARKER only
SciCall_IndicSetUnder(INDIC_NP3_COLOR_DEF, true);
SciCall_IndicSetAlpha(INDIC_NP3_COLOR_DEF, SC_ALPHA_TRANSPARENT); // reset on hover
SciCall_IndicSetOutlineAlpha(INDIC_NP3_COLOR_DEF, SC_ALPHA_OPAQUE);
SciCall_IndicSetHoverStyle(INDIC_NP3_COLOR_DEF, INDIC_HIDDEN); // initially hidden, INDIC_FULLBOX on hover
SciCall_IndicSetHoverFore(INDIC_NP3_COLOR_DEF, RGB(0x00, 0x00, 0x00)); // recalc on hover
SciCall_IndicSetStyle(INDIC_NP3_COLOR_DEF_T, INDIC_HIDDEN); // invisible
SciCall_IndicSetHoverStyle(INDIC_NP3_COLOR_DEF_T, INDIC_HIDDEN); // initially hidden, INDIC_TEXTFORE on hover
SciCall_IndicSetHoverFore(INDIC_NP3_COLOR_DEF_T, RGB(0x00, 0x00, 0x00));
SciCall_IndicSetStyle(INDIC_NP3_UNICODE_POINT, INDIC_COMPOSITIONTHIN /*INDIC_HIDDEN*/);
//SciCall_IndicSetUnder(INDIC_NP3_UNICODE_POINT, false);
SciCall_IndicSetAlpha(INDIC_NP3_UNICODE_POINT, SC_ALPHA_TRANSPARENT);
SciCall_IndicSetOutlineAlpha(INDIC_NP3_UNICODE_POINT, SC_ALPHA_OPAQUE);
SciCall_IndicSetHoverStyle(INDIC_NP3_UNICODE_POINT, INDIC_ROUNDBOX);
//SciCall_IndicSetHoverFore(INDIC_NP3_UNICODE_POINT, RGB(0xE0, 0xE0, 0xE0);
SciCall_IndicSetStyle(INDIC_NP3_MULTI_EDIT, INDIC_ROUNDBOX);
SciCall_IndicSetFore(INDIC_NP3_MULTI_EDIT, RGB(0xFF, 0xA5, 0x00));
SciCall_IndicSetAlpha(INDIC_NP3_MULTI_EDIT, 60);
SciCall_IndicSetOutlineAlpha(INDIC_NP3_MULTI_EDIT, 180);
// No SC_AUTOMATICFOLD_CLICK, performed by
SciCall_SetAutomaticFold(SC_AUTOMATICFOLD_SHOW | SC_AUTOMATICFOLD_CHANGE);
// Properties
SciCall_SetCaretSticky(SC_CARETSTICKY_OFF);
//SciCall_SetCaretSticky(SC_CARETSTICKY_WHITESPACE);
ResetMouseDWellTime();
int const iCaretPolicy = CARET_SLOP | CARET_EVEN | CARET_STRICT;
SciCall_SetXCaretPolicy(iCaretPolicy, Settings2.CurrentLineHorizontalSlop);
s_iCaretPolicyV = (Settings2.CurrentLineVerticalSlop > 0) ? iCaretPolicy : CARET_EVEN;
SciCall_SetXCaretPolicy(iCaretPolicy, Settings2.CurrentLineHorizontalSlop);
SciCall_SetYCaretPolicy(s_iCaretPolicyV, Settings2.CurrentLineVerticalSlop);
SciCall_SetVisiblePolicy(s_iCaretPolicyV, Settings2.CurrentLineVerticalSlop);
SciCall_SetEndAtLastLine(!Settings.ScrollPastEOF);
// Tabs
SciCall_SetUseTabs(!Globals.fvCurFile.bTabsAsSpaces);
SciCall_SetTabIndents(Globals.fvCurFile.bTabIndents);
SciCall_SetBackSpaceUnIndents(Settings.BackspaceUnindents);
SciCall_SetTabWidth(Globals.fvCurFile.iTabWidth);
SciCall_SetIndent(Globals.fvCurFile.iIndentWidth);
// Indent Guides
Style_SetIndentGuides(hwndEditCtrl, Settings.ShowIndentGuides);
// Word Wrap
_SetWrapIndentMode(hwndEditCtrl);
_SetWrapVisualFlags(hwndEditCtrl);
// Long Lines
if (Settings.MarkLongLines) {
SciCall_SetEdgeMode((Settings.LongLineMode == EDGE_BACKGROUND) ? EDGE_BACKGROUND : EDGE_LINE);
} else {
SciCall_SetEdgeMode(EDGE_NONE);
}
SciCall_SetEdgeColumn(Settings.LongLinesLimit);
// general margin
SciCall_SetMarginOptions(SC_MARGINOPTION_SUBLINESELECT);
// Nonprinting characters
SciCall_SetViewWS(Settings.ViewWhiteSpace ? SCWS_VISIBLEALWAYS : SCWS_INVISIBLE);
SciCall_SetViewEOL(Settings.ViewEOLs);
// IME Interaction
SciCall_SetIMEInteraction(Settings2.IMEInteraction);
// word delimiter handling
EditInitWordDelimiter(hwndEditCtrl);
EditReducedWordSeparatorSet(hwndEditCtrl, Settings.AccelWordNavigation);
SciCall_ClearRegisteredImages();
SciCall_AutoCSetOptions(SC_AUTOCOMPLETE_FIXED_SIZE);
SciCall_AutoCSetIgnoreCase(true);
//~SciCall_AutoCSetCaseInsensitiveBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE);
SciCall_AutoCSetOrder(SC_ORDER_PRESORTED); // already sorted ~ SC_ORDER_PERFORMSORT
}
//=============================================================================
//
// _EvalTinyExpr() - called on '?' or ENTER insert
//
static bool _EvalTinyExpr(bool qmark)
{
if (!Settings.EvalTinyExprOnSelection) {
return false;
}
DocPos const posSelStart = SciCall_GetSelectionStart();
DocPos const posBegin = qmark ? SciCall_PositionBefore(posSelStart) : posSelStart;
DocPos posBefore = SciCall_PositionBefore(posBegin);
char chBefore = SciCall_GetCharAt(posBefore);
while (IsBlankCharA(chBefore) && (posBefore > 0)) {
posBefore = SciCall_PositionBefore(posBefore);
chBefore = SciCall_GetCharAt(posBefore);
}
if (chBefore == '=') { // got "=?" or ENTER : evaluate expression trigger
int const lineLen = (int)SciCall_LineLength(SciCall_LineFromPosition(posSelStart));
char * const lineBuf = (char *)AllocMem((lineLen + 1), HEAP_ZERO_MEMORY);
WCHAR * const lineBufW = (WCHAR *)AllocMem((lineLen + 1) * sizeof(WCHAR), HEAP_ZERO_MEMORY);
if (lineBuf && lineBufW) {
if (posSelStart < SciCall_GetCurrentPos()) {
SciCall_SwapMainAnchorCaret();
}
DocPos const iLnCaretPos = SciCall_GetCurLine(lineLen, lineBuf);
lineBuf[iLnCaretPos - (posSelStart - posBefore)] = '\0'; // exclude "=?"
char const defchar = (char)te_invalid_chr();
MultiByteToWideChar(Encoding_SciCP, 0, lineBuf, -1, lineBufW, (lineLen + 1));
int const len = WideCharToMultiByte(te_cp(), (WC_COMPOSITECHECK | WC_DISCARDNS), lineBufW, -1, lineBuf, (lineLen + 1), &defchar, NULL);
FreeMem(lineBufW);
if (!len) {
return false;
}
// canonicalize fetched line
StrDelChrA(lineBuf, chr_currency);
const char *p = lineBuf;
while (IsBlankCharA(*p)) {
++p;
}
double dExprEval = 0.0;
te_int_t exprErr = 1;
while (*p && exprErr) {
dExprEval = te_interp(p, &exprErr);
// proceed to next possible expression
while (*++p && exprErr && !(te_is_num(p) || te_is_op(p))) {}
}
FreeMem(lineBuf);
if (!exprErr) {
char chExpr[80] = { '\0' };
TinyExprToStringA(chExpr, COUNTOF(chExpr), dExprEval);
SciCall_ReplaceSel("");
SciCall_SetSel(posBegin, posSelStart);
SciCall_ReplaceSel(chExpr);
return true;
}
}
}
return false;
}
//=============================================================================
//
// _InitEditWndFrame()
//
static void _InitEditWndFrame()
{
s_cxEditFrame = 0;
s_cyEditFrame = 0;
s_bIsAppThemed = IsAppThemed();
InitWindowCommon(s_hwndEditFrame, true);
if (s_bIsAppThemed) {
SetWindowLongPtr(Globals.hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(Globals.hwndEdit, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE);
SetWindowPos(Globals.hwndEdit, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
if (!IsWindowsVistaOrGreater()) {
SetWindowPos(s_hwndEditFrame, Globals.hwndEdit, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
ShowWindow(s_hwndEditFrame, SW_HIDE);
RECT rc, rc2;
GetClientRect(s_hwndEditFrame, &rc);
GetWindowRect(s_hwndEditFrame, &rc2);
s_cxEditFrame = ((rc2.right - rc2.left) - (rc.right - rc.left)) / 2;
s_cyEditFrame = ((rc2.bottom - rc2.top) - (rc.bottom - rc.top)) / 2;
}
} else {
SetWindowLongPtr(Globals.hwndEdit, GWL_EXSTYLE, WS_EX_CLIENTEDGE | GetWindowLongPtr(Globals.hwndEdit, GWL_EXSTYLE));
SetWindowPos(Globals.hwndEdit, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
ShowWindow(Globals.hwndEdit, SW_HIDE);
}
}
//=============================================================================
//
// MsgCreate() - Handles WM_CREATE
//
//
LRESULT MsgCreate(HWND hwnd, WPARAM wParam,LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
#ifdef D_NP3_WIN10_DARK_MODE
if (IsDarkModeSupported()) {
AllowDarkModeForWindowEx(hwnd, CheckDarkModeEnabled());
RefreshTitleBarThemeColor(hwnd);
}
#endif
HINSTANCE const hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
// Setup edit control
Globals.hwndEdit = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"Scintilla",
NULL,
(WS_CHILD | WS_CLIPSIBLINGS) & ~WS_VISIBLE,
0, 0, 0, 0,
hwnd,
(HMENU)IDC_EDIT,
hInstance,
NULL);
InitScintillaHandle(Globals.hwndEdit);
_InitializeSciEditCtrl(Globals.hwndEdit);
// Create Border Frame
s_hwndEditFrame = CreateWindowEx(
WS_EX_CLIENTEDGE,
WC_LISTVIEW,
NULL,
WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0, 0, 8, 8,
hwnd,
(HMENU)IDC_EDITFRAME,
hInstance,
NULL);
_InitEditWndFrame();
// Create Toolbar and Statusbar
CreateBars(hwnd, hInstance);
// Window Initialization
(void)CreateWindow(
WC_STATIC,
NULL,
WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0,0,10,10,
hwnd,
(HMENU)IDC_FILENAME,
hInstance,
NULL);
SetDlgItemText(hwnd,IDC_FILENAME,Path_Get(Paths.CurrentFile));
(void)CreateWindow(
WC_STATIC,
NULL,
WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
10,10,10,10,
hwnd,
(HMENU)IDC_REUSELOCK,
hInstance,
NULL);
SetDlgItemInt(hwnd,IDC_REUSELOCK,(UINT)GetTicks_ms(),false);
// Menu
//~SetMenuDefaultItem(GetSubMenu(GetMenu(hwnd),0),0);
// Drag & Drop
DragAcceptFiles(hwnd,TRUE);
if (Globals.hwndEdit == NULL || s_hwndEditFrame == NULL || Globals.hwndStatus == NULL || Globals.hwndToolbar == NULL || Globals.hwndRebar == NULL) {
return -1LL;
}
//~ Style_SetDefaultLexer(Globals.hwndEdit); -- done by WM_THEMECHANGED
ShowWindow(Globals.hwndEdit, SW_HIDE);
Encoding_Current(Settings.DefaultEncoding);
SciCall_SetZoom(g_IniWinInfo.zoom ? g_IniWinInfo.zoom : 100);
return 0LL;
}
//=============================================================================
//
// SelectExternalToolBar() - Select and Load an external Bitmap as ToolBarImage
//
bool SelectExternalToolBar(HWND hwnd)
{
UNREFERENCED_PARAMETER(hwnd);
HPATHL hfile_pth = Path_Allocate(NULL);
Path_WriteAccessBuf(hfile_pth, CMDLN_LENGTH_LIMIT);
WCHAR wchFilter[MIDSZ_BUFFER] = { L'\0' };
GetLngString(IDS_MUI_FILTER_BITMAP, wchFilter, COUNTOF(wchFilter));
PrepareFilterStr(wchFilter);
OPENFILENAME ofn = { sizeof(OPENFILENAME) };
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = wchFilter;
ofn.lpstrFile = Path_WriteAccessBuf(hfile_pth, 0);
ofn.lpstrDefExt = L"bmp";
ofn.nMaxFile = (DWORD)Path_GetBufCount(hfile_pth);
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_DONTADDTORECENT
| OFN_PATHMUSTEXIST | OFN_SHAREAWARE | OFN_NODEREFERENCELINKS;
if (GetOpenFileNameW(&ofn)) {
Path_Sanitize(hfile_pth);
Path_CanonicalizeEx(hfile_pth, Paths.ModuleDirectory);
Path_Reset(g_tchToolbarBitmap, Path_Get(hfile_pth));
Path_RelativeToApp(g_tchToolbarBitmap, true, true, true);
if (Globals.bCanSaveIniFile) {
IniFileSetString(Paths.IniFile, L"Toolbar Images", L"BitmapDefault", Path_Get(g_tchToolbarBitmap));
}
}
bool res = false;
if (Path_IsNotEmpty(hfile_pth)) {
WCHAR strFileName[MAX_PATH_EXPLICIT] = { 0 };
WCHAR strNewFileName[MAX_PATH_EXPLICIT] = { 0 };
Path_RenameExtension(hfile_pth, NULL); // remove
StringCchCopy(strFileName, COUNTOF(strFileName), Path_FindFileName(hfile_pth));
Path_RemoveFileSpec(hfile_pth);
if (Globals.bCanSaveIniFile) {
StringCchCopy(strNewFileName, COUNTOF(strNewFileName), strFileName);
StringCchCat(strNewFileName, COUNTOF(strNewFileName), L"Hot.bmp");
HPATHL hfile_hot_pth = Path_Copy(hfile_pth);
Path_Append(hfile_hot_pth, strNewFileName);
if (Path_IsExistingFile(hfile_hot_pth)) {
Path_Reset(g_tchToolbarBitmapHot, Path_Get(hfile_hot_pth));
Path_RelativeToApp(g_tchToolbarBitmapHot, true, true, true);
IniFileSetString(Paths.IniFile, L"Toolbar Images", L"BitmapHot", Path_Get(g_tchToolbarBitmapHot));
} else {
Path_Reset(g_tchToolbarBitmapHot, L"");
IniFileDelete(Paths.IniFile, L"Toolbar Images", L"BitmapHot", false);
}
Path_Release(hfile_hot_pth);
}
if (Globals.bCanSaveIniFile) {
StringCchCopy(strNewFileName, COUNTOF(strNewFileName), strFileName);
StringCchCat(strNewFileName, COUNTOF(strNewFileName), L"Disabled.bmp");
HPATHL hfile_dis_pth = Path_Copy(hfile_pth);
Path_Append(hfile_dis_pth, strNewFileName);
if (Path_IsExistingFile(hfile_dis_pth)) {
Path_Reset(g_tchToolbarBitmapDisabled, Path_Get(hfile_dis_pth));
Path_RelativeToApp(g_tchToolbarBitmapDisabled, true, true, true);
IniFileSetString(Paths.IniFile, L"Toolbar Images", L"BitmapDisabled", Path_Get(g_tchToolbarBitmapDisabled));
} else {
Path_Reset(g_tchToolbarBitmapDisabled, L"");
IniFileDelete(Paths.IniFile, L"Toolbar Images", L"BitmapDisabled", false);
}
Path_Release(hfile_dis_pth);
}
Settings.ToolBarTheme = 2;
res = true;
} else {
IniFileDelete(Paths.IniFile, L"Toolbar Images", L"BitmapHot", false);
IniFileDelete(Paths.IniFile, L"Toolbar Images", L"BitmapDisabled", false);
}
Path_Release(hfile_pth);
return res;
}
//=============================================================================
//
// LoadBitmapFile()
//
static HBITMAP LoadBitmapFile(const HPATHL hpath)
{
HBITMAP hbmp = NULL;
if (Path_IsExistingFile(hpath)) {
hbmp = (HBITMAP)LoadImage(NULL, Path_Get(hpath), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
bool bDimOK = false;
int height = 16;
if (hbmp) {
BITMAP bmp = { 0 };
GetObject(hbmp, sizeof(BITMAP), &bmp);
height = bmp.bmHeight;
bDimOK = (bmp.bmWidth >= (height * NUMTOOLBITMAPS));
}
if (!bDimOK) {
InfoBoxLng(MB_ICONWARNING, L"NotSuitableToolbarDim", IDS_MUI_ERR_BITMAP, Path_Get(hpath),
(height * NUMTOOLBITMAPS), height, NUMTOOLBITMAPS);
}
}
else {
WCHAR displayName[80];
Path_GetDisplayName(displayName, 80, hpath, L"<unknown>", false);
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_ERR_LOADFILE, displayName);
}
return hbmp;
}
//=============================================================================
//
// CreateScaledImageListFromBitmap()
//
static HIMAGELIST XXX_CreateScaledImageListFromBitmap(HWND hWnd, HBITMAP hBmp)
{
BITMAP bmp = { 0 };
GetObject(hBmp, sizeof(BITMAP), &bmp);
int const mod = bmp.bmWidth % NUMTOOLBITMAPS;
int const cx = (bmp.bmWidth - mod) / NUMTOOLBITMAPS;
int const cy = bmp.bmHeight;
HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, NUMTOOLBITMAPS, NUMTOOLBITMAPS);
ImageList_AddMasked(himl, hBmp, CLR_DEFAULT);
UINT const dpi = Scintilla_GetWindowDPI(hWnd);
if (!Settings.DpiScaleToolBar || (dpi == USER_DEFAULT_SCREEN_DPI)) {
return himl; // default DPI, we are done
}
// Scale button icons/images
int const scx = ScaleIntToDPI(hWnd, cx);
int const scy = ScaleIntToDPI(hWnd, cy);
HIMAGELIST hsciml = ImageList_Create(scx, scy, ILC_COLOR32 | ILC_MASK | ILC_HIGHQUALITYSCALE, NUMTOOLBITMAPS, NUMTOOLBITMAPS);
for (int i = 0; i < NUMTOOLBITMAPS; ++i) {
HICON const hicon = ImageList_GetIcon(himl, i, ILD_TRANSPARENT | ILD_PRESERVEALPHA | ILD_SCALE);
ImageList_AddIcon(hsciml, hicon);
DestroyIcon(hicon);
}
ImageList_Destroy(himl);
return hsciml;
}
//=============================================================================
//
// CreateScaledImageListFromBitmap()
//
static HIMAGELIST CreateScaledImageListFromBitmap(HWND hWnd, HBITMAP hBmp)
{
BITMAP bmp = { 0 };
GetObject(hBmp, sizeof(BITMAP), &bmp);
int const numOfToolBitmaps = (int)(bmp.bmWidth / bmp.bmHeight);
int const mod = bmp.bmWidth % numOfToolBitmaps;
int const cx = (bmp.bmWidth - mod) / numOfToolBitmaps;
int const cy = bmp.bmHeight;
HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, numOfToolBitmaps, numOfToolBitmaps);
ImageList_AddMasked(himl, hBmp, CLR_DEFAULT);
UINT const dpi = Scintilla_GetWindowDPI(hWnd);
if (!Settings.DpiScaleToolBar || (dpi == USER_DEFAULT_SCREEN_DPI)) {
return himl; // default DPI, we are done
}
// Scale button icons/images
int const scx = ScaleIntToDPI(hWnd, cx);
int const scy = ScaleIntToDPI(hWnd, cy);
HIMAGELIST hsciml = ImageList_Create(scx, scy, ILC_COLOR32 | ILC_MASK | ILC_HIGHQUALITYSCALE, numOfToolBitmaps, numOfToolBitmaps);
for (int i = 0; i < numOfToolBitmaps; ++i) {
HICON const hicon = ImageList_GetIcon(himl, i, ILD_TRANSPARENT | ILD_PRESERVEALPHA | ILD_SCALE);
ImageList_AddIcon(hsciml, hicon);
DestroyIcon(hicon);
}
ImageList_Destroy(himl);
return hsciml;
}
//==== Toolbar Style ==========================================================
#define NP3_WS_TOOLBAR (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | \
TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | TBSTYLE_ALTDRAG | TBSTYLE_LIST | \
CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_ADJUSTABLE)
//==== ReBar Style ============================================================
#define NP3_WS_REBAR (WS_CHILD | WS_CLIPCHILDREN | WS_BORDER | RBS_VARHEIGHT | \
RBS_BANDBORDERS | CCS_NODIVIDER | CCS_NOPARENTALIGN)
//=============================================================================
//
// CreateBars() - Create Toolbar and Statusbar
//
//
void CreateBars(HWND hwnd, HINSTANCE hInstance)
{
DWORD dwToolbarStyle = NP3_WS_TOOLBAR /*| TBSTYLE_CUSTOMERASE */ | TBSTYLE_TRANSPARENT;
DWORD dwToolbarExStyle = TBSTYLE_EX_DOUBLEBUFFER /* | TBSTYLE_EX_HIDECLIPPEDBUTTONS */;
if (Settings.ToolBarTheme < 0) { // undefined: determine High DPI screen
UINT const dpi = Scintilla_GetWindowDPI(hwnd);
Settings.ToolBarTheme = (dpi < LargeIconDPI()) ? 0 : 1;
}
if (Globals.hwndToolbar) {
HIMAGELIST himl = (HIMAGELIST)SendMessage(Globals.hwndToolbar, TB_GETIMAGELIST, 0, 0);
if (himl) {
ImageList_Destroy(himl);
}
himl = (HIMAGELIST)SendMessage(Globals.hwndToolbar, TB_GETHOTIMAGELIST, 0, 0);
if (himl) {
ImageList_Destroy(himl);
}
himl = (HIMAGELIST)SendMessage(Globals.hwndToolbar, TB_GETDISABLEDIMAGELIST, 0, 0);
if (himl) {
ImageList_Destroy(himl);
}
DestroyWindow(Globals.hwndToolbar);
}
OpenSettingsFile(__func__);
bool bDirtyFlag = false;
//InitToolbarWndClass(hInstance);
Globals.hwndToolbar = CreateWindowEx(dwToolbarExStyle, TOOLBARCLASSNAME, NULL, dwToolbarStyle,
0,0,0,0,hwnd,(HMENU)IDC_TOOLBAR,hInstance,NULL);
//Globals.hwndToolbar = CreateWindowEx(
// dwToolbarExStyle, // no extended styles
// s_ToolbarWndClassName, // name of status bar class
// (PCTSTR)NULL, // no text when first created
// dwToolbarStyle, // creates a visible child window
// 0, 0, 0, 0, // ignores size and position
// hwnd, // handle to parent window
// (HMENU)IDC_TOOLBAR, // child window identifier
// hInstance, // handle to application instance
// NULL); // no window creation data
InitWindowCommon(Globals.hwndToolbar, true); // (!) themed = true : glow effects
#ifdef D_NP3_WIN10_DARK_MODE
if (IsDarkModeSupported()) {
AllowDarkModeForWindowEx(Globals.hwndToolbar, CheckDarkModeEnabled());
}
#endif
SendMessage(Globals.hwndToolbar,TB_BUTTONSTRUCTSIZE,(WPARAM)sizeof(TBBUTTON),0);
// -------------------------
// Add Toolbar Bitmap
// -------------------------
HBITMAP hbmp = NULL;
HBITMAP hbmpCopy = NULL;
if ((Settings.ToolBarTheme == 2) && Path_IsNotEmpty(g_tchToolbarBitmap)) {
HPATHL hfile_pth = Path_Copy(g_tchToolbarBitmap);
Path_AbsoluteFromApp(hfile_pth, true);
hbmp = LoadBitmapFile(hfile_pth);
if (!hbmp) {
Path_Reset(g_tchToolbarBitmap, L"");
IniSectionDelete(L"Toolbar Images", L"BitmapDefault", false);
bDirtyFlag = true;
}
Path_Release(hfile_pth);
}
if (!hbmp) {
Settings.ToolBarTheme = Settings.ToolBarTheme % 2;
LPCWSTR toolBarIntRes = (Settings.ToolBarTheme == 0) ? (LPCWSTR)MAKEINTRESOURCE(IDR_MAINWNDTB) : (LPCWSTR)MAKEINTRESOURCE(IDR_MAINWNDTB2);
hbmp = LoadImage(hInstance, toolBarIntRes, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
}
// use copy for alphablend a disabled Toolbar (if not provided)
hbmpCopy = CopyImage(hbmp, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
HIMAGELIST himl = CreateScaledImageListFromBitmap(hwnd, hbmp);
DeleteObject(hbmp);
hbmp = NULL;
SendMessage(Globals.hwndToolbar,TB_SETIMAGELIST,0,(LPARAM)himl);
// --------------------------
// Add a Hot Toolbar Bitmap
// --------------------------
hbmp = NULL;
if ((Settings.ToolBarTheme == 2) && Path_IsNotEmpty(g_tchToolbarBitmapHot)) {
HPATHL hfile_pth = Path_Copy(g_tchToolbarBitmapHot);
Path_AbsoluteFromApp(hfile_pth, true);
hbmp = Path_IsExistingFile(hfile_pth) ? LoadBitmapFile(hfile_pth) : NULL;
if (!hbmp) {
Path_Reset(g_tchToolbarBitmapHot, L"");
IniSectionDelete(L"Toolbar Images", L"BitmapHot", false);
bDirtyFlag = true;
}
Path_Release(hfile_pth);
}
if (!hbmp && (Settings.ToolBarTheme < 2)) {
LPCWSTR toolBarIntRes = (Settings.ToolBarTheme == 0) ? (LPCWSTR)MAKEINTRESOURCE(IDR_MAINWNDTBHOT) : (LPCWSTR)MAKEINTRESOURCE(IDR_MAINWNDTB2HOT);
hbmp = LoadImage(hInstance, toolBarIntRes, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
}
if (hbmp) {
himl = CreateScaledImageListFromBitmap(hwnd, hbmp);
DeleteObject(hbmp);
hbmp = NULL;
SendMessage(Globals.hwndToolbar, TB_SETHOTIMAGELIST, 0, (LPARAM)himl);
} else { // clear the old one
SendMessage(Globals.hwndToolbar, TB_SETHOTIMAGELIST, 0, 0);
}
// ------------------------------
// Add a disabled Toolbar Bitmap
// ------------------------------
hbmp = NULL;
if ((Settings.ToolBarTheme == 2) && Path_IsNotEmpty(g_tchToolbarBitmapDisabled)) {
HPATHL hfile_pth = Path_Copy(g_tchToolbarBitmapDisabled);
Path_AbsoluteFromApp(hfile_pth, true);
hbmp = Path_IsExistingFile(hfile_pth) ? LoadBitmapFile(hfile_pth) : NULL;
if (!hbmp) {
Path_Reset(g_tchToolbarBitmapDisabled, L"");
IniSectionDelete(L"Toolbar Images", L"BitmapDisabled", false);
bDirtyFlag = true;
}
}
if (!hbmp && (Settings.ToolBarTheme < 2)) {
LPCWSTR toolBarIntRes = (Settings.ToolBarTheme == 0) ? (LPCWSTR)MAKEINTRESOURCE(IDR_MAINWNDTBDIS) : (LPCWSTR)MAKEINTRESOURCE(IDR_MAINWNDTB2DIS);
hbmp = LoadImage(hInstance, toolBarIntRes, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
}
if (hbmp) {
himl = CreateScaledImageListFromBitmap(hwnd, hbmp);
DeleteObject(hbmp);
hbmp = NULL;
SendMessage(Globals.hwndToolbar, TB_SETDISABLEDIMAGELIST, 0, (LPARAM)himl);
} else { // create disabled Toolbar, no external bitmap is supplied
if ((Settings.ToolBarTheme == 2) && !Path_IsNotEmpty(g_tchToolbarBitmapDisabled)) {
bool bProcessed = false;
if (Flags.ToolbarLook == 1) {
bProcessed = BitmapAlphaBlend(hbmpCopy, GetSysColor(COLOR_3DFACE), 0x60);
} else if (Flags.ToolbarLook == 2 || (!IsWindowsXPSP3OrGreater() && Flags.ToolbarLook == 0)) {
bProcessed = BitmapGrayScale(hbmpCopy);
}
if (bProcessed && !IsWindowsXPSP3OrGreater()) {
BitmapMergeAlpha(hbmpCopy, GetSysColor(COLOR_3DFACE));
}
if (bProcessed) {
himl = CreateScaledImageListFromBitmap(hwnd, hbmpCopy);
SendMessage(Globals.hwndToolbar, TB_SETDISABLEDIMAGELIST, 0, (LPARAM)himl);
}
}
}
if (hbmpCopy) {
DeleteObject(hbmpCopy);
hbmpCopy = NULL;
}
// Load toolbar labels
WCHAR tchIndex[16] = { L'\0' };
WCHAR tchDesc[80] = { L'\0' };
for (int i = 0; i < COUNTOF(s_tbbMainWnd); ++i) {
if (s_tbbMainWnd[i].fsStyle == BTNS_SEP) {
continue;
}
StringCchPrintf(tchIndex, COUNTOF(tchIndex), L"%02i", s_tbbMainWnd[i].iBitmap + 1);
if (IniSectionGetString(L"Toolbar Labels", tchIndex, L"", tchDesc, COUNTOF(tchDesc)) > 0) {
s_tbbMainWnd[i].iString = SendMessage(Globals.hwndToolbar, TB_ADDSTRING, 0, (LPARAM)tchDesc);
s_tbbMainWnd[i].fsStyle |= BTNS_AUTOSIZE | BTNS_SHOWTEXT;
} else {
GetLngString(s_tbbMainWnd[i].idCommand, tchDesc, COUNTOF(tchDesc));
s_tbbMainWnd[i].iString = SendMessage(Globals.hwndToolbar, TB_ADDSTRING, 0, (LPARAM)tchDesc); // tooltip
s_tbbMainWnd[i].fsStyle &= ~(BTNS_AUTOSIZE | BTNS_SHOWTEXT);
}
}
//~SendMessage(Globals.hwndToolbar, TB_SETMAXTEXTROWS, 0, 0);
DWORD const tbxstyle = (DWORD)SendMessage(Globals.hwndToolbar, TB_GETEXTENDEDSTYLE, 0, 0);
SendMessage(Globals.hwndToolbar,TB_SETEXTENDEDSTYLE,0,(tbxstyle | (TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER)));
SendMessage(Globals.hwndToolbar, TB_ADDBUTTONS, COUNTOF(s_tbbMainWnd), (LPARAM)s_tbbMainWnd);
if (Toolbar_SetButtons(Globals.hwndToolbar, IDT_FILE_NEW, Settings.ToolbarButtons, s_tbbMainWnd, COUNTOF(s_tbbMainWnd)) == 0) {
SendMessage(Globals.hwndToolbar, TB_ADDBUTTONS, COUNTOF(s_tbbMainWnd), (LPARAM)s_tbbMainWnd);
}
CloseSettingsFile(__func__, bDirtyFlag);
// ------------------------------
// Create ReBar and add Toolbar
// ------------------------------
if (Globals.hwndRebar) {
DestroyWindow(Globals.hwndRebar);
}
Globals.hwndRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, NP3_WS_REBAR,
0,0,0,0,hwnd,(HMENU)IDC_REBAR,hInstance,NULL);
// Theme = false (!) ~ you cannot change a toolbar's color when a visual style is active
InitWindowCommon(Globals.hwndRebar, !(IsWindows10OrGreater() && IsDarkModeSupported()));
#ifdef D_NP3_WIN10_DARK_MODE
if (IsDarkModeSupported()) {
AllowDarkModeForWindowEx(Globals.hwndRebar, CheckDarkModeEnabled());
}
#endif
REBARINFO rbi = { sizeof(REBARINFO) };
//rbi.fMask = 0;
rbi.himl = (HIMAGELIST)NULL;
SendMessage(Globals.hwndRebar, RB_SETBARINFO, 0, (LPARAM)&rbi);
RECT rc = { 0, 0, 0, 0 };
SendMessage(Globals.hwndToolbar, TB_GETITEMRECT, 0, (LPARAM)&rc);
//SendMessage(Globals.hwndToolbar,TB_SETINDENT,2,0);
REBARBANDINFO rbBand = { sizeof(REBARBANDINFO) };
rbBand.fMask = RBBIM_COLORS /*| RBBIM_TEXT | RBBIM_BACKGROUND */ |
RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE /*| RBBIM_SIZE*/;
//rbBand.fStyle = /*RBBS_CHILDEDGE |*//* RBBS_BREAK |*/ RBBS_FIXEDSIZE /*| RBBS_GRIPPERALWAYS*/;
rbBand.fStyle = s_bIsAppThemed ? (RBBS_FIXEDSIZE | RBBS_CHILDEDGE) : RBBS_FIXEDSIZE;
rbBand.hbmBack = NULL;
rbBand.lpText = L"Toolbar";
rbBand.clrFore = GetModeTextColor(UseDarkMode());
rbBand.clrBack = IsWindows10OrGreater() ? GetModeBkColor(UseDarkMode()) : GetModeBtnfaceColor(UseDarkMode());
rbBand.hwndChild = Globals.hwndToolbar;
rbBand.cxMinChild = (rc.right - rc.left) * COUNTOF(s_tbbMainWnd);
rbBand.cyMinChild = (rc.bottom - rc.top) + (2 * rc.top);
rbBand.cx = 0;
SendMessage(Globals.hwndRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
SetWindowPos(Globals.hwndRebar, NULL, 0, 0, 0, 0, SWP_NOZORDER);
GetWindowRect(Globals.hwndRebar, &rc);
s_cyReBar = (rc.bottom - rc.top);
s_cyReBarFrame = s_bIsAppThemed ? 0 : 2; // (!) frame color is same as INITIAL title-bar ???
ShowWindow(Globals.hwndRebar, Settings.ShowToolbar ? SW_SHOWDEFAULT : SW_HIDE);
// -------------------
// Create Statusbar
// -------------------
DWORD const dwStatusbarStyle = SBT_NOBORDERS | SBT_OWNERDRAW | WS_CHILD | WS_CLIPSIBLINGS;
if (Globals.hwndStatus) {
DestroyWindow(Globals.hwndStatus);
}
//~Globals.hwndStatus = CreateStatusWindow(dwStatusbarStyle, NULL, hwnd, IDC_STATUSBAR);
Globals.hwndStatus = CreateWindowEx(
WS_EX_COMPOSITED, // => double-buffering avoids flickering
STATUSCLASSNAME, // name of status bar class
(PCTSTR)NULL, // no text when first created
dwStatusbarStyle, // creates a visible child window
0, 0, 0, 0, // ignores size and position
hwnd, // handle to parent window
(HMENU)IDC_STATUSBAR, // child window identifier
hInstance, // handle to application instance
NULL); // no window creation data
InitWindowCommon(Globals.hwndStatus, true); // (!) themed = true : resize grip
// no simple status bar, to allow owner draw for dark mode
if (SendMessage(Globals.hwndStatus, SB_ISSIMPLE, 0, 0)) {
SendMessage(Globals.hwndStatus, SB_SIMPLE, FALSE, 0);
}
#ifdef D_NP3_WIN10_DARK_MODE
if (IsDarkModeSupported()) {
AllowDarkModeForWindowEx(Globals.hwndStatus, CheckDarkModeEnabled());
}
//~HDC const hdc = GetDC(Globals.hwndStatus);
//~SetBkColor(hdc, GetModeBtnfaceColor(UseDarkMode()));
//~SetTextColor(hdc, GetModeTextColor(UseDarkMode()));
//~ReleaseDC(Globals.hwndStatus, hdc);
#endif
ShowWindow(Globals.hwndStatus, Settings.ShowStatusbar ? SW_SHOWDEFAULT : SW_HIDE);
}
//=============================================================================
//
// MsgEndSession() - Handle WM_ENDSESSION,WM_DESTROY
//
LRESULT MsgEndSession(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
static bool bShutdownOK = false;
if (!bShutdownOK) {
// Terminate file watching
InstallFileWatching(false);
RestorePrevScreenPos(hwnd);
// Terminate AutoSave
AutoSaveStop();
DragAcceptFiles(hwnd, FALSE);
// Terminate clipboard watching
if (s_flagPasteBoard) {
KillTimer(hwnd, ID_PASTEBOARDTIMER);
ChangeClipboardChain(hwnd, s_hwndNextCBChain);
}
// close Find/Replace and CustomizeSchemes
CloseNonModalDialogs();
// call SaveAllSettings() when Globals.hwndToolbar is still valid
SaveAllSettings(false);
// Remove tray icon if necessary
ShowNotifyIcon(hwnd, false);
//if (IS_VALID_HANDLE(s_hEvent)) {
// CloseHandle(s_hEvent);
//}
bShutdownOK = true;
}
assert(!IsIniFileCached());
if (WM_DESTROY == umsg) {
if (IS_VALID_HANDLE(s_hEventAppIsClosing)) {
CloseHandle(s_hEventAppIsClosing);
}
PostQuitMessage(0);
}
return FALSE;
}
//=============================================================================
//
// MsgDPIChanged() - Handle WM_DPICHANGED
//
LRESULT MsgDPIChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UINT const dpi = LOWORD(wParam);
DbgLog(L"MsgDPIChanged() -> %u\n", dpi);
const RECT* const rc = (RECT*)lParam;
DocPos const pos = SciCall_GetCurrentPos();
UpdateWindowLayoutForDPI(hwnd, rc, dpi);
SendMessage(Globals.hwndEdit, WM_DPICHANGED, wParam, lParam);
MsgThemeChanged(hwnd, wParam, lParam);
Sci_GotoPosChooseCaret(pos);
return TRUE;
}
//=============================================================================
//
// MsgThemeChanged() - Handle WM_THEMECHANGED
//
LRESULT MsgThemeChanged(HWND hwnd, WPARAM wParam,LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
UNREFERENCED_PARAMETER(wParam);
#ifdef D_NP3_WIN10_DARK_MODE
AllowDarkModeForWindowEx(hwnd, UseDarkMode());
#endif
if (Globals.hwndMain) {
#ifdef D_NP3_WIN10_DARK_MODE
RefreshTitleBarThemeColor(hwnd);
#endif
// reinitialize edit frame
_InitEditWndFrame();
// recreate toolbar and statusbar
CreateBars(hwnd, Globals.hInstance);
Style_ResetCurrentLexer(Globals.hwndEdit);
Sci_RedrawScrollbars();
SetMenu(hwnd, (Settings.ShowMenubar ? Globals.hMainMenu : NULL));
DrawMenuBar(hwnd);
if (FocusedView.HideNonMatchedLines) {
EditToggleView(Globals.hwndEdit);
}
MarkAllOccurrences(_MQ_FAST, false);
SciCall_StartStyling(0);
Sci_ColouriseAll();
EditUpdateVisibleIndicators();
UpdateUI(hwnd);
}
UpdateWindowEx(hwnd);
return FALSE;
}
//=============================================================================
//
// MsgSize() - Handles WM_SIZE
//
//
LRESULT MsgSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
if (wParam == SIZE_MINIMIZED) {
return FALSE;
}
int x = 0;
int y = 0;
int cx = GET_X_LPARAM(lParam);
int cy = GET_Y_LPARAM(lParam);
if (Settings.ShowToolbar) {
//~SendMessage(Globals.hwndToolbar,WM_SIZE,0,0);
//~RECT rc;
//~GetWindowRect(Globals.hwndToolbar,&rc);
//~y = (rc.bottom - rc.top);
//~cy -= (rc.bottom - rc.top);
//~SendMessage(Globals.hwndToolbar,TB_GETITEMRECT,0,(LPARAM)&rc);
SetWindowPos(Globals.hwndRebar, NULL, 0, 0, LOWORD(lParam), s_cyReBar, SWP_NOZORDER);
// the ReBar automatically sets the correct height
// calling SetWindowPos() with the height of one toolbar button
// causes the control not to temporarily use the whole client area
// and prevents flickering
//GetWindowRect(Globals.hwndRebar,&rc);
y = s_cyReBar + s_cyReBarFrame; // define
cy -= s_cyReBar + s_cyReBarFrame; // border
}
if (Settings.ShowStatusbar) {
SendMessage(Globals.hwndStatus,WM_SIZE,0,0);
RECT rc;
GetWindowRect(Globals.hwndStatus, &rc);
cy -= (rc.bottom - rc.top);
}
HDWP const hdwp = BeginDeferWindowPos(2);
DeferWindowPos(hdwp,s_hwndEditFrame,NULL,x,y,cx,cy, SWP_NOZORDER | SWP_NOACTIVATE);
DeferWindowPos(hdwp, g_hwndEditWindow, s_hwndEditFrame,
x+s_cxEditFrame,y+s_cyEditFrame, cx-2*s_cxEditFrame,cy-2*s_cyEditFrame,
SWP_NOZORDER | SWP_NOACTIVATE);
EndDeferWindowPos(hdwp);
s_WinCurrentWidth = cx;
UpdateToolbar();
UpdateStatusbar(true);
UpdateMargins(true);
UpdateTitlebar(hwnd);
//~UpdateUI(); //~ recursion
return FALSE;
}
//=============================================================================
//
// UpdateContentArea()
//
void UpdateContentArea()
{
Sci_ForceNotifyUpdateUI(Globals.hwndMain, IDC_EDIT);
}
//=============================================================================
//
// MsgDrawItem() - Handles WM_DRAWITEM (needs SBT_OWNERDRAW)
//
// https://docs.microsoft.com/en-us/windows/win32/controls/status-bars#owner-drawn-status-bars
//
LRESULT MsgDrawItem(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(hwnd);
if (LOWORD(wParam) == IDC_STATUSBAR) { // Statusbar SB_SETTEXT caused parent's WM_DRAWITEM message
const DRAWITEMSTRUCT* const pDIS = (const DRAWITEMSTRUCT* const)lParam;
int const partId = (int)pDIS->itemID;
if (partId == -1) {
return FALSE;
}
HDC const hdc = pDIS->hDC;
RECT const rc = pDIS->rcItem;
//UINT const ctlId = pDIS->CtlID; // child window identifier
//~int const stateId = (int)pDIS->itemState ~ don't use
//~PAINTSTRUCT ps;
//~BeginPaint(hWndItem, &ps); ~ not needed on WM_DRAWITEM
//~SetModeBkColor(hdc, UseDarkMode());
SetModeBtnFaceColor(hdc, UseDarkMode());
SetModeTextColor(hdc, UseDarkMode());
#ifdef D_NP3_WIN10_DARK_MODE
if (UseDarkMode()) {
// overpaint part frames
HWND const hWndItem = pDIS->hwndItem;
int const bdh = GetSystemMetrics(SM_CYFRAME);
HDC const hdcFrm = GetWindowDC(hWndItem);
RECT rcf = rc;
for (int i = 1; i < bdh; ++i) {
FrameRect(hdcFrm, &rcf, Globals.hbrDarkModeBtnFcBrush);
rcf.left -= 1;
rcf.top -= 1;
rcf.bottom += 1;
rcf.right += 1;
}
FrameRect(hdcFrm, &rcf, GetSysColorBrush(COLOR_3DDKSHADOW));
ReleaseDC(hWndItem, hdcFrm);
}
#endif
LPCWSTR const text = (LPCWSTR)(pDIS->itemData);
ExtTextOut(hdc, rc.left + 1, rc.top + 1, ETO_OPAQUE | ETO_NUMERICSLOCAL, &rc, text, lstrlen(text), NULL);
//~EndPaint(hWndItem, &ps);
return TRUE;
}
return FALSE;
}
//=============================================================================
//
// _OnDropOneFile()
//
static LRESULT _OnDropOneFile(HWND hwnd, HPATHL hFilePath, WININFO* wi)
{
if (IsIconic(hwnd)) {
ShowWindow(hwnd, SW_RESTORE);
}
FileLoadFlags fLoadFlags = FLF_None;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
if (Path_IsExistingDirectory(hFilePath)) {
if (OpenFileDlg(Globals.hwndMain, hFilePath, hFilePath)) {
FileLoad(hFilePath, fLoadFlags);
}
}
else if (Path_IsExistingFile(hFilePath)) {
//~ ignore Flags.bReuseWindow
if (IsKeyDown(VK_CONTROL) || wi) {
DialogNewWindow(hwnd, Settings.SaveBeforeRunningTools, hFilePath, wi);
} else {
FileLoad(hFilePath, fLoadFlags);
}
} else {
// Windows Bug: wParam (HDROP) pointer is corrupted if dropped from 32-bit App
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_DROP_NO_FILE);
}
return FALSE;
}
//=============================================================================
//
// MsgDropFiles() - Handles WM_DROPFILES
//
LRESULT MsgDropFiles(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
HDROP hDrop = NULL;
if (IsWindows10OrGreater()) {
hDrop = (HDROP)wParam;
}
else // Windows7 Bug drag&drop of files from 32bit app to 64bit app
{
#ifdef _WIN64
HANDLE hProcessHeap = GetProcessHeap();
if (NULL != hProcessHeap && HeapLock(hProcessHeap)) {
PROCESS_HEAP_ENTRY heapEntry = { 0 };
while (HeapWalk(hProcessHeap, &heapEntry) != FALSE) {
if ((heapEntry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
HGLOBAL hGlobal = GlobalHandle(heapEntry.lpData);
// Assuming wParam is the WM_DROPFILES WPARAM
if ((((DWORD_PTR)hGlobal) & 0xFFFFFFFF) == (wParam & 0xFFFFFFFF)) {
hDrop = (HDROP)hGlobal; // We got it !!
break;
}
}
}
HeapUnlock(hProcessHeap);
}
#else
hDrop = (HDROP)wParam;
#endif
}
if (hDrop) {
bool const vkCtrlDown = IsKeyDown(VK_CONTROL);
HPATHL hdrop_pth = Path_Allocate(NULL);
wchar_t* const drop_buf = Path_WriteAccessBuf(hdrop_pth, STRINGW_MAX_URL_LENGTH);
UINT const cnt = DragQueryFileW(hDrop, UINT_MAX, NULL, 0);
int const offset = Settings2.LaunchInstanceWndPosOffset;
bool const bFullVisible = Settings2.LaunchInstanceFullVisible;
for (UINT i = 0; i < cnt; ++i) {
WININFO wi = GetMyWindowPlacement(hwnd, NULL, (vkCtrlDown ? (offset * (i + 1)) : 0), bFullVisible);
DragQueryFileW(hDrop, i, drop_buf, (UINT)Path_GetBufCount(hdrop_pth));
_OnDropOneFile(hwnd, hdrop_pth, (((0 == i) && !IsKeyDown(VK_CONTROL)) ? NULL : &wi));
}
DragFinish(hDrop);
Path_Release(hdrop_pth);
}
return 0;
}
#if 0
//=============================================================================
//
// DropFilesProc() - Handles DROPFILES
//
//
static DWORD DropFilesProc(CLIPFORMAT cf, HGLOBAL hData, HWND hWnd, DWORD dwKeyState, POINTL pt, void *pUserData)
{
DWORD dwEffect = DROPEFFECT_NONE;
//HWND hEditWnd = (HWND)pUserData;
UNREFERENCED_PARAMETER(pUserData);
if (cf == CF_HDROP) {
WCHAR szBuf[MAX_PATH_EXPLICIT + 40];
HDROP hDrop = (HDROP)hData;
if (IsIconic(hWnd)) {
ShowWindow(hWnd, SW_RESTORE);
}
DragQueryFile(hDrop, 0, szBuf, COUNTOF(szBuf));
FileLoadFlags fLoadFlags = FLF_None;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
if (PathIsDirectory(szBuf)) {
WCHAR tchFile[MAX_PATH_EXPLICIT] = { L'\0' };
if (OpenFileDlg(hWnd, tchFile, COUNTOF(tchFile), szBuf)) {
FileLoad(tchFile, fLoadFlags);
}
} else {
FileLoad(szBuf, fLoadFlags);
}
if (DragQueryFile(hDrop, (UINT)(-1), NULL, 0) > 1) {
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_ERR_DROP);
}
dwEffect = DROPEFFECT_COPY;
}
UNREFERENCED_PARAMETER(dwKeyState);
UNREFERENCED_PARAMETER(pt);
return dwEffect;
}
#endif
//=============================================================================
//
// MsgCopyData() - Handles WM_COPYDATA
//
//
LRESULT MsgCopyData(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
// Reset Change Notify
//bPendingChangeNotify = false;
SetDlgItemInt(hwnd, IDC_REUSELOCK, (UINT)GetTicks_ms(), false);
if (pcds->dwData == DATA_NOTEPAD3_PARAMS) {
LPnp3params const params = AllocMem(pcds->cbData, HEAP_ZERO_MEMORY);
if (params) {
CopyMemory(params, pcds->lpData, pcds->cbData);
HPATHL hfile_pth = Path_Allocate(&params->wchData);
if (params->flagLexerSpecified) {
s_flagLexerSpecified = true;
}
if (params->flagQuietCreate) {
s_flagQuietCreate = true;
}
if (params->flagFileSpecified) {
bool bOpened = false;
Encoding_Forced(params->flagSetEncoding);
FileLoadFlags fLoadFlags = FLF_None;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
if (Path_IsExistingDirectory(hfile_pth)) {
if (OpenFileDlg(Globals.hwndMain, hfile_pth, hfile_pth)) {
bOpened = FileLoad(hfile_pth, fLoadFlags);
}
} else {
bOpened = FileLoad(hfile_pth, fLoadFlags);
}
if (bOpened) {
if (params->flagChangeNotify == FWM_MSGBOX) {
FileWatching.FileWatchingMode = FWM_MSGBOX;
InstallFileWatching(true);
}
else if (params->flagChangeNotify == FWM_AUTORELOAD) {
if (FileWatching.MonitoringLog) {
PostWMCommand(Globals.hwndMain, IDM_VIEW_CHASING_DOCTAIL);
}
else {
FileWatching.FileWatchingMode = FWM_AUTORELOAD;
}
InstallFileWatching(true);
}
else if (params->flagChangeNotify == FWM_INDICATORSILENT) {
InstallFileWatching(true);
}
if (params->flagSetEncoding != CPI_NONE) {
s_flagSetEncoding = params->flagSetEncoding;
SendMessage(hwnd, WM_COMMAND, MAKELONG(IDM_ENCODING_SELECT, IDM_ENCODING_SELECT + s_flagSetEncoding), 0);
s_flagSetEncoding = CPI_NONE;
}
if (0 != params->flagSetEOLMode) {
s_flagSetEOLMode = params->flagSetEOLMode;
SendWMCommand(Globals.hwndMain, IDM_LINEENDINGS_CRLF + s_flagSetEOLMode - 1);
s_flagSetEOLMode = 0;
}
if (params->flagLexerSpecified) {
if (params->iInitialLexer < 0) {
WCHAR wchExt[32] = { L'\0' };
StringCchCopy(wchExt, COUNTOF(wchExt), L".");
StringCchCopyN(CharNextW(wchExt), 32, StrEnd(Path_Get(hfile_pth), 0) + 1, 31);
Style_SetLexerFromName(Globals.hwndEdit, hfile_pth, wchExt);
} else if (params->iInitialLexer >= 0 && params->iInitialLexer < Style_NumOfLexers()) {
Style_SetLexerFromID(Globals.hwndEdit, params->iInitialLexer);
}
}
if (params->flagTitleExcerpt) {
StringCchCopyN(s_wchTitleExcerpt, COUNTOF(s_wchTitleExcerpt), StrEnd(Path_Get(hfile_pth), 0) + 1, COUNTOF(s_wchTitleExcerpt));
}
}
// reset
Encoding_Forced(CPI_NONE);
}
if (params->flagJumpTo) {
s_flagJumpTo = true;
SciCall_SetYCaretPolicy(s_iCaretPolicyV | CARET_JUMPS, Settings2.CurrentLineVerticalSlop);
EditJumpTo(params->iInitialLine, params->iInitialColumn);
SciCall_SetYCaretPolicy(s_iCaretPolicyV, Settings2.CurrentLineVerticalSlop);
}
if (params->flagMatchText) {
g_flagMatchText = params->flagMatchText;
SetFindPattern(StrEndW(&params->wchData, 0) + 1);
SetFindReplaceData(); // s_FindReplaceData
if (g_flagMatchText & 2) {
if (!s_flagJumpTo) {
Sci_SetCaretScrollDocEnd();
}
EditFindPrev(Globals.hwndEdit, &s_FindReplaceData, false, false, false);
} else {
if (!s_flagJumpTo) {
SciCall_DocumentStart();
}
EditFindNext(Globals.hwndEdit, &s_FindReplaceData, false, false, false);
}
}
s_flagLexerSpecified = false;
s_flagQuietCreate = false;
Path_Release(hfile_pth);
FreeMem(params);
}
UpdateToolbar();
UpdateStatusbar(true);
UpdateMargins(true);
}
return FALSE;
}
//=============================================================================
//
// MsgContextMenu() - Handles WM_CONTEXTMENU and SCN_MARGINRIGHTCLICK
//
LRESULT MsgContextMenu(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
bool const bMargin = (SCN_MARGINRIGHTCLICK == umsg);
bool const bNCArea = (WM_NCRBUTTONDOWN == umsg);
int const nID = bMargin ? IDC_MARGIN : (bNCArea ? IDC_NCAREA : GetDlgCtrlID((HWND)wParam));
if ((nID != IDC_MARGIN) &&
(nID != IDC_EDIT) &&
(nID != IDC_REBAR) &&
(nID != IDC_TOOLBAR) &&
(nID != IDC_STATUSBAR) &&
(nID != IDC_NCAREA)) {
return DefWindowProc(hwnd, umsg, wParam, lParam);
}
// no context menu after undo/redo history scrolling
if (s_bUndoRedoScroll) {
s_bUndoRedoScroll = false;
return FALSE;
}
POINT pt = { 0, 0 };
pt.x = (int)((short)LOWORD(bMargin ? wParam : lParam));
pt.y = (int)((short)HIWORD(bMargin ? wParam : lParam));
#define IS_CTX_PT_VALID(P) (((P).x != -1 || (P).y != -1))
if (nID == IDC_NCAREA) { // only valid for Menu Bar
if (!IS_CTX_PT_VALID(pt)) {
GetCursorPos(&pt);
}
MENUBARINFO mbi = { sizeof(MENUBARINFO) };
GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi);
if (pt.y < mbi.rcBar.top || pt.y > mbi.rcBar.bottom) {
return DefWindowProc(hwnd, umsg, wParam, lParam);
}
}
typedef enum { MNU_NONE = -1, MNU_EDIT = 0, MNU_BAR, MNU_MARGIN, MNU_TRAY, MNU_NCAREA } mnu_t;
mnu_t imenu = MNU_NONE;
HMENU const hMenuCtx = LoadMenu(Globals.hLngResContainer, MAKEINTRESOURCE(IDR_MUI_POPUPMENU));
//SetMenuDefaultItem(GetSubMenu(hmenu,1),0,false);
switch (nID) {
case IDC_EDIT: {
if (!IS_CTX_PT_VALID(pt)) {
// caused by keyboard near caret pos
DocPos const iCurrentPos = SciCall_GetCurrentPos();
pt.x = (LONG)SciCall_PointXFromPosition(iCurrentPos);
pt.y = (LONG)SciCall_PointYFromPosition(iCurrentPos);
}
else {
ScreenToClient(Globals.hwndEdit, &pt);
}
imenu = bMargin ? MNU_MARGIN : MNU_EDIT;
if (imenu == MNU_EDIT) {
// modify configured items
HMENU const hStdCtxMenu = GetSubMenu(hMenuCtx, imenu);
if (StrIsNotEmpty(Settings2.WebTmpl1MenuName)) {
ModifyMenu(hStdCtxMenu, CMD_WEBACTION1, MF_BYCOMMAND | MF_STRING, CMD_WEBACTION1, Settings2.WebTmpl1MenuName);
}
if (StrIsNotEmpty(Settings2.WebTmpl2MenuName)) {
ModifyMenu(hStdCtxMenu, CMD_WEBACTION2, MF_BYCOMMAND | MF_STRING, CMD_WEBACTION2, Settings2.WebTmpl2MenuName);
}
}
// back to screen coordinates for menu display
ClientToScreen(Globals.hwndEdit, &pt);
} break;
case IDC_TOOLBAR:
case IDC_STATUSBAR:
case IDC_REBAR:
case IDC_NCAREA: {
if (!IS_CTX_PT_VALID(pt)) {
GetCursorPos(&pt);
}
imenu = MNU_BAR;
} break;
case IDC_MARGIN: {
if (!IS_CTX_PT_VALID(pt)) {
GetCursorPos(&pt);
}
DocLn const curLn = Sci_GetCurrentLineNumber();
int const bitmask = SciCall_MarkerGet(curLn) & ALL_MARKERS_BITMASK();
EnableCmd(hMenuCtx, IDM_EDIT_CLEAR_MARKER, bitmask);
EnableCmd(hMenuCtx, IDM_EDIT_CUT_MARKED, bitmask);
EnableCmd(hMenuCtx, IDM_EDIT_COPY_MARKED, bitmask);
EnableCmd(hMenuCtx, IDM_EDIT_DELETE_MARKED, bitmask);
const SCNotification* const scn = (SCNotification*)lParam;
switch (scn->margin) {
case MARGIN_SCI_FOLDING:
case MARGIN_SCI_CHGHIST:
case MARGIN_SCI_BOOKMRK:
case MARGIN_SCI_LINENUM:
imenu = MNU_MARGIN;
break;
default:
break;
}
} break;
default:
break;
}
if (imenu != MNU_NONE) {
TrackPopupMenuEx(GetSubMenu(hMenuCtx, imenu), TPM_LEFTBUTTON | TPM_RIGHTBUTTON, pt.x + 1, pt.y + 1, hwnd, NULL);
}
DestroyMenu(hMenuCtx);
return (imenu != MNU_NONE) ? !0 : 0;
}
//=============================================================================
//
// MsgTrayMessage() - Handles WM_TRAYMESSAGE
//
//
LRESULT MsgTrayMessage(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
switch (lParam) {
case WM_RBUTTONUP: {
HMENU hTrayMenu = LoadMenu(Globals.hLngResContainer, MAKEINTRESOURCE(IDR_MUI_POPUPMENU));
HMENU hMenuPopup = GetSubMenu(hTrayMenu, 3);
POINT pt;
int iCmd;
SetForegroundWindow(hwnd);
GetCursorPos(&pt);
SetMenuDefaultItem(hMenuPopup, IDM_TRAY_RESTORE, false);
iCmd = TrackPopupMenu(hMenuPopup,
TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
pt.x, pt.y, 0, hwnd, NULL);
PostMessage(hwnd, WM_NULL, 0, 0);
DestroyMenu(hTrayMenu);
if (iCmd == IDM_TRAY_RESTORE) {
ShowNotifyIcon(hwnd, false);
RestoreWndFromTray(hwnd);
ShowOwnedPopups(hwnd, true);
} else if (iCmd == IDM_TRAY_EXIT) {
//ShowNotifyIcon(hwnd,false);
CloseApplication();
}
}
break;
case WM_LBUTTONUP:
ShowNotifyIcon(hwnd, false);
RestoreWndFromTray(hwnd);
ShowOwnedPopups(hwnd, true);
break;
default:
return TRUE;
}
return FALSE;
}
//=============================================================================
//
// MsgEnterMenuLoop() - Handles WM_ENTERMENULOOP
//
//
LRESULT MsgEnterMenuLoop(HWND hwnd, WPARAM wParam)
{
if ((BOOL)wParam == FALSE) { // is main menu
HMENU const hCurMenu = GetMenu(hwnd);
if (!hCurMenu) {
SetMenu(hwnd, Globals.hMainMenu);
DrawMenuBar(hwnd);
}
}
return (LRESULT)wParam;
}
//=============================================================================
//
// MsgExitMenuLoop() - Handles WM_EXITMENULOOP
//
//
LRESULT MsgExitMenuLoop(HWND hwnd, WPARAM wParam)
{
if ((BOOL)wParam == FALSE) { // is main menu
HMENU const hCurMenu = GetMenu(hwnd);
if (hCurMenu && !Settings.ShowMenubar) {
SetMenu(hwnd, NULL);
DrawMenuBar(hwnd);
}
}
return (LRESULT)wParam;
}
//=============================================================================
//
// MsgInitMenu() - Handles WM_INITMENU
//
LRESULT MsgInitMenu(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
HMENU const hmenu = wParam ? (HMENU)wParam : GetMenu(hwnd);
if (!hmenu) {
return FALSE;
}
//bool const dm = UseDarkMode();
bool const si = Flags.bSingleFileInstance;
bool const cf = Path_IsNotEmpty(Paths.CurrentFile);
bool const ro = SciCall_GetReadOnly(); // scintilla mode read-only
bool const lck = (FileWatching.FileWatchingMode == FWM_EXCLUSIVELOCK); // file write lock
bool const faro = IsFileReadOnly(); // file attrib read-only
bool const pst = SciCall_CanPaste();
bool const se = SciCall_IsSelectionEmpty();
bool const mrs = Sci_IsMultiOrRectangleSelection();
bool const te = Sci_IsDocEmpty();
bool const mls = Sci_IsSelectionMultiLine();
bool const moe = IsMarkOccurrencesEnabled();
//bool const lfl = Flags.bHugeFileLoadState;
//~bool const sav = Globals.bCanSaveIniFile; ~ done by UpdateSaveSettingsCmds()
DocPos const iCurPos = SciCall_GetCurrentPos();
DocLn const iCurLine = SciCall_LineFromPosition(iCurPos);
bool const bPosInSel = Sci_IsPosInSelection(iCurPos);
// ------------------------------------------------------
EnableCmd(hmenu, IDM_FILE_REVERT, cf);
EnableCmd(hmenu, CMD_RELOADASCIIASUTF8, cf);
EnableCmd(hmenu, CMD_RELOADFORCEDETECTION, cf);
EnableCmd(hmenu, CMD_RECODEANSI, cf);
EnableCmd(hmenu, CMD_RECODEOEM, cf);
EnableCmd(hmenu, CMD_RELOADNOENCODETAGS, cf);
EnableCmd(hmenu, CMD_RECODEDEFAULT, cf);
EnableCmd(hmenu, CMD_RECODEGB18030, cf);
SetGrepWinIcon(hwnd, hmenu, IDM_GREP_WIN_SEARCH);
EnableCmd(hmenu, IDM_FILE_NEWWINDOW2, !(cf && si));
SetWinIcon(hwnd, hmenu, IDM_FILE_LAUNCH);
EnableCmd(hmenu, IDM_FILE_LAUNCH, cf);
SetUACIcon(hwnd, hmenu, IDM_FILE_LAUNCH_ELEVATED);
CheckCmd(hmenu, IDM_FILE_LAUNCH_ELEVATED, s_bIsProcessElevated);
EnableCmd(hmenu, IDM_FILE_LAUNCH_ELEVATED, !s_bIsProcessElevated);
SetWinIcon(hwnd, hmenu, IDM_FILE_RUN);
CheckCmd(hmenu, CMD_IGNORE_FILE_VARS, Flags.NoFileVariables);
EnableCmd(hmenu, IDM_FILE_PROPERTIES, cf);
EnableCmd(hmenu, IDM_FILE_CREATELINK, cf);
EnableCmd(hmenu, IDM_FILE_ADDTOFAV, cf);
EnableCmd(hmenu, IDM_FILE_READONLY, cf);
EnableCmd(hmenu, IDM_EDIT_INSERT_FILENAME, cf);
EnableCmd(hmenu, IDM_EDIT_INSERT_DIRNAME, cf);
EnableCmd(hmenu, IDM_EDIT_INSERT_PATHNAME, cf);
EnableCmd(hmenu, IDM_ENCODING_RECODE, cf);
CheckCmd(hmenu, IDM_FILE_READONLY, faro);
CheckCmd(hmenu, IDM_FILE_PRESERVE_FILEMODTIME, Flags.bPreserveFileModTime);
EnableCmd(hmenu, IDM_FILE_LOCK_SHARE_READ, cf);
CheckCmd(hmenu, IDM_FILE_LOCK_SHARE_READ, lck);
EnableCmd(hmenu, IDM_ENCODING_UNICODEREV, !ro);
EnableCmd(hmenu, IDM_ENCODING_UNICODE, !ro);
EnableCmd(hmenu, IDM_ENCODING_UTF8SIGN, !ro);
EnableCmd(hmenu, IDM_ENCODING_UTF8, !ro);
EnableCmd(hmenu, IDM_ENCODING_ANSI, !ro);
EnableCmd(hmenu, IDM_LINEENDINGS_CRLF, !ro);
EnableCmd(hmenu, IDM_LINEENDINGS_LF, !ro);
EnableCmd(hmenu, IDM_LINEENDINGS_CR, !ro);
int i;
if (Encoding_IsUNICODE_REVERSE(Encoding_GetCurrent())) {
i = IDM_ENCODING_UNICODEREV;
} else if (Encoding_IsUNICODE(Encoding_GetCurrent())) {
i = IDM_ENCODING_UNICODE;
} else if (Encoding_IsUTF8_SIGN(Encoding_GetCurrent())) {
i = IDM_ENCODING_UTF8SIGN;
} else if (Encoding_IsUTF8(Encoding_GetCurrent())) {
i = IDM_ENCODING_UTF8;
} else if (Encoding_IsANSI(Encoding_GetCurrent())) {
i = IDM_ENCODING_ANSI;
} else {
i = -1;
}
CheckMenuRadioItem(hmenu,IDM_ENCODING_ANSI,IDM_ENCODING_UTF8SIGN,i,MF_BYCOMMAND);
int const eol_mode = SciCall_GetEOLMode();
if (eol_mode == SC_EOL_CRLF) {
i = IDM_LINEENDINGS_CRLF;
} else if (eol_mode == SC_EOL_CR) {
i = IDM_LINEENDINGS_CR;
} else {
i = IDM_LINEENDINGS_LF;
}
CheckMenuRadioItem(hmenu,IDM_LINEENDINGS_CRLF,IDM_LINEENDINGS_LF,i,MF_BYCOMMAND);
EnableCmd(hmenu, IDM_FILE_RECENT, (MRU_Count(Globals.pFileMRU) > 0));
EnableCmd(hmenu, IDM_EDIT_UNDO, SciCall_CanUndo() && !ro);
EnableCmd(hmenu, IDM_EDIT_REDO, SciCall_CanRedo() && !ro);
EnableCmd(hmenu, IDM_EDIT_CUT, !te && !ro); // allow Ctrl-X w/o selection
EnableCmd(hmenu, IDM_EDIT_COPY, !te); // allow Ctrl-C w/o selection
EnableCmd(hmenu, IDM_EDIT_COPYALL, !te);
EnableCmd(hmenu, IDM_EDIT_COPYADD, !te);
EnableCmd(hmenu, IDM_EDIT_PASTE, pst && !ro);
EnableCmd(hmenu, IDM_EDIT_SWAP, (!se || pst) && !ro);
EnableCmd(hmenu, IDM_EDIT_CLEAR, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_SELECTALL, !te);
EnableCmd(hmenu, IDM_EDIT_GOTOLINE, !te);
OpenClipboard(hwnd);
EnableCmd(hmenu, IDM_EDIT_CLEARCLIPBOARD, CountClipboardFormats());
CloseClipboard();
EnableCmd(hmenu, IDM_EDIT_MOVELINEUP, !ro);
EnableCmd(hmenu, IDM_EDIT_MOVELINEDOWN, !ro);
EnableCmd(hmenu, IDM_EDIT_DUPLINEORSELECTION, !ro);
EnableCmd(hmenu, IDM_EDIT_LINETRANSPOSE, !ro);
EnableCmd(hmenu, IDM_EDIT_CUTLINE, !ro);
EnableCmd(hmenu, IDM_EDIT_COPYLINE, !mrs);
EnableCmd(hmenu, IDM_EDIT_DELETELINE, !ro);
EnableCmd(hmenu, IDM_EDIT_MERGEBLANKLINES, !ro);
EnableCmd(hmenu, IDM_EDIT_MERGEEMPTYLINES, !ro);
EnableCmd(hmenu, IDM_EDIT_REMOVEBLANKLINES, !ro);
EnableCmd(hmenu, IDM_EDIT_REMOVEEMPTYLINES, !ro);
EnableCmd(hmenu, IDM_EDIT_REMOVEDUPLICATELINES, !ro);
EnableCmd(hmenu, IDM_EDIT_INDENT, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_UNINDENT, !se && !ro);
EnableCmd(hmenu, CMD_JUMP2SELSTART, !se || mrs);
EnableCmd(hmenu, CMD_JUMP2SELEND, !se || mrs);
EnableCmd(hmenu, IDM_EDIT_PADWITHSPACES, !ro && !se);
EnableCmd(hmenu, IDM_EDIT_STRIP1STCHAR, !ro && !se);
EnableCmd(hmenu, IDM_EDIT_STRIPLASTCHAR, !ro && !se);
EnableCmd(hmenu, IDM_EDIT_TRIMLINES, !ro);
EnableCmd(hmenu, IDM_EDIT_COMPRESS_BLANKS, !ro);
EnableCmd(hmenu, IDM_EDIT_MODIFYLINES, !ro);
EnableCmd(hmenu, IDM_EDIT_ALIGN, mls && !ro);
EnableCmd(hmenu, IDM_EDIT_SORTLINES, mls && !ro);
//EnableCmd(hmenu,IDM_EDIT_COLUMNWRAP,i /*&& IsWindowsNT()*/);
EnableCmd(hmenu, IDM_EDIT_JOINLINES, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_JOINLN_NOSP, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_JOINLINES_PARA, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_CONVERTUPPERCASE, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_CONVERTLOWERCASE, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_INVERTCASE, !se && !ro /*&& IsWindowsNT()*/);
EnableCmd(hmenu, IDM_EDIT_TITLECASE, !se && !ro /*&& IsWindowsNT()*/);
EnableCmd(hmenu, IDM_EDIT_SENTENCECASE, !se && !ro /*&& IsWindowsNT()*/);
EnableCmd(hmenu, IDM_EDIT_CONVERTTABS, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_CONVERTSPACES, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_CONVERTTABS2, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_CONVERTSPACES2, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_URLENCODE, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_URLDECODE, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_BASE64ENCODE, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_BASE64DECODE, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_B64DECODESEL, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_PATH2URL, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_URL2PATH, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_INVERTBACKSLASH, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_INVERTSLASH, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_ESCAPECCHARS, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_UNESCAPECCHARS, !se && !ro);
EnableCmd(hmenu, IDM_EDIT_CHAR2HEX, !ro); // Char2Hex allowed for char after current pos
EnableCmd(hmenu, IDM_EDIT_HEX2CHAR, !se && !ro);
EnableCmd(hmenu, IDM_SET_SHOWEXCERPT, !se);
WCHAR cmnt[8];
Lexer_GetLineCommentStrg(cmnt, COUNTOF(cmnt));
EnableCmd(hmenu, IDM_EDIT_LINECOMMENT, StrIsNotEmpty(cmnt) && !ro);
EnableCmd(hmenu, IDM_EDIT_LINECOMMENT_ADD, StrIsNotEmpty(cmnt) && !ro);
EnableCmd(hmenu, IDM_EDIT_LINECOMMENT_REMOVE, StrIsNotEmpty(cmnt) && !ro);
EnableCmd(hmenu, IDM_EDIT_LINECOMMENT_BLOCKEDIT, StrIsNotEmpty(cmnt) && !ro);
Lexer_GetStreamCommentStrgs(cmnt, cmnt, COUNTOF(cmnt));
EnableCmd(hmenu, IDM_EDIT_STREAMCOMMENT, StrIsNotEmpty(cmnt) && !ro);
EnableCmd(hmenu, CMD_INSERTNEWLINE, !ro);
EnableCmd(hmenu, IDM_EDIT_INSERT_TAG, !ro);
EnableCmd(hmenu, IDM_EDIT_INSERT_ENCODING, (Encoding_GetParseNames(Encoding_GetCurrent()) != NULL) && !ro);
EnableCmd(hmenu, IDM_EDIT_INSERT_SHORTDATE, !ro);
EnableCmd(hmenu, IDM_EDIT_INSERT_LONGDATE, !ro);
EnableCmd(hmenu, IDM_EDIT_INSERT_GUID, !ro);
EnableCmd(hmenu, IDM_EDIT_FIND, !te);
EnableCmd(hmenu, IDM_EDIT_SAVEFIND, !te);
EnableCmd(hmenu, IDM_EDIT_FINDNEXT, !te);
EnableCmd(hmenu, IDM_EDIT_FINDPREV, !te);
EnableCmd(hmenu, IDM_EDIT_REPLACE, !te && !ro);
EnableCmd(hmenu, IDM_EDIT_REPLACENEXT, !te && !ro);
EnableCmd(hmenu, IDM_EDIT_SELTONEXT, !te);
EnableCmd(hmenu, IDM_EDIT_SELTOPREV, !te);
EnableCmd(hmenu, IDM_EDIT_FINDMATCHINGBRACE, !te);
EnableCmd(hmenu, IDM_EDIT_SELTOMATCHINGBRACE, !te);
SetGrepWinIcon(hwnd, hmenu, IDM_GREP_WIN_SEARCH2);
CheckCmd(hmenu, IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK, Settings.SplitUndoTypingSeqOnLnBreak);
EnableCmd(hmenu, BME_EDIT_BOOKMARKPREV, !te);
EnableCmd(hmenu, BME_EDIT_BOOKMARKNEXT, !te);
EnableCmd(hmenu, BME_EDIT_BOOKMARKTOGGLE, !te);
EnableCmd(hmenu, BME_EDIT_BOOKMARKCLEAR, !te);
EnableCmd(hmenu, IDM_EDIT_DELETELINELEFT, !te && !ro);
EnableCmd(hmenu, IDM_EDIT_DELETELINERIGHT, !te && !ro);
EnableCmd(hmenu, CMD_CTRLBACK, !te && !ro);
EnableCmd(hmenu, CMD_CTRLDEL, !te && !ro);
EnableCmd(hmenu, CMD_INSERT_TIMESTAMP, !ro);
EnableCmd(hmenu, CMD_UPDATE_TIMESTAMPS, !te && !ro);
EnableCmd(hmenu, IDM_VIEW_FONT, !IsWindow(Globals.hwndDlgCustomizeSchemes));
EnableCmd(hmenu, IDM_VIEW_CURRENTSCHEME, !IsWindow(Globals.hwndDlgCustomizeSchemes));
CheckCmd(hmenu, IDM_VIEW_USE2NDDEFAULT, Style_GetUse2ndDefault());
CheckCmd(hmenu, IDM_VIEW_READONLY, ro);
CheckCmd(hmenu, IDM_VIEW_WORDWRAP, Globals.fvCurFile.bWordWrap);
CheckCmd(hmenu, IDM_VIEW_LONGLINEMARKER, Settings.MarkLongLines);
CheckCmd(hmenu, IDM_VIEW_SHOWINDENTGUIDES, Settings.ShowIndentGuides);
CheckCmd(hmenu, IDM_VIEW_LINENUMBERS, SciCall_GetMarginWidthN(MARGIN_SCI_LINENUM) > 0);
CheckCmd(hmenu, IDM_VIEW_BOOKMARK_MARGIN, SciCall_GetMarginWidthN(MARGIN_SCI_BOOKMRK) > 0);
CheckCmd(hmenu, IDM_VIEW_CHGHIST_TOGGLE_MARGIN, SciCall_GetMarginWidthN(MARGIN_SCI_CHGHIST) > 0);
CheckCmd(hmenu, IDM_VIEW_CHASING_DOCTAIL, FileWatching.MonitoringLog);
CheckCmd(hmenu, IDM_VIEW_MARKOCCUR_ONOFF, moe);
CheckCmd(hmenu, IDM_VIEW_MARKOCCUR_BOOKMARKS, Settings.MarkOccurrencesBookmark);
EnableCmd(hmenu, IDM_VIEW_MARKOCCUR_BOOKMARKS, moe);
CheckCmd(hmenu, IDM_VIEW_MARKOCCUR_VISIBLE, Settings.MarkOccurrencesMatchVisible);
CheckCmd(hmenu, IDM_VIEW_MARKOCCUR_CASE, Settings.MarkOccurrencesMatchCase);
CheckCmd(hmenu, IDM_VIEW_TOGGLE_VIEW, FocusedView.HideNonMatchedLines);
EnableCmd(hmenu, IDM_VIEW_TOGGLE_VIEW, IsFocusedViewAllowed());
i = IDM_VIEW_FV_FOLD;
int const fvm_mode = Settings.FocusViewMarkerMode;
if (fvm_mode == FVMM_MARGIN) {
i = IDM_VIEW_FV_BOOKMARK;
} else if (fvm_mode == FVMM_LN_BACKGR) {
i = IDM_VIEW_FV_HIGHLIGHT;
} else if (fvm_mode == (FVMM_MARGIN | FVMM_FOLD)) {
i = IDM_VIEW_FV_BKMRKFOLD;
} else if (fvm_mode == (FVMM_LN_BACKGR | FVMM_FOLD)) {
i = IDM_VIEW_FV_HIGHLGFOLD;
} else {
i = IDM_VIEW_FV_FOLD;
}
CheckMenuRadioItem(hmenu, IDM_VIEW_FV_FOLD, IDM_VIEW_FV_HIGHLGFOLD, i, MF_BYCOMMAND);
CheckCmd(hmenu, IDM_VIEW_HYPERLINKHOTSPOTS, Settings.HyperlinkHotspot);
int const _SUB_MNU_2 = 8; // menu:View -> base for parent of sub-menus (adj. offset accordingly)
int const chState = SciCall_GetChangeHistory();
assert(chState == Settings.ChangeHistoryMode);
i = IDM_VIEW_CHGHIST_NONE;
i += (chState & SC_CHANGE_HISTORY_MARKERS) ? 1 : 0;
i += (chState & SC_CHANGE_HISTORY_INDICATORS) ? 2 : 0;
CheckMenuRadioItem(hmenu, IDM_VIEW_CHGHIST_NONE, IDM_VIEW_CHGHIST_ALL, i, MF_BYCOMMAND);
CheckCmdPos(GetSubMenu(hmenu, 2), _SUB_MNU_2 + 0, (i != IDM_VIEW_CHGHIST_NONE));
i = IDM_VIEW_COLORDEFHOTSPOTS + Settings.ColorDefHotspot;
CheckMenuRadioItem(hmenu, IDM_VIEW_COLORDEFHOTSPOTS, IDM_VIEW_COLOR_BGRA, i, MF_BYCOMMAND);
CheckCmdPos(GetSubMenu(hmenu, 2), _SUB_MNU_2 + 4, IsColorDefHotspotEnabled());
CheckCmd(hmenu, IDM_VIEW_UNICODE_POINTS, Settings.HighlightUnicodePoints);
CheckCmd(hmenu, IDM_VIEW_MATCHBRACES, Settings.MatchBraces);
i = IDM_VIEW_HILITCURLN_NONE + Settings.HighlightCurrentLine;
CheckMenuRadioItem(hmenu, IDM_VIEW_HILITCURLN_NONE, IDM_VIEW_HILITCURLN_FRAME, i, MF_BYCOMMAND);
CheckCmdPos(GetSubMenu(hmenu, 2), _SUB_MNU_2 + 7, (i != IDM_VIEW_HILITCURLN_NONE));
#ifdef D_NP3_WIN10_DARK_MODE
EnableCmd(hmenu, IDM_VIEW_WIN_DARK_MODE, IsDarkModeSupported());
CheckCmd(hmenu, IDM_VIEW_WIN_DARK_MODE, IsSettingDarkMode());
#else
RemoveMenu(hmenu, IDM_VIEW_WIN_DARK_MODE, 0);
#endif
// --------------------------------------------------------------------------
int const mnuMain = 2;
int const mnuSubOcc = _SUB_MNU_2 + 8;
int const mnuSubSubWord = 6;
if (Settings.MarkOccurrencesMatchWholeWords) {
i = IDM_VIEW_MARKOCCUR_WORD;
} else if (Settings.MarkOccurrencesCurrentWord) {
i = IDM_VIEW_MARKOCCUR_CURRENT;
} else {
i = IDM_VIEW_MARKOCCUR_WNONE;
}
CheckMenuRadioItem(hmenu, IDM_VIEW_MARKOCCUR_WNONE, IDM_VIEW_MARKOCCUR_CURRENT, i, MF_BYCOMMAND);
CheckCmdPos(GetSubMenu(GetSubMenu(hmenu, mnuMain), mnuSubOcc), mnuSubSubWord, (i != IDM_VIEW_MARKOCCUR_WNONE));
i = IsMarkOccurrencesEnabled();
EnableCmd(hmenu, IDM_VIEW_MARKOCCUR_VISIBLE, i);
EnableCmd(hmenu, IDM_VIEW_MARKOCCUR_CASE, i);
EnableCmd(hmenu, IDM_VIEW_MARKOCCUR_WNONE, i);
EnableCmd(hmenu, IDM_VIEW_MARKOCCUR_WORD, i);
EnableCmd(hmenu, IDM_VIEW_MARKOCCUR_CURRENT, i);
EnableCmdPos(GetSubMenu(GetSubMenu(hmenu, mnuMain), mnuSubOcc), mnuSubSubWord, i);
CheckCmdPos(GetSubMenu(hmenu, mnuMain), mnuSubOcc, i);
// --------------------------------------------------------------------------
bool const fd = (FocusedView.CodeFoldingAvailable && FocusedView.ShowCodeFolding);
EnableCmd(hmenu, IDM_VIEW_FOLDING, FocusedView.CodeFoldingAvailable && !FocusedView.HideNonMatchedLines);
CheckCmd(hmenu, IDM_VIEW_FOLDING, fd);
EnableCmd(hmenu, IDM_VIEW_TOGGLEFOLDS, !te && fd);
EnableCmd(hmenu, CMD_FOLDJUMPDOWN, !te && fd);
EnableCmd(hmenu, CMD_FOLDJUMPUP, !te && fd);
EnableCmd(hmenu, CMD_FOLDCOLLAPSE, !te && fd);
EnableCmd(hmenu, CMD_FOLDEXPAND, !te && fd);
bool const bF = (SC_FOLDLEVELBASE < (SciCall_GetFoldLevel(iCurLine) & SC_FOLDLEVELNUMBERMASK));
bool const bH = (SciCall_GetFoldLevel(iCurLine) & SC_FOLDLEVELHEADERFLAG);
EnableCmd(hmenu, IDM_VIEW_TOGGLE_CURRENT_FOLD, !te && fd && (bF || bH));
CheckCmdPos(GetSubMenu(hmenu, 2), _SUB_MNU_2 + 14, fd);
// --------------------------------------------------------------------------
CheckCmd(hmenu, IDM_VIEW_SHOWBLANKS, Settings.ViewWhiteSpace);
CheckCmd(hmenu, IDM_VIEW_SHOWEOLS, Settings.ViewEOLs);
CheckCmd(hmenu, IDM_VIEW_WORDWRAPSYMBOLS, Settings.ShowWordWrapSymbols);
CheckCmd(hmenu, IDM_VIEW_TITLEBAR, Settings.ShowTitlebar);
CheckCmd(hmenu, IDM_VIEW_MENUBAR, Settings.ShowMenubar);
CheckCmd(hmenu, IDM_VIEW_TOOLBAR, Settings.ShowToolbar);
EnableCmd(hmenu, IDM_VIEW_CUSTOMIZETB, Settings.ShowToolbar);
CheckCmd(hmenu, IDM_VIEW_STATUSBAR, Settings.ShowStatusbar);
CheckCmd(hmenu, IDM_VIEW_DPISCALETB, Settings.DpiScaleToolBar);
CheckCmd(hmenu, IDM_VIEW_STICKYWINPOS, Flags.bStickyWindowPosition);
CheckCmd(hmenu, IDM_VIEW_SHOW_HYPLNK_CALLTIP, Settings.ShowHypLnkToolTip);
CheckCmd(hmenu, IDM_VIEW_SCROLLPASTEOF, Settings.ScrollPastEOF);
//i = SciCall_GetLexer();
//EnableCmd(hmenu,IDM_SET_AUTOCLOSETAGS,(i == SCLEX_HTML || i == SCLEX_XML));
CheckCmd(hmenu, IDM_SET_AUTOCLOSETAGS, Settings.AutoCloseTags /*&& (i == SCLEX_HTML || i == SCLEX_XML)*/);
CheckCmd(hmenu, IDM_SET_AUTOCLOSEQUOTES, Settings.AutoCloseQuotes);
CheckCmd(hmenu, IDM_SET_AUTOCLOSEBRACKETS, Settings.AutoCloseBrackets);
CheckCmd(hmenu, IDM_SET_REUSEWINDOW, Flags.bReuseWindow);
CheckCmd(hmenu, IDM_SET_SINGLEFILEINSTANCE, Flags.bSingleFileInstance);
CheckCmd(hmenu, IDM_SET_ALWAYSONTOP, Settings.AlwaysOnTop);
CheckCmd(hmenu, IDM_SET_MINTOTRAY, Settings.MinimizeToTray);
CheckCmd(hmenu, IDM_SET_TRANSPARENT, Settings.TransparentMode);
CheckCmd(hmenu, IDM_SET_TABSASSPACES, Globals.fvCurFile.bTabsAsSpaces);
CheckCmd(hmenu, IDM_SET_AUTOINDENTTEXT, Settings.AutoIndent);
EnableCmd(hmenu, IDM_EDIT_COMPLETEWORD, !te && !ro);
CheckCmd(hmenu, IDM_SET_AUTOCOMPLETEWORDS, Settings.AutoCompleteWords && !ro);
CheckCmd(hmenu, IDM_SET_AUTOCLEXKEYWORDS, Settings.AutoCLexerKeyWords && !ro);
CheckCmd(hmenu, IDM_SET_ALTERNATE_WORD_SEPS, Settings.AccelWordNavigation);
CheckCmd(hmenu, IDM_SET_AUTOSAVE_BACKUP, (Settings.AutoSaveOptions & (ASB_Periodic | ASB_Backup)));
bool const dwr = (Settings.RenderingTechnology > SC_TECHNOLOGY_DEFAULT);
//bool const gdi = ((Settings.RenderingTechnology % SC_TECHNOLOGY_DIRECTWRITEDC) == 0);
i = IDM_SET_RENDER_TECH_GDI + Settings.RenderingTechnology;
CheckMenuRadioItem(hmenu, IDM_SET_RENDER_TECH_GDI, IDM_SET_RENDER_TECH_D2DDC, i, MF_BYCOMMAND);
CheckCmd(hmenu, IDM_SET_RTL_LAYOUT_EDIT, Settings.EditLayoutRTL);
//~EnableCmd(hmenu, IDM_SET_RTL_LAYOUT_EDIT, gdi);
CheckCmd(hmenu, IDM_SET_RTL_LAYOUT_DLG, Settings.DialogsLayoutRTL);
if (dwr) {
i = IDM_SET_BIDIRECTIONAL_NONE + Settings.Bidirectional;
CheckMenuRadioItem(hmenu, IDM_SET_BIDIRECTIONAL_NONE, IDM_SET_BIDIRECTIONAL_R2L, i, MF_BYCOMMAND);
} else {
i = IDM_SET_BIDIRECTIONAL_NONE;
CheckMenuRadioItem(hmenu, IDM_SET_BIDIRECTIONAL_NONE, IDM_SET_BIDIRECTIONAL_R2L, i, MF_BYCOMMAND);
}
EnableCmd(hmenu, IDM_SET_BIDIRECTIONAL_NONE, dwr);
EnableCmd(hmenu, IDM_SET_BIDIRECTIONAL_L2R, dwr);
EnableCmd(hmenu, IDM_SET_BIDIRECTIONAL_R2L, dwr);
CheckCmd(hmenu, IDS_USE_LOCALE_DATEFMT, Settings.PreferredLocale4DateFmt);
CheckCmd(hmenu, IDM_SET_MUTE_MESSAGEBEEP, Settings.MuteMessageBeep);
CheckCmd(hmenu, IDM_SET_SAVEBEFORERUNNINGTOOLS, Settings.SaveBeforeRunningTools);
//~EnableCmd(hmenu, IDM_SET_SAVEBEFORERUNNINGTOOLS, !faro);
CheckCmd(hmenu, IDM_SET_NOSAVERECENT, Settings.SaveRecentFiles);
CheckCmd(hmenu, IDM_SET_NOPRESERVECARET, Settings.PreserveCaretPos);
CheckCmd(hmenu, IDM_SET_NOSAVEFINDREPL, Settings.SaveFindReplace);
CheckCmd(hmenu, IDM_SET_AUTOLOAD_MRU_FILE, Settings.AutoLoadMRUFile);
CheckCmd(hmenu, IDM_SET_EVALTINYEXPRONSEL, Settings.EvalTinyExprOnSelection);
CheckCmd(hmenu, IDM_SET_CHANGENOTIFY, (FileWatching.FileWatchingMode != FWM_DONT_CARE));
if (StrIsNotEmpty(s_wchTitleExcerpt)) {
i = IDM_SET_SHOWEXCERPT;
} else if (Settings.PathNameFormat == 0) {
i = IDM_SET_SHOWFILENAMEONLY;
} else if (Settings.PathNameFormat == 1) {
i = IDM_SET_SHOWFILENAMEFIRST;
} else {
i = IDM_SET_SHOWFULLPATH;
}
CheckMenuRadioItem(hmenu, IDM_SET_SHOWFILENAMEONLY, IDM_SET_SHOWEXCERPT, i, MF_BYCOMMAND);
if (Settings.EscFunction == 1) {
i = IDM_SET_ESCMINIMIZE;
} else if (Settings.EscFunction == 2) {
i = IDM_SET_ESCEXIT;
} else {
i = IDM_SET_NOESCFUNC;
}
CheckMenuRadioItem(hmenu, IDM_SET_NOESCFUNC, IDM_SET_ESCEXIT, i, MF_BYCOMMAND);
bool const bIsHLink = (SciCall_IndicatorValueAt(INDIC_NP3_HYPERLINK, iCurPos) > 0);
EnableCmd(hmenu, CMD_OPEN_HYPERLINK, !mrs && bIsHLink);
EnableCmd(hmenu, CMD_WEBACTION1, !se && !mrs && bPosInSel && !bIsHLink);
EnableCmd(hmenu, CMD_WEBACTION2, !se && !mrs && bPosInSel && !bIsHLink);
i = (int)Path_IsNotEmpty(Settings2.AdministrationTool);
EnableCmd(hmenu, IDM_HELP_ADMINEXE, i);
#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS)
for (unsigned lng = 0; lng < MuiLanguages_CountOf(); ++lng) {
//EnableCmd(hmenu, GetMUILngResourceID(lng), ExistMUILanguageDLL(lng));
CheckCmd(hmenu, GetMUILngResourceID(lng), IsMUILanguageActive(lng));
}
#endif
UpdateSaveSettingsCmds();
return FALSE;
}
#if 0
//=============================================================================
//
// MsgKeyDown() - Handles WM_KEYDOWN event
// ~~~ no event from Scintilla ~~~
//
//
LRESULT MsgKeyDown(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
if (IsKeyDown(VK_CONTROL)) {
SciCall_SetCursor(SC_NP3_CURSORHAND);
}
return FALSE;
}
#endif
//=============================================================================
//
// _ApplyChangeHistoryMode() - Handles Change-History Settings
//
static void _ApplyChangeHistoryMode()
{
int const iChgHist = SciCall_GetChangeHistory();
if (iChgHist == Settings.ChangeHistoryMode) { return; }
if ((!iChgHist && Settings.ChangeHistoryMode) || !Settings.ChangeHistoryMode) {
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, L"AllowClearUndoHistory", IDS_MUI_ASK_CLEAR_UNDO))) {
UndoRedoReset();
}
else {
Settings.ChangeHistoryMode = iChgHist;
return;
}
}
else {
SciCall_SetChangeHistory(Settings.ChangeHistoryMode);
}
UpdateMargins(true);
UpdateToolbar();
}
//=============================================================================
//
// MsgCommand() - Handles WM_COMMAND
//
LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
unsigned const iLoWParam = (unsigned)LOWORD(wParam);
#if defined(HAVE_DYN_LOAD_LIBS_MUI_LNGS)
bool const bIsLngMenuCmd = ((iLoWParam >= IDS_MUI_LANG_EN_US) && (iLoWParam < (IDS_MUI_LANG_EN_US + MuiLanguages_CountOf())));
if (bIsLngMenuCmd) {
DynamicLanguageMenuCmd(iLoWParam);
Style_InsertThemesMenu(Globals.hMainMenu);
DrawMenuBar(Globals.hwndMain);
UpdateToolbar();
UpdateStatusbar(true);
return FALSE;
}
#endif
bool const bIsThemesMenuCmd = ((iLoWParam >= IDM_THEMES_FACTORY_RESET) && (iLoWParam < (int)(IDM_THEMES_FACTORY_RESET + ThemeItems_CountOf())));
if (bIsThemesMenuCmd) {
if (iLoWParam == IDM_THEMES_FACTORY_RESET) {
if (!IsYesOkay(InfoBoxLng(MB_OKCANCEL | MB_ICONWARNING, L"MsgResetScheme", IDS_MUI_WARN_STYLE_RESET))) {
return FALSE;
}
}
Style_DynamicThemesMenuCmd(iLoWParam);
return FALSE;
}
switch(iLoWParam) {
case SCEN_CHANGE:
EditUpdateVisibleIndicators();
MarkAllOccurrences(-1, false);
break;
case IDT_TIMER_UPDATE_STATUSBAR:
_UpdateStatusbarDelayed((bool)lParam);
break;
case IDT_TIMER_UPDATE_TOOLBAR:
_UpdateToolbarDelayed();
break;
case IDT_TIMER_UPDATE_TITLEBAR:
_UpdateTitlebarDelayed((HWND)lParam);
break;
case IDT_TIMER_CALLBACK_MRKALL:
EditMarkAllOccurrences(Globals.hwndEdit, (bool)lParam);
break;
case IDT_TIMER_CLEAR_CALLTIP:
Sci_CallTipCancelEx();
break;
case IDT_TIMER_UNDO_TRANSACTION:
_SplitUndoTransaction();
break;
case IDM_FILE_NEW: {
HPATHL hfile_pth = Path_Allocate(L"");
FileLoadFlags fLoadFlags = FLF_New;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
FileLoad(hfile_pth, fLoadFlags);
Path_Release(hfile_pth);
} break;
case IDM_FILE_OPEN: {
HPATHL hfile_pth = Path_Allocate(L"");
FileLoadFlags fLoadFlags = FLF_None;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
FileLoad(hfile_pth, fLoadFlags);
Path_Release(hfile_pth);
} break;
case IDM_FILE_REVERT:
if (!FileWatching.MonitoringLog) {
if (IsSaveNeeded()) {
if (!IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONQUESTION, NULL, IDS_MUI_ASK_REVERT))) {
break;
}
//~ don't revert if no save needed
//~FileRevert(Paths.CurrentFile, false);
}
// revert in any case (manually forced)
FileRevert(Paths.CurrentFile, true);
}
break;
case IDM_FILE_SAVE:
FileSave(FSF_SaveAlways);
break;
case IDM_FILE_SAVEAS:
FileSave(FSF_SaveAlways | FSF_SaveAs);
break;
case IDM_FILE_SAVECOPY:
FileSave(FSF_SaveAlways | FSF_SaveAs | FSF_SaveCopy);
break;
case IDM_FILE_PRESERVE_FILEMODTIME: {
if (!Flags.bPreserveFileModTime) {
InfoBoxLng(MB_OK, L"PreserveFileModTime", IDS_MUI_INF_PRSVFILEMODTM);
}
Flags.bPreserveFileModTime = true;
FileSave(FSF_SaveAlways);
}
break;
case IDM_FILE_READONLY:
if (Path_IsNotEmpty(Paths.CurrentFile)) {
DWORD dwFileAttributes = Path_GetFileAttributes(Paths.CurrentFile);
if (IsReadOnly(dwFileAttributes)) {
dwFileAttributes = (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
} else {
dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
}
WCHAR szDisplayName[MAX_PATH_EXPLICIT>>1] = { L'\0' };
if (!Path_SetFileAttributes(Paths.CurrentFile, dwFileAttributes)) {
Path_GetDisplayName(szDisplayName, COUNTOF(szDisplayName), Paths.CurrentFile, NULL, false);
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_READONLY_MODIFY, szDisplayName);
}
if (Flags.bSettingsFileSoftLocked) {
Globals.bCanSaveIniFile = CanAccessPath(Paths.IniFile, GENERIC_WRITE);
UpdateSaveSettingsCmds();
}
UpdateToolbar();
}
break;
case IDM_FILE_LOCK_SHARE_READ:
InstallFileWatching(false); // terminate
if (FileWatching.FileWatchingMode == FWM_EXCLUSIVELOCK) {
FileWatching.FileWatchingMode = Settings.FileWatchingMode;
} else {
FileWatching.FileWatchingMode = FWM_EXCLUSIVELOCK;
}
InstallFileWatching(true);
break;
case IDM_FILE_BROWSE:
DialogFileBrowse(hwnd);
break;
case IDM_GREP_WIN_SEARCH:
case IDM_GREP_WIN_SEARCH2: {
WCHAR wchBuffer[MIDSZ_BUFFER] = { L'\0' };
EditGetSelectedText(wchBuffer, COUNTOF(wchBuffer));
DialogGrepWin(hwnd, wchBuffer);
}
break;
case IDM_FILE_NEWWINDOW:
case IDM_FILE_NEWWINDOW2: {
SaveAllSettings(false);
HPATHL hpth = (iLoWParam == IDM_FILE_NEWWINDOW2) ? Paths.CurrentFile : NULL;
DialogNewWindow(hwnd, Settings.SaveBeforeRunningTools, hpth, NULL);
}
break;
case IDM_FILE_LAUNCH: {
if (Path_IsEmpty(Paths.CurrentFile)) {
break;
}
if (Settings.SaveBeforeRunningTools && !FileSave(FSF_Ask)) {
break;
}
HPATHL hdir = Path_Copy(Paths.CurrentFile);
Path_RemoveFileSpec(hdir);
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_DEFAULT;
sei.hwnd = hwnd;
sei.lpVerb = NULL;
sei.lpFile = Path_Get(Paths.CurrentFile);
sei.lpParameters = NULL;
sei.lpDirectory = Path_Get(hdir);
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&sei);
Path_Release(hdir);
}
break;
case IDM_FILE_EXPLORE_DIR: {
if (Settings.SaveBeforeRunningTools && !FileSave(FSF_Ask)) {
break;
}
PIDLIST_ABSOLUTE pidl = NULL;
SHParseDisplayName(Path_IsNotEmpty(Paths.CurrentFile) ? Path_Get(Paths.CurrentFile) : Path_Get(Paths.WorkingDirectory),
NULL, &pidl, SFGAO_BROWSABLE | SFGAO_FILESYSTEM, NULL);
if (pidl) {
SHOpenFolderAndSelectItems(pidl, 0, NULL, 0);
ILFree(pidl);
}
}
break;
case IDM_FILE_LAUNCH_ELEVATED: {
EditFileIOStatus fioStatus = INIT_FILEIO_STATUS;
fioStatus.iEncoding = Encoding_GetCurrent();
fioStatus.iEOLMode = SciCall_GetEOLMode();
if (DoElevatedRelaunch(&fioStatus, false)) {
CloseApplication();
} else {
InfoBoxLng(MB_ICONSHIELD, NULL, IDS_MUI_ERR_ELEVATED_RIGHTS);
}
}
break;
case IDM_FILE_RUN: {
if (Settings.SaveBeforeRunningTools && !FileSave(FSF_Ask)) {
break;
}
HPATHL hcpy = Path_Copy(Paths.CurrentFile);
Path_QuoteSpaces(hcpy, false);
RunDlg(hwnd, Path_Get(hcpy));
Path_Release(hcpy);
}
break;
case IDM_FILE_OPENWITH:
if (Settings.SaveBeforeRunningTools && !FileSave(FSF_Ask)) {
break;
}
OpenWithDlg(hwnd,Path_Get(Paths.CurrentFile));
break;
case IDM_FILE_PAGESETUP:
EditPrintSetup(Globals.hwndEdit);
break;
case IDM_FILE_PRINT: {
WCHAR tchPageFmt[32] = { L'\0' };
WCHAR szDisplayName[MAX_PATH_EXPLICIT>>1];
GetLngString(IDS_MUI_UNTITLED, szDisplayName, COUNTOF(szDisplayName));
Path_GetDisplayName(szDisplayName, COUNTOF(szDisplayName), Paths.CurrentFile, NULL, false);
GetLngString(IDS_MUI_PRINT_PAGENUM,tchPageFmt,COUNTOF(tchPageFmt));
if (!EditPrint(Globals.hwndEdit, szDisplayName, tchPageFmt)) {
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_PRINT_ERROR, szDisplayName);
}
}
break;
case IDM_FILE_PROPERTIES: {
if (Path_IsEmpty(Paths.CurrentFile)) {
break;
}
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_INVOKEIDLIST;
sei.hwnd = hwnd;
sei.lpVerb = L"properties";
sei.lpFile = Path_Get(Paths.CurrentFile);
sei.lpParameters = NULL;
sei.lpDirectory = NULL;
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&sei);
}
break;
case IDM_FILE_CREATELINK: {
if (Path_IsEmpty(Paths.CurrentFile)) {
break;
}
WCHAR tchDescription[128] = { L'\0' };
GetLngString(IDS_MUI_LINKDESCRIPTION, tchDescription, COUNTOF(tchDescription));
if (!Path_CreateDeskLnk(Paths.CurrentFile, tchDescription)) {
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_ERR_CREATELINK);
}
}
break;
case IDM_FILE_OPENFAV:
if (FileSave(FSF_Ask)) {
HPATHL hfile_pth = Path_Allocate(NULL);
if (FavoritesDlg(hwnd, hfile_pth)) {
if (Path_IsLnkFile(hfile_pth)) {
Path_GetLnkPath(hfile_pth, hfile_pth);
}
FileLoadFlags fLoadFlags = FLF_DontSave;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
if (Path_IsExistingDirectory(hfile_pth)) {
if (OpenFileDlg(Globals.hwndMain, hfile_pth, hfile_pth)) {
FileLoad(hfile_pth, fLoadFlags);
}
}
else {
FileLoad(hfile_pth, fLoadFlags);
}
}
Path_Release(hfile_pth);
}
break;
case IDM_FILE_ADDTOFAV:
if (Path_IsNotEmpty(Paths.CurrentFile)) {
AddToFavDlg(hwnd, Paths.CurrentFile);
}
break;
case IDM_FILE_MANAGEFAV: {
// Run favorites directory
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_DEFAULT;
sei.hwnd = hwnd;
sei.lpVerb = NULL;
sei.lpFile = Path_Get(Settings.FavoritesDir);
sei.lpParameters = NULL;
sei.lpDirectory = NULL;
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&sei);
}
break;
case IDM_FILE_RECENT:
if (MRU_Count(Globals.pFileMRU) > 0) {
if (FileSave(FSF_Ask)) {
HPATHL hfile_pth = Path_Allocate(NULL);
if (FileMRUDlg(hwnd, hfile_pth)) {
FileLoadFlags fLoadFlags = FLF_DontSave;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
FileLoad(hfile_pth, fLoadFlags);
}
Path_Release(hfile_pth);
}
}
break;
case IDM_FILE_EXIT:
CloseApplication();
break;
case IDM_ENCODING_ANSI:
case IDM_ENCODING_UNICODE:
case IDM_ENCODING_UNICODEREV:
case IDM_ENCODING_UTF8:
case IDM_ENCODING_UTF8SIGN:
case IDM_ENCODING_SELECT: {
cpi_enc_t iNewEncoding = (HIWORD(wParam) >= IDM_ENCODING_SELECT) ?
(cpi_enc_t)(HIWORD(wParam) - IDM_ENCODING_SELECT) : Encoding_GetCurrent();
if (iLoWParam == IDM_ENCODING_SELECT) {
if ((HIWORD(wParam) < IDM_ENCODING_SELECT) && !SelectEncodingDlg(hwnd, &iNewEncoding, false)) {
break; // no change
}
} else {
switch (iLoWParam) {
case IDM_ENCODING_UNICODE:
iNewEncoding = CPI_UNICODEBOM;
break;
case IDM_ENCODING_UNICODEREV:
iNewEncoding = CPI_UNICODEBEBOM;
break;
case IDM_ENCODING_UTF8:
iNewEncoding = CPI_UTF8;
break;
case IDM_ENCODING_UTF8SIGN:
iNewEncoding = CPI_UTF8SIGN;
break;
case IDM_ENCODING_ANSI:
iNewEncoding = CPI_ANSI_DEFAULT;
}
}
BeginWaitCursorUID(Flags.bHugeFileLoadState, IDS_MUI_SB_RECODING_DOC);
if (EditSetNewEncoding(Globals.hwndEdit, iNewEncoding, (s_flagSetEncoding != CPI_NONE))) {
UpdateMargins(true);
SetSaveNeeded(true);
}
EndWaitCursor();
UpdateToolbar();
}
break;
case IDM_ENCODING_RECODE: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
cpi_enc_t iNewEncoding = Encoding_MapSignature(Encoding_GetCurrent());
if (IsSaveNeeded()) {
if (!IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONQUESTION, NULL, IDS_MUI_ASK_RECODE))) {
break;
}
}
if (SelectEncodingDlg(hwnd, &iNewEncoding, true)) {
Encoding_Forced(iNewEncoding);
FileLoadFlags const fLoadFlags = FLF_DontSave | FLF_Reload | FLF_SkipUnicodeDetect | FLF_SkipANSICPDetection;
FileLoad(Paths.CurrentFile, fLoadFlags);
}
}
}
break;
case IDM_ENCODING_SETDEFAULT:
SelectDefEncodingDlg(hwnd, &Settings.DefaultEncoding);
UpdateToolbar();
UpdateStatusbar(false);
break;
case IDM_LINEENDINGS_CRLF:
case IDM_LINEENDINGS_CR:
case IDM_LINEENDINGS_LF: {
int const _eol_mode = (iLoWParam - IDM_LINEENDINGS_CRLF); // SC_EOL_CRLF(0), SC_EOL_CR(1), SC_EOL_LF(2)
BeginWaitCursorUID(Flags.bHugeFileLoadState, IDS_MUI_SB_CONV_LNBRK);
SciCall_SetEOLMode(_eol_mode);
EditEnsureConsistentLineEndings(Globals.hwndEdit);
EndWaitCursor();
UpdateToolbar();
}
break;
case IDM_LINEENDINGS_SETDEFAULT:
SelectDefLineEndingDlg(hwnd, (LPARAM)&Settings.DefaultEOLMode);
break;
case IDM_EDIT_UNDO:
if (SciCall_CanUndo()) {
//LimitNotifyEvents(EVM_UndoRedo);
SciCall_Undo();
//RestoreNotifyEvents();
}
break;
case IDM_EDIT_REDO:
if (SciCall_CanRedo()) {
//LimitNotifyEvents(EVM_UndoRedo);
SciCall_Redo();
//RestoreNotifyEvents();
}
break;
case IDM_EDIT_CUT: {
if (SciCall_IsSelectionEmpty() && Settings2.NoCutLineOnEmptySelection) {
break;
}
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
}
EditDeleteMarkerInSelection();
if (SciCall_IsSelectionEmpty()) {
EditCutLines(Globals.hwndEdit, true);
} else {
SciCall_Cut();
}
}
break;
case IDM_EDIT_CUTLINE: {
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
}
//~ explicit(!): ignore (SciCall_IsSelectionEmpty()) && Settings2.NoCutLineOnEmptySelection)
EditDeleteMarkerInSelection();
EditCutLines(Globals.hwndEdit, false);
}
break;
case IDM_EDIT_COPY: {
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
}
if (SciCall_IsSelectionEmpty()) {
if (!HandleHotSpotURLClicked(SciCall_GetCurrentPos(), COPY_HYPERLINK) &&
!Settings2.NoCopyLineOnEmptySelection) {
if (Sci_GetNetLineLength(Sci_GetCurrentLineNumber()) > 0) {
SciCall_CopyAllowLine(); // (!) VisualStudio behavior
// On Windows, an extra "MSDEVLineSelect" marker is added to the clipboard
// which is then used in SCI_PASTE to paste the whole line before the current line.
}
}
} else {
EditCopyMultiSelection(Globals.hwndEdit);
}
}
break;
case IDM_EDIT_COPYLINE: {
if (Sci_IsMultiOrRectangleSelection()) {
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_SELRECTORMULTI);
break;
}
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
}
DocPos const iSelLnStart = Sci_GetLineStartPosition(SciCall_GetSelectionStart());
// copy incl last line-breaks
DocLn const lnSelLast = SciCall_LineFromPosition(SciCall_GetSelectionEnd());
DocPos const iSelLnEnd = SciCall_PositionFromLine(lnSelLast) + SciCall_LineLength(lnSelLast);
SciCall_CopyRange(iSelLnStart, iSelLnEnd);
}
break;
case IDM_EDIT_COPYALL: {
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
}
SciCall_CopyRange(0, Sci_GetDocEndPosition());
}
break;
case IDM_EDIT_COPYADD: {
if (Sci_IsMultiOrRectangleSelection()) {
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_SELRECTORMULTI);
break;
}
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
}
DocPos const posSelStart = SciCall_IsSelectionEmpty() ? Sci_GetLineStartPosition(SciCall_GetSelectionStart()) : SciCall_GetSelectionStart();
DocPos const posSelEnd = SciCall_IsSelectionEmpty() ? Sci_GetLineEndPosition(SciCall_GetSelectionEnd()) : SciCall_GetSelectionEnd();
EditCopyRangeAppend(Globals.hwndEdit, posSelStart, posSelEnd, true);
}
break;
case IDM_EDIT_PASTE:
if (SciCall_CanPaste()) {
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
}
UndoTransActionBegin();
SciCall_Paste();
EndUndoTransAction();
}
break;
case IDM_EDIT_SWAP:
if (!SciCall_IsSelectionEmpty() && SciCall_CanPaste()) {
if (s_flagPasteBoard) {
s_bLastCopyFromMe = true;
}
EditSwapClipboard(Globals.hwndEdit, Settings.SkipUnicodeDetection);
}
break;
case IDM_EDIT_CLEARCLIPBOARD:
EditClearClipboard(Globals.hwndEdit);
break;
case IDM_EDIT_SELECTALL:
SciCall_SelectAll();
break;
case IDM_EDIT_SELECTWORD: {
if (SciCall_IsSelectionEmpty()) {
EditSelectWordAtPos(SciCall_GetCurrentPos(), false);
if (!SciCall_IsSelectionEmpty()) {
SciCall_ChooseCaretX();
break;
}
}
// selection not empty or no word found - select line
DocPos const iLineStart = SciCall_LineFromPosition(SciCall_GetSelectionStart());
DocPos const iLineEnd = SciCall_LineFromPosition(SciCall_GetSelectionEnd());
SciCall_SetSelection(SciCall_GetLineEndPosition(iLineEnd), SciCall_PositionFromLine(iLineStart));
SciCall_ChooseCaretX();
}
break;
case IDM_EDIT_SELECTALLMATCHES: {
if (!Sci_IsMultiOrRectangleSelection()) {
if (IsWindow(Globals.hwndDlgFindReplace)) {
SetFindReplaceData(); // s_FindReplaceData
EditSelectionMultiSelectAllEx(Globals.hwndEdit, &s_FindReplaceData);
} else {
if (SciCall_IsSelectionEmpty()) {
EditSelectWordAtPos(SciCall_GetCurrentPos(), false);
}
EditSelectionMultiSelectAll();
}
}
}
break;
case IDM_EDIT_MOVELINEUP:
EditMoveUp(Globals.hwndEdit);
break;
case IDM_EDIT_MOVELINEDOWN:
EditMoveDown(Globals.hwndEdit);
break;
case IDM_EDIT_DUPLINEORSELECTION:
if (SciCall_IsSelectionEmpty()) {
SciCall_LineDuplicate();
} else {
SciCall_SelectionDuplicate();
}
break;
case IDM_EDIT_LINETRANSPOSE:
SciCall_LineTranspose();
break;
case IDM_EDIT_DELETELINE: {
UserMarkerDeleteAll(Sci_GetCurrentLineNumber());
SciCall_LineDelete();
if (Sci_InLastLine()) {
SciCall_DeleteBack();
SciCall_Home();
}
}
break;
case IDM_EDIT_DELETELINELEFT: {
SciCall_DelLineLeft();
}
break;
case IDM_EDIT_DELETELINERIGHT: {
SciCall_DelLineRight();
}
break;
case IDM_EDIT_INDENT:
EditIndentBlock(Globals.hwndEdit, SCI_TAB, true, false);
break;
case IDM_EDIT_UNINDENT:
EditIndentBlock(Globals.hwndEdit, SCI_BACKTAB, true, false);
break;
case CMD_TAB:
EditIndentBlock(Globals.hwndEdit, SCI_TAB, false, false);
break;
case CMD_BACKTAB:
EditIndentBlock(Globals.hwndEdit, SCI_BACKTAB, false, false);
break;
case CMD_CTRLTAB:
SciCall_SetUseTabs(true);
SciCall_SetTabIndents(false);
EditIndentBlock(Globals.hwndEdit, SCI_TAB, false, false);
SciCall_SetTabIndents(Globals.fvCurFile.bTabIndents);
SciCall_SetUseTabs(!Globals.fvCurFile.bTabsAsSpaces);
break;
case CMD_CHECK_INDENTATION: {
EditFileIOStatus status = INIT_FILEIO_STATUS;
EditIndentationStatistic(Globals.hwndEdit, &status);
if (ConsistentIndentationCheck(&status)) {
InfoBoxLng(MB_ICONINFORMATION, NULL, IDS_MUI_INDENT_CONSISTENT);
}
}
break;
case CMD_DELETEBACK: {
EditDeleteMarkerInSelection();
SciCall_DeleteBack();
}
break;
case CMD_VK_INSERT:
SciCall_EditToggleOverType();
break;
case IDM_EDIT_ENCLOSESELECTION: {
static ENCLOSESELDATA data = { 0 };
if (EditEncloseSelectionDlg(hwnd, &data)) {
EditEncloseSelection(data.pwsz1, data.pwsz2);
}
}
break;
case IDM_EDIT_PADWITHSPACES:
UndoTransActionBegin();
EditPadWithSpaces(Globals.hwndEdit, false);
EndUndoTransAction();
break;
case IDM_EDIT_STRIP1STCHAR:
EditStripFirstCharacter(Globals.hwndEdit);
break;
case IDM_EDIT_STRIPLASTCHAR:
EditStripLastCharacter(Globals.hwndEdit, false, false);
break;
case IDM_EDIT_TRIMLINES:
EditStripLastCharacter(Globals.hwndEdit, false, true);
break;
case IDM_EDIT_COMPRESS_BLANKS:
EditCompressBlanks(Globals.hwndEdit);
break;
case IDM_EDIT_MERGEBLANKLINES:
EditRemoveBlankLines(Globals.hwndEdit, true, true);
break;
case IDM_EDIT_MERGEEMPTYLINES:
EditRemoveBlankLines(Globals.hwndEdit, true, false);
break;
case IDM_EDIT_REMOVEBLANKLINES:
EditRemoveBlankLines(Globals.hwndEdit, false, true);
break;
case IDM_EDIT_REMOVEEMPTYLINES:
EditRemoveBlankLines(Globals.hwndEdit, false, false);
break;
case IDM_EDIT_REMOVEDUPLICATELINES:
EditRemoveDuplicateLines(Globals.hwndEdit, false);
break;
case IDM_EDIT_CLEAR_MARKER:
EditBookmarkToggle(Globals.hwndEdit, Sci_GetCurrentLineNumber(), 0);
break;
case IDM_EDIT_CUT_MARKED:
EditFocusMarkedLinesCmd(Globals.hwndEdit, true, true);
break;
case IDM_EDIT_COPY_MARKED:
EditFocusMarkedLinesCmd(Globals.hwndEdit, true, false);
break;
case IDM_EDIT_DELETE_MARKED:
EditFocusMarkedLinesCmd(Globals.hwndEdit, false, true);
break;
case IDM_EDIT_MODIFYLINES: {
static ENCLOSESELDATA data = { 0 };
if (EditModifyLinesDlg(hwnd, &data)) {
EditModifyLines(&data);
}
}
break;
case IDM_EDIT_ALIGN:
if (EditAlignDlg(hwnd,&s_iAlignMode)) {
EditAlignText(s_iAlignMode);
}
break;
case IDM_EDIT_SORTLINES:
if (EditSortDlg(hwnd,&s_iSortOptions)) {
EditSortLines(Globals.hwndEdit, s_iSortOptions);
}
break;
case IDM_EDIT_COLUMNWRAP: {
UINT uWrpCol = Globals.iWrapCol;
if (ColumnWrapDlg(hwnd, IDD_MUI_COLUMNWRAP, &uWrpCol)) {
Globals.iWrapCol = clampi((int)uWrpCol, SciCall_GetTabWidth(), LONG_LINES_MARKER_LIMIT);
EditWrapToColumnEx(Globals.hwndEdit, Globals.iWrapCol);
}
}
break;
case IDM_EDIT_SPLITLINES:
EditSplitLines(Globals.hwndEdit);
break;
case IDM_EDIT_JOINLINES:
EditJoinLinesEx(false, true);
break;
case IDM_EDIT_JOINLN_NOSP:
EditJoinLinesEx(false, false);
break;
case IDM_EDIT_JOINLINES_PARA:
EditJoinLinesEx(true, true);
break;
case IDM_EDIT_CONVERTUPPERCASE:
SciCall_UpperCase();
break;
case IDM_EDIT_CONVERTLOWERCASE:
SciCall_LowerCase();
break;
case IDM_EDIT_INVERTCASE:
EditInvertCase(Globals.hwndEdit);
break;
case IDM_EDIT_TITLECASE:
EditTitleCase(Globals.hwndEdit);
break;
case IDM_EDIT_SENTENCECASE:
EditSentenceCase(Globals.hwndEdit);
break;
case IDM_EDIT_CONVERTTABS:
EditTabsToSpaces(Globals.fvCurFile.iTabWidth, false);
break;
case IDM_EDIT_CONVERTSPACES:
EditSpacesToTabs(Globals.fvCurFile.iTabWidth, false);
break;
case IDM_EDIT_CONVERTTABS2:
EditTabsToSpaces(Globals.fvCurFile.iTabWidth, true);
break;
case IDM_EDIT_CONVERTSPACES2:
EditSpacesToTabs(Globals.fvCurFile.iTabWidth, true);
break;
case IDM_EDIT_INSERT_TAG: {
static ENCLOSESELDATA data = { 0 };
UINT repeat = 1;
if (EditInsertTagDlg(hwnd, &data, &repeat)) {
while (repeat > 0) {
EditEncloseSelection(data.pwsz1, data.pwsz2);
--repeat;
}
}
}
break;
case IDM_EDIT_INSERT_ENCODING: {
cpi_enc_t const iEncoding = Encoding_GetCurrent();
char chEncStrg[128] = { '\0' };
WideCharToMultiByteEx(Encoding_SciCP, 0, Encoding_GetLabel(iEncoding), -1, chEncStrg, COUNTOF(chEncStrg), NULL, NULL);
EditReplaceSelection(chEncStrg, false);
}
break;
case IDM_EDIT_INSERT_SHORTDATE:
case IDM_EDIT_INSERT_LONGDATE:
EditInsertDateTimeStrg((iLoWParam == IDM_EDIT_INSERT_SHORTDATE), false);
break;
case IDM_EDIT_INSERT_FILENAME:
case IDM_EDIT_INSERT_DIRNAME:
case IDM_EDIT_INSERT_PATHNAME: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
if (iLoWParam == IDM_EDIT_INSERT_FILENAME) {
HPATHL hfilename = Path_Allocate(Path_FindFileName(Paths.CurrentFile));
SetClipboardText(hwnd, Path_Get(hfilename), Path_GetLength(hfilename));
Path_Release(hfilename);
}
else if (iLoWParam == IDM_EDIT_INSERT_DIRNAME) {
HPATHL hcpy = Path_Copy(Paths.CurrentFile);
Path_RemoveFileSpec(hcpy);
SetClipboardText(hwnd, Path_Get(hcpy), Path_GetLength(hcpy));
Path_Release(hcpy);
} else {
SetClipboardText(hwnd, Path_Get(Paths.CurrentFile), Path_GetLength(Paths.CurrentFile));
}
} else {
WCHAR tchUntitled[64];
GetLngString(IDS_MUI_UNTITLED, tchUntitled, COUNTOF(tchUntitled));
SetClipboardText(hwnd, tchUntitled, StringCchLen(tchUntitled, 0));
}
}
break;
case IDM_EDIT_INSERT_GUID: {
GUID guid;
if (SUCCEEDED(CoCreateGuid(&guid))) {
WCHAR wchBuf[128] = { L'\0' };
if (StringFromGUID2(&guid, wchBuf, COUNTOF(wchBuf))) {
StrTrim(wchBuf, L"{}");
SetClipboardText(hwnd, wchBuf, StringCchLen(wchBuf, 0));
//char chGuidBuffer[128] = { '\0' };
//if (WideCharToMultiByte(Encoding_SciCP, 0, wchBuf, -1, chGuidBuffer, (int)COUNTOF(chGuidBuffer), NULL, NULL)) {
// EditReplaceSelection(chGuidBuffer, false);
//}
}
}
}
break;
case IDM_EDIT_LINECOMMENT:
case IDM_EDIT_LINECOMMENT_ADD:
case IDM_EDIT_LINECOMMENT_REMOVE: {
WCHAR comment[8] = { L'\0' };
bool const bAtStart = Lexer_GetLineCommentStrg(comment, COUNTOF(comment));
if (StrIsNotEmpty(comment)) {
switch (iLoWParam) {
case IDM_EDIT_LINECOMMENT_ADD:
EditToggleLineCommentsSimple(comment, bAtStart, LNC_ADD);
break;
case IDM_EDIT_LINECOMMENT_REMOVE:
EditToggleLineCommentsSimple(comment, bAtStart, LNC_REMOVE);
break;
default:
EditToggleLineCommentsSimple(comment, bAtStart, LNC_TOGGLE);
break;
}
}
}
break;
case IDM_EDIT_LINECOMMENT_BLOCKEDIT: {
WCHAR comment[8] = { L'\0' };
bool const bAtStart = Lexer_GetLineCommentStrg(comment, COUNTOF(comment));
if (StrIsNotEmpty(comment)) {
EditToggleLineCommentsExtended(comment, bAtStart);
}
}
break;
case IDM_EDIT_STREAMCOMMENT: {
static ENCLOSESELDATA data = { 0 };
Lexer_GetStreamCommentStrgs(data.pwsz1, data.pwsz2, ENCLDATA_SIZE);
if (StrIsNotEmpty(data.pwsz1)) {
EditEncloseSelection(data.pwsz1, data.pwsz2);
}
}
break;
case IDM_EDIT_URLENCODE: {
EditURLEncode(false);
}
break;
case IDM_EDIT_URLDECODE: {
EditURLDecode(false);
}
break;
case IDM_EDIT_BASE64ENCODE: {
EditBase64Code(Globals.hwndEdit, true, Encoding_GetCurrent());
}
break;
case IDM_EDIT_BASE64DECODE: {
EditBase64Code(Globals.hwndEdit, false, Encoding_GetCurrent());
}
break;
case IDM_EDIT_B64DECODESEL: {
cpi_enc_t iEncoding = Encoding_GetCurrent();
if (!SelectEncodingDlg(hwnd, &iEncoding, false)) {
break; // no selection
}
EditBase64Code(Globals.hwndEdit, false, iEncoding);
}
break;
case IDM_EDIT_URL2PATH: {
EditURLEncode(true);
}
break;
case IDM_EDIT_PATH2URL: {
EditURLDecode(true);
}
break;
case IDM_EDIT_INVERTBACKSLASH: {
EditReplaceAllChr(L'\\', L'/');
} break;
case IDM_EDIT_INVERTSLASH: {
EditReplaceAllChr(L'/', L'\\');
}
break;
case IDM_EDIT_ESCAPECCHARS: {
EditEscapeCChars(Globals.hwndEdit);
}
break;
case IDM_EDIT_UNESCAPECCHARS: {
EditUnescapeCChars(Globals.hwndEdit);
}
break;
case IDM_EDIT_CHAR2HEX:
EditChar2Hex(Globals.hwndEdit);
break;
case IDM_EDIT_HEX2CHAR:
EditHex2Char(Globals.hwndEdit);
break;
case IDM_EDIT_FINDMATCHINGBRACE:
EditFindMatchingBrace(Globals.hwndEdit);
break;
case IDM_EDIT_SELTOMATCHINGBRACE:
EditSelectToMatchingBrace(Globals.hwndEdit);
break;
// Main Bookmark Functions
case BME_EDIT_BOOKMARKNEXT:
EditBookmarkNext(Globals.hwndEdit, Sci_GetCurrentLineNumber());
break;
case BME_EDIT_BOOKMARKPREV:
EditBookmarkPrevious(Globals.hwndEdit, Sci_GetCurrentLineNumber());
break;
case BME_EDIT_BOOKMARKTOGGLE:
EditBookmarkToggle(Globals.hwndEdit, Sci_GetCurrentLineNumber(), 0);
break;
case BME_EDIT_BOOKMARKCLEAR:
EditClearAllBookMarks(Globals.hwndEdit);
break;
case IDM_EDIT_FIND: {
SetFindReplaceData(); // s_FindReplaceData
if (!IsWindow(Globals.hwndDlgFindReplace)) {
Globals.bFindReplCopySelOrClip = true;
/*Globals.hwndDlgFindReplace =*/ EditFindReplaceDlg(Globals.hwndEdit, &s_FindReplaceData, false);
} else {
Globals.bFindReplCopySelOrClip = (GetForegroundWindow() != Globals.hwndDlgFindReplace);
if (GetDlgItem(Globals.hwndDlgFindReplace, IDC_REPLACE)) {
SendWMCommand(Globals.hwndDlgFindReplace, IDMSG_SWITCHTOFIND);
DestroyWindow(Globals.hwndDlgFindReplace);
/*Globals.hwndDlgFindReplace =*/ EditFindReplaceDlg(Globals.hwndEdit, &s_FindReplaceData, false);
} else {
SetForegroundWindow(Globals.hwndDlgFindReplace);
PostMessage(Globals.hwndDlgFindReplace, WM_NEXTDLGCTL, (WPARAM)(GetDlgItem(Globals.hwndDlgFindReplace, IDC_FINDTEXT)), 1);
}
}
}
break;
case IDM_EDIT_REPLACE: {
SetFindReplaceData(); // s_FindReplaceData
if (!IsWindow(Globals.hwndDlgFindReplace)) {
Globals.bFindReplCopySelOrClip = true;
/*Globals.hwndDlgFindReplace =*/ EditFindReplaceDlg(Globals.hwndEdit, &s_FindReplaceData, true);
} else {
Globals.bFindReplCopySelOrClip = (GetForegroundWindow() != Globals.hwndDlgFindReplace);
if (!GetDlgItem(Globals.hwndDlgFindReplace, IDC_REPLACE)) {
SendWMCommand(Globals.hwndDlgFindReplace, IDMSG_SWITCHTOREPLACE);
DestroyWindow(Globals.hwndDlgFindReplace);
/*Globals.hwndDlgFindReplace =*/ EditFindReplaceDlg(Globals.hwndEdit, &s_FindReplaceData, true);
} else {
SetForegroundWindow(Globals.hwndDlgFindReplace);
PostMessage(Globals.hwndDlgFindReplace, WM_NEXTDLGCTL, (WPARAM)(GetDlgItem(Globals.hwndDlgFindReplace, IDC_FINDTEXT)), 1);
}
}
}
break;
case IDM_EDIT_FINDNEXT:
case IDM_EDIT_FINDPREV:
case IDM_EDIT_REPLACENEXT:
case IDM_EDIT_SELTONEXT:
case IDM_EDIT_SELTOPREV:
if (Sci_IsDocEmpty()) {
break;
}
if (Sci_IsMultiSelection()) {
switch (iLoWParam) {
case IDM_EDIT_SELTONEXT: {
SciCall_RotateSelection();
Sci_ScrollSelectionToView();
}
break;
case IDM_EDIT_SELTOPREV: {
DocPosU const iMain = SciCall_GetMainSelection();
if (iMain > 0) {
SciCall_SetMainSelection(iMain - 1);
} else {
DocPosU const iNewMain = SciCall_GetSelections() - 1;
SciCall_SetMainSelection(iNewMain);
}
Sci_ScrollSelectionToView();
}
break;
default:
break;
}
break; // done
}
SetFindReplaceData(); // s_FindReplaceData
if (IsFindPatternEmpty() && StrgIsNotEmpty(s_FindReplaceData.chFindPattern)) {
if (iLoWParam != IDM_EDIT_REPLACENEXT) {
SendWMCommand(hwnd, IDM_EDIT_FIND);
} else {
SendWMCommand(hwnd, IDM_EDIT_REPLACE);
}
} else {
switch (iLoWParam) {
case IDM_EDIT_FINDNEXT:
EditFindNext(Globals.hwndEdit, &s_FindReplaceData, false, false, true);
break;
case IDM_EDIT_FINDPREV:
EditFindPrev(Globals.hwndEdit, &s_FindReplaceData, false, false, true);
break;
case IDM_EDIT_REPLACENEXT:
if (Globals.bReplaceInitialized) {
EditReplace(Globals.hwndEdit, &s_FindReplaceData);
} else {
SendWMCommand(hwnd, IDM_EDIT_REPLACE);
}
break;
case IDM_EDIT_SELTONEXT:
if (IsFindPatternEmpty()) {
if (!SetCurrentSelAsFindReplaceData(&s_FindReplaceData)) {
break;
}
}
EditFindNext(Globals.hwndEdit, &s_FindReplaceData, true, false, false);
break;
case IDM_EDIT_SELTOPREV:
if (IsFindPatternEmpty()) {
if (!SetCurrentSelAsFindReplaceData(&s_FindReplaceData)) {
break;
}
}
EditFindPrev(Globals.hwndEdit, &s_FindReplaceData, true, false, false);
break;
}
}
break;
case CMD_FINDNEXTSEL:
case CMD_FINDPREVSEL:
case IDM_EDIT_SAVEFIND: {
if (SetCurrentSelAsFindReplaceData(&s_FindReplaceData)) {
MRU_Add(Globals.pMRUfind, GetFindPattern(), 0, -1, -1, NULL);
s_FindReplaceData.fuFlags &= (~(SCFIND_REGEXP | SCFIND_POSIX));
s_FindReplaceData.bTransformBS = false;
switch (iLoWParam) {
case IDM_EDIT_SAVEFIND:
break;
case CMD_FINDNEXTSEL:
EditFindNext(Globals.hwndEdit, &s_FindReplaceData, false, false, false);
break;
case CMD_FINDPREVSEL:
EditFindPrev(Globals.hwndEdit, &s_FindReplaceData, false, false, false);
break;
}
}
}
break;
case IDM_EDIT_COMPLETEWORD:
EditAutoCompleteWord(Globals.hwndEdit, true);
break;
case IDM_EDIT_GOTOLINE:
EditLinenumDlg(Globals.hwndEdit);
break;
case IDM_VIEW_SCHEME:
Style_SelectLexerDlg(Globals.hwndEdit);
break;
case IDM_VIEW_USE2NDDEFAULT:
Style_ToggleUse2ndDefault(Globals.hwndEdit);
break;
case IDM_VIEW_SCHEMECONFIG:
if (!IsWindow(Globals.hwndDlgCustomizeSchemes)) {
Globals.hwndDlgCustomizeSchemes = Style_CustomizeSchemesDlg(Globals.hwndEdit);
} else {
SetForegroundWindow(Globals.hwndDlgCustomizeSchemes);
}
SendWMCommand(Globals.hwndDlgCustomizeSchemes, IDC_SETCURLEXERTV);
break;
case IDM_VIEW_FONT:
case IDM_VIEW_CURRENTSCHEME:
if (!IsWindow(Globals.hwndDlgCustomizeSchemes)) {
Style_SetDefaultFont(Globals.hwndEdit, (iLoWParam == IDM_VIEW_FONT));
}
UpdateMargins(true);
break;
case IDM_VIEW_READONLY:
SciCall_SetReadOnly(!SciCall_GetReadOnly());
Settings.DocReadOnlyMode = SciCall_GetReadOnly();
UpdateToolbar();
break;
case IDM_VIEW_WORDWRAP:
Globals.fvCurFile.bWordWrap = Settings.WordWrap = !Settings.WordWrap;
_SetWrapIndentMode(Globals.hwndEdit);
Sci_ScrollSelectionToView();
UpdateToolbar();
break;
case IDM_SET_WORDWRAPSETTINGS:
if (WordWrapSettingsDlg(hwnd,IDD_MUI_WORDWRAP, &Settings.WordWrapIndent)) {
_SetWrapIndentMode(Globals.hwndEdit);
_SetWrapVisualFlags(Globals.hwndEdit);
UpdateToolbar();
}
break;
case IDM_VIEW_WORDWRAPSYMBOLS:
Settings.ShowWordWrapSymbols = !Settings.ShowWordWrapSymbols;
_SetWrapVisualFlags(Globals.hwndEdit);
UpdateToolbar();
break;
case IDM_VIEW_LONGLINEMARKER: {
Settings.MarkLongLines = !Settings.MarkLongLines;
size_t cnt = 0;
int edgeColumns[EDGELINE_NUM_LIMIT] = { 0 };
if (Settings.MarkLongLines) {
cnt = ReadVectorFromString(Globals.fvCurFile.wchMultiEdgeLines, edgeColumns, COUNTOF(edgeColumns), 0, LONG_LINES_MARKER_LIMIT, 0, true);
}
Style_SetMultiEdgeLine(edgeColumns, cnt);
}
break;
case IDM_SET_LONGLINESETTINGS: {
int iLongLinesLimit = Defaults.LongLinesLimit;
if (LongLineSettingsDlg(hwnd, IDD_MUI_LONGLINES, Globals.fvCurFile.wchMultiEdgeLines)) {
int edgeColumns[EDGELINE_NUM_LIMIT];
size_t const cnt = ReadVectorFromString(Globals.fvCurFile.wchMultiEdgeLines, edgeColumns, COUNTOF(edgeColumns), 0, LONG_LINES_MARKER_LIMIT, 0, true);
if (cnt == 0) {
Settings.MarkLongLines = false;
} else if (cnt == 1) {
iLongLinesLimit = edgeColumns[0];
Settings.MarkLongLines = true;
//~Settings.LongLineMode = EDGE_LINE|EDGE_BACKGROUND; // set by Dlg
} else {
iLongLinesLimit = edgeColumns[cnt - 1];
Settings.MarkLongLines = true;
Settings.LongLineMode = EDGE_MULTILINE;
}
Globals.iWrapCol = iLongLinesLimit;
Settings.LongLinesLimit = iLongLinesLimit;
// new multi-edge lines setting
WCHAR col[32];
Settings.MultiEdgeLines[0] = L'\0';
for (size_t i = 0; i < cnt; ++i) {
StringCchPrintf(col, COUNTOF(col), ((i == 0) ? L"%i" : L" %i"), edgeColumns[i]);
StringCchCat(Settings.MultiEdgeLines, COUNTOF(Settings.MultiEdgeLines), col);
}
// make current too
StringCchCopy(Globals.fvCurFile.wchMultiEdgeLines, COUNTOF(Globals.fvCurFile.wchMultiEdgeLines), Settings.MultiEdgeLines);
Style_SetMultiEdgeLine(edgeColumns, cnt);
}
}
break;
case IDS_USE_LOCALE_DATEFMT:
Settings.PreferredLocale4DateFmt = !Settings.PreferredLocale4DateFmt;
break;
case IDM_SET_TABSASSPACES: {
Settings.TabsAsSpaces = !Settings.TabsAsSpaces;
Globals.fvCurFile.bTabsAsSpaces = Settings.TabsAsSpaces;
SciCall_SetUseTabs(!Globals.fvCurFile.bTabsAsSpaces);
}
break;
case IDM_SET_TABSETTINGS:
if (TabSettingsDlg(hwnd,IDD_MUI_TABSETTINGS,NULL)) {
SciCall_SetUseTabs(!Globals.fvCurFile.bTabsAsSpaces);
SciCall_SetTabIndents(Globals.fvCurFile.bTabIndents);
SciCall_SetBackSpaceUnIndents(Settings.BackspaceUnindents);
SciCall_SetTabWidth(Globals.fvCurFile.iTabWidth);
SciCall_SetIndent(Globals.fvCurFile.iIndentWidth);
if (SciCall_GetWrapIndentMode() == SC_WRAPINDENT_FIXED) {
_SetWrapStartIndent(Globals.hwndEdit);
}
}
break;
case IDM_VIEW_SHOWINDENTGUIDES:
Settings.ShowIndentGuides = !Settings.ShowIndentGuides;
Style_SetIndentGuides(Globals.hwndEdit,Settings.ShowIndentGuides);
break;
case IDM_SET_AUTOINDENTTEXT:
Settings.AutoIndent = !Settings.AutoIndent;
break;
case IDM_VIEW_LINENUMBERS:
Settings.ShowLineNumbers = !Settings.ShowLineNumbers;
UpdateMargins(true);
break;
case IDM_VIEW_BOOKMARK_MARGIN:
Settings.ShowBookmarkMargin = !Settings.ShowBookmarkMargin;
UpdateMargins(true);
break;
case IDM_SET_AUTOCOMPLETEWORDS:
Settings.AutoCompleteWords = !Settings.AutoCompleteWords;
SciCall_AutoCCancel();
break;
case IDM_SET_AUTOCLEXKEYWORDS:
Settings.AutoCLexerKeyWords = !Settings.AutoCLexerKeyWords;
SciCall_AutoCCancel();
break;
case IDM_SET_ALTERNATE_WORD_SEPS:
Settings.AccelWordNavigation = !Settings.AccelWordNavigation;
EditReducedWordSeparatorSet(Globals.hwndEdit, Settings.AccelWordNavigation);
MarkAllOccurrences(-1, true);
break;
case IDM_VIEW_MARKOCCUR_ONOFF:
Settings.MarkOccurrences = !Settings.MarkOccurrences;
if (!Settings.MarkOccurrences && FocusedView.HideNonMatchedLines) {
EditToggleView(Globals.hwndEdit);
}
if (IsMarkOccurrencesEnabled()) {
MarkAllOccurrences(_MQ_FAST, true);
} else {
EditClearAllOccurrenceMarkers(Globals.hwndEdit);
}
break;
case IDM_VIEW_MARKOCCUR_BOOKMARKS:
Settings.MarkOccurrencesBookmark = !Settings.MarkOccurrencesBookmark;
SciCall_MarkerDefine(MARKER_NP3_OCCURRENCE, Settings.MarkOccurrencesBookmark ? SC_MARK_ARROWS : SC_MARK_BACKGROUND);
break;
case IDM_VIEW_MARKOCCUR_VISIBLE:
Settings.MarkOccurrencesMatchVisible = !Settings.MarkOccurrencesMatchVisible;
MarkAllOccurrences(_MQ_FAST, true);
break;
case IDM_VIEW_TOGGLE_VIEW:
if (FocusedView.HideNonMatchedLines) {
EditToggleView(Globals.hwndEdit);
MarkAllOccurrences(_MQ_FAST, true);
} else {
EditToggleView(Globals.hwndEdit);
}
CheckCmd(GetMenu(hwnd), IDM_VIEW_TOGGLE_VIEW, FocusedView.HideNonMatchedLines);
break;
case IDM_VIEW_FV_FOLD:
case IDM_VIEW_FV_BOOKMARK:
case IDM_VIEW_FV_HIGHLIGHT:
case IDM_VIEW_FV_BKMRKFOLD:
case IDM_VIEW_FV_HIGHLGFOLD: {
int newSetting = Settings.FocusViewMarkerMode;
switch (iLoWParam) {
case IDM_VIEW_FV_FOLD:
newSetting = (FVMM_FOLD);
break;
case IDM_VIEW_FV_BOOKMARK:
newSetting = (FVMM_MARGIN);
break;
case IDM_VIEW_FV_HIGHLIGHT:
newSetting = (FVMM_LN_BACKGR);
break;
case IDM_VIEW_FV_BKMRKFOLD:
newSetting = (FVMM_MARGIN | FVMM_FOLD);
break;
case IDM_VIEW_FV_HIGHLGFOLD:
newSetting = (FVMM_LN_BACKGR | FVMM_FOLD);
break;
}
if (newSetting != Settings.FocusViewMarkerMode) {
if (FocusedView.HideNonMatchedLines) {
if ((newSetting & FVMM_FOLD) != (Settings.FocusViewMarkerMode & FVMM_FOLD)) {
EditToggleView(Globals.hwndEdit);
}
}
for (int m = MARKER_NP3_1; m < MARKER_NP3_BOOKMARK; ++m) {
SciCall_MarkerDefine(m, (newSetting & FVMM_LN_BACKGR) ? SC_MARK_BACKGROUND : SC_MARK_BOOKMARK);
}
Settings.FocusViewMarkerMode = newSetting;
}
}
break;
case IDM_VIEW_MARKOCCUR_CASE:
Settings.MarkOccurrencesMatchCase = !Settings.MarkOccurrencesMatchCase;
MarkAllOccurrences(-1, true);
break;
case IDM_VIEW_MARKOCCUR_WNONE:
Settings.MarkOccurrencesMatchWholeWords = false;
Settings.MarkOccurrencesCurrentWord = false;
MarkAllOccurrences(-1, true);
break;
case IDM_VIEW_MARKOCCUR_WORD:
Settings.MarkOccurrencesMatchWholeWords = true;
Settings.MarkOccurrencesCurrentWord = false;
MarkAllOccurrences(-1, true);
break;
case IDM_VIEW_MARKOCCUR_CURRENT:
Settings.MarkOccurrencesMatchWholeWords = false;
Settings.MarkOccurrencesCurrentWord = true;
MarkAllOccurrences(-1, true);
break;
case IDM_VIEW_FOLDING:
Settings.ShowCodeFolding = !Settings.ShowCodeFolding;
FocusedView.ShowCodeFolding = Settings.ShowCodeFolding;
Style_UpdateFoldingMargin(Globals.hwndEdit, FocusedView.ShowCodeFolding);
if (!FocusedView.ShowCodeFolding) {
EditToggleFolds(EXPAND, true);
}
break;
case IDM_VIEW_TOGGLEFOLDS:
EditToggleFolds(SNIFF, SciCall_IsSelectionEmpty());
break;
case IDM_VIEW_TOGGLE_CURRENT_FOLD:
EditToggleFolds(SNIFF, false);
break;
case IDM_VIEW_SHOWBLANKS:
Settings.ViewWhiteSpace = !Settings.ViewWhiteSpace;
SciCall_SetViewWS(Settings.ViewWhiteSpace ? SCWS_VISIBLEALWAYS : SCWS_INVISIBLE);
break;
case IDM_VIEW_SHOWEOLS:
Settings.ViewEOLs = !Settings.ViewEOLs;
SciCall_SetViewEOL(Settings.ViewEOLs);
break;
case IDM_VIEW_MATCHBRACES:
Settings.MatchBraces = !Settings.MatchBraces;
if (Settings.MatchBraces) {
EditMatchBrace(Globals.hwndEdit);
} else {
SciCall_BraceHighLight(INVALID_POSITION, INVALID_POSITION);
}
break;
case IDM_SET_AUTOCLOSETAGS:
Settings.AutoCloseTags = !Settings.AutoCloseTags;
break;
case IDM_SET_AUTOCLOSEQUOTES:
Settings.AutoCloseQuotes = !Settings.AutoCloseQuotes;
break;
case IDM_SET_AUTOCLOSEBRACKETS:
Settings.AutoCloseBrackets = !Settings.AutoCloseBrackets;
break;
case IDM_VIEW_TOGGLE_HILITCURLN:
case IDM_VIEW_HILITCURLN_NONE:
case IDM_VIEW_HILITCURLN_BACK:
case IDM_VIEW_HILITCURLN_FRAME: {
int const set = iLoWParam - IDM_VIEW_HILITCURLN_NONE;
Settings.HighlightCurrentLine = (set >= 0) ? set : ((Settings.HighlightCurrentLine + 1) % 3);
Style_HighlightCurrentLine(Globals.hwndEdit, Settings.HighlightCurrentLine);
}
break;
case IDM_VIEW_CHGHIST_NONE:
case IDM_VIEW_CHGHIST_MARGIN:
case IDM_VIEW_CHGHIST_DOCTXT:
case IDM_VIEW_CHGHIST_ALL: {
int const set = iLoWParam - IDM_VIEW_CHGHIST_NONE;
switch (set) {
case 0:
Settings.ChangeHistoryMode = SC_CHANGE_HISTORY_DISABLED;
break;
case 1:
Settings.ChangeHistoryMode = SC_CHANGE_HISTORY_ENABLED | SC_CHANGE_HISTORY_MARKERS;
break;
case 2:
Settings.ChangeHistoryMode = SC_CHANGE_HISTORY_ENABLED | SC_CHANGE_HISTORY_INDICATORS;
break;
case 3:
Settings.ChangeHistoryMode = SC_CHANGE_HISTORY_ENABLED | SC_CHANGE_HISTORY_INDICATORS | SC_CHANGE_HISTORY_MARKERS;
break;
default:
break;
}
_ApplyChangeHistoryMode();
break;
}
break;
case IDM_VIEW_CHGHIST_TOGGLE_MARGIN:
if (Settings.ChangeHistoryMode & SC_CHANGE_HISTORY_MARKERS) {
Settings.ChangeHistoryMode &= ~SC_CHANGE_HISTORY_MARKERS;
if (!(Settings.ChangeHistoryMode & SC_CHANGE_HISTORY_INDICATORS)) {
Settings.ChangeHistoryMode = SC_CHANGE_HISTORY_DISABLED;
}
}
else {
Settings.ChangeHistoryMode |= (SC_CHANGE_HISTORY_ENABLED | SC_CHANGE_HISTORY_MARKERS);
}
_ApplyChangeHistoryMode();
break;
case IDM_VIEW_CHGHIST_CLEAR_UNDOREDO:
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, L"AllowClearUndoHistory", IDS_MUI_ASK_CLEAR_UNDO))) {
UndoRedoReset();
UpdateMargins(true);
UpdateToolbar();
}
break;
case IDM_VIEW_HYPERLINKHOTSPOTS:
Settings.HyperlinkHotspot = !Settings.HyperlinkHotspot;
EditUpdateVisibleIndicators();
ResetMouseDWellTime();
break;
case IDM_VIEW_SHOW_HYPLNK_CALLTIP:
Settings.ShowHypLnkToolTip = !Settings.ShowHypLnkToolTip;
ResetMouseDWellTime();
break;
case IDM_VIEW_COLORDEFHOTSPOTS:
case IDM_VIEW_COLOR_ARGB:
case IDM_VIEW_COLOR_RGBA:
case IDM_VIEW_COLOR_BGRA: {
Settings.ColorDefHotspot = iLoWParam - IDM_VIEW_COLORDEFHOTSPOTS;
EditUpdateVisibleIndicators();
ResetMouseDWellTime();
}
break;
case IDM_VIEW_UNICODE_POINTS:
Settings.HighlightUnicodePoints = !Settings.HighlightUnicodePoints;
EditUpdateVisibleIndicators();
ResetMouseDWellTime();
break;
case IDM_VIEW_ZOOMIN: {
SciCall_ZoomIn();
ShowZoomCallTip();
}
break;
case IDM_VIEW_ZOOMOUT: {
SciCall_ZoomOut();
ShowZoomCallTip();
}
break;
case IDM_VIEW_RESETZOOM: {
SciCall_SetZoom(100);
ShowZoomCallTip();
}
break;
case IDM_VIEW_CHASING_DOCTAIL: {
InstallFileWatching(false);
static DocPos _lastCaretPos = -1;
if (_lastCaretPos == -1) {
_lastCaretPos = SciCall_GetCurrentPos();
}
static FILE_WATCHING_MODE _saveChgNotify = FWM_NO_INIT;
if (_saveChgNotify == FWM_NO_INIT) {
_saveChgNotify = FileWatching.FileWatchingMode;
}
FileWatching.MonitoringLog = !FileWatching.MonitoringLog; // toggle
if (FileWatching.MonitoringLog) {
SetForegroundWindow(hwnd);
_lastCaretPos = SciCall_GetCurrentPos();
_saveChgNotify = FileWatching.FileWatchingMode;
FileWatching.FileWatchingMode = FWM_AUTORELOAD;
SciCall_SetEndAtLastLine(false); // false(!)
FileRevert(Paths.CurrentFile, true);
SciCall_SetReadOnly(FileWatching.MonitoringLog);
}
else {
FileWatching.FileWatchingMode = _saveChgNotify;
SciCall_SetEndAtLastLine(!Settings.ScrollPastEOF);
SciCall_SetReadOnly(Settings.DocReadOnlyMode);
SciCall_GotoPos(_lastCaretPos);
}
InstallFileWatching(true);
CheckCmd(GetMenu(Globals.hwndMain), IDM_VIEW_CHASING_DOCTAIL, FileWatching.MonitoringLog);
}
break;
case IDM_VIEW_SCROLLPASTEOF:
Settings.ScrollPastEOF = !Settings.ScrollPastEOF;
SciCall_SetEndAtLastLine(!Settings.ScrollPastEOF);
break;
case IDM_VIEW_TITLEBAR:
Settings.ShowTitlebar = !Settings.ShowTitlebar;
if (Settings.ShowTitlebar) {
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_CAPTION);
UpdateTitlebar(hwnd);
}
else {
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_CAPTION);
}
UpdateUI(hwnd);
break;
case IDM_VIEW_MENUBAR:
Settings.ShowMenubar = !Settings.ShowMenubar;
SetMenu(hwnd, (Settings.ShowMenubar ? Globals.hMainMenu : NULL));
DrawMenuBar(Globals.hwndMain);
break;
case IDM_VIEW_TOOLBAR:
Settings.ShowToolbar = !Settings.ShowToolbar;
ShowWindow(Globals.hwndRebar, (Settings.ShowToolbar ? SW_SHOWDEFAULT : SW_HIDE));
UpdateUI(hwnd);
break;
case IDM_VIEW_CUSTOMIZETB:
SendMessage(Globals.hwndToolbar,TB_CUSTOMIZE,0,0);
UpdateUI(hwnd);
break;
case IDM_VIEW_TOGGLETB:
Settings.ToolBarTheme = (Settings.ToolBarTheme + 1) % 3;
CreateBars(hwnd, Globals.hInstance);
UpdateUI(hwnd);
break;
case IDM_VIEW_LOADTHEMETB:
if (SelectExternalToolBar(hwnd)) {
CreateBars(hwnd, Globals.hInstance);
UpdateUI(hwnd);
}
break;
case IDM_VIEW_DPISCALETB:
Settings.DpiScaleToolBar = !Settings.DpiScaleToolBar;
SendMessage(hwnd, WM_THEMECHANGED, 0, 0);
break;
case IDM_VIEW_STATUSBAR:
Settings.ShowStatusbar = !Settings.ShowStatusbar;
ShowWindow(Globals.hwndStatus, (Settings.ShowStatusbar ? SW_SHOWDEFAULT : SW_HIDE));
UpdateUI(hwnd);
break;
case IDM_VIEW_STICKYWINPOS:
if (IsCmdEnabled(hwnd, IDM_VIEW_STICKYWINPOS)) {
Flags.bStickyWindowPosition = !Flags.bStickyWindowPosition; // toggle
if (Flags.bStickyWindowPosition) {
InfoBoxLng(MB_OK, L"MsgStickyWinPos", IDS_MUI_STICKYWINPOS);
}
if (OpenSettingsFile("IDM_VIEW_STICKYWINPOS")) {
SaveWindowPositionSettings(!Flags.bStickyWindowPosition);
if (Flags.bStickyWindowPosition != DefaultFlags.bStickyWindowPosition) {
if (Globals.bCanSaveIniFile) {
IniSectionSetBool(Constants.Settings2_Section, L"StickyWindowPosition", Flags.bStickyWindowPosition);
}
}
else {
IniSectionDelete(Constants.Settings2_Section, L"StickyWindowPosition", false);
}
CloseSettingsFile("IDM_VIEW_STICKYWINPOS", true);
}
}
break;
case IDM_SET_REUSEWINDOW:
if (IsCmdEnabled(hwnd, IDM_SET_REUSEWINDOW)) {
Flags.bReuseWindow = !Flags.bReuseWindow; // reverse
if (Globals.bCanSaveIniFile) {
if (Flags.bReuseWindow != DefaultFlags.bReuseWindow) {
IniFileSetBool(Paths.IniFile, Constants.Settings2_Section, L"ReuseWindow", Flags.bReuseWindow);
} else {
IniFileDelete(Paths.IniFile, Constants.Settings2_Section, L"ReuseWindow", false);
}
}
}
break;
case IDM_SET_SINGLEFILEINSTANCE:
if (IsCmdEnabled(hwnd, IDM_SET_SINGLEFILEINSTANCE)) {
Flags.bSingleFileInstance = !Flags.bSingleFileInstance; // reverse
if (Globals.bCanSaveIniFile) {
if (Flags.bSingleFileInstance != DefaultFlags.bSingleFileInstance) {
IniFileSetBool(Paths.IniFile, Constants.Settings2_Section, L"SingleFileInstance", Flags.bSingleFileInstance);
} else {
IniFileDelete(Paths.IniFile, Constants.Settings2_Section, L"SingleFileInstance", false);
}
}
}
break;
case IDM_SET_ALWAYSONTOP:
if (Settings.AlwaysOnTop) {
SetWindowPos(hwnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
Settings.AlwaysOnTop = false;
} else {
SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
Settings.AlwaysOnTop = true;
}
UpdateToolbar();
break;
case IDM_SET_MINTOTRAY:
Settings.MinimizeToTray = !Settings.MinimizeToTray;
break;
case IDM_SET_TRANSPARENT:
Settings.TransparentMode = !Settings.TransparentMode;
SetWindowTransparentMode(hwnd,Settings.TransparentMode, Settings2.OpacityLevel);
break;
case IDM_SET_RENDER_TECH_GDI:
case IDM_SET_RENDER_TECH_D2D:
case IDM_SET_RENDER_TECH_D2DRETAIN:
case IDM_SET_RENDER_TECH_D2DDC: {
int const prevRT = SciCall_GetTechnology();
Settings.RenderingTechnology = (iLoWParam - IDM_SET_RENDER_TECH_GDI);
if (prevRT != Settings.RenderingTechnology) {
SciCall_SetTechnology(Settings.RenderingTechnology);
Settings.RenderingTechnology = SciCall_GetTechnology(); // switched ?
}
int const prevBD = SciCall_GetBidirectional();
if (prevBD != Settings.Bidirectional) {
SciCall_SetBidirectional(Settings.Bidirectional);
Settings.Bidirectional = SciCall_GetBidirectional(); // switched ?
}
if ((prevRT != Settings.RenderingTechnology) || (prevBD != Settings.Bidirectional)) {
Style_ResetCurrentLexer(Globals.hwndEdit);
}
}
break;
case IDM_SET_RTL_LAYOUT_EDIT:
Settings.EditLayoutRTL = !Settings.EditLayoutRTL;
SetWindowLayoutRTL(Globals.hwndEdit, Settings.EditLayoutRTL);
InvalidateStyleRedraw();
break;
case IDM_SET_RTL_LAYOUT_DLG:
Settings.DialogsLayoutRTL = !Settings.DialogsLayoutRTL;
SetWindowLayoutRTL(Globals.hwndMain, Settings.DialogsLayoutRTL);
SetWindowLayoutRTL(Globals.hwndToolbar, Settings.DialogsLayoutRTL);
SetWindowLayoutRTL(Globals.hwndRebar, Settings.DialogsLayoutRTL);
SetWindowLayoutRTL(Globals.hwndStatus, Settings.DialogsLayoutRTL);
break;
case IDM_SET_BIDIRECTIONAL_NONE:
case IDM_SET_BIDIRECTIONAL_L2R:
case IDM_SET_BIDIRECTIONAL_R2L: {
SciCall_SetBidirectional(iLoWParam - IDM_SET_BIDIRECTIONAL_NONE);
Settings.Bidirectional = SciCall_GetBidirectional();
}
break;
#ifdef D_NP3_WIN10_DARK_MODE
case IDM_VIEW_WIN_DARK_MODE: {
if (!IsYesOkay(InfoBoxLng(MB_OKCANCEL | MB_ICONWARNING, L"MsgResetScheme", IDS_MUI_WARN_STYLE_RESET))) {
break;
}
Settings.WinThemeDarkMode = IsSettingDarkMode() ? WINDSPMOD_LIGHT : WINDSPMOD_DARK; // toggle non auto!
SetDarkMode(IsSettingDarkMode());
Style_DynamicThemesMenuCmd(IDM_THEMES_FACTORY_RESET);
if (IsWindow(Globals.hwndDlgFindReplace)) {
//~SendMessage(Globals.hwndDlgFindReplace, WM_THEMECHANGED, 0, 0); ~ (!) incomplete update
bool const isReplDlg = !!GetDlgItem(Globals.hwndDlgFindReplace, IDC_REPLACE);
PostWMCommand(hwnd, isReplDlg ? IDM_EDIT_FIND : IDM_EDIT_REPLACE); // swap
PostWMCommand(hwnd, isReplDlg ? IDM_EDIT_REPLACE : IDM_EDIT_FIND); // restore
PostMessage(hwnd, WM_SETFOCUS, 0, 0);
}
if (IsWindow(Globals.hwndDlgCustomizeSchemes)) {
//~SendMessage(Globals.hwndDlgCustomizeSchemes, WM_CLOSE, 0, 0); ~ no need for restart
//~PostWMCommand(hwnd, IDM_VIEW_SCHEMECONFIG);
SendMessage(Globals.hwndDlgCustomizeSchemes, WM_THEMECHANGED, 0, 0);
//PostMessage(Globals.hwndDlgCustomizeSchemes, WM_NCACTIVATE, FALSE, -1); // (!)
//PostMessage(Globals.hwndDlgCustomizeSchemes, WM_NCACTIVATE, TRUE, 0);
PostMessage(hwnd, WM_SETFOCUS, 0, 0);
}
PostMessage(hwnd, WM_THEMECHANGED, 0, 0);
}
break;
#endif
case IDM_SET_MUTE_MESSAGEBEEP:
Settings.MuteMessageBeep = !Settings.MuteMessageBeep;
break;
case IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK:
Settings.SplitUndoTypingSeqOnLnBreak = !Settings.SplitUndoTypingSeqOnLnBreak;
break;
//case IDM_SET_INLINE_IME:
// Settings2.IMEInteraction = (Settings2.IMEInteraction == SC_IME_WINDOWED) ? SC_IME_INLINE : SC_IME_WINDOWED;
// SciCall_SetIMEInteraction(Settings2.IMEInteraction);
// break;
case IDM_SET_SHOWFILENAMEONLY:
case IDM_SET_SHOWFILENAMEFIRST:
case IDM_SET_SHOWFULLPATH:
Settings.PathNameFormat = iLoWParam - IDM_SET_SHOWFILENAMEONLY;
StringCchCopy(s_wchTitleExcerpt,COUNTOF(s_wchTitleExcerpt),L"");
UpdateTitlebar(hwnd);
break;
case IDM_SET_SHOWEXCERPT:
EditGetExcerpt(Globals.hwndEdit,s_wchTitleExcerpt,COUNTOF(s_wchTitleExcerpt));
UpdateTitlebar(hwnd);
break;
case IDM_SET_NOSAVERECENT:
Settings.SaveRecentFiles = !Settings.SaveRecentFiles;
break;
case IDM_SET_NOPRESERVECARET:
Settings.PreserveCaretPos = !Settings.PreserveCaretPos;
break;
case IDM_SET_NOSAVEFINDREPL:
Settings.SaveFindReplace = !Settings.SaveFindReplace;
break;
case IDM_SET_AUTOLOAD_MRU_FILE:
Settings.AutoLoadMRUFile = !Settings.AutoLoadMRUFile;
break;
case IDM_SET_SAVEBEFORERUNNINGTOOLS:
Settings.SaveBeforeRunningTools = !Settings.SaveBeforeRunningTools;
break;
case IDM_SET_EVALTINYEXPRONSEL:
Settings.EvalTinyExprOnSelection = !Settings.EvalTinyExprOnSelection;
UpdateStatusbar(false);
break;
case IDM_SET_CHANGENOTIFY:
InstallFileWatching(false);
if (ChangeNotifyDlg(hwnd)) {
InstallFileWatching(true);
}
break;
case IDM_SET_AUTOSAVE_BACKUP: {
int const periodSav = Settings.AutoSaveInterval;
if (AutoSaveBackupSettingsDlg(hwnd)) {
if (Settings.AutoSaveOptions & ASB_Periodic) {
AutoSaveStart(periodSav != Settings.AutoSaveInterval);
}
else {
AutoSaveStop();
}
}
}
break;
case IDM_SET_NOESCFUNC:
case IDM_SET_ESCMINIMIZE:
case IDM_SET_ESCEXIT:
Settings.EscFunction = iLoWParam - IDM_SET_NOESCFUNC;
break;
case IDM_SET_SAVESETTINGS:
if (IsCmdEnabled(hwnd, IDM_SET_SAVESETTINGS)) {
Settings.SaveSettings = !Settings.SaveSettings;
if (Globals.bCanSaveIniFile) {
if (Settings.SaveSettings == Defaults.SaveSettings) {
IniFileDelete(Paths.IniFile, Constants.Settings_Section, L"SaveSettings", false);
} else {
IniFileSetBool(Paths.IniFile, Constants.Settings_Section, L"SaveSettings", Settings.SaveSettings);
}
}
}
break;
case IDM_SET_SAVESETTINGSNOW:
if (IsCmdEnabled(hwnd, IDM_SET_SAVESETTINGSNOW)) {
CmdSaveSettingsNow();
}
break;
case IDM_HELP_ONLINEDOCUMENTATION:
ShellExecute(0, 0, ONLINE_HELP_WEBSITE, 0, 0, SW_SHOW);
break;
case IDM_HELP_ABOUT: {
//~HMODULE hRichEdit = LoadLibrary(L"RICHED20.DLL"); // Use RICHEDIT_CONTROL_VER for control in common_res.h
HMODULE const hRichEdit = LoadLibrary(L"MSFTEDIT.DLL"); // Use "RichEdit50W" for control in common_res.h;
if (hRichEdit) {
ThemedDialogBox(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_ABOUT), hwnd, AboutDlgProc);
FreeLibrary(hRichEdit);
}
}
break;
case IDM_SETPASS:
if (GetFileKey(Globals.hwndEdit)) {
SetSaveNeeded(true);
}
break;
case IDM_HELP_CMD:
DisplayCmdLineHelp(hwnd);
break;
case CMD_ESCAPE: {
DocPos const iCurPos = SciCall_GetCurrentPos();
int skipLevel = Settings2.ExitOnESCSkipLevel;
if (SciCall_AutoCActive()) {
SciCall_AutoCCancel();
--skipLevel;
} else if (SciCall_CallTipActive()) {
Sci_CallTipCancelEx();
s_bCallTipEscDisabled = true;
--skipLevel;
} else if (s_bInMultiEditMode) {
//~UndoTransActionBegin();
SciCall_SetIndicatorCurrent(INDIC_NP3_MULTI_EDIT);
SciCall_IndicatorClearRange(0, Sci_GetDocEndPosition());
SciCall_ClearSelections();
//~EndUndoTransAction();
SciCall_GotoPos(iCurPos);
s_bInMultiEditMode = false;
--skipLevel;
}
if ((!SciCall_IsSelectionEmpty() || Sci_IsMultiOrRectangleSelection()) && (skipLevel == Settings2.ExitOnESCSkipLevel)) {
Sci_GotoPosChooseCaret(iCurPos);
skipLevel -= Default_ExitOnESCSkipLevel;
}
if ((skipLevel < 0) || (skipLevel == Settings2.ExitOnESCSkipLevel)) {
switch (Settings.EscFunction) {
case 1:
SendMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
break;
case 2:
CloseApplication();
break;
default:
Sci_GotoPosChooseCaret(iCurPos);
break;
}
}
SciCall_Cancel();
}
break;
case CMD_SHIFTESC:
FileSave(FSF_EndSession);
case IDT_FILE_EXIT:
CloseApplication();
break;
case CMD_INSERTNEWLINE: {
UndoTransActionBegin();
const DocPos iPos = SciCall_GetCurrentPos();
const DocLn iLine = SciCall_LineFromPosition(iPos);
if (iLine <= 0) {
SciCall_GotoLine(0);
SciCall_NewLine();
SciCall_GotoLine(0);
} else {
SciCall_GotoPos(SciCall_GetLineEndPosition(iLine - 1));
SciCall_NewLine();
}
EndUndoTransAction();
}
break;
case CMD_ENTER_RETURN: {
_EvalTinyExpr(false);
SciCall_NewLine();
}
break;
// Newline with toggled auto indent setting
case CMD_SHIFTCTRLENTER:
Settings.AutoIndent = !Settings.AutoIndent;
SciCall_NewLine();
Settings.AutoIndent = !Settings.AutoIndent;
break;
case CMD_CLEAR:
case IDM_EDIT_CLEAR:
//~UndoTransActionBegin();
EditDeleteMarkerInSelection();
SciCall_Clear();
//~EndUndoTransAction();
break;
case CMD_ARROW_UP:
if (Sci_IsMultiSelection()) {
SciCall_Cancel();
}
SciCall_LineUp();
break;
case CMD_ARROW_DOWN:
if (Sci_IsMultiSelection()) {
SciCall_Cancel();
}
SciCall_LineDown();
break;
case CMD_SCROLLUP:
if (Sci_IsMultiSelection()) {
SciCall_LineUpExtend();
} else {
SciCall_LineScrollUp();
}
break;
case CMD_SCROLLDOWN:
if (Sci_IsMultiSelection()) {
SciCall_LineDownExtend();
} else {
SciCall_LineScrollDown();
}
break;
case CMD_CTRLLEFT:
if (Sci_IsMultiSelection()) {
SciCall_CharLeftExtend();
} else {
SciCall_WordLeft();
}
break;
case CMD_CTRLRIGHT:
if (Sci_IsMultiSelection()) {
SciCall_CharRightExtend();
} else {
SciCall_WordRight();
}
break;
case CMD_PARAGRAPH_UP:
if (!SciCall_IsSelectionEmpty() && Sci_IsStreamSelection()) {
SciCall_ParaUpExtend();
} else {
SciCall_ParaUp();
}
break;
case CMD_PARAGRAPH_DOWN:
if (!SciCall_IsSelectionEmpty() && Sci_IsStreamSelection()) {
SciCall_ParaDownExtend();
} else {
SciCall_ParaDown();
}
break;
case CMD_CTRLBACK: {
DocPos const iPos = SciCall_GetCurrentPos();
DocPos const iAnchor = SciCall_GetAnchor();
DocLn const iLine = SciCall_LineFromPosition(iPos);
DocPos const iStartPos = SciCall_PositionFromLine(iLine);
DocPos const iIndentPos = SciCall_GetLineIndentPosition(iLine);
if (iPos != iAnchor) {
UndoTransActionBegin();
SciCall_SetSel(iPos, iPos);
EndUndoTransAction();
} else {
if (iPos == iStartPos) {
SciCall_DeleteBack();
} else if (iPos <= iIndentPos) {
SciCall_DelLineLeft();
} else {
SciCall_DelWordLeft();
}
}
}
break;
case CMD_CTRLDEL: {
const DocPos iPos = SciCall_GetCurrentPos();
const DocPos iAnchor = SciCall_GetAnchor();
const DocLn iLine = SciCall_LineFromPosition(iPos);
const DocPos iStartPos = SciCall_PositionFromLine(iLine);
const DocPos iEndPos = SciCall_GetLineEndPosition(iLine);
if (iPos != iAnchor) {
UndoTransActionBegin();
SciCall_SetSel(iPos, iPos);
EndUndoTransAction();
} else {
if (iStartPos != iEndPos) {
SciCall_DelWordRight();
} else { // iStartPos == iEndPos
UserMarkerDeleteAll(Sci_GetCurrentLineNumber());
SciCall_LineDelete();
}
}
}
break;
case CMD_RECODEDEFAULT: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
Encoding_Forced(Settings.DefaultEncoding);
FileLoadFlags const fLoadFlags = FLF_Reload | FLF_SkipUnicodeDetect | FLF_SkipANSICPDetection;
FileLoad(Paths.CurrentFile, fLoadFlags);
}
}
break;
case CMD_RECODEANSI: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
Encoding_Forced(CPI_ANSI_DEFAULT);
FileLoadFlags const fLoadFlags = FLF_Reload | FLF_SkipUnicodeDetect | FLF_SkipANSICPDetection;
FileLoad(Paths.CurrentFile, fLoadFlags);
}
}
break;
case CMD_RECODEOEM: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
Encoding_Forced(CPI_OEM);
FileLoadFlags const fLoadFlags = FLF_Reload | FLF_SkipUnicodeDetect | FLF_SkipANSICPDetection;
FileLoad(Paths.CurrentFile, fLoadFlags);
}
}
break;
case CMD_RECODEGB18030: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
Encoding_Forced(Encoding_GetByCodePage(54936)); // GB18030
FileLoadFlags const fLoadFlags = FLF_Reload | FLF_SkipUnicodeDetect | FLF_SkipANSICPDetection;
FileLoad(Paths.CurrentFile, fLoadFlags);
}
}
break;
case CMD_RELOADASCIIASUTF8: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
Encoding_Forced(CPI_UTF8);
FileLoadFlags const fLoadFlags = FLF_Reload | FLF_SkipUnicodeDetect | FLF_SkipANSICPDetection;
FileLoad(Paths.CurrentFile, fLoadFlags);
}
}
break;
case CMD_RELOADFORCEDETECTION: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
Encoding_Forced(CPI_NONE);
FileLoadFlags const fLoadFlags = FLF_Reload | FLF_ForceEncDetection;
FileLoad(Paths.CurrentFile, fLoadFlags);
}
}
break;
case CMD_RELOADNOENCODETAGS: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
bool const _bNoEncodingTags = Settings.NoEncodingTags;
Settings.NoEncodingTags = true;
FileLoadFlags fLoadFlags = FLF_Reload;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
FileLoad(Paths.CurrentFile, fLoadFlags);
Settings.NoEncodingTags = _bNoEncodingTags;
}
}
break;
case CMD_IGNORE_FILE_VARS:
Flags.NoFileVariables = !Flags.NoFileVariables;
if (Globals.bCanSaveIniFile) {
if (Flags.NoFileVariables != DefaultFlags.NoFileVariables) {
IniFileSetBool(Paths.IniFile, Constants.Settings2_Section, L"NoFileVariables", Flags.NoFileVariables);
} else {
IniFileDelete(Paths.IniFile, Constants.Settings2_Section, L"NoFileVariables", false);
}
}
break;
case CMD_LEXDEFAULT:
Style_SetDefaultLexer(Globals.hwndEdit);
break;
//case CMD_LEXHTML:
// Style_SetHTMLLexer(Globals.hwndEdit);
// break;
//case CMD_LEXXML:
// Style_SetXMLLexer(Globals.hwndEdit);
// break;
case CMD_INSERT_TIMESTAMP:
EditInsertDateTimeStrg(true, true);
break;
case CMD_UPDATE_TIMESTAMPS:
EditUpdateTimestamps();
break;
case IDM_HELP_ADMINEXE:
DialogAdminExe(hwnd, true);
break;
case IDM_HELP_UPDATEWEBSITE:
DialogAdminExe(hwnd, false);
break;
case CMD_WEBACTION1:
case CMD_WEBACTION2: {
const wchar_t* const wchWebTemplate = ((iLoWParam == CMD_WEBACTION1) ? StrgGet(Settings2.WebTemplate1) : StrgGet(Settings2.WebTemplate2));
if (StrIsNotEmpty(wchWebTemplate)) {
WCHAR wszSelection[STRINGW_MAX_URL_LENGTH + 1] = { L'\0' };
size_t const cchSelection = EditGetSelectedText(wszSelection, COUNTOF(wszSelection));
if (1 < cchSelection) {
HPATHL hdir = Path_Copy(Paths.CurrentFile);
Path_RemoveFileSpec(hdir);
// Check lpszSelection and truncate bad WCHARs
WCHAR* lpsz = StrChr(wszSelection, L'\r');
if (lpsz) {
*lpsz = L'\0';
}
lpsz = StrChr(wszSelection, L'\n');
if (lpsz) {
*lpsz = L'\0';
}
lpsz = StrChr(wszSelection, L'\t');
if (lpsz) {
*lpsz = L'\0';
}
HSTRINGW hstr_hyplnk = StrgCreate(NULL);
StrgFormat(hstr_hyplnk, wchWebTemplate, wszSelection);
ExpandEnvironmentStrgs(hstr_hyplnk, false);
if (StrgIsNotEmpty(Settings2.HyperlinkShellExURLWithApp))
{
HSTRINGW hstr_params = StrgCopy(Settings2.HyperlinkShellExURLCmdLnArgs);
StrgReplace(hstr_params, URLPLACEHLDR, StrgGet(hstr_hyplnk));
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_DEFAULT;
sei.hwnd = NULL;
sei.lpVerb = NULL;
sei.lpFile = StrgGet(Settings2.HyperlinkShellExURLWithApp);
sei.lpParameters = StrgGet(hstr_params);
sei.lpDirectory = Path_Get(hdir);
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&sei);
StrgDestroy(hstr_params);
}
else {
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_NOZONECHECKS;
sei.hwnd = NULL;
sei.lpVerb = NULL;
sei.lpFile = StrgGet(hstr_hyplnk);
sei.lpParameters = NULL;
sei.lpDirectory = Path_Get(hdir);
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&sei);
}
StrgDestroy(hstr_hyplnk);
Path_Release(hdir);
}
}
}
break;
/* ~~~
case CMD_INCLINELIMIT:
case CMD_DECLINELIMIT:
if (!Settings.MarkLongLines)
SendWMCommand(hwnd, IDM_VIEW_LONGLINEMARKER);
else {
if (iLoWParam == CMD_INCLINELIMIT)
Settings.LongLinesLimit++;
else
Settings.LongLinesLimit--;
Globals.fvCurFile.iLongLinesLimit = clampi(Settings.LongLinesLimit, 0, LONG_LINES_MARKER_LIMIT);
SciCall_SetEdgeColumn(Settings.LongLinesLimit);
//Globals.fvCurFile.iLongLinesLimit = Settings.LongLinesLimit;
}
break;
~~~ */
case CMD_STRINGIFY: {
EditEncloseSelection(L"'", L"'");
}
break;
case CMD_STRINGIFY2: {
EditEncloseSelection(L"\"", L"\"");
}
break;
case CMD_EMBRACE: {
EditEncloseSelection(L"(", L")");
}
break;
case CMD_EMBRACE2: {
EditEncloseSelection(L"[", L"]");
}
break;
case CMD_EMBRACE3: {
EditEncloseSelection(L"{", L"}");
}
break;
case CMD_EMBRACE4: {
EditEncloseSelection(L"`", L"`");
}
break;
case CMD_INCREASENUM:
EditModifyNumber(Globals.hwndEdit,true);
break;
case CMD_DECREASENUM:
EditModifyNumber(Globals.hwndEdit,false);
break;
case CMD_TOGGLETITLE:
EditGetExcerpt(Globals.hwndEdit,s_wchTitleExcerpt,COUNTOF(s_wchTitleExcerpt));
UpdateTitlebar(hwnd);
break;
case CMD_JUMP2SELSTART:
if (!EditSetCaretToSelectionStart() && Sci_IsMultiOrRectangleSelection()) {
size_t const n = SciCall_GetSelections();
DocLn const lineStart = SciCall_LineFromPosition(SciCall_GetSelectionNCaret(0));
DocPos const beg = SciCall_PositionFromLine(lineStart);
SciCall_ClearSelections(); // needed to reset mode
SciCall_SetSelection(beg, beg);
for (size_t i = 1; i < n; ++i) {
DocPos const pos = SciCall_PositionFromLine(lineStart + i);
SciCall_AddSelection(pos, pos);
}
}
Sci_ScrollChooseCaret();
break;
case CMD_JUMP2SELEND:
if (!EditSetCaretToSelectionEnd() && Sci_IsMultiOrRectangleSelection()) {
size_t const n = SciCall_GetSelections();
DocLn const lineStart = SciCall_LineFromPosition(SciCall_GetSelectionNCaret(0));
DocPos const beg = SciCall_GetLineEndPosition(lineStart);
SciCall_ClearSelections(); // needed to reset mode
SciCall_SetSelection(beg, beg);
for (size_t i = 1; i < n; ++i) {
DocPos const pos = SciCall_GetLineEndPosition(lineStart + i);
SciCall_AddSelection(pos, pos);
}
}
Sci_ScrollChooseCaret();
break;
case CMD_COPYPATHNAME: {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
SetClipboardText(hwnd, Path_Get(Paths.CurrentFile), Path_GetLength(Paths.CurrentFile));
} else {
WCHAR tchUntitled[64] = { L'\0' };
GetLngString(IDS_MUI_UNTITLED, tchUntitled, COUNTOF(tchUntitled));
SetClipboardText(hwnd, tchUntitled, StringCchLen(tchUntitled, 0));
}
}
break;
case CMD_COPYWINPOS: {
WININFO wi = GetMyWindowPlacement(Globals.hwndMain, NULL, 0, false);
WCHAR wchBuf[128] = { L'\0' };
StringCchPrintf(wchBuf, COUNTOF(wchBuf), L"/pos " WINDOWPOS_STRGFORMAT, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, (int)wi.max);
SetClipboardText(hwnd, wchBuf, StringCchLen(wchBuf, 0));
}
break;
case CMD_INITIALWINPOS:
SnapToWinInfoPos(hwnd, g_IniWinInfo, SCR_NORMAL, SW_SHOWDEFAULT);
break;
case CMD_FULLSCRWINPOS: {
WININFO wi = GetMyWindowPlacement(hwnd, NULL, 0, false);
SnapToWinInfoPos(hwnd, wi, SCR_FULL_SCREEN, SW_SHOWDEFAULT);
}
break;
case CMD_DEFAULTWINPOS:
SnapToWinInfoPos(hwnd, g_DefWinInfo, SCR_NORMAL, SW_SHOWDEFAULT);
break;
case CMD_SAVEASDEFWINPOS: {
WININFO const wi = GetMyWindowPlacement(hwnd, NULL, 0, false);
StringCchPrintf(Settings2.DefaultWindowPosition, COUNTOF(Settings2.DefaultWindowPosition),
WINDOWPOS_STRGFORMAT, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, (int)wi.max);
if (Globals.bCanSaveIniFile) {
// overwrite bad defined default position
_IniFileWriteDefaultWindowPosition(wi);
}
g_DefWinInfo = wi; //~GetWinInfoByFlag(-1); // use current win pos as new default
}
break;
case CMD_CLEARSAVEDWINPOS:
g_DefWinInfo = GetFactoryDefaultWndPos(hwnd, 2);
StringCchCopy(Settings2.DefaultWindowPosition, COUNTOF(Settings2.DefaultWindowPosition), L"");
WCHAR tchScrnDim[64] = { L'\0' };
StringCchPrintf(tchScrnDim, COUNTOF(tchScrnDim), L"%ix%i " DEF_WIN_POSITION_STRG,
GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
IniFileDelete(Paths.IniFile, Constants.Window_Section, tchScrnDim, true);
IniFileDelete(Paths.IniFile, Constants.Settings2_Section, DEF_WIN_POSITION_STRG, true);
break;
case CMD_OPENINIFILE:
if (Path_IsNotEmpty(Paths.IniFile)) {
SaveAllSettings(false);
FileLoadFlags const fLoadFlags = FLF_SkipANSICPDetection;
FileLoad(Paths.IniFile, fLoadFlags);
}
break;
case CMD_OPEN_HYPERLINK:
HandleHotSpotURLClicked(SciCall_GetCurrentPos(), (OPEN_WITH_BROWSER | OPEN_IN_NOTEPAD3));
break;
case CMD_FOLDJUMPDOWN:
EditFoldCmdKey(DOWN, SNIFF);
break;
case CMD_FOLDJUMPUP:
EditFoldCmdKey(UP, SNIFF);
break;
case CMD_FOLDCOLLAPSE:
EditFoldCmdKey(NONE, FOLD);
break;
case CMD_FOLDEXPAND:
EditFoldCmdKey(NONE, EXPAND);
break;
case IDT_FILE_NEW:
if (IsCmdEnabled(hwnd,IDM_FILE_NEW)) {
SendWMCommand(hwnd, IDM_FILE_NEW);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_NEW_WINDOW:
if (IsCmdEnabled(hwnd, IDM_FILE_NEWWINDOW)) {
SendWMCommand(hwnd, IDM_FILE_NEWWINDOW);
} else {
SimpleBeep();
}
break;
case IDT_FILE_OPEN:
if (IsCmdEnabled(hwnd,IDM_FILE_OPEN)) {
SendWMCommand(hwnd, IDM_FILE_OPEN);
} else {
SimpleBeep();
}
break;
case IDT_FILE_BROWSE:
if (IsCmdEnabled(hwnd,IDM_FILE_BROWSE)) {
SendWMCommand(hwnd, IDM_FILE_BROWSE);
} else {
SimpleBeep();
}
break;
case IDT_FILE_RECENT:
if (IsCmdEnabled(hwnd,IDM_FILE_RECENT)) {
SendWMCommand(hwnd, IDM_FILE_RECENT);
} else {
SimpleBeep();
}
break;
case IDT_FILE_SAVE:
if (IsCmdEnabled(hwnd,IDM_FILE_SAVE)) {
SendWMCommand(hwnd, IDM_FILE_SAVE);
} else {
SimpleBeep();
}
break;
case IDT_EDIT_UNDO:
if (IsCmdEnabled(hwnd,IDM_EDIT_UNDO)) {
SendWMCommand(hwnd, IDM_EDIT_UNDO);
} else {
SimpleBeep();
}
break;
case IDT_EDIT_REDO:
if (IsCmdEnabled(hwnd,IDM_EDIT_REDO)) {
SendWMCommand(hwnd, IDM_EDIT_REDO);
} else {
SimpleBeep();
}
break;
case IDT_EDIT_CUT:
if (IsCmdEnabled(hwnd,IDM_EDIT_CUT)) {
SendWMCommand(hwnd, IDM_EDIT_CUT);
//~SendWMCommand(hwnd, IDM_EDIT_CUTLINE);
} else {
SimpleBeep();
}
break;
case IDT_EDIT_COPY:
if (IsCmdEnabled(hwnd,IDM_EDIT_COPY)) {
SendWMCommand(hwnd, IDM_EDIT_COPY);
} else {
SendWMCommand(hwnd, IDM_EDIT_COPYALL);
}
break;
case IDT_EDIT_PASTE:
if (IsCmdEnabled(hwnd,IDM_EDIT_PASTE)) {
SendWMCommand(hwnd, IDM_EDIT_PASTE);
} else {
SimpleBeep();
}
break;
case IDT_EDIT_FIND:
if (IsCmdEnabled(hwnd,IDM_EDIT_FIND)) {
SendWMCommand(hwnd, IDM_EDIT_FIND);
} else {
SimpleBeep();
}
break;
case IDT_EDIT_REPLACE:
if (IsCmdEnabled(hwnd,IDM_EDIT_REPLACE)) {
SendWMCommand(hwnd, IDM_EDIT_REPLACE);
} else {
SimpleBeep();
}
break;
case IDT_GREP_WIN_TOOL:
if (IsCmdEnabled(hwnd, IDM_GREP_WIN_SEARCH)) {
SendWMCommand(hwnd, IDM_GREP_WIN_SEARCH);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_WORDWRAP:
if (IsCmdEnabled(hwnd,IDM_VIEW_WORDWRAP)) {
SendWMCommand(hwnd, IDM_VIEW_WORDWRAP);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_ZOOMIN:
if (IsCmdEnabled(hwnd,IDM_VIEW_ZOOMIN)) {
SendWMCommand(hwnd, IDM_VIEW_ZOOMIN);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_RESETZOOM:
if (IsCmdEnabled(hwnd, IDM_VIEW_RESETZOOM)) {
SendWMCommand(hwnd, IDM_VIEW_RESETZOOM);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_ZOOMOUT:
if (IsCmdEnabled(hwnd,IDM_VIEW_ZOOMOUT)) {
SendWMCommand(hwnd, IDM_VIEW_ZOOMOUT);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_CHASING_DOCTAIL:
if (IsCmdEnabled(hwnd, IDM_VIEW_CHASING_DOCTAIL)) {
SendWMCommand(hwnd, IDM_VIEW_CHASING_DOCTAIL);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_SCHEME:
if (IsCmdEnabled(hwnd,IDM_VIEW_SCHEME)) {
SendWMCommand(hwnd, IDM_VIEW_SCHEME);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_SCHEMECONFIG:
if (IsCmdEnabled(hwnd,IDM_VIEW_SCHEMECONFIG)) {
SendWMCommand(hwnd, IDM_VIEW_SCHEMECONFIG);
} else {
SimpleBeep();
}
break;
case IDT_FILE_SAVEAS:
if (IsCmdEnabled(hwnd,IDM_FILE_SAVEAS)) {
SendWMCommand(hwnd, IDM_FILE_SAVEAS);
} else {
SimpleBeep();
}
break;
case IDT_FILE_SAVECOPY:
if (IsCmdEnabled(hwnd,IDM_FILE_SAVECOPY)) {
SendWMCommand(hwnd, IDM_FILE_SAVECOPY);
} else {
SimpleBeep();
}
break;
case IDT_EDIT_CLEAR:
if (IsCmdEnabled(hwnd,IDM_EDIT_CLEAR)) {
SendWMCommand(hwnd, IDM_EDIT_CLEAR);
} else {
SciCall_ClearAll();
}
break;
case IDT_FILE_PRINT:
if (IsCmdEnabled(hwnd,IDM_FILE_PRINT)) {
SendWMCommand(hwnd, IDM_FILE_PRINT);
} else {
SimpleBeep();
}
break;
case IDT_FILE_OPENFAV:
if (IsCmdEnabled(hwnd,IDM_FILE_OPENFAV)) {
SendWMCommand(hwnd, IDM_FILE_OPENFAV);
} else {
SimpleBeep();
}
break;
case IDT_FILE_ADDTOFAV:
if (IsCmdEnabled(hwnd,IDM_FILE_ADDTOFAV)) {
SendWMCommand(hwnd, IDM_FILE_ADDTOFAV);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_TOGGLEFOLDS:
if (IsCmdEnabled(hwnd,IDM_VIEW_TOGGLEFOLDS)) {
SendWMCommand(hwnd, IDM_VIEW_TOGGLEFOLDS);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_TOGGLE_VIEW:
if (IsCmdEnabled(hwnd,IDM_VIEW_TOGGLE_VIEW)) {
SendWMCommand(hwnd, IDM_VIEW_TOGGLE_VIEW);
} else {
SimpleBeep();
}
break;
case IDT_VIEW_PIN_ON_TOP:
if (IsCmdEnabled(hwnd, IDM_SET_ALWAYSONTOP)) {
SendWMCommand(hwnd, IDM_SET_ALWAYSONTOP);
} else {
SimpleBeep();
}
break;
case IDT_FILE_LAUNCH:
if (IsCmdEnabled(hwnd,IDM_FILE_LAUNCH)) {
SendWMCommand(hwnd, IDM_FILE_LAUNCH);
} else {
SimpleBeep();
}
break;
default:
return DefWindowProc(hwnd, umsg, wParam, lParam);
}
return FALSE;
}
//=============================================================================
//
// MsgSysCommand() - Handles WM_SYSCOMMAND
//
LRESULT MsgSysCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
switch (wParam) {
case SC_MINIMIZE:
ShowOwnedPopups(hwnd, false);
if (Settings.MinimizeToTray) {
MinimizeWndToTray(hwnd);
ShowNotifyIcon(hwnd, true);
SetNotifyIconTitle(hwnd);
return FALSE; // swallowed
}
break;
case SC_RESTORE: {
LRESULT lrv = DefWindowProc(hwnd, umsg, wParam, lParam);
ShowOwnedPopups(hwnd, true);
return(lrv);
}
default:
break;
}
return DefWindowProc(hwnd, umsg, wParam, lParam);
}
//=============================================================================
//
// MsgUahMenuBar() - Handles WM_UAH... commands
// https://github.com/adzm/win32-custom-menubar-aero-theme
// https://stackoverflow.com/questions/57177310/how-to-paint-over-white-line-between-menu-bar-and-client-area-of-window
//
#if 0
inline static RECT GetNonclientMenuBorderRect(HWND hwnd)
{
RECT rc;
GetClientRect(hwnd, &rc);
MapRectClientToWndCoords(hwnd, &rc);
rc.top = rc.bottom + 1;
rc.bottom += 2;
return rc;
}
#endif
LRESULT MsgUahMenuBar(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
static HTHEME s_darkMenuTheme = NULL;
switch (umsg) {
case WM_UAHINITMENU: {
if (!s_darkMenuTheme) {
s_darkMenuTheme = OpenThemeData(hwnd, L"Menu");
}
} break;
case WM_UAHDESTROYWINDOW: {
if (s_darkMenuTheme) {
CloseThemeData(s_darkMenuTheme);
s_darkMenuTheme = NULL;
}
} break;
case WM_UAHDRAWMENU: {
if (!UseDarkMode()) {
break;
}
UAHMENU* const pUDM = (UAHMENU*)lParam;
RECT rc = { 0 };
// get the menubar rect
MENUBARINFO mbi = { sizeof(mbi) };
GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi);
RECT rcWindow;
GetWindowRect(hwnd, &rcWindow);
// the rcBar is offset by the window rect
rc = mbi.rcBar;
OffsetRect(&rc, -rcWindow.left, -rcWindow.top);
// fill line below bar
//~rc.bottom += 2;
FillRect(pUDM->hdc, &rc, Globals.hbrDarkModeBkgBrush);
return TRUE;
}
case WM_NCACTIVATE:
case WM_NCPAINT: {
// get rid of annoying menu-bar bottom line
// (only called if in dark mode)
MENUBARINFO mbi = { sizeof(mbi) };
if (!GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi)) {
return FALSE;
}
RECT rcClient = { 0 };
GetClientRect(hwnd, &rcClient);
MapWindowPoints(hwnd, NULL, (POINT*)&rcClient, 2);
RECT rcWindow = { 0 };
GetWindowRect(hwnd, &rcWindow);
OffsetRect(&rcClient, -rcWindow.left, -rcWindow.top);
// the rcBar is offset by the window rect
RECT rcAnnoyingLine = rcClient;
rcAnnoyingLine.bottom = rcAnnoyingLine.top;
rcAnnoyingLine.top -= 1;
HDC const hdc = GetWindowDC(hwnd);
FillRect(hdc, &rcAnnoyingLine, Globals.hbrDarkModeBtnFcBrush); // Globals.hbrDarkModeBkgBrush
ReleaseDC(hwnd, hdc);
return TRUE;
}
case WM_UAHDRAWMENUITEM: {
if (!UseDarkMode()) {
break;
}
UAHDRAWMENUITEM* pUDMI = (UAHDRAWMENUITEM*)lParam;
HBRUSH* pbrBackground = &Globals.hbrDarkModeBkgBrush;
// get the menu item string
wchar_t menuString[256] = { 0 };
MENUITEMINFO mii = { sizeof(mii), MIIM_STRING };
{
mii.dwTypeData = menuString;
mii.cch = (sizeof(menuString) / 2) - 1;
GetMenuItemInfo(pUDMI->um.hmenu, pUDMI->umi.iPosition, TRUE, &mii);
}
// get the item state for drawing
DWORD dwFlags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
int iTextStateID = 0;
int iBackgroundStateID = 0;
{
if ((pUDMI->dis.itemState & ODS_INACTIVE) | (pUDMI->dis.itemState & ODS_DEFAULT)) {
// normal display
iTextStateID = MPI_NORMAL;
iBackgroundStateID = MPI_NORMAL;
}
if (pUDMI->dis.itemState & ODS_HOTLIGHT) {
// hot tracking
iTextStateID = MPI_HOT;
iBackgroundStateID = MPI_HOT;
pbrBackground = &Globals.hbrDarkModeBkgHotBrush;
}
if (pUDMI->dis.itemState & ODS_SELECTED) {
// clicked -- MENU_POPUPITEM has no state for this, though MENU_BARITEM does
iTextStateID = MPI_HOT;
iBackgroundStateID = MPI_HOT;
pbrBackground = &Globals.hbrDarkModeBkgSelBrush;
}
if ((pUDMI->dis.itemState & ODS_GRAYED) || (pUDMI->dis.itemState & ODS_DISABLED)) {
// disabled / grey text
iTextStateID = MPI_DISABLED;
iBackgroundStateID = MPI_DISABLED;
}
if (pUDMI->dis.itemState & ODS_NOACCEL) {
dwFlags |= DT_HIDEPREFIX;
}
}
DTTOPTS opts = { sizeof(opts), DTT_TEXTCOLOR, iTextStateID != MPI_DISABLED ? Settings2.DarkModeTxtColor : RGB(0x80, 0x80, 0x80) };
FillRect(pUDMI->um.hdc, &pUDMI->dis.rcItem, *pbrBackground);
DrawThemeTextEx(s_darkMenuTheme, pUDMI->um.hdc, MENU_BARITEM, MBI_NORMAL, menuString, mii.cch, dwFlags, &pUDMI->dis.rcItem, &opts);
return TRUE;
} break;
case WM_UAHMEASUREMENUITEM: {
// allow the default window procedure to handle the message
// since we don't really care about changing the width
//LRESULT const res = DefWindowProc(hwnd, umsg, wParam, lParam);
// but we can modify it here to make it 1/3rd wider and higher for example
//UAHMEASUREMENUITEM* const pMmi = (UAHMEASUREMENUITEM*)lParam;
//pMmi->mis.itemWidth = (pMmi->mis.itemWidth * 4) / 3;
//pMmi->mis.itemHeight = (pMmi->mis.itemHeight * 4) / 3;
//return res;
} break;
// don't care
case WM_UAHNCPAINTMENUPOPUP:
default:
break;
}
return DefWindowProc(hwnd, umsg, wParam, lParam);
}
//=============================================================================
//
// HandleDWellStartEnd()
//
static DocPos prevCursorPosition = -1;
void HandleDWellStartEnd(const DocPos position, const UINT uid)
{
static DocPos prevStartPosition = -1;
static DocPos prevEndPosition = -1;
if (position >= 0) {
if (prevCursorPosition < 0) {
prevCursorPosition = position;
}
if (prevStartPosition < 0) {
prevStartPosition = position;
}
if (prevEndPosition < 0) {
prevEndPosition = position;
}
}
int indicator_id = INDICATOR_CONTAINER;
switch (uid) {
case SCN_DWELLSTART: {
if (position < 0) {
Sci_CallTipCancelEx();
prevCursorPosition = -1;
return;
}
if (Settings.HyperlinkHotspot) {
if (SciCall_IndicatorValueAt(INDIC_NP3_HYPERLINK, position) > 0) {
indicator_id = INDIC_NP3_HYPERLINK;
if (position != prevCursorPosition) {
Sci_CallTipCancelEx();
}
}
}
if (IsColorDefHotspotEnabled()) {
if (SciCall_IndicatorValueAt(INDIC_NP3_COLOR_DEF, position) > 0) {
indicator_id = INDIC_NP3_COLOR_DEF;
}
}
if (Settings.HighlightUnicodePoints) {
if (SciCall_IndicatorValueAt(INDIC_NP3_UNICODE_POINT, position) > 0) {
indicator_id = INDIC_NP3_UNICODE_POINT;
}
}
switch (indicator_id) {
case INDIC_NP3_HYPERLINK:
if (!Settings.ShowHypLnkToolTip || SciCall_CallTipActive()) {
return;
}
break;
case INDIC_NP3_UNICODE_POINT:
if (!Settings.HighlightUnicodePoints || SciCall_CallTipActive()) {
return;
}
break;
case INDIC_NP3_COLOR_DEF:
// ok
break;
// nothing to do for these indicators
case INDICATOR_CONTAINER:
default:
return;
}
// ----------------------------------------------------------------------
if ((position < prevStartPosition) || (position > prevEndPosition)) {
s_bCallTipEscDisabled = false;
}
DocPos const firstPos = SciCall_IndicatorStart(indicator_id, position);
DocPos const lastPos = SciCall_IndicatorEnd(indicator_id, position);
DocPos const length = (lastPos - firstPos);
// WebLinks and Color Refs are ASCII only - No need for UTF-8 conversion here
if (INDIC_NP3_HYPERLINK == indicator_id) {
if (!s_bCallTipEscDisabled) {
const char * const pUrlBegin = SciCall_GetRangePointer(firstPos, length);
char chScheme[32] = { '\0' };
for (unsigned i = 0; i < COUNTOF(chScheme); ++i) {
chScheme[i] = pUrlBegin[i];
if (!pUrlBegin[i] || pUrlBegin[i] == ':') {
break;
}
}
CHAR chCallTip[MIDSZ_BUFFER] = { L'\0' };
size_t cch = 0;
if (StrStrIA(chScheme, "file:") == chScheme) {
WCHAR wchUrl[INTERNET_MAX_URL_LENGTH] = { L'\0' };
int const cchUrl = MultiByteToWideChar(Encoding_SciCP, 0, pUrlBegin, (int)length, wchUrl, COUNTOF(wchUrl));
wchUrl[cchUrl] = L'\0';
StrTrim(wchUrl, L" \r\n\t");
SplitFilePathLineNum(wchUrl, NULL); // cut off possible linenum spec
HPATHL hurl_pth = Path_Allocate(NULL);
DWORD cchPath = INTERNET_MAX_URL_LENGTH;
LPWSTR const url_buf = Path_WriteAccessBuf(hurl_pth, cchPath);
if (FAILED(PathCreateFromUrlW(wchUrl, url_buf, &cchPath, 0))) {
const char *p = &pUrlBegin[CONSTSTRGLEN("file://")];
while (p && (*p == '/')) { ++p; }
StringCchCopyN(url_buf, Path_GetBufCount(hurl_pth), wchUrl, cchUrl); // no op
cchPath = (DWORD)Path_GetLength(hurl_pth);
}
Path_Sanitize(hurl_pth);
Path_NormalizeEx(hurl_pth, Paths.WorkingDirectory, true, false);
bool found = true;
if (Path_IsExistingFile(hurl_pth)) {
GetLngStringW2MB(IDS_MUI_URL_FILE_EXISTS, chCallTip, (int)(COUNTOF(chCallTip) >> 1));
} else if (Path_IsExistingDirectory(hurl_pth)) {
GetLngStringW2MB(IDS_MUI_URL_DIR_EXISTS, chCallTip, (int)(COUNTOF(chCallTip) >> 1));
} else {
found = false;
GetLngStringW2MB(IDS_MUI_URL_PATH_NOT_FOUND, chCallTip, (int)(COUNTOF(chCallTip) >> 1));
}
if (found) {
cch = StringCchLenA(chCallTip, COUNTOF(chCallTip));
GetLngStringW2MB(IDS_MUI_URL_OPEN_FILE, &chCallTip[cch], (int)(COUNTOF(chCallTip) - cch));
}
Path_Release(hurl_pth);
} else { // Web URL
StringCchCopyNA(chCallTip, COUNTOF(chCallTip) >> 1, pUrlBegin, length);
cch = StringCchLenA(chCallTip, COUNTOF(chCallTip) >> 1);
GetLngStringW2MB(IDS_MUI_URL_OPEN_BROWSER, &chCallTip[cch], (int)(COUNTOF(chCallTip) - cch));
}
if (!StrIsEmptyA(chCallTip)) {
// first show, then set highlight range
// SciCall_CallTipSetPosition(true);
SciCall_CallTipShow(position, chCallTip);
SciCall_CallTipSetHlt(0, (int)cch);
}
}
} else if (INDIC_NP3_COLOR_DEF == indicator_id) {
char chText[MICRO_BUFFER] = { '\0' };
// Color Refs are ASCII only - No need for UTF-8 conversion here
StringCchCopyNA(chText, COUNTOF(chText), SciCall_GetRangePointer(firstPos, length), length);
unsigned int iValue = 0;
if (sscanf_s(&chText[1], "%x", &iValue) == 1) {
COLORREF rgb = 0x000000;
int alpha = SC_ALPHA_OPAQUE;
if (length >= 8) { // ARGB, RGBA, BGRA
switch (Settings.ColorDefHotspot) {
case 1:
rgb = ARGB_TO_COLREF(iValue);
alpha = ARGB_GET_ALPHA(iValue);
break;
case 2:
rgb = RGBA_TO_COLREF(iValue);
alpha = RGBA_GET_ALPHA(iValue);
break;
case 3:
rgb = BGRA_TO_COLREF(iValue);
alpha = BGRA_GET_ALPHA(iValue);
break;
case 0:
default:
break;
}
} else { // RGB
rgb = RGB((iValue >> 16) & 0xFF, (iValue >> 8) & 0xFF, iValue & 0xFF);
alpha = SC_ALPHA_OPAQUE;
}
COLORREF const fgr = CalcContrastColor(rgb, alpha);
SciCall_SetIndicatorCurrent(INDIC_NP3_COLOR_DEF_T);
SciCall_IndicatorFillRange(firstPos, length);
SciCall_IndicSetHoverFore(INDIC_NP3_COLOR_DEF_T, fgr);
SciCall_IndicSetAlpha(INDIC_NP3_COLOR_DEF, Sci_ClampAlpha(alpha));
SciCall_IndicSetHoverFore(INDIC_NP3_COLOR_DEF, rgb);
SciCall_IndicSetHoverStyle(INDIC_NP3_COLOR_DEF, INDIC_FULLBOX);
SciCall_IndicSetHoverStyle(INDIC_NP3_COLOR_DEF_T, INDIC_TEXTFORE);
}
} else if (INDIC_NP3_UNICODE_POINT == indicator_id) {
if (!s_bCallTipEscDisabled) {
char chHex2Char[MIDSZ_BUFFER] = {'\0'};
// No need for UTF-8 conversion here and
StringCchCopyNA(chHex2Char, COUNTOF(chHex2Char), SciCall_GetRangePointer(firstPos, length), length);
//StrTrimA(chHex2Char, " \t\n\r");
Hex2Char(chHex2Char, COUNTOF(chHex2Char));
if (StrIsEmptyA(chHex2Char)) {
break;
}
// first show, then set highlight range
// SciCall_CallTipSetPosition(true);
SciCall_CallTipShow(position, chHex2Char);
SciCall_CallTipSetHlt(0, (int)length);
}
}
prevCursorPosition = position;
prevStartPosition = firstPos;
prevEndPosition = lastPos;
}
break;
case SCN_DWELLEND: {
if ((position >= prevStartPosition) && ((position <= prevEndPosition))) {
return; // avoid flickering
}
Sci_CallTipCancelEx();
DocPos const curPos = SciCall_GetCurrentPos();
if ((curPos >= prevStartPosition) && ((curPos <= prevEndPosition))) {
return; // no change for if caret in range
}
s_bCallTipEscDisabled = false;
prevCursorPosition = -1;
// clear SCN_DWELLSTART visual styles
SciCall_SetIndicatorCurrent(INDIC_NP3_COLOR_DEF_T);
SciCall_IndicatorClearRange(0, Sci_GetDocEndPosition());
// hide color of color definition
SciCall_IndicSetHoverStyle(INDIC_NP3_COLOR_DEF, INDIC_HIDDEN); // hide box
SciCall_IndicSetHoverStyle(INDIC_NP3_COLOR_DEF_T, INDIC_HIDDEN); // hide txt
//~ this will destroy rectangular selection on multi-replace ???
//~ !!! strange side-effects using following statements !!!
//~~~SciCall_IndicSetAlpha(INDIC_NP3_COLOR_DEF, SC_ALPHA_TRANSPARENT);
//~~~SciCall_IndicSetFore(INDIC_NP3_COLOR_DEF, RGB(0,0,0));
}
break;
default:
break;
}
}
//=============================================================================
//
// HandleHotSpotURLClicked()
//
//
bool HandleHotSpotURLClicked(const DocPos position, const HYPERLINK_OPS operation)
{
if (position < 0) {
return false;
}
//~SciCall_PostMsg(WM_LBUTTONUP, MK_LBUTTON, 0);
Sci_CallTipCancelEx();
bool bHandled = false;
if (SciCall_IndicatorValueAt(INDIC_NP3_HYPERLINK, position)) {
DocPos const firstPos = SciCall_IndicatorStart(INDIC_NP3_HYPERLINK, position);
DocPos const lastPos = SciCall_IndicatorEnd(INDIC_NP3_HYPERLINK, position);
DocPos const length = min_p(lastPos - firstPos, INTERNET_MAX_URL_LENGTH);
if (length < 4) {
return false;
}
const char * const pszText = SciCall_GetRangePointer(firstPos, length);
WCHAR szTextW[INTERNET_MAX_URL_LENGTH + 1];
ptrdiff_t const cchTextW = MultiByteToWideChar(Encoding_SciCP, 0, pszText, (int)length, szTextW, COUNTOF(szTextW));
szTextW[cchTextW] = L'\0';
StrTrim(szTextW, L" \r\n\t");
const WCHAR* const chkPreFix = L"file://";
size_t const lenPfx = StringCchLen(chkPreFix, 0);
if (operation & SELECT_HYPERLINK) {
SciCall_SetSelection(firstPos, lastPos);
bHandled = true;
} else if (operation & COPY_HYPERLINK) {
if (cchTextW > 0) {
DWORD cchEscapedW = (DWORD)(length * 3 + 1);
LPWSTR const pszEscapedW = (LPWSTR)AllocMem(cchEscapedW * sizeof(WCHAR), HEAP_ZERO_MEMORY);
if (pszEscapedW) {
//~UrlEscape(szTextW, pszEscapedW, &cchEscapedW, (URL_BROWSER_MODE | URL_ESCAPE_AS_UTF8));
UrlEscapeEx(szTextW, pszEscapedW, &cchEscapedW, false);
SetClipboardText(Globals.hwndMain, pszEscapedW, cchEscapedW);
FreeMem(pszEscapedW);
bHandled = true;
}
}
} else {
WCHAR szUnEscW[INTERNET_MAX_URL_LENGTH + 1];
DWORD dCch = COUNTOF(szUnEscW);
int lineNum = -1;
SplitFilePathLineNum(szTextW, &lineNum);
lineNum = clampi(lineNum, 0, INT_MAX);
if (((operation & OPEN_IN_NOTEPAD3) || (operation & OPEN_NEW_NOTEPAD3)) && UrlIsFileUrl(szTextW)) {
bool const bReuseWindow = Flags.bReuseWindow && !(operation & OPEN_NEW_NOTEPAD3);
PathCreateFromUrlW(szTextW, szUnEscW, &dCch, 0);
szUnEscW[INTERNET_MAX_URL_LENGTH] = L'\0'; // limit length
StrTrim(szUnEscW, L"/");
HPATHL hfile_pth = Path_Allocate(szUnEscW);
Path_CanonicalizeEx(hfile_pth, Paths.ModuleDirectory);
//@@@???Path_CanonicalizeEx(hfile_pth, Paths.WorkingDirectory);
bool success = false;
FileLoadFlags fLoadFlags = FLF_None;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
if (Path_IsExistingFile(hfile_pth)) {
if (bReuseWindow) {
success = FileLoad(hfile_pth, fLoadFlags);
} else {
WCHAR wchParams[64];
StringCchPrintf(wchParams, COUNTOF(wchParams), L"%s /g %i", Flags.bSingleFileInstance ? L"/ns" : L"/n", lineNum);
success = LaunchNewInstance(Globals.hwndMain, wchParams, Path_Get(hfile_pth));
}
}
else if (Path_IsExistingDirectory(hfile_pth)) {
if (bReuseWindow) {
if (OpenFileDlg(Globals.hwndMain, hfile_pth, hfile_pth)) {
success = FileLoad(hfile_pth, fLoadFlags);
}
} else {
WCHAR wchParams[64];
StringCchPrintf(wchParams, COUNTOF(wchParams), L"%s", Flags.bSingleFileInstance ? L"/ns" : L"/n");
success = LaunchNewInstance(Globals.hwndMain, wchParams, Path_Get(hfile_pth));
}
}
if (bReuseWindow && success && (lineNum >= 0)) {
lineNum = clampi(lineNum - 1, 0, INT_MAX);
//~SciCall_GotoLine((DocLn)lineNum);
SciCall_PostMsg(SCI_GOTOLINE, (WPARAM)lineNum, 0);
}
bHandled = true;
Path_Release(hfile_pth);
} else if (operation & OPEN_WITH_BROWSER) { // open in web browser or associated application
HPATHL hDirectory = Path_Allocate(NULL);
if (UrlIsFileUrl(szTextW)) {
// ShellExecuteExW() will handle file-system path correctly for "file://" protocol
StringCchCopy(szUnEscW, COUNTOF(szUnEscW), chkPreFix);
dCch -= (DWORD)lenPfx;
PathCreateFromUrl(szTextW, &szUnEscW[lenPfx], &dCch, 0);
Path_Reset(hDirectory, szUnEscW);
Path_RemoveFileSpec(hDirectory);
} else {
UrlUnescapeEx(szTextW, szUnEscW, &dCch);
}
if (Path_IsEmpty(hDirectory) && Path_IsNotEmpty(Paths.CurrentFile)) {
Path_Reset(hDirectory, Path_Get(Paths.CurrentFile));
Path_RemoveFileSpec(hDirectory);
}
if (StrgIsNotEmpty(Settings2.HyperlinkShellExURLWithApp)) {
HSTRINGW hstr_params = StrgCopy(Settings2.HyperlinkShellExURLCmdLnArgs);
StrgReplace(hstr_params, URLPLACEHLDR, szUnEscW);
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_DEFAULT;
sei.hwnd = NULL;
sei.lpVerb = NULL;
sei.lpFile = StrgGet(Settings2.HyperlinkShellExURLWithApp);
sei.lpParameters = StrgIsNotEmpty(hstr_params) ? StrgGet(hstr_params) : szUnEscW;
sei.lpDirectory = Path_Get(hDirectory);
sei.nShow = SW_SHOWNORMAL;
bHandled = ShellExecuteExW(&sei);
StrgDestroy(hstr_params);
} else {
const WCHAR *const lpVerb = StrIsEmpty(Settings2.HyperlinkFileProtocolVerb) ? NULL : Settings2.HyperlinkFileProtocolVerb;
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_NOZONECHECKS;
sei.hwnd = NULL;
sei.lpVerb = lpVerb;
sei.lpFile = szUnEscW;
sei.lpParameters = NULL;
sei.lpDirectory = Path_Get(hDirectory);
sei.nShow = SW_SHOWNORMAL;
bHandled = ShellExecuteExW(&sei);
}
Path_Release(hDirectory);
}
}
}
if (!(operation & SELECT_HYPERLINK)) {
SciCall_SetEmptySelection(position);
}
return bHandled;
}
//=============================================================================
//
// HandleColorDefClicked()
//
void HandleColorDefClicked(HWND hwnd, const DocPos position)
{
if (SciCall_IndicatorValueAt(INDIC_NP3_COLOR_DEF, position) == 0) {
return;
}
DocPos const firstPos = SciCall_IndicatorStart(INDIC_NP3_COLOR_DEF, position);
DocPos const lastPos = SciCall_IndicatorEnd(INDIC_NP3_COLOR_DEF, position);
DocPos const length = (lastPos - firstPos);
char chText[32] = { '\0' };
// Color Refs are ASCII only - No need for UTF-8 conversion here
StringCchCopyNA(chText, COUNTOF(chText), SciCall_GetRangePointer(firstPos, length), length);
unsigned int iValue = 0;
if (sscanf_s(&chText[1], "%x", &iValue) == 1) {
COLORREF rgbCur = 0x000000;
BYTE alpha = 0xFF;
if (length >= 8) { // ARGB, RGBA, BGRA
switch (Settings.ColorDefHotspot) {
case 1:
rgbCur = ARGB_TO_COLREF(iValue);
alpha = ARGB_GET_ALPHA(iValue);
break;
case 2:
rgbCur = RGBA_TO_COLREF(iValue);
alpha = RGBA_GET_ALPHA(iValue);
break;
case 3:
rgbCur = BGRA_TO_COLREF(iValue);
alpha = BGRA_GET_ALPHA(iValue);
break;
case 0:
default:
break;
}
} else { // RGB
rgbCur = RGB((iValue >> 16) & 0xFF, (iValue >> 8) & 0xFF, iValue & 0xFF);
alpha = 0xFF;
}
CHOOSECOLOR cc = { sizeof(CHOOSECOLOR) };
cc.hwndOwner = hwnd;
cc.hInstance = (HWND)Globals.hLngResContainer; // Globals.hInstance;
cc.rgbResult = rgbCur;
cc.lpCustColors = &g_colorCustom[0];
cc.Flags = CC_FULLOPEN | CC_RGBINIT | CC_ANYCOLOR;
// custom hook
cc.Flags |= CC_ENABLEHOOK;
cc.lpfnHook = (LPCCHOOKPROC)ColorDialogHookProc;
WININFO const wi = GetMyWindowPlacement(Globals.hwndEdit, NULL, 0, false);
int const offset = f2int(Style_GetCurrentLexerFontSize()) << 1;
POINT pt = { 0L, 0L };
pt.x = wi.x + SciCall_PointXFromPosition(SciCall_GetCurrentPos()) + offset;
pt.y = wi.y + SciCall_PointYFromPosition(SciCall_GetCurrentPos()) + offset;
cc.lCustData = (LPARAM)&pt;
// Color.dlg resource template
cc.Flags |= CC_ENABLETEMPLATE | CC_ENABLETEMPLATEHANDLE;
cc.lpTemplateName = MAKEINTRESOURCEW(IDD_MUI_SYSCOLOR_DLG);
if (!ChooseColor(&cc)) {
return;
}
COLORREF const rgbNew = cc.rgbResult;
CHAR wchColor[32] = { L'\0' };
if (length >= 8) {
switch (Settings.ColorDefHotspot) {
case 1:
StringCchPrintfA(wchColor, COUNTOF(wchColor), "#%02X%02X%02X%02X", (int)(alpha),
(int)GetRValue(rgbNew), (int)GetGValue(rgbNew), (int)GetBValue(rgbNew));
break;
case 2:
StringCchPrintfA(wchColor, COUNTOF(wchColor), "#%02X%02X%02X%02X",
(int)GetRValue(rgbNew), (int)GetGValue(rgbNew), (int)GetBValue(rgbNew),
(int)(alpha));
break;
case 3:
StringCchPrintfA(wchColor, COUNTOF(wchColor), "#%02X%02X%02X%02X",
(int)GetBValue(rgbNew), (int)GetGValue(rgbNew), (int)GetRValue(rgbNew),
(int)(alpha));
break;
case 0:
default:
break;
}
} else {
StringCchPrintfA(wchColor, COUNTOF(wchColor), "#%02X%02X%02X",
(int)GetRValue(rgbNew), (int)GetGValue(rgbNew), (int)GetBValue(rgbNew));
}
SciCall_SetTargetRange(firstPos, lastPos);
Sci_ReplaceTargetTestChgHist(length, wchColor);
EditUpdateVisibleIndicators();
}
}
//=============================================================================
//
// _HandleAutoIndent()
//
static void _HandleAutoIndent(int const charAdded)
{
// TODO: handle indent after '{' and un-indent on '}' in C/C++ ?
// in CRLF mode handle LF only...
int const eol_mode = SciCall_GetEOLMode();
if (((SC_EOL_CRLF == eol_mode) && (charAdded != '\r')) || (SC_EOL_CRLF != eol_mode)) {
DocLn const iCurLine = Sci_GetCurrentLineNumber();
// Move bookmark along with line if inserting lines (pressing return within indent area of line) because Scintilla does not do this for us
if (iCurLine > 0) {
//~DocPos const iPrevLineLength = Sci_GetNetLineLength(iCurLine - 1);
if (SciCall_GetLineEndPosition(iCurLine - 1) == SciCall_GetLineIndentPosition(iCurLine - 1)) {
int const bitmask = SciCall_MarkerGet(iCurLine - 1) & ALL_MARKERS_BITMASK();
if (bitmask) {
UserMarkerDeleteAll(iCurLine - 1);
SciCall_MarkerAddSet(iCurLine, bitmask);
}
}
//~if (iLineLength <= 2)
{
DocLn const iPrevLine = iCurLine - 1;
DocPos const iPrevLineLength = SciCall_LineLength(iPrevLine);
char * const pLineBuf = (char*)AllocMem(iPrevLineLength + 1, HEAP_ZERO_MEMORY);
if (pLineBuf) {
SciCall_GetLine_Safe(iPrevLine, pLineBuf);
for (char* pPos = pLineBuf; *pPos; pPos++) {
if ((*pPos != ' ') && (*pPos != '\t')) {
*pPos = '\0';
break;
}
}
if (*pLineBuf) {
SciCall_AddText((DocPos)StringCchLenA(pLineBuf, SizeOfMem(pLineBuf)), pLineBuf);
}
FreeMem(pLineBuf);
}
}
}
}
}
//=============================================================================
//
// _HandleAutoCloseTags()
//
static void _HandleAutoCloseTags()
{
if (Sci_IsMultiSelection()) {
return;
}
/// int const lexerID = SciCall_GetLexer();
/// if (lexerID == SCLEX_HTML || lexerID == SCLEX_XML)
DocPos const maxSearchBackward = 8192;
DocPos const iCurPos = SciCall_GetCurrentPos();
DocPos const iHelper = iCurPos - maxSearchBackward;
DocPos const iStartPos = max_p(0, iHelper);
DocPos const iSize = iCurPos - iStartPos;
if (iSize >= 3) {
const char* const pBegin = SciCall_GetRangePointer(iStartPos, iSize);
if (pBegin[iSize - 2] != '/') {
const char* pCur = &pBegin[iSize - 2];
while (pCur > pBegin && *pCur != '<' && *pCur != '>') {
--pCur;
}
int cchIns = 2;
char replaceBuf[SMALL_BUFFER];
StringCchCopyA(replaceBuf, COUNTOF(replaceBuf), "</");
if (*pCur == '<') {
++pCur;
while ((StrChrA(":_-.", *pCur) || IsCharAlphaNumericA(*pCur)) && (cchIns < (COUNTOF(replaceBuf) - 2))) {
replaceBuf[cchIns++] = *pCur++;
}
}
replaceBuf[cchIns++] = '>';
replaceBuf[cchIns] = '\0';
// except tags w/o closing tags
const char* const nonClosingTags[9] = { "</base>", "</bgsound>", "</br>", "</embed>", "</hr>", "</img>", "</input>", "</link>", "</meta>" };
int const cntCount = COUNTOF(nonClosingTags);
bool isNonClosingTag = false;
for (int i = 0; ((i < cntCount) && !isNonClosingTag); ++i) {
isNonClosingTag = (StrCmpIA(replaceBuf, nonClosingTags[i]) == 0);
}
if ((cchIns > 3) && !isNonClosingTag) {
EditReplaceSelection(replaceBuf, false);
SciCall_SetSel(iCurPos, iCurPos);
}
}
}
}
//=============================================================================
//
// _HandleInsertCheck()
//
static inline void _SaveSelectionToBuffer()
{
if (!s_SelectionBuffer) {
return;
}
if (Sci_IsMultiOrRectangleSelection()) {
s_SelectionBuffer[0] = '\0';
s_SelectionBuffer[1] = 'X';
return;
}
size_t len = SciCall_GetSelText(NULL);
if ((len + 3) > SizeOfMem(s_SelectionBuffer)) {
s_SelectionBuffer = (char*)ReAllocMem(s_SelectionBuffer, len + 3, HEAP_ZERO_MEMORY);
}
Sci_GetSelectionTextN(&s_SelectionBuffer[1], SizeOfMem(s_SelectionBuffer) - 2);
s_SelectionBuffer[0] = s_SelectionBuffer[1];
}
static inline DocPos _EncloseSelectionBuffer(const char op, const char cl)
{
if (!s_SelectionBuffer) {
return 0;
}
if (s_SelectionBuffer[0] == '\0' && s_SelectionBuffer[1] == 'X') {
// IsMultiOrRectangleSelection:
s_SelectionBuffer[0] = op;
s_SelectionBuffer[1] = '\0';
return 1;
}
size_t len = s_SelectionBuffer ? strlen(s_SelectionBuffer) : 0;
len += (len ? 0 : 1); // empty correction
s_SelectionBuffer[0] = op;
s_SelectionBuffer[len++] = cl;
s_SelectionBuffer[len] = '\0';
return len;
}
static inline void _HandleInsertCheck(const SCNotification* const scn)
{
if (Sci_IsMultiOrRectangleSelection() || !scn || !(scn->text)) {
return;
}
if (Settings.AutoCloseQuotes) {
if (scn->length == 1) {
DocPos len = 0;
switch (scn->text[0]) {
case '"':
if (Sci_GetCurrChar() == '"') {
SciCall_ChangeInsertion(0, ""); // clear
SciCall_PostMsg(SCI_CHARRIGHT, 0, 0);
}
else {
len = _EncloseSelectionBuffer('"', '"');
}
break;
case '\'':
if (Sci_GetCurrChar() == '\'') {
SciCall_ChangeInsertion(0, ""); // clear
SciCall_PostMsg(SCI_CHARRIGHT, 0, 0);
}
else {
len = _EncloseSelectionBuffer('\'', '\'');
}
break;
case '`':
if (Sci_GetCurrChar() == '`') {
SciCall_ChangeInsertion(0, ""); // clear
SciCall_PostMsg(SCI_CHARRIGHT, 0, 0);
}
else {
len = _EncloseSelectionBuffer('`', '`');
}
break;
default:
break;
}
if (len) {
SciCall_ChangeInsertion(len, s_SelectionBuffer);
if (len == 2) {
SciCall_PostMsg(SCI_CHARLEFT, 0, 0);
}
}
}
}
if (Settings.AutoCloseBrackets) {
if (scn->length == 1) {
DocPos len = 0;
switch (scn->text[0]) {
case '[':
len = _EncloseSelectionBuffer('[', ']');
break;
case '{':
len = _EncloseSelectionBuffer('{', '}');
break;
case '(':
len = _EncloseSelectionBuffer('(', ')');
break;
case ')':
if (Sci_GetCurrChar() == ')') {
SciCall_ChangeInsertion(0, ""); // clear
SciCall_PostMsg(SCI_CHARRIGHT, 0, 0);
}
break;
case '}':
if (Sci_GetCurrChar() == '}') {
SciCall_ChangeInsertion(0, ""); // clear
SciCall_PostMsg(SCI_CHARRIGHT, 0, 0);
}
break;
case ']':
if (Sci_GetCurrChar() == ']') {
SciCall_ChangeInsertion(0, ""); // clear
SciCall_PostMsg(SCI_CHARRIGHT, 0, 0);
}
break;
default:
break;
}
if (len) {
SciCall_ChangeInsertion(len, s_SelectionBuffer);
if (len == 2) {
SciCall_PostMsg(SCI_CHARLEFT, 0, 0);
}
}
}
}
}
static inline void _HandleDeleteCheck(const SCNotification* const scn)
{
if (Settings.AutoCloseQuotes) {
if (scn->length == 1) {
bool bDelPair = false;
char const chrAfter = SciCall_GetCharAt(scn->position);
switch (scn->text[0]) {
case '"':
if (chrAfter == '"')
bDelPair = true;
break;
case '\'':
if (chrAfter == '\'')
bDelPair = true;
break;
case '`':
if (chrAfter == '`')
bDelPair = true;
break;
default:
break;
}
if (bDelPair) {
SciCall_PostMsg(SCI_CHARRIGHT, 0, 0);
SciCall_PostMsg(SCI_DELETEBACK, 0, 0);
}
}
}
if (Settings.AutoCloseBrackets) {
if (scn->length == 1) {
bool bDelPair = false;
char const chrAfter = SciCall_GetCharAt(scn->position);
switch (scn->text[0]) {
case '[':
if (chrAfter == ']')
bDelPair = true;
break;
case '{':
if (chrAfter == '}')
bDelPair = true;
case '(':
if (chrAfter == ')')
bDelPair = true;
break;
default:
break;
}
if (bDelPair) {
SciCall_PostMsg(SCI_CHARRIGHT, 0, 0);
SciCall_PostMsg(SCI_DELETEBACK, 0, 0);
}
}
}
}
#if 0
//=============================================================================
//
// _IsIMEOpenInNoNativeMode()
//
static bool _IsIMEOpenInNoNativeMode()
{
bool result = false;
HIMC const himc = ImmGetContext(Globals.hwndEdit);
if (himc) {
if (ImmGetOpenStatus(himc)) {
DWORD dwConversion = IME_CMODE_ALPHANUMERIC, dwSentence = 0;
if (ImmGetConversionStatus(himc, &dwConversion, &dwSentence)) {
result = (dwConversion != IME_CMODE_ALPHANUMERIC);
}
}
ImmReleaseContext(Globals.hwndEdit, himc);
}
return result;
}
#endif
//=============================================================================
//
// MsgNotifyLean() - Handles WM_NOTIFY (only absolute neccessary events)
//
// !!! Set correct SCI_SETMODEVENTMASK in _InitializeSciEditCtrl()
//
inline static LRESULT _MsgNotifyLean(const SCNotification *const scn, bool* bModified) {
const LPNMHDR pnmh = (LPNMHDR)scn;
static LONG _urtoken = URTok_NoTransaction;
// --- check only mandatory events (must be fast !!!) ---
if (pnmh->idFrom == IDC_EDIT) {
switch (pnmh->code) {
case SCN_MODIFIED: {
*bModified = false; // init
int const iModType = scn->modificationType;
if ((iModType & SC_MULTISTEPUNDOREDO) && !(iModType & SC_LASTSTEPINUNDOREDO)) {
return TRUE; // wait for last step in multi-step-undo/redo
}
bool const bInUndoRedoStep = (iModType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO));
if (iModType & SC_MOD_INSERTCHECK) {
if (!bInUndoRedoStep) {
_HandleInsertCheck(scn);
}
}
if (iModType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) {
*bModified = false; // not yet
if (!bInUndoRedoStep) {
if (!_InUndoRedoTransaction() && (_urtoken < URTok_TokenStart)) {
_SaveSelectionToBuffer();
bool const bSelEmpty = SciCall_IsSelectionEmpty();
bool const bIsMultiRectSel = Sci_IsMultiOrRectangleSelection();
if (!bSelEmpty || bIsMultiRectSel) {
LONG const tok = _SaveUndoSelection();
_urtoken = (tok >= URTok_TokenStart ? tok : _urtoken);
}
// TODO: @@@ Find reason for why this NOP workaround is needed:
if (!bSelEmpty && bIsMultiRectSel) {
// need to trigger SCI:InvalidateCaret()
bool const bAddSelTyping = SciCall_GetAdditionalSelectionTyping();
//~SciCall_SetAdditionalSelectionTyping(!bAddSelTyping); // v5.1.1: no check for change, so:
SciCall_SetAdditionalSelectionTyping(bAddSelTyping);
}
}
}
} else if (iModType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) {
if (!bInUndoRedoStep) {
if (!_InUndoRedoTransaction() && (_urtoken >= URTok_TokenStart)) {
_SaveRedoSelection(_urtoken, SciCall_GetModify());
_urtoken = URTok_NoTransaction;
}
if (iModType & SC_MOD_DELETETEXT) {
_HandleDeleteCheck(scn);
}
}
*bModified = true;
}
// check for ADDUNDOACTION step
if (iModType & SC_MOD_CONTAINER) {
// we are inside undo/redo transaction, so do delayed PostMessage() instead of SendMessage()
if (iModType & SC_PERFORMED_UNDO) {
PostMessage(Globals.hwndMain, WM_RESTORE_UNDOREDOACTION, (WPARAM)UNDO, (LPARAM)scn->token);
} else if (iModType & SC_PERFORMED_REDO) {
PostMessage(Globals.hwndMain, WM_RESTORE_UNDOREDOACTION, (WPARAM)REDO, (LPARAM)scn->token);
}
}
if (*bModified) {
LONG64 const timeout = Settings2.UndoTransactionTimeout;
if (timeout != 0LL) {
if (!bInUndoRedoStep) {
_DelaySplitUndoTransaction(max_ll(_MQ_IMMEDIATE, timeout));
}
}
}
} break;
case SCN_SAVEPOINTREACHED: {
SetSaveDone();
} break;
case SCN_SAVEPOINTLEFT: {
SetSaveNeeded(false);
} break;
case SCN_MODIFYATTEMPTRO: {
if (FocusedView.HideNonMatchedLines) {
EditToggleView(Globals.hwndEdit);
}
else {
if (!FileWatching.MonitoringLog
&& !IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONINFORMATION, L"QuietKeepReadonlyLock", IDS_MUI_DOCUMENT_READONLY)))
{
SendWMCommand(Globals.hwndMain, IDM_VIEW_READONLY);
}
else {
AttentionBeep(MB_YESNO | MB_ICONINFORMATION);
}
}
} break;
default:
break;
} // switch
return TRUE;
}
return FALSE;
}
//=============================================================================
//
// _MsgNotifyFromEdit() - Handles WM_NOTIFY (only absolute neccessary events)
//
// !!! Set correct SCI_SETMODEVENTMASK in _InitializeSciEditCtrl()
//
static LRESULT _MsgNotifyFromEdit(HWND hwnd, const SCNotification* const scn)
{
const LPNMHDR pnmh = (LPNMHDR)scn;
static int _s_indic_click_modifiers = SCMOD_NORM;
bool bModified = false;
LRESULT resMN = _MsgNotifyLean(scn, &bModified);
switch (pnmh->code) {
// not send
//~ case SCN_KEY:
// unused:
case SCN_HOTSPOTCLICK:
case SCN_HOTSPOTDOUBLECLICK:
case SCN_HOTSPOTRELEASECLICK:
return FALSE;
case SCN_MODIFIED: {
/// bModified = set in _MsgNotifyLean() !
if (bModified) {
int const iModType = scn->modificationType;
if (IsMarkOccurrencesEnabled()) {
MarkAllOccurrences(-1, true);
}
EditUpdateVisibleIndicators();
if (scn->linesAdded != 0) {
if (Settings.SplitUndoTypingSeqOnLnBreak && (scn->linesAdded > 0)) {
if (!(iModType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO))) {
_SplitUndoTransaction();
}
}
UpdateMargins(false);
}
if (s_bInMultiEditMode && !(iModType & SC_MULTILINEUNDOREDO)) {
if (!Sci_IsMultiSelection()) {
SciCall_SetIndicatorCurrent(INDIC_NP3_MULTI_EDIT);
SciCall_IndicatorClearRange(0, Sci_GetDocEndPosition());
s_bInMultiEditMode = false;
}
}
}
return resMN;
}
case SCN_AUTOCSELECTION: {
switch (scn->listCompletionMethod) {
case SC_AC_TAB:
case SC_AC_COMMAND:
case SC_AC_DOUBLECLICK:
// accepted
break;
case SC_AC_FILLUP:
// see: SciCall_AutoCSetFillups() -> accepted
break;
case SC_AC_NEWLINE:
if (!EditCheckNewLineInACFillUps()) {
SciCall_AutoCCancel(); // rejected
SciCall_PostMsg(SCI_NEWLINE, 0, 0);
}
break;
default:
SciCall_AutoCCancel(); // rejected
break;
}
}
break;
case SCN_STYLENEEDED: {
// this event needs SCI_SETLEXER(SCLEX_CONTAINER)
//EditUpdateIndicators(SciCall_GetEndStyled(), scn->position, false);
}
break;
case SCN_UPDATEUI: {
static DocPos selCnt = 0;
int const iUpd = scn->updated;
if (iUpd & (SC_UPDATE_SELECTION | SC_UPDATE_CONTENT)) {
// Brace Match
if (Settings.MatchBraces) {
EditMatchBrace(Globals.hwndEdit);
}
if (iUpd & SC_UPDATE_SELECTION) {
// clear marks only, if selection changed
if (IsMarkOccurrencesEnabled()) {
bool const bValidSel = !SciCall_IsSelectionEmpty() && !Sci_IsMultiOrRectangleSelection();
if (bValidSel || Settings.MarkOccurrencesCurrentWord) {
MarkAllOccurrences(-1, true);
} else {
if (Globals.iMarkOccurrencesCount) {
EditClearAllOccurrenceMarkers(Globals.hwndEdit);
}
}
}
DocPos const selDiff = (SciCall_GetSelectionEnd() - SciCall_GetSelectionStart());
if (selDiff != selCnt) {
selCnt = selDiff;
UpdateToolbar();
}
}
if (iUpd & SC_UPDATE_CONTENT) {
UpdateMargins(false);
UpdateTitlebar(Globals.hwndMain);
//~ Style and Marker are out of scope here => using WM_COMMAND -> SCEN_CHANGE instead!
//~MarkAllOccurrences(-1, false);
//~EditUpdateVisibleIndicators(); // will lead to recursion
}
UpdateStatusbar(false);
} else if (iUpd & SC_UPDATE_V_SCROLL) {
if (IsMarkOccurrencesEnabled() && Settings.MarkOccurrencesMatchVisible) {
MarkAllOccurrences(-1, false);
}
EditUpdateVisibleIndicators();
}
}
break;
case SCN_DWELLSTART:
case SCN_DWELLEND: {
HandleDWellStartEnd(scn->position, pnmh->code);
}
break;
case SCN_DOUBLECLICK: {
HandleHotSpotURLClicked(scn->position, SELECT_HYPERLINK); // COPY_HYPERLINK
}
break;
case SCN_CALLTIPCLICK: {
if (prevCursorPosition >= 0) {
//~HandleHotSpotURLClicked(SciCall_CallTipPosStart(), OPEN_WITH_BROWSER);
HandleHotSpotURLClicked(prevCursorPosition, OPEN_WITH_BROWSER);
}
}
break;
case SCN_INDICATORCLICK: {
_s_indic_click_modifiers = scn->modifiers;
}
break;
case SCN_INDICATORRELEASE: {
if (SciCall_IndicatorValueAt(INDIC_NP3_HYPERLINK, scn->position) > 0) {
bool const bIsNoSel = Sci_IsSingleSelection() && SciCall_IsSelectionEmpty();
if ((_s_indic_click_modifiers & SCMOD_ALT) && bIsNoSel)
{
if (_s_indic_click_modifiers & SCMOD_CTRL) {
HandleHotSpotURLClicked(scn->position, OPEN_NEW_NOTEPAD3);
} else {
HandleHotSpotURLClicked(scn->position, OPEN_IN_NOTEPAD3);
}
} else if (_s_indic_click_modifiers & SCMOD_CTRL) {
HandleHotSpotURLClicked(scn->position, OPEN_WITH_BROWSER); // if applicable (file://)
}
} else if (SciCall_IndicatorValueAt(INDIC_NP3_COLOR_DEF, scn->position) > 0) {
if (_s_indic_click_modifiers & SCMOD_CTRL) {
HandleColorDefClicked(Globals.hwndEdit, scn->position);
}
}
_s_indic_click_modifiers = SCMOD_NORM;
}
break;
case SCN_CHARADDED: {
int const ich = scn->ch;
Sci_CallTipCancelEx();
if (Sci_IsMultiSelection()) {
SciCall_SetIndicatorCurrent(INDIC_NP3_MULTI_EDIT);
DocPosU const selCount = SciCall_GetSelections();
for (DocPosU s = 0; s < selCount; ++s) {
DocPos const pos = SciCall_GetSelectionNStart(s);
SciCall_IndicatorFillRange(SciCall_PositionBefore(pos), 1);
}
s_bInMultiEditMode = true;
}
switch (ich) {
case '\r':
case '\n':
if (Settings.AutoIndent) {
_HandleAutoIndent(ich);
}
break;
case '>':
if (Settings.AutoCloseTags) {
_HandleAutoCloseTags();
}
break;
case '?':
_EvalTinyExpr(true);
break;
default:
break;
}
if ((Settings.AutoCompleteWords || Settings.AutoCLexerKeyWords)) {
if (!EditAutoCompleteWord(Globals.hwndEdit, false)) {
return FALSE;
}
}
}
break;
case SCN_AUTOCCHARDELETED:
if ((Settings.AutoCompleteWords || Settings.AutoCLexerKeyWords)) {
if (!EditAutoCompleteWord(Globals.hwndEdit, false)) {
return FALSE;
}
}
break;
case SCN_NEEDSHOWN: {
DocLn const iFirstLine = SciCall_LineFromPosition(scn->position);
DocLn const iLastLine = SciCall_LineFromPosition(scn->position + scn->length - 1);
for (DocLn i = iFirstLine; i <= iLastLine; ++i) {
if (!SciCall_GetLineVisible(i)) {
SciCall_EnsureVisible(i);
}
}
EditUpdateVisibleIndicators();
}
break;
case SCN_MARGINCLICK: {
switch (scn->margin) {
case MARGIN_SCI_FOLDING:
EditFoldClick(SciCall_LineFromPosition(scn->position), scn->modifiers);
break;
case MARGIN_SCI_BOOKMRK:
EditBookmarkToggle(Globals.hwndEdit, SciCall_LineFromPosition(scn->position), scn->modifiers);
break;
case MARGIN_SCI_CHGHIST:
case MARGIN_SCI_LINENUM:
//~SciCall_GotoLine(SciCall_LineFromPosition(scn->position));
// fallthrough
default:
return 0;
}
}
break;
case SCN_MARGINRIGHTCLICK: {
POINT pt = { -1, -1 };
MsgContextMenu(hwnd, SCN_MARGINRIGHTCLICK, MAKEWPARAM(pt.x, pt.y), (LPARAM)scn);
}
break;
// ~~~ Not used in Windows ~~~
// see: CMD_ALTUP / CMD_ALTDOWN
//case SCN_KEY:
// // Also see the corresponding patch in scintilla\src\Editor.cxx
// FoldAltArrow(scn->ch, scn->modifiers);
// break;
case SCN_ZOOM:
UpdateToolbar();
UpdateMargins(true);
break;
#if 0
case SCN_URIDROPPED: {
HPATHL hfile_pth = Path_Allocate(NULL);
wchar_t* const file_buf = Path_WriteAccessBuf(hfile_pth, STRINGW_MAX_URL_LENGTH);
int const cnt = MultiByteToWideChar(CP_UTF8, 0, scn->text, -1, file_buf, (int)Path_GetBufCount(hfile_pth));
LRESULT const result = (cnt > 0) ? _OnDropOneFile(hwnd, hfile_pth, NULL) : FALSE;
Path_Release(hfile_pth);
return result;
}
#endif
default:
return FALSE;
}
return TRUE;
}
//=============================================================================
//
// MsgNotify() - Handles WM_NOTIFY
//
// !!! Set correct SCI_SETMODEVENTMASK in _InitializeSciEditCtrl()
//
static bool s_mod_ctrl_pressed = false;
static bool s_tb_reset_already = false;
LRESULT MsgNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
LRESULT result = FALSE;
SET_FCT_GUARD(result)
const SCNotification* const scn = (SCNotification*)lParam;
const LPNMHDR pnmh = (LPNMHDR)scn;
switch (pnmh->idFrom) {
case IDC_EDIT: {
bool bModified = false;
result = NotifyDocChanged() ? _MsgNotifyFromEdit(hwnd, scn) : _MsgNotifyLean(scn, &bModified);
} break;
// ------------------------------------------------------------------------
case IDC_TOOLBAR:
switch (pnmh->code) {
case TBN_QUERYDELETE:
case TBN_QUERYINSERT:
// (!) must exist and return true
result = TRUE;
break;
case TBN_BEGINADJUST:
s_tb_reset_already = false;
break;
case TBN_GETBUTTONINFO: {
if (((LPTBNOTIFY)lParam)->iItem < COUNTOF(s_tbbMainWnd)) {
WCHAR tch[SMALL_BUFFER] = { L'\0' };
GetLngString(s_tbbMainWnd[((LPTBNOTIFY)lParam)->iItem].idCommand, tch, COUNTOF(tch));
StringCchCopyN(((LPTBNOTIFY)lParam)->pszText, ((LPTBNOTIFY)lParam)->cchText, tch, ((LPTBNOTIFY)lParam)->cchText);
CopyMemory(&((LPTBNOTIFY)lParam)->tbButton, &s_tbbMainWnd[((LPTBNOTIFY)lParam)->iItem], sizeof(TBBUTTON));
result = TRUE;
}
}
break;
case TBN_RESET: {
int const count = (int)SendMessage(Globals.hwndToolbar, TB_BUTTONCOUNT, 0, 0);
for (int i = 0; i < count; i++) {
SendMessage(Globals.hwndToolbar, TB_DELETEBUTTON, 0, 0);
}
if (s_tb_reset_already) {
if (Toolbar_SetButtons(Globals.hwndToolbar, IDT_FILE_NEW, Defaults.ToolbarButtons, s_tbbMainWnd, COUNTOF(s_tbbMainWnd)) == 0) {
SendMessage(Globals.hwndToolbar, TB_ADDBUTTONS, COUNTOF(s_tbbMainWnd), (LPARAM)s_tbbMainWnd);
}
} else {
if (Toolbar_SetButtons(Globals.hwndToolbar, IDT_FILE_NEW, Settings.ToolbarButtons, s_tbbMainWnd, COUNTOF(s_tbbMainWnd)) == 0) {
SendMessage(Globals.hwndToolbar, TB_ADDBUTTONS, COUNTOF(s_tbbMainWnd), (LPARAM)s_tbbMainWnd);
}
}
s_tb_reset_already = !s_tb_reset_already;
}
break;
case TBN_ENDADJUST:
UpdateToolbar();
result = TRUE;
break;
case NM_CUSTOMDRAW: {
LPNMTBCUSTOMDRAW const lpNMTBCustomDraw = (LPNMTBCUSTOMDRAW)lParam;
result = CDRF_DODEFAULT;
switch (lpNMTBCustomDraw->nmcd.dwDrawStage) {
case CDDS_PREPAINT:
result = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT: {
//~HDC const hdc = lpNMTBCustomDraw->nmcd.hdc;
//~if (hdc) {
//~ SetBkColor(hdc, GetModeBtnfaceColor(UseDarkMode()));
//~ SetTextColor(hdc, GetModeTextColor(UseDarkMode()));
//~}
lpNMTBCustomDraw->clrBtnFace = GetModeBtnfaceColor(UseDarkMode());
lpNMTBCustomDraw->clrText = GetModeTextColor(UseDarkMode());
result = TBCDRF_USECDCOLORS;
}
break;
default:
break;
}
}
default:
break;
}
break;
// ------------------------------------------------------------------------
case IDC_STATUSBAR:
result = TRUE;
switch(pnmh->code) {
case NM_CLICK: { // single click
LPNMMOUSE const pnmm = (LPNMMOUSE)lParam;
if (pnmm->dwItemSpec >= COUNTOF(g_vSBSOrder)) {
break;
}
switch (g_vSBSOrder[pnmm->dwItemSpec]) {
case STATUS_EOLMODE: {
if (Globals.bDocHasInconsistentEOLs) {
int const eol_mode = SciCall_GetEOLMode();
int const eol_cmd = (eol_mode == SC_EOL_CRLF) ? IDM_LINEENDINGS_CRLF :
((eol_mode == SC_EOL_CR) ? IDM_LINEENDINGS_CR : IDM_LINEENDINGS_LF);
UINT const msgid = (eol_mode == SC_EOL_CRLF) ? IDS_MUI_EOLMODENAME_CRLF :
((eol_mode == SC_EOL_CR) ? IDS_MUI_EOLMODENAME_CR : IDS_MUI_EOLMODENAME_LF);
WCHAR wch[64] = {L'\0'};
GetLngString(msgid, wch, COUNTOF(wch));
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, NULL, IDS_MUI_WARN_NORMALIZE_EOLS, wch))) {
PostWMCommand(hwnd, eol_cmd);
}
}
}
break;
default:
result = FALSE;
break;
}
}
break;
case NM_DBLCLK: { // double click
LPNMMOUSE const pnmm = (LPNMMOUSE)lParam;
result = TRUE;
switch (g_vSBSOrder[pnmm->dwItemSpec]) {
case STATUS_DOCLINE:
case STATUS_DOCCOLUMN:
PostWMCommand(hwnd, IDM_EDIT_GOTOLINE);
break;
case STATUS_CODEPAGE:
PostWMCommand(hwnd, IDM_ENCODING_SELECT);
break;
case STATUS_EOLMODE: {
int const eol_mode = (SciCall_GetEOLMode() + 1) % 3;
// skip unusual CR-only mode; should be explicitly set by menu or dialog only, so:
int const eol_cmd = (eol_mode == SC_EOL_CRLF) ? IDM_LINEENDINGS_CRLF : IDM_LINEENDINGS_LF;
//~((eol_mode == SC_EOL_CR) ? IDM_LINEENDINGS_CR : IDM_LINEENDINGS_LF);
PostWMCommand(hwnd, eol_cmd);
}
break;
case STATUS_OVRMODE:
PostWMCommand(hwnd, CMD_VK_INSERT);
break;
case STATUS_2ND_DEF:
PostWMCommand(hwnd, IDM_VIEW_USE2NDDEFAULT);
break;
case STATUS_LEXER:
PostWMCommand(hwnd, IDM_VIEW_SCHEME);
break;
case STATUS_TINYEXPR: {
char chExpr[80] = { '\0' };
if (s_iExprError == 0) {
TinyExprToStringA(chExpr, COUNTOF(chExpr), s_dExpression);
} else if (s_iExprError > 0) {
StringCchPrintfA(chExpr, COUNTOF(chExpr), "^[" TE_INT_FMT "]", s_iExprError);
SciCall_CopyText((DocPos)StringCchLenA(chExpr, COUNTOF(chExpr)), chExpr);
}
SciCall_CopyText((DocPos)StringCchLenA(chExpr, COUNTOF(chExpr)), chExpr);
}
break;
default:
result = FALSE;
break;
}
}
break;
case NM_RCLICK: {
POINT pt = { 0, 0 };
GetCursorPos(&pt);
MsgContextMenu(hwnd, 0, (WPARAM)Globals.hwndStatus, MAKELPARAM(pt.x, pt.y));
} break;
default:
break;
}
break;
// ------------------------------------------------------------------------
default:
switch(pnmh->code) {
// ToolTip
case TTN_NEEDTEXT:
if (!(((LPTOOLTIPTEXT)lParam)->uFlags & TTF_IDISHWND)) {
WCHAR tch[SMALL_BUFFER] = { L'\0' };
GetLngString((UINT)pnmh->idFrom,tch,COUNTOF(tch));
WCHAR* pttText = ((LPTOOLTIPTEXT)lParam)->szText;
size_t const ttLen = COUNTOF(((LPTOOLTIPTEXT)lParam)->szText);
StringCchCopyN(pttText, ttLen, tch,COUNTOF(tch));
result = TRUE;
}
break;
default:
break;
}
break;
}
RESET_FCT_GUARD();
return result;
}
//=============================================================================
//
// ParseCommandLine()
//
static void ParseCmdLnOption(LPWSTR lp1, LPWSTR lp2, const size_t len); // forward decl
// -----------------------------------------------------------------------------
void ParseCommandLine()
{
LPWSTR lpCmdLine = GetCommandLine();
if (StrIsEmpty(lpCmdLine)) {
return;
}
// Good old console can also send args separated by Tabs
StrTab2Space(lpCmdLine);
size_t const len = StringCchLen(lpCmdLine,0) + 2UL;
LPWSTR const lp1 = AllocMem(sizeof(WCHAR)*len,HEAP_ZERO_MEMORY);
LPWSTR const lp2 = AllocMem(sizeof(WCHAR)*len,HEAP_ZERO_MEMORY);
LPWSTR const lp3 = AllocMem(sizeof(WCHAR)*len,HEAP_ZERO_MEMORY);
if (lp1 && lp2 && lp3) {
// Start with 2nd argument
ExtractFirstArgument(lpCmdLine, lp1, lp3, (int)len);
bool bContinue = true;
bool bIsFileArg = false;
s_flagSetEncoding = CPI_NONE;
while (bContinue && ExtractFirstArgument(lp3, lp1, lp2, (int)len)) {
// options
if (!bIsFileArg && (lp1[0] == L'+') && (lp1[1] == L'\0')) {
Globals.CmdLnFlag_MultiFileArg = 2;
bIsFileArg = true;
StringCchCopy(lp3, len, lp2); // next arg
}
else if (!bIsFileArg && (lp1[0] == L'-') && (lp1[1] == L'\0')) {
Globals.CmdLnFlag_MultiFileArg = 1;
bIsFileArg = true;
StringCchCopy(lp3, len, lp2); // next arg
}
else if (!bIsFileArg && ((*lp1 == L'/') && (*lp2 == '\0')) && (StrStrW(&lp1[1], L"/") != NULL)) {
bIsFileArg = true; // WSL2 filepath (at least 2 slashes needed)
}
else if (!bIsFileArg && ((*lp1 == L'/') || (*lp1 == L'-'))) {
StrLTrimI(lp1, L"-/"); // LeftTrim
ParseCmdLnOption(lp1, lp2, len);
bIsFileArg = false;
}
else {
bIsFileArg = true;
}
// pathname
if (bIsFileArg) {
LPWSTR const lpFileBuf = AllocMem(sizeof(WCHAR) * len, HEAP_ZERO_MEMORY);
if (lpFileBuf) {
size_t const fileArgLen = StringCchLen(lp3, len);
s_cchiFileList = (int)(StringCchLen(lpCmdLine, len - 2) - fileArgLen);
if (s_lpOrigFileArg) {
FreeMem(s_lpOrigFileArg);
s_lpOrigFileArg = NULL;
}
size_t const alloc_spc = sizeof(WCHAR) * (fileArgLen + 1);
s_lpOrigFileArg = AllocMem(alloc_spc, HEAP_ZERO_MEMORY); // changed for ActivatePrevInst() needs
StringCchCopy(s_lpOrigFileArg, alloc_spc, lp3);
Path_Reset(s_pthArgFilePath, lp3);
if (!Path_IsRelative(s_pthArgFilePath) && !Path_IsUNC(s_pthArgFilePath) && (Path_GetDriveNumber(s_pthArgFilePath) == -1))
{
HPATHL pthAdjustPath = Path_Copy(Paths.WorkingDirectory);
Path_StripToRoot(pthAdjustPath);
Path_Append(pthAdjustPath, Path_Get(s_pthArgFilePath));
Path_Reset(s_pthArgFilePath, Path_Get(pthAdjustPath));
Path_Release(pthAdjustPath);
}
HPATHL pthAddFile = Path_Allocate(NULL);
while ((s_cFileList < FILE_LIST_SIZE) && ExtractFirstArgument(lp3, lpFileBuf, lp3, (int)len)) {
Path_Reset(pthAddFile, lpFileBuf);
Path_NormalizeEx(pthAddFile, Paths.WorkingDirectory, true, true);
Path_QuoteSpaces(pthAddFile, false);
s_lpFileList[s_cFileList] = StrDupW(Path_Get(pthAddFile)); // LocalAlloc()
s_cFileList += 1;
}
Path_Release(pthAddFile);
bContinue = false;
FreeMem(lpFileBuf);
}
}
// Continue with next argument
if (bContinue) {
StringCchCopy(lp3, len, lp2);
}
}
FreeMem(lp1);
FreeMem(lp2);
FreeMem(lp3);
}
}
static void ParseCmdLnOption(LPWSTR lp1, LPWSTR lp2, const size_t len)
{
static bool bIsNotepadReplacement = false;
// Encoding
cpi_enc_t const encoding = Encoding_MatchW(lp1);
if (StringCchCompareXI(lp1, L"ANSI") == 0 || StringCchCompareXI(lp1, L"A") == 0 || StringCchCompareXI(lp1, L"MBCS") == 0) {
s_flagSetEncoding = CPI_ANSI_DEFAULT;
}
else if (StringCchCompareXI(lp1, L"UNICODE") == 0 || StringCchCompareXI(lp1, L"W") == 0) {
s_flagSetEncoding = CPI_UNICODEBOM;
}
else if (StringCchCompareXI(lp1, L"UNICODEBE") == 0 || StringCchCompareXI(lp1, L"UNICODE-BE") == 0) {
s_flagSetEncoding = CPI_UNICODEBEBOM;
}
else if (StringCchCompareXI(lp1, L"UTF8") == 0 || StringCchCompareXI(lp1, L"UTF-8") == 0) {
s_flagSetEncoding = CPI_UTF8;
}
else if (StringCchCompareXI(lp1, L"UTF8SIG") == 0 || StringCchCompareXI(lp1, L"UTF-8SIG") == 0 ||
StringCchCompareXI(lp1, L"UTF8SIGNATURE") == 0 || StringCchCompareXI(lp1, L"UTF-8SIGNATURE") == 0 ||
StringCchCompareXI(lp1, L"UTF8-SIGNATURE") == 0 || StringCchCompareXI(lp1, L"UTF-8-SIGNATURE") == 0) {
s_flagSetEncoding = CPI_UTF8SIGN;
}
// maybe parsed encoding
else if (Encoding_IsValid(encoding)) {
s_flagSetEncoding = encoding;
}
// EOL Mode
else if (StringCchCompareXI(lp1, L"CRLF") == 0 || StringCchCompareXI(lp1, L"CR+LF") == 0) {
s_flagSetEOLMode = IDM_LINEENDINGS_CRLF - IDM_LINEENDINGS_CRLF + 1;
}
else if (StringCchCompareXI(lp1, L"CR") == 0) {
s_flagSetEOLMode = IDM_LINEENDINGS_CR - IDM_LINEENDINGS_CRLF + 1;
}
else if (StringCchCompareXI(lp1, L"LF") == 0) {
s_flagSetEOLMode = IDM_LINEENDINGS_LF - IDM_LINEENDINGS_CRLF + 1;
}
// Shell integration
else if (StrCmpNI(lp1, L"appid=", CONSTSTRGLEN(L"appid=")) == 0) {
StringCchCopyN(Settings2.AppUserModelID, COUNTOF(Settings2.AppUserModelID),
lp1 + CONSTSTRGLEN(L"appid="), len - CONSTSTRGLEN(L"appid="));
StrTrim(Settings2.AppUserModelID, L" ");
if (StrIsEmpty(Settings2.AppUserModelID)) {
StringCchCopy(Settings2.AppUserModelID, COUNTOF(Settings2.AppUserModelID), _W("Rizonesoft.") _W(SAPPNAME));
}
}
else if (StrCmpNI(lp1, L"sysmru=", CONSTSTRGLEN(L"sysmru=")) == 0) {
WCHAR wch[16];
StringCchCopyN(wch, COUNTOF(wch), lp1 + CONSTSTRGLEN(L"sysmru="), COUNTOF(wch));
StrTrim(wch, L" ");
if (*wch == L'1') {
Globals.CmdLnFlag_ShellUseSystemMRU = 2;
}
else {
Globals.CmdLnFlag_ShellUseSystemMRU = 1;
}
}
// Relaunch elevated
else if (StrCmpNI(lp1, RELAUNCH_ELEVATED_BUF_ARG, CONSTSTRGLEN(RELAUNCH_ELEVATED_BUF_ARG)) == 0) {
Path_Reset(s_hpthRelaunchElevatedFile, lp1 + CONSTSTRGLEN(RELAUNCH_ELEVATED_BUF_ARG));
//?TrimSpcW(s_hpthRelaunchElevatedFile);
Path_NormalizeEx(s_hpthRelaunchElevatedFile, Paths.ModuleDirectory, true, Flags.bSearchPathIfRelative);
s_IsThisAnElevatedRelaunch = true;
}
else {
switch (*CharUpper(lp1)) {
case L'N':
Globals.CmdLnFlag_ReuseWindow = 1;
if (*CharUpper(lp1 + 1) == L'S') {
Globals.CmdLnFlag_SingleFileInstance = 2;
}
else {
Globals.CmdLnFlag_SingleFileInstance = 1;
}
break;
case L'R':
if (*CharUpper(lp1 + 1) == L'P') {
Flags.bPreserveFileModTime = true;
}
else {
Globals.CmdLnFlag_ReuseWindow = 2;
if (*CharUpper(lp1 + 1) == L'S') {
Globals.CmdLnFlag_SingleFileInstance = 2;
}
else {
Globals.CmdLnFlag_SingleFileInstance = 1;
}
}
break;
case L'F':
if (*(lp1 + 1) == L'0' || *CharUpper(lp1 + 1) == L'O') {
Path_Reset(Paths.IniFile, L"*?");
}
else if (ExtractFirstArgument(lp2, lp1, lp2, (int)len)) {
WCHAR wchPath[INTERNET_MAX_URL_LENGTH];
StringCchCopyN(wchPath, COUNTOF(wchPath), lp1, len);
Path_Reset(Paths.IniFile, wchPath);
Path_NormalizeEx(Paths.IniFile, Paths.ModuleDirectory, true, false);
}
break;
case L'I':
s_flagStartAsTrayIcon = true;
break;
case L'O':
if (*(lp1 + 1) == L'0' || *(lp1 + 1) == L'-' || *CharUpper(lp1 + 1) == L'O') {
Globals.CmdLnFlag_AlwaysOnTop = 1;
}
else {
Globals.CmdLnFlag_AlwaysOnTop = 2;
}
break;
case L'P': {
WCHAR* lp = lp1;
if (StrCmpNI(lp1, L"POS:", CONSTSTRGLEN(L"POS:")) == 0) {
lp += CONSTSTRGLEN(L"POS:") - 1;
}
else if (StrCmpNI(lp1, L"POS", CONSTSTRGLEN(L"POS")) == 0) {
lp += CONSTSTRGLEN(L"POS") - 1;
}
else if (*(lp1 + 1) == L':') {
lp += 1;
}
else if (bIsNotepadReplacement) {
if (*(lp1 + 1) == L'T') {
ExtractFirstArgument(lp2, lp1, lp2, (int)len);
}
break;
}
if (*(lp + 1) == L'0' || *CharUpper(lp + 1) == L'O') {
Globals.CmdLnFlag_PosParam = true;
Globals.CmdLnFlag_WindowPos = 1;
}
else if (*CharUpper(lp + 1) == L'D' || *CharUpper(lp + 1) == L'S') {
Globals.CmdLnFlag_PosParam = true;
Globals.CmdLnFlag_WindowPos = (StrChrI((lp + 1), L'L')) ? 3 : 2;
}
else if (StrChrI(L"FLTRBM", *(lp + 1))) {
WCHAR* p = (lp + 1);
Globals.CmdLnFlag_PosParam = true;
Globals.CmdLnFlag_WindowPos = 0;
while (*p) {
switch (*CharUpper(p)) {
case L'F':
Globals.CmdLnFlag_WindowPos &= ~(4 | 8 | 16 | 32);
Globals.CmdLnFlag_WindowPos |= 64;
break;
case L'L':
Globals.CmdLnFlag_WindowPos &= ~(8 | 64);
Globals.CmdLnFlag_WindowPos |= 4;
break;
case L'R':
Globals.CmdLnFlag_WindowPos &= ~(4 | 64);
Globals.CmdLnFlag_WindowPos |= 8;
break;
case L'T':
Globals.CmdLnFlag_WindowPos &= ~(32 | 64);
Globals.CmdLnFlag_WindowPos |= 16;
break;
case L'B':
Globals.CmdLnFlag_WindowPos &= ~(16 | 64);
Globals.CmdLnFlag_WindowPos |= 32;
break;
case L'M':
if (Globals.CmdLnFlag_WindowPos == 0) {
Globals.CmdLnFlag_WindowPos |= 64;
}
Globals.CmdLnFlag_WindowPos |= 128;
break;
}
p = CharNext(p);
}
}
else if (ExtractFirstArgument(lp2, lp1, lp2, (int)len)) {
WININFO wi = INIT_WININFO;
int iMaximize = 0;
int const itok = swscanf_s(lp1, WINDOWPOS_STRGFORMAT, &wi.x, &wi.y, &wi.cx, &wi.cy, &wi.dpi, &iMaximize);
if (itok == 4 || itok == 5 || itok == 6) { // scan successful
Globals.CmdLnFlag_PosParam = true;
Globals.CmdLnFlag_WindowPos = 0;
if (itok == 4) {
wi.dpi = USER_DEFAULT_SCREEN_DPI;
iMaximize = 0;
}
else if (itok == 5) { // maybe DPI or Maxi (old)
if (wi.dpi < (USER_DEFAULT_SCREEN_DPI >> 2)) {
iMaximize = wi.dpi;
wi.dpi = USER_DEFAULT_SCREEN_DPI;
}
else {
iMaximize = 0;
}
}
wi.max = !!iMaximize;
g_IniWinInfo = wi; // set window placement
}
}
} break;
case L'T':
if (ExtractFirstArgument(lp2, lp1, lp2, (int)len)) {
StringCchCopyN(s_wchTitleExcerpt, COUNTOF(s_wchTitleExcerpt), lp1, len);
s_flagKeepTitleExcerpt = true;
}
break;
case L'C':
s_flagNewFromClipboard = true;
break;
case L'B':
s_flagPasteBoard = true;
break;
case L'E':
if (ExtractFirstArgument(lp2, lp1, lp2, (int)len)) {
s_flagSetEncoding = Encoding_MatchW(lp1);
}
break;
case L'G':
if (ExtractFirstArgument(lp2, lp1, lp2, (int)len)) {
int itok = swscanf_s(lp1, L"%i,%i", &s_iInitialLine, &s_iInitialColumn);
if (itok == 1 || itok == 2) { // scan successful
s_flagJumpTo = true;
}
}
break;
case L'M': {
bool bFindUp = false;
bool bMatchCase = false;
bool bRegex = false;
bool bDotMatchAll = false;
bool bTransBS = false;
if (StrChr(lp1, L'-')) {
bFindUp = true;
}
if (StrChr(lp1, L'C')) {
bMatchCase = true;
}
if (StrChr(lp1, L'R')) {
bRegex = true;
bTransBS = true;
}
if (StrChr(lp1, L'A')) {
bDotMatchAll = true;
}
if (StrChr(lp1, L'B')) {
bTransBS = true;
}
if (ExtractFirstArgument(lp2, lp1, lp2, (int)len)) {
SetFindPattern(lp1);
g_flagMatchText = 1;
if (bFindUp) {
g_flagMatchText |= 2;
}
if (bRegex) {
g_flagMatchText |= 4;
}
if (bMatchCase) {
g_flagMatchText |= 8;
}
if (bDotMatchAll) {
g_flagMatchText |= 16;
}
if (bTransBS) {
g_flagMatchText |= 32;
}
}
} break;
case L'L':
if (*(lp1 + 1) == L'0' || *(lp1 + 1) == L'-' || *CharUpper(lp1 + 1) == L'O') {
s_flagChangeNotify = FWM_MSGBOX;
}
else if (*(lp1 + 1) == L'1' || *(lp1 + 1) == L'+' || *CharUpper(lp1 + 1) == L'X') {
s_flagChangeNotify = FWM_EXCLUSIVELOCK;
}
else {
s_flagChangeNotify = FWM_AUTORELOAD;
}
break;
case L'Q':
if (*CharUpper(lp1 + 1) == L'S') {
s_flagSaveOnRelaunch = true;
}
else {
s_flagQuietCreate = true;
}
break;
case L'S':
if (ExtractFirstArgument(lp2, lp1, lp2, (int)len)) {
if (s_lpSchemeArg) {
LocalFree(s_lpSchemeArg); // StrDup()
s_lpSchemeArg = NULL;
}
s_lpSchemeArg = StrDup(lp1);
s_flagLexerSpecified = true;
}
break;
case L'D':
if (s_lpSchemeArg) {
LocalFree(s_lpSchemeArg); // StrDup()
s_lpSchemeArg = NULL;
}
s_iInitialLexer = 0;
s_flagLexerSpecified = true;
break;
case L'H':
if (s_lpSchemeArg) {
LocalFree(s_lpSchemeArg); // StrDup()
s_lpSchemeArg = NULL;
}
s_iInitialLexer = 35;
s_flagLexerSpecified = true;
break;
case L'X':
if (s_lpSchemeArg) {
LocalFree(s_lpSchemeArg); // StrDup()
s_lpSchemeArg = NULL;
}
s_iInitialLexer = 36;
s_flagLexerSpecified = true;
break;
case L'U':
if (*CharUpper(lp1 + 1) == L'C') {
SetEvent(s_hEventAppIsClosing);
}
else {
Flags.bDoRelaunchElevated = true;
}
break;
case L'Y':
Flags.bSearchPathIfRelative = true;
break;
case L'Z':
ExtractFirstArgument(lp2, lp1, lp2, (int)len);
Globals.CmdLnFlag_MultiFileArg = 1;
bIsNotepadReplacement = true;
break;
case L'?':
s_flagDisplayHelp = true;
break;
case L'V':
Globals.CmdLnFlag_PrintFileAndLeave = 1;
if (*CharUpper(lp1 + 1) == L'D') {
Globals.CmdLnFlag_PrintFileAndLeave = 2; // open printer dialog
}
break;
default:
break;
}
}
}
//=============================================================================
//
// CheckAutoLoadMostRecent()
//
void CheckAutoLoadMostRecent()
{
// Add most recent from file history
if (Path_IsEmpty(s_pthArgFilePath) && Settings.AutoLoadMRUFile) {
if (MRU_Count(Globals.pFileMRU) > 0) {
LPWSTR const szFileBuf = Path_WriteAccessBuf(s_pthArgFilePath, PATHLONG_MAX_CCH); // reserve buffer
int const cchFileBuf = (int)Path_GetBufCount(s_pthArgFilePath);
MRU_Enum(Globals.pFileMRU, 0, szFileBuf, cchFileBuf);
Path_Sanitize(s_pthArgFilePath);
Path_UnQuoteSpaces(s_pthArgFilePath);
Path_AbsoluteFromApp(s_pthArgFilePath, true);
}
}
}
//=============================================================================
//
// _DelayUpdateStatusbar()
//
static void _DelayUpdateStatusbar(const int delay, const bool bForceRedraw)
{
CmdMessageQueue_t mqc = MQ_WM_CMD_INIT(Globals.hwndMain, IDT_TIMER_UPDATE_STATUSBAR, bForceRedraw);
_MQ_AppendCmd(&mqc, _MQ_ms2cycl(delay));
}
//=============================================================================
//
// _DelayUpdateToolbar()
//
static void _DelayUpdateToolbar(const LONG64 delay)
{
CmdMessageQueue_t mqc = MQ_WM_CMD_INIT(Globals.hwndMain, IDT_TIMER_UPDATE_TOOLBAR, 0LL);
_MQ_AppendCmd(&mqc, _MQ_ms2cycl(delay));
}
//=============================================================================
//
// _DelayUpdateTitlebar()
//
static void _DelayUpdateTitlebar(const LONG64 delay, const HWND hwnd)
{
CmdMessageQueue_t mqc = MQ_WM_CMD_INIT(Globals.hwndMain, IDT_TIMER_UPDATE_TITLEBAR, (LPARAM)hwnd);
_MQ_AppendCmd(&mqc, _MQ_ms2cycl(delay));
}
//=============================================================================
//
// _DelayClearCallTip()
//
static void _DelayClearCallTip(const LONG64 delay)
{
CmdMessageQueue_t mqc = MQ_WM_CMD_INIT(Globals.hwndMain, IDT_TIMER_CLEAR_CALLTIP, 0LL);
_MQ_AppendCmd(&mqc, _MQ_ms2cycl(delay));
}
//=============================================================================
//
// _DelaySplitUndoTransaction()
//
static void _DelaySplitUndoTransaction(const LONG64 delay)
{
CmdMessageQueue_t mqc = MQ_WM_CMD_INIT(Globals.hwndMain, IDT_TIMER_UNDO_TRANSACTION, 0);
_MQ_AppendCmd(&mqc, _MQ_ms2cycl(delay));
}
//=============================================================================
//
// MarkAllOccurrences()
//
void MarkAllOccurrences(const LONG64 delay, const bool bForceClear)
{
CmdMessageQueue_t mqc = MQ_WM_CMD_INIT(Globals.hwndMain, IDT_TIMER_CALLBACK_MRKALL, bForceClear);
LONG64 const timer = (delay < 0) ? Settings2.UpdateDelayMarkAllOccurrences : delay;
_MQ_AppendCmd(&mqc, _MQ_ms2cycl(timer));
}
//=============================================================================
//
// UpdateTitlebar()
//
void UpdateTitlebar(const HWND hwnd)
{
_DelayUpdateTitlebar(_MQ_STD, hwnd);
}
//=============================================================================
//
// _UpdateTitlebarDelayed()
//
static void _UpdateTitlebarDelayed(const HWND hwnd)
{
if (hwnd == Globals.hwndMain && Settings.ShowTitlebar) {
TITLEPROPS_T props = { 0 };
props.iFormat = Settings.PathNameFormat;
props.bPasteBoard = s_flagPasteBoard;
props.bIsElevated = s_bIsProcessElevated;
props.bModified = IsSaveNeeded();
props.bFileLocked = (FileWatching.FileWatchingMode == FWM_EXCLUSIVELOCK);
props.bFileChanged = IsFileChangedFlagSet();
props.bFileDeleted = IsFileDeletedFlagSet();
props.bReadOnly = IsFileReadOnly();
SetWindowTitle(Globals.hwndMain, Paths.CurrentFile, props, s_wchTitleExcerpt, false);
}
//if (!IsWindows10OrGreater()) {
// PostMessage(hwnd, WM_NCACTIVATE, FALSE, -1); // (!)
// PostMessage(hwnd, WM_NCACTIVATE, TRUE, 0);
//}
}
//=============================================================================
//
// UpdateToolbar()
//
void UpdateToolbar()
{
_DelayUpdateToolbar(_MQ_STD);
_DelayUpdateTitlebar(_MQ_STD, Globals.hwndMain);
}
//=============================================================================
static void _UpdateToolbarDelayed()
{
if (!Settings.ShowToolbar) {
return;
}
EnableTool(Globals.hwndToolbar, IDT_FILE_ADDTOFAV, Path_IsNotEmpty(Paths.CurrentFile));
EnableTool(Globals.hwndToolbar, IDT_FILE_SAVE, IsSaveNeeded() || IsFileChangedFlagSet() /*&& !bReadOnly*/);
EnableTool(Globals.hwndToolbar, IDT_FILE_RECENT, (MRU_Count(Globals.pFileMRU) > 0));
CheckTool(Globals.hwndToolbar, IDT_VIEW_WORDWRAP, Globals.fvCurFile.bWordWrap);
CheckTool(Globals.hwndToolbar, IDT_VIEW_CHASING_DOCTAIL, FileWatching.MonitoringLog);
CheckTool(Globals.hwndToolbar, IDT_VIEW_PIN_ON_TOP, Settings.AlwaysOnTop);
bool const b1 = SciCall_IsSelectionEmpty();
bool const b2 = !Sci_IsDocEmpty();
bool const ro = SciCall_GetReadOnly();
bool const tv = FocusedView.HideNonMatchedLines;
EnableTool(Globals.hwndToolbar, IDT_EDIT_UNDO, SciCall_CanUndo() && !ro);
EnableTool(Globals.hwndToolbar, IDT_EDIT_REDO, SciCall_CanRedo() && !ro);
EnableTool(Globals.hwndToolbar, IDT_EDIT_PASTE, SciCall_CanPaste() && !ro);
EnableTool(Globals.hwndToolbar, IDT_FILE_LAUNCH, b2);
EnableTool(Globals.hwndToolbar, IDT_EDIT_FIND, b2);
//EnableTool(Globals.hwndToolbar, ,b2);
//EnableTool(Globals.hwndToolbar, IDT_EDIT_FINDPREV,b2 && !StrIsEmptyA(s_FindReplaceData.szFind));
EnableTool(Globals.hwndToolbar, IDT_EDIT_REPLACE, b2 && !ro);
EnableTool(Globals.hwndToolbar, IDT_EDIT_CUT, !b1 && !ro);
EnableTool(Globals.hwndToolbar, IDT_EDIT_COPY, !b1 && !ro);
EnableTool(Globals.hwndToolbar, IDT_EDIT_CLEAR, !b1 && !ro);
EnableTool(Globals.hwndToolbar, IDT_VIEW_TOGGLEFOLDS, b2 && (FocusedView.CodeFoldingAvailable && FocusedView.ShowCodeFolding));
EnableTool(Globals.hwndToolbar, IDT_VIEW_TOGGLE_VIEW, b2 && IsFocusedViewAllowed());
CheckTool(Globals.hwndToolbar, IDT_VIEW_TOGGLE_VIEW, tv);
int const zoom = SciCall_GetZoom();
CheckTool(Globals.hwndToolbar, IDT_VIEW_ZOOMIN, (zoom > 100));
CheckTool(Globals.hwndToolbar, IDT_VIEW_RESETZOOM, (zoom == 100));
CheckTool(Globals.hwndToolbar, IDT_VIEW_ZOOMOUT, (zoom < 100));
}
//=============================================================================
//
// _CalculateStatusbarSections
// vSectionWidth[] must be pre-filled with -1
//
#define txtWidth 80
typedef WCHAR sectionTxt_t[txtWidth];
static void _CalculateStatusbarSections(int vSectionWidth[], sectionTxt_t tchStatusBar[], bool* bIsUpdNeeded)
{
// main window width changed ?
static int s_iWinFormerWidth = -1;
if (s_iWinFormerWidth != s_WinCurrentWidth) {
*bIsUpdNeeded = true;
s_iWinFormerWidth = s_WinCurrentWidth;
}
if (!(*bIsUpdNeeded)) {
return;
}
// count fixed and dynamic optimized pixels
int pxCount = 0;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (g_iStatusbarVisible[i]) {
if (g_iStatusbarWidthSpec[i] == 0) { // dynamic optimized
SIZE const size = _StatusCalcTextSize(Globals.hwndStatus, tchStatusBar[i]);
vSectionWidth[i] = (size.cx + 8L);
} else if (g_iStatusbarWidthSpec[i] < -1) { // fixed pixel count
vSectionWidth[i] = -(g_iStatusbarWidthSpec[i]);
}
//else { /* 0,-1 : relative counts */ }
// accumulate
if (vSectionWidth[i] > 0) {
pxCount += vSectionWidth[i];
}
}
}
int const iPropSectTotalWidth = s_WinCurrentWidth - pxCount - STAUSBAR_RIGHT_MARGIN;
// init proportional section checker
bool bIsPropSection[STATUS_SECTOR_COUNT] = SBS_INIT_ZERO;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if ((g_iStatusbarVisible[i]) && (vSectionWidth[i] < 0)) {
assert(g_iStatusbarWidthSpec[i] > 0);
bIsPropSection[i] = true;
}
}
// get min. required widths
int vMinWidth[STATUS_SECTOR_COUNT] = SBS_INIT_ZERO;
int iTotalMinWidth = 0;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (bIsPropSection[i]) {
SIZE const size = _StatusCalcTextSize(Globals.hwndStatus, tchStatusBar[i]);
int const iMinWidth = (size.cx + 8L);
vMinWidth[i] = iMinWidth;
iTotalMinWidth += iMinWidth;
}
}
if (iTotalMinWidth >= iPropSectTotalWidth) {
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (bIsPropSection[i]) {
vSectionWidth[i] = vMinWidth[i];
}
}
} else { // space left for proportional elements
int vPropWidth[STATUS_SECTOR_COUNT] = SBS_INIT_ZERO;
int totalCnt = 0;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (bIsPropSection[i]) {
vPropWidth[i] = iPropSectTotalWidth * g_iStatusbarWidthSpec[i];
totalCnt += g_iStatusbarWidthSpec[i];
}
}
// normalize
int const iCeilFloor = (totalCnt + 1) / 2;
//int iTotalPropWidth = 0;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (bIsPropSection[i]) {
int const width = (totalCnt > 1) ? ((vPropWidth[i] + iCeilFloor) / totalCnt) : 0;
vPropWidth[i] = width;
//iTotalPropWidth += width;
}
}
// check for fitting
int iOverlappingText = 0;
int iOvlTxtCount = 0;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (bIsPropSection[i]) {
if (vMinWidth[i] > vPropWidth[i]) {
iOverlappingText += (vMinWidth[i] - vPropWidth[i]);
++iOvlTxtCount;
}
}
}
if (iOvlTxtCount == 0) {
// we are fine
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (bIsPropSection[i]) {
vSectionWidth[i] = vPropWidth[i];
}
}
} else { // handling overlaps
while (iOverlappingText > 0) {
const int iNoProgress = iOverlappingText;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (bIsPropSection[i]) {
if (vMinWidth[i] < vPropWidth[i]) {
vPropWidth[i] -= 1;
--iOverlappingText;
} else if (vMinWidth[i] > vPropWidth[i]) {
vPropWidth[i] = vMinWidth[i];
}
}
if (iOverlappingText == 0) {
break; /* for */
}
}
if ((iOverlappingText == 0) || (iNoProgress == iOverlappingText)) {
break;
}
}
// fill missing widths
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
if (bIsPropSection[i]) {
vSectionWidth[i] = vPropWidth[i];
}
}
}
}
}
//=============================================================================
//
// _InterpMultiSelectionTinyExpr()
//
//
static double _InterpMultiSelectionTinyExpr(te_int_t* piExprError)
{
#define _tmpBufCnt 128
char tmpRectSelN[_tmpBufCnt] = { '\0' };
DocPosU const selCount = SciCall_GetSelections();
int const calcBufSize = (int)(_tmpBufCnt * selCount + 1);
char * const calcBuffer = (char*)AllocMem(calcBufSize, HEAP_ZERO_MEMORY);
WCHAR * const calcBufferW = (WCHAR*)AllocMem(calcBufSize * sizeof(WCHAR), HEAP_ZERO_MEMORY);
bool bLastCharWasDigit = false;
for (DocPosU i = 0; i < selCount; ++i) {
DocPos const posSelStart = SciCall_GetSelectionNStart(i);
DocPos const posSelEnd = SciCall_GetSelectionNEnd(i);
size_t const cchToCopy = (size_t)(posSelEnd - posSelStart);
StringCchCopyNA(tmpRectSelN, _tmpBufCnt, SciCall_GetRangePointer(posSelStart, (DocPos)cchToCopy), cchToCopy);
StrTrimA(tmpRectSelN, " ");
char const defchar = (char)0x24;
MultiByteToWideChar(Encoding_SciCP, 0, calcBuffer, -1, calcBufferW, calcBufSize);
WideCharToMultiByte(1252, (WC_COMPOSITECHECK | WC_DISCARDNS), calcBufferW, -1, calcBuffer, calcBufSize, &defchar, NULL);
StrDelChrA(calcBuffer, chr_currency);
if (!StrIsEmptyA(tmpRectSelN)) {
if (IsDigitA(tmpRectSelN[0]) && bLastCharWasDigit) {
StringCchCatA(calcBuffer, SizeOfMem(calcBuffer), "+"); // default: add numbers
}
bLastCharWasDigit = IsDigitA(tmpRectSelN[StringCchLenA(tmpRectSelN,COUNTOF(tmpRectSelN)) - 1]);
StringCchCatA(calcBuffer, SizeOfMem(calcBuffer), tmpRectSelN);
}
}
double const result = te_interp(calcBuffer, piExprError);
FreeMem(calcBufferW);
FreeMem(calcBuffer);
return result;
}
//=============================================================================
//
// UpdateStatusbar()
//
//
void UpdateStatusbar(const bool bForceRedraw)
{
_DelayUpdateStatusbar(_MQ_FAST, bForceRedraw);
}
//=============================================================================
const static WCHAR *const FR_StatusW[] = { L"[>--<]", L"[>>--]", L"[>>-+]", L"[+->]>", L"[--<<]", L"[+-<<]", L"<[<-+]" };
static void _UpdateStatusbarDelayed(bool bForceRedraw)
{
if (!Settings.ShowStatusbar) {
return;
}
static sectionTxt_t tchStatusBar[STATUS_SECTOR_COUNT] = { L'\0' };
// ------------------------------------------------------
// common calculations
// ------------------------------------------------------
DocPos const iPos = SciCall_GetCurrentPos();
DocLn const iLnFromPos = SciCall_LineFromPosition(iPos);
DocPos const iLineBegin = SciCall_PositionFromLine(iLnFromPos);
DocPos const iLineBack = SciCall_GetLineEndPosition(iLnFromPos);
DocPos const iSelStart = SciCall_GetSelectionStart();
DocPos const iSelEnd = SciCall_GetSelectionEnd();
bool const bIsSelectionEmpty = SciCall_IsSelectionEmpty();
bool const bIsMultiSelection = Sci_IsMultiOrRectangleSelection();
bool const bIsSelCharCountable = !bIsSelectionEmpty && !bIsMultiSelection;
bool const bIsWindowFindReplace = IsWindow(Globals.hwndDlgFindReplace);
bool bIsUpdateNeeded = bForceRedraw;
static WCHAR tchLn[32] = { L'\0' };
static WCHAR tchLines[32] = { L'\0' };
// ------------------------------------------------------
if (g_iStatusbarVisible[STATUS_DOCLINE] || bIsWindowFindReplace) {
static DocLn s_iLnFromPos = -1;
static DocLn s_iLnCnt = -1;
if (bForceRedraw || (s_iLnFromPos != iLnFromPos)) {
StringCchPrintf(tchLn, COUNTOF(tchLn), DOCPOSFMTW, iLnFromPos + 1);
FormatNumberStr(tchLn, COUNTOF(tchLn), 0);
}
DocLn const iLnCnt = SciCall_GetLineCount();
if (bForceRedraw || (s_iLnCnt != iLnCnt)) {
StringCchPrintf(tchLines, COUNTOF(tchLines), DOCPOSFMTW, iLnCnt);
FormatNumberStr(tchLines, COUNTOF(tchLines), 0);
}
if (bForceRedraw || ((s_iLnFromPos != iLnFromPos) || (s_iLnCnt != iLnCnt))) {
StringCchPrintf(tchStatusBar[STATUS_DOCLINE], txtWidth, L"%s%s / %s%s",
g_mxSBPrefix[STATUS_DOCLINE], tchLn, tchLines, g_mxSBPostfix[STATUS_DOCLINE]);
s_iLnFromPos = iLnFromPos;
s_iLnCnt = iLnCnt;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
static WCHAR tchCol[32] = { L'\0' };
if (g_iStatusbarVisible[STATUS_DOCCOLUMN] || bIsWindowFindReplace) {
DocPos const colOffset = Globals.bZeroBasedColumnIndex ? 0 : 1;
static DocPos s_iCol = -1;
DocPos const iCol = SciCall_GetColumn(iPos) + SciCall_GetSelectionNCaretVirtualSpace(0);
if (bForceRedraw || (s_iCol != iCol)) {
StringCchPrintf(tchCol, COUNTOF(tchCol), DOCPOSFMTW, iCol + colOffset);
FormatNumberStr(tchCol, COUNTOF(tchCol), 0);
}
static DocPos s_iCols = -1;
static WCHAR tchCols[32] = { L'\0' };
DocPos const iCols = SciCall_GetColumn(iLineBack);
if (bForceRedraw || (s_iCols != iCols)) {
StringCchPrintf(tchCols, COUNTOF(tchCols), DOCPOSFMTW, iCols);
FormatNumberStr(tchCols, COUNTOF(tchCols), 0);
}
if (bForceRedraw || ((s_iCol != iCol) || (s_iCols != iCols))) {
StringCchPrintf(tchStatusBar[STATUS_DOCCOLUMN], txtWidth, L"%s%s / %s%s",
g_mxSBPrefix[STATUS_DOCCOLUMN], tchCol, tchCols, g_mxSBPostfix[STATUS_DOCCOLUMN]);
s_iCol = iCol;
s_iCols = iCols;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
if (g_iStatusbarVisible[STATUS_DOCCHAR]) {
static WCHAR tchChr[32] = { L'\0' };
static WCHAR tchChrs[32] = { L'\0' };
static DocPos s_iChr = -1;
DocPos const chrOffset = Globals.bZeroBasedCharacterCount ? 0 : 1;
DocPos const iChr = SciCall_CountCharacters(iLineBegin, iPos);
if (bForceRedraw || (s_iChr != iChr)) {
StringCchPrintf(tchChr, COUNTOF(tchChr), DOCPOSFMTW, iChr + chrOffset);
FormatNumberStr(tchChr, COUNTOF(tchChr), 0);
}
static DocPos s_iChrs = -1;
DocPos const iChrs = SciCall_CountCharacters(iLineBegin, iLineBack);
if (bForceRedraw || (s_iChrs != iChrs)) {
StringCchPrintf(tchChrs, COUNTOF(tchChrs), DOCPOSFMTW, iChrs);
FormatNumberStr(tchChrs, COUNTOF(tchChrs), 0);
}
if ((s_iChr != iChr) || (s_iChrs != iChrs)) {
StringCchPrintf(tchStatusBar[STATUS_DOCCHAR], txtWidth, L"%s%s / %s%s",
g_mxSBPrefix[STATUS_DOCCHAR], tchChr, tchChrs, g_mxSBPostfix[STATUS_DOCCHAR]);
s_iChr = iChr;
s_iChrs = iChrs;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
if (g_iStatusbarVisible[STATUS_UNICODEPT]) {
static WCHAR tchChr[32] = { L'\0' };
static UINT64 s_wChr = L'\0';
static int const len = sizeof(UINT64) / sizeof(WCHAR);
DocPos const iPosAfter = SciCall_PositionAfter(iPos);
int const chrLen = (int)(iPosAfter - iPos);
char chChrs[8] = { '\0' };
struct Sci_TextRangeFull tr = { { iPos, iPosAfter }, chChrs };
SciCall_GetTextRangeFull(&tr);
UINT64 wChr = L'\0';
MultiByteToWideChar(Encoding_SciCP, 0, chChrs, chrLen, (LPWSTR)&wChr, len);
if (bForceRedraw || (s_wChr != wChr)) {
if (wChr <= 0x7F)
StringCchPrintf(tchChr, COUNTOF(tchChr), L"0x%.4X (ASC:%i)", LOWORD(wChr), LOWORD(wChr));
else if (wChr <= 0xFFFF)
StringCchPrintf(tchChr, COUNTOF(tchChr), L"0x%.4X (DEC:%i)", LOWORD(wChr), LOWORD(wChr));
else
StringCchPrintf(tchChr, COUNTOF(tchChr), L"0x%.4X 0x%.4X", LOWORD(wChr), HIWORD(wChr));
}
if (s_wChr != wChr) {
StringCchPrintf(tchStatusBar[STATUS_UNICODEPT], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_UNICODEPT], tchChr, g_mxSBPostfix[STATUS_UNICODEPT]);
s_wChr = wChr;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
static WCHAR tchSel[32] = { L'\0' };
// number of selected chars in statusbar
if (g_iStatusbarVisible[STATUS_SELECTION] || g_iStatusbarVisible[STATUS_SELCTBYTES] || bIsWindowFindReplace) {
static bool s_bIsSelCountable = false;
static bool s_bIsMultiSelection = false;
static DocPos s_iSelStart = -1;
static DocPos s_iSelEnd = -1;
if (bForceRedraw || ((s_bIsSelCountable != bIsSelCharCountable) || (s_iSelStart != iSelStart)
|| (s_iSelEnd != iSelEnd)) || (s_bIsMultiSelection != bIsMultiSelection)) {
static WCHAR tchSelB[64] = { L'\0' };
if (bIsSelCharCountable) {
DocPos const iSel = Flags.bHugeFileLoadState ? (iSelEnd - iSelStart) : SciCall_CountCharacters(iSelStart, iSelEnd);
StringCchPrintf(tchSel, COUNTOF(tchSel), DOCPOSFMTW, iSel);
FormatNumberStr(tchSel, COUNTOF(tchSel), 0);
StrFormatByteSizeEx((ULONGLONG)(iSelEnd - iSelStart), SFBS_FLAGS_ROUND_TO_NEAREST_DISPLAYED_DIGIT, tchSelB, COUNTOF(tchSelB));
} else if (bIsMultiSelection) {
StringCchPrintf(tchSel, COUNTOF(tchSel), L"# " DOCPOSFMTW, SciCall_GetSelections());
tchSelB[0] = L'0';
tchSelB[1] = L'\0';
} else {
tchSel[0] = L'-';
tchSel[1] = L'-';
tchSel[2] = L'\0';
tchSelB[0] = L'0';
tchSelB[1] = L'\0';
}
if (Flags.bHugeFileLoadState) {
StringCchPrintf(tchStatusBar[STATUS_SELECTION], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_SELCTBYTES], tchSel, g_mxSBPostfix[STATUS_SELCTBYTES]);
} else {
StringCchPrintf(tchStatusBar[STATUS_SELECTION], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_SELECTION], tchSel, g_mxSBPostfix[STATUS_SELECTION]);
}
StringCchPrintf(tchStatusBar[STATUS_SELCTBYTES], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_SELCTBYTES], tchSelB, g_mxSBPostfix[STATUS_SELCTBYTES]);
s_bIsSelCountable = bIsSelCharCountable;
s_bIsMultiSelection = bIsMultiSelection;
s_iSelStart = iSelStart;
s_iSelEnd = iSelEnd;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
// number of selected lines in statusbar
if (g_iStatusbarVisible[STATUS_SELCTLINES]) {
static bool s_bIsSelectionEmpty = true;
static DocLn s_iLinesSelected = -1;
DocLn const iLineStart = SciCall_LineFromPosition(iSelStart);
DocLn const iLineEnd = SciCall_LineFromPosition(iSelEnd);
DocPos const iStartOfLinePos = SciCall_PositionFromLine(iLineEnd);
DocLn const iLinesSelected = ((iSelStart != iSelEnd) && (iStartOfLinePos != iSelEnd)) ? ((iLineEnd - iLineStart) + 1) : (iLineEnd - iLineStart);
if (bForceRedraw || ((s_bIsSelectionEmpty != bIsSelectionEmpty) || (s_iLinesSelected != iLinesSelected))) {
static bool s_bIsMultiSelection = false;
static WCHAR tchLinesSelected[32] = { L'\0' };
if (bIsSelectionEmpty || bIsMultiSelection) {
tchLinesSelected[0] = L'-';
tchLinesSelected[1] = L'-';
tchLinesSelected[2] = L'\0';
} else {
StringCchPrintf(tchLinesSelected, COUNTOF(tchLinesSelected), DOCPOSFMTW, iLinesSelected);
FormatNumberStr(tchLinesSelected, COUNTOF(tchLinesSelected), 0);
}
StringCchPrintf(tchStatusBar[STATUS_SELCTLINES], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_SELCTLINES], tchLinesSelected, g_mxSBPostfix[STATUS_SELCTLINES]);
s_bIsSelectionEmpty = bIsSelectionEmpty;
s_bIsMultiSelection = bIsMultiSelection;
s_iLinesSelected = iLinesSelected;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
// try calculate expression of selection
if (g_iStatusbarVisible[STATUS_TINYEXPR]) {
static WCHAR tchExpression[32] = { L'\0' };
static te_int_t s_iExErr = -3;
s_dExpression = 0.0;
tchExpression[0] = L'-';
tchExpression[1] = L'-';
tchExpression[2] = L'\0';
if (Settings.EvalTinyExprOnSelection) {
if (bIsSelCharCountable) {
static char chSeBuf[LARGE_BUFFER] = { '\0' };
static WCHAR wchSelBuf[LARGE_BUFFER] = { L'\0' };
DocPos const iSelLen = SciCall_GetSelText(NULL);
if (iSelLen < COUNTOF(chSeBuf)) { // should be fast !
SciCall_GetSelText(chSeBuf);
//~StrDelChrA(chExpression, " \r\n\t\v");
StrDelChrA(chSeBuf, "\r\n");
StrTrimA(chSeBuf, "= ?");
char const defchar = (char)0x24;
MultiByteToWideChar(Encoding_SciCP, 0, chSeBuf, -1, wchSelBuf, LARGE_BUFFER);
WideCharToMultiByte(1252, (WC_COMPOSITECHECK | WC_DISCARDNS), wchSelBuf, -1, chSeBuf, LARGE_BUFFER, &defchar, NULL);
StrDelChrA(chSeBuf, chr_currency);
s_dExpression = te_interp(chSeBuf, &s_iExprError);
} else {
s_iExprError = -1;
}
} else if (Sci_IsMultiOrRectangleSelection() && !bIsSelectionEmpty) {
s_dExpression = _InterpMultiSelectionTinyExpr(&s_iExprError);
} else {
s_iExprError = -2;
}
} else {
s_iExprError = -3;
}
if (!s_iExprError) {
TinyExprToString(tchExpression, COUNTOF(tchExpression), s_dExpression);
} else if (s_iExprError > 0) {
StringCchPrintf(tchExpression, COUNTOF(tchExpression), L"^[" _W(TE_INT_FMT) L"]", s_iExprError);
}
if (bForceRedraw || (!s_iExprError || (s_iExErr != s_iExprError))) {
StringCchPrintf(tchStatusBar[STATUS_TINYEXPR], txtWidth, L"%s%s%s ",
g_mxSBPrefix[STATUS_TINYEXPR], tchExpression, g_mxSBPostfix[STATUS_TINYEXPR]);
s_iExErr = s_iExprError;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
static WCHAR tchOccOf[50] = { L'\0' };
static WCHAR tchOcc2[24] = { L'\0' };
// number of occurrence marks found
if (g_iStatusbarVisible[STATUS_OCCURRENCE] || bIsWindowFindReplace) {
static DocPosU s_iSeletionMarkNumber = 0;
static DocPosU s_iMarkOccurrencesCount = 0;
static bool s_bMOVisible = false;
if (bForceRedraw || ((s_bMOVisible != Settings.MarkOccurrencesMatchVisible) ||
(s_iSeletionMarkNumber != Globals.iSelectionMarkNumber) ||
(s_iMarkOccurrencesCount != Globals.iMarkOccurrencesCount))) {
if (Globals.iMarkOccurrencesCount) {
StringCchPrintf(tchOccOf, COUNTOF(tchOccOf), DOCPOSFMTW, Globals.iSelectionMarkNumber);
FormatNumberStr(tchOccOf, COUNTOF(tchOccOf), 0);
StringCchPrintf(tchOcc2, COUNTOF(tchOcc2), DOCPOSFMTW, Globals.iMarkOccurrencesCount);
FormatNumberStr(tchOcc2, COUNTOF(tchOcc2), 0);
StringCchCat(tchOccOf, COUNTOF(tchOccOf), L"/");
StringCchCat(tchOccOf, COUNTOF(tchOccOf), tchOcc2);
} else {
StringCchCopy(tchOccOf, COUNTOF(tchOccOf), L"-/-");
}
if (Settings.MarkOccurrencesMatchVisible) {
StringCchCat(tchOccOf, COUNTOF(tchOccOf), L"(V)");
}
StringCchPrintf(tchStatusBar[STATUS_OCCURRENCE], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_OCCURRENCE], tchOccOf, g_mxSBPostfix[STATUS_OCCURRENCE]);
s_bMOVisible = Settings.MarkOccurrencesMatchVisible;
s_iSeletionMarkNumber = Globals.iSelectionMarkNumber;
s_iMarkOccurrencesCount = Globals.iMarkOccurrencesCount;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
// number of replaced pattern
if (g_iStatusbarVisible[STATUS_OCCREPLACE] || bIsWindowFindReplace) {
static DocPosU s_iReplacedOccurrences = 0;
if (bForceRedraw || (s_iReplacedOccurrences != Globals.iReplacedOccurrences)) {
static WCHAR tchRepl[64] = { L'\0' };
if (Globals.iReplacedOccurrences) {
StringCchPrintf(tchRepl, COUNTOF(tchRepl), DOCPOSFMTW, Globals.iReplacedOccurrences);
FormatNumberStr(tchRepl, COUNTOF(tchRepl), 0);
} else {
StringCchCopy(tchRepl, COUNTOF(tchRepl), L"--");
}
StringCchPrintf(tchStatusBar[STATUS_OCCREPLACE], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_OCCREPLACE], tchRepl, g_mxSBPostfix[STATUS_OCCREPLACE]);
s_iReplacedOccurrences = Globals.iReplacedOccurrences;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
// get number of bytes in current encoding
if (g_iStatusbarVisible[STATUS_DOCSIZE]) {
static DocPos s_iTextLength = -1;
DocPos const iTextLength = SciCall_GetTextLength();
if (bForceRedraw || (s_iTextLength != iTextLength)) {
static WCHAR tchBytes[32] = { L'\0' };
StrFormatByteSizeEx((ULONGLONG)iTextLength, SFBS_FLAGS_ROUND_TO_NEAREST_DISPLAYED_DIGIT, tchBytes, COUNTOF(tchBytes));
StringCchPrintf(tchStatusBar[STATUS_DOCSIZE], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_DOCSIZE], tchBytes, g_mxSBPostfix[STATUS_DOCSIZE]);
s_iTextLength = iTextLength;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
if (g_iStatusbarVisible[STATUS_CODEPAGE]) {
static cpi_enc_t s_iEncoding = CPI_NONE;
cpi_enc_t const iEncoding = Encoding_GetCurrent();
if (bForceRedraw || (s_iEncoding != iEncoding)) {
StringCchPrintf(tchStatusBar[STATUS_CODEPAGE], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_CODEPAGE], Encoding_GetLabel(iEncoding), g_mxSBPostfix[STATUS_CODEPAGE]);
s_iEncoding = iEncoding;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
const WCHAR* const _LF_f = L"%sLF%s";
const WCHAR* const _LFi_f = L"%sLF*%s";
const WCHAR* const _CR_f = L"%sCR%s";
const WCHAR* const _CRi_f = L"%sCR*%s";
const WCHAR* const _CRLF_f = L"%sCR+LF%s";
const WCHAR* const _CRLFi_f = L"%sCR+LF*%s";
if (g_iStatusbarVisible[STATUS_EOLMODE]) {
static int s_iEOLMode = -1;
int const eol_mode = SciCall_GetEOLMode();
if (bForceRedraw || (s_iEOLMode != eol_mode)) {
static WCHAR tchEOL[16] = { L'\0' };
if (eol_mode == SC_EOL_LF) {
StringCchPrintf(tchStatusBar[STATUS_EOLMODE], txtWidth, (Globals.bDocHasInconsistentEOLs ? _LFi_f : _LF_f),
g_mxSBPrefix[STATUS_EOLMODE], g_mxSBPostfix[STATUS_EOLMODE]);
} else if (eol_mode == SC_EOL_CR) {
StringCchPrintf(tchStatusBar[STATUS_EOLMODE], txtWidth, (Globals.bDocHasInconsistentEOLs ? _CRi_f : _CR_f),
g_mxSBPrefix[STATUS_EOLMODE], g_mxSBPostfix[STATUS_EOLMODE]);
} else {
StringCchPrintf(tchStatusBar[STATUS_EOLMODE], txtWidth, (Globals.bDocHasInconsistentEOLs ? _CRLFi_f : _CRLF_f),
g_mxSBPrefix[STATUS_EOLMODE], g_mxSBPostfix[STATUS_EOLMODE]);
}
s_iEOLMode = eol_mode;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
if (g_iStatusbarVisible[STATUS_OVRMODE]) {
static bool s_bIsOVR = -1;
bool const bIsOVR = SciCall_GetOverType();
if (bForceRedraw || (s_bIsOVR != bIsOVR)) {
if (bIsOVR) {
StringCchPrintf(tchStatusBar[STATUS_OVRMODE], txtWidth, L"%sOVR%s",
g_mxSBPrefix[STATUS_OVRMODE], g_mxSBPostfix[STATUS_OVRMODE]);
} else {
StringCchPrintf(tchStatusBar[STATUS_OVRMODE], txtWidth, L"%sINS%s",
g_mxSBPrefix[STATUS_OVRMODE], g_mxSBPostfix[STATUS_OVRMODE]);
}
s_bIsOVR = bIsOVR;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
if (g_iStatusbarVisible[STATUS_2ND_DEF]) {
static bool s_bUse2ndDefault = true;
bool const bUse2ndDefault = Style_GetUse2ndDefault();
if (bForceRedraw || (s_bUse2ndDefault != bUse2ndDefault)) {
if (bUse2ndDefault)
StringCchPrintf(tchStatusBar[STATUS_2ND_DEF], txtWidth, L"%s2ND%s",
g_mxSBPrefix[STATUS_2ND_DEF], g_mxSBPostfix[STATUS_2ND_DEF]);
else
StringCchPrintf(tchStatusBar[STATUS_2ND_DEF], txtWidth, L"%sSTD%s",
g_mxSBPrefix[STATUS_2ND_DEF], g_mxSBPostfix[STATUS_2ND_DEF]);
s_bUse2ndDefault = bUse2ndDefault;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
if (g_iStatusbarVisible[STATUS_LEXER]) {
static int s_iCurLexer = -1;
int const iCurLexer = Style_GetCurrentLexerRID();
if (bForceRedraw || (s_iCurLexer != iCurLexer)) {
static WCHAR tchLexerName[MINI_BUFFER];
if (Style_IsCurLexerStandard()) {
Style_GetLexerDisplayName(NULL, tchLexerName, MINI_BUFFER); // don't distinguish between STD/2ND
} else {
Style_GetLexerDisplayName(Style_GetCurrentLexerPtr(), tchLexerName, MINI_BUFFER);
}
StringCchPrintf(tchStatusBar[STATUS_LEXER], txtWidth, L"%s%s%s",
g_mxSBPrefix[STATUS_LEXER], tchLexerName, g_mxSBPostfix[STATUS_LEXER]);
s_iCurLexer = iCurLexer;
bIsUpdateNeeded = true;
}
}
// ------------------------------------------------------
// ==== Statusbar widths ====
int g_vStatusbarSectionWidth[STATUS_SECTOR_COUNT] = SBS_INIT_MINUS;
_CalculateStatusbarSections(g_vStatusbarSectionWidth, tchStatusBar, &bIsUpdateNeeded);
if (bIsUpdateNeeded) {
int aStatusbarSections[STATUS_SECTOR_COUNT] = SBS_INIT_ZERO;
BYTE cnt = 0;
int totalWidth = 0;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
int const id = g_vSBSOrder[i];
if ((id >= 0) && (g_vStatusbarSectionWidth[id] >= 0)) {
totalWidth += g_vStatusbarSectionWidth[id];
aStatusbarSections[cnt++] = totalWidth;
}
}
if (cnt > 0) {
aStatusbarSections[cnt - 1] = -1; // expand to right edge
} else {
aStatusbarSections[0] = -1;
Settings.ShowStatusbar = false;
}
SendMessage(Globals.hwndStatus, WM_SETREDRAW, FALSE, 0);
SIZE const size = _StatusCalcTextSize(Globals.hwndStatus, L"X");
SendMessage(Globals.hwndStatus, SB_SETMINHEIGHT, MAKEWPARAM(size.cy + 2, 0), 0);
SendMessage(Globals.hwndStatus, SB_SETPARTS, (WPARAM)cnt, (LPARAM)aStatusbarSections);
cnt = 0;
for (int i = 0; i < STATUS_SECTOR_COUNT; ++i) {
int const id = g_vSBSOrder[i];
if ((id >= 0) && (g_vStatusbarSectionWidth[id] >= 0)) {
StatusSetText(Globals.hwndStatus, cnt++, tchStatusBar[id]);
}
}
SendMessage(Globals.hwndStatus, WM_SETREDRAW, TRUE, 0);
InvalidateRect(Globals.hwndStatus, NULL, TRUE);
//PostMessage(Globals.hwndStatus, WM_SIZE, 0, 0);
}
// --------------------------------------------------------------------------
// update Find/Replace dialog (if any)
if (bIsWindowFindReplace) {
static WCHAR tchReplOccs[64] = { L'\0' };
if (Globals.iReplacedOccurrences) {
StringCchPrintf(tchReplOccs, COUNTOF(tchReplOccs), DOCPOSFMTW, Globals.iReplacedOccurrences);
FormatNumberStr(tchReplOccs, COUNTOF(tchReplOccs), 0);
}
else {
StringCchCopy(tchReplOccs, COUNTOF(tchReplOccs), L"--");
}
const WCHAR* const SBFMT = L" %s%s / %s %s%s %s%s %s%s %s%s ( %s ) ";
static WCHAR tchFRStatus[128] = { L'\0' };
StringCchPrintf(tchFRStatus, COUNTOF(tchFRStatus), SBFMT,
g_mxSBPrefix[STATUS_DOCLINE], tchLn, tchLines,
g_mxSBPrefix[STATUS_DOCCOLUMN], tchCol,
g_mxSBPrefix[STATUS_SELECTION], tchSel,
g_mxSBPrefix[STATUS_OCCURRENCE], tchOccOf,
g_mxSBPrefix[STATUS_OCCREPLACE], tchReplOccs,
FR_StatusW[Globals.FindReplaceMatchFoundState]);
SetWindowText(GetDlgItem(Globals.hwndDlgFindReplace, IDS_FR_STATUS_TEXT), tchFRStatus);
}
}
//=============================================================================
//
// UpdateMargins()
//
//
void UpdateMargins(const bool bForce)
{
Style_UpdateAllMargins(Globals.hwndEdit, bForce);
}
//=============================================================================
//
// UpdateSaveSettingsCmds()
//
//
void UpdateSaveSettingsCmds()
{
bool const bSoftLocked = Flags.bSettingsFileSoftLocked;
bool const bHaveIniFile = Path_IsNotEmpty(Paths.IniFile);
bool const bHaveFallbackIniFile = Path_IsNotEmpty(Paths.IniFileDefault);
bool const bCurrFileLocked = (FileWatching.FileWatchingMode == FWM_EXCLUSIVELOCK);
bool const bCanSav = Globals.bCanSaveIniFile = !(bSoftLocked && bCurrFileLocked) && CanAccessPath(Paths.IniFile, GENERIC_WRITE);
HMENU const hmenu = Globals.hMainMenu;
CheckCmd(hmenu, IDM_SET_SAVESETTINGS, Settings.SaveSettings && !bSoftLocked);
EnableCmd(hmenu, IDM_SET_SAVESETTINGS, bCanSav && !bSoftLocked);
EnableCmd(hmenu, IDM_SET_SAVESETTINGSNOW, (bHaveIniFile || bHaveFallbackIniFile) && !bSoftLocked);
EnableCmd(hmenu, CMD_OPENINIFILE, bHaveIniFile && !bSoftLocked);
EnableCmd(hmenu, IDM_SET_REUSEWINDOW, bCanSav);
EnableCmd(hmenu, IDM_SET_SINGLEFILEINSTANCE, bCanSav);
EnableCmd(hmenu, IDM_VIEW_STICKYWINPOS, bCanSav);
EnableCmd(hmenu, CMD_SAVEASDEFWINPOS, bCanSav);
EnableCmd(hmenu, IDM_SET_NOSAVERECENT, bCanSav);
EnableCmd(hmenu, IDM_SET_NOPRESERVECARET, Settings.SaveRecentFiles && bCanSav);
EnableCmd(hmenu, IDM_SET_NOSAVEFINDREPL, bCanSav);
EnableCmd(hmenu, IDM_SET_AUTOLOAD_MRU_FILE, bCanSav);
DrawMenuBar(Globals.hwndMain);
}
//=============================================================================
//
// UndoRedoRecordingStart()
//
static void _UndoRedoRecordingStart()
{
_UndoRedoActionMap(URTok_NoTransaction, NULL); // clear
SciCall_SetUndoCollection(true);
SciCall_EmptyUndoBuffer();
SciCall_SetSavePoint();
SciCall_SetChangeHistory(Settings.ChangeHistoryMode);
UpdateMargins(true);
}
//=============================================================================
//
// UndoRedoRecordingStop()
//
static void _UndoRedoRecordingStop()
{
_UndoRedoActionMap(URTok_NoTransaction, NULL); // clear
SciCall_EmptyUndoBuffer();
SciCall_SetSavePoint();
SciCall_SetChangeHistory(SC_CHANGE_HISTORY_DISABLED);
SciCall_SetUndoCollection(false);
}
//=============================================================================
//
// UndoRedoReset()
//
void UndoRedoReset()
{
_UndoRedoRecordingStop();
_UndoRedoRecordingStart();
}
//=============================================================================
//
// _SaveUndoSelection()
//
static LONG _SaveUndoSelection()
{
static DocPosU _s_iSelection = 0LL; // index
UndoRedoSelection_t sel = INIT_UNDOREDOSEL; // = InitUndoRedoSelection(&sel);
CopyUndoRedoSelection(&sel, NULL); // utarray_new()
DocPosU const numOfSel = SciCall_GetSelections();
// each single selection of a multi-selection will call thid method
// we are only interested in the first call
if (0LL == _s_iSelection) {
_s_iSelection = numOfSel;
}
if ((numOfSel-1) != --_s_iSelection) {
return URTok_NoTransaction;
}
int const selMode = ((numOfSel > 1) && !SciCall_IsSelectionRectangle()) ? NP3_SEL_MULTI : SciCall_GetSelectionMode();
sel.selMode_undo = selMode;
switch (selMode) {
case NP3_SEL_MULTI: {
for (DocPosU i = 0; i < numOfSel; ++i) {
if (sel.anchorPos_undo && sel.curPos_undo) {
DocPos const anchorPos = SciCall_GetSelectionNAnchor(i);
utarray_push_back(sel.anchorPos_undo, &anchorPos);
DocPos const curPos = SciCall_GetSelectionNCaret(i);
utarray_push_back(sel.curPos_undo, &curPos);
}
if (!Settings2.DenyVirtualSpaceAccess && sel.anchorVS_undo && sel.curVS_undo) {
DocPos const anchorVS = SciCall_GetSelectionNAnchorVirtualSpace(i);
utarray_push_back(sel.anchorVS_undo, &anchorVS);
DocPos const curVS = SciCall_GetSelectionNCaretVirtualSpace(i);
utarray_push_back(sel.curVS_undo, &curVS);
}
}
}
break;
case SC_SEL_RECTANGLE:
case SC_SEL_THIN: {
DocPos const anchorPos = SciCall_GetRectangularSelectionAnchor();
utarray_push_back(sel.anchorPos_undo, &anchorPos);
DocPos const curPos = SciCall_GetRectangularSelectionCaret();
utarray_push_back(sel.curPos_undo, &curPos);
if (!Settings2.DenyVirtualSpaceAccess) {
DocPos const anchorVS = SciCall_GetRectangularSelectionAnchorVirtualSpace();
utarray_push_back(sel.anchorVS_undo, &anchorVS);
DocPos const curVS = SciCall_GetRectangularSelectionCaretVirtualSpace();
utarray_push_back(sel.curVS_undo, &curVS);
}
}
break;
case SC_SEL_LINES:
case SC_SEL_STREAM:
default: {
DocPos const anchorPos = SciCall_GetAnchor();
utarray_push_back(sel.anchorPos_undo, &anchorPos);
DocPos const curPos = SciCall_GetCurrentPos();
utarray_push_back(sel.curPos_undo, &curPos);
DocPos const dummy = (DocPos)-1;
utarray_push_back(sel.anchorVS_undo, &dummy);
utarray_push_back(sel.curVS_undo, &dummy);
}
break;
}
const UndoRedoSelection_t* pSel = &sel;
LONG const token = _UndoRedoActionMap(URTok_NoTransaction, &pSel);
DelUndoRedoSelection(&sel); // utarray_free()
_s_iSelection = 0; // reset
return token;
}
//=============================================================================
//
// _SaveRedoSelection()
//
//
static void _SaveRedoSelection(const LONG token, const bool bAddAction)
{
static DocPosU _s_iSelection = 0; // index
if (token <= URTok_NoTransaction) {
return;
}
UndoRedoSelection_t* pSel = NULL;
DocPosU const numOfSel = SciCall_GetSelections();
// each single selection of a multi-selection will call this method
// we are only interested in the last call
if (0 == _s_iSelection) {
_s_iSelection = numOfSel;
}
if (0 != --_s_iSelection) {
return;
}
if (bAddAction) {
if ((_UndoRedoActionMap(token, &pSel) >= URTok_TokenStart) && (pSel != NULL)) {
int const selMode = ((numOfSel > 1) && !SciCall_IsSelectionRectangle()) ? NP3_SEL_MULTI : SciCall_GetSelectionMode();
pSel->selMode_redo = selMode;
switch (selMode) {
case NP3_SEL_MULTI: {
for (DocPosU i = 0; i < numOfSel; ++i) {
DocPos const anchorPos = SciCall_GetSelectionNAnchor(i);
utarray_push_back(pSel->anchorPos_redo, &anchorPos);
DocPos const curPos = SciCall_GetSelectionNCaret(i);
utarray_push_back(pSel->curPos_redo, &curPos);
if (!Settings2.DenyVirtualSpaceAccess) {
DocPos const anchorVS = SciCall_GetSelectionNAnchorVirtualSpace(i);
utarray_push_back(pSel->anchorVS_redo, &anchorVS);
DocPos const curVS = SciCall_GetSelectionNCaretVirtualSpace(i);
utarray_push_back(pSel->curVS_redo, &curVS);
}
}
} break;
case SC_SEL_RECTANGLE:
case SC_SEL_THIN: {
DocPos const anchorPos = SciCall_GetRectangularSelectionAnchor();
utarray_push_back(pSel->anchorPos_redo, &anchorPos);
DocPos const curPos = SciCall_GetRectangularSelectionCaret();
utarray_push_back(pSel->curPos_redo, &curPos);
if (!Settings2.DenyVirtualSpaceAccess) {
DocPos const anchorVS = SciCall_GetRectangularSelectionAnchorVirtualSpace();
utarray_push_back(pSel->anchorVS_redo, &anchorVS);
DocPos const curVS = SciCall_GetRectangularSelectionCaretVirtualSpace();
utarray_push_back(pSel->curVS_redo, &curVS);
}
} break;
case SC_SEL_LINES:
case SC_SEL_STREAM:
default: {
DocPos const anchorPos = SciCall_GetAnchor();
utarray_push_back(pSel->anchorPos_redo, &anchorPos);
DocPos const curPos = SciCall_GetCurrentPos();
utarray_push_back(pSel->curPos_redo, &curPos);
//~DocPos const dummy = (DocPos)-1;
//~utarray_push_back(pSel->anchorVS_redo, &dummy);
//~utarray_push_back(pSel->curVS_redo, &dummy);
} break;
}
//~SciCall_AddUndoAction((int)token, UNDO_MAY_COALESCE);
SciCall_AddUndoAction((int)token, UNDO_NONE);
}
else {
_UndoRedoActionMap(token, NULL); // remove
}
}
}
//=============================================================================
//
// BeginUndoActionSelection()
//
LONG BeginUndoActionSelection()
{
if (SciCall_GetUndoCollection()) {
SciCall_BeginUndoAction();
++UndoRedoActionStackCount;
if (1 == UndoRedoActionStackCount) {
DisableDocChangeNotification();
}
return SciCall_IsSelectionEmpty() ? URTok_NoTransaction : _SaveUndoSelection();
}
return URTok_NoRecording;
}
//=============================================================================
//
// EndUndoActionSelection()
//
const char* const _assert_msg = "Broken UndoRedo-Transaction!";
//
void EndUndoActionSelection(const LONG token)
{
if (SciCall_GetUndoCollection()) {
if (token >= URTok_TokenStart) {
_SaveRedoSelection(token, SciCall_GetModify());
}
--UndoRedoActionStackCount;
SciCall_EndUndoAction();
if (0 == UndoRedoActionStackCount) {
EnableDocChangeNotification(EVM_Default);
}
assert(_assert_msg && (UndoRedoActionStackCount >= 0));
}
}
//=============================================================================
//
// _RestoreActionSelection()
//
static void _RestoreActionSelection(const LONG token, DoAction doAct)
{
if (_InUndoRedoTransaction()) {
assert("Wrong Transaction!" && 0);
return;
}
UndoRedoSelection_t* pSel = NULL;
if ((_UndoRedoActionMap(token, &pSel) >= URTok_TokenStart) && (pSel != NULL)) {
LimitNotifyEvents();
DocPos* pPosAnchor = (DocPos*)((UNDO == doAct) ? utarray_front(pSel->anchorPos_undo) : utarray_front(pSel->anchorPos_redo));
DocPos* pPosCur = (DocPos*)((UNDO == doAct) ? utarray_front(pSel->curPos_undo) : utarray_front(pSel->curPos_redo));
DocPos* pPosAnchorVS = (DocPos*)((UNDO == doAct) ? utarray_front(pSel->anchorVS_undo) : utarray_front(pSel->anchorVS_redo));
DocPos* pPosCurVS = (DocPos*)((UNDO == doAct) ? utarray_front(pSel->curVS_undo) : utarray_front(pSel->curVS_redo));
if (pPosAnchor && pPosCur) {
// Ensure that the first and last lines of a selection are always unfolded
// This needs to be done _before_ the SCI_SETSEL message
DocLn const anchorPosLine = SciCall_LineFromPosition((*pPosAnchor));
DocLn const currPosLine = SciCall_LineFromPosition((*pPosCur));
SciCall_EnsureVisible(anchorPosLine);
if (anchorPosLine != currPosLine) {
SciCall_EnsureVisible(currPosLine);
}
int const selectionMode = (UNDO == doAct) ? pSel->selMode_undo : pSel->selMode_redo;
SciCall_SetSelectionMode((selectionMode == NP3_SEL_MULTI) ? SC_SEL_STREAM : selectionMode);
switch (selectionMode) {
case NP3_SEL_MULTI: {
unsigned int i = 0;
DocPosU const selCount = (UNDO == doAct) ? utarray_len(pSel->anchorPos_undo) : utarray_len(pSel->anchorPos_redo);
DocPosU const selCountVS = (UNDO == doAct) ? utarray_len(pSel->anchorVS_undo) : utarray_len(pSel->anchorVS_redo);
SciCall_SetSelection(*pPosCur, *pPosAnchor);
if (pPosAnchorVS && pPosCurVS) {
SciCall_SetSelectionNAnchorVirtualSpace(0, *pPosAnchorVS);
SciCall_SetSelectionNCaretVirtualSpace(0, *pPosCurVS);
}
SciCall_Cancel(); // (!) else shift-key selection behavior is kept
++i;
while (i < selCount) {
pPosAnchor = (DocPos*)((UNDO == doAct) ? utarray_eltptr(pSel->anchorPos_undo, i) : utarray_eltptr(pSel->anchorPos_redo, i));
pPosCur = (DocPos*)((UNDO == doAct) ? utarray_eltptr(pSel->curPos_undo, i) : utarray_eltptr(pSel->curPos_redo, i));
if (pPosAnchor && pPosCur) {
SciCall_AddSelection(*pPosCur, *pPosAnchor);
if (i < selCountVS) {
pPosAnchorVS = (DocPos*)((UNDO == doAct) ? utarray_eltptr(pSel->anchorVS_undo, i) : utarray_eltptr(pSel->anchorVS_redo, i));
pPosCurVS = (DocPos*)((UNDO == doAct) ? utarray_eltptr(pSel->curVS_undo, i) : utarray_eltptr(pSel->curVS_redo, i));
if (pPosAnchorVS && pPosCurVS) {
SciCall_SetSelectionNAnchorVirtualSpace(i, *pPosAnchorVS);
SciCall_SetSelectionNCaretVirtualSpace(i, *pPosCurVS);
}
}
}
++i;
}
//~SciCall_SetMainSelection(0);
}
break;
case SC_SEL_RECTANGLE:
case SC_SEL_THIN:
SciCall_SetRectangularSelectionAnchor(*pPosAnchor);
SciCall_SetRectangularSelectionCaret(*pPosCur);
if (pPosAnchorVS && pPosCurVS) {
SciCall_SetRectangularSelectionAnchorVirtualSpace(*pPosAnchorVS);
SciCall_SetRectangularSelectionCaretVirtualSpace(*pPosCurVS);
}
SciCall_Cancel(); // (!) else shift-key selection behavior is kept
break;
case SC_SEL_LINES:
case SC_SEL_STREAM:
default:
if (pPosAnchor && pPosCur) {
SciCall_SetSelection(*pPosCur, *pPosAnchor);
}
SciCall_Cancel(); // (!) else shift-key selection behavior is kept
break;
}
}
if (pPosAnchor && pPosCur) {
SciCall_ScrollRange(*pPosAnchor, *pPosCur);
}
SciCall_ChooseCaretX();
RestoreNotifyEvents();
}
else {
assert("Invalid Token to Restore!" && 0);
}
}
#if 0
//=============================================================================
//
// _RestoreActionSelection()
//
//
static void _RestoreActionSelection(const LONG token, DoAction doAct)
{
if (_InUndoRedoTransaction()) {
assert("Wrong Transaction!" && 0);
return;
}
UndoRedoSelection_t* pSel = NULL;
if ((_UndoRedoActionMap(token, &pSel) >= URTok_TokenStart) && (pSel != NULL)) {
// we are inside undo/redo transaction, so do delayed PostMessage() instead of SendMessage()
DocPos* pPosAnchor = (DocPos*)((UNDO == doAct) ? utarray_front(pSel->anchorPos_undo) : utarray_front(pSel->anchorPos_redo));
DocPos* pPosCur = (DocPos*)((UNDO == doAct) ? utarray_front(pSel->curPos_undo) : utarray_front(pSel->curPos_redo));
DocPos* pPosAnchorVS = (DocPos*)((UNDO == doAct) ? utarray_front(pSel->anchorVS_undo) : utarray_front(pSel->anchorVS_redo));
DocPos* pPosCurVS = (DocPos*)((UNDO == doAct) ? utarray_front(pSel->curVS_undo) : utarray_front(pSel->curVS_redo));
if (pPosAnchor && pPosCur) {
// Ensure that the first and last lines of a selection are always unfolded
// This needs to be done _before_ the SCI_SETSEL message
DocLn const anchorPosLine = SciCall_LineFromPosition((*pPosAnchor));
DocLn const currPosLine = SciCall_LineFromPosition((*pPosCur));
SciCall_PostMsg(SCI_ENSUREVISIBLE, anchorPosLine, 0);
if (anchorPosLine != currPosLine) {
SciCall_PostMsg(SCI_ENSUREVISIBLE, currPosLine, 0);
}
int const selectionMode = (UNDO == doAct) ? pSel->selMode_undo : pSel->selMode_redo;
SciCall_PostMsg(SCI_SETSELECTIONMODE, (WPARAM)((selectionMode == NP3_SEL_MULTI) ? SC_SEL_STREAM : selectionMode), 0);
switch (selectionMode) {
case NP3_SEL_MULTI: {
unsigned int i = 0;
DocPosU const selCount = (UNDO == doAct) ? utarray_len(pSel->anchorPos_undo) : utarray_len(pSel->anchorPos_redo);
DocPosU const selCountVS = (UNDO == doAct) ? utarray_len(pSel->anchorVS_undo) : utarray_len(pSel->anchorVS_redo);
SciCall_PostMsg(SCI_SETSELECTION, (WPARAM)(*pPosCur), (LPARAM)(*pPosAnchor));
if (pPosAnchorVS && pPosCurVS) {
SciCall_PostMsg(SCI_SETSELECTIONNANCHORVIRTUALSPACE, (WPARAM)0, (LPARAM)(*pPosAnchorVS));
SciCall_PostMsg(SCI_SETSELECTIONNCARETVIRTUALSPACE, (WPARAM)0, (LPARAM)(*pPosCurVS));
}
SciCall_PostMsg(SCI_CANCEL, 0, 0); // (!) else shift-key selection behavior is kept
++i;
while (i < selCount) {
pPosAnchor = (DocPos*)((UNDO == doAct) ? utarray_eltptr(pSel->anchorPos_undo, i) : utarray_eltptr(pSel->anchorPos_redo, i));
pPosCur = (DocPos*)((UNDO == doAct) ? utarray_eltptr(pSel->curPos_undo, i) : utarray_eltptr(pSel->curPos_redo, i));
if (pPosAnchor && pPosCur) {
SciCall_PostMsg(SCI_ADDSELECTION, (WPARAM)(*pPosCur), (LPARAM)(*pPosAnchor));
if (i < selCountVS) {
pPosAnchorVS = (DocPos*)((UNDO == doAct) ? utarray_eltptr(pSel->anchorVS_undo, i) : utarray_eltptr(pSel->anchorVS_redo, i));
pPosCurVS = (DocPos*)((UNDO == doAct) ? utarray_eltptr(pSel->curVS_undo, i) : utarray_eltptr(pSel->curVS_redo, i));
if (pPosAnchorVS && pPosCurVS) {
SciCall_PostMsg(SCI_SETSELECTIONNANCHORVIRTUALSPACE, (WPARAM)i, (LPARAM)(*pPosAnchorVS));
SciCall_PostMsg(SCI_SETSELECTIONNCARETVIRTUALSPACE, (WPARAM)i, (LPARAM)(*pPosCurVS));
}
}
}
++i;
}
//~SciCall_PostMsg(SCI_SETMAINSELECTION, (WPARAM)0, (LPARAM)0);
}
break;
case SC_SEL_RECTANGLE:
case SC_SEL_THIN:
SciCall_PostMsg(SCI_SETRECTANGULARSELECTIONANCHOR, (WPARAM)(*pPosAnchor), 0);
SciCall_PostMsg(SCI_SETRECTANGULARSELECTIONCARET, (WPARAM)(*pPosCur), 0);
if (pPosAnchorVS && pPosCurVS) {
SciCall_PostMsg(SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE, (WPARAM)(*pPosAnchorVS), 0);
SciCall_PostMsg(SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE, (WPARAM)(*pPosCurVS), 0);
}
SciCall_PostMsg(SCI_CANCEL, 0, 0); // (!) else shift-key selection behavior is kept
break;
case SC_SEL_LINES:
case SC_SEL_STREAM:
default:
if (pPosAnchor && pPosCur) {
SciCall_PostMsg(SCI_SETSELECTION, (WPARAM)(*pPosCur), (LPARAM)(*pPosAnchor));
}
SciCall_PostMsg(SCI_CANCEL, 0, 0); // (!) else shift-key selection behavior is kept
break;
}
}
if (pPosAnchor && pPosCur) {
SciCall_PostMsg(SCI_SCROLLRANGE, (WPARAM)(*pPosAnchor), (LPARAM)(*pPosCur));
}
SciCall_PostMsg(SCI_CHOOSECARETX, 0, 0);
}
else {
assert("Invalid Token to Restore!" && 0);
}
}
#endif
//=============================================================================
//
// _UndoRedoActionMap()
//
//
static LONG _UndoRedoActionMap(const LONG token, const UndoRedoSelection_t** selection)
{
static ULONG uiTokenCnt = URTok_TokenStart;
if (UndoRedoSelectionUTArray == NULL) {
return URTok_NoRecording;
};
if (selection == NULL) {
if (token <= URTok_NoTransaction) { // reset / clear
if (SciCall_GetUndoCollection()) {
while (UndoRedoActionStackCount > 0) {
SciCall_EndUndoAction();
--UndoRedoActionStackCount;
}
}
UndoRedoActionStackCount = 0;
utarray_clear(UndoRedoSelectionUTArray);
//~utarray_free(UndoRedoSelectionUTArray);
//~utarray_init(UndoRedoSelectionUTArray, &UndoRedoSelection_icd);
uiTokenCnt = URTok_TokenStart;
}
else { // remove token indexed action
utarray_erase(UndoRedoSelectionUTArray, (ULONG)token, 1);
if (((ULONG)token + 1UL) == uiTokenCnt) {
--uiTokenCnt;
}
else {
assert("Invalid index of item to remove!" && 0);
}
}
return URTok_NoTransaction;
}
// indexing is unsigned
ULONG utoken = (token >= URTok_TokenStart) ? (ULONG)token : 0UL;
if (!SciCall_GetUndoCollection()) {
assert("Inactive Undo Collection!" && 0);
return URTok_NoRecording;
}
// get or set map item request ?
if ((token >= URTok_TokenStart) && (utoken < uiTokenCnt)) {
if ((*selection) == NULL) {
// this is a get request
(*selection) = (UndoRedoSelection_t*)utarray_eltptr(UndoRedoSelectionUTArray, utoken);
} else {
// this is a set request (fill redo pos)
assert("Invalid set request (fill redo pos)!" && 0); // not used yet
//~utarray_insert(UndoRedoSelectionUTArray, (void*)(*selection), utoken);
}
// don't clear map item here (token used in redo/undo again)
}
else if (token <= URTok_NoTransaction) {
// set map new item request
LONG const newToken = (LONG)uiTokenCnt;
utarray_insert(UndoRedoSelectionUTArray, (void*)(*selection), uiTokenCnt);
uiTokenCnt = (uiTokenCnt < (ULONG)LONG_MAX) ? (uiTokenCnt + 1UL) : 0UL; // round robin next
return newToken;
}
else {
assert("Invalid Token to Set/Get!" && 0);
}
return token;
}
//=============================================================================
//
// FileIO()
//
//
bool FileIO(bool fLoad, const HPATHL hfile_pth, EditFileIOStatus* status,
FileLoadFlags fLoadFlags, FileSaveFlags fSaveFlags, bool bSetSavePoint)
{
bool bSuccess = false;
if (fLoad) {
bSuccess = EditLoadFile(Globals.hwndEdit, hfile_pth, status, fLoadFlags, bSetSavePoint);
SciCall_SetReadOnly(Settings.DocReadOnlyMode || FileWatching.MonitoringLog);
}
else {
int idx;
if (MRU_FindPath(Globals.pFileMRU, hfile_pth, &idx)) {
Globals.pFileMRU->iEncoding[idx] = status->iEncoding;
Globals.pFileMRU->iCaretPos[idx] = (Settings.PreserveCaretPos ? SciCall_GetCurrentPos() : -1);
Globals.pFileMRU->iSelAnchPos[idx] = (Settings.PreserveCaretPos ? SciCall_GetAnchor() : -1);
WCHAR wchBookMarks[MRU_BMRK_SIZE] = { L'\0' };
EditGetBookmarkList(Globals.hwndEdit, wchBookMarks, COUNTOF(wchBookMarks));
if (Globals.pFileMRU->pszBookMarks[idx]) {
LocalFree(Globals.pFileMRU->pszBookMarks[idx]); // StrDup()
Globals.pFileMRU->pszBookMarks[idx] = NULL;
}
Globals.pFileMRU->pszBookMarks[idx] = StrDup(wchBookMarks);
}
bSuccess = EditSaveFile(Globals.hwndEdit, hfile_pth, status, fSaveFlags, Flags.bPreserveFileModTime);
}
return bSuccess;
}
//=============================================================================
//
// ConsistentIndentationCheck()
//
//
bool ConsistentIndentationCheck(EditFileIOStatus* status)
{
bool const hasTabOrSpaceIndent = (status->indentCount[I_TAB_LN] > 0) && (status->indentCount[I_SPC_LN] > 0);
bool const hasMixedIndents = (status->indentCount[I_MIX_LN] > 0);
//bool const hasIrregularIndentDepth = (status->indentCount[I_TAB_MOD_X] > 0) || (status->indentCount[I_SPC_MOD_X] > 0);
if (hasTabOrSpaceIndent || hasMixedIndents /*|| hasIrregularIndentDepth */) {
if (WarnIndentationDlg(Globals.hwndMain, status)) {
bool const useTabs = SciCall_GetUseTabs();
SciCall_SetUseTabs(status->iGlobalIndent == I_TAB_LN);
bool const tabIndents = SciCall_GetTabIndents();
SciCall_SetTabIndents(true);
bool const backSpcUnindents = SciCall_GetBackSpaceUnIndents();
SciCall_SetBackSpaceUnIndents(true);
EditIndentBlock(Globals.hwndEdit, SCI_TAB, true, true);
EditIndentBlock(Globals.hwndEdit, SCI_BACKTAB, true, true);
SciCall_SetUseTabs(useTabs);
SciCall_SetTabIndents(tabIndents);
SciCall_SetBackSpaceUnIndents(backSpcUnindents);
Sci_GotoPosChooseCaret(0);
} else {
status->iGlobalIndent = I_MIX_LN;
return false;
}
}
return true;
}
//=============================================================================
//
// FileLoad()
//
//
static inline bool IsFileVarLogFile()
{
if (SciCall_GetTextLength() >= 4) {
char tch[5] = { '\0', '\0', '\0', '\0', '\0' };
SciCall_GetText(COUNTOF(tch) - 1, tch);
return (StrCmpA(tch, ".LOG") == 0);
}
return false;
}
static inline void _ResetFileWatchingMode() {
FileWatching.FileWatchingMode = (s_flagChangeNotify != FWM_NO_INIT) ? s_flagChangeNotify : Settings.FileWatchingMode;
if (FileWatching.MonitoringLog) {
FileWatching.FileWatchingMode = FWM_AUTORELOAD;
PostWMCommand(Globals.hwndMain, IDM_VIEW_CHASING_DOCTAIL);
}
ResetFileObservationData(true);
}
bool FileLoad(const HPATHL hfile_pth, const FileLoadFlags fLoadFlags)
{
bool fSuccess = false;
bool const bReloadFile = (fLoadFlags & FLF_Reload);
EditFileIOStatus fioStatus = INIT_FILEIO_STATUS;
fioStatus.iEOLMode = Settings.DefaultEOLMode;
fioStatus.iEncoding = Settings.DefaultEncoding;
if (!(fLoadFlags & FLF_DontSave)) {
if (!FileSave(FSF_Ask)) {
return false;
}
}
if (!bReloadFile) {
ResetEncryption();
}
if (fLoadFlags & FLF_New) {
if (FocusedView.HideNonMatchedLines) {
EditToggleView(Globals.hwndEdit);
}
if (!s_IsThisAnElevatedRelaunch) {
Flags.bPreserveFileModTime = DefaultFlags.bPreserveFileModTime;
}
Path_Empty(Paths.CurrentFile, false);
SetDlgItemText(Globals.hwndMain, IDC_FILENAME, Path_Get(Paths.CurrentFile));
SetDlgItemInt(Globals.hwndMain, IDC_REUSELOCK, (UINT)GetTicks_ms(), false);
if (!s_flagKeepTitleExcerpt) {
StringCchCopy(s_wchTitleExcerpt, COUNTOF(s_wchTitleExcerpt), L"");
}
FileVars_GetFromData(NULL, 0, &Globals.fvCurFile); // init-reset
EditSetNewText(Globals.hwndEdit, "", 0, false, false);
SciCall_SetEOLMode(Settings.DefaultEOLMode);
Encoding_Current(Settings.DefaultEncoding);
Style_SetDefaultLexer(Globals.hwndEdit);
SetSaveDone();
// Restart file watching
AutoSaveStop();
InstallFileWatching(false); // terminate old
if (Settings.ResetFileWatching) {
_ResetFileWatchingMode();
}
InstallFileWatching(true);
Flags.bSettingsFileSoftLocked = false;
UpdateSaveSettingsCmds();
UndoRedoReset();
UpdateToolbar();
UpdateMargins(true);
UpdateStatusbar(true);
if (SciCall_GetZoom() != 100) {
ShowZoomCallTip();
}
return true;
}
HPATHL hopen_file = Path_Copy(hfile_pth);
if (Path_IsEmpty(hopen_file)) {
if (!OpenFileDlg(Globals.hwndMain, hopen_file, hopen_file)) {
Path_Release(hopen_file);
return false;
}
}
else {
Path_Reset(hopen_file, Path_Get(hfile_pth));
}
Path_NormalizeEx(hopen_file, Paths.WorkingDirectory, true, Flags.bSearchPathIfRelative);
if (!bReloadFile && Path_StrgComparePathNormalized(hopen_file, Paths.CurrentFile) == 0) {
Path_Release(hopen_file);
return false;
}
if (!bReloadFile && Flags.bSingleFileInstance) {
Path_Reset(s_pthCheckFilePath, Path_Get(hopen_file));
HWND hwnd = NULL;
EnumWindows(_EnumWndProc2, (LPARAM)&hwnd);
if (hwnd != NULL) {
if (!s_bInitAppDone || IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONQUESTION, L"InfoInstanceExist", IDS_MUI_ASK_INSTANCE_EXISTS))) {
if (IsIconic(hwnd)) {
ShowWindowAsync(hwnd, SW_RESTORE);
}
if (!IsWindowVisible(hwnd)) {
SendMessage(hwnd, WM_TRAYMESSAGE, 0, WM_LBUTTONDBLCLK);
SendMessage(hwnd, WM_TRAYMESSAGE, 0, WM_LBUTTONUP);
}
SetForegroundWindow(hwnd);
}
Path_Release(hopen_file);
return false;
}
}
// Ask to create a new file...
if (!bReloadFile && !Path_IsExistingFile(hopen_file)) {
bool bCreateFile = s_flagQuietCreate;
if (!bCreateFile) {
WCHAR szDisplayName[MAX_PATH_EXPLICIT >> 1] = { L'\0' };
GetLngString(IDS_MUI_UNTITLED, szDisplayName, COUNTOF(szDisplayName));
Path_GetDisplayName(szDisplayName, COUNTOF(szDisplayName), hopen_file, NULL, false); //~Path_FindFileName(hopen_file)
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONQUESTION, NULL, IDS_MUI_ASK_CREATE, szDisplayName))) {
Path_CanonicalizeEx(hopen_file, Paths.WorkingDirectory);
bCreateFile = true;
}
}
if (bCreateFile) {
HANDLE hFile = CreateFileW(Path_Get(hopen_file),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
Globals.dwLastError = GetLastError();
fSuccess = IS_VALID_HANDLE(hFile);
if (fSuccess) {
FileVars_GetFromData(NULL, 0, &Globals.fvCurFile); // init/reset
EditSetNewText(Globals.hwndEdit, "", 0, false, false);
Style_SetDefaultLexer(Globals.hwndEdit);
SciCall_SetEOLMode(Settings.DefaultEOLMode);
if (Encoding_IsValid(Encoding_Forced(CPI_GET))) {
fioStatus.iEncoding = Encoding_Forced(CPI_GET);
Encoding_Current(fioStatus.iEncoding);
}
else {
fioStatus.iEncoding = Globals.fvCurFile.iEncoding;
Encoding_Current(Globals.fvCurFile.iEncoding);
}
}
if (IS_VALID_HANDLE(hFile)) {
CloseHandle(hFile);
}
}
else {
Path_Release(hopen_file);
return false;
}
}
else {
int idx;
if (!bReloadFile && MRU_FindPath(Globals.pFileMRU, hopen_file, &idx)) {
fioStatus.iEncoding = Globals.pFileMRU->iEncoding[idx];
if (Encoding_IsValid(fioStatus.iEncoding)) {
Encoding_SrcWeak(fioStatus.iEncoding);
}
}
else {
fioStatus.iEncoding = Encoding_GetCurrent();
}
fSuccess = FileIO(true, hopen_file, &fioStatus, fLoadFlags, FSF_None, !(bReloadFile || s_IsThisAnElevatedRelaunch));
}
bool bUnknownLexer = s_flagLexerSpecified;
if (fSuccess) {
// keep change-history on reload (!)
if (!bReloadFile) {
UndoRedoReset();
}
if (!s_IsThisAnElevatedRelaunch) {
Flags.bPreserveFileModTime = DefaultFlags.bPreserveFileModTime;
}
//~Path_Swap(Paths.CurrentFile, hopen_file); ~ hopen_file needed later
Path_Reset(Paths.CurrentFile, Path_Get(hopen_file)); // dup
SetDlgItemText(Globals.hwndMain, IDC_FILENAME, Path_Get(Paths.CurrentFile));
SetDlgItemInt(Globals.hwndMain, IDC_REUSELOCK, (UINT)GetTicks_ms(), false);
if (!s_flagKeepTitleExcerpt) {
StringCchCopy(s_wchTitleExcerpt, COUNTOF(s_wchTitleExcerpt), L"");
}
if (!s_flagLexerSpecified) { // flagLexerSpecified will be cleared
bUnknownLexer = !Style_SetLexerFromFile(Globals.hwndEdit, Paths.CurrentFile);
}
SciCall_SetEOLMode(fioStatus.iEOLMode);
Encoding_Current(fioStatus.iEncoding); // load may change encoding
int idx = 0;
DocPos iCaretPos = -1;
DocPos iAnchorPos = -1;
LPCWSTR pszBookMarks = L"";
if (!bReloadFile && MRU_FindPath(Globals.pFileMRU, Paths.CurrentFile, &idx)) {
iCaretPos = Globals.pFileMRU->iCaretPos[idx];
iAnchorPos = Globals.pFileMRU->iSelAnchPos[idx];
pszBookMarks = Globals.pFileMRU->pszBookMarks[idx];
}
if (!(Flags.bDoRelaunchElevated || s_IsThisAnElevatedRelaunch)) {
MRU_AddPath(Globals.pFileMRU, Paths.CurrentFile, Flags.RelativeFileMRU, Flags.PortableMyDocs, fioStatus.iEncoding, iCaretPos, iAnchorPos, pszBookMarks);
AddFilePathToRecentDocs(Paths.CurrentFile);
}
EditSetBookmarkList(Globals.hwndEdit, pszBookMarks);
if (IsFindPatternEmpty()) {
SetFindPattern((Globals.pMRUfind ? Globals.pMRUfind->pszItems[0] : L""));
}
// Install watching of the current file
AutoSaveStop();
InstallFileWatching(false); // terminate previous
if (!bReloadFile && Settings.ResetFileWatching) {
_ResetFileWatchingMode();
}
// consistent settings file handling (if loaded in editor)
Flags.bSettingsFileSoftLocked = (Path_StrgComparePathNormalized(Paths.CurrentFile, Paths.IniFile) == 0);
// the .LOG feature ...
if (IsFileVarLogFile()) {
Sci_SetCaretScrollDocEnd();
UndoTransActionBegin();
SciCall_NewLine();
SendWMCommand(Globals.hwndMain, IDM_EDIT_INSERT_SHORTDATE);
SciCall_DocumentEnd();
SciCall_NewLine();
EndUndoTransAction();
}
if (!bReloadFile) {
UpdateSaveSettingsCmds();
}
// set historic caret/selection pos
if (!FileWatching.MonitoringLog && (s_flagChangeNotify != FWM_AUTORELOAD)) {
if ((iCaretPos >= 0) && (iAnchorPos >= 0)) {
Sci_SetStreamSelection(iAnchorPos, iCaretPos, true);
Sci_ScrollSelectionToView();
}
else {
Sci_GotoPosChooseCaret(0);
}
}
// Show warning: Unicode file loaded as ANSI
if (fioStatus.bUnicodeErr) {
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_ERR_UNICODE);
}
// Show inconsistent line endings warning
Globals.bDocHasInconsistentEOLs = fioStatus.bInconsistentEOLs;
bool const bCheckFile = !Globals.CmdLnFlag_PrintFileAndLeave && !fioStatus.bEncryptedRaw && !(fioStatus.bUnknownExt && bUnknownLexer) && !bReloadFile;
//&& (fioStatus.iEncoding == Settings.DefaultEncoding) ???
bool const bCheckEOL = bCheckFile && Globals.bDocHasInconsistentEOLs && Settings.WarnInconsistEOLs;
if (bCheckEOL && !Style_MaybeBinaryFile(Globals.hwndEdit, Paths.CurrentFile)) {
if (WarnLineEndingDlg(Globals.hwndMain, &fioStatus)) {
UndoTransActionBegin();
SciCall_ConvertEOLs(fioStatus.iEOLMode);
EndUndoTransAction();
Globals.bDocHasInconsistentEOLs = false;
}
SciCall_SetEOLMode(fioStatus.iEOLMode);
}
// Show inconsistent indentation
fioStatus.iGlobalIndent = I_MIX_LN; // init
bool const bCheckIndent = bCheckFile && !Flags.bHugeFileLoadState && Settings.WarnInconsistentIndents;
if (bCheckIndent && !Style_MaybeBinaryFile(Globals.hwndEdit, Paths.CurrentFile)) {
EditIndentationStatistic(Globals.hwndEdit, &fioStatus);
ConsistentIndentationCheck(&fioStatus);
}
if (Settings.AutoDetectIndentSettings && !Globals.CmdLnFlag_PrintFileAndLeave) {
if (!Settings.WarnInconsistentIndents || (fioStatus.iGlobalIndent != I_MIX_LN)) {
EditIndentationStatistic(Globals.hwndMain, &fioStatus); // new statistic needed
}
Globals.fvCurFile.bTabsAsSpaces = (fioStatus.indentCount[I_TAB_LN] < fioStatus.indentCount[I_SPC_LN]) ? true : false;
SciCall_SetUseTabs(!Globals.fvCurFile.bTabsAsSpaces);
}
}
else if (!(Flags.bHugeFileLoadState || fioStatus.bUnknownExt)) {
WCHAR displayName[80];
Path_GetDisplayName(displayName, 80, hopen_file, L"<unknown>", false);
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_ERR_LOADFILE, displayName);
Flags.bHugeFileLoadState = false; // reset
}
UpdateToolbar();
UpdateMargins(true);
UpdateStatusbar(true);
if (SciCall_GetZoom() != 100) {
ShowZoomCallTip();
}
Path_Release(hopen_file);
ResetFileObservationData(true);
InstallFileWatching(fSuccess);
return fSuccess;
}
//=============================================================================
//
// FileRevert()
//
bool FileRevert(const HPATHL hfile_pth, bool bIgnoreCmdLnEnc)
{
if (Path_IsEmpty(hfile_pth)) {
return false;
}
DocLn const curLineNum = Sci_GetCurrentLineNumber();
DocPos const curColumnNum = Sci_GetCurrentColumnNumber();
DocLn const firstVisibleLine = SciCall_GetFirstVisibleLine();
bool const bIsAtDocEnd = (curLineNum >= (Sci_GetLastDocLineNumber() - Settings2.CurrentLineVerticalSlop));
Encoding_SrcWeak(CPI_NONE);
if (bIgnoreCmdLnEnc) {
Encoding_Forced(CPI_NONE); // ignore history too
} else {
Encoding_SrcWeak(Encoding_GetCurrent());
}
//~InstallFileWatching(false); // terminate
FileLoadFlags fLoadFlags = FLF_DontSave | FLF_Reload;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
bool const result = FileLoad(hfile_pth, fLoadFlags);
//~InstallFileWatching(true);
if (result) {
bool bPreserveView = !IsFileVarLogFile();
if (FileWatching.FileWatchingMode == FWM_AUTORELOAD) {
if (bIsAtDocEnd || FileWatching.MonitoringLog || (s_flagChangeNotify == FWM_AUTORELOAD)) {
bPreserveView = false;
}
}
if (bPreserveView) {
SciCall_SetFirstVisibleLine(firstVisibleLine);
Sci_GotoPosChooseCaret(SciCall_FindColumn(curLineNum, curColumnNum));
}
else {
// watch document end
Sci_SetCaretScrollDocEnd();
}
}
SetSaveDone();
UpdateToolbar();
UpdateMargins(true);
UpdateStatusbar(true);
return result;
}
//=============================================================================
//
// DoElevatedRelaunch()
//
//
bool DoElevatedRelaunch(EditFileIOStatus* pFioStatus, bool bAutoSaveOnRelaunch)
{
SaveAllSettings(false);
Flags.bDoRelaunchElevated = true;
LPWSTR lpCmdLine = GetCommandLine();
size_t const wlen = StringCchLen(lpCmdLine, 0) + 2;
LPWSTR const lpExe = AllocMem(sizeof(WCHAR) * wlen, HEAP_ZERO_MEMORY);
LPWSTR const lpArgs = AllocMem(sizeof(WCHAR) * wlen, HEAP_ZERO_MEMORY);
// ~ don't use original argument list (try to reconstruct current state as close as possible
#if 0
ExtractFirstArgument(lpCmdLine, lpExe, lpArgs, (int)wlen);
// remove relaunch elevated, we are doing this here already
lpArgs[StringCchLen(lpArgs, 0)] = L' '; // add a space
lpArgs = StrCutI(lpArgs, L"/u ");
lpArgs = StrCutI(lpArgs, L"-u ");
// remove forced command line encoding from argument list
WCHAR wchEncoding[80] = { L'\0' };
wchEncoding[0] = L'/';
Encoding_GetNameW(Encoding_Forced(CPI_GET), &wchEncoding[1], COUNTOF(wchEncoding)-1);
if (StrIsNotEmpty(&wchEncoding[1])) {
lpArgs = StrCutI(lpArgs, wchEncoding);
}
// remove file from argument list
if (s_lpOrigFileArg) {
lpArgs = StrCutI(lpArgs, s_lpOrigFileArg);
}
#else
lpArgs[0] = L'\0';
#endif
// ----------------------------------------------
WCHAR wchFlags[32] = { L'\0' };
if (IsAppClosing()) {
StringCchCat(wchFlags, COUNTOF(wchFlags), L"/UC ");
}
if (bAutoSaveOnRelaunch) {
StringCchCat(wchFlags, COUNTOF(wchFlags), L"/QS ");
}
if (Flags.bPreserveFileModTime) {
StringCchCat(wchFlags, COUNTOF(wchFlags), L"/RP ");
}
DocPos const iCurPos = SciCall_GetCurrentPos();
int const iCurLn = (int)SciCall_LineFromPosition(iCurPos) + 1;
int const iCurCol = (int)SciCall_GetColumn(iCurPos) + 1;
WININFO const wi = GetMyWindowPlacement(Globals.hwndMain, NULL, 0, false);
HSTRINGW hstr_args = StrgCreate(NULL);
StrgFormat(hstr_args, L"%s/pos " WINDOWPOS_STRGFORMAT L" /g %i,%i %s",
wchFlags, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, (int)wi.max, iCurLn, iCurCol, lpArgs);
WCHAR wchTempFileName[MAX_PATH_EXPLICIT + 1] = { L'\0' };
WCHAR wchTempPathBuffer[MAX_PATH_EXPLICIT + 1] = { L'\0' };
// MAX_PATH_EXPLICIT is okay for GetTempPathW() and GetTempFileNameW()
if (GetTempPathW(MAX_PATH_EXPLICIT, wchTempPathBuffer) && GetTempFileNameW(wchTempPathBuffer, L"NP3", 0, wchTempFileName)) {
HPATHL htmp_pth = Path_Allocate(wchTempFileName);
// replace possible unknown extension
Path_RenameExtension(htmp_pth, Path_IsNotEmpty(Paths.CurrentFile) ? Path_FindExtension(Paths.CurrentFile) : L".txt");
if (pFioStatus && FileIO(false, htmp_pth, pFioStatus, FLF_None, FSF_SaveCopy, true)) {
// preserve encoding
WCHAR wchEncoding[80] = { L'\0' };
Encoding_GetNameW(Encoding_GetCurrent(), wchEncoding, COUNTOF(wchEncoding));
StrgFormat(hstr_args, L"%s/%s /pos " WINDOWPOS_STRGFORMAT L" /g %i,%i /%s\"%s\" %s",
wchFlags, wchEncoding, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, (int)wi.max, iCurLn, iCurCol, RELAUNCH_ELEVATED_BUF_ARG, Path_Get(htmp_pth), lpArgs);
if (!StrStrI(StrgGet(hstr_args), Path_FindFileName(Paths.CurrentFile))) {
if (Path_IsNotEmpty(Paths.CurrentFile)) {
StrgFormat(hstr_args, L"%s \"%s\"", StrgGet(hstr_args), Path_Get(Paths.CurrentFile));
}
}
}
Path_Release(htmp_pth);
FreeMem(lpExe);
FreeMem(lpArgs);
}
if (RelaunchElevated(StrgGet(hstr_args))) {
// set no change and quit
SetSaveDone();
} else {
Globals.dwLastError = GetLastError();
if (PathIsExistingFile(wchTempFileName)) {
DeleteFileW(wchTempFileName);
}
Flags.bDoRelaunchElevated = false;
}
StrgDestroy(hstr_args);
return Flags.bDoRelaunchElevated;
}
//=============================================================================
static void _MRU_UpdateSession()
{
int idx = 0;
if (MRU_FindPath(Globals.pFileMRU, Paths.CurrentFile, &idx)) {
Globals.pFileMRU->iEncoding[idx] = Encoding_GetCurrent();
Globals.pFileMRU->iCaretPos[idx] = (Settings.PreserveCaretPos) ? SciCall_GetCurrentPos() : -1;
Globals.pFileMRU->iSelAnchPos[idx] = (Settings.PreserveCaretPos) ? (Sci_IsMultiOrRectangleSelection() ? -1 : SciCall_GetAnchor()) : -1;
WCHAR wchBookMarks[MRU_BMRK_SIZE] = { L'\0' };
EditGetBookmarkList(Globals.hwndEdit, wchBookMarks, COUNTOF(wchBookMarks));
if (Globals.pFileMRU->pszBookMarks[idx]) {
LocalFree(Globals.pFileMRU->pszBookMarks[idx]); // StrDup()
Globals.pFileMRU->pszBookMarks[idx] = NULL;
}
Globals.pFileMRU->pszBookMarks[idx] = StrDup(wchBookMarks);
}
}
static void _MRU_AddSession()
{
cpi_enc_t iCurrEnc = Encoding_GetCurrent();
const DocPos iCaretPos = SciCall_GetCurrentPos();
const DocPos iAnchorPos = Sci_IsMultiOrRectangleSelection() ? -1 : SciCall_GetAnchor();
WCHAR wchBookMarks[MRU_BMRK_SIZE] = { L'\0' };
EditGetBookmarkList(Globals.hwndEdit, wchBookMarks, COUNTOF(wchBookMarks));
MRU_AddPath(Globals.pFileMRU, Paths.CurrentFile, Flags.RelativeFileMRU, Flags.PortableMyDocs, iCurrEnc, iCaretPos, iAnchorPos, wchBookMarks);
}
// ----------------------------------------------------------------------------
//
// FileSave()
//
//
bool FileSave(FileSaveFlags fSaveFlags)
{
bool fSuccess = false;
EditFileIOStatus fioStatus = INIT_FILEIO_STATUS;
fioStatus.iEncoding = Encoding_GetCurrent();
fioStatus.iEOLMode = SciCall_GetEOLMode();
bool bIsEmptyNewFile = false;
if (Flags.SaveBlankNewFile) {
bIsEmptyNewFile = (Path_IsEmpty(Paths.CurrentFile) && (SciCall_GetTextLength() <= 0LL));
}
else {
if (Path_IsEmpty(Paths.CurrentFile)) {
DocPos const cchText = SciCall_GetTextLength();
if (cchText <= 0) {
bIsEmptyNewFile = true;
}
else {
struct Sci_TextToFindFull ft = { { 0, 0 }, "\\S+", { 0, 0 } };
ft.chrg.cpMax = Sci_GetDocEndPosition();
DocPos const iPos = SciCall_FindTextFull(SCFIND_REGEXP, &ft);
bIsEmptyNewFile = ((iPos < 0) || (iPos >= ft.chrg.cpMax));
}
}
}
bool const bSaveNeeded = (IsSaveNeeded() || IsFileChangedFlagSet()) && !bIsEmptyNewFile;
if (!(fSaveFlags & FSF_SaveAs) && !(fSaveFlags & FSF_SaveAlways) && !bSaveNeeded) {
_MRU_UpdateSession();
AutoSaveStop();
ResetFileObservationData(true);
return true;
}
if (fSaveFlags & FSF_Ask) {
// File or "Untitled" ...
WCHAR wchFileName[MAX_PATH_EXPLICIT>>1] = { L'\0' };
GetLngString(IDS_MUI_UNTITLED, wchFileName, COUNTOF(wchFileName));
Path_GetDisplayName(wchFileName, COUNTOF(wchFileName), Paths.CurrentFile, NULL, false);
INT_PTR const answer = (Settings.MuteMessageBeep) ?
InfoBoxLng(MB_YESNOCANCEL | MB_ICONWARNING, NULL, IDS_MUI_ASK_SAVE, wchFileName) :
MessageBoxLng(MB_YESNOCANCEL | MB_ICONWARNING, IDS_MUI_ASK_SAVE, wchFileName);
switch (answer)
{
case IDCANCEL:
return false;
case IDNO:
_MRU_UpdateSession();
AutoSaveStop();
return true;
default:
// proceed
break;
}
}
// Read only...
if (!(fSaveFlags & FSF_SaveAs) && !(fSaveFlags & FSF_SaveCopy) && Path_IsNotEmpty(Paths.CurrentFile)) {
if (IsFileReadOnly()) {
UpdateToolbar();
INT_PTR const answer = (Settings.MuteMessageBeep) ?
InfoBoxLng(MB_YESNO | MB_ICONWARNING, NULL, IDS_MUI_READONLY_SAVE, Path_FindFileName(Paths.CurrentFile)) :
MessageBoxLng(MB_YESNO | MB_ICONWARNING, IDS_MUI_READONLY_SAVE, Path_Get(Paths.CurrentFile));
if (IsYesOkay(answer)) {
fSaveFlags |= FSF_SaveAs;
} else {
return false;
}
}
}
// Save As...
if ((fSaveFlags & FSF_SaveAs) || (fSaveFlags & FSF_SaveCopy) || Path_IsEmpty(Paths.CurrentFile)) {
static HPATHL _hpthLastSaveCopyDir = NULL; // session remember copyTo dir
if (!_hpthLastSaveCopyDir) {
_hpthLastSaveCopyDir = Path_Allocate(L"");
}
HPATHL hfile_pth = Path_Allocate(NULL);
HPATHL hdir_pth = Path_Allocate(NULL);
if ((fSaveFlags & FSF_SaveCopy) && Path_IsNotEmpty(_hpthLastSaveCopyDir)) {
Path_Reset(hdir_pth, Path_Get(_hpthLastSaveCopyDir));
} else {
Path_Reset(hdir_pth, Path_Get(Paths.CurrentFile));
Path_RemoveFileSpec(hdir_pth);
}
Path_Reset(hfile_pth, Path_FindFileName(Paths.CurrentFile));
bool const ok = SaveFileDlg(Globals.hwndMain, hfile_pth, Path_IsNotEmpty(hdir_pth) ? hdir_pth : NULL);
if (ok) {
if (!(fSaveFlags & FSF_SaveCopy)) {
if (fSaveFlags & FSF_SaveAs) {
SaveAllSettings(false); // session on old file ends, save side-by-side settings
}
InstallFileWatching(false); // terminate
fSaveFlags |= FSF_EndSession;
}
fSuccess = FileIO(false, hfile_pth, &fioStatus, FLF_None, fSaveFlags, true);
if (fSuccess) {
if (!(fSaveFlags & FSF_SaveCopy)) {
Path_Swap(Paths.CurrentFile, hfile_pth);
SetDlgItemText(Globals.hwndMain, IDC_FILENAME, Path_Get(Paths.CurrentFile));
SetDlgItemInt(Globals.hwndMain, IDC_REUSELOCK, (UINT)GetTicks_ms(), false);
if (!s_flagKeepTitleExcerpt) {
StringCchCopy(s_wchTitleExcerpt, COUNTOF(s_wchTitleExcerpt), L"");
}
Style_SetLexerFromFile(Globals.hwndEdit, Paths.CurrentFile);
} else {
Path_Swap(_hpthLastSaveCopyDir, hfile_pth);
Path_RemoveFileSpec(_hpthLastSaveCopyDir);
}
}
}
Path_Release(hdir_pth);
Path_Release(hfile_pth);
if (!ok) {
return false;
}
} else {
InstallFileWatching(false); // terminate
fSuccess = FileIO(false, Paths.CurrentFile, &fioStatus, FLF_None, FSF_EndSession, true);
}
if (fSuccess) {
if (!(fSaveFlags & FSF_SaveCopy) && !Flags.bDoRelaunchElevated) {
_MRU_AddSession();
AddFilePathToRecentDocs(Paths.CurrentFile);
// Install watching of the current file
if ((fSaveFlags & FSF_SaveAs) && Settings.ResetFileWatching) {
_ResetFileWatchingMode();
}
InstallFileWatching(true);
}
else {
_MRU_UpdateSession();
}
// if current file is settings/config file: ask to start
if (Flags.bSettingsFileSoftLocked && !IsAppClosing()) {
///~ LoadSettings(); NOT all settings will be applied ...
WCHAR tch[256] = { L'\0' };
if (Settings.SaveSettings) { LoadLngStringW(IDS_MUI_RELOADCFGSEX, tch, COUNTOF(tch)); }
UINT const typ = Settings.SaveSettings ? (MB_YESNO | MB_ICONWARNING) : (MB_YESNO | MB_ICONINFORMATION);
LONG const answer = InfoBoxLng(typ, L"ReloadExSavedCfg", IDS_MUI_RELOADSETTINGS, tch);
if (IsYesOkay(answer)) {
///~SaveAllSettings(true); ~ already saved (CurrentFile)
DialogNewWindow(Globals.hwndMain, false, Paths.CurrentFile, NULL);
CloseApplication();
}
}
} else if (!fioStatus.bCancelDataLoss) {
LPCWSTR const currentFileName = Path_FindFileName(Paths.CurrentFile);
if (!s_bIsProcessElevated && (Globals.dwLastError == ERROR_ACCESS_DENIED)) {
INT_PTR const answer = (Settings.MuteMessageBeep) ?
InfoBoxLng(MB_YESNO | MB_ICONSHIELD, NULL, IDS_MUI_ERR_ACCESSDENIED, currentFileName, _W(SAPPNAME)) :
MessageBoxLng(MB_YESNO | MB_ICONSHIELD, IDS_MUI_ERR_ACCESSDENIED, Path_Get(Paths.CurrentFile), _W(SAPPNAME));
if (IsYesOkay(answer)) {
if (DoElevatedRelaunch(&fioStatus, true)) {
CloseApplication();
} else {
ResetEvent(s_hEventAppIsClosing);
if (Settings.MuteMessageBeep) {
InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_ERR_SAVEFILE, currentFileName);
} else {
MessageBoxLng(MB_ICONWARNING, IDS_MUI_ERR_SAVEFILE, Path_Get(Paths.CurrentFile));
}
}
}
} else {
if (Settings.MuteMessageBeep) {
InfoBoxLng(MB_ICONERROR, NULL, IDS_MUI_ERR_SAVEFILE, currentFileName);
} else {
MessageBoxLng(MB_ICONERROR, IDS_MUI_ERR_SAVEFILE, Path_Get(Paths.CurrentFile));
}
}
}
if (fSuccess) {
AutoSaveStop();
ResetFileObservationData(true);
}
UpdateToolbar();
return fSuccess;
}
// ============================================================================
//
// CountRunningInstances()
//
//
static BOOL CALLBACK _EnumWndCountProc(HWND hwnd, LPARAM lParam)
{
WCHAR szClassName[64] = { L'\0' };
if (GetClassName(hwnd, szClassName, COUNTOF(szClassName))) {
if (StrCmpW(szClassName, s_wchWndClass) == 0) {
*(int*)lParam += 1;
}
}
return TRUE;
}
int CountRunningInstances() {
int count = 0;
EnumWindows(_EnumWndCountProc, (LPARAM)&count);
return count;
}
/******************************************************************************
*
* ActivatePrevInst()
*
* Tries to find and activate an already open Notepad3 Window
*
*
******************************************************************************/
bool ActivatePrevInst()
{
HWND hwnd = NULL;
COPYDATASTRUCT cds = { 0 };
if ((!Flags.bReuseWindow && !Flags.bSingleFileInstance) || s_flagStartAsTrayIcon || s_flagNewFromClipboard || s_flagPasteBoard) {
return false;
}
if (Flags.bSingleFileInstance && Path_IsNotEmpty(s_pthArgFilePath)) {
Path_NormalizeEx(s_pthArgFilePath, Paths.WorkingDirectory, true, Flags.bSearchPathIfRelative);
Path_Reset(s_pthCheckFilePath, Path_Get(s_pthArgFilePath));
EnumWindows(_EnumWndProc2,(LPARAM)&hwnd);
if (hwnd != NULL) {
// Enabled
if (IsWindowEnabled(hwnd)) {
// Make sure the previous window won't pop up a change notification message
//SendMessage(hwnd,WM_CHANGENOTIFYCLEAR,0,0);
if (IsIconic(hwnd)) {
ShowWindowAsync(hwnd, SW_RESTORE);
}
if (!IsWindowVisible(hwnd)) {
SendMessage(hwnd,WM_TRAYMESSAGE,0,WM_LBUTTONDBLCLK);
SendMessage(hwnd,WM_TRAYMESSAGE,0,WM_LBUTTONUP);
}
SetForegroundWindow(hwnd);
size_t cb = sizeof(np3params);
if (s_lpSchemeArg) {
cb += ((StringCchLen(s_lpSchemeArg, 0) + 1) * sizeof(WCHAR));
}
if (!IsFindPatternEmpty()) {
cb += ((LengthOfFindPattern() + 1) * sizeof(WCHAR));
}
LPnp3params params = AllocMem(cb, HEAP_ZERO_MEMORY);
params->flagFileSpecified = false;
params->flagChangeNotify = FWM_DONT_CARE; //(!)
params->flagQuietCreate = false;
params->flagLexerSpecified = s_flagLexerSpecified ? 1 : 0;
if (s_flagLexerSpecified && s_lpSchemeArg) {
StringCchCopyW(StrEnd(&params->wchData,0)+1,(StringCchLen(s_lpSchemeArg,0)+1),s_lpSchemeArg);
params->iInitialLexer = -1;
} else {
params->iInitialLexer = s_iInitialLexer;
}
params->flagJumpTo = s_flagJumpTo ? 1 : 0;
params->iInitialLine = s_iInitialLine;
params->iInitialColumn = s_iInitialColumn;
params->flagSetEncoding = s_flagSetEncoding;
params->flagSetEOLMode = s_flagSetEOLMode;
params->flagTitleExcerpt = 0;
params->flagMatchText = g_flagMatchText;
if (!IsFindPatternEmpty()) {
StringCchCopyW(StrEnd(&params->wchData, 0) + 1, (LengthOfFindPattern() + 1), GetFindPattern());
}
cds.dwData = DATA_NOTEPAD3_PARAMS;
cds.cbData = (DWORD)SizeOfMem(params);
cds.lpData = params;
SendMessage(hwnd,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds);
FreeMem(params);
params = NULL;
return true;
}
// IsWindowEnabled()
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, NULL, IDS_MUI_ERR_PREVWINDISABLED))) {
return false;
}
return true;
}
}
if (!Flags.bReuseWindow) {
return false;
}
hwnd = NULL;
EnumWindows(_EnumWndProc,(LPARAM)&hwnd);
// Found a window
if (hwnd != NULL) {
// Enabled
if (IsWindowEnabled(hwnd)) {
// Make sure the previous window won't pop up a change notification message
//SendMessage(hwnd,WM_CHANGENOTIFYCLEAR,0,0);
if (IsIconic(hwnd)) {
ShowWindowAsync(hwnd, SW_RESTORE);
}
if (!IsWindowVisible(hwnd)) {
SendMessage(hwnd,WM_TRAYMESSAGE,0,WM_LBUTTONDBLCLK);
SendMessage(hwnd,WM_TRAYMESSAGE,0,WM_LBUTTONUP);
}
SetForegroundWindow(hwnd);
if (Path_IsNotEmpty(s_pthArgFilePath))
{
size_t cb = sizeof(np3params);
cb += (Path_GetLength(s_pthArgFilePath) + 1) * sizeof(WCHAR);
if (s_lpSchemeArg) {
cb += (StringCchLen(s_lpSchemeArg, 0) + 1) * sizeof(WCHAR);
}
size_t cchTitleExcerpt = StringCchLen(s_wchTitleExcerpt,COUNTOF(s_wchTitleExcerpt));
if (cchTitleExcerpt) {
cb += (cchTitleExcerpt + 1) * sizeof(WCHAR);
}
if (!IsFindPatternEmpty()) {
cb += ((LengthOfFindPattern() + 1) * sizeof(WCHAR));
}
LPnp3params params = AllocMem(cb, HEAP_ZERO_MEMORY);
params->flagFileSpecified = true;
StringCchCopyW(&params->wchData, Path_GetLength(s_pthArgFilePath) + 1, Path_Get(s_pthArgFilePath));
params->flagChangeNotify = s_flagChangeNotify;
params->flagQuietCreate = s_flagQuietCreate ? 1 : 0;
params->flagLexerSpecified = s_flagLexerSpecified ? 1 : 0;
if (s_flagLexerSpecified && s_lpSchemeArg) {
StringCchCopyW(StrEnd(&params->wchData,0)+1, StringCchLen(s_lpSchemeArg,0)+1,s_lpSchemeArg);
params->iInitialLexer = -1;
} else {
params->iInitialLexer = s_iInitialLexer;
}
params->flagJumpTo = s_flagJumpTo ? 1 : 0;
params->iInitialLine = s_iInitialLine;
params->iInitialColumn = s_iInitialColumn;
params->flagSetEncoding = s_flagSetEncoding;
params->flagSetEOLMode = s_flagSetEOLMode;
if (cchTitleExcerpt) {
StringCchCopyW(StrEnd(&params->wchData,0)+1,cchTitleExcerpt+1,s_wchTitleExcerpt);
params->flagTitleExcerpt = 1;
} else {
params->flagTitleExcerpt = 0;
}
params->flagMatchText = g_flagMatchText;
if (!IsFindPatternEmpty()) {
StringCchCopyW(StrEnd(&params->wchData, 0) + 1, (LengthOfFindPattern() + 1), GetFindPattern());
}
cds.dwData = DATA_NOTEPAD3_PARAMS;
cds.cbData = (DWORD)SizeOfMem(params);
cds.lpData = params;
SendMessage(hwnd,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds);
FreeMem(params);
params = NULL;
Path_Empty(s_pthArgFilePath, false);
}
return true;
}
// IsWindowEnabled()
return !IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, NULL, IDS_MUI_ERR_PREVWINDISABLED));
}
return false;
}
//=============================================================================
//
// LaunchNewInstance()
//
//
bool LaunchNewInstance(HWND hwnd, LPCWSTR lpszParameter, LPCWSTR lpszFilePath)
{
HPATHL hexe_pth = Path_Allocate(NULL);
Path_GetModuleFilePath(hexe_pth);
HSTRINGW hstrParams = StrgCreate(lpszParameter);
LPWSTR const params_buf = StrgWriteAccessBuf(hstrParams, CMDLN_LENGTH_LIMIT);
HPATHL hdir_pth = Path_Allocate(lpszFilePath);
if (Path_IsEmpty(hdir_pth)) {
Path_Reset(hdir_pth, Path_Get(Paths.WorkingDirectory));
}
else {
int const offset = Settings2.LaunchInstanceWndPosOffset;
int const bFullVisible = Settings2.LaunchInstanceFullVisible;
int const instCnt = CountRunningInstances();
WININFO wi = GetMyWindowPlacement(hwnd, NULL, offset * instCnt, bFullVisible);
WCHAR wchPos[80] = { L'\0' };
StringCchPrintf(wchPos, COUNTOF(wchPos), L"-pos " WINDOWPOS_STRGFORMAT, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, (int)wi.max);
StringCchPrintf(params_buf, StrgGetAllocLength(hstrParams),
L"%s %s \"%s\"", lpszParameter, wchPos, lpszFilePath);
Path_RemoveFileSpec(hdir_pth);
}
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_DEFAULT;
sei.hwnd = hwnd;
sei.lpVerb = NULL;
sei.lpFile = Path_Get(hexe_pth);
sei.lpParameters = StrgGet(hstrParams);
sei.lpDirectory = Path_Get(hdir_pth);
sei.nShow = SW_NORMAL;
bool const res = ShellExecuteExW(&sei);
Path_Release(hdir_pth);
StrgDestroy(hstrParams);
Path_Release(hexe_pth);
return res;
}
//=============================================================================
//
// RelaunchMultiInst()
//
//
bool RelaunchMultiInst()
{
if (Flags.MultiFileArg && (s_cFileList > 1)) {
LPWSTR lpCmdLine = StrDup(GetCommandLine());
size_t fl = 0;
for (int i = 0; i < s_cFileList; i++) {
fl = max_s(fl, StringCchLen(s_lpFileList[i], 0));
}
size_t len = StringCchLen(lpCmdLine,0) + fl + 80ULL;
LPWSTR lpCmdLineNew = AllocMem(sizeof(WCHAR) * len, HEAP_ZERO_MEMORY);
StrTab2Space(lpCmdLine);
StringCchCopy(lpCmdLine + s_cchiFileList, 2, L"");
WCHAR* pwch = CharPrev(lpCmdLine, StrEnd(lpCmdLine, len));
int k = 0;
while (*pwch == L' ' || *pwch == L'-' || *pwch == L'+') {
*pwch = L' ';
pwch = CharPrev(lpCmdLine, pwch);
if (k++ > 1) {
s_cchiFileList--;
}
}
int const offset = Settings2.LaunchInstanceWndPosOffset;
for (int i = 0; i < s_cFileList; i++) {
WININFO wi = g_IniWinInfo;
wi.x += (i * offset);
wi.y += (i * offset);
WCHAR wchPos[80] = { L'\0' };
if (!Globals.CmdLnFlag_PosParam) {
StringCchPrintf(wchPos, COUNTOF(wchPos), L" -pos " WINDOWPOS_STRGFORMAT, wi.x, wi.y, wi.cx, wi.cy, wi.dpi, (int)wi.max);
}
size_t const pl = StringCchLen(wchPos, 80) + 1;
StringCchCopy(lpCmdLineNew, len, lpCmdLine);
StringCchCat(lpCmdLineNew, len, wchPos);
StringCchCopy(lpCmdLineNew + s_cchiFileList + pl, 8, L" /n - ");
StringCchCat(lpCmdLineNew, len, s_lpFileList[i]);
LocalFree(s_lpFileList[i]); // StrDup()
s_lpFileList[i] = NULL;
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = { 0 };
CreateProcessW(NULL, lpCmdLineNew, NULL, NULL, false, CREATE_NEW_PROCESS_GROUP, NULL, Path_Get(Paths.WorkingDirectory), &si, &pi);
//~WaitForSingleObject(pi.hProcess, INFINITE);
WaitForSingleObject(pi.hProcess, 125); // pause 125ms to start next
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
LocalFree(lpCmdLine); // StrDup()
lpCmdLine = NULL;
FreeMem(lpCmdLineNew);
lpCmdLineNew = NULL;
Path_Empty(s_pthArgFilePath, true);
return true;
}
for (int i = 0; i < s_cFileList; i++) {
LocalFree(s_lpFileList[i]); // StrDup()
s_lpFileList[i] = NULL;
}
return false;
}
//=============================================================================
//
// RelaunchElevated()
//
//
bool RelaunchElevated(LPCWSTR lpNewCmdLnArgs)
{
if (!IsWindowsVistaOrGreater() || !Flags.bDoRelaunchElevated ||
s_bIsProcessElevated || s_IsThisAnElevatedRelaunch || s_bIsRunAsAdmin ||
s_flagDisplayHelp) {
return false; // reject initial RelaunchElevated() try
}
LPCWSTR lpCmdLine = GetCommandLine();
size_t const wlen = StringCchLen(lpCmdLine, 0) + 2ULL;
HPATHL hfile = Path_Allocate(NULL);
wchar_t* const fbuf = Path_WriteAccessBuf(hfile, PATHLONG_MAX_CCH);
HSTRINGW hstrOrigArgs = StrgCreate(NULL);
wchar_t* const arg_buf = StrgWriteAccessBuf(hstrOrigArgs, CMDLN_LENGTH_LIMIT);
ExtractFirstArgument(lpCmdLine, fbuf, arg_buf, min_i((int)wlen, CMDLN_LENGTH_LIMIT));
// overrides:
Path_GetModuleFilePath(hfile);
if (StrIsNotEmpty(lpNewCmdLnArgs)) {
StringCchCopy(arg_buf, StrgGetAllocLength(hstrOrigArgs), lpNewCmdLnArgs);
}
StrgSanitize(hstrOrigArgs);
StrgCat(hstrOrigArgs, L" ");
// remove relaunch elevated, we are doing this here already
StrCutIW(arg_buf, L"/u ");
StrCutIW(arg_buf, L"-u ");
StrgSanitize(hstrOrigArgs);
if (!(StrStrIW(arg_buf, L"/f ") || StrStrIW(arg_buf, L"-f ") || Path_IsEmpty(Paths.IniFile)))
{
HSTRINGW hipa_str = StrgCreate(NULL);
StrgFormat(hipa_str, L"/f \"%s\" ", Path_Get(Paths.IniFile));
StrgInsert(hstrOrigArgs, 0, StrgGet(hipa_str));
StrgDestroy(hipa_str);
}
bool res = false;
if (StrgIsNotEmpty(hstrOrigArgs)) {
STARTUPINFO si = { sizeof(STARTUPINFO) };
GetStartupInfo(&si);
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_UNICODE | SEE_MASK_HMONITOR | SEE_MASK_NOZONECHECKS | SEE_MASK_WAITFORINPUTIDLE;
sei.hwnd = GetForegroundWindow();
sei.hMonitor = MonitorFromWindow(sei.hwnd, MONITOR_DEFAULTTONEAREST);
sei.lpVerb = L"runas";
sei.lpFile = Path_Get(hfile);
sei.lpParameters = StrgGet(hstrOrigArgs);
sei.lpDirectory = Path_Get(Paths.WorkingDirectory);
sei.nShow = si.wShowWindow ? si.wShowWindow : SW_SHOWNORMAL;
res = ShellExecuteExW(&sei);
}
StrgDestroy(hstrOrigArgs);
Path_Release(hfile);
return res;
}
//=============================================================================
//
// ShowNotifyIcon()
//
//
void ShowNotifyIcon(HWND hwnd,bool bAdd)
{
HICON hIcon = NULL;
LoadIconWithScaleDown(Globals.hInstance, MAKEINTRESOURCE(IDR_MAINWND),
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), &hIcon);
NOTIFYICONDATA nid = { sizeof(NOTIFYICONDATA) };
nid.hWnd = hwnd;
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_TRAYMESSAGE;
nid.hIcon = hIcon;
StringCchCopy(nid.szTip,COUNTOF(nid.szTip), _W(SAPPNAME));
if (bAdd) {
Shell_NotifyIcon(NIM_ADD,&nid);
} else {
Shell_NotifyIcon(NIM_DELETE,&nid);
}
}
//=============================================================================
//
// SetNotifyIconTitle()
//
void SetNotifyIconTitle(HWND hwnd)
{
NOTIFYICONDATA nid = { sizeof(NOTIFYICONDATA) };
nid.hWnd = hwnd;
nid.uID = 0;
nid.uFlags = NIF_TIP;
nid.szTip[0] = L'\0';
WCHAR tchTitle[256] = { L'\0' };
if (StrIsNotEmpty(s_wchTitleExcerpt)) {
WCHAR tchFormat[128] = { L'\0' };
GetLngString(IDS_MUI_TITLEEXCERPT,tchFormat,COUNTOF(tchFormat));
StringCchPrintf(tchTitle,COUNTOF(tchTitle),tchFormat,s_wchTitleExcerpt);
}
else if (Path_IsNotEmpty(Paths.CurrentFile)) {
HPATHL hfilename = Path_Allocate(Path_FindFileName(Paths.CurrentFile));
StringCchCopy(tchTitle, COUNTOF(tchTitle), Path_Get(hfilename));
Path_Release(hfilename);
} else {
GetLngString(IDS_MUI_UNTITLED, tchTitle, COUNTOF(tchTitle) - 4);
}
if (IsSaveNeeded()) {
StringCchCat(nid.szTip, COUNTOF(nid.szTip), DOCMODDIFYD);
}
if (IsFileChangedFlagSet()) {
if (IsFileDeletedFlagSet()) {
StringCchCatN(nid.szTip, COUNTOF(nid.szTip), Settings2.FileDeletedIndicator, 3);
} else {
StringCchCatN(nid.szTip, COUNTOF(nid.szTip), Settings2.FileChangedIndicator, 3);
}
StringCchCat(nid.szTip, COUNTOF(nid.szTip), L" ");
}
StringCchCat(nid.szTip, COUNTOF(nid.szTip), tchTitle);
Shell_NotifyIcon(NIM_MODIFY,&nid);
}
//=============================================================================
//
// ResetMouseDWellTime()
//
void ResetMouseDWellTime()
{
if (Settings.ShowHypLnkToolTip || IsColorDefHotspotEnabled() || Settings.HighlightUnicodePoints) {
SciCall_SetMouseDWellTime(USER_TIMER_MINIMUM << 4);
} else {
Sci_DisableMouseDWellNotification();
}
}
//=============================================================================
//
// ShowZoomCallTip()
//
void ShowZoomCallTip()
{
static char chToolTip[64] = { '\0' };
int const delayClr = Settings2.ZoomTooltipTimeout;
if (delayClr >= (_MQ_TIMER_CYCLE << 3)) {
StringCchPrintfA(chToolTip, COUNTOF(chToolTip), "Zoom: %i%%", SciCall_GetZoom());
DocPos const iPos = SciCall_PositionFromLine(SciCall_GetFirstVisibleLine());
int const iXOff = SciCall_GetXOffset();
SciCall_SetXOffset(-4); // move away from margin
SciCall_CallTipSetPosition(true); // show above
SciCall_CallTipShow(iPos, chToolTip);
SciCall_SetXOffset(iXOff);
_DelayClearCallTip(delayClr);
} else {
Sci_CallTipCancelEx();
}
}
//=============================================================================
//
// ShowWrapAroundCallTip()
//
void ShowWrapAroundCallTip(bool forwardSearch)
{
static char chToolTip[80<<2] = { '\0' };
int const delayClr = Settings2.WrapAroundTooltipTimeout;
if (delayClr >= (_MQ_TIMER_CYCLE << 3)) {
WCHAR wchToolTip[80] = { '\0' };
if (forwardSearch) {
GetLngString(IDS_MUI_WRAPSEARCH_FWD, wchToolTip, COUNTOF(wchToolTip));
} else {
GetLngString(IDS_MUI_WRAPSEARCH_BCK, wchToolTip, COUNTOF(wchToolTip));
}
//StringCchCat(wchToolTip, COUNTOF(wchToolTip), FR_StatusW[Globals.FindReplaceMatchFoundState]);
WideCharToMultiByte(Encoding_SciCP, 0, wchToolTip, -1, chToolTip, (int)COUNTOF(chToolTip), NULL, NULL);
SciCall_CallTipShow(SciCall_GetCurrentPos(), chToolTip);
_DelayClearCallTip(delayClr);
} else {
Sci_CallTipCancelEx();
}
}
//=============================================================================
//
// PasteBoardTimerProc()
//
void CALLBACK PasteBoardTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(idEvent);
UNREFERENCED_PARAMETER(dwTime);
if ((s_iLastCopyTime > 0) && ((GetTicks_ms() - s_iLastCopyTime) > 200)) {
if (SciCall_CanPaste()) {
bool bAutoIndent2 = Settings.AutoIndent;
Settings.AutoIndent = 0;
EditJumpTo(-1, 0);
UndoTransActionBegin();
if (!Sci_IsDocEmpty()) {
SciCall_NewLine();
}
SciCall_Paste();
SciCall_NewLine();
EndUndoTransAction();
Sci_ScrollSelectionToView();
Settings.AutoIndent = bAutoIndent2;
}
s_iLastCopyTime = 0;
}
}
//=============================================================================
//
// MsgFileChangeNotify() - Handles WM_FILECHANGEDNOTIFY
//
LRESULT MsgFileChangeNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
if (IsAppClosing()) { return TRUE; }
SET_FCT_GUARD(TRUE);
DocPos const iCurPos = SciCall_GetCurrentPos();
if (Path_IsExistingFile(Paths.CurrentFile)) {
bool bRevertFile = IsSaveNeeded();
switch (FileWatching.FileWatchingMode) {
case FWM_AUTORELOAD:
bRevertFile = true;
break;
case FWM_MSGBOX: {
SetForegroundWindow(hwnd);
/// LONG const answer = MessageBoxExW(Globals.hwndMain, L"File change, Cancel, Retry, Continue", L"NP3", MB_ABORTRETRYIGNORE, GetLangIdByLocaleName(Globals.CurrentLngLocaleName));
LONG const answer = InfoBoxLng(MB_FILECHANGEDNOTIFY | MB_ICONWARNING, NULL, IDS_MUI_FILECHANGENOTIFY);
switch (LOWORD(answer)) {
case IDCANCEL:
case IDABORT:
FileWatching.FileWatchingMode = FWM_INDICATORSILENT;
SetSaveNeeded(true);
bRevertFile = false;
ResetFileObservationData(false); // false (!)
UpdateToolbar();
break;
case IDIGNORE:
case IDCONTINUE:
UndoRedoReset();
FileRevert(Paths.CurrentFile, false);
SciCall_SetReadOnly(FileWatching.MonitoringLog);
FileWatching.MonitoringLog = false; // will be reset in IDM_VIEW_CHASING_DOCTAIL
PostWMCommand(Globals.hwndMain, IDM_VIEW_CHASING_DOCTAIL);
bRevertFile = false; // done already
break;
case IDTRYAGAIN:
case IDCLOSE:
default:
bRevertFile = true;
ResetFileObservationData(true);
break;
}
} break;
case FWM_DONT_CARE:
case FWM_EXCLUSIVELOCK:
ResetFileObservationData(true);
break;
case FWM_INDICATORSILENT:
bRevertFile = false;
UpdateToolbar();
break;
case FWM_NO_INIT:
default:
assert("Invalid FileWatching Mode!" && 0);
break;
}
if (bRevertFile) {
SetForegroundWindow(hwnd);
FileRevert(Paths.CurrentFile, false);
if (FileWatching.MonitoringLog || (s_flagChangeNotify == FWM_AUTORELOAD)) {
SciCall_SetReadOnly(FileWatching.MonitoringLog);
}
else {
Sci_GotoPosChooseCaret(iCurPos);
}
}
}
else { // file has been deleted
InstallFileWatching(false); // terminate
if (FileWatching.FileWatchingMode == FWM_MSGBOX) {
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, NULL, IDS_MUI_FILECHANGENOTIFY2))) {
FileSave(FSF_SaveAlways);
}
else {
SetSaveNeeded(true);
}
}
else {
// FWM_INDICATORSILENT: nothing todo here
SetSaveNeeded(true);
}
}
RESET_FCT_GUARD();
return TRUE;
}
//=============================================================================
//
// InstallFileWatching()
//
//=============================================================================
static inline void NotifyIfFileHasChanged()
{
if (IsFileChangedFlagSet() || IsFileDeletedFlagSet() || RaiseFlagIfCurrentFileChanged()) {
PostMessage(Globals.hwndMain, WM_FILECHANGEDNOTIFY, 0, 0);
}
// reset Timeout interval
InterlockedExchange64(&(s_FileChgObsvrData.iFileChangeNotifyTime), GetTicks_ms());
}
// ----------------------------------------------------------------------------
// FWM_MSGBOX (polling: FileWatching.FileCheckInterval)
// FWM_AUTORELOAD (also FileWatching.MonitoringLog)
static void CALLBACK WatchTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
UNREFERENCED_PARAMETER(dwTime);
UNREFERENCED_PARAMETER(idEvent);
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(hwnd);
LONG64 const diff = (GetTicks_ms() - InterlockedOr64(&(s_FileChgObsvrData.iFileChangeNotifyTime), 0LL));
// Directory-Observer is not notified for continuously updated (log-)files
if (diff > FileWatching.FileCheckInterval) {
NotifyIfFileHasChanged();
}
}
// ----------------------------------------------------------------------------
unsigned int WINAPI FileChangeObserver(LPVOID lpParam)
{
PFCOBSRVDATA_T const pFCOBSVData = (PFCOBSRVDATA_T)(LONG_PTR)lpParam;
unsigned int retcode = 0;
if (pFCOBSVData) {
BackgroundWorker* const worker = &(pFCOBSVData->worker);
assert(!IS_VALID_HANDLE(pFCOBSVData->hFileChanged) && "ChangeHandle not properly closed!");
pFCOBSVData->hFileChanged = FindFirstChangeNotificationW(Path_Get(pFCOBSVData->worker.hFilePath), false,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE);
while (BackgroundWorker_Continue(worker)) {
switch (WaitForSingleObject(pFCOBSVData->hFileChanged, 100)) {
case WAIT_TIMEOUT:
// okay, check BGWorker cancellation or wait again until done
break;
case WAIT_OBJECT_0:
// check if current file is trigger for directory notification
if (RaiseFlagIfCurrentFileChanged()) {
if (FileWatching.FileCheckInterval <= MIN_FC_POLL_INTERVAL) {
NotifyIfFileHasChanged(); // immediate notification
}
}
FindNextChangeNotification(pFCOBSVData->hFileChanged);
break;
case WAIT_ABANDONED:
case WAIT_FAILED:
default:
BackgroundWorker_Cancel(worker);
retcode = 1;
break;
}
}
FindCloseChangeNotification(pFCOBSVData->hFileChanged); // stop monitoring
pFCOBSVData->hFileChanged = INVALID_HANDLE_VALUE;
BackgroundWorker_End(worker, retcode);
}
return retcode;
}
// ----------------------------------------------------------------------------
void InstallFileWatching(const bool bInstall) {
static HANDLE _hCurrFileHandle = INVALID_HANDLE_VALUE; // exclusive lock
// don't install FileWathing on own Settings IniFile
if (bInstall && Flags.bSettingsFileSoftLocked) {
return;
}
HPATHL hdir_pth = Path_Copy(Paths.CurrentFile);
Path_RemoveFileSpec(hdir_pth);
bool const bFileDirExists = Path_IsNotEmpty(Paths.CurrentFile) && Path_IsExistingDirectory(hdir_pth);
bool const bFileExists = bFileDirExists && Path_IsExistingFile(Paths.CurrentFile);
bool const bExclusiveLock = (FileWatching.FileWatchingMode == FWM_EXCLUSIVELOCK);
bool const bWatchFile = (FileWatching.FileWatchingMode != FWM_DONT_CARE) && !bExclusiveLock;
// always release exclusive file lock in any case
if (IS_VALID_HANDLE(_hCurrFileHandle)) {
CloseHandle(_hCurrFileHandle);
_hCurrFileHandle = INVALID_HANDLE_VALUE;
}
// static init
if (!IS_VALID_HANDLE(s_FileChgObsvrData.worker.eventCancel)) {
BackgroundWorker_Init(&(s_FileChgObsvrData.worker), NULL, NULL);
}
bool const bTerminate = !bInstall || !bWatchFile || !bFileDirExists /*~||!bFileExists~*/;
// Terminate previous watching
if (bTerminate) {
KillTimer(Globals.hwndMain, ID_WATCHTIMER);
BackgroundWorker_Cancel(&(s_FileChgObsvrData.worker));
ResetFileObservationData(false); // (!) false
}
if (bInstall && bFileExists) {
if (bWatchFile) {
if (!IS_VALID_HANDLE(s_FileChgObsvrData.worker.workerThread)) {
// Save data of current file
ResetFileObservationData(false); // (!) false
Path_Reset(s_FileChgObsvrData.worker.hFilePath, Path_Get(hdir_pth)); // directory monitoring
BackgroundWorker_Start(&(s_FileChgObsvrData.worker), FileChangeObserver, &s_FileChgObsvrData);
}
InterlockedExchange64(&(s_FileChgObsvrData.iFileChangeNotifyTime), GetTicks_ms());
if (Settings2.FileCheckInterval > 0) {
SetTimer(Globals.hwndMain, ID_WATCHTIMER, (UINT)FileWatching.FileCheckInterval, WatchTimerProc);
}
else {
KillTimer(Globals.hwndMain, ID_WATCHTIMER);
}
}
else if (bExclusiveLock) {
assert(!IS_VALID_HANDLE(_hCurrFileHandle) && "CurrFileHandle not properly closed!");
bool const bPrevReadOnlyAttrib = IsFileReadOnly();
if (bPrevReadOnlyAttrib) {
SendWMCommand(Globals.hwndMain, IDM_FILE_READONLY); // try to gain access
}
if (!IsFileReadOnly()) {
_hCurrFileHandle = CreateFile(Path_Get(Paths.CurrentFile),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, // 0 => NO FILE_SHARE_RW
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
Globals.dwLastError = GetLastError();
if (!IS_VALID_HANDLE(_hCurrFileHandle)) {
WCHAR wchDisplayName[MAX_PATH_EXPLICIT>>1];
GetLngString(IDS_MUI_UNTITLED, wchDisplayName, COUNTOF(wchDisplayName));
Path_GetDisplayName(wchDisplayName, COUNTOF(wchDisplayName), Paths.CurrentFile, NULL, false);
InfoBoxLng(MB_ICONERROR, NULL, IDS_MUI_FILELOCK_ERROR, wchDisplayName);
// need to chose another mode
FILE_WATCHING_MODE const fwm = Settings.FileWatchingMode;
FileWatching.FileWatchingMode = (fwm != FWM_EXCLUSIVELOCK) ? fwm : FWM_MSGBOX;
InstallFileWatching(true);
}
}
if (bPrevReadOnlyAttrib && !IsFileReadOnly()) {
SendWMCommand(Globals.hwndMain, IDM_FILE_READONLY); // try to reset
}
}
}
Path_Release(hdir_pth);
UpdateSaveSettingsCmds(); // (!) reflection
UpdateToolbar();
}
//=============================================================================
//
// AutoSaveStart()
//
static bool s_bAutoSaveTimerSet = false;
void AutoSaveStart(bool bReset)
{
if ((Settings.AutoSaveOptions & ASB_Periodic) && Settings.AutoSaveInterval >= USER_TIMER_MINIMUM) {
if (bReset || !s_bAutoSaveTimerSet) {
s_bAutoSaveTimerSet = true;
SetTimer(Globals.hwndMain, ID_AUTOSAVETIMER, Settings.AutoSaveInterval, AutoSaveTimerProc);
}
return;
}
if (s_bAutoSaveTimerSet) {
s_bAutoSaveTimerSet = false;
KillTimer(Globals.hwndMain, ID_AUTOSAVETIMER);
}
}
//=============================================================================
//
// AutoSaveStop()
//
void AutoSaveStop()
{
if (s_bAutoSaveTimerSet) {
s_bAutoSaveTimerSet = false;
KillTimer(Globals.hwndMain, ID_AUTOSAVETIMER);
}
}
//=============================================================================
//
// AutoSaveDoWork()
//
void AutoSaveDoWork(FileSaveFlags fSaveFlags)
{
if (!IsSaveNeeded()) {
return;
}
FileSave(fSaveFlags | FSF_AutoSave);
}
//=============================================================================
//
// AutoSaveTimerProc()
//
void CALLBACK AutoSaveTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(idEvent);
UNREFERENCED_PARAMETER(dwTime);
AutoSaveDoWork(FSF_None);
}
/// End of Notepad3.c ///