Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
cuteLib-hsrt
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Deploy
Releases
Package registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Tobias Glaser
cuteLib-hsrt
Commits
7747f99e
Commit
7747f99e
authored
1 month ago
by
tobiglaser
Browse files
Options
Downloads
Patches
Plain Diff
added Doxxygen comments
parent
da6392dd
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
include/cute.h
+54
-33
54 additions, 33 deletions
include/cute.h
src/control.cpp
+172
-1
172 additions, 1 deletion
src/control.cpp
with
226 additions
and
34 deletions
include/cute.h
+
54
−
33
View file @
7747f99e
...
...
@@ -10,11 +10,16 @@
namespace
cute
{
struct
Point
struct
Point
///< Representation of a Point in 2D-Space used by this library.
{
float
x
;
float
y
;
};
/**
* @brief This enum can be used to set different levels of detail in your plotting.
* They are in ascending order, so you can do if(verbosity() >= result).
*/
enum
Verbosity
{
silent
,
...
...
@@ -23,11 +28,19 @@ namespace cute
verbose
,
all
};
enum
Scale
enum
Scale
///< Representing different axis scalings.
{
linear
,
logarithmic
};
/**
* @brief Representation of RGB colors used when drawing points and lines.
* For the Transparency, 0 is fully visible, 255 is unvisible.
* Think of it as the inverse of the alpha in RGBA.all
* @todo This should just be Alpha, shouldn't it?
*/
struct
Color
{
uint8_t
red
;
...
...
@@ -35,7 +48,8 @@ namespace cute
uint8_t
blue
;
uint8_t
transparency
;
};
enum
LineStyle
enum
LineStyle
///< Different possibilities to draw your lines.
{
none
,
solid
,
...
...
@@ -44,41 +58,44 @@ namespace cute
dashDot
,
DashDotDot
};
enum
Shape
enum
Shape
///< Draw your Points as circles or rectangles.
{
circle
,
rectangle
};
namespace
Colors
namespace
Colors
///< A collection of Color presets. Not exhaustive, try them, change them, suggest other ones.
{
constexpr
Color
none
=
{
0
,
0
,
0
,
0xFF
};
constexpr
Color
white
=
{
0xFF
,
0xFF
,
0xFF
,
0
};
constexpr
Color
black
=
{
0
,
0
,
0
,
0
};
constexpr
Color
red
=
{
0xFF
,
0
,
0
,
0
};
constexpr
Color
darkRed
=
{
0x80
,
0
,
0
,
0
};
constexpr
Color
green
=
{
0
,
0xFF
,
0
,
0
};
constexpr
Color
darkGreen
=
{
0
,
0x80
,
0
,
0
};
constexpr
Color
blue
=
{
0
,
0
,
0xFF
,
0
};
constexpr
Color
darkBlue
=
{
0
,
0
,
0x80
,
0
};
constexpr
Color
cyan
=
{
0
,
0xFF
,
0xFF
,
0
};
constexpr
Color
darkCyan
=
{
0
,
0x80
,
0x80
,
0
};
constexpr
Color
magenta
=
{
0xFF
,
0
,
0xFF
,
0
};
constexpr
Color
darkMagenta
=
{
0x80
,
0
,
0x80
,
0
};
constexpr
Color
yellow
=
{
0xFF
,
0xFF
,
0
,
0
};
constexpr
Color
darkYellow
=
{
0x80
,
0x80
,
0
,
0
};
constexpr
Color
gray
=
{
0xA0
,
0xA0
,
0xA4
,
0
};
constexpr
Color
darkGray
=
{
0x80
,
0x80
,
0x80
,
0
};
constexpr
Color
lightGray
=
{
0xC0
,
0xC0
,
0xC0
,
0
};
constexpr
Color
none
=
{
0
,
0
,
0
,
0xFF
};
///< {0, 0, 0, 0xFF}
constexpr
Color
white
=
{
0xFF
,
0xFF
,
0xFF
,
0
};
///< {0xFF, 0xFF, 0xFF, 0}
constexpr
Color
black
=
{
0
,
0
,
0
,
0
};
///< {0, 0, 0, 0}
constexpr
Color
red
=
{
0xFF
,
0
,
0
,
0
};
///< {0xFF, 0, 0, 0}
constexpr
Color
darkRed
=
{
0x80
,
0
,
0
,
0
};
///< {0x80, 0, 0, 0}
constexpr
Color
green
=
{
0
,
0xFF
,
0
,
0
};
///< {0, 0xFF, 0, 0}
constexpr
Color
darkGreen
=
{
0
,
0x80
,
0
,
0
};
///< {0, 0x80, 0, 0}
constexpr
Color
blue
=
{
0
,
0
,
0xFF
,
0
};
///< {0, 0, 0xFF, 0}
constexpr
Color
darkBlue
=
{
0
,
0
,
0x80
,
0
};
///< {0, 0, 0x80, 0}
constexpr
Color
cyan
=
{
0
,
0xFF
,
0xFF
,
0
};
///< {0, 0xFF, 0xFF, 0}
constexpr
Color
darkCyan
=
{
0
,
0x80
,
0x80
,
0
};
///< {0, 0x80, 0x80, 0}
constexpr
Color
magenta
=
{
0xFF
,
0
,
0xFF
,
0
};
///< {0xFF, 0, 0xFF, 0}
constexpr
Color
darkMagenta
=
{
0x80
,
0
,
0x80
,
0
};
///< {0x80, 0, 0x80, 0}
constexpr
Color
yellow
=
{
0xFF
,
0xFF
,
0
,
0
};
///< {0xFF, 0xFF, 0, 0}
constexpr
Color
darkYellow
=
{
0x80
,
0x80
,
0
,
0
};
///< {0x80, 0x80, 0, 0}
constexpr
Color
gray
=
{
0xA0
,
0xA0
,
0xA4
,
0
};
///< {0xA0, 0xA0, 0xA4, 0}
constexpr
Color
darkGray
=
{
0x80
,
0x80
,
0x80
,
0
};
///< {0x80, 0x80, 0x80, 0}
constexpr
Color
lightGray
=
{
0xC0
,
0xC0
,
0xC0
,
0
};
///< {0xC0, 0xC0, 0xC0, 0}
}
// namespace Colors
struct
PlotProperties
struct
PlotProperties
///< A structure to bundle all the possibilities to infuelce how your Data should be plotted.
{
std
::
string
name
=
""
;
int
size
=
10
;
Color
color
=
Colors
::
none
;
LineStyle
line
=
solid
;
bool
onTop
=
false
;
bool
legend
=
true
;
Shape
shape
=
circle
;
std
::
string
name
=
""
;
///< The name displayed in the Legend. An empty name will cause it not to be displayed.
int
size
=
10
;
///< The diameter of points and the width of lines. No fix unit sadly, adjust yourself.
Color
color
=
Colors
::
none
;
///< The color of what you want plotted. The default value none will have a color chosen at random.
LineStyle
line
=
solid
;
///< The style, you want lines to be drawn in.
bool
onTop
=
false
;
///< Wether that Data should always be displayed above other data. So you dont have to redraw points manually all the time.
bool
legend
=
true
;
///< Whether you want the data to show up in the legend.
Shape
shape
=
circle
;
///< The shape you want points to have.
};
void
DYNAMIC
setPlotVisible
(
int
plot
,
bool
visible
=
true
);
void
DYNAMIC
setPlotTitle
(
int
plot
,
const
std
::
string
&
title
);
...
...
@@ -132,15 +149,19 @@ namespace cute
std
::
chrono
::
microseconds
DYNAMIC
timerResult
();
/**
* @brief This is only here to facilitate loading and unloading functions, loaded dynamically from a .dll.
* @todo With the current approach or with static libraries, this is unneccessary.
*/
namespace
core
{
// These are for loading and unloading libcute.dll at runtime
#if !defined(RUNTIME_LOAD) and !defined(EXPORT_CUTE)
inline
int
initialize
()
inline
int
initialize
()
///< In case of not loading at runtime and importing cute as the User, do nothing.
{
return
0
;
}
inline
void
shutdown
()
{}
inline
void
shutdown
()
{}
///< In case of not loading at runtime and importing cute as the User, do nothing.
#else
int
initialize
();
void
shutdown
();
...
...
This diff is collapsed.
Click to expand it.
src/control.cpp
+
172
−
1
View file @
7747f99e
...
...
@@ -21,7 +21,10 @@
#include
<random>
#include
<variant>
/**
* @brief Most connections, hopefully all that are more sophisticated than just visuals or inside other Objects
* If something isn't working, you likely forgot to establish the connection here.
*/
void
Control
::
makeConnections
()
{
CuteControl
*
cc
=
&
CuteControl
::
get
();
...
...
@@ -57,6 +60,19 @@ void Control::makeConnections()
&
CuteControl
::
changeVerbosity
);
}
/**
* @brief Blocking. Does setup and starts the Application.
* This is the equivalent to the classic minimal main() function of a Qt Widget App.
* MainWindow and QApplication are created, Control's connections established.
* Afterwards the Users setup() is called, so that all functionality is available.
* QApplication::exec() is blocking, so just before that, in the case of autorun being set,
* the appropriate thread is started.
* This works fine, because QApplications event queue is already created on construction,
* and will only processed on execution.
*
* @param userSetup Pointer to the User implemented Setup function.
* @return int return value of QApplication::exec() or -1 if called before exiting.
*/
int
Control
::
run
(
void
(
*
userSetup
)())
{
static
bool
running
=
false
;
...
...
@@ -83,6 +99,12 @@ int Control::run(void (*userSetup)())
return
-
1
;
}
/**
* @brief Construct a new Control::Control object
* Here, in a not at all dynamic way, the vectors for processing plot commands
* are created.
* @todo This really should not be hardcoded.
*/
Control
::
Control
()
{
onTopSeries
.
emplace_back
();
...
...
@@ -93,42 +115,99 @@ Control::Control()
plotHistory
.
emplace_back
();
}
/**
* @brief Appends a QString to MainWindows logging Area / textEdit.
*
* @param message The message to be appended.
*/
void
Control
::
logMessage
(
const
QString
message
)
{
w
->
textEdit
->
append
(
message
);
}
/**
* @brief Sets the status bars progress bar to the given percentage. Only integer values are supported.
*
* @param percentage The Percentage 0 - 100, the processbar should show.
*/
void
Control
::
setProgress
(
int
percentage
)
{
w
->
progressBar
->
setValue
(
percentage
);
}
/**
* @brief Displays the given message in MainWindows status bar for duration_s seconds.
*
* @param message The QString to be displayed.
* @param duration_s Time in seconds, the message should stay. 0 will have the message only disappear when overwritten.
*/
void
Control
::
setStatusMessage
(
const
QString
message
,
int
duration_s
)
{
w
->
statusBar
->
showMessage
(
message
,
duration_s
*
1000
);
}
/**
* @brief Show or hide the given plot
*
* @param plot The number of the plot to be manipulated. Starting from 0 for the left mose plot.
* @param visible Whether to show or hide.
* @todo ensure every graphing widget can hide
*/
void
Control
::
setPlotVisible
(
int
plot
,
bool
visible
)
{
w
->
graphingWidgets
[
plot
]
->
setHidden
(
!
visible
);
}
/**
* @brief Change the given plots title in ChartMenu and in the Plot itself.
* The ChartMenu has a separate memory of the plot titles, so it it can show them without having to look them up,
* which would create complicated dependencies.
* @todo This will break, if other plotting widgets than QChart are added. Most easy thing would likely be,
* to offer setTile() as an interface in the new Widget and adjust the this->charts vector accordingly.
*
* @param plot The number of the plot to be manipulated. Starting from 0 for the left mose plot.
* @param title The new title.
*/
void
Control
::
setPlotTitle
(
int
plot
,
const
QString
title
)
{
w
->
charts
[
plot
]
->
setTitle
(
title
);
w
->
cm
->
titleChanged
(
plot
,
title
);
}
/**
* @brief Instruct the MainWindow to change the given plots theme to one of the themes built into QtCharts
* This will affect all and only QCharts.
*
* @param themeNumber 0-7 are valid.
*/
void
Control
::
setPlotTheme
(
int
themeNumber
)
{
w
->
changeChartTheme
(
themeNumber
);
}
/**
* @brief Whether the legend should be shown or hidden
*
* @param plot The number of the plot to be manipulated. Starting from 0 for the left mose plot.
* @param visible Whether to show or hide.
* @todo dynamic graphs...
*/
void
Control
::
setLegendVisible
(
int
plot
,
bool
visible
)
{
w
->
charts
[
plot
]
->
legend
()
->
setVisible
(
visible
);
}
/**
* @brief Applies the given Titles to the axes of that plot. Hides the Title if empty.
* Manipulating the axes is a bit tedious, since we can only get a list of all axes from the chart.
* We then have to check it's properties to find the orientation.
*
* @param plot The plot to be manipulated.
* @param x Title for the x-axis.
* @param y Title for the y-axis.
* @todo dynamic graphs...
*/
void
Control
::
setAxisTitles
(
int
plot
,
QString
x
,
QString
y
)
{
if
((
size_t
)
plot
>=
w
->
charts
.
size
())
...
...
@@ -149,6 +228,14 @@ void Control::setAxisTitles(int plot, QString x, QString y)
}
}
/**
* @brief Show or hide the given plots axes.
*
* @param plot The plot to be manipulated.
* @param x Wether the x-axis should be visible.
* @param y Wether the y-axis should be visible.
* @todo dynamic graphs...
*/
void
Control
::
setAxisVisible
(
int
plot
,
bool
x
,
bool
y
)
{
if
((
size_t
)
plot
>=
w
->
charts
.
size
())
...
...
@@ -167,12 +254,25 @@ void Control::setAxisVisible(int plot, bool x, bool y)
}
}
/**
* @brief Add or "register" the given function to the Application
* The same order in both locations is crutial,
* as the index will be used to choose the threads function.
* @param func The function pointer to be called by the AlgoThread.
* @param name The name to be displayed in the ConfigPanels QCombobox algoBox.
*/
void
Control
::
registerAlgorithm
(
void
(
*
func
)(),
const
QString
name
)
{
algorithms
.
emplace_back
(
func
,
name
);
w
->
addAlgorithm
(
name
);
}
/**
* @brief To be called when the AlgoThread should end before the Algorithm has ended.
* This will simply emit a signal to the AlgoThread, that it may please terminate.
* The User is responsible for running AlgoThread event loop and cleanly ending their function.
* cute::ok() is provided for that purpose.
*/
void
Control
::
stopThread
()
{
if
(
thread
)
...
...
@@ -181,6 +281,10 @@ void Control::stopThread()
}
}
/**
* @brief This should be called, when the tread finishes it's execution.abort
* The thread related variables and displays are reset here.
*/
void
Control
::
threadEnded
()
{
threadRunning
=
false
;
...
...
@@ -188,6 +292,18 @@ void Control::threadEnded()
thread
=
nullptr
;
}
/**
* @brief Sets up and starts an AlgoThread.
* A new thread is created and connected such, that when finished, it notifies Control and flags itself for deletion.
* CuteControl is then handed it's problem and the currently set verbosity, so that it can start execution right away.
* Most importantly CuteControl is then moved to the EventQueue of the newly created thread.
* That has to be done, since CuteControl was created in the main thread and thus is hooked into the main EventLoop.
* This can only be done, pushing from the objects current thread, so it has to be moved back by the AlgoThread.
* When the objects are in different threads, the signals are automatically stored and processed in the receivers EventQueue.
* This way, it is thread safe.
*
* @param func The function/algorithm to be executed by the AlgoThread.
*/
void
Control
::
startThread
(
void
(
*
func
)())
{
if
(
!
thread
)
...
...
@@ -207,6 +323,10 @@ void Control::startThread(void (*func)())
}
}
/**
* @brief Depending on if a thread has already been started, either start or stop a thread.
* The appropriate algorithm is determined here from the current selection of the algoBox.
*/
void
Control
::
onRunButton
()
{
if
(
!
thread
)
...
...
@@ -221,18 +341,35 @@ void Control::onRunButton()
}
}
/**
* @brief Change the problem widget stack to random generation and set the given size.
* The setProblem functions only manipulate the entries in the View.abort
* When a problem is to be generated, the necessary information will be pulled from the View.
* @param n The number to be entered into the QSpinBox.
*/
void
Control
::
setProblemSize
(
int
n
)
{
w
->
configPanel
->
stackedWidget
->
setCurrentWidget
(
w
->
configPanel
->
randomWidget
);
w
->
configPanel
->
problemSizeBox
->
setValue
(
n
);
}
/**
* @brief Change the problem widget stack to reading from a file and set the path.
* The setProblem functions only manipulate the entries in the View.abort
* When a problem is to be generated, the necessary information will be pulled from the View.
* @param path The QString to be entered into the QLineEdit. No validity checks are performed here.
*/
void
Control
::
setProblemFile
(
QString
path
)
{
w
->
configPanel
->
stackedWidget
->
setCurrentWidget
(
w
->
configPanel
->
fileWidget
);
w
->
configPanel
->
fileLine
->
setText
(
path
);
}
/**
* @brief Depending of if the problem was locked/retained or not, a new problem is generated or the old problem is used.
*
* @return std::vector<cute::Point> The given Problem. Newly generated if problemRetained was not set.
*/
std
::
vector
<
cute
::
Point
>
Control
::
getProblem
()
{
if
(
!
problemRetained
)
...
...
@@ -242,6 +379,20 @@ std::vector<cute::Point> Control::getProblem()
return
problem
;
}
/**
* @brief Big function, filling the problem member variable with the method selected in the GUI.
* The method depends on the current Widget of the ConfigPanel.
* For random generation, floats with 2 decimal places and to a maximum number of 100 are generated.
* These values are currently hard coded. The amount of numbers is read directly from the GUI.
*
* For reading a file, the CSVParser is used.
* The path is read directly from the GUI.
* Only lines with at least two fields and numbers in the first two fields are read.abort
* Other lines as well as data beyond the second column are simply discarted.
*
* For interpreting pasted or drag'n'dropped data, the CSVParser is used is the same way,
* with the exception of the string being handed to the parser rather than a filepath.
*/
void
Control
::
generateProblem
()
{
problem
.
clear
();
...
...
@@ -304,6 +455,10 @@ void Control::generateProblem()
}
}
/**
* @brief Resets the left most plot (plot0) and plots the problems Points to it.
* @todo getProblem is called here, but is that problem then used by the thread, if it is not locked? UX wise, that would make sense.
*/
void
Control
::
onPreviewButton
()
{
if
(
!
threadRunning
)
...
...
@@ -313,6 +468,12 @@ void Control::onPreviewButton()
}
}
/**
* @brief Depending on the state, set problemRetained and show that in the View, or release them.
* The Problem is not overwritten, so it can be locked again.abort
* In case no problem has been generated before, one is generated.
* Another option would be to just do nothing in that case.
*/
void
Control
::
onLockButton
()
{
if
(
problemRetained
)
...
...
@@ -552,6 +713,11 @@ void Control::resizeAxes(int plot)
}
}
/**
* @brief Remove all series from the plot and the plots history and onTop vectors
* This currently only works with QCharts.
* @param plot The plot to be reset.
*/
void
Control
::
resetPlot
(
int
plot
)
{
w
->
charts
[
plot
]
->
removeAllSeries
();
...
...
@@ -663,6 +829,11 @@ void Control::setPlotScale(int plot, int x, int y)
resizeAxes
(
plot
);
}
/**
* @brief Will write the current problem to a .csv file.
* The path is chosen by the User in a QFileDialog.
* To be called when the Menubars Save Button is clicked.
*/
void
Control
::
saveProblem
()
{
QString
filter
=
"CSV File (*.csv)"
;
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment