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