]> git.saurik.com Git - wxWidgets.git/blob - utils/framelayout/src/barhintspl.cpp
don't crash when invalid colour is set as fg/bg colour
[wxWidgets.git] / utils / framelayout / src / barhintspl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: No names yet.
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
5 // Modified by:
6 // Created: 30/11/98 (my 22th birthday :-)
7 // RCS-ID: $Id$
8 // Copyright: (c) Aleksandras Gluchovas
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "rowlayoutpl.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 "wx/utils.h"
29 #include "barhintspl.h"
30
31 // fixed settings
32
33 #define GROOVE_WIDTH 3 // left shade + middle line + right shade
34 #define GROOVE_TO_GROOVE_GAP 1
35 #define BOX_T_BOX_GAP 2
36 #define BOX_TO_GROOVE_GAP 3
37
38 #define BOXES_IN_HINT 2
39 #define CLOSE_BOX_IDX 0
40 #define COLLAPSE_BOX_IDX 1
41
42 // used interally
43
44 #define CLOSE_BOX_HITTED 1
45 #define COLLAPSE_BOX_HITTED 2
46
47 /***** Implementation fro class cbBarHintsPlugin *****/
48
49 IMPLEMENT_DYNAMIC_CLASS( cbBarHintsPlugin, cbPluginBase )
50
51 BEGIN_EVENT_TABLE( cbBarHintsPlugin, cbPluginBase )
52
53 EVT_PL_SIZE_BAR_WND ( cbBarHintsPlugin::OnSizeBarWindow )
54 EVT_PL_DRAW_BAR_DECOR( cbBarHintsPlugin::OnDrawBarDecorations )
55
56 EVT_PL_LEFT_DOWN( cbBarHintsPlugin::OnLeftDown )
57 EVT_PL_LEFT_UP ( cbBarHintsPlugin::OnLeftUp )
58 EVT_PL_MOTION ( cbBarHintsPlugin::OnMotion )
59
60 END_EVENT_TABLE()
61
62 cbBarHintsPlugin::cbBarHintsPlugin(void)
63
64 : mpPane( 0 ),
65 mCollapseBoxOn( TRUE ),
66 mCloseBoxOn ( TRUE ),
67 mBtnPressed ( FALSE ),
68 mGrooveCount ( 2 ),
69 mHintGap ( 4 ),
70 mXWeight ( 2 )
71 {}
72
73 cbBarHintsPlugin::cbBarHintsPlugin( wxFrameLayout* pLayout, int paneMask )
74
75 : cbPluginBase( pLayout, paneMask ),
76 mpPane( 0 ),
77 mCollapseBoxOn( TRUE ),
78 mCloseBoxOn ( TRUE ),
79 mBtnPressed ( FALSE ),
80 mGrooveCount ( 2 ),
81 mHintGap ( 5 ),
82 mXWeight ( 2 )
83 {}
84
85 void cbBarHintsPlugin::SetGrooveCount( int nGrooves )
86 {
87 mGrooveCount = nGrooves;
88 }
89
90 void cbBarHintsPlugin::CreateBoxes()
91 {
92 cbCloseBox* box1 = new cbCloseBox();
93 cbCollapseBox* box2 = new cbCollapseBox();
94
95 mBoxes[CLOSE_BOX_IDX] = box1;
96 mBoxes[COLLAPSE_BOX_IDX] = box2;
97
98 for( int i = 0; i != BOXES_IN_HINT; ++i )
99 {
100 mBoxes[i]->mpLayout = mpLayout;
101 mBoxes[i]->mpPlugin = this;
102 mBoxes[i]->mpWnd = NULL;
103 }
104 }
105
106 void cbBarHintsPlugin::Draw3DBox( wxDC& dc, const wxPoint& pos, bool pressed )
107 {
108 }
109
110 void cbBarHintsPlugin::DrawCloseBox( wxDC& dc, const wxPoint& pos, bool pressed )
111 {
112 }
113
114 void cbBarHintsPlugin::DrawCollapseBox( wxDC& dc, const wxPoint& pos,
115 bool atLeft, bool disabled, bool pressed )
116 {
117 }
118
119 void cbBarHintsPlugin::DrawGrooves( wxDC& dc, const wxPoint& pos, int length )
120 {
121 int ofs = 0;
122
123 for( int i = 0; i != mGrooveCount; ++i, ofs += ( GROOVE_WIDTH + GROOVE_TO_GROOVE_GAP ) )
124
125 if ( mpPane->IsHorizontal() )
126 {
127 dc.SetPen( mpLayout->mLightPen );
128 dc.DrawLine( pos.x + ofs, pos.y, pos.x + ofs, pos.y + length - 1 );
129 dc.DrawPoint( pos.x + ofs + 1, pos.y );
130
131 dc.SetPen( mpLayout->mDarkPen );
132 dc.DrawLine( pos.x + ofs + 2, pos.y, pos.x + ofs + 2, pos.y + length );
133 dc.DrawPoint( pos.x + ofs + 1, pos.y + length - 1 );
134 dc.DrawPoint( pos.x + ofs, pos.y + length - 1 );
135 }
136 else
137 {
138 dc.SetPen( mpLayout->mLightPen );
139 dc.DrawLine( pos.x, pos.y + ofs, pos.x + length - 1, pos.y + ofs );
140 dc.DrawPoint( pos.x, pos.y + ofs + 1 );
141
142 dc.SetPen( mpLayout->mDarkPen );
143 dc.DrawLine( pos.x, pos.y + ofs + 2, pos.x + length, pos.y + ofs + 2 );
144 dc.DrawPoint( pos.x + length - 1, pos.y + ofs + 1 );
145 dc.DrawPoint( pos.x + length - 1, pos.y + ofs );
146 }
147 }
148
149 void cbBarHintsPlugin::ExcludeHints( wxRect& rect, cbBarInfo& info )
150 {
151 int boxHeight = BTN_BOX_HEIGHT;
152
153 // collapse and close box are not placed on fixed bars
154
155 if ( info.IsFixed() || ( !mCloseBoxOn && !mCollapseBoxOn ) )
156
157 boxHeight = 0;
158
159 int height = wxMax( mGrooveCount*(GROOVE_WIDTH + GROOVE_TO_GROOVE_GAP)
160 - GROOVE_TO_GROOVE_GAP,
161 boxHeight
162 );
163
164 if ( mpPane->IsHorizontal() )
165 {
166 rect.x += ( mHintGap*2 + height );
167 rect.width -= (height + 2*mHintGap);
168
169 rect.x -= info.mDimInfo.mHorizGap + 2;
170 rect.width += info.mDimInfo.mHorizGap + 2;
171 }
172 else
173 {
174 rect.y += (mHintGap*2 + height);
175 rect.height -= (height + 2*mHintGap);
176
177 rect.y -= info.mDimInfo.mVertGap + 2;
178 rect.height += info.mDimInfo.mVertGap + 2;
179 }
180 }
181
182 void cbBarHintsPlugin::DoDrawHint( wxDC& dc, wxRect& rect,
183 int pos, int boxOfs, int grooveOfs,
184 bool isFixed )
185 {
186 if ( !isFixed )
187 {
188 if ( mpPane->IsHorizontal() )
189 {
190 if ( mCloseBoxOn )
191
192 mBoxes[CLOSE_BOX_IDX]->Draw( dc );
193
194 if ( mCollapseBoxOn )
195
196 mBoxes[COLLAPSE_BOX_IDX]->Draw( dc );
197 }
198 else
199 {
200 if ( mCloseBoxOn )
201
202 mBoxes[CLOSE_BOX_IDX]->Draw( dc );
203
204 if ( mCollapseBoxOn )
205
206 mBoxes[COLLAPSE_BOX_IDX]->Draw( dc );
207 }
208 }
209
210 if ( mpPane->IsHorizontal() )
211
212 DrawGrooves( dc, wxPoint( rect.x + mHintGap + grooveOfs, pos ),
213 rect.height - (pos - rect.y) - mHintGap );
214 else
215 DrawGrooves( dc, wxPoint( rect.x + mHintGap, rect.y + mHintGap + grooveOfs ),
216 (pos - rect.x) - mHintGap );
217 }
218
219 void cbBarHintsPlugin::GetHintsLayout( wxRect& rect, cbBarInfo& info,
220 int& boxOfs, int& grooveOfs, int& pos )
221 {
222 int boxHeight = BTN_BOX_HEIGHT;
223 int boxWidth = BTN_BOX_WIDTH + BOX_TO_GROOVE_GAP + BTN_BOX_WIDTH;
224
225 // collapse and close box are not placed on fixed bars
226
227 if ( info.IsFixed() || ( !mCloseBoxOn && !mCollapseBoxOn ) )
228 {
229 boxHeight = 0;
230 boxWidth = 0;
231 }
232 else
233 if ( !mCloseBoxOn || !mCollapseBoxOn )
234
235 boxWidth = BTN_BOX_WIDTH;
236
237 int grooveHeight = mGrooveCount*(GROOVE_WIDTH + GROOVE_TO_GROOVE_GAP)
238 - GROOVE_TO_GROOVE_GAP;
239
240 int height = wxMax( grooveHeight, boxHeight );
241
242 // center boxs and groves with respect to each other
243
244 boxOfs = ( height - boxHeight ) / 2;
245 grooveOfs = ( height - grooveHeight ) / 2;
246
247 pos = ( mpPane->IsHorizontal() ) ? rect.y + mHintGap
248 : rect.x + rect.width - mHintGap;
249
250 // setup positions for boxes
251
252 if ( !info.IsFixed() )
253 {
254 // what direction "collapse-triangle" should look at?
255
256 bool& isAtLeft = ((cbCollapseBox*)(mBoxes[COLLAPSE_BOX_IDX]))->mIsAtLeft;
257
258 isAtLeft= info.mBounds.x <= mpPane->mPaneWidth - ( info.mBounds.x + info.mBounds.width );
259
260 if ( info.IsExpanded() )
261 {
262 isAtLeft = FALSE;
263
264 cbBarInfo* pCur = info.mpPrev;
265
266 while( pCur )
267 {
268 if ( !pCur->IsFixed() )
269 {
270 isAtLeft = TRUE; break;
271 }
272
273 pCur = pCur->mpPrev;
274 }
275 }
276
277 // collapse/expand works only when more not-fixed bars are present in the same row
278
279 mBoxes[COLLAPSE_BOX_IDX]->Enable( info.mpRow->mNotFixedBarsCnt > 1 );
280
281 for( int i = 0; i != BOXES_IN_HINT; ++i )
282
283 mBoxes[i]->mpPane = mpPane;
284
285
286 if ( mpPane->IsHorizontal() )
287 {
288 if ( mCloseBoxOn )
289 {
290 mBoxes[CLOSE_BOX_IDX]->mPos = wxPoint( rect.x + mHintGap + boxOfs, pos );
291
292 pos += BTN_BOX_HEIGHT;
293 }
294
295 if ( mCollapseBoxOn )
296 {
297 if ( mCloseBoxOn ) pos += BOX_T_BOX_GAP;
298
299 mBoxes[COLLAPSE_BOX_IDX]->mPos = wxPoint( rect.x + mHintGap + boxOfs, pos );
300
301 pos += BTN_BOX_HEIGHT;
302
303 pos += BOX_TO_GROOVE_GAP;
304 }
305 }
306 else
307 {
308 if ( mCloseBoxOn )
309 {
310 pos -= BTN_BOX_WIDTH;
311
312 mBoxes[CLOSE_BOX_IDX]->mPos = wxPoint( pos , rect.y + mHintGap + boxOfs );
313 }
314
315 if ( mCollapseBoxOn )
316 {
317 if ( mCloseBoxOn ) pos -= BOX_T_BOX_GAP;
318
319 pos -= BTN_BOX_WIDTH;
320
321 mBoxes[COLLAPSE_BOX_IDX]->mPos = wxPoint( pos, rect.y + mHintGap + boxOfs );
322
323 pos -= BOX_TO_GROOVE_GAP;
324 }
325 }
326 }
327 }
328
329 static inline bool is_in_box( const wxPoint& rectPos, const wxPoint& mousePos )
330 {
331 return ( mousePos.x >= rectPos.x &&
332 mousePos.y >= rectPos.y &&
333 mousePos.x < rectPos.x + BTN_BOX_WIDTH &&
334 mousePos.y < rectPos.y + BTN_BOX_HEIGHT );
335 }
336
337 int cbBarHintsPlugin::HitTestHints( cbBarInfo& info, const wxPoint& pos )
338 {
339 wxPoint inPane = pos;
340 mpPane->PaneToFrame( &inPane.x, &inPane.y );
341
342 wxRect& rect = info.mBoundsInParent;
343
344 if ( info.IsFixed() ) return FALSE;
345
346 int boxOfs, grooveOfs, coord;
347
348 GetHintsLayout( rect, info, boxOfs, grooveOfs, coord );
349
350 if ( mpPane->IsHorizontal() )
351 {
352 if ( mCloseBoxOn )
353 {
354 if ( is_in_box( wxPoint( rect.x + mHintGap + boxOfs, coord ), inPane ) )
355
356 return CLOSE_BOX_HITTED;
357
358 coord += BTN_BOX_HEIGHT;
359 }
360
361 if ( mCollapseBoxOn )
362 {
363 if ( mCloseBoxOn ) coord += BOX_T_BOX_GAP;
364
365 if ( is_in_box( wxPoint( rect.x + mHintGap + boxOfs, coord ), inPane ) )
366
367 return COLLAPSE_BOX_HITTED;
368
369 coord += BTN_BOX_HEIGHT;
370 }
371 }
372 else
373 {
374 if ( mCloseBoxOn )
375 {
376 coord -= BTN_BOX_WIDTH;
377
378 if ( is_in_box( wxPoint( coord , rect.y + mHintGap + boxOfs ), inPane ) )
379
380 return CLOSE_BOX_HITTED;
381 }
382
383 if ( mCollapseBoxOn )
384 {
385 if ( mCloseBoxOn ) coord -= BOX_T_BOX_GAP;
386 coord -= BTN_BOX_WIDTH;
387
388 if ( is_in_box( wxPoint( coord, rect.y + mHintGap + boxOfs ), inPane ) )
389
390 return COLLAPSE_BOX_HITTED;
391 }
392 }
393
394 return FALSE;
395 }
396
397 // handlers for plugin-events
398
399 void cbBarHintsPlugin::OnSizeBarWindow( cbSizeBarWndEvent& event )
400 {
401 wxRect& rect = event.mBoundsInParent;
402 mpPane = event.mpPane;
403
404 ExcludeHints( rect, *event.mpBar );
405
406 event.Skip(); // pass event to the next plugin in the chain
407 }
408
409 void cbBarHintsPlugin::OnDrawBarDecorations( cbDrawBarDecorEvent& event )
410 {
411 wxRect& rect = event.mBoundsInParent;
412 mpPane = event.mpPane;
413
414 int boxOfs, grooveOfs, pos;
415
416 GetHintsLayout( rect, *event.mpBar, boxOfs, grooveOfs, pos );
417
418 DoDrawHint( *event.mpDc, rect, pos, boxOfs, grooveOfs, event.mpBar->IsFixed() );
419
420 // let other plugins add on their decorations
421
422 event.Skip();
423 }
424
425 void cbBarHintsPlugin::OnLeftDown( cbLeftDownEvent& event )
426 {
427 mpPane = event.mpPane;
428
429 wxPoint inFrame = event.mPos;
430 mpPane->PaneToFrame( &inFrame.x, &inFrame.y );
431
432 wxBarIterator iter( mpPane->GetRowList() );
433
434 mpClickedBar = NULL;
435
436 while ( iter.Next() )
437 {
438 cbBarInfo& bar = iter.BarInfo();
439
440 int boxOfs, grooveOfs, pos;
441
442 GetHintsLayout( bar.mBoundsInParent, bar, boxOfs, grooveOfs, pos );
443
444 if ( !bar.IsFixed() )
445
446 for( int i = 0; i != BOXES_IN_HINT; ++i )
447 {
448 mBoxes[i]->OnLeftDown( inFrame );
449
450 if ( mBoxes[i]->mPressed )
451 {
452 mBtnPressed = TRUE;
453 mpClickedBar = &bar;
454
455 return; // event handled
456 }
457 }
458 }
459
460 event.Skip();
461 }
462
463 void cbBarHintsPlugin::OnLeftUp( cbLeftUpEvent& event )
464 {
465 if ( mBtnPressed )
466 {
467 wxPoint inFrame = event.mPos;
468 mpPane->PaneToFrame( &inFrame.x, &inFrame.y );
469
470 int boxOfs, grooveOfs, pos;
471
472 GetHintsLayout( mpClickedBar->mBoundsInParent, *mpClickedBar, boxOfs, grooveOfs, pos );
473
474 int result = HitTestHints( *mpClickedBar, event.mPos );
475
476 for( int i = 0; i != BOXES_IN_HINT; ++i )
477 {
478 mBoxes[i]->OnLeftUp( inFrame );
479
480 if ( mBoxes[i]->WasClicked() )
481 {
482 if ( i == 0 )
483
484 mpLayout->SetBarState( mpClickedBar, wxCBAR_HIDDEN, TRUE );
485 else
486 {
487 if ( mpClickedBar->IsExpanded() )
488
489 mpPane->ContractBar( mpClickedBar );
490 else
491 mpPane->ExpandBar( mpClickedBar );
492 }
493 }
494 }
495
496 mBtnPressed = FALSE;
497 return;
498 }
499 else
500 event.Skip();
501 }
502
503 void cbBarHintsPlugin::OnMotion( cbMotionEvent& event )
504 {
505 if ( mBtnPressed )
506 {
507 wxPoint inFrame = event.mPos;
508 mpPane->PaneToFrame( &inFrame.x, &inFrame.y );
509
510 mpPane = event.mpPane;
511
512 for( int i = 0; i != BOXES_IN_HINT; ++i )
513
514 mBoxes[i]->OnMotion( inFrame );
515 }
516 else
517 event.Skip();
518 }
519
520 void cbBarHintsPlugin::OnInitPlugin()
521 {
522 cbPluginBase::OnInitPlugin();
523
524 cbDockPane** panes = mpLayout->GetPanesArray();
525
526 for( int i = 0; i != MAX_PANES; ++i )
527
528 if ( panes[i]->MatchesMask( mPaneMask ) )
529 {
530 panes[i]->mProps.mMinCBarDim.x = 25;
531 panes[i]->mProps.mMinCBarDim.y = 16;
532 }
533
534 CreateBoxes();
535 }