UI WorkspaceWindows follow window resize

Fixed bug in restore window position.
This commit is contained in:
Bruno Herbelin
2022-01-06 14:58:35 +01:00
parent b894ea866a
commit d4f370c071
4 changed files with 139 additions and 120 deletions

View File

@@ -134,6 +134,10 @@ static void WindowRefreshCallback( GLFWwindow * )
static void WindowResizeCallback( GLFWwindow *w, int width, int height) static void WindowResizeCallback( GLFWwindow *w, int width, int height)
{ {
// UI manager tries to keep windows in the workspace
WorkspaceWindow::notifyWorkspaceSizeChanged(GLFW_window_[w]->previous_size.x, GLFW_window_[w]->previous_size.y, width, height);
GLFW_window_[w]->previous_size = glm::vec2(width, height);
int id = GLFW_window_[w]->index(); int id = GLFW_window_[w]->index();
if (!Settings::application.windows[id].fullscreen) { if (!Settings::application.windows[id].fullscreen) {
Settings::application.windows[id].w = width; Settings::application.windows[id].w = width;
@@ -724,6 +728,8 @@ bool RenderingWindow::init(int index, GLFWwindow *share)
// ensure minimal window size // ensure minimal window size
glfwSetWindowSizeLimits(window_, 800, 500, GLFW_DONT_CARE, GLFW_DONT_CARE); glfwSetWindowSizeLimits(window_, 800, 500, GLFW_DONT_CARE, GLFW_DONT_CARE);
previous_size = glm::vec2(winset.w, winset.h);
// set initial position // set initial position
glfwSetWindowPos(window_, winset.x, winset.y); glfwSetWindowPos(window_, winset.x, winset.y);

View File

@@ -85,6 +85,8 @@ public:
static GLFWmonitor *monitorAt(int x, int y); static GLFWmonitor *monitorAt(int x, int y);
// get which monitor has this name // get which monitor has this name
static GLFWmonitor *monitorNamed(const std::string &name); static GLFWmonitor *monitorNamed(const std::string &name);
glm::vec2 previous_size;
}; };
class Rendering class Rendering

View File

@@ -1878,6 +1878,8 @@ struct ImGuiProperties
float progress; // [0 1] float progress; // [0 1]
float target; // 1 go to outside, 0 go to user pos float target; // 1 go to outside, 0 go to user pos
bool animation; // need animation bool animation; // need animation
bool resizing_workspace;
ImVec2 resized_pos;
ImGuiProperties () ImGuiProperties ()
{ {
@@ -1885,6 +1887,7 @@ struct ImGuiProperties
progress = 0.f; progress = 0.f;
target = 0.f; target = 0.f;
animation = false; animation = false;
resizing_workspace = false;
} }
}; };
@@ -1903,67 +1906,96 @@ void WorkspaceWindow::toggleClearRestoreWorkspace()
void WorkspaceWindow::restoreWorkspace(bool instantaneous) void WorkspaceWindow::restoreWorkspace(bool instantaneous)
{ {
clear_workspace_enabled = false; if (clear_workspace_enabled) {
const ImVec2 display_size = ImGui::GetIO().DisplaySize;
for(auto it = windows_.cbegin(); it != windows_.cend(); ++it) {
ImGuiProperties *impl = (*it)->impl_;
if (impl && impl->ptr)
{
float margin = (impl->ptr->MenuBarHeight() + impl->ptr->TitleBarHeight()) * 3.f;
impl->user_pos.x = CLAMP(impl->user_pos.x, -impl->ptr->SizeFull.x +margin, display_size.x -margin);
impl->user_pos.y = CLAMP(impl->user_pos.y, -impl->ptr->SizeFull.y +margin, display_size.y -margin);
for(auto it = windows_.cbegin(); it != windows_.cend(); ++it) { if (instantaneous) {
ImGuiProperties *impl = (*it)->impl_; impl->animation = false;
if (impl && impl->ptr) ImGui::SetWindowPos(impl->ptr, impl->user_pos);
{ }
if (instantaneous) { else {
impl->animation = false; // remember outside position before move
ImGui::SetWindowPos(impl->ptr, impl->user_pos); impl->outside_pos = impl->ptr->Pos;
}
else {
// remember outside position before move
impl->outside_pos = impl->ptr->Pos;
// initialize animation // initialize animation
impl->progress = 1.f; impl->progress = 1.f;
impl->target = 0.f; impl->target = 0.f;
impl->animation = true; impl->animation = true;
}
} }
} }
} }
clear_workspace_enabled = false;
} }
void WorkspaceWindow::clearWorkspace() void WorkspaceWindow::clearWorkspace()
{ {
clear_workspace_enabled = true; if (!clear_workspace_enabled) {
const ImVec2 display_size = ImGui::GetIO().DisplaySize;
for(auto it = windows_.cbegin(); it != windows_.cend(); ++it) {
ImGuiProperties *impl = (*it)->impl_;
if (impl && impl->ptr)
{
// remember user position before move
impl->user_pos = impl->ptr->Pos;
const ImVec2 display_size = ImGui::GetIO().DisplaySize; // init before decision
impl->outside_pos = impl->ptr->Pos;
// distance to right side, top & bottom
float right = display_size.x - (impl->ptr->Pos.x + impl->ptr->SizeFull.x * 0.7);
float top = impl->ptr->Pos.y;
float bottom = display_size.y - (impl->ptr->Pos.y + impl->ptr->SizeFull.y);
// move to closest border, with a margin to keep visible
float margin = (impl->ptr->MenuBarHeight() + impl->ptr->TitleBarHeight()) * 1.5f;
if (top < bottom && top < right)
impl->outside_pos.y = margin - impl->ptr->SizeFull.y;
else if (right < top && right < bottom)
impl->outside_pos.x = display_size.x - margin;
else
impl->outside_pos.y = display_size.y - margin;
// initialize animation
impl->progress = 0.f;
impl->target = 1.f;
impl->animation = true;
}
}
}
clear_workspace_enabled = true;
}
void WorkspaceWindow::notifyWorkspaceSizeChanged(int prev_width, int prev_height, int curr_width, int curr_height)
{
for(auto it = windows_.cbegin(); it != windows_.cend(); ++it) { for(auto it = windows_.cbegin(); it != windows_.cend(); ++it) {
ImGuiProperties *impl = (*it)->impl_; ImGuiProperties *impl = (*it)->impl_;
if (impl && impl->ptr) if ((*it)->Visible() && impl && impl->ptr)
{ {
// remember user position before move ImVec2 distance_to_corner = ImVec2(prev_width, prev_height) - impl->ptr->Pos - impl->ptr->SizeFull;
impl->user_pos = impl->ptr->Pos;
// init before decision impl->resized_pos = impl->ptr->Pos;
impl->outside_pos = impl->ptr->Pos;
// distance to right side, top & bottom if ( ABS(distance_to_corner.x) < 100.f ) {
float right = display_size.x - (impl->ptr->Pos.x + impl->ptr->SizeFull.x * 0.7); impl->resized_pos.x += curr_width - prev_width;
float top = impl->ptr->Pos.y; impl->resizing_workspace = true;
float bottom = display_size.y - (impl->ptr->Pos.y + impl->ptr->SizeFull.y); }
// move to closest border, with a margin to keep visible if ( ABS(distance_to_corner.y) < 100.f ) {
float margin = (impl->ptr->MenuBarHeight() + impl->ptr->TitleBarHeight()) * 1.5f; impl->resized_pos.y += curr_height -prev_height;
if (top < bottom && top < right) impl->resizing_workspace = true;
impl->outside_pos.y = margin - impl->ptr->SizeFull.y; }
else if (right < top && right < bottom)
impl->outside_pos.x = display_size.x - margin;
else
impl->outside_pos.y = display_size.y - margin;
// initialize animation
impl->progress = 0.f;
impl->target = 1.f;
impl->animation = true;
} }
} }
} }
void WorkspaceWindow::Update() void WorkspaceWindow::Update()
{ {
// get ImGui pointer to window (available only after first run) // get ImGui pointer to window (available only after first run)
@@ -1972,41 +2004,57 @@ void WorkspaceWindow::Update()
if (w != NULL) { if (w != NULL) {
impl_ = new ImGuiProperties; impl_ = new ImGuiProperties;
impl_->ptr = w; impl_->ptr = w;
impl_->user_pos = w->Pos;
} }
} }
// if an animation is requested // if an animation is requested
else if (impl_->animation) { else if (Visible()){
// increment animation progress by small steps // perform animation for clear/restore workspace
impl_->progress += SIGN(impl_->target -impl_->progress) * 0.1f; if (impl_->animation) {
// finished animation : apply full target position // increment animation progress by small steps
if (ABS_DIFF(impl_->target, impl_->progress) < 0.05f) { impl_->progress += SIGN(impl_->target -impl_->progress) * 0.1f;
impl_->animation = false; // finished animation : apply full target position
ImVec2 pos = impl_->user_pos * (1.f -impl_->target) + impl_->outside_pos * impl_->target; if (ABS_DIFF(impl_->target, impl_->progress) < 0.05f) {
impl_->animation = false;
ImVec2 pos = impl_->user_pos * (1.f -impl_->target) + impl_->outside_pos * impl_->target;
ImGui::SetWindowPos(impl_->ptr, pos);
}
// move window by interpolation between user position and outside target position
else {
ImVec2 pos = impl_->user_pos * (1.f -impl_->progress) + impl_->outside_pos * impl_->progress;
ImGui::SetWindowPos(impl_->ptr, pos);
}
}
// move windows because workspace was resized
if (impl_->resizing_workspace) {
// how far from the target ?
ImVec2 delta = impl_->resized_pos - impl_->ptr->Pos;
// got close enough to stop workspace resize
if (ABS(delta.x) < 2.f && ABS(delta.y) < 2.f)
impl_->resizing_workspace = false;
// dichotomic reach of target position
ImVec2 pos = impl_->ptr->Pos + delta * 0.5f;
ImGui::SetWindowPos(impl_->ptr, pos); ImGui::SetWindowPos(impl_->ptr, pos);
} }
// move window by interpolation between user position and outside target position // dimm window if clear mode is fullly enabled
else { if (clear_workspace_enabled)
ImVec2 pos = impl_->user_pos * (1.f -impl_->progress) + impl_->outside_pos * impl_->progress;
ImGui::SetWindowPos(impl_->ptr, pos);
}
}
// if clear mode is fullly enabled
else if (clear_workspace_enabled && Visible())
{
// draw another window on top of the WorkspaceWindow, at exact same position and size
ImGuiWindow* window = impl_->ptr;
ImGui::SetNextWindowPos(window->Pos, ImGuiCond_Always);
ImGui::SetNextWindowSize(window->Size, ImGuiCond_Always);
char nameoverlay[64];
sprintf(nameoverlay, "%sOverlay", name_);
if (ImGui::Begin(nameoverlay, NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings ))
{ {
// exit workspace clear mode if user clics on the window // draw another window on top of the WorkspaceWindow, at exact same position and size
ImGui::InvisibleButton("##dummy", window->Size); ImGuiWindow* window = impl_->ptr;
if (ImGui::IsItemClicked()) ImGui::SetNextWindowPos(window->Pos, ImGuiCond_Always);
WorkspaceWindow::restoreWorkspace(); ImGui::SetNextWindowSize(window->Size, ImGuiCond_Always);
ImGui::End(); char nameoverlay[64];
sprintf(nameoverlay, "%sOverlay", name_);
if (ImGui::Begin(nameoverlay, NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings ))
{
// exit workspace clear mode if user clics on the window
ImGui::InvisibleButton("##dummy", window->Size);
if (ImGui::IsItemClicked())
WorkspaceWindow::restoreWorkspace();
ImGui::End();
}
} }
} }
} }
@@ -2037,9 +2085,10 @@ void SourceController::resetActiveSelection()
void SourceController::setVisible(bool on) void SourceController::setVisible(bool on)
{ {
// restore workspace to show the window
if (WorkspaceWindow::clear_workspace_enabled) { if (WorkspaceWindow::clear_workspace_enabled) {
WorkspaceWindow::restoreWorkspace(on); WorkspaceWindow::restoreWorkspace(on);
// do not change status: the restore workspace above showed the window // do not change status if ask to hide (consider user asked to toggle because the window was not visible)
if (!on) return; if (!on) return;
} }
@@ -2103,9 +2152,6 @@ void SourceController::Update()
void SourceController::Render() void SourceController::Render()
{ {
ImGui::SetNextWindowPos(ImVec2(1180, 400), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
// estimate window size // estimate window size
const ImGuiContext& g = *GImGui; const ImGuiContext& g = *GImGui;
h_space_ = g.Style.ItemInnerSpacing.x; h_space_ = g.Style.ItemInnerSpacing.x;
@@ -2118,21 +2164,18 @@ void SourceController::Render()
// all together: 1 title bar + spacing + 1 toolbar + spacing + 2 timelines + scrollbar // all together: 1 title bar + spacing + 1 toolbar + spacing + 2 timelines + scrollbar
mediaplayer_height_ = buttons_height_ + 2.f * timeline_height_ + 2.f * scrollbar_ + v_space_; mediaplayer_height_ = buttons_height_ + 2.f * timeline_height_ + 2.f * scrollbar_ + v_space_;
// constraint position // constraint size
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)); ImGui::SetNextWindowSizeConstraints(ImVec2(min_width_, 2.f * mediaplayer_height_), ImVec2(FLT_MAX, FLT_MAX));
ImGui::SetNextWindowPos(ImVec2(1180, 400), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
if ( !ImGui::Begin(name_, &Settings::application.widget.media_player, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse )) // Window named "SourceController" at instanciation
if ( !ImGui::Begin(name_, &Settings::application.widget.media_player,
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ))
{ {
ImGui::End(); ImGui::End();
return; return;
} }
source_window_pos = ImGui::GetWindowPos();
source_window_size = ImGui::GetWindowSize();
// menu (no title bar) // menu (no title bar)
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
@@ -3447,9 +3490,10 @@ OutputPreview::OutputPreview() : WorkspaceWindow("OutputPreview"), video_recorde
void OutputPreview::setVisible(bool on) void OutputPreview::setVisible(bool on)
{ {
// restore workspace to show the window
if (WorkspaceWindow::clear_workspace_enabled) { if (WorkspaceWindow::clear_workspace_enabled) {
WorkspaceWindow::restoreWorkspace(on); WorkspaceWindow::restoreWorkspace(on);
// do not change status: the restore workspace above showed the window // do not change status if ask to hide (consider user asked to toggle because the window was not visible)
if (!on) return; if (!on) return;
} }
@@ -3532,26 +3576,19 @@ void OutputPreview::Render()
FrameBuffer *output = Mixer::manager().session()->frame(); FrameBuffer *output = Mixer::manager().session()->frame();
if (output) if (output)
{ {
// constraint position
static ImVec2 preview_window_pos = ImVec2(1180, 20);
static ImVec2 preview_window_size = ImVec2(400, 260);
// SetNextWindowVisible(preview_window_pos, preview_window_size);
// constraint aspect ratio resizing // constraint aspect ratio resizing
float ar = output->aspectRatio(); float ar = output->aspectRatio();
ImGui::SetNextWindowSizeConstraints(ImVec2(300, 200), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, &ar); ImGui::SetNextWindowSizeConstraints(ImVec2(300, 200), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, &ar);
ImGui::SetNextWindowPos(ImVec2(1180, 20), ImGuiCond_FirstUseEver); ImGui::SetNextWindowPos(ImVec2(1180, 20), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(400, 260), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(400, 260), ImGuiCond_FirstUseEver);
// Window named "OutputPreview" at instanciation
if ( !ImGui::Begin(name_, &Settings::application.widget.preview, if ( !ImGui::Begin(name_, &Settings::application.widget.preview,
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ) ) ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ) )
{ {
ImGui::End(); ImGui::End();
return; return;
} }
preview_window_pos = ImGui::GetWindowPos();
preview_window_size = ImGui::GetWindowSize();
// return from thread for folder openning // return from thread for folder openning
if (recordFolderDialog->closed() && !recordFolderDialog->path().empty()) if (recordFolderDialog->closed() && !recordFolderDialog->path().empty())
@@ -3872,9 +3909,10 @@ TimerMetronome::TimerMetronome() : WorkspaceWindow("Timer")
void TimerMetronome::setVisible(bool on) void TimerMetronome::setVisible(bool on)
{ {
// restore workspace to show the window
if (WorkspaceWindow::clear_workspace_enabled) { if (WorkspaceWindow::clear_workspace_enabled) {
WorkspaceWindow::restoreWorkspace(on); WorkspaceWindow::restoreWorkspace(on);
// do not change status: the restore workspace above showed the window // do not change status if ask to hide (consider user asked to toggle because the window was not visible)
if (!on) return; if (!on) return;
} }
@@ -3906,7 +3944,6 @@ void TimerMetronome::Render()
return; return;
} }
// menu (no title bar) // menu (no title bar)
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
@@ -6312,30 +6349,3 @@ void SetMouseCursor(ImVec2 mousepos, View::Cursor c)
} }
} }
} }
//void SetNextWindowVisible(ImVec2 pos, ImVec2 size, float margin)
//{
// bool need_update = false;
// ImVec2 pos_target = pos;
// const ImGuiIO& io = ImGui::GetIO();
// if ( pos_target.y > io.DisplaySize.y - margin ){
// pos_target.y = io.DisplaySize.y - margin;
// need_update = true;
// }
// if ( pos_target.y + size.y < margin ){
// pos_target.y = margin - size.y;
// need_update = true;
// }
// if ( pos_target.x > io.DisplaySize.x - margin){
// pos_target.x = io.DisplaySize.x - margin;
// need_update = true;
// }
// if ( pos_target.x + size.x < margin ){
// pos_target.x = margin - size.x;
// need_update = true;
// }
// if (need_update)
// ImGui::SetNextWindowPos(pos_target, ImGuiCond_Always);
//}

View File

@@ -215,6 +215,7 @@ public:
static void toggleClearRestoreWorkspace(); static void toggleClearRestoreWorkspace();
static void clearWorkspace(); static void clearWorkspace();
static void restoreWorkspace(bool instantaneous = false); static void restoreWorkspace(bool instantaneous = false);
static void notifyWorkspaceSizeChanged(int prev_width, int prev_height, int curr_width, int curr_height);
// for inherited classes // for inherited classes
virtual void Update(); virtual void Update();