quinta-feira, 12 de julho de 2007

The SlidingSeparator

Yep, reusable objects are always fun. The problem with wxSplitter­Window is that it is intended to split a window / document, not to separate two windows / objects. The alternative is the sash window but this doesn't have a live update, and only exposes the dragged event. Ah, who am I fooling with all these excuses? I want to make a sliding separator, that's all!

With live update it's easy. You put a tiny window between the other two, catch the mouse down event, store current mouse position and capture the mouse. On motion the tiny window follows the mouse and the neighbours are sized / positioned according. On mouse up the fellow is released from the capture. With no live update -- that is, with a "shadow separator" -- things aren't so straight, you have to draw on the screen.

Now the details: you can't move the handle outside his area, and should keep an eye on the mouse capture. WxWidgets has a wxWindow:­:GetMinSize, that must be respected and solves the first problem. The wxMouse­CaptureLost­Event solves the second; this event is currently emitted under Windows only, with Linux you can't Alt-Tab while the mouse is captured, afaics.

Digesting:
SlideSep::SlideSep(wxWindow* parent, wxWindow* top_left, 
wxWindow* bottom_right, wxWindowID id,
const wxPoint& pos, const wxSize& size)
: wxWindow(parent, id, pos, size) {

SetCursor(wxCursor(wxCURSOR_SIZEWE));
m_windowBR = bottom_right;
m_windowTL = top_left;
}

void SlideSep::OnLeftDown(wxMouseEvent& event) {
this->CaptureMouse();
m_startPoint = event.GetPosition();
event.Skip();
}

void SlideSep::OnMotion(wxMouseEvent& event) {
if (HasCapture()) {
// TODO: implement orient
int dx = event.GetPosition().x - m_startPoint.x;
wxSize m1 = m_windowTL->GetMinSize();
wxSize m2 = m_windowBR->GetMinSize();
wxSize s1 = m_windowTL->GetSize();
wxSize s2 = m_windowBR->GetSize();
// space available is size - minSize
int av1 = m1.x == -1? s1.x: s1.x - m1.x;
int av2 = m2.x == -1? s2.x: s2.x - m2.x;
// limit move to space available
if (-dx > av1) dx = -av1;
if (dx > av2) dx = av2;
if (dx != 0) {
m_windowTL->SetSize(s1.x +dx, s1.y);
wxPoint p = this->GetPosition();
this->Move(p.x +dx, p.y);
p = m_windowBR->GetPosition();
m_windowBR->SetSize(p.x +dx, p.y, s2.x -dx, s2.y);
}
}
event.Skip();
}

void SlideSep::OnLeftUp(wxMouseEvent& event) {
if (HasCapture()) {
this->ReleaseMouse();
}
event.Skip();
}

void SlideSep::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) {
// in Windows there is a debug alert without this
}


As reference the complete source files are here. It works well with no sizer, but there is no point about that. As expected, with a box sizer item's proportion rules when the window is resized -- next problem to be solved.

For now I'm loosing the native sash look, but maybe the DrawSplitterSash method is what I need.

Etiquetas: ,

0 Comentários:

Enviar um comentário

Subscrever Enviar feedback [Atom]

<< Página inicial