Move dropdown button text and icon code to dropdown button class

This commit is contained in:
dec05eba
2024-08-01 18:38:06 +02:00
parent 5d40409fc6
commit 6624db873c
13 changed files with 644 additions and 102 deletions

2
TODO
View File

@@ -9,3 +9,5 @@ Maybe change design to have black triangles appear and get larger until they fil
All of these things should be done with vertex buffer, for real 3D. All of these things should be done with vertex buffer, for real 3D.
DISPLAY gamescope-0 DISPLAY gamescope-0
Colorscheme should follow graphics card in use. On nvidia use nvidia green, on intel use intel blue and on amd use amd red.

66
include/GsrInfo.hpp Normal file
View File

@@ -0,0 +1,66 @@
#pragma once
#include <string>
#include <vector>
#include <mglpp/system/vec.hpp>
namespace gsr {
struct SupportedVideoCodecs {
bool h264 = false;
bool hevc = false;
bool av1 = false;
bool vp8 = false;
bool vp9 = false;
};
struct GsrMonitor {
std::string name;
mgl::vec2i size;
};
struct SupportedCaptureOptions {
bool window = false;
bool focused = false;
bool screen = false;
bool portal = false;
std::vector<GsrMonitor> monitors;
};
enum class DisplayServer {
UNKNOWN,
X11,
WAYLAND
};
struct SystemInfo {
DisplayServer display_server = DisplayServer::UNKNOWN;
};
enum class GpuVendor {
UNKNOWN,
AMD,
INTEL,
NVIDIA
};
struct GpuInfo {
GpuVendor vendor = GpuVendor::UNKNOWN;
};
struct GsrInfo {
SystemInfo system_info;
GpuInfo gpu_info;
SupportedVideoCodecs supported_video_codecs;
SupportedCaptureOptions supported_capture_options;
};
enum class GsrInfoExitStatus {
OK,
FAILED_TO_RUN_COMMAND,
OPENGL_FAILED,
NO_DRM_CARD
};
GsrInfoExitStatus get_gpu_screen_recorder_info(GsrInfo *gsr_info);
}

18
include/Theme.hpp Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include <mglpp/graphics/Color.hpp>
namespace gsr {
struct GsrInfo;
struct Theme {
Theme() = default;
Theme(const Theme&) = delete;
Theme& operator=(const Theme&) = delete;
mgl::Color tint_color = mgl::Color(118, 185, 0);
};
void init_theme(const gsr::GsrInfo &gsr_info);
const Theme& get_theme();
}

View File

@@ -0,0 +1,54 @@
#pragma once
#include "Widget.hpp"
#include <string>
#include <functional>
#include <vector>
#include <mglpp/graphics/Text.hpp>
#include <mglpp/graphics/Sprite.hpp>
namespace gsr {
class DropdownButton : public Widget {
public:
DropdownButton(mgl::Font *title_font, mgl::Font *description_font, const char *title, const char *description_activated, const char *description_deactivated, mgl::Texture *icon_texture, mgl::vec2f size);
DropdownButton(const DropdownButton&) = delete;
DropdownButton& operator=(const DropdownButton&) = delete;
bool on_event(mgl::Event &event, mgl::Window &window) override;
void draw(mgl::Window &window) override;
void add_item(const std::string &text, const std::string &id);
void set_item_label(const std::string &id, const std::string &new_label);
void set_activated(bool activated);
mgl::vec2f get_size();
std::function<void(const std::string &id)> on_click;
private:
void update_if_dirty();
private:
struct Item {
mgl::Text text;
std::string id;
};
std::vector<Item> items;
mgl::Font *title_font;
mgl::Font *description_font;
mgl::vec2f size;
bool mouse_inside = false;
bool show_dropdown = false;
bool dirty = true;
mgl::vec2f max_size;
int mouse_inside_item = -1;
mgl::Text title;
mgl::Text description;
mgl::Sprite icon_sprite;
std::string description_activated;
std::string description_deactivated;
bool activated = false;
};
}

13
include/gui/Utils.hpp Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <mglpp/system/vec.hpp>
#include <mglpp/graphics/Color.hpp>
namespace mgl {
class Window;
}
namespace gsr {
// Inner border
void draw_rectangle_outline(mgl::Window &window, mgl::vec2f pos, mgl::vec2f size, mgl::Color color, float border_size);
}

179
src/GsrInfo.cpp Normal file
View File

