Added variant.h/cpp; changed variable names in object.h; added some
[wxWidgets.git] / src / generic / sashwin.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: sashwin.cpp
3 // Purpose: wxSashWindow implementation. A sash window has an optional
4 // sash on each edge, allowing it to be dragged. An event
5 // is generated when the sash is released.
6 // Author: Julian Smart
7 // Modified by:
8 // Created: 01/02/97
9 // RCS-ID: $Id$
10 // Copyright: (c) Julian Smart
11 // Licence: wxWindows license
12 /////////////////////////////////////////////////////////////////////////////
13
14 #ifdef __GNUG__
15 #pragma implementation "sashwin.h"
16 #endif
17
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #ifndef WX_PRECOMP
26 #include "wx/wx.h"
27 #endif
28
29 #include <math.h>
30 #include <stdlib.h>
31
32 #include "wx/string.h"
33 #include "wx/dcscreen.h"
34 #include "wx/sashwin.h"
35
36 #if !USE_SHARED_LIBRARY
37 IMPLEMENT_DYNAMIC_CLASS(wxSashWindow, wxWindow)
38 IMPLEMENT_DYNAMIC_CLASS(wxSashEvent, wxCommandEvent)
39
40 BEGIN_EVENT_TABLE(wxSashWindow, wxWindow)
41 EVT_PAINT(wxSashWindow::OnPaint)
42 EVT_SIZE(wxSashWindow::OnSize)
43 EVT_MOUSE_EVENTS(wxSashWindow::OnMouseEvent)
44 END_EVENT_TABLE()
45 #endif
46
47 wxSashWindow::wxSashWindow()
48 {
49 m_draggingEdge = wxSASH_NONE;
50 m_dragMode = wxSASH_DRAG_NONE;
51 m_oldX = 0;
52 m_oldY = 0;
53 m_firstX = 0;
54 m_firstY = 0;
55 m_borderSize = 3 ;
56 m_extraBorderSize = 0;
57 m_sashCursorWE = NULL;
58 m_sashCursorNS = NULL;
59
60 m_minimumPaneSizeX = 0;
61 m_minimumPaneSizeY = 0;
62 m_maximumPaneSizeX = 0;
63 m_maximumPaneSizeY = 0;
64 }
65
66 wxSashWindow::wxSashWindow(wxWindow *parent, wxWindowID id, const wxPoint& pos,
67 const wxSize& size, long style, const wxString& name)
68 :wxWindow(parent, id, pos, size, style, name)
69 {
70 m_draggingEdge = wxSASH_NONE;
71 m_dragMode = wxSASH_DRAG_NONE;
72 m_oldX = 0;
73 m_oldY = 0;
74 m_firstX = 0;
75 m_firstY = 0;
76 m_borderSize = 3;
77 m_extraBorderSize = 0;
78 m_minimumPaneSizeX = 0;
79 m_minimumPaneSizeY = 0;
80 m_maximumPaneSizeX = 0;
81 m_maximumPaneSizeY = 0;
82 m_sashCursorWE = new wxCursor(wxCURSOR_SIZEWE);
83 m_sashCursorNS = new wxCursor(wxCURSOR_SIZENS);
84
85 // Eventually, we'll respond to colour change messages
86 InitColours();
87 }
88
89 wxSashWindow::~wxSashWindow()
90 {
91 delete m_sashCursorWE;
92 delete m_sashCursorNS;
93 }
94
95 void wxSashWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
96 {
97 wxPaintDC dc(this);
98
99 #if 0
100 if ( m_borderSize > 0 )
101 DrawBorders(dc);
102 #endif
103
104 DrawSashes(dc);
105 }
106
107 void wxSashWindow::OnMouseEvent(wxMouseEvent& event)
108 {
109 long x, y;
110 event.Position(&x, &y);
111
112 wxSashEdgePosition sashHit = SashHitTest(x, y);
113
114 if (event.LeftDown())
115 {
116 if ( sashHit != wxSASH_NONE )
117 {
118 CaptureMouse();
119
120 // Required for X to specify that
121 // that we wish to draw on top of all windows
122 // - and we optimise by specifying the area
123 // for creating the overlap window.
124 wxScreenDC::StartDrawingOnTop(this);
125
126 // We don't say we're dragging yet; we leave that
127 // decision for the Dragging() branch, to ensure
128 // the user has dragged a little bit.
129 m_dragMode = wxSASH_DRAG_LEFT_DOWN;
130 m_draggingEdge = sashHit;
131 m_firstX = x;
132 m_firstY = y;
133 }
134 }
135 else if ( event.LeftUp() && m_dragMode == wxSASH_DRAG_LEFT_DOWN )
136 {
137 // Wasn't a proper drag
138 ReleaseMouse();
139 wxScreenDC::EndDrawingOnTop();
140 m_dragMode = wxSASH_DRAG_NONE;
141 m_draggingEdge = wxSASH_NONE;
142
143 SetCursor(*wxSTANDARD_CURSOR);
144 }
145 else if (event.LeftUp() && m_dragMode == wxSASH_DRAG_DRAGGING)
146 {
147 // We can stop dragging now and see what we've got.
148 m_dragMode = wxSASH_DRAG_NONE;
149 ReleaseMouse();
150 // Erase old tracker
151 DrawSashTracker(m_draggingEdge, m_oldX, m_oldY);
152
153 // End drawing on top (frees the window used for drawing
154 // over the screen)
155 wxScreenDC::EndDrawingOnTop();
156
157 int w, h;
158 GetSize(&w, &h);
159 int xp, yp;
160 GetPosition(&xp, &yp);
161
162 wxSashEdgePosition edge = m_draggingEdge;
163 m_draggingEdge = wxSASH_NONE;
164
165 wxRect dragRect;
166 wxSashDragStatus status = wxSASH_STATUS_OK;
167 switch (edge)
168 {
169 case wxSASH_TOP:
170 {
171 if (y > (yp + h))
172 status = wxSASH_STATUS_OUT_OF_RANGE;
173 int newHeight = (h - y);
174 dragRect = wxRect(xp, (yp + h) - newHeight, w, newHeight);
175 break;
176 }
177 case wxSASH_BOTTOM:
178 {
179 if (y < 0)
180 status = wxSASH_STATUS_OUT_OF_RANGE;
181 int newHeight = y;
182 dragRect = wxRect(xp, yp, w, newHeight);
183 break;
184 }
185 case wxSASH_LEFT:
186 {
187 if (x > (xp + w))
188 status = wxSASH_STATUS_OUT_OF_RANGE;
189 int newWidth = (w - x);
190 dragRect = wxRect((xp + w) - newWidth, yp, newWidth, h);
191 break;
192 }
193 case wxSASH_RIGHT:
194 {
195 if (x < 0)
196 status = wxSASH_STATUS_OUT_OF_RANGE;
197 int newWidth = x;
198 dragRect = wxRect(xp, yp, newWidth, h);
199 break;
200 }
201 case wxSASH_NONE:
202 {
203 break;
204 }
205 }
206
207 wxSashEvent event(GetId(), edge);
208 event.SetEventObject(this);
209 event.SetDragStatus(status);
210 event.SetDragRect(dragRect);
211 GetEventHandler()->ProcessEvent(event);
212 }
213 else if (event.Moving() && !event.Dragging())
214 {
215 // Just change the cursor if required
216 if ( sashHit != wxSASH_NONE )
217 {
218 if ( (sashHit == wxSASH_LEFT) || (sashHit == wxSASH_RIGHT) )
219 {
220 SetCursor(*m_sashCursorWE);
221 }
222 else
223 {
224 SetCursor(*m_sashCursorNS);
225 }
226 }
227 else
228 {
229 SetCursor(*wxSTANDARD_CURSOR);
230 }
231 }
232 else if ( event.Dragging() &&
233 ((m_dragMode == wxSASH_DRAG_DRAGGING) || (m_dragMode == wxSASH_DRAG_LEFT_DOWN))
234 )
235 {
236 if ( (m_draggingEdge == wxSASH_LEFT) || (m_draggingEdge == wxSASH_RIGHT) )
237 {
238 SetCursor(*m_sashCursorWE);
239 }
240 else
241 {
242 SetCursor(*m_sashCursorNS);
243 }
244
245 if (m_dragMode == wxSASH_DRAG_LEFT_DOWN)
246 {
247 m_dragMode = wxSASH_DRAG_DRAGGING;
248 DrawSashTracker(m_draggingEdge, x, y);
249 }
250 else
251 {
252 if ( m_dragMode == wxSASH_DRAG_DRAGGING )
253 {
254 // Erase old tracker
255 DrawSashTracker(m_draggingEdge, m_oldX, m_oldY);
256
257 // Draw new one
258 DrawSashTracker(m_draggingEdge, x, y);
259 }
260 }
261 m_oldX = x;
262 m_oldY = y;
263 }
264 else if ( event.LeftDClick() )
265 {
266 // Nothing
267 }
268 else
269 {
270 }
271 }
272
273 void wxSashWindow::OnSize(wxSizeEvent& WXUNUSED(event))
274 {
275 SizeWindows();
276 }
277
278 wxSashEdgePosition wxSashWindow::SashHitTest(int x, int y, int WXUNUSED(tolerance))
279 {
280 int cx, cy;
281 GetClientSize(& cx, & cy);
282
283 int i;
284 for (i = 0; i < 4; i++)
285 {
286 wxSashEdge& edge = m_sashes[i];
287 wxSashEdgePosition position = (wxSashEdgePosition) i ;
288
289 if (edge.m_show)
290 {
291 switch (position)
292 {
293 case wxSASH_TOP:
294 {
295 if (y >= 0 && y <= GetEdgeMargin(position))
296 return wxSASH_TOP;
297 break;
298 }
299 case wxSASH_RIGHT:
300 {
301 if ((x >= cx - GetEdgeMargin(position)) && (x <= cx))
302 return wxSASH_RIGHT;
303 break;
304 }
305 case wxSASH_BOTTOM:
306 {
307 if ((y >= cy - GetEdgeMargin(position)) && (y <= cy))
308 return wxSASH_BOTTOM;
309 break;
310 }
311 case wxSASH_LEFT:
312 {
313 if ((x >= GetEdgeMargin(position)) && (x >= 0))
314 return wxSASH_LEFT;
315 break;
316 }
317 case wxSASH_NONE:
318 {
319 break;
320 }
321 }
322 }
323 }
324 return wxSASH_NONE;
325 }
326
327 // Draw 3D effect borders
328 void wxSashWindow::DrawBorders(wxDC& dc)
329 {
330 int w, h;
331 GetClientSize(&w, &h);
332
333 wxPen mediumShadowPen(m_mediumShadowColour, 1, wxSOLID);
334 wxPen darkShadowPen(m_darkShadowColour, 1, wxSOLID);
335 wxPen lightShadowPen(m_lightShadowColour, 1, wxSOLID);
336 wxPen hilightPen(m_hilightColour, 1, wxSOLID);
337
338 if ( GetWindowStyleFlag() & wxSP_3D )
339 {
340 dc.SetPen(mediumShadowPen);
341 dc.DrawLine(0, 0, w-1, 0);
342 dc.DrawLine(0, 0, 0, h - 1);
343
344 dc.SetPen(darkShadowPen);
345 dc.DrawLine(1, 1, w-2, 1);
346 dc.DrawLine(1, 1, 1, h-2);
347
348 dc.SetPen(hilightPen);
349 dc.DrawLine(0, h-1, w-1, h-1);
350 dc.DrawLine(w-1, 0, w-1, h); // Surely the maximum y pos. should be h - 1.
351 /// Anyway, h is required for MSW.
352
353 dc.SetPen(lightShadowPen);
354 dc.DrawLine(w-2, 1, w-2, h-2); // Right hand side
355 dc.DrawLine(1, h-2, w-1, h-2); // Bottom
356 }
357 else if ( GetWindowStyleFlag() & wxSP_BORDER )
358 {
359 dc.SetBrush(*wxTRANSPARENT_BRUSH);
360 dc.SetPen(*wxBLACK_PEN);
361 dc.DrawRectangle(0, 0, w-1, h-1);
362 }
363
364 dc.SetPen(wxNullPen);
365 dc.SetBrush(wxNullBrush);
366 }
367
368 void wxSashWindow::DrawSashes(wxDC& dc)
369 {
370 int i;
371 for (i = 0; i < 4; i++)
372 if (m_sashes[i].m_show)
373 DrawSash((wxSashEdgePosition) i, dc);
374 }
375
376 // Draw the sash
377 void wxSashWindow::DrawSash(wxSashEdgePosition edge, wxDC& dc)
378 {
379 int w, h;
380 GetClientSize(&w, &h);
381
382 wxPen facePen(m_faceColour, 1, wxSOLID);
383 wxBrush faceBrush(m_faceColour, wxSOLID);
384 wxPen mediumShadowPen(m_mediumShadowColour, 1, wxSOLID);
385 wxPen darkShadowPen(m_darkShadowColour, 1, wxSOLID);
386 wxPen lightShadowPen(m_lightShadowColour, 1, wxSOLID);
387 wxPen hilightPen(m_hilightColour, 1, wxSOLID);
388 wxPen blackPen(wxColour(0, 0, 0), 1, wxSOLID);
389 wxPen whitePen(wxColour(255, 255, 255), 1, wxSOLID);
390
391 if ( edge == wxSASH_LEFT || edge == wxSASH_RIGHT )
392 {
393 int sashPosition = 0;
394 if (edge == wxSASH_LEFT)
395 sashPosition = 0;
396 else
397 sashPosition = w - GetEdgeMargin(edge);
398
399 dc.SetPen(facePen);
400 dc.SetBrush(faceBrush);
401 dc.DrawRectangle(sashPosition, 0, GetEdgeMargin(edge), h);
402
403 if (GetWindowStyleFlag() & wxSW_3D)
404 {
405 if (edge == wxSASH_LEFT)
406 {
407 // Draw a black line on the left to indicate that the
408 // sash is raised
409 dc.SetPen(blackPen);
410 dc.DrawLine(GetEdgeMargin(edge), 0, GetEdgeMargin(edge), h);
411 }
412 else
413 {
414 // Draw a white line on the right to indicate that the
415 // sash is raised
416 dc.SetPen(whitePen);
417 dc.DrawLine(w - GetEdgeMargin(edge), 0, w - GetEdgeMargin(edge), h);
418 }
419 }
420 }
421 else // top or bottom
422 {
423 int sashPosition = 0;
424 if (edge == wxSASH_TOP)
425 sashPosition = 0;
426 else
427 sashPosition = h - GetEdgeMargin(edge);
428
429 dc.SetPen(facePen);
430 dc.SetBrush(faceBrush);
431 dc.DrawRectangle(0, sashPosition, w, GetEdgeMargin(edge));
432
433 if (GetWindowStyleFlag() & wxSW_3D)
434 {
435 if (edge == wxSASH_BOTTOM)
436 {
437 // Draw a black line on the bottom to indicate that the
438 // sash is raised
439 dc.SetPen(blackPen);
440 dc.DrawLine(0, h - GetEdgeMargin(edge), w, h - GetEdgeMargin(edge));
441 }
442 else
443 {
444 // Draw a white line on the top to indicate that the
445 // sash is raised
446 dc.SetPen(whitePen);
447 dc.DrawLine(0, GetEdgeMargin(edge), w, GetEdgeMargin(edge));
448 }
449 }
450 }
451
452 dc.SetPen(wxNullPen);
453 dc.SetBrush(wxNullBrush);
454 }
455
456 // Draw the sash tracker (for whilst moving the sash)
457 void wxSashWindow::DrawSashTracker(wxSashEdgePosition edge, int x, int y)
458 {
459 int w, h;
460 GetClientSize(&w, &h);
461
462 wxScreenDC screenDC;
463 int x1, y1;
464 int x2, y2;
465
466 if ( edge == wxSASH_LEFT || edge == wxSASH_RIGHT )
467 {
468 x1 = x; y1 = 2;
469 x2 = x; y2 = h-2;
470
471 if ( (edge == wxSASH_LEFT) && (x1 > w) )
472 {
473 x1 = w; x2 = w;
474 }
475 else if ( (edge == wxSASH_RIGHT) && (x1 < 0) )
476 {
477 x1 = 0; x2 = 0;
478 }
479 }
480 else
481 {
482 x1 = 2; y1 = y;
483 x2 = w-2; y2 = y;
484
485 if ( (edge == wxSASH_TOP) && (y1 > h) )
486 {
487 y1 = h;
488 y2 = h;
489 }
490 else if ( (edge == wxSASH_BOTTOM) && (y1 < 0) )
491 {
492 y1 = 0;
493 y2 = 0;
494 }
495 }
496
497 ClientToScreen(&x1, &y1);
498 ClientToScreen(&x2, &y2);
499
500 wxPen sashTrackerPen(*wxBLACK, 2, wxSOLID);
501
502 screenDC.SetLogicalFunction(wxXOR);
503 screenDC.SetPen(sashTrackerPen);
504 screenDC.SetBrush(*wxTRANSPARENT_BRUSH);
505
506 screenDC.DrawLine(x1, y1, x2, y2);
507
508 screenDC.SetLogicalFunction(wxCOPY);
509
510 screenDC.SetPen(wxNullPen);
511 screenDC.SetBrush(wxNullBrush);
512 }
513
514 // Position and size subwindows.
515 // Note that the border size applies to each subwindow, not
516 // including the edges next to the sash.
517 void wxSashWindow::SizeWindows()
518 {
519 int cw, ch;
520 GetClientSize(&cw, &ch);
521
522 if (GetChildren()->Number() > 0)
523 {
524 wxWindow* child = (wxWindow*) (GetChildren()->First()->Data());
525
526 int x = 0;
527 int y = 0;
528 int width = cw;
529 int height = ch;
530
531 // Top
532 if (m_sashes[0].m_show)
533 {
534 y = m_borderSize;
535 height -= m_borderSize;
536 }
537 y += m_extraBorderSize;
538
539 // Left
540 if (m_sashes[3].m_show)
541 {
542 x = m_borderSize;
543 width -= m_borderSize;
544 }
545 x += m_extraBorderSize;
546
547 // Right
548 if (m_sashes[1].m_show)
549 {
550 width -= m_borderSize;
551 }
552 width -= 2*m_extraBorderSize;
553
554 // Bottom
555 if (m_sashes[2].m_show)
556 {
557 height -= m_borderSize;
558 }
559 height -= 2*m_extraBorderSize;
560
561 child->SetSize(x, y, width, height);
562 }
563
564 wxClientDC dc(this);
565 DrawBorders(dc);
566 DrawSashes(dc);
567 }
568
569 // Initialize colours
570 void wxSashWindow::InitColours()
571 {
572 // Shadow colours
573 #if defined(__WIN95__)
574 m_faceColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
575 m_mediumShadowColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW);
576 m_darkShadowColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DDKSHADOW);
577 m_lightShadowColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT);
578 m_hilightColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHILIGHT);
579 #else
580 m_faceColour = *(wxTheColourDatabase->FindColour("LIGHT GREY"));
581 m_mediumShadowColour = *(wxTheColourDatabase->FindColour("GREY"));
582 m_darkShadowColour = *(wxTheColourDatabase->FindColour("BLACK"));
583 m_lightShadowColour = *(wxTheColourDatabase->FindColour("LIGHT GREY"));
584 m_hilightColour = *(wxTheColourDatabase->FindColour("WHITE"));
585 #endif
586 }
587
588 void wxSashWindow::SetSashVisible(wxSashEdgePosition edge, bool sash)
589 {
590 m_sashes[edge].m_show = sash;
591 if (sash)
592 m_sashes[edge].m_margin = m_borderSize;
593 else
594 m_sashes[edge].m_margin = 0;
595 }
596