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);