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