1 #include "CtrlLib.h"
2 
3 namespace Upp {
4 
CtrlsImageLook(Value * look,int i,int n)5 void CtrlsImageLook(Value *look, int i, int n)
6 {
7 	while(n--)
8 		*look++ = CtrlsImg::Get(i++);
9 }
10 
CtrlsImageLook(Value * look,int i,const Image & image,const Color * color,int n)11 void CtrlsImageLook(Value *look, int i, const Image& image, const Color *color, int n)
12 {
13 	for(int q = 0; q < n; q++)
14 		*look++ = ChLookWith(CtrlsImg::Get(i++), image, *color++);
15 }
16 
CtrlsImageLook(Value * look,int i,const Image & image,int n)17 void CtrlsImageLook(Value *look, int i, const Image& image, int n)
18 {
19 	for(int q = 0; q < n; q++)
20 		*look++ = ChLookWith(CtrlsImg::Get(i++), image);
21 }
22 
DeAmp(const char * s)23 String DeAmp(const char *s)
24 {
25 	String out;
26 	for(; *s; out.Cat(*s++))
27 		if(*s == '&')
28 			out.Cat('&');
29 	return out;
30 }
31 
GetSmartTextSize(const char * text,Font font,int cx)32 Size GetSmartTextSize(const char *text, Font font, int cx) {
33 	if(*text == '\1') {
34 		Size sz;
35 		RichText txt = ParseQTF(text + 1);
36 		txt.ApplyZoom(GetRichTextStdScreenZoom());
37 		sz.cx = min(cx, txt.GetWidth());
38 		sz.cy = txt.GetHeight(Zoom(1, 1), sz.cx);
39 		return sz;
40 	}
41 	return GetTLTextSize(ToUnicode(text, CHARSET_DEFAULT), font);
42 }
43 
GetSmartTextHeight(const char * s,int cx,Font font)44 int GetSmartTextHeight(const char *s, int cx, Font font) {
45 	if(*s == '\1') {
46 		Size sz;
47 		RichText txt = ParseQTF(s + 1);
48 		txt.ApplyZoom(GetRichTextStdScreenZoom());
49 		return txt.GetHeight(Zoom(1, 1), cx);
50 	}
51 	int cy = font.Info().GetHeight();
52 	int h = cy;
53 	while(*s) {
54 		if(*s == '\n')
55 			h += cy;
56 		s++;
57 	}
58 	return h;
59 }
60 
DrawSmartText(Draw & draw,int x,int y,int cx,const char * text,Font font,Color ink,int accesskey)61 void DrawSmartText(Draw& draw, int x, int y, int cx, const char *text, Font font, Color ink, int accesskey) {
62 	if(*text == '\1') {
63 		RichText txt = ParseQTF(text + 1, accesskey);
64 		txt.ApplyZoom(GetRichTextStdScreenZoom());
65 		txt.Paint(Zoom(1, 1), draw, x, y, cx);
66 		return;
67 	}
68 	DrawTLText(draw, x, y, cx, ToUnicode(text, CHARSET_DEFAULT), font, ink, accesskey);
69 }
70 
CompareAccessKey(int accesskey,dword key)71 bool CompareAccessKey(int accesskey, dword key)
72 {
73 	return accesskey && dword(ToUpper(accesskey & 255) - 'A' + K_ALT_A) == key;
74 }
75 
ExtractAccessKey(const char * s,String & label)76 int  ExtractAccessKey(const char *s, String& label)
77 {
78 	byte akey = 0;
79 	int  pos = 0;
80 	String text;
81 	bool qtf = *s == '\1';
82 	while(*s)
83 		if((*s == '&' && !qtf || *s == '\b') && s[1] && s[1] != '&') {
84 			akey = ToAscii(ToUpper(s[1]));
85 			pos = text.GetLength() + 1;
86 			s++;
87 		}
88 		else
89 			text.Cat(*s++);
90 	text.Shrink();
91 	label = text;
92 	return MAKELONG(akey, pos);
93 }
94 
ChooseAccessKey(const char * text,dword used)95 int  ChooseAccessKey(const char *text, dword used)
96 {
97 	for(const char *s = text; *s; s++) {
98 		byte ac = *s;
99 		if(ac < 128 && ac >= 'A' && ac <= 'Z' && (Ctrl::AccessKeyBit(ac) & used) == 0)
100 			return MAKELONG(ac, s - text + 1);
101 	}
102 	for(const char *s = text; *s; s++) {
103 		dword ac = ToUpper(*s);
104 		if(ac < 128 && ac >= 'A' && ac <= 'Z' && ac != 'I' && ac != 'L' && (Ctrl::AccessKeyBit(ac) & used) == 0)
105 			return ac;
106 	}
107 	for(const char *s = text; *s; s++) {
108 		dword ac = ToUpper(*s);
109 		if(ac < 128 && ac >= 'A' && ac <= 'Z' && (Ctrl::AccessKeyBit(ac) & used) == 0)
110 			return ac;
111 	}
112 	return 0;
113 }
114 
DrawLabel()115 DrawLabel::DrawLabel()
116 {
117 	push = focus = disabled = false;
118 	lspc = rspc = 0;
119 	limg_never_hide = false;
120 	rimg_never_hide = false;
121 	ink = disabledink = Null;
122 	align = valign = ALIGN_CENTER;
123 	accesskey = 0;
124 	accesspos = -1;
125 	font = StdFont();
126 	nowrap = false;
127 }
128 
GetSize(int txtcx) const129 Size DrawLabel::GetSize(int txtcx) const
130 {
131 	return GetSize(txtcx, limg.GetSize(), lspc, rimg.GetSize(), rspc);
132 }
133 
GetSize(int txtcx,Size sz1,int lspc,Size sz2,int rspc) const134 Size DrawLabel::GetSize(int txtcx, Size sz1, int lspc, Size sz2, int rspc) const
135 {
136 	Size isz(0, 0);
137 	Size txtsz = *text ? GetSmartTextSize(text, font, nowrap ? INT_MAX/2 : txtcx)
138 	                   : paintrect.GetStdSize();
139 
140 	if(!IsNull(lspc)) {
141 		isz.cx = lspc;
142 		isz.cy = sz1.cy;
143 		isz.cx += sz1.cx;
144 	}
145 
146 	if(!IsNull(rspc)) {
147 		isz.cx += rspc;
148 		if(sz2.cy > isz.cy) isz.cy = sz2.cy;
149 		isz.cx += sz2.cx;
150 	}
151 
152 	isz.cy = max(txtsz.cy, max(sz1.cy, sz2.cy));
153 	isz.cx += txtsz.cx;
154 
155 	return isz;
156 }
157 
DisImage(const Image & m)158 Image DisImage(const Image& m)
159 {
160 	Image mm = Grayscale(m, 200);
161 	ImageBuffer ib(mm);
162 	RGBA *s = ~ib;
163 	RGBA *e = s + ib.GetLength();
164 	while(s < e)
165 		(s++)->a /= 3;
166 	Premultiply(ib);
167 	return ib;
168 }
169 
DisabledImage(const Image & img,bool dis)170 Image DisabledImage(const Image& img, bool dis)
171 {
172 	return dis ? MakeImage(img, GUI_GlobalStyle() == GUISTYLE_CLASSIC ? Etched : DisImage)
173 	           : img;
174 }
175 
GetLabelTextColor(const Ctrl * ctrl)176 Color GetLabelTextColor(const Ctrl *ctrl)
177 {
178 	if(!IsLabelTextColorMismatch())
179 		return SColorLabel();
180 	while(ctrl) {
181 		if(!ctrl->IsTransparent()) {
182 			if(dynamic_cast<const TopWindow *>(ctrl) || dynamic_cast<const TabCtrl *>(ctrl) ||
183 			   dynamic_cast<const ToolBar *>(ctrl) || dynamic_cast<const MenuBar *>(ctrl) ||
184 			   dynamic_cast<const StaticRect *>(ctrl) || dynamic_cast<const StaticBarArea *>(ctrl))
185 				break;
186 			return SColorText();
187 		}
188 		ctrl = ctrl->GetParent();
189 	}
190 	return SColorLabel();
191 }
192 
Paint(Ctrl * ctrl,Draw & w,const Rect & r,bool visibleaccesskey) const193 Size DrawLabel::Paint(Ctrl *ctrl, Draw& w, const Rect& r, bool visibleaccesskey) const
194 {
195 	int lspc = this->lspc;
196 	int rspc = this->rspc;
197 	Size sz1 = limg.GetSize();
198 	Size sz2 = rimg.GetSize();
199 	int txtcx = r.GetWidth() - sz1.cx - Nvl(lspc, 0) - sz2.cx - Nvl(rspc, 0);
200 	Size txtsz = *text ? GetSmartTextSize(text, font, nowrap ? INT_MAX/2 : txtcx) : paintrect.GetStdSize();
201 	if(txtsz.cx) {
202 		if(!rimg_never_hide && txtsz.cx + sz1.cx + sz2.cx + Nvl(lspc, 0) + Nvl(rspc, 0) > r.GetWidth()) {
203 			sz2.cx = 0;
204 			rspc = 0;
205 		}
206 		if(!limg_never_hide && txtsz.cx + sz1.cx + sz2.cx + Nvl(lspc, 0) + Nvl(rspc, 0) > r.GetWidth()) {
207 			sz1.cx = 0;
208 			lspc = 0;
209 		}
210 	}
211 	Size isz = GetSize(txtcx, sz1, lspc, sz2, rspc);
212 	Point p = r.TopLeft(), ip;
213 	if(align == ALIGN_LEFT)
214 		p.x = r.left;
215 	else
216 	if(align == ALIGN_RIGHT)
217 		p.x = r.right - isz.cx;
218 	else
219 	if(align == ALIGN_CENTER)
220 		p.x = (r.right + r.left - isz.cx) / 2;
221 	if(valign == ALIGN_TOP)
222 		p.y = r.top;
223 	else
224 	if(valign == ALIGN_BOTTOM)
225 		p.y = r.bottom - isz.cy;
226 	else
227 	if(valign == ALIGN_CENTER)
228 		p.y = (r.bottom + r.top - txtsz.cy) / 2;
229 	Color color = disabled && !IsNull(disabledink) ? disabledink : ink;
230 	if(IsNull(color))
231 		color = disabled ? SColorDisabled : GetLabelTextColor(ctrl);
232 	int ix;
233 	if(IsNull(lspc))
234 		ix = r.left + push;
235 	else {
236 		ix = p.x + push;
237 		p.x += sz1.cx;
238 		p.x += lspc;
239 	}
240 	int iy = push + (r.top + r.bottom - sz1.cy) / 2;
241 
242 	if(sz1.cx) {
243 		if(IsNull(lcolor))
244 			w.DrawImage(ix, iy, DisabledImage(limg, disabled));
245 		else
246 			w.DrawImage(ix, iy, limg, lcolor);
247 	}
248 	iy = push + (r.top + r.bottom - sz2.cy) / 2;
249 	ix = (IsNull(rspc) ? r.right - sz2.cx : p.x + txtsz.cx + rspc) + push;
250 	if(sz2.cx) {
251 		if(IsNull(rcolor))
252 			w.DrawImage(ix, iy, DisabledImage(rimg, disabled));
253 		else
254 			w.DrawImage(ix, iy, rimg, rcolor);
255 	}
256 	paintrect.Paint(w, p.x + push, p.y + push, txtsz.cx, isz.cy, color, Null);
257 	if(*text) {
258 		if(disabled && *text != '\1')
259 			DrawSmartText(w, p.x + push + 1, p.y + push + 1,
260 			              nowrap ? INT_MAX/2 : txtcx, text, font, SColorPaper);
261 		DrawSmartText(w, p.x + push, p.y + push, nowrap ? INT_MAX/2 : txtcx,
262 		              text, font, color, visibleaccesskey ? accesskey : 0);
263 		if(focus)
264 			DrawFocus(w, p.x - 2, p.y, txtsz.cx + 5, isz.cy);
265 	}
266 
267 	return isz;
268 }
269 
Paint(Ctrl * ctrl,Draw & w,int x,int y,int cx,int cy,bool visibleaccesskey) const270 Size DrawLabel::Paint(Ctrl *ctrl, Draw& w, int x, int y, int cx, int cy, bool visibleaccesskey) const
271 {
272 	return Paint(ctrl, w, RectC(x, y, cx, cy), visibleaccesskey);
273 }
274 
Paint(Draw & w,const Rect & r,bool visibleaccesskey) const275 Size DrawLabel::Paint(Draw& w, const Rect& r, bool visibleaccesskey) const
276 {
277 	return Paint(NULL, w, r, visibleaccesskey);
278 }
279 
Paint(Draw & w,int x,int y,int cx,int cy,bool vak) const280 Size DrawLabel::Paint(Draw& w, int x, int y, int cx, int cy, bool vak) const
281 {
282 	return Paint(w, RectC(x, y, cx, cy), vak);
283 }
284 
LabelUpdate()285 void LabelBase::LabelUpdate() {}
286 
SetLeftImage(const Image & img,int spc,bool never_hide)287 LabelBase& LabelBase::SetLeftImage(const Image& img, int spc, bool never_hide) {
288 	lbl.limg = img;
289 	lbl.lspc = spc;
290 	lbl.limg_never_hide = never_hide;
291 	LabelUpdate();
292 	return *this;
293 }
294 
SetRightImage(const Image & img,int spc,bool never_hide)295 LabelBase& LabelBase::SetRightImage(const Image& img, int spc, bool never_hide) {
296 	lbl.rimg = img;
297 	lbl.rspc = spc;
298 	lbl.rimg_never_hide = never_hide;
299 	LabelUpdate();
300 	return *this;
301 }
302 
SetPaintRect(const PaintRect & paintrect)303 LabelBase& LabelBase::SetPaintRect(const PaintRect& paintrect) {
304 	lbl.paintrect = paintrect;
305 	LabelUpdate();
306 	return *this;
307 }
308 
309 
SetText(const char * text)310 LabelBase& LabelBase::SetText(const char *text) {
311 	lbl.text = text;
312 	LabelUpdate();
313 	return *this;
314 }
315 
SetFont(Font font)316 LabelBase& LabelBase::SetFont(Font font) {
317 	if(lbl.font != font) {
318 		lbl.font = font;
319 		LabelUpdate();
320 	}
321 	return *this;
322 }
323 
NoWrap(bool b)324 LabelBase& LabelBase::NoWrap(bool b)
325 {
326 	if(lbl.nowrap != b) {
327 		lbl.nowrap = b;
328 		LabelUpdate();
329 	}
330 	return *this;
331 }
332 
SetInk(Color ink,Color disabledink)333 LabelBase& LabelBase::SetInk(Color ink, Color disabledink) {
334 	if(lbl.ink != ink || lbl.disabledink != disabledink) {
335 		lbl.ink = ink;
336 		lbl.disabledink = disabledink;
337 		LabelUpdate();
338 	}
339 	return *this;
340 }
341 
SetAlign(int align)342 LabelBase& LabelBase::SetAlign(int align) {
343 	if(lbl.align != align) {
344 		lbl.align = align;
345 		LabelUpdate();
346 	}
347 	return *this;
348 }
349 
SetVAlign(int valign)350 LabelBase& LabelBase::SetVAlign(int valign) {
351 	if(lbl.valign != valign) {
352 		lbl.valign = valign;
353 		LabelUpdate();
354 	}
355 	return *this;
356 }
357 
PaintLabel(Ctrl * ctrl,Draw & w,const Rect & r,bool disabled,bool push,bool focus,bool vak)358 Size LabelBase::PaintLabel(Ctrl *ctrl, Draw& w, const Rect& r, bool disabled, bool push, bool focus, bool vak)
359 {
360 	DrawLabel lbl1 = lbl;
361 	lbl1.disabled = disabled;
362 	lbl1.push = push;
363 	lbl1.focus = focus;
364 	return lbl1.Paint(ctrl, w, r, vak);
365 }
366 
PaintLabel(Ctrl * ctrl,Draw & w,int x,int y,int cx,int cy,bool disabled,bool push,bool focus,bool vak)367 Size LabelBase::PaintLabel(Ctrl *ctrl, Draw& w, int x, int y, int cx, int cy, bool disabled, bool push, bool focus, bool vak)
368 {
369 	return PaintLabel(ctrl, w, RectC(x, y, cx, cy), disabled, push, focus, vak);
370 }
371 
PaintLabel(Draw & w,const Rect & r,bool disabled,bool push,bool focus,bool vak)372 Size LabelBase::PaintLabel(Draw& w, const Rect& r, bool disabled, bool push, bool focus, bool vak)
373 {
374 	return PaintLabel(NULL, w, r, disabled, push, focus, vak);
375 }
376 
377 
PaintLabel(Draw & w,int x,int y,int cx,int cy,bool disabled,bool push,bool focus,bool vak)378 Size LabelBase::PaintLabel(Draw& w, int x, int y, int cx, int cy, bool disabled, bool push, bool focus, bool vak)
379 {
380 	return PaintLabel(w, RectC(x, y, cx, cy), disabled, push, focus, vak);
381 }
382 
GetLabelSize() const383 Size LabelBase::GetLabelSize() const
384 {
385 	return lbl.GetSize();
386 }
387 
388 void LinkToolTipIn__();
389 
~LabelBase()390 LabelBase::~LabelBase() {
391 	LinkToolTipIn__();
392 }
393 
DrawFocus(Draw & w,int x,int y,int cx,int cy,Color c)394 void DrawFocus(Draw& w, int x, int y, int cx, int cy, Color c) {
395 	w.Clipoff(x, y, cx, cy);
396 	for(int a = 0; a < cx; a += CtrlImg::focus_h().GetWidth()) {
397 		w.DrawImage(a, 0, CtrlImg::focus_h(), c);
398 		w.DrawImage(a, cy - DPI(1), CtrlImg::focus_h(), c);
399 	}
400 	for(int a = 0; a < cy; a += CtrlImg::focus_v().GetHeight()) {
401 		w.DrawImage(0, a, CtrlImg::focus_v(), c);
402 		w.DrawImage(cx - DPI(1), a, CtrlImg::focus_v(), c);
403 	}
404 	w.End();
405 }
406 
DrawFocus(Draw & w,const Rect & r,Color c)407 void DrawFocus(Draw& w, const Rect& r, Color c) {
408 	DrawFocus(w, r.left, r.top, r.Width(), r.Height(), c);
409 }
410 
DrawHorzDrop(Draw & w,int x,int y,int cx)411 void DrawHorzDrop(Draw& w, int x, int y, int cx)
412 {
413 	w.DrawRect(x, y, cx, 2, SColorHighlight);
414 	w.DrawRect(x, y - 2, 1, 6, SColorHighlight);
415 	w.DrawRect(x + cx - 1, y - 2, 1, 6, SColorHighlight);
416 	w.DrawRect(x + 1, y - 1, 1, 4, SColorHighlight);
417 	w.DrawRect(x + cx - 2, y - 1, 1, 4, SColorHighlight);
418 }
419 
DrawVertDrop(Draw & w,int x,int y,int cy)420 void DrawVertDrop(Draw& w, int x, int y, int cy)
421 {
422 	w.DrawRect(x, y, 2, cy, SColorHighlight);
423 	w.DrawRect(x - 2, y, 6, 1, SColorHighlight);
424 	w.DrawRect(x - 2, y + cy - 1, 6, 1, SColorHighlight);
425 	w.DrawRect(x - 1, y + 1, 4, 1, SColorHighlight);
426 	w.DrawRect(x - 1, y + cy - 2, 4, 1, SColorHighlight);
427 }
428 
GetDragScroll(Ctrl * ctrl,Point p,Size max)429 Point GetDragScroll(Ctrl *ctrl, Point p, Size max)
430 {
431 	if(ctrl->IsReadOnly())
432 		return Point(0, 0);
433 	Size sz = ctrl->GetSize();
434 	Size sd = min(sz / 6, Size(16, 16));
435 	Point d(0, 0);
436 	if(p.x < sd.cx)
437 		d.x = p.x - sd.cx;
438 	if(p.x > sz.cx - sd.cx)
439 		d.x = p.x - sz.cx + sd.cx;
440 	if(p.y < sd.cy)
441 		d.y = p.y - sd.cy;
442 	if(p.y > sz.cy - sd.cy)
443 		d.y = p.y - sz.cy + sd.cy;
444 	d.x = minmax(d.x, -max.cx, max.cx);
445 	d.y = minmax(d.y, -max.cy, max.cy);
446 	return d;
447 }
448 
GetDragScroll(Ctrl * ctrl,Point p,int max)449 Point GetDragScroll(Ctrl *ctrl, Point p, int max)
450 {
451 	return GetDragScroll(ctrl, p, Size(max, max));
452 }
453 
LookMargins(const Rect & r,const Value & ch)454 Rect LookMargins(const Rect& r, const Value& ch)
455 {
456 	Rect m = ChMargins(ch);
457 	int fcy = GetStdFontCy();
458 	if(m.top + m.bottom + fcy > r.GetHeight())
459 		m.top = m.bottom = max((r.GetHeight() - fcy) / 2, 0);
460 	return m;
461 }
462 
FrameLayout(Rect & r)463 void ActiveEdgeFrame::FrameLayout(Rect& r)
464 {
465 	Rect m = LookMargins(r, edge[0]);
466 	r.left += m.left;
467 	r.right -= m.right;
468 	r.top += m.top;
469 	r.bottom -= m.bottom;
470 }
471 
FramePaint(Draw & w,const Rect & r)472 void ActiveEdgeFrame::FramePaint(Draw& w, const Rect& r)
473 {
474 	int i = 0;
475 	if(ctrl) {
476 		i = !ctrl->IsEnabled() || ctrl->IsReadOnly() ? CTRL_DISABLED
477 		    : button ? push : ctrl->HasFocus() ? CTRL_PRESSED
478 		    : mousein ? CTRL_HOT
479 		    : CTRL_NORMAL;
480 	}
481 	ChPaintEdge(w, r, edge[i]);
482 	if(!IsNull(coloredge))
483 		ChPaintEdge(w, r, coloredge, color);
484 }
485 
FrameAddSize(Size & sz)486 void ActiveEdgeFrame::FrameAddSize(Size& sz)
487 {
488 	Rect m = ChMargins(edge[0]);
489 	sz.cx += m.left + m.right;
490 	sz.cy += m.top + m.bottom;
491 }
492 
Set(const Ctrl * ctrl_,const Value * edge_,bool active)493 void ActiveEdgeFrame::Set(const Ctrl *ctrl_, const Value *edge_, bool active)
494 {
495 	ctrl = active ? ctrl_ : NULL;
496 	edge = edge_;
497 }
498 
499 }
500