Some work on DashboardItems

- Add new DashboardItemText that displays a static text on screen (closes #1423)
 - Add the ability to change the format string to the DashboardItemDate, DashboardItemDistance, and DashboardItemSimulationIncrement
This commit is contained in:
Alexander Bock
2020-12-08 23:44:24 +01:00
parent 63160768d5
commit 8d3bf03db0
13 changed files with 394 additions and 37 deletions

View File

@@ -544,6 +544,8 @@ public:
}
}
std::string dateFromEphemerisTime(double ephemerisTime, const char* format);
/**
* Returns the \p position of a \p target body relative to an \p observer in a
* specific \p referenceFrame, optionally corrected for \p lightTime (planetary

View File

@@ -34,6 +34,7 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditempropertyvalue.h
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemsimulationincrement.h
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemspacing.h
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemtext.h
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemvelocity.h
${CMAKE_CURRENT_SOURCE_DIR}/lightsource/cameralightsource.h
${CMAKE_CURRENT_SOURCE_DIR}/lightsource/scenegraphlightsource.h
@@ -86,6 +87,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditempropertyvalue.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemsimulationincrement.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemspacing.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemtext.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemvelocity.cpp
${CMAKE_CURRENT_SOURCE_DIR}/lightsource/cameralightsource.cpp
${CMAKE_CURRENT_SOURCE_DIR}/lightsource/scenegraphlightsource.cpp

View File

@@ -33,6 +33,7 @@
#include <modules/base/dashboard/dashboarditempropertyvalue.h>
#include <modules/base/dashboard/dashboarditemsimulationincrement.h>
#include <modules/base/dashboard/dashboarditemspacing.h>
#include <modules/base/dashboard/dashboarditemtext.h>
#include <modules/base/dashboard/dashboarditemvelocity.h>
#include <modules/base/lightsource/cameralightsource.h>
#include <modules/base/lightsource/scenegraphlightsource.h>
@@ -120,6 +121,7 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) {
"DashboardItemSimulationIncrement"
);
fDashboard->registerClass<DashboardItemSpacing>("DashboardItemSpacing");
fDashboard->registerClass<DashboardItemText>("DashboardItemText");
fDashboard->registerClass<DashboardItemVelocity>("DashboardItemVelocity");
auto fRenderable = FactoryManager::ref().factory<Renderable>();

View File

@@ -27,10 +27,12 @@
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/timemanager.h>
#include <ghoul/font/font.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/profiling.h>
namespace {
@@ -49,6 +51,22 @@ namespace {
"Font Size",
"This value determines the size of the font that is used to render the date."
};
constexpr openspace::properties::Property::PropertyInfo FormatStringInfo = {
"FormatString",
"Format String",
"The format text describing how this dashboard item renders it's text. This text "
"must contain exactly one {} which is a placeholder that will contain the date"
};
constexpr openspace::properties::Property::PropertyInfo TimeFormatInfo = {
"TimeFormat",
"Time Format",
"The format string used for formatting the date/time before being passed to the "
"string in FormatString. See "
"https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/timout_c.html for full "
"information about how to structure this format"
};
} // namespace
namespace openspace {
@@ -75,6 +93,18 @@ documentation::Documentation DashboardItemDate::Documentation() {
new IntVerifier,
Optional::Yes,
FontSizeInfo.description
},
{
FormatStringInfo.identifier,
new StringVerifier,
Optional::Yes,
FormatStringInfo.description
},
{
TimeFormatInfo.identifier,
new StringVerifier,
Optional::Yes,
TimeFormatInfo.description
}
}
};
@@ -84,6 +114,8 @@ DashboardItemDate::DashboardItemDate(const ghoul::Dictionary& dictionary)
: DashboardItem(dictionary)
, _fontName(FontNameInfo, KeyFontMono)
, _fontSize(FontSizeInfo, DefaultFontSize, 6.f, 144.f, 1.f)
, _formatString(FormatStringInfo, "Date: {} UTC")
, _timeFormat(TimeFormatInfo, "YYYY MON DDTHR:MN:SC.### ::RND")
{
documentation::testSpecificationAndThrow(
Documentation(),
@@ -106,6 +138,16 @@ DashboardItemDate::DashboardItemDate(const ghoul::Dictionary& dictionary)
_font = global::fontManager->font(_fontName, _fontSize);
});
addProperty(_fontSize);
if (dictionary.hasKey(FormatStringInfo.identifier)) {
_formatString = dictionary.value<std::string>(FormatStringInfo.identifier);
}
addProperty(_formatString);
if (dictionary.hasKey(TimeFormatInfo.identifier)) {
_timeFormat = dictionary.value<std::string>(TimeFormatInfo.identifier);
}
addProperty(_timeFormat);
_font = global::fontManager->font(_fontName, _fontSize);
}
@@ -113,20 +155,24 @@ DashboardItemDate::DashboardItemDate(const ghoul::Dictionary& dictionary)
void DashboardItemDate::render(glm::vec2& penPosition) {
ZoneScoped
RenderFont(
*_font,
penPosition,
fmt::format("Date: {} UTC", global::timeManager->time().UTC())
std::string time = SpiceManager::ref().dateFromEphemerisTime(
global::timeManager->time().j2000Seconds(),
_timeFormat.value().c_str()
);
try {
RenderFont(*_font, penPosition, fmt::format(_formatString.value().c_str(), time));
}
catch (const fmt::format_error&) {
LERRORC("DashboardItemDate", "Illegal format string");
}
penPosition.y -= _font->height();
}
glm::vec2 DashboardItemDate::size() const {
ZoneScoped
return _font->boundingBox(
fmt::format("Date: {} UTC", global::timeManager->time().UTC())
);
std::string_view time = global::timeManager->time().UTC();
return _font->boundingBox(fmt::format(_formatString.value().c_str(), time));
}
} // namespace openspace

View File

@@ -50,6 +50,8 @@ public:
private:
properties::StringProperty _fontName;
properties::FloatProperty _fontSize;
properties::StringProperty _formatString;
properties::StringProperty _timeFormat;
std::shared_ptr<ghoul::fontrendering::Font> _font;
};

View File

@@ -101,6 +101,14 @@ namespace {
"to convert the meters into."
};
constexpr openspace::properties::Property::PropertyInfo FormatStringInfo = {
"FormatString",
"Format String",
"The format string that is used for formatting the distance string. This format "
"receives four parameters: The name of the source, the name of the destination "
"the value of the distance and the unit of the distance"
};
std::vector<std::string> unitList() {
std::vector<std::string> res(openspace::DistanceUnits.size());
std::transform(
@@ -179,6 +187,12 @@ documentation::Documentation DashboardItemDistance::Documentation() {
new StringInListVerifier(unitList()),
Optional::Yes,
RequestedUnitInfo.description
},
{
FormatStringInfo.identifier,
new StringVerifier,
Optional::Yes,
FormatStringInfo.description
}
}
};
@@ -206,6 +220,7 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary
properties::StringProperty(DestinationNodeNameInfo),
nullptr
}
, _formatString(FormatStringInfo, "Distance from {} to {}: {:f} {}")
{
documentation::testSpecificationAndThrow(
Documentation(),
@@ -358,6 +373,11 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary
_requestedUnit.setVisibility(properties::Property::Visibility::Hidden);
addProperty(_requestedUnit);
if (dictionary.hasKey(FormatStringInfo.identifier)) {
_formatString = dictionary.value<std::string>(FormatStringInfo.identifier);
}
addProperty(_formatString);
_font = global::fontManager->font(_fontName, _fontSize);
_buffer.resize(256);
@@ -445,14 +465,19 @@ void DashboardItemDistance::render(glm::vec2& penPosition) {
}
std::fill(_buffer.begin(), _buffer.end(), 0);
char* end = fmt::format_to(
_buffer.data(),
"Distance from {} to {}: {:f} {}\0",
sourceInfo.second, destinationInfo.second, dist.first, dist.second
);
try {
char* end = fmt::format_to(
_buffer.data(),
_formatString.value().c_str(),
sourceInfo.second, destinationInfo.second, dist.first, dist.second
);
std::string_view text = std::string_view(_buffer.data(), end - _buffer.data());
RenderFont(*_font, penPosition, text);
std::string_view text = std::string_view(_buffer.data(), end - _buffer.data());
RenderFont(*_font, penPosition, text);
}
catch (const fmt::format_error&) {
LERRORC("DashboardItemDate", "Illegal format string");
}
penPosition.y -= _font->height();
}

View File

@@ -75,6 +75,7 @@ private:
properties::FloatProperty _fontSize;
properties::BoolProperty _doSimplification;
properties::OptionProperty _requestedUnit;
properties::StringProperty _formatString;
Component _source;
Component _destination;

View File

@@ -32,6 +32,7 @@
#include <ghoul/font/font.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/profiling.h>
namespace {
@@ -66,6 +67,26 @@ namespace {
"convert the seconds into."
};
constexpr openspace::properties::Property::PropertyInfo TransitionFormatInfo = {
"TransitionFormat",
"Transition Format",
"Format string used to format the text used while in a delta time transition, "
"that is if the current delta time is being interpolated to reach a target "
"delta time. This format gets five parameters in this order: The target delta "
"time value, the target delta time unit, the string 'Paused' if the delta time "
"is paused or the empty string otherwise, the current delta time value, and the "
"current delta time unit"
};
constexpr openspace::properties::Property::PropertyInfo RegularFormatInfo = {
"RegularFormat",
"Regular Format",
"The format string used to format the text if the target delta time is the same "
"as the current delta time. This format gets three parameters in this order: "
"The target delta value, the target delta unit, and the string 'Paused' if the "
"delta time is paused or the empty string otherwise"
};
std::vector<std::string> unitList() {
std::vector<std::string> res(openspace::TimeUnits.size());
std::transform(
@@ -114,6 +135,18 @@ documentation::Documentation DashboardItemSimulationIncrement::Documentation() {
new StringInListVerifier(unitList()),
Optional::Yes,
RequestedUnitInfo.description
},
{
TransitionFormatInfo.identifier,
new StringVerifier,
Optional::Yes,
TransitionFormatInfo.description
},
{
RegularFormatInfo.identifier,
new StringVerifier,
Optional::Yes,
RegularFormatInfo.description
}
}
};
@@ -126,6 +159,11 @@ DashboardItemSimulationIncrement::DashboardItemSimulationIncrement(
, _fontSize(FontSizeInfo, DefaultFontSize, 6.f, 144.f, 1.f)
, _doSimplification(SimplificationInfo, true)
, _requestedUnit(RequestedUnitInfo, properties::OptionProperty::DisplayType::Dropdown)
, _transitionFormat(
TransitionFormatInfo,
"Simulation increment: {:.1f} {:s} / second{:s} (current: {:.1f} {:s})"
)
, _regularFormat(RegularFormatInfo, "Simulation increment: {:.1f} {:s} / second{:s}")
{
documentation::testSpecificationAndThrow(
Documentation(),
@@ -173,6 +211,19 @@ DashboardItemSimulationIncrement::DashboardItemSimulationIncrement(
_requestedUnit.setVisibility(properties::Property::Visibility::Hidden);
addProperty(_requestedUnit);
if (dictionary.hasKey(TransitionFormatInfo.identifier)) {
_transitionFormat = dictionary.value<std::string>(
TransitionFormatInfo.identifier
);
}
addProperty(_transitionFormat);
if (dictionary.hasKey(RegularFormatInfo.identifier)) {
_regularFormat = dictionary.value<std::string>(RegularFormatInfo.identifier);
}
addProperty(_regularFormat);
_font = global::fontManager->font(_fontName, _fontSize);
}
@@ -203,28 +254,33 @@ void DashboardItemSimulationIncrement::render(glm::vec2& penPosition) {
std::string pauseText = global::timeManager->isPaused() ? " (Paused)" : "";
if (targetDt != currentDt && !global::timeManager->isPaused()) {
// We are in the middle of a transition
RenderFont(
*_font,
penPosition,
fmt::format(
"Simulation increment: {:.1f} {:s} / second{:s} (current: {:.1f} {:s})",
targetDeltaTime.first, targetDeltaTime.second,
pauseText,
currentDeltaTime.first, currentDeltaTime.second
)
);
try {
if (targetDt != currentDt && !global::timeManager->isPaused()) {
// We are in the middle of a transition
RenderFont(
*_font,
penPosition,
fmt::format(
_transitionFormat.value().c_str(),
targetDeltaTime.first, targetDeltaTime.second,
pauseText,
currentDeltaTime.first, currentDeltaTime.second
)
);
}
else {
RenderFont(
*_font,
penPosition,
fmt::format(
_regularFormat.value().c_str(),
targetDeltaTime.first, targetDeltaTime.second, pauseText
)
);
}
}
else {
RenderFont(
*_font,
penPosition,
fmt::format(
"Simulation increment: {:.1f} {:s} / second{:s}",
targetDeltaTime.first, targetDeltaTime.second, pauseText
)
);
catch (const fmt::format_error&) {
LERRORC("DashboardItemDate", "Illegal format string");
}
penPosition.y -= _font->height();
}

View File

@@ -54,6 +54,9 @@ private:
properties::BoolProperty _doSimplification;
properties::OptionProperty _requestedUnit;
properties::StringProperty _transitionFormat;
properties::StringProperty _regularFormat;
std::shared_ptr<ghoul::fontrendering::Font> _font;
};

View File

@@ -0,0 +1,143 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2020 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/base/dashboard/dashboarditemtext.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <ghoul/font/font.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/misc/profiling.h>
namespace {
constexpr const char* KeyFontMono = "Mono";
constexpr const float DefaultFontSize = 10.f;
constexpr openspace::properties::Property::PropertyInfo FontNameInfo = {
"FontName",
"Font Name",
"This value is the name of the font that is used. It can either refer to an "
"internal name registered previously, or it can refer to a path that is used."
};
constexpr openspace::properties::Property::PropertyInfo FontSizeInfo = {
"FontSize",
"Font Size",
"This value determines the size of the font that is used to render the date."
};
constexpr openspace::properties::Property::PropertyInfo TextInfo = {
"Text",
"Text",
"The text to be displayed"
};
} // namespace
namespace openspace {
documentation::Documentation DashboardItemText::Documentation() {
using namespace documentation;
return {
"DashboardItem Text",
"base_dashboarditem_text",
{
{
"Type",
new StringEqualVerifier("DashboardItemText"),
Optional::No
},
{
FontNameInfo.identifier,
new StringVerifier,
Optional::Yes,
FontNameInfo.description
},
{
FontSizeInfo.identifier,
new IntVerifier,
Optional::Yes,
FontSizeInfo.description
},
{
TextInfo.identifier,
new StringVerifier,
Optional::Yes,
TextInfo.description
}
}
};
}
DashboardItemText::DashboardItemText(const ghoul::Dictionary& dictionary)
: DashboardItem(dictionary)
, _fontName(FontNameInfo, KeyFontMono)
, _fontSize(FontSizeInfo, DefaultFontSize, 6.f, 144.f, 1.f)
, _text(TextInfo, "")
{
documentation::testSpecificationAndThrow(
Documentation(),
dictionary,
"DashboardItemText"
);
if (dictionary.hasKey(FontNameInfo.identifier)) {
_fontName = dictionary.value<std::string>(FontNameInfo.identifier);
}
_fontName.onChange([this]() {
_font = global::fontManager->font(_fontName, _fontSize);
});
addProperty(_fontName);
if (dictionary.hasKey(FontSizeInfo.identifier)) {
_fontSize = static_cast<float>(dictionary.value<double>(FontSizeInfo.identifier));
}
_fontSize.onChange([this]() {
_font = global::fontManager->font(_fontName, _fontSize);
});
addProperty(_fontSize);
if (dictionary.hasKey(TextInfo.identifier)) {
_text = dictionary.value<std::string>(TextInfo.identifier);
};
addProperty(_text);
_font = global::fontManager->font(_fontName, _fontSize);
}
void DashboardItemText::render(glm::vec2& penPosition) {
ZoneScoped
RenderFont(*_font, penPosition, _text.value());
penPosition.y -= _font->height();
}
glm::vec2 DashboardItemText::size() const {
ZoneScoped
return _font->boundingBox(_text.value());
}
} // namespace openspace

View File

@@ -0,0 +1,60 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2020 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMTEXT___H__
#define __OPENSPACE_MODULE_BASE___DASHBOARDITEMTEXT___H__
#include <openspace/rendering/dashboarditem.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
namespace ghoul::fontrendering { class Font; }
namespace openspace {
namespace documentation { struct Documentation; }
class DashboardItemText : public DashboardItem {
public:
DashboardItemText(const ghoul::Dictionary& dictionary);
virtual ~DashboardItemText() = default;
void render(glm::vec2& penPosition) override;
glm::vec2 size() const override;
static documentation::Documentation Documentation();
private:
properties::StringProperty _fontName;
properties::FloatProperty _fontSize;
properties::StringProperty _text;
std::shared_ptr<ghoul::fontrendering::Font> _font;
};
} // namespace openspace
#endif // __OPENSPACE_MODULE_BASE___DASHBOARDITEMTEXT___H__

View File

@@ -571,6 +571,22 @@ double SpiceManager::ephemerisTimeFromDate(const char* timeString) const {
return et;
}
std::string SpiceManager::dateFromEphemerisTime(double ephemerisTime, const char* format)
{
char Buffer[128];
std::memset(Buffer, char(0), 128);
timout_c(ephemerisTime, format, 128, Buffer);
if (failed_c()) {
throwSpiceError(fmt::format(
"Error converting ephemeris time '{}' to date with format '{}'",
ephemerisTime, format
));
}
return std::string(Buffer);
}
glm::dvec3 SpiceManager::targetPosition(const std::string& target,
const std::string& observer,
const std::string& referenceFrame,

View File

@@ -97,8 +97,7 @@ std::string_view Time::UTC() const {
std::memset(b, 0, 32);
SpiceManager::ref().dateFromEphemerisTime(_time, b, 32, Format);
return std::string_view(b, 32);
return std::string_view(b);
}
std::string_view Time::ISO8601() const {