diff --git a/gui/images/find-replace.svg b/gui/images/find-replace.svg
new file mode 100644
index 0000000..597e290
--- /dev/null
+++ b/gui/images/find-replace.svg
@@ -0,0 +1,1020 @@
+
+
+
diff --git a/gui/images/find.svg b/gui/images/find.svg
new file mode 100644
index 0000000..63710a1
--- /dev/null
+++ b/gui/images/find.svg
@@ -0,0 +1,394 @@
+
+
+
diff --git a/src/gui/i18napp.cpp b/src/gui/i18napp.cpp
index 9d99c91..6111960 100644
--- a/src/gui/i18napp.cpp
+++ b/src/gui/i18napp.cpp
@@ -32,6 +32,8 @@ I18NArtProvider::I18NArtProvider()
{ wxART_PASTE, L"images/paste.svg" },
{ wxART_REDO, L"images/redo.svg" },
{ wxART_UNDO, L"images/undo.svg" },
+ { wxART_FIND, L"images/find.svg" },
+ { wxART_FIND_AND_REPLACE, L"images/find-replace.svg" },
{ L"ID_STRING_INFO", L"images/string-info.svg" },
{ L"ID_CONVERT_STRING", L"images/convert-text.svg" },
{ L"ID_SELECT_ALL", L"images/select-all.svg" },
diff --git a/src/gui/i18nframe.cpp b/src/gui/i18nframe.cpp
index 09f2c3d..c383416 100644
--- a/src/gui/i18nframe.cpp
+++ b/src/gui/i18nframe.cpp
@@ -61,6 +61,11 @@ void I18NFrame::InitControls()
wxDefaultSize, wxRIBBON_PANEL_NO_AUTO_MINIMISE);
m_editBar = new wxRibbonButtonBar(editPanel);
+ m_editBar->AddButton(
+ wxID_FIND, _(L"Find"),
+ wxArtProvider::GetBitmap(wxART_FIND, wxART_OTHER, FromDIP(wxSize{ 32, 32 }))
+ .ConvertToImage());
+
m_editBar->AddButton(
wxID_PASTE, _(L"Paste"),
wxArtProvider::GetBitmap(wxART_PASTE, wxART_OTHER, FromDIP(wxSize{ 32, 32 }))
@@ -352,6 +357,9 @@ void I18NFrame::InitControls()
wxAcceleratorTable accelTable(std::size(accelEntries), accelEntries);
SetAcceleratorTable(accelTable);
+ Bind(wxEVT_FIND, &I18NFrame::OnFind, this);
+ Bind(wxEVT_FIND_NEXT, &I18NFrame::OnFind, this);
+ Bind(wxEVT_FIND_CLOSE, &I18NFrame::OnFind, this);
Bind(wxEVT_CLOSE_WINDOW,
[this](wxCloseEvent& event)
{
@@ -359,6 +367,19 @@ void I18NFrame::InitControls()
SaveProjectIfNeeded();
event.Skip();
});
+ Bind(
+ wxEVT_RIBBONBUTTONBAR_CLICKED,
+ [this]([[maybe_unused]] wxCommandEvent&)
+ {
+ if (m_findDlg == nullptr)
+ {
+ m_findDlg = new wxFindReplaceDialog(this, &m_findData, _(L"Find"));
+ }
+
+ m_findDlg->Show();
+ m_findDlg->SetFocus();
+ },
+ wxID_FIND);
Bind(wxEVT_RIBBONBUTTONBAR_CLICKED, &I18NFrame::OnNew, this, wxID_NEW);
Bind(wxEVT_RIBBONBUTTONBAR_CLICKED, &I18NFrame::OnOpen, this, wxID_OPEN);
Bind(wxEVT_RIBBONBUTTONBAR_CLICKED, &I18NFrame::OnSave, this, wxID_SAVE);
@@ -1649,3 +1670,53 @@ void I18NFrame::OnClose(wxCloseEvent& event)
wxGetApp().m_defaultOptions.m_editorHeight = ToDIP(m_editor->GetSize().GetHeight());
event.Skip();
}
+
+void I18NFrame::OnFind(wxFindDialogEvent& event)
+ {
+ // if they were just hitting Cancel then close
+ if (event.GetEventType() == wxEVT_FIND_CLOSE)
+ {
+ if (m_findDlg != nullptr)
+ {
+ m_findDlg->Destroy();
+ m_findDlg = nullptr;
+ }
+ return;
+ }
+
+ const int flags{ event.GetFlags() };
+ int searchFlags{ 0 };
+ if (flags & wxFR_MATCHCASE)
+ {
+ searchFlags = searchFlags | wxSTC_FIND_MATCHCASE;
+ }
+ if (flags & wxFR_WHOLEWORD)
+ {
+ searchFlags = searchFlags | wxSTC_FIND_WHOLEWORD;
+ }
+
+ m_editor->SearchAnchor();
+ long selStart, selEnd;
+ m_editor->GetSelection(&selStart, &selEnd);
+ long foundPos{ wxSTC_INVALID_POSITION };
+ if (flags & wxFR_DOWN)
+ {
+ m_editor->SetSelection(selEnd, selEnd);
+ m_editor->SearchAnchor();
+ foundPos = m_editor->SearchNext(searchFlags, event.GetFindString());
+ m_editor->SearchAnchor();
+ m_editor->EnsureCaretVisible();
+ }
+ else
+ {
+ foundPos = m_editor->SearchPrev(searchFlags, event.GetFindString());
+ m_editor->SearchAnchor();
+ m_editor->EnsureCaretVisible();
+ }
+
+ if (foundPos == wxSTC_INVALID_POSITION)
+ {
+ wxMessageBox(_(L"No further occurrences found."), _(L"Item Not Found"),
+ wxOK | wxICON_INFORMATION, this);
+ }
+ }
diff --git a/src/gui/i18nframe.h b/src/gui/i18nframe.h
index 8e354d2..c99efe5 100644
--- a/src/gui/i18nframe.h
+++ b/src/gui/i18nframe.h
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -82,14 +83,15 @@ class I18NFrame : public wxFrame
void OnConvertString([[maybe_unused]] wxCommandEvent&);
void OnAbout([[maybe_unused]] wxCommandEvent&);
void OnHelp([[maybe_unused]] wxCommandEvent&);
-
void OnClose(wxCloseEvent& event);
+ void OnFind(wxFindDialogEvent& event);
private:
void OnEditButtonClicked(wxRibbonButtonBarEvent& event);
void EnableEditBar(const bool enable)
{
+ m_editBar->EnableButton(wxID_FIND, enable);
m_editBar->EnableButton(wxID_UNDO, enable);
m_editBar->EnableButton(wxID_REDO, enable);
m_editBar->EnableButton(wxID_PASTE, enable);
@@ -137,6 +139,9 @@ class I18NFrame : public wxFrame
wxString m_activeSourceFile;
bool m_promptForFileSave{ true };
+ wxFindReplaceData m_findData;
+ wxFindReplaceDialog* m_findDlg{ nullptr };
+
bool m_projectDirty{ false };
wxString m_activeProjectFilePath;