mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-07 16:30:00 +01:00
Player timeline for selection
Selection of media sources now displays in a list with proportional timelines, showing actual play time and cursor on effective timeline with opacity curve.
This commit is contained in:
555
ImGuiToolkit.cpp
555
ImGuiToolkit.cpp
@@ -435,240 +435,19 @@ void ImGuiToolkit::HelpIcon(const char* desc, int i, int j, const char* shortcut
|
||||
#define NUM_MARKS 10
|
||||
#define LARGE_TICK_INCREMENT 1
|
||||
#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)
|
||||
void ImGuiToolkit::RenderTimeline (ImGuiWindow* window, ImRect timeline_bbox, guint64 start, guint64 end, guint64 step, bool verticalflip)
|
||||
{
|
||||
// get window
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
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 style & id
|
||||
const ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const float fontsize = g.FontSize;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImU32 text_color = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
|
||||
//
|
||||
// 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 false;
|
||||
|
||||
// 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)
|
||||
guint64 duration = end - start;
|
||||
float time_ = static_cast<float> ( static_cast<double>(*time - start) / static_cast<double>(duration) );
|
||||
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(duration) );
|
||||
|
||||
//
|
||||
// SECOND GET USER INPUT AND PERFORM CHANGES AND DECISIONS
|
||||
//
|
||||
|
||||
// read user input from system
|
||||
bool left_mouse_press = false;
|
||||
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);
|
||||
left_mouse_press = hovered && ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||
if (focus_requested || left_mouse_press || g.NavActivateId == id || g.NavInputId == id)
|
||||
{
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
// time Slider behavior
|
||||
ImRect grab_slider_bb;
|
||||
ImU32 grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrab);
|
||||
float time_slider = time_ * 10.f; // x 10 precision on grab
|
||||
float time_zero = 0.f;
|
||||
float time_end = 10.f;
|
||||
bool value_changed = ImGui::SliderBehavior(slider_bbox, id, ImGuiDataType_Float, &time_slider, &time_zero,
|
||||
&time_end, "%.2f", 1.f, ImGuiSliderFlags_None, &grab_slider_bb);
|
||||
if (value_changed){
|
||||
// g_print("slider %f %ld \n", time_slider, static_cast<guint64> ( static_cast<double>(time_slider) * static_cast<double>(duration) ));
|
||||
*time = static_cast<guint64> ( 0.1 * static_cast<double>(time_slider) * static_cast<double>(end) ) + start;
|
||||
grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrabActive);
|
||||
}
|
||||
|
||||
//
|
||||
// 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_;
|
||||
|
||||
// tick at each step: add a label every 0 frames
|
||||
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>(duration) );
|
||||
}
|
||||
}
|
||||
|
||||
// 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 < duration )
|
||||
{
|
||||
// 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 + start ) / 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>(duration) );
|
||||
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
|
||||
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);
|
||||
|
||||
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)
|
||||
guint64 duration = end - start;
|
||||
float time_ = static_cast<float> ( static_cast<double>(time - start) / static_cast<double>(duration) );
|
||||
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(duration) );
|
||||
|
||||
//
|
||||
// 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];
|
||||
@@ -701,73 +480,239 @@ void ImGuiToolkit::Timeline (const char* label, guint64 time, guint64 start, gui
|
||||
}
|
||||
}
|
||||
|
||||
// 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 tics and text
|
||||
char text_buf[24];
|
||||
|
||||
// render text duration
|
||||
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s",
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
|
||||
|
||||
// render tick and text START
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%s",
|
||||
GstToolkit::time_to_string(start, GstToolkit::TIME_STRING_MINIMAL).c_str());
|
||||
ImVec2 beginning_label_size = ImGui::CalcTextSize(text_buf, NULL);
|
||||
ImVec2 beginning_label_pos = timeline_bbox.GetTL() + ImVec2(3.f, fontsize);
|
||||
if (verticalflip)
|
||||
beginning_label_pos.y -= fontsize;
|
||||
ImGui::RenderTextClipped( beginning_label_pos, beginning_label_pos + beginning_label_size,
|
||||
text_buf, NULL, &beginning_label_size);
|
||||
window->DrawList->AddLine( timeline_bbox.GetTL(), timeline_bbox.GetBL(), text_color, 1.5f);
|
||||
|
||||
|
||||
// render tick and text END
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_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, 5.f);
|
||||
if (overlay_size.x > 0.0f)
|
||||
ImGui::RenderTextClipped( duration_label, bbox.Max, overlay_buf, NULL, &overlay_size);
|
||||
ImVec2 duration_label_size = ImGui::CalcTextSize(text_buf, NULL);
|
||||
ImVec2 duration_label_pos = timeline_bbox.GetTR() + ImVec2( -2.f -duration_label_size.x, fontsize);
|
||||
if (verticalflip)
|
||||
duration_label_pos.y -= fontsize;
|
||||
ImGui::RenderTextClipped( duration_label_pos, duration_label_pos + duration_label_size,
|
||||
text_buf, NULL, &duration_label_size);
|
||||
window->DrawList->AddLine( timeline_bbox.GetTR(), timeline_bbox.GetBR(), text_color, 1.5f);
|
||||
|
||||
// render tick marks
|
||||
ImGui::PopFont();
|
||||
|
||||
// render the tick marks along TIMELINE
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_Text] -ImVec4(0.f,0.f,0.f,0.4f));
|
||||
ImVec2 pos = verticalflip ? timeline_bbox.GetBL() : timeline_bbox.GetTL();
|
||||
guint64 tick = 0;
|
||||
while ( tick < duration )
|
||||
{
|
||||
// large tick mark
|
||||
float tick_length = !(tick%large_tick_step) ? fontsize - style.FramePadding.y : style.FramePadding.y;
|
||||
float tick_length = (tick%large_tick_step) ? style.FramePadding.y : fontsize - style.FramePadding.y;
|
||||
|
||||
// label tick mark
|
||||
if ( !(tick%label_tick_step) ) {
|
||||
tick_length = fontsize;
|
||||
guint64 ticklabel = 100 * (guint64) round( (double)( tick + start) / 100.0); // round value to avoid '0.99' and alike
|
||||
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s",
|
||||
ImFormatString(text_buf, IM_ARRAYSIZE(text_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);
|
||||
}
|
||||
ImVec2 label_size = ImGui::CalcTextSize(text_buf, NULL);
|
||||
ImVec2 mini = ImVec2( pos.x - label_size.x / 2.f, pos.y);
|
||||
ImVec2 maxi = ImVec2( pos.x + label_size.x / 2.f, pos.y);
|
||||
|
||||
// draw the tick mark each step
|
||||
window->DrawList->AddLine( pos, pos + ImVec2(0.f, tick_length), color);
|
||||
if (verticalflip) {
|
||||
mini.y -= tick_length + label_size.y;
|
||||
maxi.y -= tick_length;
|
||||
}
|
||||
else {
|
||||
mini.y += tick_length;
|
||||
maxi.y += tick_length + label_size.y;
|
||||
}
|
||||
|
||||
// do not overlap with labels for beginning and duration
|
||||
if (mini.x - style.ItemSpacing.x > (beginning_label_pos.x + beginning_label_size.x) && maxi.x + style.ItemSpacing.x < duration_label_pos.x)
|
||||
ImGui::RenderTextClipped(mini, maxi, text_buf, NULL, &label_size);
|
||||
}
|
||||
|
||||
// next tick
|
||||
tick += tick_step;
|
||||
float tick_percent = static_cast<float> ( static_cast<double>(tick) / static_cast<double>(duration) );
|
||||
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
|
||||
|
||||
// draw the tick mark each step
|
||||
if (verticalflip) {
|
||||
window->DrawList->AddLine( pos, pos - ImVec2(0.f, tick_length), text_color);
|
||||
pos = ImLerp(timeline_bbox.GetBL(), timeline_bbox.GetBR(), tick_percent);
|
||||
}
|
||||
else {
|
||||
window->DrawList->AddLine( pos, pos + ImVec2(0.f, tick_length), text_color);
|
||||
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
}
|
||||
|
||||
bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 start, guint64 end, guint64 step, const float width)
|
||||
{
|
||||
// get window
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
// 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 false;
|
||||
|
||||
// cursor size
|
||||
const float cursor_width = 0.5f * fontsize;
|
||||
|
||||
// TIMELINE is inside the bbox, in a slightly smaller bounding box
|
||||
ImRect timeline_bbox(bbox);
|
||||
timeline_bbox.Expand( ImVec2() - style.FramePadding );
|
||||
|
||||
// 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 - start) );
|
||||
|
||||
//
|
||||
// SECOND GET USER INPUT AND PERFORM CHANGES AND DECISIONS
|
||||
//
|
||||
|
||||
// read user input from system
|
||||
bool left_mouse_press = false;
|
||||
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);
|
||||
left_mouse_press = hovered && ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||
if (focus_requested || left_mouse_press || g.NavActivateId == id || g.NavInputId == id)
|
||||
{
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
// tick EOF
|
||||
window->DrawList->AddLine( timeline_bbox.GetTR(), timeline_bbox.GetTR() + ImVec2(0.f, fontsize), color);
|
||||
// time Slider behavior
|
||||
ImRect grab_slider_bb;
|
||||
ImU32 grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrab);
|
||||
float time_slider = time_ * 10.f; // x 10 precision on grab
|
||||
float time_zero = 0.f;
|
||||
float time_end = 10.f;
|
||||
bool value_changed = ImGui::SliderBehavior(slider_bbox, id, ImGuiDataType_Float, &time_slider, &time_zero,
|
||||
&time_end, "%.2f", 1.f, ImGuiSliderFlags_None, &grab_slider_bb);
|
||||
if (value_changed){
|
||||
// g_print("slider %f %ld \n", time_slider, static_cast<guint64> ( static_cast<double>(time_slider) * static_cast<double>(duration) ));
|
||||
*time = static_cast<guint64> ( 0.1 * static_cast<double>(time_slider) * static_cast<double>(end - start) ) + start;
|
||||
grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrabActive);
|
||||
}
|
||||
|
||||
// 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);
|
||||
//
|
||||
// THIRD RENDER
|
||||
//
|
||||
|
||||
// // 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);
|
||||
// }
|
||||
// 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);
|
||||
|
||||
// render the timeline
|
||||
RenderTimeline(window, timeline_bbox, start, end, step);
|
||||
|
||||
// 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
|
||||
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), time_) - ImVec2(cursor_width, 2.f);
|
||||
ImGui::RenderArrow(window->DrawList, pos, ImGui::GetColorU32(ImGuiCol_SliderGrab), ImGuiDir_Up);
|
||||
|
||||
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_width = 0.5f * fontsize;
|
||||
|
||||
// TIMELINE is inside the bbox, in a slightly smaller bounding box
|
||||
ImRect timeline_bbox(bbox);
|
||||
timeline_bbox.Expand( ImVec2() - style.FramePadding );
|
||||
|
||||
// units conversion: from time to float (calculation made with higher precision first)
|
||||
guint64 duration = end - start;
|
||||
float time_ = static_cast<float> ( static_cast<double>(time - start) / static_cast<double>(duration) );
|
||||
|
||||
//
|
||||
// THIRD RENDER
|
||||
//
|
||||
|
||||
// Render the bounding box
|
||||
ImGui::RenderFrame(bbox.Min, bbox.Max, ImGui::GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
|
||||
// render the timeline
|
||||
RenderTimeline(window, timeline_bbox, start, end, step);
|
||||
|
||||
// draw the cursor
|
||||
if ( time_ > -FLT_EPSILON && 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);
|
||||
ImGui::RenderArrow(window->DrawList, pos, ImGui::GetColorU32(ImGuiCol_SliderGrab), ImGuiDir_Up);
|
||||
}
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
// get window
|
||||
@@ -908,31 +853,10 @@ bool ImGuiToolkit::EditPlotLines(const char* label, float *array, int values_cou
|
||||
return array_changed;
|
||||
}
|
||||
|
||||
// Function to create Gaussian filter
|
||||
void FilterCreation(float GKernel[], int N)
|
||||
{
|
||||
// intialising standard deviation to 1.0
|
||||
float sigma = N * 0.25f;
|
||||
float s = 2.0 * sigma * sigma;
|
||||
|
||||
// sum is for normalization
|
||||
float max = 0.0;
|
||||
|
||||
// generating 5x5 kernel
|
||||
for (int x = 0 ; x < N; x++) {
|
||||
float r = x;
|
||||
GKernel[x] = (exp(-(r * r) / s)) / sqrt(M_PI * 2.0 * sigma);
|
||||
max = MAX(max, GKernel[x]);
|
||||
}
|
||||
|
||||
// normalising the Kernel
|
||||
for (int i = 0; i < N; ++i)
|
||||
GKernel[i] /= max;
|
||||
}
|
||||
|
||||
|
||||
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, guint64 start, guint64 end,
|
||||
bool edit_histogram, bool *released, const ImVec2 size)
|
||||
{
|
||||
bool array_changed = false;
|
||||
|
||||
@@ -942,7 +866,7 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
||||
return false;
|
||||
|
||||
// capture coordinates before any draw or action
|
||||
ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
|
||||
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
|
||||
@@ -976,9 +900,17 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
||||
|
||||
const ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const float _h_space = g.Style.WindowPadding.x;
|
||||
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 = start + (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) {
|
||||
|
||||
@@ -989,12 +921,8 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
||||
static size_t previous_index = UINT32_MAX;
|
||||
if (mouse_press)
|
||||
{
|
||||
|
||||
float x = (float) values_count * (mouse_pos_in_canvas.x - _h_space) / (size.x - 2.f * _h_space);
|
||||
size_t index = CLAMP( (int) floor(x), 0, values_count);
|
||||
|
||||
float y = mouse_pos_in_canvas.y / bbox.GetHeight();
|
||||
y = CLAMP( (y * (values_max-values_min)) + values_min, values_min, values_max);
|
||||
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;
|
||||
@@ -1015,7 +943,7 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
||||
histogram_array[i] = target_value;
|
||||
}
|
||||
else {
|
||||
const float target_value = values_max - y;
|
||||
const float target_value = values_max - val;
|
||||
|
||||
for (size_t i = left; i < right; ++i)
|
||||
lines_array[i] = target_value;
|
||||
@@ -1038,9 +966,9 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
||||
// back to draw
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot transparent histogram
|
||||
// plot histogram (with frame)
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, bg_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, style.Colors[ImGuiCol_TitleBg]);
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, style.Colors[ImGuiCol_TitleBg]); // a dark color
|
||||
char buf[128];
|
||||
sprintf(buf, "##Histo%s", label);
|
||||
ImGui::PlotHistogram(buf, histogram_array, values_count, 0, NULL, values_min, values_max, size);
|
||||
@@ -1048,21 +976,40 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
||||
|
||||
ImGui::SetCursorScreenPos(canvas_pos);
|
||||
|
||||
// plot lines
|
||||
// plot (transparent) 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);
|
||||
|
||||
// draw the cursor bar
|
||||
// draw the cursor
|
||||
if (hovered) {
|
||||
const ImU32 cur_color = ImGui::GetColorU32( style.Colors[ImGuiCol_CheckMark] );
|
||||
// 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);
|
||||
if (edit_histogram)
|
||||
window->DrawList->AddLine( canvas_pos + ImVec2(mouse_pos_in_canvas.x, 4.f), canvas_pos + ImVec2(mouse_pos_in_canvas.x, size.y - 4.f), cur_color);
|
||||
else {
|
||||
window->DrawList->AddCircleFilled(canvas_pos + mouse_pos_in_canvas, 3.f, cur_color, 8);
|
||||
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;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include "rsc/fonts/IconsFontAwesome5.h"
|
||||
|
||||
namespace ImGuiToolkit
|
||||
@@ -13,7 +13,7 @@ namespace ImGuiToolkit
|
||||
// Icons from resource icon.dds
|
||||
void Icon (int i, int j, bool enabled = true);
|
||||
bool IconButton (int i, int j, const char *tooltips = nullptr);
|
||||
bool IconButton (const char* icon = ICON_FA_EXCLAMATION_CIRCLE, const char *tooltips = nullptr);
|
||||
bool IconButton (const char* icon, const char *tooltips = nullptr);
|
||||
bool IconToggle (int i, int j, int i_toggle, int j_toggle, bool* toggle, const char *tooltips[] = nullptr);
|
||||
void ShowIconsWindow(bool* p_open);
|
||||
|
||||
@@ -23,21 +23,23 @@ namespace ImGuiToolkit
|
||||
bool ButtonIconMultistate (std::vector<std::pair<int, int> > icons, int* state);
|
||||
bool ComboIcon (std::vector<std::pair<int, int> > icons, std::vector<std::string> labels, int* state);
|
||||
|
||||
// utility buttons
|
||||
// buttons
|
||||
bool ButtonToggle (const char* label, bool* toggle);
|
||||
bool ButtonSwitch (const char* label, bool* toggle , const char *help = nullptr);
|
||||
void ButtonOpenUrl (const char* label, const char* url, const ImVec2& size_arg = ImVec2(0,0));
|
||||
|
||||
// tooltip and mouse over
|
||||
void ToolTip (const char* desc, const char* shortcut = nullptr);
|
||||
void HelpMarker (const char* desc, const char* icon = ICON_FA_QUESTION_CIRCLE, const char* shortcut = nullptr);
|
||||
void HelpIcon (const char* desc, int i = 19, int j = 5, const char* shortcut = nullptr);
|
||||
|
||||
// utility sliders
|
||||
// sliders
|
||||
bool TimelineSlider (const char* label, guint64 *time, guint64 start, guint64 end, guint64 step, const float width);
|
||||
void RenderTimeline (struct ImGuiWindow* window, struct ImRect timeline_bbox, guint64 start, guint64 end, guint64 step, bool verticalflip = false);
|
||||
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 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, guint64 start, 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);
|
||||
|
||||
// fonts from ressources 'fonts/'
|
||||
@@ -51,12 +53,11 @@ namespace ImGuiToolkit
|
||||
void SetFont (font_style type, const std::string &ttf_font_name, int pointsize, int oversample = 2);
|
||||
void PushFont (font_style type);
|
||||
|
||||
void WindowText(const char* window_name, ImVec2 window_pos, const char* text);
|
||||
bool WindowButton(const char* window_name, ImVec2 window_pos, const char* text);
|
||||
void WindowDragFloat(const char* window_name, ImVec2 window_pos, float* v, float v_speed, float v_min, float v_max, const char* format);
|
||||
// text input
|
||||
bool InputText(const char* label, std::string* str);
|
||||
bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), int linesize = 0);
|
||||
|
||||
|
||||
// color of gui items
|
||||
// accent color of UI
|
||||
typedef enum {
|
||||
ACCENT_BLUE =0,
|
||||
ACCENT_ORANGE,
|
||||
@@ -65,8 +66,11 @@ namespace ImGuiToolkit
|
||||
void SetAccentColor (accent_color color);
|
||||
struct ImVec4 HighlightColor (bool active = true);
|
||||
|
||||
bool InputText(const char* label, std::string* str);
|
||||
bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), int linesize = 0);
|
||||
// varia
|
||||
void WindowText(const char* window_name, ImVec2 window_pos, const char* text);
|
||||
bool WindowButton(const char* window_name, ImVec2 window_pos, const char* text);
|
||||
void WindowDragFloat(const char* window_name, ImVec2 window_pos, float* v, float v_speed, float v_min, float v_max, const char* format);
|
||||
|
||||
}
|
||||
|
||||
#endif // __IMGUI_TOOLKIT_H_
|
||||
|
||||
42
Timeline.cpp
42
Timeline.cpp
@@ -142,6 +142,40 @@ bool Timeline::addGap(GstClockTime begin, GstClockTime end)
|
||||
return addGap( TimeInterval(begin, end) );
|
||||
}
|
||||
|
||||
bool Timeline::cut(GstClockTime t)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (timing_.includes(t))
|
||||
{
|
||||
TimeIntervalSet::iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t));
|
||||
// cut a gap
|
||||
if ( g != gaps_.end() )
|
||||
{
|
||||
GstClockTime b = g->begin;
|
||||
gaps_.erase(g);
|
||||
ret = addGap(b, t);
|
||||
}
|
||||
// create a gap
|
||||
else {
|
||||
TimeIntervalSet::iterator previous = gaps_.end();
|
||||
for (g = gaps_.begin(); g != gaps_.end(); previous = g++) {
|
||||
if ( g->begin > t)
|
||||
break;
|
||||
}
|
||||
if (previous == gaps_.end())
|
||||
ret = addGap( TimeInterval(timing_.begin, t) );
|
||||
else {
|
||||
GstClockTime b = previous->begin;
|
||||
gaps_.erase(previous);
|
||||
ret = addGap(b, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Timeline::addGap(TimeInterval s)
|
||||
{
|
||||
if ( s.is_valid() ) {
|
||||
@@ -180,6 +214,7 @@ GstClockTime Timeline::sectionsDuration() const
|
||||
for (auto it = gaps_.begin(); it != gaps_.end(); ++it)
|
||||
d += (*it).end - (*it).begin;
|
||||
|
||||
// remove sum of gaps from actual duration
|
||||
return duration() - d;
|
||||
}
|
||||
|
||||
@@ -304,6 +339,13 @@ float Timeline::fadingAt(const GstClockTime t) const
|
||||
return v;
|
||||
}
|
||||
|
||||
size_t Timeline::fadingIndexAt(const GstClockTime t) const
|
||||
{
|
||||
double true_index = (static_cast<double>(MAX_TIMELINE_ARRAY) * static_cast<double>(t)) / static_cast<double>(timing_.end);
|
||||
double previous_index = floor(true_index);
|
||||
return MINI( static_cast<size_t>(previous_index), MAX_TIMELINE_ARRAY-1);
|
||||
}
|
||||
|
||||
void Timeline::clearFading()
|
||||
{
|
||||
// fill static with 1 (only once)
|
||||
|
||||
@@ -62,6 +62,10 @@ struct TimeInterval
|
||||
{
|
||||
return (is_valid() && t != GST_CLOCK_TIME_NONE && !(t < this->begin) && !(t > this->end) );
|
||||
}
|
||||
inline bool includes(const TimeInterval& b) const
|
||||
{
|
||||
return (is_valid() && b.is_valid() && includes(b.begin) && includes(b.end) );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +73,7 @@ struct order_comparator
|
||||
{
|
||||
inline bool operator () (const TimeInterval a, const TimeInterval b) const
|
||||
{
|
||||
return (a < b);
|
||||
return (a < b || a.begin < b.begin);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,11 +118,13 @@ public:
|
||||
void setGaps(const TimeIntervalSet &g);
|
||||
bool addGap(TimeInterval s);
|
||||
bool addGap(GstClockTime begin, GstClockTime end);
|
||||
bool cut(GstClockTime t);
|
||||
bool removeGaptAt(GstClockTime t);
|
||||
bool gapAt(const GstClockTime t, TimeInterval &gap) const;
|
||||
|
||||
// Manipulation of Fading
|
||||
float fadingAt(const GstClockTime t) const;
|
||||
size_t fadingIndexAt(const GstClockTime t) const;
|
||||
inline float *fadingArray() { return fadingArray_; }
|
||||
void clearFading();
|
||||
|
||||
|
||||
@@ -2113,6 +2113,136 @@ void SourceController::Render()
|
||||
|
||||
}
|
||||
|
||||
void DrawTimeScale(const char* label, guint64 duration, double width_ratio)
|
||||
{
|
||||
// get window
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
// get style & id
|
||||
const ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
|
||||
const ImVec2 timeline_size( static_cast<float>( static_cast<double>(duration) * width_ratio ), 2.f * g.FontSize);
|
||||
|
||||
const ImVec2 pos = window->DC.CursorPos;
|
||||
const ImVec2 frame_size( timeline_size.x + 2.f * style.FramePadding.x, timeline_size.y + style.FramePadding.y);
|
||||
const ImRect bbox(pos, pos + frame_size);
|
||||
ImGui::ItemSize(frame_size, style.FramePadding.y);
|
||||
if (!ImGui::ItemAdd(bbox, id))
|
||||
return;
|
||||
|
||||
const ImVec2 timescale_pos = pos + ImVec2(style.FramePadding.x, 0.f);
|
||||
const ImRect timescale_bbox( timescale_pos, timescale_pos + timeline_size);
|
||||
|
||||
ImGuiToolkit::RenderTimeline(window, timescale_bbox, 0, duration, 1000, true);
|
||||
|
||||
}
|
||||
|
||||
void DrawTimeline(const char* label, Timeline *timeline, guint64 time, double width_ratio, float height)
|
||||
{
|
||||
// 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
|
||||
//
|
||||
|
||||
// fixed elements of timeline
|
||||
float *lines_array = timeline->fadingArray();
|
||||
const guint64 duration = timeline->sectionsDuration();
|
||||
TimeIntervalSet se = timeline->sections();
|
||||
const ImVec2 timeline_size( static_cast<float>( static_cast<double>(duration) * width_ratio ), 2.f * fontsize);
|
||||
|
||||
// widget bounding box
|
||||
const ImVec2 frame_pos = window->DC.CursorPos;
|
||||
const ImVec2 frame_size( timeline_size.x + 2.f * style.FramePadding.x, height);
|
||||
const ImRect bbox(frame_pos, frame_pos + frame_size);
|
||||
ImGui::ItemSize(frame_size, style.FramePadding.y);
|
||||
if (!ImGui::ItemAdd(bbox, id))
|
||||
return;
|
||||
|
||||
// capture hover to avoid tooltip on plotlines
|
||||
ImGui::ItemHoverable(bbox, id);
|
||||
|
||||
// cursor size
|
||||
const float cursor_width = 0.5f * fontsize;
|
||||
|
||||
// TIMELINE is inside the bbox, at the bottom
|
||||
const ImVec2 timeline_pos = frame_pos + ImVec2(style.FramePadding.x, frame_size.y - timeline_size.y -style.FramePadding.y);
|
||||
const ImRect timeline_bbox( timeline_pos, timeline_pos + timeline_size);
|
||||
|
||||
// PLOT of opacity is inside the bbox, at the top
|
||||
const ImVec2 plot_pos = frame_pos + style.FramePadding;
|
||||
const ImRect plot_bbox( plot_pos, plot_pos + ImVec2(timeline_size.x, frame_size.y - 2.f * style.FramePadding.y - timeline_size.y));
|
||||
|
||||
//
|
||||
// THIRD RENDER
|
||||
//
|
||||
|
||||
// Render the bounding box frame
|
||||
ImGui::RenderFrame(bbox.Min, bbox.Max, ImGui::GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
|
||||
// loop over sections of sources' timelines
|
||||
guint64 d = 0;
|
||||
guint64 e = 0;
|
||||
ImVec2 section_bbox_min = timeline_bbox.Min;
|
||||
for (auto section = se.begin(); section != se.end(); ++section) {
|
||||
|
||||
// increment duration to adjust horizontal position
|
||||
d += section->duration();
|
||||
e = section->end;
|
||||
const float percent = static_cast<float>(d) / static_cast<float>(duration) ;
|
||||
ImVec2 section_bbox_max = ImLerp(timeline_bbox.GetBL(), timeline_bbox.GetBR(), percent);
|
||||
|
||||
// adjust bbox of section and render a timeline
|
||||
ImRect section_bbox(section_bbox_min, section_bbox_max);
|
||||
ImGuiToolkit::RenderTimeline(window, section_bbox, section->begin, section->end, timeline->step());
|
||||
|
||||
// draw the cursor
|
||||
float time_ = static_cast<float> ( static_cast<double>(time - section->begin) / static_cast<double>(section->duration()) );
|
||||
if ( time_ > -FLT_EPSILON && time_ < 1.f ) {
|
||||
ImVec2 pos = ImLerp(section_bbox.GetTL(), section_bbox.GetTR(), time_) - ImVec2(cursor_width, 2.f);
|
||||
ImGui::RenderArrow(window->DrawList, pos, ImGui::GetColorU32(ImGuiCol_SliderGrab), ImGuiDir_Up);
|
||||
}
|
||||
|
||||
// draw plot of lines
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 0.f));
|
||||
ImGui::SetCursorScreenPos(ImVec2(section_bbox_min.x, plot_bbox.Min.y));
|
||||
// find the index in timeline array of the section start time
|
||||
size_t i = timeline->fadingIndexAt(section->begin);
|
||||
// number of values is the index after end time of section (+1), minus the start index
|
||||
size_t values_count = 1 + timeline->fadingIndexAt(section->end) - i;
|
||||
ImGui::PlotLines("##linessection", lines_array + i, values_count, 0, NULL, 0.f, 1.f, ImVec2(section_bbox.GetWidth(), plot_bbox.GetHeight()));
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(1);
|
||||
|
||||
// detect if there was a gap before
|
||||
if (i > 0)
|
||||
window->DrawList->AddRectFilled(ImVec2(section_bbox_min.x -2.f, plot_bbox.Min.y), ImVec2(section_bbox_min.x + 2.f, plot_bbox.Max.y), ImGui::GetColorU32(ImGuiCol_TitleBg));
|
||||
|
||||
// iterate: next bbox of section starts at end of current
|
||||
section_bbox_min.x = section_bbox_max.x;
|
||||
}
|
||||
|
||||
// detect if there is a gap after
|
||||
if (e < timeline->duration())
|
||||
window->DrawList->AddRectFilled(ImVec2(section_bbox_min.x -2.f, plot_bbox.Min.y), ImVec2(section_bbox_min.x + 2.f, plot_bbox.Max.y), ImGui::GetColorU32(ImGuiCol_TitleBg));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SourceController::RenderSelection(size_t i)
|
||||
{
|
||||
ImVec2 top = ImGui::GetCursorScreenPos();
|
||||
@@ -2121,7 +2251,6 @@ void SourceController::RenderSelection(size_t i)
|
||||
|
||||
selection_ = Mixer::manager().session()->playGroup(i);
|
||||
int numsources = selection_.size();
|
||||
bool buttons_enabled = false;
|
||||
|
||||
// no source selected
|
||||
if (numsources < 1)
|
||||
@@ -2140,27 +2269,38 @@ void SourceController::RenderSelection(size_t i)
|
||||
}
|
||||
else {
|
||||
///
|
||||
/// Sources grid
|
||||
/// Sources LIST
|
||||
///
|
||||
///
|
||||
|
||||
// get max duration
|
||||
// get max duration and max frame width
|
||||
GstClockTime maxduration = 0;
|
||||
float maxframewidth = 0.f;
|
||||
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());
|
||||
GstClockTime d = (static_cast<double>(ms->mediaplayer()->timeline()->sectionsDuration()) / ms->mediaplayer()->playSpeed());
|
||||
if ( d > maxduration )
|
||||
maxduration = d;
|
||||
}
|
||||
float w = 1.5f * _timeline_height * (*source)->frame()->aspectRatio();
|
||||
if ( w > maxframewidth)
|
||||
maxframewidth = w;
|
||||
}
|
||||
// compute the ratio for timeline rendering : width (pixel) per time unit (ms)
|
||||
const float w = rendersize.x -maxframewidth - 3.f * _h_space - _scrollbar;
|
||||
const double width_ratio = static_cast<double>(w) / static_cast<double>(maxduration);
|
||||
|
||||
|
||||
// draw list
|
||||
ImGui::BeginChild("##v_scroll2", rendersize, false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
// draw list in a scroll area
|
||||
ImGui::BeginChild("##v_scroll2", rendersize, false);
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, _v_space));
|
||||
// draw play time scale if a duration is set
|
||||
if (maxduration > 0) {
|
||||
ImGui::SetCursorPos(ImGui::GetCursorPos() + ImVec2( maxframewidth + _h_space, 0));
|
||||
DrawTimeScale("##timescale", maxduration, width_ratio);
|
||||
}
|
||||
|
||||
// loop over all sources
|
||||
for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
||||
|
||||
ImVec2 framesize(1.5f * _timeline_height * (*source)->frame()->aspectRatio(), 1.5f * _timeline_height);
|
||||
@@ -2171,52 +2311,25 @@ void SourceController::RenderSelection(size_t i)
|
||||
UserInterface::manager().showSourceEditor(*source);
|
||||
|
||||
// text below thumbnail to show status
|
||||
const char *icon = ICON_FA_SNOWFLAKE;
|
||||
if ((*source)->active()) {
|
||||
icon = (*source)->playing() ? ICON_FA_PLAY : ICON_FA_PAUSE;
|
||||
buttons_enabled = true;
|
||||
}
|
||||
ImGui::Text("%s %s", icon, GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
||||
ImGui::Text(" %s %s", SourcePlayIcon(*source), GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
||||
|
||||
// get media source
|
||||
MediaSource *ms = dynamic_cast<MediaSource *>(*source);
|
||||
if (ms != nullptr) {
|
||||
ImGui::SetCursorPos(image_top + ImVec2( framesize.x + _h_space, 0));
|
||||
// ok, get the media player of the media source
|
||||
MediaPlayer *mp = ms->mediaplayer();
|
||||
Timeline *tl = mp->timeline();
|
||||
|
||||
// cut gaps
|
||||
// // timeline of MediaSource to the right
|
||||
// static float gaps[MAX_TIMELINE_ARRAY];
|
||||
// static float fade[MAX_TIMELINE_ARRAY];
|
||||
// size_t numsteps = tl->fillSectionsArrays(gaps, fade) - 1;
|
||||
// start to draw timeline aligned at maximum frame width + horizontal space
|
||||
ImGui::SetCursorPos(image_top + ImVec2( maxframewidth + _h_space, 0));
|
||||
|
||||
ImVec2 size(rendersize.x - framesize.x - _h_space - _scrollbar, 1.5f * _timeline_height);
|
||||
// draw the mediaplayer's timeline, with the indication of cursor position
|
||||
// NB: use the same width/time ratio for all to ensure timing vertical correspondance
|
||||
DrawTimeline("##timeline_mediaplayer", mp->timeline(), mp->position(), width_ratio / fabs(mp->playSpeed()), framesize.y);
|
||||
|
||||
// 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();
|
||||
GstClockTime playtime = tl->sectionsDuration();
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 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("%d sections, %s play time / %.2f speed = %s (effective duration)",
|
||||
se.size(), GstToolkit::time_to_string(playtime).c_str(),
|
||||
mp->playSpeed(), GstToolkit::time_to_string(t).c_str());
|
||||
ImGui::SetCursorPos(image_top + ImVec2( maxframewidth + _h_space, framesize.y + _v_space));
|
||||
ImGui::Text("%s play time @ %.2f speed / %s (max duration)",
|
||||
GstToolkit::time_to_string(mp->timeline()->sectionsDuration()).c_str(),
|
||||
mp->playSpeed(), GstToolkit::time_to_string(maxduration).c_str());
|
||||
}
|
||||
|
||||
// next line position
|
||||
@@ -2224,52 +2337,15 @@ void SourceController::RenderSelection(size_t i)
|
||||
// ImGui::Spacing();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
// ImGui::BeginChild("##v_scroll", rendersize, false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
// {
|
||||
// ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, _v_space));
|
||||
|
||||
// // area horizontal pack
|
||||
// int numcolumns = CLAMP( int(ceil(1.0f * rendersize.x / rendersize.y)), 1, numsources );
|
||||
// ImGui::Columns( numcolumns, "##selectiongrid", false);
|
||||
|
||||
// for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
||||
|
||||
// ImVec2 framesize(ImGui::GetColumnWidth(), ImGui::GetColumnWidth() / (*source)->frame()->aspectRatio());
|
||||
// framesize.x -= _h_space;
|
||||
// ImVec2 image_top = ImGui::GetCursorPos();
|
||||
|
||||
// if (SourceButton(*source, framesize))
|
||||
// UserInterface::manager().showSourceEditor(*source);
|
||||
|
||||
// // Play icon lower left corner
|
||||
// ImGuiToolkit::PushFont(framesize.x > 350.f ? ImGuiToolkit::FONT_LARGE : ImGuiToolkit::FONT_MONO);
|
||||
// float h = ImGui::GetTextLineHeightWithSpacing();
|
||||
// ImGui::SetCursorPos(image_top + ImVec2( _h_space, framesize.y - h));
|
||||
// if ((*source)->active())
|
||||
// ImGui::Text("%s %s", (*source)->playing() ? ICON_FA_PLAY : ICON_FA_PAUSE, GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
||||
// else
|
||||
// ImGui::Text("%s %s", ICON_FA_SNOWFLAKE, GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
||||
// ImGui::PopFont();
|
||||
|
||||
// ImGui::Spacing();
|
||||
// ImGui::NextColumn();
|
||||
// }
|
||||
|
||||
// ImGui::Columns(1);
|
||||
// ImGui::PopStyleVar();
|
||||
// }
|
||||
// ImGui::EndChild();
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
/// Play button bar
|
||||
///
|
||||
DrawButtonBar(bottom, rendersize.x, buttons_enabled);
|
||||
DrawButtonBar(bottom, rendersize.x);
|
||||
|
||||
///
|
||||
/// Selection of sources
|
||||
@@ -2368,42 +2444,43 @@ void SourceController::RenderSelectedSources()
|
||||
ImGui::Text("Nothing to play");
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
///
|
||||
/// Play button bar
|
||||
/// Play button bar (automatically disabled)
|
||||
///
|
||||
DrawButtonBar(bottom, rendersize.x, false);
|
||||
DrawButtonBar(bottom, rendersize.x);
|
||||
|
||||
}
|
||||
// single source selected
|
||||
else if (numsources < 2)
|
||||
{
|
||||
///
|
||||
/// Sources display
|
||||
/// Single Source display
|
||||
///
|
||||
RenderSingleSource( selection_.front() );
|
||||
}
|
||||
// Several sources selected
|
||||
else {
|
||||
|
||||
///
|
||||
/// Sources grid
|
||||
///
|
||||
///
|
||||
bool buttons_enabled = false;
|
||||
ImGui::BeginChild("##v_scroll", rendersize, false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
ImGui::BeginChild("##v_scroll", rendersize, false);
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, _v_space));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 2.f * _v_space));
|
||||
|
||||
// area horizontal pack
|
||||
int numcolumns = CLAMP( int(ceil(1.0f * rendersize.x / rendersize.y)), 1, numsources );
|
||||
ImGui::Columns( numcolumns, "##selectiongrid", false);
|
||||
float widthcolumn = rendersize.x / static_cast<float>(numcolumns);
|
||||
widthcolumn -= _scrollbar;
|
||||
|
||||
// loop over sources in grid
|
||||
for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
||||
|
||||
ImVec2 framesize(ImGui::GetColumnWidth(), ImGui::GetColumnWidth() / (*source)->frame()->aspectRatio());
|
||||
framesize.x -= _h_space;
|
||||
|
||||
///
|
||||
/// Source Image Button
|
||||
///
|
||||
ImVec2 image_top = ImGui::GetCursorPos();
|
||||
ImVec2 framesize(widthcolumn, widthcolumn / (*source)->frame()->aspectRatio());
|
||||
if (SourceButton(*source, framesize))
|
||||
UserInterface::manager().showSourceEditor(*source);
|
||||
|
||||
@@ -2411,12 +2488,7 @@ void SourceController::RenderSelectedSources()
|
||||
ImGuiToolkit::PushFont(framesize.x > 350.f ? ImGuiToolkit::FONT_LARGE : ImGuiToolkit::FONT_MONO);
|
||||
float h = ImGui::GetTextLineHeightWithSpacing();
|
||||
ImGui::SetCursorPos(image_top + ImVec2( _h_space, framesize.y - h));
|
||||
if ((*source)->active()) {
|
||||
ImGui::Text("%s %s", (*source)->playing() ? ICON_FA_PLAY : ICON_FA_PAUSE, GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
||||
buttons_enabled = true;
|
||||
}
|
||||
else
|
||||
ImGui::Text(ICON_FA_SNOWFLAKE " %s", GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
||||
ImGui::Text("%s %s", SourcePlayIcon(*source), GstToolkit::time_to_string((*source)->playtime()).c_str() );
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::Spacing();
|
||||
@@ -2431,10 +2503,10 @@ void SourceController::RenderSelectedSources()
|
||||
///
|
||||
/// Play button bar
|
||||
///
|
||||
DrawButtonBar(bottom, rendersize.x, buttons_enabled);
|
||||
DrawButtonBar(bottom, rendersize.x);
|
||||
|
||||
///
|
||||
/// New Selection from active sources
|
||||
/// Menu to store Selection from current sources
|
||||
///
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.14f, 0.14f, 0.14f, 0.5f));
|
||||
@@ -2491,10 +2563,16 @@ void SourceController::RenderSingleSource(Source *s)
|
||||
framesize.x = tmp.x;
|
||||
}
|
||||
|
||||
///
|
||||
/// Image
|
||||
///
|
||||
top += corner;
|
||||
ImGui::SetCursorScreenPos(top);
|
||||
ImGui::Image((void*)(uintptr_t) s->texture(), framesize);
|
||||
|
||||
///
|
||||
/// Info overlays
|
||||
///
|
||||
ImGui::SetCursorScreenPos(top + ImVec2(framesize.x - ImGui::GetTextLineHeightWithSpacing(), _v_space));
|
||||
ImGui::Text(ICON_FA_INFO_CIRCLE);
|
||||
if (ImGui::IsItemHovered()){
|
||||
@@ -2516,17 +2594,13 @@ void SourceController::RenderSingleSource(Source *s)
|
||||
// Play icon lower left corner
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
||||
ImGui::SetCursorScreenPos(bottom + ImVec2(_h_space, -ImGui::GetTextLineHeightWithSpacing()));
|
||||
if (s->active())
|
||||
ImGui::Text("%s %s", s->playing() ? ICON_FA_PLAY : ICON_FA_PAUSE, GstToolkit::time_to_string(s->playtime()).c_str() );
|
||||
else
|
||||
ImGui::Text("%s %s", ICON_FA_SNOWFLAKE, GstToolkit::time_to_string(s->playtime()).c_str() );
|
||||
ImGui::Text("%s %s", SourcePlayIcon(s), GstToolkit::time_to_string(s->playtime()).c_str() );
|
||||
ImGui::PopFont();
|
||||
|
||||
///
|
||||
/// Play source button bar
|
||||
/// Play button bar
|
||||
///
|
||||
DrawButtonBar(bottom, rendersize.x, s->active());
|
||||
|
||||
DrawButtonBar(bottom, rendersize.x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2555,10 +2629,16 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
framesize.x = tmp.x;
|
||||
}
|
||||
|
||||
///
|
||||
/// Image
|
||||
///
|
||||
top += corner;
|
||||
ImGui::SetCursorScreenPos(top);
|
||||
ImGui::Image((void*)(uintptr_t) mp->texture(), framesize);
|
||||
|
||||
///
|
||||
/// Info overlays
|
||||
///
|
||||
ImGui::SetCursorScreenPos(top + ImVec2(framesize.x - ImGui::GetTextLineHeightWithSpacing(), _v_space));
|
||||
ImGui::Text(ICON_FA_INFO_CIRCLE);
|
||||
if (ImGui::IsItemHovered()){
|
||||
@@ -2588,11 +2668,11 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
if (mp->isEnabled())
|
||||
ImGui::Text("%s %s", mp->isPlaying() ? ICON_FA_PLAY : ICON_FA_PAUSE, GstToolkit::time_to_string(mp->position()).c_str() );
|
||||
else
|
||||
ImGui::Text(ICON_FA_SNOWFLAKE " %s", GstToolkit::time_to_string(mp->position()).c_str() );
|
||||
ImGui::Text( ICON_FA_SNOWFLAKE " %s", GstToolkit::time_to_string(mp->position()).c_str() );
|
||||
ImGui::PopFont();
|
||||
|
||||
///
|
||||
/// media player buttons bar
|
||||
/// media player buttons bar (custom)
|
||||
///
|
||||
draw_list->AddRectFilled(bottom, bottom + ImVec2(rendersize.x, _buttons_height), ImGui::GetColorU32(ImGuiCol_FrameBg), _h_space);
|
||||
|
||||
@@ -2651,6 +2731,9 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
mp->setPlaySpeed( static_cast<double>(speed) );
|
||||
}
|
||||
|
||||
///
|
||||
/// Media Player context menu
|
||||
///
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(rendersize.x - _buttons_height / 1.5f);
|
||||
|
||||
@@ -2659,11 +2742,11 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
ImGui::OpenPopup( "MenuTimeline" );
|
||||
if (ImGui::BeginPopup( "MenuTimeline" ))
|
||||
{
|
||||
if (ImGui::MenuItem(UNICODE_MULTIPLY " " ICON_FA_CARET_RIGHT " Reset Speed" )){
|
||||
if (ImGui::MenuItem(UNICODE_MULTIPLY " " ICON_FA_CARET_RIGHT " Reset speed" )){
|
||||
speed = 1.f;
|
||||
mp->setPlaySpeed( static_cast<double>(speed) );
|
||||
}
|
||||
if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset Timeline" )){
|
||||
if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset timeline" )){
|
||||
timeline_zoom = 1.f;
|
||||
mp->timeline()->clearFading();
|
||||
mp->timeline()->clearGaps();
|
||||
@@ -2681,7 +2764,14 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (Settings::application.render.gpu_decoding && ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware Decoding"))
|
||||
if (ImGui::BeginMenu(ICON_FA_CUT " Auto cut" )){
|
||||
if (ImGui::MenuItem("Cut faded areas"))
|
||||
if (mp->timeline()->autoCut())
|
||||
Action::manager().store("Timeline Auto cut");
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (Settings::application.render.gpu_decoding && ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware decoding"))
|
||||
{
|
||||
bool hwdec = !mp->softwareDecodingForced();
|
||||
if (ImGui::MenuItem("Auto", "", &hwdec ))
|
||||
@@ -2723,7 +2813,7 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
{
|
||||
bool released = false;
|
||||
if ( ImGuiToolkit::EditPlotHistoLines("##TimelineArray", tl->gapsArray(), tl->fadingArray(),
|
||||
MAX_TIMELINE_ARRAY, 0.f, 1.f,
|
||||
MAX_TIMELINE_ARRAY, 0.f, 1.f, tl->begin(), tl->end(),
|
||||
Settings::application.widget.timeline_editmode, &released, size) ) {
|
||||
tl->update();
|
||||
}
|
||||
@@ -2745,15 +2835,15 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
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] = {"Draw opacity", "Cut sections"};
|
||||
const char *tooltip[2] = {"Draw opacity tool", "Cut tool"};
|
||||
ImGuiToolkit::IconToggle(7,4,8,3, &Settings::application.widget.timeline_editmode, tooltip);
|
||||
|
||||
ImGui::SetCursorScreenPos(bottom + ImVec2(1.f, 0.5f * _timeline_height));
|
||||
if (Settings::application.widget.timeline_editmode) {
|
||||
// action auto cut
|
||||
if (ImGuiToolkit::IconButton(14, 12, "Auto cut")) {
|
||||
if (mp->timeline()->autoCut())
|
||||
Action::manager().store("Timeline Auto cut");
|
||||
if (ImGuiToolkit::IconButton(9, 3, "Cut at cursor")) {
|
||||
if (mp->timeline()->cut(mp->position()))
|
||||
Action::manager().store("Timeline Cut");
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2780,9 +2870,9 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
///
|
||||
/// media player actions
|
||||
///
|
||||
/// media player timeline actions
|
||||
///
|
||||
|
||||
// request seek (ASYNC)
|
||||
if ( slider_pressed_ && mp->go_to(seek_t) )
|
||||
slider_pressed_ = false;
|
||||
@@ -2797,41 +2887,81 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||
}
|
||||
}
|
||||
|
||||
void SourceController::DrawButtonBar(ImVec2 bottom, float width, bool enabled)
|
||||
const char *SourceController::SourcePlayIcon(Source *s)
|
||||
{
|
||||
if (s->active()) {
|
||||
if ( s->playing() )
|
||||
return ICON_FA_PLAY;
|
||||
else
|
||||
return ICON_FA_PAUSE;
|
||||
}
|
||||
else
|
||||
return ICON_FA_SNOWFLAKE;
|
||||
}
|
||||
|
||||
void SourceController::DrawButtonBar(ImVec2 bottom, float width)
|
||||
{
|
||||
// draw box
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
draw_list->AddRectFilled(bottom, bottom + ImVec2(width, _buttons_height), ImGui::GetColorU32(ImGuiCol_FrameBg), _h_space);
|
||||
|
||||
// buttons style: inactive if no source in selection
|
||||
if (!enabled || selection_.empty()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.6, 0.6, 0.6, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||
// prepare position to draw text
|
||||
ImGui::SetCursorScreenPos(bottom + ImVec2(_h_space, _v_space) );
|
||||
|
||||
// play bar is enabled if only one source selected is enabled
|
||||
bool enabled = false;
|
||||
for (auto source = selection_.begin(); source != selection_.end(); ++source){
|
||||
if ( (*source)->active() ) {
|
||||
enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// buttons style for disabled / enabled bar
|
||||
if (enabled) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.14f, 0.14f, 0.14f, 0.5f));
|
||||
}
|
||||
else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.6, 0.6, 0.6, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||
}
|
||||
|
||||
ImGui::SetCursorScreenPos(bottom + ImVec2(_h_space, _v_space) );
|
||||
// Always the rewind button
|
||||
if (ImGui::Button(ICON_FA_FAST_BACKWARD) && enabled) {
|
||||
for (auto source = selection_.begin(); source != selection_.end(); ++source)
|
||||
(*source)->replay();
|
||||
}
|
||||
ImGui::SameLine(0, _h_space);
|
||||
if (ImGui::Button(ICON_FA_PLAY) && enabled) {
|
||||
for (auto source = selection_.begin(); source != selection_.end(); ++source)
|
||||
(*source)->play(true);
|
||||
|
||||
// unique play / pause button for single source
|
||||
if (selection_.size() == 1) {
|
||||
Source *s = selection_.front();
|
||||
if (s->playing()) {
|
||||
if (ImGui::Button(ICON_FA_PAUSE) && enabled)
|
||||
(s)->play(false);
|
||||
} else {
|
||||
if (ImGui::Button(ICON_FA_PLAY) && enabled)
|
||||
(s)->play(true);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine(0, _h_space);
|
||||
if (ImGui::Button(ICON_FA_PAUSE) && enabled) {
|
||||
for (auto source = selection_.begin(); source != selection_.end(); ++source)
|
||||
(*source)->play(false);
|
||||
// separate play & pause buttons for multiple sources (or none)
|
||||
else {
|
||||
if (ImGui::Button(ICON_FA_PLAY) && enabled) {
|
||||
for (auto source = selection_.begin(); source != selection_.end(); ++source)
|
||||
(*source)->play(true);
|
||||
}
|
||||
ImGui::SameLine(0, _h_space);
|
||||
if (ImGui::Button(ICON_FA_PAUSE) && enabled) {
|
||||
for (auto source = selection_.begin(); source != selection_.end(); ++source)
|
||||
(*source)->play(false);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine(0, _h_space);
|
||||
|
||||
// restore
|
||||
// restore style
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
|
||||
@@ -2958,7 +3088,7 @@ void Navigator::Render()
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 p1 = ImGui::GetCursorScreenPos() + ImVec2(icon_width, 0.5f * icon_width);
|
||||
ImVec2 p2 = ImVec2(p1.x + 2.f, p1.y + 2.f);
|
||||
const ImU32 color = ImGui::GetColorU32( style.Colors[ImGuiCol_Text] );
|
||||
const ImU32 color = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
if ((*iter)->mode() == Source::CURRENT) {
|
||||
p1 = ImGui::GetCursorScreenPos() + ImVec2(icon_width, 0);
|
||||
p2 = ImVec2(p1.x + 2.f, p1.y + icon_width);
|
||||
|
||||
@@ -118,9 +118,10 @@ class SourceController
|
||||
std::string active_label_;
|
||||
int active_selection_;
|
||||
InfoVisitor info_;
|
||||
|
||||
SourceList selection_;
|
||||
void DrawButtonBar(ImVec2 bottom, float width, bool enabled = true);
|
||||
|
||||
void DrawButtonBar(ImVec2 bottom, float width);
|
||||
const char *SourcePlayIcon(Source *s);
|
||||
|
||||
bool SourceButton(Source *s, ImVec2 framesize);
|
||||
void RenderSelectedSources();
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user