diff --git a/bin/app/data/color_schemes/bad_rainbow.xml b/bin/app/data/color_schemes/bad_rainbow.xml
index aa837bc2..d6e97900 100644
--- a/bin/app/data/color_schemes/bad_rainbow.xml
+++ b/bin/app/data/color_schemes/bad_rainbow.xml
@@ -181,7 +181,7 @@
#FFFF0000
-
+
#C2AFEF
#3D3D3D
@@ -189,7 +189,17 @@
#987CEA
-
+
+
+
+ transparent
+ #D2FA6E
+ #262626
+
+
+ #FA6EF3
+
+
@@ -436,6 +446,14 @@
+
+
+ #494949
+ #D4D4D4
+ #878787
+ #878787
+
+
#494949
@@ -452,10 +470,22 @@
#7B7B7B
-
- #494949
- #D4D4D4
- #878787
- #878787
-
+
+
+ #808080
+
+ #494949
+ #D4D4D4
+ #A0A0A0
+
+ white
+
+
diff --git a/bin/app/data/color_schemes/bright.xml b/bin/app/data/color_schemes/bright.xml
index e603b443..3adbfe72 100644
--- a/bin/app/data/color_schemes/bright.xml
+++ b/bin/app/data/color_schemes/bright.xml
@@ -179,7 +179,7 @@
#CCFF0000
-
+
#C7C7E2
#000000
@@ -187,7 +187,17 @@
#ABABDD
-
+
+
+
+ transparent
+ #8ADBBC
+ #000000
+
+
+ #DB97C2
+
+
@@ -397,15 +407,14 @@
-
- white
-
+
white
black
#878787
#878787
+
white
@@ -422,4 +431,22 @@
grey
+
+
+ #E0E0E0
+
+ white
+ black
+ #A0A0A0
+
+ black
+
+
diff --git a/bin/app/data/color_schemes/dark.xml b/bin/app/data/color_schemes/dark.xml
index 27d1d63f..54faec61 100644
--- a/bin/app/data/color_schemes/dark.xml
+++ b/bin/app/data/color_schemes/dark.xml
@@ -181,7 +181,7 @@
#FFFF0000
-
+
#207EA8
#F7F7F7
@@ -190,7 +190,17 @@
#006D93
#134B63
-
+
+
+
+ transparent
+ #6EDB42
+ #000000
+
+
+ #FF52E8
+
+
@@ -407,6 +417,14 @@
+
+
+ #272728
+ white
+ #878787
+ #878787
+
+
#272728
@@ -423,10 +441,22 @@
#969696
-
- #272728
- white
- #878787
- #878787
-
+
+
+ #777777
+
+ #272728
+ #F7F7F7
+ #A0A0A0
+
+ #F7F7F7
+
+
diff --git a/bin/app/data/gui/screen_search_view/images/close.png b/bin/app/data/gui/screen_search_view/images/close.png
new file mode 100755
index 00000000..e7ac9b40
Binary files /dev/null and b/bin/app/data/gui/screen_search_view/images/close.png differ
diff --git a/bin/app/data/gui/screen_search_view/screen_search_view.css b/bin/app/data/gui/screen_search_view/screen_search_view.css
new file mode 100644
index 00000000..80258f2c
--- /dev/null
+++ b/bin/app/data/gui/screen_search_view/screen_search_view.css
@@ -0,0 +1,82 @@
+#screen_search_bar {
+ border: none;
+}
+
+#screen_search_box {
+ padding-left: 10;
+ border-top: 1px solid #BEBEBE;
+ background: ;
+}
+
+#search_box {
+ background: ;
+ border: none;
+ color: ;
+ font-family: ;
+ font-size: px;
+ margin: 4px 0;
+ max-width: px;
+ min-height: 20px;
+ padding: 1px 0px 1px 0px;
+}
+
+#match_label {
+ border: none;
+ background: ;
+ color: ;
+ font-size: px;
+ margin: 4px 0;
+ padding-right: 4px;
+ text-align: right;
+ min-width: px;
+ min-height: 20px;
+ max-height: 40px;
+}
+
+#search_button, #prev_button, #next_button, #close_button {
+ background: ;
+ width: 20px;
+ min-height: 20px;
+ max-height: 40px;
+ border-radius: 0;
+ margin: 4px 0;
+}
+
+#search_button {
+ border-bottom-left-radius: 10px;
+ border-top-left-radius: 10px;
+ padding-left: 2px;
+}
+
+#prev_button {
+ margin: 4px 1px;
+}
+
+#next_button {
+ border-bottom-right-radius: 10px;
+ border-top-right-radius: 10px;
+}
+
+#prev_button:disabled, #next_button:disabled {
+ background: ;
+}
+
+#prev_button:hover, #next_button:hover {
+ background: ;
+}
+
+#prev_button:pressed, #next_button:pressed {
+ background: ;
+}
+
+#close_button {
+ background: transparent;
+ margin: 4px 6px;
+ padding-top: 1px;
+}
+
+#filter_checkbox {
+ color: ;
+ margin-left: 20px;
+ font-size: px;
+}
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index 6745d73e..503ab534 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -10,6 +10,7 @@ add_files(
component/controller/helper/ListLayouter.h
component/controller/helper/NetworkProtocolHelper.cpp
component/controller/helper/NetworkProtocolHelper.h
+ component/controller/helper/ScreenSearchInterfaces.h
component/controller/helper/SnippetMerger.cpp
component/controller/helper/SnippetMerger.h
component/controller/helper/TrailLayouter.cpp
@@ -32,6 +33,8 @@ add_files(
component/controller/LogController.h
component/controller/RefreshController.cpp
component/controller/RefreshController.h
+ component/controller/ScreenSearchController.cpp
+ component/controller/ScreenSearchController.h
component/controller/SearchController.cpp
component/controller/SearchController.h
component/controller/StatusBarController.cpp
@@ -66,6 +69,8 @@ add_files(
component/view/MainView.h
component/view/RefreshView.cpp
component/view/RefreshView.h
+ component/view/ScreenSearchView.cpp
+ component/view/ScreenSearchView.h
component/view/SearchView.cpp
component/view/SearchView.h
component/view/StatusBarView.cpp
diff --git a/src/lib/component/Component.cpp b/src/lib/component/Component.cpp
index b5f580d8..38d1a415 100644
--- a/src/lib/component/Component.cpp
+++ b/src/lib/component/Component.cpp
@@ -30,3 +30,13 @@ Component::~Component()
m_view->setComponent(NULL);
}
}
+
+Controller* Component::getControllerPtr() const
+{
+ return m_controller.get();
+}
+
+View* Component::getViewPtr() const
+{
+ return m_view.get();
+}
diff --git a/src/lib/component/Component.h b/src/lib/component/Component.h
index c6d6c5fa..a7ad841a 100644
--- a/src/lib/component/Component.h
+++ b/src/lib/component/Component.h
@@ -15,9 +15,13 @@ public:
template
ControllerType* getController() const;
+ Controller* getControllerPtr() const;
+
template
ViewType* getView() const;
+ View* getViewPtr() const;
+
private:
const std::shared_ptr m_controller;
const std::shared_ptr m_view;
diff --git a/src/lib/component/ComponentFactory.cpp b/src/lib/component/ComponentFactory.cpp
index 882ffa67..ceda2354 100644
--- a/src/lib/component/ComponentFactory.cpp
+++ b/src/lib/component/ComponentFactory.cpp
@@ -8,6 +8,7 @@
#include "component/controller/GraphController.h"
#include "component/controller/LogController.h"
#include "component/controller/RefreshController.h"
+#include "component/controller/ScreenSearchController.h"
#include "component/controller/SearchController.h"
#include "component/controller/StatusBarController.h"
#include "component/controller/StatusController.h"
@@ -18,6 +19,7 @@
#include "component/view/ErrorView.h"
#include "component/view/LogView.h"
#include "component/view/RefreshView.h"
+#include "component/view/ScreenSearchView.h"
#include "component/view/SearchView.h"
#include "component/view/StatusBarView.h"
#include "component/view/StatusView.h"
@@ -58,14 +60,6 @@ std::shared_ptr ComponentFactory::createActivationComponent()
return std::make_shared(nullptr, controller);
}
-std::shared_ptr ComponentFactory::createTooltipComponent(ViewLayout* viewLayout)
-{
- std::shared_ptr view = m_viewFactory->createTooltipView(viewLayout);
- std::shared_ptr controller = std::make_shared(m_storageAccess);
-
- return std::make_shared(view, controller);
-}
-
std::shared_ptr ComponentFactory::createBookmarkComponent(ViewLayout* viewLayout)
{
std::shared_ptr view = m_viewFactory->createBookmarkView(viewLayout);
@@ -90,6 +84,14 @@ std::shared_ptr ComponentFactory::createErrorComponent(ViewLayout* vi
return std::make_shared(view, controller);
}
+std::shared_ptr ComponentFactory::createGraphComponent(ViewLayout* viewLayout)
+{
+ std::shared_ptr view = m_viewFactory->createGraphView(viewLayout);
+ std::shared_ptr controller = std::make_shared(m_storageAccess);
+
+ return std::make_shared(view, controller);
+}
+
std::shared_ptr ComponentFactory::createLogComponent(ViewLayout* viewLayout)
{
std::shared_ptr view = m_viewFactory->createLogView(viewLayout);
@@ -100,14 +102,6 @@ std::shared_ptr ComponentFactory::createLogComponent(ViewLayout* view
return std::make_shared(view, controller);
}
-std::shared_ptr ComponentFactory::createGraphComponent(ViewLayout* viewLayout)
-{
- std::shared_ptr view = m_viewFactory->createGraphView(viewLayout);
- std::shared_ptr controller = std::make_shared(m_storageAccess);
-
- return std::make_shared(view, controller);
-}
-
std::shared_ptr ComponentFactory::createRefreshComponent(ViewLayout* viewLayout)
{
std::shared_ptr view = m_viewFactory->createRefreshView(viewLayout);
@@ -116,18 +110,18 @@ std::shared_ptr ComponentFactory::createRefreshComponent(ViewLayout*
return std::make_shared(view, controller);
}
-std::shared_ptr ComponentFactory::createSearchComponent(ViewLayout* viewLayout)
+std::shared_ptr ComponentFactory::createScreenSearchComponent(ViewLayout* viewLayout)
{
- std::shared_ptr view = m_viewFactory->createSearchView(viewLayout);
- std::shared_ptr controller = std::make_shared(m_storageAccess);
+ std::shared_ptr view = m_viewFactory->createScreenSearchView(viewLayout);
+ std::shared_ptr controller = std::make_shared();
return std::make_shared(view, controller);
}
-std::shared_ptr ComponentFactory::createUndoRedoComponent(ViewLayout* viewLayout)
+std::shared_ptr ComponentFactory::createSearchComponent(ViewLayout* viewLayout)
{
- std::shared_ptr view = m_viewFactory->createUndoRedoView(viewLayout);
- std::shared_ptr controller = std::make_shared(m_storageAccess);
+ std::shared_ptr view = m_viewFactory->createSearchView(viewLayout);
+ std::shared_ptr controller = std::make_shared(m_storageAccess);
return std::make_shared(view, controller);
}
@@ -148,6 +142,22 @@ std::shared_ptr ComponentFactory::createStatusComponent(ViewLayout* v
return std::make_shared(view, controller);
}
+std::shared_ptr ComponentFactory::createTooltipComponent(ViewLayout* viewLayout)
+{
+ std::shared_ptr view = m_viewFactory->createTooltipView(viewLayout);
+ std::shared_ptr controller = std::make_shared(m_storageAccess);
+
+ return std::make_shared(view, controller);
+}
+
+std::shared_ptr ComponentFactory::createUndoRedoComponent(ViewLayout* viewLayout)
+{
+ std::shared_ptr view = m_viewFactory->createUndoRedoView(viewLayout);
+ std::shared_ptr controller = std::make_shared(m_storageAccess);
+
+ return std::make_shared(view, controller);
+}
+
ComponentFactory::ComponentFactory()
{
}
diff --git a/src/lib/component/ComponentFactory.h b/src/lib/component/ComponentFactory.h
index 433941b7..ccec633d 100644
--- a/src/lib/component/ComponentFactory.h
+++ b/src/lib/component/ComponentFactory.h
@@ -26,6 +26,7 @@ public:
std::shared_ptr createGraphComponent(ViewLayout* viewLayout);
std::shared_ptr createLogComponent(ViewLayout* viewLayout);
std::shared_ptr createRefreshComponent(ViewLayout* viewLayout);
+ std::shared_ptr createScreenSearchComponent(ViewLayout* viewLayout);
std::shared_ptr createSearchComponent(ViewLayout* viewLayout);
std::shared_ptr createStatusBarComponent(ViewLayout* viewLayout);
std::shared_ptr createStatusComponent(ViewLayout* viewLayout);
diff --git a/src/lib/component/ComponentManager.cpp b/src/lib/component/ComponentManager.cpp
index 62b35eaa..a3d4df65 100644
--- a/src/lib/component/ComponentManager.cpp
+++ b/src/lib/component/ComponentManager.cpp
@@ -1,6 +1,7 @@
#include "component/ComponentManager.h"
#include "component/controller/Controller.h"
+#include "component/controller/ScreenSearchController.h"
#include "component/view/CompositeView.h"
#include "component/view/DialogView.h"
#include "component/view/TabbedView.h"
@@ -52,6 +53,12 @@ void ComponentManager::setup(ViewLayout* viewLayout)
std::shared_ptr tooltipComponent = m_componentFactory->createTooltipComponent(viewLayout);
m_components.push_back(tooltipComponent);
+ std::shared_ptr screenSearchComponent = m_componentFactory->createScreenSearchComponent(viewLayout);
+ ScreenSearchController* screenSearchController = screenSearchComponent->getController();
+ screenSearchController->addResponder(dynamic_cast(graphComponent->getViewPtr()));
+ screenSearchController->addResponder(dynamic_cast(codeComponent->getViewPtr()));
+ m_components.push_back(screenSearchComponent);
+
m_dialogView = m_componentFactory->getViewFactory()->createDialogView(viewLayout, m_componentFactory->getStorageAccess());
std::shared_ptr tabbedView =
diff --git a/src/lib/component/controller/ScreenSearchController.cpp b/src/lib/component/controller/ScreenSearchController.cpp
new file mode 100644
index 00000000..e107cd18
--- /dev/null
+++ b/src/lib/component/controller/ScreenSearchController.cpp
@@ -0,0 +1,153 @@
+#include "component/controller/ScreenSearchController.h"
+
+#include "component/view/ScreenSearchView.h"
+
+ScreenSearchController::ScreenSearchController()
+{
+}
+
+ScreenSearchController::~ScreenSearchController()
+{
+}
+
+void ScreenSearchController::clear()
+{
+}
+
+void ScreenSearchController::foundMatches(ScreenSearchResponder* responder, size_t matchCount)
+{
+ if (matchCount)
+ {
+ std::lock_guard lock(m_matchMutex);
+
+ size_t responderId = getResponderId(responder);
+ if (!responderId)
+ {
+ return;
+ }
+
+ std::vector> newMatches;
+ for (size_t i = 0; i < matchCount; i++)
+ {
+ newMatches.push_back(std::make_pair(responderId, i));
+ }
+
+ size_t i = 0;
+ while (i < m_matches.size() && responderId > m_matches[i].first)
+ {
+ i++;
+ }
+
+ m_matches.insert(m_matches.begin() + i, newMatches.begin(), newMatches.end());
+ m_matchIndex = m_matches.size();
+ }
+
+ getView()->setMatchCount(m_matches.size());
+}
+
+void ScreenSearchController::addResponder(ScreenSearchResponder* responder)
+{
+ if (responder)
+ {
+ m_responders.push_back(responder);
+ getView()->addResponder(responder->getName());
+ }
+}
+
+void ScreenSearchController::search(const std::string& query, const std::set& responderNames)
+{
+ {
+ std::lock_guard lock(m_matchMutex);
+ m_matches.clear();
+ m_matchIndex = 0;
+ }
+
+ getView()->setMatchCount(0);
+
+ for (ScreenSearchResponder* responder : m_responders)
+ {
+ if (!responder->isVisible())
+ {
+ continue;
+ }
+
+ if (query.size() && responderNames.find(responder->getName()) != responderNames.end())
+ {
+ responder->findMatches(this, query);
+ }
+ else
+ {
+ responder->clearMatches();
+ }
+ }
+}
+
+void ScreenSearchController::activateMatch(bool next)
+{
+ std::lock_guard lock(m_matchMutex);
+ if (!m_matches.size())
+ {
+ return;
+ }
+
+ if (m_matchIndex != m_matches.size())
+ {
+ auto match = m_matches[m_matchIndex];
+ m_responders[match.first - 1]->deactivateMatch(match.second);
+ }
+
+ if (next)
+ {
+ if (m_matchIndex == m_matches.size())
+ {
+ m_matchIndex = 0;
+ }
+ else
+ {
+ m_matchIndex = (m_matchIndex + 1) % m_matches.size();
+ }
+ }
+ else
+ {
+ if (m_matchIndex == 0)
+ {
+ m_matchIndex = m_matches.size() - 1;
+ }
+ else
+ {
+ m_matchIndex--;
+ }
+ }
+
+ auto match = m_matches[m_matchIndex];
+ m_responders[match.first - 1]->activateMatch(match.second);
+
+ getView()->setMatchIndex(m_matchIndex + 1);
+}
+
+void ScreenSearchController::clearMatches()
+{
+ {
+ std::lock_guard lock(m_matchMutex);
+ m_matches.clear();
+ m_matchIndex = 0;
+ }
+
+ for (ScreenSearchResponder* responder : m_responders)
+ {
+ responder->clearMatches();
+ }
+}
+
+size_t ScreenSearchController::getResponderId(ScreenSearchResponder* responder) const
+{
+ for (size_t i = 0; i < m_responders.size(); i++)
+ {
+ if (m_responders[i] == responder)
+ {
+ return i + 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/lib/component/controller/ScreenSearchController.h b/src/lib/component/controller/ScreenSearchController.h
new file mode 100644
index 00000000..f763e85c
--- /dev/null
+++ b/src/lib/component/controller/ScreenSearchController.h
@@ -0,0 +1,40 @@
+#ifndef SCREEN_SEARCH_CONTROLLER_H
+#define SCREEN_SEARCH_CONTROLLER_H
+
+#include
+#include
+
+#include "component/controller/Controller.h"
+#include "component/controller/helper/ScreenSearchInterfaces.h"
+#include "utility/messaging/MessageListener.h"
+
+class ScreenSearchController
+ : public Controller
+ , public ScreenSearchSender
+{
+public:
+ ScreenSearchController();
+ virtual ~ScreenSearchController();
+
+ // Controller implementation
+ virtual void clear();
+
+ // ScreenSearchSender implementation
+ virtual void foundMatches(ScreenSearchResponder* responder, size_t matchCount);
+
+ void addResponder(ScreenSearchResponder* responder);
+ void search(const std::string& query, const std::set& responderNames);
+ void activateMatch(bool next);
+ void clearMatches();
+
+private:
+ size_t getResponderId(ScreenSearchResponder* responder) const;
+
+ std::vector m_responders;
+
+ std::vector> m_matches;
+ size_t m_matchIndex = 0;
+ std::mutex m_matchMutex;
+};
+
+#endif // SCREEN_SEARCH_CONTROLLER_H
diff --git a/src/lib/component/controller/helper/ControllerProxy.h b/src/lib/component/controller/helper/ControllerProxy.h
new file mode 100644
index 00000000..bba5eb3f
--- /dev/null
+++ b/src/lib/component/controller/helper/ControllerProxy.h
@@ -0,0 +1,47 @@
+#ifndef CONTROLLER_PROXY_H
+#define CONTROLLER_PROXY_H
+
+#include
+
+#include "utility/scheduling/TaskLambda.h"
+
+#include "component/view/View.h"
+
+class ControllerProxy
+{
+public:
+ ControllerProxy(View* view)
+ : m_view(view)
+ {
+ }
+
+ template
+ void execute(std::function callback)
+ {
+ ControllerType* controller = m_view->getController();
+ if (controller)
+ {
+ callback(controller);
+ }
+ }
+
+ template
+ void executeAsTask(std::function callback)
+ {
+ ControllerType* controller = m_view->getController();
+ if (controller)
+ {
+ Task::dispatch(std::make_shared(
+ [callback, controller]()
+ {
+ callback(controller);
+ }
+ ));
+ }
+ }
+
+private:
+ View* m_view;
+};
+
+#endif // CONTROLLER_PROXY_H
diff --git a/src/lib/component/controller/helper/ScreenSearchInterfaces.h b/src/lib/component/controller/helper/ScreenSearchInterfaces.h
new file mode 100644
index 00000000..3110fd95
--- /dev/null
+++ b/src/lib/component/controller/helper/ScreenSearchInterfaces.h
@@ -0,0 +1,28 @@
+#ifndef SCREEN_SEARCH_INTERFACES_H
+#define SCREEN_SEARCH_INTERFACES_H
+
+class ScreenSearchResponder;
+
+class ScreenSearchSender
+{
+public:
+ virtual ~ScreenSearchSender() {}
+
+ virtual void foundMatches(ScreenSearchResponder* responder, size_t matchCount) = 0;
+};
+
+class ScreenSearchResponder
+{
+public:
+ virtual ~ScreenSearchResponder() {}
+
+ virtual std::string getName() const = 0;
+ virtual bool isVisible() const = 0;
+
+ virtual void findMatches(ScreenSearchSender* sender, const std::string& query) = 0;
+ virtual void activateMatch(size_t matchIndex) = 0;
+ virtual void deactivateMatch(size_t matchIndex) = 0;
+ virtual void clearMatches() = 0;
+};
+
+#endif // SCREEN_SEARCH_INTERFACES_H
diff --git a/src/lib/component/view/CodeView.h b/src/lib/component/view/CodeView.h
index 74b497db..6e8f0d4c 100644
--- a/src/lib/component/view/CodeView.h
+++ b/src/lib/component/view/CodeView.h
@@ -5,6 +5,7 @@
#include "data/ErrorInfo.h"
+#include "component/controller/helper/ScreenSearchInterfaces.h"
#include "component/view/helper/CodeSnippetParams.h"
#include "component/view/View.h"
@@ -14,6 +15,7 @@ class SourceLocationCollection;
class CodeView
: public View
+ , public ScreenSearchResponder
{
public:
static const char* VIEW_NAME;
diff --git a/src/lib/component/view/GraphView.h b/src/lib/component/view/GraphView.h
index 2a5d1277..97f3fbef 100644
--- a/src/lib/component/view/GraphView.h
+++ b/src/lib/component/view/GraphView.h
@@ -6,6 +6,7 @@
#include "utility/math/Vector2.h"
#include "utility/types.h"
+#include "component/controller/helper/ScreenSearchInterfaces.h"
#include "component/view/View.h"
struct DummyEdge;
@@ -14,6 +15,7 @@ class Graph;
class GraphView
: public View
+ , public ScreenSearchResponder
{
public:
static const char* VIEW_NAME;
diff --git a/src/lib/component/view/GraphViewStyle.cpp b/src/lib/component/view/GraphViewStyle.cpp
index 33bd11ea..4ec1c636 100644
--- a/src/lib/component/view/GraphViewStyle.cpp
+++ b/src/lib/component/view/GraphViewStyle.cpp
@@ -22,6 +22,7 @@ float GraphViewStyle::s_zoomFactor;
std::map GraphViewStyle::s_nodeColors;
std::map GraphViewStyle::s_edgeColors;
+std::map GraphViewStyle::s_screenMatchColors;
Vec2i GraphViewStyle::alignOnRaster(Vec2i position)
{
@@ -142,6 +143,7 @@ void GraphViewStyle::loadStyleSettings()
s_nodeColors.clear();
s_edgeColors.clear();
+ s_screenMatchColors.clear();
s_gridCellPadding = getImpl()->getCharHeightForNodeType(Node::NODE_TYPE) - 8;
s_gridCellSize = s_gridCellPadding / 2;
@@ -713,6 +715,28 @@ const std::string& GraphViewStyle::getEdgeColor(const std::string& typeStr, bool
return s_edgeColors.find(type)->second;
}
+const GraphViewStyle::NodeColor& GraphViewStyle::getScreenMatchColor(bool focus)
+{
+ auto it = s_screenMatchColors.find(focus);
+ if (it != s_screenMatchColors.end())
+ {
+ return it->second;
+ }
+
+ NodeColor color;
+ ColorScheme* scheme = ColorScheme::getInstance().get();
+
+ ColorScheme::ColorState state = focus ? ColorScheme::FOCUS : ColorScheme::NORMAL;
+
+ color.fill = scheme->getCodeAnnotationTypeColor("screen_search", "fill", state);
+ color.border = scheme->getCodeAnnotationTypeColor("screen_search", "border", state);
+ color.text = scheme->getCodeAnnotationTypeColor("screen_search", "text", state);
+
+ s_screenMatchColors.emplace(focus, color);
+
+ return s_screenMatchColors.find(focus)->second;
+}
+
void GraphViewStyle::addIcon(Node::NodeType type, bool hasChildren, NodeStyle* style)
{
switch (type)
diff --git a/src/lib/component/view/GraphViewStyle.h b/src/lib/component/view/GraphViewStyle.h
index e86e4108..a22a08dd 100644
--- a/src/lib/component/view/GraphViewStyle.h
+++ b/src/lib/component/view/GraphViewStyle.h
@@ -138,6 +138,7 @@ public:
static const NodeColor& getNodeColor(const std::string& typeStr, bool focus);
static const std::string& getEdgeColor(const std::string& typeStr, bool focus);
+ static const NodeColor& getScreenMatchColor(bool focus);
static int s_gridCellSize;
static int s_gridCellPadding;
@@ -156,6 +157,7 @@ private:
static std::map s_nodeColors;
static std::map s_edgeColors;
+ static std::map s_screenMatchColors;
};
#endif // GRAPH_VIEW_STYLE_H
diff --git a/src/lib/component/view/ScreenSearchView.cpp b/src/lib/component/view/ScreenSearchView.cpp
new file mode 100644
index 00000000..2157b03d
--- /dev/null
+++ b/src/lib/component/view/ScreenSearchView.cpp
@@ -0,0 +1,15 @@
+#include "component/view/ScreenSearchView.h"
+
+ScreenSearchView::ScreenSearchView(ViewLayout* viewLayout)
+ : View(viewLayout)
+{
+}
+
+ScreenSearchView::~ScreenSearchView()
+{
+}
+
+std::string ScreenSearchView::getName() const
+{
+ return "ScreenSearchView";
+}
diff --git a/src/lib/component/view/ScreenSearchView.h b/src/lib/component/view/ScreenSearchView.h
new file mode 100644
index 00000000..7fd57f1c
--- /dev/null
+++ b/src/lib/component/view/ScreenSearchView.h
@@ -0,0 +1,22 @@
+#ifndef SCREEN_SEARCH_VIEW_H
+#define SCREEN_SEARCH_VIEW_H
+
+#include "component/view/View.h"
+
+class ScreenSearchView
+ : public View
+{
+public:
+ ScreenSearchView(ViewLayout* viewLayout);
+ virtual ~ScreenSearchView();
+
+ // View implementation
+ virtual std::string getName() const;
+
+ virtual void setMatchCount(size_t matchCount) = 0;
+ virtual void setMatchIndex(size_t matchIndex) = 0;
+
+ virtual void addResponder(const std::string& name) = 0;
+};
+
+#endif // SCREEN_SEARCH_VIEW_H
diff --git a/src/lib/component/view/View.h b/src/lib/component/view/View.h
index 77c9b115..1712b864 100644
--- a/src/lib/component/view/View.h
+++ b/src/lib/component/view/View.h
@@ -8,6 +8,7 @@
#include "component/view/ViewLayout.h"
class ViewWidgetWrapper;
+class ControllerProxy;
class View
{
@@ -43,6 +44,8 @@ protected:
void setWidgetWrapper(std::shared_ptr widgetWrapper);
private:
+ friend ControllerProxy;
+
Component* m_component;
ViewLayout* const m_viewLayout;
std::shared_ptr m_widgetWrapper;
diff --git a/src/lib/component/view/ViewFactory.h b/src/lib/component/view/ViewFactory.h
index aba4675a..18749da1 100644
--- a/src/lib/component/view/ViewFactory.h
+++ b/src/lib/component/view/ViewFactory.h
@@ -13,6 +13,7 @@ class GraphView;
class MainView;
class LogView;
class RefreshView;
+class ScreenSearchView;
class SearchView;
class StatusBarView;
class StatusView;
@@ -39,6 +40,7 @@ public:
virtual std::shared_ptr createGraphView(ViewLayout* viewLayout) const = 0;
virtual std::shared_ptr createLogView(ViewLayout* viewLayout) const = 0;
virtual std::shared_ptr createRefreshView(ViewLayout* viewLayout) const = 0;
+ virtual std::shared_ptr createScreenSearchView(ViewLayout* viewLayout) const = 0;
virtual std::shared_ptr createSearchView(ViewLayout* viewLayout) const = 0;
virtual std::shared_ptr createStatusBarView(ViewLayout* viewLayout) const = 0;
virtual std::shared_ptr createStatusView(ViewLayout* viewLayout) const = 0;
diff --git a/src/lib/data/location/LocationType.cpp b/src/lib/data/location/LocationType.cpp
index ea932f05..eb3b2b31 100644
--- a/src/lib/data/location/LocationType.cpp
+++ b/src/lib/data/location/LocationType.cpp
@@ -10,10 +10,12 @@ int locationTypeToInt(LocationType type)
return 1;
case LOCATION_LOCAL_SYMBOL:
return 2;
- case LOCATION_FULLTEXT:
- return 3;
case LOCATION_ERROR:
+ return 3;
+ case LOCATION_FULLTEXT_SEARCH:
return 4;
+ case LOCATION_SCREEN_SEARCH:
+ return 5;
}
}
@@ -28,9 +30,11 @@ LocationType intToLocationType(int value)
case 2:
return LOCATION_LOCAL_SYMBOL;
case 3:
- return LOCATION_FULLTEXT;
- case 4:
return LOCATION_ERROR;
+ case 4:
+ return LOCATION_FULLTEXT_SEARCH;
+ case 5:
+ return LOCATION_SCREEN_SEARCH;
}
return LOCATION_TOKEN;
}
diff --git a/src/lib/data/location/LocationType.h b/src/lib/data/location/LocationType.h
index 52ca50be..2dc173db 100644
--- a/src/lib/data/location/LocationType.h
+++ b/src/lib/data/location/LocationType.h
@@ -6,8 +6,9 @@ enum LocationType
LOCATION_TOKEN,
LOCATION_SCOPE,
LOCATION_LOCAL_SYMBOL,
- LOCATION_FULLTEXT,
- LOCATION_ERROR
+ LOCATION_ERROR,
+ LOCATION_FULLTEXT_SEARCH,
+ LOCATION_SCREEN_SEARCH
};
int locationTypeToInt(LocationType type);
diff --git a/src/lib/data/location/SourceLocation.cpp b/src/lib/data/location/SourceLocation.cpp
index 7b7521c0..3bea1974 100644
--- a/src/lib/data/location/SourceLocation.cpp
+++ b/src/lib/data/location/SourceLocation.cpp
@@ -177,7 +177,7 @@ bool SourceLocation::isScopeLocation() const
bool SourceLocation::isFullTextSearchMatch() const
{
- return m_type == LOCATION_FULLTEXT;
+ return m_type == LOCATION_FULLTEXT_SEARCH;
}
std::ostream& operator<<(std::ostream& ostream, const SourceLocation& location)
diff --git a/src/lib/data/storage/PersistentStorage.cpp b/src/lib/data/storage/PersistentStorage.cpp
index 8e87e610..a533311e 100644
--- a/src/lib/data/storage/PersistentStorage.cpp
+++ b/src/lib/data/storage/PersistentStorage.cpp
@@ -557,7 +557,7 @@ std::shared_ptr PersistentStorage::getFullTextSearchLo
Id locationId = ~(~Id(0) >> 1) + collection->getSourceLocationCount() + 1;
collection->addSourceLocation(
- LOCATION_FULLTEXT,
+ LOCATION_FULLTEXT_SEARCH,
locationId,
std::vector(),
filePath,
diff --git a/src/lib_gui/CMakeLists.txt b/src/lib_gui/CMakeLists.txt
index 9d94fe1e..18734fad 100644
--- a/src/lib_gui/CMakeLists.txt
+++ b/src/lib_gui/CMakeLists.txt
@@ -48,6 +48,8 @@ add_files(
qt/element/QtProgressBar.h
qt/element/QtRefreshBar.cpp
qt/element/QtRefreshBar.h
+ qt/element/QtScreenSearchBox.cpp
+ qt/element/QtScreenSearchBox.h
qt/element/QtSearchBar.cpp
qt/element/QtSearchBar.h
qt/element/QtSmartSearchBox.cpp
@@ -145,6 +147,8 @@ add_files(
qt/view/QtMainView.h
qt/view/QtRefreshView.cpp
qt/view/QtRefreshView.h
+ qt/view/QtScreenSearchView.cpp
+ qt/view/QtScreenSearchView.h
qt/view/QtSearchView.cpp
qt/view/QtSearchView.h
qt/view/QtStatusBarView.cpp
diff --git a/src/lib_gui/qt/element/QtCodeArea.cpp b/src/lib_gui/qt/element/QtCodeArea.cpp
index 42b12a06..35f25593 100644
--- a/src/lib_gui/qt/element/QtCodeArea.cpp
+++ b/src/lib_gui/qt/element/QtCodeArea.cpp
@@ -19,6 +19,7 @@
#include "utility/messaging/type/MessageMoveIDECursor.h"
#include "utility/messaging/type/MessageShowErrors.h"
#include "utility/utility.h"
+#include "utility/utilityString.h"
#include "qt/element/QtCodeNavigator.h"
#include "qt/utility/QtContextMenu.h"
@@ -163,6 +164,18 @@ void QtCodeArea::lineNumberAreaPaintEvent(QPaintEvent *event)
}
break;
+ case LOCATION_ERROR:
+ case LOCATION_SCREEN_SEARCH:
+ if (annotation.isFocused || annotation.isActive)
+ {
+ focus = true;
+ }
+ else
+ {
+ active = true;
+ }
+ break;
+
case LOCATION_TOKEN:
case LOCATION_SCOPE:
if (annotation.isFocused && utility::shareElement(activeSymbolIds, annotation.tokenIds))
@@ -356,6 +369,65 @@ QRectF QtCodeArea::getLineRectForLineNumber(uint lineNumber) const
return blockBoundingGeometry(block);
}
+void QtCodeArea::findScreenMatches(const std::string& query, std::vector>* screenMatches)
+{
+ const std::string& code = utility::toLowerCase(getCode());
+ size_t pos = 0;
+ while (pos != std::string::npos)
+ {
+ pos = code.find(query, pos);
+ if (pos == std::string::npos)
+ {
+ break;
+ }
+
+ Annotation matchAnnotation;
+ matchAnnotation.start = pos;
+ matchAnnotation.end = pos + query.size();
+
+ std::pair start = toLineColumn(matchAnnotation.start);
+ matchAnnotation.startLine = start.first;
+ matchAnnotation.startCol = start.second;
+
+ std::pair end = toLineColumn(matchAnnotation.end);
+ matchAnnotation.endLine = end.first;
+ matchAnnotation.endCol = end.second;
+
+ // Set first 2 bits to 1 to avoid collisions
+ matchAnnotation.locationId = ~(~Id(0) >> 2) + screenMatches->size() + 1;
+ matchAnnotation.locationType = LOCATION_SCREEN_SEARCH;
+
+ matchAnnotation.isActive = false;
+ matchAnnotation.isFocused = false;
+
+ m_annotations.push_back(matchAnnotation);
+ screenMatches->push_back(std::make_pair(this, matchAnnotation.locationId));
+
+ pos += query.size();
+ }
+
+ if (screenMatches->size() && screenMatches->back().first == this)
+ {
+ viewport()->update();
+ }
+}
+
+void QtCodeArea::clearScreenMatches()
+{
+ size_t i = m_annotations.size();
+ while (i > 0 && m_annotations[i - 1].locationType == LOCATION_SCREEN_SEARCH)
+ {
+ i--;
+ m_linesToRehighlight.push_back(m_annotations[i].startLine - getStartLineNumber());
+ }
+
+ if (i != m_annotations.size())
+ {
+ m_annotations.erase(m_annotations.begin() + i, m_annotations.end());
+ viewport()->update();
+ }
+}
+
void QtCodeArea::resizeEvent(QResizeEvent *e)
{
QPlainTextEdit::resizeEvent(e);
diff --git a/src/lib_gui/qt/element/QtCodeArea.h b/src/lib_gui/qt/element/QtCodeArea.h
index 0185066c..25d331e0 100644
--- a/src/lib_gui/qt/element/QtCodeArea.h
+++ b/src/lib_gui/qt/element/QtCodeArea.h
@@ -83,6 +83,9 @@ public:
QRectF getLineRectForLineNumber(uint lineNumber) const;
+ void findScreenMatches(const std::string& query, std::vector>* screenMatches);
+ void clearScreenMatches();
+
protected:
virtual void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE;
virtual void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
diff --git a/src/lib_gui/qt/element/QtCodeField.cpp b/src/lib_gui/qt/element/QtCodeField.cpp
index 2506a9d7..c7467c12 100644
--- a/src/lib_gui/qt/element/QtCodeField.cpp
+++ b/src/lib_gui/qt/element/QtCodeField.cpp
@@ -549,7 +549,7 @@ const QtCodeField::AnnotationColor& QtCodeField::getAnnotationColorForAnnotation
if (!s_annotationColors.size())
{
ColorScheme* scheme = ColorScheme::getInstance().get();
- std::vector types = { "token", "local_symbol", "scope", "error", "fulltext" };
+ std::vector types = { "token", "local_symbol", "scope", "error", "fulltext_search", "screen_search" };
std::vector states = { ColorScheme::NORMAL, ColorScheme::FOCUS, ColorScheme::ACTIVE };
for (const std::string& type : types)
@@ -579,10 +579,14 @@ const QtCodeField::AnnotationColor& QtCodeField::getAnnotationColorForAnnotation
{
i = 9;
}
- else if (annotation.locationType == LOCATION_FULLTEXT)
+ else if (annotation.locationType == LOCATION_FULLTEXT_SEARCH)
{
i = 12;
}
+ else if (annotation.locationType == LOCATION_SCREEN_SEARCH)
+ {
+ i = 15;
+ }
if (annotation.isActive)
{
diff --git a/src/lib_gui/qt/element/QtCodeField.h b/src/lib_gui/qt/element/QtCodeField.h
index a33f7565..b7ed38b8 100644
--- a/src/lib_gui/qt/element/QtCodeField.h
+++ b/src/lib_gui/qt/element/QtCodeField.h
@@ -99,6 +99,7 @@ protected:
std::vector m_annotations;
std::vector m_hoveredAnnotations;
+ std::vector m_linesToRehighlight;
private:
static std::vector s_annotationColors;
@@ -113,7 +114,6 @@ private:
QtHighlighter* m_highlighter;
std::vector m_lineLengths;
- std::vector m_linesToRehighlight;
int m_endTextEditPosition;
};
diff --git a/src/lib_gui/qt/element/QtCodeFile.cpp b/src/lib_gui/qt/element/QtCodeFile.cpp
index 2b74e1b0..fbe16a95 100644
--- a/src/lib_gui/qt/element/QtCodeFile.cpp
+++ b/src/lib_gui/qt/element/QtCodeFile.cpp
@@ -143,13 +143,12 @@ QtCodeSnippet* QtCodeFile::addCodeSnippet(const CodeSnippetParams& params)
}
}
-
+ m_isCollapsed = false;
std::shared_ptr snippet(new QtCodeSnippet(params, m_navigator, this));
if (params.reduced)
{
m_title->setProject(params.title);
- m_isCollapsed = false;
}
m_snippetLayout->addWidget(snippet.get());
@@ -172,10 +171,6 @@ QtCodeSnippet* QtCodeFile::addCodeSnippet(const CodeSnippetParams& params)
return m_fileSnippet.get();
}
- else
- {
- m_isCollapsed = false;
- }
m_snippets.push_back(snippet);
@@ -229,6 +224,11 @@ QtCodeSnippet* QtCodeFile::insertCodeSnippet(const CodeSnippetParams& params)
QtCodeSnippet* QtCodeFile::getSnippetForLocationId(Id locationId) const
{
+ if (m_fileSnippet && m_fileSnippet->isVisible() && m_fileSnippet->getLineNumberForLocationId(locationId))
+ {
+ return m_fileSnippet.get();
+ }
+
for (const std::shared_ptr& snippet : m_snippets)
{
if (snippet->getLineNumberForLocationId(locationId))
@@ -438,6 +438,23 @@ void QtCodeFile::updateTitleBar()
m_title->updateTexts();
}
+void QtCodeFile::findScreenMatches(const std::string& query, std::vector>* screenMatches)
+{
+ if (m_fileSnippet && m_fileSnippet->isVisible())
+ {
+ m_fileSnippet->findScreenMatches(query, screenMatches);
+ return;
+ }
+
+ for (const std::shared_ptr& snippet : m_snippets)
+ {
+ if (snippet->isVisible())
+ {
+ snippet->findScreenMatches(query, screenMatches);
+ }
+ }
+}
+
void QtCodeFile::clickedMinimizeButton()
{
// overview stats
diff --git a/src/lib_gui/qt/element/QtCodeFile.h b/src/lib_gui/qt/element/QtCodeFile.h
index 9a39ddbc..d5f6716c 100644
--- a/src/lib_gui/qt/element/QtCodeFile.h
+++ b/src/lib_gui/qt/element/QtCodeFile.h
@@ -14,6 +14,7 @@
class QLabel;
class QPushButton;
+class QtCodeArea;
class QtCodeFileTitleButton;
class QtCodeNavigator;
class QtCodeSnippet;
@@ -59,6 +60,8 @@ public:
void updateSnippets();
void updateTitleBar();
+ void findScreenMatches(const std::string& query, std::vector>* screenMatches);
+
public slots:
void clickedMinimizeButton();
void clickedSnippetButton();
diff --git a/src/lib_gui/qt/element/QtCodeFileList.cpp b/src/lib_gui/qt/element/QtCodeFileList.cpp
index b6f457af..da911cd6 100644
--- a/src/lib_gui/qt/element/QtCodeFileList.cpp
+++ b/src/lib_gui/qt/element/QtCodeFileList.cpp
@@ -199,6 +199,14 @@ void QtCodeFileList::onWindowFocus()
}
}
+void QtCodeFileList::findScreenMatches(const std::string& query, std::vector>* screenMatches)
+{
+ for (const std::shared_ptr& filePtr : m_files)
+ {
+ filePtr->findScreenMatches(query, screenMatches);
+ }
+}
+
void QtCodeFileList::setFileMinimized(const FilePath path)
{
getFile(path)->setMinimized();
diff --git a/src/lib_gui/qt/element/QtCodeFileList.h b/src/lib_gui/qt/element/QtCodeFileList.h
index 6d6d020c..97afc43e 100644
--- a/src/lib_gui/qt/element/QtCodeFileList.h
+++ b/src/lib_gui/qt/element/QtCodeFileList.h
@@ -43,6 +43,8 @@ public:
virtual void onWindowFocus();
+ virtual void findScreenMatches(const std::string& query, std::vector>* screenMatches);
+
void setFileMinimized(const FilePath path);
void setFileSnippets(const FilePath path);
void setFileMaximized(const FilePath path);
diff --git a/src/lib_gui/qt/element/QtCodeFileSingle.cpp b/src/lib_gui/qt/element/QtCodeFileSingle.cpp
index d70936e8..10071ec8 100644
--- a/src/lib_gui/qt/element/QtCodeFileSingle.cpp
+++ b/src/lib_gui/qt/element/QtCodeFileSingle.cpp
@@ -225,6 +225,14 @@ void QtCodeFileSingle::onWindowFocus()
m_title->updateTexts();
}
+void QtCodeFileSingle::findScreenMatches(const std::string& query, std::vector>* screenMatches)
+{
+ if (m_area)
+ {
+ m_area->findScreenMatches(query, screenMatches);
+ }
+}
+
const FilePath& QtCodeFileSingle::getCurrentFilePath() const
{
return m_currentFilePath;
diff --git a/src/lib_gui/qt/element/QtCodeFileSingle.h b/src/lib_gui/qt/element/QtCodeFileSingle.h
index 456905dd..3bb18edc 100644
--- a/src/lib_gui/qt/element/QtCodeFileSingle.h
+++ b/src/lib_gui/qt/element/QtCodeFileSingle.h
@@ -43,6 +43,8 @@ public:
virtual void onWindowFocus() override;
+ virtual void findScreenMatches(const std::string& query, std::vector>* screenMatches) override;
+
const FilePath& getCurrentFilePath() const;
bool hasFileCached(const FilePath& filePath) const;
diff --git a/src/lib_gui/qt/element/QtCodeNavigateable.h b/src/lib_gui/qt/element/QtCodeNavigateable.h
index ba4931a4..8bf09aef 100644
--- a/src/lib_gui/qt/element/QtCodeNavigateable.h
+++ b/src/lib_gui/qt/element/QtCodeNavigateable.h
@@ -10,6 +10,7 @@
class FilePath;
class QRectF;
class QAbstractScrollArea;
+class QtCodeArea;
class QWidget;
class QtCodeNavigateable
@@ -29,6 +30,8 @@ public:
virtual void onWindowFocus() = 0;
+ virtual void findScreenMatches(const std::string& query, std::vector>* screenMatches) = 0;
+
protected:
void ensureWidgetVisibleAnimated(QWidget* parentWidget, QWidget *childWidget, QRectF rect, bool animated, bool onTop);
void ensurePercentVisibleAnimated(double percentA, double percentB, bool animated, bool onTop);
diff --git a/src/lib_gui/qt/element/QtCodeNavigator.cpp b/src/lib_gui/qt/element/QtCodeNavigator.cpp
index e0bc412c..96c4630e 100644
--- a/src/lib_gui/qt/element/QtCodeNavigator.cpp
+++ b/src/lib_gui/qt/element/QtCodeNavigator.cpp
@@ -15,6 +15,7 @@
#include "data/location/SourceLocation.h"
#include "data/location/SourceLocationCollection.h"
#include "data/location/SourceLocationFile.h"
+#include "qt/element/QtCodeArea.h"
#include "qt/element/QtCodeFile.h"
#include "qt/element/QtCodeSnippet.h"
#include "qt/utility/utilityQt.h"
@@ -255,6 +256,9 @@ void QtCodeNavigator::clearCodeSnippets()
m_refIndex = 0;
m_singleHasNewFile = false;
+
+ m_screenMatches.clear();
+ m_activeScreenMatchId = 0;
}
void QtCodeNavigator::clearFile()
@@ -549,6 +553,60 @@ void QtCodeNavigator::refreshStyle()
clearCaches();
}
+size_t QtCodeNavigator::findScreenMatches(const std::string& query)
+{
+ clearScreenMatches();
+
+ m_current->findScreenMatches(query, &m_screenMatches);
+
+ return m_screenMatches.size();
+}
+
+void QtCodeNavigator::activateScreenMatch(size_t matchIndex)
+{
+ if (matchIndex >= m_screenMatches.size())
+ {
+ return;
+ }
+
+ std::pair p = m_screenMatches[matchIndex];
+ m_activeScreenMatchId = p.second;
+ m_currentActiveLocationIds.insert(m_activeScreenMatchId);
+ p.first->updateContent();
+
+ requestScroll(p.first->getSourceLocationFile()->getFilePath(), 0, m_activeScreenMatchId, true, false);
+ emit scrollRequest();
+}
+
+void QtCodeNavigator::deactivateScreenMatch(size_t matchIndex)
+{
+ if (matchIndex >= m_screenMatches.size())
+ {
+ return;
+ }
+
+ m_currentActiveLocationIds.erase(m_screenMatches[matchIndex].second);
+ m_screenMatches[matchIndex].first->updateContent();
+
+ m_activeScreenMatchId = 0;
+}
+
+void QtCodeNavigator::clearScreenMatches()
+{
+ if (m_activeScreenMatchId)
+ {
+ m_currentActiveLocationIds.erase(m_activeScreenMatchId);
+ m_activeScreenMatchId = 0;
+ }
+
+ for (auto p : m_screenMatches)
+ {
+ p.first->clearScreenMatches();
+ }
+
+ m_screenMatches.clear();
+}
+
void QtCodeNavigator::scrollToValue(int value, bool inListMode)
{
if ((m_mode == MODE_LIST) == inListMode)
diff --git a/src/lib_gui/qt/element/QtCodeNavigator.h b/src/lib_gui/qt/element/QtCodeNavigator.h
index 4e4423f0..4dfc2f62 100644
--- a/src/lib_gui/qt/element/QtCodeNavigator.h
+++ b/src/lib_gui/qt/element/QtCodeNavigator.h
@@ -83,6 +83,11 @@ public:
void refreshStyle();
+ size_t findScreenMatches(const std::string& query);
+ void activateScreenMatch(size_t matchIndex);
+ void deactivateScreenMatch(size_t matchIndex);
+ void clearScreenMatches();
+
void scrollToValue(int value, bool inListMode);
void scrollToLine(const FilePath& filePath, unsigned int line);
void scrollToDefinition(bool animated, bool ignoreActiveReference);
@@ -192,6 +197,9 @@ private:
ScrollRequest m_scrollRequest;
bool m_singleHasNewFile;
+
+ std::vector> m_screenMatches;
+ Id m_activeScreenMatchId = 0;
};
#endif // QT_CODE_NAVIGATOR_H
diff --git a/src/lib_gui/qt/element/QtCodeSnippet.cpp b/src/lib_gui/qt/element/QtCodeSnippet.cpp
index a4ffda37..ecddfde0 100644
--- a/src/lib_gui/qt/element/QtCodeSnippet.cpp
+++ b/src/lib_gui/qt/element/QtCodeSnippet.cpp
@@ -187,6 +187,11 @@ std::string QtCodeSnippet::getCode() const
return m_codeArea->getCode();
}
+void QtCodeSnippet::findScreenMatches(const std::string& query, std::vector>* screenMatches)
+{
+ m_codeArea->findScreenMatches(query, screenMatches);
+}
+
void QtCodeSnippet::clickedTitle()
{
if (m_titleId > 0)
diff --git a/src/lib_gui/qt/element/QtCodeSnippet.h b/src/lib_gui/qt/element/QtCodeSnippet.h
index ed43e80f..9040a57b 100644
--- a/src/lib_gui/qt/element/QtCodeSnippet.h
+++ b/src/lib_gui/qt/element/QtCodeSnippet.h
@@ -51,6 +51,8 @@ public:
std::string getCode() const;
+ void findScreenMatches(const std::string& query, std::vector>* screenMatches);
+
private slots:
void clickedTitle();
void clickedFooter();
diff --git a/src/lib_gui/qt/element/QtScreenSearchBox.cpp b/src/lib_gui/qt/element/QtScreenSearchBox.cpp
new file mode 100644
index 00000000..7f43338d
--- /dev/null
+++ b/src/lib_gui/qt/element/QtScreenSearchBox.cpp
@@ -0,0 +1,263 @@
+#include "qt/element/QtScreenSearchBox.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "component/controller/helper/ControllerProxy.h"
+#include "component/controller/ScreenSearchController.h"
+#include "qt/utility/utilityQt.h"
+#include "utility/ResourcePaths.h"
+
+
+QtFocusInFilter::QtFocusInFilter()
+{
+}
+
+bool QtFocusInFilter::eventFilter(QObject* obj, QEvent* event)
+{
+ QLineEdit* lineEdit = dynamic_cast(obj);
+ if (lineEdit && event->type() == QEvent::FocusIn && dynamic_cast(event)->reason() == Qt::MouseFocusReason)
+ {
+ emit focusIn();
+ }
+
+ return QObject::eventFilter(obj, event);
+}
+
+
+QtScreenSearchBox::QtScreenSearchBox(ControllerProxy* controllerProxy, QWidget* parent)
+ : QFrame(parent)
+ , m_controllerProxy(controllerProxy)
+{
+ setObjectName("screen_search_box");
+
+ QHBoxLayout* layout = new QHBoxLayout();
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ setLayout(layout);
+
+ // search field
+ {
+ m_searchButton = new QPushButton();
+ m_searchButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
+ m_searchButton->setObjectName("search_button");
+ layout->addWidget(m_searchButton);
+
+ connect(m_searchButton, &QPushButton::clicked, this, &QtScreenSearchBox::setFocus);
+
+ m_searchBox = new QLineEdit(this);
+ m_searchBox->setObjectName("search_box");
+ m_searchBox->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
+ m_searchBox->setAttribute(Qt::WA_MacShowFocusRect, 0); // remove blue focus box on Mac
+ layout->addWidget(m_searchBox);
+
+ connect(m_searchBox, &QLineEdit::textChanged, this, &QtScreenSearchBox::searchQueryChanged);
+ connect(m_searchBox, &QLineEdit::returnPressed, this, &QtScreenSearchBox::returnPressed);
+
+ QtFocusInFilter* filter = new QtFocusInFilter();
+ m_searchBox->installEventFilter(filter);
+ connect(filter, &QtFocusInFilter::focusIn, this, &QtScreenSearchBox::findMatches);
+ }
+
+ // match label
+ {
+ m_matchLabel = new QPushButton();
+ m_matchLabel->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
+ m_matchLabel->setObjectName("match_label");
+ layout->addWidget(m_matchLabel);
+
+ connect(m_matchLabel, &QPushButton::clicked, this, &QtScreenSearchBox::setFocus);
+ }
+
+ // buttons
+ {
+ m_prevButton = new QPushButton();
+ m_nextButton = new QPushButton();
+
+ m_prevButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
+ m_nextButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
+
+ m_prevButton->setObjectName("prev_button");
+ m_nextButton->setObjectName("next_button");
+
+ layout->addWidget(m_prevButton);
+ layout->addWidget(m_nextButton);
+
+ connect(m_prevButton, &QPushButton::clicked, this, &QtScreenSearchBox::previousPressed);
+ connect(m_nextButton, &QPushButton::clicked, this, &QtScreenSearchBox::nextPressed);
+ }
+
+ // filter
+ {
+ m_checkboxLayout = new QHBoxLayout();
+ layout->addLayout(m_checkboxLayout);
+ layout->addStretch();
+ }
+
+ // buttons
+ {
+ m_closeButton = new QPushButton();
+ m_closeButton->setObjectName("close_button");
+ m_closeButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
+ layout->addWidget(m_closeButton);
+
+ connect(m_closeButton, &QPushButton::clicked, [this](){ emit closePressed(); });
+ }
+
+ m_timer = new QTimer(this);
+ m_timer->setSingleShot(true);
+ connect(m_timer, &QTimer::timeout, this, &QtScreenSearchBox::findMatches);
+
+ refreshStyle();
+ setMatchCount(0);
+}
+
+QtScreenSearchBox::~QtScreenSearchBox()
+{
+}
+
+void QtScreenSearchBox::refreshStyle()
+{
+ m_searchButton->setIcon(utility::createButtonIcon(
+ ResourcePaths::getGuiPath().str() + "search_view/images/search.png",
+ "screen_search/button"
+ ));
+
+ m_prevButton->setIcon(utility::createButtonIcon(
+ ResourcePaths::getGuiPath().str() + "code_view/images/arrow_left.png",
+ "screen_search/button"
+ ));
+
+ m_nextButton->setIcon(utility::createButtonIcon(
+ ResourcePaths::getGuiPath().str() + "code_view/images/arrow_right.png",
+ "screen_search/button"
+ ));
+
+ m_closeButton->setIcon(utility::createButtonIcon(
+ ResourcePaths::getGuiPath().str() + "screen_search_view/images/close.png",
+ "screen_search/button"
+ ));
+
+ m_searchButton->setIconSize(QSize(12, 12));
+ m_prevButton->setIconSize(QSize(12, 12));
+ m_nextButton->setIconSize(QSize(12, 12));
+ m_closeButton->setIconSize(QSize(15, 15));
+}
+
+void QtScreenSearchBox::setMatchCount(size_t matchCount)
+{
+ m_matchCount = matchCount;
+ m_matchIndex = 0;
+ updateMatchLabel();
+
+ m_prevButton->setEnabled(matchCount > 0);
+ m_nextButton->setEnabled(matchCount > 0);
+}
+
+void QtScreenSearchBox::setMatchIndex(size_t matchIndex)
+{
+ m_matchIndex = matchIndex;
+ updateMatchLabel();
+}
+
+void QtScreenSearchBox::addResponder(const std::string& name)
+{
+ QCheckBox* box = new QCheckBox(name.c_str());
+ box->setObjectName("filter_checkbox");
+ box->setChecked(true);
+ m_checkBoxes.push_back(box);
+ m_checkboxLayout->addWidget(box);
+
+ connect(box, &QCheckBox::stateChanged, this, &QtScreenSearchBox::findMatches);
+}
+
+void QtScreenSearchBox::setFocus()
+{
+ m_searchBox->setFocus();
+
+ if (m_searchBox->text().size())
+ {
+ m_searchBox->selectAll();
+ searchQueryChanged();
+ }
+}
+
+void QtScreenSearchBox::searchQueryChanged()
+{
+ m_timer->stop();
+ m_timer->start(200);
+}
+
+void QtScreenSearchBox::findMatches()
+{
+ m_controllerProxy->executeAsTask(
+ [this](ScreenSearchController* controller)
+ {
+ std::set responderNames;
+ for (QCheckBox* box : m_checkBoxes)
+ {
+ if (box->isChecked())
+ {
+ responderNames.insert(box->text().toStdString());
+ }
+ }
+
+ controller->search(m_searchBox->text().toLower().toStdString(), responderNames);
+ }
+ );
+}
+
+void QtScreenSearchBox::returnPressed()
+{
+ if (Qt::KeyboardModifier::ShiftModifier & QApplication::keyboardModifiers())
+ {
+ previousPressed();
+ }
+ else
+ {
+ nextPressed();
+ }
+}
+
+void QtScreenSearchBox::previousPressed()
+{
+ activateMatch(false);
+}
+
+void QtScreenSearchBox::nextPressed()
+{
+ activateMatch(true);
+}
+
+void QtScreenSearchBox::activateMatch(bool next)
+{
+ m_controllerProxy->executeAsTask(
+ [next, this](ScreenSearchController* controller)
+ {
+ controller->activateMatch(next);
+ }
+ );
+}
+
+void QtScreenSearchBox::updateMatchLabel()
+{
+ QString text;
+
+ if (m_matchIndex > 0)
+ {
+ text += QString::number(m_matchIndex) + " of ";
+ }
+
+ text += QString::number(m_matchCount) + " match";
+ if (m_matchCount != 1)
+ {
+ text += "es";
+ }
+
+ m_matchLabel->setText(text);
+}
diff --git a/src/lib_gui/qt/element/QtScreenSearchBox.h b/src/lib_gui/qt/element/QtScreenSearchBox.h
new file mode 100644
index 00000000..ef9a4c83
--- /dev/null
+++ b/src/lib_gui/qt/element/QtScreenSearchBox.h
@@ -0,0 +1,84 @@
+#ifndef QT_SCREEN_SEARCH_BOX_H
+#define QT_SCREEN_SEARCH_BOX_H
+
+#include
+
+class ControllerProxy;
+class QCheckBox;
+class QHBoxLayout;
+class QLineEdit;
+class QPushButton;
+class QTimer;
+
+
+class QtFocusInFilter
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ QtFocusInFilter();
+
+signals:
+ void focusIn();
+
+protected:
+ bool eventFilter(QObject* obj, QEvent* event);
+};
+
+
+class QtScreenSearchBox
+ : public QFrame
+{
+ Q_OBJECT
+
+public:
+ QtScreenSearchBox(ControllerProxy* controllerProxy, QWidget* parent = nullptr);
+ virtual ~QtScreenSearchBox();
+
+ void refreshStyle();
+
+ void setMatchCount(size_t matchCount);
+ void setMatchIndex(size_t matchIndex);
+
+ void addResponder(const std::string& name);
+
+signals:
+ void closePressed();
+
+public slots:
+ void setFocus();
+
+private slots:
+ void searchQueryChanged();
+ void findMatches();
+ void returnPressed();
+
+ void previousPressed();
+ void nextPressed();
+
+private:
+ void activateMatch(bool next);
+
+ void updateMatchLabel();
+
+ ControllerProxy* m_controllerProxy;
+
+ QLineEdit* m_searchBox;
+ QPushButton* m_matchLabel;
+
+ QPushButton* m_searchButton;
+ QPushButton* m_prevButton;
+ QPushButton* m_nextButton;
+ QPushButton* m_closeButton;
+
+ QHBoxLayout* m_checkboxLayout;
+ std::vector m_checkBoxes;
+
+ size_t m_matchCount = 0;
+ size_t m_matchIndex = 0;
+
+ QTimer* m_timer;
+};
+
+#endif // QT_SCREEN_SEARCH_BOX_H
diff --git a/src/lib_gui/qt/utility/QtHighlighter.cpp b/src/lib_gui/qt/utility/QtHighlighter.cpp
index e6a171e4..af8bc536 100644
--- a/src/lib_gui/qt/utility/QtHighlighter.cpp
+++ b/src/lib_gui/qt/utility/QtHighlighter.cpp
@@ -5,6 +5,7 @@
#include
#include "settings/ColorScheme.h"
+#include "utility/utility.h"
QVector QtHighlighter::s_highlightingRules;
QVector QtHighlighter::s_highlightingRulesCpp;
@@ -110,16 +111,16 @@ QtHighlighter::QtHighlighter(QTextDocument *document, LanguageType language)
: m_document(document)
, m_language(language)
{
- if (m_language == LANGUAGE_UNKNOWN)
- {
- return;
- }
-
if (!s_highlightingRules.size())
{
createHighlightingRules();
}
+ if (m_language == LANGUAGE_UNKNOWN)
+ {
+ return;
+ }
+
if (m_language == LANGUAGE_JAVA)
{
m_highlightingRules = s_highlightingRulesJava;
@@ -134,11 +135,6 @@ QtHighlighter::QtHighlighter(QTextDocument *document, LanguageType language)
void QtHighlighter::highlightDocument()
{
- if (m_language == LANGUAGE_UNKNOWN)
- {
- return;
- }
-
QTextDocument* doc = document();
int docStart = 0;
@@ -150,26 +146,29 @@ void QtHighlighter::highlightDocument()
docEnd -= 1;
applyFormat(docStart, docEnd, s_textFormat);
- m_ranges.clear();
-
m_highlightedLines.clear();
m_highlightedLines.resize(document()->blockCount(), false);
- for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
- {
- formatBlock(it, s_quotationRule, &m_ranges, true);
- }
-
- highlightMultiLineComments(&m_ranges);
-}
-
-void QtHighlighter::highlightRange(int startLine, int endLine)
-{
if (m_language == LANGUAGE_UNKNOWN)
{
return;
}
+ m_quotationRanges.clear();
+ m_multiLineCommentRanges.clear();
+
+ std::vector> ranges;
+ ranges.push_back(std::pair(docStart, docEnd));
+ for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
+ {
+ utility::append(m_quotationRanges, formatBlockForRule(it, s_quotationRule, &ranges));
+ }
+
+ highlightMultiLineComments();
+}
+
+void QtHighlighter::highlightRange(int startLine, int endLine)
+{
if (startLine < 0 || endLine < 0 || startLine > endLine || endLine > int(m_highlightedLines.size()))
{
return;
@@ -199,22 +198,19 @@ void QtHighlighter::highlightRange(int startLine, int endLine)
{
if (!m_highlightedLines[index])
{
- applyFormatWithoutRanges(it.position(), it.position() + it.length() - 1, s_textFormat, m_ranges);
+ applyFormat(it.position(), it.position() + it.length() - 1, s_textFormat);
- foreach (const HighlightingRule &rule, m_highlightingRules)
+ if (m_language != LANGUAGE_UNKNOWN)
{
- formatBlock(it, rule, &m_ranges, false);
- }
- }
- index++;
- }
+ foreach (const HighlightingRule &rule, m_highlightingRules)
+ {
+ formatBlockForRule(it, rule);
+ }
- index = startLine;
- for (QTextBlock it = start; it != end; it = it.next())
- {
- if (!m_highlightedLines[index])
- {
- formatBlock(it, s_commentRule, &m_ranges, false);
+ formatBlockIfInRange(it, s_quotationRule.format, &m_quotationRanges);
+ formatBlockForRule(it, s_commentRule, &m_quotationRanges);
+ formatBlockIfInRange(it, s_commentRule.format, &m_multiLineCommentRanges);
+ }
}
index++;
}
@@ -244,40 +240,6 @@ void QtHighlighter::applyFormat(int startPosition, int endPosition, const QTextC
cursor.setCharFormat(format);
}
-void QtHighlighter::applyFormatWithoutRanges(
- int startPosition, int endPosition, const QTextCharFormat& format, const std::vector>& ranges
-){
- std::vector> highlightRanges;
-
- for (const std::pair p : ranges)
- {
- if (p.first <= startPosition && p.second >= endPosition)
- {
- return;
- }
-
- if (p.first > startPosition && p.first < endPosition)
- {
- highlightRanges.push_back(std::pair(startPosition, p.first - 1));
- }
-
- if (p.second > startPosition && p.second < endPosition)
- {
- highlightRanges.push_back(std::pair(p.second + 1, endPosition));
- }
- }
-
- if (!highlightRanges.size())
- {
- highlightRanges.push_back(std::pair(startPosition, endPosition));
- }
-
- for (const std::pair p : highlightRanges)
- {
- applyFormat(p.first, p.second, format);
- }
-}
-
QTextCharFormat QtHighlighter::getFormat(int startPosition, int endPosition) const
{
QTextCursor cursor(document());
@@ -285,7 +247,7 @@ QTextCharFormat QtHighlighter::getFormat(int startPosition, int endPosition) con
return cursor.charFormat();
}
-void QtHighlighter::highlightMultiLineComments(std::vector>* ranges)
+void QtHighlighter::highlightMultiLineComments()
{
QTextDocument* doc = document();
@@ -305,7 +267,7 @@ void QtHighlighter::highlightMultiLineComments(std::vector>*
cursorStart.setPosition(cursorStart.selectionEnd() - 2);
}
}
- while (isInRange(cursorStart.position(), *ranges));
+ while (isInRange(cursorStart.position(), m_quotationRanges));
if (cursorStart.isNull())
{
@@ -318,9 +280,7 @@ void QtHighlighter::highlightMultiLineComments(std::vector>*
break;
}
- applyFormat(cursorStart.selectionStart(), cursorEnd.position(), s_commentRule.format);
- ranges->push_back(std::pair(cursorStart.selectionStart(), cursorEnd.position()));
-
+ m_multiLineCommentRanges.push_back(std::pair(cursorStart.selectionStart(), cursorEnd.position()));
cursorStart = cursorEnd;
}
}
@@ -348,34 +308,47 @@ bool QtHighlighter::isInRange(int pos, const std::vector>& r
return false;
}
-void QtHighlighter::formatBlock(
- const QTextBlock& block, const HighlightingRule& rule, std::vector>* ranges, bool saveRange
+std::vector> QtHighlighter::formatBlockForRule(
+ const QTextBlock& block, const HighlightingRule& rule, std::vector>* ranges
){
QRegExp expression(rule.pattern);
int pos = block.position();
int index = expression.indexIn(block.text());
+
std::vector> newRanges;
while (index >= 0)
{
int length = expression.matchedLength();
- if (!isInRange(pos + index, *ranges))
+ if (!ranges || !isInRange(pos + index, *ranges))
{
applyFormat(pos + index, pos + index + length, rule.format);
}
- if (saveRange)
- {
- newRanges.push_back(std::pair(pos + index, pos + index + length - 1));
- }
+ newRanges.push_back(std::pair(pos + index, pos + index + length));
index = expression.indexIn(block.text(), index + length);
}
- if (saveRange)
+ return newRanges;
+}
+
+void QtHighlighter::formatBlockIfInRange(
+ const QTextBlock& block, const QTextCharFormat& format, std::vector>* ranges
+){
+ int startPos = block.position();
+ int endPos = startPos + block.length() - 1;
+
+ for (auto range : *ranges)
{
- ranges->insert(ranges->end(), newRanges.begin(), newRanges.end());
+ int start = std::max(range.first, startPos);
+ int end = std::min(range.second, endPos);
+
+ if (start <= end)
+ {
+ applyFormat(start, end, format);
+ }
}
}
diff --git a/src/lib_gui/qt/utility/QtHighlighter.h b/src/lib_gui/qt/utility/QtHighlighter.h
index 989f8fbb..77e36f93 100644
--- a/src/lib_gui/qt/utility/QtHighlighter.h
+++ b/src/lib_gui/qt/utility/QtHighlighter.h
@@ -21,8 +21,6 @@ public:
void rehighlightLines(const std::vector& lines);
void applyFormat(int startPosition, int endPosition, const QTextCharFormat& format);
- void applyFormatWithoutRanges(
- int startPosition, int endPosition, const QTextCharFormat& format, const std::vector>& ranges);
QTextCharFormat getFormat(int startPosition, int endPosition) const;
@@ -36,11 +34,13 @@ private:
QTextCharFormat format;
};
- void highlightMultiLineComments(std::vector>* ranges);
+ void highlightMultiLineComments();
bool isInRange(int index, const std::vector>& ranges) const;
- void formatBlock(
- const QTextBlock& block, const HighlightingRule& rule, std::vector>* ranges, bool saveRange);
+ std::vector> formatBlockForRule(
+ const QTextBlock& block, const HighlightingRule& rule, std::vector>* ranges = nullptr);
+ void formatBlockIfInRange(
+ const QTextBlock& block, const QTextCharFormat& format, std::vector>* ranges);
QTextDocument* document() const;
@@ -56,7 +56,8 @@ private:
LanguageType m_language;
QVector m_highlightingRules;
- std::vector> m_ranges;
+ std::vector> m_quotationRanges;
+ std::vector> m_multiLineCommentRanges;
std::vector m_highlightedLines;
};
diff --git a/src/lib_gui/qt/view/QtCodeView.cpp b/src/lib_gui/qt/view/QtCodeView.cpp
index a65c2ff5..e6aa257f 100644
--- a/src/lib_gui/qt/view/QtCodeView.cpp
+++ b/src/lib_gui/qt/view/QtCodeView.cpp
@@ -45,6 +45,52 @@ void QtCodeView::refreshView()
});
}
+bool QtCodeView::isVisible() const
+{
+ return m_widget->isVisible();
+}
+
+void QtCodeView::findMatches(ScreenSearchSender* sender, const std::string& query)
+{
+ m_onQtThread(
+ [sender, query, this]()
+ {
+ size_t matchCount = m_widget->findScreenMatches(query);
+ sender->foundMatches(this, matchCount);
+ }
+ );
+}
+
+void QtCodeView::activateMatch(size_t matchIndex)
+{
+ m_onQtThread(
+ [matchIndex, this]()
+ {
+ m_widget->activateScreenMatch(matchIndex);
+ }
+ );
+}
+
+void QtCodeView::deactivateMatch(size_t matchIndex)
+{
+ m_onQtThread(
+ [matchIndex, this]()
+ {
+ m_widget->deactivateScreenMatch(matchIndex);
+ }
+ );
+}
+
+void QtCodeView::clearMatches()
+{
+ m_onQtThread(
+ [this]()
+ {
+ m_widget->clearScreenMatches();
+ }
+ );
+}
+
void QtCodeView::clear()
{
m_onQtThread([=]()
diff --git a/src/lib_gui/qt/view/QtCodeView.h b/src/lib_gui/qt/view/QtCodeView.h
index 359f86d8..893ab41f 100644
--- a/src/lib_gui/qt/view/QtCodeView.h
+++ b/src/lib_gui/qt/view/QtCodeView.h
@@ -18,6 +18,13 @@ public:
virtual void initView();
virtual void refreshView();
+ // ScreenSearchResponder implementation
+ virtual bool isVisible() const;
+ virtual void findMatches(ScreenSearchSender* sender, const std::string& query);
+ virtual void activateMatch(size_t matchIndex);
+ virtual void deactivateMatch(size_t matchIndex);
+ virtual void clearMatches();
+
// CodeView implementation
virtual void clear();
diff --git a/src/lib_gui/qt/view/QtGraphView.cpp b/src/lib_gui/qt/view/QtGraphView.cpp
index d128d0cd..9b2db149 100644
--- a/src/lib_gui/qt/view/QtGraphView.cpp
+++ b/src/lib_gui/qt/view/QtGraphView.cpp
@@ -168,6 +168,80 @@ void QtGraphView::refreshView()
getView()->refreshStyle();
}
+bool QtGraphView::isVisible() const
+{
+ return QtViewWidgetWrapper::getWidgetOfView(this)->isVisible();
+}
+
+void QtGraphView::findMatches(ScreenSearchSender* sender, const std::string& query)
+{
+ m_onQtThread(
+ [sender, query, this]()
+ {
+ m_matchedNodes.clear();
+
+ for (std::shared_ptr node : m_oldNodes)
+ {
+ node->matchNameRecursive(query, &m_matchedNodes);
+ }
+
+ sender->foundMatches(this, m_matchedNodes.size());
+ }
+ );
+}
+
+void QtGraphView::activateMatch(size_t matchIndex)
+{
+ m_onQtThread(
+ [matchIndex, this]()
+ {
+ if (matchIndex >= m_matchedNodes.size())
+ {
+ return;
+ }
+
+ QtGraphNode* node = m_matchedNodes[matchIndex];
+
+ node->setActiveMatch(true);
+ node->updateStyle();
+
+ centerNode(node);
+ }
+ );
+}
+
+void QtGraphView::deactivateMatch(size_t matchIndex)
+{
+ m_onQtThread(
+ [matchIndex, this]()
+ {
+ if (matchIndex >= m_matchedNodes.size())
+ {
+ return;
+ }
+
+ QtGraphNode* node = m_matchedNodes[matchIndex];
+ node->setActiveMatch(false);
+ node->updateStyle();
+ }
+ );
+}
+
+void QtGraphView::clearMatches()
+{
+ m_onQtThread(
+ [this]()
+ {
+ for (QtGraphNode* node : m_matchedNodes)
+ {
+ node->removeNameMatch();
+ }
+
+ m_matchedNodes.clear();
+ }
+ );
+}
+
void QtGraphView::rebuildGraph(
std::shared_ptr graph,
const std::vector>& nodes,
@@ -599,6 +673,8 @@ void QtGraphView::doRebuildGraph(
m_graph = graph;
}
+ m_matchedNodes.clear();
+
QGraphicsView* view = getView();
@@ -682,6 +758,8 @@ void QtGraphView::doClear()
m_graph.reset();
m_oldGraph.reset();
+
+ m_matchedNodes.clear();
}
void QtGraphView::doResize()
diff --git a/src/lib_gui/qt/view/QtGraphView.h b/src/lib_gui/qt/view/QtGraphView.h
index 778ec4c4..f13c3264 100644
--- a/src/lib_gui/qt/view/QtGraphView.h
+++ b/src/lib_gui/qt/view/QtGraphView.h
@@ -39,6 +39,14 @@ public:
virtual void initView();
virtual void refreshView();
+ // ScreenSearchResponder implementation
+ virtual bool isVisible() const;
+ virtual void findMatches(ScreenSearchSender* sender, const std::string& query);
+ virtual void activateMatch(size_t matchIndex);
+ virtual void deactivateMatch(size_t matchIndex);
+ virtual void clearMatches();
+
+ // GraphView implementation
virtual void rebuildGraph(
std::shared_ptr graph,
const std::vector>& nodes,
@@ -164,6 +172,9 @@ private:
QLabel* m_trailDepthLabel;
std::vector m_virtualNodeRects;
+
+ // Name matches
+ std::vector m_matchedNodes;
};
#endif // QT_GRAPH_VIEW_H
diff --git a/src/lib_gui/qt/view/QtScreenSearchView.cpp b/src/lib_gui/qt/view/QtScreenSearchView.cpp
new file mode 100644
index 00000000..049dfec8
--- /dev/null
+++ b/src/lib_gui/qt/view/QtScreenSearchView.cpp
@@ -0,0 +1,98 @@
+#include "qt/view/QtScreenSearchView.h"
+
+#include
+
+#include "component/controller/ScreenSearchController.h"
+#include "qt/element/QtScreenSearchBox.h"
+#include "qt/utility/utilityQt.h"
+#include "qt/view/QtMainView.h"
+#include "qt/view/QtViewWidgetWrapper.h"
+#include "qt/window/QtMainWindow.h"
+#include "utility/ResourcePaths.h"
+
+QtScreenSearchView::QtScreenSearchView(ViewLayout* viewLayout)
+ : ScreenSearchView(viewLayout)
+ , m_controllerProxy(this)
+{
+ m_widget = new QtScreenSearchBox(&m_controllerProxy);
+
+ m_bar = new QToolBar();
+ m_bar->setObjectName("screen_search_bar");
+ m_bar->setMovable(false);
+ m_bar->addWidget(m_widget);
+
+ QtMainWindow* mainWindow = dynamic_cast(getViewLayout())->getMainWindow();
+
+ QObject::connect(m_widget, &QtScreenSearchBox::closePressed, this, &QtScreenSearchView::hide);
+ QObject::connect(mainWindow, &QtMainWindow::showScreenSearch, this, &QtScreenSearchView::show);
+ QObject::connect(mainWindow, &QtMainWindow::hideScreenSearch, this, &QtScreenSearchView::hide);
+}
+
+QtScreenSearchView::~QtScreenSearchView()
+{
+}
+
+void QtScreenSearchView::createWidgetWrapper()
+{
+ setWidgetWrapper(std::make_shared(m_widget));
+}
+
+void QtScreenSearchView::initView()
+{
+}
+
+void QtScreenSearchView::refreshView()
+{
+ m_onQtThread([=]()
+ {
+ m_bar->setStyleSheet(
+ utility::getStyleSheet(ResourcePaths::getGuiPath().concat(
+ FilePath("screen_search_view/screen_search_view.css"))).c_str()
+ );
+
+ m_widget->refreshStyle();
+ });
+}
+
+void QtScreenSearchView::setMatchCount(size_t matchCount)
+{
+ m_onQtThread([=]()
+ {
+ m_widget->setMatchCount(matchCount);
+ });
+}
+
+void QtScreenSearchView::setMatchIndex(size_t matchIndex)
+{
+ m_onQtThread([=]()
+ {
+ m_widget->setMatchIndex(matchIndex);
+ });
+}
+
+void QtScreenSearchView::addResponder(const std::string& name)
+{
+ m_widget->addResponder(name);
+}
+
+void QtScreenSearchView::show()
+{
+ QtMainWindow* mainWindow = dynamic_cast(getViewLayout())->getMainWindow();
+ mainWindow->addToolBar(Qt::BottomToolBarArea, m_bar);
+
+ m_bar->show();
+ m_widget->setFocus();
+}
+
+void QtScreenSearchView::hide()
+{
+ m_bar->hide();
+ m_widget->setMatchCount(0);
+
+ m_controllerProxy.executeAsTask(
+ [](ScreenSearchController* controller)
+ {
+ controller->clearMatches();
+ }
+ );
+}
diff --git a/src/lib_gui/qt/view/QtScreenSearchView.h b/src/lib_gui/qt/view/QtScreenSearchView.h
new file mode 100644
index 00000000..8bd52356
--- /dev/null
+++ b/src/lib_gui/qt/view/QtScreenSearchView.h
@@ -0,0 +1,44 @@
+#ifndef QT_SCREEN_SEARCH_VIEW_H
+#define QT_SCREEN_SEARCH_VIEW_H
+
+#include "component/controller/helper/ControllerProxy.h"
+#include "component/view/ScreenSearchView.h"
+#include "qt/utility/QtThreadedFunctor.h"
+
+class QtScreenSearchBox;
+class QToolBar;
+
+class QtScreenSearchView
+ : public QObject
+ , public ScreenSearchView
+{
+ Q_OBJECT
+
+public:
+ QtScreenSearchView(ViewLayout* viewLayout);
+ ~QtScreenSearchView();
+
+ // View implementation
+ virtual void createWidgetWrapper() override;
+ virtual void initView() override;
+ virtual void refreshView() override;
+
+ // ScreenSearchView implementation
+ virtual void setMatchCount(size_t matchCount) override;
+ virtual void setMatchIndex(size_t matchIndex) override;
+
+ virtual void addResponder(const std::string& name) override;
+
+public slots:
+ void show();
+ void hide();
+
+private:
+ ControllerProxy m_controllerProxy;
+ QtThreadedLambdaFunctor m_onQtThread;
+
+ QtScreenSearchBox* m_widget;
+ QToolBar* m_bar;
+};
+
+#endif // QT_SCREEN_SEARCH_VIEW_H
diff --git a/src/lib_gui/qt/view/QtTooltipView.cpp b/src/lib_gui/qt/view/QtTooltipView.cpp
index e0c9509e..82e0cbc8 100644
--- a/src/lib_gui/qt/view/QtTooltipView.cpp
+++ b/src/lib_gui/qt/view/QtTooltipView.cpp
@@ -5,13 +5,12 @@
#include "qt/view/QtMainView.h"
#include "qt/view/QtViewWidgetWrapper.h"
#include "qt/window/QtMainWindow.h"
-#include "settings/ColorScheme.h"
#include "utility/ResourcePaths.h"
QtTooltipView::QtTooltipView(ViewLayout* viewLayout)
: TooltipView(viewLayout)
{
- m_widget = new QtTooltip(dynamic_cast(getViewLayout())->getMainWindow());
+ m_widget = new QtTooltip(dynamic_cast(viewLayout)->getMainWindow());
}
QtTooltipView::~QtTooltipView()
@@ -31,7 +30,9 @@ void QtTooltipView::refreshView()
{
m_onQtThread([=]()
{
- setStyleSheet();
+ m_widget->setStyleSheet(
+ utility::getStyleSheet(ResourcePaths::getGuiPath().concat(FilePath("tooltip_view/tooltip_view.css"))).c_str()
+ );
});
}
@@ -68,10 +69,3 @@ bool QtTooltipView::tooltipVisible() const
{
return m_widget->isVisible();
}
-
-void QtTooltipView::setStyleSheet()
-{
- m_widget->setStyleSheet(
- utility::getStyleSheet(ResourcePaths::getGuiPath().concat(FilePath("tooltip_view/tooltip_view.css"))).c_str()
- );
-}
diff --git a/src/lib_gui/qt/view/QtTooltipView.h b/src/lib_gui/qt/view/QtTooltipView.h
index a324ed70..6d5ea566 100644
--- a/src/lib_gui/qt/view/QtTooltipView.h
+++ b/src/lib_gui/qt/view/QtTooltipView.h
@@ -25,9 +25,6 @@ public:
virtual bool tooltipVisible() const;
private:
- void setStyleSheet();
- void doRefreshView();
-
QtThreadedLambdaFunctor m_onQtThread;
QtTooltip* m_widget;
diff --git a/src/lib_gui/qt/view/QtViewFactory.cpp b/src/lib_gui/qt/view/QtViewFactory.cpp
index 958a70aa..dce70986 100644
--- a/src/lib_gui/qt/view/QtViewFactory.cpp
+++ b/src/lib_gui/qt/view/QtViewFactory.cpp
@@ -11,6 +11,7 @@
#include "qt/view/QtLogView.h"
#include "qt/view/QtMainView.h"
#include "qt/view/QtRefreshView.h"
+#include "qt/view/QtScreenSearchView.h"
#include "qt/view/QtSearchView.h"
#include "qt/view/QtStatusBarView.h"
#include "qt/view/QtStatusView.h"
@@ -84,6 +85,11 @@ std::shared_ptr QtViewFactory::createRefreshView(ViewLayout* viewLa
return View::createInitAndAddToLayout(viewLayout);
}
+std::shared_ptr QtViewFactory::createScreenSearchView(ViewLayout* viewLayout) const
+{
+ return View::createAndInit(viewLayout);
+}
+
std::shared_ptr QtViewFactory::createSearchView(ViewLayout* viewLayout) const
{
return View::createInitAndAddToLayout(viewLayout);
diff --git a/src/lib_gui/qt/view/QtViewFactory.h b/src/lib_gui/qt/view/QtViewFactory.h
index d1f13777..ffc59736 100644
--- a/src/lib_gui/qt/view/QtViewFactory.h
+++ b/src/lib_gui/qt/view/QtViewFactory.h
@@ -20,6 +20,7 @@ public:
virtual std::shared_ptr createGraphView(ViewLayout* viewLayout) const;
virtual std::shared_ptr createLogView(ViewLayout* viewLayout) const;
virtual std::shared_ptr createRefreshView(ViewLayout* viewLayout) const;
+ virtual std::shared_ptr createScreenSearchView(ViewLayout* viewLayout) const;
virtual std::shared_ptr createSearchView(ViewLayout* viewLayout) const;
virtual std::shared_ptr createStatusBarView(ViewLayout* viewLayout) const;
virtual std::shared_ptr createStatusView(ViewLayout* viewLayout) const;
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNode.cpp b/src/lib_gui/qt/view/graphElements/QtGraphNode.cpp
index fe9c8773..826abd25 100644
--- a/src/lib_gui/qt/view/graphElements/QtGraphNode.cpp
+++ b/src/lib_gui/qt/view/graphElements/QtGraphNode.cpp
@@ -2,6 +2,7 @@
#include
#include
+#include
#include
#include
@@ -11,6 +12,7 @@
#include "qt/view/graphElements/nodeComponents/QtGraphNodeComponent.h"
#include "qt/view/graphElements/QtGraphEdge.h"
#include "utility/ResourcePaths.h"
+#include "utility/utilityString.h"
void QtGraphNode::blendIn()
{
@@ -40,10 +42,6 @@ QFont QtGraphNode::getFontForNodeType(Node::NodeType type)
}
QtGraphNode::QtGraphNode()
- : m_icon(nullptr)
- , m_isActive(false)
- , m_multipleActive(false)
- , m_isHovering(false)
{
this->setPen(QPen(Qt::transparent));
@@ -244,6 +242,35 @@ void QtGraphNode::focusOut()
updateStyle();
}
+void QtGraphNode::matchNameRecursive(const std::string& query, std::vector* matchedNodes)
+{
+ matchName(query, matchedNodes);
+
+ for (auto subNode : m_subNodes)
+ {
+ subNode->matchNameRecursive(query, matchedNodes);
+ }
+}
+
+void QtGraphNode::removeNameMatch()
+{
+ if (m_matchLength)
+ {
+ m_matchRect->hide();
+ m_matchText->hide();
+
+ m_matchPos = 0;
+ m_matchLength = 0;
+
+ updateStyle();
+ }
+}
+
+void QtGraphNode::setActiveMatch(bool active)
+{
+ m_isActiveMatch = active;
+}
+
bool QtGraphNode::isDataNode() const
{
return false;
@@ -407,6 +434,40 @@ void QtGraphNode::notifyEdgesAfterMove()
}
}
+void QtGraphNode::matchName(const std::string& query, std::vector* matchedNodes)
+{
+ m_isActiveMatch = false;
+ std::string name = getName();
+ size_t pos = utility::toLowerCase(name).find(query);
+
+ if (pos != std::string::npos)
+ {
+ if (!m_matchText)
+ {
+ m_matchRect = new QtRoundedRectItem(this);
+ m_matchText = new QGraphicsSimpleTextItem(this);
+ }
+
+ m_matchRect->show();
+ m_matchText->show();
+
+ std::string matchName(name.length(), ' ');
+ matchName.replace(pos, query.length(), name.substr(pos, query.length()));
+ m_matchText->setText(matchName.c_str());
+
+ matchedNodes->push_back(this);
+
+ m_matchPos = pos;
+ m_matchLength = query.length();
+
+ updateStyle();
+ }
+ else if (m_matchLength)
+ {
+ removeNameMatch();
+ }
+}
+
void QtGraphNode::setStyle(const GraphViewStyle::NodeStyle& style)
{
QPen pen(Qt::transparent);
@@ -462,4 +523,25 @@ void QtGraphNode::setStyle(const GraphViewStyle::NodeStyle& style)
m_text->setFont(font);
m_text->setBrush(QBrush(style.color.text.c_str()));
m_text->setPos(style.iconOffset.x + style.iconSize + style.textOffset.x, style.textOffset.y);
+
+ if (m_matchLength)
+ {
+ GraphViewStyle::NodeColor color = GraphViewStyle::getScreenMatchColor(m_isActiveMatch);
+
+ m_matchText->setFont(font);
+ m_matchText->setBrush(QBrush(color.text.c_str()));
+ m_matchText->setPos(style.iconOffset.x + style.iconSize + style.textOffset.x, style.textOffset.y);
+
+ float charWidth = QFontMetrics(font).width("QtGraphNode::QtGraphNode::QtGraphNode") / 37.0f;
+ float charHeight = QFontMetrics(font).height();
+ m_matchRect->setRect(
+ style.iconOffset.x + style.iconSize + style.textOffset.x + m_matchPos * charWidth,
+ style.textOffset.y,
+ m_matchLength * charWidth,
+ charHeight
+ );
+ m_matchRect->setPen(QPen(color.border.c_str()));
+ m_matchRect->setBrush(QBrush(color.fill.c_str()));
+ m_matchRect->setRadius(3);
+ }
}
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNode.h b/src/lib_gui/qt/view/graphElements/QtGraphNode.h
index 3a7a535a..046af9d5 100644
--- a/src/lib_gui/qt/view/graphElements/QtGraphNode.h
+++ b/src/lib_gui/qt/view/graphElements/QtGraphNode.h
@@ -74,6 +74,10 @@ public:
void focusIn();
void focusOut();
+ void matchNameRecursive(const std::string& query, std::vector* matchedNodes);
+ void removeNameMatch();
+ void setActiveMatch(bool active);
+
virtual bool isDataNode() const;
virtual bool isAccessNode() const;
virtual bool isExpandToggleNode() const;
@@ -99,6 +103,8 @@ protected:
void notifyEdgesAfterMove();
+ virtual void matchName(const std::string& query, std::vector* matchedNodes);
+
void setStyle(const GraphViewStyle::NodeStyle& style);
std::list> m_outEdges;
@@ -107,19 +113,26 @@ protected:
std::weak_ptr m_parentNode;
std::list> m_subNodes;
- QGraphicsSimpleTextItem* m_text;
- QtRoundedRectItem* m_rect;
- QtRoundedRectItem* m_undefinedRect;
- QGraphicsPixmapItem* m_icon;
+ QGraphicsSimpleTextItem* m_text = nullptr;
+ QtRoundedRectItem* m_rect = nullptr;
+ QtRoundedRectItem* m_undefinedRect = nullptr;
+ QGraphicsPixmapItem* m_icon = nullptr;
Vec2i m_size;
- bool m_isActive;
- bool m_multipleActive;
- bool m_isHovering;
+ bool m_isActive = false;
+ bool m_multipleActive = false;
+ bool m_isHovering = false;
private:
std::list> m_components;
+
+ // Name match
+ QGraphicsSimpleTextItem* m_matchText = nullptr;
+ QtRoundedRectItem* m_matchRect = nullptr;
+ size_t m_matchPos = 0;
+ size_t m_matchLength = 0;
+ bool m_isActiveMatch = false;
};
#endif // QT_GRAPH_NODE_H
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNodeAccess.h b/src/lib_gui/qt/view/graphElements/QtGraphNodeAccess.h
index 9893f15e..9babdc7f 100644
--- a/src/lib_gui/qt/view/graphElements/QtGraphNodeAccess.h
+++ b/src/lib_gui/qt/view/graphElements/QtGraphNodeAccess.h
@@ -23,6 +23,9 @@ public:
void hideLabel();
+protected:
+ virtual void matchName(const std::string& query, std::vector* matchedNodes) {}
+
private:
AccessKind m_accessKind;
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNodeExpandToggle.h b/src/lib_gui/qt/view/graphElements/QtGraphNodeExpandToggle.h
index d8162c01..8927348d 100644
--- a/src/lib_gui/qt/view/graphElements/QtGraphNodeExpandToggle.h
+++ b/src/lib_gui/qt/view/graphElements/QtGraphNodeExpandToggle.h
@@ -19,6 +19,9 @@ public:
virtual void onClick();
virtual void updateStyle();
+protected:
+ virtual void matchName(const std::string& query, std::vector