mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
Update New Source panel for Media
Added list of recent files, recent recordings, and folders list of media files. All saved in settings. Connect list of recent recordings with recorder.
This commit is contained in:
@@ -462,6 +462,8 @@ void VideoRecorder::terminate()
|
|||||||
Log::Info("Video Recording : try a lower resolution / a lower framerate / a larger buffer size / a faster codec.");
|
Log::Info("Video Recording : try a lower resolution / a lower framerate / a larger buffer size / a faster codec.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remember and inform
|
||||||
|
Settings::application.recentRecordings.push(filename_);
|
||||||
Log::Notify("Video Recording %s is ready.", filename_.c_str());
|
Log::Notify("Video Recording %s is ready.", filename_.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,12 @@
|
|||||||
|
|
||||||
class PNGRecorder : public FrameGrabber
|
class PNGRecorder : public FrameGrabber
|
||||||
{
|
{
|
||||||
std::string filename_;
|
std::string filename_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PNGRecorder();
|
PNGRecorder();
|
||||||
|
std::string filename() const { return filename_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ protected:
|
|||||||
|
|
||||||
class VideoRecorder : public FrameGrabber
|
class VideoRecorder : public FrameGrabber
|
||||||
{
|
{
|
||||||
std::string filename_;
|
std::string filename_;
|
||||||
|
|
||||||
std::string init(GstCaps *caps) override;
|
std::string init(GstCaps *caps) override;
|
||||||
void terminate() override;
|
void terminate() override;
|
||||||
@@ -58,7 +59,7 @@ public:
|
|||||||
|
|
||||||
VideoRecorder();
|
VideoRecorder();
|
||||||
std::string info() const override;
|
std::string info() const override;
|
||||||
|
std::string filename() const { return filename_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
85
Settings.cpp
85
Settings.cpp
@@ -238,6 +238,29 @@ void Settings::Save(uint64_t runtime)
|
|||||||
}
|
}
|
||||||
recent->InsertEndChild(recentmedia);
|
recent->InsertEndChild(recentmedia);
|
||||||
|
|
||||||
|
// recent import folders
|
||||||
|
XMLElement *recentimportfolder = xmlDoc.NewElement( "ImportFolder" );
|
||||||
|
recentmedia->SetAttribute("path", application.recentImportFolders.path.c_str());
|
||||||
|
for(auto it = application.recentImportFolders.filenames.cbegin();
|
||||||
|
it != application.recentImportFolders.filenames.cend(); ++it) {
|
||||||
|
XMLElement *pathNode = xmlDoc.NewElement("path");
|
||||||
|
XMLText *text = xmlDoc.NewText( (*it).c_str() );
|
||||||
|
pathNode->InsertEndChild( text );
|
||||||
|
recentimportfolder->InsertFirstChild(pathNode);
|
||||||
|
}
|
||||||
|
recent->InsertEndChild(recentimportfolder);
|
||||||
|
|
||||||
|
// recent recordings
|
||||||
|
XMLElement *recentrecord = xmlDoc.NewElement( "Record" );
|
||||||
|
for(auto it = application.recentRecordings.filenames.cbegin();
|
||||||
|
it != application.recentRecordings.filenames.cend(); ++it) {
|
||||||
|
XMLElement *pathNode = xmlDoc.NewElement("path");
|
||||||
|
XMLText *text = xmlDoc.NewText( (*it).c_str() );
|
||||||
|
pathNode->InsertEndChild( text );
|
||||||
|
recentrecord->InsertFirstChild(pathNode);
|
||||||
|
}
|
||||||
|
recent->InsertEndChild(recentrecord);
|
||||||
|
|
||||||
// recent dialog path
|
// recent dialog path
|
||||||
XMLElement *recentdialogpath = xmlDoc.NewElement( "Dialog" );
|
XMLElement *recentdialogpath = xmlDoc.NewElement( "Dialog" );
|
||||||
for(auto it = application.dialogRecentFolder.cbegin();
|
for(auto it = application.dialogRecentFolder.cbegin();
|
||||||
@@ -517,6 +540,37 @@ void Settings::Load()
|
|||||||
application.recentImport.push( std::string (p) );
|
application.recentImport.push( std::string (p) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// recent import folders
|
||||||
|
XMLElement * pImportFolder = pElement->FirstChildElement("ImportFolder");
|
||||||
|
if (pImportFolder)
|
||||||
|
{
|
||||||
|
const char *path_ = pImportFolder->Attribute("path");
|
||||||
|
if (path_)
|
||||||
|
application.recentImportFolders.path = std::string(path_);
|
||||||
|
application.recentImportFolders.filenames.clear();
|
||||||
|
XMLElement* path = pImportFolder->FirstChildElement("path");
|
||||||
|
for( ; path ; path = path->NextSiblingElement())
|
||||||
|
{
|
||||||
|
const char *p = path->GetText();
|
||||||
|
if (p)
|
||||||
|
application.recentImportFolders.push( std::string (p) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// recent recordings
|
||||||
|
XMLElement * pRecord = pElement->FirstChildElement("Record");
|
||||||
|
if (pRecord)
|
||||||
|
{
|
||||||
|
application.recentRecordings.filenames.clear();
|
||||||
|
XMLElement* path = pRecord->FirstChildElement("path");
|
||||||
|
for( ; path ; path = path->NextSiblingElement())
|
||||||
|
{
|
||||||
|
const char *p = path->GetText();
|
||||||
|
if (p)
|
||||||
|
application.recentRecordings.push( std::string (p) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// recent dialog path
|
// recent dialog path
|
||||||
XMLElement * pDialog = pElement->FirstChildElement("Dialog");
|
XMLElement * pDialog = pElement->FirstChildElement("Dialog");
|
||||||
if (pDialog)
|
if (pDialog)
|
||||||
@@ -582,6 +636,37 @@ void Settings::History::validate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO unified history function saving
|
||||||
|
//void load_history(Settings::History &h, XMLElement *root)
|
||||||
|
//{
|
||||||
|
// XMLElement * pElement = root->FirstChildElement("Import");
|
||||||
|
// if (pElement)
|
||||||
|
// {
|
||||||
|
// h.filenames.clear();
|
||||||
|
// XMLElement* path = pElement->FirstChildElement("path");
|
||||||
|
// for( ; path ; path = path->NextSiblingElement())
|
||||||
|
// {
|
||||||
|
// const char *p = path->GetText();
|
||||||
|
// if (p)
|
||||||
|
// h.push( std::string (p) );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//XMLElement *save_history(Settings::History &h, XMLDocument &xmlDoc)
|
||||||
|
//{
|
||||||
|
// XMLElement *pElement = xmlDoc.NewElement( "Import" );
|
||||||
|
// for(auto it = h.filenames.cbegin();
|
||||||
|
// it != h.filenames.cend(); ++it) {
|
||||||
|
// XMLElement *fileNode = xmlDoc.NewElement("path");
|
||||||
|
// XMLText *text = xmlDoc.NewText( (*it).c_str() );
|
||||||
|
// fileNode->InsertEndChild( text );
|
||||||
|
// pElement->InsertFirstChild(fileNode);
|
||||||
|
// }
|
||||||
|
// return pElement;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
void Settings::Lock()
|
void Settings::Lock()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -243,6 +243,8 @@ struct Application
|
|||||||
History recentSessions;
|
History recentSessions;
|
||||||
History recentFolders;
|
History recentFolders;
|
||||||
History recentImport;
|
History recentImport;
|
||||||
|
History recentImportFolders;
|
||||||
|
History recentRecordings;
|
||||||
std::map< std::string, std::string > dialogRecentFolder;
|
std::map< std::string, std::string > dialogRecentFolder;
|
||||||
|
|
||||||
// Metronome & stopwatch
|
// Metronome & stopwatch
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ std::string readable_date_time_string(std::string date){
|
|||||||
|
|
||||||
// globals
|
// globals
|
||||||
const std::chrono::milliseconds timeout = std::chrono::milliseconds(4);
|
const std::chrono::milliseconds timeout = std::chrono::milliseconds(4);
|
||||||
std::vector< std::future<FrameGrabber *> > _video_recorders;
|
std::vector< std::future<VideoRecorder *> > _video_recorders;
|
||||||
FrameGrabber *delayTrigger(FrameGrabber *g, std::chrono::milliseconds delay) {
|
VideoRecorder *delayTrigger(VideoRecorder *g, std::chrono::milliseconds delay) {
|
||||||
std::this_thread::sleep_for (delay);
|
std::this_thread::sleep_for (delay);
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
@@ -324,17 +324,20 @@ void UserInterface::handleKeyboard()
|
|||||||
FrameGrabbing::manager().add(new PNGRecorder);
|
FrameGrabbing::manager().add(new PNGRecorder);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// toggle recording
|
// toggle recording stop / start
|
||||||
if (video_recorder_) {
|
if (video_recorder_) {
|
||||||
// allow 'save & continue' for Ctrl+Alt+R if no timeout for recording
|
// 'save & continue' for Ctrl+Alt+R if no timeout for recording
|
||||||
if (alt_modifier_active && Settings::application.record.timeout == RECORD_MAX_TIMEOUT) {
|
if (alt_modifier_active && Settings::application.record.timeout == RECORD_MAX_TIMEOUT) {
|
||||||
VideoRecorder *rec = new VideoRecorder;
|
VideoRecorder *rec = new VideoRecorder;
|
||||||
FrameGrabbing::manager().chain(video_recorder_, rec);
|
FrameGrabbing::manager().chain(video_recorder_, rec);
|
||||||
video_recorder_ = rec;
|
video_recorder_ = rec;
|
||||||
}
|
}
|
||||||
// normal case: Ctrl+R stop recording
|
// normal case: Ctrl+R stop recording
|
||||||
else
|
else {
|
||||||
|
// prepare for next open new source panel to show the recording
|
||||||
|
navigator.setNewMedia(Navigator::MEDIA_RECORDING, video_recorder_->filename());
|
||||||
video_recorder_->stop();
|
video_recorder_->stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_video_recorders.emplace_back( std::async(std::launch::async, delayTrigger, new VideoRecorder,
|
_video_recorders.emplace_back( std::async(std::launch::async, delayTrigger, new VideoRecorder,
|
||||||
@@ -795,7 +798,7 @@ void UserInterface::Render()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// verify the video recorder is valid (change to nullptr if invalid)
|
// verify the video recorder is valid (change to nullptr if invalid)
|
||||||
FrameGrabbing::manager().verify(&video_recorder_);
|
FrameGrabbing::manager().verify( (FrameGrabber**) &video_recorder_);
|
||||||
if (video_recorder_ // if there is an ongoing recorder
|
if (video_recorder_ // if there is an ongoing recorder
|
||||||
&& Settings::application.record.timeout < RECORD_MAX_TIMEOUT // and if the timeout is valid
|
&& Settings::application.record.timeout < RECORD_MAX_TIMEOUT // and if the timeout is valid
|
||||||
&& video_recorder_->duration() > Settings::application.record.timeout ) // and the timeout is reached
|
&& video_recorder_->duration() > Settings::application.record.timeout ) // and the timeout is reached
|
||||||
@@ -1340,12 +1343,18 @@ void UserInterface::RenderPreview()
|
|||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_RECORD, 0.8f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_RECORD, 0.8f));
|
||||||
if ( ImGui::MenuItem( ICON_FA_SQUARE " Stop Record", CTRL_MOD "R") ) {
|
if ( ImGui::MenuItem( ICON_FA_SQUARE " Stop Record", CTRL_MOD "R") ) {
|
||||||
video_recorder_->stop();
|
video_recorder_->stop();
|
||||||
|
// prepare for next open new source panel to show the recording
|
||||||
|
navigator.setNewMedia(Navigator::MEDIA_RECORDING, video_recorder_->filename());
|
||||||
}
|
}
|
||||||
// offer the 'save & continue' recording for undefined duration
|
// offer the 'save & continue' recording for undefined duration
|
||||||
if (Settings::application.record.timeout == RECORD_MAX_TIMEOUT) {
|
if (Settings::application.record.timeout == RECORD_MAX_TIMEOUT) {
|
||||||
if ( ImGui::MenuItem( ICON_FA_ARROW_ALT_CIRCLE_DOWN " Save & continue", CTRL_MOD "Alt+R") ) {
|
if ( ImGui::MenuItem( ICON_FA_ARROW_ALT_CIRCLE_DOWN " Save & continue", CTRL_MOD "Alt+R") ) {
|
||||||
|
// prepare for next open new source panel to show the recording
|
||||||
|
navigator.setNewMedia(Navigator::MEDIA_RECORDING, video_recorder_->filename());
|
||||||
|
// create a new recorder chainned to the current one
|
||||||
VideoRecorder *rec = new VideoRecorder;
|
VideoRecorder *rec = new VideoRecorder;
|
||||||
FrameGrabbing::manager().chain(video_recorder_, rec);
|
FrameGrabbing::manager().chain(video_recorder_, rec);
|
||||||
|
// swap recorder
|
||||||
video_recorder_ = rec;
|
video_recorder_ = rec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3700,6 +3709,9 @@ Navigator::Navigator()
|
|||||||
pannel_visible_ = false;
|
pannel_visible_ = false;
|
||||||
view_pannel_visible = false;
|
view_pannel_visible = false;
|
||||||
clearButtonSelection();
|
clearButtonSelection();
|
||||||
|
|
||||||
|
new_media_mode = MEDIA_RECENT;
|
||||||
|
new_media_mode_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Navigator::applyButtonSelection(int index)
|
void Navigator::applyButtonSelection(int index)
|
||||||
@@ -3724,7 +3736,8 @@ void Navigator::clearButtonSelection()
|
|||||||
// clear new source pannel
|
// clear new source pannel
|
||||||
new_source_preview_.setSource();
|
new_source_preview_.setSource();
|
||||||
pattern_type = -1;
|
pattern_type = -1;
|
||||||
_selectedFiles.clear();
|
sourceSequenceFiles.clear();
|
||||||
|
setNewMedia(new_media_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Navigator::showPannelSource(int index)
|
void Navigator::showPannelSource(int index)
|
||||||
@@ -4037,6 +4050,43 @@ void Navigator::RenderSourcePannel(Source *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Navigator::setNewMedia(MediaCreateMode mode, std::string path)
|
||||||
|
{
|
||||||
|
// switch new source to Media pannel
|
||||||
|
Settings::application.source.new_type = SOURCE_FILE;
|
||||||
|
|
||||||
|
// change mode
|
||||||
|
new_media_mode = mode;
|
||||||
|
new_media_mode_changed = true;
|
||||||
|
// mode dependent actions
|
||||||
|
switch (new_media_mode) {
|
||||||
|
case MEDIA_RECENT:
|
||||||
|
// set filename
|
||||||
|
sourceMediaFileCurrent = path;
|
||||||
|
// set combo to 'recent files'
|
||||||
|
Settings::application.recentImportFolders.path = IMGUI_LABEL_RECENT_FILES;
|
||||||
|
break;
|
||||||
|
case MEDIA_RECORDING:
|
||||||
|
// set filename
|
||||||
|
sourceMediaFileCurrent = path;
|
||||||
|
// set combo to 'recent recordings'
|
||||||
|
Settings::application.recentImportFolders.path = IMGUI_LABEL_RECENT_RECORDS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case MEDIA_FOLDER:
|
||||||
|
// reset filename
|
||||||
|
sourceMediaFileCurrent.clear();
|
||||||
|
// set combo: a path was selected
|
||||||
|
if (!path.empty())
|
||||||
|
Settings::application.recentImportFolders.path.assign(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear preview
|
||||||
|
new_source_preview_.setSource();
|
||||||
|
}
|
||||||
|
|
||||||
void Navigator::RenderNewPannel()
|
void Navigator::RenderNewPannel()
|
||||||
{
|
{
|
||||||
// Next window is a side pannel
|
// Next window is a side pannel
|
||||||
@@ -4058,7 +4108,7 @@ void Navigator::RenderNewPannel()
|
|||||||
//
|
//
|
||||||
// News Source selection pannel
|
// News Source selection pannel
|
||||||
//
|
//
|
||||||
static const char* origin_names[5] = { ICON_FA_PHOTO_VIDEO " File",
|
static const char* origin_names[SOURCE_TYPES] = { ICON_FA_PHOTO_VIDEO " File",
|
||||||
ICON_FA_SORT_NUMERIC_DOWN " Sequence",
|
ICON_FA_SORT_NUMERIC_DOWN " Sequence",
|
||||||
ICON_FA_PLUG " Connected",
|
ICON_FA_PLUG " Connected",
|
||||||
ICON_FA_COG " Generated",
|
ICON_FA_COG " Generated",
|
||||||
@@ -4071,66 +4121,157 @@ void Navigator::RenderNewPannel()
|
|||||||
ImGui::SetCursorPosY(2.f * width_);
|
ImGui::SetCursorPosY(2.f * width_);
|
||||||
|
|
||||||
// File Source creation
|
// File Source creation
|
||||||
if (Settings::application.source.new_type == 0) {
|
if (Settings::application.source.new_type == SOURCE_FILE) {
|
||||||
|
|
||||||
static DialogToolkit::OpenMediaDialog fileimportdialog("Open Media");
|
static DialogToolkit::OpenMediaDialog fileimportdialog("Open Media");
|
||||||
|
static DialogToolkit::OpenFolderDialog folderimportdialog("Select Folder");
|
||||||
|
|
||||||
// clic button to load file
|
// clic button to load file
|
||||||
if ( ImGui::Button( ICON_FA_FILE_EXPORT " Open media", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) )
|
if ( ImGui::Button( ICON_FA_FILE_EXPORT " Open File", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) )
|
||||||
fileimportdialog.open();
|
fileimportdialog.open();
|
||||||
|
|
||||||
// Indication
|
// Indication
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGuiToolkit::HelpMarker("Create a source from a file:\n"
|
ImGuiToolkit::HelpMarker("Create a source from a file:\n"
|
||||||
ICON_FA_CARET_RIGHT " Video (*.mpg, *mov, *.avi, etc.)\n"
|
ICON_FA_CARET_RIGHT " Video (*.mpg, *mov, *.avi, etc.)\n"
|
||||||
ICON_FA_CARET_RIGHT " Image (*.jpg, *.png, etc.)\n"
|
ICON_FA_CARET_RIGHT " Image (*.jpg, *.png, etc.)\n"
|
||||||
ICON_FA_CARET_RIGHT " Vector graphics (*.svg)\n"
|
ICON_FA_CARET_RIGHT " Vector graphics (*.svg)\n"
|
||||||
ICON_FA_CARET_RIGHT " vimix session (*.mix)\n\n"
|
ICON_FA_CARET_RIGHT " vimix session (*.mix)\n"
|
||||||
"(Equivalent to dropping the file in the workspace)");
|
"\nNB: Equivalent to dropping the file in the workspace");
|
||||||
|
|
||||||
// get media file if dialog finished
|
// get media file if dialog finished
|
||||||
if (fileimportdialog.closed()){
|
if (fileimportdialog.closed()){
|
||||||
// get the filename from this file dialog
|
// get the filename from this file dialog
|
||||||
std::string open_filename = fileimportdialog.path();
|
std::string importpath = fileimportdialog.path();
|
||||||
// create a source with this file
|
// switch to recent files
|
||||||
if (open_filename.empty()) {
|
setNewMedia(MEDIA_RECENT, importpath);
|
||||||
new_source_preview_.setSource();
|
// open file
|
||||||
Log::Notify("No file selected.");
|
if (!importpath.empty()) {
|
||||||
} else {
|
std::string label = BaseToolkit::transliterate( sourceMediaFileCurrent );
|
||||||
std::string label = BaseToolkit::transliterate( open_filename );
|
new_source_preview_.setSource( Mixer::manager().createSourceFile(sourceMediaFileCurrent), label);
|
||||||
label = BaseToolkit::trunc_string(label, 35);
|
|
||||||
new_source_preview_.setSource( Mixer::manager().createSourceFile(open_filename), label);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// combo of recent media filenames
|
// combo to offer lists
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
if (ImGui::BeginCombo("##RecentImport", IMGUI_LABEL_RECENT_FILES))
|
if (ImGui::BeginCombo("##SelectionNewMedia", BaseToolkit::trunc_string(Settings::application.recentImportFolders.path, 25).c_str() ))
|
||||||
{
|
{
|
||||||
std::list<std::string> recent = Settings::application.recentImport.filenames;
|
// Mode MEDIA_RECENT : recent files
|
||||||
for (std::list<std::string>::iterator path = recent.begin(); path != recent.end(); ++path )
|
if (ImGui::Selectable( ICON_FA_LIST_OL IMGUI_LABEL_RECENT_FILES) ) {
|
||||||
{
|
setNewMedia(MEDIA_RECENT);
|
||||||
std::string recentpath(*path);
|
}
|
||||||
if ( SystemToolkit::file_exists(recentpath)) {
|
// Mode MEDIA_RECORDING : recent recordings
|
||||||
std::string label = BaseToolkit::transliterate( recentpath );
|
if (ImGui::Selectable( ICON_FA_LIST_UL IMGUI_LABEL_RECENT_RECORDS) ) {
|
||||||
label = BaseToolkit::trunc_string(label, 35);
|
setNewMedia(MEDIA_RECORDING);
|
||||||
if (ImGui::Selectable( label.c_str() )) {
|
}
|
||||||
new_source_preview_.setSource( Mixer::manager().createSourceFile(recentpath.c_str()), label);
|
// Mode MEDIA_FOLDER : known folders
|
||||||
}
|
for(auto foldername = Settings::application.recentImportFolders.filenames.begin();
|
||||||
|
foldername != Settings::application.recentImportFolders.filenames.end(); foldername++) {
|
||||||
|
std::string f = std::string(ICON_FA_FOLDER) + " " + BaseToolkit::trunc_string( *foldername, 40);
|
||||||
|
if (ImGui::Selectable( f.c_str() )) {
|
||||||
|
setNewMedia(MEDIA_FOLDER, *foldername);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Add a folder for MEDIA_FOLDER
|
||||||
|
if (ImGui::Selectable( ICON_FA_FOLDER_PLUS " Add Folder") ) {
|
||||||
|
folderimportdialog.open();
|
||||||
|
}
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return from thread for folder openning
|
||||||
|
if (folderimportdialog.closed() && !folderimportdialog.path().empty()) {
|
||||||
|
Settings::application.recentImportFolders.push(folderimportdialog.path());
|
||||||
|
setNewMedia(MEDIA_FOLDER, folderimportdialog.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
// icons to clear lists or discarc folder
|
||||||
|
ImVec2 pos_top = ImGui::GetCursorPos();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
|
||||||
|
if ( new_media_mode == MEDIA_FOLDER ) {
|
||||||
|
if (ImGuiToolkit::IconButton( ICON_FA_FOLDER_MINUS, "Discard folder")) {
|
||||||
|
Settings::application.recentImportFolders.filenames.remove(Settings::application.recentImportFolders.path);
|
||||||
|
if (Settings::application.recentImportFolders.filenames.empty())
|
||||||
|
// revert mode RECENT
|
||||||
|
setNewMedia(MEDIA_RECENT);
|
||||||
|
else
|
||||||
|
setNewMedia(MEDIA_FOLDER, Settings::application.recentImportFolders.filenames.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( new_media_mode == MEDIA_RECORDING ) {
|
||||||
|
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear list")) {
|
||||||
|
Settings::application.recentRecordings.filenames.clear();
|
||||||
|
Settings::application.recentRecordings.front_is_valid = false;
|
||||||
|
setNewMedia(MEDIA_RECORDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( new_media_mode == MEDIA_RECENT ) {
|
||||||
|
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear list")) {
|
||||||
|
Settings::application.recentImport.filenames.clear();
|
||||||
|
Settings::application.recentImport.front_is_valid = false;
|
||||||
|
setNewMedia(MEDIA_RECENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::SetCursorPos(pos_top);
|
||||||
|
|
||||||
|
// change session list if changed
|
||||||
|
if (new_media_mode_changed || Settings::application.recentImport.changed || Settings::application.recentRecordings.changed) {
|
||||||
|
|
||||||
|
// MODE RECENT
|
||||||
|
if ( new_media_mode == MEDIA_RECENT) {
|
||||||
|
// show list of recent imports
|
||||||
|
Settings::application.recentImport.validate();
|
||||||
|
sourceMediaFiles = Settings::application.recentImport.filenames;
|
||||||
|
Settings::application.recentImport.changed = false;
|
||||||
|
}
|
||||||
|
// MODE RECORDINGS
|
||||||
|
else if ( new_media_mode == MEDIA_RECORDING) {
|
||||||
|
// show list of recent records
|
||||||
|
Settings::application.recentRecordings.validate();
|
||||||
|
sourceMediaFiles = Settings::application.recentRecordings.filenames;
|
||||||
|
Settings::application.recentRecordings.changed = false;
|
||||||
|
}
|
||||||
|
// MODE LIST FOLDER
|
||||||
|
else if ( new_media_mode == MEDIA_FOLDER) {
|
||||||
|
// show list of media files in folder
|
||||||
|
sourceMediaFiles = SystemToolkit::list_directory( Settings::application.recentImportFolders.path, { MEDIA_FILES_PATTERN });
|
||||||
|
}
|
||||||
|
// indicate the list changed (do not change at every frame)
|
||||||
|
new_media_mode_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// different labels for each mode
|
||||||
|
static const char *listboxname[3] = { "##NewSourceMediaRecent", "##NewSourceMediaRecording", "##NewSourceMediafolder"};
|
||||||
|
// display the import-list and detect if one was selected
|
||||||
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
|
if (ImGui::ListBoxHeader(listboxname[new_media_mode], sourceMediaFiles.size(), CLAMP(sourceMediaFiles.size(), 4, 6)) ) {
|
||||||
|
// loop over list of files
|
||||||
|
for(auto it = sourceMediaFiles.begin(); it != sourceMediaFiles.end(); ++it) {
|
||||||
|
// build displayed file name
|
||||||
|
std::string filename = BaseToolkit::transliterate(*it);
|
||||||
|
std::string label = BaseToolkit::trunc_string(SystemToolkit::filename(filename), 25);
|
||||||
|
// add selectable item to ListBox; open if clickec
|
||||||
|
if (ImGui::Selectable( label.c_str(), sourceMediaFileCurrent.compare(*it) == 0 )) {
|
||||||
|
// set new source preview
|
||||||
|
new_source_preview_.setSource( Mixer::manager().createSourceFile(*it), filename);
|
||||||
|
// remember current list item
|
||||||
|
sourceMediaFileCurrent = *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::ListBoxFooter();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Folder Source creator
|
// Folder Source creator
|
||||||
else if (Settings::application.source.new_type == 1){
|
else if (Settings::application.source.new_type == SOURCE_SEQUENCE){
|
||||||
|
|
||||||
bool update_new_source = false;
|
bool update_new_source = false;
|
||||||
static DialogToolkit::MultipleImagesDialog _selectImagesDialog("Select Images");
|
static DialogToolkit::MultipleImagesDialog _selectImagesDialog("Select Images");
|
||||||
|
|
||||||
// clic button to load file
|
// clic button to load file
|
||||||
if ( ImGui::Button( ICON_FA_IMAGES " Open images", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) ) {
|
if ( ImGui::Button( ICON_FA_IMAGES " Open images", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) ) {
|
||||||
_selectedFiles.clear();
|
sourceSequenceFiles.clear();
|
||||||
_selectImagesDialog.open();
|
_selectImagesDialog.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4140,15 +4281,15 @@ void Navigator::RenderNewPannel()
|
|||||||
|
|
||||||
// return from thread for folder openning
|
// return from thread for folder openning
|
||||||
if (_selectImagesDialog.closed()) {
|
if (_selectImagesDialog.closed()) {
|
||||||
_selectedFiles = _selectImagesDialog.images();
|
sourceSequenceFiles = _selectImagesDialog.images();
|
||||||
if (_selectedFiles.empty())
|
if (sourceSequenceFiles.empty())
|
||||||
Log::Notify("No file selected.");
|
Log::Notify("No file selected.");
|
||||||
// ask to reload the preview
|
// ask to reload the preview
|
||||||
update_new_source = true;
|
update_new_source = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiple files selected
|
// multiple files selected
|
||||||
if (_selectedFiles.size() > 1) {
|
if (sourceSequenceFiles.size() > 1) {
|
||||||
|
|
||||||
// set framerate
|
// set framerate
|
||||||
static int _fps = 30;
|
static int _fps = 30;
|
||||||
@@ -4164,27 +4305,27 @@ void Navigator::RenderNewPannel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (update_new_source) {
|
if (update_new_source) {
|
||||||
std::string label = BaseToolkit::transliterate( BaseToolkit::common_pattern(_selectedFiles) );
|
std::string label = BaseToolkit::transliterate( BaseToolkit::common_pattern(sourceSequenceFiles) );
|
||||||
label = BaseToolkit::trunc_string(label, 35);
|
label = BaseToolkit::trunc_string(label, 35);
|
||||||
new_source_preview_.setSource( Mixer::manager().createSourceMultifile(_selectedFiles, _fps), label);
|
new_source_preview_.setSource( Mixer::manager().createSourceMultifile(sourceSequenceFiles, _fps), label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// single file selected
|
// single file selected
|
||||||
else if (_selectedFiles.size() > 0) {
|
else if (sourceSequenceFiles.size() > 0) {
|
||||||
|
|
||||||
ImGui::Text("Single file selected");
|
ImGui::Text("Single file selected");
|
||||||
|
|
||||||
if (update_new_source) {
|
if (update_new_source) {
|
||||||
std::string label = BaseToolkit::transliterate( _selectedFiles.front() );
|
std::string label = BaseToolkit::transliterate( sourceSequenceFiles.front() );
|
||||||
label = BaseToolkit::trunc_string(label, 35);
|
label = BaseToolkit::trunc_string(label, 35);
|
||||||
new_source_preview_.setSource( Mixer::manager().createSourceFile(_selectedFiles.front()), label);
|
new_source_preview_.setSource( Mixer::manager().createSourceFile(sourceSequenceFiles.front()), label);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Internal Source creator
|
// Internal Source creator
|
||||||
else if (Settings::application.source.new_type == 4){
|
else if (Settings::application.source.new_type == SOURCE_INTERNAL){
|
||||||
|
|
||||||
// fill new_source_preview with a new source
|
// fill new_source_preview with a new source
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
@@ -4213,7 +4354,7 @@ void Navigator::RenderNewPannel()
|
|||||||
ICON_FA_CARET_RIGHT " Clone other sources");
|
ICON_FA_CARET_RIGHT " Clone other sources");
|
||||||
}
|
}
|
||||||
// Generated Source creator
|
// Generated Source creator
|
||||||
else if (Settings::application.source.new_type == 3){
|
else if (Settings::application.source.new_type == SOURCE_GENERATED){
|
||||||
|
|
||||||
bool update_new_source = false;
|
bool update_new_source = false;
|
||||||
|
|
||||||
@@ -4255,7 +4396,7 @@ void Navigator::RenderNewPannel()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// External source creator
|
// External source creator
|
||||||
else if (Settings::application.source.new_type == 2){
|
else if (Settings::application.source.new_type == SOURCE_CONNECTED){
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
if (ImGui::BeginCombo("##External", "Select device"))
|
if (ImGui::BeginCombo("##External", "Select device"))
|
||||||
@@ -4290,7 +4431,7 @@ void Navigator::RenderNewPannel()
|
|||||||
// if a new source was added
|
// if a new source was added
|
||||||
if (new_source_preview_.filled()) {
|
if (new_source_preview_.filled()) {
|
||||||
// show preview
|
// show preview
|
||||||
new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, Settings::application.source.new_type != 2);
|
new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
|
||||||
// ask to import the source in the mixer
|
// ask to import the source in the mixer
|
||||||
ImGui::NewLine();
|
ImGui::NewLine();
|
||||||
if (new_source_preview_.ready() && ImGui::Button( ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) {
|
if (new_source_preview_.ready() && ImGui::Button( ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) {
|
||||||
@@ -4340,13 +4481,13 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
if (ImGui::BeginCombo("##SelectionSession", BaseToolkit::trunc_string(Settings::application.recentFolders.path, 25).c_str() )) {
|
if (ImGui::BeginCombo("##SelectionSession", BaseToolkit::trunc_string(Settings::application.recentFolders.path, 25).c_str() )) {
|
||||||
|
|
||||||
// Option 0 : recent files
|
// Mode 0 : recent files
|
||||||
if (ImGui::Selectable( ICON_FA_CLOCK IMGUI_LABEL_RECENT_FILES) ) {
|
if (ImGui::Selectable( ICON_FA_LIST_OL IMGUI_LABEL_RECENT_FILES) ) {
|
||||||
Settings::application.recentFolders.path = IMGUI_LABEL_RECENT_FILES;
|
Settings::application.recentFolders.path = IMGUI_LABEL_RECENT_FILES;
|
||||||
selection_session_mode = 0;
|
selection_session_mode = 0;
|
||||||
selection_session_mode_changed = true;
|
selection_session_mode_changed = true;
|
||||||
}
|
}
|
||||||
// Options 1 : known folders
|
// Mode 1 : known folders
|
||||||
for(auto foldername = Settings::application.recentFolders.filenames.begin();
|
for(auto foldername = Settings::application.recentFolders.filenames.begin();
|
||||||
foldername != Settings::application.recentFolders.filenames.end(); foldername++) {
|
foldername != Settings::application.recentFolders.filenames.end(); foldername++) {
|
||||||
std::string f = std::string(ICON_FA_FOLDER) + " " + BaseToolkit::trunc_string( *foldername, 40);
|
std::string f = std::string(ICON_FA_FOLDER) + " " + BaseToolkit::trunc_string( *foldername, 40);
|
||||||
@@ -4358,7 +4499,7 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
selection_session_mode_changed = true;
|
selection_session_mode_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Option 2 : add a folder
|
// Add a folder
|
||||||
if (ImGui::Selectable( ICON_FA_FOLDER_PLUS " Add Folder") )
|
if (ImGui::Selectable( ICON_FA_FOLDER_PLUS " Add Folder") )
|
||||||
customFolder.open();
|
customFolder.open();
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
@@ -4390,7 +4531,7 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear history")) {
|
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear list")) {
|
||||||
Settings::application.recentSessions.filenames.clear();
|
Settings::application.recentSessions.filenames.clear();
|
||||||
Settings::application.recentSessions.front_is_valid = false;
|
Settings::application.recentSessions.front_is_valid = false;
|
||||||
// reload the list next time
|
// reload the list next time
|
||||||
@@ -4690,7 +4831,7 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
|
||||||
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear undo")) {
|
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear history")) {
|
||||||
Action::manager().init();
|
Action::manager().init();
|
||||||
}
|
}
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
@@ -5226,7 +5367,7 @@ void SourcePreview::setSource(Source *s, const string &label)
|
|||||||
delete source_;
|
delete source_;
|
||||||
|
|
||||||
source_ = s;
|
source_ = s;
|
||||||
label_ = label;
|
label_ = BaseToolkit::trunc_string(label, 35);
|
||||||
reset_ = true;
|
reset_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5237,7 +5378,7 @@ Source * SourcePreview::getSource()
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourcePreview::Render(float width, bool controlbutton)
|
void SourcePreview::Render(float width)
|
||||||
{
|
{
|
||||||
if(source_) {
|
if(source_) {
|
||||||
// cancel if failed
|
// cancel if failed
|
||||||
@@ -5270,15 +5411,21 @@ void SourcePreview::Render(float width, bool controlbutton)
|
|||||||
FrameBuffer *frame = source_->frame();
|
FrameBuffer *frame = source_->frame();
|
||||||
ImVec2 preview_size(width, width / frame->aspectRatio());
|
ImVec2 preview_size(width, width / frame->aspectRatio());
|
||||||
ImGui::Image((void*)(uintptr_t) frame->texture(), preview_size);
|
ImGui::Image((void*)(uintptr_t) frame->texture(), preview_size);
|
||||||
|
// if the source is playable and once its ready
|
||||||
if (controlbutton && source_->ready()) {
|
if (source_->playable() && source_->ready()) {
|
||||||
ImVec2 pos = ImGui::GetCursorPos();
|
// activate the source on mouse over
|
||||||
ImGui::SameLine();
|
bool activate = ImGui::IsItemHovered();
|
||||||
bool active = source_->active();
|
if (source_->active() != activate)
|
||||||
if (ImGuiToolkit::IconToggle(12,7,1,8, &active))
|
source_->setActive(activate);
|
||||||
source_->setActive(active);
|
// show icon '>' to indicate if we can activate it
|
||||||
ImGui::SetCursorPos(pos);
|
if (!activate) {
|
||||||
|
ImVec2 pos = ImGui::GetCursorPos();
|
||||||
|
ImGui::SetCursorPos(pos + preview_size * ImVec2(0.5f, -0.6f));
|
||||||
|
ImGuiToolkit::Icon(12,7);
|
||||||
|
ImGui::SetCursorPos(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// information text
|
||||||
ImGuiToolkit::Icon(source_->icon().x, source_->icon().y);
|
ImGuiToolkit::Icon(source_->icon().x, source_->icon().y);
|
||||||
ImGui::SameLine(0, 10);
|
ImGui::SameLine(0, 10);
|
||||||
ImGui::Text("%s", label_.c_str());
|
ImGui::Text("%s", label_.c_str());
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ struct ImVec2;
|
|||||||
class MediaPlayer;
|
class MediaPlayer;
|
||||||
class FrameBufferImage;
|
class FrameBufferImage;
|
||||||
class FrameGrabber;
|
class FrameGrabber;
|
||||||
|
class VideoRecorder;
|
||||||
|
|
||||||
class SourcePreview {
|
class SourcePreview {
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ public:
|
|||||||
void setSource(Source *s = nullptr, const std::string &label = "");
|
void setSource(Source *s = nullptr, const std::string &label = "");
|
||||||
Source *getSource();
|
Source *getSource();
|
||||||
|
|
||||||
void Render(float width, bool controlbutton = false);
|
void Render(float width);
|
||||||
bool ready() const;
|
bool ready() const;
|
||||||
inline bool filled() const { return source_ != nullptr; }
|
inline bool filled() const { return source_ != nullptr; }
|
||||||
};
|
};
|
||||||
@@ -67,7 +68,6 @@ class Navigator
|
|||||||
bool view_pannel_visible;
|
bool view_pannel_visible;
|
||||||
bool selected_button[NAV_COUNT];
|
bool selected_button[NAV_COUNT];
|
||||||
int pattern_type;
|
int pattern_type;
|
||||||
std::list<std::string> _selectedFiles;
|
|
||||||
void clearButtonSelection();
|
void clearButtonSelection();
|
||||||
void applyButtonSelection(int index);
|
void applyButtonSelection(int index);
|
||||||
|
|
||||||
@@ -80,8 +80,6 @@ class Navigator
|
|||||||
void RenderNewPannel();
|
void RenderNewPannel();
|
||||||
void RenderViewPannel(ImVec2 draw_pos, ImVec2 draw_size);
|
void RenderViewPannel(ImVec2 draw_pos, ImVec2 draw_size);
|
||||||
|
|
||||||
SourcePreview new_source_preview_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Navigator();
|
Navigator();
|
||||||
|
|
||||||
@@ -92,7 +90,31 @@ public:
|
|||||||
void togglePannelNew();
|
void togglePannelNew();
|
||||||
void showConfig();
|
void showConfig();
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MEDIA_RECENT = 0,
|
||||||
|
MEDIA_RECORDING,
|
||||||
|
MEDIA_FOLDER
|
||||||
|
} MediaCreateMode;
|
||||||
|
void setNewMedia(MediaCreateMode mode, std::string path = std::string());
|
||||||
|
|
||||||
void Render();
|
void Render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// for new source panel
|
||||||
|
typedef enum {
|
||||||
|
SOURCE_FILE = 0,
|
||||||
|
SOURCE_SEQUENCE,
|
||||||
|
SOURCE_CONNECTED,
|
||||||
|
SOURCE_GENERATED,
|
||||||
|
SOURCE_INTERNAL,
|
||||||
|
SOURCE_TYPES
|
||||||
|
} NewSourceType;
|
||||||
|
SourcePreview new_source_preview_;
|
||||||
|
std::list<std::string> sourceSequenceFiles;
|
||||||
|
std::list<std::string> sourceMediaFiles;
|
||||||
|
std::string sourceMediaFileCurrent;
|
||||||
|
MediaCreateMode new_media_mode;
|
||||||
|
bool new_media_mode_changed;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ToolBox
|
class ToolBox
|
||||||
@@ -199,7 +221,7 @@ class UserInterface
|
|||||||
unsigned int screenshot_step;
|
unsigned int screenshot_step;
|
||||||
|
|
||||||
// frame grabbers
|
// frame grabbers
|
||||||
FrameGrabber *video_recorder_;
|
VideoRecorder *video_recorder_;
|
||||||
|
|
||||||
#if defined(LINUX)
|
#if defined(LINUX)
|
||||||
FrameGrabber *webcam_emulator_;
|
FrameGrabber *webcam_emulator_;
|
||||||
|
|||||||
@@ -72,6 +72,7 @@
|
|||||||
#define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput"
|
#define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput"
|
||||||
#define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?"
|
#define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?"
|
||||||
#define IMGUI_LABEL_RECENT_FILES " Recent files"
|
#define IMGUI_LABEL_RECENT_FILES " Recent files"
|
||||||
|
#define IMGUI_LABEL_RECENT_RECORDS " Recent recordings"
|
||||||
#define IMGUI_RIGHT_ALIGN -3.5f * ImGui::GetTextLineHeightWithSpacing()
|
#define IMGUI_RIGHT_ALIGN -3.5f * ImGui::GetTextLineHeightWithSpacing()
|
||||||
#define IMGUI_TOP_ALIGN 10
|
#define IMGUI_TOP_ALIGN 10
|
||||||
#define IMGUI_COLOR_OVERLAY IM_COL32(5, 5, 5, 150)
|
#define IMGUI_COLOR_OVERLAY IM_COL32(5, 5, 5, 150)
|
||||||
|
|||||||
Reference in New Issue
Block a user