mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-12 10:49:59 +01:00
New SourcePlayer
Work in progress; Sources now have play/pause and associated play functions. Media player can play all playable sources, and adapts to control a media player when possible. Selection of play groups (to finalize)
This commit is contained in:
@@ -738,7 +738,7 @@ bool ImGuiToolkit::EditPlotLines(const char* label, float *array, int values_cou
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 *released, const ImVec2 size)
|
int values_count, float values_min, float values_max, bool cut, bool *released, const ImVec2 size)
|
||||||
{
|
{
|
||||||
bool array_changed = false;
|
bool array_changed = false;
|
||||||
|
|
||||||
@@ -764,9 +764,7 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
|||||||
*released = false;
|
*released = false;
|
||||||
|
|
||||||
// read user input and activate widget
|
// read user input and activate widget
|
||||||
const bool left_mouse_press = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
const bool mouse_press = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||||
const bool right_mouse_press = ImGui::IsMouseDown(ImGuiMouseButton_Right) | (ImGui::GetIO().KeyAlt & left_mouse_press) ;
|
|
||||||
const bool mouse_press = left_mouse_press | right_mouse_press;
|
|
||||||
const bool hovered = ImGui::ItemHoverable(bbox, id);
|
const bool hovered = ImGui::ItemHoverable(bbox, id);
|
||||||
bool temp_input_is_active = ImGui::TempInputIsActive(id);
|
bool temp_input_is_active = ImGui::TempInputIsActive(id);
|
||||||
if (!temp_input_is_active)
|
if (!temp_input_is_active)
|
||||||
@@ -805,7 +803,7 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array,
|
|||||||
if (previous_index == UINT32_MAX)
|
if (previous_index == UINT32_MAX)
|
||||||
previous_index = index;
|
previous_index = index;
|
||||||
|
|
||||||
if (right_mouse_press){
|
if (cut){
|
||||||
static float target_value = values_min;
|
static float target_value = values_min;
|
||||||
|
|
||||||
// toggle value histo
|
// toggle value histo
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace ImGuiToolkit
|
|||||||
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);
|
||||||
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 *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);
|
||||||
|
|
||||||
// fonts from ressources 'fonts/'
|
// fonts from ressources 'fonts/'
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -108,12 +108,38 @@ void MediaSource::setActive (bool on)
|
|||||||
{
|
{
|
||||||
bool was_active = active_;
|
bool was_active = active_;
|
||||||
|
|
||||||
|
// try to activate (may fail if source is cloned)
|
||||||
Source::setActive(on);
|
Source::setActive(on);
|
||||||
|
|
||||||
// change status of media player (only if status changed)
|
// change status of media player (only if status changed)
|
||||||
if ( active_ != was_active ) {
|
if ( active_ != was_active )
|
||||||
mediaplayer_->enable(active_);
|
mediaplayer_->enable(active_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MediaSource::playing () const
|
||||||
|
{
|
||||||
|
return mediaplayer_->isPlaying();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSource::play (bool on)
|
||||||
|
{
|
||||||
|
mediaplayer_->play(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaSource::playable () const
|
||||||
|
{
|
||||||
|
return !mediaplayer_->isImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSource::replay ()
|
||||||
|
{
|
||||||
|
mediaplayer_->rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
guint64 MediaSource::playtime () const
|
||||||
|
{
|
||||||
|
return mediaplayer_->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaSource::update(float dt)
|
void MediaSource::update(float dt)
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ public:
|
|||||||
// implementation of source API
|
// implementation of source API
|
||||||
void update (float dt) override;
|
void update (float dt) override;
|
||||||
void setActive (bool on) override;
|
void setActive (bool on) override;
|
||||||
|
bool playing () const override;
|
||||||
|
void play (bool) override;
|
||||||
|
bool playable () const override;
|
||||||
|
void replay () override;
|
||||||
|
guint64 playtime () const override;
|
||||||
void render() override;
|
void render() override;
|
||||||
bool failed() const override;
|
bool failed() const override;
|
||||||
uint texture() const override;
|
uint texture() const override;
|
||||||
|
|||||||
@@ -115,6 +115,22 @@ void MultiFile::close ()
|
|||||||
Stream::close();
|
Stream::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiFile::setIndex(int val)
|
||||||
|
{
|
||||||
|
if (src_) {
|
||||||
|
g_object_set (src_, "index", val, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MultiFile::index()
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
if (src_) {
|
||||||
|
g_object_get (src_, "index", &val, NULL);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
void MultiFile::setProperties (int begin, int end, int loop)
|
void MultiFile::setProperties (int begin, int end, int loop)
|
||||||
{
|
{
|
||||||
if (src_) {
|
if (src_) {
|
||||||
@@ -187,6 +203,27 @@ void MultiFileSource::setRange (int begin, int end)
|
|||||||
multifile()->setProperties (begin_, end_, loop_);
|
multifile()->setProperties (begin_, end_, loop_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiFileSource::replay ()
|
||||||
|
{
|
||||||
|
if (multifile()) {
|
||||||
|
multifile()->setIndex (begin_);
|
||||||
|
stream_->rewind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
guint64 MultiFileSource::playtime () const
|
||||||
|
{
|
||||||
|
guint64 time = 0;
|
||||||
|
|
||||||
|
if (multifile())
|
||||||
|
time += multifile()->index();
|
||||||
|
|
||||||
|
time *= GST_SECOND;
|
||||||
|
time /= framerate_;
|
||||||
|
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
void MultiFileSource::accept (Visitor& v)
|
void MultiFileSource::accept (Visitor& v)
|
||||||
{
|
{
|
||||||
Source::accept(v);
|
Source::accept(v);
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ public:
|
|||||||
// dynamic change of gstreamer multifile source properties
|
// dynamic change of gstreamer multifile source properties
|
||||||
void setProperties(int begin, int end, int loop);
|
void setProperties(int begin, int end, int loop);
|
||||||
|
|
||||||
|
// image index
|
||||||
|
int index();
|
||||||
|
void setIndex(int val);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GstElement *src_ ;
|
GstElement *src_ ;
|
||||||
};
|
};
|
||||||
@@ -42,6 +46,8 @@ public:
|
|||||||
|
|
||||||
// Source interface
|
// Source interface
|
||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
|
void replay () override;
|
||||||
|
guint64 playtime () const override;
|
||||||
|
|
||||||
// StreamSource interface
|
// StreamSource interface
|
||||||
Stream *stream () const override { return stream_; }
|
Stream *stream () const override { return stream_; }
|
||||||
|
|||||||
53
Session.cpp
53
Session.cpp
@@ -459,6 +459,59 @@ std::list<MixingGroup *>::iterator Session::endMixingGroup()
|
|||||||
return mixing_groups_.end();
|
return mixing_groups_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t Session::numPlayGroups() const
|
||||||
|
{
|
||||||
|
return play_groups_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::addPlayGroup(const SourceIdList &ids)
|
||||||
|
{
|
||||||
|
play_groups_.push_back( ids );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::addToPlayGroup(size_t i, Source *s)
|
||||||
|
{
|
||||||
|
if (i < play_groups_.size() )
|
||||||
|
{
|
||||||
|
if ( std::find(play_groups_[i].begin(), play_groups_[i].end(), s->id()) == play_groups_[i].end() )
|
||||||
|
play_groups_[i].push_back(s->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::removeFromPlayGroup(size_t i, Source *s)
|
||||||
|
{
|
||||||
|
if (i < play_groups_.size() )
|
||||||
|
{
|
||||||
|
if ( std::find(play_groups_[i].begin(), play_groups_[i].end(), s->id()) != play_groups_[i].end() )
|
||||||
|
play_groups_[i].remove( s->id() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::deletePlayGroup(size_t i)
|
||||||
|
{
|
||||||
|
if (i < play_groups_.size() )
|
||||||
|
play_groups_.erase( play_groups_.begin() + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceList Session::playGroup(size_t i) const
|
||||||
|
{
|
||||||
|
SourceList list;
|
||||||
|
|
||||||
|
if (i < play_groups_.size() )
|
||||||
|
{
|
||||||
|
for (auto sid = play_groups_[i].begin(); sid != play_groups_[i].end(); ++sid){
|
||||||
|
|
||||||
|
SourceList::const_iterator it = std::find_if(sources_.begin(), sources_.end(), Source::hasId( *sid));;
|
||||||
|
if ( it != sources_.end())
|
||||||
|
list.push_back( *it);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
void Session::lock()
|
void Session::lock()
|
||||||
{
|
{
|
||||||
access_.lock();
|
access_.lock();
|
||||||
|
|||||||
10
Session.h
10
Session.h
@@ -126,6 +126,15 @@ public:
|
|||||||
// snapshots
|
// snapshots
|
||||||
SessionSnapshots * const snapshots () { return &snapshots_; }
|
SessionSnapshots * const snapshots () { return &snapshots_; }
|
||||||
|
|
||||||
|
// playlists
|
||||||
|
void addPlayGroup(const SourceIdList &ids);
|
||||||
|
void deletePlayGroup(size_t i);
|
||||||
|
size_t numPlayGroups() const;
|
||||||
|
SourceList playGroup(size_t i) const;
|
||||||
|
void addToPlayGroup(size_t i, Source *s);
|
||||||
|
void removeFromPlayGroup(size_t i, Source *s);
|
||||||
|
std::vector<SourceIdList> getPlayGroups() { return play_groups_; }
|
||||||
|
|
||||||
// lock and unlock access (e.g. while saving)
|
// lock and unlock access (e.g. while saving)
|
||||||
void lock ();
|
void lock ();
|
||||||
void unlock ();
|
void unlock ();
|
||||||
@@ -141,6 +150,7 @@ protected:
|
|||||||
std::list<MixingGroup *> mixing_groups_;
|
std::list<MixingGroup *> mixing_groups_;
|
||||||
std::map<View::Mode, Group*> config_;
|
std::map<View::Mode, Group*> config_;
|
||||||
SessionSnapshots snapshots_;
|
SessionSnapshots snapshots_;
|
||||||
|
std::vector<SourceIdList> play_groups_;
|
||||||
float fading_target_;
|
float fading_target_;
|
||||||
std::mutex access_;
|
std::mutex access_;
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,9 @@ void SessionCreator::load(const std::string& filename)
|
|||||||
// load notes
|
// load notes
|
||||||
loadNotes( xmlDoc_.FirstChildElement("Notes") );
|
loadNotes( xmlDoc_.FirstChildElement("Notes") );
|
||||||
|
|
||||||
|
// load playlists
|
||||||
|
loadPlayGroups( xmlDoc_.FirstChildElement("PlayGroups") );
|
||||||
|
|
||||||
// all good
|
// all good
|
||||||
session_->setFilename(filename);
|
session_->setFilename(filename);
|
||||||
}
|
}
|
||||||
@@ -163,7 +166,8 @@ void SessionCreator::loadNotes(XMLElement *notesNode)
|
|||||||
XMLElement *sizeNode = note->FirstChildElement("size");
|
XMLElement *sizeNode = note->FirstChildElement("size");
|
||||||
if (sizeNode) tinyxml2::XMLElementToGLM( sizeNode->FirstChildElement("vec2"), N.size);
|
if (sizeNode) tinyxml2::XMLElementToGLM( sizeNode->FirstChildElement("vec2"), N.size);
|
||||||
XMLElement* contentNode = note->FirstChildElement("text");
|
XMLElement* contentNode = note->FirstChildElement("text");
|
||||||
if (contentNode) N.text = std::string ( contentNode->GetText() );
|
if (contentNode && contentNode->GetText())
|
||||||
|
N.text = std::string ( contentNode->GetText() );
|
||||||
|
|
||||||
session_->addNote(N);
|
session_->addNote(N);
|
||||||
}
|
}
|
||||||
@@ -171,6 +175,29 @@ void SessionCreator::loadNotes(XMLElement *notesNode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionCreator::loadPlayGroups(tinyxml2::XMLElement *playgroupNode)
|
||||||
|
{
|
||||||
|
if (playgroupNode != nullptr && session_ != nullptr) {
|
||||||
|
|
||||||
|
XMLElement* playgroup = playgroupNode->FirstChildElement("PlayGroup");
|
||||||
|
for( ; playgroup ; playgroup = playgroup->NextSiblingElement())
|
||||||
|
{
|
||||||
|
SourceIdList playgroup_sources;
|
||||||
|
|
||||||
|
XMLElement* playgroupSourceNode = playgroup->FirstChildElement("source");
|
||||||
|
for ( ; playgroupSourceNode ; playgroupSourceNode = playgroupSourceNode->NextSiblingElement()) {
|
||||||
|
uint64_t id__ = 0;
|
||||||
|
playgroupSourceNode->QueryUnsigned64Attribute("id", &id__);
|
||||||
|
|
||||||
|
if (sources_id_.count(id__) > 0)
|
||||||
|
playgroup_sources.push_back( id__ );
|
||||||
|
|
||||||
|
}
|
||||||
|
session_->addPlayGroup( playgroup_sources );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SessionLoader::SessionLoader(): Visitor(),
|
SessionLoader::SessionLoader(): Visitor(),
|
||||||
session_(nullptr), xmlCurrent_(nullptr), recursion_(0)
|
session_(nullptr), xmlCurrent_(nullptr), recursion_(0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ class SessionCreator : public SessionLoader {
|
|||||||
|
|
||||||
void loadConfig(tinyxml2::XMLElement *viewsNode);
|
void loadConfig(tinyxml2::XMLElement *viewsNode);
|
||||||
void loadNotes(tinyxml2::XMLElement *notesNode);
|
void loadNotes(tinyxml2::XMLElement *notesNode);
|
||||||
|
void loadPlayGroups(tinyxml2::XMLElement *playlistsNode);
|
||||||
void loadSnapshots(tinyxml2::XMLElement *snapshotNode);
|
void loadSnapshots(tinyxml2::XMLElement *snapshotNode);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#include "Mixer.h"
|
#include "Mixer.h"
|
||||||
|
|
||||||
|
|
||||||
SessionSource::SessionSource(uint64_t id) : Source(id), failed_(false)
|
SessionSource::SessionSource(uint64_t id) : Source(id), failed_(false), timer_(0), paused_(false)
|
||||||
{
|
{
|
||||||
session_ = new Session;
|
session_ = new Session;
|
||||||
}
|
}
|
||||||
@@ -62,11 +62,11 @@ uint SessionSource::texture() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SessionSource::setActive (bool on)
|
void SessionSource::setActive (bool on)
|
||||||
{
|
{
|
||||||
Source::setActive(on);
|
Source::setActive(on);
|
||||||
|
|
||||||
// change status of session (recursive change of internal sources)
|
// change status of session (recursive change of internal sources)
|
||||||
if (session_ != nullptr)
|
if (session_)
|
||||||
session_->setActive(active_);
|
session_->setActive(active_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +76,10 @@ void SessionSource::update(float dt)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// update content
|
// update content
|
||||||
if (active_)
|
if (active_ && !paused_) {
|
||||||
session_->update(dt);
|
session_->update(dt);
|
||||||
|
timer_ += guint64(dt * 1000.f) * GST_USECOND;
|
||||||
|
}
|
||||||
|
|
||||||
// delete a source which failed
|
// delete a source which failed
|
||||||
if (session_->failedSource() != nullptr) {
|
if (session_->failedSource() != nullptr) {
|
||||||
@@ -90,6 +92,15 @@ void SessionSource::update(float dt)
|
|||||||
Source::update(dt);
|
Source::update(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionSource::replay ()
|
||||||
|
{
|
||||||
|
if (session_) {
|
||||||
|
for( SourceList::iterator it = session_->begin(); it != session_->end(); ++it)
|
||||||
|
(*it)->replay();
|
||||||
|
timer_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SessionFileSource::SessionFileSource(uint64_t id) : SessionSource(id), path_(""), initialized_(false), wait_for_sources_(false)
|
SessionFileSource::SessionFileSource(uint64_t id) : SessionSource(id), path_(""), initialized_(false), wait_for_sources_(false)
|
||||||
{
|
{
|
||||||
@@ -150,6 +161,7 @@ void SessionFileSource::load(const std::string &p, uint recursion)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// will be ready after init and one frame rendered
|
// will be ready after init and one frame rendered
|
||||||
|
initialized_ = false;
|
||||||
ready_ = false;
|
ready_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +344,7 @@ RenderSource::RenderSource(uint64_t id) : Source(id), session_(nullptr)
|
|||||||
|
|
||||||
bool RenderSource::failed() const
|
bool RenderSource::failed() const
|
||||||
{
|
{
|
||||||
if ( mode_ > Source::UNINITIALIZED && session_!=nullptr )
|
if ( renderbuffer_ != nullptr && session_ != nullptr )
|
||||||
return renderbuffer_->resolution() != session_->frame()->resolution();
|
return renderbuffer_->resolution() != session_->frame()->resolution();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -372,7 +384,7 @@ void RenderSource::init()
|
|||||||
|
|
||||||
glm::vec3 RenderSource::resolution() const
|
glm::vec3 RenderSource::resolution() const
|
||||||
{
|
{
|
||||||
if (mode_ > Source::UNINITIALIZED)
|
if (renderbuffer_ != nullptr)
|
||||||
return renderbuffer_->resolution();
|
return renderbuffer_->resolution();
|
||||||
else if (session_ && session_->frame())
|
else if (session_ && session_->frame())
|
||||||
return session_->frame()->resolution();
|
return session_->frame()->resolution();
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ public:
|
|||||||
// implementation of source API
|
// implementation of source API
|
||||||
void update (float dt) override;
|
void update (float dt) override;
|
||||||
void setActive (bool on) override;
|
void setActive (bool on) override;
|
||||||
|
bool playing () const override { return !paused_; }
|
||||||
|
void play (bool on) override { paused_ = !on; }
|
||||||
|
bool playable () const override { return true; }
|
||||||
|
guint64 playtime () const override { return timer_; }
|
||||||
|
void replay () override;
|
||||||
bool failed () const override;
|
bool failed () const override;
|
||||||
uint texture () const override;
|
uint texture () const override;
|
||||||
|
|
||||||
@@ -24,6 +29,8 @@ protected:
|
|||||||
|
|
||||||
Session *session_;
|
Session *session_;
|
||||||
std::atomic<bool> failed_;
|
std::atomic<bool> failed_;
|
||||||
|
guint64 timer_;
|
||||||
|
bool paused_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SessionFileSource : public SessionSource
|
class SessionFileSource : public SessionSource
|
||||||
@@ -80,6 +87,9 @@ public:
|
|||||||
RenderSource(uint64_t id = 0);
|
RenderSource(uint64_t id = 0);
|
||||||
|
|
||||||
// implementation of source API
|
// implementation of source API
|
||||||
|
bool playing () const override { return true; }
|
||||||
|
void play (bool) override {}
|
||||||
|
bool playable () const override { return false; }
|
||||||
bool failed () const override;
|
bool failed () const override;
|
||||||
uint texture() const override;
|
uint texture() const override;
|
||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
|
|||||||
@@ -58,63 +58,109 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
|
|||||||
delete thumbnail;
|
delete thumbnail;
|
||||||
|
|
||||||
// 2. config of views
|
// 2. config of views
|
||||||
XMLElement *views = xmlDoc.NewElement("Views");
|
saveConfig( &xmlDoc, session );
|
||||||
xmlDoc.InsertEndChild(views);
|
|
||||||
{
|
|
||||||
XMLElement *mixing = xmlDoc.NewElement( "Mixing" );
|
|
||||||
mixing->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::MIXING), &xmlDoc));
|
|
||||||
views->InsertEndChild(mixing);
|
|
||||||
|
|
||||||
XMLElement *geometry = xmlDoc.NewElement( "Geometry" );
|
|
||||||
geometry->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::GEOMETRY), &xmlDoc));
|
|
||||||
views->InsertEndChild(geometry);
|
|
||||||
|
|
||||||
XMLElement *layer = xmlDoc.NewElement( "Layer" );
|
|
||||||
layer->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::LAYER), &xmlDoc));
|
|
||||||
views->InsertEndChild(layer);
|
|
||||||
|
|
||||||
XMLElement *appearance = xmlDoc.NewElement( "Texture" );
|
|
||||||
appearance->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::TEXTURE), &xmlDoc));
|
|
||||||
views->InsertEndChild(appearance);
|
|
||||||
|
|
||||||
XMLElement *render = xmlDoc.NewElement( "Rendering" );
|
|
||||||
render->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::RENDERING), &xmlDoc));
|
|
||||||
views->InsertEndChild(render);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. snapshots
|
// 3. snapshots
|
||||||
XMLElement *snapshots = xmlDoc.NewElement("Snapshots");
|
saveSnapshots( &xmlDoc, session );
|
||||||
const XMLElement* N = session->snapshots()->xmlDoc_->FirstChildElement();
|
|
||||||
for( ; N ; N=N->NextSiblingElement())
|
|
||||||
snapshots->InsertEndChild( N->DeepClone( &xmlDoc ));
|
|
||||||
xmlDoc.InsertEndChild(snapshots);
|
|
||||||
|
|
||||||
// 4. optional notes
|
// 4. optional notes
|
||||||
XMLElement *notes = xmlDoc.NewElement("Notes");
|
saveNotes( &xmlDoc, session );
|
||||||
xmlDoc.InsertEndChild(notes);
|
|
||||||
for (auto nit = session->beginNotes(); nit != session->endNotes(); ++nit) {
|
|
||||||
XMLElement *note = xmlDoc.NewElement( "Note" );
|
|
||||||
note->SetAttribute("large", (*nit).large );
|
|
||||||
note->SetAttribute("stick", (*nit).stick );
|
|
||||||
XMLElement *pos = xmlDoc.NewElement("pos");
|
|
||||||
pos->InsertEndChild( XMLElementFromGLM(&xmlDoc, (*nit).pos) );
|
|
||||||
note->InsertEndChild(pos);
|
|
||||||
XMLElement *size = xmlDoc.NewElement("size");
|
|
||||||
size->InsertEndChild( XMLElementFromGLM(&xmlDoc, (*nit).size) );
|
|
||||||
note->InsertEndChild(size);
|
|
||||||
XMLElement *content = xmlDoc.NewElement("text");
|
|
||||||
XMLText *text = xmlDoc.NewText( (*nit).text.c_str() );
|
|
||||||
content->InsertEndChild( text );
|
|
||||||
note->InsertEndChild(content);
|
|
||||||
|
|
||||||
notes->InsertEndChild(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 5. optional playlists
|
||||||
|
savePlayGroups( &xmlDoc, session );
|
||||||
|
|
||||||
// save file to disk
|
// save file to disk
|
||||||
return ( XMLSaveDoc(&xmlDoc, filename) );
|
return ( XMLSaveDoc(&xmlDoc, filename) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionVisitor::saveConfig(tinyxml2::XMLDocument *doc, Session *session)
|
||||||
|
{
|
||||||
|
if (doc != nullptr && session != nullptr)
|
||||||
|
{
|
||||||
|
XMLElement *views = doc->NewElement("Views");
|
||||||
|
|
||||||
|
XMLElement *mixing = doc->NewElement( "Mixing" );
|
||||||
|
mixing->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::MIXING), doc));
|
||||||
|
views->InsertEndChild(mixing);
|
||||||
|
|
||||||
|
XMLElement *geometry = doc->NewElement( "Geometry" );
|
||||||
|
geometry->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::GEOMETRY), doc));
|
||||||
|
views->InsertEndChild(geometry);
|
||||||
|
|
||||||
|
XMLElement *layer = doc->NewElement( "Layer" );
|
||||||
|
layer->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::LAYER), doc));
|
||||||
|
views->InsertEndChild(layer);
|
||||||
|
|
||||||
|
XMLElement *appearance = doc->NewElement( "Texture" );
|
||||||
|
appearance->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::TEXTURE), doc));
|
||||||
|
views->InsertEndChild(appearance);
|
||||||
|
|
||||||
|
XMLElement *render = doc->NewElement( "Rendering" );
|
||||||
|
render->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::RENDERING), doc));
|
||||||
|
views->InsertEndChild(render);
|
||||||
|
|
||||||
|
doc->InsertEndChild(views);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionVisitor::saveSnapshots(tinyxml2::XMLDocument *doc, Session *session)
|
||||||
|
{
|
||||||
|
if (doc != nullptr && session != nullptr)
|
||||||
|
{
|
||||||
|
XMLElement *snapshots = doc->NewElement("Snapshots");
|
||||||
|
const XMLElement* N = session->snapshots()->xmlDoc_->FirstChildElement();
|
||||||
|
for( ; N ; N=N->NextSiblingElement())
|
||||||
|
snapshots->InsertEndChild( N->DeepClone( doc ));
|
||||||
|
doc->InsertEndChild(snapshots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionVisitor::saveNotes(tinyxml2::XMLDocument *doc, Session *session)
|
||||||
|
{
|
||||||
|
if (doc != nullptr && session != nullptr)
|
||||||
|
{
|
||||||
|
XMLElement *notes = doc->NewElement("Notes");
|
||||||
|
for (auto nit = session->beginNotes(); nit != session->endNotes(); ++nit) {
|
||||||
|
XMLElement *note = doc->NewElement( "Note" );
|
||||||
|
note->SetAttribute("large", (*nit).large );
|
||||||
|
note->SetAttribute("stick", (*nit).stick );
|
||||||
|
XMLElement *pos = doc->NewElement("pos");
|
||||||
|
pos->InsertEndChild( XMLElementFromGLM(doc, (*nit).pos) );
|
||||||
|
note->InsertEndChild(pos);
|
||||||
|
XMLElement *size = doc->NewElement("size");
|
||||||
|
size->InsertEndChild( XMLElementFromGLM(doc, (*nit).size) );
|
||||||
|
note->InsertEndChild(size);
|
||||||
|
XMLElement *content = doc->NewElement("text");
|
||||||
|
XMLText *text = doc->NewText( (*nit).text.c_str() );
|
||||||
|
content->InsertEndChild( text );
|
||||||
|
note->InsertEndChild(content);
|
||||||
|
|
||||||
|
notes->InsertEndChild(note);
|
||||||
|
}
|
||||||
|
doc->InsertEndChild(notes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionVisitor::savePlayGroups(tinyxml2::XMLDocument *doc, Session *session)
|
||||||
|
{
|
||||||
|
if (doc != nullptr && session != nullptr)
|
||||||
|
{
|
||||||
|
XMLElement *playlistNode = doc->NewElement("PlayGroups");
|
||||||
|
std::vector<SourceIdList> pl = session->getPlayGroups();
|
||||||
|
for (auto plit = pl.begin(); plit != pl.end(); ++plit) {
|
||||||
|
XMLElement *list = doc->NewElement("PlayGroup");
|
||||||
|
playlistNode->InsertEndChild(list);
|
||||||
|
for (auto id = plit->begin(); id != plit->end(); ++id) {
|
||||||
|
XMLElement *sour = doc->NewElement("source");
|
||||||
|
sour->SetAttribute("id", *id);
|
||||||
|
list->InsertEndChild(sour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doc->InsertEndChild(playlistNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SessionVisitor::SessionVisitor(tinyxml2::XMLDocument *doc,
|
SessionVisitor::SessionVisitor(tinyxml2::XMLDocument *doc,
|
||||||
tinyxml2::XMLElement *root,
|
tinyxml2::XMLElement *root,
|
||||||
bool recursive) : Visitor(), recursive_(recursive), xmlCurrent_(root)
|
bool recursive) : Visitor(), recursive_(recursive), xmlCurrent_(root)
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ class SessionVisitor : public Visitor {
|
|||||||
tinyxml2::XMLDocument *xmlDoc_;
|
tinyxml2::XMLDocument *xmlDoc_;
|
||||||
tinyxml2::XMLElement *xmlCurrent_;
|
tinyxml2::XMLElement *xmlCurrent_;
|
||||||
|
|
||||||
|
static void saveConfig(tinyxml2::XMLDocument *doc, Session *session);
|
||||||
|
static void saveSnapshots(tinyxml2::XMLDocument *doc, Session *session);
|
||||||
|
static void saveNotes(tinyxml2::XMLDocument *doc, Session *session);
|
||||||
|
static void savePlayGroups(tinyxml2::XMLDocument *doc, Session *session);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SessionVisitor(tinyxml2::XMLDocument *doc = nullptr,
|
SessionVisitor(tinyxml2::XMLDocument *doc = nullptr,
|
||||||
tinyxml2::XMLElement *root = nullptr,
|
tinyxml2::XMLElement *root = nullptr,
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ void Settings::Save()
|
|||||||
widgetsNode->SetAttribute("preview", application.widget.preview);
|
widgetsNode->SetAttribute("preview", application.widget.preview);
|
||||||
widgetsNode->SetAttribute("history", application.widget.history);
|
widgetsNode->SetAttribute("history", application.widget.history);
|
||||||
widgetsNode->SetAttribute("media_player", application.widget.media_player);
|
widgetsNode->SetAttribute("media_player", application.widget.media_player);
|
||||||
|
widgetsNode->SetAttribute("timeline_editmode", application.widget.timeline_editmode);
|
||||||
widgetsNode->SetAttribute("shader_editor", application.widget.shader_editor);
|
widgetsNode->SetAttribute("shader_editor", application.widget.shader_editor);
|
||||||
widgetsNode->SetAttribute("stats", application.widget.stats);
|
widgetsNode->SetAttribute("stats", application.widget.stats);
|
||||||
widgetsNode->SetAttribute("stats_mode", application.widget.stats_mode);
|
widgetsNode->SetAttribute("stats_mode", application.widget.stats_mode);
|
||||||
@@ -270,6 +271,7 @@ void Settings::Load()
|
|||||||
widgetsNode->QueryBoolAttribute("preview", &application.widget.preview);
|
widgetsNode->QueryBoolAttribute("preview", &application.widget.preview);
|
||||||
widgetsNode->QueryBoolAttribute("history", &application.widget.history);
|
widgetsNode->QueryBoolAttribute("history", &application.widget.history);
|
||||||
widgetsNode->QueryBoolAttribute("media_player", &application.widget.media_player);
|
widgetsNode->QueryBoolAttribute("media_player", &application.widget.media_player);
|
||||||
|
widgetsNode->QueryBoolAttribute("timeline_editmode", &application.widget.timeline_editmode);
|
||||||
widgetsNode->QueryBoolAttribute("shader_editor", &application.widget.shader_editor);
|
widgetsNode->QueryBoolAttribute("shader_editor", &application.widget.shader_editor);
|
||||||
widgetsNode->QueryBoolAttribute("stats", &application.widget.stats);
|
widgetsNode->QueryBoolAttribute("stats", &application.widget.stats);
|
||||||
widgetsNode->QueryIntAttribute("stats_mode", &application.widget.stats_mode);
|
widgetsNode->QueryIntAttribute("stats_mode", &application.widget.stats_mode);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ struct WidgetsConfig
|
|||||||
bool history;
|
bool history;
|
||||||
bool media_player;
|
bool media_player;
|
||||||
bool media_player_view;
|
bool media_player_view;
|
||||||
|
bool timeline_editmode;
|
||||||
bool shader_editor;
|
bool shader_editor;
|
||||||
bool toolbox;
|
bool toolbox;
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ struct WidgetsConfig
|
|||||||
history = false;
|
history = false;
|
||||||
media_player = false;
|
media_player = false;
|
||||||
media_player_view = true;
|
media_player_view = true;
|
||||||
|
timeline_editmode = false;
|
||||||
shader_editor = false;
|
shader_editor = false;
|
||||||
toolbox = false;
|
toolbox = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -871,7 +871,6 @@ void CloneSource::setActive (bool on)
|
|||||||
origin_->touch();
|
origin_->touch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint CloneSource::texture() const
|
uint CloneSource::texture() const
|
||||||
{
|
{
|
||||||
if (origin_ != nullptr)
|
if (origin_ != nullptr)
|
||||||
|
|||||||
11
Source.h
11
Source.h
@@ -139,6 +139,13 @@ public:
|
|||||||
} Workspace;
|
} Workspace;
|
||||||
inline Workspace workspace () const { return workspace_; }
|
inline Workspace workspace () const { return workspace_; }
|
||||||
|
|
||||||
|
// a Source shall define a way to play
|
||||||
|
virtual bool playable () const = 0;
|
||||||
|
virtual bool playing () const = 0;
|
||||||
|
virtual void play (bool on) = 0;
|
||||||
|
virtual void replay () {}
|
||||||
|
virtual guint64 playtime () const { return 0; }
|
||||||
|
|
||||||
// a Source shall informs if the source failed (i.e. shall be deleted)
|
// a Source shall informs if the source failed (i.e. shall be deleted)
|
||||||
virtual bool failed () const = 0;
|
virtual bool failed () const = 0;
|
||||||
|
|
||||||
@@ -299,6 +306,10 @@ public:
|
|||||||
|
|
||||||
// implementation of source API
|
// implementation of source API
|
||||||
void setActive (bool on) override;
|
void setActive (bool on) override;
|
||||||
|
bool playing () const override { return true; }
|
||||||
|
void play (bool) override {}
|
||||||
|
bool playable () const override { return false; }
|
||||||
|
void replay () override {}
|
||||||
uint texture() const override;
|
uint texture() const override;
|
||||||
bool failed() const override { return origin_ == nullptr; }
|
bool failed() const override { return origin_ == nullptr; }
|
||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
|
|||||||
@@ -14,6 +14,18 @@ bool compare_depth (Source * first, Source * second)
|
|||||||
return ( first->depth() < second->depth() );
|
return ( first->depth() < second->depth() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool notplayable (const Source *s) { return !s->playable(); }
|
||||||
|
|
||||||
|
SourceList playable_only (const SourceList &list)
|
||||||
|
{
|
||||||
|
SourceList pl = list;
|
||||||
|
|
||||||
|
pl.remove_if(notplayable);
|
||||||
|
|
||||||
|
return pl;
|
||||||
|
}
|
||||||
|
|
||||||
SourceList depth_sorted(const SourceList &list)
|
SourceList depth_sorted(const SourceList &list)
|
||||||
{
|
{
|
||||||
SourceList sl = list;
|
SourceList sl = list;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class Session;
|
|||||||
typedef std::list<Source *> SourceList;
|
typedef std::list<Source *> SourceList;
|
||||||
typedef std::list<SourceCore *> SourceCoreList;
|
typedef std::list<SourceCore *> SourceCoreList;
|
||||||
|
|
||||||
|
SourceList playable_only (const SourceList &list);
|
||||||
SourceList depth_sorted (const SourceList &list);
|
SourceList depth_sorted (const SourceList &list);
|
||||||
SourceList mixing_sorted (const SourceList &list, glm::vec2 center = glm::vec2(0.f, 0.f));
|
SourceList mixing_sorted (const SourceList &list, glm::vec2 center = glm::vec2(0.f, 0.f));
|
||||||
SourceList intersect (const SourceList &first, const SourceList &second);
|
SourceList intersect (const SourceList &first, const SourceList &second);
|
||||||
|
|||||||
23
Stream.cpp
23
Stream.cpp
@@ -31,6 +31,7 @@ Stream::Stream()
|
|||||||
opened_ = false;
|
opened_ = false;
|
||||||
enabled_ = true;
|
enabled_ = true;
|
||||||
desired_state_ = GST_STATE_PAUSED;
|
desired_state_ = GST_STATE_PAUSED;
|
||||||
|
position_ = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
width_ = -1;
|
width_ = -1;
|
||||||
height_ = -1;
|
height_ = -1;
|
||||||
@@ -371,7 +372,26 @@ bool Stream::isPlaying(bool testpipeline) const
|
|||||||
return state == GST_STATE_PLAYING;
|
return state == GST_STATE_PLAYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stream::rewind()
|
||||||
|
{
|
||||||
|
if ( pipeline_ == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
GstEvent *seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
|
||||||
|
GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_END, 0);
|
||||||
|
gst_element_send_event(pipeline_, seek_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
GstClockTime Stream::position()
|
||||||
|
{
|
||||||
|
if (position_ == GST_CLOCK_TIME_NONE && pipeline_ != nullptr) {
|
||||||
|
gint64 p = GST_CLOCK_TIME_NONE;
|
||||||
|
if ( gst_element_query_position (pipeline_, GST_FORMAT_TIME, &p) )
|
||||||
|
position_ = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return position_;
|
||||||
|
}
|
||||||
|
|
||||||
void Stream::init_texture(guint index)
|
void Stream::init_texture(guint index)
|
||||||
{
|
{
|
||||||
@@ -545,6 +565,9 @@ void Stream::update()
|
|||||||
frame_[read_index].unmap();
|
frame_[read_index].unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we just displayed a vframe : set position time to frame PTS
|
||||||
|
position_ = frame_[read_index].position;
|
||||||
|
|
||||||
// avoid reading it again
|
// avoid reading it again
|
||||||
frame_[read_index].status = INVALID;
|
frame_[read_index].status = INVALID;
|
||||||
}
|
}
|
||||||
|
|||||||
9
Stream.h
9
Stream.h
@@ -83,6 +83,14 @@ public:
|
|||||||
* Performs a full check of the Gstreamer pipeline if testpipeline is true
|
* Performs a full check of the Gstreamer pipeline if testpipeline is true
|
||||||
* */
|
* */
|
||||||
bool isPlaying(bool testpipeline = false) const;
|
bool isPlaying(bool testpipeline = false) const;
|
||||||
|
/**
|
||||||
|
* Attempt to restart
|
||||||
|
* */
|
||||||
|
virtual void rewind();
|
||||||
|
/**
|
||||||
|
* Get position time
|
||||||
|
* */
|
||||||
|
virtual GstClockTime position();
|
||||||
/**
|
/**
|
||||||
* Get rendering update framerate
|
* Get rendering update framerate
|
||||||
* measured during play
|
* measured during play
|
||||||
@@ -126,6 +134,7 @@ protected:
|
|||||||
bool live_;
|
bool live_;
|
||||||
|
|
||||||
// GST & Play status
|
// GST & Play status
|
||||||
|
GstClockTime position_;
|
||||||
GstState desired_state_;
|
GstState desired_state_;
|
||||||
GstElement *pipeline_;
|
GstElement *pipeline_;
|
||||||
GstVideoInfo v_frame_video_info_;
|
GstVideoInfo v_frame_video_info_;
|
||||||
|
|||||||
@@ -102,13 +102,49 @@ void StreamSource::setActive (bool on)
|
|||||||
{
|
{
|
||||||
bool was_active = active_;
|
bool was_active = active_;
|
||||||
|
|
||||||
|
// try to activate (may fail if source is cloned)
|
||||||
Source::setActive(on);
|
Source::setActive(on);
|
||||||
|
|
||||||
// change status of media player (only if status changed)
|
// change status of stream (only if status changed)
|
||||||
if ( active_ != was_active ) {
|
if ( stream_ && active_ != was_active )
|
||||||
if (stream_)
|
stream_->enable(active_);
|
||||||
stream_->enable(active_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool StreamSource::playing () const
|
||||||
|
{
|
||||||
|
if ( stream_ )
|
||||||
|
return stream_->isPlaying();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamSource::play (bool on)
|
||||||
|
{
|
||||||
|
if ( stream_ )
|
||||||
|
stream_->play(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool StreamSource::playable () const
|
||||||
|
{
|
||||||
|
if ( stream_ )
|
||||||
|
return !stream_->singleFrame();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamSource::replay ()
|
||||||
|
{
|
||||||
|
if ( stream_ )
|
||||||
|
stream_->rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
guint64 StreamSource::playtime () const
|
||||||
|
{
|
||||||
|
if ( stream_ )
|
||||||
|
return stream_->position();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamSource::update(float dt)
|
void StreamSource::update(float dt)
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ public:
|
|||||||
// implementation of source API
|
// implementation of source API
|
||||||
void update (float dt) override;
|
void update (float dt) override;
|
||||||
void setActive (bool on) override;
|
void setActive (bool on) override;
|
||||||
|
bool playing () const override;
|
||||||
|
void play (bool) override;
|
||||||
|
bool playable () const override;
|
||||||
|
void replay () override;
|
||||||
|
guint64 playtime () const override;
|
||||||
bool failed() const override;
|
bool failed() const override;
|
||||||
uint texture() const override;
|
uint texture() const override;
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ static TextEditor editor;
|
|||||||
|
|
||||||
#include "UserInterfaceManager.h"
|
#include "UserInterfaceManager.h"
|
||||||
#define PLOT_ARRAY_SIZE 180
|
#define PLOT_ARRAY_SIZE 180
|
||||||
#define LABEL_AUTO_MEDIA_PLAYER "Active source"
|
#define LABEL_AUTO_MEDIA_PLAYER "Selected sources"
|
||||||
|
|
||||||
// utility functions
|
// utility functions
|
||||||
void ShowAboutGStreamer(bool* p_open);
|
void ShowAboutGStreamer(bool* p_open);
|
||||||
@@ -141,7 +141,6 @@ bool UserInterface::Init()
|
|||||||
ImGuiToolkit::SetFont(ImGuiToolkit::FONT_BOLD, "Roboto-Bold", int(base_font_size) );
|
ImGuiToolkit::SetFont(ImGuiToolkit::FONT_BOLD, "Roboto-Bold", int(base_font_size) );
|
||||||
ImGuiToolkit::SetFont(ImGuiToolkit::FONT_ITALIC, "Roboto-Italic", int(base_font_size) );
|
ImGuiToolkit::SetFont(ImGuiToolkit::FONT_ITALIC, "Roboto-Italic", int(base_font_size) );
|
||||||
ImGuiToolkit::SetFont(ImGuiToolkit::FONT_MONO, "Hack-Regular", int(base_font_size) - 2);
|
ImGuiToolkit::SetFont(ImGuiToolkit::FONT_MONO, "Hack-Regular", int(base_font_size) - 2);
|
||||||
// font for Navigator = 1.5 x base size (with low oversampling)
|
|
||||||
ImGuiToolkit::SetFont(ImGuiToolkit::FONT_LARGE, "Hack-Regular", MIN(int(base_font_size * 1.5f), 50), 1 );
|
ImGuiToolkit::SetFont(ImGuiToolkit::FONT_LARGE, "Hack-Regular", MIN(int(base_font_size * 1.5f), 50), 1 );
|
||||||
|
|
||||||
// info
|
// info
|
||||||
@@ -216,10 +215,10 @@ void UserInterface::handleKeyboard()
|
|||||||
// New Session
|
// New Session
|
||||||
Mixer::manager().close();
|
Mixer::manager().close();
|
||||||
}
|
}
|
||||||
// else if (ImGui::IsKeyPressed( GLFW_KEY_SPACE )) {
|
else if (ImGui::IsKeyPressed( GLFW_KEY_SPACE )) {
|
||||||
// // New Session
|
// New Session
|
||||||
// Mixer::manager().session()->setActive( !Mixer::manager().session()->active() );
|
Mixer::manager().session()->setActive( !Mixer::manager().session()->active() );
|
||||||
// }
|
}
|
||||||
else if (ImGui::IsKeyPressed( GLFW_KEY_L )) {
|
else if (ImGui::IsKeyPressed( GLFW_KEY_L )) {
|
||||||
// Logs
|
// Logs
|
||||||
Settings::application.widget.logs = !Settings::application.widget.logs;
|
Settings::application.widget.logs = !Settings::application.widget.logs;
|
||||||
@@ -752,7 +751,8 @@ void UserInterface::Render()
|
|||||||
if (Settings::application.widget.history)
|
if (Settings::application.widget.history)
|
||||||
RenderHistory();
|
RenderHistory();
|
||||||
if (Settings::application.widget.media_player)
|
if (Settings::application.widget.media_player)
|
||||||
mediacontrol.Render();
|
sourcecontrol.Render();
|
||||||
|
// mediacontrol.Render();
|
||||||
if (Settings::application.widget.shader_editor)
|
if (Settings::application.widget.shader_editor)
|
||||||
RenderShaderEditor();
|
RenderShaderEditor();
|
||||||
if (Settings::application.widget.logs)
|
if (Settings::application.widget.logs)
|
||||||
@@ -2293,7 +2293,7 @@ void MediaController::Render()
|
|||||||
if ( ImGuiToolkit::EditPlotHistoLines("##TimelineArray",
|
if ( ImGuiToolkit::EditPlotHistoLines("##TimelineArray",
|
||||||
mp_->timeline()->gapsArray(),
|
mp_->timeline()->gapsArray(),
|
||||||
mp_->timeline()->fadingArray(),
|
mp_->timeline()->fadingArray(),
|
||||||
MAX_TIMELINE_ARRAY, 0.f, 1.f, &released, size) ) {
|
MAX_TIMELINE_ARRAY, 0.f, 1.f, true, &released, size) ) {
|
||||||
mp_->timeline()->update();
|
mp_->timeline()->update();
|
||||||
}
|
}
|
||||||
else if (released) {
|
else if (released) {
|
||||||
@@ -2343,6 +2343,668 @@ void MediaController::Render()
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// SOURCE CONTROLLER
|
||||||
|
///
|
||||||
|
SourceController::SourceController() : active_label_(LABEL_AUTO_MEDIA_PLAYER),
|
||||||
|
active_selection_(-1), media_playing_mode_(false), slider_pressed_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SourceController::Render()
|
||||||
|
{
|
||||||
|
// ImGui::SetNextWindowPos(ImVec2(1180, 400), ImGuiCond_FirstUseEver);
|
||||||
|
// ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
|
||||||
|
|
||||||
|
// estimate window size
|
||||||
|
const ImGuiContext& g = *GImGui;
|
||||||
|
_h_space = g.Style.WindowPadding.x;
|
||||||
|
_v_space = g.Style.FramePadding.y;
|
||||||
|
_buttons_height = g.FontSize + _v_space * 4.0f ;
|
||||||
|
_min_width = 6.f * _buttons_height;
|
||||||
|
_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;
|
||||||
|
|
||||||
|
// constraint position
|
||||||
|
static ImVec2 source_window_pos = ImVec2(1180, 20);
|
||||||
|
static ImVec2 source_window_size = ImVec2(400, 260);
|
||||||
|
SetNextWindowVisible(source_window_pos, source_window_size);
|
||||||
|
|
||||||
|
ImGui::SetNextWindowSizeConstraints(ImVec2(_min_width, 2.f * _mediaplayer_height), ImVec2(FLT_MAX, FLT_MAX));
|
||||||
|
|
||||||
|
if ( !ImGui::Begin(IMGUI_TITLE_MEDIAPLAYER, &Settings::application.widget.media_player, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ))
|
||||||
|
{
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
source_window_pos = ImGui::GetWindowPos();
|
||||||
|
source_window_size = ImGui::GetWindowSize();
|
||||||
|
|
||||||
|
|
||||||
|
// menu (no title bar)
|
||||||
|
if (ImGui::BeginMenuBar())
|
||||||
|
{
|
||||||
|
if (ImGuiToolkit::IconButton(4,16))
|
||||||
|
Settings::application.widget.media_player = false;
|
||||||
|
if (ImGui::BeginMenu(IMGUI_TITLE_MEDIAPLAYER))
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( ImGui::MenuItem( ICON_FA_TIMES " Close", CTRL_MOD "P") )
|
||||||
|
Settings::application.widget.media_player = false;
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu(active_label_.c_str()))
|
||||||
|
{
|
||||||
|
if (ImGui::MenuItem("Selected sources")) {
|
||||||
|
active_selection_ = -1;
|
||||||
|
active_label_ = LABEL_AUTO_MEDIA_PLAYER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display list of available media
|
||||||
|
for (size_t i = 0 ; i < Mixer::manager().session()->numPlayGroups(); ++i)
|
||||||
|
{
|
||||||
|
std::string label = std::string("Selection #") + std::to_string(i);
|
||||||
|
if (ImGui::MenuItem( label.c_str() )) {
|
||||||
|
active_selection_ = i;
|
||||||
|
active_label_ = label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("New selection"))
|
||||||
|
{
|
||||||
|
active_selection_ = Mixer::manager().session()->numPlayGroups();
|
||||||
|
active_label_ = std::string("Selection #") + std::to_string(active_selection_);
|
||||||
|
Mixer::manager().session()->addPlayGroup( ids(playable_only(Mixer::selection().getCopy())) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (active_selection_ > -1) {
|
||||||
|
selection_ = Mixer::manager().session()->playGroup(active_selection_);
|
||||||
|
RenderSelection(active_selection_);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selection_ = playable_only(Mixer::selection().getCopy());
|
||||||
|
RenderSelectedSources();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceController::RenderSelection(size_t i)
|
||||||
|
{
|
||||||
|
ImVec2 top = ImGui::GetCursorScreenPos();
|
||||||
|
ImVec2 rendersize = ImGui::GetContentRegionAvail() - ImVec2(0, _buttons_height + _scrollbar + _v_space);
|
||||||
|
ImVec2 bottom = ImVec2(top.x, top.y + rendersize.y + _v_space);
|
||||||
|
|
||||||
|
int numsources = selection_.size();
|
||||||
|
// no source selected
|
||||||
|
if (numsources < 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
///
|
||||||
|
/// Sources grid
|
||||||
|
///
|
||||||
|
ImGui::BeginChild("##v_scroll", rendersize, false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||||
|
{
|
||||||
|
// 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) {
|
||||||
|
|
||||||
|
FrameBuffer *frame = (*source)->frame();
|
||||||
|
ImVec2 framesize(ImGui::GetColumnWidth(), ImGui::GetColumnWidth() / frame->aspectRatio());
|
||||||
|
|
||||||
|
ImVec2 image_top = ImGui::GetCursorPos();
|
||||||
|
ImGui::SetCursorPosX(image_top.x -_h_space );
|
||||||
|
ImGui::Image((void*)(uintptr_t) (*source)->texture(), framesize);
|
||||||
|
ImVec2 image_bottom = ImGui::GetCursorPos();
|
||||||
|
|
||||||
|
// Play icon lower left corner
|
||||||
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
||||||
|
ImGui::SetCursorPos(image_top + ImVec2( numcolumns > 1 ? 0.f : _h_space, framesize.y - ImGui::GetTextLineHeightWithSpacing()));
|
||||||
|
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::SetCursorPos(image_bottom);
|
||||||
|
ImGui::NextColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Columns(1);
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Play button bar
|
||||||
|
///
|
||||||
|
DrawButtonBar(bottom, rendersize.x);
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.14f, 0.14f, 0.14f, 0.7f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.14f, 0.14f, 0.14f, 0.7f));
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos(bottom + ImVec2(rendersize.x * 0.6f, _v_space) );
|
||||||
|
ImGui::SetNextItemWidth(-_h_space);
|
||||||
|
std::string label = std::to_string(numsources) + ( numsources > 1 ? " sources" : " source");
|
||||||
|
if (ImGui::BeginCombo("##SelectionImport", label.c_str()))
|
||||||
|
{
|
||||||
|
for (auto s = Mixer::manager().session()->begin(); s != Mixer::manager().session()->end(); ++s) {
|
||||||
|
if ( (*s)->playable() ) {
|
||||||
|
|
||||||
|
if (std::find(selection_.begin(),selection_.end(),*s) == selection_.end()) {
|
||||||
|
if (ImGui::MenuItem( (*s)->name().c_str() ))
|
||||||
|
Mixer::manager().session()->addToPlayGroup(i, *s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ImGui::MenuItem( (*s)->name().c_str(), ICON_FA_CHECK ))
|
||||||
|
Mixer::manager().session()->removeFromPlayGroup(i, *s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(4);
|
||||||
|
|
||||||
|
|
||||||
|
// const float preview_height = 4.5f * ImGui::GetFrameHeightWithSpacing();
|
||||||
|
|
||||||
|
// ImGui::Columns(2, NULL, true);
|
||||||
|
|
||||||
|
// // selection_ = Mixer::manager().session()->getDepthSortedList();
|
||||||
|
|
||||||
|
// Source *_toremove = nullptr;
|
||||||
|
// for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
||||||
|
|
||||||
|
// FrameBuffer *frame = (*source)->frame();
|
||||||
|
// float width = ImGui::GetColumnWidth();
|
||||||
|
// float height = width / frame->aspectRatio();
|
||||||
|
// if (height > preview_height) {
|
||||||
|
// height = preview_height;
|
||||||
|
// width = height * frame->aspectRatio();
|
||||||
|
// }
|
||||||
|
// ImVec2 top = ImGui::GetCursorPos();
|
||||||
|
// ImGui::Image((void*)(uintptr_t) (*source)->texture(), ImVec2(width, height));
|
||||||
|
// ImVec2 bottom = ImGui::GetCursorPos();
|
||||||
|
|
||||||
|
// // Context menu button up-left corner
|
||||||
|
// if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly))
|
||||||
|
// {
|
||||||
|
// ImGui::SetCursorPos(top + ImVec2(_h_space, _v_space));
|
||||||
|
// if (ImGuiToolkit::ButtonIcon(5, 8))
|
||||||
|
// ImGui::OpenPopup( "MenuSourceControl" );
|
||||||
|
// if (ImGui::BeginPopup( "MenuSourceControl" ))
|
||||||
|
// {
|
||||||
|
// if (ImGui::MenuItem(ICON_FA_MINUS_SQUARE " Remove from selection" )){
|
||||||
|
// _toremove = *source;
|
||||||
|
// }
|
||||||
|
// if (ImGui::MenuItem(ICON_FA_FILM " Open in Player" )){
|
||||||
|
|
||||||
|
// }
|
||||||
|
// ImGui::EndPopup();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Play icon lower left corner
|
||||||
|
// ImGui::SetCursorPos(top + ImVec2(_h_space, height - ImGui::GetTextLineHeightWithSpacing()));
|
||||||
|
// if ((*source)->active())
|
||||||
|
// ImGui::Text("%s", (*source)->playing() ? ICON_FA_PLAY : ICON_FA_PAUSE );
|
||||||
|
// else
|
||||||
|
// ImGui::Text(ICON_FA_SNOWFLAKE);
|
||||||
|
|
||||||
|
|
||||||
|
// ImGui::SetCursorPos(bottom + ImVec2(0, _v_space));
|
||||||
|
// ImGui::NextColumn();
|
||||||
|
|
||||||
|
// }
|
||||||
|
// // apply source removal
|
||||||
|
// if (_toremove)
|
||||||
|
// selection_.remove(_toremove);
|
||||||
|
|
||||||
|
// // Add source in selection
|
||||||
|
// ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
||||||
|
// if (ImGuiToolkit::IconButton(ICON_FA_PLUS_SQUARE))
|
||||||
|
// ImGui::OpenPopup( "SelectionAddSourceList" );
|
||||||
|
// ImGui::PopFont();
|
||||||
|
// if (ImGui::BeginPopup( "SelectionAddSourceList" ))
|
||||||
|
// {
|
||||||
|
// uint count = 0;
|
||||||
|
// for (auto s = Mixer::manager().session()->begin(); s != Mixer::manager().session()->end(); ++s) {
|
||||||
|
// if ( (*s)->playable() && std::find(selection_.begin(),selection_.end(),*s) == selection_.end()) {
|
||||||
|
// if (ImGui::MenuItem( (*s)->name().c_str() ))
|
||||||
|
// selection_.push_back( *s );
|
||||||
|
// ++count;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (count<1)
|
||||||
|
// ImGui::MenuItem( "No playable source available ", 0, false, false);
|
||||||
|
// ImGui::EndPopup();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ImGui::Columns(1);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceController::RenderSelectedSources()
|
||||||
|
{
|
||||||
|
|
||||||
|
ImVec2 top = ImGui::GetCursorScreenPos();
|
||||||
|
ImVec2 rendersize = ImGui::GetContentRegionAvail() - ImVec2(0, _buttons_height + _scrollbar + _v_space);
|
||||||
|
ImVec2 bottom = ImVec2(top.x, top.y + rendersize.y + _v_space);
|
||||||
|
|
||||||
|
int numsources = selection_.size();
|
||||||
|
// no source selected
|
||||||
|
if (numsources < 1)
|
||||||
|
{
|
||||||
|
///
|
||||||
|
/// Centered text
|
||||||
|
///
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.6, 0.6, 0.6, 0.5f));
|
||||||
|
ImVec2 center = rendersize * ImVec2(0.5f, 0.5f);
|
||||||
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_ITALIC);
|
||||||
|
center.x -= ImGui::GetTextLineHeight() * 2.f;
|
||||||
|
ImGui::SetCursorScreenPos(top + center);
|
||||||
|
ImGui::Text("Nothing to play");
|
||||||
|
ImGui::PopFont();
|
||||||
|
ImGui::PopStyleColor(1);
|
||||||
|
///
|
||||||
|
/// Play button bar
|
||||||
|
///
|
||||||
|
DrawButtonBar(bottom, rendersize.x);
|
||||||
|
|
||||||
|
}
|
||||||
|
// single source selected
|
||||||
|
else if (numsources < 2)
|
||||||
|
{
|
||||||
|
///
|
||||||
|
/// Sources display
|
||||||
|
///
|
||||||
|
RenderSingleSource( selection_.front() );
|
||||||
|
}
|
||||||
|
// Several sources selected
|
||||||
|
else {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sources grid
|
||||||
|
///
|
||||||
|
ImGui::BeginChild("##v_scroll", rendersize, false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||||
|
{
|
||||||
|
// 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) {
|
||||||
|
|
||||||
|
FrameBuffer *frame = (*source)->frame();
|
||||||
|
ImVec2 framesize(ImGui::GetColumnWidth(), ImGui::GetColumnWidth() / frame->aspectRatio());
|
||||||
|
|
||||||
|
ImVec2 image_top = ImGui::GetCursorPos();
|
||||||
|
ImGui::SetCursorPosX(image_top.x -_h_space );
|
||||||
|
ImGui::Image((void*)(uintptr_t) (*source)->texture(), framesize);
|
||||||
|
ImVec2 image_bottom = ImGui::GetCursorPos();
|
||||||
|
|
||||||
|
// Play icon lower left corner
|
||||||
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
||||||
|
ImGui::SetCursorPos(image_top + ImVec2( numcolumns > 1 ? 0.f : _h_space, framesize.y - ImGui::GetTextLineHeightWithSpacing()));
|
||||||
|
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::SetCursorPos(image_bottom);
|
||||||
|
ImGui::NextColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Columns(1);
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Play button bar
|
||||||
|
///
|
||||||
|
DrawButtonBar(bottom, rendersize.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceController::RenderSingleSource(Source *s)
|
||||||
|
{
|
||||||
|
if ( s == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// in case of a MediaSource
|
||||||
|
MediaSource *ms = dynamic_cast<MediaSource *>(s);
|
||||||
|
if ( ms != nullptr) {
|
||||||
|
RenderMediaPlayer( ms->mediaplayer() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImVec2 top = ImGui::GetCursorScreenPos();
|
||||||
|
ImVec2 rendersize = ImGui::GetContentRegionAvail() - ImVec2(0, _buttons_height + _scrollbar + _v_space);
|
||||||
|
ImVec2 bottom = ImVec2(top.x, top.y + rendersize.y + _v_space);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Centered frame
|
||||||
|
///
|
||||||
|
FrameBuffer *frame = s->frame();
|
||||||
|
ImVec2 framesize = rendersize;
|
||||||
|
ImVec2 corner(0.f, 0.f);
|
||||||
|
ImVec2 tmp = ImVec2(framesize.y * frame->aspectRatio(), framesize.x / frame->aspectRatio());
|
||||||
|
if (tmp.x > framesize.x) {
|
||||||
|
corner.y = (framesize.y - tmp.y) / 2.f;
|
||||||
|
framesize.y = tmp.y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
corner.x = (framesize.x - tmp.x) / 2.f;
|
||||||
|
framesize.x = tmp.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos(top + corner);
|
||||||
|
ImGui::Image((void*)(uintptr_t) s->texture(), framesize);
|
||||||
|
|
||||||
|
// Play icon lower left corner
|
||||||
|
ImGuiToolkit::PushFont(framesize.x > 200.f ? ImGuiToolkit::FONT_LARGE : ImGuiToolkit::FONT_MONO);
|
||||||
|
ImGui::SetCursorScreenPos(top + corner + ImVec2(_h_space, framesize.y - 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::PopFont();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Play source button bar
|
||||||
|
///
|
||||||
|
DrawButtonBar(bottom, rendersize.x);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
||||||
|
{
|
||||||
|
static float timeline_zoom = 1.f;
|
||||||
|
const float slider_zoom_width = _timeline_height / 2.f;
|
||||||
|
|
||||||
|
ImVec2 top = ImGui::GetCursorScreenPos();
|
||||||
|
ImVec2 rendersize = ImGui::GetContentRegionAvail() - ImVec2(0, _mediaplayer_height);
|
||||||
|
ImVec2 bottom = ImVec2(top.x, top.y + rendersize.y + _v_space);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Centered frame
|
||||||
|
///
|
||||||
|
ImVec2 framesize = rendersize;
|
||||||
|
ImVec2 corner(0.f, 0.f);
|
||||||
|
ImVec2 tmp = ImVec2(framesize.y * mp->aspectRatio(), framesize.x / mp->aspectRatio());
|
||||||
|
if (tmp.x > framesize.x) {
|
||||||
|
corner.y = (framesize.y - tmp.y) / 2.f;
|
||||||
|
framesize.y = tmp.y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
corner.x = (framesize.x - tmp.x) / 2.f;
|
||||||
|
framesize.x = tmp.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos(top + corner);
|
||||||
|
ImGui::Image((void*)(uintptr_t) mp->texture(), framesize);
|
||||||
|
|
||||||
|
// Play icon lower left corner
|
||||||
|
ImGuiToolkit::PushFont(framesize.x > 200.f ? ImGuiToolkit::FONT_LARGE : ImGuiToolkit::FONT_MONO);
|
||||||
|
ImGui::SetCursorScreenPos(top + corner + ImVec2(_h_space, framesize.y - ImGui::GetTextLineHeightWithSpacing()));
|
||||||
|
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("%s %s", ICON_FA_SNOWFLAKE, GstToolkit::time_to_string(mp->position()).c_str() );
|
||||||
|
ImGui::PopFont();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// media player buttons bar
|
||||||
|
///
|
||||||
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
|
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.24f, 0.24f, 0.24f, 0.7f));
|
||||||
|
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.4f));
|
||||||
|
|
||||||
|
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, ¤t_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 x %.1f", 2.f))
|
||||||
|
mp->setPlaySpeed( static_cast<double>(speed) );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (ImGui::MenuItem("Reset Speed" )){
|
||||||
|
speed = 1.f;
|
||||||
|
mp->setPlaySpeed( static_cast<double>(speed) );
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem( "Reset Timeline" )){
|
||||||
|
timeline_zoom = 1.f;
|
||||||
|
mp->timeline()->clearFading();
|
||||||
|
mp->timeline()->clearGaps();
|
||||||
|
Action::manager().store("Timeline Reset");
|
||||||
|
}
|
||||||
|
if (ImGui::BeginMenu("Smooth curve"))
|
||||||
|
{
|
||||||
|
const char* names[] = { "Just a little", "A bit more", "Quite a lot"};
|
||||||
|
for (int i = 0; i < IM_ARRAYSIZE(names); ++i) {
|
||||||
|
if (ImGui::MenuItem(names[i])) {
|
||||||
|
mp->timeline()->smoothFading( 10 * (int) pow(4, i) );
|
||||||
|
Action::manager().store("Timeline Smooth curve");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
if (ImGui::BeginMenu("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( 10 * (i + 1) );
|
||||||
|
Action::manager().store("Timeline Auto fading");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
if (Settings::application.render.gpu_decoding && ImGui::BeginMenu("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
|
||||||
|
///
|
||||||
|
ImGui::SetCursorScreenPos(bottom + ImVec2(0, _buttons_height + _v_space) );
|
||||||
|
|
||||||
|
// seek position
|
||||||
|
guint64 seek_t = mp->position();
|
||||||
|
|
||||||
|
// scrolling sub-window
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(1.f, 1.f));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.f);
|
||||||
|
|
||||||
|
ImVec2 top_scrollwindow = ImGui::GetCursorPos();
|
||||||
|
ImVec2 scrollwindow = ImVec2(ImGui::GetContentRegionAvail().x - slider_zoom_width - 3.0,
|
||||||
|
2.f * _timeline_height + _scrollbar );
|
||||||
|
|
||||||
|
ImGui::BeginChild("##scrolling", scrollwindow, false, ImGuiWindowFlags_HorizontalScrollbar);
|
||||||
|
{
|
||||||
|
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), _timeline_height -1);
|
||||||
|
size.x *= timeline_zoom;
|
||||||
|
|
||||||
|
bool released = false;
|
||||||
|
if ( ImGuiToolkit::EditPlotHistoLines("##TimelineArray",
|
||||||
|
mp->timeline()->gapsArray(),
|
||||||
|
mp->timeline()->fadingArray(),
|
||||||
|
MAX_TIMELINE_ARRAY, 0.f, 1.f,
|
||||||
|
Settings::application.widget.timeline_editmode, &released, size) ) {
|
||||||
|
mp->timeline()->update();
|
||||||
|
}
|
||||||
|
else if (released) {
|
||||||
|
Action::manager().store("Timeline change");
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom timeline slider
|
||||||
|
slider_pressed_ = ImGuiToolkit::TimelineSlider("##timeline", &seek_t, mp->timeline()->begin(),
|
||||||
|
mp->timeline()->end(), mp->timeline()->step(), size.x);
|
||||||
|
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
|
// action mode
|
||||||
|
ImGui::SetCursorPos(top_scrollwindow + ImVec2(scrollwindow.x + 3.f, 0));
|
||||||
|
ImGuiToolkit::IconToggle(7,4,8,3,&Settings::application.widget.timeline_editmode);
|
||||||
|
|
||||||
|
// zoom slider
|
||||||
|
ImGui::SetCursorPos(top_scrollwindow + ImVec2(scrollwindow.x + 3.f, 0.5f * _timeline_height + 3.f));
|
||||||
|
ImGui::VSliderFloat("##TimelineZoom", ImVec2(slider_zoom_width, 1.5f * _timeline_height - 3.f), &timeline_zoom, 1.0, 5.f, "");
|
||||||
|
|
||||||
|
///
|
||||||
|
/// media player actions
|
||||||
|
///
|
||||||
|
///
|
||||||
|
// request seek (ASYNC)
|
||||||
|
if ( slider_pressed_ && mp->go_to(seek_t) )
|
||||||
|
slider_pressed_ = false;
|
||||||
|
|
||||||
|
// play/stop command should be following the playing mode (buttons)
|
||||||
|
// AND force to stop when the slider is pressed
|
||||||
|
bool media_play = media_playing_mode_ & (!slider_pressed_);
|
||||||
|
|
||||||
|
// apply play action to media only if status should change
|
||||||
|
if ( mp->isPlaying() != media_play ) {
|
||||||
|
mp->play( media_play );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceController::DrawButtonBar(ImVec2 bottom, float width)
|
||||||
|
{
|
||||||
|
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 (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));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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.24f, 0.24f, 0.24f, 0.7f));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos(bottom + ImVec2(_h_space, _v_space) );
|
||||||
|
if (ImGui::Button(ICON_FA_FAST_BACKWARD))
|
||||||
|
{
|
||||||
|
for (auto source = selection_.begin(); source != selection_.end(); ++source)
|
||||||
|
(*source)->replay();
|
||||||
|
}
|
||||||
|
ImGui::SameLine(0, _h_space);
|
||||||
|
if (ImGui::Button(ICON_FA_PLAY))
|
||||||
|
{
|
||||||
|
for (auto source = selection_.begin(); source != selection_.end(); ++source)
|
||||||
|
(*source)->play(true);
|
||||||
|
}
|
||||||
|
ImGui::SameLine(0, _h_space);
|
||||||
|
if (ImGui::Button(ICON_FA_PAUSE))
|
||||||
|
{
|
||||||
|
for (auto source = selection_.begin(); source != selection_.end(); ++source)
|
||||||
|
(*source)->play(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// NAVIGATOR
|
/// NAVIGATOR
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
#define NAV_MENU 66
|
#define NAV_MENU 66
|
||||||
#define NAV_TRANS 67
|
#define NAV_TRANS 67
|
||||||
|
|
||||||
|
#include "SourceList.h"
|
||||||
|
|
||||||
struct ImVec2;
|
struct ImVec2;
|
||||||
class Source;
|
|
||||||
class MediaPlayer;
|
class MediaPlayer;
|
||||||
class FrameBufferImage;
|
class FrameBufferImage;
|
||||||
class FrameGrabber;
|
class FrameGrabber;
|
||||||
@@ -119,6 +120,36 @@ public:
|
|||||||
void Render();
|
void Render();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SourceController
|
||||||
|
{
|
||||||
|
float _min_width;
|
||||||
|
float _h_space;
|
||||||
|
float _v_space;
|
||||||
|
float _buttons_height;
|
||||||
|
float _timeline_height;
|
||||||
|
float _scrollbar;
|
||||||
|
float _mediaplayer_height;
|
||||||
|
|
||||||
|
std::string active_label_;
|
||||||
|
int active_selection_;
|
||||||
|
|
||||||
|
SourceList selection_;
|
||||||
|
void DrawButtonBar(ImVec2 bottom, float width);
|
||||||
|
|
||||||
|
void RenderSelectedSources();
|
||||||
|
void RenderSelection(size_t i);
|
||||||
|
void RenderSingleSource(Source *s);
|
||||||
|
|
||||||
|
bool media_playing_mode_;
|
||||||
|
bool slider_pressed_;
|
||||||
|
void RenderMediaPlayer(MediaPlayer *mp);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SourceController();
|
||||||
|
|
||||||
|
void Render();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class UserInterface
|
class UserInterface
|
||||||
{
|
{
|
||||||
@@ -126,6 +157,7 @@ class UserInterface
|
|||||||
Navigator navigator;
|
Navigator navigator;
|
||||||
ToolBox toolbox;
|
ToolBox toolbox;
|
||||||
MediaController mediacontrol;
|
MediaController mediacontrol;
|
||||||
|
SourceController sourcecontrol;
|
||||||
|
|
||||||
bool ctrl_modifier_active;
|
bool ctrl_modifier_active;
|
||||||
bool alt_modifier_active;
|
bool alt_modifier_active;
|
||||||
|
|||||||
Reference in New Issue
Block a user