@@ -0,0 +1,179 @@
#include "../include/GsrInfo.hpp"
#include <string.h>
#include <functional>
namespace gsr {
using StringSplitCallback = std::function<bool(std::string_view line)>;
static void string_split_char(const std::string &str, char delimiter, StringSplitCallback callback_func) {
size_t index = 0;
while(index < str.size()) {
size_t new_index = str.find(delimiter, index);
if(new_index == std::string::npos)
new_index = str.size();
if(!callback_func({str.data() + index, new_index - index}))
break;
index = new_index + 1;
}
}
static void parse_system_info_line(GsrInfo *gsr_info, const std::string &line) {
const size_t space_index = line.find(' ');
if(space_index == std::string::npos)
return;
const std::string_view attribute_name = {line.c_str(), space_index};
const std::string_view attribute_value = {line.c_str() + space_index + 1, line.size() - (space_index + 1)};
if(attribute_name == "display_server") {
if(attribute_value == "x11")
gsr_info->system_info.display_server = DisplayServer::X11;
else if(attribute_value == "wayland")
gsr_info->system_info.display_server = DisplayServer::WAYLAND;
}
}
static void parse_gpu_info_line(GsrInfo *gsr_info, const std::string &line) {
const size_t space_index = line.find(' ');
if(space_index == std::string::npos)
return;
const std::string_view attribute_name = {line.c_str(), space_index};
const std::string_view attribute_value = {line.c_str() + space_index + 1, line.size() - (space_index + 1)};
if(attribute_name == "vendor") {
if(attribute_value == "amd")
gsr_info->gpu_info.vendor = GpuVendor::AMD;
else if(attribute_value == "intel")
gsr_info->gpu_info.vendor = GpuVendor::INTEL;
else if(attribute_value == "nvidia")
gsr_info->gpu_info.vendor = GpuVendor::NVIDIA;
}
}
static void parse_video_codecs_line(GsrInfo *gsr_info, const std::string &line) {
if(line == "h264")
gsr_info->supported_video_codecs.h264 = true;
else if(line == "hevc")
gsr_info->supported_video_codecs.hevc = true;
else if(line == "av1")
gsr_info->supported_video_codecs.av1 = true;
else if(line == "vp8")
gsr_info->supported_video_codecs.vp8 = true;
else if(line == "vp9")
gsr_info->supported_video_codecs.vp9 = true;
}
static GsrMonitor capture_option_line_to_monitor(const std::string &line) {
size_t space_index = line.find(' ');
if(space_index == std::string::npos)
return { line, {0, 0} };
mgl::vec2i size = {0, 0};
if(sscanf(line.c_str() + space_index + 1, "%dx%d", &size.x, &size.y) != 2)
size = {0, 0};
return { line.substr(0, space_index), size };
}
static void parse_capture_options_line(GsrInfo *gsr_info, const std::string &line) {
if(line == "window")
gsr_info->supported_capture_options.window = true;
else if(line == "focused")
gsr_info->supported_capture_options.focused = true;
else if(line == "screen")
gsr_info->supported_capture_options.screen = true;
else if(line == "portal")
gsr_info->supported_capture_options.portal = true;
else
gsr_info->supported_capture_options.monitors.push_back(capture_option_line_to_monitor(line));
}
enum class GsrInfoSection {
UNKNOWN,
SYSTEM_INFO,
GPU_INFO,
VIDEO_CODECS,
CAPTURE_OPTIONS
};
static bool starts_with(const std::string &str, const char *substr) {
size_t len = strlen(substr);
return str.size() >= len && memcmp(str.data(), substr, len) == 0;
}
GsrInfoExitStatus get_gpu_screen_recorder_info(GsrInfo *gsr_info) {
*gsr_info = GsrInfo{};
FILE *f = popen("gpu-screen-recorder --info", "r");
if(!f) {
fprintf(stderr, "error: 'gpu-screen-recorder --info' failed\n");
return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND;
}
char output[8192];
ssize_t bytes_read = fread(output, 1, sizeof(output) - 1, f);
if(bytes_read < 0 || ferror(f)) {
fprintf(stderr, "error: failed to read 'gpu-screen-recorder --info' output\n");
pclose(f);
return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND;
}
output[bytes_read] = '\0';
GsrInfoSection section = GsrInfoSection::UNKNOWN;
string_split_char(output, '\n', [&](std::string_view line) {
const std::string line_str(line.data(), line.size());
if(starts_with(line_str, "section=")) {
const char *section_name = line_str.c_str() + 8;
if(strcmp(section_name, "system_info") == 0)
section = GsrInfoSection::SYSTEM_INFO;
else if(strcmp(section_name, "gpu_info") == 0)
section = GsrInfoSection::GPU_INFO;
else if(strcmp(section_name, "video_codecs") == 0)
section = GsrInfoSection::VIDEO_CODECS;
else if(strcmp(section_name, "capture_options") == 0)
section = GsrInfoSection::CAPTURE_OPTIONS;
else
section = GsrInfoSection::UNKNOWN;
return true;
}
switch(section) {
case GsrInfoSection::UNKNOWN: {
break;
}
case GsrInfoSection::SYSTEM_INFO: {
parse_system_info_line(gsr_info, line_str);
break;
}
case GsrInfoSection::GPU_INFO: {
parse_gpu_info_line(gsr_info, line_str);
break;
}
case GsrInfoSection::VIDEO_CODECS: {
parse_video_codecs_line(gsr_info, line_str);
break;
}
case GsrInfoSection::CAPTURE_OPTIONS: {
parse_capture_options_line(gsr_info, line_str);
break;
}
}
return true;
});
int status = pclose(f);
if(WIFEXITED(status)) {
switch(WEXITSTATUS(status)) {
case 0: return GsrInfoExitStatus::OK;
case 22: return GsrInfoExitStatus::OPENGL_FAILED;
case 23: return GsrInfoExitStatus::NO_DRM_CARD;
default: return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND;
}
}
return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND;
}
}

