1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        toolwnd.cpp
3 // Purpose:     wxToolWindow implementation.
4 // Author:      Aleksandras Gluchovas
5 // Modified by:
6 // Created:     06/09/98
7 // RCS-ID:      $Id: toolwnd.cpp 35650 2005-09-23 12:56:45Z MR $
8 // Copyright:   (c) Aleksandras Gluchovas
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14 
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18 
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22 
23 #include "wx/fl/toolwnd.h"
24 
25 #define _IMG_A  0xAA    // Note: modified from _A to _IMG_A, _A was already defined (cygwin)
26 #define _IMG_B  0x00    // Note: modified from _B to _IMG_A, _B was already defined (cygwin)
27 #define _IMG_C  0x55    // Note: modified from _C to _IMG_C, for consistency reasons.
28 #define _IMG_D  0x00    // Note: modified from _D to _IMG_D, for consistency reasons.
29 
30 // FOR NOW:: static
31 
32 static const unsigned char _gCheckerImg[16] = { _IMG_A,_IMG_B,_IMG_C,_IMG_D,
33                                                 _IMG_A,_IMG_B,_IMG_C,_IMG_D,
34                                                 _IMG_A,_IMG_B,_IMG_C,_IMG_D,
35                                                 _IMG_A,_IMG_B,_IMG_C,_IMG_D
36                                               };
37 
38 /***** Implementation for class wxToolWindow *****/
39 
40 IMPLEMENT_DYNAMIC_CLASS( wxToolWindow, wxFrame)
41 
42 BEGIN_EVENT_TABLE( wxToolWindow, wxFrame )
43 
44     EVT_PAINT    ( wxToolWindow::OnPaint )
45     EVT_MOTION   ( wxToolWindow::OnMotion )
46     EVT_LEFT_DOWN( wxToolWindow::OnLeftDown )
47     EVT_LEFT_UP  ( wxToolWindow::OnLeftUp )
48     EVT_SIZE     ( wxToolWindow::OnSize )
49 
50 
51     EVT_ERASE_BACKGROUND( wxToolWindow::OnEraseBackground )
52 
53 END_EVENT_TABLE()
54 
55 enum INTERNAL_HIT_CODES
56 {
57     HITS_WND_NOTHING,
58     HITS_WND_CLIENT,
59     HITS_WND_TITLE,
60 
61     HITS_WND_LEFT_EDGE,
62     HITS_WND_RIGHT_EDGE,
63     HITS_WND_TOP_EDGE,
64     HITS_WND_BOTTOM_EDGE,
65 
66     HITS_WND_TOP_LEFT_CORNER,
67     HITS_WND_BOTTOM_RIGHT_CORNER,
68     HITS_WND_TOP_RIGHT_CORNER,
69     HITS_WND_BOTTOM_LEFT_CORNER
70 };
71 
wxToolWindow()72 wxToolWindow::wxToolWindow()
73 
74     : mpClientWnd   ( NULL ),
75 
76 #ifndef __WXMSW__
77     mTitleFont( 8, wxSWISS,  wxNORMAL, wxNORMAL ),
78 #else
79     // just to simulate MS-Dev style
80     mTitleFont( 8, wxSWISS,  wxNORMAL, wxNORMAL, false, wxT("MS Sans Serif") ),
81 #endif
82 
83     mTitleHeight  ( 16 ),
84     mClntHorizGap ( 2 ),
85     mClntVertGap  ( 2 ),
86     mWndVertGap   ( 4 ),
87     mWndHorizGap  ( 4 ),
88 
89     mButtonGap    ( 2 ),
90     mInTitleMargin( 4 ),
91     mHintBorder   ( 4 ),
92 
93     mResizeStarted( false ),
94     mRealTimeUpdatesOn( true ),
95 
96     mMTolerance   ( 5 ), // mouse-resizing tollerance
97 
98     mCursorType( HITS_WND_NOTHING ),
99     mMouseCaptured( false ),
100 
101     mpScrDc( NULL )
102 
103 {
104 }
105 
~wxToolWindow()106 wxToolWindow::~wxToolWindow()
107 {
108     if ( mpScrDc ) delete mpScrDc;
109 
110     for( size_t i = 0; i != mButtons.Count(); ++i )
111         delete mButtons[i];
112 }
113 
LayoutMiniButtons()114 void wxToolWindow::LayoutMiniButtons()
115 {
116     int w,h;
117 
118     GetSize( &w, &h );
119 
120     int x = w - mWndHorizGap - mInTitleMargin - BTN_BOX_WIDTH;
121     int y = mWndVertGap + 2;
122 
123     for( size_t i = 0; i != mButtons.Count(); ++i )
124     {
125         mButtons[i]->SetPos( wxPoint( x,y ) );
126         x-= BTN_BOX_WIDTH + mButtonGap;
127     }
128 }
129 
SetClient(wxWindow * pWnd)130 void wxToolWindow::SetClient( wxWindow* pWnd )
131 {
132     mpClientWnd = pWnd;
133 }
134 
GetClient()135 wxWindow* wxToolWindow::GetClient()
136 {
137     return mpClientWnd;
138 }
139 
SetTitleFont(wxFont & font)140 void wxToolWindow::SetTitleFont( wxFont& font )
141 {
142     mTitleFont = font;
143 }
144 
AddMiniButton(cbMiniButton * pBtn)145 void wxToolWindow::AddMiniButton( cbMiniButton* pBtn )
146 {
147     pBtn->mpWnd = this;
148 
149     mButtons.Add( pBtn );
150 
151     // not necesserely now..
152     //LayoutMiniButtons();
153 }
154 
OnPaint(wxPaintEvent & WXUNUSED (event))155 void wxToolWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
156 {
157     wxPaintDC pdc( this );
158     wxWindowDC dc( this );
159 
160     int w,h;
161     GetSize( &w, &h );
162 
163     wxBrush backGround( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID );
164     //dc.SetBrush( *wxLIGHT_GREY_BRUSH );
165     dc.SetBrush( backGround );
166     dc.SetPen( *wxTRANSPARENT_PEN );
167 
168     int y = mWndVertGap + mTitleHeight + mClntVertGap;
169 
170     dc.DrawRectangle( 0,0, w, y );                                      // Top grey part.
171     dc.DrawRectangle( 0,y-1, mWndHorizGap + mClntHorizGap, h - y );     // Left grey part.
172     dc.DrawRectangle( w - ( mWndHorizGap + mClntHorizGap ), y-1,
173                       mWndHorizGap + mClntHorizGap, h - y );            // Right grey part.
174     dc.DrawRectangle( 0, h - mWndVertGap - mClntVertGap, w, mWndVertGap + mClntVertGap ); // Bottom grey part.
175 
176     // draw shades
177     dc.SetPen( *wxLIGHT_GREY_PEN );
178 
179     dc.DrawLine( 0,0, w, 0 );
180     dc.DrawLine( 0,0, 0, h );
181 
182     dc.SetPen( *wxWHITE_PEN );
183 
184     dc.DrawLine( 1,1, w, 1 );
185     dc.DrawLine( 1,2, 1, h );
186 
187     dc.SetPen( *wxGREY_PEN );
188 
189     dc.DrawLine( w - 2, 1, w - 2, h - 1 );
190     dc.DrawLine( 1, h - 2, w - 2, h - 2 );
191 
192     dc.SetPen( *wxBLACK_PEN );
193 
194     dc.DrawLine( 0, h - 1, w, h - 1 );
195     dc.DrawLine( w-1, 0, w-1, h );
196 
197     // fill inner area
198 
199     dc.SetBrush( *wxTheBrushList->FindOrCreateBrush( wxColour( 0,0,128 ), wxSOLID ) );
200 
201     dc.DrawRectangle( mWndHorizGap, mWndVertGap, w - mWndHorizGap*2, mTitleHeight );
202 
203     dc.SetFont( mTitleFont );
204 
205     for( size_t i = 0; i != mButtons.Count(); ++i )
206         mButtons[i]->Draw( dc );
207 
208     int x1 = mWndHorizGap + mClntHorizGap;
209     int x2 = mButtons[ mButtons.GetCount() - 1 ]->mPos.x - mClntHorizGap*2;
210 
211     dc.SetClippingRegion( x1, mWndVertGap + mClntVertGap, x2 - x1, mTitleHeight );
212 
213     dc.SetTextForeground( *wxWHITE );
214     dc.SetBackgroundMode(  wxTRANSPARENT );
215     dc.DrawText( GetTitle(), mWndHorizGap + 2, mWndVertGap + 1 );
216 }
217 
GetScrWindowRect(wxRect & r)218 void wxToolWindow::GetScrWindowRect( wxRect& r )
219 {
220     int x,y;
221     GetPosition(&x,&y);
222     int w,h;
223     GetSize( &w, &h );
224 
225     r.x = x; r.y = y;
226     r.width = w; r.height = h;
227 }
228 
GetScrMousePos(wxMouseEvent & event,wxPoint & pos)229 void wxToolWindow::GetScrMousePos( wxMouseEvent& event, wxPoint& pos )
230 {
231     int x = event.m_x, y = event.m_y;
232 
233     ClientToScreen( &x, &y );
234 
235     pos.x = x; pos.y = y;
236 }
237 
HitTestWindow(wxMouseEvent & event)238 int wxToolWindow::HitTestWindow( wxMouseEvent& event )
239 {
240     wxPoint pos;
241     wxRect r;
242 
243     GetScrMousePos( event, pos );
244     GetScrWindowRect( r );
245 
246     int k = mMTolerance;
247 
248     if ( !( pos.x >= r.x && pos.y >= r.y &&
249             pos.x < r.x + r.width &&
250             pos.y < r.y + r.height )
251        )
252         return HITS_WND_NOTHING;
253 
254     if ( pos.y <= r.y + k )
255     {
256         if ( pos.x < r.x + k*2 )
257             return HITS_WND_TOP_LEFT_CORNER;
258         else
259         {
260             if ( pos.x >= r.x + r.width - k*2 )
261                 return HITS_WND_TOP_RIGHT_CORNER;
262             else
263                 return HITS_WND_TOP_EDGE;
264         }
265     }
266     else
267     {
268         if ( pos.y >= r.y + r.height - k )
269         {
270             if ( pos.x < r.x + k*2 )
271                 return HITS_WND_BOTTOM_LEFT_CORNER;
272             else
273             {
274                 if ( pos.x > r.x + r.width - k*2 )
275                     return HITS_WND_BOTTOM_RIGHT_CORNER;
276                 else
277                     return HITS_WND_BOTTOM_EDGE;
278             }
279         }
280         else
281         {
282             if ( pos.x <= r.x + k )
283                 return HITS_WND_LEFT_EDGE;
284             else
285             {
286                 if ( pos.x >= r.x + r.width - k )
287                     return HITS_WND_RIGHT_EDGE;
288                 else
289                 {
290                     if ( pos.y <= r.y + mWndVertGap + mTitleHeight + mClntVertGap )
291                         return HITS_WND_TITLE;
292                     else
293                         return HITS_WND_CLIENT;
294                 }
295             }
296         }
297     }
298 }
299 
DrawHintRect(const wxRect & r)300 void wxToolWindow::DrawHintRect( const wxRect& r )
301 {
302     // BUG BUG BUG (wx):: somehow stippled brush works only
303     //                    when the bitmap created on stack, not
304     //                    as a member of the class
305 
306     int prevLF = mpScrDc->GetLogicalFunction();
307 
308     mpScrDc->SetLogicalFunction( wxXOR );
309 
310     wxBitmap checker( (const char*)_gCheckerImg, 8,8 );
311 
312     wxBrush checkerBrush( checker );
313 
314     mpScrDc->SetPen( *wxTRANSPARENT_PEN );
315     mpScrDc->SetBrush( checkerBrush );
316 
317     int half = mHintBorder / 2;
318 
319     mpScrDc->DrawRectangle( r.x - half, r.y - half,
320                             r.width + 2*half, mHintBorder );
321 
322     mpScrDc->DrawRectangle( r.x - half, r.y + r.height - half,
323                             r.width + 2*half, mHintBorder );
324 
325     mpScrDc->DrawRectangle( r.x - half, r.y + half - 1,
326                             mHintBorder, r.height - 2*half + 2);
327 
328     mpScrDc->DrawRectangle( r.x + r.width - half,
329                             r.y + half - 1,
330                             mHintBorder, r.height - 2*half + 2);
331 
332     mpScrDc->SetBrush( wxNullBrush );
333 
334     mpScrDc->SetLogicalFunction( prevLF );
335 }
336 
SetHintCursor(int type)337 void wxToolWindow::SetHintCursor( int type )
338 {
339     if ( mResizeStarted )
340         return;
341 
342     if ( type == HITS_WND_NOTHING || type == HITS_WND_CLIENT )
343     {
344         // the cursor is out of window - reset to arrow
345 
346         if ( mMouseCaptured )
347         {
348             ReleaseMouse();
349             mMouseCaptured = false;
350         }
351 
352         SetCursor( wxCURSOR_ARROW );
353 
354         mCursorType = type;
355 
356         return;
357     }
358 
359     // did the cursor actually changed?
360 
361     if ( type != mCursorType )
362     {
363         mCursorType = type;
364 
365         switch ( type )
366         {
367             case HITS_WND_LEFT_EDGE   : SetCursor( wxCURSOR_SIZEWE ); break;
368             case HITS_WND_RIGHT_EDGE  : SetCursor( wxCURSOR_SIZEWE ); break;
369             case HITS_WND_TOP_EDGE    : SetCursor( wxCURSOR_SIZENS ); break;
370             case HITS_WND_BOTTOM_EDGE : SetCursor( wxCURSOR_SIZENS ); break;
371 
372             case HITS_WND_TOP_LEFT_CORNER     : SetCursor( wxCURSOR_SIZENWSE ); break;
373             case HITS_WND_BOTTOM_RIGHT_CORNER : SetCursor( wxCURSOR_SIZENWSE ); break;
374             case HITS_WND_TOP_RIGHT_CORNER    : SetCursor( wxCURSOR_SIZENESW ); break;
375             case HITS_WND_BOTTOM_LEFT_CORNER  : SetCursor( wxCURSOR_SIZENESW ); break;
376 
377             case HITS_WND_TITLE  : SetCursor( wxCURSOR_ARROW ); break;
378             case HITS_WND_CLIENT : SetCursor( wxCURSOR_ARROW ); break;
379 
380             default: break;
381         }
382 
383         if (mMouseCaptured)
384         {
385             mMouseCaptured = false;
386             ReleaseMouse();
387         }
388     }
389 
390     if ( !mMouseCaptured )
391     {
392         mMouseCaptured = true;
393         CaptureMouse();
394     }
395 }
396 
397 #define FL_INFINITY 32768
398 
clip_to(int & value,long from,long till)399 static inline void clip_to( int& value, long from, long till )
400 {
401     if ( value < from )
402         value = from;
403 
404     if ( value > till )
405         value = till;
406 }
407 
AdjustRectPos(const wxRect & original,const wxSize & newDim,wxRect & newRect)408 void wxToolWindow::AdjustRectPos( const wxRect& original, const wxSize& newDim, wxRect& newRect )
409 {
410     if ( mCursorType == HITS_WND_TOP_EDGE ||
411          mCursorType == HITS_WND_TOP_LEFT_CORNER )
412     {
413         newRect.x = original.x + original.width  - newDim.x;
414         newRect.y = original.y + original.height - newDim.y;
415     }
416     else
417     if ( mCursorType == HITS_WND_LEFT_EDGE ||
418          mCursorType == HITS_WND_BOTTOM_LEFT_CORNER )
419     {
420         newRect.x = original.x + original.width  - newDim.x;
421         newRect.y = original.y;
422     }
423     else
424     if ( mCursorType == HITS_WND_RIGHT_EDGE ||
425          mCursorType == HITS_WND_TOP_RIGHT_CORNER )
426     {
427         newRect.x = original.x;
428         newRect.y = original.y + original.height - newDim.y;
429     }
430     else
431     if ( mCursorType == HITS_WND_BOTTOM_EDGE ||
432          mCursorType == HITS_WND_BOTTOM_RIGHT_CORNER )
433     {
434         newRect.x = original.x;
435         newRect.y = original.y;
436     }
437 
438     newRect.width  = newDim.x;
439     newRect.height = newDim.y;
440 }
441 
CalcResizedRect(wxRect & rect,wxPoint & delta,const wxSize & minDim)442 void wxToolWindow::CalcResizedRect( wxRect& rect, wxPoint& delta, const wxSize& minDim )
443 {
444     // Microsoft's rect-coordinates are best suited
445     // for the case of corner-clipping
446 
447     int left   = mInitialRect.x;
448     int top    = mInitialRect.y;
449     int right  = mInitialRect.x + mInitialRect.width;
450     int bottom = mInitialRect.y + mInitialRect.height;
451 
452     // constraint delta edge is dragged
453 
454     switch ( mCursorType )
455     {
456         case HITS_WND_LEFT_EDGE   : delta.y = 0; break;
457         case HITS_WND_RIGHT_EDGE  : delta.y = 0; break;
458         case HITS_WND_TOP_EDGE    : delta.x = 0; break;
459         case HITS_WND_BOTTOM_EDGE : delta.x = 0; break;
460         default: break;
461     }
462 
463     if ( mCursorType == HITS_WND_TOP_EDGE ||
464          mCursorType == HITS_WND_TOP_LEFT_CORNER )
465     {
466         left += delta.x;
467         top  += delta.y;
468 
469         clip_to( left, -FL_INFINITY, mInitialRect.x + mInitialRect.width  - minDim.x  );
470         clip_to( top,  -FL_INFINITY, mInitialRect.y + mInitialRect.height - minDim.y );
471     }
472     else
473     if ( mCursorType == HITS_WND_LEFT_EDGE ||
474          mCursorType == HITS_WND_BOTTOM_LEFT_CORNER )
475     {
476         left   += delta.x;
477         bottom += delta.y;
478 
479         clip_to( left,    -FL_INFINITY, mInitialRect.x + mInitialRect.width  - minDim.x  );
480         clip_to( bottom,  mInitialRect.y + minDim.y, FL_INFINITY );
481     }
482     else
483     if ( mCursorType == HITS_WND_RIGHT_EDGE ||
484         mCursorType == HITS_WND_TOP_RIGHT_CORNER )
485     {
486         right += delta.x;
487         top   += delta.y;
488 
489         clip_to( right, mInitialRect.x + minDim.x, FL_INFINITY );
490         clip_to( top,   -FL_INFINITY, mInitialRect.y + mInitialRect.height - minDim.y );
491     }
492     else
493     if ( mCursorType == HITS_WND_BOTTOM_EDGE ||
494          mCursorType == HITS_WND_BOTTOM_RIGHT_CORNER )
495     {
496         right  += delta.x;
497         bottom += delta.y;
498 
499         clip_to( right,  mInitialRect.x + minDim.x,  FL_INFINITY );
500         clip_to( bottom, mInitialRect.y + minDim.y, FL_INFINITY );
501     }
502     else
503     {
504         wxFAIL_MSG( _T("what did the cursor hit?") );
505     }
506 
507     rect.x = left;
508     rect.y = top;
509     rect.width  = right - left;
510     rect.height = bottom - top;
511 }
512 
GetMinimalWndDim()513 wxSize wxToolWindow::GetMinimalWndDim()
514 {
515     return wxSize( (mWndHorizGap + mClntHorizGap)*2 + BTN_BOX_WIDTH*4,
516                    (mWndVertGap  + mClntVertGap )*2 + mTitleHeight );
517 }
518 
OnMotion(wxMouseEvent & event)519 void wxToolWindow::OnMotion( wxMouseEvent& event )
520 {
521     if ( !mResizeStarted )
522     {
523         for( size_t i = 0; i != mButtons.Count(); ++i )
524             mButtons[i]->OnMotion( wxPoint( event.m_x, event.m_y ) );
525 
526         SetHintCursor( HitTestWindow( event ) );
527         return;
528     }
529 
530     wxPoint pos;
531     GetScrMousePos( event, pos );
532 
533     if ( mCursorType == HITS_WND_TITLE )
534     {
535         int w,h;
536         GetSize( &w, &h );
537 
538         SetSize( mInitialRect.x + pos.x - mDragOrigin.x,
539                  mInitialRect.y + pos.y - mDragOrigin.y,
540                  w,h, 0 );
541     }
542 
543     else
544     {
545         wxPoint delta( pos.x - mDragOrigin.x, pos.y - mDragOrigin.y );
546 
547         wxRect newRect;
548 
549         wxSize minDim = GetMinimalWndDim();
550 
551         CalcResizedRect( newRect, delta, minDim );
552 
553         wxSize borderDim( ( mWndHorizGap + mClntHorizGap )*2,
554                           ( mWndVertGap  + mClntVertGap  )*2 + mTitleHeight );
555 
556         wxSize preferred = GetPreferredSize( wxSize( newRect.width  - borderDim.x,
557                                              newRect.height - borderDim.y ) );
558 
559         preferred.x += borderDim.x;
560         preferred.y += borderDim.y;
561 
562         //CalcResizedRect( newRect, delta, preferred );
563 
564         wxRect finalRect = newRect;
565 
566         AdjustRectPos( newRect, preferred, finalRect );
567 
568         if ( mRealTimeUpdatesOn )
569         {
570             SetSize( finalRect.x, finalRect.y,
571                      finalRect.width, finalRect.height, 0 );
572         }
573         else
574         {
575             DrawHintRect( mPrevHintRect );
576             DrawHintRect( finalRect );
577 
578             ::wxLogTrace(wxT("wxToolWindow"),wxT("%d,%d / %d,%d\n"), finalRect.x, finalRect.y, finalRect.width, finalRect.height);
579         }
580 
581         mPrevHintRect = finalRect;
582     }
583 }
584 
OnLeftDown(wxMouseEvent & event)585 void wxToolWindow::OnLeftDown( wxMouseEvent& event )
586 {
587     int result = HitTestWindow( event );
588 
589     for( size_t i = 0; i != mButtons.Count(); ++i )
590     {
591         mButtons[i]->OnLeftDown( wxPoint( event.m_x, event.m_y ) );
592 
593         if ( mButtons[i]->IsPressed() )
594             return; // button hitted,
595     }
596 
597     if ( result >= HITS_WND_LEFT_EDGE || result == HITS_WND_TITLE )
598     {
599         GetScrMousePos( event, mDragOrigin );
600 
601         /*
602         if ( mMouseCaptured `)
603         {
604             ReleaseMouse();
605             mMouseCaptured = false;
606         }*/
607 
608         if ( result == HITS_WND_TITLE &&
609              HandleTitleClick( event ) )
610             return;
611 
612         mResizeStarted = true;
613 
614         int x,y;
615         GetPosition( &x, &y );
616 
617         mInitialRect.x = x;
618         mInitialRect.y = y;
619 
620         GetSize( &x, &y );
621         mInitialRect.width  = x;
622         mInitialRect.height = y;
623 
624         mPrevHintRect = mInitialRect;
625 
626         if ( mCursorType != HITS_WND_TITLE && !mRealTimeUpdatesOn )
627         {
628             mpScrDc = new wxScreenDC();
629 
630             wxScreenDC::StartDrawingOnTop( (wxRect*)NULL );
631 
632             DrawHintRect( mInitialRect );
633         }
634     }
635 }
636 
OnLeftUp(wxMouseEvent & event)637 void wxToolWindow::OnLeftUp( wxMouseEvent& event )
638 {
639     for( size_t i = 0; i != mButtons.Count(); ++i )
640     {
641         mButtons[i]->OnLeftUp( wxPoint( event.m_x, event.m_y ) );
642 
643         if ( mButtons[i]->WasClicked() )
644         {
645             OnMiniButtonClicked( i ); // notify derived classes
646             mButtons[i]->Reset();
647         }
648     }
649 
650     if ( mResizeStarted )
651     {
652         mResizeStarted = false;
653 
654         if ( mCursorType != HITS_WND_TITLE )
655         {
656             if ( !mRealTimeUpdatesOn )
657             {
658                 DrawHintRect( mPrevHintRect );
659 
660                 wxScreenDC::EndDrawingOnTop();
661 
662                 delete mpScrDc;
663 
664                 mpScrDc = NULL;
665 
666                 SetSize( mPrevHintRect.x, mPrevHintRect.y,
667                          mPrevHintRect.width, mPrevHintRect.height, 0 );
668             }
669         }
670     }
671 }
672 
OnSize(wxSizeEvent & WXUNUSED (event))673 void wxToolWindow::OnSize( wxSizeEvent& WXUNUSED(event) )
674 {
675     if ( mpClientWnd )
676     {
677         int w,h;
678         GetSize( &w, &h );
679 
680         int x = mWndHorizGap + mClntHorizGap;
681         int y = mWndVertGap  + mTitleHeight + mClntVertGap;
682 
683         mpClientWnd->SetSize( x-1, y-1,
684                               w - 2*(mWndHorizGap + mClntHorizGap),
685                               h - y - mClntVertGap - mWndVertGap,
686                               0
687                             );
688     }
689 
690     LayoutMiniButtons();
691 }
692 
GetPreferredSize(const wxSize & given)693 wxSize wxToolWindow::GetPreferredSize( const wxSize& given )
694 {
695     return given;
696 }
697 
OnEraseBackground(wxEraseEvent & WXUNUSED (event))698 void wxToolWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
699 {
700     // nothing
701 }
702 
703 /***** Implementation for class cbMiniButton *****/
704 
cbMiniButton()705 cbMiniButton::cbMiniButton()
706 
707     : mVisible( true ),
708       mEnabled( true ),
709 
710       mpLayout( NULL ),
711       mpPane  ( NULL ),
712       mpPlugin( NULL ),
713       mpWnd   ( NULL ),
714 
715       mWasClicked( false ),
716       mDragStarted( false ),
717       mPressed( false )
718 {}
719 
SetPos(const wxPoint & pos)720 void cbMiniButton::SetPos( const wxPoint& pos )
721 {
722     mPos = pos;
723 }
724 
HitTest(const wxPoint & pos)725 bool cbMiniButton::HitTest( const wxPoint& pos )
726 {
727     if ( !mVisible ) return false;
728 
729     return ( pos.x >= mPos.x && pos.y >= mPos.y &&
730              pos.x < mPos.x + BTN_BOX_WIDTH     &&
731              pos.y < mPos.y + BTN_BOX_HEIGHT );
732 }
733 
OnLeftDown(const wxPoint & pos)734 void cbMiniButton::OnLeftDown( const wxPoint& pos )
735 {
736     if ( !mVisible || mDragStarted ) return;
737 
738     if ( HitTest( pos ) && mEnabled )
739     {
740         if ( mpPlugin )
741         {
742             mpLayout->CaptureEventsForPane( mpPane );
743             mpLayout->CaptureEventsForPlugin( mpPlugin );
744         }
745         else
746             mpWnd->CaptureMouse();
747 
748         mDragStarted = true;
749         mPressed     = true;
750         mWasClicked  = false;
751 
752         Refresh();
753     }
754 }
755 
OnLeftUp(const wxPoint & WXUNUSED (pos))756 void cbMiniButton::OnLeftUp( const wxPoint& WXUNUSED(pos) )
757 {
758     if ( !mVisible || !mDragStarted ) return;
759 
760     if ( mpPlugin )
761     {
762         mpLayout->ReleaseEventsFromPane( mpPane );
763         mpLayout->ReleaseEventsFromPlugin( mpPlugin );
764     }
765     else
766         mpWnd->ReleaseMouse();
767 
768     mWasClicked  = mPressed;
769     mDragStarted = false;
770 
771     mPressed = false;
772     Refresh();
773 }
774 
OnMotion(const wxPoint & pos)775 void cbMiniButton::OnMotion( const wxPoint& pos )
776 {
777     if ( !mVisible ) return;
778 
779     if ( mDragStarted )
780     {
781         mPressed = HitTest( pos );
782 
783         Refresh();
784     }
785 }
786 
Refresh()787 void cbMiniButton::Refresh()
788 {
789     if ( mpLayout )
790     {
791          wxClientDC dc( &mpLayout->GetParentFrame() );
792 
793          Draw( dc );
794     }
795     else
796     {
797         wxWindowDC dc( mpWnd );
798 
799         Draw( dc );
800     }
801 }
802 
Draw(wxDC & dc)803 void cbMiniButton::Draw( wxDC& dc )
804 {
805     if ( !mVisible ) return;
806 
807     dc.SetPen( *wxTRANSPARENT_PEN );
808 
809     dc.SetBrush( *wxLIGHT_GREY_BRUSH );
810 
811     dc.DrawRectangle( mPos.x + 1, mPos.y + 1, BTN_BOX_WIDTH - 2, BTN_BOX_HEIGHT - 2 );
812 
813     // "hard-code" metafile
814 
815     if ( !mPressed )
816         dc.SetPen( *wxWHITE_PEN );
817     else
818         dc.SetPen( *wxBLACK_PEN );
819 
820     dc.DrawLine( mPos.x, mPos.y, mPos.x + BTN_BOX_WIDTH, mPos.y );
821     dc.DrawLine( mPos.x, mPos.y, mPos.x, mPos.y + BTN_BOX_HEIGHT );
822 
823     dc.SetPen( *wxGREY_PEN );
824 
825     if ( !mPressed )
826     {
827         dc.DrawLine( mPos.x + 1, mPos.y + BTN_BOX_HEIGHT - 2,
828                      mPos.x + BTN_BOX_WIDTH - 1, mPos.y + BTN_BOX_HEIGHT - 2 );
829 
830         dc.DrawLine( mPos.x + BTN_BOX_WIDTH - 2, mPos.y + 1,
831                      mPos.x + BTN_BOX_WIDTH - 2, mPos.y + BTN_BOX_HEIGHT - 1 );
832     }
833     else
834     {
835         dc.DrawLine( mPos.x + 1, mPos.y + 1,
836                      mPos.x + BTN_BOX_WIDTH - 2, mPos.y + 1 );
837 
838         dc.DrawLine( mPos.x + 1, mPos.y + 1,
839                      mPos.x + 1, mPos.y + BTN_BOX_HEIGHT - 2 );
840     }
841 
842     if ( !mPressed )
843         dc.SetPen( *wxBLACK_PEN );
844     else
845         dc.SetPen( *wxWHITE_PEN );
846 
847     dc.DrawLine( mPos.x, mPos.y + BTN_BOX_HEIGHT - 1,
848                  mPos.x + BTN_BOX_WIDTH, mPos.y + BTN_BOX_HEIGHT - 1 );
849 
850     dc.DrawLine( mPos.x + BTN_BOX_WIDTH - 1, mPos.y ,
851                  mPos.x + BTN_BOX_WIDTH - 1, mPos.y + BTN_BOX_HEIGHT );
852 }
853 
WasClicked()854 bool cbMiniButton::WasClicked()
855 {
856     return mWasClicked;
857 }
858 
Reset()859 void cbMiniButton::Reset()
860 {
861     mWasClicked = false;
862 }
863 
864 /***** Implementation fro class cbCloseBox *****/
865 
Draw(wxDC & dc)866 void cbCloseBox::Draw( wxDC& dc )
867 {
868     cbMiniButton::Draw( dc );
869 
870     dc.SetPen( *wxBLACK_PEN );
871 
872     int width = BTN_BOX_WIDTH - 7;
873 
874     int xOfs = (mPressed) ? 4 : 3;
875     int yOfs = (mPressed) ? 4 : 3;
876 
877     for( int i = 0; i != BTN_X_WEIGHT; ++i )
878     {
879         dc.DrawLine( mPos.x + xOfs + i,
880                      mPos.y + yOfs,
881                      mPos.x + xOfs + i + width,
882                      mPos.y + yOfs + width );
883 
884         dc.DrawLine( mPos.x + xOfs + i + width - 1,
885                      mPos.y + yOfs,
886                      mPos.x + xOfs + i - 1,
887                      mPos.y + yOfs + width );
888     }
889 }
890 
891 /***** Implementation fro class cbCollapseBox *****/
892 
my_swap(int & a,int & b)893 inline static void my_swap( int& a, int& b )
894 {
895     long tmp = a;
896     a = b;
897     b = tmp;
898 }
899 
Draw(wxDC & dc)900 void cbCollapseBox::Draw( wxDC& dc )
901 {
902     cbMiniButton::Draw( dc );
903 
904     dc.SetPen( *wxTRANSPARENT_PEN );
905 
906     wxPoint arr[3];
907 
908     int yOfs  = (mPressed) ? 3 : 2;
909     int xOfs  = (mPressed) ? 5 : 4;
910     int width = BTN_BOX_WIDTH - 8;
911 
912     // rotating/shifting triangle inside collapse box
913 
914     arr[0].x = xOfs;
915     arr[0].y = yOfs-1;
916     arr[2].x = xOfs;
917     arr[2].y = BTN_BOX_HEIGHT - yOfs - 1;
918     arr[1].x = xOfs + width;
919     arr[1].y = (arr[2].y + arr[0].y)/2;
920 
921     if ( !mIsAtLeft )
922     {
923         arr[0].x = BTN_BOX_WIDTH - arr[0].x;
924         arr[1].x = BTN_BOX_WIDTH - arr[1].x;
925         arr[2].x = BTN_BOX_WIDTH - arr[2].x;
926     }
927 
928     if ( !mpPane->IsHorizontal() )
929     {
930         my_swap( arr[0].y, arr[0].x );
931         my_swap( arr[1].y, arr[1].x );
932         my_swap( arr[2].y, arr[2].x );
933 
934         arr[0].x += 1;
935         arr[1].x += 1;
936         arr[2].x += 1;
937 
938         //arr[1].y -= 1;
939     }
940 
941     arr[0].x += mPos.x;
942     arr[0].y += mPos.y;
943     arr[1].x += mPos.x;
944     arr[1].y += mPos.y;
945     arr[2].x += mPos.x;
946     arr[2].y += mPos.y;
947 
948     if ( !mEnabled ) dc.SetBrush( *wxGREY_BRUSH );
949     else dc.SetBrush( *wxBLACK_BRUSH );
950 
951     dc.DrawPolygon( 3, arr );
952     dc.SetBrush( wxNullBrush );
953 }
954 
955 /***** Implementation for class cbDockBoxBox *****/
956 
Draw(wxDC & dc)957 void cbDockBox::Draw( wxDC& dc )
958 {
959     cbMiniButton::Draw( dc );
960 
961     int width = BTN_BOX_WIDTH - 7;
962 
963     int xOfs = (mPressed) ? 4 : 3;
964     int yOfs = (mPressed) ? 4 : 3;
965 
966     dc.SetPen( *wxBLACK_PEN );
967     dc.SetBrush( *wxBLACK_BRUSH );
968 
969     dc.DrawRectangle( mPos.x + xOfs, mPos.y + yOfs, width, width );
970 
971     xOfs += 1;
972     yOfs += 1;
973 
974     dc.SetBrush( *wxWHITE_BRUSH );
975 
976     dc.DrawRectangle( mPos.x + xOfs, mPos.y + yOfs, width-2, width-2 );
977 }
978 
979 /***** Implementation for class wxToolWindow *****/
980 
IMPLEMENT_DYNAMIC_CLASS(cbFloatedBarWindow,wxToolWindow)981 IMPLEMENT_DYNAMIC_CLASS( cbFloatedBarWindow, wxToolWindow )
982 
983 BEGIN_EVENT_TABLE( cbFloatedBarWindow, wxToolWindow )
984 
985     EVT_LEFT_DCLICK( cbFloatedBarWindow::OnDblClick )
986 
987 END_EVENT_TABLE()
988 
989 cbFloatedBarWindow::cbFloatedBarWindow()
990 
991     : mpBar( NULL )
992 {
993     AddMiniButton( new cbCloseBox() );
994     AddMiniButton( new cbDockBox()  );
995 }
996 
SetBar(cbBarInfo * pBar)997 void cbFloatedBarWindow::SetBar( cbBarInfo* pBar )
998 {
999     mpBar = pBar;
1000 }
1001 
GetBar()1002 cbBarInfo* cbFloatedBarWindow::GetBar()
1003 {
1004     return mpBar;
1005 }
1006 
SetLayout(wxFrameLayout * pLayout)1007 void cbFloatedBarWindow::SetLayout( wxFrameLayout* pLayout )
1008 {
1009     mpLayout = pLayout;
1010 }
1011 
PositionFloatedWnd(int scrX,int scrY,int width,int height)1012 void cbFloatedBarWindow::PositionFloatedWnd( int scrX,  int scrY,
1013                                              int width, int height )
1014 {
1015     wxSize minDim = GetMinimalWndDim();
1016 
1017     SetSize( scrX - mWndHorizGap - mClntHorizGap,
1018              scrY - mClntVertGap - mTitleHeight - mWndVertGap,
1019              width + minDim.x, height + minDim.y, 0 );
1020 }
1021 
GetPreferredSize(const wxSize & given)1022 wxSize cbFloatedBarWindow::GetPreferredSize( const wxSize& given )
1023 {
1024     if ( mpBar->mDimInfo.GetDimHandler() )
1025     {
1026         cbBarDimHandlerBase* pHandler = mpBar->mDimInfo.GetDimHandler();
1027 
1028         wxSize prefDim;
1029 
1030         // int vtad = *((int*)pHandler);
1031 
1032         pHandler->OnResizeBar( mpBar, given, prefDim );
1033 
1034         return prefDim;
1035     }
1036     else
1037     {
1038         if ( mpBar->IsFixed() )
1039             return mpBar->mDimInfo.mSizes[ wxCBAR_FLOATING ];
1040         else
1041             return given; // not-fixed bars are resized exactly the way user wants
1042     }
1043 }
1044 
OnMiniButtonClicked(int btnIdx)1045 void cbFloatedBarWindow::OnMiniButtonClicked( int btnIdx )
1046 {
1047     // #1 - close mini-button
1048     // #0 - dock mini-button
1049 
1050     if ( btnIdx == 0 )
1051     {
1052         mpBar->mAlignment = -1; // sepcial "marking" for hidden bars out of floated state
1053         mpLayout->SetBarState( mpBar, wxCBAR_HIDDEN, true );
1054     }
1055     else
1056         mpLayout->SetBarState( mpBar, wxCBAR_DOCKED_HORIZONTALLY, true );
1057 }
1058 
HandleTitleClick(wxMouseEvent & event)1059 bool cbFloatedBarWindow::HandleTitleClick( wxMouseEvent& event )
1060 {
1061     ReleaseMouse();
1062     mMouseCaptured = false;
1063 
1064     wxPoint scrPos;
1065     GetScrMousePos( event, scrPos );
1066 
1067     int msX = scrPos.x,
1068         msY = scrPos.y;
1069 
1070     mpLayout->GetParentFrame().ScreenToClient( &msX, &msY );
1071 
1072     int x,y;
1073     GetPosition(&x,&y);
1074     int w,h;
1075     GetSize( &w, &h );
1076 
1077     wxSize minDim = GetMinimalWndDim();
1078 
1079     w -= minDim.x;
1080     h -= minDim.y;
1081 
1082     x += mWndHorizGap + mClntHorizGap;
1083     y += mWndVertGap  + mTitleHeight + mClntVertGap;
1084 
1085     mpLayout->GetParentFrame().ScreenToClient( &x, &y );
1086 
1087     wxRect& bounds = mpBar->mDimInfo.mBounds[ wxCBAR_FLOATING ];
1088 
1089     bounds.x = x;
1090     bounds.y = y;
1091     bounds.width  = w;
1092     bounds.height = h;
1093 
1094     cbStartBarDraggingEvent dragEvt( mpBar, wxPoint(msX,msY),
1095                                      mpLayout->GetPanesArray()[FL_ALIGN_TOP] );
1096 
1097     mpLayout->FirePluginEvent( dragEvt );
1098 
1099     return true;
1100 }
1101 
OnDblClick(wxMouseEvent & WXUNUSED (event))1102 void cbFloatedBarWindow::OnDblClick( wxMouseEvent& WXUNUSED(event) )
1103 {
1104     mpLayout->SetBarState( mpBar, wxCBAR_DOCKED_HORIZONTALLY, true );
1105 
1106     //wxMessageBox("toolWnd - dblClick!");
1107 }
1108 
1109