add creator
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,4 +2,3 @@ build
|
|||||||
.cache
|
.cache
|
||||||
subprojects/*
|
subprojects/*
|
||||||
!subprojects/*.wrap
|
!subprojects/*.wrap
|
||||||
src/noinc.hpp
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ deps = [
|
|||||||
dependency('libpqxx'),
|
dependency('libpqxx'),
|
||||||
dependency('uuid'),
|
dependency('uuid'),
|
||||||
dependency('threads'),
|
dependency('threads'),
|
||||||
|
dependency('gtk+-3.0'),
|
||||||
dependency('OpenGL'),
|
dependency('OpenGL'),
|
||||||
dependency('sndfile'),
|
dependency('sndfile'),
|
||||||
subproject('vertex_engine').get_variable('vertex_engine_dep'),
|
subproject('vertex_engine').get_variable('vertex_engine_dep'),
|
||||||
|
|||||||
21
run.sh
21
run.sh
@@ -1,21 +0,0 @@
|
|||||||
#!/bin/zsh
|
|
||||||
|
|
||||||
PROJECT_NAME=$(basename $PWD)
|
|
||||||
|
|
||||||
run() {
|
|
||||||
command meson compile -C build
|
|
||||||
if [[ -z "$1" ]]; then
|
|
||||||
cd build
|
|
||||||
./bin/$PROJECT_NAME
|
|
||||||
cd ..
|
|
||||||
else
|
|
||||||
meson test $1 -C build
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -d "build" ]; then
|
|
||||||
run
|
|
||||||
else
|
|
||||||
command meson setup build
|
|
||||||
run
|
|
||||||
fi
|
|
||||||
@@ -10,6 +10,7 @@ headers = [
|
|||||||
'monitor/gui/components/audio/audio.hpp',
|
'monitor/gui/components/audio/audio.hpp',
|
||||||
'monitor/gui/components/markers/markers.hpp',
|
'monitor/gui/components/markers/markers.hpp',
|
||||||
'monitor/gui/components/helpers/helpers.hpp',
|
'monitor/gui/components/helpers/helpers.hpp',
|
||||||
|
'monitor/gui/components/file_dialog/file_dialog.hpp',
|
||||||
|
|
||||||
############ GUI/WIN
|
############ GUI/WIN
|
||||||
'monitor/gui/win/win.hpp',
|
'monitor/gui/win/win.hpp',
|
||||||
@@ -17,6 +18,7 @@ headers = [
|
|||||||
############ UTILS
|
############ UTILS
|
||||||
'monitor/utils/var.hpp',
|
'monitor/utils/var.hpp',
|
||||||
'monitor/libs/audio/audio.hpp',
|
'monitor/libs/audio/audio.hpp',
|
||||||
|
'monitor/libs/gtkfd/gtkfd.hpp',
|
||||||
|
|
||||||
############
|
############
|
||||||
# RUN
|
# RUN
|
||||||
@@ -31,9 +33,6 @@ sources = [
|
|||||||
'monitor/gui/components/creator/cpp/base.cpp',
|
'monitor/gui/components/creator/cpp/base.cpp',
|
||||||
'monitor/gui/components/creator/cpp/on_event.cpp',
|
'monitor/gui/components/creator/cpp/on_event.cpp',
|
||||||
'monitor/gui/components/creator/cpp/render/render.cpp',
|
'monitor/gui/components/creator/cpp/render/render.cpp',
|
||||||
'monitor/gui/components/creator/cpp/render/buttons.cpp',
|
|
||||||
'monitor/gui/components/creator/cpp/render/combo.cpp',
|
|
||||||
'monitor/gui/components/creator/cpp/render/setup.cpp',
|
|
||||||
'monitor/gui/components/creator/cpp/render/spinner.cpp',
|
'monitor/gui/components/creator/cpp/render/spinner.cpp',
|
||||||
'monitor/gui/components/snapshot/cpp/base.cpp',
|
'monitor/gui/components/snapshot/cpp/base.cpp',
|
||||||
'monitor/gui/components/snapshot/cpp/on_event.cpp',
|
'monitor/gui/components/snapshot/cpp/on_event.cpp',
|
||||||
@@ -50,9 +49,11 @@ sources = [
|
|||||||
'monitor/gui/components/helpers/cpp/base.cpp',
|
'monitor/gui/components/helpers/cpp/base.cpp',
|
||||||
'monitor/gui/components/helpers/cpp/on_event.cpp',
|
'monitor/gui/components/helpers/cpp/on_event.cpp',
|
||||||
'monitor/gui/components/helpers/cpp/render.cpp',
|
'monitor/gui/components/helpers/cpp/render.cpp',
|
||||||
|
'monitor/gui/components/file_dialog/file_dialog.cpp',
|
||||||
|
|
||||||
############ UTILS
|
############ UTILS
|
||||||
'monitor/libs/audio/audio.cpp',
|
'monitor/libs/audio/audio.cpp',
|
||||||
|
'monitor/libs/gtkfd/gtkfd.cpp',
|
||||||
|
|
||||||
############ GUI/WIN
|
############ GUI/WIN
|
||||||
'monitor/gui/win/cpp/base.cpp',
|
'monitor/gui/win/cpp/base.cpp',
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
#include "monitor/gui/components/creator/creator.hpp"
|
#include "monitor/gui/components/creator/creator.hpp"
|
||||||
|
|
||||||
#include "monitor/utils/event_type.hpp"
|
#include "monitor/utils/event_type.hpp"
|
||||||
#include "monitor/utils/var.hpp"
|
|
||||||
|
|
||||||
namespace monitor::components
|
namespace monitor::components
|
||||||
{
|
{
|
||||||
void creator::on_attach()
|
void creator::on_attach()
|
||||||
{
|
{
|
||||||
CONNECT(this);
|
CONNECT(this);
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(utils::var::DIR))
|
|
||||||
if (entry.is_directory()) m_dirs.push_back(entry.path().filename().string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void creator::on_detach()
|
void creator::on_detach()
|
||||||
@@ -22,33 +18,24 @@ namespace monitor::components
|
|||||||
void creator::create()
|
void creator::create()
|
||||||
{
|
{
|
||||||
m_status = utils::var::STATUS::PROCESS;
|
m_status = utils::var::STATUS::PROCESS;
|
||||||
m_setup.m_file = utils::var::DIR / m_dir.m_name / m_file.m_name;
|
|
||||||
// send to: tabs
|
|
||||||
VE::event e { utils::event_type::CREATE_SNAPSHOT, m_setup };
|
|
||||||
EMIT(e);
|
|
||||||
clear();
|
|
||||||
|
|
||||||
|
auto f = [this]() {
|
||||||
|
m_setup.m_file = m_file_path;
|
||||||
|
// send to: tabs
|
||||||
|
VE::event e { utils::event_type::CREATE_SNAPSHOT, m_setup };
|
||||||
|
EMIT(e);
|
||||||
|
};
|
||||||
|
std::thread th(f);
|
||||||
|
th.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void creator::clear()
|
void creator::clear()
|
||||||
{
|
{
|
||||||
m_dir.clear();
|
|
||||||
m_file.clear();
|
|
||||||
m_files.clear();
|
|
||||||
m_status = utils::var::STATUS::COMPLETED;
|
m_status = utils::var::STATUS::COMPLETED;
|
||||||
|
|
||||||
auto future = std::async(std::launch::async, [this]() {
|
auto future = std::async(std::launch::async, [this]() {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||||
|
m_file_path.clear();
|
||||||
m_status = utils::var::STATUS::EMPTY;
|
m_status = utils::var::STATUS::EMPTY;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void creator::set_domain(std::string name)
|
|
||||||
{
|
|
||||||
if (name == "frequensy")
|
|
||||||
m_setup.m_domain = hr::DOMAIN_PLUGIN::FREQUENSY;
|
|
||||||
else
|
|
||||||
m_setup.m_domain = hr::DOMAIN_PLUGIN::TIME;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ namespace monitor::components
|
|||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
// case utils::event_type::CREATE_WORKSPACE_COMPLETE:
|
case utils::event_type::CREATE_SNAPSHOT_COMPLETED:
|
||||||
// {
|
{
|
||||||
// clear();
|
clear();
|
||||||
// break;
|
break;
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
#include "monitor/gui/components/creator/creator.hpp"
|
|
||||||
#include "monitor/utils/var.hpp"
|
|
||||||
|
|
||||||
namespace monitor::components
|
|
||||||
{
|
|
||||||
void creator::render_buttons()
|
|
||||||
{
|
|
||||||
ImGui::BeginDisabled(m_status == utils::var::STATUS::EMPTY);
|
|
||||||
ImGui::BeginDisabled(m_status == utils::var::STATUS::PROCESS);
|
|
||||||
ImGui::BeginDisabled(m_status == utils::var::STATUS::COMPLETED);
|
|
||||||
|
|
||||||
if (ImGui::Button("create", ImVec2{ 94.f, 27.f })) create();
|
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
#include "monitor/gui/components/creator/creator.hpp"
|
|
||||||
#include "monitor/utils/var.hpp"
|
|
||||||
|
|
||||||
namespace monitor::components
|
|
||||||
{
|
|
||||||
void creator::render_combo()
|
|
||||||
{
|
|
||||||
auto ctx = ImGui::GetCurrentContext();
|
|
||||||
ImGui::SameLine(0.f, ctx->Style.FramePadding.x);
|
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(400.f);
|
|
||||||
if (ImGui::BeginCombo(VE_NO_NAME("select_dir"), m_dir.m_id < 0 ? "---" : m_dirs[m_dir.m_id].c_str()))
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < m_dirs.size(); ++i)
|
|
||||||
{
|
|
||||||
const bool is_selected = (m_dir.m_id == static_cast<int>(i));
|
|
||||||
if (ImGui::Selectable(m_dirs[i].c_str(), is_selected))
|
|
||||||
{
|
|
||||||
m_files.clear();
|
|
||||||
m_dir.init(i, m_dirs[i]);
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(utils::var::DIR/m_dir.m_name))
|
|
||||||
if (entry.is_regular_file()) m_files.push_back(entry.path().filename().string());
|
|
||||||
}
|
|
||||||
if (is_selected) ImGui::SetItemDefaultFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = ImGui::GetCurrentContext();
|
|
||||||
ImGui::SameLine(0.f, ctx->Style.FramePadding.x);
|
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(400.f);
|
|
||||||
if (ImGui::BeginCombo(VE_NO_NAME("select_file"), m_file.m_id < 0 ? "---" : m_files[m_file.m_id].c_str()))
|
|
||||||
{
|
|
||||||
if (!m_files.empty())
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < m_files.size(); ++i)
|
|
||||||
{
|
|
||||||
const bool is_selected = (m_file.m_id == static_cast<int>(i));
|
|
||||||
if (ImGui::Selectable(m_files[i].c_str(), is_selected))
|
|
||||||
{
|
|
||||||
m_file.init(i, m_files[i]);
|
|
||||||
m_status = utils::var::STATUS::READY;
|
|
||||||
}
|
|
||||||
if (is_selected) ImGui::SetItemDefaultFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "monitor/gui/components/creator/creator.hpp"
|
#include "monitor/gui/components/creator/creator.hpp"
|
||||||
|
#include "monitor/gui/components/file_dialog/file_dialog.hpp"
|
||||||
|
|
||||||
namespace monitor::components
|
namespace monitor::components
|
||||||
{
|
{
|
||||||
@@ -6,11 +7,33 @@ namespace monitor::components
|
|||||||
{
|
{
|
||||||
auto ctx = ImGui::GetCurrentContext();
|
auto ctx = ImGui::GetCurrentContext();
|
||||||
|
|
||||||
render_combo();
|
ImGui::BeginDisabled(m_status == utils::var::STATUS::PROCESS);
|
||||||
render_spinner();
|
ImGui::BeginDisabled(m_status == utils::var::STATUS::COMPLETED);
|
||||||
ImGui::SameLine(0.f, 9.f * ctx->Style.FramePadding.x);
|
if (ImGui::Button("open", ImVec2{ 94.f, 27.f }))
|
||||||
render_setup();
|
{
|
||||||
ImGui::SameLine(0.f, 2.f * ctx->Style.FramePadding.x);
|
m_file_path = m_fd.open();
|
||||||
render_buttons();
|
if (!m_file_path.empty()) m_status = utils::var::STATUS::READY;
|
||||||
|
else m_status = utils::var::STATUS::EMPTY;
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (!m_file_path.empty())
|
||||||
|
{
|
||||||
|
ImGui::Text(m_file_path.filename().c_str());
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(m_status == utils::var::STATUS::EMPTY);
|
||||||
|
ImGui::BeginDisabled(m_status == utils::var::STATUS::PROCESS);
|
||||||
|
ImGui::BeginDisabled(m_status == utils::var::STATUS::COMPLETED);
|
||||||
|
if (ImGui::Button("create", ImVec2{ 94.f, 27.f })) create();
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
render_spinner();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
#include "monitor/gui/components/creator/creator.hpp"
|
|
||||||
#include <harmonica.hpp>
|
|
||||||
|
|
||||||
namespace monitor::components
|
|
||||||
{
|
|
||||||
void creator::render_setup()
|
|
||||||
{
|
|
||||||
ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
|
|
||||||
|
|
||||||
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
|
|
||||||
|
|
||||||
ImGui::Text("block size:");
|
|
||||||
ImGui::SameLine(0.0f, spacing);
|
|
||||||
render_block_size_setup(spacing);
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text(" | ");
|
|
||||||
ImGui::SameLine(0.f, spacing);
|
|
||||||
|
|
||||||
render_step_size_setup(spacing);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text(" | ");
|
|
||||||
|
|
||||||
ImGui::PopItemFlag();
|
|
||||||
}
|
|
||||||
|
|
||||||
void creator::render_block_size_setup(float spacing)
|
|
||||||
{
|
|
||||||
ImGui::SetCursorPosY(8.f);
|
|
||||||
VE_PUSH_FONT(ICON, 12);
|
|
||||||
ImGui::PushID(VE_NO_NAME("block_size minus"));
|
|
||||||
if (ImGui::Button(VE::style::icon::ICON_MINUS, ImVec2{24, 20}))
|
|
||||||
{
|
|
||||||
m_setup.m_block_size -= m_step;
|
|
||||||
m_setup.m_block_size = std::max(m_step, m_setup.m_block_size);
|
|
||||||
}
|
|
||||||
ImGui::PopID();
|
|
||||||
VE_POP_FONT();
|
|
||||||
|
|
||||||
ImGui::SameLine(0.0f, spacing);
|
|
||||||
ImGui::Text("%zu", m_setup.m_block_size);
|
|
||||||
// тут нужно жестко, а то при изменении циферек прагает в сторону поле
|
|
||||||
ImGui::SameLine(1000.0f);
|
|
||||||
|
|
||||||
ImGui::SetCursorPosY(8.f);
|
|
||||||
VE_PUSH_FONT(ICON, 12);
|
|
||||||
ImGui::PushID(VE_NO_NAME("block_size plus"));
|
|
||||||
if (ImGui::Button(VE::style::icon::ICON_PLUS, ImVec2{24, 20}))
|
|
||||||
m_setup.m_block_size += m_step;
|
|
||||||
ImGui::PopID();
|
|
||||||
VE_POP_FONT();
|
|
||||||
ImGui::PopItemFlag();
|
|
||||||
}
|
|
||||||
|
|
||||||
void creator::render_step_size_setup(float spacing)
|
|
||||||
{
|
|
||||||
ImGui::Text("step size:");
|
|
||||||
ImGui::SameLine(0.0f, spacing);
|
|
||||||
|
|
||||||
ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
|
|
||||||
ImGui::SetCursorPosY(8.f);
|
|
||||||
VE_PUSH_FONT(ICON, 12);
|
|
||||||
ImGui::PushID(VE_NO_NAME("step_size_minus"));
|
|
||||||
if (ImGui::Button(VE::style::icon::ICON_MINUS, ImVec2{24, 20}))
|
|
||||||
{
|
|
||||||
m_setup.m_step_size -= m_step;
|
|
||||||
m_setup.m_step_size = std::max(m_step, m_setup.m_step_size);
|
|
||||||
}
|
|
||||||
ImGui::PopID();
|
|
||||||
VE_POP_FONT();
|
|
||||||
|
|
||||||
ImGui::SameLine(0.0f, spacing);
|
|
||||||
ImGui::Text("%zu", m_setup.m_step_size);
|
|
||||||
// тут нужно жестко, а то при изменении циферек прагает в сторону поле
|
|
||||||
ImGui::SameLine(1195.0f);
|
|
||||||
|
|
||||||
ImGui::SetCursorPosY(8.f);
|
|
||||||
VE_PUSH_FONT(ICON, 12);
|
|
||||||
ImGui::PushID(VE_NO_NAME("step_size_plus"));
|
|
||||||
if (ImGui::Button(VE::style::icon::ICON_PLUS, ImVec2{24, 20}))
|
|
||||||
m_setup.m_step_size += m_step;
|
|
||||||
ImGui::PopID();
|
|
||||||
VE_POP_FONT();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,11 @@ namespace monitor::components
|
|||||||
{
|
{
|
||||||
void creator::render_spinner()
|
void creator::render_spinner()
|
||||||
{
|
{
|
||||||
ImVec2 pos{ 830.f, 12.f };
|
ImVec2 buttonPos = ImGui::GetItemRectMin(); // левый верхний угол кнопки
|
||||||
|
ImVec2 buttonSize = ImGui::GetItemRectSize(); // размер кнопки
|
||||||
|
float spacing = 10.f;
|
||||||
|
ImVec2 pos = ImVec2(buttonPos.x + buttonSize.x + spacing, buttonPos.y);
|
||||||
|
|
||||||
if (m_status == utils::var::STATUS::COMPLETED) m_spinner.render(pos);
|
if (m_status == utils::var::STATUS::COMPLETED) m_spinner.render(pos);
|
||||||
else if (m_status == utils::var::STATUS::READY) m_spinner.render(pos, "#B4CF16");
|
else if (m_status == utils::var::STATUS::READY) m_spinner.render(pos, "#B4CF16");
|
||||||
else if (m_status == utils::var::STATUS::PROCESS) m_spinner.render(pos, "#B82C5C", true);
|
else if (m_status == utils::var::STATUS::PROCESS) m_spinner.render(pos, "#B82C5C", true);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <VE.hpp>
|
#include <VE.hpp>
|
||||||
#include <harmonica.hpp>
|
#include <harmonica.hpp>
|
||||||
#include "monitor/gui/components/spinner/spinner.hpp"
|
#include "monitor/gui/components/spinner/spinner.hpp"
|
||||||
|
#include "monitor/gui/components/file_dialog/file_dialog.hpp"
|
||||||
#include "monitor/utils/var.hpp"
|
#include "monitor/utils/var.hpp"
|
||||||
|
|
||||||
namespace monitor::components
|
namespace monitor::components
|
||||||
@@ -13,42 +14,18 @@ namespace monitor::components
|
|||||||
VE_EVENT_OVERIDE();
|
VE_EVENT_OVERIDE();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct combo
|
|
||||||
{
|
|
||||||
std::string m_name = "no selected";
|
|
||||||
int m_id = -1;
|
|
||||||
void init(int id, std::string name) { m_id = id; m_name = name; }
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_name.clear();
|
|
||||||
m_id = -1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<std::string> m_dirs;
|
|
||||||
std::vector<std::string> m_files;
|
|
||||||
combo m_dir;
|
|
||||||
combo m_file;
|
|
||||||
utils::var::STATUS m_status = utils::var::STATUS::EMPTY;
|
utils::var::STATUS m_status = utils::var::STATUS::EMPTY;
|
||||||
components::spinner m_spinner;
|
components::spinner m_spinner;
|
||||||
hr::setup m_setup;
|
|
||||||
std::size_t m_step = 256;
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set_domain(std::string name);
|
hr::setup m_setup;
|
||||||
|
file_dialog m_fd;
|
||||||
|
std::filesystem::path m_file_path;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void render_spinner();
|
||||||
void create();
|
void create();
|
||||||
void clear();
|
void clear();
|
||||||
void render_combo();
|
|
||||||
void render_spinner();
|
|
||||||
void render_buttons();
|
|
||||||
void render_setup();
|
|
||||||
void render_combo_signals();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void render_block_size_setup(float spacing);
|
|
||||||
void render_step_size_setup(float spacing);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
src/monitor/gui/components/file_dialog/file_dialog.cpp
Normal file
9
src/monitor/gui/components/file_dialog/file_dialog.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "file_dialog.hpp"
|
||||||
|
|
||||||
|
namespace monitor::components
|
||||||
|
{
|
||||||
|
std::filesystem::path file_dialog::open(const std::filesystem::path& default_path)
|
||||||
|
{
|
||||||
|
return m_nfd.open(default_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/monitor/gui/components/file_dialog/file_dialog.hpp
Normal file
19
src/monitor/gui/components/file_dialog/file_dialog.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "monitor/libs/gtkfd/gtkfd.hpp"
|
||||||
|
|
||||||
|
namespace monitor::components
|
||||||
|
{
|
||||||
|
class file_dialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
file_dialog() = default;
|
||||||
|
~file_dialog() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::filesystem::path open(const std::filesystem::path& default_path = "/mnt/raid/projects/dsp/songs");
|
||||||
|
|
||||||
|
private:
|
||||||
|
libs::gtkfd m_nfd;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -29,6 +29,9 @@ namespace monitor::components
|
|||||||
s->init(setup);
|
s->init(setup);
|
||||||
s->on_attach();
|
s->on_attach();
|
||||||
m_snapshots.push_back(s);
|
m_snapshots.push_back(s);
|
||||||
|
|
||||||
|
VE::event e { utils::event_type::CREATE_SNAPSHOT_COMPLETED, nullptr };
|
||||||
|
EMIT(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tabs::string_cut(std::filesystem::path p, int n)
|
std::string tabs::string_cut(std::filesystem::path p, int n)
|
||||||
|
|||||||
500
src/monitor/libs/gtkfd.OLD/gtkfd.cpp
Normal file
500
src/monitor/libs/gtkfd.OLD/gtkfd.cpp
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "gtkfd.hpp"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Free_Guard
|
||||||
|
{
|
||||||
|
T* data;
|
||||||
|
Free_Guard(T* freeable) noexcept : data(freeable) {}
|
||||||
|
~Free_Guard() { NFDi_Free(data); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FreeCheck_Guard
|
||||||
|
{
|
||||||
|
T* data;
|
||||||
|
FreeCheck_Guard(T* freeable = nullptr) noexcept : data(freeable) {}
|
||||||
|
~FreeCheck_Guard() { if (data) NFDi_Free(data); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* current error */
|
||||||
|
const char* g_errorstr = nullptr;
|
||||||
|
|
||||||
|
void NFDi_SetError(const char* msg)
|
||||||
|
{
|
||||||
|
g_errorstr = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
T* NFDi_Malloc(size_t bytes)
|
||||||
|
{
|
||||||
|
void* ptr = malloc(bytes);
|
||||||
|
if (!ptr) NFDi_SetError("NFDi_Malloc failed.");
|
||||||
|
return static_cast<T*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void NFDi_Free(T *ptr)
|
||||||
|
{
|
||||||
|
assert(ptr);
|
||||||
|
free(static_cast<void*>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T* copy(const T* begin, const T* end, T* out)
|
||||||
|
{
|
||||||
|
for (; begin != end; ++begin) *out++ = *begin;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not own the filter and extension.
|
||||||
|
struct Pair_GtkFileFilter_FileExtension
|
||||||
|
{
|
||||||
|
GtkFileFilter* filter;
|
||||||
|
const char* extensionBegin;
|
||||||
|
const char* extensionEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ButtonClickedArgs
|
||||||
|
{
|
||||||
|
Pair_GtkFileFilter_FileExtension* map;
|
||||||
|
GtkFileChooser* chooser;
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddFiltersToDialog(GtkFileChooser* chooser, const item* filterList, uint_t filterCount)
|
||||||
|
{
|
||||||
|
if (filterCount)
|
||||||
|
{
|
||||||
|
assert(filterList);
|
||||||
|
// we have filters to add ... format and add them
|
||||||
|
|
||||||
|
for (uint_t index = 0; index != filterCount; ++index)
|
||||||
|
{
|
||||||
|
GtkFileFilter* filter = gtk_file_filter_new();
|
||||||
|
|
||||||
|
// count number of file extensions
|
||||||
|
size_t sep = 1;
|
||||||
|
for (const char* p_spec = filterList[index].m_spec; *p_spec; ++p_spec) if (*p_spec == L',') ++sep;
|
||||||
|
|
||||||
|
// calculate space needed (including the trailing '\0')
|
||||||
|
size_t nameSize = sep + strlen(filterList[index].m_spec) + 3 + strlen(filterList[index].m_name);
|
||||||
|
|
||||||
|
// malloc the required memory
|
||||||
|
char* nameBuf = NFDi_Malloc<char>(sizeof(char) * nameSize);
|
||||||
|
|
||||||
|
char* p_nameBuf = nameBuf;
|
||||||
|
for (const char* p_filterName = filterList[index].m_name; *p_filterName; ++p_filterName) *p_nameBuf++ = *p_filterName;
|
||||||
|
*p_nameBuf++ = ' ';
|
||||||
|
*p_nameBuf++ = '(';
|
||||||
|
const char* p_extensionStart = filterList[index].m_spec;
|
||||||
|
for (const char *p_spec = filterList[index].m_spec; true; ++p_spec)
|
||||||
|
{
|
||||||
|
if (*p_spec == ',' || !*p_spec)
|
||||||
|
{
|
||||||
|
if (*p_spec == ',')
|
||||||
|
{
|
||||||
|
*p_nameBuf++ = ',';
|
||||||
|
*p_nameBuf++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// +1 for the trailing '\0'
|
||||||
|
char* extnBuf = NFDi_Malloc<char>(sizeof(char) * (p_spec - p_extensionStart + 3));
|
||||||
|
char* p_extnBufEnd = extnBuf;
|
||||||
|
*p_extnBufEnd++ = '*';
|
||||||
|
*p_extnBufEnd++ = '.';
|
||||||
|
p_extnBufEnd = copy(p_extensionStart, p_spec, p_extnBufEnd);
|
||||||
|
*p_extnBufEnd++ = '\0';
|
||||||
|
assert((unsigned int)(p_extnBufEnd - extnBuf) == sizeof(char) * (p_spec - p_extensionStart + 3));
|
||||||
|
gtk_file_filter_add_pattern(filter, extnBuf);
|
||||||
|
NFDi_Free(extnBuf);
|
||||||
|
if (*p_spec) p_extensionStart = p_spec + 1;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
else *p_nameBuf++ = *p_spec;
|
||||||
|
}
|
||||||
|
*p_nameBuf++ = ')';
|
||||||
|
*p_nameBuf++ = '\0';
|
||||||
|
assert((unsigned int)(p_nameBuf - nameBuf) == sizeof(char) * nameSize);
|
||||||
|
|
||||||
|
// add to the filter
|
||||||
|
gtk_file_filter_set_name(filter, nameBuf);
|
||||||
|
|
||||||
|
// free the memory
|
||||||
|
NFDi_Free(nameBuf);
|
||||||
|
|
||||||
|
// add filter to chooser
|
||||||
|
gtk_file_chooser_add_filter(chooser, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* always append a wildcard option to the end*/
|
||||||
|
|
||||||
|
GtkFileFilter* filter = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_set_name(filter, "All files");
|
||||||
|
gtk_file_filter_add_pattern(filter, "*");
|
||||||
|
gtk_file_chooser_add_filter(chooser, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns null-terminated map (trailing .filter is null)
|
||||||
|
Pair_GtkFileFilter_FileExtension* AddFiltersToDialogWithMap(GtkFileChooser* chooser, const item* filterList, uint_t filterCount)
|
||||||
|
{
|
||||||
|
Pair_GtkFileFilter_FileExtension* map = NFDi_Malloc<Pair_GtkFileFilter_FileExtension>(sizeof(Pair_GtkFileFilter_FileExtension) * (filterCount + 1));
|
||||||
|
|
||||||
|
if (filterCount)
|
||||||
|
{
|
||||||
|
assert(filterList);
|
||||||
|
for (uint_t index = 0; index != filterCount; ++index)
|
||||||
|
{
|
||||||
|
GtkFileFilter* filter = gtk_file_filter_new();
|
||||||
|
|
||||||
|
// store filter in map
|
||||||
|
map[index].filter = filter;
|
||||||
|
map[index].extensionBegin = filterList[index].m_spec;
|
||||||
|
map[index].extensionEnd = nullptr;
|
||||||
|
|
||||||
|
// count number of file extensions
|
||||||
|
std::size_t sep = 1;
|
||||||
|
for (const char *p_spec = filterList[index].m_spec; *p_spec; ++p_spec)
|
||||||
|
if (*p_spec == L',') ++sep;
|
||||||
|
|
||||||
|
// calculate space needed (including the trailing '\0')
|
||||||
|
std::size_t nameSize = sep + strlen(filterList[index].m_spec) + 3 + strlen(filterList[index].m_name);
|
||||||
|
|
||||||
|
// malloc the required memory
|
||||||
|
char* nameBuf = NFDi_Malloc<char>(sizeof(char) * nameSize);
|
||||||
|
char* p_nameBuf = nameBuf;
|
||||||
|
|
||||||
|
for (const char *p_filterName = filterList[index].m_name; *p_filterName; ++p_filterName) *p_nameBuf++ = *p_filterName;
|
||||||
|
*p_nameBuf++ = ' ';
|
||||||
|
*p_nameBuf++ = '(';
|
||||||
|
const char* p_extensionStart = filterList[index].m_spec;
|
||||||
|
|
||||||
|
for (const char* p_spec = filterList[index].m_spec; true; ++p_spec)
|
||||||
|
{
|
||||||
|
if (*p_spec == ',' || !*p_spec)
|
||||||
|
{
|
||||||
|
if (*p_spec == ',')
|
||||||
|
{
|
||||||
|
*p_nameBuf++ = ',';
|
||||||
|
*p_nameBuf++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// +1 for the trailing '\0'
|
||||||
|
char *extnBuf = NFDi_Malloc<char>(sizeof(char) * (p_spec - p_extensionStart + 3));
|
||||||
|
char *p_extnBufEnd = extnBuf;
|
||||||
|
*p_extnBufEnd++ = '*';
|
||||||
|
*p_extnBufEnd++ = '.';
|
||||||
|
p_extnBufEnd = copy(p_extensionStart, p_spec, p_extnBufEnd);
|
||||||
|
*p_extnBufEnd++ = '\0';
|
||||||
|
assert((unsigned int)(p_extnBufEnd - extnBuf) == sizeof(char) * (p_spec - p_extensionStart + 3));
|
||||||
|
gtk_file_filter_add_pattern(filter, extnBuf);
|
||||||
|
NFDi_Free(extnBuf);
|
||||||
|
|
||||||
|
// store current pointer in map (if it's the first one)
|
||||||
|
if (map[index].extensionEnd == nullptr) map[index].extensionEnd = p_spec;
|
||||||
|
if (*p_spec) p_extensionStart = p_spec + 1;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
else *p_nameBuf++ = *p_spec;
|
||||||
|
}
|
||||||
|
*p_nameBuf++ = ')';
|
||||||
|
*p_nameBuf++ = '\0';
|
||||||
|
assert((unsigned int)(p_nameBuf - nameBuf) == sizeof(char) * nameSize);
|
||||||
|
|
||||||
|
// add to the filter
|
||||||
|
gtk_file_filter_set_name(filter, nameBuf);
|
||||||
|
|
||||||
|
// free the memory
|
||||||
|
NFDi_Free(nameBuf);
|
||||||
|
|
||||||
|
// add filter to chooser
|
||||||
|
gtk_file_chooser_add_filter(chooser, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set trailing map index to null
|
||||||
|
map[filterCount].filter = nullptr;
|
||||||
|
|
||||||
|
/* always append a wildcard option to the end*/
|
||||||
|
GtkFileFilter* filter = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_set_name(filter, "All files");
|
||||||
|
gtk_file_filter_add_pattern(filter, "*");
|
||||||
|
gtk_file_chooser_add_filter(chooser, filter);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDefaultPath(GtkFileChooser* chooser, const char *defaultPath)
|
||||||
|
{
|
||||||
|
if (!defaultPath || !*defaultPath) return;
|
||||||
|
|
||||||
|
/* GTK+ manual recommends not specifically setting the default path.
|
||||||
|
We do it anyway in order to be consistent across platforms.
|
||||||
|
If consistency with the native OS is preferred, this is the line
|
||||||
|
to comment out. -ml */
|
||||||
|
gtk_file_chooser_set_current_folder(chooser, defaultPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDefaultName(GtkFileChooser* chooser, const char *defaultName)
|
||||||
|
{
|
||||||
|
if (!defaultName || !*defaultName) return;
|
||||||
|
gtk_file_chooser_set_current_name(chooser, defaultName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitForCleanup()
|
||||||
|
{
|
||||||
|
while (gtk_events_pending()) gtk_main_iteration();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Widget_Guard
|
||||||
|
{
|
||||||
|
GtkWidget* data;
|
||||||
|
Widget_Guard(GtkWidget* widget) : data(widget) {}
|
||||||
|
~Widget_Guard()
|
||||||
|
{
|
||||||
|
WaitForCleanup();
|
||||||
|
gtk_widget_destroy(data);
|
||||||
|
WaitForCleanup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void FileActivatedSignalHandler(GtkButton* saveButton, void* userdata)
|
||||||
|
{
|
||||||
|
ButtonClickedArgs* args = static_cast<ButtonClickedArgs*>(userdata);
|
||||||
|
GtkFileChooser* chooser = args->chooser;
|
||||||
|
char* currentFileName = gtk_file_chooser_get_current_name(chooser);
|
||||||
|
|
||||||
|
if (*currentFileName)
|
||||||
|
{
|
||||||
|
// string is not empty
|
||||||
|
// find a '.' in the file name
|
||||||
|
const char* p_period = currentFileName;
|
||||||
|
for (;*p_period; ++p_period) if (*p_period == '.') break;
|
||||||
|
|
||||||
|
if (!*p_period)
|
||||||
|
{ // there is no '.', so append the default extension
|
||||||
|
Pair_GtkFileFilter_FileExtension* filterMap = static_cast<Pair_GtkFileFilter_FileExtension*>(args->map);
|
||||||
|
GtkFileFilter* currentFilter = gtk_file_chooser_get_filter(chooser);
|
||||||
|
if (currentFilter)
|
||||||
|
for (;filterMap->filter; ++filterMap)
|
||||||
|
if (filterMap->filter == currentFilter) break;
|
||||||
|
|
||||||
|
if (filterMap->filter)
|
||||||
|
{
|
||||||
|
// memory for appended string (including '.' and trailing '\0')
|
||||||
|
char* appendedFileName = NFDi_Malloc<char>(sizeof(char) * ((p_period - currentFileName) + (filterMap->extensionEnd - filterMap->extensionBegin) + 2));
|
||||||
|
char* p_fileName = copy(currentFileName, p_period, appendedFileName);
|
||||||
|
*p_fileName++ = '.';
|
||||||
|
p_fileName = copy(filterMap->extensionBegin, filterMap->extensionEnd, p_fileName);
|
||||||
|
*p_fileName++ = '\0';
|
||||||
|
|
||||||
|
assert(p_fileName - appendedFileName == (p_period - currentFileName) + (filterMap->extensionEnd - filterMap->extensionBegin) + 2);
|
||||||
|
|
||||||
|
// set the appended file name
|
||||||
|
gtk_file_chooser_set_current_name(chooser, appendedFileName);
|
||||||
|
|
||||||
|
// free the memory
|
||||||
|
NFDi_Free(appendedFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// free the memory
|
||||||
|
g_free(currentFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* NFD_GetError(void)
|
||||||
|
{
|
||||||
|
return g_errorstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_ClearError(void)
|
||||||
|
{
|
||||||
|
NFDi_SetError(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public */
|
||||||
|
nfdresult_t Init()
|
||||||
|
{
|
||||||
|
// Init GTK
|
||||||
|
if (!gtk_init_check(NULL, NULL))
|
||||||
|
{
|
||||||
|
NFDi_SetError("gtk_init_check failed to initilaize GTK+");
|
||||||
|
return nfdresult_t::ERROR;
|
||||||
|
}
|
||||||
|
return nfdresult_t::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_Quit(void)
|
||||||
|
{
|
||||||
|
// do nothing, GTK cannot be de-initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_FreePathN(char* filePath)
|
||||||
|
{
|
||||||
|
assert(filePath);
|
||||||
|
g_free(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogN(char** outPath, const item* filterList, uint_t filterCount, const char* defaultPath)
|
||||||
|
{
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Open File", nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, nullptr);
|
||||||
|
|
||||||
|
// guard to destroy the widget when returning from this function
|
||||||
|
Widget_Guard widgetGuard(widget);
|
||||||
|
|
||||||
|
/* Build the filter list */
|
||||||
|
AddFiltersToDialog(GTK_FILE_CHOOSER(widget), filterList, filterCount);
|
||||||
|
|
||||||
|
/* Set the default path */
|
||||||
|
SetDefaultPath(GTK_FILE_CHOOSER(widget), defaultPath);
|
||||||
|
|
||||||
|
if (gtk_dialog_run(GTK_DIALOG(widget)) == GTK_RESPONSE_ACCEPT)
|
||||||
|
{
|
||||||
|
// write out the file name
|
||||||
|
*outPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
|
||||||
|
return nfdresult_t::OKAY;
|
||||||
|
}
|
||||||
|
else return nfdresult_t::CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogMultipleN(const nfdpathset_t** outPaths, const item* filterList, uint_t filterCount, const char* defaultPath )
|
||||||
|
{
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Open Files", nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, nullptr);
|
||||||
|
|
||||||
|
// guard to destroy the widget when returning from this function
|
||||||
|
Widget_Guard widgetGuard(widget);
|
||||||
|
|
||||||
|
// set select multiple
|
||||||
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(widget), TRUE);
|
||||||
|
|
||||||
|
/* Build the filter list */
|
||||||
|
AddFiltersToDialog(GTK_FILE_CHOOSER(widget), filterList, filterCount);
|
||||||
|
|
||||||
|
/* Set the default path */
|
||||||
|
SetDefaultPath(GTK_FILE_CHOOSER(widget), defaultPath);
|
||||||
|
|
||||||
|
if (gtk_dialog_run(GTK_DIALOG(widget)) == GTK_RESPONSE_ACCEPT)
|
||||||
|
{
|
||||||
|
// write out the file name
|
||||||
|
GSList *fileList = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
|
||||||
|
*outPaths = fileList;
|
||||||
|
return nfdresult_t::OKAY;
|
||||||
|
}
|
||||||
|
else return nfdresult_t::CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_SaveDialogN(char** outPath, const item* filterList, uint_t filterCount, const char* defaultPath, const char* defaultName)
|
||||||
|
{
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Save File", nullptr, GTK_FILE_CHOOSER_ACTION_SAVE, "_Cancel", GTK_RESPONSE_CANCEL, nullptr);
|
||||||
|
|
||||||
|
// guard to destroy the widget when returning from this function
|
||||||
|
Widget_Guard widgetGuard(widget);
|
||||||
|
GtkWidget* saveButton = gtk_dialog_add_button(GTK_DIALOG(widget), "_Save", GTK_RESPONSE_ACCEPT);
|
||||||
|
|
||||||
|
// Prompt on overwrite
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(widget), TRUE);
|
||||||
|
|
||||||
|
/* Build the filter list */
|
||||||
|
ButtonClickedArgs buttonClickedArgs;
|
||||||
|
buttonClickedArgs.chooser = GTK_FILE_CHOOSER(widget);
|
||||||
|
buttonClickedArgs.map = AddFiltersToDialogWithMap(GTK_FILE_CHOOSER(widget), filterList, filterCount);
|
||||||
|
|
||||||
|
/* Set the default path */
|
||||||
|
SetDefaultPath(GTK_FILE_CHOOSER(widget), defaultPath);
|
||||||
|
|
||||||
|
/* Set the default file name */
|
||||||
|
SetDefaultName(GTK_FILE_CHOOSER(widget), defaultName);
|
||||||
|
|
||||||
|
/* set the handler to add file extension */
|
||||||
|
gulong handlerID = g_signal_connect(G_OBJECT(saveButton), "pressed", G_CALLBACK(FileActivatedSignalHandler), static_cast<void*>(&buttonClickedArgs));
|
||||||
|
|
||||||
|
/* invoke the dialog (blocks until dialog is closed) */
|
||||||
|
gint result = gtk_dialog_run(GTK_DIALOG(widget));
|
||||||
|
|
||||||
|
/* unset the handler */
|
||||||
|
g_signal_handler_disconnect(G_OBJECT(saveButton), handlerID);
|
||||||
|
|
||||||
|
/* free the filter map */
|
||||||
|
NFDi_Free(buttonClickedArgs.map);
|
||||||
|
|
||||||
|
if (result == GTK_RESPONSE_ACCEPT)
|
||||||
|
{
|
||||||
|
// write out the file name
|
||||||
|
*outPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
|
||||||
|
return nfdresult_t::OKAY;
|
||||||
|
}
|
||||||
|
else return nfdresult_t::CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PickFolderN(char** outPath, const char* defaultPath)
|
||||||
|
{
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Select folder", nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Cancel", GTK_RESPONSE_CANCEL, "_Select", GTK_RESPONSE_ACCEPT, nullptr);
|
||||||
|
|
||||||
|
// guard to destroy the widget when returning from this function
|
||||||
|
Widget_Guard widgetGuard(widget);
|
||||||
|
|
||||||
|
/* Set the default path */
|
||||||
|
SetDefaultPath(GTK_FILE_CHOOSER(widget), defaultPath);
|
||||||
|
|
||||||
|
if (gtk_dialog_run(GTK_DIALOG(widget)) == GTK_RESPONSE_ACCEPT)
|
||||||
|
{
|
||||||
|
// write out the file name
|
||||||
|
*outPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
|
||||||
|
return nfdresult_t::OKAY;
|
||||||
|
}
|
||||||
|
else return nfdresult_t::CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetCount(const nfdpathset_t* pathSet, uint_t* count)
|
||||||
|
{
|
||||||
|
assert(pathSet);
|
||||||
|
|
||||||
|
// const_cast because methods on GSList aren't const, but it should act like const to the caller
|
||||||
|
GSList*fileList = const_cast<GSList*>(static_cast<const GSList*>(pathSet));
|
||||||
|
|
||||||
|
*count = g_slist_length(fileList);
|
||||||
|
return nfdresult_t::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetPathN(const nfdpathset_t* pathSet, uint_t index, char** outPath)
|
||||||
|
{
|
||||||
|
assert(pathSet);
|
||||||
|
|
||||||
|
// const_cast because methods on GSList aren't const, but it should act like const to the caller
|
||||||
|
GSList* fileList = const_cast<GSList*>(static_cast<const GSList*>(pathSet));
|
||||||
|
|
||||||
|
// Note: this takes linear time... but should be good enough
|
||||||
|
*outPath = static_cast<char*>(g_slist_nth_data(fileList, index));
|
||||||
|
return nfdresult_t::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_FreePathN(const char* filePath)
|
||||||
|
{
|
||||||
|
assert(filePath);
|
||||||
|
// no-op, because NFD_PathSet_Free does the freeing for us
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_Free(const nfdpathset_t *pathSet)
|
||||||
|
{
|
||||||
|
assert(pathSet);
|
||||||
|
|
||||||
|
// const_cast because methods on GSList aren't const, but it should act like const to the caller
|
||||||
|
GSList* fileList = const_cast<GSList*>(static_cast<const GSList*>(pathSet));
|
||||||
|
|
||||||
|
// free all the nodes
|
||||||
|
for (GSList* node = fileList; node; node = node->next)
|
||||||
|
{
|
||||||
|
assert(node->data);
|
||||||
|
g_free(node->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// free the path set memory
|
||||||
|
g_slist_free(fileList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
244
src/monitor/libs/gtkfd.OLD/gtkfd.hpp
Normal file
244
src/monitor/libs/gtkfd.OLD/gtkfd.hpp
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory> // for std::unique_ptr
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include "monitor/utils/using.hpp"
|
||||||
|
|
||||||
|
namespace monitor::libs
|
||||||
|
{
|
||||||
|
class gtkfd
|
||||||
|
{
|
||||||
|
struct item
|
||||||
|
{
|
||||||
|
const char* m_name;
|
||||||
|
const char* m_spec;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
using nfdpathset_t = GSList;
|
||||||
|
|
||||||
|
struct item
|
||||||
|
{
|
||||||
|
const char* m_name;
|
||||||
|
const char* m_spec;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class nfdresult_t
|
||||||
|
{
|
||||||
|
OKAY, /* user pressed okay, or successful return */
|
||||||
|
ERROR, /* programmatic error */
|
||||||
|
CANCEL /* user pressed cancel */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* call this to de-initialize NFD, if NFD_Init returned NFD_OKAY */
|
||||||
|
void NFD_Quit(void);
|
||||||
|
|
||||||
|
/* free a file path that was returned by the dialogs */
|
||||||
|
/* Note: use NFD_PathSet_FreePath to free path from pathset instead of this function */
|
||||||
|
void NFD_FreePathN(char* filePath);
|
||||||
|
|
||||||
|
/* single file open dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathN() if this function returns NFD_OKAY */
|
||||||
|
/* If filterCount is zero, filterList is ignored (you can use NULL) */
|
||||||
|
/* If defaultPath is NULL, the operating system will decide */
|
||||||
|
nfdresult_t NFD_OpenDialogN(char** outPath, const item* filterList, uint_t filterCount, const char* defaultPath);
|
||||||
|
|
||||||
|
/* multiple file open dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPaths` via NFD_PathSet_Free() if this function returns NFD_OKAY */
|
||||||
|
/* If filterCount is zero, filterList is ignored (you can use NULL) */
|
||||||
|
/* If defaultPath is NULL, the operating system will decide */
|
||||||
|
nfdresult_t NFD_OpenDialogMultipleN(const nfdpathset_t** outPaths, const item* filterList, uint_t filterCount, const char* defaultPath);
|
||||||
|
|
||||||
|
/* save dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathN() if this function returns NFD_OKAY */
|
||||||
|
/* If filterCount is zero, filterList is ignored (you can use NULL) */
|
||||||
|
/* If defaultPath is NULL, the operating system will decide */
|
||||||
|
nfdresult_t NFD_SaveDialogN(char** outPath, const item* filterList, uint_t filterCount, const char* defaultPath, const char* defaultName);
|
||||||
|
|
||||||
|
/* select folder dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathN() if this function returns NFD_OKAY */
|
||||||
|
/* If defaultPath is NULL, the operating system will decide */
|
||||||
|
nfdresult_t NFD_PickFolderN(char** outPath, const char* defaultPath);
|
||||||
|
|
||||||
|
/* Get last error -- set when nfdresult_t returns NFD_ERROR */
|
||||||
|
/* Returns the last error that was set, or NULL if there is no error. */
|
||||||
|
/* The memory is owned by NFD and should not be freed by user code. */
|
||||||
|
/* This is *always* ASCII printable characters, so it can be interpreted as UTF-8 without any conversion. */
|
||||||
|
const char* NFD_GetError(void);
|
||||||
|
|
||||||
|
nfdresult_t Init();
|
||||||
|
|
||||||
|
/* clear the error */
|
||||||
|
void NFD_ClearError(void);
|
||||||
|
|
||||||
|
/* get the number of entries stored in pathSet */
|
||||||
|
/* note that some paths might be invalid (NFD_ERROR will be returned by NFD_PathSet_GetPath), so we might not actually have this number of usable paths */
|
||||||
|
nfdresult_t NFD_PathSet_GetCount(const nfdpathset_t* pathSet, uint_t* count);
|
||||||
|
|
||||||
|
/* Get the UTF-8 path at offset index */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_PathSet_FreePathN() if this function returns NFD_OKAY */
|
||||||
|
nfdresult_t NFD_PathSet_GetPathN(const nfdpathset_t* pathSet, uint_t index, char** outPath);
|
||||||
|
|
||||||
|
/* Free the path gotten by NFD_PathSet_GetPathN */
|
||||||
|
void NFD_PathSet_FreePathN(const char* filePath);
|
||||||
|
|
||||||
|
/* Free the pathSet */
|
||||||
|
void NFD_PathSet_Free(const nfdpathset_t* pathSet);
|
||||||
|
|
||||||
|
namespace gtkfd
|
||||||
|
{
|
||||||
|
inline nfdresult_t init() noexcept
|
||||||
|
{
|
||||||
|
return ::Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Quit() noexcept
|
||||||
|
{
|
||||||
|
::NFD_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void FreePath(char *outPath) noexcept
|
||||||
|
{
|
||||||
|
::NFD_FreePathN(outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nfdresult_t OpenDialog(char*& outPath, const item* filterList = nullptr, uint_t filterCount = 0, const char* defaultPath = nullptr) noexcept
|
||||||
|
{
|
||||||
|
return ::NFD_OpenDialogN(&outPath, filterList, filterCount, defaultPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nfdresult_t OpenDialogMultiple(const nfdpathset_t*& outPaths, const item* filterList = nullptr, uint_t filterCount = 0, const char* defaultPath = nullptr) noexcept
|
||||||
|
{
|
||||||
|
return ::NFD_OpenDialogMultipleN(&outPaths, filterList, filterCount, defaultPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nfdresult_t SaveDialog(char*& outPath, const item* filterList = nullptr, uint_t filterCount = 0, const char* defaultPath = nullptr, const char* defaultName = nullptr) noexcept
|
||||||
|
{
|
||||||
|
return ::NFD_SaveDialogN(&outPath, filterList, filterCount, defaultPath, defaultName);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nfdresult_t PickFolder(char*& outPath, const char* defaultPath = nullptr) noexcept
|
||||||
|
{
|
||||||
|
return ::NFD_PickFolderN(&outPath, defaultPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* GetError() noexcept
|
||||||
|
{
|
||||||
|
return ::NFD_GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ClearError() noexcept
|
||||||
|
{
|
||||||
|
::NFD_ClearError();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace PathSet
|
||||||
|
{
|
||||||
|
inline nfdresult_t Count(const nfdpathset_t* pathSet, uint_t& count) noexcept
|
||||||
|
{
|
||||||
|
return ::NFD_PathSet_GetCount(pathSet, &count);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nfdresult_t GetPath(const nfdpathset_t* pathSet, uint_t index, char*& outPath) noexcept
|
||||||
|
{
|
||||||
|
return ::NFD_PathSet_GetPathN(pathSet, index, &outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void FreePath(char* filePath) noexcept
|
||||||
|
{
|
||||||
|
::NFD_PathSet_FreePathN(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Free(const nfdpathset_t* pathSet) noexcept
|
||||||
|
{
|
||||||
|
::NFD_PathSet_Free(pathSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class guard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline guard() noexcept { init(); }
|
||||||
|
inline ~guard() noexcept { Quit(); }
|
||||||
|
|
||||||
|
// Not allowed to copy or move this class
|
||||||
|
guard(const guard&) = delete;
|
||||||
|
guard& operator=(const guard&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct PathDeleter
|
||||||
|
{
|
||||||
|
inline void operator()(T* ptr) const noexcept { FreePath(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::unique_ptr<char, PathDeleter<char>> UniquePath;
|
||||||
|
typedef std::unique_ptr<char, PathDeleter<char>> UniquePathN;
|
||||||
|
typedef std::unique_ptr<char, PathDeleter<char>> UniquePathU8;
|
||||||
|
|
||||||
|
struct PathSetDeleter
|
||||||
|
{
|
||||||
|
inline void operator()(const nfdpathset_t* ptr) const noexcept { PathSet::Free(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::unique_ptr<const nfdpathset_t, PathSetDeleter> UniquePathSet;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct PathSetPathDeleter
|
||||||
|
{
|
||||||
|
inline void operator()(T* ptr) const noexcept { PathSet::FreePath(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::unique_ptr<char, PathSetPathDeleter<char>> UniquePathSetPath;
|
||||||
|
typedef std::unique_ptr<char, PathSetPathDeleter<char>> UniquePathSetPathN;
|
||||||
|
typedef std::unique_ptr<char, PathSetPathDeleter<char>> UniquePathSetPathU8;
|
||||||
|
|
||||||
|
inline nfdresult_t OpenDialog(UniquePathN& outPath, const item* filterList = nullptr, uint_t filterCount = 0, const char* defaultPath = nullptr) noexcept
|
||||||
|
{
|
||||||
|
char* out;
|
||||||
|
nfdresult_t res = OpenDialog(out, filterList, filterCount, defaultPath);
|
||||||
|
if (res == nfdresult_t::OKAY) outPath.reset(out);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nfdresult_t OpenDialogMultiple(UniquePathSet& outPaths, const item* filterList = nullptr, uint_t filterCount = 0, const char* defaultPath = nullptr) noexcept
|
||||||
|
{
|
||||||
|
const nfdpathset_t* out;
|
||||||
|
nfdresult_t res = OpenDialogMultiple(out, filterList, filterCount, defaultPath);
|
||||||
|
if (res == nfdresult_t::OKAY) outPaths.reset(out);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nfdresult_t SaveDialog(UniquePathN& outPath, const item* filterList = nullptr, uint_t filterCount = 0, const char* defaultPath = nullptr, const char* defaultName = nullptr) noexcept
|
||||||
|
{
|
||||||
|
char* out;
|
||||||
|
nfdresult_t res = SaveDialog(out, filterList, filterCount, defaultPath, defaultName);
|
||||||
|
if (res == nfdresult_t::OKAY) outPath.reset(out);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nfdresult_t PickFolder(UniquePathN& outPath, const char* defaultPath = nullptr) noexcept
|
||||||
|
{
|
||||||
|
char* out;
|
||||||
|
nfdresult_t res = PickFolder(out, defaultPath);
|
||||||
|
if (res == nfdresult_t::OKAY) outPath.reset(out);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace PathSet
|
||||||
|
{
|
||||||
|
inline nfdresult_t Count(const UniquePathSet& uniquePathSet, uint_t& count) noexcept { return Count(uniquePathSet.get(), count); }
|
||||||
|
inline nfdresult_t GetPath(const UniquePathSet& uniquePathSet, uint_t index, UniquePathSetPathN& outPath) noexcept
|
||||||
|
{
|
||||||
|
char* out;
|
||||||
|
nfdresult_t res = GetPath(uniquePathSet.get(), index, out);
|
||||||
|
if (res == nfdresult_t::OKAY) outPath.reset(out);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
42
src/monitor/libs/gtkfd/gtkfd.cpp
Normal file
42
src/monitor/libs/gtkfd/gtkfd.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include "gtkfd.hpp"
|
||||||
|
#include <hack/logger/logger.hpp>
|
||||||
|
|
||||||
|
namespace monitor::libs
|
||||||
|
{
|
||||||
|
void WaitForCleanup()
|
||||||
|
{
|
||||||
|
while (gtk_events_pending()) gtk_main_iteration();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct widget_guard
|
||||||
|
{
|
||||||
|
GtkWidget* m_widget;
|
||||||
|
widget_guard(GtkWidget* w) : m_widget(w) {}
|
||||||
|
~widget_guard()
|
||||||
|
{
|
||||||
|
WaitForCleanup();
|
||||||
|
gtk_widget_destroy(m_widget);
|
||||||
|
WaitForCleanup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::filesystem::path gtkfd::open(const std::filesystem::path& default_path) noexcept
|
||||||
|
{
|
||||||
|
std::filesystem::path out_path;
|
||||||
|
if (!gtk_init_check(NULL, NULL))
|
||||||
|
{
|
||||||
|
hack::error()("Failed init gtk");
|
||||||
|
return out_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Open File", nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, nullptr);
|
||||||
|
widget_guard wg(widget);
|
||||||
|
|
||||||
|
// set the default path
|
||||||
|
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(widget), default_path.c_str());
|
||||||
|
|
||||||
|
if (gtk_dialog_run(GTK_DIALOG(widget)) == GTK_RESPONSE_ACCEPT)
|
||||||
|
out_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
|
||||||
|
return out_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/monitor/libs/gtkfd/gtkfd.hpp
Normal file
19
src/monitor/libs/gtkfd/gtkfd.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
namespace monitor::libs
|
||||||
|
{
|
||||||
|
class gtkfd
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
gtkfd() = default;
|
||||||
|
~gtkfd() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::filesystem::path open(const std::filesystem::path& default_path) noexcept;
|
||||||
|
std::filesystem::path save(const std::filesystem::path& default_path, const std::string& default_name) noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@@ -5,6 +5,8 @@ namespace monitor::utils
|
|||||||
enum class event_type
|
enum class event_type
|
||||||
{
|
{
|
||||||
CREATE_SNAPSHOT,
|
CREATE_SNAPSHOT,
|
||||||
|
CREATE_SNAPSHOT_COMPLETED,
|
||||||
|
|
||||||
SET_AUDIO_POSITION,
|
SET_AUDIO_POSITION,
|
||||||
AUDIO_PAUSE,
|
AUDIO_PAUSE,
|
||||||
AUDIO_STOP,
|
AUDIO_STOP,
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <hack/logger/logger.hpp>
|
#include <hack/logger/logger.hpp>
|
||||||
|
|
||||||
#include "noinc.hpp"
|
|
||||||
|
|
||||||
namespace monitor::utils::var
|
namespace monitor::utils::var
|
||||||
{
|
{
|
||||||
const std::size_t MAX_RENDER_SIZE = 1'200'000;
|
const std::size_t MAX_RENDER_SIZE = 1'200'000;
|
||||||
|
|||||||
Reference in New Issue
Block a user