mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
work in progress selection timeline
This commit is contained in:
211
ImGuiToolkit.cpp
211
ImGuiToolkit.cpp
@@ -435,10 +435,10 @@ void ImGuiToolkit::HelpIcon(const char* desc, int i, int j, const char* shortcut
|
|||||||
#define NUM_MARKS 10
|
#define NUM_MARKS 10
|
||||||
#define LARGE_TICK_INCREMENT 1
|
#define LARGE_TICK_INCREMENT 1
|
||||||
#define LABEL_TICK_INCREMENT 3
|
#define LABEL_TICK_INCREMENT 3
|
||||||
|
static guint64 optimal_tick_marks[NUM_MARKS + LABEL_TICK_INCREMENT] = { 100 * MILISECOND, 500 * MILISECOND, 1 * SECOND, 2 * SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 1 * MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 60 * MINUTE, 60 * MINUTE };
|
||||||
|
|
||||||
bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 start, guint64 end, guint64 step, const float width)
|
bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 start, guint64 end, guint64 step, const float width)
|
||||||
{
|
{
|
||||||
static guint64 optimal_tick_marks[NUM_MARKS + LABEL_TICK_INCREMENT] = { 100 * MILISECOND, 500 * MILISECOND, 1 * SECOND, 2 * SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 1 * MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 60 * MINUTE, 60 * MINUTE };
|
|
||||||
|
|
||||||
// get window
|
// get window
|
||||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||||
if (window->SkipItems)
|
if (window->SkipItems)
|
||||||
@@ -533,16 +533,12 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 star
|
|||||||
{
|
{
|
||||||
large_tick_step = 10 * step;
|
large_tick_step = 10 * step;
|
||||||
|
|
||||||
if (step > 0) {
|
// try to put a label every second
|
||||||
// try to put a label every second
|
if ( 1000000000 % step < 1000)
|
||||||
if ( 1000000000 % step < 1000)
|
label_tick_step = (1000000000 / step) * step;
|
||||||
label_tick_step = (1000000000 / step) * step;
|
// not a round framerate: probalby best to use 10 frames interval
|
||||||
// not a round framerate: probalby best to use 10 frames interval
|
|
||||||
else
|
|
||||||
label_tick_step = 10 * step;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
label_tick_step = 30 * step;
|
label_tick_step = 10 * step;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// while there is less than 5 pixels between two tick marks (or at last optimal tick mark)
|
// while there is less than 5 pixels between two tick marks (or at last optimal tick mark)
|
||||||
@@ -622,6 +618,153 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 star
|
|||||||
return left_mouse_press;
|
return left_mouse_press;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImGuiToolkit::Timeline (const char* label, guint64 time, guint64 start, guint64 end, guint64 step, const float width)
|
||||||
|
{
|
||||||
|
// get window
|
||||||
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||||
|
if (window->SkipItems)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get style & id
|
||||||
|
const ImGuiContext& g = *GImGui;
|
||||||
|
const ImGuiStyle& style = g.Style;
|
||||||
|
const float fontsize = g.FontSize;
|
||||||
|
const ImGuiID id = window->GetID(label);
|
||||||
|
|
||||||
|
//
|
||||||
|
// FIRST PREPARE ALL data structures
|
||||||
|
//
|
||||||
|
|
||||||
|
// widget bounding box
|
||||||
|
const float height = 2.f * (fontsize + style.FramePadding.y);
|
||||||
|
ImVec2 pos = window->DC.CursorPos;
|
||||||
|
ImVec2 size = ImVec2(width, height);
|
||||||
|
ImRect bbox(pos, pos + size);
|
||||||
|
ImGui::ItemSize(size, style.FramePadding.y);
|
||||||
|
if (!ImGui::ItemAdd(bbox, id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// cursor size
|
||||||
|
const float cursor_scale = 1.f;
|
||||||
|
const float cursor_width = 0.5f * fontsize * cursor_scale;
|
||||||
|
|
||||||
|
// TIMELINE is inside the bbox, in a slightly smaller bounding box
|
||||||
|
ImRect timeline_bbox(bbox);
|
||||||
|
timeline_bbox.Expand( ImVec2(-cursor_width, -style.FramePadding.y) );
|
||||||
|
|
||||||
|
// SLIDER is inside the timeline
|
||||||
|
// ImRect slider_bbox( timeline_bbox.GetTL() + ImVec2(-cursor_width + 2.f, cursor_width + 4.f ), timeline_bbox.GetBR() + ImVec2( cursor_width - 2.f, 0.f ) );
|
||||||
|
|
||||||
|
// units conversion: from time to float (calculation made with higher precision first)
|
||||||
|
float time_ = static_cast<float> ( static_cast<double>(time - start) / static_cast<double>(end) );
|
||||||
|
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(end) );
|
||||||
|
|
||||||
|
//
|
||||||
|
// THIRD RENDER
|
||||||
|
//
|
||||||
|
|
||||||
|
// Render the bounding box
|
||||||
|
const ImU32 frame_col = ImGui::GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
|
||||||
|
ImGui::RenderFrame(bbox.Min, bbox.Max, frame_col, true, style.FrameRounding);
|
||||||
|
|
||||||
|
// by default, put a tick mark at every frame step and a large mark every second
|
||||||
|
guint64 tick_step = step;
|
||||||
|
guint64 large_tick_step = optimal_tick_marks[1+LARGE_TICK_INCREMENT];
|
||||||
|
guint64 label_tick_step = optimal_tick_marks[1+LABEL_TICK_INCREMENT];
|
||||||
|
|
||||||
|
// how many pixels to represent one frame step?
|
||||||
|
float tick_step_pixels = timeline_bbox.GetWidth() * step_;
|
||||||
|
|
||||||
|
// large space
|
||||||
|
if (tick_step_pixels > 5.f)
|
||||||
|
{
|
||||||
|
large_tick_step = 10 * step;
|
||||||
|
|
||||||
|
// try to put a label every second
|
||||||
|
if ( 1000000000 % step < 1000)
|
||||||
|
label_tick_step = (1000000000 / step) * step;
|
||||||
|
// not a round framerate: probalby best to use 10 frames interval
|
||||||
|
else
|
||||||
|
label_tick_step = 10 * step;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// while there is less than 5 pixels between two tick marks (or at last optimal tick mark)
|
||||||
|
for ( int i=0; i<10 && tick_step_pixels < 5.f; ++i )
|
||||||
|
{
|
||||||
|
// try to use the optimal tick marks pre-defined
|
||||||
|
tick_step = optimal_tick_marks[i];
|
||||||
|
large_tick_step = optimal_tick_marks[i+LARGE_TICK_INCREMENT];
|
||||||
|
label_tick_step = optimal_tick_marks[i+LABEL_TICK_INCREMENT];
|
||||||
|
tick_step_pixels = timeline_bbox.GetWidth() * static_cast<float> ( static_cast<double>(tick_step) / static_cast<double>(end) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// render the tick marks along TIMELINE
|
||||||
|
ImU32 color = ImGui::GetColorU32( style.Colors[ImGuiCol_Text] );
|
||||||
|
pos = timeline_bbox.GetTL();
|
||||||
|
guint64 tick = 0;
|
||||||
|
char overlay_buf[24];
|
||||||
|
|
||||||
|
// render text duration
|
||||||
|
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s",
|
||||||
|
GstToolkit::time_to_string(end, GstToolkit::TIME_STRING_MINIMAL).c_str());
|
||||||
|
ImVec2 overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
|
||||||
|
ImVec2 duration_label = bbox.GetBR() - overlay_size - ImVec2(3.f, 3.f);
|
||||||
|
if (overlay_size.x > 0.0f)
|
||||||
|
ImGui::RenderTextClipped( duration_label, bbox.Max, overlay_buf, NULL, &overlay_size);
|
||||||
|
|
||||||
|
// render tick marks
|
||||||
|
while ( tick < end)
|
||||||
|
{
|
||||||
|
// large tick mark
|
||||||
|
float tick_length = !(tick%large_tick_step) ? fontsize - style.FramePadding.y : style.FramePadding.y;
|
||||||
|
|
||||||
|
// label tick mark
|
||||||
|
if ( !(tick%label_tick_step) ) {
|
||||||
|
tick_length = fontsize;
|
||||||
|
guint64 ticklabel = 100 * (guint64) round( (double)( tick ) / 100.0); // round value to avoid '0.99' and alike
|
||||||
|
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s",
|
||||||
|
GstToolkit::time_to_string(ticklabel, GstToolkit::TIME_STRING_MINIMAL).c_str());
|
||||||
|
overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
|
||||||
|
ImVec2 mini = ImVec2( pos.x - overlay_size.x / 2.f, pos.y + tick_length );
|
||||||
|
ImVec2 maxi = ImVec2( pos.x + overlay_size.x / 2.f, pos.y + tick_length + overlay_size.y );
|
||||||
|
// do not overlap with label for duration
|
||||||
|
if (maxi.x < duration_label.x)
|
||||||
|
ImGui::RenderTextClipped(mini, maxi, overlay_buf, NULL, &overlay_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the tick mark each step
|
||||||
|
window->DrawList->AddLine( pos, pos + ImVec2(0.f, tick_length), color);
|
||||||
|
|
||||||
|
// next tick
|
||||||
|
tick += tick_step;
|
||||||
|
float tick_percent = static_cast<float> ( static_cast<double>(tick) / static_cast<double>(end) );
|
||||||
|
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tick EOF
|
||||||
|
window->DrawList->AddLine( timeline_bbox.GetTR(), timeline_bbox.GetTR() + ImVec2(0.f, fontsize), color);
|
||||||
|
|
||||||
|
// disabled: render position
|
||||||
|
// ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s", GstToolkit::time_to_string(*time).c_str());
|
||||||
|
// overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
|
||||||
|
// overlay_size = ImVec2(3.f, -3.f - overlay_size.y);
|
||||||
|
// if (overlay_size.x > 0.0f)
|
||||||
|
// ImGui::RenderTextClipped( bbox.GetBL() + overlay_size, bbox.Max, overlay_buf, NULL, &overlay_size);
|
||||||
|
|
||||||
|
// // draw slider grab handle
|
||||||
|
// if (grab_slider_bb.Max.x > grab_slider_bb.Min.x) {
|
||||||
|
// window->DrawList->AddRectFilled(grab_slider_bb.Min, grab_slider_bb.Max, grab_slider_color, style.GrabRounding);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// draw the cursor
|
||||||
|
if ( time_ > 0.f && time_ < 1.f ) {
|
||||||
|
color = ImGui::GetColorU32(style.Colors[ImGuiCol_SliderGrab]);
|
||||||
|
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), time_) - ImVec2(cursor_width, 2.f);
|
||||||
|
ImGui::RenderArrow(window->DrawList, pos, color, ImGuiDir_Up, cursor_scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//bool ImGuiToolkit::InvisibleSliderInt(const char* label, guint64 *index, guint64 min, guint64 max, ImVec2 size)
|
//bool ImGuiToolkit::InvisibleSliderInt(const char* label, guint64 *index, guint64 min, guint64 max, ImVec2 size)
|
||||||
bool ImGuiToolkit::InvisibleSliderInt(const char* label, uint *index, uint min, uint max, ImVec2 size)
|
bool ImGuiToolkit::InvisibleSliderInt(const char* label, uint *index, uint min, uint max, ImVec2 size)
|
||||||
{
|
{
|
||||||
@@ -785,6 +928,7 @@ void FilterCreation(float GKernel[], int N)
|
|||||||
GKernel[i] /= max;
|
GKernel[i] /= max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array, float *lines_array,
|
bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array, float *lines_array,
|
||||||
int values_count, float values_min, float values_max, bool edit_histogram, bool *released, const ImVec2 size)
|
int values_count, float values_min, float values_max, bool edit_histogram, bool *released, const ImVec2 size)
|
||||||
{
|
{
|
||||||
@@ -922,6 +1066,51 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
|||||||
return array_changed;
|
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 ImGuiContext& g = *GImGui;
|
||||||
|
const ImGuiStyle& style = g.Style;
|
||||||
|
ImVec4 bg_color = style.Colors[ImGuiCol_FrameBg];
|
||||||
|
|
||||||
|
// back to draw
|
||||||
|
ImGui::SetCursorScreenPos(canvas_pos);
|
||||||
|
|
||||||
|
// plot transparent histogram
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, bg_color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0, 0, 0, 250));
|
||||||
|
char buf[128];
|
||||||
|
sprintf(buf, "##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 lines
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
|
||||||
|
sprintf(buf, "##Lines%s", label);
|
||||||
|
ImGui::PlotLines(buf, lines_array, values_count, 0, NULL, values_min, values_max, size);
|
||||||
|
ImGui::PopStyleColor(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ImGuiToolkit::SetFont(ImGuiToolkit::font_style style, const std::string &ttf_font_name, int pointsize, int oversample)
|
void ImGuiToolkit::SetFont(ImGuiToolkit::font_style style, const std::string &ttf_font_name, int pointsize, int oversample)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ namespace ImGuiToolkit
|
|||||||
|
|
||||||
// utility sliders
|
// utility sliders
|
||||||
bool TimelineSlider (const char* label, guint64 *time, guint64 start, guint64 end, guint64 step, const float width);
|
bool TimelineSlider (const char* label, guint64 *time, guint64 start, guint64 end, guint64 step, const float width);
|
||||||
|
void Timeline (const char* label, guint64 time, guint64 start, guint64 end, guint64 step, const float width);
|
||||||
bool InvisibleSliderInt(const char* label, uint *index, uint min, uint max, const ImVec2 size);
|
bool InvisibleSliderInt(const char* label, uint *index, uint min, uint max, const ImVec2 size);
|
||||||
bool EditPlotLines(const char* label, float *array, int values_count, float values_min, float values_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, bool cut, bool *released, const ImVec2 size);
|
bool EditPlotHistoLines(const char* label, float *histogram_array, float *lines_array, int values_count, float values_min, float values_max, 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);
|
||||||
|
|
||||||
// fonts from ressources 'fonts/'
|
// fonts from ressources 'fonts/'
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
101
Timeline.cpp
101
Timeline.cpp
@@ -6,6 +6,10 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Timeline.h"
|
#include "Timeline.h"
|
||||||
|
|
||||||
|
|
||||||
|
static float empty_gaps[MAX_TIMELINE_ARRAY] = {};
|
||||||
|
static float empty_fade[MAX_TIMELINE_ARRAY] = {};
|
||||||
|
|
||||||
struct includesTime: public std::unary_function<TimeInterval, bool>
|
struct includesTime: public std::unary_function<TimeInterval, bool>
|
||||||
{
|
{
|
||||||
inline bool operator()(const TimeInterval s) const
|
inline bool operator()(const TimeInterval s) const
|
||||||
@@ -163,6 +167,88 @@ bool Timeline::removeGaptAt(GstClockTime t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GstClockTime Timeline::sectionsDuration() const
|
||||||
|
{
|
||||||
|
GstClockTime d = 0;
|
||||||
|
|
||||||
|
// compute the sum of durations of gaps
|
||||||
|
for (auto it = gaps_.begin(); it != gaps_.end(); ++it)
|
||||||
|
d += (*it).end - (*it).begin;
|
||||||
|
|
||||||
|
return duration() - d;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Timeline::fillSectionsArrays( float* const gaps, float* const fading)
|
||||||
|
{
|
||||||
|
size_t arraysize = MAX_TIMELINE_ARRAY;
|
||||||
|
float* gapsptr = gaps;
|
||||||
|
float* fadingptr = fading;
|
||||||
|
|
||||||
|
if (gaps_array_need_update_)
|
||||||
|
fillArrayFromGaps(gapsArray_, MAX_TIMELINE_ARRAY);
|
||||||
|
|
||||||
|
if (gaps_.size() > 0) {
|
||||||
|
|
||||||
|
// indices to define [s e[] sections
|
||||||
|
size_t s = 0;
|
||||||
|
size_t e = MAX_TIMELINE_ARRAY;
|
||||||
|
arraysize = 0;
|
||||||
|
|
||||||
|
auto it = gaps_.begin();
|
||||||
|
|
||||||
|
// cut at the beginning
|
||||||
|
if ((*it).begin == timing_.begin) {
|
||||||
|
for (size_t i = 0; i < 5; ++i)
|
||||||
|
gapsptr[ MAX(i, 0) ] = 1.f;
|
||||||
|
|
||||||
|
s = ( (*it).end * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop
|
||||||
|
for (; it != gaps_.end(); ++it) {
|
||||||
|
|
||||||
|
// [s e] section
|
||||||
|
e = ( (*it).begin * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||||
|
|
||||||
|
size_t n = e - s;
|
||||||
|
memcpy( gapsptr, gapsArray_ + s, n * sizeof(float));
|
||||||
|
memcpy( fadingptr, fadingArray_ + s, n * sizeof(float));
|
||||||
|
|
||||||
|
for (size_t i = -5; i > 0; ++i)
|
||||||
|
gapsptr[ MAX(n+i, 0) ] = 1.f;
|
||||||
|
|
||||||
|
gapsptr += n;
|
||||||
|
fadingptr += n;
|
||||||
|
arraysize += n;
|
||||||
|
|
||||||
|
// next section
|
||||||
|
s = ( (*it).end * MAX_TIMELINE_ARRAY ) / timing_.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// close last [s e] section
|
||||||
|
if (s != MAX_TIMELINE_ARRAY) {
|
||||||
|
|
||||||
|
// [s e] section
|
||||||
|
e = MAX_TIMELINE_ARRAY;
|
||||||
|
|
||||||
|
size_t n = e - s;
|
||||||
|
memcpy( gapsptr, gapsArray_ + s, n * sizeof(float));
|
||||||
|
memcpy( fadingptr, fadingArray_ + s, n * sizeof(float));
|
||||||
|
arraysize += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
memcpy( gaps, gapsArray_, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||||
|
memcpy( fading, fadingArray_, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
return arraysize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TimeIntervalSet Timeline::sections() const
|
TimeIntervalSet Timeline::sections() const
|
||||||
{
|
{
|
||||||
TimeIntervalSet sec;
|
TimeIntervalSet sec;
|
||||||
@@ -200,7 +286,7 @@ void Timeline::clearGaps()
|
|||||||
gaps_array_need_update_ = true;
|
gaps_array_need_update_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Timeline::fadingAt(const GstClockTime t)
|
float Timeline::fadingAt(const GstClockTime t) const
|
||||||
{
|
{
|
||||||
double true_index = (static_cast<double>(MAX_TIMELINE_ARRAY) * static_cast<double>(t)) / static_cast<double>(timing_.end);
|
double true_index = (static_cast<double>(MAX_TIMELINE_ARRAY) * static_cast<double>(t)) / static_cast<double>(timing_.end);
|
||||||
double previous_index = floor(true_index);
|
double previous_index = floor(true_index);
|
||||||
@@ -215,8 +301,13 @@ float Timeline::fadingAt(const GstClockTime t)
|
|||||||
|
|
||||||
void Timeline::clearFading()
|
void Timeline::clearFading()
|
||||||
{
|
{
|
||||||
for(int i=0;i<MAX_TIMELINE_ARRAY;++i)
|
// fill static with 1 (only once)
|
||||||
fadingArray_[i] = 1.f;
|
if (empty_fade[0] < 1.f){
|
||||||
|
for(int i=0;i<MAX_TIMELINE_ARRAY;++i)
|
||||||
|
empty_fade[i] = 1.f;
|
||||||
|
}
|
||||||
|
// clear with static array
|
||||||
|
memcpy(fadingArray_, empty_fade, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::smoothFading(uint N)
|
void Timeline::smoothFading(uint N)
|
||||||
@@ -340,8 +431,8 @@ void Timeline::fillArrayFromGaps(float *array, size_t array_size)
|
|||||||
// fill the array from gaps
|
// fill the array from gaps
|
||||||
if (array != nullptr && array_size > 0 && timing_.is_valid()) {
|
if (array != nullptr && array_size > 0 && timing_.is_valid()) {
|
||||||
|
|
||||||
for(int i=0;i<array_size;++i)
|
// clear with static array
|
||||||
gapsArray_[i] = 0.f;
|
memcpy(gapsArray_, empty_gaps, MAX_TIMELINE_ARRAY * sizeof(float));
|
||||||
|
|
||||||
// for each gap
|
// for each gap
|
||||||
for (auto it = gaps_.begin(); it != gaps_.end(); ++it)
|
for (auto it = gaps_.begin(); it != gaps_.end(); ++it)
|
||||||
|
|||||||
11
Timeline.h
11
Timeline.h
@@ -105,9 +105,8 @@ public:
|
|||||||
GstClockTime next(GstClockTime time) const;
|
GstClockTime next(GstClockTime time) const;
|
||||||
GstClockTime previous(GstClockTime time) const;
|
GstClockTime previous(GstClockTime time) const;
|
||||||
|
|
||||||
// Manipulation of gaps in the timeline
|
// Manipulation of gaps
|
||||||
inline TimeIntervalSet gaps() const { return gaps_; }
|
inline TimeIntervalSet gaps() const { return gaps_; }
|
||||||
inline TimeIntervalSet sections() const;
|
|
||||||
inline size_t numGaps() const { return gaps_.size(); }
|
inline size_t numGaps() const { return gaps_.size(); }
|
||||||
float *gapsArray();
|
float *gapsArray();
|
||||||
void clearGaps();
|
void clearGaps();
|
||||||
@@ -117,13 +116,19 @@ public:
|
|||||||
bool removeGaptAt(GstClockTime t);
|
bool removeGaptAt(GstClockTime t);
|
||||||
bool gapAt(const GstClockTime t, TimeInterval &gap) const;
|
bool gapAt(const GstClockTime t, TimeInterval &gap) const;
|
||||||
|
|
||||||
float fadingAt(const GstClockTime t);
|
// Manipulation of Fading
|
||||||
|
float fadingAt(const GstClockTime t) const;
|
||||||
inline float *fadingArray() { return fadingArray_; }
|
inline float *fadingArray() { return fadingArray_; }
|
||||||
void clearFading();
|
void clearFading();
|
||||||
|
|
||||||
|
// Edit
|
||||||
void smoothFading(uint N = 1);
|
void smoothFading(uint N = 1);
|
||||||
void autoFading(uint milisecond = 100);
|
void autoFading(uint milisecond = 100);
|
||||||
bool autoCut();
|
bool autoCut();
|
||||||
|
TimeIntervalSet sections() const;
|
||||||
|
|
||||||
|
GstClockTime sectionsDuration() const;
|
||||||
|
size_t fillSectionsArrays(float * const gaps, float * const fading);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
@@ -2102,41 +2102,82 @@ void SourceController::RenderSelection(size_t i)
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
|
||||||
ImGui::BeginChild("##v_scroll", rendersize, false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
// get max duration
|
||||||
|
GstClockTime maxduration = 0;
|
||||||
|
for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
||||||
|
MediaSource *ms = dynamic_cast<MediaSource *>(*source);
|
||||||
|
if (ms != nullptr) {
|
||||||
|
GstClockTime d = ((double) ms->mediaplayer()->timeline()->sectionsDuration() / ms->mediaplayer()->playSpeed());
|
||||||
|
if ( d > maxduration )
|
||||||
|
maxduration = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// draw list
|
||||||
|
ImGui::BeginChild("##v_scroll2", rendersize, false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||||
{
|
{
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, _v_space));
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, _v_space));
|
||||||
|
|
||||||
for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
||||||
|
|
||||||
ImVec2 framesize(1.5f * _timeline_height * (*source)->frame()->aspectRatio(), 1.5f * _timeline_height);
|
ImVec2 framesize(1.5f * _timeline_height * (*source)->frame()->aspectRatio(), 1.5f * _timeline_height);
|
||||||
|
|
||||||
ImVec2 image_top = ImGui::GetCursorPos();
|
ImVec2 image_top = ImGui::GetCursorPos();
|
||||||
|
|
||||||
|
// Thumbnail of source (clic to open)
|
||||||
if (SourceButton(*source, framesize))
|
if (SourceButton(*source, framesize))
|
||||||
UserInterface::manager().showSourceEditor(*source);
|
UserInterface::manager().showSourceEditor(*source);
|
||||||
|
|
||||||
// ImGui::SetCursorPos(image_top + ImVec2( _h_space, framesize.y));
|
// text below thumbnail to show status
|
||||||
|
const char *icon = ICON_FA_SNOWFLAKE;
|
||||||
if ((*source)->active())
|
if ((*source)->active())
|
||||||
ImGui::Text("%s %s", (*source)->playing() ? ICON_FA_PLAY : ICON_FA_PAUSE, GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
icon = (*source)->playing() ? ICON_FA_PLAY : ICON_FA_PAUSE;
|
||||||
else
|
ImGui::Text("%s %s", icon, GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
||||||
ImGui::Text("%s %s", ICON_FA_SNOWFLAKE, GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
|
||||||
|
|
||||||
ImGui::SetCursorPos(image_top + ImVec2( framesize.x + _h_space, 0));
|
|
||||||
|
|
||||||
MediaSource *ms = dynamic_cast<MediaSource *>(*source);
|
MediaSource *ms = dynamic_cast<MediaSource *>(*source);
|
||||||
if (ms != nullptr) {
|
if (ms != nullptr) {
|
||||||
|
ImGui::SetCursorPos(image_top + ImVec2( framesize.x + _h_space, 0));
|
||||||
MediaPlayer *mp = ms->mediaplayer();
|
MediaPlayer *mp = ms->mediaplayer();
|
||||||
ImVec2 size(rendersize.x - framesize.x - _h_space - _scrollbar, 2.f * _timeline_height);
|
Timeline *tl = mp->timeline();
|
||||||
bool released = false;
|
|
||||||
ImGuiToolkit::EditPlotHistoLines("##TimelineArray",
|
// cut gaps
|
||||||
mp->timeline()->gapsArray(),
|
// // timeline of MediaSource to the right
|
||||||
mp->timeline()->fadingArray(),
|
// static float gaps[MAX_TIMELINE_ARRAY];
|
||||||
MAX_TIMELINE_ARRAY, 0.f, 1.f, true, &released, size);
|
// static float fade[MAX_TIMELINE_ARRAY];
|
||||||
|
// size_t numsteps = tl->fillSectionsArrays(gaps, fade) - 1;
|
||||||
|
|
||||||
|
ImVec2 size(rendersize.x - framesize.x - _h_space - _scrollbar, 1.5f * _timeline_height);
|
||||||
|
GstClockTime playtime = 0;
|
||||||
|
|
||||||
|
// GstClockTime d = tl->sectionsDuration();
|
||||||
|
// size.x = size.x * d / ( maxduration * mp->playSpeed() );
|
||||||
|
|
||||||
|
// ImGuiToolkit::ShowPlotHistoLines("##TimelineArray2", gaps, fade, numsteps, 0.f, 1.f, size);
|
||||||
|
|
||||||
|
TimeIntervalSet se = tl->sections();
|
||||||
|
for (auto section = se.begin(); section != se.end(); ++section) {
|
||||||
|
|
||||||
|
GstClockTime d = section->duration();
|
||||||
|
float w = size.x * d / ( maxduration * mp->playSpeed() );
|
||||||
|
ImGuiToolkit::Timeline("##timeline2", mp->position(), section->begin, section->end, tl->step(), w);
|
||||||
|
ImGui::SameLine(0,1);
|
||||||
|
|
||||||
|
playtime += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImGuiToolkit::Timeline("##timeline2", mp->position(), tl->begin(), tl->end(), tl->step(), size.x);
|
||||||
|
|
||||||
|
// text below timeline to show info
|
||||||
|
ImGui::SetCursorPos(image_top + ImVec2( framesize.x + _h_space, 1.5f * _timeline_height + _v_space));
|
||||||
|
GstClockTime t = (GstClockTime) ( (double) playtime / mp->playSpeed() );
|
||||||
|
ImGui::Text("%s play time / %.2f speed = %s (effective duration)", GstToolkit::time_to_string(playtime).c_str(), mp->playSpeed(), GstToolkit::time_to_string(t).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Spacing();
|
// next line position
|
||||||
|
ImGui::SetCursorPos(image_top + ImVec2(0, 2.0f * _timeline_height + _v_space));
|
||||||
|
// ImGui::Spacing();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Columns(1);
|
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|||||||
Reference in New Issue
Block a user