Player: move up timeline and adjust size

keep play button bar at the bottom for all configurations, avoid text and buttons overlay when Player is small. Fix cut timing in selection
This commit is contained in:
Bruno
2021-06-15 23:51:59 +02:00
parent 37445b8857
commit e3578df8a0
4 changed files with 280 additions and 244 deletions

View File

@@ -505,18 +505,6 @@ void ImGuiToolkit::RenderTimeline (ImGuiWindow* window, ImRect timeline_bbox, gu
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());
@@ -528,6 +516,19 @@ void ImGuiToolkit::RenderTimeline (ImGuiWindow* window, ImRect timeline_bbox, gu
text_buf, NULL, &duration_label_size);
window->DrawList->AddLine( timeline_bbox.GetTR(), timeline_bbox.GetBR(), text_color, 1.5f);
// 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;
if ( beginning_label_pos.x + beginning_label_size.x < duration_label_pos . x) {
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);
ImGui::PopFont();
// render the tick marks along TIMELINE

View File

@@ -268,6 +268,28 @@ GstClockTime Timeline::sectionsDuration() const
return duration() - d;
}
GstClockTime Timeline::sectionsTimeAt(GstClockTime t) const
{
// target time
GstClockTime d = t;
// loop over gaps
for (auto it = gaps_.begin(); it != gaps_.end(); ++it) {
// gap before target?
if ( (*it).end < d ) {
// increment target
d += (*it).end - (*it).begin;
}
else
// done
break;
}
// return updated target
return d;
}
size_t Timeline::fillSectionsArrays( float* const gaps, float* const fading)
{
size_t arraysize = MAX_TIMELINE_ARRAY;

View File

@@ -120,10 +120,15 @@ public:
bool addGap(GstClockTime begin, GstClockTime end);
bool cut(GstClockTime t, bool left, bool join_extremity);
bool removeGaptAt(GstClockTime t);
bool gapAt(const GstClockTime t) const;
bool getGapAt(const GstClockTime t, TimeInterval &gap) const;
// inverse of gaps: sections of play areas
TimeIntervalSet sections() const;
GstClockTime sectionsDuration() const;
GstClockTime sectionsTimeAt(GstClockTime t) const;
size_t fillSectionsArrays(float * const gaps, float * const fading);
// Manipulation of Fading
float fadingAt(const GstClockTime t) const;
size_t fadingIndexAt(const GstClockTime t) const;
@@ -134,10 +139,6 @@ public:
void smoothFading(uint N = 1);
void autoFading(uint milisecond = 100);
bool autoCut();
TimeIntervalSet sections() const;
GstClockTime sectionsDuration() const;
size_t fillSectionsArrays(float * const gaps, float * const fading);
private:

View File

@@ -2015,7 +2015,7 @@ void SourceController::Render()
_timeline_height = (g.FontSize + _v_space) * 2.0f ; // double line for each timeline
_scrollbar = g.Style.ScrollbarSize;
// all together: 1 title bar + spacing + 1 toolbar + spacing + 2 timelines + scrollbar
_mediaplayer_height = _buttons_height + 2.f * _timeline_height + _scrollbar + 2.f * _v_space;
_mediaplayer_height = _buttons_height + 2.f * _timeline_height + 2.f * _scrollbar + _v_space;
// constraint position
static ImVec2 source_window_pos = ImVec2(1180, 20);
@@ -2337,6 +2337,8 @@ void SourceController::RenderSelection(size_t i)
// 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);
if ( w > maxframewidth ) {
// next icon buttons are small
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3.f, 3.f));
@@ -2359,6 +2361,7 @@ void SourceController::RenderSelection(size_t i)
for (auto d = durations.crbegin(); d != durations.crend(); ++d) {
// next buttons sub id
ImGui::PushID( static_cast<int>(*d));
// calculate position of icons
@@ -2407,7 +2410,7 @@ void SourceController::RenderSelection(size_t i)
// middle buttons : offer to cut at this position
else if ( playdur > (*d) ) {
char text_buf[256];
GstClockTime cutposition = (*d) * fabs(mp->playSpeed());
GstClockTime cutposition = mp->timeline()->sectionsTimeAt( (*d) * fabs(mp->playSpeed()) );
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "Cut at %s",
GstToolkit::time_to_string(cutposition, GstToolkit::TIME_STRING_MINIMAL).c_str());
@@ -2446,6 +2449,8 @@ void SourceController::RenderSelection(size_t i)
ImGui::PopID();
}
}
// next line position
ImGui::SetCursorPos(image_top + ImVec2(0, 2.0f * _timeline_height + 2.f * _v_space));
}
@@ -2523,20 +2528,20 @@ void SourceController::RenderSelectionContextMenu()
std::ostringstream info;
info << SystemToolkit::base_filename( _selection_mediaplayer->filename() );
if ( ImGuiToolkit::MenuItemIcon(14, 16, ICON_FA_CARET_LEFT " Accelerate", false, fabs(_selection_target_faster) > 0 )){
if ( ImGuiToolkit::MenuItemIcon(14, 16, ICON_FA_CARET_LEFT " Accelerate" , false, fabs(_selection_target_faster) > 0 )){
_selection_mediaplayer->setPlaySpeed( _selection_target_faster );
info << ": Speed x" << std::setprecision(3) << _selection_target_faster;
Action::manager().store(info.str());
}
if ( ImGuiToolkit::MenuItemIcon(15, 16, ICON_FA_CARET_RIGHT " Slow down", false, fabs(_selection_target_slower) > 0 )){
if ( ImGuiToolkit::MenuItemIcon(15, 16, "Slow down " ICON_FA_CARET_RIGHT , false, fabs(_selection_target_slower) > 0 )){
_selection_mediaplayer->setPlaySpeed( _selection_target_slower );
info << ": Speed x" << std::setprecision(3) << _selection_target_slower;
Action::manager().store(info.str());
}
if ( _selection_mediaplayer->timeline()->gapAt( _selection_mediaplayer->timeline()->end()) ) {
if ( ImGuiToolkit::MenuItemIcon(7, 0, "Remove end gap" )){
info << ": Remove end gap ";
if ( ImGuiToolkit::MenuItemIcon(7, 0, "Restore ending" )){
info << ": Restore ending";
if ( _selection_mediaplayer->timeline()->removeGaptAt(_selection_mediaplayer->timeline()->end()) )
Action::manager().store(info.str());
}
@@ -2763,12 +2768,17 @@ void SourceController::RenderSingleSource(Source *s)
void SourceController::RenderMediaPlayer(MediaPlayer *mp)
{
// for action manager
std::ostringstream oss;
oss << SystemToolkit::base_filename( mp->filename() );
// for draw
static float timeline_zoom = 1.f;
const float slider_zoom_width = _timeline_height / 2.f;
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 top = ImGui::GetCursorScreenPos();
ImVec2 rendersize = ImGui::GetContentRegionAvail() - ImVec2(0, _mediaplayer_height);
const ImVec2 top = ImGui::GetCursorScreenPos();
const ImVec2 rendersize = ImGui::GetContentRegionAvail() - ImVec2(0, _mediaplayer_height);
ImVec2 bottom = ImVec2(top.x, top.y + rendersize.y + _v_space);
///
@@ -2789,32 +2799,32 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
///
/// Image
///
top += corner;
ImGui::SetCursorScreenPos(top);
const ImVec2 top_image = top + corner;
ImGui::SetCursorScreenPos(top_image);
ImGui::Image((void*)(uintptr_t) mp->texture(), framesize);
///
/// Info overlays
///
ImGui::SetCursorScreenPos(top + ImVec2(framesize.x - ImGui::GetTextLineHeightWithSpacing(), _v_space));
ImGui::SetCursorScreenPos(top_image + ImVec2(framesize.x - ImGui::GetTextLineHeightWithSpacing(), _v_space));
ImGui::Text(ICON_FA_INFO_CIRCLE);
if (ImGui::IsItemHovered()){
// information visitor
mp->accept(info_);
float tooltip_height = 3.f * ImGui::GetTextLineHeightWithSpacing();
draw_list->AddRectFilled(top, top + ImVec2(framesize.x, tooltip_height), IMGUI_COLOR_OVERLAY);
ImGui::SetCursorScreenPos(top + ImVec2(_h_space, _v_space));
draw_list->AddRectFilled(top_image, top_image + ImVec2(framesize.x, tooltip_height), IMGUI_COLOR_OVERLAY);
ImGui::SetCursorScreenPos(top_image + ImVec2(_h_space, _v_space));
ImGui::Text("%s", info_.str().c_str());
// Icon to inform hardware decoding
if ( !mp->hardwareDecoderName().empty()) {
ImGui::SetCursorScreenPos(top + ImVec2( framesize.x - ImGui::GetTextLineHeightWithSpacing(), 0.35f * tooltip_height));
ImGui::SetCursorScreenPos(top_image + ImVec2( framesize.x - ImGui::GetTextLineHeightWithSpacing(), 0.35f * tooltip_height));
ImGui::Text(ICON_FA_MICROCHIP);
}
// refresh frequency
if ( mp->isPlaying()) {
ImGui::SetCursorScreenPos(top + ImVec2( framesize.x - 1.5f * _buttons_height, 0.667f * tooltip_height));
ImGui::SetCursorScreenPos(top_image + ImVec2( framesize.x - 1.5f * _buttons_height, 0.667f * tooltip_height));
ImGui::Text("%.1f Hz", mp->updateFrameRate());
}
}
@@ -2828,143 +2838,14 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
ImGui::Text( ICON_FA_SNOWFLAKE " %s", GstToolkit::time_to_string(mp->position()).c_str() );
ImGui::PopFont();
///
/// media player buttons bar (custom)
///
draw_list->AddRectFilled(bottom, bottom + ImVec2(rendersize.x, _buttons_height), ImGui::GetColorU32(ImGuiCol_FrameBg), _h_space);
// buttons style
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));
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.24f, 0.24f, 0.24f, 0.2f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.14f, 0.14f, 0.14f, 0.5f));
ImGui::SetCursorScreenPos(bottom + ImVec2(_h_space, _v_space) );
if (ImGui::Button(mp->playSpeed() > 0 ? ICON_FA_FAST_BACKWARD :ICON_FA_FAST_FORWARD))
mp->rewind();
// ignore actual play status of mediaplayer when slider is pressed
if (!slider_pressed_)
media_playing_mode_ = mp->isPlaying();
// display buttons Play/Stop depending on current playing mode
ImGui::SameLine(0, _h_space);
if (media_playing_mode_) {
if (ImGui::Button(ICON_FA_PAUSE))
media_playing_mode_ = false;
ImGui::SameLine(0, _h_space);
ImGui::PushButtonRepeat(true);
if (ImGui::Button( mp->playSpeed() < 0 ? ICON_FA_BACKWARD :ICON_FA_FORWARD))
mp->jump ();
ImGui::PopButtonRepeat();
}
else {
if (ImGui::Button(ICON_FA_PLAY))
media_playing_mode_ = true;
ImGui::SameLine(0, _h_space);
ImGui::PushButtonRepeat(true);
if (ImGui::Button( mp->playSpeed() < 0 ? ICON_FA_STEP_BACKWARD : ICON_FA_STEP_FORWARD))
mp->step();
ImGui::PopButtonRepeat();
}
// loop modes button
ImGui::SameLine(0, _h_space);
static int current_loop = 0;
static std::vector< std::pair<int, int> > iconsloop = { {0,15}, {1,15}, {19,14} };
current_loop = (int) mp->loop();
if ( ImGuiToolkit::ButtonIconMultistate(iconsloop, &current_loop) )
mp->setLoop( (MediaPlayer::LoopMode) current_loop );
std::ostringstream oss;
oss << SystemToolkit::base_filename( mp->filename() );
// speed slider (if enough space)
float speed = static_cast<float>(mp->playSpeed());
if ( rendersize.x > _min_width * 1.4f ) {
ImGui::SameLine(0, MAX(_h_space * 2.f, rendersize.x - _min_width * 1.6f) );
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - _buttons_height );
if (ImGui::DragFloat( "##Speed", &speed, 0.01f, -10.f, 10.f, "Speed " UNICODE_MULTIPLY " %.1f", 2.f))
mp->setPlaySpeed( static_cast<double>(speed) );
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << ": Speed x" << std::setprecision(3) << speed;
Action::manager().store(oss.str());
}
}
///
/// Media Player context menu
///
ImGui::SameLine();
ImGui::SetCursorPosX(rendersize.x - _buttons_height / 1.5f);
// Timeline popup menu
if (ImGuiToolkit::IconButton(5,8) )
ImGui::OpenPopup( "MenuTimeline" );
if (ImGui::BeginPopup( "MenuTimeline" ))
{
if (ImGuiToolkit::MenuItemIcon(19,15,"Reset speed" )){
speed = 1.f;
mp->setPlaySpeed( static_cast<double>(speed) );
oss << ": Speed x1";
Action::manager().store(oss.str());
}
if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset timeline" )){
timeline_zoom = 1.f;
mp->timeline()->clearFading();
mp->timeline()->clearGaps();
oss << ": Reset timeline";
Action::manager().store(oss.str());
}
if (ImGui::BeginMenu(ICON_FA_RANDOM " Auto fading"))
{
const char* names[] = { "250 ms", "500 ms", "1 second", "2 seconds"};
for (int i = 0; i < IM_ARRAYSIZE(names); ++i) {
if (ImGui::MenuItem(names[i])) {
mp->timeline()->autoFading( 250 * (int ) pow(2, i) );
mp->timeline()->smoothFading( 2 * (i + 1) );
oss << ": Timeline Auto fading " << 250 * (int ) pow(2, i);
Action::manager().store(oss.str());
}
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu(ICON_FA_CUT " Auto cut" )){
if (ImGuiToolkit::MenuItemIcon(14, 12, "Cut faded areas" ))
if (mp->timeline()->autoCut()){
oss << ": Cut faded areas";
Action::manager().store(oss.str());
}
ImGui::EndMenu();
}
if (Settings::application.render.gpu_decoding && ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware decoding"))
{
bool hwdec = !mp->softwareDecodingForced();
if (ImGui::MenuItem("Auto", "", &hwdec ))
mp->setSoftwareDecodingForced(false);
hwdec = mp->softwareDecodingForced();
if (ImGui::MenuItem("Disabled", "", &hwdec ))
mp->setSoftwareDecodingForced(true);
ImGui::EndMenu();
}
ImGui::EndPopup();
}
// restore buttons style
ImGui::PopStyleColor(5);
///
/// media player timelines
///
bottom += ImVec2(0, _buttons_height + _v_space);
ImGui::SetCursorScreenPos(bottom);
// ignore actual play status of mediaplayer when slider is pressed
if (!slider_pressed_)
media_playing_mode_ = mp->isPlaying();
// seek position
guint64 seek_t = mp->position();
@@ -2972,6 +2853,7 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
// scrolling sub-window
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(1.f, 1.f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.f);
ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImVec4(0.f, 0.f, 0.f, 0.0f));
ImVec2 scrollwindow = ImVec2(ImGui::GetContentRegionAvail().x - slider_zoom_width - 3.0,
2.f * _timeline_height + _scrollbar );
@@ -3063,6 +2945,135 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
ImGui::VSliderFloat("##TimelineZoom", ImVec2(slider_zoom_width, _timeline_height), &timeline_zoom, 1.0, 5.f, "");
ImGui::PopStyleVar(2);
ImGui::PopStyleColor(1);
///
/// media player buttons bar (custom)
///
bottom.x = top.x;
bottom.y += 2.f * _timeline_height + _scrollbar;
draw_list->AddRectFilled(bottom, bottom + ImVec2(rendersize.x, _buttons_height), ImGui::GetColorU32(ImGuiCol_FrameBg), _h_space);
// buttons style
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));
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.24f, 0.24f, 0.24f, 0.2f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.14f, 0.14f, 0.14f, 0.5f));
ImGui::SetCursorScreenPos(bottom + ImVec2(_h_space, _v_space) );
if (ImGui::Button(mp->playSpeed() > 0 ? ICON_FA_FAST_BACKWARD :ICON_FA_FAST_FORWARD))
mp->rewind();
// display buttons Play/Stop depending on current playing mode
ImGui::SameLine(0, _h_space);
if (media_playing_mode_) {
if (ImGui::Button(ICON_FA_PAUSE))
media_playing_mode_ = false;
ImGui::SameLine(0, _h_space);
ImGui::PushButtonRepeat(true);
if (ImGui::Button( mp->playSpeed() < 0 ? ICON_FA_BACKWARD :ICON_FA_FORWARD))
mp->jump ();
ImGui::PopButtonRepeat();
}
else {
if (ImGui::Button(ICON_FA_PLAY))
media_playing_mode_ = true;
ImGui::SameLine(0, _h_space);
ImGui::PushButtonRepeat(true);
if (ImGui::Button( mp->playSpeed() < 0 ? ICON_FA_STEP_BACKWARD : ICON_FA_STEP_FORWARD))
mp->step();
ImGui::PopButtonRepeat();
}
// loop modes button
ImGui::SameLine(0, _h_space);
static int current_loop = 0;
static std::vector< std::pair<int, int> > iconsloop = { {0,15}, {1,15}, {19,14} };
current_loop = (int) mp->loop();
if ( ImGuiToolkit::ButtonIconMultistate(iconsloop, &current_loop) )
mp->setLoop( (MediaPlayer::LoopMode) current_loop );
// speed slider (if enough space)
float speed = static_cast<float>(mp->playSpeed());
if ( rendersize.x > _min_width * 1.4f ) {
ImGui::SameLine(0, MAX(_h_space * 2.f, rendersize.x - _min_width * 1.6f) );
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - _buttons_height );
if (ImGui::DragFloat( "##Speed", &speed, 0.01f, -10.f, 10.f, "Speed " UNICODE_MULTIPLY " %.1f", 2.f))
mp->setPlaySpeed( static_cast<double>(speed) );
if (ImGui::IsItemDeactivatedAfterEdit()){
oss << ": Speed x" << std::setprecision(3) << speed;
Action::manager().store(oss.str());
}
}
///
/// Media Player context menu
///
ImGui::SameLine();
ImGui::SetCursorPosX(rendersize.x - _buttons_height / 1.5f);
// Timeline popup menu
if (ImGuiToolkit::IconButton(5,8) )
ImGui::OpenPopup( "MenuTimeline" );
if (ImGui::BeginPopup( "MenuTimeline" ))
{
if (ImGuiToolkit::MenuItemIcon(19,15,"Reset speed" )){
speed = 1.f;
mp->setPlaySpeed( static_cast<double>(speed) );
oss << ": Speed x1";
Action::manager().store(oss.str());
}
if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset timeline" )){
timeline_zoom = 1.f;
mp->timeline()->clearFading();
mp->timeline()->clearGaps();
oss << ": Reset timeline";
Action::manager().store(oss.str());
}
if (ImGui::BeginMenu(ICON_FA_RANDOM " Auto fading"))
{
const char* names[] = { "250 ms", "500 ms", "1 second", "2 seconds"};
for (int i = 0; i < IM_ARRAYSIZE(names); ++i) {
if (ImGui::MenuItem(names[i])) {
mp->timeline()->autoFading( 250 * (int ) pow(2, i) );
mp->timeline()->smoothFading( 2 * (i + 1) );
oss << ": Timeline Auto fading " << 250 * (int ) pow(2, i);
Action::manager().store(oss.str());
}
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu(ICON_FA_CUT " Auto cut" ))
{
if (ImGuiToolkit::MenuItemIcon(14, 12, "Cut faded areas" ))
if (mp->timeline()->autoCut()){
oss << ": Cut faded areas";
Action::manager().store(oss.str());
}
ImGui::EndMenu();
}
if (Settings::application.render.gpu_decoding && ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware decoding"))
{
bool hwdec = !mp->softwareDecodingForced();
if (ImGui::MenuItem("Auto", "", &hwdec ))
mp->setSoftwareDecodingForced(false);
hwdec = mp->softwareDecodingForced();
if (ImGui::MenuItem("Disabled", "", &hwdec ))
mp->setSoftwareDecodingForced(true);
ImGui::EndMenu();
}
ImGui::EndPopup();
}
// restore buttons style
ImGui::PopStyleColor(5);
///
/// media player timeline actions
@@ -3080,6 +3091,7 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
if ( mp->isPlaying() != media_play ) {
mp->play( media_play );
}
}
const char *SourceController::SourcePlayIcon(Source *s)