summaryrefslogtreecommitdiff
path: root/ui/triple_splitter.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:20:50 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:20:50 +0200
commit7e706cf64654aea466c059c307e5723e2423ed5d (patch)
treee85f0d28d7c81b6d21419fc38e1a654cca2212b1 /ui/triple_splitter.cpp
parent5.5 (diff)
downloadFreeFileSync-7e706cf64654aea466c059c307e5723e2423ed5d.tar.gz
FreeFileSync-7e706cf64654aea466c059c307e5723e2423ed5d.tar.bz2
FreeFileSync-7e706cf64654aea466c059c307e5723e2423ed5d.zip
5.6
Diffstat (limited to 'ui/triple_splitter.cpp')
-rw-r--r--ui/triple_splitter.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/ui/triple_splitter.cpp b/ui/triple_splitter.cpp
new file mode 100644
index 00000000..5783bc4f
--- /dev/null
+++ b/ui/triple_splitter.cpp
@@ -0,0 +1,230 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#include "triple_splitter.h"
+#include <algorithm>
+
+using namespace zen;
+
+
+namespace
+{
+//------------ Grid Constants -------------------------------
+const int SASH_HIT_TOLERANCE = 5; //currently onla a placebo!
+const int SASH_SIZE = 10;
+const double SASH_GRAVITY = 0.5; //value within [0, 1]; 1 := resize left only, 0 := resize right only
+const int CHILD_WINDOW_MIN_SIZE = 50; //min. size of managed windows
+
+const wxColor COLOR_SASH_GRADIENT_FROM = wxColour(192, 192, 192); //light grey
+const wxColor COLOR_SASH_GRADIENT_TO = *wxWHITE;
+}
+
+TripleSplitter::TripleSplitter(wxWindow* parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style) : wxWindow(parent, id, pos, size, style | wxTAB_TRAVERSAL), //tab between windows
+ centerOffset(0),
+ windowL(nullptr),
+ windowC(nullptr),
+ windowR(nullptr)
+{
+ Connect(wxEVT_PAINT, wxPaintEventHandler(TripleSplitter::onPaintEvent ), nullptr, this);
+ Connect(wxEVT_SIZE, wxSizeEventHandler (TripleSplitter::onSizeEvent ), nullptr, this);
+ //http://wiki.wxwidgets.org/Flicker-Free_Drawing
+ Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(TripleSplitter::onEraseBackGround), nullptr, this);
+#if wxCHECK_VERSION(2, 9, 1)
+ SetBackgroundStyle(wxBG_STYLE_PAINT);
+#else
+ SetBackgroundStyle(wxBG_STYLE_CUSTOM);
+#endif
+ Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(TripleSplitter::onMouseLeftDown ), nullptr, this);
+ Connect(wxEVT_LEFT_UP, wxMouseEventHandler(TripleSplitter::onMouseLeftUp ), nullptr, this);
+ Connect(wxEVT_MOTION, wxMouseEventHandler(TripleSplitter::onMouseMovement ), nullptr, this);
+ Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(TripleSplitter::onLeaveWindow ), nullptr, this);
+ Connect(wxEVT_MOUSE_CAPTURE_LOST, wxMouseCaptureLostEventHandler(TripleSplitter::onMouseCaptureLost), nullptr, this);
+ Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(TripleSplitter::onMouseLeftDouble), nullptr, this);
+}
+
+
+void TripleSplitter::updateWindowSizes()
+{
+ if (windowL && windowC && windowR)
+ {
+ const int centerPosX = getCenterPosX();
+ const int centerWidth = getCenterWidth();
+
+ const wxRect clientRect = GetClientRect();
+
+ const int widthL = centerPosX;
+ const int windowRposX = widthL + centerWidth;
+ const int widthR = clientRect.width - windowRposX;
+
+ windowL->SetSize(0, 0, widthL, clientRect.height);
+ windowC->SetSize(widthL + SASH_SIZE, 0, windowC->GetSize().GetWidth(), clientRect.height);
+ windowR->SetSize(windowRposX, 0, widthR, clientRect.height);
+
+ wxClientDC dc(this);
+ drawSash(dc);
+ }
+}
+
+
+class TripleSplitter::SashMove
+{
+public:
+ SashMove(wxWindow& wnd, int mousePosX, int centerPosX) : wnd_(wnd), mousePosX_(mousePosX), centerPosX_(centerPosX)
+ {
+ wnd_.SetCursor(wxCURSOR_SIZEWE);
+ wnd_.CaptureMouse();
+ }
+ ~SashMove()
+ {
+ wnd_.SetCursor(*wxSTANDARD_CURSOR);
+ if (wnd_.HasCapture())
+ wnd_.ReleaseMouse();
+ }
+ int getMousePosXStart () { return mousePosX_; }
+ int getCenterPosXStart() { return centerPosX_; }
+
+private:
+ wxWindow& wnd_;
+ const int mousePosX_;
+ const int centerPosX_;
+};
+
+
+inline
+int TripleSplitter::getCenterWidth() const
+{
+ return 2 * SASH_SIZE + (windowC ? windowC->GetSize().GetWidth() : 0);
+}
+
+
+int TripleSplitter::getCenterPosXOptimal() const
+{
+ const wxRect clientRect = GetClientRect();
+ const int centerWidth = getCenterWidth();
+ return (clientRect.width - centerWidth) * SASH_GRAVITY; //allowed to be negative for extreme client widths!
+}
+
+int TripleSplitter::getCenterPosX() const
+{
+ const wxRect clientRect = GetClientRect();
+ const int centerWidth = getCenterWidth();
+ const int centerPosXOptimal = getCenterPosXOptimal();
+
+ //normalize "centerPosXOptimal + centerOffset"
+ if (clientRect.width < 2 * CHILD_WINDOW_MIN_SIZE + centerWidth) //continuous transition between conditional branches!
+ //use fixed "centeroffset" when "clientRect.width == 2 * CHILD_WINDOW_MIN_SIZE + centerWidth"
+ return centerPosXOptimal + CHILD_WINDOW_MIN_SIZE - static_cast<int>(2 * CHILD_WINDOW_MIN_SIZE * SASH_GRAVITY); //avoid rounding error
+ else
+ return std::max(CHILD_WINDOW_MIN_SIZE, //make sure centerPosXOptimal + offset is within bounds
+ std::min(centerPosXOptimal + centerOffset, clientRect.width - CHILD_WINDOW_MIN_SIZE - centerWidth));
+}
+
+
+void TripleSplitter::drawSash(wxDC& dc)
+{
+ const int centerPosX = getCenterPosX();
+ const int centerWidth = getCenterWidth();
+
+ auto draw = [&](wxRect rect)
+ {
+ const int sash2ndHalf = 3;
+ rect.width -= sash2ndHalf;
+ dc.GradientFillLinear(rect, COLOR_SASH_GRADIENT_FROM, COLOR_SASH_GRADIENT_TO, wxEAST);
+
+ rect.x += rect.width;
+ rect.width = sash2ndHalf;
+ dc.GradientFillLinear(rect, COLOR_SASH_GRADIENT_FROM, COLOR_SASH_GRADIENT_TO, wxWEST);
+
+ static_assert(SASH_SIZE > sash2ndHalf, "");
+ };
+
+ const wxRect rectSashL(centerPosX, 0, SASH_SIZE, GetClientRect().height);
+ const wxRect rectSashR(centerPosX + centerWidth - SASH_SIZE, 0, SASH_SIZE, GetClientRect().height);
+
+ draw(rectSashL);
+ draw(rectSashR);
+}
+
+
+bool TripleSplitter::hitOnSashLine(int posX) const
+{
+ const int centerPosX = getCenterPosX();
+ const int centerWidth = getCenterWidth();
+
+ //we don't get events outside of sash, so SASH_HIT_TOLERANCE is currently *useless*
+ auto hitSash = [&](int sashX) { return sashX - SASH_HIT_TOLERANCE <= posX && posX < sashX + SASH_SIZE + SASH_HIT_TOLERANCE; };
+
+ return hitSash(centerPosX) || hitSash(centerPosX + centerWidth - SASH_SIZE); //hit one of the two sash lines
+}
+
+
+void TripleSplitter::onMouseLeftDown(wxMouseEvent& event)
+{
+ activeMove.reset();
+
+ const int posX = event.GetPosition().x;
+ if (hitOnSashLine(posX))
+ activeMove.reset(new SashMove(*this, posX, getCenterPosX()));
+ event.Skip();
+}
+
+
+void TripleSplitter::onMouseLeftUp(wxMouseEvent& event)
+{
+ activeMove.reset(); //nothing else to do, actual work done by onMouseMovement()
+ event.Skip();
+}
+
+
+void TripleSplitter::onMouseMovement(wxMouseEvent& event)
+{
+ if (activeMove)
+ {
+ centerOffset = activeMove->getCenterPosXStart() - getCenterPosXOptimal() + event.GetPosition().x - activeMove->getMousePosXStart();
+
+ updateWindowSizes();
+ Update(); //no time to wait until idle event!
+ }
+ else
+ {
+ //we receive those only while above the sash, not the managed windows!
+ SetCursor(wxCURSOR_SIZEWE); //set window-local only!
+ }
+ event.Skip();
+}
+
+
+void TripleSplitter::onLeaveWindow(wxMouseEvent& event)
+{
+ //even called when moving from sash over to managed windows!
+ if (!activeMove)
+ SetCursor(*wxSTANDARD_CURSOR);
+ event.Skip();
+}
+
+
+void TripleSplitter::onMouseCaptureLost(wxMouseCaptureLostEvent& event)
+{
+ activeMove.reset();
+ updateWindowSizes();
+ //event.Skip(); -> we DID handle it!
+}
+
+
+void TripleSplitter::onMouseLeftDouble(wxMouseEvent& event)
+{
+ const int posX = event.GetPosition().x;
+ if (hitOnSashLine(posX))
+ {
+ centerOffset = 0; //reset sash according to gravity
+ updateWindowSizes();
+ }
+ event.Skip();
+}
bgstack15