34
src/Theme.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include "../include/Theme.hpp"
#include "../include/GsrInfo.hpp"
#include <assert.h>
namespace gsr {
static Theme theme;
static bool initialized = false;
void init_theme(const gsr::GsrInfo &gsr_info) {
switch(gsr_info.gpu_info.vendor) {
case gsr::GpuVendor::UNKNOWN: {
break;
}
case gsr::GpuVendor::AMD: {
theme.tint_color = mgl::Color(221, 0, 49);
break;
}
case gsr::GpuVendor::INTEL: {
theme.tint_color = mgl::Color(8, 109, 183);
break;
}
case gsr::GpuVendor::NVIDIA: {
theme.tint_color = mgl::Color(118, 185, 0);
break;
}
}
initialized = true;
}
const Theme& get_theme() {
assert(initialized);
return theme;
}
}

View File

@@ -1,4 +1,5 @@
#include "../../include/gui/Button.hpp" #include "../../include/gui/Button.hpp"
#include "../../include/Theme.hpp"
#include <mglpp/graphics/Rectangle.hpp> #include <mglpp/graphics/Rectangle.hpp>
#include <mglpp/window/Window.hpp> #include <mglpp/window/Window.hpp>
#include <mglpp/window/Event.hpp> #include <mglpp/window/Event.hpp>
@@ -40,7 +41,7 @@ namespace gsr {
} }
const int border_size = 5; const int border_size = 5;
const mgl::Color border_color(118, 185, 0); const mgl::Color border_color = gsr::get_theme().tint_color;
// Green line at top // Green line at top
{ {

View File

@@ -1,4 +1,6 @@
#include "../../include/gui/ComboBox.hpp" #include "../../include/gui/ComboBox.hpp"
#include "../../include/gui/Utils.hpp"
#include "../../include/Theme.hpp"
#include <mglpp/graphics/Rectangle.hpp> #include <mglpp/graphics/Rectangle.hpp>
#include <mglpp/graphics/Font.hpp> #include <mglpp/graphics/Font.hpp>
#include <mglpp/window/Window.hpp> #include <mglpp/window/Window.hpp>
@@ -46,40 +48,6 @@ namespace gsr {
return true; return true;
} }
static void draw_rectangle_outline(mgl::Window &window, mgl::vec2f pos, mgl::vec2f size, mgl::Color color, float border_size) {
// Green line at top
{
mgl::Rectangle rect({ size.x, border_size });
rect.set_position(pos);
rect.set_color(color);
window.draw(rect);
}
// Green line at bottom
{
mgl::Rectangle rect({ size.x, border_size });
rect.set_position(pos + mgl::vec2f(0.0f, size.y - border_size));
rect.set_color(color);
window.draw(rect);
}
// Green line at left
{
mgl::Rectangle rect({ border_size, size.y - border_size * 2 });
rect.set_position(pos + mgl::vec2f(0, border_size));
rect.set_color(color);
window.draw(rect);
}
// Green line at right
{
mgl::Rectangle rect({ border_size, size.y - border_size * 2 });
rect.set_position(pos + mgl::vec2f(size.x - border_size, border_size));
rect.set_color(color);
window.draw(rect);
}
}
void ComboBox::draw(mgl::Window &window) { void ComboBox::draw(mgl::Window &window) {
update_if_dirty(); update_if_dirty();
@@ -102,10 +70,10 @@ namespace gsr {
mgl::vec2f pos = position + mgl::vec2f(padding_left, padding_top); mgl::vec2f pos = position + mgl::vec2f(padding_left, padding_top);
Item &item = items[selected_item]; Item &item = items[selected_item];
item.text.set_position(pos); item.text.set_position(pos.floor());
if(show_dropdown) { if(show_dropdown) {
const int border_size = 3; const int border_size = 3;
const mgl::Color border_color(118, 185, 0); const mgl::Color border_color = gsr::get_theme().tint_color;
draw_rectangle_outline(window, pos - mgl::vec2f(padding_left, padding_top), item_size, border_color, border_size); draw_rectangle_outline(window, pos - mgl::vec2f(padding_left, padding_top), item_size, border_color, border_size);
} }
window.draw(item.text); window.draw(item.text);
@@ -113,7 +81,7 @@ namespace gsr {
for(size_t i = 0; i < items.size(); ++i) { for(size_t i = 0; i < items.size(); ++i) {
Item &item = items[i]; Item &item = items[i];
item.text.set_position(pos); item.text.set_position(pos.floor());
const mgl::FloatRect text_bounds = item.text.get_bounds(); const mgl::FloatRect text_bounds = item.text.get_bounds();
if(show_dropdown) { if(show_dropdown) {
@@ -121,7 +89,7 @@ namespace gsr {
inside = mgl::FloatRect(text_bounds.position - mgl::vec2f(padding_left, padding_top), item_size).contains({ (float)mouse_pos.x, (float)mouse_pos.y }); inside = mgl::FloatRect(text_bounds.position - mgl::vec2f(padding_left, padding_top), item_size).contains({ (float)mouse_pos.x, (float)mouse_pos.y });
if(inside) { if(inside) {
mgl::Rectangle item_background(text_bounds.position - mgl::vec2f(padding_left, padding_top), item_size); mgl::Rectangle item_background(text_bounds.position - mgl::vec2f(padding_left, padding_top), item_size);
item_background.set_color(mgl::Color(118, 185, 0)); item_background.set_color(gsr::get_theme().tint_color);
window.draw(item_background); window.draw(item_background);
} else { } else {
/*const int border_size = 3; /*const int border_size = 3;

181
src/gui/DropdownButton.cpp Normal file
View File

@@ -0,0 +1,181 @@
#include "../../include/gui/DropdownButton.hpp"
#include "../../include/gui/Utils.hpp"
#include "../../include/Theme.hpp"
#include <mglpp/graphics/Rectangle.hpp>
#include <mglpp/graphics/Texture.hpp>
#include <mglpp/window/Window.hpp>
#include <mglpp/window/Event.hpp>
#include <mglpp/system/FloatRect.hpp>
namespace gsr {
static const float padding_top = 10.0f;
static const float padding_bottom = 10.0f;
static const float padding_left = 10.0f;
static const float padding_right = 10.0f;
static const int border_size = 5;
DropdownButton::DropdownButton(mgl::Font *title_font, mgl::Font *description_font, const char *title, const char *description_activated, const char *description_deactivated, mgl::Texture *icon_texture, mgl::vec2f size) :
title_font(title_font), description_font(description_font), size(size), title(title, *title_font), description(description_deactivated, *description_font),
description_activated(description_activated), description_deactivated(description_deactivated)
{
if(icon_texture && icon_texture->is_valid()) {
icon_sprite.set_texture(icon_texture);
icon_sprite.set_height((int)(size.y * 0.5f));
}
this->description.set_color(mgl::Color(150, 150, 150));
}
bool DropdownButton::on_event(mgl::Event &event, mgl::Window&) {
if(event.type == mgl::Event::MouseMoved) {
const mgl::vec2f collision_margin(1.0f, 1.0f); // Makes sure that multiple buttons that are next to each other wont activate at the same time when the cursor is right between them
const bool inside = mgl::FloatRect(position + collision_margin, size - collision_margin).contains({ (float)event.mouse_move.x, (float)event.mouse_move.y });
if(mouse_inside && !inside) {
mouse_inside = false;
} else if(!mouse_inside && inside) {
mouse_inside = true;
}
} else if(event.type == mgl::Event::MouseButtonPressed) {
const bool clicked_inside = mouse_inside;
show_dropdown = clicked_inside;
if(on_click && mouse_inside_item >= 0 && mouse_inside_item < (int)items.size())
on_click(items[mouse_inside_item].id);
}
return true;
}
void DropdownButton::draw(mgl::Window &window) {
update_if_dirty();
if(show_dropdown) {
// Background
{
mgl::Rectangle rect(size);
rect.set_position(position);
rect.set_color(mgl::Color(0, 0, 0, 255));
window.draw(rect);
}
const mgl::Color border_color = gsr::get_theme().tint_color;
// Green line at top
{
mgl::Rectangle rect({ size.x, border_size });
rect.set_position(position);
rect.set_color(border_color);
window.draw(rect);
}
} else if(mouse_inside) {
// Background
{
mgl::Rectangle rect(size);
rect.set_position(position);
rect.set_color(mgl::Color(0, 0, 0, 255));
window.draw(rect);
}
const mgl::Color border_color = gsr::get_theme().tint_color;
draw_rectangle_outline(window, position, size, border_color, border_size);
} else {
// Background
mgl::Rectangle rect(size);
rect.set_position(position);
rect.set_color(mgl::Color(0, 0, 0, 220));
window.draw(rect);
}
const int text_margin = size.y * 0.085;
const auto title_bounds = title.get_bounds();
title.set_position((position + mgl::vec2f(size.x * 0.5f - title_bounds.size.x * 0.5f, text_margin)).floor());
window.draw(title);
const auto description_bounds = description.get_bounds();
description.set_position((position + mgl::vec2f(size.x * 0.5f - description_bounds.size.x * 0.5f, size.y - description_bounds.size.y - text_margin)).floor());
window.draw(description);
if(icon_sprite.get_texture()->is_valid()) {
icon_sprite.set_position((position + size * 0.5f - icon_sprite.get_size() * 0.5f).floor());
window.draw(icon_sprite);
}
mouse_inside_item = -1;
if(show_dropdown) {
const mgl::vec2i mouse_pos = window.get_mouse_position();
mgl::Rectangle dropdown_bg(max_size);
dropdown_bg.set_position(position + mgl::vec2f(0.0f, size.y));
dropdown_bg.set_color(mgl::Color(0, 0, 0));
window.draw(dropdown_bg);
mgl::vec2f item_position = dropdown_bg.get_position();
for(size_t i = 0; i < items.size(); ++i) {
auto &item = items[i];
const auto text_bounds = item.text.get_bounds();
const float item_height = padding_top + text_bounds.size.y + padding_bottom;
if(mouse_inside_item == -1) {
const mgl::vec2f item_size(max_size.x, item_height);
const bool inside = mgl::FloatRect(item_position, item_size).contains({ (float)mouse_pos.x, (float)mouse_pos.y });
if(inside) {
draw_rectangle_outline(window, item_position, item_size, gsr::get_theme().tint_color, 5);
mouse_inside_item = i;
}
}
item.text.set_position((item_position + mgl::vec2f(padding_left, item_height * 0.5f - text_bounds.size.y * 0.5f)).floor());
window.draw(item.text);
item_position.y += item_height;
}
}
}
void DropdownButton::add_item(const std::string &text, const std::string &id) {
items.push_back({mgl::Text(text, *title_font), id});
dirty = true;
}
void DropdownButton::set_item_label(const std::string &id, const std::string &new_label) {
for(auto &item : items) {
if(item.id == id) {
item.text.set_string(new_label);
dirty = true;
return;
}
}
}
void DropdownButton::set_activated(bool activated) {
if(this->activated == activated)
return;
this->activated = activated;
if(activated) {
description = mgl::Text(description_activated, *description_font);
description.set_color(get_theme().tint_color);
icon_sprite.set_color(get_theme().tint_color);
} else {
description = mgl::Text(description_deactivated, *description_font);
description.set_color(mgl::Color(150, 150, 150));
icon_sprite.set_color(mgl::Color(255, 255, 255));
}
}
void DropdownButton::update_if_dirty() {
if(!dirty)
return;
max_size = { size.x, 0.0f };
for(Item &item : items) {
const mgl::vec2f bounds = item.text.get_bounds().size;
max_size.x = std::max(max_size.x, bounds.x + padding_left + padding_right);
max_size.y += bounds.y + padding_top + padding_bottom;
}
dirty = false;
}
mgl::vec2f DropdownButton::get_size() {
update_if_dirty();
return size;
}
}

43
src/gui/Utils.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include "../../include/gui/Utils.hpp"
#include <mglpp/window/Window.hpp>
#include <mglpp/graphics/Rectangle.hpp>
namespace gsr {
// TODO: Use vertices to make it one draw call
void draw_rectangle_outline(mgl::Window &window, mgl::vec2f pos, mgl::vec2f size, mgl::Color color, float border_size) {
pos = pos.floor();
size = size.floor();
border_size = (int)border_size;
// Green line at top
{
mgl::Rectangle rect({ size.x, border_size });
rect.set_position(pos);
rect.set_color(color);
window.draw(rect);
}
// Green line at bottom
{
mgl::Rectangle rect({ size.x, border_size });
rect.set_position(pos + mgl::vec2f(0.0f, size.y - border_size));
rect.set_color(color);
window.draw(rect);
}
// Green line at left
{
mgl::Rectangle rect({ border_size, size.y - border_size * 2 });
rect.set_position(pos + mgl::vec2f(0, border_size));
rect.set_color(color);
window.draw(rect);
}
// Green line at right
{
mgl::Rectangle rect({ border_size, size.y - border_size * 2 });
rect.set_position(pos + mgl::vec2f(size.x - border_size, border_size));
rect.set_color(color);
window.draw(rect);
}
}
}

View File

@@ -42,10 +42,11 @@ namespace gsr {
Widget *widget = *it; Widget *widget = *it;
if(widget->move_to_top) { if(widget->move_to_top) {
widget->move_to_top = false; widget->move_to_top = false;
if(widgets.back() != widget) { std::swap(*it, widgets.back());
/*if(widgets.back() != widget) {
widgets.erase(it); widgets.erase(it);
widgets.push_back(widget); widgets.push_back(widget);
} }*/
} }
} }

View File

@@ -1,8 +1,10 @@
#include "../include/gui/WidgetContainer.hpp" #include "../include/gui/WidgetContainer.hpp"
#include "../include/gui/Button.hpp" #include "../include/gui/DropdownButton.hpp"
#include "../include/gui/ComboBox.hpp" #include "../include/gui/ComboBox.hpp"
#include "../include/Process.hpp" #include "../include/Process.hpp"
#include "../include/Theme.hpp"
#include "../include/GsrInfo.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -138,6 +140,15 @@ int main(int argc, char **argv) {
signal(SIGINT, sigint_handler); signal(SIGINT, sigint_handler);
gsr::GsrInfo gsr_info;
// TODO:
gsr::GsrInfoExitStatus gsr_info_exit_status = gsr::get_gpu_screen_recorder_info(&gsr_info);
if(gsr_info_exit_status != gsr::GsrInfoExitStatus::OK) {
fprintf(stderr, "error: failed to get gpu-screen-recorder info\n");
exit(1);
}
gsr::init_theme(gsr_info);
std::string program_root_dir = dirname(argv[0]); std::string program_root_dir = dirname(argv[0]);
if(!program_root_dir.empty() && program_root_dir.back() != '/') if(!program_root_dir.empty() && program_root_dir.back() != '/')
program_root_dir += '/'; program_root_dir += '/';
@@ -225,10 +236,7 @@ int main(int argc, char **argv) {
bg_screenshot_overlay.set_color(bg_color); bg_screenshot_overlay.set_color(bg_color);
struct MainButton { struct MainButton {
mgl::Text title; std::unique_ptr<gsr::DropdownButton> button;
mgl::Text description;
mgl::Sprite icon;
std::unique_ptr<gsr::Button> button;
gsr::GsrMode mode; gsr::GsrMode mode;
}; };
@@ -256,26 +264,17 @@ int main(int argc, char **argv) {
&stream_button_texture &stream_button_texture
}; };
const int button_height = window_create_params.size.y / 6.0f; const int button_height = window_create_params.size.y / 5.0f;
const int button_width = button_height; const int button_width = button_height;
std::vector<MainButton> main_buttons; std::vector<MainButton> main_buttons;
for(int i = 0; i < 3; ++i) { for(int i = 0; i < 3; ++i) {
mgl::Text title(titles[i], {0.0f, 0.0f}, title_font); auto button = std::make_unique<gsr::DropdownButton>(&title_font, &font, titles[i], descriptions_on[i], descriptions_off[i], textures[i], mgl::vec2f(button_width, button_height));
title.set_color(mgl::Color(255, 255, 255)); button->add_item("Start", "start");
button->add_item("Settings", "settings");
mgl::Text description(descriptions_off[i], {0.0f, 0.0f}, font);
description.set_color(mgl::Color(150, 150, 150));
mgl::Sprite sprite(textures[i]);
sprite.set_height(button_height * 0.5f);
auto button = std::make_unique<gsr::Button>(mgl::vec2f(button_width, button_height));
MainButton main_button = { MainButton main_button = {
std::move(title),
std::move(description),
std::move(sprite),
std::move(button), std::move(button),
gsr::GsrMode::Unknown gsr::GsrMode::Unknown
}; };
@@ -285,7 +284,6 @@ int main(int argc, char **argv) {
auto update_overlay_shape = [&](std::optional<gsr::GsrMode> gsr_mode = std::nullopt) { auto update_overlay_shape = [&](std::optional<gsr::GsrMode> gsr_mode = std::nullopt) {
fprintf(stderr, "update overlay shape!\n"); fprintf(stderr, "update overlay shape!\n");
const int main_button_margin = button_height * 0.085;// * get_config().scale;
const int spacing = 0;// * get_config().scale; const int spacing = 0;// * get_config().scale;
const int combined_spacing = spacing * std::max(0, (int)main_buttons.size() - 1); const int combined_spacing = spacing * std::max(0, (int)main_buttons.size() - 1);
@@ -303,37 +301,18 @@ int main(int argc, char **argv) {
for(size_t i = 0; i < main_buttons.size(); ++i) { for(size_t i = 0; i < main_buttons.size(); ++i) {
if(main_buttons[i].mode != gsr::GsrMode::Unknown && main_buttons[i].mode == gsr_mode.value()) { if(main_buttons[i].mode != gsr::GsrMode::Unknown && main_buttons[i].mode == gsr_mode.value()) {
main_buttons[i].description.set_string(descriptions_on[i]); main_buttons[i].button->set_activated(true);
main_buttons[i].description.set_color(mgl::Color(118, 185, 0));
main_buttons[i].icon.set_color(mgl::Color(118, 185, 0));
} else { } else {
main_buttons[i].description.set_string(descriptions_off[i]); main_buttons[i].button->set_activated(false);
main_buttons[i].description.set_color(mgl::Color(150, 150, 150));
main_buttons[i].icon.set_color(mgl::Color(255, 255, 255));
} }
main_buttons[i].title.set_position(
mgl::vec2f(
main_button_pos.x + per_button_width * 0.5f - main_buttons[i].title.get_bounds().size.x * 0.5f,
main_button_pos.y + main_button_margin).floor());
main_buttons[i].description.set_position(
mgl::vec2f(
main_button_pos.x + per_button_width * 0.5f - main_buttons[i].description.get_bounds().size.x * 0.5f,
main_button_pos.y + overlay_desired_size.y - main_buttons[i].description.get_bounds().size.y - main_button_margin).floor());
main_buttons[i].icon.set_position(
mgl::vec2f(
main_button_pos.x + per_button_width * 0.5f - main_buttons[i].icon.get_texture()->get_size().x * main_buttons[i].icon.get_scale().x * 0.5f,
main_button_pos.y + overlay_desired_size.y * 0.5f - main_buttons[i].icon.get_texture()->get_size().y * main_buttons[i].icon.get_scale().y * 0.5f).floor());
main_buttons[i].button->set_position(main_button_pos.to_vec2f()); main_buttons[i].button->set_position(main_button_pos.to_vec2f());
main_button_pos.x += per_button_width + combined_spacing; main_button_pos.x += per_button_width + combined_spacing;
} }
}; };
// Replay // Replay
main_buttons[0].button->on_click = [&]() { main_buttons[0].button->on_click = [&](const std::string &id) {
/* /*
char window_to_record_str[32]; char window_to_record_str[32];
snprintf(window_to_record_str, sizeof(window_to_record_str), "%ld", target_window); snprintf(window_to_record_str, sizeof(window_to_record_str), "%ld", target_window);
@@ -353,9 +332,12 @@ int main(int argc, char **argv) {
// TODO: Monitor /tmp/gpu-screen-recorder and update ui to match state // TODO: Monitor /tmp/gpu-screen-recorder and update ui to match state
// Record // Record
main_buttons[1].button->on_click = [&]() { main_buttons[1].button->on_click = [&](const std::string &id) {
window.close(); if(id != "start")
usleep(1000 * 50); // 50 milliseconds return;
// window.close();
// usleep(1000 * 50); // 50 milliseconds
pid_t gpu_screen_recorder_process = -1; pid_t gpu_screen_recorder_process = -1;
gsr::GsrMode gsr_mode = gsr::GsrMode::Unknown; gsr::GsrMode gsr_mode = gsr::GsrMode::Unknown;
@@ -366,12 +348,13 @@ int main(int argc, char **argv) {
perror("waitpid failed"); perror("waitpid failed");
/* Ignore... */ /* Ignore... */
} }
window.set_visible(false); // window.set_visible(false);
window.close(); // window.close();
return; // return;
//exit(0); //exit(0);
//update_overlay_shape(gsr::GsrMode::Unknown); update_overlay_shape(gsr::GsrMode::Unknown);
//return; main_buttons[1].button->set_item_label(id, "Start");
return;
} }
const char *args[] = { const char *args[] = {
@@ -382,10 +365,14 @@ int main(int argc, char **argv) {
nullptr nullptr
}; };
gsr::exec_program_daemonized(args); gsr::exec_program_daemonized(args);
//update_overlay_shape(gsr::GsrMode::Record); update_overlay_shape(gsr::GsrMode::Record);
main_buttons[1].button->set_item_label(id, "Stop");
//exit(0); //exit(0);
window.set_visible(false); // window.set_visible(false);
window.close(); // window.close();
// TODO: Show notification with args:
// "Recording has started" 3.0 ./images/record.png 76b900
}; };
main_buttons[1].mode = gsr::GsrMode::Record; main_buttons[1].mode = gsr::GsrMode::Record;
@@ -415,11 +402,11 @@ int main(int argc, char **argv) {
//XGrabServer(display); //XGrabServer(display);
mgl::Rectangle top_bar_background(mgl::vec2f(window.get_size().x, window.get_size().y*0.05f).floor()); mgl::Rectangle top_bar_background(mgl::vec2f(window.get_size().x, window.get_size().y*0.06f).floor());
top_bar_background.set_color(mgl::Color(0, 0, 0, 220)); top_bar_background.set_color(mgl::Color(0, 0, 0, 220));
mgl::Text top_bar_text("GPU Screen Recorder", top_bar_font); mgl::Text top_bar_text("GPU Screen Recorder", top_bar_font);
//top_bar_text.set_color(mgl::Color(118, 185, 0)); //top_bar_text.set_color(gsr::get_theme().tint_color);
top_bar_text.set_position((top_bar_background.get_position() + top_bar_background.get_size()*0.5f - top_bar_text.get_bounds().size*0.5f).floor()); top_bar_text.set_position((top_bar_background.get_position() + top_bar_background.get_size()*0.5f - top_bar_text.get_bounds().size*0.5f).floor());
// gsr::ComboBox record_area_box(&title_font); // gsr::ComboBox record_area_box(&title_font);
@@ -458,7 +445,7 @@ int main(int argc, char **argv) {
// framerate_title.set_position(mgl::vec2f(framerate_box.get_position().x, framerate_box.get_position().y - title_font.get_character_size() - 10.0f)); // framerate_title.set_position(mgl::vec2f(framerate_box.get_position().x, framerate_box.get_position().y - title_font.get_character_size() - 10.0f));
mgl::Texture close_texture; mgl::Texture close_texture;
if(!close_texture.load_from_file("images/cross.png", {false, false, false})) if(!close_texture.load_from_file("images/cross.png"))
startup_error("failed to load texture: images/cross.png"); startup_error("failed to load texture: images/cross.png");
mgl::Sprite close_sprite(&close_texture); mgl::Sprite close_sprite(&close_texture);
@@ -489,7 +476,7 @@ int main(int argc, char **argv) {
const float settings_topline_thickness = 5.0f; const float settings_topline_thickness = 5.0f;
mgl::Rectangle settings_topline(settings_background.get_position() - mgl::vec2f(0.0f, settings_topline_thickness), mgl::vec2f(settings_background.get_size().x, settings_topline_thickness)); mgl::Rectangle settings_topline(settings_background.get_position() - mgl::vec2f(0.0f, settings_topline_thickness), mgl::vec2f(settings_background.get_size().x, settings_topline_thickness));
settings_topline.set_color(mgl::Color(118, 185, 0)); settings_topline.set_color(gsr::get_theme().tint_color);
*/ */
mgl::Clock state_update_timer; mgl::Clock state_update_timer;
@@ -517,11 +504,6 @@ int main(int argc, char **argv) {
// window.draw(video_quality_title); // window.draw(video_quality_title);
// window.draw(framerate_title); // window.draw(framerate_title);
widget_container.draw(window); widget_container.draw(window);
for(auto &main_button : main_buttons) {
window.draw(main_button.icon);
window.draw(main_button.title);
window.draw(main_button.description);
}
window.draw(top_bar_background); window.draw(top_bar_background);
window.draw(top_bar_text); window.draw(top_bar_text);
window.draw(logo_sprite); window.draw(logo_sprite);