1 #include "CtrlCore.h"
2 
3 namespace Upp {
4 
5 #define LLOG(x)     // DLOG(x)
6 #define LTIMING(x)  // DTIMING(x)
7 
8 bool Ctrl::globalbackpaint;
9 bool Ctrl::globalbackbuffer;
10 
sCheckGuiLock()11 static void sCheckGuiLock()
12 {
13 	ASSERT_(ThreadHasGuiLock(), "Using GUI in non-main thread without GuiLock");
14 }
15 
RefreshFrame(const Rect & r)16 void Ctrl::RefreshFrame(const Rect& r) {
17 	sCheckGuiLock();
18 	GuiLock __; // Beware: Even if we have ThreadHasGuiLock ASSERT, we still can be the main thread!
19 	if(!IsOpen() || !IsVisible() || r.IsEmpty()) return;
20 	LTIMING("RefreshFrame");
21 	LLOG("RefreshRect " << Name() << ' ' << r);
22 	if(GuiPlatformRefreshFrameSpecial(r))
23 		return;
24 	if(!top && !IsDHCtrl()) {
25 		if(InFrame())
26 			parent->RefreshFrame(r + GetRect().TopLeft());
27 		else
28 			parent->Refresh(r + GetRect().TopLeft());
29 	}
30 	else {
31 		LLOG("WndInvalidateRect: " << r << ' ' << Name());
32 		LTIMING("RefreshFrame InvalidateRect");
33 		WndInvalidateRect(r);
34 	}
35 }
36 
Refresh0(const Rect & area)37 void Ctrl::Refresh0(const Rect& area) {
38 	RefreshFrame((area + GetView().TopLeft()) & GetView().Inflated(OverPaint()));
39 }
40 
Refresh(const Rect & area)41 void Ctrl::Refresh(const Rect& area) {
42 	sCheckGuiLock();
43 	GuiLock __; // Beware: Even if we have ThreadHasGuiLock ASSERT, we still can be the main thread!
44 	if(fullrefresh || !IsVisible() || !IsOpen()) return;
45 	LLOG("Refresh " << Name() << ' ' <<  area);
46 	Refresh0(area);
47 }
48 
Refresh()49 void Ctrl::Refresh() {
50 	sCheckGuiLock();
51 	GuiLock __; // Beware: Even if we have ThreadHasGuiLock ASSERT, we still can be the main thread!
52 	if(fullrefresh || !IsVisible() || !IsOpen()) return;
53 	LLOG("Refresh " << Name() << " full:" << fullrefresh);
54 	if(!GuiPlatformSetFullRefreshSpecial())
55 		fullrefresh = true; // Needs to be set ahead because of possible MT ICall that can cause repaint during Refresh0
56 	Refresh0(Rect(GetSize()).Inflated(OverPaint()));
57 }
58 
Refresh(int x,int y,int cx,int cy)59 void Ctrl::Refresh(int x, int y, int cx, int cy) {
60 	Refresh(RectC(x, y, cx, cy));
61 }
62 
RefreshFrame(int x,int y,int cx,int cy)63 void Ctrl::RefreshFrame(int x, int y, int cx, int cy) {
64 	RefreshFrame(RectC(x, y, cx, cy));
65 }
66 
RefreshFrame()67 void Ctrl::RefreshFrame() {
68 	LLOG("RefreshFrame " << Name());
69 	RefreshFrame(Rect(GetRect().Size()).Inflated(overpaint));
70 }
71 
ScrollRefresh(const Rect & r,int dx,int dy)72 void  Ctrl::ScrollRefresh(const Rect& r, int dx, int dy)
73 {
74 	sCheckGuiLock();
75 	GuiLock __; // Beware: Even if we have ThreadHasGuiLock ASSERT, we still can be the main thread!
76 	LLOG("ScrollRefresh " << r << " " << dx << " " << dy);
77 	if(!IsOpen() || !IsVisible() || r.IsEmpty()) return;
78 	int tdx = tabs(dx), tdy = tabs(dy);
79 	if(dx) WndInvalidateRect(RectC(dx >= 0 ? r.left : r.right - tdx, r.top - tdy, tdx, r.Height()));
80 	if(dy) WndInvalidateRect(RectC(r.left - tdx, dy >= 0 ? r.top : r.bottom - tdy, r.Width(), tdy));
81 }
82 
AddScroll(const Rect & sr,int dx,int dy)83 bool Ctrl::AddScroll(const Rect& sr, int dx, int dy)
84 {
85 	GuiLock __;
86 	if(!top)
87 		return true;
88 	for(int i = 0; i < top->scroll.GetCount(); i++) {
89 		Scroll& sc = top->scroll[i];
90 		if(sc.rect == sr && sgn(dx) == sgn(sc.dx) && sgn(dy) == sgn(sc.dy)) {
91 			sc.dx += dx;
92 			sc.dy += dy;
93 			ScrollRefresh(sc.rect, sc.dx, sc.dy);
94 			return false;
95 		}
96 		if(sc.rect.Intersects(sr)) {
97 			sc.rect |= sr;
98 			sc.dx = sc.dy = 0;
99 			WndInvalidateRect(sc.rect);
100 			return true;
101 		}
102 	}
103 	Scroll& sc = top->scroll.Add();
104 	sc.rect = sr;
105 	sc.dx = dx;
106 	sc.dy = dy;
107 	ScrollRefresh(sc.rect, sc.dx, sc.dy);
108 	return false;
109 }
110 
GetClippedView()111 Rect  Ctrl::GetClippedView()
112 {
113 	GuiLock __;
114 	Rect sv = GetScreenView();
115 	Rect view = sv;
116 	Ctrl *q = parent;
117 	Ctrl *w = this;
118 	while(q) {
119 		view &= w->InFrame() ? q->GetScreenRect() : q->GetScreenView();
120 		w = q;
121 		q = q->parent;
122 	}
123 	return view - GetScreenRect().TopLeft();
124 }
125 
ScrollCtrl(Top * top,Ctrl * q,const Rect & r,Rect cr,int dx,int dy)126 void Ctrl::ScrollCtrl(Top *top, Ctrl *q, const Rect& r, Rect cr, int dx, int dy)
127 {
128 	if(top && r.Intersects(cr)) { // Uno: Contains -> Intersetcs
129 		Rect to = cr;
130 		GetTopRect(to, false);
131 		if(r.Intersects(cr.Offseted(-dx, -dy))) { // Uno's suggestion 06/11/26 Contains -> Intersetcs
132 			Rect from = cr.Offseted(-dx, -dy);
133 			GetTopRect(from, false);
134 			MoveCtrl *m = FindMoveCtrlPtr(top->move, q);
135 			if(m && m->from == from && m->to == to) {
136 				LLOG("ScrollView Matched " << from << " -> " << to);
137 				m->ctrl = NULL;
138 				return;
139 			}
140 		}
141 
142 		if(r.Intersects(cr.Offseted(dx, dy))) { // Uno's suggestion 06/11/26 Contains -> Intersetcs
143 			Rect from = to;
144 			to = cr.Offseted(dx, dy);
145 			GetTopRect(to, false);
146 			MoveCtrl& m = top->scroll_move.Add(q);
147 			m.from = from;
148 			m.to = to;
149 			m.ctrl = q;
150 			LLOG("ScrollView Add " << UPP::Name(q) << from << " -> " << to);
151 			return;
152 		}
153 		cr &= r;
154 		if(!cr.IsEmpty()) {
155 			Refresh(cr);
156 			Refresh(cr + Point(dx, dy));
157 		}
158 	}
159 }
160 
ScrollView(const Rect & _r,int dx,int dy)161 void  Ctrl::ScrollView(const Rect& _r, int dx, int dy)
162 {
163 	GuiLock __;
164 	LLOG("ScrollView " << _r << " " << dx << " " << dy);
165 #ifdef GUIPLATFORM_NOSCROLL
166 	LLOG("NOSCROLL");
167 	Refresh(_r);
168 #else
169 	if(IsFullRefresh() || !IsVisible())
170 		return;
171 	if(IsDHCtrl()) {
172 		Refresh(_r);
173 		return;
174 	}
175 	Size vsz = GetSize();
176 	dx = sgn(dx) * min(abs(dx), vsz.cx);
177 	dy = sgn(dy) * min(abs(dy), vsz.cy);
178 	Rect r = _r & vsz;
179 	LLOG("ScrollView2 " << r << " " << dx << " " << dy);
180 	Ctrl *w;
181 	for(w = this; w->parent; w = w->parent)
182 		if(w->InFrame()) {
183 			Refresh();
184 			return;
185 		}
186 	if(!w || !w->top) return;
187 	Rect view = InFrame() ? GetView() : GetClippedView();
188 	Rect sr = (r + view.TopLeft()) & view;
189 	sr += GetScreenRect().TopLeft() - w->GetScreenRect().TopLeft();
190 	if(w->AddScroll(sr, dx, dy))
191 		Refresh();
192 	else {
193 		LTIMING("ScrollCtrls1");
194 		Top *top = GetTopCtrl()->top;
195 		for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
196 			if(q->InView())
197 				ScrollCtrl(top, q, r, q->GetRect(), dx, dy);
198 		if(parent)
199 			for(Ctrl *q = parent->GetFirstChild(); q; q = q->GetNext())
200 				if(q->InView() && q != this)
201 					ScrollCtrl(top, q, r, q->GetScreenRect() - GetScreenView().TopLeft(), dx, dy);
202 	}
203 #endif
204 }
205 
ScrollView(int x,int y,int cx,int cy,int dx,int dy)206 void  Ctrl::ScrollView(int x, int y, int cx, int cy, int dx, int dy) {
207 	ScrollView(RectC(x, y, cx, cy), dx, dy);
208 }
209 
ScrollView(int dx,int dy)210 void  Ctrl::ScrollView(int dx, int dy) {
211 	ScrollView(Rect(GetSize()), dx, dy);
212 }
213 
SyncScroll()214 void  Ctrl::SyncScroll()
215 {
216 	GuiLock __;
217 	if(!top)
218 		return;
219 	Vector<Scroll> scroll = pick(top->scroll);
220 	top->scroll.Clear();
221 	if(IsFullRefresh())
222 		return;
223 	for(int i = 0; i < scroll.GetCount(); i++) {
224 		Scroll& sc = scroll[i];
225 		if(abs(sc.dx) > 3 * sc.rect.Width() / 4 || abs(sc.dy) > 3 * sc.rect.Height() / 4) {
226 			LLOG("Sync scroll Invalidate rect" << sc.rect);
227 			WndInvalidateRect(sc.rect);
228 		}
229 		else
230 		if(sc.dx || sc.dy) {
231 			LLOG("WndScrollView " << sc.rect);
232 			WndScrollView(sc.rect, sc.dx, sc.dy);
233 		}
234 	}
235 }
236 
GetOpaqueRect() const237 Rect Ctrl::GetOpaqueRect() const
238 {
239 	return IsTransparent() ? Rect(0, 0, 0, 0) : GetSize();
240 }
241 
GetVoidRect() const242 Rect Ctrl::GetVoidRect() const
243 {
244 	return Rect(0, 0, 0, 0);
245 }
246 
247 
248 #ifdef _DEBUG
249 
250 struct sDrawLevelCheck {
251 	Draw&        w;
252 	int          lvl;
253 	const Ctrl  *q;
254 
CheckUpp::sDrawLevelCheck255 	void Check() {
256 		ASSERT_(lvl == w.GetCloffLevel(), "Draw::Begin/End mismatch for " + UPP::Name(q));
257 	}
258 
sDrawLevelCheckUpp::sDrawLevelCheck259 	sDrawLevelCheck(Draw& w, const Ctrl *q) : w(w), lvl(w.GetCloffLevel()), q(q) {}
260 	// NOTE: Checking level in destructor is a bad idea because of exceptions
261 };
262 
263 #define LEVELCHECK(w, q)    sDrawLevelCheck _x_(w, q)
264 #define DOLEVELCHECK        _x_.Check();
265 #else
266 #define LEVELCHECK(w, q)
267 #define DOLEVELCHECK
268 #endif
269 
CtrlPaint(SystemDraw & w,const Rect & clip)270 void Ctrl::CtrlPaint(SystemDraw& w, const Rect& clip) {
271 	GuiLock __;
272 	LEVELCHECK(w, this);
273 	LTIMING("CtrlPaint");
274 	LLOG("=== CtrlPaint " << UPP::Name(this) << ", clip: " << clip << ", rect: " << GetRect() << ", view: " << GetView());
275 	Rect rect = GetRect().GetSize();
276 	Rect orect = rect.Inflated(overpaint);
277 	if(!IsShown() || orect.IsEmpty() || clip.IsEmpty() || !clip.Intersects(orect))
278 		return;
279 	Ctrl *q;
280 	Rect view = rect;
281 	for(int i = 0; i < frame.GetCount(); i++) {
282 		LEVELCHECK(w, NULL);
283 		frame[i].frame->FramePaint(w, view);
284 		view = frame[i].view;
285 	}
286 	Rect oview = view.Inflated(overpaint);
287 	bool hasviewctrls = false;
288 	bool viewexcluded = false;
289 	bool hiddenbychild = false;
290 	for(q = firstchild; q; q = q->next)
291 		if(q->IsShown()) {
292 			if(q->GetRect().Contains(orect) && !q->IsTransparent())
293 				hiddenbychild = true;
294 			if(q->InFrame()) {
295 				if(!viewexcluded && IsTransparent() && q->GetRect().Intersects(view)) {
296 					w.Begin();
297 					w.ExcludeClip(view);
298 					viewexcluded = true;
299 				}
300 				LEVELCHECK(w, q);
301 				Point off = q->GetRect().TopLeft();
302 				w.Offset(off);
303 				q->CtrlPaint(w, clip - off);
304 				w.End();
305 			}
306 			else
307 				hasviewctrls = true;
308 		}
309 	if(viewexcluded)
310 		w.End();
311 	DOLEVELCHECK;
312 	if(!hiddenbychild && !oview.IsEmpty() && oview.Intersects(clip) && w.IsPainting(oview)) {
313 		LEVELCHECK(w, this);
314 		if(overpaint) {
315 			w.Clip(oview);
316 			w.Offset(view.left, view.top);
317 			Paint(w);
318 			PaintCaret(w);
319 			w.End();
320 			w.End();
321 		}
322 		else {
323 			w.Clipoff(view);
324 			Paint(w);
325 			PaintCaret(w);
326 			w.End();
327 		}
328 	}
329 	if(hasviewctrls && !view.IsEmpty()) {
330 		Rect cl = clip & view;
331 		w.Clip(cl);
332 		for(q = firstchild; q; q = q->next)
333 			if(q->IsShown() && q->InView()) {
334 				LEVELCHECK(w, q);
335 				Rect qr = q->GetRect();
336 				Point off = qr.TopLeft() + view.TopLeft();
337 				Rect ocl = cl - off;
338 				if(ocl.Intersects(Rect(qr.GetSize()).Inflated(overpaint))) {
339 					w.Offset(off);
340 					q->CtrlPaint(w, ocl);
341 					w.End();
342 				}
343 			}
344 		w.End();
345 	}
346 	DOLEVELCHECK;
347 }
348 
349 int sShowRepaint;
350 
ShowRepaint(int q)351 void Ctrl::ShowRepaint(int q)
352 {
353 	sShowRepaint = q;
354 }
355 
ShowRepaintRect(SystemDraw & w,const Rect & r,Color c)356 void ShowRepaintRect(SystemDraw& w, const Rect& r, Color c)
357 {
358 	if(sShowRepaint) {
359 		w.DrawRect(r, c);
360 		SystemDraw::Flush();
361 		Sleep(sShowRepaint);
362 	}
363 }
364 
PaintOpaqueAreas(SystemDraw & w,const Rect & r,const Rect & clip,bool nochild)365 bool Ctrl::PaintOpaqueAreas(SystemDraw& w, const Rect& r, const Rect& clip, bool nochild)
366 {
367 	GuiLock __;
368 	LTIMING("PaintOpaqueAreas");
369 	if(!IsShown() || r.IsEmpty() || !r.Intersects(clip) || !w.IsPainting(r))
370 		return true;
371 	Point off = r.TopLeft();
372 	Point viewpos = off + GetView().TopLeft();
373 	if(backpaint == EXCLUDEPAINT)
374 		return w.ExcludeClip(r);
375 	Rect cview = clip & (GetView() + off);
376 	for(Ctrl *q = lastchild; q; q = q->prev)
377 		if(!q->PaintOpaqueAreas(w, q->GetRect() + (q->InView() ? viewpos : off),
378 		                        q->InView() ? cview : clip))
379 			return false;
380 	if(nochild && (lastchild || GetNext()))
381 		return true;
382 	Rect opaque = (GetOpaqueRect() + viewpos) & clip;
383 	if(opaque.IsEmpty())
384 		return true;
385 #ifdef SYSTEMDRAW
386 	if(backpaint == FULLBACKPAINT && !dynamic_cast<BackDraw *>(&w))
387 #else
388 	if(backpaint == FULLBACKPAINT && !w.IsBack())
389 #endif
390 	{
391 		ShowRepaintRect(w, opaque, LtRed());
392 		BackDraw bw;
393 		bw.Create(w, opaque.GetSize());
394 		bw.Offset(viewpos - opaque.TopLeft());
395 		bw.SetPaintingDraw(w, opaque.TopLeft());
396 		{
397 			LEVELCHECK(bw, this);
398 			Paint(bw);
399 			PaintCaret(bw);
400 			DOLEVELCHECK;
401 		}
402 		bw.Put(w, opaque.TopLeft());
403 	}
404 	else {
405 		w.Clip(opaque);
406 		ShowRepaintRect(w, opaque, Green());
407 		w.Offset(viewpos);
408 		{
409 			LEVELCHECK(w, this);
410 			Paint(w);
411 			PaintCaret(w);
412 			DOLEVELCHECK;
413 		}
414 		w.End();
415 		w.End();
416 	}
417 	LLOG("Exclude " << opaque);
418 	return w.ExcludeClip(opaque);
419 }
420 
Area(const Rect & r)421 inline int Area(const Rect& r)
422 {
423 	return r.GetHeight() * r.GetWidth();
424 }
425 
CombineArea(Vector<Rect> & area,const Rect & r)426 void CombineArea(Vector<Rect>& area, const Rect& r)
427 {
428 	LTIMING("CombineArea");
429 	if(r.IsEmpty()) return;
430 	int ra = Area(r);
431 	for(int i = 0; i < area.GetCount(); i++) {
432 		Rect ur = r | area[i];
433 		int a = Area(ur);
434 		if(a < 2 * (ra + Area(area[i])) || a < 16000) {
435 			area[i] = ur;
436 			return;
437 		}
438 	}
439 	area.Add(r);
440 }
441 
GatherTransparentAreas(Vector<Rect> & area,SystemDraw & w,Rect r,const Rect & clip)442 void Ctrl::GatherTransparentAreas(Vector<Rect>& area, SystemDraw& w, Rect r, const Rect& clip)
443 {
444 	GuiLock __;
445 	LTIMING("GatherTransparentAreas");
446 	Point off = r.TopLeft();
447 	Point viewpos = off + GetView().TopLeft();
448 	r.Inflate(overpaint);
449 	Rect notr = GetVoidRect();
450 	if(notr.IsEmpty())
451 		notr = GetOpaqueRect();
452 	notr += viewpos;
453 	if(!IsShown() || r.IsEmpty() || !clip.Intersects(r) || !w.IsPainting(r))
454 		return;
455 	if(notr.IsEmpty())
456 		CombineArea(area, r & clip);
457 	else {
458 		if(notr != r) {
459 			CombineArea(area, clip & Rect(r.left, r.top, notr.left, r.bottom));
460 			CombineArea(area, clip & Rect(notr.right, r.top, r.right, r.bottom));
461 			CombineArea(area, clip & Rect(notr.left, r.top, notr.right, notr.top));
462 			CombineArea(area, clip & Rect(notr.left, notr.bottom, notr.right, r.bottom));
463 		}
464 		for(Ctrl *q = firstchild; q; q = q->next) {
465 			Point qoff = q->InView() ? viewpos : off;
466 			Rect qr = q->GetRect() + qoff;
467 			if(clip.Intersects(qr))
468 				q->GatherTransparentAreas(area, w, qr, clip);
469 		}
470 	}
471 }
472 
FindBestOpaque(const Rect & clip)473 Ctrl *Ctrl::FindBestOpaque(const Rect& clip)
474 {
475 	GuiLock __;
476 	Ctrl *w = NULL;
477 	for(Ctrl *q = GetFirstChild(); q; q = q->GetNext()) {
478 		if(q->IsVisible() && GetScreenView().Contains(q->GetScreenRect())) {
479 			Rect sw = q->GetScreenView();
480 			if((q->GetOpaqueRect() + sw.TopLeft()).Contains(clip)) {
481 				w = q;
482 				Ctrl *h = q->FindBestOpaque(clip);
483 				if(h) w = h;
484 			}
485 			else
486 			if(q->GetScreenView().Contains(clip))
487 				w = q->FindBestOpaque(clip);
488 			else
489 			if(q->GetScreenRect().Intersects(clip))
490 				w = NULL;
491 		}
492 	}
493 	return w;
494 }
495 
ExcludeDHCtrls(SystemDraw & w,const Rect & r,const Rect & clip)496 void Ctrl::ExcludeDHCtrls(SystemDraw& w, const Rect& r, const Rect& clip)
497 {
498 	GuiLock __;
499 	LTIMING("PaintOpaqueAreas");
500 	if(!IsShown() || r.IsEmpty() || !r.Intersects(clip) || !w.IsPainting(r))
501 		return;
502 	Point off = r.TopLeft();
503 	Point viewpos = off + GetView().TopLeft();
504 	if(dynamic_cast<DHCtrl *>(this)) {
505 		w.ExcludeClip(r);
506 		return;
507 	}
508 	Rect cview = clip & (GetView() + off);
509 	for(Ctrl *q = lastchild; q; q = q->prev)
510 		q->ExcludeDHCtrls(w, q->GetRect() + (q->InView() ? viewpos : off),
511 		                  q->InView() ? cview : clip);
512 }
513 
UpdateArea0(SystemDraw & draw,const Rect & clip,int backpaint)514 void Ctrl::UpdateArea0(SystemDraw& draw, const Rect& clip, int backpaint)
515 {
516 	GuiLock __;
517 	LTIMING("UpdateArea");
518 	LLOG("========== UPDATE AREA " << UPP::Name(this) << ", clip: " << clip << " ==========");
519 	ExcludeDHCtrls(draw, GetRect().GetSize(), clip);
520 	if(globalbackbuffer) {
521 		CtrlPaint(draw, clip);
522 		LLOG("========== END (TARGET IS BACKBUFFER)");
523 		return;
524 	}
525 	if(backpaint == FULLBACKPAINT || globalbackpaint) {
526 		ShowRepaintRect(draw, clip, LtRed());
527 		BackDraw bw;
528 		bw.Create(draw, clip.GetSize());
529 		bw.Offset(-clip.TopLeft());
530 		bw.SetPaintingDraw(draw, clip.TopLeft());
531 		CtrlPaint(bw, clip);
532 		bw.Put(draw, clip.TopLeft());
533 		LLOG("========== END (FULLBACKPAINT)");
534 		return;
535 	}
536 	if(backpaint == TRANSPARENTBACKPAINT) {
537 		LLOG("TransparentBackpaint");
538 		Vector<Rect> area;
539 		GatherTransparentAreas(area, draw, GetRect().GetSize(), clip);
540 		for(int i = 0; i < area.GetCount(); i++) {
541 			Rect ar = area[i];
542 			LLOG("Painting area: " << ar);
543 			ShowRepaintRect(draw, ar, LtBlue());
544 			BackDraw bw;
545 			bw.Create(draw, ar.GetSize());
546 			bw.Offset(-ar.TopLeft());
547 			bw.SetPaintingDraw(draw, ar.TopLeft());
548 			CtrlPaint(bw, ar);
549 			bw.Put(draw, ar.TopLeft());
550 			if(!draw.ExcludeClip(ar)) {
551 				LLOG("========== END");
552 				return;
553 			}
554 		}
555 		PaintOpaqueAreas(draw, GetRect().GetSize(), clip);
556 		LLOG("========== END");
557 		return;
558 	}
559 	CtrlPaint(draw, clip);
560 	LLOG("========== END");
561 }
562 
563 void SweepMkImageCache();
564 
UpdateArea(SystemDraw & draw,const Rect & clip)565 void Ctrl::UpdateArea(SystemDraw& draw, const Rect& clip)
566 {
567 	GuiLock __;
568 	if(IsPanicMode())
569 		return;
570 	RemoveFullRefresh();
571 	Point sp = GetScreenRect().TopLeft();
572 	Ctrl *b = FindBestOpaque(clip + sp);
573 	if(b) {
574 		Point p = b->GetScreenRect().TopLeft() - sp;
575 		draw.Offset(p);
576 		b->UpdateArea0(draw, clip.Offseted(-p), backpaint);
577 		draw.End();
578 	}
579 	else
580 		UpdateArea0(draw, clip, backpaint);
581 	SweepMkImageCache();
582 }
583 
RemoveFullRefresh()584 void Ctrl::RemoveFullRefresh()
585 {
586 	GuiLock __;
587 	fullrefresh = false;
588 	for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
589 		q->RemoveFullRefresh();
590 }
591 
GetTopRect(Rect & r,bool inframe,bool clip)592 Ctrl *Ctrl::GetTopRect(Rect& r, bool inframe, bool clip)
593 {
594 	GuiLock __;
595 	if(!inframe) {
596 		if(clip)
597 			r &= Rect(GetSize());
598 		r.Offset(GetView().TopLeft());
599 	}
600 	if(parent) {
601 		r.Offset(GetRect().TopLeft());
602 		return parent->GetTopRect(r, InFrame(), clip);
603 	}
604 	return this;
605 }
606 
DoSync(Ctrl * q,Rect r,bool inframe)607 void  Ctrl::DoSync(Ctrl *q, Rect r, bool inframe)
608 {
609 	GuiLock __;
610 	ASSERT(q);
611 	LLOG("DoSync " << UPP::Name(q) << " " << r);
612 	Ctrl *top = q->GetTopRect(r, inframe);
613 	if(top && top->IsOpen()) {
614 		top->SyncScroll();
615 		top->WndUpdate(r);
616 	}
617 }
618 
Sync()619 void  Ctrl::Sync()
620 {
621 	GuiLock __;
622 	LLOG("Sync " << Name());
623 	if(top && IsOpen()) {
624 		LLOG("Sync UpdateWindow " << Name());
625 		SyncScroll();
626 		WndUpdate();
627 	}
628 	else
629 	if(parent)
630 		DoSync(parent, GetRect(), inframe);
631 	SyncCaret();
632 }
633 
Sync(const Rect & sr)634 void Ctrl::Sync(const Rect& sr)
635 {
636 	GuiLock __;
637 	LLOG("Sync " << Name() << "   " << sr);
638 	DoSync(this, sr, true);
639 	SyncCaret();
640 }
641 
DrawCtrlWithParent(Draw & w,int x,int y)642 void Ctrl::DrawCtrlWithParent(Draw& w, int x, int y)
643 {
644 	GuiLock __;
645 	if(parent) {
646 		Rect r = GetRect();
647 		Ctrl *top = parent->GetTopRect(r, inframe);
648 		w.Clip(x, y, r.Width(), r.Height());
649 		w.Offset(x - r.left, y - r.top);
650 		SystemDraw *ws = dynamic_cast<SystemDraw *>(&w);
651 		if(ws)
652 			top->UpdateArea(*ws, r);
653 		w.End();
654 		w.End();
655 	}
656 	else
657 		DrawCtrl(w, x, y);
658 }
659 
DrawCtrl(Draw & w,int x,int y)660 void Ctrl::DrawCtrl(Draw& w, int x, int y)
661 {
662 	GuiLock __;
663 	w.Offset(x, y);
664 
665 	SystemDraw *ws = dynamic_cast<SystemDraw *>(&w);
666 	if(ws)
667 		UpdateArea(*ws, GetRect().GetSize());
668 
669 //	CtrlPaint(w, GetSize()); _DBG_
670 
671 	w.End();
672 }
673 
SyncMoves()674 void Ctrl::SyncMoves()
675 {
676 	GuiLock __;
677 	if(!top)
678 		return;
679 	for(int i = 0; i < top->move.GetCount(); i++) {
680 		MoveCtrl& m = top->move[i];
681 		if(m.ctrl) {
682 			RefreshFrame(m.from);
683 			RefreshFrame(m.to);
684 		}
685 	}
686 	for(int i = 0; i < top->scroll_move.GetCount(); i++) {
687 		MoveCtrl& s = top->scroll_move[i];
688 		if(s.ctrl) {
689 			RefreshFrame(s.from);
690 			RefreshFrame(s.to);
691 		}
692 	}
693 	top->move.Clear();
694 	top->scroll_move.Clear();
695 }
696 
BackPaintHint()697 Ctrl& Ctrl::BackPaintHint()
698 {
699 	GuiLock __;
700 		BackPaint();
701 	return *this;
702 }
703 
GlobalBackPaint(bool b)704 void  Ctrl::GlobalBackPaint(bool b)
705 {
706 	GuiLock __;
707 	globalbackpaint = b;
708 }
709 
GlobalBackPaintHint()710 void  Ctrl::GlobalBackPaintHint()
711 {
712 	GlobalBackPaint();
713 }
714 
GlobalBackBuffer(bool b)715 void Ctrl::GlobalBackBuffer(bool b)
716 {
717 	GuiLock __;
718 	globalbackbuffer = b;
719 }
720 
721 }
722