1 //------------------------------------------------------------------------------
2 // emBorder.cpp
3 //
4 // Copyright (C) 2005-2011,2014-2016,2020 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #include <emCore/emBorder.h>
22 #include <emCore/emInstallInfo.h>
23 #include <emCore/emRes.h>
24
25
emBorder(ParentArg parent,const emString & name,const emString & caption,const emString & description,const emImage & icon)26 emBorder::emBorder(
27 ParentArg parent, const emString & name, const emString & caption,
28 const emString & description, const emImage & icon
29 )
30 : emPanel(parent,name),
31 Caption(caption),
32 Description(description),
33 Icon(icon)
34 {
35 emBorder * tkp;
36 emPanel * p;
37 TkResources * r;
38 emRootContext * rc;
39 emString resDir;
40
41 rc=&GetRootContext();
42 TkResVarModel=emVarModel<TkResources>::Acquire(*rc,"");
43 r=&TkResVarModel->Var;
44 if (r->ImgButton.IsEmpty()) {
45 resDir=emGetInstallPath(EM_IDT_RES,"emCore","toolkit");
46 r->ImgButton=emGetResImage(*rc,emGetChildPath(resDir,"Button.tga"));
47 r->ImgButtonBorder=emGetResImage(*rc,emGetChildPath(resDir,"ButtonBorder.tga"));
48 r->ImgButtonChecked=emGetResImage(*rc,emGetChildPath(resDir,"ButtonChecked.tga"));
49 r->ImgButtonPressed=emGetResImage(*rc,emGetChildPath(resDir,"ButtonPressed.tga"));
50 r->ImgCheckBox=emGetResImage(*rc,emGetChildPath(resDir,"CheckBox.tga"));
51 r->ImgCheckBoxPressed=emGetResImage(*rc,emGetChildPath(resDir,"CheckBoxPressed.tga"));
52 r->ImgCustomRectBorder=emGetResImage(*rc,emGetChildPath(resDir,"CustomRectBorder.tga"));
53 r->ImgDir=emGetResImage(*rc,emGetChildPath(resDir,"Dir.tga"));
54 r->ImgDirUp=emGetResImage(*rc,emGetChildPath(resDir,"DirUp.tga"));
55 r->ImgGroupBorder=emGetResImage(*rc,emGetChildPath(resDir,"GroupBorder.tga"));
56 r->ImgGroupInnerBorder=emGetResImage(*rc,emGetChildPath(resDir,"GroupInnerBorder.tga"));
57 r->ImgIOField=emGetResImage(*rc,emGetChildPath(resDir,"IOField.tga"));
58 r->ImgPopupBorder=emGetResImage(*rc,emGetChildPath(resDir,"PopupBorder.tga"));
59 r->ImgRadioBox=emGetResImage(*rc,emGetChildPath(resDir,"RadioBox.tga"));
60 r->ImgRadioBoxPressed=emGetResImage(*rc,emGetChildPath(resDir,"RadioBoxPressed.tga"));
61 r->ImgSplitter=emGetResImage(*rc,emGetChildPath(resDir,"Splitter.tga"));
62 r->ImgSplitterPressed=emGetResImage(*rc,emGetChildPath(resDir,"SplitterPressed.tga"));
63 r->ImgTunnel=emGetResImage(*rc,emGetChildPath(resDir,"Tunnel.tga"));
64 }
65
66 Aux=NULL;
67
68 for (p=GetParent(); p; p=p->GetParent()) {
69 tkp=dynamic_cast<emBorder*>(p);
70 if (tkp) {
71 Look=tkp->Look;
72 break;
73 }
74 }
75
76 MaxIconAreaTallness=1.0;
77 BorderScaling=1.0;
78 LabelAlignment=EM_ALIGN_LEFT;
79 CaptionAlignment=EM_ALIGN_LEFT;
80 DescriptionAlignment=EM_ALIGN_LEFT;
81 OuterBorder=OBT_NONE;
82 InnerBorder=IBT_NONE;
83 IconAboveCaption=false;
84 LabelInBorder=true;
85 }
86
87
~emBorder()88 emBorder::~emBorder()
89 {
90 if (Aux) delete Aux;
91 }
92
93
SetCaption(const emString & caption)94 void emBorder::SetCaption(const emString & caption)
95 {
96 if (Caption!=caption) {
97 Caption=caption;
98 InvalidatePainting();
99 InvalidateChildrenLayout();
100 }
101 }
102
103
SetDescription(const emString & description)104 void emBorder::SetDescription(const emString & description)
105 {
106 if (Description!=description) {
107 Description=description;
108 InvalidatePainting();
109 InvalidateChildrenLayout();
110 }
111 }
112
113
SetIcon(const emImage & icon)114 void emBorder::SetIcon(const emImage & icon)
115 {
116 if (Icon!=icon) {
117 Icon=icon;
118 InvalidatePainting();
119 InvalidateChildrenLayout();
120 }
121 }
122
123
SetLabel(const emString & caption,const emString & description,const emImage & icon)124 void emBorder::SetLabel(
125 const emString & caption, const emString & description,
126 const emImage & icon
127 )
128 {
129 SetCaption(caption);
130 SetDescription(description);
131 SetIcon(icon);
132 }
133
134
SetLabelAlignment(emAlignment labelAlignment)135 void emBorder::SetLabelAlignment(emAlignment labelAlignment)
136 {
137 if (LabelAlignment!=labelAlignment) {
138 LabelAlignment=labelAlignment;
139 InvalidatePainting();
140 InvalidateChildrenLayout();
141 }
142 }
143
144
SetCaptionAlignment(emAlignment captionAlignment)145 void emBorder::SetCaptionAlignment(emAlignment captionAlignment)
146 {
147 if (CaptionAlignment!=captionAlignment) {
148 CaptionAlignment=captionAlignment;
149 InvalidatePainting();
150 InvalidateChildrenLayout();
151 }
152 }
153
154
SetDescriptionAlignment(emAlignment descriptionAlignment)155 void emBorder::SetDescriptionAlignment(emAlignment descriptionAlignment)
156 {
157 if (DescriptionAlignment!=descriptionAlignment) {
158 DescriptionAlignment=descriptionAlignment;
159 InvalidatePainting();
160 InvalidateChildrenLayout();
161 }
162 }
163
164
SetIconAboveCaption(bool iconAboveCaption)165 void emBorder::SetIconAboveCaption(bool iconAboveCaption)
166 {
167 if (IconAboveCaption!=iconAboveCaption) {
168 IconAboveCaption=iconAboveCaption;
169 InvalidatePainting();
170 InvalidateChildrenLayout();
171 }
172 }
173
174
SetMaxIconAreaTallness(double maxIconAreaTallness)175 void emBorder::SetMaxIconAreaTallness(double maxIconAreaTallness)
176 {
177 if (maxIconAreaTallness<1E-10) maxIconAreaTallness=1E-10;
178 if (MaxIconAreaTallness!=maxIconAreaTallness) {
179 MaxIconAreaTallness=maxIconAreaTallness;
180 InvalidatePainting();
181 InvalidateChildrenLayout();
182 }
183 }
184
185
SetOuterBorderType(OuterBorderType obt)186 void emBorder::SetOuterBorderType(OuterBorderType obt)
187 {
188 if (OuterBorder!=(emByte)obt) {
189 OuterBorder=(emByte)obt;
190 InvalidatePainting();
191 InvalidateChildrenLayout();
192 }
193 }
194
195
SetInnerBorderType(InnerBorderType ibt)196 void emBorder::SetInnerBorderType(InnerBorderType ibt)
197 {
198 if (InnerBorder!=(emByte)ibt) {
199 InnerBorder=(emByte)ibt;
200 InvalidatePainting();
201 InvalidateChildrenLayout();
202 }
203 }
204
205
SetBorderType(OuterBorderType obt,InnerBorderType ibt)206 void emBorder::SetBorderType(OuterBorderType obt, InnerBorderType ibt)
207 {
208 if (OuterBorder!=(emByte)obt || InnerBorder!=(emByte)ibt) {
209 OuterBorder=(emByte)obt;
210 InnerBorder=(emByte)ibt;
211 InvalidatePainting();
212 InvalidateChildrenLayout();
213 }
214 }
215
216
SetBorderScaling(double borderScaling)217 void emBorder::SetBorderScaling(double borderScaling)
218 {
219 if (borderScaling<1E-10) borderScaling=1E-10;
220 if (BorderScaling!=borderScaling) {
221 BorderScaling=borderScaling;
222 InvalidatePainting();
223 InvalidateChildrenLayout();
224 }
225 }
226
227
SetLook(const emLook & look,bool recursively)228 void emBorder::SetLook(const emLook & look, bool recursively)
229 {
230 emPanel * p;
231
232 if (Look!=look) {
233 Look=look;
234 InvalidatePainting();
235 InvalidateChildrenLayout();
236 }
237 if (recursively) {
238 for (p=GetFirstChild(); p; p=p->GetNext()) {
239 look.Apply(p,true);
240 }
241 }
242 }
243
244
HaveAux(const emString & panelName,double tallness)245 void emBorder::HaveAux(const emString & panelName, double tallness)
246 {
247 if (!Aux) {
248 Aux=new AuxData;
249 Aux->PanelName=panelName;
250 Aux->Tallness=tallness;
251 InvalidatePainting();
252 InvalidateChildrenLayout();
253 }
254 else {
255 if (Aux->PanelName!=panelName) {
256 Aux->PanelName=panelName;
257 Aux->PanelPointerCache=NULL;
258 InvalidateChildrenLayout();
259 }
260 if (Aux->Tallness!=tallness) {
261 Aux->Tallness=tallness;
262 InvalidatePainting();
263 InvalidateChildrenLayout();
264 }
265 }
266 }
267
268
RemoveAux()269 void emBorder::RemoveAux()
270 {
271 if (Aux) {
272 delete Aux;
273 Aux=NULL;
274 InvalidatePainting();
275 InvalidateChildrenLayout();
276 }
277 }
278
279
GetAuxPanelName() const280 const emString & emBorder::GetAuxPanelName() const
281 {
282 static const emString emptyString;
283 // Okay this is thread-safe as long as the string is empty.
284
285 if (!Aux) return emptyString;
286 return Aux->PanelName;
287 }
288
289
GetAuxTallness() const290 double emBorder::GetAuxTallness() const
291 {
292 if (!Aux) return 1.0;
293 return Aux->Tallness;
294 }
295
296
GetAuxPanel()297 emPanel * emBorder::GetAuxPanel()
298 {
299 emPanel * p;
300
301 if (!Aux) return NULL;
302 p=Aux->PanelPointerCache;
303 if (!p) {
304 p=GetChild(Aux->PanelName);
305 if (p) Aux->PanelPointerCache=p;
306 }
307 return p;
308 }
309
310
GetAuxRect(double * pX,double * pY,double * pW,double * pH,emColor * pCanvasColor) const311 void emBorder::GetAuxRect(
312 double * pX, double * pY, double * pW, double * pH,
313 emColor * pCanvasColor
314 ) const
315 {
316 if (!Aux) {
317 if (pX) *pX=0.0;
318 if (pY) *pY=0.0;
319 if (pW) *pW=1E-100;
320 if (pH) *pH=1E-100;
321 if (pCanvasColor) *pCanvasColor=0;
322 return;
323 }
324 DoBorder(
325 BORDER_FUNC_AUX_RECT,NULL,GetCanvasColor(),
326 pX,pY,pW,pH,NULL,pCanvasColor
327 );
328 }
329
330
GetSubstanceRect(double * pX,double * pY,double * pW,double * pH,double * pR) const331 void emBorder::GetSubstanceRect(
332 double * pX, double * pY, double * pW, double * pH, double * pR
333 ) const
334 {
335 DoBorder(
336 BORDER_FUNC_SUBSTANCE_ROUND_RECT,NULL,GetCanvasColor(),
337 pX,pY,pW,pH,pR,NULL
338 );
339 }
340
341
GetContentRoundRect(double * pX,double * pY,double * pW,double * pH,double * pR,emColor * pCanvasColor) const342 void emBorder::GetContentRoundRect(
343 double * pX, double * pY, double * pW, double * pH, double * pR,
344 emColor * pCanvasColor
345 ) const
346 {
347 DoBorder(
348 BORDER_FUNC_CONTENT_ROUND_RECT,NULL,GetCanvasColor(),
349 pX,pY,pW,pH,pR,pCanvasColor
350 );
351 }
352
353
GetContentRect(double * pX,double * pY,double * pW,double * pH,emColor * pCanvasColor) const354 void emBorder::GetContentRect(
355 double * pX, double * pY, double * pW, double * pH,
356 emColor * pCanvasColor
357 ) const
358 {
359 DoBorder(
360 BORDER_FUNC_CONTENT_RECT,NULL,GetCanvasColor(),
361 pX,pY,pW,pH,NULL,pCanvasColor
362 );
363 }
364
365
GetContentRectUnobscured(double * pX,double * pY,double * pW,double * pH,emColor * pCanvasColor) const366 void emBorder::GetContentRectUnobscured(
367 double * pX, double * pY, double * pW, double * pH,
368 emColor * pCanvasColor
369 ) const
370 {
371 DoBorder(
372 BORDER_FUNC_CONTENT_RECT_UNOBSCURED,NULL,GetCanvasColor(),
373 pX,pY,pW,pH,NULL,pCanvasColor
374 );
375 }
376
377
Notice(NoticeFlags flags)378 void emBorder::Notice(NoticeFlags flags)
379 {
380 if ((flags&(NF_ENABLE_CHANGED|NF_ACTIVE_CHANGED|NF_FOCUS_CHANGED))!=0) {
381 InvalidatePainting();
382 }
383 if ((flags&NF_ENABLE_CHANGED)!=0) {
384 if (InnerBorder==(emByte)IBT_INPUT_FIELD || InnerBorder==(emByte)IBT_OUTPUT_FIELD) {
385 InvalidateChildrenLayout();
386 }
387 }
388 emPanel::Notice(flags);
389 }
390
391
IsOpaque() const392 bool emBorder::IsOpaque() const
393 {
394 switch (OuterBorder) {
395 case OBT_FILLED:
396 case OBT_MARGIN_FILLED:
397 case OBT_POPUP_ROOT:
398 return Look.GetBgColor().IsOpaque();
399 default:
400 return false;
401 }
402 }
403
404
Paint(const emPainter & painter,emColor canvasColor) const405 void emBorder::Paint(const emPainter & painter, emColor canvasColor) const
406 {
407 DoBorder(BORDER_FUNC_PAINT,&painter,canvasColor,NULL,NULL,NULL,NULL,NULL,NULL);
408 }
409
410
LayoutChildren()411 void emBorder::LayoutChildren()
412 {
413 emColor cc;
414 double x,y,w,h;
415 emPanel * p;
416
417 if (!Aux) return;
418 p=Aux->PanelPointerCache;
419 if (!p) {
420 p=GetChild(Aux->PanelName);
421 if (!p) return;
422 Aux->PanelPointerCache=p;
423 }
424 GetAuxRect(&x,&y,&w,&h,&cc);
425 p->Layout(x,y,w,h,cc);
426 }
427
428
HasHowTo() const429 bool emBorder::HasHowTo() const
430 {
431 return false;
432 }
433
434
GetHowTo() const435 emString emBorder::GetHowTo() const
436 {
437 emString h;
438
439 h=HowToPreface;
440 if (!IsEnabled()) h+=HowToDisabled;
441 if (IsFocusable()) h+=HowToFocus;
442 return h;
443 }
444
445
PaintContent(const emPainter & painter,double x,double y,double w,double h,emColor canvasColor) const446 void emBorder::PaintContent(
447 const emPainter & painter, double x, double y, double w, double h,
448 emColor canvasColor
449 ) const
450 {
451 }
452
453
HasLabel() const454 bool emBorder::HasLabel() const
455 {
456 return !Caption.IsEmpty() || !Description.IsEmpty() || !Icon.IsEmpty();
457 }
458
459
GetBestLabelTallness() const460 double emBorder::GetBestLabelTallness() const
461 {
462 double bestTallness;
463
464 DoLabel(
465 LABEL_FUNC_GET_BEST_TALLNESS,NULL,0.0,0.0,1.0,1.0,
466 0,0,&bestTallness
467 );
468 return bestTallness;
469 }
470
471
PaintLabel(const emPainter & painter,double x,double y,double w,double h,emColor color,emColor canvasColor) const472 void emBorder::PaintLabel(
473 const emPainter & painter, double x, double y, double w, double h,
474 emColor color, emColor canvasColor
475 ) const
476 {
477 DoLabel(
478 LABEL_FUNC_PAINT,&painter,x,y,w,h,color,canvasColor,NULL
479 );
480 }
481
482
SetLabelInBorder(bool labelInBorder)483 void emBorder::SetLabelInBorder(bool labelInBorder)
484 {
485 if (LabelInBorder!=labelInBorder) {
486 LabelInBorder=labelInBorder;
487 InvalidatePainting();
488 InvalidateChildrenLayout();
489 }
490 }
491
492
TkResources()493 emBorder::TkResources::TkResources()
494 {
495 }
496
497
~TkResources()498 emBorder::TkResources::~TkResources()
499 {
500 }
501
502
GetContentRoundRect(double * pX,double * pY,double * pW,double * pH,double * pR,emColor * pCanvasColor)503 void emBorder::GetContentRoundRect(
504 double * pX, double * pY, double * pW, double * pH, double * pR,
505 emColor * pCanvasColor
506 )
507 {
508 ((const emBorder*)this)->GetContentRoundRect(pX,pY,pW,pH,pR,pCanvasColor);
509 }
510
511
GetContentRect(double * pX,double * pY,double * pW,double * pH,emColor * pCanvasColor)512 void emBorder::GetContentRect(
513 double * pX, double * pY, double * pW, double * pH,
514 emColor * pCanvasColor
515 )
516 {
517 ((const emBorder*)this)->GetContentRect(pX,pY,pW,pH,pCanvasColor);
518 }
519
520
GetContentRectUnobscured(double * pX,double * pY,double * pW,double * pH,emColor * pCanvasColor)521 void emBorder::GetContentRectUnobscured(
522 double * pX, double * pY, double * pW, double * pH,
523 emColor * pCanvasColor
524 )
525 {
526 ((const emBorder*)this)->GetContentRectUnobscured(pX,pY,pW,pH,pCanvasColor);
527 }
528
HasHowTo()529 bool emBorder::HasHowTo()
530 {
531 return ((const emBorder*)this)->HasHowTo();
532 }
533
534
GetHowTo()535 emString emBorder::GetHowTo()
536 {
537 return ((const emBorder*)this)->GetHowTo();
538 }
539
540
PaintContent(const emPainter & painter,double x,double y,double w,double h,emColor canvasColor)541 void emBorder::PaintContent(
542 const emPainter & painter, double x, double y, double w, double h,
543 emColor canvasColor
544 )
545 {
546 ((const emBorder*)this)->PaintContent(painter,x,y,w,h,canvasColor);
547 }
548
549
HasLabel()550 bool emBorder::HasLabel()
551 {
552 return ((const emBorder*)this)->HasLabel();
553 }
554
555
GetBestLabelTallness()556 double emBorder::GetBestLabelTallness()
557 {
558 return ((const emBorder*)this)->GetBestLabelTallness();
559 }
560
561
PaintLabel(const emPainter & painter,double x,double y,double w,double h,emColor color,emColor canvasColor)562 void emBorder::PaintLabel(
563 const emPainter & painter, double x, double y, double w, double h,
564 emColor color, emColor canvasColor
565 )
566 {
567 ((const emBorder*)this)->PaintLabel(painter,x,y,w,h,color,canvasColor);
568 }
569
570
DoBorder(DoBorderFunc func,const emPainter * painter,emColor canvasColor,double * pX,double * pY,double * pW,double * pH,double * pR,emColor * pCanvasColor) const571 void emBorder::DoBorder(
572 DoBorderFunc func, const emPainter * painter, emColor canvasColor,
573 double * pX, double * pY, double * pW, double * pH, double * pR,
574 emColor * pCanvasColor
575 ) const
576 {
577 double s,d,e,f,g,h,r,tx,ty,tw,th,tr;
578 double minSpace,howToSpace,labelSpace;
579 double rndX,rndY,rndW,rndH,rndR,recX,recY,recW,recH;
580 emColor color,color2;
581
582 h=GetHeight();
583
584 switch ((OuterBorderType)OuterBorder) {
585 default: // OBT_NONE or OBT_FILLED
586 if (func==BORDER_FUNC_SUBSTANCE_ROUND_RECT) {
587 if (pX) *pX=0.0;
588 if (pY) *pY=0.0;
589 if (pW) *pW=1.0;
590 if (pH) *pH=h;
591 if (pR) *pR=0.0;
592 return;
593 }
594 rndX=0.0;
595 rndY=0.0;
596 rndW=1.0;
597 rndH=h;
598 rndR=0.0;
599 minSpace=0.0;
600 howToSpace=0.023;
601 labelSpace=0.17;
602 if ((OuterBorderType)OuterBorder==OBT_FILLED) {
603 color=Look.GetBgColor();
604 if (!color.IsTotallyTransparent()) {
605 if (func==BORDER_FUNC_PAINT) painter->Clear(color,canvasColor);
606 canvasColor=color;
607 }
608 }
609 break;
610 case OBT_MARGIN:
611 case OBT_MARGIN_FILLED:
612 d=emMin(1.0,h)*BorderScaling*0.04;
613 rndX=d;
614 rndY=d;
615 rndW=1.0-2*d;
616 rndH=h-2*d;
617 rndR=0.0;
618 minSpace=0.0;
619 howToSpace=0.023;
620 labelSpace=0.17;
621 if (func==BORDER_FUNC_SUBSTANCE_ROUND_RECT) {
622 if (pX) *pX=d;
623 if (pY) *pY=d;
624 if (pW) *pW=1.0-2*d;
625 if (pH) *pH=h-2*d;
626 if (pR) *pR=0.0;
627 return;
628 }
629 if ((OuterBorderType)OuterBorder==OBT_MARGIN_FILLED) {
630 color=Look.GetBgColor();
631 if (!color.IsTotallyTransparent()) {
632 if (func==BORDER_FUNC_PAINT) painter->Clear(color,canvasColor);
633 canvasColor=color;
634 }
635 }
636 break;
637 case OBT_RECT:
638 s=emMin(1.0,h)*BorderScaling;
639 d=s*0.023;
640 e=s*0.02;
641 f=d+e;
642 rndX=f;
643 rndY=f;
644 rndW=1.0-2*f;
645 rndH=h-2*f;
646 rndR=0.0;
647 minSpace=howToSpace=0.023;
648 labelSpace=0.17;
649 color=Look.GetBgColor();
650 if (func==BORDER_FUNC_SUBSTANCE_ROUND_RECT) {
651 if (pX) *pX=d;
652 if (pY) *pY=d;
653 if (pW) *pW=1.0-2*d;
654 if (pH) *pH=h-2*d;
655 if (pR) *pR=0.0;
656 return;
657 }
658 if (!color.IsTotallyTransparent()) {
659 if (func==BORDER_FUNC_PAINT) {
660 painter->PaintRect(
661 d,d,1.0-2*d,h-2*d,
662 color,canvasColor
663 );
664 }
665 canvasColor=color;
666 }
667 if (func==BORDER_FUNC_PAINT) {
668 d+=e*0.5;
669 color=Look.GetFgColor();
670 if (!IsEnabled()) color=color.GetTransparented(75.0F);
671 painter->PaintRectOutline(
672 d,d,1.0-2*d,h-2*d,e,
673 color,canvasColor
674 );
675 }
676 break;
677 case OBT_ROUND_RECT:
678 s=emMin(1.0,h)*BorderScaling;
679 d=s*0.023;
680 e=s*0.02;
681 f=s*0.22;
682 g=d+e;
683 rndX=g;
684 rndY=g;
685 rndW=1.0-2*g;
686 rndH=h-2*g;
687 rndR=f-e;
688 minSpace=howToSpace=0.023;
689 labelSpace=0.17;
690 color=Look.GetBgColor();
691 if (func==BORDER_FUNC_SUBSTANCE_ROUND_RECT) {
692 if (pX) *pX=d;
693 if (pY) *pY=d;
694 if (pW) *pW=1.0-2*d;
695 if (pH) *pH=h-2*d;
696 if (pR) *pR=f;
697 return;
698 }
699 if (!color.IsTotallyTransparent()) {
700 if (func==BORDER_FUNC_PAINT) {
701 painter->PaintRoundRect(
702 d,d,1.0-2*d,h-2*d,f,f,
703 color,canvasColor
704 );
705 }
706 canvasColor=color;
707 }
708 if (func==BORDER_FUNC_PAINT) {
709 d+=e*0.5;
710 f-=e*0.5;
711 color=Look.GetFgColor();
712 if (!IsEnabled()) color=color.GetTransparented(75.0F);
713 painter->PaintRoundRectOutline(
714 d,d,1.0-2*d,h-2*d,f,f,e,
715 color,canvasColor
716 );
717 }
718 break;
719 case OBT_GROUP:
720 s=emMin(1.0,h)*BorderScaling;
721 d=s*0.0104;
722 rndX=d;
723 rndY=d;
724 rndW=1.0-2*d;
725 rndH=h-2*d;
726 rndR=s*0.0188;
727 minSpace=howToSpace=0.0046;
728 labelSpace=0.05;
729 color=Look.GetBgColor();
730 if (func==BORDER_FUNC_SUBSTANCE_ROUND_RECT) {
731 r=rndR*(280.0/209.0);
732 e=r-rndR;
733 if (pX) *pX=rndX-e;
734 if (pY) *pY=rndY-e;
735 if (pW) *pW=rndW+2*e;
736 if (pH) *pH=rndH+2*e;
737 if (pR) *pR=r;
738 return;
739 }
740 if (func==BORDER_FUNC_PAINT) {
741 color2=canvasColor;
742 if (
743 !color.IsTotallyTransparent() &&
744 (!color2.IsOpaque() || color2!=color)
745 ) {
746 r=rndR*(280.0/209.0);
747 e=r-rndR;
748 painter->PaintRoundRect(
749 rndX-e,rndY-e,rndW+2*e,rndH+2*e,
750 r,r,
751 color,
752 color2
753 );
754 color2=0;
755 }
756 r=rndR*(286.0/209.0);
757 e=r-rndR;
758 painter->PaintBorderImage(
759 rndX-e,rndY-e,rndW+2*e,rndH+2*e,
760 r,r,r,r,
761 GetTkResources().ImgGroupBorder,
762 286,286,286,286,
763 255,color2,0757
764 );
765 }
766 if (!color.IsTotallyTransparent()) canvasColor=color;
767 break;
768 case OBT_INSTRUMENT:
769 s=emMin(1.0,h)*BorderScaling;
770 d=s*0.052;
771 rndX=d;
772 rndY=d;
773 rndW=1.0-2*d;
774 rndH=h-2*d;
775 rndR=s*0.094;
776 minSpace=howToSpace=0.023;
777 labelSpace=0.17;
778 color=Look.GetBgColor();
779 if (func==BORDER_FUNC_SUBSTANCE_ROUND_RECT) {
780 r=rndR*(280.0/209.0);
781 e=r-rndR;
782 if (pX) *pX=rndX-e;
783 if (pY) *pY=rndY-e;
784 if (pW) *pW=rndW+2*e;
785 if (pH) *pH=rndH+2*e;
786 if (pR) *pR=r;
787 return;
788 }
789 if (func==BORDER_FUNC_PAINT) {
790 color2=canvasColor;
791 if (
792 !color.IsTotallyTransparent() &&
793 (!color2.IsOpaque() || color2!=color)
794 ) {
795 r=rndR*(280.0/209.0);
796 e=r-rndR;
797 painter->PaintRoundRect(
798 rndX-e,rndY-e,rndW+2*e,rndH+2*e,
799 r,r,
800 color,
801 color2
802 );
803 color2=0;
804 }
805 r=rndR*(286.0/209.0);
806 e=r-rndR;
807 painter->PaintBorderImage(
808 rndX-e,rndY-e,rndW+2*e,rndH+2*e,
809 r,r,r,r,
810 GetTkResources().ImgGroupBorder,
811 286,286,286,286,
812 255,color2,0757
813 );
814 }
815 if (!color.IsTotallyTransparent()) canvasColor=color;
816 break;
817 case OBT_INSTRUMENT_MORE_ROUND:
818 s=emMin(1.0,h)*BorderScaling;
819 d=s*0.052;
820 rndX=d;
821 rndY=d;
822 rndW=1.0-2*d;
823 rndH=h-2*d;
824 rndR=s*0.223;
825 minSpace=howToSpace=0.023;
826 labelSpace=0.17;
827 color=Look.GetBgColor();
828 if (func==BORDER_FUNC_SUBSTANCE_ROUND_RECT) {
829 r=rndR*(336/293.4);
830 e=r-rndR;
831 if (pX) *pX=rndX-e;
832 if (pY) *pY=rndY-e;
833 if (pW) *pW=rndW+2*e;
834 if (pH) *pH=rndH+2*e;
835 if (pR) *pR=r;
836 return;
837 }
838 if (func==BORDER_FUNC_PAINT) {
839 color2=canvasColor;
840 if (
841 !color.IsTotallyTransparent() &&
842 (!color2.IsOpaque() || color2!=color)
843 ) {
844 r=rndR*(336/293.4);
845 e=r-rndR;
846 painter->PaintRoundRect(
847 rndX-e,rndY-e,rndW+2*e,rndH+2*e,
848 r,r,
849 color,
850 color2
851 );
852 color2=0;
853 }
854 r=rndR*(340.0/293.4);
855 e=r-rndR;
856 painter->PaintBorderImage(
857 rndX-e,rndY-e,rndW+2*e,rndH+2*e,
858 r,r,r,r,
859 GetTkResources().ImgButtonBorder,
860 340,340,340,340,
861 255,color2,0757
862 );
863 }
864 if (!color.IsTotallyTransparent()) canvasColor=color;
865 break;
866 case OBT_POPUP_ROOT:
867 if (func==BORDER_FUNC_SUBSTANCE_ROUND_RECT) {
868 if (pX) *pX=0.0;
869 if (pY) *pY=0.0;
870 if (pW) *pW=1.0;
871 if (pH) *pH=h;
872 if (pR) *pR=0.0;
873 return;
874 }
875 s=emMin(1.0,h)*BorderScaling;
876 d=s*0.006;
877 rndX=d;
878 rndY=d;
879 rndW=1.0-2*d;
880 rndH=h-2*d;
881 rndR=0.0;
882 minSpace=0.0;
883 howToSpace=0.023;
884 labelSpace=0.17;
885 color=Look.GetBgColor();
886 if (!color.IsTotallyTransparent()) {
887 if (func==BORDER_FUNC_PAINT) {
888 painter->Clear(color,canvasColor);
889 }
890 canvasColor=color;
891 }
892 if (func==BORDER_FUNC_PAINT) {
893 r=d*(159.0/159.0);
894 painter->PaintBorderImage(
895 0.0,0.0,1.0,h,
896 r,r,r,r,
897 GetTkResources().ImgPopupBorder,
898 159,159,159,159,
899 255,canvasColor,0757
900 );
901 }
902 break;
903 }
904
905 s=emMin(rndW,rndH)*BorderScaling;
906 minSpace*=s;
907
908 if (HasHowTo()) {
909 howToSpace*=s;
910 if (func==BORDER_FUNC_PAINT) {
911 tw=howToSpace*0.9;
912 th=tw*2.0;
913 tx=rndX+(howToSpace-tw)*0.5;
914 ty=rndY+(rndH-th)*0.5;
915 painter->PaintRoundRect(
916 tx,ty,tw,th,tw*0.01,tw*0.01,
917 Look.GetFgColor().GetTransparented(90.0F),
918 canvasColor
919 );
920 if (PanelToViewDeltaX(tw)*PanelToViewDeltaY(th)>100.0) {
921 d=tw*0.01;
922 painter->PaintTextBoxed(
923 tx+d,ty+d,tw-d*2,th-d*2,
924 GetHowTo(),
925 th,
926 Look.GetFgColor().GetTransparented(35.0F),
927 canvasColor,
928 EM_ALIGN_TOP_LEFT,
929 EM_ALIGN_LEFT,
930 0.9
931 );
932 }
933 }
934 if (howToSpace>minSpace) {
935 rndX+=howToSpace-minSpace;
936 rndW-=howToSpace-minSpace;
937 }
938 }
939
940 if (LabelInBorder && HasLabel()) {
941 labelSpace*=s;
942 if (func==BORDER_FUNC_PAINT || func==BORDER_FUNC_AUX_RECT) {
943 d=labelSpace*0.1;
944 ty=rndY+d;
945 th=labelSpace-2*d;
946 e=emMax(d,minSpace);
947 if (e<rndR) {
948 f=d*0.77;
949 r=rndR-f;
950 g=r-d+f;
951 f=rndR-sqrt(r*r-g*g);
952 if (e<f) e=f;
953 }
954 tx=rndX+e;
955 tw=rndW-2*e;
956 if (Aux) {
957 d=th*0.2;
958 e=th/Aux->Tallness;
959 f=d+e+th/GetBestLabelTallness()*0.5;
960 if (tw<f) {
961 f=tw/f;
962 d*=f;
963 e*=f;
964 ty+=(th-th*f)*0.5;
965 th*=f;
966 }
967 if (func==BORDER_FUNC_AUX_RECT) {
968 if (pX) *pX=tx+tw-e;
969 if (pY) *pY=ty;
970 if (pW) *pW=e;
971 if (pH) *pH=th;
972 if (pCanvasColor) *pCanvasColor=canvasColor;
973 return;
974 }
975 tw-=d+e;
976 }
977 PaintLabel(
978 *painter,
979 tx,ty,tw,th,
980 IsEnabled() ?
981 Look.GetFgColor()
982 :
983 Look.GetFgColor().GetTransparented(75.0F),
984 canvasColor
985 );
986 }
987 rndX+=minSpace;
988 rndW-=2*minSpace;
989 rndY+=labelSpace;
990 rndH-=labelSpace+minSpace;
991 rndR-=minSpace;
992 if (rndR>0.0) {
993 recX=rndX+rndR*0.5;
994 recW=rndW-rndR;
995 recY=rndY;
996 recH=rndH-rndR*0.5;
997 d=minSpace+rndR*0.5-labelSpace;
998 if (d>0) { recY+=d; recH-=d; }
999 }
1000 else {
1001 rndR=0.0;
1002 recX=rndX;
1003 recW=rndW;
1004 recY=rndY;
1005 recH=rndH;
1006 }
1007 }
1008 else if (Aux) {
1009 s=emMin(rndW,rndH);
1010 tw=s*0.1;
1011 th=tw*Aux->Tallness;
1012 d=s*0.01;
1013 e=rndH-2*emMax(rndR,d);
1014 if (th>e) {
1015 th=emMax(1E-100,e);
1016 tw=th/Aux->Tallness;
1017 }
1018 if (func==BORDER_FUNC_AUX_RECT) {
1019 if (pX) *pX=rndX+rndW-tw-d;
1020 if (pY) *pY=rndY+(rndH-th)*0.5;
1021 if (pW) *pW=tw;
1022 if (pH) *pH=th;
1023 if (pCanvasColor) *pCanvasColor=canvasColor;
1024 return;
1025 }
1026 e=s*0.015;
1027 tw+=e+d;
1028 if (tw<minSpace) tw=minSpace;
1029 rndX+=minSpace;
1030 rndW-=minSpace+tw;
1031 rndY+=minSpace;
1032 rndH-=2*minSpace;
1033 rndR-=minSpace;
1034 if (rndR>0.0) {
1035 recX=rndX+rndR*0.5;
1036 recW=rndW-rndR*0.5;
1037 recY=rndY+rndR*0.5;
1038 recH=rndH-rndR;
1039 d=minSpace+rndR*0.5-tw;
1040 if (d>0) recW-=d;
1041 }
1042 else {
1043 rndR=0.0;
1044 recX=rndX;
1045 recW=rndW;
1046 recY=rndY;
1047 recH=rndH;
1048 }
1049 }
1050 else {
1051 rndX+=minSpace;
1052 rndY+=minSpace;
1053 rndW-=2*minSpace;
1054 rndH-=2*minSpace;
1055 rndR-=minSpace;
1056 if (rndR>0.0) {
1057 recX=rndX+rndR*0.5;
1058 recY=rndY+rndR*0.5;
1059 recW=rndW-rndR;
1060 recH=rndH-rndR;
1061 }
1062 else {
1063 rndR=0.0;
1064 recX=rndX;
1065 recW=rndW;
1066 recY=rndY;
1067 recH=rndH;
1068 }
1069 }
1070
1071 switch (InnerBorder) {
1072 case IBT_GROUP:
1073 r=emMin(rndW,rndH)*BorderScaling*0.0188;
1074 if (rndR<r) rndR=r;
1075 if (func==BORDER_FUNC_PAINT) {
1076 painter->PaintBorderImage(
1077 rndX,rndY,rndW,rndH,
1078 rndR,rndR,rndR,rndR,
1079 GetTkResources().ImgGroupInnerBorder,
1080 225,225,225,225,
1081 255,canvasColor,0757
1082 );
1083 }
1084 d=rndR*(17.0/225.0);
1085 rndX+=d;
1086 rndY+=d;
1087 rndW-=2*d;
1088 rndH-=2*d;
1089 rndR-=d;
1090 recX=rndX+rndR*0.5;
1091 recY=rndY+rndR*0.5;
1092 recW=rndW-rndR;
1093 recH=rndH-rndR;
1094 break;
1095 case IBT_INPUT_FIELD:
1096 case IBT_OUTPUT_FIELD:
1097 r=emMin(rndW,rndH)*BorderScaling*0.094;
1098 if (rndR<r) rndR=r;
1099 d=(1-(216.0-16.0)/216.0)*rndR;
1100 tx=rndX+d;
1101 ty=rndY+d;
1102 tw=rndW-2*d;
1103 th=rndH-2*d;
1104 tr=rndR-d;
1105 recX=tx+tr*0.5;
1106 recY=ty+tr*0.5;
1107 recW=tw-tr;
1108 recH=th-tr;
1109 if ((InnerBorderType)InnerBorder==IBT_INPUT_FIELD) color=Look.GetInputBgColor();
1110 else color=Look.GetOutputBgColor();
1111 if (!IsEnabled()) color=color.GetBlended(Look.GetBgColor(),80.0F);
1112 if (func==BORDER_FUNC_PAINT) {
1113 painter->PaintRoundRect(tx,ty,tw,th,tr,tr,color,canvasColor);
1114 canvasColor=color;
1115 PaintContent(*painter,recX,recY,recW,recH,canvasColor);
1116 painter->PaintBorderImage(
1117 rndX,rndY,rndW,rndH,
1118 300.0/216*rndR,346.0/216*rndR,216.0/216*rndR,216.0/216*rndR,
1119 GetTkResources().ImgIOField,
1120 300,346,216,216,
1121 255,0,0757
1122 );
1123 return;
1124 }
1125 if (func==BORDER_FUNC_CONTENT_RECT_UNOBSCURED) {
1126 d=220.0/216.0*rndR;
1127 if (pX) *pX=rndX+d;
1128 if (pY) *pY=rndY+d;
1129 if (pW) *pW=rndW-2*d;
1130 if (pH) *pH=rndH-2*d;
1131 if (pCanvasColor) *pCanvasColor=color;
1132 return;
1133 }
1134 rndX=tx;
1135 rndY=ty;
1136 rndW=tw;
1137 rndH=th;
1138 rndR=tr;
1139 canvasColor=color;
1140 break;
1141 case IBT_CUSTOM_RECT:
1142 d=rndR*0.25;
1143 rndX+=d;
1144 rndY+=d;
1145 rndW-=2*d;
1146 rndH-=2*d;
1147 rndR-=d;
1148 r=emMin(1.0,h)*BorderScaling*0.0125;
1149 if (rndR<r) rndR=r;
1150 if (func==BORDER_FUNC_PAINT) {
1151 painter->PaintBorderImage(
1152 rndX,rndY,rndW,rndH,
1153 rndR,rndR,rndR,rndR,
1154 GetTkResources().ImgCustomRectBorder,
1155 200,200,200,200,
1156 255,canvasColor,0757
1157 );
1158 }
1159 d=rndR;
1160 rndX+=d;
1161 rndY+=d;
1162 rndW-=2*d;
1163 rndH-=2*d;
1164 rndR=0;
1165 recX=rndX;
1166 recY=rndY;
1167 recW=rndW;
1168 recH=rndH;
1169 break;
1170 default:
1171 break;
1172 }
1173
1174 if (func==BORDER_FUNC_CONTENT_ROUND_RECT) {
1175 if (pX) *pX=rndX;
1176 if (pY) *pY=rndY;
1177 if (pW) *pW=rndW;
1178 if (pH) *pH=rndH;
1179 if (pR) *pR=rndR;
1180 if (pCanvasColor) *pCanvasColor=canvasColor;
1181 }
1182 else if (
1183 func==BORDER_FUNC_CONTENT_RECT ||
1184 func==BORDER_FUNC_CONTENT_RECT_UNOBSCURED
1185 ) {
1186 if (pX) *pX=recX;
1187 if (pY) *pY=recY;
1188 if (pW) *pW=recW;
1189 if (pH) *pH=recH;
1190 if (pCanvasColor) *pCanvasColor=canvasColor;
1191 }
1192 else {
1193 PaintContent(*painter,recX,recY,recW,recH,canvasColor);
1194 }
1195 }
1196
1197
DoLabel(DoLabelFunc func,const emPainter * painter,double x,double y,double w,double h,emColor color,emColor canvasColor,double * pBestTallness) const1198 void emBorder::DoLabel(
1199 DoLabelFunc func, const emPainter * painter, double x, double y,
1200 double w, double h, emColor color, emColor canvasColor,
1201 double * pBestTallness
1202 ) const
1203 {
1204 double iconX,iconY,iconW,iconH,capX,capY,capW,capH,descX,descY,descW,descH;
1205 double gap1,gap2,totalW,totalH,minTotalW,minWS,f,w2,h2;
1206
1207 totalW=1.0;
1208 totalH=1.0;
1209
1210 if (!Caption.IsEmpty()) {
1211 capW=emPainter::GetTextSize(Caption,1.0,true,0.0,&capH);
1212 totalW=capW;
1213 totalH=capH;
1214 }
1215 else {
1216 capW=0.0;
1217 capH=0.0;
1218 }
1219
1220 if (!Icon.IsEmpty()) {
1221 iconW=Icon.GetWidth();
1222 iconH=Icon.GetHeight();
1223 if (iconH > iconW*MaxIconAreaTallness) {
1224 iconH = iconW*MaxIconAreaTallness;
1225 }
1226 if (!Caption.IsEmpty()) {
1227 if (IconAboveCaption) {
1228 f=capH*3.0;
1229 iconW*=f/iconH;
1230 iconH=f;
1231 gap1=capH*0.1;
1232 totalW=emMax(iconW,capW);
1233 totalH=iconH+gap1+capH;
1234 }
1235 else {
1236 iconW*=capH/iconH;
1237 iconH=capH;
1238 gap1=capH*0.1;
1239 totalW=iconW+gap1+capW;
1240 totalH=capH;
1241 }
1242 }
1243 else {
1244 totalW=iconW;
1245 totalH=iconH;
1246 gap1=0.0;
1247 }
1248 }
1249 else {
1250 iconW=0.0;
1251 iconH=0.0;
1252 gap1=0.0;
1253 }
1254
1255 if (!Description.IsEmpty()) {
1256 descW=emPainter::GetTextSize(Description,1.0,true,0.0,&descH);
1257 if (!Icon.IsEmpty() || !Caption.IsEmpty()) {
1258 if (!Caption.IsEmpty()) {
1259 f=capH*0.15;
1260 descW=f/descH;
1261 descH=f;
1262 }
1263 else {
1264 f=iconH*0.05;
1265 descW=f/descH;
1266 descH=f;
1267 }
1268 if (descW>totalW) {
1269 descH*=totalW/descW;
1270 descW=totalW;
1271 }
1272 gap2=descH*0.05;
1273 totalH=totalH+gap2+descH;
1274 }
1275 else {
1276 totalW=descW;
1277 totalH=descH;
1278 gap2=0.0;
1279 }
1280 }
1281 else {
1282 descW=0.0;
1283 descH=0.0;
1284 gap2=0.0;
1285 }
1286
1287 if (func==LABEL_FUNC_GET_BEST_TALLNESS) {
1288 *pBestTallness=totalH/totalW;
1289 return;
1290 }
1291
1292 minWS=0.5;
1293
1294 f=h/totalH;
1295 w2=f*totalW;
1296 if (w2<=w) {
1297 if (!(LabelAlignment&EM_ALIGN_LEFT)) {
1298 if (!(LabelAlignment&EM_ALIGN_RIGHT)) {
1299 x+=(w-w2)*0.5;
1300 }
1301 else {
1302 x+=w-w2;
1303 }
1304 }
1305 w=w2;
1306 }
1307 else {
1308 if (!Icon.IsEmpty()) {
1309 if (IconAboveCaption) {
1310 minTotalW=iconW;
1311 }
1312 else {
1313 minTotalW=iconW+gap1+capW*minWS;
1314 }
1315 }
1316 else {
1317 minTotalW=totalW*minWS;
1318 }
1319 w2=f*minTotalW;
1320 if (w2>w) {
1321 f=w/minTotalW;
1322 h2=f*totalH;
1323 if (!(LabelAlignment&EM_ALIGN_TOP)) {
1324 if (!(LabelAlignment&EM_ALIGN_BOTTOM)) {
1325 y+=(h-h2)*0.5;
1326 }
1327 else {
1328 y+=h-h2;
1329 }
1330 }
1331 h=h2;
1332 }
1333 }
1334
1335 iconW*=f;
1336 iconH*=f;
1337 gap1*=f;
1338 iconY=y;
1339 capH*=f;
1340 if (IconAboveCaption) {
1341 iconX=x+(w-iconW)*0.5;
1342 capX=x;
1343 capY=iconY+iconH+gap1;
1344 capW=w;
1345 }
1346 else {
1347 iconX=x;
1348 capX=iconX+iconW+gap1;
1349 capY=y;
1350 capW=x+w-capX;
1351 }
1352 gap2*=f;
1353 descX=x;
1354 descY=emMax(iconY+iconH,capY+capH)+gap2;
1355 descW=w;
1356 descH*=f;
1357
1358 if (!Icon.IsEmpty()) {
1359 f=iconH*Icon.GetWidth()/Icon.GetHeight();
1360 iconX+=(iconW-f)*0.5;
1361 iconW=f;
1362 if (Icon.GetChannelCount()==1) {
1363 painter->PaintImageColored(
1364 iconX,
1365 iconY,
1366 iconW,
1367 iconH,
1368 Icon,
1369 0,
1370 color,
1371 canvasColor,
1372 emTexture::EXTEND_ZERO
1373 );
1374 }
1375 else {
1376 painter->PaintImage(
1377 iconX,
1378 iconY,
1379 iconW,
1380 iconH,
1381 Icon,
1382 color.GetAlpha(),
1383 canvasColor
1384 );
1385 }
1386 }
1387 if (!Caption.IsEmpty()) {
1388 painter->PaintTextBoxed(
1389 capX,
1390 capY,
1391 capW,
1392 capH,
1393 Caption,
1394 capH,
1395 color,
1396 canvasColor,
1397 EM_ALIGN_CENTER,
1398 CaptionAlignment,
1399 minWS
1400 );
1401 }
1402 if (!Description.IsEmpty()) {
1403 painter->PaintTextBoxed(
1404 descX,
1405 descY,
1406 descW,
1407 descH,
1408 Description,
1409 descH,
1410 color,
1411 canvasColor,
1412 EM_ALIGN_CENTER,
1413 DescriptionAlignment,
1414 minWS
1415 );
1416 }
1417 }
1418
1419
1420 const char * emBorder::HowToPreface=
1421 "How to use this panel\n"
1422 "#####################\n"
1423 "\n"
1424 "Here is some text describing the usage of this panel. The text consists of\n"
1425 "multiple sections which may come from different parts of the program based on\n"
1426 "each other. If something is contradictory, the later section should count.\n"
1427 ;
1428
1429
1430 const char * emBorder::HowToDisabled=
1431 "\n"
1432 "\n"
1433 "DISABLED\n"
1434 "\n"
1435 "This panel is currently disabled, because the panel is probably irrelevant for\n"
1436 "the current state of the program or data. Any try to modify data or to trigger a\n"
1437 "function may silently be ignored.\n"
1438 ;
1439
1440
1441 const char * emBorder::HowToFocus=
1442 "\n"
1443 "\n"
1444 "FOCUS\n"
1445 "\n"
1446 "This panel is focusable. Only one panel can be focused at a time. The focus is\n"
1447 "indicated by small arrows pointing to the focused panel. If a panel is focused,\n"
1448 "it gets the keyboard input. If the focused panel does not know what to do with a\n"
1449 "certain input key, it may even forward the input to its ancestor panels.\n"
1450 "\n"
1451 "How to move or set the focus:\n"
1452 "\n"
1453 "* Just zoom and scroll around - the focus is moved automatically by that.\n"
1454 "\n"
1455 "* Click with the left or right mouse button on a panel to give it the focus.\n"
1456 "\n"
1457 "* Press Tab or Shift+Tab to move the focus to the next or previous sister\n"
1458 " panel.\n"
1459 "\n"
1460 "* Press the cursor keys to move the focus to a sister panel in the desired\n"
1461 " direction.\n"
1462 "\n"
1463 "* Press Page-Up or -Down to move the focus to a child or parent panel.\n"
1464 ;
1465