1 #include "Fb.h"
2 
3 #ifdef GUI_FB
4 
5 NAMESPACE_UPP
6 
7 #define LLOG(x)   //DLOG(x)
8 #define LDUMP(x)  //DDUMP(x)
9 #define LDUMPC(x) //DDUMPC(x)
10 
11 ImageBuffer    Ctrl::framebuffer;
12 Vector<Rect>   Ctrl::invalid;
13 Vector<Rect>   Ctrl::update;
14 
15 Ptr<Ctrl>      Ctrl::desktop;
16 Vector<Ctrl *> Ctrl::topctrl;
17 
18 Point          Ctrl::fbCursorPos = Null;
19 Image          Ctrl::fbCursorImage;
20 Point          Ctrl::fbCursorBakPos = Null;
21 Image          Ctrl::fbCursorBak;
22 Rect           Ctrl::fbCaretRect;
23 Image          Ctrl::fbCaretBak;
24 int            Ctrl::fbCaretTm;
25 int            Ctrl::renderingMode = MODE_ANTIALIASED;
26 bool           Ctrl::fbEndSession;
27 bool           Ctrl::FullWindowDrag;
28 int            Ctrl::PaintLock;
29 
SetDesktop(Ctrl & q)30 void Ctrl::SetDesktop(Ctrl& q)
31 {
32 	desktop = &q;
33 	desktop->SetRect(framebuffer.GetSize());
34 	desktop->SetOpen(true);
35 	desktop->NewTop();
36 	invalid.Add(framebuffer.GetSize());
37 }
38 
SetRenderingMode(int mode)39 void Ctrl::SetRenderingMode(int mode)
40 {
41 	renderingMode = mode;
42 	invalid.Add(framebuffer.GetSize());
43 }
44 
InitFB()45 void Ctrl::InitFB()
46 {
47 	Ctrl::GlobalBackBuffer();
48 	Ctrl::InitTimer();
49 	framebuffer.Create(1, 1);
50 
51 #ifdef PLATFORM_POSIX
52 	SetStdFont(ScreenSans(12)); //FIXME general handling
53 #endif
54 	ChStdSkin();
55 
56 	static StaticRect x;
57 	x.Color(Cyan());
58 	SetDesktop(x);
59 }
60 
EndSession()61 void Ctrl::EndSession()
62 {
63 	GuiLock __;
64 	LLOG("Ctrl::EndSession");
65 	fbEndSession = true;
66 	EndSessionLoopNo = EventLoopNo;
67 }
68 
ExitFB()69 void Ctrl::ExitFB()
70 {
71 	TopWindow::ShutdownWindows();
72 	Ctrl::CloseTopCtrls();
73 	if(fbEndSession)
74 		FBQuitSession();
75 }
76 
SetFramebufferSize(Size sz)77 void Ctrl::SetFramebufferSize(Size sz)
78 {
79 	framebuffer.Create(sz);
80 	if(desktop)
81 		desktop->SetRect(sz);
82 	invalid.Add(sz);
83 	SyncTopWindows();
84 }
85 
FindTopCtrl() const86 int Ctrl::FindTopCtrl() const
87 {
88 	for(int i = 0; i < topctrl.GetCount(); i++)
89 		if(this == topctrl[i])
90 			return i;
91 	return -1;
92 }
93 
IsAlphaSupported()94 bool Ctrl::IsAlphaSupported()
95 {
96 	return false;
97 }
98 
IsCompositedGui()99 bool Ctrl::IsCompositedGui()
100 {
101 	return false;
102 }
103 
GetTopCtrls()104 Vector<Ctrl *> Ctrl::GetTopCtrls()
105 {
106 	Vector<Ctrl *> ctrl;
107 	if(desktop)
108 		ctrl.Add(desktop);
109 	for(int i = 0; i < topctrl.GetCount(); i++)
110 		if(!dynamic_cast<TopWindowFrame *>(topctrl[i]))
111 			ctrl.Add(topctrl[i]);
112 	return ctrl;
113 }
114 
GetOwner()115 Ctrl *Ctrl::GetOwner()
116 {
117 	GuiLock __;
118 	int q = FindTopCtrl();
119 	if(q > 0 && topctrl[q]->top) {
120 		Ctrl *x = topctrl[q]->top->owner_window;
121 		LDUMP(Upp::Name(x));
122 		return dynamic_cast<TopWindowFrame *>(x) ? x->GetOwner() : x;
123 	}
124 	return NULL;
125 }
126 
GetActiveCtrl()127 Ctrl *Ctrl::GetActiveCtrl()
128 {
129 	GuiLock __;
130 	return focusCtrl ? focusCtrl->GetTopCtrl() : NULL;
131 }
132 
133 // Vector<Callback> Ctrl::hotkey;
134 
RegisterSystemHotKey(dword key,Callback cb)135 int Ctrl::RegisterSystemHotKey(dword key, Callback cb)
136 {
137 /*	ASSERT(key >= K_DELTA);
138 	int q = hotkey.GetCount();
139 	for(int i = 0; i < hotkey.GetCount(); i++)
140 		if(!hotkey[i]) {
141 			q = i;
142 			break;
143 		}
144 	hotkey.At(q) = cb;
145 	dword mod = 0;
146 	if(key & K_ALT)
147 		mod |= MOD_ALT;
148 	if(key & K_SHIFT)
149 		mod |= MOD_SHIFT;
150 	if(key & K_CTRL)
151 		mod |= MOD_CONTROL;
152 
153 	return RegisterHotKey(NULL, q, mod, key & 0xffff) ? q : -1;*/
154 	return -1;
155 }
156 
UnregisterSystemHotKey(int id)157 void Ctrl::UnregisterSystemHotKey(int id)
158 {
159 /*	if(id >= 0 && id < hotkey.GetCount()) {
160 		UnregisterHotKey(NULL, id);
161 		hotkey[id].Clear();
162 	}*/
163 }
164 
IsWaitingEvent()165 bool Ctrl::IsWaitingEvent()
166 {
167 	return FBIsWaitingEvent();
168 }
169 
AddUpdate(const Rect & rect)170 void Ctrl::AddUpdate(const Rect& rect)
171 {
172 	LLOG("@AddUpdate " << rect);
173 	AddRefreshRect(update, rect);
174 }
175 
AddInvalid(const Rect & rect)176 void Ctrl::AddInvalid(const Rect& rect)
177 {
178 	LLOG("@AddInvalid " << rect);
179 	AddRefreshRect(invalid, rect);
180 }
181 
SyncTopWindows()182 void Ctrl::SyncTopWindows()
183 {
184 	for(int i = 0; i < topctrl.GetCount(); i++) {
185 		TopWindow *w = dynamic_cast<TopWindow *>(topctrl[i]);
186 		if(w)
187 			w->SyncRect();
188 	}
189 }
190 
ProcessEvent(bool * quit)191 bool Ctrl::ProcessEvent(bool *quit)
192 {
193 	LLOG("@ ProcessEvent");
194 	ASSERT(IsMainThread());
195 	if(!GetMouseLeft() && !GetMouseRight() && !GetMouseMiddle())
196 		ReleaseCtrlCapture();
197 	if(FBProcessEvent(quit)) {
198 		LLOG("FBProcesEvent returned true");
199 		SyncTopWindows();
200 		DefferedFocusSync();
201 		SyncCaret();
202 		return true;
203 	}
204 	return false;
205 }
206 
GetClipBound(const Vector<Rect> & inv,const Rect & r)207 Rect Ctrl::GetClipBound(const Vector<Rect>& inv, const Rect& r)
208 {
209 	Rect ri = Null;
210 	for(int j = 0; j < inv.GetCount(); j++) {
211 		Rect rr = inv[j] & r;
212 		if(!rr.IsEmpty())
213 			ri = IsNull(ri) ? rr : rr | ri;
214 	}
215 	return ri;
216 }
217 
218 
ViewDraw(Ctrl * ctrl)219 ViewDraw::ViewDraw(Ctrl *ctrl)
220 {
221 	if(Ctrl::invalid.GetCount())
222 		Ctrl::DoPaint();
223 	Ctrl::invalid.Clear();
224 	Ctrl::RemoveCursor();
225 	Ctrl::RemoveCaret();
226 	Rect r = ctrl->GetScreenView();
227 	Ctrl::invalid.Add(r);
228 	Ctrl::AddUpdate(r);
229 	for(int i = max(ctrl->GetTopCtrl()->FindTopCtrl() + 1, 0); i < Ctrl::topctrl.GetCount(); i++) {
230 		Rect rr = Ctrl::topctrl[i]->GetScreenRect();
231 		ExcludeClip(rr);
232 		Subtract(Ctrl::invalid, rr);
233 	}
234 	Offset(r.TopLeft());
235 }
236 
~ViewDraw()237 ViewDraw::~ViewDraw()
238 {
239 	FBInitUpdate();
240 	Ctrl::DoUpdate();
241 	FBFlush();
242 //	Ctrl::invalid.Clear();
243 }
244 
DoUpdate()245 void Ctrl::DoUpdate()
246 {
247 	LLOG("DoUpdate");
248 	invalid.Clear();
249 	CursorSync();
250 	LDUMPC(update);
251 #if 0
252 	FBUpdate(framebuffer.GetSize());
253 #else
254 	for(int i = 0; i < update.GetCount(); i++) {
255 		LDUMP(update[i]);
256 		FBUpdate(update[i]);
257 	}
258 #endif
259 	update.Clear();
260 //	Sleep(1000);
261 }
262 
GetPaintRects()263 Vector<Rect> Ctrl::GetPaintRects()
264 {
265 	Vector<Rect> r;
266 	int q = FindTopCtrl();
267 	r.Add(GetScreenRect());
268 	for(int i = max(FindTopCtrl() + 1, 0); i < topctrl.GetCount(); i++)
269 		Subtract(r, topctrl[i]->GetScreenRect());
270 	return r;
271 }
272 
273 
DDRect(RGBA * t,int dir,const byte * pattern,int pos,int count)274 void DDRect(RGBA *t, int dir, const byte *pattern, int pos, int count)
275 {
276 	while(count-- > 0) {
277 		byte p = pattern[7 & pos++];
278 		t->r ^= p;
279 		t->g ^= p;
280 		t->b ^= p;
281 		t += dir;
282 	}
283 }
284 
DrawLine(const Vector<Rect> & clip,int x,int y,int cx,int cy,bool horz,const byte * pattern,int animation)285 void Ctrl::DrawLine(const Vector<Rect>& clip, int x, int y, int cx, int cy, bool horz, const byte *pattern, int animation)
286 {
287 	if(cx <= 0 || cy <= 0)
288 		return;
289 	Vector<Rect> rr = Intersection(clip, RectC(x, y, cx, cy));
290 	for(int i = 0; i < rr.GetCount(); i++) {
291 		Rect r = rr[i];
292 		AddUpdate(r);
293 		if(horz)
294 			for(int y = r.top; y < r.bottom; y++)
295 				DDRect(framebuffer[y] + r.left, 1, pattern, r.left + animation, r.GetWidth());
296 		else
297 			for(int x = r.left; x < r.right; x++)
298 				DDRect(framebuffer[r.top] + x, framebuffer.GetWidth(), pattern, r.top + animation, r.GetHeight());
299 	}
300 }
301 
DragRectDraw0(const Vector<Rect> & clip,const Rect & rect,int n,const byte * pattern,int animation)302 void Ctrl::DragRectDraw0(const Vector<Rect>& clip, const Rect& rect, int n, const byte *pattern, int animation)
303 {
304 	int hn = min(rect.GetHeight(), n);
305 	int vn = min(rect.GetWidth(), n);
306 	DrawLine(clip, rect.left, rect.top, rect.GetWidth(), hn, true, pattern, animation);
307 	DrawLine(clip, rect.left, rect.top + hn, vn, rect.GetHeight() - hn, false, pattern, animation);
308 	DrawLine(clip, rect.right - vn, rect.top + hn, vn, rect.GetHeight() - hn, false, pattern, animation);
309 	DrawLine(clip, rect.left + vn, rect.bottom - hn, rect.GetWidth() - 2 * vn, hn, true, pattern, animation);
310 }
311 
DragRectDraw(const Rect & rect1,const Rect & rect2,const Rect & clip,int n,Color color,int type,int animation)312 void Ctrl::DragRectDraw(const Rect& rect1, const Rect& rect2, const Rect& clip, int n,
313                         Color color, int type, int animation)
314 {
315 	static byte solid[] =  { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
316 	static byte normal[] = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00 };
317 	static byte dashed[] = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
318 	Point p = GetScreenView().TopLeft();
319 	Vector<Rect> pr;
320 	if(type & DRAWDRAGRECT_SCREEN) {
321 		pr.Add(Rect(framebuffer.GetSize()));
322 		type &= ~DRAWDRAGRECT_SCREEN;
323 		p = Point(0, 0);
324 	}
325 	else
326 		pr = Intersection(GetPaintRects(), clip.Offseted(p));
327 	const byte *pattern = type == DRAWDRAGRECT_DASHED ? dashed :
328 	                      type == DRAWDRAGRECT_NORMAL ? normal : solid;
329 	RemoveCursor();
330 	RemoveCaret();
331 	DragRectDraw0(pr, rect1.Offseted(p), n, pattern, animation);
332 	DragRectDraw0(pr, rect2.Offseted(p), n, pattern, animation);
333 }
334 
DoPaint()335 void Ctrl::DoPaint()
336 {
337 	LLOG("@ DoPaint");
338 	if(!PaintLock) {
339 		bool scroll = false;
340 		if(desktop)
341 			desktop->SyncScroll();
342 		for(int i = 0; i < topctrl.GetCount(); i++)
343 			topctrl[i]->SyncScroll();
344 		if((invalid.GetCount() || scroll) && desktop) {
345 			RemoveCursor();
346 			RemoveCaret();
347 			for(int phase = 0; phase < 2; phase++) {
348 				LLOG("DoPaint invalid phase " << phase);
349 				LDUMPC(invalid);
350 				SystemDraw painter;
351 				painter.Begin();
352 				for(int i = 0; i < invalid.GetCount(); i++) {
353 					painter.RectPath(invalid[i]);
354 					AddUpdate(invalid[i]);
355 				}
356 				painter.Painter::Clip();
357 				for(int i = topctrl.GetCount() - 1; i >= 0; i--) {
358 					Rect r = topctrl[i]->GetRect();
359 					Rect ri = GetClipBound(invalid, r);
360 					if(!IsNull(ri)) {
361 						painter.Clipoff(r);
362 						topctrl[i]->UpdateArea(painter, ri - r.TopLeft());
363 						painter.End();
364 						Subtract(invalid, r);
365 						painter.ExcludeClip(r);
366 					}
367 				}
368 				Rect ri = GetClipBound(invalid, framebuffer.GetSize());
369 				if(!IsNull(ri))
370 					desktop->UpdateArea(painter, ri);
371 			}
372 		}
373 	}
374 	DoUpdate();
375 }
376 
WndUpdate0r(const Rect & r)377 void Ctrl::WndUpdate0r(const Rect& r)
378 {
379 	GuiLock __;
380 	Rect rr = r + GetRect().TopLeft();
381 	bool dummy;
382 	Vector<Rect> h;
383 	h <<= invalid;
384 	invalid = Intersect(invalid, rr, dummy);
385 	FBInitUpdate();
386 	DoPaint();
387 	invalid <<= h;
388 	Subtract(invalid, rr);
389 	FBFlush();
390 }
391 
ProcessEvents(bool * quit)392 bool Ctrl::ProcessEvents(bool *quit)
393 {
394 	//LOGBLOCK("@ ProcessEvents");
395 //	MemoryCheckDebug();
396 	if(!ProcessEvent(quit))
397 		return false;
398 	while(ProcessEvent(quit) && (!LoopCtrl || LoopCtrl->InLoop()));
399 	TimeStop tm;
400 	TimerProc(GetTickCount());
401 	LLOG("TimerProc elapsed: " << tm);
402 	SweepMkImageCache();
403 	FBInitUpdate();
404 	DoPaint();
405 	FBFlush();
406 	return true;
407 }
408 
EventLoop0(Ctrl * ctrl)409 void Ctrl::EventLoop0(Ctrl *ctrl)
410 {
411 	GuiLock __;
412 	ASSERT(IsMainThread());
413 	ASSERT(LoopLevel == 0 || ctrl);
414 	LoopLevel++;
415 	LLOG("Entering event loop at level " << LoopLevel << LOG_BEGIN);
416 	Ptr<Ctrl> ploop;
417 	if(ctrl) {
418 		ploop = LoopCtrl;
419 		LoopCtrl = ctrl;
420 		ctrl->inloop = true;
421 	}
422 
423 	bool quit = false;
424 	int64 loopno = ++EventLoopNo;
425 	ProcessEvents(&quit);
426 	while(loopno > EndSessionLoopNo && !quit && (ctrl ? ctrl->IsOpen() && ctrl->InLoop() : GetTopCtrls().GetCount()))
427 	{
428 //		LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / GuiSleep");
429 		SyncCaret();
430 		GuiSleep(20);
431 //		LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / ProcessEvents");
432 		ProcessEvents(&quit);
433 //		LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / after ProcessEvents");
434 		LDUMP(loopno);
435 		LDUMP(fbEndSessionLoop);
436 	}
437 
438 	if(ctrl)
439 		LoopCtrl = ploop;
440 	LoopLevel--;
441 	LLOG(LOG_END << "Leaving event loop ");
442 }
443 
GuiSleep0(int ms)444 void Ctrl::GuiSleep0(int ms)
445 {
446 	GuiLock __;
447 	ASSERT(IsMainThread());
448 	LLOG("GuiSleep");
449 	int level = LeaveGuiMutexAll();
450 	FBSleep(ms);
451 	EnterGuiMutex(level);
452 }
453 
GetWndScreenRect() const454 Rect Ctrl::GetWndScreenRect() const
455 {
456 	GuiLock __;
457 	return GetRect();
458 }
459 
WndShow0(bool b)460 void Ctrl::WndShow0(bool b)
461 {
462 	GuiLock __;
463 }
464 
WndUpdate0()465 void Ctrl::WndUpdate0()
466 {
467 	GuiLock __;
468 }
469 
IsWndOpen() const470 bool Ctrl::IsWndOpen() const {
471 	GuiLock __;
472 	return FindTopCtrl() >= 0 || this == desktop;
473 }
474 
SetAlpha(byte alpha)475 void Ctrl::SetAlpha(byte alpha)
476 {
477 	GuiLock __;
478 }
479 
GetWorkArea() const480 Rect Ctrl::GetWorkArea() const
481 {
482 	GuiLock __;
483 	return framebuffer.GetSize();
484 }
485 
GetWorkArea(Array<Rect> & rc)486 void Ctrl::GetWorkArea(Array<Rect>& rc)
487 {
488 	GuiLock __;
489 	Array<Rect> r;
490 	r.Add(framebuffer.GetSize());
491 }
492 
GetVirtualWorkArea()493 Rect Ctrl::GetVirtualWorkArea()
494 {
495 	return framebuffer.GetSize();
496 }
497 
GetWorkArea(Point pt)498 Rect Ctrl::GetWorkArea(Point pt)
499 {
500 	return framebuffer.GetSize();
501 }
502 
GetVirtualScreenArea()503 Rect Ctrl::GetVirtualScreenArea()
504 {
505 	GuiLock __;
506 	return framebuffer.GetSize();
507 }
508 
GetPrimaryWorkArea()509 Rect Ctrl::GetPrimaryWorkArea()
510 {
511 	Rect r;
512 	return framebuffer.GetSize();
513 }
514 
GetPrimaryScreenArea()515 Rect Ctrl::GetPrimaryScreenArea()
516 {
517 	return framebuffer.GetSize();
518 }
519 
GetKbdDelay()520 int Ctrl::GetKbdDelay()
521 {
522 	GuiLock __;
523 	return 500;
524 }
525 
GetKbdSpeed()526 int Ctrl::GetKbdSpeed()
527 {
528 	GuiLock __;
529 	return 1000 / 32;
530 }
531 
DestroyWnd()532 void Ctrl::DestroyWnd()
533 {
534 	for(int i = 0; i < topctrl.GetCount(); i++)
535 		if(topctrl[i]->top && topctrl[i]->top->owner_window == this)
536 			topctrl[i]->WndDestroy0();
537 	int q = FindTopCtrl();
538 	if(q >= 0) {
539 		AddInvalid(GetRect());
540 		topctrl.Remove(q);
541 	}
542 	if(top) {
543 		delete top;
544 		top = NULL;
545 	}
546 	isopen = false;
547 	TopWindow *win = dynamic_cast<TopWindow *>(this);
548 	if(win)
549 		win->DestroyFrame();
550 }
551 
WndDestroy0()552 void Ctrl::WndDestroy0()
553 {
554 	DestroyWnd();
555 	if(topctrl.GetCount())
556 		topctrl.Top()->ActivateWnd();
557 }
558 
PutForeground()559 void Ctrl::PutForeground()
560 {
561 	int q = FindTopCtrl();
562 	if(q >= 0) {
563 		AddInvalid(GetRect());
564 		topctrl.Remove(q);
565 		topctrl.Add(this);
566 	}
567 	Vector< Ptr<Ctrl> > fw;
568 	for(int i = 0; i < topctrl.GetCount(); i++)
569 		if(topctrl[i] && topctrl[i]->top && topctrl[i]->top->owner_window == this && topctrl[i] != this)
570 			fw.Add(topctrl[i]);
571 	for(int i = 0; i < fw.GetCount(); i++)
572 		if(fw[i])
573 			fw[i]->PutForeground();
574 }
575 
SetWndForeground0()576 void Ctrl::SetWndForeground0()
577 {
578 	GuiLock __;
579 	ASSERT(IsOpen());
580 	if(IsWndForeground())
581 		return;
582 	Ctrl *to = this;
583 	while(to->top && to->top->owner_window)
584 		to = to->top->owner_window;
585 	to->PutForeground();
586 	if(this != focusCtrl)
587 		ActivateWnd();
588 }
589 
IsWndForeground() const590 bool Ctrl::IsWndForeground() const
591 {
592 	GuiLock __;
593 	bool b = false;
594 	for(int i = 0; i < topctrl.GetCount(); i++) {
595 		const TopWindow *tw = dynamic_cast<const TopWindow *>(topctrl[i]);
596 		if(tw)
597 			b = tw == this;
598 	}
599 	return b;
600 }
601 
WndEnable0(bool * b)602 void Ctrl::WndEnable0(bool *b)
603 {
604 	GuiLock __;
605 	*b = true;
606 }
607 
SetWndFocus0(bool * b)608 void Ctrl::SetWndFocus0(bool *b)
609 {
610 	GuiLock __;
611 	*b = true;
612 }
613 
HasWndFocus() const614 bool Ctrl::HasWndFocus() const
615 {
616 	GuiLock __;
617 	return focusCtrl && focusCtrl->GetTopCtrl() == this;
618 }
619 
SetWndCapture()620 bool Ctrl::SetWndCapture()
621 {
622 	GuiLock __;
623 	ASSERT(IsMainThread());
624 	return true;
625 }
626 
ReleaseWndCapture()627 bool Ctrl::ReleaseWndCapture()
628 {
629 	GuiLock __;
630 	ASSERT(IsMainThread());
631 	return true;
632 }
633 
HasWndCapture() const634 bool Ctrl::HasWndCapture() const
635 {
636 	GuiLock __;
637 	return captureCtrl && captureCtrl->GetTopCtrl() == this;
638 }
639 
WndInvalidateRect(const Rect & r)640 void Ctrl::WndInvalidateRect(const Rect& r)
641 {
642 	GuiLock __;
643 	int q = FindTopCtrl();
644 	if(q >= 0)
645 		AddInvalid(r + topctrl[q]->GetRect().TopLeft());
646 	else
647 		AddInvalid(r);
648 }
649 
WndSetPos0(const Rect & rect)650 void Ctrl::WndSetPos0(const Rect& rect)
651 {
652 	GuiLock __;
653 	TopWindow *w = dynamic_cast<TopWindow *>(this);
654 	if(w)
655 		w->SyncFrameRect(rect);
656 	invalid.Add(GetRect());
657 	SetWndRect(rect);
658 	invalid.Add(rect);
659 }
660 
WndScrollView0(const Rect & r,int dx,int dy)661 void  Ctrl::WndScrollView0(const Rect& r, int dx, int dy)
662 {
663 	GuiLock __;
664 	if(dx == 0 && dy == 0)
665 		return;
666 	if(dx && dy) {
667 		Refresh(r);
668 		return;
669 	}
670 	RemoveCursor();
671 	RemoveCaret();
672 	Rect sr = r.Offseted(GetScreenRect().TopLeft());
673 	Vector<Rect> pr = Intersection(GetPaintRects(), sr);
674 	for(int i = 0; i < pr.GetCount(); i++) {
675 		Rect r = pr[i];
676 		if(dx) {
677 			int n = r.GetWidth() - abs(dx);
678 			if(n > 0) {
679 				int to = r.left + dx * (dx > 0);
680 				int from = r.left - dx * (dx < 0);
681 				for(int y = r.top; y < r.bottom; y++)
682 					memmove(framebuffer[y] + to, framebuffer[y] + from, n * sizeof(RGBA));
683 			}
684 			n = min(abs(dx), r.GetWidth());
685 			Refresh(dx < 0 ? r.left : r.right - n, r.top, n, r.GetHeight());
686 		}
687 		else {
688 			int n = r.GetHeight() - abs(dy);
689 			for(int y = 0; y < n; y++)
690 				memmove(framebuffer[dy < 0 ? r.top + y : r.bottom - 1 - y] + r.left,
691 				        framebuffer[dy < 0 ? r.top + y - dy : r.bottom - 1 - y - dy] + r.left,
692 				        r.GetWidth() * sizeof(RGBA));
693 			n = min(abs(dy), r.GetHeight());
694 			Refresh(r.left, dy < 0 ? r.bottom - n : r.top, r.GetWidth(), n);
695 		}
696 	}
697 
698 	Vector<Rect> ur;
699 	for(int i = 0; i < invalid.GetCount(); i++)
700 		if(invalid[i].Intersects(sr))
701 			ur.Add(invalid[i]);
702 	for(int i = 0; i < ur.GetCount(); i++)
703 		AddInvalid(ur[i].Offseted(dx, dy));
704 }
705 
PopUp(Ctrl * owner,bool savebits,bool activate,bool dropshadow,bool topmost)706 void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool dropshadow, bool topmost)
707 {
708 	ASSERT(!IsChild() && !IsOpen() && FindTopCtrl() < 0);
709 	NewTop();
710 	if(owner) {
711 		Ctrl *owner_window = owner->GetTopWindow();
712 		if(!owner_window)
713 			owner_window = owner->GetTopCtrl();
714 		ASSERT(owner_window->IsOpen());
715 		if(owner_window != desktop) {
716 			owner_window->SetForeground();
717 			top->owner_window = owner_window;
718 		}
719 	}
720 	topctrl.Add(this);
721 	popup = isopen = true;
722 	RefreshLayoutDeep();
723 	if(activate) SetFocusWnd();
724 	AddInvalid(GetRect());
725 }
726 
GetDefaultWindowRect()727 Rect Ctrl::GetDefaultWindowRect() {
728 	GuiLock __;
729 	static int ii = 0;
730 	Size sz = framebuffer.GetSize();
731 	Rect rect = framebuffer.GetSize();
732 	rect.Deflate(sz / 10);
733 	rect.Offset(Size(GetStdFontCy(), 2 * GetStdFontCy()) * (++ii % 8));
734 	return rect;
735 }
736 
SplitCmdLine__(const char * cmd)737 Vector<WString> SplitCmdLine__(const char *cmd)
738 {
739 	Vector<WString> out;
740 	while(*cmd)
741 		if((byte)*cmd <= ' ')
742 			cmd++;
743 		else if(*cmd == '\"') {
744 			WString quoted;
745 			while(*++cmd && (*cmd != '\"' || *++cmd == '\"'))
746 				quoted.Cat(FromSystemCharset(String(cmd, 1)).ToWString());
747 			out.Add(quoted);
748 		}
749 		else {
750 			const char *begin = cmd;
751 			while((byte)*cmd > ' ')
752 				cmd++;
753 			out.Add(String(begin, cmd).ToWString());
754 		}
755 	return out;
756 }
757 
758 END_UPP_NAMESPACE
759 
760 #endif
761