diff --git a/PowerEditor/installer/nativeLang/english.xml b/PowerEditor/installer/nativeLang/english.xml
index 921102752..27d4b70af 100644
--- a/PowerEditor/installer/nativeLang/english.xml
+++ b/PowerEditor/installer/nativeLang/english.xml
@@ -1889,6 +1889,7 @@ If you select advanced mode but do not edit files in the aforementioned language
+
diff --git a/PowerEditor/installer/nativeLang/english_customizable.xml b/PowerEditor/installer/nativeLang/english_customizable.xml
index ec2ec2418..ba4938d60 100644
--- a/PowerEditor/installer/nativeLang/english_customizable.xml
+++ b/PowerEditor/installer/nativeLang/english_customizable.xml
@@ -1889,6 +1889,7 @@ If you select advanced mode but do not edit files in the aforementioned language
+
diff --git a/PowerEditor/installer/nativeLang/french.xml b/PowerEditor/installer/nativeLang/french.xml
index 6e060fed0..da6c07c8a 100644
--- a/PowerEditor/installer/nativeLang/french.xml
+++ b/PowerEditor/installer/nativeLang/french.xml
@@ -1884,6 +1884,7 @@ Si vous sélectionnez le mode avancé sans modifier les fichiers des langues men
+
diff --git a/PowerEditor/installer/nativeLang/taiwaneseMandarin.xml b/PowerEditor/installer/nativeLang/taiwaneseMandarin.xml
index 291972749..4e3a4f0f7 100644
--- a/PowerEditor/installer/nativeLang/taiwaneseMandarin.xml
+++ b/PowerEditor/installer/nativeLang/taiwaneseMandarin.xml
@@ -1708,6 +1708,7 @@ C、C++、Java、C#、Objective-C、PHP、JavaScript、JSP、CSS、Perl、Rust
+
diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp
index a29ecd888..d8dba7c05 100644
--- a/PowerEditor/src/MISC/Common/Common.cpp
+++ b/PowerEditor/src/MISC/Common/Common.cpp
@@ -2094,4 +2094,61 @@ bool isCoreWindows()
return isCoreWindows;
}
+
+bool ControlInfoTip::init(HINSTANCE hInst, HWND ctrl2attached, HWND ctrl2attachedParent, const wstring& tipStr, bool isRTL)
+{
+ _hWndInfoTip = CreateWindowEx(isRTL ? WS_EX_LAYOUTRTL : 0, TOOLTIPS_CLASS, NULL,
+ WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ctrl2attachedParent, NULL,
+ hInst, NULL);
+
+ if (!_hWndInfoTip)
+ return false;
+
+ _toolInfo.cbSize = sizeof(_toolInfo);
+ _toolInfo.hwnd = ctrl2attachedParent;
+ _toolInfo.uFlags = TTF_IDISHWND | TTF_TRACK;
+ _toolInfo.uId = (UINT_PTR)ctrl2attached;
+ _toolInfo.lpszText = const_cast(tipStr.c_str());
+
+ if (!SendMessage(_hWndInfoTip, TTM_ADDTOOL, 0, (LPARAM)&_toolInfo))
+ {
+ ::DestroyWindow(_hWndInfoTip);
+ _hWndInfoTip = nullptr;
+ return false;
+ }
+
+ SendMessage(_hWndInfoTip, TTM_SETMAXTIPWIDTH, 0, 200);
+ SendMessage(_hWndInfoTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAKELPARAM((15000), (0)));
+ SendMessage(_hWndInfoTip, TTM_ACTIVATE, TRUE, 0); // Activates the tooltip control globally
+
+ return true;
+}
+
+void ControlInfoTip::show() const
+{
+ if (!isValid()) return;
+
+ RECT rcComboBox;
+ GetWindowRect(reinterpret_cast(_toolInfo.uId), &rcComboBox);
+
+ int xPos = rcComboBox.left + (rcComboBox.right - rcComboBox.left) / 2;
+ int yPos = rcComboBox.top + 25;
+
+ SendMessage(_hWndInfoTip, TTM_TRACKPOSITION, 0, MAKELPARAM(xPos, yPos));
+ SendMessage(_hWndInfoTip, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&_toolInfo);
+}
+
+void ControlInfoTip::hide()
+{
+ if (_hWndInfoTip)
+ {
+ SendMessage(_hWndInfoTip, TTM_TRACKACTIVATE, (WPARAM)FALSE, (LPARAM)&_toolInfo);
+ DestroyWindow(_hWndInfoTip);
+ _hWndInfoTip = nullptr;
+ }
+}
+
#pragma warning(default:4996)
diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h
index 7c624ab00..7b7103b0a 100644
--- a/PowerEditor/src/MISC/Common/Common.h
+++ b/PowerEditor/src/MISC/Common/Common.h
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -296,3 +297,34 @@ bool doesPathExist(const wchar_t* path, DWORD milliSec2wait = 0, bool* isTimeout
bool isWindowVisibleOnAnyMonitor(const RECT& rectWndIn);
bool isCoreWindows();
+
+class ControlInfoTip final
+{
+public:
+ ControlInfoTip() {};
+ ~ControlInfoTip() {
+ if (_hWndInfoTip) {
+ hide();
+ }
+ };
+ bool init(HINSTANCE hInst, HWND ctrl2attached, HWND ctrl2attachedParent, const std::wstring& tipStr, bool isRTL);
+
+ bool isValid() const {
+ return _hWndInfoTip != nullptr;
+ };
+
+ HWND getTipHandle() const {
+ return _hWndInfoTip;
+ };
+
+ void show() const;
+
+ void hide();
+
+private:
+ HWND _hWndInfoTip = nullptr;
+ TOOLINFO _toolInfo = {};
+
+ ControlInfoTip(const ControlInfoTip&) = delete;
+ ControlInfoTip& operator=(const ControlInfoTip&) = delete;
+};
diff --git a/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp b/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp
index 212625432..bee3a7bd8 100644
--- a/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp
+++ b/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp
@@ -1550,6 +1550,10 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
HWND hFindCombo = ::GetDlgItem(_hSelf, IDFINDWHAT);
HWND hReplaceCombo = ::GetDlgItem(_hSelf, IDREPLACEWITH);
+
+ ::SendMessage(hFindCombo, CB_LIMITTEXT, FINDREPLACE_MAXLENGTH - 2, 0);
+ ::SendMessage(hReplaceCombo, CB_LIMITTEXT, FINDREPLACE_MAXLENGTH - 2, 0);
+
HWND hFiltersCombo = ::GetDlgItem(_hSelf, IDD_FINDINFILES_FILTERS_COMBO);
HWND hDirCombo = ::GetDlgItem(_hSelf, IDD_FINDINFILES_DIR_COMBO);
@@ -1918,6 +1922,14 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
return TRUE;
}
+ case WM_NCLBUTTONDOWN:
+ {
+ if (_maxLenOnSearchTip.isValid())
+ {
+ _maxLenOnSearchTip.hide();
+ }
+ return FALSE;
+ }
case WM_COMMAND:
{
@@ -1926,6 +1938,47 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
FindHistory & findHistory = nppParamInst.getFindHistory();
switch (LOWORD(wParam))
{
+ case IDFINDWHAT:
+ case IDREPLACEWITH:
+ {
+ if (HIWORD(wParam) == CBN_EDITUPDATE)
+ {
+ HWND hComboBox = ::GetDlgItem(_hSelf, LOWORD(wParam));
+ LRESULT length = ::GetWindowTextLength(hComboBox);
+ if (length >= FINDREPLACE_MAXLENGTH - 2)
+ {
+ if (!_maxLenOnSearchTip.isValid()) // Create the tooltip and add the tool ONLY ONCE
+ {
+ NativeLangSpeaker* pNativeSpeaker = nppParamInst.getNativeLangSpeaker();
+ static wstring maxLenOnSearchTip = pNativeSpeaker->getLocalizedStrFromID("max-len-on-search-tip", L"Only 2046 bytes are allowed for the find/replace text length - your input could be truncated.");
+ bool isSuccessful = _maxLenOnSearchTip.init(_hInst, hComboBox, _hSelf, maxLenOnSearchTip.c_str(), _isRTL);
+
+ if (!isSuccessful)
+ {
+ return FALSE;
+ }
+
+ NppDarkMode::setDarkTooltips(_maxLenOnSearchTip.getTipHandle(), NppDarkMode::ToolTipsType::tooltip);
+ }
+ _maxLenOnSearchTip.show();
+ }
+ else
+ {
+ if (_maxLenOnSearchTip.isValid())
+ {
+ _maxLenOnSearchTip.hide();
+ }
+ }
+ }
+ else if (HIWORD(wParam) == CBN_KILLFOCUS || HIWORD(wParam) == CBN_SELCHANGE)
+ {
+ if (_maxLenOnSearchTip.isValid())
+ {
+ _maxLenOnSearchTip.hide();
+ }
+ }
+ return TRUE;
+ }
//Single actions
case IDC_2_BUTTONS_MODE:
{
@@ -2007,7 +2060,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
FindStatus findStatus = FSFound;
processFindNext(_options._str2Search.c_str(), _env, &findStatus);
- NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
+ NativeLangSpeaker *pNativeSpeaker = nppParamInst.getNativeLangSpeaker();
if (findStatus == FSEndReached)
{
wstring msg = pNativeSpeaker->getLocalizedStrFromID("find-status-end-reached", FIND_STATUS_END_REACHED_TEXT);
@@ -2362,8 +2415,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
if (_currentStatus == REPLACE_DLG)
{
- NppParameters& nppParam = NppParameters::getInstance();
- const NppGUI& nppGui = nppParam.getNppGUI();
+ const NppGUI& nppGui = nppParamInst.getNppGUI();
if (!nppGui._confirmReplaceInAllOpenDocs || replaceInOpenDocsConfirmCheck())
{
setStatusbarMessage(L"", FSNoMessage);
@@ -2391,7 +2443,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
setStatusbarMessage(L"", FSNoMessage);
if ((*_ppEditView)->getCurrentBuffer()->isReadOnly())
{
- NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
+ NativeLangSpeaker *pNativeSpeaker = nppParamInst.getNativeLangSpeaker();
wstring msg = pNativeSpeaker->getLocalizedStrFromID("find-status-replace-readonly", L"Replace: Cannot replace text. The current document is read only.");
setStatusbarMessage(msg, FSNotFound);
return TRUE;
@@ -2411,7 +2463,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
nppParamInst._isFindReplacing = false;
- NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
+ NativeLangSpeaker *pNativeSpeaker = nppParamInst.getNativeLangSpeaker();
if (nbReplaced == FIND_INVALID_REGULAR_EXPRESSION)
{
setStatusbarMessageWithRegExprErr(*_ppEditView);
@@ -2456,7 +2508,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
int nbCounted = processAll(ProcessCountAll, &_options);
- NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
+ NativeLangSpeaker *pNativeSpeaker = nppParamInst.getNativeLangSpeaker();
if (nbCounted == FIND_INVALID_REGULAR_EXPRESSION)
{
setStatusbarMessageWithRegExprErr(*_ppEditView);
@@ -2509,7 +2561,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
nppParamInst._isFindReplacing = false;
- NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
+ NativeLangSpeaker *pNativeSpeaker = nppParamInst.getNativeLangSpeaker();
if (nbMarked == FIND_INVALID_REGULAR_EXPRESSION)
{
setStatusbarMessageWithRegExprErr(*_ppEditView);
@@ -2675,7 +2727,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
{
::SendDlgItemMessage(_hSelf, IDC_TRANSPARENT_LOSSFOCUS_RADIO, BM_SETCHECK, BST_UNCHECKED, 0);
::SendDlgItemMessage(_hSelf, IDC_TRANSPARENT_ALWAYS_RADIO, BM_SETCHECK, BST_UNCHECKED, 0);
- (NppParameters::getInstance()).removeTransparent(_hSelf);
+ nppParamInst.removeTransparent(_hSelf);
findHistory._transparencyMode = FindHistory::none;
}
@@ -2685,14 +2737,14 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
case IDC_TRANSPARENT_ALWAYS_RADIO :
{
int percent = static_cast(::SendDlgItemMessage(_hSelf, IDC_PERCENTAGE_SLIDER, TBM_GETPOS, 0, 0));
- (NppParameters::getInstance()).SetTransparent(_hSelf, percent);
+ nppParamInst.SetTransparent(_hSelf, percent);
findHistory._transparencyMode = FindHistory::persistent;
}
return TRUE;
case IDC_TRANSPARENT_LOSSFOCUS_RADIO :
{
- (NppParameters::getInstance()).removeTransparent(_hSelf);
+ nppParamInst.removeTransparent(_hSelf);
findHistory._transparencyMode = FindHistory::onLosingFocus;
}
return TRUE;
@@ -2761,7 +2813,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
{
if (_currentStatus == FINDINFILES_DLG)
{
- NativeLangSpeaker* pNativeSpeaker = NppParameters::getInstance().getNativeLangSpeaker();
+ NativeLangSpeaker* pNativeSpeaker = nppParamInst.getNativeLangSpeaker();
const wstring title = pNativeSpeaker->getLocalizedStrFromID("find-in-files-select-folder", L"Select a folder to search from");
folderBrowser(_hSelf, title, IDD_FINDINFILES_DIR_COMBO, _options._directory.c_str());
}
@@ -2773,7 +2825,7 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
RECT rc{};
getWindowRect(rc);
LONG w = rc.right - rc.left;
- bool& isLessModeOn = NppParameters::getInstance().getNppGUI()._findWindowLessMode;
+ bool& isLessModeOn = nppParamInst.getNppGUI()._findWindowLessMode;
isLessModeOn = !isLessModeOn;
long dlgH = (isLessModeOn ? _lesssModeHeight : _szMinDialog.cy) + _szBorder.cy;
@@ -2895,6 +2947,7 @@ bool FindReplaceDlg::processFindNext(const wchar_t *txt2find, const FindOption *
(*_ppEditView)->execute(SCI_SETSEARCHFLAGS, flags);
+ NativeLangSpeaker* pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
posFind = (*_ppEditView)->searchInTarget(pText, stringSizeFind, startPosition, endPosition);
if (posFind == -1) //no match found in target, check if a new target should be used
@@ -2928,7 +2981,6 @@ bool FindReplaceDlg::processFindNext(const wchar_t *txt2find, const FindOption *
//failed, or failed twice with wrap
if (pOptions->_incrementalType == NotIncremental) //incremental search doesn't trigger messages
{
- NativeLangSpeaker* pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
wstring warningMsg = pNativeSpeaker->getLocalizedStrFromID("find-status-cannot-find", L"Find: Can't find the text \"$STR_REPLACE$\"");
wstring newTxt2find = stringReplace(txt2find, L"&", L"&&");
@@ -2983,7 +3035,6 @@ bool FindReplaceDlg::processFindNext(const wchar_t *txt2find, const FindOption *
// Show a calltip for a zero length match
if (start == end)
{
- NativeLangSpeaker* pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
wstring msg = pNativeSpeaker->getLocalizedStrFromID("find-regex-zero-length-match", L"zero length match");
msg = L"^ " + msg;
(*_ppEditView)->showCallTip(start, msg.c_str());
@@ -3022,6 +3073,8 @@ bool FindReplaceDlg::processReplace(const wchar_t *txt2find, const wchar_t *txt2
FindStatus status;
moreMatches = processFindNext(txt2find, &replaceOptions, &status, FINDNEXTTYPE_FINDNEXTFORREPLACE);
+ NativeLangSpeaker* pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
+
if (moreMatches)
{
Sci_CharacterRangeFull nextFind = (*_ppEditView)->getSelection();
@@ -3056,8 +3109,6 @@ bool FindReplaceDlg::processReplace(const wchar_t *txt2find, const wchar_t *txt2
}
(*_ppEditView)->execute(SCI_SETSEL, start + replacedLen, start + replacedLen);
- NativeLangSpeaker* pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
-
NppParameters& nppParam = NppParameters::getInstance();
const NppGUI& nppGui = nppParam.getNppGUI();
@@ -3098,7 +3149,6 @@ bool FindReplaceDlg::processReplace(const wchar_t *txt2find, const wchar_t *txt2
{
if (_statusbarTooltipMsg.empty()) // Tooltip message non-empty means there's a find problem - so we keep the message as it is and not erase it
{
- NativeLangSpeaker* pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
wstring msg = pNativeSpeaker->getLocalizedStrFromID("find-status-replace-not-found", L"Replace: no occurrence was found");
msg += L" ";
diff --git a/PowerEditor/src/ScintillaComponent/FindReplaceDlg.h b/PowerEditor/src/ScintillaComponent/FindReplaceDlg.h
index bf7c932e2..0a88d810d 100644
--- a/PowerEditor/src/ScintillaComponent/FindReplaceDlg.h
+++ b/PowerEditor/src/ScintillaComponent/FindReplaceDlg.h
@@ -484,6 +484,8 @@ private:
std::vector _reduce2hide_fip = { IDD_FINDINFILES_FILTERS_STATIC, IDD_FINDINFILES_FILTERS_COMBO, IDCANCEL };
std::vector _reduce2hide_mark = { IDC_MARKLINE_CHECK, IDC_PURGE_CHECK, IDC_IN_SELECTION_CHECK, IDC_REPLACEINSELECTION, IDC_COPY_MARKED_TEXT, IDCANCEL };
+ ControlInfoTip _maxLenOnSearchTip;
+
void enableFindDlgItem(int dlgItemID, bool isEnable = true);
void showFindDlgItem(int dlgItemID, bool isShow = true);