1 #include "CtrlCore.h"
2 
3 namespace Upp {
4 
5 #define LLOG(x)  // DLOG(x)
6 
7 Ptr<Ctrl> Ctrl::eventCtrl;
8 Ptr<Ctrl> Ctrl::mouseCtrl;
9 Ptr<Ctrl> Ctrl::captureCtrl;
10 Ptr<Ctrl> Ctrl::repeatTopCtrl;
11 Point     Ctrl::repeatMousePos;
12 bool      Ctrl::ignoreclick;
13 bool      Ctrl::ignoremouseup;
14 bool      Ctrl::mouseinframe;
15 bool      Ctrl::mouseinview;
16 Point     Ctrl::mousepos;
17 Point     Ctrl::leftmousepos = Null;
18 Point     Ctrl::rightmousepos = Null;
19 Point     Ctrl::middlemousepos = Null;
20 
GetMouseFlags()21 dword GetMouseFlags() {
22 	dword style = 0;
23 	if(GetAlt()) style |= K_ALT;
24 	if(GetCtrl()) style |= K_CTRL;
25 	if(GetShift()) style |= K_SHIFT;
26 	if(GetMouseLeft()) style |= K_MOUSELEFT;
27 	if(GetMouseRight()) style |= K_MOUSERIGHT;
28 	if(GetMouseMiddle()) style |= K_MOUSEMIDDLE;
29 	return style;
30 }
31 
LogMouseEvent(const char * f,const Ctrl * ctrl,int event,Point p,int zdelta,dword keyflags)32 void Ctrl::LogMouseEvent(const char *f, const Ctrl *ctrl, int event, Point p, int zdelta, dword keyflags)
33 {
34 	if(!Ini::user_log)
35 		return;
36 	String txt = f;
37 	txt += (event & BUTTON) == RIGHT ? "RIGHT" : (event & BUTTON) == MIDDLE ? "MIDDLE" : "LEFT";
38 	switch(event & ACTION) {
39 	case DOWN:        txt << "DOWN"; break;
40 	case UP:          txt << "UP"; break;
41 	case DOUBLE:      txt << "DOUBLE"; break;
42 	case MOUSEWHEEL:  txt << "WHEEL"; break;
43 	default:
44 		return;
45 	}
46 	txt << ' ' << p << " (";
47 	if(keyflags & K_ALT)
48 		txt << " ALT";
49 	if(keyflags & K_CTRL)
50 		txt << " CTRL";
51 	if(keyflags & K_SHIFT)
52 		txt << " SHIFT";
53 	if(keyflags & K_MOUSELEFT)
54 		txt << " LEFT";
55 	if(keyflags & K_MOUSERIGHT)
56 		txt << " RIGHT";
57 	if(keyflags & K_MOUSEMIDDLE)
58 		txt << " MIDDLE";
59 	txt << " ) " << Desc(ctrl);
60 	USRLOG(txt);
61 	LLOG(txt);
62 }
63 
FrameMouseEventH(int event,Point p,int zdelta,dword keyflags)64 Image Ctrl::FrameMouseEventH(int event, Point p, int zdelta, dword keyflags)
65 {
66 	GuiLock __;
67 	Ptr<Ctrl> this_ = this;
68 	for(int i = 0; i < mousehook().GetCount(); i++)
69 		if(this_ && (*mousehook()[i])(this, true, event, p, zdelta, keyflags))
70 			return Image::Arrow();
71 	if(this_)
72 		LogMouseEvent("FRAME ", this, event, p, zdelta, keyflags);
73 	eventCtrl = this_;
74 	if(parent && this_)
75 		parent->ChildFrameMouseEvent(this, event, p, zdelta, keyflags);
76 	return this_ ? FrameMouseEvent(event, p, zdelta, keyflags) : Image();
77 }
78 
FrameMouseEvent(int event,Point p,int zdelta,dword keyflags)79 Image Ctrl::FrameMouseEvent(int event, Point p, int zdelta, dword keyflags)
80 {
81 	return Image::Arrow();
82 }
83 
84 static bool sPropagated;
85 
MouseEvent0(int event,Point p,int zdelta,dword keyflags)86 Image Ctrl::MouseEvent0(int event, Point p, int zdelta, dword keyflags)
87 {
88 	GuiLock __;
89 	Ptr<Ctrl> this_ = this;
90 	bool pb = sPropagated;
91 	sPropagated = false;
92 	Image m = this_ ? MouseEvent(event, p, zdelta, keyflags) : Image();
93 	if(event == MOUSEWHEEL && !sPropagated && this_ && parent)
94 		parent->ChildMouseEvent(this, event, p, zdelta, keyflags);
95 	sPropagated = pb;
96 	return m;
97 }
98 
MouseEventH(int event,Point p,int zdelta,dword keyflags)99 Image Ctrl::MouseEventH(int event, Point p, int zdelta, dword keyflags)
100 {
101 	GuiLock __;
102 	Ptr<Ctrl> this_ = this;
103 	for(int i = 0; i < mousehook().GetCount(); i++)
104 		if(this_ && (*mousehook()[i])(this, false, event, p, zdelta, keyflags))
105 			return Image::Arrow();
106 	if(this_)
107 		LogMouseEvent(NULL, this, event, p, zdelta, keyflags);
108 	if(this_ && parent && event != MOUSEWHEEL)
109 		parent->ChildMouseEvent(this, event, p, zdelta, keyflags);
110 	return MouseEvent0(event, p, zdelta, keyflags);
111 }
112 
MouseWheel(Point p,int zd,dword kf)113 void Ctrl::MouseWheel(Point p, int zd, dword kf)
114 {
115 	if(parent) {
116 		p += GetScreenView().TopLeft();
117 		Rect r = parent->GetScreenView();
118 		if(r.Contains(p)) {
119 			parent->MouseEvent0(MOUSEWHEEL, p - r.TopLeft(), zd, kf);
120 			sPropagated = true;
121 		}
122 	}
123 }
124 
ChildFrameMouseEvent(Ctrl * child,int event,Point p,int zdelta,dword keyflags)125 void Ctrl::ChildFrameMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags)
126 {
127 	GuiLock __;
128 	if(parent)
129 		parent->ChildFrameMouseEvent(child, event, p, zdelta, keyflags);
130 }
131 
ChildMouseEvent(Ctrl * child,int event,Point p,int zdelta,dword keyflags)132 void Ctrl::ChildMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags)
133 {
134 	GuiLock __;
135 	if(parent)
136 		parent->ChildMouseEvent(child, event, p, zdelta, keyflags);
137 }
138 
MouseEvent(int event,Point p,int zdelta,dword keyflags)139 Image Ctrl::MouseEvent(int event, Point p, int zdelta, dword keyflags)
140 {
141 	LLOG("MouseEvent " << UPP::Name(this) << " " << FormatIntHex(event));
142 	switch(event) {
143 	case MOUSEENTER:
144 		MouseEnter(p, keyflags);
145 		break;
146 	case MOUSEMOVE:
147 		MouseMove(p, keyflags);
148 		break;
149 	case LEFTDOWN:
150 		LeftDown(p, keyflags);
151 		break;
152 	case LEFTDOUBLE:
153 		LeftDouble(p, keyflags);
154 		break;
155 	case LEFTDRAG:
156 		LeftDrag(p, keyflags);
157 		break;
158 	case LEFTHOLD:
159 		LeftHold(p, keyflags);
160 		break;
161 	case LEFTTRIPLE:
162 		LeftTriple(p, keyflags);
163 		break;
164 	case LEFTREPEAT:
165 		LeftRepeat(p, keyflags);
166 		break;
167 	case LEFTUP:
168 		LeftUp(p, keyflags);
169 		break;
170 	case RIGHTDRAG:
171 		RightDrag(p, keyflags);
172 		break;
173 	case RIGHTHOLD:
174 		RightHold(p, keyflags);
175 		break;
176 	case RIGHTTRIPLE:
177 		RightTriple(p, keyflags);
178 		break;
179 	case RIGHTDOWN:
180 		RightDown(p, keyflags);
181 		break;
182 	case RIGHTDOUBLE:
183 		RightDouble(p, keyflags);
184 		break;
185 	case RIGHTREPEAT:
186 		RightRepeat(p, keyflags);
187 		break;
188 	case RIGHTUP:
189 		RightUp(p, keyflags);
190 		break;
191 	case MIDDLEDRAG:
192 		MiddleDrag(p, keyflags);
193 		break;
194 	case MIDDLEHOLD:
195 		MiddleHold(p, keyflags);
196 		break;
197 	case MIDDLETRIPLE:
198 		MiddleTriple(p, keyflags);
199 		break;
200 	case MIDDLEDOWN:
201 		MiddleDown(p, keyflags);
202 		break;
203 	case MIDDLEDOUBLE:
204 		MiddleDouble(p, keyflags);
205 		break;
206 	case MIDDLEREPEAT:
207 		MiddleRepeat(p, keyflags);
208 		break;
209 	case MIDDLEUP:
210 		MiddleUp(p, keyflags);
211 		break;
212 	case MOUSELEAVE:
213 		MouseLeave();
214 		break;
215 	case MOUSEWHEEL:
216 		MouseWheel(p, zdelta, keyflags);
217 		break;
218 	case CURSORIMAGE:
219 		return CursorImage(p, keyflags);
220 	}
221 	return Image::Arrow();
222 }
223 
CursorImage(Point p,dword keyflags)224 Image Ctrl::CursorImage(Point p, dword keyflags)
225 {
226 	return Image::Arrow();
227 }
228 
IgnoreMouseClick()229 void Ctrl::IgnoreMouseClick()
230 {
231 	GuiLock __;
232 	LLOG("IgnoreMouseClick");
233 	ignoreclick = true;
234 	KillRepeat();
235 }
236 
IgnoreMouseUp()237 void Ctrl::IgnoreMouseUp()
238 {
239 	GuiLock __;
240 	LLOG("Ctrl::IgnoreMouseUp");
241 	if(GetMouseLeft() || GetMouseRight() || GetMouseMiddle()) {
242 		IgnoreMouseClick();
243 		ignoremouseup = true;
244 	}
245 }
246 
UnIgnoreMouse()247 void Ctrl::UnIgnoreMouse()
248 {
249 	GuiLock __;
250 	LLOG("Ctrl::EndIgnore");
251 	KillRepeat();
252 	ignoreclick = false;
253 	ignoremouseup = false;
254 }
255 
EndIgnore()256 void Ctrl::EndIgnore()
257 {
258 	GuiLock __;
259 	LLOG("Ctrl::EndIgnore");
260 	if(GetMouseLeft() || GetMouseRight() || GetMouseMiddle()) return;
261 	KillRepeat();
262 	ignoreclick = false;
263 	ignoremouseup = false;
264 }
265 
IsMouseActive() const266 bool Ctrl::IsMouseActive() const
267 {
268 	GuiLock __;
269 	return IsVisible() && IsEnabled() && IsOpen() && !ignoremouse;
270 }
271 
ChildFromPoint(Point & pt) const272 Ctrl *Ctrl::ChildFromPoint(Point& pt) const
273 {
274 	GuiLock __;
275 	Ctrl *q;
276 	Point p = pt;
277 	Rect view = GetView();
278 	if(view.Contains(p)) {
279 		Point vp = p - view.TopLeft();
280 		for(q = GetLastChild(); q; q = q->prev) {
281 			if(q->InView() && q->IsMouseActive()) {
282 				Rect r = q->GetRect();
283 				if(r.Contains(vp)) {
284 					pt = vp - r.TopLeft();
285 					return q;
286 				}
287 			}
288 		}
289 		return NULL;
290 	}
291 	for(q = GetLastChild(); q; q = q->prev) {
292 		if(q->InFrame() && q->IsMouseActive()) {
293 			Rect r = q->GetRect();
294 			if(r.Contains(p)) {
295 				pt = p - r.TopLeft();
296 				return q;
297 			}
298 		}
299 	}
300 	return NULL;
301 }
302 
MEvent0(int e,Point p,int zd)303 Image Ctrl::MEvent0(int e, Point p, int zd)
304 {
305 	GuiLock __;
306 	LLOG("MEvent0 " << Name() << " event: " << FormatIntHex(e, 0) << " point:" << p);
307 	Ptr<Ctrl> _this = this;
308 	mousepos = p;
309 	dword mm = 0;
310 	if((e & ACTION) == DOUBLE)
311 		mm |= K_MOUSEDOUBLE;
312 	if((e & ACTION) == TRIPLE)
313 		mm |= K_MOUSETRIPLE;
314 	Rect view = GetView();
315 	if(mouseCtrl != this) {
316 		if(mouseCtrl) {
317 			Ptr<Ctrl> mousectrl = mouseCtrl;
318 			mousectrl->MouseEventH(MOUSELEAVE, Point(0, 0), zd, GetMouseFlags() | mm);
319 			if(mousectrl)
320 				mousectrl->FrameMouseEventH(MOUSELEAVE, Point(0, 0), zd, GetMouseFlags() | mm);
321 		}
322 		mouseinframe = mouseinview = false;
323 		if(_this) {
324 			mouseCtrl = _this;
325 			mouseinframe = true;
326 			FrameMouseEventH(MOUSEENTER, p, zd, GetMouseFlags() | mm);
327 		}
328 	}
329 	bool inview = view.Contains(p);
330 	if(inview != mouseinview && _this) {
331 		mouseinview = inview;
332 		MouseEventH(inview ? MOUSEENTER : MOUSELEAVE, p, zd, GetMouseFlags() | mm);
333 	}
334 	if(_this) {
335 		if(view.Contains(p) || HasCapture()) {
336 			p -= view.TopLeft();
337 			return MouseEventH(e, p, zd, GetMouseFlags() | mm);
338 		}
339 		else
340 			return FrameMouseEventH(e, p, zd, GetMouseFlags() | mm);
341 	}
342 	return Image::Arrow();
343 }
344 
LRepeat()345 void    Ctrl::LRepeat() {
346 	GuiLock __;
347 	if(repeatTopCtrl && GetMouseLeft()) {
348 		if(repeatTopCtrl->HasFocusDeep())
349 			repeatTopCtrl->DispatchMouseEvent(LEFTREPEAT, repeatMousePos, 0);
350 	}
351 	else
352 		KillRepeat();
353 	LLOG("LRepeat " << UPP::Name(mouseCtrl));
354 }
355 
sDistMax(Point a,Point b)356 static int sDistMax(Point a, Point b)
357 {
358 	return IsNull(a) ? INT_MAX : max(abs(a.x - b.x), abs(a.y - b.y));
359 }
360 
sDistMin(Point a,Point b)361 static int sDistMin(Point a, Point b)
362 {
363 	return IsNull(a) ? -1 : max(abs(a.x - b.x), abs(a.y - b.y));
364 }
365 
LRep()366 void    Ctrl::LRep() {
367 	LLOG("LRep");
368 	UPP::SetTimeCallback(-GetKbdSpeed(), callback(&Ctrl::LRepeat), &mousepos);
369 }
370 
LHold()371 void    Ctrl::LHold() {
372 	GuiLock __;
373 	if(sDistMax(leftmousepos, mousepos) < GUI_DragDistance() && repeatTopCtrl && GetMouseLeft())
374 		repeatTopCtrl->DispatchMouseEvent(LEFTHOLD, repeatMousePos, 0);
375 }
376 
RRepeat()377 void    Ctrl::RRepeat() {
378 	GuiLock __;
379 	if(repeatTopCtrl && GetMouseRight()) {
380 		if(repeatTopCtrl->HasFocusDeep())
381 			repeatTopCtrl->DispatchMouseEvent(RIGHTREPEAT, repeatMousePos, 0);
382 	}
383 	else
384 		KillRepeat();
385 }
386 
RRep()387 void    Ctrl::RRep() {
388 	UPP::SetTimeCallback(-GetKbdSpeed(), callback(&Ctrl::RRepeat), &mousepos);
389 }
390 
RHold()391 void    Ctrl::RHold() {
392 	GuiLock __;
393 	if(sDistMax(rightmousepos, mousepos) < GUI_DragDistance() && repeatTopCtrl && GetMouseRight())
394 		repeatTopCtrl->DispatchMouseEvent(RIGHTHOLD, repeatMousePos, 0);
395 }
396 
MRepeat()397 void    Ctrl::MRepeat() {
398 	GuiLock __;
399 	if(repeatTopCtrl && GetMouseMiddle()) {
400 		if(repeatTopCtrl->HasFocusDeep())
401 			repeatTopCtrl->DispatchMouseEvent(MIDDLEREPEAT, repeatMousePos, 0);
402 	}
403 	else
404 		KillRepeat();
405 }
406 
MRep()407 void    Ctrl::MRep() {
408 	GuiLock __;
409 	UPP::SetTimeCallback(-GetKbdSpeed(), callback(&Ctrl::MRepeat), &mousepos);
410 }
411 
MHold()412 void    Ctrl::MHold() {
413 	GuiLock __;
414 	if(sDistMax(middlemousepos, mousepos) < GUI_DragDistance() && repeatTopCtrl && GetMouseMiddle())
415 		repeatTopCtrl->DispatchMouseEvent(MIDDLEHOLD, repeatMousePos, 0);
416 }
417 
KillRepeat()418 void    Ctrl::KillRepeat() {
419 	GuiLock __;
420 	LLOG("Ctrl::KillRepeat");
421 	UPP::KillTimeCallback(&mousepos);
422 	repeatTopCtrl = NULL;
423 	leftmousepos = Null;
424 	rightmousepos = Null;
425 	middlemousepos = Null;
426 }
427 
HasMouse() const428 bool    Ctrl::HasMouse() const
429 {
430 	GuiLock __;
431 	return mouseCtrl == this;
432 }
433 
HasMouseDeep() const434 bool    Ctrl::HasMouseDeep() const
435 {
436 	GuiLock __;
437 	return mouseCtrl == this || HasChildDeep(mouseCtrl);
438 }
439 
GetMouseCtrl()440 Ctrl   *Ctrl::GetMouseCtrl()
441 {
442 	GuiLock __;
443 	return mouseCtrl;
444 }
445 
HasMouseInFrame(const Rect & r) const446 bool    Ctrl::HasMouseInFrame(const Rect& r) const
447 {
448 	GuiLock __;
449 	if(!HasMouse())
450 		return false;
451 	Rect q = GetVisibleScreenRect();
452 	q = r.Offseted(q.TopLeft()) & q;
453 	return q.Contains(GetMousePos());
454 }
455 
HasMouseIn(const Rect & r) const456 bool    Ctrl::HasMouseIn(const Rect& r) const
457 {
458 	GuiLock __;
459 	if(!HasMouse())
460 		return false;
461 	return (r.Offseted(GetScreenView().TopLeft()) & GetVisibleScreenView()).Contains(GetMousePos());
462 }
463 
GetMouseViewPos() const464 Point Ctrl::GetMouseViewPos() const
465 {
466 	GuiLock __;
467 	return GetMousePos() - GetVisibleScreenView().TopLeft();
468 }
469 
DoCursorShape()470 void    Ctrl::DoCursorShape() {
471 	GuiLock __;
472 	Image m = CursorOverride();
473 	if(IsNull(m))
474 		if(mouseCtrl)
475 			SetMouseCursor(mouseCtrl->MEvent0(CURSORIMAGE, mousepos, 0));
476 		else
477 			SetMouseCursor(Image::Arrow());
478 	else
479 		SetMouseCursor(m);
480 }
481 
CheckMouseCtrl()482 void    Ctrl::CheckMouseCtrl() {
483 	LLOG("CheckMouseCtrl " << mouseCtrl);
484 	GuiLock __;
485 	Point p = GetMousePos();
486 	if(mouseCtrl) {
487 		Rect r = mouseCtrl->GetScreenRect();
488 		LLOG("CheckMouseCtrl mouseCtrl " << UPP::Name(mouseCtrl) << " " << r);
489 		if(!mouseCtrl->HasCapture() && !r.Contains(p)) {
490 			Ptr<Ctrl> mousectrl = mouseCtrl;
491 			if(mouseinview)
492 				mousectrl->MouseEventH(MOUSELEAVE, p - mousectrl->GetScreenView().TopLeft(),
493 				                       0, GetMouseFlags());
494 			if(mouseinframe && mousectrl)
495 				mousectrl->FrameMouseEventH(MOUSELEAVE, p - r.TopLeft(),
496 				                            0, GetMouseFlags());
497 			mouseinview = mouseinframe = false;
498 			mouseCtrl = NULL;
499 			leftmousepos = rightmousepos = middlemousepos = Null;
500 			KillRepeat();
501 		}
502 	}
503 	DoCursorShape();
504 }
505 
506 Point leftdblpos = Null, rightdblpos = Null, middledblpos = Null;
507 int leftdbltime = Null, rightdbltime = Null, middledbltime = Null;
508 
sDblTime(int time)509 bool sDblTime(int time)
510 {
511 	return !IsNull(time) && (int)msecs() - time < GUI_DblClickTime();
512 }
513 
DispatchMouse(int e,Point p,int zd)514 Image Ctrl::DispatchMouse(int e, Point p, int zd) {
515 	GuiLock __;
516 	if(e == MOUSEWHEEL && !zd) // ignore non-scroll wheel events
517 		return Null;
518 	if(e == MOUSEMOVE && repeatTopCtrl == this) {
519 		if(sDistMin(leftmousepos, p) > GUI_DragDistance() && GetMouseLeft()) {
520 			DispatchMouseEvent(LEFTDRAG, leftmousepos, 0);
521 			leftmousepos = Null;
522 		}
523 		if(sDistMin(rightmousepos, p) > GUI_DragDistance() && GetMouseRight()) {
524 			DispatchMouseEvent(RIGHTDRAG, rightmousepos, 0);
525 			rightmousepos = Null;
526 		}
527 		if(sDistMin(middlemousepos, p) > GUI_DragDistance() && GetMouseMiddle()) {
528 			DispatchMouseEvent(MIDDLEDRAG, middlemousepos, 0);
529 			middlemousepos = Null;
530 		}
531 	}
532 	repeatMousePos = p;
533 	if(e == LEFTDOUBLE) {
534 		leftdbltime = msecs();
535 		leftdblpos = p;
536 		UPP::SetTimeCallback(GetKbdDelay(), callback(&Ctrl::LRep), &mousepos);
537 		repeatTopCtrl = this;
538 	}
539 	if(e == RIGHTDOUBLE) {
540 		rightdbltime = msecs();
541 		rightdblpos = p;
542 		UPP::SetTimeCallback(GetKbdDelay(), callback(&Ctrl::RRep), &mousepos);
543 		repeatTopCtrl = this;
544 	}
545 	if(e == MIDDLEDOUBLE) {
546 		middledbltime = msecs();
547 		middledblpos = p;
548 		UPP::SetTimeCallback(GetKbdDelay(), callback(&Ctrl::MRep), &mousepos);
549 		repeatTopCtrl = this;
550 	}
551 	if(e == LEFTDOWN) {
552 		LLOG("Ctrl::DispatchMouse: init left repeat for " << UPP::Name(this) << " at " << p);
553 		UPP::SetTimeCallback(GetKbdDelay(), callback(&Ctrl::LRep), &mousepos);
554 		UPP::SetTimeCallback(2 * GetKbdDelay(), callback(&Ctrl::LHold), &mousepos);
555 		leftmousepos = p;
556 		if(sDistMax(leftdblpos, p) < GUI_DragDistance() && sDblTime(leftdbltime))
557 			e = LEFTTRIPLE;
558 		repeatTopCtrl = this;
559 	}
560 	if(e == RIGHTDOWN) {
561 		LLOG("Ctrl::DispatchMouse: init right repeat for " << UPP::Name(this) << " at " << p);
562 		UPP::SetTimeCallback(GetKbdDelay(), callback(&Ctrl::RRep), &mousepos);
563 		UPP::SetTimeCallback(2 * GetKbdDelay(), callback(&Ctrl::RHold), &mousepos);
564 		rightmousepos = p;
565 		if(sDistMax(rightdblpos, p) < GUI_DragDistance() && sDblTime(rightdbltime))
566 			e = RIGHTTRIPLE;
567 		repeatTopCtrl = this;
568 	}
569 	if(e == MIDDLEDOWN) {
570 		LLOG("Ctrl::DispatchMouse: init middle repeat for " << UPP::Name(this) << " at " << p);
571 		UPP::SetTimeCallback(GetKbdDelay(), callback(&Ctrl::MRep), &mousepos);
572 		UPP::SetTimeCallback(2 * GetKbdDelay(), callback(&Ctrl::MHold), &mousepos);
573 		middlemousepos = p;
574 		if(sDistMax(middledblpos, p) < GUI_DragDistance() && sDblTime(middledbltime))
575 			e = MIDDLETRIPLE;
576 		repeatTopCtrl = this;
577 	}
578 	if(repeatTopCtrl != this)
579 		repeatTopCtrl = NULL;
580 	if(e == LEFTUP)
581 		leftmousepos = Null;
582 	if(e == RIGHTUP)
583 		rightmousepos = Null;
584 	if(e == MIDDLEUP)
585 		rightmousepos = Null;
586 	if(findarg(e, LEFTUP, RIGHTUP, MIDDLEUP) >= 0)
587 		KillRepeat();
588 	Image result = DispatchMouseEvent(e, p, zd);
589 	if(!GetMouseRight() && !GetMouseMiddle() && !GetMouseLeft())
590 		ReleaseCtrlCapture();
591 	return result;
592 }
593 
DispatchMouseEvent(int e,Point p,int zd)594 Image Ctrl::DispatchMouseEvent(int e, Point p, int zd) {
595 	GuiLock __;
596 	if(captureCtrl && captureCtrl != this && captureCtrl->IsMouseActive()) {
597 		if(captureCtrl->IsEnabled())
598 			return captureCtrl->MEvent0(e, p + GetScreenRect().TopLeft() -
599 			                            captureCtrl->GetScreenRect().TopLeft(), zd);
600 		else
601 			return Image::Arrow();
602 	}
603 	if(!IsEnabled())
604 		return Image::Arrow();
605 	Ctrl *top = this;
606 	if(e == MOUSEWHEEL && !GetParent()) {
607 		Ctrl *w = GetFocusCtrl();
608 		if(w) {
609 			top = w->GetTopCtrl();
610 			p = GetMousePos() - top->GetScreenRect().TopLeft();
611 		}
612 	}
613 	Ctrl *q = top->ChildFromPoint(p);
614 	return q ? q->DispatchMouseEvent(e, p, zd) : top->MEvent0(e, p, zd);
615 }
616 
SetCapture()617 bool Ctrl::SetCapture() {
618 	GuiLock __;
619 	ReleaseCtrlCapture();
620 	if(!GetTopCtrl()->SetWndCapture()) return false;
621 	captureCtrl = mouseCtrl = this;
622 	return true;
623 }
624 
ReleaseCapture()625 bool Ctrl::ReleaseCapture() {
626 	GuiLock __;
627 	return this == captureCtrl && ReleaseCtrlCapture();
628 }
629 
ReleaseCtrlCapture()630 bool Ctrl::ReleaseCtrlCapture() {
631 	GuiLock __;
632 	LLOG("ReleaseCtrlCapture");
633 	if(captureCtrl) {
634 		captureCtrl->CancelMode();
635 		Ctrl *w = captureCtrl->GetTopCtrl();
636 		captureCtrl = NULL;
637 		CheckMouseCtrl();
638 		if(w->HasWndCapture()) {
639 			w->ReleaseWndCapture();
640 			return true;
641 		}
642 	}
643 	return false;
644 }
645 
HasCapture() const646 bool Ctrl::HasCapture() const {
647 	GuiLock __;
648 	if(captureCtrl != this)
649 		return false;
650 	return captureCtrl == this && GetTopCtrl()->HasWndCapture();
651 }
652 
GetCaptureCtrl()653 Ctrl * Ctrl::GetCaptureCtrl()
654 {
655 	GuiLock __;
656 	return captureCtrl && captureCtrl->GetTopCtrl()->HasWndCapture() ? captureCtrl : NULL;
657 }
658 
GetVisibleChild(Ctrl * ctrl,Point p,bool pointinframe)659 Ctrl *Ctrl::GetVisibleChild(Ctrl *ctrl, Point p, bool pointinframe)
660 {
661 	GuiLock __;
662 	if(!pointinframe)
663 		p += ctrl->GetView().TopLeft();
664 	Ctrl *q;
665 	Rect view = ctrl->GetView();
666 	if(view.Contains(p)) {
667 		p -= view.TopLeft();
668 		for(q = ctrl->GetLastChild(); q; q = q->GetPrev()) {
669 			if(q->InView() && q->IsVisible()) {
670 				Rect r = q->GetRect();
671 				if(r.Contains(p))
672 					return GetVisibleChild(q, p - r.TopLeft(), true);
673 			}
674 		}
675 	}
676 	else
677 		for(q = ctrl->GetLastChild(); q; q = q->GetPrev()) {
678 			if(q->InFrame() && q->IsVisible()) {
679 				Rect r = q->GetRect();
680 				if(r.Contains(p))
681 					return GetVisibleChild(q, p - r.TopLeft(), true);
682 			}
683 		}
684 	return ctrl;
685 }
686 
AutoWaitCursor(int & avg)687 AutoWaitCursor::AutoWaitCursor(int& avg) : WaitCursor(avg >= 0), avg(avg) {
688 	time0 = msecs();
689 }
690 
~AutoWaitCursor()691 AutoWaitCursor::~AutoWaitCursor() {
692 	if(time0) avg = msecs() - time0 - 500;
693 	if(avg < -10000) avg = -10000;
694 	if(avg >  10000) avg = 10000;
695 }
696 
CursorOverride()697 Image& Ctrl::CursorOverride()
698 {
699 	GuiLock __;
700 	static Image m;
701 	return m;
702 }
703 
OverrideCursor(const Image & m)704 Image Ctrl::OverrideCursor(const Image& m)
705 {
706 	GuiLock __;
707 	Image om = CursorOverride();
708 	CursorOverride() = m;
709 	DoCursorShape();
710 	if(!mouseCtrl)
711 		SetMouseCursor(IsNull(m) ? Image::Arrow() : m);
712 	return om;
713 }
714 
Show()715 void WaitCursor::Show() {
716 	if(flag)
717 		prev = Ctrl::OverrideCursor(Image::Wait());
718 	flag = false;
719 }
720 
WaitCursor(bool show)721 WaitCursor::WaitCursor(bool show) {
722 	LLOG("WaitCursor");
723 	flag = true;
724 	if(show) Show();
725 }
726 
~WaitCursor()727 WaitCursor::~WaitCursor() {
728 	if(!flag)
729 		Ctrl::OverrideCursor(prev);
730 }
731 
732 }
733