stereo-vision
All Data Structures Namespaces Functions Modules Pages
cvui.h
1 /*
2  A (very) simple UI lib built on top of OpenCV drawing primitives.
3  Version: 2.7.0
4 
5  Usage:
6 
7  One (and only one) of your C++ files must define CVUI_IMPLEMENTATION
8  before the inclusion of cvui.h to ensure its implementaiton is compiled.
9 
10  E.g:
11 
12  #define CVUI_IMPLEMENTATION
13  #include "cvui.h"
14 
15  int main() {
16  }
17 
18  All other files can include cvui.h without defining CVUI_IMPLEMENTATION.
19 
20  Use of cvui revolves around calling cvui::init() to initialize the lib,
21  rendering cvui components to a cv::Mat (that you handle yourself) and
22  finally showing that cv::Mat on the screen using cvui::imshow(), which
23  is cvui's version of cv::imshow(). Alternatively you can use cv::imshow()
24  to show things, but in such case you must call cvui::update() yourself
25  before calling cv::imshow().
26 
27  E.g.:
28 
29  #include <opencv2/opencv.hpp>
30  #define CVUI_IMPLEMENTATION
31  #include "cvui.h"
32 
33  #define WINDOW1_NAME "Window 1"
34 
35  int main() {
36  cvui::init(WINDOW1_NAME);
37  cv::Mat frame = cv::Mat(cv::Size(400, 200), CV_8UC3);
38 
39  while(true) {
40  frame = cv::Scalar(49, 52, 49);
41  cvui::text(frame, x, y, "Hello world!");
42 
43  cvui::imshow(WINDOW1_NAME, frame);
44 
45  if (cv::waitKey(20) == 27) {
46  break;
47  }
48  }
49  return 0;
50  }
51 
52  Read the full documentation at https://dovyski.github.io/cvui/
53 
54  Copyright (c) 2016 Fernando Bevilacqua <dovyski@gmail.com>
55  Licensed under the MIT license.
56 */
57 
58 #ifndef _CVUI_H_
59 #define _CVUI_H_
60 
61 #include <iostream>
62 #include <vector>
63 #include <map>
64 #include <stdarg.h>
65 
66 #include <opencv2/imgproc/imgproc.hpp>
67 #include <opencv2/highgui/highgui.hpp>
68 #include <opencv2/core/core.hpp>
69 
70 namespace cvui
71 {
88 void init(const cv::String& theWindowName, int theDelayWaitKey = -1, bool theCreateNamedWindow = true);
89 
106 void init(const cv::String theWindowNames[], size_t theHowManyWindows, int theDelayWaitKey = -1, bool theCreateNamedWindows = true);
107 
122 void watch(const cv::String& theWindowName, bool theCreateNamedWindow = true);
123 
183 void context(const cv::String& theWindowName);
184 
202 void imshow(const cv::String& theWindowName, cv::InputArray theFrame);
203 
211 int lastKeyPressed();
212 
219 cv::Point mouse(const cv::String& theWindowName = "");
220 
248 bool mouse(int theQuery);
249 
262 bool mouse(const cv::String& theWindowName, int theQuery);
263 
275 bool mouse(int theButton, int theQuery);
276 
286 bool mouse(const cv::String& theWindowName, int theButton, int theQuery);
287 
298 bool button(cv::Mat& theWhere, int theX, int theY, const cv::String& theLabel);
299 
312 bool button(cv::Mat& theWhere, int theX, int theY, int theWidth, int theHeight, const cv::String& theLabel);
313 
331 bool button(cv::Mat& theWhere, int theX, int theY, cv::Mat& theIdle, cv::Mat& theOver, cv::Mat& theDown);
332 
344 void image(cv::Mat& theWhere, int theX, int theY, cv::Mat& theImage);
345 
358 bool checkbox(cv::Mat& theWhere, int theX, int theY, const cv::String& theLabel, bool *theState, unsigned int theColor = 0xCECECE);
359 
372 void text(cv::Mat& theWhere, int theX, int theY, const cv::String& theText, double theFontScale = 0.4, unsigned int theColor = 0xCECECE);
373 
391 void printf(cv::Mat& theWhere, int theX, int theY, double theFontScale, unsigned int theColor, const char *theFmt, ...);
392 
410 void printf(cv::Mat& theWhere, int theX, int theY, const char *theFmt, ...);
411 
424 int counter(cv::Mat& theWhere, int theX, int theY, int *theValue, int theStep = 1, const char *theFormat = "%d");
425 
438 double counter(cv::Mat& theWhere, int theX, int theY, double *theValue, double theStep = 0.5, const char *theFormat = "%.2f");
439 
474 template <typename T>
475 bool trackbar(cv::Mat& theWhere, int theX, int theY, int theWidth, T *theValue, T theMin, T theMax, int theSegments = 1, const char *theLabelFormat = "%.1Lf", unsigned int theOptions = 0, T theDiscreteStep = 1);
476 
489 void window(cv::Mat& theWhere, int theX, int theY, int theWidth, int theHeight, const cv::String& theTitle);
490 
504 void rect(cv::Mat& theWhere, int theX, int theY, int theWidth, int theHeight, unsigned int theBorderColor, unsigned int theFillingColor = 0xff000000);
505 
519 void sparkline(cv::Mat& theWhere, std::vector<double>& theValues, int theX, int theY, int theWidth, int theHeight, unsigned int theColor = 0x00FF00);
520 
542 int iarea(int theX, int theY, int theWidth, int theHeight);
543 
605 void beginRow(cv::Mat &theWhere, int theX, int theY, int theWidth = -1, int theHeight = -1, int thePadding = 0);
606 
615 void endRow();
616 
678 void beginColumn(cv::Mat &theWhere, int theX, int theY, int theWidth = -1, int theHeight = -1, int thePadding = 0);
679 
688 void endColumn();
689 
705 void beginRow(int theWidth = -1, int theHeight = -1, int thePadding = 0);
706 
722 void beginColumn(int theWidth = -1, int theHeight = -1, int thePadding = 0);
723 
739 void space(int theValue = 5);
740 
756 void text(const cv::String& theText, double theFontScale = 0.4, unsigned int theColor = 0xCECECE);
757 
775 bool button(int theWidth, int theHeight, const cv::String& theLabel);
776 
791 bool button(const cv::String& theLabel);
792 
815 bool button(cv::Mat& theIdle, cv::Mat& theOver, cv::Mat& theDown);
816 
831 void image(cv::Mat& theImage);
832 
849 bool checkbox(const cv::String& theLabel, bool *theState, unsigned int theColor = 0xCECECE);
850 
873 void printf(double theFontScale, unsigned int theColor, const char *theFmt, ...);
874 
896 void printf(const char *theFmt, ...);
897 
915 int counter(int *theValue, int theStep = 1, const char *theFormat = "%d");
916 
934 double counter(double *theValue, double theStep = 0.5, const char *theFormat = "%.2f");
935 
975 template <typename T> // T can be any float type (float, double, long double)
976 bool trackbar(int theWidth, T *theValue, T theMin, T theMax, int theSegments = 1, const char *theLabelFormat = "%.1Lf", unsigned int theOptions = 0, T theDiscreteStep = 1);
977 
993 void window(int theWidth, int theHeight, const cv::String& theTitle);
994 
1011 void rect(int theWidth, int theHeight, unsigned int theBorderColor, unsigned int theFillingColor = 0xff000000);
1012 
1028 void sparkline(std::vector<double>& theValues, int theWidth, int theHeight, unsigned int theColor = 0x00FF00);
1029 
1040 void update(const cv::String& theWindowName = "");
1041 
1042 // Internally used to handle mouse events
1043 void handleMouse(int theEvent, int theX, int theY, int theFlags, void* theData);
1044 
1045 // Compatibility macros to allow compilation with either OpenCV 2.x or OpenCV 3.x
1046 #if (CV_MAJOR_VERSION < 3)
1047  #define CVUI_ANTIALISED CV_AA
1048 #else
1049  #define CVUI_ANTIALISED cv::LINE_AA
1050 #endif
1051 #define CVUI_FILLED -1
1052 
1053 // If we are not in a Windows-based environment, replace Windows-specific functions with
1054 // their POSIX equivalents.
1055 #if !defined(_MSC_VER)
1056  #define vsprintf_s vsprintf
1057  #define sprintf_s sprintf
1058 #endif
1059 
1060 // Adjust things accoridng to platform
1061 #ifdef _MSC_VER
1062  #define _CVUI_COMPILE_MESSAGE(x) message(x)
1063 
1064  // If windows.h has already been included, min() and max() will be defined.
1065  // In such case, a shit storm will rain on us, producing all kinds of
1066  // compilation problems with cvui. If min/max are already defined,
1067  // let's undef them for now and redef them at the end of this file.
1068  #ifdef min
1069  #define __cvui_min min
1070  #undef min
1071  #endif
1072  #ifdef max
1073  #define __cvui_max max
1074  #undef max
1075  #endif
1076 #elif __GNUC__
1077  #define _CVUI_COMPILE_MESSAGE(x) message x
1078 #endif
1079 
1080 // Some compilation messages
1081 #define _CVUI_IMPLEMENTATION_NOTICE "cvui.h: compiling implementation because of CVUI_IMPLEMENTATION. See: https://dovyski.github.io/cvui/usage/"
1082 #define _CVUI_NO_IMPLEMENTATION_NOTICE "cvui.h: implementation skipped. Ensure one of your C++ files included cvui.h after a #define CVUI_IMPLEMENTATION. See: https://dovyski.github.io/cvui/usage/"
1083 
1084 // Below is paranoic, dramatic bug-fixing action to ensure no evil macro
1085 // have already defined our names. For some bizarre reason, cvui did not
1086 // compile in one of my projects because OUT was already defined. So be it.
1087 #undef VERSION
1088 #undef ROW
1089 #undef COLUMN
1090 #undef DOWN
1091 #undef CLICK
1092 #undef OVER
1093 #undef OUT
1094 #undef UP
1095 #undef IS_DOWN
1096 #undef LEFT_BUTTON
1097 #undef MIDDLE_BUTTON
1098 #undef RIGHT_BUTTON
1099 
1100 // Check for Unix stuff
1101 #ifdef __GNUC__
1102  // just to remove the warning under gcc that is introduced by the VERSION variable below
1103  // (needed for those who compile with -Werror (make warning as errors)
1104  #pragma GCC diagnostic ignored "-Wunused-variable"
1105 #endif
1106 
1107 // Lib version
1108 static const char *VERSION = "2.7.0";
1109 
1110 const int ROW = 0;
1111 const int COLUMN = 1;
1112 const int DOWN = 2;
1113 const int CLICK = 3;
1114 const int OVER = 4;
1115 const int OUT = 5;
1116 const int UP = 6;
1117 const int IS_DOWN = 7;
1118 
1119 // Constants regarding mouse buttons
1120 const int LEFT_BUTTON = 0;
1121 const int MIDDLE_BUTTON = 1;
1122 const int RIGHT_BUTTON = 2;
1123 
1124 // Constants regarding components
1125 const unsigned int TRACKBAR_HIDE_SEGMENT_LABELS = 1;
1126 const unsigned int TRACKBAR_HIDE_STEP_SCALE = 2;
1127 const unsigned int TRACKBAR_DISCRETE = 4;
1128 const unsigned int TRACKBAR_HIDE_MIN_MAX_LABELS = 8;
1129 const unsigned int TRACKBAR_HIDE_VALUE_LABEL = 16;
1130 const unsigned int TRACKBAR_HIDE_LABELS = 32;
1131 
1132 // Describes the block structure used by the lib to handle `begin*()` and `end*()` calls.
1133 typedef struct {
1134  cv::Mat where; // where the block should be rendered to.
1135  cv::Rect rect; // the size and position of the block.
1136  cv::Rect fill; // the filled area occuppied by the block as it gets modified by its inner components.
1137  cv::Point anchor; // the point where the next component of the block should be rendered.
1138  int padding; // padding among components within this block.
1139  int type; // type of the block, e.g. ROW or COLUMN.
1140 } cvui_block_t;
1141 
1142 // Describes a component label, including info about a shortcut.
1143 // If a label contains "Re&start", then:
1144 // - hasShortcut will be true
1145 // - shortcut will be 's'
1146 // - textBeforeShortcut will be "Re"
1147 // - textAfterShortcut will be "tart"
1148 typedef struct {
1149  bool hasShortcut;
1150  char shortcut;
1151  std::string textBeforeShortcut;
1152  std::string textAfterShortcut;
1153 } cvui_label_t;
1154 
1155 // Describe a mouse button
1156 typedef struct {
1157  bool justReleased; // if the mouse button was released, i.e. click event.
1158  bool justPressed; // if the mouse button was just pressed, i.e. true for a frame when a button is down.
1159  bool pressed; // if the mouse button is pressed or not.
1160 } cvui_mouse_btn_t;
1161 
1162 // Describe the information of the mouse cursor
1163 typedef struct {
1164  cvui_mouse_btn_t buttons[3]; // status of each button. Use cvui::{RIGHT,LEFT,MIDDLE}_BUTTON to access the buttons.
1165  cvui_mouse_btn_t anyButton; // represent the behavior of all mouse buttons combined
1166  cv::Point position; // x and y coordinates of the mouse at the moment.
1167 } cvui_mouse_t;
1168 
1169 // Describes a (window) context.
1170 typedef struct {
1171  cv::String windowName; // name of the window related to this context.
1172  cvui_mouse_t mouse; // the mouse cursor related to this context.
1173 } cvui_context_t;
1174 
1175 // Internal namespace with all code that is shared among components/functions.
1176 // You should probably not be using anything from here.
1177 namespace internal
1178 {
1179  static cv::String gDefaultContext;
1180  static cv::String gCurrentContext;
1181  static std::map<cv::String, cvui_context_t> gContexts; // indexed by the window name.
1182  static char gBuffer[1024];
1183  static int gLastKeyPressed; // TODO: collect it per window
1184  static int gDelayWaitKey;
1185  static cvui_block_t gScreen;
1186 
1187  struct TrackbarParams {
1188  long double min;
1189  long double max;
1190  long double step;
1191  int segments;
1192  unsigned int options;
1193  std::string labelFormat;
1194 
1195  inline TrackbarParams()
1196  : min(0.)
1197  , max(25.)
1198  , step(1.)
1199  , segments(0)
1200  , options(0)
1201  , labelFormat("%.0Lf")
1202  {}
1203  };
1204 
1205  static cvui_block_t gStack[100]; // TODO: make it dynamic?
1206  static int gStackCount = -1;
1207  static const int gTrackbarMarginX = 14;
1208 
1209  bool isMouseButton(cvui_mouse_btn_t& theButton, int theQuery);
1210  void resetMouseButton(cvui_mouse_btn_t& theButton);
1211  void init(const cv::String& theWindowName, int theDelayWaitKey);
1212  cvui_context_t& getContext(const cv::String& theWindowName = "");
1213  bool bitsetHas(unsigned int theBitset, unsigned int theValue);
1214  void error(int theId, std::string theMessage);
1215  void updateLayoutFlow(cvui_block_t& theBlock, cv::Size theSize);
1216  bool blockStackEmpty();
1217  cvui_block_t& topBlock();
1218  cvui_block_t& pushBlock();
1219  cvui_block_t& popBlock();
1220  void begin(int theType, cv::Mat &theWhere, int theX, int theY, int theWidth, int theHeight, int thePadding);
1221  void end(int theType);
1222  cvui_label_t createLabel(const std::string &theLabel);
1223  int iarea(int theX, int theY, int theWidth, int theHeight);
1224  bool button(cvui_block_t& theBlock, int theX, int theY, int theWidth, int theHeight, const cv::String& theLabel, bool theUpdateLayout);
1225  bool button(cvui_block_t& theBlock, int theX, int theY, const cv::String& theLabel);
1226  bool button(cvui_block_t& theBlock, int theX, int theY, cv::Mat& theIdle, cv::Mat& theOver, cv::Mat& theDown, bool theUpdateLayout);
1227  void image(cvui_block_t& theBlock, int theX, int theY, cv::Mat& theImage);
1228  bool checkbox(cvui_block_t& theBlock, int theX, int theY, const cv::String& theLabel, bool *theState, unsigned int theColor);
1229  void text(cvui_block_t& theBlock, int theX, int theY, const cv::String& theText, double theFontScale, unsigned int theColor, bool theUpdateLayout);
1230  int counter(cvui_block_t& theBlock, int theX, int theY, int *theValue, int theStep, const char *theFormat);
1231  double counter(cvui_block_t& theBlock, int theX, int theY, double *theValue, double theStep, const char *theFormat);
1232  void window(cvui_block_t& theBlock, int theX, int theY, int theWidth, int theHeight, const cv::String& theTitle);
1233  void rect(cvui_block_t& theBlock, int theX, int theY, int theWidth, int theHeight, unsigned int theBorderColor, unsigned int theFillingColor);
1234  void sparkline(cvui_block_t& theBlock, std::vector<double>& theValues, int theX, int theY, int theWidth, int theHeight, unsigned int theColor);
1235  bool trackbar(cvui_block_t &theBlock, int theX, int theY, int theWidth, long double *theValue, const TrackbarParams& theParams);
1236  inline void trackbarForceValuesAsMultiplesOfSmallStep(const TrackbarParams & theParams, long double *theValue);
1237  inline long double trackbarXPixelToValue(const TrackbarParams & theParams, cv::Rect & theBounding, int thePixelX);
1238  inline int trackbarValueToXPixel(const TrackbarParams & theParams, cv::Rect & theBounding, long double theValue);
1239  inline double clamp01(double value);
1240  void findMinMax(std::vector<double>& theValues, double *theMin, double *theMax);
1241  cv::Scalar hexToScalar(unsigned int theColor);
1242  void resetRenderingBuffer(cvui_block_t& theScreen);
1243 
1244  template <typename T> // T can be any floating point type (float, double, long double)
1245  TrackbarParams makeTrackbarParams(T min, T max, int theDecimals = 1, int theSegments = 1, T theStep = -1., unsigned int theOptions = 0, const char *theFormat = "%.1Lf");
1246 
1247  template<typename T>
1248  bool trackbar(T *theValue, const TrackbarParams& theParams);
1249 
1250  template <typename T> // T can be any numeric type (int, double, unsigned int, etc)
1251  bool trackbar(cv::Mat& theWhere, int theX, int theY, int theWidth, T *theValue, const TrackbarParams& theParams);
1252 
1253  template<typename num_type>
1254  TrackbarParams makeTrackbarParams(num_type theMin, num_type theMax, num_type theStep, int theSegments, const char *theLabelFormat, unsigned int theOptions) {
1255  TrackbarParams aParams;
1256 
1257  aParams.min = (long double)theMin;
1258  aParams.max = (long double)theMax;
1259  aParams.step = (long double)theStep;
1260  aParams.options = theOptions;
1261  aParams.segments = theSegments;
1262  aParams.labelFormat = theLabelFormat;
1263 
1264  return aParams;
1265  }
1266 
1267  template <typename num_type>
1268  bool trackbar(int theWidth, num_type *theValue, const TrackbarParams& theParams) {
1269  cvui_block_t& aBlock = internal::topBlock();
1270 
1271  long double aValueAsDouble = static_cast<long double>(*theValue);
1272  bool aResult = internal::trackbar(aBlock, aBlock.anchor.x, aBlock.anchor.y, theWidth, &aValueAsDouble, theParams);
1273  *theValue = static_cast<num_type>(aValueAsDouble);
1274 
1275  return aResult;
1276  }
1277 
1278  template <typename num_type>
1279  bool trackbar(cv::Mat& theWhere, int theX, int theY, int theWidth, num_type *theValue, const TrackbarParams& theParams) {
1280  gScreen.where = theWhere;
1281 
1282  long double aValueAsDouble = static_cast<long double>(*theValue);
1283  bool aResult = internal::trackbar(gScreen, theX, theY, theWidth, &aValueAsDouble, theParams);
1284  *theValue = static_cast<num_type>(aValueAsDouble);
1285 
1286  return aResult;
1287  }
1288 }
1289 
1290 // Internal namespace that contains all rendering functions.
1291 namespace render {
1292  void text(cvui_block_t& theBlock, const cv::String& theText, cv::Point& thePos, double theFontScale, unsigned int theColor);
1293  void button(cvui_block_t& theBlock, int theState, cv::Rect& theShape, const cv::String& theLabel);
1294  void buttonLabel(cvui_block_t& theBlock, int theState, cv::Rect theRect, const cv::String& theLabel, cv::Size& theTextSize);
1295  void image(cvui_block_t& theBlock, cv::Rect& theRect, cv::Mat& theImage);
1296  void counter(cvui_block_t& theBlock, cv::Rect& theShape, const cv::String& theValue);
1297  void trackbarHandle(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams, cv::Rect& theWorkingArea);
1298  void trackbarPath(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams, cv::Rect& theWorkingArea);
1299  void trackbarSteps(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams, cv::Rect& theWorkingArea);
1300  void trackbarSegmentLabel(cvui_block_t& theBlock, cv::Rect& theShape, const internal::TrackbarParams &theParams, long double theValue, cv::Rect& theWorkingArea, bool theShowLabel);
1301  void trackbarSegments(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams, cv::Rect& theWorkingArea);
1302  void trackbar(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams);
1303  void checkbox(cvui_block_t& theBlock, int theState, cv::Rect& theShape);
1304  void checkboxLabel(cvui_block_t& theBlock, cv::Rect& theRect, const cv::String& theLabel, cv::Size& theTextSize, unsigned int theColor);
1305  void checkboxCheck(cvui_block_t& theBlock, cv::Rect& theShape);
1306  void window(cvui_block_t& theBlock, cv::Rect& theTitleBar, cv::Rect& theContent, const cv::String& theTitle);
1307  void rect(cvui_block_t& theBlock, cv::Rect& thePos, unsigned int theBorderColor, unsigned int theFillingColor);
1308  void sparkline(cvui_block_t& theBlock, std::vector<double>& theValues, cv::Rect &theRect, double theMin, double theMax, unsigned int theColor);
1309 
1310  int putText(cvui_block_t& theBlock, int theState, cv::Scalar aColor, const std::string& theText, const cv::Point & thePosition);
1311  int putTextCentered(cvui_block_t& theBlock, const cv::Point & position, const std::string &text);
1312 }
1313 
1314 template <typename num_type>
1315 bool trackbar(cv::Mat& theWhere, int theX, int theY, int theWidth, num_type *theValue, num_type theMin, num_type theMax, int theSegments, const char *theLabelFormat, unsigned int theOptions, num_type theDiscreteStep) {
1316  internal::TrackbarParams aParams = internal::makeTrackbarParams(theMin, theMax, theDiscreteStep, theSegments, theLabelFormat, theOptions);
1317  return trackbar<num_type>(theWhere, theX, theY, theWidth, theValue, aParams);
1318 }
1319 
1320 template <typename num_type>
1321 bool trackbar(int theWidth, num_type *theValue, num_type theMin, num_type theMax, int theSegments, const char *theLabelFormat, unsigned int theOptions, num_type theDiscreteStep) {
1322  internal::TrackbarParams aParams = internal::makeTrackbarParams(theMin, theMax, theDiscreteStep, theSegments, theLabelFormat, theOptions);
1323  return trackbar<num_type>(theWidth, theValue, aParams);
1324 }
1325 
1326 } // namespace cvui
1327 
1328 #endif // _CVUI_H_
1329 
1330 // Below this line is the implementation of all functions declared above.
1331 
1332 #if !defined(CVUI_IMPLEMENTATION) && !defined(CVUI_DISABLE_COMPILATION_NOTICES)
1333  // cvui.h is being included without CVUI_IMEPLEMENTATION. Let's output a compile notice about it
1334  // to help those trying to debug possible cvui compilation errors.
1335  #pragma _CVUI_COMPILE_MESSAGE(_CVUI_NO_IMPLEMENTATION_NOTICE)
1336 #endif
1337 
1338 //#ifdef CVUI_IMPLEMENTATION
1339 
1340 // Show some helping hand in case cvui.h does not compile because of inclusion in multiple files.
1341 #ifndef CVUI_DISABLE_COMPILATION_NOTICES
1342  #pragma _CVUI_COMPILE_MESSAGE(_CVUI_IMPLEMENTATION_NOTICE)
1343 #endif
1344 
1345 namespace cvui
1346 {
1347 
1348 // This is an internal namespace with all code
1349 // that is shared among components/functions
1350 namespace internal
1351 {
1352  bool isMouseButton(cvui_mouse_btn_t& theButton, int theQuery) {
1353  bool aRet = false;
1354 
1355  switch (theQuery) {
1356  case cvui::CLICK:
1357  case cvui::UP:
1358  aRet = theButton.justReleased; break;
1359  case cvui::DOWN:
1360  aRet = theButton.justPressed; break;
1361  case cvui::IS_DOWN:
1362  aRet = theButton.pressed; break;
1363  }
1364 
1365  return aRet;
1366  }
1367 
1368  void resetMouseButton(cvui_mouse_btn_t& theButton) {
1369  theButton.justPressed = false;
1370  theButton.justReleased = false;
1371  theButton.pressed = false;
1372  }
1373 
1374  void init(const cv::String& theWindowName, int theDelayWaitKey) {
1375  internal::gDefaultContext = theWindowName;
1376  internal::gCurrentContext = theWindowName;
1377  internal::gDelayWaitKey = theDelayWaitKey;
1378  internal::gLastKeyPressed = -1;
1379  }
1380 
1381  cvui_context_t& getContext(const cv::String& theWindowName) {
1382  if (!theWindowName.empty()) {
1383  // Get context in particular
1384  return internal::gContexts[theWindowName];
1385 
1386  } else if (!internal::gCurrentContext.empty()) {
1387  // No window provided, return currently active context.
1388  return internal::gContexts[internal::gCurrentContext];
1389 
1390  } else if (!internal::gDefaultContext.empty()) {
1391  // We have no active context, so let's use the default one.
1392  return internal::gContexts[internal::gDefaultContext];
1393 
1394  } else {
1395  // Apparently we have no window at all! <o>
1396  // This should not happen. Probably cvui::init() was never called.
1397  internal::error(5, "Unable to read context. Did you forget to call cvui::init()?");
1398  return internal::gContexts["first"]; // return to make the compiler happy.
1399  }
1400  }
1401 
1402  bool bitsetHas(unsigned int theBitset, unsigned int theValue) {
1403  return (theBitset & theValue) != 0;
1404  }
1405 
1406  void error(int theId, std::string theMessage) {
1407  std::cout << "[CVUI] Fatal error (code " << theId << "): " << theMessage << "\n";
1408  cv::waitKey(100000);
1409  exit(-1);
1410  }
1411 
1412  void updateLayoutFlow(cvui_block_t& theBlock, cv::Size theSize) {
1413  int aValue;
1414 
1415  if (theBlock.type == ROW) {
1416  aValue = theSize.width + theBlock.padding;
1417 
1418  theBlock.anchor.x += aValue;
1419  theBlock.fill.width += aValue;
1420  theBlock.fill.height = std::max(theSize.height, theBlock.fill.height);
1421 
1422  }
1423  else if (theBlock.type == COLUMN) {
1424  aValue = theSize.height + theBlock.padding;
1425 
1426  theBlock.anchor.y += aValue;
1427  theBlock.fill.height += aValue;
1428  theBlock.fill.width = std::max(theSize.width, theBlock.fill.width);
1429  }
1430  }
1431 
1432  bool blockStackEmpty() {
1433  return gStackCount == -1;
1434  }
1435 
1436  cvui_block_t& topBlock() {
1437  if (gStackCount < 0) {
1438  error(3, "You are using a function that should be enclosed by begin*() and end*(), but you probably forgot to call begin*().");
1439  }
1440 
1441  return gStack[gStackCount];
1442  }
1443 
1444  cvui_block_t& pushBlock() {
1445  return gStack[++gStackCount];
1446  }
1447 
1448  cvui_block_t& popBlock() {
1449  // Check if there is anything to be popped out from the stack.
1450  if (gStackCount < 0) {
1451  error(1, "Mismatch in the number of begin*()/end*() calls. You are calling one more than the other.");
1452  }
1453 
1454  return gStack[gStackCount--];
1455  }
1456 
1457  void begin(int theType, cv::Mat &theWhere, int theX, int theY, int theWidth, int theHeight, int thePadding) {
1458  cvui_block_t& aBlock = internal::pushBlock();
1459 
1460  aBlock.where = theWhere;
1461 
1462  aBlock.rect.x = theX;
1463  aBlock.rect.y = theY;
1464  aBlock.rect.width = theWidth;
1465  aBlock.rect.height = theHeight;
1466 
1467  aBlock.fill = aBlock.rect;
1468  aBlock.fill.width = 0;
1469  aBlock.fill.height = 0;
1470 
1471  aBlock.anchor.x = theX;
1472  aBlock.anchor.y = theY;
1473 
1474  aBlock.padding = thePadding;
1475  aBlock.type = theType;
1476  }
1477 
1478  void end(int theType) {
1479  cvui_block_t& aBlock = popBlock();
1480 
1481  if (aBlock.type != theType) {
1482  error(4, "Calling wrong type of end*(). E.g. endColumn() instead of endRow(). Check if your begin*() calls are matched with their appropriate end*() calls.");
1483  }
1484 
1485  // If we still have blocks in the stack, we must update
1486  // the current top with the dimensions that were filled by
1487  // the newly popped block.
1488 
1489  if (!blockStackEmpty()) {
1490  cvui_block_t& aTop = topBlock();
1491  cv::Size aSize;
1492 
1493  // If the block has rect.width < 0 or rect.heigth < 0, it means the
1494  // user don't want to calculate the block's width/height. It's up to
1495  // us do to the math. In that case, we use the block's fill rect to find
1496  // out the occupied space. If the block's width/height is greater than
1497  // zero, then the user is very specific about the desired size. In that
1498  // case, we use the provided width/height, no matter what the fill rect
1499  // actually is.
1500  aSize.width = aBlock.rect.width < 0 ? aBlock.fill.width : aBlock.rect.width;
1501  aSize.height = aBlock.rect.height < 0 ? aBlock.fill.height : aBlock.rect.height;
1502 
1503  updateLayoutFlow(aTop, aSize);
1504  }
1505  }
1506 
1507  // Find the min and max values of a vector
1508  void findMinMax(std::vector<double>& theValues, double *theMin, double *theMax) {
1509  std::vector<double>::size_type aSize = theValues.size(), i;
1510  double aMin = theValues[0], aMax = theValues[0];
1511 
1512  for (i = 0; i < aSize; i++) {
1513  if (theValues[i] < aMin) {
1514  aMin = theValues[i];
1515  }
1516 
1517  if (theValues[i] > aMax) {
1518  aMax = theValues[i];
1519  }
1520  }
1521 
1522  *theMin = aMin;
1523  *theMax = aMax;
1524  }
1525 
1526  cvui_label_t createLabel(const std::string &theLabel) {
1527  cvui_label_t aLabel;
1528  std::stringstream aBefore, aAfter;
1529 
1530  aLabel.hasShortcut = false;
1531  aLabel.shortcut = 0;
1532  aLabel.textBeforeShortcut = "";
1533  aLabel.textAfterShortcut = "";
1534 
1535  for (size_t i = 0; i < theLabel.size(); i++) {
1536  char c = theLabel[i];
1537  if ((c == '&') && (i < theLabel.size() - 1)) {
1538  aLabel.hasShortcut = true;
1539  aLabel.shortcut = theLabel[i + 1];
1540  ++i;
1541  }
1542  else if (!aLabel.hasShortcut) {
1543  aBefore << c;
1544  }
1545  else {
1546  aAfter << c;
1547  }
1548  }
1549 
1550  aLabel.textBeforeShortcut = aBefore.str();
1551  aLabel.textAfterShortcut = aAfter.str();
1552 
1553  return aLabel;
1554  }
1555 
1556  cv::Scalar hexToScalar(unsigned int theColor) {
1557  int aAlpha = (theColor >> 24) & 0xff;
1558  int aRed = (theColor >> 16) & 0xff;
1559  int aGreen = (theColor >> 8) & 0xff;
1560  int aBlue = theColor & 0xff;
1561 
1562  return cv::Scalar(aBlue, aGreen, aRed, aAlpha);
1563  }
1564 
1565  void resetRenderingBuffer(cvui_block_t& theScreen) {
1566  theScreen.rect.x = 0;
1567  theScreen.rect.y = 0;
1568  theScreen.rect.width = 0;
1569  theScreen.rect.height = 0;
1570 
1571  theScreen.fill = theScreen.rect;
1572  theScreen.fill.width = 0;
1573  theScreen.fill.height = 0;
1574 
1575  theScreen.anchor.x = 0;
1576  theScreen.anchor.y = 0;
1577 
1578  theScreen.padding = 0;
1579  }
1580 
1581 
1582  inline double clamp01(double value)
1583  {
1584  value = value > 1. ? 1. : value;
1585  value = value < 0. ? 0. : value;
1586  return value;
1587  }
1588 
1589  inline void trackbarForceValuesAsMultiplesOfSmallStep(const TrackbarParams & theParams, long double *theValue)
1590  {
1591  if (bitsetHas(theParams.options, TRACKBAR_DISCRETE) && theParams.step != 0.) {
1592  long double k = (*theValue - theParams.min) / theParams.step;
1593  k = (long double)cvRound((double)k);
1594  *theValue = theParams.min + theParams.step * k;
1595  }
1596  }
1597 
1598  inline long double trackbarXPixelToValue(const TrackbarParams & theParams, cv::Rect & theBounding, int thePixelX)
1599  {
1600  long double ratio = (thePixelX - (long double)(theBounding.x + gTrackbarMarginX)) / (long double)(theBounding.width - 2 * gTrackbarMarginX);
1601  ratio = clamp01(ratio);
1602  long double value = theParams.min + ratio * (theParams.max - theParams.min);
1603  return value;
1604  }
1605 
1606  inline int trackbarValueToXPixel(const TrackbarParams & theParams, cv::Rect & theBounding, long double theValue)
1607  {
1608  long double aRatio = (theValue - theParams.min) / (theParams.max - theParams.min);
1609  aRatio = clamp01(aRatio);
1610  long double thePixelsX = (long double)theBounding.x + gTrackbarMarginX + aRatio * (long double)(theBounding.width - 2 * gTrackbarMarginX);
1611  return (int)thePixelsX;
1612  }
1613 
1614  int iarea(int theX, int theY, int theWidth, int theHeight) {
1615  cvui_mouse_t& aMouse = internal::getContext().mouse;
1616 
1617  // By default, return that the mouse is out of the interaction area.
1618  int aRet = cvui::OUT;
1619 
1620  // Check if the mouse is over the interaction area.
1621  bool aMouseIsOver = cv::Rect(theX, theY, theWidth, theHeight).contains(aMouse.position);
1622 
1623  if (aMouseIsOver) {
1624  if (aMouse.anyButton.pressed) {
1625  aRet = cvui::DOWN;
1626  } else {
1627  aRet = cvui::OVER;
1628  }
1629  }
1630 
1631  // Tell if the button was clicked or not
1632  if (aMouseIsOver && aMouse.anyButton.justReleased) {
1633  aRet = cvui::CLICK;
1634  }
1635 
1636  return aRet;
1637  }
1638 
1639  bool button(cvui_block_t& theBlock, int theX, int theY, int theWidth, int theHeight, const cv::String& theLabel, bool theUpdateLayout) {
1640  // Calculate the space that the label will fill
1641  cv::Size aTextSize = getTextSize(theLabel, cv::FONT_HERSHEY_SIMPLEX, 0.4, 1, nullptr);
1642 
1643  // Make the button bit enough to house the label
1644  cv::Rect aRect(theX, theY, theWidth, theHeight);
1645 
1646  // Render the button according to mouse interaction, e.g. OVER, DOWN, OUT.
1647  int aStatus = cvui::iarea(theX, theY, aRect.width, aRect.height);
1648  render::button(theBlock, aStatus, aRect, theLabel);
1649  render::buttonLabel(theBlock, aStatus, aRect, theLabel, aTextSize);
1650 
1651  // Update the layout flow according to button size
1652  // if we were told to update.
1653  if (theUpdateLayout) {
1654  cv::Size aSize(theWidth, theHeight);
1655  updateLayoutFlow(theBlock, aSize);
1656  }
1657 
1658  bool aWasShortcutPressed = false;
1659 
1660  //Handle keyboard shortcuts
1661  if (internal::gLastKeyPressed != -1) {
1662  // TODO: replace with something like strpos(). I think it has better performance.
1663  auto aLabel = internal::createLabel(theLabel);
1664  if (aLabel.hasShortcut && (tolower(aLabel.shortcut) == tolower((char)internal::gLastKeyPressed))) {
1665  aWasShortcutPressed = true;
1666  }
1667  }
1668 
1669  // Return true if the button was clicked
1670  return aStatus == cvui::CLICK || aWasShortcutPressed;
1671  }
1672 
1673  bool button(cvui_block_t& theBlock, int theX, int theY, const cv::String& theLabel) {
1674  // Calculate the space that the label will fill
1675  cv::Size aTextSize = getTextSize(theLabel, cv::FONT_HERSHEY_SIMPLEX, 0.4, 1, nullptr);
1676 
1677  // Create a button based on the size of the text
1678  return internal::button(theBlock, theX, theY, aTextSize.width + 30, aTextSize.height + 18, theLabel, true);
1679  }
1680 
1681  bool button(cvui_block_t& theBlock, int theX, int theY, cv::Mat& theIdle, cv::Mat& theOver, cv::Mat& theDown, bool theUpdateLayout) {
1682  cv::Rect aRect(theX, theY, theIdle.cols, theIdle.rows);
1683  int aStatus = cvui::iarea(theX, theY, aRect.width, aRect.height);
1684 
1685  switch (aStatus) {
1686  case cvui::OUT: render::image(theBlock, aRect, theIdle); break;
1687  case cvui::OVER: render::image(theBlock, aRect, theOver); break;
1688  case cvui::DOWN: render::image(theBlock, aRect, theDown); break;
1689  }
1690 
1691  // Update the layout flow according to button size
1692  // if we were told to update.
1693  if (theUpdateLayout) {
1694  cv::Size aSize(aRect.width, aRect.height);
1695  updateLayoutFlow(theBlock, aSize);
1696  }
1697 
1698  // Return true if the button was clicked
1699  return aStatus == cvui::CLICK;
1700  }
1701 
1702  void image(cvui_block_t& theBlock, int theX, int theY, cv::Mat& theImage) {
1703  cv::Rect aRect(theX, theY, theImage.cols, theImage.rows);
1704 
1705  // TODO: check for render outside the frame area
1706  render::image(theBlock, aRect, theImage);
1707 
1708  // Update the layout flow according to image size
1709  cv::Size aSize(theImage.cols, theImage.rows);
1710  updateLayoutFlow(theBlock, aSize);
1711  }
1712 
1713  bool checkbox(cvui_block_t& theBlock, int theX, int theY, const cv::String& theLabel, bool *theState, unsigned int theColor) {
1714  cvui_mouse_t& aMouse = internal::getContext().mouse;
1715  cv::Rect aRect(theX, theY, 15, 15);
1716  cv::Size aTextSize = getTextSize(theLabel, cv::FONT_HERSHEY_SIMPLEX, 0.4, 1, nullptr);
1717  cv::Rect aHitArea(theX, theY, aRect.width + aTextSize.width + 6, aRect.height);
1718  bool aMouseIsOver = aHitArea.contains(aMouse.position);
1719 
1720  if (aMouseIsOver) {
1721  render::checkbox(theBlock, cvui::OVER, aRect);
1722 
1723  if (aMouse.anyButton.justReleased) {
1724  *theState = !(*theState);
1725  }
1726  } else {
1727  render::checkbox(theBlock, cvui::OUT, aRect);
1728  }
1729 
1730  render::checkboxLabel(theBlock, aRect, theLabel, aTextSize, theColor);
1731 
1732  if (*theState) {
1733  render::checkboxCheck(theBlock, aRect);
1734  }
1735 
1736  // Update the layout flow
1737  cv::Size aSize(aHitArea.width, aHitArea.height);
1738  updateLayoutFlow(theBlock, aSize);
1739 
1740  return *theState;
1741  }
1742 
1743  void text(cvui_block_t& theBlock, int theX, int theY, const cv::String& theText, double theFontScale, unsigned int theColor, bool theUpdateLayout) {
1744  cv::Size aTextSize = cv::getTextSize(theText, cv::FONT_HERSHEY_SIMPLEX, theFontScale, 1, nullptr);
1745  cv::Point aPos(theX, theY + aTextSize.height);
1746 
1747  render::text(theBlock, theText, aPos, theFontScale, theColor);
1748 
1749  if (theUpdateLayout) {
1750  // Add an extra pixel to the height to overcome OpenCV font size problems.
1751  aTextSize.height += 1;
1752 
1753  updateLayoutFlow(theBlock, aTextSize);
1754  }
1755  }
1756 
1757  int counter(cvui_block_t& theBlock, int theX, int theY, int *theValue, int theStep, const char *theFormat) {
1758  cv::Rect aContentArea(theX + 22, theY, 48, 22);
1759 
1760  if (internal::button(theBlock, theX, theY, 22, 22, "-", false)) {
1761  *theValue -= theStep;
1762  }
1763 
1764  sprintf_s(internal::gBuffer, theFormat, *theValue);
1765  render::counter(theBlock, aContentArea, internal::gBuffer);
1766 
1767  if (internal::button(theBlock, aContentArea.x + aContentArea.width, theY, 22, 22, "+", false)) {
1768  *theValue += theStep;
1769  }
1770 
1771  // Update the layout flow
1772  cv::Size aSize(22 * 2 + aContentArea.width, aContentArea.height);
1773  updateLayoutFlow(theBlock, aSize);
1774 
1775  return *theValue;
1776  }
1777 
1778  double counter(cvui_block_t& theBlock, int theX, int theY, double *theValue, double theStep, const char *theFormat) {
1779  cv::Rect aContentArea(theX + 22, theY, 48, 22);
1780 
1781  if (internal::button(theBlock, theX, theY, 22, 22, "-", false)) {
1782  *theValue -= theStep;
1783  }
1784 
1785  sprintf_s(internal::gBuffer, theFormat, *theValue);
1786  render::counter(theBlock, aContentArea, internal::gBuffer);
1787 
1788  if (internal::button(theBlock, aContentArea.x + aContentArea.width, theY, 22, 22, "+", false)) {
1789  *theValue += theStep;
1790  }
1791 
1792  // Update the layout flow
1793  cv::Size aSize(22 * 2 + aContentArea.width, aContentArea.height);
1794  updateLayoutFlow(theBlock, aSize);
1795 
1796  return *theValue;
1797  }
1798 
1799  bool trackbar(cvui_block_t& theBlock, int theX, int theY, int theWidth, long double *theValue, const TrackbarParams & theParams) {
1800  cvui_mouse_t& aMouse = internal::getContext().mouse;
1801  cv::Rect aContentArea(theX, theY, theWidth, 45);
1802  long double aValue = *theValue;
1803  bool aMouseIsOver = aContentArea.contains(aMouse.position);
1804 
1805  render::trackbar(theBlock, aMouseIsOver ? OVER : OUT, aContentArea, *theValue, theParams);
1806 
1807  if (aMouse.anyButton.pressed && aMouseIsOver) {
1808  *theValue = internal::trackbarXPixelToValue(theParams, aContentArea, aMouse.position.x);
1809 
1810  if (bitsetHas(theParams.options, TRACKBAR_DISCRETE)) {
1811  internal::trackbarForceValuesAsMultiplesOfSmallStep(theParams, theValue);
1812  }
1813  }
1814 
1815  // Update the layout flow
1816  cv::Size aSize = aContentArea.size();
1817  updateLayoutFlow(theBlock, aSize);
1818 
1819  return (*theValue != aValue);
1820  }
1821 
1822 
1823  void window(cvui_block_t& theBlock, int theX, int theY, int theWidth, int theHeight, const cv::String& theTitle) {
1824  cv::Rect aTitleBar(theX, theY, theWidth, 20);
1825  cv::Rect aContent(theX, theY + aTitleBar.height, theWidth, theHeight - aTitleBar.height);
1826 
1827  render::window(theBlock, aTitleBar, aContent, theTitle);
1828 
1829  // Update the layout flow
1830  cv::Size aSize(theWidth, theHeight);
1831  updateLayoutFlow(theBlock, aSize);
1832  }
1833 
1834  void rect(cvui_block_t& theBlock, int theX, int theY, int theWidth, int theHeight, unsigned int theBorderColor, unsigned int theFillingColor) {
1835  cv::Point aAnchor(theX, theY);
1836  cv::Rect aRect(theX, theY, theWidth, theHeight);
1837 
1838  aRect.x = aRect.width < 0 ? aAnchor.x + aRect.width : aAnchor.x;
1839  aRect.y = aRect.height < 0 ? aAnchor.y + aRect.height : aAnchor.y;
1840  aRect.width = std::abs(aRect.width);
1841  aRect.height = std::abs(aRect.height);
1842 
1843  render::rect(theBlock, aRect, theBorderColor, theFillingColor);
1844 
1845  // Update the layout flow
1846  cv::Size aSize(aRect.width, aRect.height);
1847  updateLayoutFlow(theBlock, aSize);
1848  }
1849 
1850  void sparkline(cvui_block_t& theBlock, std::vector<double>& theValues, int theX, int theY, int theWidth, int theHeight, unsigned int theColor) {
1851  double aMin, aMax;
1852  cv::Rect aRect(theX, theY, theWidth, theHeight);
1853  std::vector<double>::size_type aHowManyValues = theValues.size();
1854 
1855  if (aHowManyValues >= 2) {
1856  internal::findMinMax(theValues, &aMin, &aMax);
1857  render::sparkline(theBlock, theValues, aRect, aMin, aMax, theColor);
1858  } else {
1859  internal::text(theBlock, theX, theY, aHowManyValues == 0 ? "No data." : "Insufficient data points.", 0.4, 0xCECECE, false);
1860  }
1861 
1862  // Update the layout flow
1863  cv::Size aSize(theWidth, theHeight);
1864  updateLayoutFlow(theBlock, aSize);
1865  }
1866 } // namespace internal
1867 
1868 // This is an internal namespace with all functions
1869 // that actually render each one of the UI components
1870 namespace render
1871 {
1872  void text(cvui_block_t& theBlock, const cv::String& theText, cv::Point& thePos, double theFontScale, unsigned int theColor) {
1873  cv::putText(theBlock.where, theText, thePos, cv::FONT_HERSHEY_SIMPLEX, theFontScale, internal::hexToScalar(theColor), 1, CVUI_ANTIALISED);
1874  }
1875 
1876  void button(cvui_block_t& theBlock, int theState, cv::Rect& theShape, const cv::String& theLabel) {
1877  // Outline
1878  cv::rectangle(theBlock.where, theShape, cv::Scalar(0x29, 0x29, 0x29));
1879 
1880  // Border
1881  theShape.x++; theShape.y++; theShape.width -= 2; theShape.height -= 2;
1882  cv::rectangle(theBlock.where, theShape, cv::Scalar(0x4A, 0x4A, 0x4A));
1883 
1884  // Inside
1885  theShape.x++; theShape.y++; theShape.width -= 2; theShape.height -= 2;
1886  cv::rectangle(theBlock.where, theShape, theState == OUT ? cv::Scalar(0x42, 0x42, 0x42) : (theState == OVER ? cv::Scalar(0x52, 0x52, 0x52) : cv::Scalar(0x32, 0x32, 0x32)), CVUI_FILLED);
1887  }
1888 
1889  int putText(cvui_block_t& theBlock, int theState, cv::Scalar aColor, const std::string& theText, const cv::Point & thePosition) {
1890  double aFontSize = theState == cvui::DOWN ? 0.39 : 0.4;
1891  cv::Size aSize;
1892 
1893  if (theText != "") {
1894  cv::putText(theBlock.where, theText, thePosition, cv::FONT_HERSHEY_SIMPLEX, aFontSize, aColor, 1, CVUI_ANTIALISED);
1895  aSize = cv::getTextSize(theText, cv::FONT_HERSHEY_SIMPLEX, aFontSize, 1, nullptr);
1896  }
1897 
1898  return aSize.width;
1899  }
1900 
1901  int putTextCentered(cvui_block_t& theBlock, const cv::Point & position, const std::string &text) {
1902  double aFontScale = 0.3;
1903 
1904  auto size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, aFontScale, 1, nullptr);
1905  cv::Point positionDecentered(position.x - size.width / 2, position.y);
1906  cv::putText(theBlock.where, text, positionDecentered, cv::FONT_HERSHEY_SIMPLEX, aFontScale, cv::Scalar(0xCE, 0xCE, 0xCE), 1, CVUI_ANTIALISED);
1907 
1908  return size.width;
1909  };
1910 
1911  void buttonLabel(cvui_block_t& theBlock, int theState, cv::Rect theRect, const cv::String& theLabel, cv::Size& theTextSize) {
1912  cv::Point aPos(theRect.x + theRect.width / 2 - theTextSize.width / 2, theRect.y + theRect.height / 2 + theTextSize.height / 2);
1913  cv::Scalar aColor = cv::Scalar(0xCE, 0xCE, 0xCE);
1914 
1915  auto aLabel = internal::createLabel(theLabel);
1916 
1917  if (!aLabel.hasShortcut) {
1918  putText(theBlock, theState, aColor, theLabel, aPos);
1919  }
1920  else {
1921  int aWidth = putText(theBlock, theState, aColor, aLabel.textBeforeShortcut, aPos);
1922  int aStart = aPos.x + aWidth;
1923  aPos.x += aWidth;
1924 
1925  std::string aShortcut;
1926  aShortcut.push_back(aLabel.shortcut);
1927 
1928  aWidth = putText(theBlock, theState, aColor, aShortcut, aPos);
1929  int aEnd = aStart + aWidth;
1930  aPos.x += aWidth;
1931 
1932  putText(theBlock, theState, aColor, aLabel.textAfterShortcut, aPos);
1933  cv::line(theBlock.where, cv::Point(aStart, aPos.y + 3), cv::Point(aEnd, aPos.y + 3), aColor, 1, CVUI_ANTIALISED);
1934  }
1935  }
1936 
1937  void image(cvui_block_t& theBlock, cv::Rect& theRect, cv::Mat& theImage) {
1938  theImage.copyTo(theBlock.where(theRect));
1939  }
1940 
1941  void counter(cvui_block_t& theBlock, cv::Rect& theShape, const cv::String& theValue) {
1942  cv::rectangle(theBlock.where, theShape, cv::Scalar(0x29, 0x29, 0x29), CVUI_FILLED); // fill
1943  cv::rectangle(theBlock.where, theShape, cv::Scalar(0x45, 0x45, 0x45)); // border
1944 
1945  cv::Size aTextSize = getTextSize(theValue, cv::FONT_HERSHEY_SIMPLEX, 0.4, 1, nullptr);
1946 
1947  cv::Point aPos(theShape.x + theShape.width / 2 - aTextSize.width / 2, theShape.y + aTextSize.height / 2 + theShape.height / 2);
1948  cv::putText(theBlock.where, theValue, aPos, cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0xCE, 0xCE, 0xCE), 1, CVUI_ANTIALISED);
1949  }
1950 
1951  void trackbarHandle(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams, cv::Rect& theWorkingArea) {
1952  cv::Point aBarTopLeft(theWorkingArea.x, theWorkingArea.y + theWorkingArea.height / 2);
1953  int aBarHeight = 7;
1954 
1955  // Draw the rectangle representing the handle
1956  int aPixelX = internal::trackbarValueToXPixel(theParams, theShape, theValue);
1957  int aIndicatorWidth = 5;
1958  int aIndicatorHeight = 8;
1959  cv::Point aPoint1(aPixelX - aIndicatorWidth, aBarTopLeft.y - aIndicatorHeight-4);
1960  cv::Point aPoint2(aPixelX + aIndicatorWidth, aBarTopLeft.y + aBarHeight + aIndicatorHeight-4);
1961  cv::Rect aRect(aPoint1, aPoint2);
1962 
1963  int aFillColor = theState == OVER ? 0x4084DF : 0x4084DF;
1964 
1965  // rect(theBlock, aRect, 0x212121, 0x212121);
1966  // aRect.x += 1; aRect.y += 1; aRect.width -= 2; aRect.height -= 2;
1967  rect(theBlock, aRect, aFillColor, aFillColor);
1968 
1969  bool aShowLabel = internal::bitsetHas(theParams.options, cvui::TRACKBAR_HIDE_VALUE_LABEL) == false;
1970 
1971  // Draw the handle label
1972  if (aShowLabel) {
1973  cv::Point aTextPos(aPixelX, aPoint2.y + 11);
1974  sprintf_s(internal::gBuffer, theParams.labelFormat.c_str(), static_cast<long double>(theValue));
1975  putTextCentered(theBlock, aTextPos, internal::gBuffer);
1976  }
1977  }
1978 
1979  void trackbarPath(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams, cv::Rect& theWorkingArea) {
1980  int aBarHeight = 22;
1981  // cv::Point aBarTopLeft(theWorkingArea.x, theWorkingArea.y + theWorkingArea.height / 2);
1982  cv::Point aBarTopLeft(theWorkingArea.x, theWorkingArea.y + 10);
1983  cv::Rect aRect(aBarTopLeft, cv::Size(theWorkingArea.width, aBarHeight));
1984 
1985  int aBorderColor = theState == OVER ? 0x4e4e4e : 0x3e3e3e;
1986 
1987  rect(theBlock, aRect, aBorderColor, 0x25354e);
1988  cv::line(theBlock.where, cv::Point(aRect.x + 1, aRect.y + aBarHeight - 2), cv::Point(aRect.x + aRect.width - 2, aRect.y + aBarHeight - 2), cv::Scalar(0x0e, 0x0e, 0x0e));
1989  }
1990 
1991  void trackbarSteps(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams, cv::Rect& theWorkingArea) {
1992  cv::Point aBarTopLeft(theWorkingArea.x, theWorkingArea.y + theWorkingArea.height / 2);
1993  cv::Scalar aColor(0x51, 0x51, 0x51);
1994 
1995  bool aDiscrete = internal::bitsetHas(theParams.options, cvui::TRACKBAR_DISCRETE);
1996  long double aFixedStep = aDiscrete ? theParams.step : (theParams.max - theParams.min) / 20;
1997 
1998  // TODO: check min, max and step to prevent infinite loop.
1999  for (long double aValue = theParams.min; aValue <= theParams.max; aValue += aFixedStep) {
2000  int aPixelX = internal::trackbarValueToXPixel(theParams, theShape, aValue);
2001  cv::Point aPoint1(aPixelX, aBarTopLeft.y);
2002  cv::Point aPoint2(aPixelX, aBarTopLeft.y - 3);
2003  cv::line(theBlock.where, aPoint1, aPoint2, aColor);
2004  }
2005  }
2006 
2007  void trackbarSegmentLabel(cvui_block_t& theBlock, cv::Rect& theShape, const internal::TrackbarParams &theParams, long double theValue, cv::Rect& theWorkingArea, bool theShowLabel) {
2008  cv::Scalar aColor(0x51, 0x51, 0x51);
2009  cv::Point aBarTopLeft(theWorkingArea.x, theWorkingArea.y + theWorkingArea.height / 2);
2010 
2011  int aPixelX = internal::trackbarValueToXPixel(theParams, theShape, theValue);
2012 
2013  cv::Point aPoint1(aPixelX, aBarTopLeft.y);
2014  cv::Point aPoint2(aPixelX, aBarTopLeft.y - 8);
2015  cv::line(theBlock.where, aPoint1, aPoint2, aColor);
2016 
2017  if (theShowLabel)
2018  {
2019  sprintf_s(internal::gBuffer, theParams.labelFormat.c_str(), theValue);
2020  cv::Point aTextPos(aPixelX, aBarTopLeft.y - 11);
2021  putTextCentered(theBlock, aTextPos, internal::gBuffer);
2022  }
2023  }
2024 
2025  void trackbarSegments(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams, cv::Rect& theWorkingArea) {
2026  int aSegments = theParams.segments < 1 ? 1 : theParams.segments;
2027  long double aSegmentLength = (long double)(theParams.max - theParams.min) / (long double)aSegments;
2028 
2029  bool aHasMinMaxLabels = internal::bitsetHas(theParams.options, TRACKBAR_HIDE_MIN_MAX_LABELS) == false;
2030 
2031  // Render the min value label
2032  trackbarSegmentLabel(theBlock, theShape, theParams, theParams.min, theWorkingArea, aHasMinMaxLabels);
2033 
2034  //Draw large steps and labels
2035  bool aHasSegmentLabels = internal::bitsetHas(theParams.options, TRACKBAR_HIDE_SEGMENT_LABELS) == false;
2036  // TODO: check min, max and step to prevent infinite loop.
2037  for (long double aValue = theParams.min; aValue <= theParams.max; aValue += aSegmentLength) {
2038  trackbarSegmentLabel(theBlock, theShape, theParams, aValue, theWorkingArea, aHasSegmentLabels);
2039  }
2040 
2041  // Render the max value label
2042  trackbarSegmentLabel(theBlock, theShape, theParams, theParams.max, theWorkingArea, aHasMinMaxLabels);
2043  }
2044 
2045  void trackbar(cvui_block_t& theBlock, int theState, cv::Rect& theShape, double theValue, const internal::TrackbarParams &theParams) {
2046  cv::Rect aWorkingArea(theShape.x + internal::gTrackbarMarginX, theShape.y, theShape.width - 2 * internal::gTrackbarMarginX, theShape.height);
2047 
2048  trackbarPath(theBlock, theState, theShape, theValue, theParams, aWorkingArea);
2049 
2050  bool aHideAllLabels = internal::bitsetHas(theParams.options, cvui::TRACKBAR_HIDE_LABELS);
2051  bool aShowSteps = internal::bitsetHas(theParams.options, cvui::TRACKBAR_HIDE_STEP_SCALE) == false;
2052 
2053  if (aShowSteps && !aHideAllLabels) {
2054  trackbarSteps(theBlock, theState, theShape, theValue, theParams, aWorkingArea);
2055  }
2056 
2057  if (!aHideAllLabels) {
2058  trackbarSegments(theBlock, theState, theShape, theValue, theParams, aWorkingArea);
2059  }
2060 
2061  trackbarHandle(theBlock, theState, theShape, theValue, theParams, aWorkingArea);
2062  }
2063 
2064  void checkbox(cvui_block_t& theBlock, int theState, cv::Rect& theShape) {
2065  // Outline
2066  cv::rectangle(theBlock.where, theShape, theState == OUT ? cv::Scalar(0x63, 0x63, 0x63) : cv::Scalar(0x80, 0x80, 0x80));
2067 
2068  // Border
2069  theShape.x++; theShape.y++; theShape.width -= 2; theShape.height -= 2;
2070  cv::rectangle(theBlock.where, theShape, cv::Scalar(0x17, 0x17, 0x17));
2071 
2072  // Inside
2073  theShape.x++; theShape.y++; theShape.width -= 2; theShape.height -= 2;
2074  cv::rectangle(theBlock.where, theShape, cv::Scalar(0x29, 0x29, 0x29), CVUI_FILLED);
2075  }
2076 
2077  void checkboxLabel(cvui_block_t& theBlock, cv::Rect& theRect, const cv::String& theLabel, cv::Size& theTextSize, unsigned int theColor) {
2078  cv::Point aPos(theRect.x + theRect.width + 6, theRect.y + theTextSize.height + theRect.height / 2 - theTextSize.height / 2 - 1);
2079  text(theBlock, theLabel, aPos, 0.4, theColor);
2080  }
2081 
2082  void checkboxCheck(cvui_block_t& theBlock, cv::Rect& theShape) {
2083  theShape.x++; theShape.y++; theShape.width -= 2; theShape.height -= 2;
2084  cv::rectangle(theBlock.where, theShape, cv::Scalar(0xFF, 0xBF, 0x75), CVUI_FILLED);
2085  }
2086 
2087  void window(cvui_block_t& theBlock, cv::Rect& theTitleBar, cv::Rect& theContent, const cv::String& theTitle) {
2088  bool aTransparecy = false;
2089  double aAlpha = 0.3;
2090  cv::Mat aOverlay;
2091 
2092  // Render the title bar.
2093  // First the border
2094  cv::rectangle(theBlock.where, theTitleBar, cv::Scalar(0x4A, 0x4A, 0x4A));
2095  // then the inside
2096  theTitleBar.x++; theTitleBar.y++; theTitleBar.width -= 2; theTitleBar.height -= 2;
2097  cv::rectangle(theBlock.where, theTitleBar, cv::Scalar(0x21, 0x21, 0x21), CVUI_FILLED);
2098 
2099  // Render title text.
2100  cv::Point aPos(theTitleBar.x + 5, theTitleBar.y + 12);
2101  cv::putText(theBlock.where, theTitle, aPos, cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0xCE, 0xCE, 0xCE), 1, CVUI_ANTIALISED);
2102 
2103  // Render the body.
2104  // First the border.
2105  cv::rectangle(theBlock.where, theContent, cv::Scalar(0x4A, 0x4A, 0x4A));
2106 
2107  // Then the filling.
2108  theContent.x++; theContent.y++; theContent.width -= 2; theContent.height -= 2;
2109  cv::rectangle(aOverlay, theContent, cv::Scalar(0x31, 0x31, 0x31), CVUI_FILLED);
2110 
2111  if (aTransparecy) {
2112  theBlock.where.copyTo(aOverlay);
2113  cv::rectangle(aOverlay, theContent, cv::Scalar(0x31, 0x31, 0x31), CVUI_FILLED);
2114  cv::addWeighted(aOverlay, aAlpha, theBlock.where, 1.0 - aAlpha, 0.0, theBlock.where);
2115 
2116  }
2117  else {
2118  cv::rectangle(theBlock.where, theContent, cv::Scalar(0x31, 0x31, 0x31), CVUI_FILLED);
2119  }
2120  }
2121 
2122  void rect(cvui_block_t& theBlock, cv::Rect& thePos, unsigned int theBorderColor, unsigned int theFillingColor) {
2123  cv::Scalar aBorder = internal::hexToScalar(theBorderColor);
2124  cv::Scalar aFilling = internal::hexToScalar(theFillingColor);
2125 
2126  bool aHasFilling = aFilling[3] != 0xff;
2127 
2128  if (aHasFilling) {
2129  if (aFilling[3] == 0x00) {
2130  // full opacity
2131  cv::rectangle(theBlock.where, thePos, aFilling, CVUI_FILLED, CVUI_ANTIALISED);
2132  }
2133  else {
2134  cv::Rect aClippedRect = thePos & cv::Rect(cv::Point(0, 0), theBlock.where.size());
2135  double aAlpha = 1.00 - static_cast<double>(aFilling[3]) / 255;
2136  cv::Mat aOverlay(aClippedRect.size(), theBlock.where.type(), aFilling);
2137  cv::addWeighted(aOverlay, aAlpha, theBlock.where(aClippedRect), 1.00 - aAlpha, 0.0, theBlock.where(aClippedRect));
2138  }
2139  }
2140 
2141  // Render the border
2142  cv::rectangle(theBlock.where, thePos, aBorder, 1, CVUI_ANTIALISED);
2143  }
2144 
2145  void sparkline(cvui_block_t& theBlock, std::vector<double>& theValues, cv::Rect &theRect, double theMin, double theMax, unsigned int theColor) {
2146  std::vector<double>::size_type aSize = theValues.size(), i;
2147  double aGap, aPosX, aScale = 0, x, y;
2148 
2149  aScale = theMax - theMin;
2150  aGap = (double)theRect.width / aSize;
2151  aPosX = theRect.x;
2152 
2153  for (i = 0; i <= aSize - 2; i++) {
2154  x = aPosX;
2155  y = (theValues[i] - theMin) / aScale * -(theRect.height - 5) + theRect.y + theRect.height - 5;
2156  cv::Point aPoint1((int)x, (int)y);
2157 
2158  x = aPosX + aGap;
2159  y = (theValues[i + 1] - theMin) / aScale * -(theRect.height - 5) + theRect.y + theRect.height - 5;
2160  cv::Point aPoint2((int)x, (int)y);
2161 
2162  cv::line(theBlock.where, aPoint1, aPoint2, internal::hexToScalar(theColor));
2163  aPosX += aGap;
2164  }
2165  }
2166 } // namespace render
2167 
2168 void init(const cv::String& theWindowName, int theDelayWaitKey, bool theCreateNamedWindow) {
2169  internal::init(theWindowName, theDelayWaitKey);
2170  watch(theWindowName, theCreateNamedWindow);
2171 }
2172 
2173 void init(const cv::String theWindowNames[], size_t theHowManyWindows, int theDelayWaitKey, bool theCreateNamedWindows) {
2174  internal::init(theWindowNames[0], theDelayWaitKey);
2175 
2176  for (size_t i = 0; i < theHowManyWindows; i++) {
2177  watch(theWindowNames[i], theCreateNamedWindows);
2178  }
2179 }
2180 
2181 void watch(const cv::String& theWindowName, bool theCreateNamedWindow) {
2182  cvui_context_t aContex;
2183 
2184  if (theCreateNamedWindow) {
2185  cv::namedWindow(theWindowName);
2186  }
2187 
2188  aContex.windowName = theWindowName;
2189  aContex.mouse.position.x = 0;
2190  aContex.mouse.position.y = 0;
2191 
2192  internal::resetMouseButton(aContex.mouse.anyButton);
2193  internal::resetMouseButton(aContex.mouse.buttons[RIGHT_BUTTON]);
2194  internal::resetMouseButton(aContex.mouse.buttons[MIDDLE_BUTTON]);
2195  internal::resetMouseButton(aContex.mouse.buttons[LEFT_BUTTON]);
2196 
2197  internal::gContexts[theWindowName] = aContex;
2198  cv::setMouseCallback(theWindowName, handleMouse, &internal::gContexts[theWindowName]);
2199 }
2200 
2201 void context(const cv::String& theWindowName) {
2202  internal::gCurrentContext = theWindowName;
2203 }
2204 
2205 void imshow(const cv::String& theWindowName, cv::InputArray theFrame) {
2206  cvui::update(theWindowName);
2207  cv::imshow(theWindowName, theFrame);
2208 }
2209 
2210 int lastKeyPressed() {
2211  return internal::gLastKeyPressed;
2212 }
2213 
2214 cv::Point mouse(const cv::String& theWindowName) {
2215  return internal::getContext(theWindowName).mouse.position;
2216 }
2217 
2218 bool mouse(int theQuery) {
2219  return mouse("", theQuery);
2220 }
2221 
2222 bool mouse(const cv::String& theWindowName, int theQuery) {
2223  cvui_mouse_btn_t& aButton = internal::getContext(theWindowName).mouse.anyButton;
2224  bool aRet = internal::isMouseButton(aButton, theQuery);
2225 
2226  return aRet;
2227 }
2228 
2229 bool mouse(int theButton, int theQuery) {
2230  return mouse("", theButton, theQuery);
2231 }
2232 
2233 bool mouse(const cv::String& theWindowName, int theButton, int theQuery) {
2234  if (theButton != RIGHT_BUTTON && theButton != MIDDLE_BUTTON && theButton != LEFT_BUTTON) {
2235  internal::error(6, "Invalid mouse button. Are you using one of the available: cvui::{RIGHT,MIDDLE,LEFT}_BUTTON ?");
2236  }
2237 
2238  cvui_mouse_btn_t& aButton = internal::getContext(theWindowName).mouse.buttons[theButton];
2239  bool aRet = internal::isMouseButton(aButton, theQuery);
2240 
2241  return aRet;
2242 }
2243 
2244 bool button(cv::Mat& theWhere, int theX, int theY, const cv::String& theLabel) {
2245  internal::gScreen.where = theWhere;
2246  return internal::button(internal::gScreen, theX, theY, theLabel);
2247 }
2248 
2249 bool button(cv::Mat& theWhere, int theX, int theY, int theWidth, int theHeight, const cv::String& theLabel) {
2250  internal::gScreen.where = theWhere;
2251  return internal::button(internal::gScreen, theX, theY, theWidth, theHeight, theLabel, true);
2252 }
2253 
2254 bool button(cv::Mat& theWhere, int theX, int theY, cv::Mat& theIdle, cv::Mat& theOver, cv::Mat& theDown) {
2255  internal::gScreen.where = theWhere;
2256  return internal::button(internal::gScreen, theX, theY, theIdle, theOver, theDown, true);
2257 }
2258 
2259 void image(cv::Mat& theWhere, int theX, int theY, cv::Mat& theImage) {
2260  internal::gScreen.where = theWhere;
2261  return internal::image(internal::gScreen, theX, theY, theImage);
2262 }
2263 
2264 bool checkbox(cv::Mat& theWhere, int theX, int theY, const cv::String& theLabel, bool *theState, unsigned int theColor) {
2265  internal::gScreen.where = theWhere;
2266  return internal::checkbox(internal::gScreen, theX, theY, theLabel, theState, theColor);
2267 }
2268 
2269 void text(cv::Mat& theWhere, int theX, int theY, const cv::String& theText, double theFontScale, unsigned int theColor) {
2270  internal::gScreen.where = theWhere;
2271  internal::text(internal::gScreen, theX, theY, theText, theFontScale, theColor, true);
2272 }
2273 
2274 void printf(cv::Mat& theWhere, int theX, int theY, double theFontScale, unsigned int theColor, const char *theFmt, ...) {
2275  va_list aArgs;
2276 
2277  va_start(aArgs, theFmt);
2278  vsprintf_s(internal::gBuffer, theFmt, aArgs);
2279  va_end(aArgs);
2280 
2281  internal::gScreen.where = theWhere;
2282  internal::text(internal::gScreen, theX, theY, internal::gBuffer, theFontScale, theColor, true);
2283 }
2284 
2285 void printf(cv::Mat& theWhere, int theX, int theY, const char *theFmt, ...) {
2286  va_list aArgs;
2287 
2288  va_start(aArgs, theFmt);
2289  vsprintf_s(internal::gBuffer, theFmt, aArgs);
2290  va_end(aArgs);
2291 
2292  internal::gScreen.where = theWhere;
2293  internal::text(internal::gScreen, theX, theY, internal::gBuffer, 0.4, 0xCECECE, true);
2294 }
2295 
2296 int counter(cv::Mat& theWhere, int theX, int theY, int *theValue, int theStep, const char *theFormat) {
2297  internal::gScreen.where = theWhere;
2298  return internal::counter(internal::gScreen, theX, theY, theValue, theStep, theFormat);
2299 }
2300 
2301 double counter(cv::Mat& theWhere, int theX, int theY, double *theValue, double theStep, const char *theFormat) {
2302  internal::gScreen.where = theWhere;
2303  return internal::counter(internal::gScreen, theX, theY, theValue, theStep, theFormat);
2304 }
2305 
2306 void window(cv::Mat& theWhere, int theX, int theY, int theWidth, int theHeight, const cv::String& theTitle) {
2307  internal::gScreen.where = theWhere;
2308  internal::window(internal::gScreen, theX, theY, theWidth, theHeight, theTitle);
2309 }
2310 
2311 void rect(cv::Mat& theWhere, int theX, int theY, int theWidth, int theHeight, unsigned int theBorderColor, unsigned int theFillingColor) {
2312  internal::gScreen.where = theWhere;
2313  internal::rect(internal::gScreen, theX, theY, theWidth, theHeight, theBorderColor, theFillingColor);
2314 }
2315 
2316 void sparkline(cv::Mat& theWhere, std::vector<double>& theValues, int theX, int theY, int theWidth, int theHeight, unsigned int theColor) {
2317  internal::gScreen.where = theWhere;
2318  internal::sparkline(internal::gScreen, theValues, theX, theY, theWidth, theHeight, theColor);
2319 }
2320 
2321 int iarea(int theX, int theY, int theWidth, int theHeight) {
2322  return internal::iarea(theX, theY, theWidth, theHeight);
2323 }
2324 
2325 void beginRow(cv::Mat &theWhere, int theX, int theY, int theWidth, int theHeight, int thePadding) {
2326  internal::begin(ROW, theWhere, theX, theY, theWidth, theHeight, thePadding);
2327 }
2328 
2329 void endRow() {
2330  internal::end(ROW);
2331 }
2332 
2333 void beginColumn(cv::Mat &theWhere, int theX, int theY, int theWidth, int theHeight, int thePadding) {
2334  internal::begin(COLUMN, theWhere, theX, theY, theWidth, theHeight, thePadding);
2335 }
2336 
2337 void endColumn() {
2338  internal::end(COLUMN);
2339 }
2340 
2341 void beginRow(int theWidth, int theHeight, int thePadding) {
2342  cvui_block_t& aBlock = internal::topBlock();
2343  internal::begin(ROW, aBlock.where, aBlock.anchor.x, aBlock.anchor.y, theWidth, theHeight, thePadding);
2344 }
2345 
2346 void beginColumn(int theWidth, int theHeight, int thePadding) {
2347  cvui_block_t& aBlock = internal::topBlock();
2348  internal::begin(COLUMN, aBlock.where, aBlock.anchor.x, aBlock.anchor.y, theWidth, theHeight, thePadding);
2349 }
2350 
2351 void space(int theValue) {
2352  cvui_block_t& aBlock = internal::topBlock();
2353  cv::Size aSize(theValue, theValue);
2354 
2355  internal::updateLayoutFlow(aBlock, aSize);
2356 }
2357 
2358 bool button(const cv::String& theLabel) {
2359  cvui_block_t& aBlock = internal::topBlock();
2360  return internal::button(aBlock, aBlock.anchor.x, aBlock.anchor.y, theLabel);
2361 }
2362 
2363 bool button(int theWidth, int theHeight, const cv::String& theLabel) {
2364  cvui_block_t& aBlock = internal::topBlock();
2365  return internal::button(aBlock, aBlock.anchor.x, aBlock.anchor.y, theWidth, theHeight, theLabel, true);
2366 }
2367 
2368 bool button(cv::Mat& theIdle, cv::Mat& theOver, cv::Mat& theDown) {
2369  cvui_block_t& aBlock = internal::topBlock();
2370  return internal::button(aBlock, aBlock.anchor.x, aBlock.anchor.y, theIdle, theOver, theDown, true);
2371 }
2372 
2373 void image(cv::Mat& theImage) {
2374  cvui_block_t& aBlock = internal::topBlock();
2375  return internal::image(aBlock, aBlock.anchor.x, aBlock.anchor.y, theImage);
2376 }
2377 
2378 bool checkbox(const cv::String& theLabel, bool *theState, unsigned int theColor) {
2379  cvui_block_t& aBlock = internal::topBlock();
2380  return internal::checkbox(aBlock, aBlock.anchor.x, aBlock.anchor.y, theLabel, theState, theColor);
2381 }
2382 
2383 void text(const cv::String& theText, double theFontScale, unsigned int theColor) {
2384  cvui_block_t& aBlock = internal::topBlock();
2385  internal::text(aBlock, aBlock.anchor.x, aBlock.anchor.y, theText, theFontScale, theColor, true);
2386 }
2387 
2388 void printf(double theFontScale, unsigned int theColor, const char *theFmt, ...) {
2389  cvui_block_t& aBlock = internal::topBlock();
2390  va_list aArgs;
2391 
2392  va_start(aArgs, theFmt);
2393  vsprintf_s(internal::gBuffer, theFmt, aArgs);
2394  va_end(aArgs);
2395 
2396  internal::text(aBlock, aBlock.anchor.x, aBlock.anchor.y, internal::gBuffer, theFontScale, theColor, true);
2397 }
2398 
2399 void printf(const char *theFmt, ...) {
2400  cvui_block_t& aBlock = internal::topBlock();
2401  va_list aArgs;
2402 
2403  va_start(aArgs, theFmt);
2404  vsprintf_s(internal::gBuffer, theFmt, aArgs);
2405  va_end(aArgs);
2406 
2407  internal::text(aBlock, aBlock.anchor.x, aBlock.anchor.y, internal::gBuffer, 0.4, 0xCECECE, true);
2408 }
2409 
2410 int counter(int *theValue, int theStep, const char *theFormat) {
2411  cvui_block_t& aBlock = internal::topBlock();
2412  return internal::counter(aBlock, aBlock.anchor.x, aBlock.anchor.y, theValue, theStep, theFormat);
2413 }
2414 
2415 double counter(double *theValue, double theStep, const char *theFormat) {
2416  cvui_block_t& aBlock = internal::topBlock();
2417  return internal::counter(aBlock, aBlock.anchor.x, aBlock.anchor.y, theValue, theStep, theFormat);
2418 }
2419 
2420 void window(int theWidth, int theHeight, const cv::String& theTitle) {
2421  cvui_block_t& aBlock = internal::topBlock();
2422  internal::window(aBlock, aBlock.anchor.x, aBlock.anchor.y, theWidth, theHeight, theTitle);
2423 }
2424 
2425 void rect(int theWidth, int theHeight, unsigned int theBorderColor, unsigned int theFillingColor) {
2426  cvui_block_t& aBlock = internal::topBlock();
2427  internal::rect(aBlock, aBlock.anchor.x, aBlock.anchor.y, theWidth, theHeight, theBorderColor, theFillingColor);
2428 }
2429 
2430 void sparkline(std::vector<double>& theValues, int theWidth, int theHeight, unsigned int theColor) {
2431  cvui_block_t& aBlock = internal::topBlock();
2432  internal::sparkline(aBlock, theValues, aBlock.anchor.x, aBlock.anchor.y, theWidth, theHeight, theColor);
2433 }
2434 
2435 void update(const cv::String& theWindowName) {
2436  cvui_context_t& aContext = internal::getContext(theWindowName);
2437 
2438  aContext.mouse.anyButton.justReleased = false;
2439  aContext.mouse.anyButton.justPressed = false;
2440 
2441  for (int i = cvui::LEFT_BUTTON; i <= cvui::RIGHT_BUTTON; i++) {
2442  aContext.mouse.buttons[i].justReleased = false;
2443  aContext.mouse.buttons[i].justPressed = false;
2444  }
2445 
2446  internal::resetRenderingBuffer(internal::gScreen);
2447 
2448  // If we were told to keep track of the keyboard shortcuts, we
2449  // proceed to handle opencv event queue.
2450  if (internal::gDelayWaitKey > 0) {
2451  internal::gLastKeyPressed = cv::waitKey(internal::gDelayWaitKey);
2452  }
2453 
2454  if (!internal::blockStackEmpty()) {
2455  internal::error(2, "Calling update() before finishing all begin*()/end*() calls. Did you forget to call a begin*() or an end*()? Check if every begin*() has an appropriate end*() call before you call update().");
2456  }
2457 }
2458 
2459 void handleMouse(int theEvent, int theX, int theY, int theFlags, void* theData) {
2460  int aButtons[3] = { cvui::LEFT_BUTTON, cvui::MIDDLE_BUTTON, cvui::RIGHT_BUTTON };
2461  int aEventsDown[3] = { cv::EVENT_LBUTTONDOWN, cv::EVENT_MBUTTONDOWN, cv::EVENT_RBUTTONDOWN };
2462  int aEventsUp[3] = { cv::EVENT_LBUTTONUP, cv::EVENT_MBUTTONUP, cv::EVENT_RBUTTONUP };
2463 
2464  cvui_context_t *aContext = (cvui_context_t *)theData;
2465 
2466  for (int i = 0; i < 3; i++) {
2467  int aBtn = aButtons[i];
2468 
2469  if (theEvent == aEventsDown[i]) {
2470  aContext->mouse.anyButton.justPressed = true;
2471  aContext->mouse.anyButton.pressed = true;
2472  aContext->mouse.buttons[aBtn].justPressed = true;
2473  aContext->mouse.buttons[aBtn].pressed = true;
2474 
2475  } else if (theEvent == aEventsUp[i]) {
2476  aContext->mouse.anyButton.justReleased = true;
2477  aContext->mouse.anyButton.pressed = false;
2478  aContext->mouse.buttons[aBtn].justReleased = true;
2479  aContext->mouse.buttons[aBtn].pressed = false;
2480  }
2481  }
2482 
2483  aContext->mouse.position.x = theX;
2484  aContext->mouse.position.y = theY;
2485 }
2486 
2487 } // namespace cvui
2488 
2489 /******************************************************************************/
2490 
2491 // customized part of the library, wrapping cvui in "cvuiw" and
2492 // implementing a custom "radioButtons()" function to draw and
2493 // handle radiobutton-like object, by means of the elements already
2494 // available in the original cvui.h
2495 
2496 const int MAX_RADIO_BUTTONS = 10;
2497 const int TRACKBAR_WIDTH = 300;
2498 const int TRACKBAR_OFFSET = 45;
2499 const int RADIOBUTTON_OFFSET = 30;
2500 const int BUTTON_OFFSET = 40;
2501 
2502 namespace cvuiw {
2503 
2504  typedef struct {
2505 
2506  bool * prev_states;
2507  bool * states;
2508 
2509  } radioStates;
2510 
2511  std::vector<radioStates> radio_states(MAX_RADIO_BUTTONS);
2512  int cur_radio = 0;
2513  int cur_trackbar = 0;
2514  int cur_button_lines = 0;
2515 
2516  template <class T> T radioToValue(bool * states, std::vector<T> values)
2517  {
2518  for(int i = 0; i < values.size(); i++)
2519  if(states[i])
2520  return values.at(i);
2521 
2522  throw "No state found as bool in cvui::radiobutton()!";
2523  }
2524 
2525  template <class T> int radioToIndex(bool * states, std::vector<T> values)
2526  {
2527  for(int i = 0; i < values.size(); i++)
2528  if(states[i])
2529  return i;
2530 
2531  throw "No state found as bool in cvui::radiobutton()!";
2532  }
2533 
2534  bool * prev_states = NULL;
2535 
2536  int getLastRadioIndex()
2537  {
2538  for(int i = 0; ; i++)
2539  if(radio_states.at(cur_radio-1).states[i])
2540  return i;
2541 
2542  return -1;
2543  }
2544 
2545  int getRadioIndex(int ind)
2546  {
2547  for(int i = 0; ; i++)
2548  if(radio_states.at(ind).states[i])
2549  return i;
2550 
2551  return -1;
2552  }
2553 
2554 
2555  bool radioButtons(cv::Mat frame, std::string name, const std::vector<std::string> names, const std::vector<int> X, int default_value)
2556  {
2557 
2558  int selected = -1;
2559 
2560  // if this radiobutton states have
2561  // not been initialized yet, does it
2562 
2563  if(radio_states.at(cur_radio).states == NULL)
2564  {
2565 
2566  radio_states.at(cur_radio).states = new bool[names.size()];
2567  radio_states.at(cur_radio).prev_states = new bool[names.size()];
2568 
2569  for(int i = 0; i < names.size(); i++)
2570  {
2571  radio_states.at(cur_radio).states[i] = false;
2572  radio_states.at(cur_radio).prev_states[i] = false;
2573  }
2574 
2575  radio_states.at(cur_radio).states[default_value] = true;
2576  radio_states.at(cur_radio).prev_states[default_value] = true;
2577 
2578  }
2579 
2580  cvui::text(frame, 10, 23 + TRACKBAR_OFFSET*cur_trackbar + RADIOBUTTON_OFFSET*cur_radio + BUTTON_OFFSET*cur_button_lines, name);
2581 
2582  for(int i = 0; i < names.size(); i++)
2583  radio_states.at(cur_radio).states[i] = cvui::checkbox(frame, 130 + X.at(i), 21 + TRACKBAR_OFFSET*cur_trackbar + RADIOBUTTON_OFFSET*cur_radio + BUTTON_OFFSET*cur_button_lines, names.at(i), &radio_states.at(cur_radio).states[i]);
2584 
2585  for(int i = 0; i < names.size(); i++)
2586  if(!radio_states.at(cur_radio).prev_states[i] && radio_states.at(cur_radio).states[i])
2587  {
2588  selected = i;
2589  break;
2590  }
2591 
2592  if(selected != -1)
2593  {
2594  for(int i = 0; i < names.size(); i++)
2595  radio_states.at(cur_radio).states[i] = false;
2596 
2597  radio_states.at(cur_radio).states[selected] = true;
2598 
2599  for(int i = 0; i < names.size(); i++)
2600  radio_states.at(cur_radio).prev_states[i] = radio_states.at(cur_radio).states[i];
2601 
2602  }
2603  else
2604  {
2605  for(int i = 0; i < names.size(); i++)
2606  radio_states.at(cur_radio).states[i] = radio_states.at(cur_radio).prev_states[i];
2607  }
2608 
2609  cur_radio++;
2610 
2611  return selected != -1;
2612  }
2613 
2614  template <class T> bool trackbar(const char * theName, cv::Mat &theWhere, T *theValue, T theMin, T theMax, int theSegments = 1, const char *theLabelFormat = "%.1Lf", unsigned int theOptions = 0, T theDiscreteStep = 1)
2615  {
2616 
2617  bool status = cvui::trackbar(theWhere, 0, 5+TRACKBAR_OFFSET*cur_trackbar + RADIOBUTTON_OFFSET*cur_radio + BUTTON_OFFSET*cur_button_lines, TRACKBAR_WIDTH, theValue, theMin, theMax, theSegments, theLabelFormat, theOptions, theDiscreteStep);
2618  cvui::text(theWhere, 295, 21+TRACKBAR_OFFSET*cur_trackbar + RADIOBUTTON_OFFSET*cur_radio + BUTTON_OFFSET*cur_button_lines, theName);
2619 
2620  cur_trackbar++;
2621 
2622  return status;
2623 
2624  }
2625 
2626  bool button(cv::Mat theWhere, std::string label, int theX, int button_line)
2627  {
2628 
2629  if(button_line >= cur_button_lines)
2630  cur_button_lines++;
2631 
2632  int button_height = TRACKBAR_OFFSET*cur_trackbar + RADIOBUTTON_OFFSET*cur_radio + BUTTON_OFFSET*button_line + 20;
2633  return cvui::button(theWhere, theX, button_height, label);
2634  }
2635 
2636  void reset()
2637  {
2638  cur_radio = 0;
2639  cur_trackbar = 0;
2640  cur_button_lines = 0;
2641  }
2642 
2643  int estimateHeight(int trackbars, int radioButtons, int button_lines)
2644  {
2645  return TRACKBAR_OFFSET*trackbars + RADIOBUTTON_OFFSET*radioButtons + BUTTON_OFFSET*button_lines + 20;
2646  }
2647 
2648 } // namespace cvuiw
2649 
2650 
2651 // Final adjustments that are platform-dependent
2652 #ifdef _MSC_VER
2653  // Check if we salved the definitions of min and max, which could have
2654  // been defined by windows.h. If that is the case, we have undef'd
2655  // them at the begining of this file, so we need to restore the existing
2656  // macros now. We want to do good, not make world burn. You're welcome.
2657  #ifdef __cvui_min
2658  #define min __cvui_min
2659  #endif
2660  #ifdef __cvui_max
2661  #define max __cvui_max
2662  #endif
2663 #endif
2664 
2665 //#endif // CVUI_IMPLEMENTATION