Commit a31a70bf authored by vludv's avatar vludv

Merge branch 'master' of github.com:Itseez/opencv_contrib

parents e8d7975e 6a61e07c
*.autosave
*.pyc
*.user
*~
.*.swp
.DS_Store
.sw[a-z]
Thumbs.db
tags
tegra/
.. _Table-Of-Content-CVV:
*cvv* module. GUI for Interactive Visual Debugging
--------------------------------------------------
Here you will learn how to use the cvv module to ease programming computer vision software through visual debugging aids.
.. include:: ../../definitions/tocDefinitions.rst
+
.. tabularcolumns:: m{100pt} m{300pt}
.. cssclass:: toctableopencv
=============== ======================================================
|cvvIntro| *Title:* :ref:`Visual_Debugging_Introduction`
*Compatibility:* > OpenCV 2.4.8
*Author:* |Author_Bihlmaier|
We will learn how to debug our applications in a visual and interactive way.
=============== ======================================================
.. |cvvIntro| image:: images/Visual_Debugging_Introduction_Tutorial_Cover.jpg
:height: 90pt
:width: 90pt
.. raw:: latex
\pagebreak
.. toctree::
:hidden:
../visual_debugging_introduction/visual_debugging_introduction
set(the_description "Custom Calibration Pattern")
ocv_define_module(ccalib opencv_core opencv_imgproc opencv_calib3d opencv_features2d)
Custom Calibration Pattern
==========================
.. highlight:: cpp
CustomPattern
-------------
A custom pattern class that can be used to calibrate a camera and to further track the translation and rotation of the pattern. Defaultly it uses an ``ORB`` feature detector and a ``BruteForce-Hamming(2)`` descriptor matcher to find the location of the pattern feature points that will subsequently be used for calibration.
.. ocv:class:: CustomPattern : public Algorithm
CustomPattern::CustomPattern
----------------------------
CustomPattern constructor.
.. ocv:function:: CustomPattern()
CustomPattern::create
---------------------
A method that initializes the class and generates the necessary detectors, extractors and matchers.
.. ocv:function:: bool create(InputArray pattern, const Size2f boardSize, OutputArray output = noArray())
:param pattern: The image, which will be used as a pattern. If the desired pattern is part of a bigger image, you can crop it out using image(roi).
:param boardSize: The size of the pattern in physical dimensions. These will be used to scale the points when the calibration occurs.
:param output: A matrix that is the same as the input pattern image, but has all the feature points drawn on it.
:return Returns whether the initialization was successful or not. Possible reason for failure may be that no feature points were detected.
.. seealso::
:ocv:func:`getFeatureDetector`,
:ocv:func:`getDescriptorExtractor`,
:ocv:func:`getDescriptorMatcher`
.. note::
* Determine the number of detected feature points can be done through :ocv:func:`getPatternPoints` method.
* The feature detector, extractor and matcher cannot be changed after initialization.
CustomPattern::findPattern
--------------------------
Finds the pattern in the input image
.. ocv:function:: bool findPattern(InputArray image, OutputArray matched_features, OutputArray pattern_points, const double ratio = 0.7, const double proj_error = 8.0, const bool refine_position = false, OutputArray out = noArray(), OutputArray H = noArray(), OutputArray pattern_corners = noArray());
:param image: The input image where the pattern is searched for.
:param matched_features: A ``vector<Point2f>`` of the projections of calibration pattern points, matched in the image. The points correspond to the ``pattern_points``.``matched_features`` and ``pattern_points`` have the same size.
:param pattern_points: A ``vector<Point3f>`` of calibration pattern points in the calibration pattern coordinate space.
:param ratio: A ratio used to threshold matches based on D. Lowe's point ratio test.
:param proj_error: The maximum projection error that is allowed when the found points are back projected. A lower projection error will be beneficial for eliminating mismatches. Higher values are recommended when the camera lens has greater distortions.
:param refine_position: Whether to refine the position of the feature points with :ocv:func:`cornerSubPix`.
:param out: An image showing the matched feature points and a contour around the estimated pattern.
:param H: The homography transformation matrix between the pattern and the current image.
:param pattern_corners: A ``vector<Point2f>`` containing the 4 corners of the found pattern.
:return The method return whether the pattern was found or not.
CustomPattern::isInitialized
----------------------------
.. ocv:function:: bool isInitialized()
:return If the class is initialized or not.
CustomPattern::getPatternPoints
-------------------------------
.. ocv:function:: void getPatternPoints(OutputArray original_points)
:param original_points: Fills the vector with the points found in the pattern.
CustomPattern::getPixelSize
---------------------------
.. ocv:function:: double getPixelSize()
:return Get the physical pixel size as initialized by the pattern.
CustomPattern::setFeatureDetector
---------------------------------
.. ocv:function:: bool setFeatureDetector(Ptr<FeatureDetector> featureDetector)
:param featureDetector: Set a new FeatureDetector.
:return Is it successfully set? Will fail if the object is already initialized by :ocv:func:`create`.
.. note::
* It is left to user discretion to select matching feature detector, extractor and matchers. Please consult the documentation for each to confirm coherence.
CustomPattern::setDescriptorExtractor
-------------------------------------
.. ocv:function:: bool setDescriptorExtractor(Ptr<DescriptorExtractor> extractor)
:param extractor: Set a new DescriptorExtractor.
:return Is it successfully set? Will fail if the object is already initialized by :ocv:func:`create`.
CustomPattern::setDescriptorMatcher
-----------------------------------
.. ocv:function:: bool setDescriptorMatcher(Ptr<DescriptorMatcher> matcher)
:param matcher: Set a new DescriptorMatcher.
:return Is it successfully set? Will fail if the object is already initialized by :ocv:func:`create`.
CustomPattern::getFeatureDetector
---------------------------------
.. ocv:function:: Ptr<FeatureDetector> getFeatureDetector()
:return The used FeatureDetector.
CustomPattern::getDescriptorExtractor
-------------------------------------
.. ocv:function:: Ptr<DescriptorExtractor> getDescriptorExtractor()
:return The used DescriptorExtractor.
CustomPattern::getDescriptorMatcher
-----------------------------------
.. ocv:function:: Ptr<DescriptorMatcher> getDescriptorMatcher()
:return The used DescriptorMatcher.
CustomPattern::calibrate
------------------------
Calibrates the camera.
.. ocv:function:: double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags = 0, TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON))
See :ocv:func:`calibrateCamera` for parameter information.
CustomPattern::findRt
---------------------
Finds the rotation and translation vectors of the pattern.
.. ocv:function:: bool findRt(InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int flags = ITERATIVE)
.. ocv:function:: bool findRt(InputArray image, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int flags = ITERATIVE)
:param image: The image, in which the rotation and translation of the pattern will be found.
See :ocv:func:`solvePnP` for parameter information.
CustomPattern::findRtRANSAC
---------------------------
Finds the rotation and translation vectors of the pattern using RANSAC.
.. ocv:function:: bool findRtRANSAC(InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int iterationsCount = 100, float reprojectionError = 8.0, int minInliersCount = 100, OutputArray inliers = noArray(), int flags = ITERATIVE)
.. ocv:function:: bool findRtRANSAC(InputArray image, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int iterationsCount = 100, float reprojectionError = 8.0, int minInliersCount = 100, OutputArray inliers = noArray(), int flags = ITERATIVE)
:param image: The image, in which the rotation and translation of the pattern will be found.
See :ocv:func:`solvePnPRANSAC` for parameter information.
CustomPattern::drawOrientation
------------------------------
Draws the ``(x,y,z)`` axis on the image, in the center of the pattern, showing the orientation of the pattern.
.. ocv:function:: void drawOrientation(InputOutputArray image, InputArray tvec, InputArray rvec, InputArray cameraMatrix, InputArray distCoeffs, double axis_length = 3, int axis_width = 2)
:param image: The image, based on which the rotation and translation was calculated. The axis will be drawn in color - ``x`` - in red, ``y`` - in green, ``z`` - in blue.
:param tvec: Translation vector.
:param rvec: Rotation vector.
:param cameraMatrix: The camera matrix.
:param distCoeffs: The distortion coefficients.
:param axis_length: The length of the axis symbol.
:param axis_width: The width of the axis symbol.
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2014, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_CCALIB_HPP__
#define __OPENCV_CCALIB_HPP__
#include <opencv2/core.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <vector>
namespace cv{ namespace ccalib{
class CV_EXPORTS CustomPattern : public Algorithm
{
public:
CustomPattern();
virtual ~CustomPattern();
bool create(InputArray pattern, const Size2f boardSize, OutputArray output = noArray());
bool findPattern(InputArray image, OutputArray matched_features, OutputArray pattern_points, const double ratio = 0.7,
const double proj_error = 8.0, const bool refine_position = false, OutputArray out = noArray(),
OutputArray H = noArray(), OutputArray pattern_corners = noArray());
bool isInitialized();
void getPatternPoints(OutputArray original_points);
/*
Returns a vector<Point> of the original points.
*/
double getPixelSize();
/*
Get the pixel size of the pattern
*/
bool setFeatureDetector(Ptr<FeatureDetector> featureDetector);
bool setDescriptorExtractor(Ptr<DescriptorExtractor> extractor);
bool setDescriptorMatcher(Ptr<DescriptorMatcher> matcher);
Ptr<FeatureDetector> getFeatureDetector();
Ptr<DescriptorExtractor> getDescriptorExtractor();
Ptr<DescriptorMatcher> getDescriptorMatcher();
double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints,
Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags = 0,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON));
/*
Calls the calirateCamera function with the same inputs.
*/
bool findRt(InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs,
OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int flags = SOLVEPNP_ITERATIVE);
bool findRt(InputArray image, InputArray cameraMatrix, InputArray distCoeffs,
OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int flags = SOLVEPNP_ITERATIVE);
/*
Uses solvePnP to find the rotation and translation of the pattern
with respect to the camera frame.
*/
bool findRtRANSAC(InputArray objectPoints, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs,
OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int iterationsCount = 100,
float reprojectionError = 8.0, int minInliersCount = 100, OutputArray inliers = noArray(), int flags = SOLVEPNP_ITERATIVE);
bool findRtRANSAC(InputArray image, InputArray cameraMatrix, InputArray distCoeffs,
OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess = false, int iterationsCount = 100,
float reprojectionError = 8.0, int minInliersCount = 100, OutputArray inliers = noArray(), int flags = SOLVEPNP_ITERATIVE);
/*
Uses solvePnPRansac()
*/
void drawOrientation(InputOutputArray image, InputArray tvec, InputArray rvec, InputArray cameraMatrix,
InputArray distCoeffs, double axis_length = 3, int axis_width = 2);
/*
pattern_corners -> projected over the image position of the edges of the pattern.
*/
private:
Mat img_roi;
std::vector<Point2f> obj_corners;
double pxSize;
bool initialized;
Ptr<FeatureDetector> detector;
Ptr<DescriptorExtractor> descriptorExtractor;
Ptr<DescriptorMatcher> descriptorMatcher;
std::vector<KeyPoint> keypoints;
std::vector<Point3f> points3d;
Mat descriptor;
bool init(Mat& image, const float pixel_size, OutputArray output = noArray());
bool findPatternPass(const Mat& image, std::vector<Point2f>& matched_features, std::vector<Point3f>& pattern_points,
Mat& H, std::vector<Point2f>& scene_corners, const double pratio, const double proj_error,
const bool refine_position = false, const Mat& mask = Mat(), OutputArray output = noArray());
void scaleFoundPoints(const double squareSize, const std::vector<KeyPoint>& corners, std::vector<Point3f>& pts3d);
void check_matches(std::vector<Point2f>& matched, const std::vector<Point2f>& pattern, std::vector<DMatch>& good, std::vector<Point3f>& pattern_3d, const Mat& H);
void keypoints2points(const std::vector<KeyPoint>& in, std::vector<Point2f>& out);
void updateKeypointsPos(std::vector<KeyPoint>& in, const std::vector<Point2f>& new_pos);
void refinePointsPos(const Mat& img, std::vector<Point2f>& p);
void refineKeypointsPos(const Mat& img, std::vector<KeyPoint>& kp);
};
}} // namespace ccalib, cv
#endif
This diff is collapsed.
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2014, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_CCALIB_PRECOMP__
#define __OPENCV_CCALIB_PRECOMP__
#include <opencv2/core.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/features2d.hpp>
#include <vector>
#endif
---
AccessModifierOffset: -2
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: false
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: false
DerivePointerBinding: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 60
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerBindsToType: false
SpacesBeforeTrailingComments: 1
Cpp11BracedListStyle: false
Standard: Cpp11
IndentWidth: 8
TabWidth: 8
UseTab: ForIndentation
BreakBeforeBraces: Allman
IndentFunctionDeclarationAfterType: false
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpaceAfterControlStatementKeyword: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
...
build/
CMakeLists.txt.user
.ycm_extra_conf.py
.ycm_extra_conf.pyc
test.sh
release.sh
*.swp
*.swo
src/dbg/dbg.hpp
*~
if(NOT HAVE_QT5)
ocv_module_disable(cvv)
return()
endif()
# we need C++11 and want warnings:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -pedantic")
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow)
# Qt5
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
foreach(dt5_dep Core Gui Widgets)
add_definitions(${Qt5${dt5_dep}_DEFINITIONS})
include_directories(${Qt5${dt5_dep}_INCLUDE_DIRS})
list(APPEND CVV_LIBRARIES ${Qt5${dt5_dep}_LIBRARIES})
endforeach()
set(the_description "Debug visualization framework")
ocv_define_module(cvv opencv_core opencv_imgproc opencv_features2d ${CVV_LIBRARIES})
Copyright (c) 2013/2014 Johannes Bechberger
Copyright (c) 2013/2014 Erich Bretnütz
Copyright (c) 2013/2014 Nikolai Gaßner
Copyright (c) 2013/2014 Raphael Grimm
Copyright (c) 2013/2014 Clara Scherer
Copyright (c) 2013/2014 Florian Weber
Copyright (c) 2013/2014 Andreas Bihlmaier
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name CVVisual nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
CVVisual
========
*********************************************************************
cvv. GUI for Interactive Visual Debugging of Computer Vision Programs
*********************************************************************
The module provides an interactive GUI to debug and incrementally design computer vision algorithms. The debug statements can remain in the code after development and aid in further changes because they have neglectable overhead if the program is compiled in release mode.
.. toctree::
:maxdepth: 2
CVV API Documentation <cvv_api/index>
CVV GUI Documentation <cvv_gui/index>
CVV : the API
*************
.. highlight:: cpp
Introduction
++++++++++++
Namespace for all functions is **cvv**, i.e. *cvv::showImage()*.
Compilation:
* For development, i.e. for cvv GUI to show up, compile your code using cvv with *g++ -DCVVISUAL_DEBUGMODE*.
* For release, i.e. cvv calls doing nothing, compile your code without above flag.
See cvv tutorial for a commented example application using cvv.
API Functions
+++++++++++++
showImage
---------
Add a single image to debug GUI (similar to :imshow:`imshow <>`).
.. ocv:function:: void showImage(InputArray img, const CallMetaData& metaData, const string& description, const string& view)
:param img: Image to show in debug GUI.
:param metaData: Properly initialized CallMetaData struct, i.e. information about file, line and function name for GUI. Use CVVISUAL_LOCATION macro.
:param description: Human readable description to provide context to image.
:param view: Preselect view that will be used to visualize this image in GUI. Other views can still be selected in GUI later on.
debugFilter
-----------
Add two images to debug GUI for comparison. Usually the input and output of some filter operation, whose result should be inspected.
.. ocv:function:: void debugFilter(InputArray original, InputArray result, const CallMetaData& metaData, const string& description, const string& view)
:param original: First image for comparison, e.g. filter input.
:param result: Second image for comparison, e.g. filter output.
:param metaData: See :ocv:func:`showImage`
:param description: See :ocv:func:`showImage`
:param view: See :ocv:func:`showImage`
debugDMatch
-----------
Add a filled in :basicstructures:`DMatch <dmatch>` to debug GUI. The matches can are visualized for interactive inspection in different GUI views (one similar to an interactive :draw_matches:`drawMatches<>`).
.. ocv:function:: void debugDMatch(InputArray img1, std::vector<cv::KeyPoint> keypoints1, InputArray img2, std::vector<cv::KeyPoint> keypoints2, std::vector<cv::DMatch> matches, const CallMetaData& metaData, const string& description, const string& view, bool useTrainDescriptor)
:param img1: First image used in :basicstructures:`DMatch <dmatch>`.
:param keypoints1: Keypoints of first image.
:param img2: Second image used in DMatch.
:param keypoints2: Keypoints of second image.
:param metaData: See :ocv:func:`showImage`
:param description: See :ocv:func:`showImage`
:param view: See :ocv:func:`showImage`
:param useTrainDescriptor: Use :basicstructures:`DMatch <dmatch>`'s train descriptor index instead of query descriptor index.
finalShow
---------
This function **must** be called *once* *after* all cvv calls if any.
As an alternative create an instance of FinalShowCaller, which calls finalShow() in its destructor (RAII-style).
.. ocv:function:: void finalShow()
setDebugFlag
------------
Enable or disable cvv for current translation unit and thread (disabled this way has higher - but still low - overhead compared to using the compile flags).
.. ocv:function:: void setDebugFlag(bool active)
:param active: See above
CVV : the GUI
*************
.. highlight:: cpp
Introduction
++++++++++++
For now: See cvv tutorial.
Overview
++++++++
Filter
------
Views
++++++++
#ifndef CVVISUAL_CALL_DATA_HPP
#define CVVISUAL_CALL_DATA_HPP
#include <string>
#include <cstddef>
#include <utility>
namespace cvv
{
namespace impl
{
/**
* @brief Optional information about a location in Code.
*/
struct CallMetaData
{
public:
/**
* @brief Creates an unknown location.
*/
CallMetaData()
: file(nullptr), line(0), function(nullptr), isKnown(false)
{
}
/**
* @brief Creates the provided location.
*
* Argument should be self-explaining.
*/
CallMetaData(const char *file, size_t line, const char *function)
: file(file), line(line), function(function), isKnown(true)
{
}
operator bool()
{
return isKnown;
}
// self-explaining:
const char *file;
const size_t line;
const char *function;
/**
* @brief Whether *this holds actual data.
*/
const bool isKnown;
};
}
} // namespaces
#ifdef __GNUC__
#define CVVISUAL_FUNCTION_NAME_MACRO __PRETTY_FUNCTION__
#else
#define CVVISUAL_FUNCTION_NAME_MACRO __func__
#endif
/**
* @brief Creates an instance of CallMetaData with the location of the macro as
* value.
*/
#define CVVISUAL_LOCATION \
::cvv::impl::CallMetaData(__FILE__, __LINE__, \
CVVISUAL_FUNCTION_NAME_MACRO)
#endif
#include <opencv2/cvv/call_meta_data.hpp>
#include <opencv2/cvv/debug_mode.hpp>
#include <opencv2/cvv/dmatch.hpp>
#include <opencv2/cvv/filter.hpp>
#include <opencv2/cvv/final_show.hpp>
#include <opencv2/cvv/show_image.hpp>
#ifndef CVVISUAL_DEBUG_MODE_HPP
#define CVVISUAL_DEBUG_MODE_HPP
#if __cplusplus >= 201103L && defined CVVISUAL_USE_THREAD_LOCAL
#define CVVISUAL_THREAD_LOCAL thread_local
#else
#define CVVISUAL_THREAD_LOCAL
#endif
namespace cvv
{
namespace impl
{
/**
* The debug-flag-singleton
*/
static inline bool &getDebugFlag()
{
CVVISUAL_THREAD_LOCAL static bool flag = true;
return flag;
}
} // namespace impl
/**
* @brief Returns whether debug-mode is active for this TU and thread.
*/
static inline bool debugMode()
{
return impl::getDebugFlag();
}
/**
* @brief Set the debug-mode for this TU and thread.
*/
static inline void setDebugFlag(bool active)
{
impl::getDebugFlag() = active;
}
} // namespace cvv
#endif
#ifndef CVVISUAL_DEBUG_DMATCH_HPP
#define CVVISUAL_DEBUG_DMATCH_HPP
#include <string>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "call_meta_data.hpp"
#include "debug_mode.hpp"
namespace cvv
{
namespace impl
{
void debugDMatch(cv::InputArray img1, std::vector<cv::KeyPoint> keypoints1,
cv::InputArray img2, std::vector<cv::KeyPoint> keypoints2,
std::vector<cv::DMatch> matches, const CallMetaData &data,
const char *description, const char *view,
bool useTrainDescriptor);
} // namespace impl
#ifdef CVVISUAL_DEBUGMODE
static inline void
debugDMatch(cv::InputArray img1, std::vector<cv::KeyPoint> keypoints1,
cv::InputArray img2, std::vector<cv::KeyPoint> keypoints2,
std::vector<cv::DMatch> matches, const impl::CallMetaData &data,
const char *description = nullptr, const char *view = nullptr,
bool useTrainDescriptor = true)
{
if (debugMode())
{
impl::debugDMatch(img1, std::move(keypoints1), img2,
std::move(keypoints2), std::move(matches),
data, description, view, useTrainDescriptor);
}
}
static inline void
debugDMatch(cv::InputArray img1, std::vector<cv::KeyPoint> keypoints1,
cv::InputArray img2, std::vector<cv::KeyPoint> keypoints2,
std::vector<cv::DMatch> matches, const impl::CallMetaData &data,
const std::string &description, const std::string &view,
bool useTrainDescriptor = true)
{
if (debugMode())
{
impl::debugDMatch(img1, std::move(keypoints1), img2,
std::move(keypoints2), std::move(matches),
data, description.c_str(), view.c_str(),
useTrainDescriptor);
}
}
#else
/**
* @brief Debug a set of matches between two images.
*/
static inline void debugDMatch(cv::InputArray, std::vector<cv::KeyPoint>,
cv::InputArray, std::vector<cv::KeyPoint>,
std::vector<cv::DMatch>,
const impl::CallMetaData &,
const char * = nullptr, const char * = nullptr,
bool = true)
{
}
/**
* Dito.
*/
static inline void debugDMatch(cv::InputArray, std::vector<cv::KeyPoint>,
cv::InputArray, std::vector<cv::KeyPoint>,
std::vector<cv::DMatch>,
const impl::CallMetaData &, const std::string &,
const std::string &, bool = true)
{
}
#endif
} // namespace cvv
#endif
#ifndef CVVISUAL_DEBUG_FILTER_HPP
#define CVVISUAL_DEBUG_FILTER_HPP
#include <string>
#include "opencv2/core/core.hpp"
#include "call_meta_data.hpp"
#include "debug_mode.hpp"
namespace cvv
{
namespace impl
{
// implementation outside API
void debugFilter(cv::InputArray original, cv::InputArray result,
const CallMetaData &data, const char *description,
const char *view);
} // namespace impl
#ifdef CVVISUAL_DEBUGMODE
static inline void
debugFilter(cv::InputArray original, cv::InputArray result,
impl::CallMetaData metaData = impl::CallMetaData(),
const char *description = nullptr, const char *view = nullptr)
{
if (debugMode())
{
impl::debugFilter(original, result, metaData, description,
view);
}
}
static inline void debugFilter(cv::InputArray original, cv::InputArray result,
impl::CallMetaData metaData,
const ::std::string &description,
const ::std::string &view = "")
{
if (debugMode())
{
impl::debugFilter(original, result, metaData,
description.c_str(), view.c_str());
}
}
#else
/**
* @brief Use the debug-framework to compare two images (from which the second
* is intended to be the result of
* a filter applied to the first).
*/
static inline void debugFilter(cv::InputArray, cv::InputArray,
impl::CallMetaData = impl::CallMetaData(),
const char * = nullptr, const char * = nullptr)
{
}
/**
* Dito.
*/
static inline void debugFilter(cv::InputArray, cv::InputArray,
impl::CallMetaData, const ::std::string &,
const ::std::string &)
{
}
#endif
} // namespace cvv
#endif
#ifndef CVVISUAL_FINAL_SHOW_HPP
#define CVVISUAL_FINAL_SHOW_HPP
#include "debug_mode.hpp"
namespace cvv
{
namespace impl
{
void finalShow();
}
/**
* @brief Passes the control to the debug-window for a last time.
*
* This function must be called once if there was any prior debug-call. After that all debug-data
* are freed.
*
* If there was no prior call it may be called once in which case it returns
* without opening a window.
*
* In either case no further debug-calls must be made (undefined behaviour!!).
*
*/
inline void finalShow()
{
#ifdef CVVISUAL_DEBUGMODE
if (debugMode())
{
impl::finalShow();
}
#endif
}
/**
* @brief RAII-class to call finalShow() in it's dtor.
*/
class FinalShowCaller
{
public:
/**
* @brief Calls finalShow().
*/
~FinalShowCaller()
{
finalShow();
}
};
}
#endif
#ifndef CVVISUAL_DEBUG_SHOW_IMAGE_HPP
#define CVVISUAL_DEBUG_SHOW_IMAGE_HPP
#include <string>
#include "opencv2/core/core.hpp"
#include "call_meta_data.hpp"
#include "debug_mode.hpp"
namespace cvv
{
namespace impl
{
// implementation outside API
void showImage(cv::InputArray img, const CallMetaData &data,
const char *description, const char *view);
} // namespace impl
#ifdef CVVISUAL_DEBUGMODE
static inline void showImage(cv::InputArray img,
impl::CallMetaData metaData = impl::CallMetaData(),
const char *description = nullptr,
const char *view = nullptr)
{
if (debugMode())
{
impl::showImage(img, metaData, description, view);
}
}
static inline void showImage(cv::InputArray img, impl::CallMetaData metaData,
const ::std::string &description,
const ::std::string &view = "")
{
if (debugMode())
{
impl::showImage(img, metaData, description.c_str(),
view.c_str());
}
}
#else
/**
* Use the debug-framework to show a single image.
*/
static inline void showImage(cv::InputArray,
impl::CallMetaData = impl::CallMetaData(),
const char * = nullptr, const char * = nullptr)
{
}
/**
* Dito.
*/
static inline void showImage(cv::InputArray, impl::CallMetaData,
const ::std::string &, const ::std::string &)
{
}
#endif
} // namespace cvv
#endif
// system includes
#include <getopt.h>
#include <iostream>
// library includes
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#define CVVISUAL_DEBUGMODE
#include <opencv2/cvv/debug_mode.hpp>
#include <opencv2/cvv/show_image.hpp>
#include <opencv2/cvv/filter.hpp>
#include <opencv2/cvv/dmatch.hpp>
#include <opencv2/cvv/final_show.hpp>
template<class T> std::string toString(const T& p_arg)
{
std::stringstream ss;
ss << p_arg;
return ss.str();
}
void
usage()
{
printf("usage: cvv_demo [-r WxH]\n");
printf("-h print this help\n");
printf("-r WxH change resolution to width W and height H\n");
}
int
main(int argc, char** argv)
{
cv::Size* resolution = nullptr;
// parse options
const char* optstring = "hr:";
int opt;
while ((opt = getopt(argc, argv, optstring)) != -1) {
switch (opt) {
case 'h':
usage();
return 0;
break;
case 'r':
{
char dummych;
resolution = new cv::Size();
if (sscanf(optarg, "%d%c%d", &resolution->width, &dummych, &resolution->height) != 3) {
printf("%s not a valid resolution\n", optarg);
return 1;
}
}
break;
default: /* '?' */
usage();
return 2;
}
}
// setup video capture
cv::VideoCapture capture(0);
if (!capture.isOpened()) {
std::cout << "Could not open VideoCapture" << std::endl;
return 3;
}
if (resolution) {
printf("Setting resolution to %dx%d\n", resolution->width, resolution->height);
capture.set(CV_CAP_PROP_FRAME_WIDTH, resolution->width);
capture.set(CV_CAP_PROP_FRAME_HEIGHT, resolution->height);
}
cv::Mat prevImgGray;
std::vector<cv::KeyPoint> prevKeypoints;
cv::Mat prevDescriptors;
int maxFeatureCount = 500;
cv::ORB detector(maxFeatureCount);
cv::BFMatcher matcher(cv::NORM_HAMMING);
for (int imgId = 0; imgId < 10; imgId++) {
// capture a frame
cv::Mat imgRead;
capture >> imgRead;
printf("%d: image captured\n", imgId);
std::string imgIdString{"imgRead"};
imgIdString += toString(imgId);
cvv::showImage(imgRead, CVVISUAL_LOCATION, imgIdString.c_str());
// convert to grayscale
cv::Mat imgGray;
cv::cvtColor(imgRead, imgGray, CV_BGR2GRAY);
cvv::debugFilter(imgRead, imgGray, CVVISUAL_LOCATION, "to gray");
// detect ORB features
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
detector(imgGray, cv::noArray(), keypoints, descriptors);
printf("%d: detected %zd keypoints\n", imgId, keypoints.size());
// match them to previous image (if available)
if (!prevImgGray.empty()) {
std::vector<cv::DMatch> matches;
matcher.match(prevDescriptors, descriptors, matches);
printf("%d: all matches size=%zd\n", imgId, matches.size());
std::string allMatchIdString{"all matches "};
allMatchIdString += toString(imgId-1) + "<->" + toString(imgId);
cvv::debugDMatch(prevImgGray, prevKeypoints, imgGray, keypoints, matches, CVVISUAL_LOCATION, allMatchIdString.c_str());
// remove worst (as defined by match distance) bestRatio quantile
double bestRatio = 0.8;
std::sort(matches.begin(), matches.end());
matches.resize(int(bestRatio * matches.size()));
printf("%d: best matches size=%zd\n", imgId, matches.size());
std::string bestMatchIdString{"best " + toString(bestRatio) + " matches "};
bestMatchIdString += toString(imgId-1) + "<->" + toString(imgId);
cvv::debugDMatch(prevImgGray, prevKeypoints, imgGray, keypoints, matches, CVVISUAL_LOCATION, bestMatchIdString.c_str());
}
prevImgGray = imgGray;
prevKeypoints = keypoints;
prevDescriptors = descriptors;
}
cvv::finalShow();
return 0;
}
#include "view_controller.hpp"
#include <stdexcept>
#include <iostream>
#include <QApplication>
#include <QDesktopServices>
#include <QUrl>
#include "../gui/call_tab.hpp"
#include "../gui/call_window.hpp"
#include "../gui/overview_panel.hpp"
#include "../gui/main_call_window.hpp"
#include "../gui/filter_call_tab.hpp"
#include "../gui/match_call_tab.hpp"
#include "../gui/image_call_tab.hpp"
#include "../impl/init.hpp"
#include "../impl/filter_call.hpp"
#include "../impl/match_call.hpp"
#include "../impl/single_image_call.hpp"
#include "../impl/data_controller.hpp"
#include "../qtutil/util.hpp"
namespace cvv
{
namespace controller
{
// It's only used for instatiating a QApplication.
// static char *emptyArray[] = {""};
static char *parameterSystemV[] = { new char[1]{ 0 }, nullptr };
static int parameterSystemC = 1;
ViewController::ViewController()
{
impl::initializeFilterAndViews();
if (!QApplication::instance())
{
auto tmp =
new QApplication{ parameterSystemC, parameterSystemV };
ownsQApplication = true;
(void)tmp;
}
ovPanel = new gui::OverviewPanel{ util::makeRef(*this) };
mainWindow = new gui::MainCallWindow(util::makeRef(*this), 0, ovPanel);
windowMap[0] = std::unique_ptr<gui::CallWindow>(mainWindow);
max_window_id = 0;
mainWindow->show();
}
ViewController::~ViewController()
{
callTabMap.clear();
windowMap.clear();
windowMap.clear();
if (ownsQApplication)
{
delete QApplication::instance();
}
}
void ViewController::addCallType(const QString typeName, TabFactory constr)
{
ViewController::callTabType[typeName] = constr;
}
std::unique_ptr<cvv::gui::FilterCallTab>
makeFilterCallTab(cvv::util::Reference<cvv::impl::Call> call)
{
return cvv::util::make_unique<cvv::gui::FilterCallTab>(
*call.castTo<cvv::impl::FilterCall>());
}
std::unique_ptr<cvv::gui::MatchCallTab>
makeMatchCallTab(cvv::util::Reference<cvv::impl::Call> call)
{
return cvv::util::make_unique<cvv::gui::MatchCallTab>(
*call.castTo<cvv::impl::MatchCall>());
}
std::unique_ptr<cvv::gui::ImageCallTab>
makeImageCallTab(cvv::util::Reference<cvv::impl::Call> call)
{
return cvv::util::make_unique<cvv::gui::ImageCallTab>(
*call.castTo<cvv::impl::SingleImageCall>());
}
std::map<QString, TabFactory> ViewController::callTabType{
{ "filter", makeFilterCallTab }, { "match", makeMatchCallTab },
{ "singleImage", makeImageCallTab }
};
void ViewController::addCall(util::Reference<impl::Call> data)
{
updateMode();
if (mode == Mode::NORMAL)
{
ovPanel->addElement(*data);
mainWindow->showOverviewTab();
}
else if (mode == Mode::FAST_FORWARD)
{
ovPanel->addElementBuffered(*data);
}
}
void ViewController::exec()
{
updateMode();
if (mode == Mode::NORMAL)
{
QApplication::instance()->exec();
}
}
impl::Call &ViewController::getCall(size_t id)
{
return impl::dataController().getCall(id);
}
QString ViewController::getSetting(const QString &scope, const QString &key)
{
return qtutil::getSetting(scope, key);
}
std::vector<util::Reference<gui::CallWindow>> ViewController::getTabWindows()
{
std::vector<util::Reference<gui::CallWindow>> windows{};
for (auto &it : windowMap)
{
windows.push_back(util::makeRef(*(it.second)));
}
return windows;
}
util::Reference<gui::MainCallWindow> ViewController::getMainWindow()
{
return util::makeRef(*mainWindow);
}
void ViewController::moveCallTabToNewWindow(size_t tabId)
{
if (!hasCall(tabId))
return;
auto newWindow = util::make_unique<gui::CallWindow>(
util::makeRef<ViewController>(*this), ++max_window_id);
removeCallTab(tabId);
newWindow->addTab(getCallTab(tabId));
newWindow->show();
if (doesShowExitProgramButton)
{
newWindow->showExitProgramButton();
}
windowMap[max_window_id] = std::move(newWindow);
removeEmptyWindowsWithDelay();
}
void ViewController::moveCallTabToWindow(size_t tabId, size_t windowId)
{
if (!hasCall(tabId))
return;
removeCallTab(tabId);
auto tab = getCallTab(tabId);
windowMap[windowId]->addTab(tab);
removeEmptyWindowsWithDelay();
}
void ViewController::removeCallTab(size_t tabId, bool deleteIt, bool deleteCall, bool updateUI)
{
auto *curWindow = getCurrentWindowOfTab(tabId);
if (curWindow->hasTab(tabId))
{
getCurrentWindowOfTab(tabId)->removeTab(tabId);
if (deleteIt)
{
callTabMap.erase(tabId);
}
}
if (deleteCall && hasCall(tabId))
{
if (updateUI)
{
ovPanel->removeElement(tabId);
}
impl::dataController().removeCall(tabId);
}
removeEmptyWindowsWithDelay();
}
void ViewController::openHelpBrowser(const QString &topic)
{
qtutil::openHelpBrowser(topic);
}
void ViewController::resumeProgramExecution()
{
QApplication::instance()->exit();
}
void ViewController::setDefaultSetting(const QString &scope, const QString &key,
const QString &value)
{
qtutil::setDefaultSetting(scope, key, value);
}
void ViewController::setSetting(const QString &scope, const QString &key,
const QString &value)
{
qtutil::setSetting(scope, key, value);
}
void ViewController::showCallTab(size_t tabId)
{
auto *window = getCurrentWindowOfTab(tabId);
window->showTab(tabId);
window->setWindowState((window->windowState() & ~Qt::WindowMinimized) |
Qt::WindowActive);
window->raise();
}
void ViewController::showAndOpenCallTab(size_t tabId)
{
auto curWindow = getCurrentWindowOfTab(tabId);
if (!curWindow->hasTab(tabId))
{
moveCallTabToWindow(tabId, 0);
curWindow = mainWindow;
}
curWindow->showTab(tabId);
}
void ViewController::openCallTab(size_t tabId)
{
auto curWindow = getCurrentWindowOfTab(tabId);
if (!curWindow->hasTab(tabId))
{
moveCallTabToWindow(tabId, 0);
curWindow = mainWindow;
}
}
void ViewController::showOverview()
{
mainWindow->setWindowState(
(mainWindow->windowState() & ~Qt::WindowMinimized) |
Qt::WindowActive);
mainWindow->raise();
mainWindow->showOverviewTab();
}
gui::CallWindow *ViewController::getCurrentWindowOfTab(size_t tabId)
{
for (auto &elem : windowMap)
{
if (elem.second->hasTab(tabId))
{
return elem.second.get();
}
}
return mainWindow;
}
gui::CallTab *ViewController::getCallTab(size_t tabId)
{
if (callTabMap.count(tabId) == 0)
{
auto *call = &(getCall(tabId));
if (callTabType.count(call->type()) == 0)
{
throw std::invalid_argument{
"no such type '" + call->type().toStdString() +
"'"
};
}
callTabMap[tabId] =
callTabType[call->type()](util::makeRef(*call));
}
return callTabMap[tabId].get();
}
void ViewController::removeWindowFromMaps(size_t windowId)
{
if (windowMap.count(windowId) > 0)
{
windowMap[windowId].release();
windowMap.erase(windowId);
}
}
void ViewController::removeEmptyWindows()
{
std::vector<size_t> remIds{};
for (auto &elem : windowMap)
{
if (elem.second->tabCount() == 0 && elem.second->getId() != 0)
{
remIds.push_back(elem.first);
}
}
for (auto windowId : remIds)
{
auto window = windowMap[windowId].release();
windowMap.erase(windowId);
window->deleteLater();
}
shouldRunRemoveEmptyWindows_ = false;
}
void ViewController::removeEmptyWindowsWithDelay()
{
shouldRunRemoveEmptyWindows_ = true;
}
bool ViewController::shouldRunRemoveEmptyWindows()
{
return shouldRunRemoveEmptyWindows_;
}
void ViewController::showExitProgramButton()
{
for (auto &elem : windowMap)
{
elem.second->showExitProgramButton();
}
doesShowExitProgramButton = true;
}
bool ViewController::hasCall(size_t id)
{
return impl::dataController().hasCall(id);
}
void ViewController::setMode(Mode newMode)
{
mode = newMode;
switch (newMode)
{
case Mode::NORMAL:
break;
case Mode::HIDE:
hideAll();
QApplication::instance()->exit();
break;
case Mode::FAST_FORWARD:
if (!doesShowExitProgramButton)
{
QApplication::instance()->exit();
}
else
{
mode = Mode::NORMAL;
}
break;
}
}
Mode ViewController::getMode()
{
return mode;
}
void ViewController::updateMode()
{
if (mode == Mode::FAST_FORWARD && hasFinalCall())
{
mode = Mode::NORMAL;
ovPanel->flushElementBuffer();
}
}
void ViewController::hideAll()
{
for (auto &window : windowMap)
{
window.second->hide();
}
}
bool ViewController::hasFinalCall()
{
return doesShowExitProgramButton;
}
}
}
#ifndef CVVISUAL_VIEWCONTROLLER_HPP
#define CVVISUAL_VIEWCONTROLLER_HPP
#include <vector>
#include <algorithm>
#include <iostream>
#include <map>
#include <memory>
#include <functional>
#include <utility>
#include <QString>
#include "../util/util.hpp"
#include "../impl/call.hpp"
#include "../gui/call_window.hpp"
#include "../gui/call_tab.hpp"
namespace cvv
{
namespace gui
{
class CallTab;
class CallWindow;
class MainCallWindow;
class OverviewPanel;
}
namespace controller
{
/**
* @brief Modes that this cvv application can be running in.
*/
enum class Mode
{
/**
* @brief The normal mode.
*/
NORMAL = 0,
/**
* @brief The cvv UI is hidden.
*/
HIDE = 1,
/**
* @brief The cvv UI stops only at the final call
* The final call is the call which is called after `cvv::finalShow()`)
*/
FAST_FORWARD = 2
};
class ViewController;
/**
* @brief Typedef for a function that creates a CallTab from a impl::Call.
*/
using TabFactory =
std::function<std::unique_ptr<gui::CallTab>(util::Reference<impl::Call>)>;
/**
* @brief Controlls the windows, call tabs and the event fetch loop.
* Its the layer between the low level model (aka DataController) an the high
* level GUI (aka CallTab, OverviewPanel, ...).
*/
class ViewController
{
public:
/**
* @brief The default contructor for this class.
*/
ViewController();
/**
* @brief Clean up.
*/
~ViewController();
/**
* @brief Adds the new call tab type.
* @param typeName name of the new type
* @param constr function constructing an instance of this call tab
* type
* @return an instance of the new call tab type
*/
static void addCallType(const QString typeName, TabFactory constr);
/**
* @brief Adds a new call and shows it in the overview table.
* @param data new call (data)
*/
void addCall(util::Reference<impl::Call> data);
/**
* @brief Execute the Qt event loop.
*/
void exec();
/**
* @brief Get the call with the given id.
* @param id given id
* @return call with the given id
*/
impl::Call &getCall(size_t id);
/**
* @brief Get the current setting [key] in the given scope.
* Please use `setDefaultSetting` to set a default value that's other
* than
* an empty QString.
* @param scope given scope (e.g. 'Overview')
* @param key settings key (e.g. 'autoOpenTabs')
* @return settings string
*/
QString getSetting(const QString &scope, const QString &key);
/**
* @brief Get the inherited call windows with tabs.
* @return the inherited CallWindows
*/
std::vector<util::Reference<gui::CallWindow>> getTabWindows();
/**
* @brief Get the inherited main window.
* @return the inherited main window
*/
util::Reference<gui::MainCallWindow> getMainWindow();
/**
* @brief Move the call tab with the given id to a new window.
* @param tabId given call tab id
*/
void moveCallTabToNewWindow(size_t tabId);
/**
* @brief Move the given call tab to the given window.
* @param tabId id of the given call tab
* @param windowId id of the given window (0 is the main window)
*/
void moveCallTabToWindow(size_t tabId, size_t windowId);
/**
* @brief Removes the call tab with the given id.
* @param tabId given id
* @param deleteCall if deleteCall and deleteIt are true, it also
* deletes the proper Call
*/
void removeCallTab(size_t tabId, bool deleteIt = true,
bool deleteCall = false, bool updateUI = true);
/**
* @brief Opens the users default browser with the topic help page.
* Current URL: cvv.mostlynerdless.de/help.php?topic=[topic]
*
* Topics can be added via appending the doc/topics.yml file.
*
* @param topic help topic
*/
void openHelpBrowser(const QString &topic);
/**
* @brief Resume the execution of the calling program.
*/
void resumeProgramExecution();
/**
* @brief Set the default setting for a given stettings key and scope.
* It doesn't override existing settings.
* @param scope given settings scope
* @param key given settings key
* @param value default value of the setting
*/
void setDefaultSetting(const QString &scope, const QString &key,
const QString &value);
/**
* @brief Set the setting for a given stettings key and scope.
* @param scope given settings scope
* @param key given settings key
* @param value new value of the setting
*/
void setSetting(const QString &scope, const QString &key,
const QString &value);
/**
* @brief Show the given call tab and bring it's window to the front.
* @note It's not guaranteed that it really brings the tabs' window to the front.
* @param tabId id of the given call tab
*/
void showCallTab(size_t tabId);
/**
* @brief Shows the tab and opens it if neccessary.
* @param tabId id of the tab
*/
void showAndOpenCallTab(size_t tabId);
/**
* @brief Opens the tab it if neccessary.
* @param tabId id of the tab
*/
void openCallTab(size_t tabId);
/**
* @brief Show the overview tab (and table) and bring it's window to the
* front.
* @note The latter is not guaranteed.
*/
void showOverview();
/**
* @brief Get the window in which the given tab lays currently.
* @param tabId id of the given call tab
* @return current window
*/
gui::CallWindow *getCurrentWindowOfTab(size_t tabId);
/**
* @brief Returns the call tab with the given id and constructs it if
* doesn't exit.
* @param tabId given id
* @return call tab with given id
*/
gui::CallTab *getCallTab(size_t tabId);
/**
* @brief Remove the window from the internal data structures.
* @param windowId id of the window
* @note Only call this method if you now the implacations of deleting
* the window.
*/
void removeWindowFromMaps(size_t windowId);
/**
* @brief Shows an "Exit program" button on each window.
*/
void showExitProgramButton();
/**
* @brief Removes the empty windows.
* @note It's safer to call the removeEmptyWindowsWithDelay method
* instead.
*/
void removeEmptyWindows();
/**
* @brief Removes the empty windows with a small delay.
*/
void removeEmptyWindowsWithDelay();
/**
* @brief Checks whether or not is useful to call the
* removeEmptyWindows() method.
* @return Is is useful to call the removeEmptyWindows() method?
* @note Please don't call this method outside a periodcally called
* method.
*/
bool shouldRunRemoveEmptyWindows();
/**
* @brief Set the mode that this application is running in.
* @param newMode mode to be set
*/
void setMode(Mode newMode);
/**
* @brief Returns the mode this program is running in.
* @return the current mode, NROMAL, HIDE or FAST_FORWARD
*/
Mode getMode();
/**
* @brief Checks whether or not the `cvv::finalCall()` method has been
* called?
* @return Has the `cvv::finalCall()` method been called?
*/
bool hasFinalCall();
private:
static std::map<QString, TabFactory> callTabType;
std::map<size_t, std::unique_ptr<gui::CallWindow>> windowMap{};
gui::MainCallWindow *mainWindow;
std::map<size_t, std::unique_ptr<gui::CallTab>> callTabMap{};
gui::OverviewPanel *ovPanel;
bool doesShowExitProgramButton = false;
/**
* @brief Counter == 0 <=> you should run `removeEmptyWindows()`.
*/
bool shouldRunRemoveEmptyWindows_ = true;
Mode mode = Mode::NORMAL;
bool ownsQApplication = false;
size_t max_window_id = 0;
bool hasCall(size_t id);
void updateMode();
void hideAll();
};
}
}
#endif
#include "api.hpp"
#include "../gui/filter_call_tab.hpp"
#include "../gui/match_call_tab.hpp"
namespace cvv
{
namespace extend
{
void addCallType(const QString name, TabFactory factory)
{
controller::ViewController::addCallType(name, factory);
}
}
} // namespaces cvv::extend
#ifndef CVVISUAL_EXTENSION_API_HPP
#define CVVISUAL_EXTENSION_API_HPP
#include <opencv2/core/core.hpp>
#include <QString>
#include <QWidget>
#include "../impl/call.hpp"
#include "../controller/view_controller.hpp"
#include "../view/filter_view.hpp"
#include "../gui/match_call_tab.hpp"
#include "../gui/filter_call_tab.hpp"
#include "../qtutil/filterselectorwidget.hpp"
namespace cvv
{
namespace extend
{
/**
* @brief Introduces a new filter-view.
* @param name of the new FilterView.
* @tparam FView A FilterView. Needs to have a constructor of the form
* FView(const cvv::impl::FilterCall&, QWidget*).
*/
template <class FView> void addFilterView(const QString name)
{
cvv::gui::FilterCallTab::registerFilterView<FView>(name);
}
/**
* @brief Introduces a new match-view.
* @param name of the new MatchView.
* @tparam MView A MatchView. Needs to have a constructor of the form
* MView(const cvv::impl::MatchCall&, QWidget*).
*/
template <class MView> void addMatchView(const QString name)
{
cvv::gui::MatchCallTab::registerMatchView<MView>(name);
}
using TabFactory = controller::TabFactory;
/**
* @brief Introduces a new call-type.
* @param factory A function that recieves a reference to a call and should
* return the appropriate
* window.
*/
void addCallType(const QString name, TabFactory factory);
template <std::size_t In, std::size_t Out, class Filter>
/**
* @brief Introduces a new filter for the filter-selector-widget.
*/
bool registerFilter(const QString &name)
{
return cvv::qtutil::registerFilter<In, Out, Filter>(name);
}
}
} // namespaces cvv::extend
#endif
#ifndef CVVISUAL_CALL_TAB_HPP
#define CVVISUAL_CALL_TAB_HPP
#include <QString>
#include <QWidget>
#include "../util/util.hpp"
namespace cvv
{
namespace gui
{
/**
* @brief Super class of the inner part of a tab or window.
* A call tab.
* The inner part of a tab or a window.
* Super class for actual call tabs containing views.
*/
class CallTab : public QWidget
{
Q_OBJECT
public:
/**
* @brief Returns the name of this tab.
* @return current name
*/
const QString getName() const
{
return name;
}
/**
* @brief Sets the name of this tab.
* @param name new name
*/
void setName(const QString &newName)
{
name = newName;
}
/**
* @brief Returns the of this CallTab.
* @return the ID of the CallTab
* (ID is equal to the ID of the associated call in derived classes)
*/
virtual size_t getId() const
{
return 0;
}
private:
QString name;
};
}
} // namespaces
#endif
#include "call_window.hpp"
#include <QMenu>
#include <QStatusBar>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVariant>
#include "../stfl/stringutils.hpp"
namespace cvv
{
namespace controller
{
class ViewController;
}
namespace gui
{
CallWindow::CallWindow(util::Reference<controller::ViewController> controller,
size_t id)
: id{ id }, controller{ controller }
{
initTabs();
initFooter();
setWindowTitle(QString("CVVisual | window no. %1").arg(id));
setMinimumWidth(600);
setMinimumHeight(600);
}
void CallWindow::initTabs()
{
tabWidget = new TabWidget(this);
tabWidget->setTabsClosable(true);
tabWidget->setMovable(true);
setCentralWidget(tabWidget);
auto *flowButtons = new QHBoxLayout();
auto *flowButtonsWidget = new QWidget(this);
tabWidget->setCornerWidget(flowButtonsWidget, Qt::TopLeftCorner);
flowButtonsWidget->setLayout(flowButtons);
flowButtons->setAlignment(Qt::AlignLeft | Qt::AlignTop);
closeButton = new QPushButton("Close", this);
flowButtons->addWidget(closeButton);
closeButton->setStyleSheet(
"QPushButton {background-color: red; color: white;}");
closeButton->setToolTip("Close this debugging application.");
connect(closeButton, SIGNAL(clicked()), this, SLOT(closeApp()));
fastForwardButton = new QPushButton(">>", this);
flowButtons->addWidget(fastForwardButton);
fastForwardButton->setStyleSheet(
"QPushButton {background-color: yellow; color: blue;}");
fastForwardButton->setToolTip(
"Fast forward until cvv::finalCall() gets called.");
connect(fastForwardButton, SIGNAL(clicked()), this,
SLOT(fastForward()));
stepButton = new QPushButton("Step", this);
flowButtons->addWidget(stepButton);
stepButton->setStyleSheet(
"QPushButton {background-color: green; color: white;}");
stepButton->setToolTip(
"Resume program execution for a next debugging step.");
connect(stepButton, SIGNAL(clicked()), this, SLOT(step()));
flowButtons->setContentsMargins(0, 0, 0, 0);
flowButtons->setSpacing(0);
auto *tabBar = tabWidget->getTabBar();
tabBar->setElideMode(Qt::ElideRight);
tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
connect(tabBar, SIGNAL(customContextMenuRequested(QPoint)), this,
SLOT(contextMenuRequested(QPoint)));
connect(tabBar, SIGNAL(tabCloseRequested(int)), this,
SLOT(tabCloseRequested(int)));
}
void CallWindow::initFooter()
{
leftFooter = new QLabel();
rightFooter = new QLabel();
QStatusBar *bar = statusBar();
bar->addPermanentWidget(leftFooter, 2);
bar->addPermanentWidget(rightFooter, 2);
}
void CallWindow::showExitProgramButton()
{
stepButton->setVisible(false);
fastForwardButton->setVisible(false);
}
void CallWindow::addTab(CallTab *tab)
{
tabMap[tab->getId()] = tab;
QString name = QString("[%1] %2").arg(tab->getId()).arg(tab->getName());
int index =
tabWidget->addTab(tab, stfl::shortenString(name, 20, true, true));
tabWidget->getTabBar()->setTabData(index, QVariant((int)tab->getId()));
}
size_t CallWindow::getId()
{
return id;
}
void CallWindow::removeTab(CallTab *tab)
{
tabMap.erase(tabMap.find(tab->getId()));
int index = tabWidget->indexOf(tab);
tabWidget->removeTab(index);
}
void CallWindow::removeTab(size_t tabId)
{
if (hasTab(tabId))
{
removeTab(tabMap[tabId]);
}
}
void CallWindow::showTab(CallTab *tab)
{
tabWidget->setCurrentWidget(tab);
}
void CallWindow::showTab(size_t tabId)
{
if (hasTab(tabId))
{
showTab(tabMap[tabId]);
}
}
void CallWindow::updateLeftFooter(QString newText)
{
leftFooter->setText(newText);
}
void CallWindow::updateRightFooter(QString newText)
{
rightFooter->setText(newText);
}
void CallWindow::step()
{
controller->resumeProgramExecution();
}
void CallWindow::fastForward()
{
controller->setMode(controller::Mode::FAST_FORWARD);
}
void CallWindow::closeApp()
{
controller->setMode(controller::Mode::HIDE);
}
bool CallWindow::hasTab(size_t tabId)
{
return tabMap.count(tabId);
}
void CallWindow::contextMenuRequested(const QPoint &location)
{
controller->removeEmptyWindows();
auto tabBar = tabWidget->getTabBar();
int tabIndex = tabBar->tabAt(location);
if (tabIndex == tabOffset - 1)
return;
QMenu *menu = new QMenu(this);
connect(menu, SIGNAL(triggered(QAction *)), this,
SLOT(contextMenuAction(QAction *)));
auto windows = controller->getTabWindows();
menu->addAction(new QAction("Remove call", this));
menu->addAction(new QAction("Close tab", this));
menu->addAction(new QAction("Open in new window", this));
for (auto window : windows)
{
if (window->getId() != id)
{
menu->addAction(new QAction(
QString("Open in '%1'").arg(window->windowTitle()),
this));
}
}
currentContextMenuTabId = getCallTabIdByTabIndex(tabIndex);
menu->popup(tabBar->mapToGlobal(location));
}
void CallWindow::contextMenuAction(QAction *action)
{
if (currentContextMenuTabId == -1)
{
return;
}
auto text = action->text();
if (text == "Open in new window")
{
controller->moveCallTabToNewWindow(currentContextMenuTabId);
}
else if (text == "Remove call")
{
controller->removeCallTab(currentContextMenuTabId, true, true);
}
else if (text == "Close tab")
{
controller->removeCallTab(currentContextMenuTabId);
}
else
{
auto windows = controller->getTabWindows();
for (auto window : windows)
{
if (text ==
QString("Open in '%1'").arg(window->windowTitle()))
{
controller->moveCallTabToWindow(
currentContextMenuTabId, window->getId());
break;
}
}
}
currentContextMenuTabId = -1;
}
size_t CallWindow::tabCount()
{
return tabMap.size();
}
std::vector<size_t> CallWindow::getCallTabIds()
{
std::vector<size_t> ids{};
for (auto &elem : tabMap)
{
ids.push_back(elem.first);
}
return ids;
}
void CallWindow::closeEvent(QCloseEvent *event)
{
controller->removeWindowFromMaps(id);
// FIXME: tabWidget is already freed sometimes: Use-after-free Bug
tabWidget->clear();
for (auto &elem : tabMap)
{
controller->removeCallTab(elem.first, true);
}
event->accept();
}
void CallWindow::tabCloseRequested(int index)
{
if (hasTabAtIndex(index))
{
controller->removeCallTab(getCallTabIdByTabIndex(index));
}
controller->removeEmptyWindows();
}
size_t CallWindow::getCallTabIdByTabIndex(int index)
{
if (hasTabAtIndex(index))
{
auto tabData = tabWidget->getTabBar()->tabData(index);
bool ok = true;
size_t callTabId = tabData.toInt(&ok);
if (ok && tabMap.count(callTabId) > 0)
{
return callTabId;
}
}
return 0;
}
bool CallWindow::hasTabAtIndex(int index)
{
auto tabData = tabWidget->getTabBar()->tabData(index);
return tabData != 0 && !tabData.isNull() && tabData.isValid();
}
}
}
#ifndef CVVISUAL_CALLWINDOW_HPP
#define CVVISUAL_CALLWINDOW_HPP
#include <vector>
#include <map>
#include <QTabWidget>
#include <QMainWindow>
#include <QString>
#include <vector>
#include <QLabel>
#include <QKeyEvent>
#include <QPoint>
#include <QCloseEvent>
#include <QPushButton>
#include "call_tab.hpp"
#include "../controller/view_controller.hpp"
#include "../util/util.hpp"
#include "tabwidget.hpp"
namespace cvv
{
namespace controller
{
class ViewController;
}
namespace gui
{
/**
* @brief Window inheriting some call tabs with in a tab widget.
*/
class CallWindow : public QMainWindow
{
Q_OBJECT
public:
/**
* @brief Contructs a new call window.
* @param controller view controller that this window belongs to
* @param id id of the window
*/
CallWindow(util::Reference<controller::ViewController> controller,
size_t id);
/**
* @brief Shows an "Exit program" button.
*/
void showExitProgramButton();
/**
* @brief Add a new tab to the inherited tab widget.
* @param tab new tab
*/
void addTab(CallTab *tab);
/**
* @brief Get the id of this window.
* @return id of this window.
*/
size_t getId();
/**
* @brief Remove the given tab from this window.
* @param given tab to remove
*/
void removeTab(CallTab *tab);
/**
* @brief Remove the given tab from this window.
* @param id of the given tab
*/
void removeTab(size_t tabId);
/**
* @brief Show the given tab.
* @param given tab
*/
void showTab(CallTab *tab);
/**
* @brief Show the given tab.
* @param id of the given tab
*/
void showTab(size_t tabId);
/**
* @brief Examines whether or not the given is inherited in this window.
* @param id of the given tab
*/
bool hasTab(size_t tabId);
/**
* @brief Returns the number of tabs shown in this window.
* @return number of tabs
*/
size_t tabCount();
/**
* @brief Returns the ids of the available call tabs.
* @return available call tabs' ids
*/
std::vector<size_t> getCallTabIds();
public slots:
/**
* @brief Update the left footer with the given text.
* @param newText given text
*/
void updateLeftFooter(QString newText);
/**
* @brief Update the right footer with the given text.
* @param newText given text
*/
void updateRightFooter(QString newText);
private slots:
void contextMenuRequested(const QPoint &location);
void contextMenuAction(QAction *action);
void tabCloseRequested(int index);
void step();
void fastForward();
void closeApp();
protected:
size_t id;
util::Reference<controller::ViewController> controller;
TabWidget *tabWidget;
QMainWindow *window;
QPushButton *closeButton;
QPushButton *stepButton;
QPushButton *fastForwardButton;
std::map<size_t, CallTab *> tabMap;
QLabel *leftFooter;
QLabel *rightFooter;
int currentContextMenuTabId = -1;
int tabOffset = 0;
void initMenu();
void initTabs();
void initFooter();
void closeEvent(QCloseEvent *event);
size_t getCallTabIdByTabIndex(int index);
bool hasTabAtIndex(int index);
};
}
}
#endif
#ifndef CVVISUAL_FILTER_CALL_TAB_HPP
#define CVVISUAL_FILTER_CALL_TAB_HPP
#include <QString>
#include <QWidget>
#include "multiview_call_tab.hpp"
#include "../view/filter_view.hpp"
#include "../impl/filter_call.hpp"
namespace cvv
{
namespace gui
{
/** Filter Call Tab.
* @brief Inner part of a tab, contains a FilterView.
* The inner part of a tab or window
* containing a FilterView.
* Allows to switch views and to access the help.
*/
class FilterCallTab
: public MultiViewCallTab<cvv::view::FilterView, cvv::impl::FilterCall>
{
Q_OBJECT
public:
/**
* @brief Short constructor named after the Call, using the requested View
* from the Call or, if no or invalid request, default view.
* Initializes the FilterCallTab with the requested or default view and names it
* after the associated FilterCall.
* @param filterCall - the FilterCall containing the information to be
* visualized.
*/
FilterCallTab(const cvv::impl::FilterCall &filterCall)
: FilterCallTab{
filterCall, filterCall.requestedView()
}
{
}
/**
* @brief Constructor with possibility to select view.
* Note that the default view is still created first.
* @param call - the MatchCall containing the information to be
* visualized.
* @param filterViewId - ID of the View to be set up. If a view of this name does
* not exist, the default view will be used.
*/
FilterCallTab(const cvv::impl::FilterCall &filterCall, const QString& filterViewId)
: MultiViewCallTab<cvv::view::FilterView, cvv::impl::FilterCall>{
filterCall, filterViewId, QString{ "default_filter_view" }, QString{ "DefaultFilterView" }
}
{
}
~FilterCallTab()
{
}
/**
* @brief Register the template class to the map of FilterViews.
* View needs to offer a constructor of the form View(const
* cvv::impl::FilterCall&, QWidget*).
* @param name to register the class under.
* @tparam View - Class to register.
* @return true when the view was registered and false when the name was
* already taken.
*/
template <class View>
static bool registerFilterView(const QString &name)
{
return registerView<View>(name);
}
};
}
} // namespaces
#endif
#include <QString>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include "image_call_tab.hpp"
#include "../view/image_view.hpp"
#include "../controller/view_controller.hpp"
#include "../impl/single_image_call.hpp"
#include "../qtutil/util.hpp"
namespace cvv
{
namespace gui
{
ImageCallTab::ImageCallTab(const cvv::impl::SingleImageCall &call)
: imageCall_{ call }
{
setName(imageCall_->description());
createGui();
}
ImageCallTab::ImageCallTab(const QString &tabName,
const cvv::impl::SingleImageCall &call)
: imageCall_{ call }
{
setName(tabName);
createGui();
}
void ImageCallTab::helpButtonClicked() const
{
cvv::qtutil::openHelpBrowser("SingleImageView");
}
size_t ImageCallTab::getId() const
{
return imageCall_->getId();
}
void ImageCallTab::createGui()
{
hlayout_ = new QHBoxLayout{ this };
hlayout_->setAlignment(Qt::AlignTop);
hlayout_->addWidget(new QLabel{ "Single Image View" });
helpButton_ = new QPushButton{ "Help", this };
hlayout_->addWidget(helpButton_);
connect(helpButton_, SIGNAL(clicked()), this,
SLOT(helpButtonClicked()));
upperBar_ = new QWidget{ this };
upperBar_->setLayout(hlayout_);
vlayout_ = new QVBoxLayout{ this };
vlayout_->addWidget(upperBar_);
setView();
setLayout(vlayout_);
imageView_->showFullImage();
}
void ImageCallTab::setView()
{
imageView_ = new cvv::view::ImageView{ imageCall_->mat(), this };
vlayout_->addWidget(imageView_);
}
}
} // namespaces
#ifndef CVVISUAL_IMAGE_CALL_TAB_HPP
#define CVVISUAL_IMAGE_CALL_TAB_HPP
#include <QHBoxLayout>
#include <QString>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include "call_tab.hpp"
#include "../view/image_view.hpp"
#include "../controller/view_controller.hpp"
#include "../impl/single_image_call.hpp"
namespace cvv
{
namespace gui
{
/** Single Image Call Tab.
* @brief Inner part of a tab, contains an IageView.
* The inner part of a tab or window
* containing an ImageView.
* Allows to access the help.
*/
class ImageCallTab : public CallTab
{
Q_OBJECT
public:
/**
* @brief Short constructor named after the Call.
* Initializes the ImageCallTab and names it after the associated
* FilterCall.
* @param call the SingleImageCall containing the information to be
* visualized.
*/
ImageCallTab(const cvv::impl::SingleImageCall &call);
/**
* @brief Constructor using default view.
* Short constructor..
* @param tabName.
* @param call the SingleImageCall containing the information to be
* visualized.
* @attention might be deleted.
*/
ImageCallTab(const QString &tabName,
const cvv::impl::SingleImageCall &call);
/**
* @brief get ID.
* @return the ID of the CallTab.
* (ID is equal to the ID of the associated call).
* Overrides CallTab's getId.
*/
size_t getId() const override;
private
slots:
/**
* @brief Help Button clicked.
* Called when the help button is clicked.
*/
void helpButtonClicked() const;
private:
/**
* @brief Sets up the visible parts.
* Called by the constructors.
*/
void createGui();
/**
* @brief sets up View referred to by viewId.
* @param viewId ID of the view to be set.
* @throw std::out_of_range if no view named viewId was registered.
*/
void setView();
util::Reference<const cvv::impl::SingleImageCall> imageCall_;
cvv::view::ImageView *imageView_;
QPushButton *helpButton_;
QHBoxLayout *hlayout_;
QVBoxLayout *vlayout_;
QWidget *upperBar_;
};
}
} // namespaces
#endif
#include "main_call_window.hpp"
#include <QApplication>
#include <QPoint>
#include "../util/util.hpp"
#include "../stfl/stringutils.hpp"
namespace cvv
{
namespace gui
{
MainCallWindow::MainCallWindow(
util::Reference<controller::ViewController> controller, size_t id,
OverviewPanel *ovPanel)
: CallWindow(controller, id), ovPanel{ ovPanel }
{
tabOffset = 1;
QString name = "Overview";
tabWidget->insertTab(0, ovPanel, name);
auto *tabBar = tabWidget->getTabBar();
tabBar->tabButton(0, QTabBar::RightSide)->hide();
setWindowTitle(QString("CVVisual | main window"));
}
void MainCallWindow::showOverviewTab()
{
tabWidget->setCurrentWidget(ovPanel);
}
void MainCallWindow::closeEvent(QCloseEvent *event)
{
(void)event;
controller->setMode(controller::Mode::HIDE);
}
}
}
#ifndef CVVISUAL_MAINCALLWINDOW_HPP
#define CVVISUAL_MAINCALLWINDOW_HPP
#include <memory>
#include <QCloseEvent>
#include "call_window.hpp"
#include "overview_panel.hpp"
#include "../controller/view_controller.hpp"
#include "../util/util.hpp"
namespace cvv
{
namespace controller
{
class ViewController;
}
namespace gui
{
class OverviewPanel;
/**
* @brief A call window also inheriting the overview panel.
*/
class MainCallWindow : public CallWindow
{
Q_OBJECT
public:
/**
* @brief Constructs a new main call window.
* @param controller view controller inheriting this main window
* @param id id of this main window
* @param ovPanel inherited overview panel
*/
MainCallWindow(util::Reference<controller::ViewController> controller,
size_t id, OverviewPanel *ovPanel);
~MainCallWindow()
{
}
/**
* @brief Show the overview tab.
*/
void showOverviewTab();
/**
* @brief Hides the close window.
*/
void hideCloseWindow();
protected:
void closeEvent(QCloseEvent *event);
private:
OverviewPanel *ovPanel;
};
}
}
#endif
#ifndef CVVISUAL_MATCH_CALL_TAB_HPP
#define CVVISUAL_MATCH_CALL_TAB_HPP
#include <memory>
#include <QString>
#include <QWidget>
#include "multiview_call_tab.hpp"
#include "../view/match_view.hpp"
#include "../impl/match_call.hpp"
#include "../util/util.hpp"
namespace cvv
{
namespace gui
{
/** Match Call Tab.
* @brief Inner part of a tab, contains a MatchView.
* The inner part of a tab or window
* containing a MatchView.
* Allows to switch views and to access the help.
*/
class MatchCallTab
: public MultiViewCallTab<cvv::view::MatchView, cvv::impl::MatchCall>
{
Q_OBJECT
public:
/**
* @brief Short constructor named after Call and using the requested View
* from the Call or, if no or invalid request, default view.
* Initializes the MatchCallTab with the requested or default view and names it after
* the associated MatchCall.
* @param matchCall - the MatchCall containing the information to be
* visualized.
*/
MatchCallTab(const cvv::impl::MatchCall &matchCall)
: MatchCallTab{
matchCall, matchCall.requestedView()
}
{
}
/**
* @brief Constructor with possibility to select view.
* Note that the default view is still created first.
* @param matchCall - the MatchCall containing the information to be
* visualized.
* @param matchViewId - ID of the View to be set up. If a view of this name does
* not exist, the default view will be used.
*/
MatchCallTab(const cvv::impl::MatchCall& matchCall, const QString& matchViewId)
: MultiViewCallTab<cvv::view::MatchView, cvv::impl::MatchCall>{
matchCall, matchViewId, QString{ "default_match_view" }, QString{ "LineMatchView" }
}
{
oldView_ = view_;
connect(&this->viewSet, SIGNAL(signal()), this, SLOT(viewChanged()));
}
~MatchCallTab()
{
}
/**
* @brief Register the template class to the map of MatchViews.
* View needs to offer a constructor of the form View(const
* cvv::impl::MatchCall&, QWidget*).
* @param name to register the class under.
* @tparam View - Class to register.
* @return true when the view was registered and false when the name was
* already taken.
*/
template <class View> static bool registerMatchView(const QString &name)
{
return registerView<View>(name);
}
private slots:
/**
* @brief Slot called when the view has completely changed.
*/
void viewChanged()
{
if(oldView_ != nullptr)
{
view_->setKeyPointSelection(oldView_->getKeyPointSelection());
view_->setMatchSelection(oldView_->getMatchSelection());
}
oldView_ = view_;
}
private:
/**
* @brief usually equal to view_, but not immediately changed when view_ is changed.
*/
cvv::view::MatchView* oldView_;
};
}
} // namespaces
#endif
#ifndef CVVISUAL_MULTIVIEW_CALL_TAB_HPP
#define CVVISUAL_MULTIVIEW_CALL_TAB_HPP
#include <vector>
#include <memory>
#include <QObject>
#include <QString>
#include <QMap>
#include <QPushButton>
#include <QComboBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include "call_tab.hpp"
#include "../util/util.hpp"
#include "../qtutil/registerhelper.hpp"
#include "../qtutil/signalslot.hpp"
#include "../qtutil/util.hpp"
namespace cvv
{
namespace gui
{
/** Call Tab for multiple views.
* @brief Inner part of a tab, contains a View.
* The inner part of a tab or window
* containing a View.
* Allows to switch between different views and to access the help.
* @tparam ViewType A type of View.
* @tparam CallType A type of Call.
*/
template <class ViewType, class CallType>
class MultiViewCallTab
: public CallTab,
public cvv::qtutil::RegisterHelper<ViewType, const CallType &, QWidget *>
{
public:
/**
* @brief Short constructor named after Call and using the default view.
* Initializes the MultiViewCallTab with the default view and names it after
* the associated Call.
* @param call - the Call containing the information to be
* visualized.
* @param default_key - Key under which the default view is to be saved.
* @param standard_default - Standard default view.
*/
MultiViewCallTab(const CallType &call, const QString& default_key, const QString& standard_default)
: MultiViewCallTab{ call.description(), call, default_key, standard_default }
{
}
/**
* @brief Constructor using the default view.
* Initializes the MultiViewCallTab with the default view.
* @param name - Name to give the CallTab.
* @param call - the Call containing the information to be
* visualized.
* @param default_key - Key under which the default view is to be saved.
* @param standard_default - Standard default view.
*/
MultiViewCallTab(const QString &tabName, const CallType &call, const QString& default_key, const QString& standard_default)
: call_{ call }, currentIndexChanged{ [&]()
{
vlayout_->removeWidget(view_);
view_->setVisible(false);
setView();
} },
helpButtonClicked{ [&]()
{ qtutil::openHelpBrowser(viewId_); } },
setAsDefaultButtonClicked{ [&]()
{ qtutil::setSetting(default_scope_, default_key_, viewId_); } }
{
setName(tabName);
default_scope_ = QString{ "default_views" };
default_key_ = default_key;
standard_default_ = standard_default;
// Sets standard_default_ as default in case no other default is
// set:
qtutil::setDefaultSetting(default_scope_, default_key_,
standard_default_);
viewId_ = qtutil::getSetting(default_scope_, default_key_);
createGui();
}
/**
* @brief Constructor with possibility to select view.
* Note that the default view is still created first.
* @param call - the Call containing the information to be
* visualized.
* @param viewId - ID of the View to be set up. If a view of this name does
* not exist, the default view will be used.
* @param default_key - Key under which the default view is to be saved.
* @param standard_default - Standard default view.
*/
MultiViewCallTab(const CallType& call, const QString& viewId, const QString& default_key, const QString& standard_default)
: MultiViewCallTab{call, default_key, standard_default}
{
this->select(viewId);
}
~MultiViewCallTab()
{
}
/**
* @brief get ID.
* @return the ID of the CallTab.
* (ID is equal to the ID of the associated call).
* Overrides CallTab's getId.
*/
size_t getId() const override
{
return call_->getId();
}
/**
* @brief Register the template class to the map of Views.
* View needs to offer a constructor of the form View(const
* cvv::impl::CallType&, QWidget*).
* @param name to register the class under.
* @tparam View - Class to register.
* @return true when the view was registered and false when the name was
* already taken.
*/
template <class View> static bool registerView(const QString &name)
{
return MultiViewCallTab<ViewType, CallType>::registerElement(
name, [](const CallType &call, QWidget *parent)
{
return cvv::util::make_unique<View>(call, parent);
});
}
protected:
/**
* @brief Scope to search the default view in.
*/
QString default_scope_;
/**
* @brief Key under which the default view is saved.
*/
QString default_key_;
/**
* @brief standard default view.
*/
QString standard_default_;
/**
* @brief Sets up the visible parts.
* Called by the constructors.
*/
void createGui()
{
if (!this->select(viewId_))
{
this->select(standard_default_);
viewId_ = this->selection();
setAsDefaultButtonClicked.slot(); // Set as default.
/* If viewId_ does not name a valid View, it will be
* attempted to set standard_default_.
* If that was not registered either, the current
* selection of the ComboBox will be used automatically.
* Whichever was chosen will be set as the new default.
*/
}
hlayout_ = new QHBoxLayout{};
hlayout_->setAlignment(Qt::AlignTop | Qt::AlignRight);
hlayout_->addWidget(new QLabel{ "View:" });
hlayout_->addWidget(this->comboBox_);
setAsDefaultButton_ = new QPushButton{ "Set as default", this };
hlayout_->addWidget(setAsDefaultButton_);
helpButton_ = new QPushButton{ "Help", this };
hlayout_->addWidget(helpButton_);
upperBar_ = new QWidget{ this };
upperBar_->setLayout(hlayout_);
vlayout_ = new QVBoxLayout{};
vlayout_->addWidget(upperBar_);
setView();
setLayout(vlayout_);
QObject::connect(setAsDefaultButton_, SIGNAL(clicked()),
&setAsDefaultButtonClicked, SLOT(slot()));
QObject::connect(helpButton_, SIGNAL(clicked()),
&helpButtonClicked, SLOT(slot()));
QObject::connect(&this->signalElementSelected(),
SIGNAL(signal(QString)), &currentIndexChanged,
SLOT(slot()));
}
/**
* @brief sets up the View currently selected in the ComboBox inherited
* from RegisterHelper.
*/
void setView()
{
viewId_ = this->selection();
if (viewHistory_.count(this->selection()))
{
view_ = viewHistory_.at(this->selection());
vlayout_->addWidget(view_);
view_->setVisible(true);
}
else
{
viewHistory_.emplace(
this->selection(),
((*this)()(*call_, this).release()));
view_ = viewHistory_.at(this->selection());
vlayout_->addWidget(view_);
}
viewSet.emitSignal();
}
util::Reference<const CallType> call_;
QString viewId_;
ViewType *view_;
std::map<QString, ViewType *> viewHistory_;
QPushButton *helpButton_;
QPushButton *setAsDefaultButton_;
QHBoxLayout *hlayout_;
QVBoxLayout *vlayout_;
QWidget *upperBar_;
//signals:
/**
* @brief signal emitted whem view is completely set up.
*/
qtutil::Signal viewSet;
// slots:
/**
* @brief View selection change.
* Slot called when the index of the view selection changes.
*/
qtutil::Slot currentIndexChanged;
/**
* @brief Help Button clicked.
* Called when the help button is clicked.
*/
const qtutil::Slot helpButtonClicked;
/**
* @brief setAsDefaultButton clicked.
* Called when the setAsDefaultButton,which sets the current view as
* default, is clicked.
*/
qtutil::Slot setAsDefaultButtonClicked;
};
}
} // namespaces
#endif
#include "overview_group_subtable.hpp"
#include <utility>
#include <algorithm>
#include <sstream>
#include <QVBoxLayout>
#include <QStringList>
#include <QModelIndex>
#include <QMenu>
#include <QAction>
#include <QHeaderView>
#include <QList>
#include <QSize>
#include "call_window.hpp"
#include "overview_table.hpp"
#include "../controller/view_controller.hpp"
namespace cvv
{
namespace gui
{
OverviewGroupSubtable::OverviewGroupSubtable(
util::Reference<controller::ViewController> controller,
OverviewTable *parent, stfl::ElementGroup<OverviewTableRow> group)
: controller{ controller }, parent{ parent }, group{ std::move(group) }
{
controller->setDefaultSetting("overview", "imgsize",
QString::number(100));
initUI();
}
void OverviewGroupSubtable::initUI()
{
controller->setDefaultSetting("overview", "imgzoom", "30");
qTable = new QTableWidget(this);
qTable->setSelectionBehavior(QAbstractItemView::SelectRows);
qTable->setSelectionMode(QAbstractItemView::SingleSelection);
qTable->setTextElideMode(Qt::ElideNone);
auto verticalHeader = qTable->verticalHeader();
verticalHeader->setVisible(false);
auto horizontalHeader = qTable->horizontalHeader();
horizontalHeader->setSectionResizeMode(QHeaderView::ResizeToContents);
horizontalHeader->setStretchLastSection(false);
connect(qTable, SIGNAL(cellDoubleClicked(int, int)), this,
SLOT(rowClicked(int, int)));
qTable->setContextMenuPolicy(Qt::CustomContextMenu);
connect(qTable, SIGNAL(customContextMenuRequested(QPoint)), this,
SLOT(customMenuRequested(QPoint)));
auto *layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(qTable);
setLayout(layout);
updateUI();
}
void OverviewGroupSubtable::updateUI()
{
imgSize = controller->getSetting("overview", "imgzoom").toInt() *
width() / 400;
QStringList list{};
list << "ID";
maxImages = 0;
for (auto element : group.getElements())
{
if (maxImages < element.call()->matrixCount())
{
maxImages = element.call()->matrixCount();
}
}
if (parent->isShowingImages())
{
for (auto element : group.getElements())
{
if (maxImages < element.call()->matrixCount())
{
maxImages = element.call()->matrixCount();
}
}
for (size_t i = 0; i < maxImages; i++)
{
list << QString("Image ") + QString::number(i + 1);
}
}
list << "Description"
<< "Function"
<< "File"
<< "Line"
<< "Type";
qTable->setRowCount(group.size());
qTable->setColumnCount(list.size());
qTable->setHorizontalHeaderLabels(list);
int textRowHeight = qTable->fontMetrics().height() + 5;
if (textRowHeight >= imgSize)
{
qTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
}
else
{
qTable->setVerticalScrollMode(
QAbstractItemView::ScrollPerPixel);
}
rowHeight = std::max(imgSize, textRowHeight);
for (size_t i = 0; i < group.size(); i++)
{
group.get(i).addToTable(qTable, i, parent->isShowingImages(),
maxImages, imgSize, imgSize);
qTable->setRowHeight(i, rowHeight);
}
auto header = qTable->horizontalHeader();
header->setSectionResizeMode(0, QHeaderView::ResizeToContents);
for (size_t i = 1; i < maxImages + 1; i++)
{
header->setSectionResizeMode(i, QHeaderView::ResizeToContents);
}
for (size_t i = maxImages + 1; i < maxImages + 4; i++)
{
header->setSectionResizeMode(i, QHeaderView::Stretch);
}
header->setSectionResizeMode(maxImages + 4,
QHeaderView::ResizeToContents);
header->setSectionResizeMode(maxImages + 5,
QHeaderView::ResizeToContents);
updateMinimumSize();
}
void OverviewGroupSubtable::rowClicked(int row, int collumn)
{
(void)collumn;
size_t tabId = group.get(row).id();
controller->showAndOpenCallTab(tabId);
}
void OverviewGroupSubtable::customMenuRequested(QPoint location)
{
if (qTable->rowCount() == 0)
{
return;
}
controller->removeEmptyWindows();
QMenu *menu = new QMenu(this);
auto windows = controller->getTabWindows();
menu->addAction(new QAction("Open in new window", this));
for (auto window : windows)
{
menu->addAction(new QAction(
QString("Open in '%1'").arg(window->windowTitle()), this));
}
menu->addAction(new QAction("Remove call", this));
QModelIndex index = qTable->indexAt(location);
if (!index.isValid())
{
return;
}
int row = index.row();
QString idStr = qTable->item(row, 0)->text();
connect(menu, SIGNAL(triggered(QAction *)), this,
SLOT(customMenuAction(QAction *)));
std::stringstream{ idStr.toStdString() } >> currentCustomMenuCallTabId;
currentCustomMenuCallTabIdValid = true;
menu->popup(mapToGlobal(location));
}
void OverviewGroupSubtable::customMenuAction(QAction *action)
{
if (!currentCustomMenuCallTabIdValid)
{
return;
}
QString actionText = action->text();
if (actionText == "Open in new window")
{
controller->moveCallTabToNewWindow(currentCustomMenuCallTabId);
currentCustomMenuCallTabId = -1;
return;
}
else if (actionText == "Remove call")
{
controller->removeCallTab(currentCustomMenuCallTabId, true,
true);
currentCustomMenuCallTabId = -1;
return;
}
auto windows = controller->getTabWindows();
for (auto window : windows)
{
if (actionText ==
QString("Open in '%1'").arg(window->windowTitle()))
{
controller->moveCallTabToWindow(
currentCustomMenuCallTabId, window->getId());
break;
}
}
currentCustomMenuCallTabId = -1;
}
void OverviewGroupSubtable::resizeEvent(QResizeEvent *event)
{
(void)event;
imgSize = controller->getSetting("overview", "imgzoom").toInt() *
width() / 400;
rowHeight = std::max(imgSize, qTable->fontMetrics().height() + 5);
for (size_t row = 0; row < group.size(); row++)
{
group.get(row).resizeInTable(qTable, row,
parent->isShowingImages(), maxImages,
imgSize, imgSize);
qTable->setRowHeight(row, rowHeight);
}
updateMinimumSize();
event->accept();
}
void OverviewGroupSubtable::removeRow(size_t id)
{
for (size_t i = 0; i < group.size(); i++)
{
if (group.get(i).id() == id)
{
group.removeElement(i);
updateUI();
break;
}
}
}
bool OverviewGroupSubtable::hasRow(size_t id)
{
for (size_t i = 0; i < group.size(); i++)
{
if (group.get(i).id() == id)
{
return true;
}
}
return false;
}
void OverviewGroupSubtable::setRowGroup(
stfl::ElementGroup<OverviewTableRow> &newGroup)
{
auto compFunc = [](const OverviewTableRow &first,
const OverviewTableRow &second)
{ return first.id() == second.id(); };
if (group.hasSameElementList(newGroup, compFunc))
{
return;
}
// Now both groups aren't the same
size_t newMax = 0;
for (auto row : newGroup.getElements())
{
if (row.call()->matrixCount() > newMax)
{
newMax = row.call()->matrixCount();
}
}
if (newMax == maxImages)
{
group = newGroup;
updateUI();
return;
}
// Now both groups have the same maximum number of images within their
// elements
size_t minLength = std::min(group.size(), newGroup.size());
for (size_t i = 0; i < minLength; i++)
{
if (group.get(i).id() != newGroup.get(i).id())
{
group = newGroup;
updateUI();
return;
}
}
// Now the bigger group's element lists starts with the smaller group's
// one
if (group.size() < newGroup.size())
{
// Now the new group appends the current group
for (size_t row = group.size(); row < newGroup.size(); row++)
{
newGroup.get(row)
.addToTable(qTable, row, parent->isShowingImages(),
maxImages, imgSize, imgSize);
qTable->setRowHeight(row, rowHeight);
}
}
else
{
// Now the new group deletes elements from the current group
for (size_t row = group.size() - 1; row >= newGroup.size();
row--)
{
qTable->removeRow(row);
}
}
group = newGroup;
updateMinimumSize();
}
void OverviewGroupSubtable::updateMinimumSize()
{
int width = qTable->sizeHint().width();
setMinimumWidth(width);
int height = qTable->horizontalHeader()->height();
for (int a = 0; a < qTable->rowCount(); ++a)
{
height += qTable->rowHeight(a);
}
setMinimumHeight(height + (qTable->rowCount() * 1));
}
}
}
#ifndef CVVISUAL_OVERVIEW_GROUP_SUBTABLE_HPP
#define CVVISUAL_OVERVIEW_GROUP_SUBTABLE_HPP
#include <memory>
#include <QWidget>
#include <QTableWidget>
#include <QAction>
#include <QResizeEvent>
#include "../stfl/element_group.hpp"
#include "overview_table_row.hpp"
#include "../util/util.hpp"
#include "../controller/view_controller.hpp"
namespace cvv
{
namespace controller
{
class ViewController;
}
}
namespace cvv
{
namespace gui
{
class OverviewTable;
/**
* @brief A table for the a group of overview data sets.
*/
class OverviewGroupSubtable : public QWidget
{
Q_OBJECT
public:
/**
* @brief Constructs an over group subtable.
* @param controller view controller
* @param parent parent table
* @param group the displayed group of overview data sets
*/
OverviewGroupSubtable(
util::Reference<controller::ViewController> controller,
OverviewTable *parent, stfl::ElementGroup<OverviewTableRow> group);
~OverviewGroupSubtable()
{
}
/**
* @brief Updates the displayed table UI.
*/
void updateUI();
/**
* @brief Remove the row with the given id.
* @param given table row id
*/
void removeRow(size_t id);
/**
* @brief Checks whether or not the table shows the row with the given
* id.
* @param id given row id
* @return Does the table show the row with the given id?
*/
bool hasRow(size_t id);
/**
* @brief Set the displayed rows.
* @note This method does some optimisations to only fully rebuild all
* rows if neccessary.
* @param newGroup new group of rows that will be displayed
*/
void setRowGroup(stfl::ElementGroup<OverviewTableRow> &newGroup);
protected:
void resizeEvent(QResizeEvent *event);
private slots:
void rowClicked(int row, int collumn);
void customMenuRequested(QPoint location);
void customMenuAction(QAction *action);
private:
util::Reference<controller::ViewController> controller;
OverviewTable *parent;
stfl::ElementGroup<OverviewTableRow> group;
QTableWidget *qTable;
size_t currentCustomMenuCallTabId = 0;
bool currentCustomMenuCallTabIdValid = false;
size_t maxImages = 0;
int imgSize = 0;
int rowHeight = 0;
void initUI();
void updateMinimumSize();
};
}
}
#endif
#include "overview_panel.hpp"
#include <functional>
#include <math.h>
#include <memory>
#include <iostream>
#include <QMap>
#include <QSet>
#include <QString>
#include <QVBoxLayout>
#include <QWidget>
#include <QScrollArea>
#include "../controller/view_controller.hpp"
#include "../qtutil/stfl_query_widget.hpp"
#include "../qtutil/util.hpp"
#include "../stfl/element_group.hpp"
namespace cvv
{
namespace gui
{
OverviewPanel::OverviewPanel(
util::Reference<controller::ViewController> controller)
: controller{ controller }
{
qtutil::setDefaultSetting("overview", "imgzoom", "20");
QVBoxLayout *layout = new QVBoxLayout{};
setLayout(layout);
layout->setContentsMargins(0, 0, 0, 0);
queryWidget = new qtutil::STFLQueryWidget();
layout->addWidget(queryWidget);
table = new OverviewTable(controller);
layout->addWidget(table);
auto bottomArea = new QWidget{ this };
auto bottomLayout = new QHBoxLayout;
imgSizeSliderLabel = new QLabel{ "Zoom", bottomArea };
imgSizeSliderLabel->setMaximumWidth(50);
imgSizeSliderLabel->setAlignment(Qt::AlignRight);
bottomLayout->addWidget(imgSizeSliderLabel);
imgSizeSlider = new QSlider{ Qt::Horizontal, bottomArea };
imgSizeSlider->setMinimumWidth(50);
imgSizeSlider->setMaximumWidth(200);
imgSizeSlider->setMinimum(0);
imgSizeSlider->setMaximum(100);
imgSizeSlider->setSliderPosition(
qtutil::getSetting("overview", "imgzoom").toInt());
connect(imgSizeSlider, SIGNAL(valueChanged(int)), this,
SLOT(imgSizeSliderAction()));
bottomLayout->addWidget(imgSizeSlider);
bottomArea->setLayout(bottomLayout);
layout->addWidget(bottomArea);
initEngine();
connect(queryWidget, SIGNAL(showHelp(QString)), this,
SLOT(showHelp(QString)));
// connect(queryWidget, SIGNAL(userInputUpdate(QString)), this,
// SLOT(updateQuery(QString)));
connect(queryWidget, SIGNAL(filterSignal(QString)), this,
SLOT(filterQuery(QString)));
connect(queryWidget, SIGNAL(requestSuggestions(QString)), this,
SLOT(requestSuggestions(QString)));
}
void OverviewPanel::initEngine()
{
// raw and description filter
auto rawFilter = [](const OverviewTableRow &elem)
{
return elem.description();
};
queryEngine.addStringCmdFunc("raw", rawFilter, false);
queryEngine.addStringCmdFunc("description", rawFilter, false);
// file filter
queryEngine.addStringCmdFunc("file", [](const OverviewTableRow &elem)
{
return elem.file();
});
// function filter
queryEngine.addStringCmdFunc("function",
[](const OverviewTableRow &elem)
{
return elem.function();
});
// line filter
queryEngine.addIntegerCmdFunc("line", [](const OverviewTableRow &elem)
{ return elem.line(); });
// id filter
queryEngine.addIntegerCmdFunc("id", [](const OverviewTableRow &elem)
{
return elem.id();
});
// type filter
queryEngine.addStringCmdFunc("type", [](const OverviewTableRow &elem)
{
return elem.type();
});
//"number of images" filter
queryEngine.addIntegerCmdFunc("image_count",
[](const OverviewTableRow &elem)
{
return elem.call()->matrixCount();
});
//additional commands
//open call command
queryEngine.addAdditionalCommand("open",
[&](QStringList args, std::vector<stfl::ElementGroup<OverviewTableRow>>& groups)
{
openCommand(args, groups);
}, {"first_of_group", "last_of_group", "shown"});
}
void OverviewPanel::openCommand(QStringList args,
std::vector<stfl::ElementGroup<OverviewTableRow>>& groups)
{
if (args.contains("shown"))
{
for (auto &group : groups)
{
for (auto &elem : group.getElements())
{
controller->openCallTab(elem.id());
}
}
return;
}
if (args.contains("first_of_group") || args.contains("last_of_group"))
{
bool first = args.contains("first_of_group") ;
for (auto &group : groups)
{
if (group.size() > 0)
{
size_t index = first ? 0 : group.size() - 1;
size_t id = group.get(index).id();
controller->openCallTab(id);
}
}
}
}
void OverviewPanel::addElement(const util::Reference<const impl::Call> newCall)
{
OverviewTableRow row(newCall);
queryEngine.addNewElement(row);
table->updateRowGroups(queryEngine.reexecuteLastQuery());
}
void OverviewPanel::addElementBuffered(const util::Reference<const impl::Call> newCall)
{
elementBuffer.push_back(newCall);
}
void OverviewPanel::flushElementBuffer()
{
std::vector<OverviewTableRow> rows;
for (const util::Reference<const impl::Call> call : elementBuffer)
{
rows.push_back(OverviewTableRow(call));
}
queryEngine.addElements(std::move(rows));
table->updateRowGroups(queryEngine.reexecuteLastQuery());
elementBuffer.clear();
}
void OverviewPanel::removeElement(size_t id)
{
queryEngine.removeElements([id](OverviewTableRow elem)
{
return elem.id() == id;
});
table->removeElement(id);
}
void OverviewPanel::filterQuery(QString query)
{
table->updateRowGroups(queryEngine.query(query));
}
void OverviewPanel::updateQuery(QString query)
{
filterQuery(query);
}
void OverviewPanel::requestSuggestions(QString query)
{
queryWidget->showSuggestions(queryEngine.getSuggestions(query));
}
void OverviewPanel::imgSizeSliderAction()
{
controller->setSetting("overview", "imgzoom",
QString::number(imgSizeSlider->value()));
table->updateUI();
}
void OverviewPanel::showHelp(QString topic)
{
controller->openHelpBrowser(topic);
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef CVVISUAL_TABWIDGET
#define CVVISUAL_TABWIDGET
#include <QTabWidget>
#include <QTabBar>
namespace cvv
{
namespace gui
{
/**
* @brief A simple to QTabWidget Subclass, enabling the access to protected
* members.
*/
class TabWidget : public QTabWidget
{
public:
/**
* @brief Constructor of this class.
*/
TabWidget(QWidget *parent) : QTabWidget(parent)
{
};
/**
* @brief Returns the shown tab bar.
* This method helps to access the member tabBar which has by default
* only a protected setter.
* @return shown tab bar.
*/
QTabBar *getTabBar() const
{
return tabBar();
}
};
}
}
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#include "opencv2/cvv/filter.hpp"
#include "opencv2/cvv/call_meta_data.hpp"
#include "filter_call.hpp"
namespace cvv
{
namespace impl
{
void debugFilter(cv::InputArray original, cv::InputArray result,
const CallMetaData &data, const char *description,
const char *view)
{
debugFilterCall(original, result, data, description, view, "filter");
}
}
} // namespaces
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment