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