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