]>
Commit | Line | Data |
---|---|---|
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$ | |
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 | ||
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 | ||
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 | ||
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 | ||
97 | void cbBarHintsPlugin::SetGrooveCount( int nGrooves ) | |
98 | { | |
99 | mGrooveCount = nGrooves; | |
100 | } | |
101 | ||
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 | ||
120 | void cbBarHintsPlugin::Draw3DBox( wxDC& WXUNUSED(dc), const wxPoint& WXUNUSED(pos), bool WXUNUSED(pressed) ) | |
121 | { | |
122 | } | |
123 | ||
124 | void cbBarHintsPlugin::DrawCloseBox( wxDC& WXUNUSED(dc), const wxPoint& WXUNUSED(pos), bool WXUNUSED(pressed) ) | |
125 | { | |
126 | } | |
127 | ||
128 | void cbBarHintsPlugin::DrawCollapseBox( wxDC& WXUNUSED(dc), const wxPoint& WXUNUSED(pos), | |
129 | bool WXUNUSED(atLeft), bool WXUNUSED(disabled), bool WXUNUSED(pressed) ) | |
130 | { | |
131 | } | |
132 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | } |