mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-15 20:29:58 +01:00
New toolbox Timeline editor
DRAFT implementation of a new toolbox to apply fade-in and fade-out and to cut the timeline.
This commit is contained in:
Binary file not shown.
@@ -20,6 +20,7 @@
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <cctype>
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -35,6 +36,7 @@
|
||||
|
||||
#include "Resource.h"
|
||||
#include "GstToolkit.h"
|
||||
#include "BaseToolkit.h"
|
||||
#include "SystemToolkit.h"
|
||||
|
||||
#include "ImGuiToolkit.h"
|
||||
@@ -203,7 +205,7 @@ void ImGuiToolkit::Icon(int i, int j, bool enabled)
|
||||
ImGui::Image((void*)(intptr_t)textureicons, ImVec2(ImGui::GetTextLineHeightWithSpacing(), ImGui::GetTextLineHeightWithSpacing()), uv0, uv1, tint_color);
|
||||
}
|
||||
|
||||
bool ImGuiToolkit::ButtonIcon(int i, int j, const char *tooltip, bool expanded)
|
||||
bool ImGuiToolkit::ButtonIcon(int i, int j, const char *tooltip, bool enabled, bool expanded)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
bool ret = false;
|
||||
@@ -233,9 +235,16 @@ bool ImGuiToolkit::ButtonIcon(int i, int j, const char *tooltip, bool expanded)
|
||||
ImVec2 uv1( uv0.x + 0.05, uv0.y + 0.05 );
|
||||
|
||||
ImGui::PushID( i*20 + j);
|
||||
ret = ImGui::ImageButton((void*)(intptr_t)textureicons,
|
||||
ImVec2(g.FontSize, g.FontSize),
|
||||
uv0, uv1, g.Style.FramePadding.y);
|
||||
if (enabled)
|
||||
ret = ImGui::ImageButton((void*)(intptr_t)textureicons,
|
||||
ImVec2(g.FontSize, g.FontSize),
|
||||
uv0, uv1, g.Style.FramePadding.y);
|
||||
else
|
||||
ImGui::ImageButton((void*)(intptr_t)textureicons,
|
||||
ImVec2(g.FontSize, g.FontSize),
|
||||
uv0, uv1, g.Style.FramePadding.y,
|
||||
ImVec4(0.f, 0.f, 0.f, 0.f),
|
||||
ImVec4(0.6f, 0.6f, 0.6f, 0.8f));
|
||||
ImGui::PopID();
|
||||
|
||||
if (tooltip != nullptr && ImGui::IsItemHovered())
|
||||
@@ -760,18 +769,18 @@ bool ImGuiToolkit::SliderTiming (const char* label, uint* ms, uint v_min, uint v
|
||||
|
||||
if (min > 0) {
|
||||
if (milisec>0)
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%d min %02d s %03d ms", min, sec%60, milisec);
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%dmin %02ds %03d ms", min, sec%60, milisec);
|
||||
else
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%d min %02d s", min, sec%60);
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%dmin %02ds", min, sec%60);
|
||||
}
|
||||
else if (sec > 0) {
|
||||
if (milisec>0)
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%d s %03d ms", sec, milisec);
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%ds %03dms", sec, milisec);
|
||||
else
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%d s", sec);
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%ds", sec);
|
||||
}
|
||||
else
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%03d ms", milisec);
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%03dms", milisec);
|
||||
}
|
||||
else {
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%s", text_max);
|
||||
@@ -786,6 +795,8 @@ bool ImGuiToolkit::SliderTiming (const char* label, uint* ms, uint v_min, uint v
|
||||
bool ret = ImGui::SliderFloat(label, &val, v_min / v_step, v_max / v_step, text_buf, 2.f);
|
||||
*ms = int(floor(val)) * v_step;
|
||||
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1279,305 +1290,62 @@ bool ImGuiToolkit::InvisibleSliderFloat (const char* label, float *index, float
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
bool ImGuiToolkit::EditPlotLines (const char* label, float *array, int values_count, float values_min, float values_max, const ImVec2 size)
|
||||
bool HSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max)
|
||||
{
|
||||
bool array_changed = false;
|
||||
|
||||
// get window
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
// capture coordinates before any draw or action
|
||||
ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
|
||||
|
||||
// get id
|
||||
const ImGuiID id = window->GetID(label);
|
||||
|
||||
// add item
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImRect bbox(pos, pos + size);
|
||||
ImGui::ItemSize(size);
|
||||
if (!ImGui::ItemAdd(bbox, id))
|
||||
return false;
|
||||
|
||||
// read user input and activate widget
|
||||
const bool left_mouse_press = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||
const bool hovered = ImGui::ItemHoverable(bbox, id);
|
||||
bool temp_input_is_active = ImGui::TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
const bool focus_requested = ImGui::FocusableItemRegister(window, id);
|
||||
if (focus_requested || (hovered && left_mouse_press) )
|
||||
{
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
ImVec4* colors = ImGui::GetStyle().Colors;
|
||||
ImVec4 bg_color = hovered ? colors[ImGuiCol_FrameBgHovered] : colors[ImGuiCol_FrameBg];
|
||||
|
||||
// enter edit if widget is active
|
||||
if (ImGui::GetActiveID() == id) {
|
||||
|
||||
static uint previous_index = UINT32_MAX;
|
||||
bg_color = colors[ImGuiCol_FrameBgActive];
|
||||
|
||||
// keep active area while mouse is pressed
|
||||
if (left_mouse_press)
|
||||
{
|
||||
float x = (float) values_count * mouse_pos_in_canvas.x / bbox.GetWidth();
|
||||
uint index = CLAMP( (int) floor(x), 0, values_count-1);
|
||||
|
||||
float y = mouse_pos_in_canvas.y / bbox.GetHeight();
|
||||
y = CLAMP( (y * (values_max-values_min)) + values_min, values_min, values_max);
|
||||
|
||||
|
||||
if (previous_index == UINT32_MAX)
|
||||
previous_index = index;
|
||||
|
||||
array[index] = values_max - y;
|
||||
for (int i = MIN(previous_index, index); i < MAX(previous_index, index); ++i)
|
||||
array[i] = values_max - y;
|
||||
|
||||
previous_index = index;
|
||||
|
||||
array_changed = true;
|
||||
}
|
||||
// release active widget on mouse release
|
||||
else {
|
||||
ImGui::ClearActiveID();
|
||||
previous_index = UINT32_MAX;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// back to draw
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot lines
|
||||
char buf[128];
|
||||
snprintf(buf, 128, "##Lines%s", label);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, bg_color);
|
||||
ImGui::PlotLines(buf, array, values_count, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
return array_changed;
|
||||
}
|
||||
|
||||
|
||||
bool ImGuiToolkit::EditPlotHistoLines (const char* label, float *histogram_array, float *lines_array,
|
||||
int values_count, float values_min, float values_max, guint64 begin, guint64 end,
|
||||
bool edit_histogram, bool *released, const ImVec2 size)
|
||||
{
|
||||
bool array_changed = false;
|
||||
|
||||
// get window
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
// capture coordinates before any draw or action
|
||||
const ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
|
||||
|
||||
// get id
|
||||
const ImGuiID id = window->GetID(label);
|
||||
|
||||
// add item
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImRect bbox(pos, pos + size);
|
||||
ImGui::ItemSize(size);
|
||||
if (!ImGui::ItemAdd(bbox, id))
|
||||
return false;
|
||||
|
||||
*released = false;
|
||||
|
||||
// read user input and activate widget
|
||||
const bool mouse_press = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||
const bool hovered = ImGui::ItemHoverable(bbox, id);
|
||||
bool temp_input_is_active = ImGui::TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
const bool focus_requested = ImGui::FocusableItemRegister(window, id);
|
||||
if (focus_requested || (hovered && mouse_press) )
|
||||
{
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
const ImGuiContext& g = *GImGui;
|
||||
ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const float _h_space = style.WindowPadding.x;
|
||||
ImVec4 bg_color = hovered ? style.Colors[ImGuiCol_FrameBgHovered] : style.Colors[ImGuiCol_FrameBg];
|
||||
|
||||
// prepare index
|
||||
double x = (mouse_pos_in_canvas.x - _h_space) / (size.x - 2.f * _h_space);
|
||||
size_t index = CLAMP( (int) floor(static_cast<double>(values_count) * x), 0, values_count);
|
||||
char cursor_text[64];
|
||||
guint64 time = begin + (index * end) / static_cast<guint64>(values_count);
|
||||
ImFormatString(cursor_text, IM_ARRAYSIZE(cursor_text), "%s",
|
||||
GstToolkit::time_to_string(time, GstToolkit::TIME_STRING_MINIMAL).c_str());
|
||||
|
||||
// enter edit if widget is active
|
||||
if (ImGui::GetActiveID() == id) {
|
||||
|
||||
bg_color = style.Colors[ImGuiCol_FrameBgActive];
|
||||
|
||||
// keep active area while mouse is pressed
|
||||
static bool active = false;
|
||||
static size_t previous_index = UINT32_MAX;
|
||||
if (mouse_press)
|
||||
{
|
||||
float val = mouse_pos_in_canvas.y / bbox.GetHeight();
|
||||
val = CLAMP( (val * (values_max-values_min)) + values_min, values_min, values_max);
|
||||
|
||||
if (previous_index == UINT32_MAX)
|
||||
previous_index = index;
|
||||
|
||||
const size_t left = MIN(previous_index, index);
|
||||
const size_t right = MAX(previous_index, index);
|
||||
|
||||
if (edit_histogram){
|
||||
static float target_value = values_min;
|
||||
|
||||
// toggle value histo
|
||||
if (!active) {
|
||||
target_value = histogram_array[index] > 0.f ? 0.f : 1.f;
|
||||
active = true;
|
||||
}
|
||||
|
||||
for (size_t i = left; i < right; ++i)
|
||||
histogram_array[i] = target_value;
|
||||
}
|
||||
else {
|
||||
const float target_value = values_max - val;
|
||||
|
||||
for (size_t i = left; i < right; ++i)
|
||||
lines_array[i] = target_value;
|
||||
|
||||
}
|
||||
|
||||
previous_index = index;
|
||||
array_changed = true;
|
||||
}
|
||||
// release active widget on mouse release
|
||||
else {
|
||||
active = false;
|
||||
ImGui::ClearActiveID();
|
||||
previous_index = UINT32_MAX;
|
||||
*released = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// back to draw
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot histogram (with frame)
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, bg_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, style.Colors[ImGuiCol_ModalWindowDimBg]); // a dark color
|
||||
char buf[128];
|
||||
snprintf(buf, 128, "##Histo%s", label);
|
||||
ImGui::PlotHistogram(buf, histogram_array, values_count, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot (transparent) lines
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
|
||||
snprintf(buf, 128, "##Lines%s", label);
|
||||
ImGui::PlotLines(buf, lines_array, values_count, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
// draw the cursor
|
||||
if (hovered) {
|
||||
// prepare color and text
|
||||
const ImU32 cur_color = ImGui::GetColorU32(ImGuiCol_CheckMark);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, cur_color);
|
||||
ImVec2 label_size = ImGui::CalcTextSize(cursor_text, NULL);
|
||||
|
||||
// render cursor depending on action
|
||||
mouse_pos_in_canvas.x = CLAMP(mouse_pos_in_canvas.x, _h_space, size.x - _h_space);
|
||||
ImVec2 cursor_pos = canvas_pos;
|
||||
if (edit_histogram) {
|
||||
cursor_pos = cursor_pos + ImVec2(mouse_pos_in_canvas.x, 4.f);
|
||||
window->DrawList->AddLine( cursor_pos, cursor_pos + ImVec2(0.f, size.y - 8.f), cur_color);
|
||||
}
|
||||
else {
|
||||
cursor_pos = cursor_pos + mouse_pos_in_canvas;
|
||||
window->DrawList->AddCircleFilled( cursor_pos, 3.f, cur_color, 8);
|
||||
}
|
||||
|
||||
// draw text
|
||||
cursor_pos.y = canvas_pos.y + size.y - label_size.y - 1.f;
|
||||
if (mouse_pos_in_canvas.x + label_size.x < size.x - 2.f * _h_space)
|
||||
cursor_pos.x += _h_space;
|
||||
else
|
||||
cursor_pos.x -= label_size.x + _h_space;
|
||||
ImGui::RenderTextClipped(cursor_pos, cursor_pos + label_size, cursor_text, NULL, &label_size);
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
}
|
||||
|
||||
return array_changed;
|
||||
}
|
||||
|
||||
void ImGuiToolkit::ShowPlotHistoLines (const char* label, float *histogram_array, float *lines_array, int values_count, float values_min, float values_max, const ImVec2 size)
|
||||
{
|
||||
// get window
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
// capture coordinates before any draw or action
|
||||
ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
|
||||
|
||||
// get id
|
||||
const ImGuiID id = window->GetID(label);
|
||||
|
||||
// add item
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImRect bbox(pos, pos + size);
|
||||
ImGui::ItemSize(size);
|
||||
if (!ImGui::ItemAdd(bbox, id))
|
||||
return;
|
||||
const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
|
||||
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
|
||||
const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
|
||||
|
||||
const ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
ImVec4 bg_color = style.Colors[ImGuiCol_FrameBg];
|
||||
ImGui::ItemSize(bb, style.FramePadding.y);
|
||||
if (!ImGui::ItemAdd(frame_bb, id))
|
||||
return false;
|
||||
|
||||
// back to draw
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
const bool hovered = ImGui::ItemHoverable(frame_bb, id);
|
||||
if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id)
|
||||
{
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
|
||||
}
|
||||
|
||||
// plot transparent histogram
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, bg_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0, 0, 0, 250));
|
||||
char buf[128];
|
||||
snprintf(buf, 128, "##Histo%s", label);
|
||||
ImGui::PlotHistogram(buf, histogram_array, values_count, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(2);
|
||||
// Draw frame
|
||||
const ImU32 frame_col = ImGui::GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
|
||||
ImGui::RenderNavHighlight(frame_bb, id);
|
||||
ImGui::RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding);
|
||||
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
// Slider behavior
|
||||
ImRect grab_bb;
|
||||
const bool value_changed = ImGui::SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, "", 1.f, ImGuiSliderFlags_None, &grab_bb);
|
||||
if (value_changed)
|
||||
ImGui::MarkItemEdited(id);
|
||||
|
||||
// plot lines
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
|
||||
snprintf(buf, 128, "##Lines%s", label);
|
||||
ImGui::PlotLines(buf, lines_array, values_count, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(1);
|
||||
// Render grab
|
||||
if (grab_bb.Max.y > grab_bb.Min.y)
|
||||
window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, ImGui::GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
bool ImGuiToolkit::HSliderInt(const char *id, const ImVec2 &size, int *v, int v_min, int v_max)
|
||||
{
|
||||
return HSliderScalar(id, size, ImGuiDataType_S32, v, &v_min, &v_max);
|
||||
}
|
||||
|
||||
bool ImGuiToolkit::HSliderUInt64(const char *id, const ImVec2 &size, guint64 *v, guint64 v_min, guint64 v_max)
|
||||
{
|
||||
return HSliderScalar(id, size, ImGuiDataType_U64, v, &v_min, &v_max);
|
||||
}
|
||||
|
||||
|
||||
void ImGuiToolkit::ValueBar(float fraction, const ImVec2& size_arg)
|
||||
{
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
@@ -1909,6 +1677,93 @@ void word_wrap(std::string *str, unsigned per_line)
|
||||
|
||||
|
||||
|
||||
bool ImGuiToolkit::InputTime(const char *label, guint64 *time, ImGuiInputTextFlags flag)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// filtering for reading MM:SS.MS text entry
|
||||
static bool valid = false;
|
||||
static std::regex RegExTime("([0-9]+\\:)?([0-9]+\\:)?([0-5][0-9]|[0-9])((\\.|\\,)[0-9]+)?");
|
||||
struct TextFilters
|
||||
{
|
||||
static int FilterTime(ImGuiInputTextCallbackData *data)
|
||||
{
|
||||
if (data->EventChar < 256 && strchr("0123456789.,:", (char) data->EventChar))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
// convert gst time to hh mm s.ms
|
||||
guint64 ms = GST_TIME_AS_MSECONDS(*time);
|
||||
guint64 hh = ms / 3600000;
|
||||
guint64 mm = (ms % 3600000) / 60000;
|
||||
ms -= (hh * 3600000 + mm * 60000);
|
||||
float sec = (float) (ms) / 1000.f;
|
||||
|
||||
// write time into string
|
||||
char buf_time_input[64] = "";
|
||||
snprintf(buf_time_input, 64, "%02lu:%02lu:%04.1f", (unsigned long) hh, (unsigned long) mm, sec);
|
||||
|
||||
// draw input text field
|
||||
const ImGuiContext &g = *GImGui;
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||
flag & ImGuiInputTextFlags_ReadOnly
|
||||
? g.Style.Colors[ImGuiCol_TextDisabled]
|
||||
: ImVec4(1.0f, valid ? 1.0f : 0.2f, valid ? 1.0f : 0.2f, 1.f));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,
|
||||
flag & ImGuiInputTextFlags_ReadOnly ? g.Style.Colors[ImGuiCol_WindowBg]
|
||||
: g.Style.Colors[ImGuiCol_FrameBg]);
|
||||
ImGuiToolkit::PushFont(FONT_MONO);
|
||||
ImGui::InputText(label,
|
||||
buf_time_input,
|
||||
64,
|
||||
ImGuiInputTextFlags_CallbackCharFilter | flag,
|
||||
TextFilters::FilterTime);
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
// test string format with regular expression
|
||||
valid = std::regex_match(buf_time_input, RegExTime);
|
||||
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
if (valid) {
|
||||
ms = 0;
|
||||
sec = 0.f;
|
||||
// user confirmed the entry and the input is valid
|
||||
// split the "HH:MM:SS.ms" string in HH MM SS.ms
|
||||
std::string timing(buf_time_input);
|
||||
std::size_t found = timing.find_last_of(':');
|
||||
// read the right part SS.ms as a value
|
||||
if (std::string::npos != found
|
||||
&& BaseToolkit::is_a_value(timing.substr(found + 1), &sec)) {
|
||||
ms = (guint64) (sec * 1000.f);
|
||||
// read right part MM as a number
|
||||
timing = timing.substr(0, found);
|
||||
found = timing.find_last_of(':');
|
||||
int min = 0;
|
||||
if (std::string::npos != found
|
||||
&& BaseToolkit::is_a_number(timing.substr(found + 1), &min)) {
|
||||
ms += 60000 * (guint64) min;
|
||||
// read right part HH as a number
|
||||
timing = timing.substr(0, found);
|
||||
int hour = 0;
|
||||
if (std::string::npos != found && BaseToolkit::is_a_number(timing, &hour)) {
|
||||
ms += 3600000 * (guint64) hour;
|
||||
}
|
||||
}
|
||||
}
|
||||
// set time
|
||||
*time = GST_MSECOND * ms;
|
||||
changed = true;
|
||||
}
|
||||
// force to test validity next frame
|
||||
valid = false;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int InputTextCallback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
std::string* str = static_cast<std::string*>(data->UserData);
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace ImGuiToolkit
|
||||
void ShowIconsWindow(bool* p_open);
|
||||
|
||||
// buttons and gui items with icon
|
||||
bool ButtonIcon (int i, int j, const char* tooltip = nullptr, bool expanded = false);
|
||||
bool ButtonIcon (int i, int j, const char* tooltip = nullptr, bool enabled = true, bool expanded = false);
|
||||
bool ButtonIconToggle (int i, int j, bool* toggle, const char *tooltip = nullptr);
|
||||
bool ButtonIconMultistate (std::vector<std::pair<int, int> > icons, int* state, std::vector<std::string> tooltips);
|
||||
bool BeginMenuIcon(int i, int j, const char *label, bool enabled = true);
|
||||
@@ -55,10 +55,8 @@ namespace ImGuiToolkit
|
||||
void RenderTimelineBPM (ImVec2 min_bbox, ImVec2 max_bbox, double tempo, double quantum, guint64 begin, guint64 end, guint64 step, bool verticalflip = false);
|
||||
bool InvisibleSliderInt(const char* label, uint *index, uint min, uint max, const ImVec2 size);
|
||||
bool InvisibleSliderFloat(const char* label, float *index, float min, float max, const ImVec2 size);
|
||||
bool EditPlotLines(const char* label, float *array, int values_count, float values_min, float values_max, const ImVec2 size);
|
||||
bool EditPlotHistoLines(const char* label, float *histogram_array, float *lines_array, int values_count, float values_min, float values_max, guint64 begin, guint64 end, bool cut, bool *released, const ImVec2 size);
|
||||
void ShowPlotHistoLines(const char* label, float *histogram_array, float *lines_array, int values_count, float values_min, float values_max, const ImVec2 size);
|
||||
|
||||
bool HSliderInt(const char *id, const ImVec2 &size, int *v, int v_min, int v_max);
|
||||
bool HSliderUInt64(const char *id, const ImVec2 &size, guint64 *v, guint64 v_min, guint64 v_max);
|
||||
void ValueBar(float fraction, const ImVec2& size_arg);
|
||||
|
||||
// fonts from resources 'fonts/'
|
||||
@@ -75,6 +73,7 @@ namespace ImGuiToolkit
|
||||
void Spacing();
|
||||
|
||||
// text input
|
||||
bool InputTime(const char *label, guint64 *time, ImGuiInputTextFlags flag = 0);
|
||||
bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flag = ImGuiInputTextFlags_CharsNoBlank);
|
||||
bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), int *numline = NULL);
|
||||
void TextMultiline(const char* label, const std::string &str, float width);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#define ICON_POINTER_SPRING 13, 9
|
||||
#define ICON_POINTER_LINEAR 14, 9
|
||||
#define ICON_POINTER_GRID 15, 9
|
||||
#define ICON_POINTER_WIGGLY 10, 3
|
||||
#define ICON_POINTER_WIGGLY 16, 9
|
||||
#define ICON_POINTER_METRONOME 6, 13
|
||||
|
||||
///
|
||||
|
||||
@@ -363,9 +363,6 @@ void ShaderEditWindow::Render()
|
||||
}
|
||||
// cancel edit clone
|
||||
else {
|
||||
// possibility that source was removed
|
||||
g_printerr("cancel edit clone %ld\n", current_);
|
||||
|
||||
// disable editor
|
||||
_editor.SetReadOnly(true);
|
||||
_editor.SetColorizerEnable(false);
|
||||
|
||||
@@ -33,10 +33,8 @@
|
||||
#include "DialogToolkit.h"
|
||||
#include "GstToolkit.h"
|
||||
#include "Resource.h"
|
||||
#include "PatternSource.h"
|
||||
|
||||
#include "Mixer.h"
|
||||
#include "CloneSource.h"
|
||||
#include "MediaSource.h"
|
||||
#include "StreamSource.h"
|
||||
#include "MediaPlayer.h"
|
||||
@@ -48,6 +46,44 @@
|
||||
#define CHECKER_RESOLUTION 6000
|
||||
class Stream *checker_background_ = new Stream;
|
||||
|
||||
typedef struct payload
|
||||
{
|
||||
enum Action {
|
||||
FADE_IN,
|
||||
FADE_OUT,
|
||||
FADE_IN_OUT,
|
||||
FADE_OUT_IN,
|
||||
CUT,
|
||||
CUT_MERGE,
|
||||
CUT_ERASE
|
||||
};
|
||||
Action action;
|
||||
guint64 drop_time;
|
||||
guint64 timing;
|
||||
int argument;
|
||||
|
||||
payload()
|
||||
{
|
||||
action = FADE_IN;
|
||||
drop_time = GST_CLOCK_TIME_NONE;
|
||||
timing = GST_CLOCK_TIME_NONE;
|
||||
argument = 0;
|
||||
}
|
||||
|
||||
payload(payload const &pl)
|
||||
: action(pl.action)
|
||||
, drop_time(pl.drop_time)
|
||||
, timing(pl.timing)
|
||||
, argument(pl.argument){
|
||||
}
|
||||
|
||||
payload(Action a, guint64 t, int arg)
|
||||
: action(a), timing(t), argument(arg)
|
||||
{
|
||||
drop_time = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
} TimelinePayload;
|
||||
|
||||
SourceControlWindow::SourceControlWindow() : WorkspaceWindow("SourceController"),
|
||||
min_width_(0.f), h_space_(0.f), v_space_(0.f), scrollbar_(0.f),
|
||||
@@ -57,7 +93,7 @@ SourceControlWindow::SourceControlWindow() : WorkspaceWindow("SourceController")
|
||||
selection_context_menu_(false), selection_mediaplayer_(nullptr), selection_target_slower_(0), selection_target_faster_(0),
|
||||
mediaplayer_active_(nullptr), mediaplayer_edit_fading_(false), mediaplayer_set_duration_(0),
|
||||
mediaplayer_edit_pipeline_(false), mediaplayer_mode_(false), mediaplayer_slider_pressed_(false), mediaplayer_timeline_zoom_(1.f),
|
||||
magnifying_glass(false)
|
||||
mediaplayer_edit_panel_(false), magnifying_glass(false)
|
||||
{
|
||||
info_.setExtendedStringMode();
|
||||
|
||||
@@ -437,8 +473,8 @@ void SourceControlWindow::Render()
|
||||
_alpha_fading ? MediaPlayer::FADING_ALPHA : MediaPlayer::FADING_COLOR);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem(LABEL_EDIT_FADING))
|
||||
mediaplayer_edit_fading_ = true;
|
||||
// if (ImGui::MenuItem(LABEL_EDIT_FADING))
|
||||
// mediaplayer_edit_fading_ = true;
|
||||
|
||||
if (ImGui::BeginMenu(ICON_FA_CLOCK " Metronome"))
|
||||
{
|
||||
@@ -526,6 +562,445 @@ void DrawTimeScale(const char* label, guint64 duration, double width_ratio)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool EditPlotHistoLines (const char* label, float *histogram_array, float *lines_array,
|
||||
int values_count, float values_min, float values_max, guint64 begin, guint64 end,
|
||||
bool edit_histogram, bool *released, TimelinePayload **payload, const ImVec2 size)
|
||||
{
|
||||
bool array_changed = false;
|
||||
|
||||
// get window
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
// capture coordinates before any draw or action
|
||||
const ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
|
||||
|
||||
// get id
|
||||
const ImGuiID id = window->GetID(label);
|
||||
|
||||
// add item
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImRect bbox(pos, pos + size);
|
||||
ImGui::ItemSize(size);
|
||||
if (!ImGui::ItemAdd(bbox, id))
|
||||
return false;
|
||||
|
||||
*released = false;
|
||||
|
||||
// read user input and activate widget
|
||||
const bool mouse_press = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||
bool hovered = ImGui::ItemHoverable(bbox, id);
|
||||
bool temp_input_is_active = ImGui::TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
const bool focus_requested = ImGui::FocusableItemRegister(window, id);
|
||||
if (focus_requested || (hovered && mouse_press) )
|
||||
{
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
const ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const float _h_space = style.WindowPadding.x;
|
||||
ImVec4 bg_color = hovered ? style.Colors[ImGuiCol_FrameBgHovered] : style.Colors[ImGuiCol_FrameBg];
|
||||
|
||||
// prepare index
|
||||
double x = (mouse_pos_in_canvas.x - _h_space) / (size.x - 2.f * _h_space);
|
||||
size_t index = CLAMP( (int) floor(static_cast<double>(values_count) * x), 0, values_count);
|
||||
char cursor_text[64];
|
||||
guint64 time = begin + (index * end) / static_cast<guint64>(values_count);
|
||||
|
||||
// enter edit if widget is active
|
||||
if (ImGui::GetActiveID() == id) {
|
||||
|
||||
bg_color = style.Colors[ImGuiCol_FrameBgActive];
|
||||
|
||||
// keep active area while mouse is pressed
|
||||
static bool active = false;
|
||||
static size_t previous_index = UINT32_MAX;
|
||||
if (mouse_press)
|
||||
{
|
||||
float val = mouse_pos_in_canvas.y / bbox.GetHeight();
|
||||
val = CLAMP( (val * (values_max-values_min)) + values_min, values_min, values_max);
|
||||
|
||||
if (previous_index == UINT32_MAX)
|
||||
previous_index = index;
|
||||
|
||||
const size_t left = MIN(previous_index, index);
|
||||
const size_t right = MAX(previous_index, index);
|
||||
|
||||
if (edit_histogram){
|
||||
static float target_value = values_min;
|
||||
|
||||
// toggle value histo
|
||||
if (!active) {
|
||||
target_value = histogram_array[index] > 0.f ? 0.f : 1.f;
|
||||
active = true;
|
||||
}
|
||||
|
||||
for (size_t i = left; i < right; ++i)
|
||||
histogram_array[i] = target_value;
|
||||
}
|
||||
else {
|
||||
const float target_value = values_max - val;
|
||||
|
||||
for (size_t i = left; i < right; ++i)
|
||||
lines_array[i] = target_value;
|
||||
|
||||
}
|
||||
|
||||
previous_index = index;
|
||||
array_changed = true;
|
||||
}
|
||||
// release active widget on mouse release
|
||||
else {
|
||||
active = false;
|
||||
ImGui::ClearActiveID();
|
||||
previous_index = UINT32_MAX;
|
||||
*released = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// accept drops on timeline plot-histogram
|
||||
else if (ImGui::BeginDragDropTarget()) {
|
||||
const ImGuiPayload *tmp = ImGui::GetDragDropPayload();
|
||||
if (tmp && tmp->IsDataType("DND_TIMELINE")) {
|
||||
TimelinePayload *pl = (TimelinePayload *) tmp->Data;
|
||||
if (pl->action != TimelinePayload::CUT
|
||||
&& pl->action != TimelinePayload::CUT_ERASE) {
|
||||
hovered = true;
|
||||
edit_histogram = true;
|
||||
}
|
||||
}
|
||||
const ImGuiPayload *accepted = ImGui::AcceptDragDropPayload("DND_TIMELINE");
|
||||
if (accepted) {
|
||||
*payload = (TimelinePayload *) accepted->Data;
|
||||
(*payload)->drop_time = time;
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
// back to draw
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot histogram (with frame)
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, bg_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, style.Colors[ImGuiCol_ModalWindowDimBg]); // a dark color
|
||||
char buf[128];
|
||||
snprintf(buf, 128, "##Histo%s", label);
|
||||
ImGui::PlotHistogram(buf, histogram_array, values_count, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
// back to draw
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot (transparent) lines
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
|
||||
snprintf(buf, 128, "##Lines%s", label);
|
||||
ImGui::PlotLines(buf, lines_array, values_count, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
|
||||
// draw the cursor
|
||||
if (hovered) {
|
||||
|
||||
ImFormatString(cursor_text, IM_ARRAYSIZE(cursor_text), "%s",
|
||||
GstToolkit::time_to_string(time).c_str());
|
||||
|
||||
// prepare color and text
|
||||
const ImU32 cur_color = ImGui::GetColorU32(ImGuiCol_CheckMark);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, cur_color);
|
||||
ImVec2 label_size = ImGui::CalcTextSize(cursor_text, NULL);
|
||||
|
||||
// render cursor depending on action
|
||||
mouse_pos_in_canvas.x = CLAMP(mouse_pos_in_canvas.x, _h_space, size.x - _h_space);
|
||||
ImVec2 cursor_pos = canvas_pos;
|
||||
if (edit_histogram) {
|
||||
cursor_pos = cursor_pos + ImVec2(mouse_pos_in_canvas.x, 4.f);
|
||||
window->DrawList->AddLine( cursor_pos, cursor_pos + ImVec2(0.f, size.y - 8.f), cur_color);
|
||||
}
|
||||
else {
|
||||
cursor_pos = cursor_pos + mouse_pos_in_canvas;
|
||||
window->DrawList->AddCircleFilled( cursor_pos, 3.f, cur_color, 8);
|
||||
}
|
||||
|
||||
// draw text
|
||||
cursor_pos.y = canvas_pos.y + size.y - label_size.y - 1.f;
|
||||
if (mouse_pos_in_canvas.x > label_size.x * 1.5f + 2.f * _h_space)
|
||||
cursor_pos.x -= label_size.x + _h_space;
|
||||
else
|
||||
cursor_pos.x += _h_space + style.WindowPadding.x;
|
||||
ImGui::RenderTextClipped(cursor_pos, cursor_pos + label_size, cursor_text, NULL, &label_size);
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
}
|
||||
|
||||
return array_changed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool EditTimeline(const char *label,
|
||||
Timeline *tl,
|
||||
bool edit_histogram,
|
||||
bool *released,
|
||||
const ImVec2 size)
|
||||
{
|
||||
const float values_min = 0.f;
|
||||
const float values_max = 1.f;
|
||||
const guint64 begin = tl->begin();
|
||||
const guint64 end = tl->end();
|
||||
|
||||
bool cursor_dot = !edit_histogram;
|
||||
Timeline _tl;
|
||||
bool array_changed = false;
|
||||
float *lines_array = tl->fadingArray();
|
||||
float *histogram_array = tl->gapsArray();
|
||||
|
||||
// get window
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
// capture coordinates before any draw or action
|
||||
const ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
|
||||
|
||||
// get id
|
||||
const ImGuiID id = window->GetID(label);
|
||||
|
||||
// add item
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImRect bbox(pos, pos + size);
|
||||
ImGui::ItemSize(size);
|
||||
if (!ImGui::ItemAdd(bbox, id))
|
||||
return false;
|
||||
|
||||
*released = false;
|
||||
|
||||
// read user input and activate widget
|
||||
const bool mouse_press = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||
bool hovered = ImGui::ItemHoverable(bbox, id);
|
||||
bool temp_input_is_active = ImGui::TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
const bool focus_requested = ImGui::FocusableItemRegister(window, id);
|
||||
if (focus_requested || (hovered && mouse_press) )
|
||||
{
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
const ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const float _h_space = style.WindowPadding.x;
|
||||
ImVec4 bg_color = hovered ? style.Colors[ImGuiCol_FrameBgHovered] : style.Colors[ImGuiCol_FrameBg];
|
||||
|
||||
// prepare index
|
||||
double x = (mouse_pos_in_canvas.x - _h_space) / (size.x - 2.f * _h_space);
|
||||
size_t index = CLAMP( (int) floor(static_cast<double>(MAX_TIMELINE_ARRAY) * x), 0, MAX_TIMELINE_ARRAY);
|
||||
char cursor_text[64];
|
||||
guint64 time = begin + (index * end) / static_cast<guint64>(MAX_TIMELINE_ARRAY);
|
||||
|
||||
// enter edit if widget is active
|
||||
if (ImGui::GetActiveID() == id) {
|
||||
|
||||
bg_color = style.Colors[ImGuiCol_FrameBgActive];
|
||||
|
||||
// keep active area while mouse is pressed
|
||||
static bool active = false;
|
||||
static size_t previous_index = UINT32_MAX;
|
||||
if (mouse_press)
|
||||
{
|
||||
float val = mouse_pos_in_canvas.y / bbox.GetHeight();
|
||||
val = CLAMP( (val * (values_max-values_min)) + values_min, values_min, values_max);
|
||||
|
||||
if (previous_index == UINT32_MAX)
|
||||
previous_index = index;
|
||||
|
||||
const size_t left = MIN(previous_index, index);
|
||||
const size_t right = MAX(previous_index, index);
|
||||
|
||||
if (edit_histogram){
|
||||
static float target_value = values_min;
|
||||
|
||||
// toggle value histo
|
||||
if (!active) {
|
||||
target_value = histogram_array[index] > 0.f ? 0.f : 1.f;
|
||||
active = true;
|
||||
}
|
||||
|
||||
for (size_t i = left; i < right; ++i)
|
||||
histogram_array[i] = target_value;
|
||||
}
|
||||
else {
|
||||
const float target_value = values_max - val;
|
||||
|
||||
for (size_t i = left; i < right; ++i)
|
||||
lines_array[i] = target_value;
|
||||
|
||||
}
|
||||
|
||||
previous_index = index;
|
||||
array_changed = true;
|
||||
}
|
||||
// release active widget on mouse release
|
||||
else {
|
||||
active = false;
|
||||
ImGui::ClearActiveID();
|
||||
previous_index = UINT32_MAX;
|
||||
*released = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// accept drops on timeline plot-histogram
|
||||
else if (ImGui::BeginDragDropTarget()) {
|
||||
const ImGuiPayload *tmp = ImGui::GetDragDropPayload();
|
||||
if (tmp && tmp->IsDataType("DND_TIMELINE") && tmp->Data != nullptr) {
|
||||
|
||||
// get payload data (tested above)
|
||||
TimelinePayload *pl = (TimelinePayload *) tmp->Data;
|
||||
|
||||
// fake mouse hovered
|
||||
hovered = true;
|
||||
cursor_dot = false;
|
||||
|
||||
// if a timing is given, ignore cursor timing
|
||||
if (pl->timing != GST_CLOCK_TIME_NONE) {
|
||||
// replace drop time by payload timing
|
||||
// time = pl->timing;
|
||||
// // replace mouse coordinate by position from time
|
||||
// size_t index = ((pl->timing - begin) * static_cast<guint64>(MAX_TIMELINE_ARRAY)) / end ;
|
||||
// double x = static_cast<double>(index) / static_cast<double>(MAX_TIMELINE_ARRAY);
|
||||
// mouse_pos_in_canvas.x = ( x * (size.x - 2.f * _h_space)) + _h_space;
|
||||
|
||||
}
|
||||
|
||||
// dragged onto the timeline : apply changes on local copy
|
||||
switch (pl->action) {
|
||||
case TimelinePayload::CUT:
|
||||
_tl = *tl;
|
||||
_tl.cut(time, (bool) pl->argument);
|
||||
histogram_array = _tl.gapsArray();
|
||||
break;
|
||||
case TimelinePayload::CUT_MERGE:
|
||||
_tl = *tl;
|
||||
_tl.mergeGapstAt(time);
|
||||
histogram_array = _tl.gapsArray();
|
||||
break;
|
||||
case TimelinePayload::CUT_ERASE:
|
||||
_tl = *tl;
|
||||
_tl.removeGaptAt(time);
|
||||
histogram_array = _tl.gapsArray();
|
||||
break;
|
||||
case TimelinePayload::FADE_IN:
|
||||
_tl = *tl;
|
||||
_tl.fadeIn(time, pl->timing, (Timeline::FadingCurve) pl->argument);
|
||||
lines_array = _tl.fadingArray();
|
||||
break;
|
||||
case TimelinePayload::FADE_OUT:
|
||||
_tl = *tl;
|
||||
_tl.fadeOut(time, pl->timing, (Timeline::FadingCurve) pl->argument);
|
||||
lines_array = _tl.fadingArray();
|
||||
break;
|
||||
case TimelinePayload::FADE_IN_OUT:
|
||||
_tl = *tl;
|
||||
_tl.fadeInOutRange(time, pl->timing, true, (Timeline::FadingCurve) pl->argument);
|
||||
lines_array = _tl.fadingArray();
|
||||
break;
|
||||
case TimelinePayload::FADE_OUT_IN:
|
||||
_tl = *tl;
|
||||
_tl.fadeInOutRange(time, pl->timing, false, (Timeline::FadingCurve) pl->argument);
|
||||
lines_array = _tl.fadingArray();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// dropped into the timeline : confirm change to timeline
|
||||
if (ImGui::AcceptDragDropPayload("DND_TIMELINE")) {
|
||||
// copy temporary timeline into given timeline
|
||||
*tl = _tl;
|
||||
// like a mouse release
|
||||
*released = true;
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
// back to draw
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot histogram (with frame)
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, bg_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, style.Colors[ImGuiCol_ModalWindowDimBg]); // a dark color
|
||||
char buf[128];
|
||||
snprintf(buf, 128, "##Histo%s", label);
|
||||
ImGui::PlotHistogram(buf, histogram_array, MAX_TIMELINE_ARRAY, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
// back to draw
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot lines (transparent background)
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
|
||||
snprintf(buf, 128, "##Lines%s", label);
|
||||
ImGui::PlotLines(buf, lines_array, MAX_TIMELINE_ARRAY, 0, NULL, values_min, values_max, size);
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
|
||||
// draw the cursor
|
||||
if (hovered) {
|
||||
|
||||
ImFormatString(cursor_text, IM_ARRAYSIZE(cursor_text), "%s",
|
||||
GstToolkit::time_to_string(time).c_str());
|
||||
|
||||
// prepare color and text
|
||||
const ImU32 cur_color = ImGui::GetColorU32(ImGuiCol_CheckMark);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, cur_color);
|
||||
ImVec2 label_size = ImGui::CalcTextSize(cursor_text, NULL);
|
||||
|
||||
// render cursor depending on action
|
||||
mouse_pos_in_canvas.x = CLAMP(mouse_pos_in_canvas.x, _h_space, size.x - _h_space);
|
||||
ImVec2 cursor_pos = canvas_pos;
|
||||
if (cursor_dot) {
|
||||
cursor_pos = cursor_pos + mouse_pos_in_canvas;
|
||||
window->DrawList->AddCircleFilled( cursor_pos, 3.f, cur_color, 8);
|
||||
}
|
||||
else {
|
||||
cursor_pos = cursor_pos + ImVec2(mouse_pos_in_canvas.x, 4.f);
|
||||
window->DrawList->AddLine( cursor_pos, cursor_pos + ImVec2(0.f, size.y - 8.f), cur_color);
|
||||
}
|
||||
|
||||
// draw text
|
||||
cursor_pos.y = canvas_pos.y + size.y - label_size.y - 1.f;
|
||||
if (mouse_pos_in_canvas.x > label_size.x * 1.5f + 2.f * _h_space)
|
||||
cursor_pos.x -= label_size.x + _h_space;
|
||||
else
|
||||
cursor_pos.x += _h_space + style.WindowPadding.x;
|
||||
ImGui::RenderTextClipped(cursor_pos, cursor_pos + label_size, cursor_text, NULL, &label_size);
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
}
|
||||
|
||||
return array_changed;
|
||||
}
|
||||
|
||||
std::list< std::pair<float, guint64> > DrawTimeline(const char* label, Timeline *timeline, guint64 time,
|
||||
double width_ratio, float height)
|
||||
{
|
||||
@@ -1487,7 +1962,7 @@ void SourceControlWindow::RenderSingleSource(Source *s)
|
||||
width = buttons_width_ - ImGui::GetTextLineHeightWithSpacing();
|
||||
ImGui::SameLine(0, space -width);
|
||||
ImGui::SetNextItemWidth(width);
|
||||
if (ImGuiToolkit::ButtonIcon( 0, 14, LABEL_ADD_TIMELINE, space > buttons_width_ )) {
|
||||
if (ImGuiToolkit::ButtonIcon( 0, 14, LABEL_ADD_TIMELINE, true, space > buttons_width_ )) {
|
||||
|
||||
// activate mediaplayer
|
||||
mediaplayer_active_ = ms->mediaplayer();
|
||||
@@ -1550,6 +2025,22 @@ void SourceControlWindow::RenderSingleSource(Source *s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DragButtonIcon(int i, int j, const char *tooltip, TimelinePayload payload)
|
||||
{
|
||||
|
||||
|
||||
ImGuiToolkit::ButtonIcon(i, j, tooltip);
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
// _payload.action = TimelinePayload::FADE_OUT_IN;
|
||||
// _payload.timing = d * GST_MSECOND;
|
||||
// _payload.argument = Timeline::FADING_SMOOTH;
|
||||
ImGui::SetDragDropPayload("DND_TIMELINE", &payload, sizeof(TimelinePayload));
|
||||
ImGuiToolkit::Icon(i, j);
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
}
|
||||
|
||||
void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
||||
{
|
||||
static bool show_overlay_info = false;
|
||||
@@ -1693,26 +2184,25 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
||||
if (tl->is_valid())
|
||||
{
|
||||
bool released = false;
|
||||
if ( ImGuiToolkit::EditPlotHistoLines("##TimelineArray", tl->gapsArray(), tl->fadingArray(),
|
||||
MAX_TIMELINE_ARRAY, 0.f, 1.f, tl->begin(), tl->end(),
|
||||
Settings::application.widget.media_player_timeline_editmode, &released, size) ) {
|
||||
if ( EditTimeline("##TimelineArray", tl,
|
||||
Settings::application.widget.media_player_timeline_editmode,
|
||||
&released, size) ) {
|
||||
tl->update();
|
||||
}
|
||||
// end of mouse down to draw timeline
|
||||
else if (released)
|
||||
{
|
||||
tl->refresh();
|
||||
if (Settings::application.widget.media_player_timeline_editmode)
|
||||
oss << ": Timeline cut";
|
||||
else
|
||||
oss << ": Timeline opacity";
|
||||
oss << ": Timeline fading";
|
||||
Action::manager().store(oss.str());
|
||||
}
|
||||
|
||||
// custom timeline slider
|
||||
// TODO : if (mediaplayer_active_->syncToMetronome() > Metronome::SYNC_NONE)
|
||||
mediaplayer_slider_pressed_ = ImGuiToolkit::TimelineSlider("##timeline", &seek_t, tl->begin(),
|
||||
tl->first(), tl->end(), tl->step(), size.x);
|
||||
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
@@ -1721,51 +2211,13 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
||||
bottom += ImVec2(scrollwindow.x + 2.f, 0.f);
|
||||
draw_list->AddRectFilled(bottom, bottom + ImVec2(slider_zoom_width, timeline_height_ -1.f), ImGui::GetColorU32(ImGuiCol_FrameBg));
|
||||
ImGui::SetCursorScreenPos(bottom + ImVec2(1.f, 0.f));
|
||||
const char *tooltip[2] = {"Fading draw tool", "Timeline cut tool"};
|
||||
ImGuiToolkit::IconToggle(7,4,8,3, &Settings::application.widget.media_player_timeline_editmode, tooltip);
|
||||
|
||||
if (!mediaplayer_edit_panel_ && ImGuiToolkit::IconButton(11, 0, "Open panel"))
|
||||
mediaplayer_edit_panel_ = true;
|
||||
if (mediaplayer_edit_panel_ && ImGuiToolkit::IconButton(10, 0, "Close panel"))
|
||||
mediaplayer_edit_panel_ = false;
|
||||
ImGui::SetCursorScreenPos(bottom + ImVec2(1.f, 0.5f * timeline_height_));
|
||||
if (Settings::application.widget.media_player_timeline_editmode) {
|
||||
// action cut
|
||||
if (mediaplayer_active_->isPlaying()) {
|
||||
ImGuiToolkit::Indication("Pause to enable cut at cursor", 9, 3);
|
||||
}
|
||||
else if (ImGuiToolkit::IconButton(9, 3, "Cut at cursor")) {
|
||||
ImGui::OpenPopup("timeline_cut_context_menu");
|
||||
}
|
||||
if (ImGui::BeginPopup("timeline_cut_context_menu")){
|
||||
if (ImGuiToolkit::MenuItemIcon(1,0,"Cut left")){
|
||||
if (mediaplayer_active_->timeline()->cut(mediaplayer_active_->position(), true, false)) {
|
||||
oss << ": Timeline cut";
|
||||
Action::manager().store(oss.str());
|
||||
}
|
||||
}
|
||||
if (ImGuiToolkit::MenuItemIcon(2,0,"Cut right")){
|
||||
if (mediaplayer_active_->timeline()->cut(mediaplayer_active_->position(), false, false)){
|
||||
oss << ": Timeline cut";
|
||||
Action::manager().store(oss.str());
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
else {
|
||||
static int _actionsmooth = 0;
|
||||
|
||||
// action smooth
|
||||
ImGui::PushButtonRepeat(true);
|
||||
if (ImGuiToolkit::IconButton(13, 12, "Smooth fading curve")){
|
||||
mediaplayer_active_->timeline()->smoothFading( 5 );
|
||||
++_actionsmooth;
|
||||
}
|
||||
ImGui::PopButtonRepeat();
|
||||
|
||||
if (_actionsmooth > 0 && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
|
||||
oss << ": Timeline opacity smooth";
|
||||
Action::manager().store(oss.str());
|
||||
_actionsmooth = 0;
|
||||
}
|
||||
}
|
||||
const char *tooltip[2] = {"Fading tool", "Cutting tool"};
|
||||
ImGuiToolkit::IconToggle(7,4,8,3, &Settings::application.widget.media_player_timeline_editmode, tooltip);
|
||||
|
||||
// zoom slider
|
||||
ImGui::SetCursorScreenPos(bottom + ImVec2(0.f, timeline_height_));
|
||||
@@ -1932,6 +2384,345 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
///
|
||||
/// Window area to edit gaps or fading
|
||||
///
|
||||
if (mediaplayer_edit_panel_) {
|
||||
|
||||
const ImVec2 gap_dialog_size(buttons_width_ * 3.0f, buttons_height_ * 1.42);
|
||||
const ImVec2 gap_dialog_pos = rendersize + ImVec2(h_space_, buttons_height_) - gap_dialog_size;
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyle().Colors[ImGuiCol_PopupBg] );
|
||||
ImGui::SetCursorPos(gap_dialog_pos);
|
||||
ImGui::BeginChild("##EditGapsWindow",
|
||||
gap_dialog_size, true,
|
||||
ImGuiWindowFlags_NoScrollbar);
|
||||
|
||||
// variables state of panel
|
||||
static int current_curve = 2;
|
||||
static uint d = UINT_MAX;
|
||||
static guint64 target_time = 30000000000;
|
||||
|
||||
// timeline to edit
|
||||
Timeline *tl = mediaplayer_active_->timeline();
|
||||
|
||||
///
|
||||
/// PANEL FOR CUT TIMELINE MODE
|
||||
///
|
||||
ImGui::Spacing();
|
||||
if (Settings::application.widget.media_player_timeline_editmode) {
|
||||
|
||||
// PANEL WITH LARGE FONTS
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
||||
|
||||
///
|
||||
/// CUT LEFT OF CURSOR
|
||||
///
|
||||
DragButtonIcon(9, 3, "Drop in timeline to\nCut left",
|
||||
TimelinePayload(TimelinePayload::CUT, 0, 1) );
|
||||
///
|
||||
/// CUT RIGHT OF CURSOR
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(10, 3, "Drop in timeline to\nCut right",
|
||||
TimelinePayload(TimelinePayload::CUT, 0, 0) );
|
||||
|
||||
if (tl->numGaps() > 0) {
|
||||
///
|
||||
/// MERGE CUTS AT CURSOR
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(19, 3, "Drop in timeline to\nMerge right",
|
||||
TimelinePayload(TimelinePayload::CUT_MERGE, 0, 0) );
|
||||
///
|
||||
/// ERASE CUT AT CURSOR
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(0, 4, "Drop in timeline to\nErase right",
|
||||
TimelinePayload(TimelinePayload::CUT_ERASE, 0, 0) );
|
||||
}
|
||||
else {
|
||||
///
|
||||
/// DISABLED ICONS IF NO GAP
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGuiToolkit::ButtonIcon(19, 3, "No gap to merge", false);
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGuiToolkit::ButtonIcon(0, 4, "No gap to erase", false);
|
||||
}
|
||||
|
||||
///
|
||||
/// SEPARATOR
|
||||
///
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::Text("|");
|
||||
|
||||
///
|
||||
/// Enter time or percentage of time
|
||||
///
|
||||
target_time = MIN(target_time, tl->duration());
|
||||
|
||||
ImGui::SameLine(0, 0);
|
||||
ImVec2 draw_pos = ImGui::GetCursorPos();
|
||||
ImGui::SetNextItemWidth(180); // TODO VARIABLE WIDTH
|
||||
ImGuiToolkit::InputTime("##Time", &target_time);
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(draw_pos.x, draw_pos.y + 35));
|
||||
ImGuiToolkit::HSliderUInt64("#SliderTime", ImVec2(180, 14), &target_time, 0, tl->duration());
|
||||
|
||||
// static int p = 5;
|
||||
// ImGuiToolkit::HSliderInt("#toto", ImVec2(140, 14), &p, 1, 9);
|
||||
// if (ImGui::IsItemActive()) {
|
||||
// ImGuiToolkit::PushFont(ImGuiToolkit::FONT_DEFAULT);
|
||||
// ImGui::SetTooltip("%d%%", p * 10);
|
||||
// ImGui::PopFont();
|
||||
// }
|
||||
// if (ImGui::IsItemDeactivatedAfterEdit()){
|
||||
|
||||
// }
|
||||
|
||||
// ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
// ImVec2 draw_pos = ImGui::GetCursorPos() + ImVec2(0, v_space_);
|
||||
// ImGui::SetCursorPos(ImVec2(gap_dialog_size.x - ImGui::GetTextLineHeightWithSpacing()- IMGUI_SAME_LINE,
|
||||
// draw_pos.y));
|
||||
// static bool percentage = false;
|
||||
// ImGuiToolkit::IconToggle(19, 10, 3, 7, &percentage);
|
||||
// ImGui::SetCursorPos(draw_pos);
|
||||
// if (percentage) {
|
||||
// int target_percent = (int) ( (100 * target_time) / tl->duration() );
|
||||
// ImGui::SetNextItemWidth(-ImGui::GetTextLineHeightWithSpacing());
|
||||
// ImGui::DragInt("##percent", &target_percent, 1, 0, 100);
|
||||
// target_time = (tl->duration() * (guint64) target_percent) / 100;
|
||||
// }
|
||||
// else {
|
||||
// ImGui::SetNextItemWidth(-ImGui::GetTextLineHeightWithSpacing());
|
||||
// ImGuiToolkit::InputTime("##Time", &target_time);
|
||||
// }
|
||||
|
||||
// Action buttons
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
|
||||
ImGui::SetCursorPos(
|
||||
ImVec2(gap_dialog_size.x - 4.f * ImGui::GetTextLineHeightWithSpacing() - IMGUI_SAME_LINE,
|
||||
draw_pos.y));
|
||||
|
||||
// ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
if (ImGuiToolkit::ButtonIcon(17, 3, "Cut left at given time")) {
|
||||
tl->cut(target_time, true);
|
||||
tl->refresh();
|
||||
}
|
||||
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
if (ImGuiToolkit::ButtonIcon(18, 3, "Cut right at given time")){
|
||||
tl->cut(target_time, false);
|
||||
tl->refresh();
|
||||
}
|
||||
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
if (ImGuiToolkit::ButtonIcon(11, 14, "Clear all gaps"))
|
||||
tl->clearGaps();
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// end icons
|
||||
ImGui::PopFont();
|
||||
}
|
||||
///
|
||||
/// FADING
|
||||
///
|
||||
else {
|
||||
// Icons for Drag & Drop
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
||||
|
||||
///
|
||||
/// CURVE MODE
|
||||
///
|
||||
const std::vector<std::string> tooltips_curve = {{"Fading Sharp"},
|
||||
{"Fading Linear"},
|
||||
{"Fading Smooth"}};
|
||||
const std::vector<std::pair<int, int> > options_curve
|
||||
= {{12, 12},
|
||||
{13, 12},
|
||||
{14, 12}};
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
// ImGuiToolkit::ButtonIconMultistate(options_curve, ¤t_curve, tooltips_curve);
|
||||
ImGuiToolkit::IconMultistate(options_curve, ¤t_curve, tooltips_curve);
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
///
|
||||
/// FADING SHARP
|
||||
///
|
||||
if (current_curve == 0) {
|
||||
///
|
||||
/// FADE IN
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(14, 10, "Drop in timeline to insert\nSharp fade-in",
|
||||
TimelinePayload(TimelinePayload::FADE_IN, d*GST_MSECOND, Timeline::FADING_SHARP));
|
||||
///
|
||||
/// FADE OUT
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(11, 10, "Drop in timeline to insert\nSharp fade-out",
|
||||
TimelinePayload(TimelinePayload::FADE_OUT, d*GST_MSECOND, Timeline::FADING_SHARP));
|
||||
///
|
||||
/// FADE IN & OUT
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(9, 10, "Drop in timeline to insert\nSharp fade in & out",
|
||||
TimelinePayload(TimelinePayload::FADE_IN_OUT, d*GST_MSECOND, Timeline::FADING_SHARP));
|
||||
///
|
||||
/// FADE OUT & IN
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(10, 10, "Drop in timeline to insert\nSharp fade out & in",
|
||||
TimelinePayload(TimelinePayload::FADE_OUT_IN, d*GST_MSECOND, Timeline::FADING_SHARP));
|
||||
}
|
||||
///
|
||||
/// FADE LINEAR
|
||||
///
|
||||
else if (current_curve == 1) {
|
||||
///
|
||||
/// FADE IN
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(15, 10, "Drop in timeline to insert\nLinear fade-in",
|
||||
TimelinePayload(TimelinePayload::FADE_IN, d*GST_MSECOND, Timeline::FADING_LINEAR));
|
||||
///
|
||||
/// FADE OUT
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(12, 10, "Drop in timeline to insert\nLinear fade-out",
|
||||
TimelinePayload(TimelinePayload::FADE_OUT, d*GST_MSECOND, Timeline::FADING_LINEAR));
|
||||
///
|
||||
/// FADE IN & OUT
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(7, 10, "Drop in timeline to insert\nLinear fade in & out",
|
||||
TimelinePayload(TimelinePayload::FADE_IN_OUT, d*GST_MSECOND, Timeline::FADING_LINEAR));
|
||||
///
|
||||
/// FADE OUT & IN
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(8, 10, "Drop in timeline to insert\nLinear fade out & in",
|
||||
TimelinePayload(TimelinePayload::FADE_OUT_IN, d*GST_MSECOND, Timeline::FADING_LINEAR));
|
||||
}
|
||||
///
|
||||
/// FADE SMOOTH
|
||||
///
|
||||
else if (current_curve == 2) {
|
||||
///
|
||||
/// FADE IN
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(16, 10, "Drop in timeline to insert\nSmooth fade-in",
|
||||
TimelinePayload(TimelinePayload::FADE_IN, d*GST_MSECOND, Timeline::FADING_SMOOTH));
|
||||
///
|
||||
/// FADE OUT
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(13, 10, "Drop in timeline to insert\nSmooth fade-out",
|
||||
TimelinePayload(TimelinePayload::FADE_OUT, d*GST_MSECOND, Timeline::FADING_SMOOTH));
|
||||
///
|
||||
/// FADE IN & OUT
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(17, 10, "Drop in timeline to insert\nSmooth fade in & out",
|
||||
TimelinePayload(TimelinePayload::FADE_IN_OUT, d*GST_MSECOND, Timeline::FADING_SMOOTH));
|
||||
///
|
||||
/// FADE OUT & IN
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
DragButtonIcon(18, 10, "Drop in timeline to insert\nSmooth fade out & in",
|
||||
TimelinePayload(TimelinePayload::FADE_OUT_IN, d*GST_MSECOND, Timeline::FADING_SMOOTH));
|
||||
|
||||
}
|
||||
|
||||
// float md = 10000;
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGui::SetNextItemWidth(180);
|
||||
float seconds = (float) d / 1000.f;
|
||||
|
||||
if (current_curve > 0) {
|
||||
// ImGuiToolkit::SliderTiming("##Duration", &d, 60, md+50, 50, "Auto");
|
||||
// if (d > md) d = UINT_MAX;
|
||||
if (ImGui::SliderFloat("##DurationFading",
|
||||
&seconds,
|
||||
0.05f,
|
||||
60.f,
|
||||
seconds < 59.5f ? "%.2f s" : "Auto")) {
|
||||
if (seconds > 59.5f)
|
||||
d = UINT_MAX;
|
||||
else
|
||||
d = (uint) floor(seconds * 1000);
|
||||
}
|
||||
} else {
|
||||
// ImGui::TextDisabled("%.2f s", seconds);
|
||||
static char dummy_str[512];
|
||||
if (seconds < 59.5f )
|
||||
snprintf(dummy_str, 512, "%.2f s", seconds);
|
||||
else
|
||||
snprintf(dummy_str, 512, "Auto");
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f));
|
||||
ImGui::InputText("##disabledduration", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Action buttons
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
|
||||
///
|
||||
/// SEPARATOR
|
||||
///
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::Text("|");
|
||||
|
||||
// action smooth
|
||||
static int _actionsmooth = 0;
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::PushButtonRepeat(true);
|
||||
if (ImGuiToolkit::ButtonIcon(2, 7, "Apply smoothing filter")){
|
||||
tl->smoothFading( 5 );
|
||||
++_actionsmooth;
|
||||
}
|
||||
ImGui::PopButtonRepeat();
|
||||
if (_actionsmooth > 0 && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
|
||||
oss << ": Timeline opacity smooth";
|
||||
Action::manager().store(oss.str());
|
||||
_actionsmooth = 0;
|
||||
}
|
||||
|
||||
|
||||
// ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
// ImGui::SetNextItemWidth(140); // TODO VARIABLE WIDTH
|
||||
// ImVec2 draw_pos = ImGui::GetCursorPos();
|
||||
// ImGui::SetCursorPosY(draw_pos.y + 8); // TODO VARIABLE H
|
||||
// ImGuiToolkit::InputTime("##Time", &target_time);
|
||||
|
||||
|
||||
///
|
||||
/// CLEAR
|
||||
///
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
if (ImGuiToolkit::ButtonIcon(11, 14, "Clear Fading curve"))
|
||||
tl->clearFading();
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// end icons
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Dialog to edit timeline fade in and out
|
||||
///
|
||||
@@ -1989,15 +2780,15 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
||||
Timeline *tl = mediaplayer_active_->timeline();
|
||||
switch (l) {
|
||||
case 0:
|
||||
tl->fadeIn(d, (Timeline::FadingCurve) c);
|
||||
tl->fadeIn( static_cast<GstClockTime>(d) * GST_MSECOND, (Timeline::FadingCurve) c);
|
||||
oss << ": Timeline Fade in " << d;
|
||||
break;
|
||||
case 1:
|
||||
tl->fadeOut(d, (Timeline::FadingCurve) c);
|
||||
tl->fadeOut( static_cast<GstClockTime>(d) * GST_MSECOND, (Timeline::FadingCurve) c);
|
||||
oss << ": Timeline Fade out " << d;
|
||||
break;
|
||||
case 2:
|
||||
tl->autoFading(d, (Timeline::FadingCurve) c);
|
||||
tl->autoFading( static_cast<GstClockTime>(d) * GST_MSECOND, (Timeline::FadingCurve) c);
|
||||
oss << ": Timeline Fade in&out " << d;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -54,6 +54,8 @@ class SourceControlWindow : public WorkspaceWindow
|
||||
bool mediaplayer_mode_;
|
||||
bool mediaplayer_slider_pressed_;
|
||||
float mediaplayer_timeline_zoom_;
|
||||
|
||||
bool mediaplayer_edit_panel_;
|
||||
void RenderMediaPlayer(MediaSource *ms);
|
||||
|
||||
// draw methods
|
||||
|
||||
331
src/Timeline.cpp
331
src/Timeline.cpp
@@ -23,6 +23,25 @@
|
||||
#include "defines.h"
|
||||
#include "Timeline.h"
|
||||
|
||||
float clamp(float x, float lowerlimit = 0.0f, float upperlimit = 1.0f) {
|
||||
if (x < lowerlimit) return lowerlimit;
|
||||
if (x > upperlimit) return upperlimit;
|
||||
return x;
|
||||
}
|
||||
|
||||
float smootherstep(size_t edge0, size_t edge1, size_t i) {
|
||||
float x = clamp( static_cast<float>(i - edge0) / static_cast<float>(edge1 - edge0));
|
||||
return x * x * x * (x * (6.0f * x - 15.0f) + 10.0f);
|
||||
// return x * x * (3.0f - 2.0f * x);
|
||||
}
|
||||
|
||||
float linestep(size_t edge0, size_t edge1, size_t i) {
|
||||
float x = clamp( static_cast<float>(i - edge0) / static_cast<float>(edge1 - edge0));
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static float empty_zeros[MAX_TIMELINE_ARRAY] = {};
|
||||
static float empty_ones[MAX_TIMELINE_ARRAY] = {};
|
||||
@@ -200,7 +219,12 @@ bool Timeline::cut(GstClockTime t, bool left, bool join_extremity)
|
||||
break;
|
||||
}
|
||||
if (join_extremity) {
|
||||
//TODO
|
||||
if (previous != gaps_.end()) {
|
||||
for (auto g = gaps_.begin(); g != gaps_.find(*previous); ) {
|
||||
g = gaps_.erase(g);
|
||||
}
|
||||
}
|
||||
ret = addGap( TimeInterval(t, timing_.begin) );
|
||||
}
|
||||
else {
|
||||
if (previous == gaps_.end())
|
||||
@@ -271,6 +295,9 @@ void Timeline::setGaps(const TimeIntervalSet &g)
|
||||
|
||||
bool Timeline::removeGaptAt(GstClockTime t)
|
||||
{
|
||||
if (gaps_.empty())
|
||||
return false;
|
||||
|
||||
TimeIntervalSet::const_iterator s = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t));
|
||||
|
||||
if ( s != gaps_.end() ) {
|
||||
@@ -282,6 +309,41 @@ bool Timeline::removeGaptAt(GstClockTime t)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Timeline::mergeGapstAt(GstClockTime t)
|
||||
{
|
||||
if (gaps_.empty())
|
||||
return false;
|
||||
|
||||
auto first = gaps_.end();
|
||||
auto second = gaps_.end();
|
||||
|
||||
for (auto g = gaps_.begin(); g != gaps_.end(); g++) {
|
||||
if (g->includes(t)) {
|
||||
return false;
|
||||
} else if (t > g->end) {
|
||||
first = g;
|
||||
} else if (t < g->begin) {
|
||||
second = g;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first != gaps_.end() && second != gaps_.end()) {
|
||||
gaps_.erase(first);
|
||||
gaps_.erase(second);
|
||||
addGap(first->begin, second->end);
|
||||
}
|
||||
else if (second != gaps_.end()) {
|
||||
gaps_.erase(second);
|
||||
addGap(timing_.begin, second->end);
|
||||
}
|
||||
else if (first != gaps_.end()) {
|
||||
gaps_.erase(first);
|
||||
addGap(first->begin, timing_.end);
|
||||
}
|
||||
|
||||
return gaps_array_need_update_;
|
||||
}
|
||||
|
||||
GstClockTime Timeline::sectionsDuration() const
|
||||
{
|
||||
@@ -478,38 +540,60 @@ void Timeline::clearFading()
|
||||
memcpy(fadingArray_, empty_ones, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||
}
|
||||
|
||||
void Timeline::smoothFading(uint N)
|
||||
void Timeline::smoothFading(uint N, TimeInterval interval)
|
||||
{
|
||||
const float kernel[7] = { 2.f, 22.f, 97.f, 159.f, 97.f, 22.f, 2.f};
|
||||
float tmparray[MAX_TIMELINE_ARRAY];
|
||||
|
||||
for (uint n = 0; n < N; ++n) {
|
||||
// default to cover entire array
|
||||
long s = 0;
|
||||
long e = MAX_TIMELINE_ARRAY;
|
||||
|
||||
for (long i = 0; i < MAX_TIMELINE_ARRAY; ++i) {
|
||||
tmparray[i] = 0.f;
|
||||
float divider = 0.f;
|
||||
for( long j = 0; j < 7; ++j) {
|
||||
long k = i - 3 + j;
|
||||
if (k > -1 && k < MAX_TIMELINE_ARRAY-1) {
|
||||
tmparray[i] += fadingArray_[k] * kernel[j];
|
||||
divider += kernel[j];
|
||||
// if a valid interval is given in argument
|
||||
if (interval.is_valid()) {
|
||||
|
||||
// get index of begining of interval
|
||||
s = (interval.begin * MAX_TIMELINE_ARRAY) / timing_.end;
|
||||
// get index of ending of interval
|
||||
e = (interval.end * MAX_TIMELINE_ARRAY) / timing_.end;
|
||||
|
||||
// iterate a given amount of times
|
||||
for (uint n = 0; n < N; ++n) {
|
||||
// copy to tmp array
|
||||
memcpy(tmparray, fadingArray_, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||
// apply gaussian filter on the interval
|
||||
for (long i = s; i < e; ++i) {
|
||||
tmparray[i] = 0.f;
|
||||
float divider = 0.f;
|
||||
for (long j = 0; j < 7; ++j) {
|
||||
long k = i - 3 + j;
|
||||
if (k > -1 && k < MAX_TIMELINE_ARRAY - 1) {
|
||||
tmparray[i] += fadingArray_[k] * kernel[j];
|
||||
divider += kernel[j];
|
||||
}
|
||||
}
|
||||
tmparray[i] *= 1.f / divider;
|
||||
}
|
||||
tmparray[i] *= 1.f / divider;
|
||||
// copy back to array
|
||||
memcpy(fadingArray_, tmparray, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||
}
|
||||
}
|
||||
// in absence of interval given, loop over all sections
|
||||
else {
|
||||
TimeIntervalSet _intervals = sections();
|
||||
for (auto inter = _intervals.begin(); inter != _intervals.end(); inter++) {
|
||||
smoothFading(N, *inter);
|
||||
}
|
||||
|
||||
memcpy( fadingArray_, tmparray, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Timeline::autoFading(uint milisecond, FadingCurve curve)
|
||||
void Timeline::autoFading(const GstClockTime duration, FadingCurve curve)
|
||||
{
|
||||
// mow many index values of timeline array for this duration?
|
||||
size_t N = MAX_TIMELINE_ARRAY -1;
|
||||
GstClockTime d = static_cast<GstClockTime>(milisecond) * 1000000;
|
||||
if ( d < timing_.end )
|
||||
N = d / (timing_.end / MAX_TIMELINE_ARRAY);
|
||||
if ( duration < timing_.end )
|
||||
N = duration / (timing_.end / MAX_TIMELINE_ARRAY);
|
||||
|
||||
// clear with static array
|
||||
memcpy(fadingArray_, empty_zeros, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||
@@ -534,9 +618,9 @@ void Timeline::autoFading(uint milisecond, FadingCurve curve)
|
||||
size_t i = s;
|
||||
for (; i < s+n; ++i){
|
||||
const float x = static_cast<float>(i-s) / static_cast<float>(n);
|
||||
if (curve==FADING_BILINEAR)
|
||||
if (curve==FADING_LINEAR)
|
||||
fadingArray_[i] = x * x;
|
||||
else if (curve==FADING_BILINEAR_INV)
|
||||
else if (curve==FADING_SMOOTH)
|
||||
fadingArray_[i] = 1.f - ((x- 1.f) * (x - 1.f));
|
||||
else
|
||||
fadingArray_[i] = x;
|
||||
@@ -547,9 +631,9 @@ void Timeline::autoFading(uint milisecond, FadingCurve curve)
|
||||
// linear fade out ending at e
|
||||
for (; i < e; ++i) {
|
||||
const float x = static_cast<float>(e-i) / static_cast<float>(n);
|
||||
if (curve==FADING_BILINEAR)
|
||||
if (curve==FADING_LINEAR)
|
||||
fadingArray_[i] = x * x;
|
||||
else if (curve==FADING_BILINEAR_INV)
|
||||
else if (curve==FADING_SMOOTH)
|
||||
fadingArray_[i] = 1.f - ((x- 1.f) * (x - 1.f));
|
||||
else
|
||||
fadingArray_[i] = x;
|
||||
@@ -557,94 +641,177 @@ void Timeline::autoFading(uint milisecond, FadingCurve curve)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Timeline::fadeIn(uint milisecond, FadingCurve curve)
|
||||
void Timeline::fadeOut(const GstClockTime from, const GstClockTime duration, FadingCurve curve)
|
||||
{
|
||||
// mow many index values of timeline array for this duration?
|
||||
size_t N = MAX_TIMELINE_ARRAY -1;
|
||||
GstClockTime d = static_cast<GstClockTime>(milisecond) * 1000000;
|
||||
if ( d < timing_.end )
|
||||
N = d / (timing_.end / MAX_TIMELINE_ARRAY);
|
||||
GstClockTime to = from + duration;
|
||||
|
||||
// get sections (inverse of gaps) is never empty
|
||||
TimeIntervalSet sec = sections();
|
||||
auto it = sec.cbegin();
|
||||
if (duration > timing_.end) {
|
||||
to = timing_.end;
|
||||
for (auto g = gaps_.begin(); g != gaps_.end(); ++g) {
|
||||
// gap after target?
|
||||
if (g->begin > from) {
|
||||
to = g->begin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get index of begining of section
|
||||
const size_t s = ( it->begin * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||
// get index of begining of fading curve
|
||||
const size_t s = ( from * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||
|
||||
// get index of ending of section
|
||||
const size_t e = ( it->end * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||
// get index of ending of fading curve
|
||||
const size_t e = ( to * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||
|
||||
// how many index values of timeline array for this duration?
|
||||
size_t N = MAX_TIMELINE_ARRAY - 1;
|
||||
N = MIN( ( MIN( duration, timing_.end - from ) * MAX_TIMELINE_ARRAY )/ timing_.end, N );
|
||||
|
||||
// calculate size of the smooth transition in [s e] interval
|
||||
const size_t n = MIN( e-s, N );
|
||||
|
||||
// linear fade in starting at s
|
||||
// if transition too short for a linear or smooth
|
||||
if (N < 3) {
|
||||
curve = FADING_SHARP;
|
||||
N = 2;
|
||||
}
|
||||
|
||||
// linear fade out starts at s
|
||||
size_t i = s;
|
||||
float val = fadingArray_[s+n];
|
||||
for (; i < s+n; ++i) {
|
||||
const float x = static_cast<float>(i-s) / static_cast<float>(n);
|
||||
if (curve==FADING_BILINEAR)
|
||||
fadingArray_[i] = x * x;
|
||||
else if (curve==FADING_BILINEAR_INV)
|
||||
fadingArray_[i] = 1.f - ((x- 1.f) * (x - 1.f));
|
||||
else
|
||||
// float val = fadingArray_[s];
|
||||
for (; i <= s+n; ++i) {
|
||||
const float x = static_cast<float>(e-i) / static_cast<float>(n);
|
||||
// const float x = 1.f - static_cast<float>(i-s) / static_cast<float>(n);
|
||||
if (curve==FADING_LINEAR)
|
||||
fadingArray_[i] = x;
|
||||
fadingArray_[i] *= val;
|
||||
else if (curve==FADING_SMOOTH)
|
||||
fadingArray_[i] = 1.f - smootherstep(s, s+n, i);
|
||||
else
|
||||
fadingArray_[i] = 0.f;
|
||||
// fadingArray_[i] *= val;
|
||||
}
|
||||
|
||||
// add a bit of buffer to avoid jump to previous frame
|
||||
size_t b = s - (step_ / 2) / (timing_.end / MAX_TIMELINE_ARRAY);
|
||||
if (b > 0) {
|
||||
for (size_t j = b; j < s; ++j)
|
||||
fadingArray_[j] = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::fadeOut(uint milisecond, FadingCurve curve)
|
||||
void Timeline::fadeIn(const GstClockTime to, const GstClockTime duration, FadingCurve curve)
|
||||
{
|
||||
// mow many index values of timeline array for this duration?
|
||||
size_t N = MAX_TIMELINE_ARRAY -1;
|
||||
GstClockTime d = static_cast<GstClockTime>(milisecond) * 1000000;
|
||||
if ( d < timing_.end )
|
||||
N = d / (timing_.end / MAX_TIMELINE_ARRAY);
|
||||
GstClockTime from = to - duration;
|
||||
|
||||
// get sections (inverse of gaps) is never empty
|
||||
TimeIntervalSet sec = sections();
|
||||
auto it = sec.end();
|
||||
--it;
|
||||
if (duration > timing_.end) {
|
||||
for (auto g = gaps_.begin(); g != gaps_.end(); ++g) {
|
||||
// gap before target?
|
||||
if ( g->end < to )
|
||||
from = g->end;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// get index of begining of section
|
||||
const size_t s = ( it->begin * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||
// get index of begining of fading curve
|
||||
const size_t s = ( from * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||
|
||||
// get index of ending of section
|
||||
const size_t e = ( it->end * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||
// get index of ending of fading curve
|
||||
const size_t e = ( to * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||
|
||||
// how many index values of timeline array for this duration?
|
||||
size_t N = MAX_TIMELINE_ARRAY - 1;
|
||||
N = MIN( ( MIN( duration, to - timing_.begin ) * MAX_TIMELINE_ARRAY )/ timing_.end, N );
|
||||
|
||||
// if transition too short for a linear or smooth
|
||||
if (N < 3) {
|
||||
curve = FADING_SHARP;
|
||||
N = 2;
|
||||
}
|
||||
|
||||
// calculate size of the smooth transition in [s e] interval
|
||||
const size_t n = MIN( e-s, N );
|
||||
|
||||
// linear fade out ending at e
|
||||
// linear fade in ends at e
|
||||
size_t i = e-n;
|
||||
float val = fadingArray_[i];
|
||||
for (; i < e; ++i){
|
||||
const float x = static_cast<float>(e-i) / static_cast<float>(n);
|
||||
if (curve==FADING_BILINEAR)
|
||||
fadingArray_[i] = x * x;
|
||||
else if (curve==FADING_BILINEAR_INV)
|
||||
fadingArray_[i] = 1.f - ((x- 1.f) * (x - 1.f));
|
||||
else
|
||||
// float val = fadingArray_[e];
|
||||
for (; i < e; ++i) {
|
||||
// const float x = static_cast<float>(i-s) / static_cast<float>(n);
|
||||
const float x = 1.f - static_cast<float>(e - i) / static_cast<float>(n);
|
||||
if (curve==FADING_LINEAR)
|
||||
fadingArray_[i] = x;
|
||||
fadingArray_[i] *= val;
|
||||
else if (curve==FADING_SMOOTH)
|
||||
fadingArray_[i] = smootherstep(e-n, e, i);
|
||||
else
|
||||
fadingArray_[i] = 0.f;
|
||||
// fadingArray_[i] *= val;
|
||||
}
|
||||
|
||||
// add a bit of buffer to avoid jump to next frame
|
||||
size_t b = e + (1000 + step_) / (timing_.end / MAX_TIMELINE_ARRAY);
|
||||
if (b < MAX_TIMELINE_ARRAY) {
|
||||
for (size_t j = e; j < b; ++j)
|
||||
fadingArray_[j] = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::fadeInOutRange(const GstClockTime t, const GstClockTime duration, bool in_and_out, FadingCurve curve)
|
||||
{
|
||||
// init range to whole timeline
|
||||
TimeInterval range = timing_;
|
||||
|
||||
// find cuts at left and right of given time
|
||||
for (auto g = gaps_.begin(); g != gaps_.end(); g++) {
|
||||
if (g->begin < t) {
|
||||
if (g->end > t) {
|
||||
// inside a gap
|
||||
range.begin = g->begin;
|
||||
range.end = g->end;
|
||||
break;
|
||||
} else {
|
||||
// after a gap
|
||||
range.begin = g->end;
|
||||
}
|
||||
} else {
|
||||
// before a gap
|
||||
range.end = g->begin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// get index of begining of section
|
||||
const size_t s = (range.begin * MAX_TIMELINE_ARRAY) / timing_.end;
|
||||
|
||||
// get index of ending of section
|
||||
const size_t e = (range.end * MAX_TIMELINE_ARRAY) / timing_.end;
|
||||
|
||||
// get index of time in section
|
||||
const size_t m = (t * MAX_TIMELINE_ARRAY) / timing_.end;
|
||||
|
||||
size_t l = m;
|
||||
size_t r = m;
|
||||
|
||||
// if duration too short for a linear or smooth
|
||||
if (duration < 2 * step_) {
|
||||
curve = FADING_SHARP;
|
||||
}
|
||||
// if duration allows to fade in and out
|
||||
else if (2 * duration < range.duration()) {
|
||||
l = ( (range.begin + duration) * MAX_TIMELINE_ARRAY) / timing_.end;
|
||||
r = ( (range.end - duration) * MAX_TIMELINE_ARRAY) / timing_.end;
|
||||
}
|
||||
|
||||
// fill values inside range
|
||||
for (size_t k = s; k < e; ++k) {
|
||||
|
||||
if (curve == FADING_LINEAR){
|
||||
if (k<l)
|
||||
fadingArray_[k] = in_and_out ? linestep(s, l, k) : 1.f - linestep(s, l, k);
|
||||
else if (k<r)
|
||||
fadingArray_[k] = in_and_out ? 1.f : 0.f;
|
||||
else
|
||||
fadingArray_[k] = in_and_out ? 1.f - linestep(r, e, k) : linestep(r, e, k);
|
||||
}
|
||||
else if (curve == FADING_SMOOTH) {
|
||||
if (k<l)
|
||||
fadingArray_[k] = in_and_out ? smootherstep(s, l, k) : 1.f - smootherstep(s, l, k);
|
||||
else if (k<r)
|
||||
fadingArray_[k] = in_and_out ? 1.f : 0.f;
|
||||
else
|
||||
fadingArray_[k] = in_and_out ? 1.f - smootherstep(r, e, k) : smootherstep(r, e, k);
|
||||
}
|
||||
else // curve == FADING_SHARP
|
||||
fadingArray_[k] = in_and_out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool Timeline::autoCut()
|
||||
|
||||
@@ -131,8 +131,9 @@ public:
|
||||
void setGaps(const TimeIntervalSet &g);
|
||||
bool addGap(TimeInterval s);
|
||||
bool addGap(GstClockTime begin, GstClockTime end);
|
||||
bool cut(GstClockTime t, bool left, bool join_extremity);
|
||||
bool cut(GstClockTime t, bool left, bool join_extremity = false);
|
||||
bool removeGaptAt(GstClockTime t);
|
||||
bool mergeGapstAt(GstClockTime t);
|
||||
bool gapAt(const GstClockTime t) const;
|
||||
bool getGapAt(const GstClockTime t, TimeInterval &gap) const;
|
||||
|
||||
@@ -150,14 +151,19 @@ public:
|
||||
|
||||
// Edit
|
||||
typedef enum {
|
||||
FADING_LINEAR = 0,
|
||||
FADING_BILINEAR,
|
||||
FADING_BILINEAR_INV
|
||||
FADING_SHARP = 0,
|
||||
FADING_LINEAR,
|
||||
FADING_SMOOTH
|
||||
} FadingCurve;
|
||||
void smoothFading(uint N = 1);
|
||||
void autoFading(uint milisecond = 100, FadingCurve curve = FADING_LINEAR);
|
||||
void fadeIn(uint milisecond = 100, FadingCurve curve = FADING_LINEAR);
|
||||
void fadeOut(uint milisecond = 100, FadingCurve curve = FADING_LINEAR);
|
||||
void smoothFading(uint N = 1, TimeInterval interval = TimeInterval());
|
||||
void autoFading(const GstClockTime duration = 10000, FadingCurve curve = FADING_SHARP);
|
||||
|
||||
// void fadeIn(const GstClockTime duration = 100000, FadingCurve curve = FADING_LINEAR);
|
||||
// void fadeOut(const GstClockTime duration = 100000, FadingCurve curve = FADING_LINEAR);
|
||||
|
||||
void fadeIn(const GstClockTime from, const GstClockTime duration, FadingCurve curve = FADING_SHARP);
|
||||
void fadeOut(const GstClockTime to, const GstClockTime duration, FadingCurve curve = FADING_SHARP);
|
||||
void fadeInOutRange(const GstClockTime t, const GstClockTime duration, bool in_and_out, FadingCurve curve = FADING_SHARP);
|
||||
bool autoCut();
|
||||
|
||||
private:
|
||||
|
||||
@@ -234,11 +234,11 @@ void TransitionView::draw()
|
||||
// toggle transition mode
|
||||
ImGui::SetCursorScreenPos(ImVec2(pos_tran.x - 60.f, pos_tran.y +2.f));
|
||||
const char *tooltip[2] = {"Fade to black", "Cross fading"};
|
||||
ImGuiToolkit::IconToggle(0,2,0,8, &Settings::application.transition.cross_fade, tooltip );
|
||||
ImGuiToolkit::IconToggle(0, 2, 0, 8, &Settings::application.transition.cross_fade, tooltip );
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(pos_tran.x + 10.f, pos_tran.y + 2.f));
|
||||
const char *_tooltip[2] = {"Linear", "Quadratic"};
|
||||
ImGuiToolkit::IconToggle(18,3,19,3, &Settings::application.transition.profile, _tooltip );
|
||||
ImGuiToolkit::IconToggle(11, 12, 10, 12, &Settings::application.transition.profile, _tooltip );
|
||||
|
||||
// Duration slider (adjusted width)
|
||||
const float width = (pos_play.x - pos_canl.x) / 5.0;
|
||||
|
||||
@@ -2458,7 +2458,8 @@ void UserInterface::RenderHelp()
|
||||
ImGui::SetNextWindowSize(ImVec2(460, 800), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(350, 300), ImVec2(FLT_MAX, FLT_MAX));
|
||||
|
||||
if ( !ImGui::Begin(IMGUI_TITLE_HELP, &Settings::application.widget.help, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ) )
|
||||
if ( !ImGui::Begin(IMGUI_TITLE_HELP, &Settings::application.widget.help,
|
||||
ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ) )
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
@@ -6027,8 +6028,8 @@ void Navigator::RenderTransitionPannel(const ImVec2 &iconsize)
|
||||
Settings::application.transition.cross_fade = true;
|
||||
|
||||
static std::vector< std::tuple<int, int, std::string> > profile_options = {
|
||||
{18, 3, "Linear"},
|
||||
{19, 3, "Quadratic"}
|
||||
{11, 12, "Linear"},
|
||||
{10, 12, "Quadratic"}
|
||||
};
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
tmp = Settings::application.transition.profile ? 1 : 0;
|
||||
|
||||
@@ -258,7 +258,8 @@
|
||||
|
||||
#define LABEL_AUTO_MEDIA_PLAYER ICON_FA_USER_CIRCLE " User selection"
|
||||
#define LABEL_STORE_SELECTION " Create batch"
|
||||
#define LABEL_EDIT_FADING ICON_FA_RANDOM " Fade in & out"
|
||||
#define LABEL_EDIT_FADING ICON_FA_RANDOM " Edit timeline fading"
|
||||
#define LABEL_EDIT_GAPS ICON_FA_CUT " Cut timeline"
|
||||
#define LABEL_VIDEO_SEQUENCE " Encode an image sequence"
|
||||
#define LABEL_ADD_TIMELINE "Add timeline"
|
||||
#define DIALOG_TIMELINE_DURATION ICON_FA_HOURGLASS_HALF " Set timeline duration"
|
||||
|
||||
Reference in New Issue
Block a user