mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-17 05:09:58 +01:00
Change Player menu and new Frame inspector
Frame menu is active when a single source is selected. The Frame menu include actions to capture frame and to enable Frame Inspector. Frame inspector zooms on the image at cursor coordinate. Previous Control menu actions are back to main menu.
This commit is contained in:
@@ -173,6 +173,7 @@ void Settings::Save(uint64_t runtime)
|
|||||||
SourceConfNode->SetAttribute("res", application.source.res);
|
SourceConfNode->SetAttribute("res", application.source.res);
|
||||||
SourceConfNode->SetAttribute("capture_naming", application.source.capture_naming);
|
SourceConfNode->SetAttribute("capture_naming", application.source.capture_naming);
|
||||||
SourceConfNode->SetAttribute("capture_path", application.source.capture_path.c_str());
|
SourceConfNode->SetAttribute("capture_path", application.source.capture_path.c_str());
|
||||||
|
SourceConfNode->SetAttribute("inspector_zoom", application.source.inspector_zoom);
|
||||||
pRoot->InsertEndChild(SourceConfNode);
|
pRoot->InsertEndChild(SourceConfNode);
|
||||||
|
|
||||||
// Brush
|
// Brush
|
||||||
@@ -422,6 +423,7 @@ void Settings::Load()
|
|||||||
application.source.capture_path = std::string(path_);
|
application.source.capture_path = std::string(path_);
|
||||||
else
|
else
|
||||||
application.source.capture_path = SystemToolkit::home_path();
|
application.source.capture_path = SystemToolkit::home_path();
|
||||||
|
sourceconfnode->QueryFloatAttribute("inspector_zoom", &application.source.inspector_zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transition
|
// Transition
|
||||||
|
|||||||
@@ -169,12 +169,14 @@ struct SourceConfig
|
|||||||
int res;
|
int res;
|
||||||
std::string capture_path;
|
std::string capture_path;
|
||||||
int capture_naming;
|
int capture_naming;
|
||||||
|
float inspector_zoom;
|
||||||
|
|
||||||
SourceConfig() {
|
SourceConfig() {
|
||||||
new_type = 0;
|
new_type = 0;
|
||||||
ratio = 3;
|
ratio = 3;
|
||||||
res = 1;
|
res = 1;
|
||||||
capture_naming = 0;
|
capture_naming = 0;
|
||||||
|
inspector_zoom = 8.f;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2235,25 +2235,27 @@ void SourceController::Update()
|
|||||||
Settings::application.source.capture_path = captureFolderDialog->path();
|
Settings::application.source.capture_path = captureFolderDialog->path();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Capture frame on current source
|
// Capture frame on current selection
|
||||||
//
|
//
|
||||||
Source *source = Mixer::manager().currentSource();
|
Source *s = nullptr;
|
||||||
if (source != nullptr) {
|
if ( selection_.size() == 1 )
|
||||||
|
s = selection_.front();
|
||||||
|
if ( s != nullptr) {
|
||||||
// back from capture of FBO: can save file
|
// back from capture of FBO: can save file
|
||||||
if ( capture.isFull() ){
|
if ( capture.isFull() ){
|
||||||
std::string filename;
|
std::string filename;
|
||||||
// if sequencial naming of file is selected
|
// if sequencial naming of file is selected
|
||||||
if (Settings::application.source.capture_naming == 0 )
|
if (Settings::application.source.capture_naming == 0 )
|
||||||
filename = SystemToolkit::filename_sequential(Settings::application.source.capture_path, source->name(), "png");
|
filename = SystemToolkit::filename_sequential(Settings::application.source.capture_path, s->name(), "png");
|
||||||
else
|
else
|
||||||
filename = SystemToolkit::filename_dateprefix(Settings::application.source.capture_path, source->name(), "png");
|
filename = SystemToolkit::filename_dateprefix(Settings::application.source.capture_path, s->name(), "png");
|
||||||
// save capture and inform user
|
// save capture and inform user
|
||||||
capture.save( filename );
|
capture.save( filename );
|
||||||
Log::Notify("Frame saved in %s", filename.c_str() );
|
Log::Notify("Frame saved in %s", filename.c_str() );
|
||||||
}
|
}
|
||||||
// request capture : initiate capture of FBO
|
// request capture : initiate capture of FBO
|
||||||
if ( capture_request_ ) {
|
if ( capture_request_ ) {
|
||||||
capture.captureFramebuffer(source->frame());
|
capture.captureFramebuffer( s->frame() );
|
||||||
capture_request_ = false;
|
capture_request_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2300,6 +2302,15 @@ void SourceController::Render()
|
|||||||
}
|
}
|
||||||
if (ImGui::BeginMenu(IMGUI_TITLE_MEDIAPLAYER))
|
if (ImGui::BeginMenu(IMGUI_TITLE_MEDIAPLAYER))
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// Menu section for play control
|
||||||
|
//
|
||||||
|
if (ImGui::MenuItem( ICON_FA_FAST_BACKWARD " Restart", CTRL_MOD "Space", nullptr, !selection_.empty()))
|
||||||
|
replay_request_ = true;
|
||||||
|
if (ImGui::MenuItem( ICON_FA_PLAY " Play | Pause", "Space", nullptr, !selection_.empty()))
|
||||||
|
play_toggle_request_ = true;
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
//
|
//
|
||||||
// Menu section for display
|
// Menu section for display
|
||||||
//
|
//
|
||||||
@@ -2346,25 +2357,57 @@ void SourceController::Render()
|
|||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginMenu(ICON_FA_PLAY " Control"))
|
if (ImGui::BeginMenu(active_label_.c_str()))
|
||||||
{
|
{
|
||||||
//
|
// info on selection status
|
||||||
// Menu section for play control
|
size_t N = Mixer::manager().session()->numPlayGroups();
|
||||||
//
|
bool enabled = !selection_.empty() && active_selection_ < 0;
|
||||||
if (ImGui::MenuItem( ICON_FA_FAST_BACKWARD " Restart", CTRL_MOD "Space", nullptr, !selection_.empty()))
|
|
||||||
replay_request_ = true;
|
|
||||||
if (ImGui::MenuItem( ICON_FA_PLAY " Play | Pause", "Space", nullptr, !selection_.empty()))
|
|
||||||
play_toggle_request_ = true;
|
|
||||||
|
|
||||||
|
// Menu : Dynamic selection
|
||||||
|
if (ImGui::MenuItem(LABEL_AUTO_MEDIA_PLAYER))
|
||||||
|
resetActiveSelection();
|
||||||
|
// Menu : store selection
|
||||||
|
if (ImGui::MenuItem(ICON_FA_PLUS_SQUARE LABEL_STORE_SELECTION, NULL, false, enabled))
|
||||||
|
{
|
||||||
|
active_selection_ = N;
|
||||||
|
active_label_ = std::string(ICON_FA_CHECK_SQUARE " Selection #") + std::to_string(active_selection_);
|
||||||
|
Mixer::manager().session()->addPlayGroup( ids(playable_only(selection_)) );
|
||||||
|
info_.reset();
|
||||||
|
}
|
||||||
|
// Menu : list of selections
|
||||||
|
if (N>0) {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
for (size_t i = 0 ; i < N; ++i)
|
||||||
|
{
|
||||||
|
std::string label = std::string(ICON_FA_CHECK_SQUARE " Selection #") + std::to_string(i);
|
||||||
|
if (ImGui::MenuItem( label.c_str() ))
|
||||||
|
{
|
||||||
|
active_selection_ = i;
|
||||||
|
active_label_ = label;
|
||||||
|
info_.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Menu for capture frame
|
// Menu for capture frame
|
||||||
//
|
//
|
||||||
|
if ( ImGui::BeginMenu(ICON_FA_PHOTO_VIDEO " Frame", selection_.size() == 1 ) )
|
||||||
|
{
|
||||||
|
bool inspect = Settings::application.source.inspector_zoom > 0.f;
|
||||||
|
if (ImGui::MenuItem( ICON_FA_SEARCH " Inspector", NULL, &inspect ))
|
||||||
|
Settings::application.source.inspector_zoom = inspect ? 8.f : 0.f;
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_CAPTURE, 0.8f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_CAPTURE, 0.8f));
|
||||||
if (ImGui::MenuItem( ICON_FA_CAMERA_RETRO " Capture frame", "F10", nullptr, Mixer::manager().currentSource() != nullptr ))
|
if (ImGui::MenuItem( MENU_CAPTUREFRAME, "F10" ))
|
||||||
capture_request_ = true;
|
capture_request_ = true;
|
||||||
ImGui::PopStyleColor(1);
|
ImGui::PopStyleColor(1);
|
||||||
|
|
||||||
|
// separator and hack for extending menu width
|
||||||
|
ImGui::Separator();
|
||||||
ImGui::MenuItem("Settings ", nullptr, false, false);
|
ImGui::MenuItem("Settings ", nullptr, false, false);
|
||||||
|
|
||||||
// path menu selection
|
// path menu selection
|
||||||
@@ -2410,43 +2453,10 @@ void SourceController::Render()
|
|||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginMenu(active_label_.c_str()))
|
//
|
||||||
{
|
// Menu for video Mediaplayer control
|
||||||
// info on selection status
|
//
|
||||||
size_t N = Mixer::manager().session()->numPlayGroups();
|
if (ImGui::BeginMenu(ICON_FA_FILM " Video", mediaplayer_active_) )
|
||||||
bool enabled = !selection_.empty() && active_selection_ < 0;
|
|
||||||
|
|
||||||
// Menu : Dynamic selection
|
|
||||||
if (ImGui::MenuItem(LABEL_AUTO_MEDIA_PLAYER))
|
|
||||||
resetActiveSelection();
|
|
||||||
// Menu : store selection
|
|
||||||
if (ImGui::MenuItem(ICON_FA_PLUS_SQUARE LABEL_STORE_SELECTION, NULL, false, enabled))
|
|
||||||
{
|
|
||||||
active_selection_ = N;
|
|
||||||
active_label_ = std::string(ICON_FA_CHECK_SQUARE " Selection #") + std::to_string(active_selection_);
|
|
||||||
Mixer::manager().session()->addPlayGroup( ids(playable_only(selection_)) );
|
|
||||||
info_.reset();
|
|
||||||
}
|
|
||||||
// Menu : list of selections
|
|
||||||
if (N>0) {
|
|
||||||
ImGui::Separator();
|
|
||||||
for (size_t i = 0 ; i < N; ++i)
|
|
||||||
{
|
|
||||||
std::string label = std::string(ICON_FA_CHECK_SQUARE " Selection #") + std::to_string(i);
|
|
||||||
if (ImGui::MenuItem( label.c_str() ))
|
|
||||||
{
|
|
||||||
active_selection_ = i;
|
|
||||||
active_label_ = label;
|
|
||||||
info_.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mediaplayer_active_) {
|
|
||||||
if (ImGui::BeginMenu(ICON_FA_FILM " Video") )
|
|
||||||
{
|
{
|
||||||
if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset timeline")){
|
if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset timeline")){
|
||||||
mediaplayer_timeline_zoom_ = 1.f;
|
mediaplayer_timeline_zoom_ = 1.f;
|
||||||
@@ -2503,11 +2513,6 @@ void SourceController::Render()
|
|||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::SameLine(0, 2.f * g.Style.ItemSpacing.x );
|
|
||||||
ImGui::TextDisabled(ICON_FA_FILM " Video");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
@@ -3015,6 +3020,43 @@ bool SourceController::SourceButton(Source *s, ImVec2 framesize)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawInspector(uint texture, ImVec2 texturesize, ImVec2 origin)
|
||||||
|
{
|
||||||
|
if (Settings::application.source.inspector_zoom > 0 && ImGui::IsWindowFocused())
|
||||||
|
{
|
||||||
|
// region size is computed with zoom factor from settings
|
||||||
|
float region_sz = texturesize.x / Settings::application.source.inspector_zoom;
|
||||||
|
|
||||||
|
// get coordinates of area to zoom at mouse position
|
||||||
|
const ImGuiIO& io = ImGui::GetIO();
|
||||||
|
float region_x = io.MousePos.x - origin.x - region_sz * 0.5f;
|
||||||
|
if (region_x < 0.f)
|
||||||
|
region_x = 0.f;
|
||||||
|
else if (region_x > texturesize.x - region_sz)
|
||||||
|
region_x = texturesize.x - region_sz;
|
||||||
|
|
||||||
|
float region_y = io.MousePos.y - origin.y - region_sz * 0.5f;
|
||||||
|
if (region_y < 0.f)
|
||||||
|
region_y = 0.f;
|
||||||
|
else if (region_y > texturesize.y - region_sz)
|
||||||
|
region_y = texturesize.y - region_sz;
|
||||||
|
|
||||||
|
// Tooltip without border and 100% opaque
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 1.f);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.f);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.f, 0.f) );
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
|
||||||
|
// compute UV and display image in tooltip
|
||||||
|
ImVec2 uv0 = ImVec2((region_x) / texturesize.x, (region_y) / texturesize.y);
|
||||||
|
ImVec2 uv1 = ImVec2((region_x + region_sz) / texturesize.x, (region_y + region_sz) / texturesize.y);
|
||||||
|
ImGui::Image((void*)(intptr_t)texture, ImVec2(texturesize.x / 3.f, texturesize.x / 3.f), uv0, uv1, ImVec4(1.0f, 1.0f, 1.0f, 1.0f), ImVec4(1.0f, 1.0f, 1.0f, 0.5f));
|
||||||
|
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
ImGui::PopStyleVar(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize)
|
ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize)
|
||||||
{
|
{
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
@@ -3049,6 +3091,8 @@ ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize)
|
|||||||
//
|
//
|
||||||
ImVec2 slider = framesize * ImVec2(Settings::application.widget.media_player_slider,1.f);
|
ImVec2 slider = framesize * ImVec2(Settings::application.widget.media_player_slider,1.f);
|
||||||
ImGui::Image((void*)(uintptr_t) s->texture(), slider, ImVec2(0.f,0.f), ImVec2(Settings::application.widget.media_player_slider,1.f));
|
ImGui::Image((void*)(uintptr_t) s->texture(), slider, ImVec2(0.f,0.f), ImVec2(Settings::application.widget.media_player_slider,1.f));
|
||||||
|
if ( ImGui::IsItemHovered() )
|
||||||
|
DrawInspector(s->texture(), framesize, top_image);
|
||||||
|
|
||||||
//
|
//
|
||||||
// RIGHT of slider : post-processed image (after crop and color correction)
|
// RIGHT of slider : post-processed image (after crop and color correction)
|
||||||
@@ -3060,6 +3104,8 @@ ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize)
|
|||||||
// draw cropped area
|
// draw cropped area
|
||||||
ImGui::SetCursorScreenPos(top_image + croptop );
|
ImGui::SetCursorScreenPos(top_image + croptop );
|
||||||
ImGui::Image((void*)(uintptr_t) s->frame()->texture(), cropsize, ImVec2(0.f, 0.f), ImVec2(1.f,1.f));
|
ImGui::Image((void*)(uintptr_t) s->frame()->texture(), cropsize, ImVec2(0.f, 0.f), ImVec2(1.f,1.f));
|
||||||
|
if ( ImGui::IsItemHovered() )
|
||||||
|
DrawInspector(s->frame()->texture(), framesize, top_image);
|
||||||
}
|
}
|
||||||
// overlap of slider with cropped area (horizontally)
|
// overlap of slider with cropped area (horizontally)
|
||||||
else if (slider.x < croptop.x + cropsize.x ) {
|
else if (slider.x < croptop.x + cropsize.x ) {
|
||||||
@@ -3071,6 +3117,8 @@ ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize)
|
|||||||
// size is reduced by slider
|
// size is reduced by slider
|
||||||
cropsize = cropsize * ImVec2(1.f -cropped_slider, 1.f);
|
cropsize = cropsize * ImVec2(1.f -cropped_slider, 1.f);
|
||||||
ImGui::Image((void*)(uintptr_t) s->frame()->texture(), cropsize, ImVec2(cropped_slider, 0.f), ImVec2(1.f,1.f));
|
ImGui::Image((void*)(uintptr_t) s->frame()->texture(), cropsize, ImVec2(cropped_slider, 0.f), ImVec2(1.f,1.f));
|
||||||
|
if ( ImGui::IsItemHovered() )
|
||||||
|
DrawInspector(s->frame()->texture(), framesize, top_image);
|
||||||
}
|
}
|
||||||
// else : no render of cropped area
|
// else : no render of cropped area
|
||||||
|
|
||||||
@@ -3090,6 +3138,8 @@ ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImGui::Image((void*)(uintptr_t) s->texture(), framesize);
|
ImGui::Image((void*)(uintptr_t) s->texture(), framesize);
|
||||||
|
if ( ImGui::IsItemHovered() )
|
||||||
|
DrawInspector(s->texture(), framesize, top_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImRect( top_image, top_image + framesize);
|
return ImRect( top_image, top_image + framesize);
|
||||||
|
|||||||
Reference in New Issue
Block a user