diff --git a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj index 4eeb99e36..936106f3c 100644 --- a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj +++ b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj @@ -893,6 +893,14 @@ RelativePath="..\..\src\mythes.hxx" > + + + + diff --git a/aegisub/src/Makefile b/aegisub/src/Makefile index 86b055700..07e3f635a 100644 --- a/aegisub/src/Makefile +++ b/aegisub/src/Makefile @@ -198,6 +198,7 @@ SRC += \ md5.c \ mkv_wrap.cpp \ mythes.cxx \ + persist_location.cpp \ plugin_manager.cpp \ preferences.cpp \ preferences_base.cpp \ diff --git a/aegisub/src/dialog_detached_video.cpp b/aegisub/src/dialog_detached_video.cpp index 7dc94aa3c..0d65af090 100644 --- a/aegisub/src/dialog_detached_video.cpp +++ b/aegisub/src/dialog_detached_video.cpp @@ -46,6 +46,7 @@ #include "dialog_detached_video.h" #include "frame_main.h" #include "main.h" +#include "persist_location.h" #include "video_box.h" #include "video_context.h" #include "video_display.h" @@ -58,12 +59,6 @@ DialogDetachedVideo::DialogDetachedVideo(FrameMain *parent, agi::Context *contex : wxDialog(parent,-1,_T("Detached Video"),wxDefaultPosition,wxSize(400,300),wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxWANTS_CHARS) , parent(parent) { - // Set up window - int x = OPT_GET("Video/Detached/Last/X")->GetInt(); - int y = OPT_GET("Video/Detached/Last/Y")->GetInt(); - if (x != -1 && y != -1) SetPosition(wxPoint(x,y)); - if (OPT_GET("Video/Detached/Maximized")->GetBool()) Maximize(); - // Set obscure stuff SetExtraStyle((GetExtraStyle() & ~wxWS_EX_BLOCK_EVENTS) | wxWS_EX_PROCESS_UI_UPDATES); @@ -89,40 +84,18 @@ DialogDetachedVideo::DialogDetachedVideo(FrameMain *parent, agi::Context *contex videoBox->SetMinSize(wxSize(1,1)); SetMinSize(wxSize(1,1)); + persist.reset(new PersistLocation(this, "Video/Detached")); + int display_index = wxDisplay::GetFromWindow(this); - if (display_index == wxNOT_FOUND) - { - int caption_size = wxSystemSettings::GetMetric(wxSYS_CAPTION_Y, this); - Move(parent->GetPosition() + wxPoint(caption_size, caption_size)); - } - else - { + // Ensure that the dialog is no larger than the screen + if (display_index != wxNOT_FOUND) { wxRect bounds_rect = GetRect(); wxRect disp_rect = wxDisplay(display_index).GetClientArea(); - - // Ensure our x/y position is past the top left of the display - int new_x = std::max(bounds_rect.x, disp_rect.x); - int new_y = std::max(bounds_rect.y, disp_rect.y); - // Pick the smallest size of display and window. - // By doing this, we're guaranteed to get a width/height that fits on the display - // and won't have to adjust width/height any further. - int new_w = std::min(bounds_rect.width, disp_rect.width); - int new_h = std::min(bounds_rect.height, disp_rect.height); - - // Check if bottom right corner is outside display and move inside then - if (new_x + new_w > disp_rect.x + disp_rect.width) - new_x = disp_rect.x + disp_rect.width - new_w; - if (new_y + new_h > disp_rect.y + disp_rect.height) - new_y = disp_rect.y + disp_rect.height - new_h; - - SetSize(new_x, new_y, new_w, new_h, wxSIZE_ALLOW_MINUS_ONE); + SetSize(std::min(bounds_rect.width, disp_rect.width), std::min(bounds_rect.height, disp_rect.height)); } // Update parent->SetDisplayMode(0, -1); - GetPosition(&x, &y); - OPT_SET("Video/Detached/Last/X")->SetInt(x); - OPT_SET("Video/Detached/Last/Y")->SetInt(y); OPT_SET("Video/Detached/Enabled")->SetBool(true); // Copy the main accelerator table to this dialog @@ -132,13 +105,11 @@ DialogDetachedVideo::DialogDetachedVideo(FrameMain *parent, agi::Context *contex /// @brief Destructor DialogDetachedVideo::~DialogDetachedVideo() { - OPT_SET("Video/Detached/Maximized")->SetBool(IsMaximized()); } // Event table BEGIN_EVENT_TABLE(DialogDetachedVideo,wxDialog) EVT_CLOSE(DialogDetachedVideo::OnClose) - EVT_MOVE(DialogDetachedVideo::OnMove) EVT_ICONIZE(DialogDetachedVideo::OnMinimize) END_EVENT_TABLE() @@ -151,14 +122,6 @@ void DialogDetachedVideo::OnClose(wxCloseEvent &WXUNUSED(event)) { parent->SetDisplayMode(1,-1); } -/// @brief Move window -/// @param event -void DialogDetachedVideo::OnMove(wxMoveEvent &event) { - wxPoint pos = event.GetPosition(); - OPT_SET("Video/Detached/Last/X")->SetInt(pos.x); - OPT_SET("Video/Detached/Last/Y")->SetInt(pos.y); -} - /// @brief Minimize event handler /// @param event void DialogDetachedVideo::OnMinimize(wxIconizeEvent &event) { diff --git a/aegisub/src/dialog_detached_video.h b/aegisub/src/dialog_detached_video.h index 75657b724..c64748742 100644 --- a/aegisub/src/dialog_detached_video.h +++ b/aegisub/src/dialog_detached_video.h @@ -40,8 +40,11 @@ #include #endif +#include + namespace agi { struct Context; } class FrameMain; +class PersistLocation; class VideoBox; /// DOCME @@ -50,7 +53,7 @@ class VideoBox; /// /// DOCME class DialogDetachedVideo : public wxDialog { -private: + agi::scoped_ptr persist; /// DOCME VideoBox *videoBox; @@ -59,7 +62,6 @@ private: FrameMain *parent; void OnClose(wxCloseEvent &event); - void OnMove(wxMoveEvent &event); void OnMinimize(wxIconizeEvent &event); public: diff --git a/aegisub/src/persist_location.cpp b/aegisub/src/persist_location.cpp new file mode 100644 index 000000000..2e5bb50bb --- /dev/null +++ b/aegisub/src/persist_location.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2011, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ +// +// $Id$ + +/// @file persist_location.cpp +/// @see persist_location.h +/// @ingroup utility + +#include "config.h" + +#include "persist_location.h" + +#include "main.h" + +#ifndef AGI_PRE +#include +#endif + +PersistLocation::PersistLocation(wxDialog *dialog, std::string options_prefix) +: x_opt(OPT_SET(options_prefix + "/Last/X")) +, y_opt(OPT_SET(options_prefix + "/Last/Y")) +, maximize_opt(OPT_SET(options_prefix + "/Maximized")) +{ + dialog->Bind(wxEVT_MOVE, &PersistLocation::OnMove, this); + dialog->Bind(wxEVT_ICONIZE, &PersistLocation::OnMinimize, this); + + if (maximize_opt->GetBool()) dialog->Maximize(); + + int x = x_opt->GetInt(); + int y = y_opt->GetInt(); + if (x == -1 && y == -1) + dialog->CenterOnParent(); + else { + // First move to the saved place so that it ends up on the right monitor + dialog->Move(x, y); + + int display_index = wxDisplay::GetFromWindow(dialog); + + // If it's moved offscreen center on the parent and try again + if (display_index == wxNOT_FOUND) { + dialog->CenterOnParent(); + display_index = wxDisplay::GetFromWindow(dialog); + } + + // If it's still offscreen just give up + if (display_index == wxNOT_FOUND) return; + + wxRect display_area = wxDisplay(display_index).GetClientArea(); + wxSize dialog_size = dialog->GetSize(); + + // Ensure that the top-left corner is onscreen + if (x < display_area.x) x = display_area.x; + if (y < display_area.y) y = display_area.y; + + // Ensure that the bottom-right corner is onscreen as long as doing so + // wouldn't force the top-left corner offscreen + if (x + dialog_size.x > display_area.GetRight()) + x = std::max(display_area.x, display_area.GetRight() - dialog_size.x); + if (y + dialog_size.y > display_area.GetBottom()) + y = std::max(display_area.y, display_area.GetBottom() - dialog_size.y); + + dialog->Move(x, y); + } +} + +void PersistLocation::OnMove(wxMoveEvent &evt) { + wxPoint pos = evt.GetPosition(); + x_opt->SetInt(pos.x); + y_opt->SetInt(pos.y); +} + +void PersistLocation::OnMinimize(wxIconizeEvent &evt) { + maximize_opt->SetBool(!evt.IsIconized()); +} diff --git a/aegisub/src/persist_location.h b/aegisub/src/persist_location.h new file mode 100644 index 000000000..3ebc87c69 --- /dev/null +++ b/aegisub/src/persist_location.h @@ -0,0 +1,46 @@ +// Copyright (c) 2011, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ +// +// $Id$ + +/// @file persist_location.h +/// @see persist_location.cpp +/// @ingroup utility + +namespace agi { class OptionValue; } +class wxDialog; + +/// @class PersistLocation +/// @brief Automatically save and restore the location of a dialog +/// +/// This class saves the location of the supplied dialog to the preferences +/// file with the given prefix, then restores the saved position when it is +/// recreated in the future. This class should always have lifetime equal to +/// the associated dialog, as it does not unbind its events. +class PersistLocation { + agi::OptionValue *x_opt; + agi::OptionValue *y_opt; + agi::OptionValue *maximize_opt; + + void OnMove(wxMoveEvent &evt); + void OnMinimize(wxIconizeEvent &evt); + +public: + /// Persist the location of a dialog + /// @param dialog The dialog to save and restore the position of + /// @param options_prefix Prefix for the options names to store the location + PersistLocation(wxDialog *dialog, std::string options_prefix); +};