mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-12-06 21:29:41 +01:00
Use modern subclass on FindReplaceDlg combo boxes
- fix regression with temp search text not recovered - fix warnings with overloaded virtual functions Fix #17202, close #17203
This commit is contained in:
parent
0745cd922d
commit
ebf3657d67
@ -15,7 +15,6 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
#include <shlwapi.h>
|
|
||||||
#include "FindReplaceDlg.h"
|
#include "FindReplaceDlg.h"
|
||||||
#include "ScintillaEditView.h"
|
#include "ScintillaEditView.h"
|
||||||
#include "Notepad_plus_msgs.h"
|
#include "Notepad_plus_msgs.h"
|
||||||
@ -23,6 +22,16 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Utf8.h"
|
#include "Utf8.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <commctrl.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "NppConstants.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
FindOption * FindReplaceDlg::_env;
|
FindOption * FindReplaceDlg::_env;
|
||||||
@ -257,7 +266,6 @@ void Searching::displaySectionCentered(size_t posStart, size_t posEnd, Scintilla
|
|||||||
}
|
}
|
||||||
|
|
||||||
WNDPROC FindReplaceDlg::originalFinderProc = nullptr;
|
WNDPROC FindReplaceDlg::originalFinderProc = nullptr;
|
||||||
WNDPROC FindReplaceDlg::originalComboEditProc = nullptr;
|
|
||||||
|
|
||||||
FindReplaceDlg::~FindReplaceDlg()
|
FindReplaceDlg::~FindReplaceDlg()
|
||||||
{
|
{
|
||||||
@ -1572,20 +1580,13 @@ intptr_t CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARA
|
|||||||
// Change handler of edit element in the comboboxes to support Ctrl+Backspace
|
// Change handler of edit element in the comboboxes to support Ctrl+Backspace
|
||||||
COMBOBOXINFO cbinfo{};
|
COMBOBOXINFO cbinfo{};
|
||||||
cbinfo.cbSize = sizeof(COMBOBOXINFO);
|
cbinfo.cbSize = sizeof(COMBOBOXINFO);
|
||||||
GetComboBoxInfo(hFindCombo, &cbinfo);
|
for (const auto& hCombo : { hFindCombo, hReplaceCombo, hFiltersCombo, hDirCombo })
|
||||||
if (!cbinfo.hwndItem) return FALSE;
|
{
|
||||||
|
if (::GetComboBoxInfo(hCombo, &cbinfo) == FALSE || cbinfo.hwndItem == nullptr)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
originalComboEditProc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(cbinfo.hwndItem, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(comboEditProc)));
|
::SetWindowSubclass(cbinfo.hwndItem, FindReplaceDlg::ComboEditProc, static_cast<UINT_PTR>(SubclassID::first), reinterpret_cast<DWORD_PTR>(cbinfo.hwndCombo));
|
||||||
SetWindowLongPtr(cbinfo.hwndItem, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(cbinfo.hwndCombo));
|
}
|
||||||
GetComboBoxInfo(hReplaceCombo, &cbinfo);
|
|
||||||
SetWindowLongPtr(cbinfo.hwndItem, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(comboEditProc));
|
|
||||||
SetWindowLongPtr(cbinfo.hwndItem, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(cbinfo.hwndCombo));
|
|
||||||
GetComboBoxInfo(hFiltersCombo, &cbinfo);
|
|
||||||
SetWindowLongPtr(cbinfo.hwndItem, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(comboEditProc));
|
|
||||||
SetWindowLongPtr(cbinfo.hwndItem, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(cbinfo.hwndCombo));
|
|
||||||
GetComboBoxInfo(hDirCombo, &cbinfo);
|
|
||||||
SetWindowLongPtr(cbinfo.hwndItem, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(comboEditProc));
|
|
||||||
SetWindowLongPtr(cbinfo.hwndItem, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(cbinfo.hwndCombo));
|
|
||||||
|
|
||||||
setDpi();
|
setDpi();
|
||||||
|
|
||||||
@ -4881,22 +4882,57 @@ LRESULT FAR PASCAL FindReplaceDlg::finderProc(HWND hwnd, UINT message, WPARAM wP
|
|||||||
return CallWindowProc(originalFinderProc, hwnd, message, wParam, lParam);
|
return CallWindowProc(originalFinderProc, hwnd, message, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT FAR PASCAL FindReplaceDlg::comboEditProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK FindReplaceDlg::ComboEditProc(
|
||||||
|
HWND hWnd,
|
||||||
|
UINT uMsg,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam,
|
||||||
|
UINT_PTR uIdSubclass,
|
||||||
|
DWORD_PTR dwRefData
|
||||||
|
)
|
||||||
{
|
{
|
||||||
HWND hwndCombo = reinterpret_cast<HWND>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
auto* hwndCombo = reinterpret_cast<HWND>(dwRefData);
|
||||||
|
|
||||||
bool isDropped = ::SendMessage(hwndCombo, CB_GETDROPPEDSTATE, 0, 0) != 0;
|
static constexpr size_t strSize = FINDREPLACE_MAXLENGTH;
|
||||||
|
static auto draftString = []() -> std::unique_ptr<wchar_t[]>
|
||||||
const size_t strSize = FINDREPLACE_MAXLENGTH;
|
|
||||||
auto draftString = std::make_unique<wchar_t[]>(strSize);
|
|
||||||
std::fill_n(draftString.get(), strSize, L'\0');
|
|
||||||
|
|
||||||
if (isDropped && (message == WM_KEYDOWN) && (wParam == VK_DELETE))
|
|
||||||
{
|
{
|
||||||
|
auto ptr = std::make_unique<wchar_t[]>(strSize);
|
||||||
|
std::fill_n(ptr.get(), strSize, L'\0');
|
||||||
|
return ptr;
|
||||||
|
}();
|
||||||
|
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WM_NCDESTROY:
|
||||||
|
{
|
||||||
|
::RemoveWindowSubclass(hWnd, FindReplaceDlg::ComboEditProc, uIdSubclass);
|
||||||
|
draftString.reset(nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
{
|
||||||
|
if (wParam != VK_DELETE && wParam != VK_DOWN && wParam != VK_UP)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
auto curSel = ::SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
|
auto curSel = ::SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
|
||||||
if (curSel != CB_ERR)
|
switch (wParam)
|
||||||
{
|
{
|
||||||
auto itemsRemaining = ::SendMessage(hwndCombo, CB_DELETESTRING, curSel, 0);
|
case VK_DELETE:
|
||||||
|
{
|
||||||
|
if (::SendMessage(hwndCombo, CB_GETDROPPEDSTATE, 0, 0) == FALSE) // isNotDropped
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curSel == CB_ERR)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto itemsRemaining = ::SendMessage(hwndCombo, CB_DELETESTRING, curSel, 0);
|
||||||
// if we close the dropdown and reopen it, it will be correctly-sized for remaining items
|
// if we close the dropdown and reopen it, it will be correctly-sized for remaining items
|
||||||
::SendMessage(hwndCombo, CB_SHOWDROPDOWN, FALSE, 0);
|
::SendMessage(hwndCombo, CB_SHOWDROPDOWN, FALSE, 0);
|
||||||
if (itemsRemaining > 0)
|
if (itemsRemaining > 0)
|
||||||
@ -4910,37 +4946,60 @@ LRESULT FAR PASCAL FindReplaceDlg::comboEditProc(HWND hwnd, UINT message, WPARAM
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (message == WM_CHAR && wParam == 0x7F) // ASCII "DEL" (Ctrl+Backspace)
|
case VK_DOWN:
|
||||||
{
|
{
|
||||||
delLeftWordInEdit(hwnd);
|
if (curSel == CB_ERR)
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (message == WM_SETFOCUS)
|
|
||||||
{
|
|
||||||
draftString[0] = '\0';
|
|
||||||
}
|
|
||||||
else if ((message == WM_KEYDOWN) && (wParam == VK_DOWN) && (::SendMessage(hwndCombo, CB_GETCURSEL, 0, 0) == CB_ERR))
|
|
||||||
{
|
{
|
||||||
// down key on unselected combobox item -> store current edit text as draft
|
// down key on unselected combobox item -> store current edit text as draft
|
||||||
::SendMessage(hwndCombo, WM_GETTEXT, FINDREPLACE_MAXLENGTH, reinterpret_cast<LPARAM>(draftString.get()));
|
::SendMessage(hwndCombo, WM_GETTEXT, WPARAM{ strSize }, reinterpret_cast<LPARAM>(draftString.get()));
|
||||||
}
|
}
|
||||||
else if ((message == WM_KEYDOWN) && (wParam == VK_UP) && (::SendMessage(hwndCombo, CB_GETCURSEL, 0, 0) == CB_ERR))
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VK_UP:
|
||||||
|
{
|
||||||
|
if (curSel == CB_ERR)
|
||||||
{
|
{
|
||||||
// up key on unselected combobox item -> no change but select current edit text
|
// up key on unselected combobox item -> no change but select current edit text
|
||||||
::SendMessage(hwndCombo, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
|
::SendMessage(hwndCombo, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if ((message == WM_KEYDOWN) && (wParam == VK_UP) && (::SendMessage(hwndCombo, CB_GETCURSEL, 0, 0) == 0) && std::wcslen(draftString.get()) > 0)
|
|
||||||
|
if ((curSel == 0) && std::wcslen(draftString.get()) > 0)
|
||||||
{
|
{
|
||||||
// up key on top selected combobox item -> restore draft to edit text
|
// up key on top selected combobox item -> restore draft to edit text
|
||||||
::SendMessage(hwndCombo, CB_SETCURSEL, WPARAM(-1), 0);
|
::SendMessage(hwndCombo, CB_SETCURSEL, static_cast<WPARAM>(-1), 0);
|
||||||
::SendMessage(hwndCombo, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(draftString.get()));
|
::SendMessage(hwndCombo, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(draftString.get()));
|
||||||
::SendMessage(hwndCombo, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
|
::SendMessage(hwndCombo, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (message == WM_PASTE)
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_CHAR:
|
||||||
|
{
|
||||||
|
if (wParam == 0x7F) // ASCII DEL (Ctrl+Backspace)
|
||||||
|
{
|
||||||
|
delLeftWordInEdit(hWnd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_SETFOCUS:
|
||||||
|
{
|
||||||
|
draftString[0] = L'\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_PASTE:
|
||||||
{
|
{
|
||||||
// needed to allow CR (i.e., multiline) into combobox text;
|
// needed to allow CR (i.e., multiline) into combobox text;
|
||||||
// (the default functionality terminates the paste at the first CR character)
|
// (the default functionality terminates the paste at the first CR character)
|
||||||
@ -4950,24 +5009,24 @@ LRESULT FAR PASCAL FindReplaceDlg::comboEditProc(HWND hwnd, UINT message, WPARAM
|
|||||||
HWND hReplaceWithCombo = ::GetDlgItem(hParent, IDREPLACEWITH);
|
HWND hReplaceWithCombo = ::GetDlgItem(hParent, IDREPLACEWITH);
|
||||||
if ((hwndCombo == hFindWhatCombo) || (hwndCombo == hReplaceWithCombo))
|
if ((hwndCombo == hFindWhatCombo) || (hwndCombo == hReplaceWithCombo))
|
||||||
{
|
{
|
||||||
CLIPFORMAT cfColumnSelect = static_cast<CLIPFORMAT>(::RegisterClipboardFormat(L"MSDEVColumnSelect"));
|
const auto cfColumnSelect = static_cast<CLIPFORMAT>(::RegisterClipboardFormatW(L"MSDEVColumnSelect"));
|
||||||
if (!::IsClipboardFormatAvailable(cfColumnSelect))
|
if (::IsClipboardFormatAvailable(cfColumnSelect) == FALSE)
|
||||||
{
|
{
|
||||||
wstring clipboardText = strFromClipboard();
|
const auto clipboardText = std::wstring{ strFromClipboard() };
|
||||||
if (!clipboardText.empty())
|
if (!clipboardText.empty())
|
||||||
{
|
{
|
||||||
HWND hEdit = GetWindow(hwndCombo, GW_CHILD);
|
::SendMessage(hWnd, EM_REPLACESEL, TRUE, reinterpret_cast<LPARAM>(clipboardText.c_str()));
|
||||||
if (hEdit)
|
|
||||||
{
|
|
||||||
::SendMessage(hEdit, EM_REPLACESEL, TRUE, (LPARAM)clipboardText.c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return CallWindowProc(originalComboEditProc, hwnd, message, wParam, lParam);
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ::DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FindReplaceDlg::hideOrShowCtrl4reduceOrNormalMode(DIALOG_TYPE dlgT)
|
void FindReplaceDlg::hideOrShowCtrl4reduceOrNormalMode(DIALOG_TYPE dlgT)
|
||||||
|
|||||||
@ -112,12 +112,13 @@ friend class FindReplaceDlg;
|
|||||||
public:
|
public:
|
||||||
Finder() : DockingDlgInterface(IDD_FINDRESULT) {
|
Finder() : DockingDlgInterface(IDD_FINDRESULT) {
|
||||||
_markingsStruct._length = 0;
|
_markingsStruct._length = 0;
|
||||||
_markingsStruct._markings = NULL;
|
_markingsStruct._markings = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Finder() override {
|
~Finder() override {
|
||||||
_scintView.destroy();
|
_scintView.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(HINSTANCE hInst, HWND hPere, ScintillaEditView **ppEditView) {
|
void init(HINSTANCE hInst, HWND hPere, ScintillaEditView **ppEditView) {
|
||||||
DockingDlgInterface::init(hInst, hPere);
|
DockingDlgInterface::init(hInst, hPere);
|
||||||
_ppEditView = ppEditView;
|
_ppEditView = ppEditView;
|
||||||
@ -186,6 +187,8 @@ private:
|
|||||||
|
|
||||||
std::wstring _prefixLineStr;
|
std::wstring _prefixLineStr;
|
||||||
|
|
||||||
|
using DockingDlgInterface::init;
|
||||||
|
|
||||||
void setFinderReadOnly(bool isReadOnly) {
|
void setFinderReadOnly(bool isReadOnly) {
|
||||||
_scintView.execute(SCI_SETREADONLY, isReadOnly);
|
_scintView.execute(SCI_SETREADONLY, isReadOnly);
|
||||||
}
|
}
|
||||||
@ -246,8 +249,6 @@ private:
|
|||||||
void writeOptions();
|
void writeOptions();
|
||||||
};
|
};
|
||||||
|
|
||||||
LRESULT run_swapButtonProc(WNDPROC oldEditProc, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
class FindReplaceDlg : public StaticDialog
|
class FindReplaceDlg : public StaticDialog
|
||||||
{
|
{
|
||||||
friend class FindIncrementDlg;
|
friend class FindIncrementDlg;
|
||||||
@ -328,7 +329,7 @@ public :
|
|||||||
void changeTabName(DIALOG_TYPE index, const wchar_t *name2change) {
|
void changeTabName(DIALOG_TYPE index, const wchar_t *name2change) {
|
||||||
TCITEM tie{};
|
TCITEM tie{};
|
||||||
tie.mask = TCIF_TEXT;
|
tie.mask = TCIF_TEXT;
|
||||||
tie.pszText = (wchar_t *)name2change;
|
tie.pszText = const_cast<wchar_t*>(name2change);
|
||||||
TabCtrl_SetItem(_tab.getHSelf(), index, &tie);
|
TabCtrl_SetItem(_tab.getHSelf(), index, &tie);
|
||||||
|
|
||||||
wchar_t label[MAX_PATH]{};
|
wchar_t label[MAX_PATH]{};
|
||||||
@ -426,9 +427,8 @@ protected :
|
|||||||
void resizeDialogElements();
|
void resizeDialogElements();
|
||||||
intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) override;
|
intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) override;
|
||||||
static WNDPROC originalFinderProc;
|
static WNDPROC originalFinderProc;
|
||||||
static WNDPROC originalComboEditProc;
|
|
||||||
|
|
||||||
static LRESULT FAR PASCAL comboEditProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
static LRESULT CALLBACK ComboEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
|
||||||
|
|
||||||
// Window procedure for the finder
|
// Window procedure for the finder
|
||||||
static LRESULT FAR PASCAL finderProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
static LRESULT FAR PASCAL finderProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
@ -486,6 +486,9 @@ private:
|
|||||||
|
|
||||||
ControlInfoTip _maxLenOnSearchTip;
|
ControlInfoTip _maxLenOnSearchTip;
|
||||||
|
|
||||||
|
using Window::init;
|
||||||
|
using StaticDialog::create;
|
||||||
|
|
||||||
void enableFindDlgItem(int dlgItemID, bool isEnable = true);
|
void enableFindDlgItem(int dlgItemID, bool isEnable = true);
|
||||||
void showFindDlgItem(int dlgItemID, bool isShow = true);
|
void showFindDlgItem(int dlgItemID, bool isShow = true);
|
||||||
|
|
||||||
@ -538,6 +541,7 @@ class FindIncrementDlg : public StaticDialog
|
|||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
FindIncrementDlg() = default;
|
FindIncrementDlg() = default;
|
||||||
|
|
||||||
void init(HINSTANCE hInst, HWND hPere, FindReplaceDlg *pFRDlg, bool isRTL = false);
|
void init(HINSTANCE hInst, HWND hPere, FindReplaceDlg *pFRDlg, bool isRTL = false);
|
||||||
void destroy() override;
|
void destroy() override;
|
||||||
void display(bool toShow = true) const override;
|
void display(bool toShow = true) const override;
|
||||||
@ -561,6 +565,8 @@ private :
|
|||||||
ReBar* _pRebar = nullptr;
|
ReBar* _pRebar = nullptr;
|
||||||
REBARBANDINFO _rbBand{};
|
REBARBANDINFO _rbBand{};
|
||||||
|
|
||||||
|
using Window::init;
|
||||||
|
|
||||||
intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) override;
|
intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) override;
|
||||||
void markSelectedTextInc(bool enable, FindOption *opt = NULL);
|
void markSelectedTextInc(bool enable, FindOption *opt = NULL);
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user