Skip to content

Commit 339dba4

Browse files
committed
feat(cli): --size flag for initial window size
1 parent 7a2d92b commit 339dba4

File tree

1 file changed

+48
-7
lines changed

1 file changed

+48
-7
lines changed

src/main.cpp

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
# include <GLFW/glfw3native.h>
3333
#endif
3434

35+
#include <charconv>
3536
#include <iostream>
3637
#include <thread>
3738

@@ -58,6 +59,18 @@ void redrawWindow() {
5859
}
5960
}
6061

62+
// Stricter version of from_chars that only returns true if the entire input was consumed and no error occurred.
63+
template <typename T> bool fromChars(const char* begin, const char* end, T&& value) {
64+
const auto result = std::from_chars(begin, end, value);
65+
return result.ec == std::errc{} && result.ptr == end;
66+
}
67+
68+
template <typename T> bool fromChars(string_view s, T&& value) { return fromChars(s.data(), s.data() + s.size(), std::forward<T>(value)); }
69+
70+
template <typename T> bool fromChars(const string& s, T&& value) {
71+
return fromChars(s.data(), s.data() + s.size(), std::forward<T>(value));
72+
}
73+
6174
static void handleIpcPacket(const IpcPacket& packet, const std::shared_ptr<BackgroundImagesLoader>& imagesLoader) {
6275
switch (packet.type()) {
6376
case IpcPacket::OpenImage:
@@ -309,6 +322,14 @@ static int mainFunc(span<const string> arguments) {
309322
{'p', "play"},
310323
};
311324

325+
ValueFlag<string> sizeFlag{
326+
parser,
327+
"SIZE",
328+
"Initial size of the tev window as <width>x<height>. "
329+
"Default is 1024x800.",
330+
{"size"},
331+
};
332+
312333
ValueFlag<string> tonemapFlag{
313334
parser,
314335
"TONEMAP",
@@ -581,7 +602,26 @@ static int mainFunc(span<const string> arguments) {
581602
return -3;
582603
}
583604

584-
const nanogui::Vector2i size = {1024, 800};
605+
nanogui::Vector2i size = {1024, 800};
606+
if (sizeFlag) {
607+
const string sizeString = get(sizeFlag);
608+
const auto parts = split(sizeString, "x");
609+
if (parts.size() != 2) {
610+
tlog::error() << fmt::format("Invalid size specification '{}'. Must be of the form <width>x<height>.", sizeString);
611+
return -4;
612+
}
613+
614+
if (!fromChars(parts[0], size.x()) || !fromChars(parts[1], size.y())) {
615+
tlog::error() << fmt::format("Invalid size specification '{}'. Must be of the form <width>x<height>.", sizeString);
616+
return -4;
617+
}
618+
619+
if (size.x() <= 0 || size.y() <= 0) {
620+
tlog::error() << fmt::format("Invalid size specification '{}'. Width and height must be positive.", sizeString);
621+
return -4;
622+
}
623+
}
624+
585625
if (!maximize) {
586626
// Wait until the first image is loaded before creating the window such that it can size itself appropriately. We can not pass the
587627
// Window a size right away, because we don't have information about the user's monitor size or DPI scaling yet, hence `size` stays
@@ -650,17 +690,18 @@ static int mainFunc(span<const string> arguments) {
650690
}
651691

652692
if (whiteLevelFlag) {
653-
if (get(whiteLevelFlag) == "image") {
693+
const string wlValue = get(whiteLevelFlag);
694+
if (toLower(wlValue) == "image") {
654695
sImageViewer->setDisplayWhiteLevelSetting(ImageViewer::EDisplayWhiteLevelSetting::ImageMetadata);
655696
} else {
656-
try {
657-
const float whiteLevel = stof(get(whiteLevelFlag));
658-
sImageViewer->setDisplayWhiteLevelSetting(ImageViewer::EDisplayWhiteLevelSetting::Custom);
659-
sImageViewer->setDisplayWhiteLevel(whiteLevel);
660-
} catch (const invalid_argument&) {
697+
float whiteLevel = 0.0f;
698+
if (!fromChars(wlValue, whiteLevel)) {
661699
tlog::error() << fmt::format("Invalid white level value '{}'. Must be a float or 'image'.", get(whiteLevelFlag));
662700
return -4;
663701
}
702+
703+
sImageViewer->setDisplayWhiteLevelSetting(ImageViewer::EDisplayWhiteLevelSetting::Custom);
704+
sImageViewer->setDisplayWhiteLevel(whiteLevel);
664705
}
665706
}
666707

0 commit comments

Comments
 (0)