Files
vimix/src/ImGuiVisitor.cpp
2025-04-05 11:04:54 +02:00

2116 lines
79 KiB
C++

/*
* This file is part of vimix - video live mixer
*
* **Copyright** (C) 2019-2023 Bruno Herbelin <bruno.herbelin@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
**/
#include <vector>
#include <iomanip>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/constants.hpp>
#include <glm/gtc/matrix_access.hpp>
#include <tinyxml2.h>
#include "imgui.h"
#include "imgui_internal.h"
#include "Log.h"
#include "defines.h"
#include "Scene.h"
#include "Primitives.h"
//#include "ImageShader.h"
#include "ImageProcessingShader.h"
#include "MediaPlayer.h"
#include "MediaSource.h"
#include "CloneSource.h"
#include "FrameBufferFilter.h"
#include "DelayFilter.h"
#include "ImageFilter.h"
#include "RenderSource.h"
#include "SessionSource.h"
#include "PatternSource.h"
#include "DeviceSource.h"
#include "ScreenCaptureSource.h"
#include "NetworkSource.h"
#include "SrtReceiverSource.h"
#include "MultiFileSource.h"
#include "TextSource.h"
#include "ShaderSource.h"
#include "SessionCreator.h"
#include "SessionVisitor.h"
#include "Settings.h"
#include "Mixer.h"
#include "MixingGroup.h"
#include "ActionManager.h"
#include "Mixer.h"
#include "imgui.h"
#include "ImGuiToolkit.h"
#include "BaseToolkit.h"
#include "UserInterfaceManager.h"
#include "SystemToolkit.h"
#include "ImGuiVisitor.h"
ImGuiVisitor::ImGuiVisitor()
{
}
void ImGuiVisitor::visit(Node &)
{
}
void ImGuiVisitor::visit(Group &n)
{
// MODEL VIEW
ImGui::PushID(std::to_string(n.id()).c_str());
if (ImGuiToolkit::ButtonIcon(1, 16)) {
n.translation_.x = 0.f;
n.translation_.y = 0.f;
n.rotation_.z = 0.f;
n.scale_.x = 1.f;
n.scale_.y = 1.f;
Action::manager().store("Geometry Reset");
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Geometry");
if (ImGuiToolkit::ButtonIcon(6, 15)) {
n.translation_.x = 0.f;
n.translation_.y = 0.f;
Action::manager().store("Position 0.0, 0.0");
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
float translation[2] = { n.translation_.x, n.translation_.y};
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if ( ImGui::SliderFloat2("Position", translation, -5.0, 5.0) )
{
n.translation_.x = translation[0];
n.translation_.y = translation[1];
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Position " << std::setprecision(3) << n.translation_.x << ", " << n.translation_.y;
Action::manager().store(oss.str());
}
if (ImGuiToolkit::ButtonIcon(3, 15)) {
n.scale_.x = 1.f;
n.scale_.y = 1.f;
Action::manager().store("Scale 1.0 x 1.0");
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
float scale[2] = { n.scale_.x, n.scale_.y} ;
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if ( ImGui::SliderFloat2("Scale", scale, -MAX_SCALE, MAX_SCALE, "%.2f") )
{
n.scale_.x = CLAMP_SCALE(scale[0]);
n.scale_.y = CLAMP_SCALE(scale[1]);
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Scale " << std::setprecision(3) << n.scale_.x << " x " << n.scale_.y;
Action::manager().store(oss.str());
}
if (ImGuiToolkit::ButtonIcon(18, 9)){
n.rotation_.z = 0.f;
Action::manager().store("Angle 0.0");
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::SliderAngle("Angle", &(n.rotation_.z), -180.f, 180.f) ;
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << "Angle " << std::setprecision(3) << n.rotation_.z * 180.f / M_PI;
Action::manager().store(oss.str());
}
ImGui::PopID();
// spacing
ImGui::Spacing();
}
void ImGuiVisitor::visit(Switch &n)
{
if (n.numChildren()>0)
n.activeChild()->accept(*this);
}
void ImGuiVisitor::visit(Scene &n)
{
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::CollapsingHeader("Scene Property Tree"))
{
n.root()->accept(*this);
}
}
void ImGuiVisitor::visit(Primitive &n)
{
ImGui::PushID(std::to_string(n.id()).c_str());
ImGui::Text("Primitive");
n.shader()->accept(*this);
ImGui::PopID();
}
void ImGuiVisitor::visit(FrameBufferSurface &)
{
ImGui::Text("Framebuffer");
}
void ImGuiVisitor::visit(MediaPlayer &)
{
ImGui::Text("Media Player");
}
void ImGuiVisitor::visit(Shader &n)
{
ImGui::PushID(std::to_string(n.id()).c_str());
// Base color
// if (ImGuiToolkit::ButtonIcon(10, 2)) {
// n.blending = Shader::BLEND_OPACITY;
// n.color = glm::vec4(1.f, 1.f, 1.f, 1.f);
// }
// ImGui::SameLine(0, IMGUI_SAME_LINE);
// ImGui::ColorEdit3("Color", glm::value_ptr(n.color), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel ) ;
// ImGui::SameLine(0, 5);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int mode = n.blending;
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGuiToolkit::ComboIcon("Blending", &mode, Shader::blendingFunction) )
{
n.blending = Shader::BlendMode(mode);
oss << "Blending " << std::get<2>(Shader::blendingFunction[mode]).c_str();
Action::manager().store(oss.str());
}
ImGui::PopID();
}
void ImGuiVisitor::visit(ImageProcessingShader &n)
{
ImGuiIO& io = ImGui::GetIO();
ImGui::PushID(std::to_string(n.id()).c_str());
///
/// GAMMA
///
ImGui::ColorEdit3("Gamma Color", glm::value_ptr(n.gamma), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel) ;
if (ImGui::IsItemDeactivatedAfterEdit()) {
char buf[64];
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp((int)ceil(255.f * n.gamma.x),0,255),
ImClamp((int)ceil(255.f * n.gamma.y),0,255), ImClamp((int)ceil(255.f * n.gamma.z),0,255));
oss << "Gamma color " << buf;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
float val = log10f(n.gamma.w);
if ( ImGui::SliderFloat("##Gamma", &val, -1.f, 1.f, "%.3f", 2.f) )
n.gamma.w = powf(10.f, val);
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
val = CLAMP(val + 0.001f * io.MouseWheel, -1.f, 1.f);
n.gamma.w = powf(10.f, val);
oss << "Gamma " << std::setprecision(3) << val;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Gamma " << std::setprecision(3) << val;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Gamma")) {
n.gamma = glm::vec4(1.f, 1.f, 1.f, 1.f);
oss << "Gamma 0.0, #FFFFFF";
Action::manager().store(oss.str());
}
///
/// BRIGHTNESS
///
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::SliderFloat("##Brightness", &n.brightness, -1.0, 1.0, "%.3f", 2.f);
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
n.brightness = CLAMP(n.brightness + 0.001f * io.MouseWheel, -1.f, 1.f);
oss << "Brightness " << std::setprecision(3) << n.brightness;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Brightness " << std::setprecision(3) << n.brightness;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Brightness")) {
n.brightness = 0.f;
oss << "Brightness " << std::setprecision(2) << n.brightness;
Action::manager().store(oss.str());
}
///
/// CONTRAST
///
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::SliderFloat("##Contrast", &n.contrast, -1.0, 1.0, "%.3f", 2.f);
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
n.contrast = CLAMP(n.contrast + 0.001f * io.MouseWheel, -1.f, 1.f);
oss << "Contrast " << std::setprecision(3) << n.contrast;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Contrast " << std::setprecision(3) << n.contrast;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Contrast")) {
n.contrast = 0.f;
oss << "Contrast " << std::setprecision(2) << n.contrast;
Action::manager().store(oss.str());
}
///
/// SATURATION
///
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::SliderFloat("##Saturation", &n.saturation, -1.0, 1.0, "%.3f", 2.f);
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
n.saturation = CLAMP(n.saturation + 0.001f * io.MouseWheel, -1.f, 1.f);
oss << "Saturation " << std::setprecision(3) << n.saturation;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Saturation " << std::setprecision(3) << n.saturation;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Saturation")) {
n.saturation = 0.f;
oss << "Saturation " << std::setprecision(2) << n.saturation;
Action::manager().store(oss.str());
}
///
/// HUE SHIFT
///
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::SliderFloat("##Hue", &n.hueshift, 0.0, 1.0, "%.3f");
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
n.hueshift = CLAMP(n.hueshift + 0.001f * io.MouseWheel, 0.f, 1.f);
oss << "Hue shift " << std::setprecision(3) << n.hueshift;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Hue shift " << std::setprecision(3) << n.hueshift;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Hue ")) {
n.hueshift = 0.f;
oss << "Hue shift " << std::setprecision(2) << n.hueshift;
Action::manager().store(oss.str());
}
///
/// POSTERIZATION
///
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
float posterized = n.nbColors < 1 ? 257.f : n.nbColors;
if (ImGui::SliderFloat("##Posterize", &posterized, 257.f, 1.f, posterized > 256.f ? "Full range" : "%.0f colors", 0.5f)) {
n.nbColors = posterized > 256 ? 0.f : posterized;
}
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
n.nbColors = CLAMP( n.nbColors + io.MouseWheel, 1.f, 257.f);
if (n.nbColors == 0) oss << "Full range"; else oss << n.nbColors;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Posterize ";
if (n.nbColors == 0) oss << "Full range"; else oss << n.nbColors;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Posterize ")) {
n.nbColors = 0.f;
oss << "Posterize Full range";
Action::manager().store(oss.str());
}
///
/// THRESHOLD
///
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
float threshold = n.threshold < 0.001f ? 0.f : n.threshold;
if (ImGui::SliderFloat("##Threshold", &threshold, 0.f, 1.f, threshold < 0.001f ? "None" : "%.3f") ){
n.threshold = threshold < 0.001f ? 0.f : threshold;
}
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
n.threshold = CLAMP(n.threshold + 0.001f * io.MouseWheel, 0.f, 1.f);
if (n.threshold < 0.001f) oss << "None"; else oss << std::setprecision(3) << n.threshold;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Threshold ";
if (n.threshold < 0.001f) oss << "None"; else oss << std::setprecision(3) << n.threshold;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Threshold ")) {
n.threshold = 0.f;
oss << "Threshold None";
Action::manager().store(oss.str());
}
///
/// INVERSION
///
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::Combo("##Invert", &n.invert, "None\0Color RGB\0Luminance\0"))
Action::manager().store("Invert " + std::string(n.invert<1 ? "None": (n.invert>1 ? "Luminance" : "Color")));
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Invert ")) {
n.invert = 0;
oss << "Invert None";
Action::manager().store(oss.str());
}
ImGui::PopID();
ImGui::Spacing();
}
void ImGuiVisitor::visit (Source& s)
{
const float preview_width = ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
const float preview_height = 4.5f * ImGui::GetFrameHeightWithSpacing();
const float space = ImGui::GetStyle().ItemSpacing.y;
ImGui::PushID(std::to_string(s.id()).c_str());
oss = std::ostringstream();
oss << s.name() << ": ";
// blending selection
Shader::BlendMode prevblend = s.blendingShader()->blending;
s.blendingShader()->accept(*this);
if (s.blendingShader()->blending != prevblend)
s.touch();
// Draw different info if failed or succeed
if ( !s.failed() ) {
// remember where we were...
ImVec2 pos = ImGui::GetCursorPos();
// preview
float width = preview_width;
float height = s.frame()->projectionSize().y * width / ( s.frame()->projectionSize().x * s.frame()->aspectRatio());
if (height > preview_height - space) {
height = preview_height - space;
width = height * s.frame()->aspectRatio() * ( s.frame()->projectionSize().x / s.frame()->projectionSize().y);
}
// centered image
if (s.ready()) {
ImGui::SetCursorPos( ImVec2(pos.x + 0.5f * (preview_width-width), pos.y + 0.5f * (preview_height-height-space)) );
ImGui::Image((void*)(uintptr_t) s.frame()->texture(), ImVec2(width, height));
} else {
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
ImGui::SetCursorPos(
ImVec2(pos.x + (preview_width - ImGui::GetFrameHeight()) * 0.5f,
pos.y + (preview_height - ImGui::GetFrameHeight()) * 0.5f));
ImGui::Text(ICON_FA_HOURGLASS_HALF);
ImGui::PopFont();
}
// inform on visibility status
ImGui::SetCursorPos( ImVec2(preview_width + 20, pos.y ) );
if (s.active()) {
if (s.blendingShader()->color.a > 0.f)
ImGuiToolkit::Indication("Visible", ICON_FA_SUN);
else
ImGuiToolkit::Indication("not Visible", ICON_FA_MOON);
}
else
ImGuiToolkit::Indication("Inactive", ICON_FA_SNOWFLAKE);
// Inform on link
ImGui::SetCursorPos( ImVec2(preview_width + 20, pos.y + ImGui::GetFrameHeightWithSpacing()) );
if (s.mixingGroup() != nullptr) {
if (ImGuiToolkit::IconButton(ICON_FA_LINK, "Linked")){
Mixer::selection().clear();
Mixer::selection().add( s.mixingGroup()->getCopy() );
UserInterface::manager().setView(View::MIXING);
}
}
else
ImGuiToolkit::Indication("not Linked", ICON_FA_UNLINK);
// Inform on workspace
ImGui::SetCursorPos( ImVec2(preview_width + 20, pos.y + 2.1f * ImGui::GetFrameHeightWithSpacing()) );
static std::map< int, std::pair<int, std::string> > workspaces_ {
{ Source::WORKSPACE_BACKGROUND, {10, "in Background"}},
{ Source::WORKSPACE_CENTRAL, {11, "in Workspace"}},
{ Source::WORKSPACE_FOREGROUND, {12, "in Foreground"}}
};
// in Geometry view, offer to switch current workspace to the source workspace
if (Settings::application.current_view == View::GEOMETRY) {
if (ImGuiToolkit::IconButton( workspaces_[s.workspace()].first, 16, workspaces_[s.workspace()].second.c_str())) {
Settings::application.current_workspace=s.workspace();
Mixer::manager().setCurrentSource(s.id());
}
}
// otherwise in other views, just draw in indicator
else
ImGuiToolkit::Indication(workspaces_[s.workspace()].second.c_str(), workspaces_[s.workspace()].first, 16);
// locking
ImGui::SetCursorPos( ImVec2(preview_width + 20, pos.y + preview_height - ImGui::GetFrameHeightWithSpacing()) );
static const char *tooltip[2] = {"Unlocked", "Locked"};
bool l = s.locked();
if (ImGuiToolkit::IconToggle(15, 6, 17, 6, &l, tooltip ) ) {
s.setLocked(l);
if (l) {
Mixer::selection().clear();
oss << "Locked";
}
else {
Mixer::selection().set(&s);
oss << "Unlocked";
}
Action::manager().store(oss.str());
}
// Filter
bool on = s.imageProcessingEnabled();
ImGui::SetCursorPos( ImVec2( pos.x, pos.y + preview_height));
if (on)
ImGui::Text(ICON_FA_PALETTE " Color correction");
else
ImGuiToolkit::Indication("Color correction filter is disabled", ICON_FA_PALETTE " Color correction");
pos = ImGui::GetCursorPos();
// menu icon for image processing
ImGui::SameLine(preview_width, 2 * IMGUI_SAME_LINE);
static uint counter_menu_timeout = 0;
if (ImGuiToolkit::IconButton(5, 8) || ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) {
counter_menu_timeout=0;
ImGui::OpenPopup( "MenuImageProcessing" );
}
if (ImGui::BeginPopup( "MenuImageProcessing" ))
{
if (ImGui::MenuItem("Enable", NULL, &on)) {
oss << ( on ? "Enable Color correction" : "Disable Color correction");
Action::manager().store(oss.str());
s.setImageProcessingEnabled(on);
}
if (s.processingshader_link_.connected()) {
if (ImGui::MenuItem( "Unfollow", NULL, false, on)){
s.processingshader_link_.disconnect();
}
}
else {
if (ImGui::MenuItem("Reset", NULL, false, on )){
ImageProcessingShader defaultvalues;
s.processingShader()->copy(defaultvalues);
s.processingshader_link_.disconnect();
oss << "Reset Filter";
Action::manager().store(oss.str());
}
if (ImGui::MenuItem("Copy", NULL, false, on )){
std::string clipboard = SessionVisitor::getClipboard(s.processingShader());
if (!clipboard.empty())
ImGui::SetClipboardText(clipboard.c_str());
}
const char *clipboard = ImGui::GetClipboardText();
const bool can_paste = (clipboard != nullptr && SessionLoader::isClipboard(clipboard));
if (ImGui::MenuItem("Paste", NULL, false, can_paste)) {
SessionLoader::applyImageProcessing(s, clipboard);
oss << "Change Filter";
Action::manager().store(oss.str());
}
// // NON-stable style follow mechanism
// ImGui::Separator();
// if (ImGui::BeginMenu("Follow", on))
// {
// for (auto mpit = Mixer::manager().session()->begin();
// mpit != Mixer::manager().session()->end(); mpit++ )
// {
// std::string label = (*mpit)->name();
// if ( (*mpit)->id() != s.id() &&
// (*mpit)->imageProcessingEnabled() &&
// !(*mpit)->processingshader_link_.connected()) {
// if (ImGui::MenuItem( label.c_str() )){
// s.processingshader_link_.connect(*mpit);
// s.touch();
// }
// }
// }
// ImGui::EndMenu();
// }
}
if (ImGui::IsWindowHovered())
counter_menu_timeout=0;
else if (++counter_menu_timeout > 10)
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (s.imageProcessingEnabled()) {
// full panel for image processing
ImGui::SetCursorPos( pos );
ImGui::Spacing();
if (s.processingshader_link_.connected()) {
Source *target = s.processingshader_link_.source();
ImGui::Text("Following");
if ( target != nullptr && ImGui::Button(target->name().c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
Mixer::manager().setCurrentSource(target);
}
else
s.processingShader()->accept(*this);
}
}
else {
// remember where we were...
ImVec2 pos = ImGui::GetCursorPos();
// preview (black texture)
float width = preview_width;
float height = s.frame()->projectionSize().y * width / ( s.frame()->projectionSize().x * s.frame()->aspectRatio());
if (height > preview_height - space) {
height = preview_height - space;
width = height * s.frame()->aspectRatio() * ( s.frame()->projectionSize().x / s.frame()->projectionSize().y);
}
// centered image
ImGui::SetCursorPos( ImVec2(pos.x + 0.5f * (preview_width-width), pos.y + 0.5f * (preview_height-height-space)) );
ImGui::Image((void*)(uintptr_t) s.frame()->texture(), ImVec2(width, height));
// centered icon of failed (skull)
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
ImGui::SetCursorPos( ImVec2(pos.x + (preview_width -ImGui::GetFrameHeight())* 0.5f ,
pos.y + (preview_height -ImGui::GetFrameHeight()) * 0.5f) );
ImGui::Text(ICON_FA_SKULL);
ImGui::PopFont();
// back
ImGui::SetCursorPos( ImVec2( pos.x, pos.y + preview_height));
}
ImGui::PopID();
ImGui::Spacing();
ImGuiToolkit::Icon(s.icon().x, s.icon().y);
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("%s", s.info().c_str());
}
void ImGuiVisitor::visit (MediaSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// Media info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip( s.path().c_str() );
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() ) {
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
top.x += ImGui::GetFrameHeight();
}
ImGui::SetCursorPos(top);
if (ImGuiToolkit::IconButton(3, 5, "Show in finder"))
SystemToolkit::open(SystemToolkit::path_filename(s.path()));
MediaPlayer *mp = s.mediaplayer();
if (mp && !mp->isImage()) {
// information on gstreamer effect filter
if ( mp->videoEffectAvailable() && !mp->videoEffect().empty()) {
top.x += ImGui::GetFrameHeight();
ImGui::SetCursorPos(top);
std::string desc = mp->videoEffect();
desc = desc.substr(0, desc.find_first_of(' '));
desc = "Has gstreamer effect '" + desc + "'";
ImGuiToolkit::Indication(desc.c_str(),16,16);
}
ImGui::SetCursorPos(botom);
// Selector for Hardware or software decoding, if available
if ( Settings::application.render.gpu_decoding ) {
// Build string information on decoder name with icon HW/SW
bool hwdec = !mp->softwareDecodingForced();
std::string decoder = mp->decoderName();
if (hwdec) {
if ( decoder.compare("software") != 0)
decoder = ICON_FA_MICROCHIP " Hardware (" + decoder + ")";
else
decoder = ICON_FA_COGS " Software";
}
else
decoder = ICON_FA_COGS " Software only";
// Combo selector shoing the current state and the option to choose
// between auto select and forced software decoding
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("Decoding", decoder.c_str() ) )
{
if (ImGui::Selectable( ICON_FA_MICROCHIP " / " ICON_FA_COGS " Auto select", &hwdec ))
mp->setSoftwareDecodingForced(false);
if (ImGui::IsItemHovered() && !hwdec)
ImGuiToolkit::ToolTip( "Changing decoding will\nre-open the media" );
hwdec = mp->softwareDecodingForced();
if (ImGui::Selectable( ICON_FA_COGS " Software only", &hwdec ))
mp->setSoftwareDecodingForced(true);
if (ImGui::IsItemHovered() && !hwdec)
ImGuiToolkit::ToolTip( "Changing decoding will\nre-open the media" );
ImGui::EndCombo();
}
}
else {
// info of software only decoding if disabled
ImGuiToolkit::Icon(14,2,false);
ImGui::SameLine();
ImGui::TextDisabled("Hardware decoding disabled");
}
}
else
ImGui::SetCursorPos(botom);
}
else {
// failed
ImGui::SetCursorPos(top);
if (ImGuiToolkit::IconButton(ICON_FA_COPY, "Copy message"))
ImGui::SetClipboardText(info.str().c_str());
info.reset();
ImGui::SetCursorPos(botom);
// because sometimes the error comes from gpu decoding
if ( Settings::application.render.gpu_decoding &&
SystemToolkit::file_exists(s.path()) &&
!s.mediaplayer()->softwareDecodingForced() )
{
// offer to reload the source without hardware decoding
if ( ImGui::Button( ICON_FA_REDO_ALT " Try again ", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) {
// replace current source with one created with a flag forcing software decoding
Mixer::manager().replaceSource(Mixer::manager().currentSource(),
Mixer::manager().createSourceFile(s.path(), true));
}
}
}
}
void ImGuiVisitor::visit (SessionFileSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip( s.path().c_str() );
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() && s.session() != nullptr ) {
if ( s.active() && s.session()->ready() ) {
// versions
SessionSnapshots *versions = s.session()->snapshots();
if (versions->keys_.size()>0) {
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("Version", ICON_FA_CODE_BRANCH " Select" ) )
{
for (auto v = versions->keys_.crbegin() ; v != versions->keys_.crend(); ++v){
std::string label = std::to_string(*v);
const tinyxml2::XMLElement *snap = versions->xmlDoc_->FirstChildElement( SNAPSHOT_NODE(*v).c_str() );
if (snap)
label = snap->Attribute("label");
if (ImGui::Selectable( label.c_str() )) {
s.session()->applySnapshot(*v);
}
}
ImGui::EndCombo();
}
}
// fading
int f = 100 - int(s.session()->fading() * 100.f);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::SliderInt("##Fading", &f, 0, 100, f > 99 ? ICON_FA_ADJUST " None" : ICON_FA_ADJUST " %d %%") )
s.session()->setFadingTarget( float(100 - f) * 0.01f );
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << "Fading " << f << " %";
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Fading")) {
s.session()->setFadingTarget(0.f);
oss << "Fading 0 %";
Action::manager().store(oss.str());
}
// import
if ( ImGui::Button( ICON_FA_FILE_EXPORT " Import all", ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
Mixer::manager().import( &s );
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Sources");
// file open
if ( ImGui::Button( ICON_FA_FILE_UPLOAD " Open", ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
Mixer::manager().set( s.detach() );
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Session");
botom = ImGui::GetCursorPos();
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
top.x += ImGui::GetFrameHeight();
}
}
else
{
// file open
if ( ImGui::Button( ICON_FA_ARROW_CIRCLE_RIGHT " Transition", ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
{
TransitionView *tv = static_cast<TransitionView*>(Mixer::manager().view(View::TRANSITION));
tv->attach(&s);
Mixer::manager().setView(View::TRANSITION);
WorkspaceWindow::clearWorkspace();
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Session");
botom = ImGui::GetCursorPos();
}
ImGui::SetCursorPos(top);
if (ImGuiToolkit::IconButton(3, 5, "Show in finder"))
SystemToolkit::open(SystemToolkit::path_filename(s.path()));
}
else
info.reset();
ImGui::SetCursorPos(botom);
}
void ImGuiVisitor::visit (SessionGroupSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
Session *session = s.session();
if (session == nullptr)
return;
// info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
// Show list of sources in text bloc (multi line, dark background)
ImGuiTextBuffer listofsources;
listofsources.append( BaseToolkit::joinned( session->getNameList(), '\n').c_str() );
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f));
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::InputTextMultiline("##sourcesingroup", (char *)listofsources.c_str(), listofsources.size(),
ImVec2(IMGUI_RIGHT_ALIGN, CLAMP(session->size(), 2, 5) * ImGui::GetTextLineHeightWithSpacing()),
ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor(1);
if ( ImGui::Button( ICON_FA_SIGN_OUT_ALT " Expand", ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
Mixer::manager().import( &s );
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Sources");
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() ) {
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
}
}
else
info.reset();
ImGui::SetCursorPos(botom);
}
void ImGuiVisitor::visit (RenderSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
// loopback provenance
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) s.renderingProvenance();
if (ImGuiToolkit::ComboIcon("##SelectRender", &m, RenderSource::ProvenanceMethod))
s.setRenderingProvenance((RenderSource::RenderSourceProvenance)m);
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() ) {
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
top.x += ImGui::GetFrameHeight();
}
// icon to open output view
ImGui::SetCursorPos(top);
if (ImGuiToolkit::IconButton(ICON_FA_DESKTOP, "Open Display"))
Settings::application.widget.preview = true;
}
else
info.reset();
ImGui::SetCursorPos(botom);
}
void ImGuiVisitor::visit (FrameBufferFilter&)
{
}
void ImGuiVisitor::visit (PassthroughFilter&)
{
}
void ImGuiVisitor::visit (DelayFilter& f)
{
ImGuiIO& io = ImGui::GetIO();
// if (ImGuiToolkit::IconButton(ICON_FILTER_DELAY)) {
// f.setDelay(0.f);
// Action::manager().store("Delay 0 s");
// }
// ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
float d = f.delay();
if (ImGui::SliderFloat("##Delay", &d, 0.f, 2.f, "%.2f s"))
f.setDelay(d);
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
d = CLAMP( d + 0.01f * io.MouseWheel, 0.f, 2.f);
f.setDelay(d);
oss << "Delay " << std::setprecision(3) << d << " s";
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << "Delay " << std::setprecision(3) << d << " s";
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Delay ")) {
f.setDelay(0.5f);
oss << "Delay 0.5 s";
Action::manager().store(oss.str());
}
}
void ImGuiVisitor::visit (ResampleFilter& f)
{
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) f.factor();
if (ImGui::Combo("##Factor", &m, ResampleFilter::factor_label, IM_ARRAYSIZE(ResampleFilter::factor_label) )) {
f.setFactor( m );
oss << "Resample " << ResampleFilter::factor_label[m];
Action::manager().store(oss.str());
info.reset();
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Factor")) {
f.setFactor( 0 );
oss << "Resample " << ResampleFilter::factor_label[0];
Action::manager().store(oss.str());
info.reset();
}
}
void list_parameters_(ImageFilter &f, std::ostringstream &oss)
{
ImGuiIO& io = ImGui::GetIO();
std::map<std::string, float> filter_parameters = f.program().parameters();
for (auto param = filter_parameters.rbegin(); param != filter_parameters.rend(); ++param)
{
ImGui::PushID( param->first.c_str() );
float v = param->second;
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::SliderFloat( "##ImageFilterParameterEdit", &v, 0.f, 1.f, "%.2f")) {
f.setProgramParameter(param->first, v);
}
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
v = CLAMP( v + 0.01f * io.MouseWheel, 0.f, 1.f);
f.setProgramParameter(param->first, v);
oss << " " << param->first << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << " " << param->first << " " << std::setprecision(3) <<param->second;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton( param->first.c_str() )) {
v = 0.5f;
f.setProgramParameter(param->first, v);
oss << " " << param->first << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
ImGui::PopID();
}
}
void ImGuiVisitor::visit (BlurFilter& f)
{
oss << "Blur ";
// Method selection
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) f.method();
if (ImGui::Combo("##MethodBlur", &m, BlurFilter::method_label, IM_ARRAYSIZE(BlurFilter::method_label) )) {
f.setMethod( m );
oss << BlurFilter::method_label[m];
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Method")) {
f.setMethod( 0 );
oss << BlurFilter::method_label[0];
Action::manager().store(oss.str());
}
// List of parameters
list_parameters_(f, oss);
}
void ImGuiVisitor::visit (SharpenFilter& f)
{
oss << "Sharpen ";
// Method selection
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) f.method();
if (ImGui::Combo("##MethodSharpen", &m, SharpenFilter::method_label, IM_ARRAYSIZE(SharpenFilter::method_label) )) {
f.setMethod( m );
oss << SharpenFilter::method_label[m];
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Method")) {
f.setMethod( 0 );
oss << SharpenFilter::method_label[0];
Action::manager().store(oss.str());
}
// List of parameters
list_parameters_(f, oss);
}
void ImGuiVisitor::visit (SmoothFilter& f)
{
oss << "Smooth ";
// Method selection
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) f.method();
if (ImGui::Combo("##MethodSmooth", &m, SmoothFilter::method_label, IM_ARRAYSIZE(SmoothFilter::method_label) )) {
f.setMethod( m );
oss << SmoothFilter::method_label[m];
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Method")) {
f.setMethod( 0 );
oss << SmoothFilter::method_label[0];
Action::manager().store(oss.str());
}
// List of parameters
list_parameters_(f, oss);
}
void ImGuiVisitor::visit (EdgeFilter& f)
{
oss << "Edge ";
// Method selection
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) f.method();
if (ImGui::Combo("##MethodEdge", &m, EdgeFilter::method_label, IM_ARRAYSIZE(EdgeFilter::method_label) )) {
f.setMethod( m );
oss << EdgeFilter::method_label[m];
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Method")) {
f.setMethod( 0 );
oss << EdgeFilter::method_label[0];
Action::manager().store(oss.str());
}
// List of parameters
list_parameters_(f, oss);
}
void ImGuiVisitor::visit (AlphaFilter& f)
{
ImGuiIO& io = ImGui::GetIO();
oss << "Alpha ";
// Alpha operation selection
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) f.operation();
if (ImGui::Combo("##Operation", &m, AlphaFilter::operation_label, IM_ARRAYSIZE(AlphaFilter::operation_label) )) {
f.setOperation( m );
oss << AlphaFilter::operation_label[m];
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Operation")) {
f.setOperation( 0 );
oss << AlphaFilter::operation_label[0];
Action::manager().store(oss.str());
}
// List of parameters
std::map<std::string, float> filter_parameters = f.program().parameters();
if ( m == AlphaFilter::ALPHA_CHROMAKEY || m == AlphaFilter::ALPHA_LUMAKEY)
{
float v = filter_parameters["Tolerance"];
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::SliderFloat( "##Tolerance", &v, 0.f, 1.f, "%.2f")) {
f.setProgramParameter("Tolerance", v);
}
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
v = CLAMP( v + 0.01f * io.MouseWheel, 0.f, 1.f);
f.setProgramParameter("Tolerance", v);
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Tolerance" << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Tolerance" << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Tolerance")) {
v = 0.f;
f.setProgramParameter("Tolerance", v);
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Tolerance" << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
float t = filter_parameters["Threshold"];
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::SliderFloat( "##Threshold", &t, 0.f, 1.f, "%.2f")) {
f.setProgramParameter("Threshold", t);
}
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
t = CLAMP( t + 0.01f * io.MouseWheel, 0.f, 1.f);
f.setProgramParameter("Threshold", t);
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Threshold" << " " << std::setprecision(3) << t;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Threshold" << " " << std::setprecision(3) << t;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Threshold")) {
t = 0.f;
f.setProgramParameter("Threshold", t);
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Threshold" << " " << std::setprecision(3) << t;
Action::manager().store(oss.str());
}
}
if ( m == AlphaFilter::ALPHA_CHROMAKEY || m == AlphaFilter::ALPHA_FILL)
{
// read color from filter
float color[3] = {filter_parameters["Red"], filter_parameters["Green"], filter_parameters["Blue"]};
// show color
if (ImGui::ColorEdit3("Chromakey Color", color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel) )
{
f.setProgramParameter("Red", color[0]);
f.setProgramParameter("Green", color[1]);
f.setProgramParameter("Blue", color[2]);
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
char buf[64];
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp((int)ceil(255.f * color[0]),0,255),
ImClamp((int)ceil(255.f * color[1]),0,255), ImClamp((int)ceil(255.f * color[2]),0,255));
oss << " Color " << buf;
Action::manager().store(oss.str());
}
// offer to pick color
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if ( ImGui::Button( ICON_FA_EYE_DROPPER " Open selector", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ){
if ( DialogToolkit::ColorPickerDialog::instance().busy()) {
Log::Warning("Close previously openned color picker.");
}
else {
// prepare the color picker to start with filter's color
DialogToolkit::ColorPickerDialog::instance().setRGB( std::make_tuple(color[0], color[1], color[2]) );
// declare function to be called
std::string msg = oss.str();
auto applyColor = [&f, msg]( std::tuple<float, float, float> c) {
f.setProgramParameter("Red", std::get<0>(c));
f.setProgramParameter("Green", std::get<1>(c));
f.setProgramParameter("Blue", std::get<2>(c));
char buf[1024];
ImFormatString(buf, IM_ARRAYSIZE(buf), "%scolor #%02X%02X%02X",
msg.c_str(),
ImClamp((int)ceil(255.f * std::get<0>(c)),0,255),
ImClamp((int)ceil(255.f * std::get<1>(c)),0,255),
ImClamp((int)ceil(255.f * std::get<2>(c)),0,255));
Action::manager().store(buf);
};
// open dialog (starts a thread that will callthe 'applyColor' function
DialogToolkit::ColorPickerDialog::instance().open( applyColor );
}
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Color")) {
f.setProgramParameter("Red", 0.f);
f.setProgramParameter("Green", 1.f);
f.setProgramParameter("Blue", 0.f);
oss << " Color #00FF00";
Action::manager().store(oss.str());
}
}
// Luminance extra parameter
else {
float v = filter_parameters["Luminance"];
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::SliderFloat( "##Luminance", &v, 0.f, 1.f, "%.2f")) {
f.setProgramParameter("Luminance", v);
}
if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){
v = CLAMP( v + 0.01f * io.MouseWheel, 0.f, 1.f);
f.setProgramParameter("Luminance", v);
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Luminance" << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Luminance" << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Luminance")) {
v = 0.f;
f.setProgramParameter("Luminance", v);
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " " << "Luminance" << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
}
}
void ImGuiVisitor::visit (ImageFilter& f)
{
// Open Editor
if ( ImGui::Button( ICON_FA_CODE " Open editor", ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
UserInterface::manager().shadercontrol.setVisible(true);
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Code");
// List of parameters
oss << "Custom ";
list_parameters_(f, oss);
}
void ImGuiVisitor::visit (CloneSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
if ( !s.failed() ) {
// link to origin source
std::string label = std::string(s.origin()->initials()) + " - " + s.origin()->name();
if (ImGui::Button(label.c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0) )) {
Mixer::manager().setCurrentSource(s.origin());
if (UserInterface::manager().navigator.pannelVisible())
UserInterface::manager().navigator.showPannelSource( Mixer::manager().indexCurrentSource() );
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Origin");
// filter selection
int type = (int) s.filter()->type();
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGuiToolkit::ComboIcon("##SelectFilter", &type, FrameBufferFilter::Types)) {
s.setFilter( FrameBufferFilter::Type(type) );
oss << "Filter " << std::get<2>(FrameBufferFilter::Types[type]);
Action::manager().store(oss.str());
info.reset();
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Filter")) {
s.setFilter( FrameBufferFilter::FILTER_PASSTHROUGH );
oss << "Filter None";
Action::manager().store(oss.str());
info.reset();
}
// offer option to convert to Custom shader to be able to edit code
if (s.filter()->type() > FrameBufferFilter::FILTER_RESAMPLE
&& s.filter()->type() < FrameBufferFilter::FILTER_IMAGE) {
ImageFilter *imf = static_cast<ImageFilter *>(s.filter());
if (!imf->program().isTwoPass()) {
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton(ICON_FA_CODE, "Convert to custom")) {
// get code and values
const std::pair<std::string, std::string> code = imf->program().code();
const std::map<std::string, float> param = imf->program().parameters();
FilteringProgram target;
target.setCode(code);
target.setParameters(param);
target.setName(imf->program().name());
// change filter and program
s.setFilter(FrameBufferFilter::FILTER_IMAGE);
imf = static_cast<ImageFilter *>(s.filter());
imf->setProgram(target);
info.reset();
}
}
}
// filter options
s.filter()->accept(*this);
ImVec2 botom = ImGui::GetCursorPos();
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
}
ImGui::SetCursorPos(botom);
}
else {
ImGuiToolkit::ButtonDisabled("No source", ImVec2(IMGUI_RIGHT_ALIGN, 0) );
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Origin");
info.reset();
}
}
void ImGuiVisitor::visit (ShaderSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// stream info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
// filter options : open editor
s.filter()->accept(*this);
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() ) {
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
top.x += ImGui::GetFrameHeight();
}
ImGui::SetCursorPos(top);
if (ImGuiToolkit::IconButton(ICON_FA_COPY, "Copy shader code"))
ImGui::SetClipboardText( s.filter()->program().code().first.c_str() );
}
else
info.reset();
ImGui::SetCursorPos(botom);
}
void ImGuiVisitor::visit (PatternSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// stream info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("##Patterns", Pattern::get(s.pattern()->type()).label.c_str(), ImGuiComboFlags_HeightLarge) )
{
for (uint p = 0; p < Pattern::count(); ++p){
pattern_descriptor pattern = Pattern::get(p);
std::string label = pattern.label;
if (pattern.available &&
pattern.animated == s.playable() &&
ImGui::Selectable( label.c_str(), p == s.pattern()->type() )) {
s.setPattern(p, s.pattern()->resolution());
info.reset();
oss << "Pattern " << Pattern::get(p).label;
Action::manager().store(oss.str());
// ensure all sources are updated after the texture change of this one
Mixer::manager().session()->execute([](Source *so) { so->touch(Source::SourceUpdate_Mask); });
}
}
ImGui::EndCombo();
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::Text("Generator");
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() ) {
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
top.x += ImGui::GetFrameHeight();
}
ImGui::SetCursorPos(top);
if (ImGuiToolkit::IconButton(ICON_FA_COPY, "Copy gstreamer code"))
ImGui::SetClipboardText(Pattern::get( s.pattern()->type() ).pipeline.c_str());
}
else
info.reset();
ImGui::SetCursorPos(botom);
}
void ImGuiVisitor::visit (DeviceSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
if ( !s.failed() ) {
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("Device", s.device().c_str()))
{
for (int d = 0; d < Device::manager().numDevices(); ++d){
std::string namedev = Device::manager().name(d);
if (ImGui::Selectable( namedev.c_str() )) {
if ( namedev.compare(s.device())==0 )
s.reconnect();
else {
s.setDevice(namedev);
info.reset();
oss << "Device " << namedev;
Action::manager().store(oss.str());
}
// ensure all sources are updated after the texture change of this one
Mixer::manager().session()->execute([](Source *so) { so->touch(Source::SourceUpdate_Mask); });
}
}
ImGui::EndCombo();
}
ImVec2 botom = ImGui::GetCursorPos();
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
top.x += ImGui::GetFrameHeight();
}
// icon to show gstreamer properties
ImGui::SetCursorPos(top);
ImGuiToolkit::Icon(16, 16, false);
if (ImGui::IsItemHovered()) {
int index = Device::manager().index( s.device() );
std::string prop = Device::manager().properties( index );
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 14.0f);
ImGui::TextUnformatted( prop.c_str());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::SetCursorPos(botom);
}
else {
info.reset();
}
}
void ImGuiVisitor::visit (ScreenCaptureSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
if ( !s.failed() ) {
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("Window", s.window().c_str()))
{
for (int d = 0; d < ScreenCapture::manager().numWindow(); ++d){
std::string namedev = ScreenCapture::manager().name(d);
if (ImGui::Selectable( namedev.c_str() )) {
if ( namedev.compare(s.window())==0 )
s.reconnect();
else {
s.setWindow(namedev);
info.reset();
oss << "Window '" << namedev << "'";
Action::manager().store(oss.str());
}
// ensure all sources are updated after the texture change of this one
Mixer::manager().session()->execute([](Source *so) { so->touch(Source::SourceUpdate_Mask); });
}
}
ImGui::EndCombo();
}
ImVec2 botom = ImGui::GetCursorPos();
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
}
ImGui::SetCursorPos(botom);
}
else {
info.reset();
}
}
void ImGuiVisitor::visit (NetworkSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_STREAM, 0.9f));
ImGui::Text("%s", s.connection().c_str());
ImGui::PopStyleColor(1);
// network info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() ) {
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
}
}
else
info.reset();
ImGui::SetCursorPos(botom);
}
void ImGuiVisitor::visit (MultiFileSource& s)
{
static uint64_t id = 0;
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// information text
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() ) {
// Filename pattern
ImGuiTextBuffer info;
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f));
info.appendf("%s", SystemToolkit::base_filename(s.sequence().location).c_str());
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::InputText("Filenames", (char *)info.c_str(), info.size(), ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor(1);
// change range
static int _begin = -1;
if (_begin < 0 || id != s.id())
_begin = s.begin();
static int _end = -1;
if (_end < 0 || id != s.id())
_end = s.end();
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::DragIntRange2("##Range", &_begin, &_end, 1, s.sequence().min, s.sequence().max);
if (ImGui::IsItemDeactivatedAfterEdit()){
s.setRange( _begin, _end );
oss << "Range " << _begin << "-" << _end;
Action::manager().store(oss.str());
_begin = _end = -1;
}
ImGui::SameLine(0, 0);
if (ImGuiToolkit::TextButton("Range")) {
s.setRange( s.sequence().min, s.sequence().max );
oss << "Range " << s.sequence().min << "-" << s.sequence().max;
Action::manager().store(oss.str());
_begin = _end = -1;
}
// change framerate
static int _fps = -1;
if (_fps < 0 || id != s.id())
_fps = s.framerate();
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::SliderInt("##Framerate", &_fps, 1, 30, "%d fps");
if (ImGui::IsItemDeactivatedAfterEdit()){
s.setFramerate(_fps);
oss << "Framerate " << _fps << " fps";
Action::manager().store(oss.str());
_fps = -1;
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Framerate")) {
s.setFramerate(25);
oss << "Framerate 25 fps";
Action::manager().store(oss.str());
_fps = -1;
}
botom = ImGui::GetCursorPos();
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
top.x += ImGui::GetFrameHeight();
}
}
else
info.reset();
// offer to open file browser at location
ImGui::SetCursorPos(top);
if (ImGuiToolkit::IconButton(3, 5, "Show in finder"))
SystemToolkit::open(SystemToolkit::path_filename( s.sequence().location ));
ImGui::SetCursorPos(botom);
if (id != s.id())
id = s.id();
}
void ImGuiVisitor::visit (GenericStreamSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
float w = ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// stream info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + w);
s.accept(info);
if ( !s.failed() )
ImGui::Text("%s", info.str().c_str());
else {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_FAILED, 0.9f));
ImGui::Text("%s", info.str().c_str());
ImGui::PopStyleColor(1);
}
ImGui::PopTextWrapPos();
ImGui::Spacing();
// Prepare display pipeline text
static int numlines = 0;
const ImGuiContext& g = *GImGui;
ImVec2 fieldsize(w, MAX(3, numlines) * g.FontSize + g.Style.ItemSpacing.y + g.Style.FramePadding.y);
// Editor
std::string _description = s.description();
bool changed = ImGuiToolkit::InputCodeMultiline("Pipeline", &_description, fieldsize, &numlines);
ImVec2 botom = ImGui::GetCursorPos();
// Actions on the pipeline
ImGui::SetCursorPos( ImVec2(top.x, botom.y - ImGui::GetFrameHeight()));
if (ImGuiToolkit::IconButton(ICON_FA_COPY, "Copy"))
ImGui::SetClipboardText(_description.c_str());
ImGui::SetCursorPos( ImVec2(top.x + 0.9 * ImGui::GetFrameHeight(), botom.y - ImGui::GetFrameHeight()));
if (ImGuiToolkit::IconButton(ICON_FA_PASTE, "Paste")) {
_description = std::string ( ImGui::GetClipboardText() );
changed = true;
}
if (changed) {
info.reset();
s.setDescription(_description);
oss << "Change pipeline";
Action::manager().store( oss.str() );
// ensure all sources are updated after the texture change of this one
Mixer::manager().session()->execute([](Source *so) { so->touch(Source::SourceUpdate_Mask); });
}
if ( !s.failed() ) {
// icon (>) to open player
if ( s.playable() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
}
}
ImGui::SetCursorPos(botom);
}
void ImGuiVisitor::visit (SrtReceiverSource& s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// network info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
ImVec2 botom = ImGui::GetCursorPos();
if ( !s.failed() ) {
// icon (>) to open player
if ( s.stream()->isOpen() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
}
else
info.reset();
}
else
info.reset();
ImGui::SetCursorPos(botom);
}
void ImGuiVisitor::visit(TextSource &s)
{
ImVec2 top = ImGui::GetCursorPos();
top.x = 0.5f * ImGui::GetFrameHeight() + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
float w = ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
// network info
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x
+ ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
s.accept(info);
ImGui::Text("%s", info.str().c_str());
ImGui::PopTextWrapPos();
ImGui::Spacing();
ImVec2 botom = ImGui::GetCursorPos();
TextContents *tc = s.contents();
if (tc) {
// Prepare display text
static int numlines = 0;
const ImGuiContext &g = *GImGui;
ImVec2 fieldsize(w, MAX(4, numlines) * g.FontSize + g.Style.ItemSpacing.y + g.Style.FramePadding.y);
// Text contents
std::string _contents = tc->text();
// if the content is a subtitle file
if (tc->isSubtitle()) {
static char dummy_str[1024];
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
snprintf(dummy_str, 1024, "%s", _contents.c_str());
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f));
ImGui::InputText("##Filesubtitle", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor(1);
botom = ImGui::GetCursorPos();
// Action on the filename
ImGui::SetCursorPos(ImVec2(top.x, botom.y - ImGui::GetFrameHeight()));
if (ImGuiToolkit::IconButton(ICON_FA_EDIT, "Open in editor"))
SystemToolkit::open(_contents.c_str());
ImGui::SetCursorPos(
ImVec2(top.x + 0.95 * ImGui::GetFrameHeight(), botom.y - ImGui::GetFrameHeight()));
if (ImGuiToolkit::IconButton(ICON_FA_REDO_ALT, "Reload"))
s.reload();
}
// general case of free text : text editor
else {
if (ImGuiToolkit::InputTextMultiline("Text", &_contents, fieldsize, &numlines)) {
info.reset();
tc->setText(_contents);
oss << "Text changed";
Action::manager().store(oss.str());
}
botom = ImGui::GetCursorPos();
// Actions on the text
ImGui::SetCursorPos(ImVec2(top.x, botom.y - ImGui::GetFrameHeight()));
if (ImGuiToolkit::IconButton(ICON_FA_COPY, "Copy"))
ImGui::SetClipboardText(_contents.c_str());
ImGui::SetCursorPos(
ImVec2(top.x + 0.95 * ImGui::GetFrameHeight(), botom.y - ImGui::GetFrameHeight()));
_contents = std::string(ImGui::GetClipboardText());
if (_contents.empty())
ImGui::TextDisabled(ICON_FA_PASTE);
else {
if (ImGuiToolkit::IconButton(ICON_FA_PASTE, "Paste")) {
info.reset();
tc->setText(_contents);
oss << "Text changed";
Action::manager().store(oss.str());
}
}
ImGui::SetCursorPos(ImVec2(top.x, botom.y - 2.f * ImGui::GetFrameHeight()));
if (ImGuiToolkit::IconButton(ICON_FA_CODE, "Pango markup"))
SystemToolkit::open("https://docs.gtk.org/Pango/pango_markup.html");
}
// Text Properties
ImGui::SetCursorPos(botom);
ImVec4 color = ImGuiToolkit::ColorConvertARGBToFloat4(tc->color());
if (ImGui::ColorEdit4("Text Color", (float *) &color, ImGuiColorEditFlags_AlphaPreview |
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel) ) {
tc->setColor( ImGuiToolkit::ColorConvertFloat4ToARGB(color) );
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << "Change font color";
Action::manager().store(oss.str());
}
std::string font = tc->fontDescriptor();
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGuiToolkit::InputText("##Font", &font, ImGuiInputTextFlags_EnterReturnsTrue);
if (ImGui::IsItemDeactivatedAfterEdit()) {
tc->setFontDescriptor(font);
oss << "Change font";
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Font")) {
tc->setFontDescriptor("arial 24");
tc->setColor(0xffffffff);
oss << "Reset font";
Action::manager().store(oss.str());
}
botom = ImGui::GetCursorPos();
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::IconButton(1, 13, "Pango font description"))
SystemToolkit::open("https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html");
ImGui::SetCursorPos(botom);
color = ImGuiToolkit::ColorConvertARGBToFloat4(tc->outlineColor());
if (ImGui::ColorEdit4("Text Outline Color", (float *) &color, ImGuiColorEditFlags_AlphaPreview |
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel) ) {
tc->setOutlineColor( ImGuiToolkit::ColorConvertFloat4ToARGB(color) );
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << "Change outline color";
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
int outline = tc->outline();
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::Combo("##Outline", &outline, "None\0Border\0Border & shadow\0")) {
tc->setOutline(outline);
oss << "Change outline";
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Outline")) {
tc->setOutline(2);
tc->setOutlineColor(0xFF000000);
oss << "Reset outline";
Action::manager().store(oss.str());
}
// HORIZONTAL alignment
bool on = true;
uint var = tc->horizontalAlignment();
on = var == 0;
float _x = ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
_x -= 4.f * (g.FontSize + g.Style.FramePadding.x + IMGUI_SAME_LINE);
if (var != 1) {
// not centered
ImGui::SetNextItemWidth(_x);
if (var > 2) {
// Absolute position
float align_x = tc->horizontalPadding();
if (ImGui::SliderFloat("##Posx", &align_x, 0.f, 1.f, "%.2f")) {
tc->setHorizontalPadding(align_x);
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << "Change h-align coordinates";
Action::manager().store(oss.str());
}
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip( "Coordinates" );
} else {
// padding top or bottom
int pad_x = (int) tc->horizontalPadding();
if (ImGui::SliderInt("##Padx", &pad_x, 0, 1000)) {
tc->setHorizontalPadding((float) pad_x);
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << "Change h-align padding";
Action::manager().store(oss.str());
}
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip( "Padding" );
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
} else {
_x += IMGUI_SAME_LINE + g.Style.FramePadding.x;
ImGui::SetCursorPosX(_x);
}
if (ImGuiToolkit::ButtonIconToggle(17, 16, &on, "Left"))
tc->setHorizontalAlignment(0);
ImGui::SameLine(0, IMGUI_SAME_LINE);
on = var == 1;
if (ImGuiToolkit::ButtonIconToggle(18, 16, &on, "Center"))
tc->setHorizontalAlignment(1);
ImGui::SameLine(0, IMGUI_SAME_LINE);
on = var == 2;
if (ImGuiToolkit::ButtonIconToggle(19, 16, &on, "Right"))
tc->setHorizontalAlignment(2);
ImGui::SameLine(0, IMGUI_SAME_LINE);
on = var == 3;
if (ImGuiToolkit::ButtonIconToggle(6, 10, &on, "Absolute"))
tc->setHorizontalAlignment(3);
if (var != tc->horizontalAlignment()){
oss << "Change h-align";
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Horizontal")) {
tc->setHorizontalAlignment(1);
oss << "Reset h-align";
Action::manager().store(oss.str());
}
// VERTICAL alignment
var = tc->verticalAlignment();
on = var == 0;
_x = ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
_x -= 4.f * (g.FontSize + g.Style.FramePadding.x + IMGUI_SAME_LINE);
if (var != 2) {
// not centered
ImGui::SetNextItemWidth(_x);
if (var > 2) {
// Absolute position
float align_y = tc->verticalPadding();
if (ImGui::SliderFloat("##Posy", &align_y, 0.f, 1.f, "%.2f")) {
tc->setVerticalPadding(align_y);
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << "Change v-align coordinates";
Action::manager().store(oss.str());
}
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip( "Coordinates" );
} else {
// padding top or bottom
int pad_y = (int) tc->verticalPadding();
if (ImGui::SliderInt("##Pady", &pad_y, 0, 1000)) {
tc->setVerticalPadding((float) pad_y);
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << "Change v-align padding";
Action::manager().store(oss.str());
}
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip( "Padding" );
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
} else {
// no value slider for centered
_x += IMGUI_SAME_LINE + g.Style.FramePadding.x;
ImGui::SetCursorPosX(_x);
}
if (ImGuiToolkit::ButtonIconToggle(1, 17, &on, "Bottom"))
tc->setVerticalAlignment(0);
ImGui::SameLine(0, IMGUI_SAME_LINE);
on = var == 2;
if (ImGuiToolkit::ButtonIconToggle(3, 17, &on, "Center"))
tc->setVerticalAlignment(2);
ImGui::SameLine(0, IMGUI_SAME_LINE);
on = var == 1;
if (ImGuiToolkit::ButtonIconToggle(2, 17, &on, "Top"))
tc->setVerticalAlignment(1);
ImGui::SameLine(0, IMGUI_SAME_LINE);
on = var == 3;
if (ImGuiToolkit::ButtonIconToggle(3, 10, &on, "Absolute"))
tc->setVerticalAlignment(3);
if (var != tc->verticalAlignment()){
oss << "Change v-align";
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
if (ImGuiToolkit::TextButton("Vertical")) {
tc->setVerticalAlignment(2);
oss << "Reset v-align";
Action::manager().store(oss.str());
}
botom = ImGui::GetCursorPos();
}
if ( !s.failed() ) {
// icon (>) to open player
if ( s.stream()->isOpen() ) {
ImGui::SetCursorPos(top);
std::string msg = s.playing() ? "Open Player\n(source is playing)" : "Open Player\n(source is paused)";
if (ImGuiToolkit::IconButton( s.playing() ? ICON_FA_PLAY_CIRCLE : ICON_FA_PAUSE_CIRCLE, msg.c_str()))
UserInterface::manager().showSourceEditor(&s);
}
else
info.reset();
}
else
info.reset();
ImGui::SetCursorPos(botom);
}