1 //------------------------------------------------------------------------------
2 // emView.cpp
3 //
4 // Copyright (C) 2004-2011,2014,2016,2018 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/emPanel.h>
22 #include <emCore/emViewInputFilter.h>
23
24
25 //==============================================================================
26 //=================================== emView ===================================
27 //==============================================================================
28
emView(emContext & parentContext,ViewFlags viewFlags)29 emView::emView(emContext & parentContext, ViewFlags viewFlags)
30 : emContext(parentContext)
31 {
32 emContext * c;
33 emWindow * win;
34
35 CoreConfig=emCoreConfig::Acquire(GetRootContext());
36 DummyViewPort=new emViewPort();
37 DummyViewPort->CurrentView=this;
38 DummyViewPort->HomeView=this;
39 HomeViewPort=DummyViewPort;
40 CurrentViewPort=DummyViewPort;
41 Window=NULL;
42 ScreenRef=NULL;
43 PopupWindow=NULL;
44 FirstVIF=NULL;
45 LastVIF=NULL;
46 ActiveAnimator=NULL;
47 MagneticVA=NULL;
48 VisitingVA=NULL;
49 RootPanel=NULL;
50 SupremeViewedPanel=NULL;
51 MinSVP=NULL;
52 MaxSVP=NULL;
53 ActivePanel=NULL;
54 HomeX=0.0;
55 HomeY=0.0;
56 HomeWidth=1.0;
57 HomeHeight=1.0;
58 HomePixelTallness=1.0;
59 CurrentX=0.0;
60 CurrentY=0.0;
61 CurrentWidth=1.0;
62 CurrentHeight=1.0;
63 CurrentPixelTallness=1.0;
64 LastMouseX=0.0;
65 LastMouseY=0.0;
66 Title="";
67 Cursor=emCursor::NORMAL;
68 BackgroundColor=0x808080FF;
69 VFlags=0;
70 Focused=false;
71 ActivationAdherent=false;
72 TitleInvalid=false;
73 CursorInvalid=false;
74 SVPChoiceInvalid=false;
75 SVPChoiceByOpacityInvalid=false;
76 GotPopupWindowCloseSignal=false;
77 RestartInputRecursion=false;
78 ZoomedOutBeforeSG=true;
79 SettingGeometry=0;
80 SVPUpdCount=0;
81 SVPUpdSlice=0;
82 NoticeList.Prev=&NoticeList;
83 NoticeList.Next=&NoticeList;
84 UpdateEngine=new UpdateEngineClass(*this);
85 EOIEngine=NULL;
86 SeekPosPanel=NULL;
87 StressTest=NULL;
88
89 UpdateEngine->WakeUp();
90
91 SetViewFlags(viewFlags);
92
93 MagneticVA=new emMagneticViewAnimator(*this);
94 VisitingVA=new emVisitingViewAnimator(*this);
95
96 new emDefaultTouchVIF(*this);
97 new emCheatVIF(*this);
98 new emKeyboardZoomScrollVIF(*this);
99 new emMouseZoomScrollVIF(*this);
100
101 for (win=NULL, c=GetParentContext(); c!=NULL; c=c->GetParentContext()) {
102 win=dynamic_cast<emWindow*>(c);
103 if (win) break;
104 }
105 SetWindowAndScreen(win); // emWindow constructor also calls that...
106 }
107
108
~emView()109 emView::~emView()
110 {
111 AbortActiveAnimator();
112 CrossPtrList.BreakCrossPtrs();
113 //??? Should we delete child views here like emWindow deletes its child
114 //??? windows? If so, remember to adapt emSubViewPanel. (No panic,
115 //??? child views are deleted at least by the context destructor)
116 if (RootPanel) delete RootPanel;
117 if (StressTest) delete StressTest;
118 while (LastVIF) delete LastVIF;
119 if (EOIEngine) delete EOIEngine;
120 delete UpdateEngine;
121 if (VisitingVA) { delete VisitingVA; VisitingVA=NULL; }
122 if (MagneticVA) { delete MagneticVA; MagneticVA=NULL; }
123 if (HomeViewPort!=DummyViewPort) {
124 emFatalError("emView::~emView: View port must be destructed first.");
125 }
126 DummyViewPort->HomeView=NULL;
127 DummyViewPort->CurrentView=NULL;
128 delete DummyViewPort;
129 }
130
131
SetViewFlags(ViewFlags viewFlags)132 void emView::SetViewFlags(ViewFlags viewFlags)
133 {
134 ViewFlags oldFlags;
135
136 if ((viewFlags&VF_NO_ZOOM)!=0) {
137 viewFlags&=~(VF_POPUP_ZOOM|VF_EGO_MODE);
138 viewFlags|=VF_NO_USER_NAVIGATION;
139 }
140 if (VFlags!=viewFlags) {
141 oldFlags=VFlags;
142 if (
143 (viewFlags&VF_POPUP_ZOOM)!=0 &&
144 (oldFlags&VF_POPUP_ZOOM)==0
145 ) {
146 RawZoomOut();
147 }
148 VFlags=viewFlags;
149 if (
150 (viewFlags&VF_ROOT_SAME_TALLNESS)!=0 &&
151 (oldFlags&VF_ROOT_SAME_TALLNESS)==0 &&
152 RootPanel
153 ) {
154 RootPanel->Layout(0,0,1,GetHomeTallness());
155 }
156 if (
157 (viewFlags&VF_NO_ZOOM)!=0 &&
158 (oldFlags&VF_NO_ZOOM)==0
159 ) {
160 RawZoomOut();
161 }
162 if ((viewFlags&VF_EGO_MODE)!=(oldFlags&VF_EGO_MODE)) {
163 CursorInvalid=true;
164 }
165 if ((viewFlags&VF_STRESS_TEST)!=0) {
166 if (!StressTest) {
167 StressTest=new StressTestClass(*this);
168 }
169 }
170 else {
171 if (StressTest) {
172 delete StressTest;
173 StressTest=NULL;
174 InvalidatePainting();
175 }
176 }
177 SVPChoiceInvalid=true;
178 Signal(ViewFlagsSignal);
179 UpdateEngine->WakeUp();
180 }
181 }
182
183
SetBackgroundColor(emColor c)184 void emView::SetBackgroundColor(emColor c)
185 {
186 if (BackgroundColor!=c) {
187 BackgroundColor=c;
188 InvalidatePainting();
189 }
190 }
191
192
GetTitle() const193 emString emView::GetTitle() const
194 {
195 return Title;
196 }
197
198
CreateControlPanel(emPanel & parent,const emString & name)199 emPanel * emView::CreateControlPanel(
200 emPanel & parent, const emString & name
201 )
202 {
203 if (!ActivePanel) return NULL;
204 return ActivePanel->CreateControlPanel(parent,name);
205 }
206
207
Focus()208 void emView::Focus()
209 {
210 if (!Focused) CurrentViewPort->RequestFocus();
211 }
212
213
GetScreen() const214 emScreen * emView::GetScreen() const
215 {
216 return (emScreen*)ScreenRef.Get();
217 }
218
219
GetMaxPopupViewRect(double * pX,double * pY,double * pW,double * pH) const220 void emView::GetMaxPopupViewRect(
221 double * pX, double * pY, double * pW, double * pH
222 ) const
223 {
224 double x,y,w,h,mx,my,mw,mh,cx,cy;
225 const emScreen * screen;
226 bool found;
227 int i,n;
228
229 x=CurrentX;
230 y=CurrentY;
231 w=CurrentWidth;
232 h=CurrentHeight;
233 screen=GetScreen();
234 if (screen) {
235 n=screen->GetMonitorCount();
236 found=false;
237 for (i=n-1; i>=0; i--) {
238 screen->GetMonitorRect(i,&mx,&my,&mw,&mh);
239 if (
240 (!found && i==0) || (
241 mx<HomeX+HomeWidth && mx+mw>HomeX &&
242 my<HomeY+HomeHeight && my+mh>HomeY
243 )
244 ) {
245 if (!found) {
246 x=mx;
247 y=my;
248 w=mw;
249 h=mh;
250 found=true;
251 }
252 else {
253 if (x>mx) { w+=x-mx; x=mx; }
254 if (w<mx+mw-x) w=mx+mw-x;
255 if (y>my) { h+=y-my; y=my; }
256 if (h<my+mh-y) h=my+mh-y;
257 }
258 }
259 }
260 if (found) {
261 // This is just for that the users sees more than
262 // nothing even when the monitor rectangles are
263 // completely wrong.
264 cx=HomeX+HomeWidth*0.5;
265 cy=HomeY+HomeHeight*0.5;
266 if (x>cx) { w+=x-cx; x=cx; }
267 if (w<cx-x) w=cx-x;
268 if (y>cy) { h+=y-cy; y=cy; }
269 if (h<cy-y) h=cy-y;
270 }
271 }
272 if (pX) *pX=x;
273 if (pY) *pY=y;
274 if (pW) *pW=w;
275 if (pH) *pH=h;
276 }
277
278
SetActivePanel(emPanel * panel,bool adherent)279 void emView::SetActivePanel(emPanel * panel, bool adherent)
280 {
281 emPanel::NoticeFlags flags;
282 emPanel * p;
283
284 if (!panel) return;
285
286 while (!panel->Focusable) panel=panel->Parent;
287
288 if (ActivePanel!=panel) {
289 if (emIsDLogEnabled()) {
290 emDLog("emView %p: Active=\"%s\"",(const void*)this,panel->GetIdentity().Get());
291 }
292 if (ActivePanel) InvalidateHighlight();
293 flags=emPanel::NF_ACTIVE_CHANGED;
294 if (Focused) flags|=emPanel::NF_FOCUS_CHANGED;
295 if (ActivePanel) {
296 p=ActivePanel;
297 p->Active=0;
298 do {
299 p->InActivePath=0;
300 p->AddPendingNotice(flags);
301 p=p->Parent;
302 } while (p);
303 }
304 p=panel;
305 p->Active=1;
306 do {
307 p->InActivePath=1;
308 p->AddPendingNotice(flags);
309 p=p->Parent;
310 } while (p);
311 ActivePanel=panel;
312 ActivationAdherent=adherent;
313 InvalidateHighlight();
314 TitleInvalid=true;
315 UpdateEngine->WakeUp();
316 Signal(ControlPanelSignal);
317 }
318 else if (ActivationAdherent!=adherent) {
319 ActivationAdherent=adherent;
320 InvalidateHighlight();
321 }
322 }
323
324
SetActivePanelBestPossible()325 void emView::SetActivePanelBestPossible()
326 {
327 emPanel * best, * p;
328 double cx,cy,cw,ch,ex,ey,ew,eh,minW,minH,minA;
329 bool adherent;
330
331 cx=CurrentX;
332 cy=CurrentY;
333 cw=CurrentWidth;
334 ch=CurrentHeight;
335 if (PopupWindow) {
336 GetMaxPopupViewRect(&ex,&ey,&ew,&eh);
337 if (ex<cx) { ew-=cx-ex; ex=cx; }
338 if (ey<cy) { eh-=cy-ey; ey=cy; }
339 if (ew>cx+cw-ex) { ew=cx+cw-ex; }
340 if (eh>cy+ch-ey) { eh=cy+ch-ey; }
341 if (ew>=10.0 && eh>=10.0) {
342 cx=ex; cy=ey;
343 cw=ew; ch=eh;
344 }
345 }
346 minW=cw*0.99;
347 minH=ch*0.99;
348 minA=cw*ch*0.33;
349 cx+=cw*0.5;
350 cy+=ch*0.5;
351 best=SupremeViewedPanel;
352 if (!best) {
353 return;
354 }
355 for (;;) {
356 p=best->GetFocusableLastChild();
357 if (!p) break;
358 do {
359 if (
360 p->Viewed &&
361 p->ClipX1<=cx && p->ClipX2>cx &&
362 p->ClipY1<=cy && p->ClipY2>cy
363 ) break;
364 p=p->GetFocusablePrev();
365 } while(p);
366 if (!p) break;
367 if (
368 p->ClipX2-p->ClipX1<minW &&
369 p->ClipY2-p->ClipY1<minH &&
370 (p->ClipX2-p->ClipX1)*(p->ClipY2-p->ClipY1)<minA
371 ) break;
372 best=p;
373 }
374
375 while (!best->Focusable) best=best->Parent;
376
377 adherent=false;
378 if (
379 ActivationAdherent &&
380 ActivePanel &&
381 ActivePanel->Viewed &&
382 ActivePanel->ViewedWidth>=4 &&
383 ActivePanel->ViewedHeight>=4 &&
384 best->InActivePath
385 ) {
386 best=ActivePanel;
387 adherent=true;
388 }
389
390 SetActivePanel(best,adherent);
391 }
392
393
GetPanelByIdentity(const char * identity) const394 emPanel * emView::GetPanelByIdentity(const char * identity) const
395 {
396 emArray<emString> a;
397 emPanel * p;
398 int i;
399
400 p=RootPanel;
401 if (p) {
402 a=emPanel::DecodeIdentity(identity);
403 if (a.GetCount() && a[0]==p->GetName()) {
404 for (i=1; ; i++) {
405 if (i>=a.GetCount()) return p;
406 p=p->GetChild(a[i]);
407 if (!p) break;
408 }
409 }
410 }
411 return NULL;
412 }
413
414
GetPanelAt(double x,double y) const415 emPanel * emView::GetPanelAt(double x, double y) const
416 {
417 emPanel * p, * c;
418
419 p=SupremeViewedPanel;
420 if (p && p->ClipX1<=x && p->ClipX2>x && p->ClipY1<=y && p->ClipY2>y) {
421 c=p->GetLastChild();
422 while (c) {
423 if (c->Viewed && c->ClipX1<=x && c->ClipX2>x && c->ClipY1<=y &&
424 c->ClipY2>y) {
425 p=c;
426 c=p->GetLastChild();
427 }
428 else {
429 c=c->GetPrev();
430 }
431 }
432 return p;
433 }
434 else {
435 return NULL;
436 }
437 }
438
439
GetFocusablePanelAt(double x,double y,bool checkSubstance) const440 emPanel * emView::GetFocusablePanelAt(double x, double y, bool checkSubstance) const
441 {
442 emPanel * p, * c;
443
444 p=SupremeViewedPanel;
445 if (
446 p && p->ClipX1<=x && p->ClipX2>x && p->ClipY1<=y && p->ClipY2>y && (
447 !checkSubstance ||
448 p->IsPointInSubstanceRect(p->ViewToPanelX(x),p->ViewToPanelY(y))
449 )
450 ) {
451 c=p->GetFocusableLastChild();
452 while (c) {
453 if (
454 c->Viewed &&
455 c->ClipX1<=x && c->ClipX2>x && c->ClipY1<=y && c->ClipY2>y && (
456 !checkSubstance ||
457 c->IsPointInSubstanceRect(c->ViewToPanelX(x),c->ViewToPanelY(y))
458 )
459 ) {
460 p=c;
461 c=p->GetFocusableLastChild();
462 }
463 else {
464 c=c->GetFocusablePrev();
465 }
466 }
467 if (!p->IsFocusable()) p=p->GetFocusableParent();
468 return p;
469 }
470 else {
471 return NULL;
472 }
473 }
474
475
GetVisitedPanel(double * pRelX,double * pRelY,double * pRelA) const476 emPanel * emView::GetVisitedPanel(
477 double * pRelX, double * pRelY, double * pRelA
478 ) const
479 {
480 emPanel * p;
481
482 p=ActivePanel;
483 while (p && !p->InViewedPath) p=p->Parent;
484 if (!p || !p->Viewed) p=SupremeViewedPanel;
485
486 if (p) {
487 if (pRelX) *pRelX=(HomeX+HomeWidth*0.5-p->ViewedX)/p->ViewedWidth-0.5;
488 if (pRelY) *pRelY=(HomeY+HomeHeight*0.5-p->ViewedY)/p->ViewedHeight-0.5;
489 if (pRelA) *pRelA=(HomeWidth*HomeHeight)/(p->ViewedWidth*p->ViewedHeight);
490 }
491 else {
492 if (pRelX) *pRelX=0.0;
493 if (pRelY) *pRelY=0.0;
494 if (pRelA) *pRelA=0.0;
495 }
496 return p;
497 }
498
499
Visit(emPanel * panel,double relX,double relY,double relA,bool adherent)500 void emView::Visit(
501 emPanel * panel, double relX, double relY, double relA, bool adherent
502 )
503 {
504 Visit(panel->GetIdentity(), relX, relY, relA, adherent, panel->GetTitle());
505 }
506
507
Visit(const char * identity,double relX,double relY,double relA,bool adherent,const char * subject)508 void emView::Visit(
509 const char * identity, double relX, double relY, double relA,
510 bool adherent, const char * subject
511 )
512 {
513 VisitingVA->SetAnimParamsByCoreConfig(*CoreConfig);
514 VisitingVA->SetGoal(identity, relX, relY, relA, adherent, subject);
515 VisitingVA->Activate();
516 }
517
518
Visit(emPanel * panel,bool adherent)519 void emView::Visit(emPanel * panel, bool adherent)
520 {
521 Visit(panel->GetIdentity(), adherent, panel->GetTitle());
522 }
523
524
Visit(const char * identity,bool adherent,const char * subject)525 void emView::Visit(const char * identity, bool adherent, const char * subject)
526 {
527 VisitingVA->SetAnimParamsByCoreConfig(*CoreConfig);
528 VisitingVA->SetGoal(identity, adherent, subject);
529 VisitingVA->Activate();
530 }
531
532
VisitFullsized(emPanel * panel,bool adherent,bool utilizeView)533 void emView::VisitFullsized(emPanel * panel, bool adherent, bool utilizeView)
534 {
535 VisitFullsized(panel->GetIdentity(), adherent, utilizeView, panel->GetTitle());
536 }
537
538
VisitFullsized(const char * identity,bool adherent,bool utilizeView,const char * subject)539 void emView::VisitFullsized(
540 const char * identity, bool adherent, bool utilizeView,
541 const char * subject
542 )
543 {
544 VisitingVA->SetAnimParamsByCoreConfig(*CoreConfig);
545 VisitingVA->SetGoalFullsized(identity, adherent, utilizeView, subject);
546 VisitingVA->Activate();
547 }
548
549
RawVisit(emPanel * panel,double relX,double relY,double relA)550 void emView::RawVisit(emPanel * panel, double relX, double relY, double relA)
551 {
552 RawVisit(panel,relX,relY,relA,false);
553 }
554
555
RawVisit(emPanel * panel)556 void emView::RawVisit(emPanel * panel)
557 {
558 double relX,relY,relA;
559
560 if (!panel) return;
561 CalcVisitCoords(panel,&relX,&relY,&relA);
562 RawVisit(panel,relX,relY,relA);
563 }
564
565
RawVisitFullsized(emPanel * panel,bool utilizeView)566 void emView::RawVisitFullsized(emPanel * panel, bool utilizeView)
567 {
568 RawVisit(panel,0.0,0.0,utilizeView?-1.0:0.0);
569 }
570
571
VisitNext()572 void emView::VisitNext()
573 {
574 emPanel * p;
575
576 p=ActivePanel;
577 if (p) {
578 p=p->GetFocusableNext();
579 if (!p) {
580 p=ActivePanel->GetFocusableParent();
581 if (!p) p=RootPanel;
582 if (p!=ActivePanel) p=p->GetFocusableFirstChild();
583 }
584 Visit(p,true);
585 }
586 }
587
588
VisitPrev()589 void emView::VisitPrev()
590 {
591 emPanel * p;
592
593 p=ActivePanel;
594 if (p) {
595 p=p->GetFocusablePrev();
596 if (!p) {
597 p=ActivePanel->GetFocusableParent();
598 if (!p) p=RootPanel;
599 if (p!=ActivePanel) p=p->GetFocusableLastChild();
600 }
601 Visit(p,true);
602 }
603 }
604
605
VisitFirst()606 void emView::VisitFirst()
607 {
608 emPanel * p;
609
610 if (ActivePanel) {
611 p=ActivePanel->GetFocusableParent();
612 if (p) p=p->GetFocusableFirstChild();
613 if (!p) p=ActivePanel;
614 Visit(p,true);
615 }
616 }
617
618
VisitLast()619 void emView::VisitLast()
620 {
621 emPanel * p;
622
623 if (ActivePanel) {
624 p=ActivePanel->GetFocusableParent();
625 if (p) p=p->GetFocusableLastChild();
626 if (!p) p=ActivePanel;
627 Visit(p,true);
628 }
629 }
630
631
VisitLeft()632 void emView::VisitLeft()
633 {
634 VisitNeighbour(2);
635 }
636
637
VisitRight()638 void emView::VisitRight()
639 {
640 VisitNeighbour(0);
641 }
642
643
VisitUp()644 void emView::VisitUp()
645 {
646 VisitNeighbour(3);
647 }
648
649
VisitDown()650 void emView::VisitDown()
651 {
652 VisitNeighbour(1);
653 }
654
655
VisitNeighbour(int direction)656 void emView::VisitNeighbour(int direction)
657 {
658 emPanel * p, * n, * current, * parent, * best;
659 double cx1,cy1,cx2,cy2,nx1,ny1,nx2,ny2,dx,dy,d,e,fx,fy,f,bestVal,val,defdx;
660
661 direction&=3;
662 current=ActivePanel;
663 if (!current) return;
664 parent=current->GetFocusableParent();
665 if (!parent) parent=RootPanel;
666 if (parent!=current) {
667 cx1=0; cy1=0; cx2=1.0; cy2=current->GetHeight();
668 for (p=current; p!=parent; p=p->GetParent()) {
669 f=p->GetLayoutWidth();
670 fx=p->GetLayoutX();
671 fy=p->GetLayoutY();
672 cx1=cx1*f+fx;
673 cy1=cy1*f+fy;
674 cx2=cx2*f+fx;
675 cy2=cy2*f+fy;
676 }
677 best=NULL;
678 bestVal=0.0;
679 defdx=-1.0;
680 for (n=parent->GetFocusableFirstChild(); n; n=n->GetFocusableNext()) {
681 if (n==current) { defdx=-defdx; continue; }
682 nx1=0; ny1=0; nx2=1.0; ny2=n->GetHeight();
683 for (p=n; p!=parent; p=p->GetParent()) {
684 f=p->GetLayoutWidth();
685 fx=p->GetLayoutX();
686 fy=p->GetLayoutY();
687 nx1=nx1*f+fx;
688 ny1=ny1*f+fy;
689 nx2=nx2*f+fx;
690 ny2=ny2*f+fy;
691 }
692 dx=0.0;
693 dy=0.0;
694 fx=nx1-cx1;
695 fy=ny1-cy1;
696 f=sqrt(fx*fx+fy*fy);
697 if (f>1E-30) { dx+=fx/f; dy+=fy/f; }
698 fx=nx2-cx2;
699 fy=ny1-cy1;
700 f=sqrt(fx*fx+fy*fy);
701 if (f>1E-30) { dx+=fx/f; dy+=fy/f; }
702 fx=nx1-cx1;
703 fy=ny2-cy2;
704 f=sqrt(fx*fx+fy*fy);
705 if (f>1E-30) { dx+=fx/f; dy+=fy/f; }
706 fx=nx2-cx2;
707 fy=ny2-cy2;
708 f=sqrt(fx*fx+fy*fy);
709 if (f>1E-30) { dx+=fx/f; dy+=fy/f; }
710 f=sqrt(dx*dx+dy*dy);
711 if (f>1E-30) { dx/=f; dy/=f; }
712 else { dx=defdx; dy=0.0; }
713 fx=(nx1+nx2-cx1-cx2)*0.5;
714 fy=(ny1+ny2-cy1-cy2)*0.5;
715 d=sqrt(fx*fx+fy*fy);
716 if (nx2<cx1) fx=nx2-cx1;
717 else if (nx1>cx2) fx=nx1-cx2;
718 else fx=0.0;
719 if (ny2<cy1) fy=ny2-cy1;
720 else if (ny1>cy2) fy=ny1-cy2;
721 else fy=0.0;
722 e=sqrt(fx*fx+fy*fy);
723 if ((direction&1)!=0) {
724 f=dx;
725 dx=dy;
726 dy=-f;
727 }
728 if ((direction&2)!=0) {
729 dx=-dx;
730 dy=-dy;
731 }
732 if (dx<=1E-12) continue;
733 val=(e*10+d)*(1+2*dy*dy);
734 if (fabs(dy)>0.707) val*=1000*dy*dy*dy*dy;
735 if (!best || val<bestVal) {
736 best=n;
737 bestVal=val;
738 }
739 }
740 if (best) current=best;
741 }
742 Visit(current,true);
743 }
744
745
VisitIn()746 void emView::VisitIn()
747 {
748 emPanel * p;
749
750 if (!ActivePanel) return;
751 p=ActivePanel->GetFocusableFirstChild();
752 if (p) Visit(p,true);
753 else VisitFullsized(ActivePanel,true);
754 }
755
756
VisitOut()757 void emView::VisitOut()
758 {
759 double relA,relA2;
760 emPanel * p;
761
762 if (!ActivePanel) return;
763 p=ActivePanel->GetFocusableParent();
764 if (p) Visit(p,true);
765 else if (RootPanel) {
766 relA=HomeWidth*RootPanel->GetHeight()/HomePixelTallness/HomeHeight;
767 relA2=HomeHeight/RootPanel->GetHeight()*HomePixelTallness/HomeWidth;
768 if (relA<relA2) relA=relA2;
769 Visit(RootPanel,0.0,0.0,relA,true);
770 }
771 }
772
773
Scroll(double deltaX,double deltaY)774 void emView::Scroll(double deltaX, double deltaY)
775 {
776 double rx,ry,ra;
777 emPanel * p;
778
779 AbortActiveAnimator();
780 if (deltaX!=0.0 || deltaY!=0.0) {
781 p=GetVisitedPanel(&rx,&ry,&ra);
782 if (p) {
783 rx+=deltaX/p->ViewedWidth;
784 ry+=deltaY/p->ViewedHeight;
785 RawVisit(p,rx,ry,ra,true);
786 }
787 }
788 SetActivePanelBestPossible();
789 }
790
791
Zoom(double fixX,double fixY,double factor)792 void emView::Zoom(double fixX, double fixY, double factor)
793 {
794 double rx,ry,ra,reFac;
795 emPanel * p;
796
797 AbortActiveAnimator();
798 if (factor!=1.0 && factor>0.0) {
799 p=GetVisitedPanel(&rx,&ry,&ra);
800 if (p) {
801 reFac=1.0/factor;
802 rx+=(fixX-(HomeX+HomeWidth*0.5))*(1.0-reFac)/p->ViewedWidth;
803 ry+=(fixY-(HomeY+HomeHeight*0.5))*(1.0-reFac)/p->ViewedHeight;
804 ra*=reFac*reFac;
805 RawVisit(p,rx,ry,ra,true);
806 }
807 }
808 SetActivePanelBestPossible();
809 }
810
811
RawScrollAndZoom(double fixX,double fixY,double deltaX,double deltaY,double deltaZ,emPanel * panel,double * pDeltaXDone,double * pDeltaYDone,double * pDeltaZDone)812 void emView::RawScrollAndZoom(
813 double fixX, double fixY,
814 double deltaX, double deltaY, double deltaZ,
815 emPanel * panel, double * pDeltaXDone,
816 double * pDeltaYDone, double * pDeltaZDone
817 )
818 {
819 double zflpp,hx,hy,hw,hh,hmx,hmy,pvx,pvy,pvw,pvh;
820 double rx,ry,ra,rx2,ry2,ra2,reFac;
821
822 zflpp=GetZoomFactorLogarithmPerPixel();
823
824 hx=GetHomeX();
825 hy=GetHomeY();
826 hw=GetHomeWidth();
827 hh=GetHomeHeight();
828 hmx=hx+hw*0.5;
829 hmy=hy+hh*0.5;
830
831 if (panel && panel->IsViewed()) {
832 pvx=panel->GetViewedX();
833 pvy=panel->GetViewedY();
834 pvw=panel->GetViewedWidth();
835 pvh=panel->GetViewedHeight();
836 rx = (hmx-pvx) / pvw - 0.5;
837 ry = (hmy-pvy) / pvh - 0.5;
838 ra = (hw*hh) / (pvw*pvh);
839 }
840 else {
841 panel = GetVisitedPanel(&rx,&ry,&ra);
842 if (!panel) {
843 if (pDeltaXDone) *pDeltaXDone=0.0;
844 if (pDeltaYDone) *pDeltaYDone=0.0;
845 if (pDeltaZDone) *pDeltaZDone=0.0;
846 return;
847 }
848 pvw=panel->GetViewedWidth();
849 pvh=panel->GetViewedHeight();
850 }
851
852 reFac=exp(-deltaZ*zflpp);
853 rx2 = rx + ((fixX-hmx)*(1.0-reFac) + deltaX)/pvw;
854 ry2 = ry + ((fixY-hmy)*(1.0-reFac) + deltaY)/pvh;
855 ra2 = ra * reFac*reFac;
856
857 RawVisit(panel,rx2,ry2,ra2);
858
859 if (panel->IsViewed()) {
860 pvx=panel->GetViewedX();
861 pvy=panel->GetViewedY();
862 pvw=panel->GetViewedWidth();
863 pvh=panel->GetViewedHeight();
864
865 rx2 = (hmx-pvx) / pvw - 0.5;
866 ry2 = (hmy-pvy) / pvh - 0.5;
867 ra2 = (hw*hh) / (pvw*pvh);
868 reFac = sqrt(ra2/ra);
869
870 if (pDeltaXDone) {
871 *pDeltaXDone = (rx2-rx)*pvw*reFac - (fixX-hmx)*(1.0-reFac);
872 }
873 if (pDeltaYDone) {
874 *pDeltaYDone = (ry2-ry)*pvh*reFac - (fixY-hmy)*(1.0-reFac);
875 }
876 if (pDeltaZDone) {
877 *pDeltaZDone = -log(reFac)/zflpp;
878 }
879 }
880 else {
881 if (pDeltaXDone) *pDeltaXDone = deltaX;
882 if (pDeltaYDone) *pDeltaYDone = deltaY;
883 if (pDeltaZDone) *pDeltaZDone = deltaZ;
884 }
885 }
886
887
GetZoomFactorLogarithmPerPixel() const888 double emView::GetZoomFactorLogarithmPerPixel() const
889 {
890 double w,h,r;
891
892 if ((GetViewFlags()&emView::VF_POPUP_ZOOM)!=0) {
893 GetMaxPopupViewRect(NULL,NULL,&w,&h);
894 }
895 else {
896 w=GetCurrentWidth();
897 h=GetCurrentHeight();
898 }
899 r=(w+h)*0.25;
900 if (r<1.0) r=1.0;
901 return 1.33/r;
902 }
903
904
ZoomOut()905 void emView::ZoomOut()
906 {
907 AbortActiveAnimator();
908 RawZoomOut();
909 SetActivePanelBestPossible();
910 }
911
912
RawZoomOut()913 void emView::RawZoomOut()
914 {
915 RawZoomOut(false);
916 }
917
918
IsZoomedOut() const919 bool emView::IsZoomedOut() const
920 {
921 double x,y,w,h;
922 const emPanel * p;
923
924 if (SettingGeometry) return ZoomedOutBeforeSG;
925 if (VFlags&VF_POPUP_ZOOM) return PopupWindow==NULL;
926 p=SupremeViewedPanel;
927 if (!p) return true;
928 x=(HomeX-p->ViewedX)/p->ViewedWidth;
929 y=(HomeY-p->ViewedY)*HomePixelTallness/p->ViewedWidth;
930 w=HomeWidth/p->ViewedWidth;
931 h=HomeHeight*HomePixelTallness/p->ViewedWidth;
932 while (p->Parent) {
933 x=p->LayoutX+x*p->LayoutWidth;
934 y=p->LayoutY+y*p->LayoutWidth;
935 w*=p->LayoutWidth;
936 h*=p->LayoutWidth;
937 p=p->Parent;
938 }
939 return
940 x<=0.001 &&
941 y<=0.001 &&
942 x+w>=1.0-0.001 &&
943 y+h>=p->GetHeight()-0.001
944 ;
945 }
946
947
SignalEOIDelayed()948 void emView::SignalEOIDelayed()
949 {
950 if (!EOIEngine) EOIEngine=new EOIEngineClass(*this);
951 }
952
953
GetTouchEventPriority(double touchX,double touchY,bool afterVIFs) const954 double emView::GetTouchEventPriority(
955 double touchX, double touchY, bool afterVIFs
956 ) const
957 {
958 emPanel * p;
959 double pri,t;
960
961 if (!afterVIFs && FirstVIF) {
962 return FirstVIF->GetTouchEventPriority(touchX,touchY);
963 }
964 pri=-1E30;
965 p=RootPanel;
966 if (p) {
967 for (;;) {
968 if (
969 p->InViewedPath && (
970 !p->Viewed || (
971 p->ClipX1<=touchX &&
972 p->ClipY1<=touchY &&
973 p->ClipX2>touchX &&
974 p->ClipY2>touchY
975 )
976 )
977 ) {
978 t=p->GetTouchEventPriority(touchX,touchY);
979 if (pri<t) pri=t;
980 }
981 if (p->FirstChild) p=p->FirstChild;
982 else if (p->Next) p=p->Next;
983 else {
984 do {
985 p=p->Parent;
986 } while (p && !p->Next);
987 if (!p) break;
988 p=p->Next;
989 }
990 }
991 }
992 return pri;
993 }
994
995
ActivateMagneticViewAnimator()996 void emView::ActivateMagneticViewAnimator()
997 {
998 if (MagneticVA) MagneticVA->Activate();
999 }
1000
1001
AbortActiveAnimator()1002 void emView::AbortActiveAnimator()
1003 {
1004 if (ActiveAnimator) ActiveAnimator->Deactivate();
1005 }
1006
1007
Input(emInputEvent & event,const emInputState & state)1008 void emView::Input(emInputEvent & event, const emInputState & state)
1009 {
1010 emPanel * p;
1011
1012 if (ActiveAnimator) ActiveAnimator->Input(event,state);
1013
1014 if (
1015 fabs(state.GetMouseX()-LastMouseX)>0.1 ||
1016 fabs(state.GetMouseY()-LastMouseY)>0.1
1017 ) {
1018 LastMouseX=state.GetMouseX();
1019 LastMouseY=state.GetMouseY();
1020 CursorInvalid=true;
1021 UpdateEngine->WakeUp();
1022 }
1023
1024 p=RootPanel;
1025 if (p) {
1026 for (;;) {
1027 p->PendingInput=true;
1028 if (p->FirstChild) p=p->FirstChild;
1029 else if (p->Next) p=p->Next;
1030 else {
1031 do {
1032 p=p->Parent;
1033 } while (p && !p->Next);
1034 if (!p) break;
1035 p=p->Next;
1036 }
1037 }
1038 }
1039
1040 do {
1041 RestartInputRecursion=false;
1042 RecurseInput(event,state);
1043 if (RestartInputRecursion) {
1044 emDLog("emView %p: Restarting input recursion.",(const void*)this);
1045 }
1046 } while (RestartInputRecursion);
1047 }
1048
1049
GetCursor() const1050 emCursor emView::GetCursor() const
1051 {
1052 return Cursor;
1053 }
1054
1055
Paint(const emPainter & painter,emColor canvasColor) const1056 void emView::Paint(const emPainter & painter, emColor canvasColor) const
1057 {
1058 emColor ncc;
1059 emPainter pnt;
1060 const emPanel * p;
1061 double rx1,ry1,rx2,ry2,ox,oy,cx1,cy1,cx2,cy2;
1062 bool wasNotInUserSpace;
1063
1064 if (painter.GetScaleX()!=1.0 || painter.GetScaleY()!=1.0) {
1065 emFatalError("emView::Paint: Scaling not possible.");
1066 }
1067
1068 wasNotInUserSpace=painter.EnterUserSpace();
1069
1070 if (!SupremeViewedPanel) {
1071 painter.Clear(BackgroundColor,canvasColor);
1072 }
1073 else {
1074 ox=painter.GetOriginX();
1075 oy=painter.GetOriginY();
1076 rx1=painter.GetClipX1()-ox;
1077 ry1=painter.GetClipY1()-oy;
1078 rx2=painter.GetClipX2()-ox;
1079 ry2=painter.GetClipY2()-oy;
1080 p=SupremeViewedPanel;
1081 if (
1082 !p->IsOpaque() ||
1083 p->ViewedX >rx1 ||
1084 p->ViewedX+p->ViewedWidth <rx2 ||
1085 p->ViewedY >ry1 ||
1086 p->ViewedY+p->ViewedHeight<ry2
1087 ) {
1088 ncc=p->CanvasColor;
1089 if (!ncc.IsOpaque()) ncc=BackgroundColor;
1090 painter.Clear(ncc,canvasColor);
1091 canvasColor=ncc;
1092 }
1093 cx1=p->ClipX1; if (cx1<rx1) cx1=rx1;
1094 cx2=p->ClipX2; if (cx2>rx2) cx2=rx2;
1095 cy1=p->ClipY1; if (cy1<ry1) cy1=ry1;
1096 cy2=p->ClipY2; if (cy2>ry2) cy2=ry2;
1097 if (cx1<cx2 && cy1<cy2) {
1098 pnt=painter;
1099 pnt.SetClipping(cx1+ox,cy1+oy,cx2+ox,cy2+oy);
1100 pnt.SetTransformation(
1101 p->ViewedX+ox,
1102 p->ViewedY+oy,
1103 p->ViewedWidth,
1104 p->ViewedWidth/CurrentPixelTallness
1105 );
1106 p->Paint(pnt,canvasColor);
1107 painter.LeaveUserSpace();
1108 p=p->FirstChild;
1109 if (p) {
1110 for (;;) {
1111 if (p->Viewed) {
1112 cx1=p->ClipX1; if (cx1<rx1) cx1=rx1;
1113 cx2=p->ClipX2; if (cx2>rx2) cx2=rx2;
1114 if (cx1<cx2) {
1115 cy1=p->ClipY1; if (cy1<ry1) cy1=ry1;
1116 cy2=p->ClipY2; if (cy2>ry2) cy2=ry2;
1117 if (cy1<cy2) {
1118 pnt.SetClipping(cx1+ox,cy1+oy,cx2+ox,cy2+oy);
1119 pnt.SetTransformation(
1120 p->ViewedX+ox,
1121 p->ViewedY+oy,
1122 p->ViewedWidth,
1123 p->ViewedWidth/CurrentPixelTallness
1124 );
1125 painter.EnterUserSpace();
1126 p->Paint(pnt,p->CanvasColor);
1127 painter.LeaveUserSpace();
1128 if (p->FirstChild) {
1129 p=p->FirstChild;
1130 continue;
1131 }
1132 }
1133 }
1134 }
1135 if (p->Next) p=p->Next;
1136 else {
1137 do {
1138 p=p->Parent;
1139 } while (p!=SupremeViewedPanel && !p->Next);
1140 if (p==SupremeViewedPanel) break;
1141 p=p->Next;
1142 }
1143 }
1144 }
1145 painter.EnterUserSpace();
1146 }
1147 PaintHighlight(painter);
1148 }
1149
1150 if (ActiveAnimator) ActiveAnimator->Paint(painter);
1151 if (StressTest) StressTest->PaintInfo(painter);
1152
1153 if (wasNotInUserSpace) painter.LeaveUserSpace();
1154 }
1155
1156
InvalidateTitle()1157 void emView::InvalidateTitle()
1158 {
1159 Signal(TitleSignal);
1160 }
1161
1162
DoCustomCheat(const char * func)1163 void emView::DoCustomCheat(const char * func)
1164 {
1165 emContext * c;
1166 emView * v;
1167
1168 for (c=GetParentContext(); c; c=c->GetParentContext()) {
1169 v=dynamic_cast<emView*>(c);
1170 if (v) {
1171 v->DoCustomCheat(func);
1172 break;
1173 }
1174 }
1175 }
1176
1177
GetTitle()1178 emString emView::GetTitle()
1179 {
1180 return ((const emView*)this)->GetTitle();
1181 }
1182
1183
GetTouchEventPriority(double touchX,double touchY,bool afterVIFs)1184 double emView::GetTouchEventPriority(
1185 double touchX, double touchY, bool afterVIFs
1186 )
1187 {
1188 return ((const emView*)this)->GetTouchEventPriority(touchX,touchY,afterVIFs);
1189 }
1190
1191
GetCursor()1192 emCursor emView::GetCursor()
1193 {
1194 return ((const emView*)this)->GetCursor();
1195 }
1196
1197
Paint(const emPainter & painter,emColor canvasColor)1198 void emView::Paint(const emPainter & painter, emColor canvasColor)
1199 {
1200 ((const emView*)this)->Paint(painter,canvasColor);
1201 }
1202
1203
SetWindowAndScreen(emWindow * window)1204 void emView::SetWindowAndScreen(emWindow * window)
1205 {
1206 // Called by the constructors of emView and emWindow.
1207 Window=window;
1208 if (window) ScreenRef=&window->GetScreen();
1209 else ScreenRef=emScreen::LookupInherited(*this);
1210 }
1211
1212
SetFocused(bool focused)1213 void emView::SetFocused(bool focused)
1214 {
1215 emPanel * p;
1216 emPanel::NoticeFlags flags;
1217
1218 if (Focused==focused) return;
1219 if (Focused) InvalidateHighlight();
1220 Focused=focused;
1221 if (Focused) InvalidateHighlight();
1222 Signal(FocusSignal);
1223 p=RootPanel;
1224 if (p) {
1225 for (;;) {
1226 flags=
1227 emPanel::NF_VIEW_FOCUS_CHANGED |
1228 emPanel::NF_UPDATE_PRIORITY_CHANGED
1229 ;
1230 if (p->InActivePath) flags|=emPanel::NF_FOCUS_CHANGED;
1231 p->AddPendingNotice(flags);
1232 if (p->FirstChild) p=p->FirstChild;
1233 else if (p->Next) p=p->Next;
1234 else {
1235 do {
1236 p=p->Parent;
1237 } while (p && !p->Next);
1238 if (!p) break;
1239 p=p->Next;
1240 }
1241 }
1242 }
1243 }
1244
1245
SetGeometry(double x,double y,double width,double height,double pixelTallness)1246 void emView::SetGeometry(
1247 double x, double y, double width, double height, double pixelTallness
1248 )
1249 {
1250 double rx,ry,ra;
1251 emPanel * p;
1252
1253 if (width<0.0001) width=0.0001;
1254 if (height<0.0001) height=0.0001;
1255 if (pixelTallness<0.0001) pixelTallness=0.0001;
1256 if (
1257 CurrentX==x && CurrentY==y &&
1258 CurrentWidth==width && CurrentHeight==height &&
1259 CurrentPixelTallness==pixelTallness
1260 ) return;
1261
1262 ZoomedOutBeforeSG=IsZoomedOut();
1263 SettingGeometry++;
1264 p=GetVisitedPanel(&rx,&ry,&ra);
1265 CurrentViewPort->HomeView->HomeX=x;
1266 CurrentViewPort->HomeView->HomeY=y;
1267 CurrentViewPort->HomeView->HomeWidth=width;
1268 CurrentViewPort->HomeView->HomeHeight=height;
1269 CurrentViewPort->HomeView->HomePixelTallness=pixelTallness;
1270 CurrentX=x;
1271 CurrentY=y;
1272 CurrentWidth=width;
1273 CurrentHeight=height;
1274 CurrentPixelTallness=pixelTallness;
1275 CurrentViewPort->HomeView->Signal(GeometrySignal);
1276 Signal(GeometrySignal);
1277 if ((VFlags&VF_ROOT_SAME_TALLNESS)!=0 && RootPanel) {
1278 RootPanel->Layout(0,0,1,GetHomeTallness());
1279 }
1280 if (ZoomedOutBeforeSG) {
1281 RawZoomOut(true);
1282 }
1283 else if (p) {
1284 RawVisit(p,rx,ry,ra,true);
1285 }
1286 SettingGeometry--;
1287 }
1288
1289
AddToNoticeList(PanelRingNode * node)1290 void emView::AddToNoticeList(PanelRingNode * node)
1291 {
1292 node->Next=&NoticeList;
1293 node->Prev=NoticeList.Prev;
1294 node->Prev->Next=node;
1295 NoticeList.Prev=node;
1296 UpdateEngine->WakeUp();
1297 }
1298
1299
Update()1300 void emView::Update()
1301 {
1302 PanelRingNode * n;
1303 emPanel * p;
1304 emString tmp;
1305 emCursor cur;
1306
1307 if (PopupWindow && IsSignaled(PopupWindow->GetCloseSignal())) {
1308 GotPopupWindowCloseSignal=true;
1309 ZoomOut();
1310 }
1311
1312 for (;;) {
1313 n=NoticeList.Next;
1314 if (n!=&NoticeList) {
1315 do {
1316 NoticeList.Next=n->Next;
1317 NoticeList.Next->Prev=&NoticeList;
1318 n->Prev=NULL;
1319 n->Next=NULL;
1320 p=(emPanel*)(((char*)n)-offsetof(emPanel,NoticeNode));
1321 p->HandleNotice();
1322 n=NoticeList.Next;
1323 } while (n!=&NoticeList);
1324 }
1325 else if (SVPChoiceByOpacityInvalid) {
1326 SVPChoiceByOpacityInvalid=false;
1327 if (!SVPChoiceInvalid && MinSVP!=MaxSVP) {
1328 for (p=MinSVP; p!=MaxSVP; p=p->Parent) {
1329 if (
1330 p->CanvasColor.IsOpaque() ||
1331 ((const emPanel*)p)->IsOpaque()
1332 ) break;
1333 }
1334 if (SupremeViewedPanel!=p) {
1335 emDLog("emView %p: SVP choice invalid by opacity.",(const void*)this);
1336 SVPChoiceInvalid=true;
1337 }
1338 }
1339 }
1340 else if (SVPChoiceInvalid) {
1341 SVPChoiceInvalid=false;
1342 p=GetVisitedPanel();
1343 if (p) {
1344 RawVisitAbs(
1345 p,
1346 p->ViewedX,
1347 p->ViewedY,
1348 p->ViewedWidth,
1349 false
1350 );
1351 }
1352 }
1353 else if (TitleInvalid) {
1354 TitleInvalid=false;
1355 if (ActivePanel) tmp=ActivePanel->GetTitle();
1356 else tmp="";
1357 if (Title!=tmp) {
1358 Title=tmp;
1359 InvalidateTitle();
1360 }
1361 }
1362 else if (CursorInvalid) {
1363 CursorInvalid=false;
1364 p=GetPanelAt(LastMouseX,LastMouseY);
1365 if (p) cur=p->GetCursor();
1366 else cur=emCursor::NORMAL;
1367 if ((VFlags&VF_EGO_MODE)!=0) {
1368 if (cur==emCursor::NORMAL) cur=emCursor::CROSSHAIR;
1369 }
1370 if (Cursor!=cur) {
1371 Cursor=cur;
1372 InvalidateCursor();
1373 }
1374 }
1375 else {
1376 break;
1377 }
1378 }
1379 }
1380
1381
CalcVisitCoords(const emPanel * panel,double * pRelX,double * pRelY,double * pRelA) const1382 void emView::CalcVisitCoords(
1383 const emPanel * panel, double * pRelX, double * pRelY, double * pRelA
1384 ) const
1385 {
1386 static const double MIN_REL_DISTANCE=0.03;
1387 static const double MIN_REL_CIRCUMFERENCE=0.05;
1388 const emPanel * p, * cp;
1389 double ph,dx,dy,sx,sy,sw,sh,minvw,maxvw,vx,vy,vw,vh;
1390 double ctx,cty,ctw,cth,csx,csy,csw,csh;
1391
1392 ph=panel->GetHeight();
1393
1394 if ((VFlags&VF_POPUP_ZOOM)!=0) {
1395 GetMaxPopupViewRect(&sx,&sy,&sw,&sh);
1396 }
1397 else {
1398 sx=CurrentX;
1399 sy=CurrentY;
1400 sw=CurrentWidth;
1401 sh=CurrentHeight;
1402 }
1403
1404 dx=emMin(
1405 CurrentWidth*MIN_REL_DISTANCE,
1406 CurrentHeight*MIN_REL_DISTANCE*CurrentPixelTallness
1407 );
1408 dy=dx/CurrentPixelTallness;
1409 sx+=dx;
1410 sy+=dy;
1411 sw-=2*dx;
1412 sh-=2*dy;
1413
1414 maxvw=emMin(sw,sh/ph*CurrentPixelTallness);
1415 minvw=emMin(
1416 (CurrentWidth+CurrentHeight)*MIN_REL_CIRCUMFERENCE/
1417 (1.0+ph/CurrentPixelTallness),
1418 maxvw*0.999
1419 );
1420
1421 if (
1422 panel->Viewed &&
1423 panel->ViewedWidth>=minvw &&
1424 panel->ViewedWidth<=maxvw &&
1425 panel->ViewedX>=sx &&
1426 panel->ViewedX+panel->ViewedWidth<=sx+sw &&
1427 panel->ViewedY>=sy &&
1428 panel->ViewedY+panel->ViewedHeight<=sy+sh
1429 ) {
1430 if (pRelX) *pRelX=(HomeX+HomeWidth*0.5-panel->ViewedX)/panel->ViewedWidth-0.5;
1431 if (pRelY) *pRelY=(HomeY+HomeHeight*0.5-panel->ViewedY)/panel->ViewedHeight-0.5;
1432 if (pRelA) *pRelA=(HomeWidth*HomeHeight)/(panel->ViewedWidth*panel->ViewedHeight);
1433 return;
1434 }
1435
1436 cp=panel;
1437 ctx=0.0;
1438 cty=0.0;
1439 ctw=1.0;
1440 cth=ph;
1441 while (cp!=SupremeViewedPanel && (cp->Viewed || !cp->InViewedPath)) {
1442 ctx=cp->LayoutX+ctx*cp->LayoutWidth;
1443 cty=cp->LayoutY+cty*cp->LayoutWidth;
1444 ctw*=cp->LayoutWidth;
1445 cth*=cp->LayoutWidth;
1446 cp=cp->Parent;
1447 }
1448
1449 p=SupremeViewedPanel;
1450 csx=(sx-p->ViewedX)/p->ViewedWidth;
1451 csy=(sy-p->ViewedY)*CurrentPixelTallness/p->ViewedWidth;
1452 csw=sw/p->ViewedWidth;
1453 csh=sh*CurrentPixelTallness/p->ViewedWidth;
1454 while (p!=cp) {
1455 csx=p->LayoutX+csx*p->LayoutWidth;
1456 csy=p->LayoutY+csy*p->LayoutWidth;
1457 csw*=p->LayoutWidth;
1458 csh*=p->LayoutWidth;
1459 p=p->Parent;
1460 }
1461
1462 if (ctw*sw>=maxvw*csw) vw=maxvw;
1463 else if (ctw*sw<=minvw*csw) vw=minvw;
1464 else vw=ctw/csw*sw;
1465 vh=vw*ph/CurrentPixelTallness;
1466
1467 if (ctw>csw) {
1468 vx=-(csx+csw*0.5-ctx)*vw;
1469 if (vx<=(-sw*0.5)*ctw) vx=sx;
1470 else if (vx>=(sw*0.5-vw)*ctw) vx=sx+sw-vw;
1471 else vx=vx/ctw+sx+sw*0.5;
1472 }
1473 else {
1474 vx=(ctx+ctw*0.5-csx)*sw;
1475 if (vx<=vw*0.5*csw) vx=sx;
1476 else if (vx>=(sw-vw*0.5)*csw) vx=sx+sw-vw;
1477 else vx=vx/csw+sx-vw*0.5;
1478 }
1479
1480 if (cth>csh) {
1481 vy=-(csy+csh*0.5-cty)*vh;
1482 if (vy<=(-sh*0.5)*cth) vy=sy;
1483 else if (vy>=(sh*0.5-vh)*cth) vy=sy+sh-vh;
1484 else vy=vy/cth+sy+sh*0.5;
1485 }
1486 else {
1487 vy=(cty+cth*0.5-csy)*sh;
1488 if (vy<=vh*0.5*csh) vy=sy;
1489 else if (vy>=(sh-vh*0.5)*csh) vy=sy+sh-vh;
1490 else vy=vy/csh+sy-vh*0.5;
1491 }
1492
1493 if (pRelX) *pRelX=(HomeX+HomeWidth*0.5-vx)/vw-0.5;
1494 if (pRelY) *pRelY=(HomeY+HomeHeight*0.5-vy)/vh-0.5;
1495 if (pRelA) *pRelA=(HomeWidth*HomeHeight)/(vw*vh);
1496 }
1497
1498
CalcVisitFullsizedCoords(const emPanel * panel,double * pRelX,double * pRelY,double * pRelA,bool utilizeView) const1499 void emView::CalcVisitFullsizedCoords(
1500 const emPanel * panel, double * pRelX, double * pRelY, double * pRelA,
1501 bool utilizeView
1502 ) const
1503 {
1504 double fx,fy,fw,fh,ph,vx,vy,vw,vh,ex,ey,ew,eh;
1505
1506 if ((VFlags&VF_POPUP_ZOOM)!=0) {
1507 GetMaxPopupViewRect(&fx,&fy,&fw,&fh);
1508 }
1509 else {
1510 fx=HomeX;
1511 fy=HomeY;
1512 fw=HomeWidth;
1513 fh=HomeHeight;
1514 }
1515
1516 panel->GetEssenceRect(&ex,&ey,&ew,&eh);
1517 ph=panel->GetHeight();
1518 if ((ew*fh*HomePixelTallness>=eh*fw) != utilizeView) {
1519 vw=fw/ew;
1520 vh=vw*ph/HomePixelTallness;
1521 }
1522 else {
1523 vh=fh/eh*ph;
1524 vw=vh/ph*HomePixelTallness;
1525 }
1526 vx=fx+fw*0.5-(ex+ew*0.5)*vw;
1527 vy=fy+fh*0.5-(ey+eh*0.5)/ph*vh;
1528
1529 *pRelX=(HomeX+HomeWidth*0.5-vx)/vw-0.5;
1530 *pRelY=(HomeY+HomeHeight*0.5-vy)/vh-0.5;
1531 *pRelA=(HomeWidth*HomeHeight)/(vw*vh);
1532 }
1533
1534
RawVisit(emPanel * panel,double relX,double relY,double relA,bool forceViewingUpdate)1535 void emView::RawVisit(
1536 emPanel * panel, double relX, double relY, double relA,
1537 bool forceViewingUpdate
1538 )
1539 {
1540 double vx,vy,vw,vh;
1541
1542 if (!panel) return;
1543 if (relA<=0.0) CalcVisitFullsizedCoords(panel,&relX,&relY,&relA,relA<-0.9);
1544 vw=sqrt(HomeWidth*HomeHeight*HomePixelTallness/(relA*panel->GetHeight()));
1545 vh=vw*panel->GetHeight()/HomePixelTallness;
1546 vx=HomeX+HomeWidth*0.5-(relX+0.5)*vw;
1547 vy=HomeY+HomeHeight*0.5-(relY+0.5)*vh;
1548 RawVisitAbs(panel,vx,vy,vw,forceViewingUpdate);
1549 }
1550
1551
RawVisitAbs(emPanel * panel,double vx,double vy,double vw,bool forceViewingUpdate)1552 void emView::RawVisitAbs(
1553 emPanel * panel, double vx, double vy, double vw,
1554 bool forceViewingUpdate
1555 )
1556 {
1557 emPanel * vp, * p, * sp;
1558 double w,h,vh,x1,y1,x2,y2,sx,sy,sw,sh;
1559 bool wasFocused;
1560
1561 if (!panel) return;
1562
1563 SVPChoiceByOpacityInvalid=false;
1564 SVPChoiceInvalid=false;
1565
1566 if (VFlags&VF_NO_ZOOM) {
1567 vp=RootPanel;
1568 h=vp->GetHeight();
1569 if (CurrentHeight*CurrentPixelTallness>=CurrentWidth*h) {
1570 vw=CurrentWidth;
1571 vx=CurrentX;
1572 vy=CurrentY+(CurrentHeight-vw*h/CurrentPixelTallness)*0.5;
1573 }
1574 else {
1575 vw=CurrentHeight*CurrentPixelTallness/h;
1576 vx=CurrentX+(CurrentWidth-vw)*0.5;
1577 vy=CurrentY;
1578 }
1579 }
1580 else {
1581 vp=panel;
1582 }
1583
1584 for (;;) {
1585 p=vp->Parent;
1586 if (!p) break;
1587 w=vw/vp->LayoutWidth;
1588 if (w>MaxSVPSize || w*p->GetHeight()>MaxSVPSize) break;
1589 vx-=vp->LayoutX*w;
1590 vy-=vp->LayoutY*w/CurrentPixelTallness;
1591 vw=w;
1592 vp=p;
1593 }
1594
1595 vh=vp->GetHeight()*vw/HomePixelTallness;
1596
1597 if (vp==RootPanel) {
1598 if (vw<HomeWidth && vh<HomeHeight) {
1599 vx=(HomeX+HomeWidth*0.5-vx)/vw;
1600 vy=(HomeY+HomeHeight*0.5-vy)/vh;
1601 if (vh*HomeWidth<vw*HomeHeight) {
1602 vw=HomeWidth;
1603 vh=vw*vp->GetHeight()/HomePixelTallness;
1604 }
1605 else {
1606 vh=HomeHeight;
1607 vw=vh/vp->GetHeight()*HomePixelTallness;
1608 }
1609 vx=HomeX+HomeWidth*0.5-vx*vw;
1610 vy=HomeY+HomeHeight*0.5-vy*vh;
1611 }
1612
1613 if ((VFlags&VF_EGO_MODE)!=0) {
1614 x1=x2=HomeX+HomeWidth*0.5;
1615 y1=y2=HomeY+HomeHeight*0.5;
1616 }
1617 else {
1618 if (vh*HomeWidth<vw*HomeHeight) {
1619 x1=HomeX;
1620 x2=HomeX+HomeWidth;
1621 y1=HomeY+HomeHeight*0.5-HomeWidth*vp->GetHeight()/HomePixelTallness*0.5;
1622 y2=HomeY+HomeHeight*0.5+HomeWidth*vp->GetHeight()/HomePixelTallness*0.5;
1623 }
1624 else {
1625 x1=HomeX+HomeWidth*0.5-HomeHeight/vp->GetHeight()*HomePixelTallness*0.5;
1626 x2=HomeX+HomeWidth*0.5+HomeHeight/vp->GetHeight()*HomePixelTallness*0.5;
1627 y1=HomeY;
1628 y2=HomeY+HomeHeight;
1629 }
1630 }
1631 if (vx>x1) vx=x1;
1632 if (vx<x2-vw) vx=x2-vw;
1633 if (vy>y1) vy=y1;
1634 if (vy<y2-vh) vy=y2-vh;
1635 }
1636
1637 if ((VFlags&VF_POPUP_ZOOM)!=0) {
1638 if (
1639 vp!=RootPanel ||
1640 vx<HomeX-0.1 || vx+vw>HomeX+HomeWidth+0.1 ||
1641 vy<HomeY-0.1 || vy+vh>HomeY+HomeHeight+0.1
1642 ) {
1643 if (!PopupWindow) {
1644 wasFocused=Focused;
1645 PopupWindow=new emWindow(
1646 *this,
1647 0,
1648 emWindow::WF_POPUP,
1649 "emViewPopup"
1650 );
1651 GotPopupWindowCloseSignal=false;
1652 UpdateEngine->AddWakeUpSignal(PopupWindow->GetCloseSignal());
1653 PopupWindow->SetBackgroundColor(GetBackgroundColor());
1654 SwapViewPorts(true);
1655 if (wasFocused && !Focused) CurrentViewPort->RequestFocus();
1656 }
1657 GetMaxPopupViewRect(&sx,&sy,&sw,&sh);
1658 if (vp==RootPanel) {
1659 x1=floor(vx);
1660 y1=floor(vy);
1661 x2=ceil(vx+vw);
1662 y2=ceil(vy+vh);
1663 if (x1<sx) x1=sx;
1664 if (y1<sy) y1=sy;
1665 if (x2>sx+sw) x2=sx+sw;
1666 if (y2>sy+sh) y2=sy+sh;
1667 if (x2<x1+1.0) x2=x1+1.0;
1668 if (y2<y1+1.0) y2=y1+1.0;
1669 }
1670 else {
1671 x1=sx;
1672 y1=sy;
1673 x2=sx+sw;
1674 y2=sy+sh;
1675 }
1676 if (
1677 fabs(x1-CurrentX)>0.01 || fabs(x2-CurrentX-CurrentWidth)>0.01 ||
1678 fabs(y1-CurrentY)>0.01 || fabs(y2-CurrentY-CurrentHeight)>0.01
1679 ) {
1680 SwapViewPorts(false);
1681 PopupWindow->SetViewPosSize(x1,y1,x2-x1,y2-y1);
1682 SwapViewPorts(false);
1683 forceViewingUpdate=true;
1684 }
1685 }
1686 else if (PopupWindow) {
1687 wasFocused=Focused;
1688 SwapViewPorts(true);
1689 delete PopupWindow;
1690 PopupWindow=NULL;
1691 Signal(GeometrySignal);
1692 forceViewingUpdate=true;
1693 if (wasFocused && !Focused && !GotPopupWindowCloseSignal) {
1694 CurrentViewPort->RequestFocus();
1695 }
1696 }
1697 }
1698
1699 FindBestSVP(&vp,&vx,&vy,&vw);
1700
1701 p=vp;
1702 w=vw;
1703 for (;;) {
1704 sp=p;
1705 p=p->Parent;
1706 if (!p) break;
1707 w=w/sp->LayoutWidth;
1708 if (w>MaxSVPSize || w*p->GetHeight()>MaxSVPSize) break;
1709 }
1710 MaxSVP=sp;
1711
1712 sp=vp;
1713 sx=vx;
1714 sy=vy;
1715 sw=vw;
1716 for (;;) {
1717 p=sp->LastChild;
1718 if (!p) break;
1719 x1=(CurrentX+1E-4-sx)/sw;
1720 x2=(CurrentX+CurrentWidth-1E-4-sx)/sw;
1721 y1=(CurrentY+1E-4-sy)*(CurrentPixelTallness/sw);
1722 y2=(CurrentY+CurrentHeight-1E-4-sy)*(CurrentPixelTallness/sw);
1723 do {
1724 if (
1725 p->LayoutX<x2 && p->LayoutX+p->LayoutWidth>x1 &&
1726 p->LayoutY<y2 && p->LayoutY+p->LayoutHeight>y1
1727 ) break;
1728 p=p->Prev;
1729 } while (p);
1730 if (
1731 !p || p->LayoutX>x1 || p->LayoutX+p->LayoutWidth<x2 ||
1732 p->LayoutY>y1 || p->LayoutY+p->LayoutHeight<y2
1733 ) break;
1734 sp=p;
1735 sx+=p->LayoutX*sw;
1736 sy+=p->LayoutY*sw/CurrentPixelTallness;
1737 sw*=p->LayoutWidth;
1738 }
1739 MinSVP=sp;
1740
1741 if (
1742 forceViewingUpdate ||
1743 SupremeViewedPanel!=vp ||
1744 fabs(vp->ViewedX-vx)>=0.001 ||
1745 fabs(vp->ViewedY-vy)>=0.001 ||
1746 fabs(vp->ViewedWidth-vw)>=0.001
1747 ) {
1748 if (SVPUpdSlice!=GetScheduler().GetTimeSliceCounter()) {
1749 SVPUpdSlice=GetScheduler().GetTimeSliceCounter();
1750 SVPUpdCount=0;
1751 }
1752 SVPUpdCount++;
1753 if (SVPUpdCount>1000) {
1754 // Get out of a very unlikely situation where we have an
1755 // end-less loop of choosing a different SVP and
1756 // creating/destroying panels through the notice
1757 // mechanism. SVP choice depends on floating-point
1758 // calculations and that can result different in a
1759 // repetition with the same input numbers...
1760 if (SVPUpdCount%1000==1 || SVPUpdCount>10000) {
1761 vx+=emGetDblRandom(-0.01,0.01);
1762 vy+=emGetDblRandom(-0.01,0.01);
1763 vw*=emGetDblRandom(0.9999999999,1.0000000001);
1764 }
1765 }
1766 if (emIsDLogEnabled()) {
1767 emDLog("emView %p: SVP=\"%s\"",(const void*)this,vp->GetIdentity().Get());
1768 }
1769 p=SupremeViewedPanel;
1770 if (p) {
1771 p->InViewedPath=0;
1772 p->Viewed=0;
1773 p->AddPendingNotice(
1774 emPanel::NF_VIEWING_CHANGED |
1775 emPanel::NF_UPDATE_PRIORITY_CHANGED |
1776 emPanel::NF_MEMORY_LIMIT_CHANGED
1777 );
1778 p->UpdateChildrenViewing();
1779 for (;;) {
1780 p=p->Parent;
1781 if (!p) break;
1782 p->InViewedPath=0;
1783 p->AddPendingNotice(
1784 emPanel::NF_VIEWING_CHANGED |
1785 emPanel::NF_UPDATE_PRIORITY_CHANGED |
1786 emPanel::NF_MEMORY_LIMIT_CHANGED
1787 );
1788 }
1789 }
1790 SupremeViewedPanel=vp;
1791 vp->InViewedPath=1;
1792 vp->Viewed=1;
1793 vp->ViewedX=vx;
1794 vp->ViewedY=vy;
1795 vp->ViewedWidth=vw;
1796 vp->ViewedHeight=vw*vp->GetHeight()/CurrentPixelTallness;
1797 vp->ClipX1=vp->ViewedX;
1798 if (vp->ClipX1<CurrentX) vp->ClipX1=CurrentX;
1799 vp->ClipY1=vp->ViewedY;
1800 if (vp->ClipY1<CurrentY) vp->ClipY1=CurrentY;
1801 vp->ClipX2=vp->ViewedX+vp->ViewedWidth;
1802 if (vp->ClipX2>CurrentX+CurrentWidth) vp->ClipX2=CurrentX+CurrentWidth;
1803 vp->ClipY2=vp->ViewedY+vp->ViewedHeight;
1804 if (vp->ClipY2>CurrentY+CurrentHeight) vp->ClipY2=CurrentY+CurrentHeight;
1805 vp->AddPendingNotice(
1806 emPanel::NF_VIEWING_CHANGED |
1807 emPanel::NF_UPDATE_PRIORITY_CHANGED |
1808 emPanel::NF_MEMORY_LIMIT_CHANGED
1809 );
1810 vp->UpdateChildrenViewing();
1811 for (p=vp->Parent; p; p=p->Parent) {
1812 p->InViewedPath=1;
1813 p->AddPendingNotice(
1814 emPanel::NF_VIEWING_CHANGED |
1815 emPanel::NF_UPDATE_PRIORITY_CHANGED |
1816 emPanel::NF_MEMORY_LIMIT_CHANGED
1817 );
1818 }
1819 RestartInputRecursion=true;
1820 CursorInvalid=true;
1821 UpdateEngine->WakeUp();
1822 InvalidatePainting();
1823 }
1824 }
1825
1826
RawZoomOut(bool forceViewingUpdate)1827 void emView::RawZoomOut(bool forceViewingUpdate)
1828 {
1829 double relA,relA2;
1830
1831 if (RootPanel) {
1832 relA=HomeWidth*RootPanel->GetHeight()/HomePixelTallness/HomeHeight;
1833 relA2=HomeHeight/RootPanel->GetHeight()*HomePixelTallness/HomeWidth;
1834 if (relA<relA2) relA=relA2;
1835 RawVisit(RootPanel,0.0,0.0,relA,forceViewingUpdate);
1836 }
1837
1838 if (IsPoppedUp()) {
1839 emFatalError("emView::RawZoomOut: Inconsistent algorithms.");
1840 }
1841 }
1842
1843
FindBestSVP(emPanel ** pPanel,double * pVx,double * pVy,double * pVw) const1844 void emView::FindBestSVP(
1845 emPanel * * pPanel, double * pVx, double * pVy, double * pVw
1846 ) const
1847 {
1848 emPanel * vp, * p, * op;
1849 double vx,vy,vw,x,y,w,minS;
1850 bool b;
1851 int i;
1852
1853 vp=*pPanel;
1854 vx=*pVx;
1855 vy=*pVy;
1856 vw=*pVw;
1857 for (i=0; i<2; i++) {
1858 minS = (i==0 ? MaxSVPSize : MaxSVPSearchSize);
1859 op=vp;
1860 for (;;) {
1861 p=vp->Parent;
1862 if (!p) break;
1863 w=vw/vp->LayoutWidth;
1864 if (w>minS || w*p->GetHeight()>minS) break;
1865 vx-=vp->LayoutX*w;
1866 vy-=vp->LayoutY*w/CurrentPixelTallness;
1867 vw=w;
1868 vp=p;
1869 }
1870 if (op==vp && i>0) break;
1871 b=
1872 vx<=CurrentX+1E-4 &&
1873 vx+vw>=CurrentX+CurrentWidth-1E-4 &&
1874 vy<=CurrentY+1E-4 &&
1875 vy+vp->GetHeight()*vw/CurrentPixelTallness>=CurrentY+CurrentHeight-1E-4
1876 ;
1877 p=vp; x=vx; y=vy; w=vw;
1878 b=FindBestSVPInTree(&p,&x,&y,&w,b);
1879 if (*pPanel!=p) {
1880 *pPanel=p;
1881 *pVx=x;
1882 *pVy=y;
1883 *pVw=w;
1884 }
1885 if (b) break;
1886 }
1887 }
1888
1889
FindBestSVPInTree(emPanel ** pPanel,double * pVx,double * pVy,double * pVw,bool covering) const1890 bool emView::FindBestSVPInTree(
1891 emPanel * * pPanel, double * pVx, double * pVy, double * pVw, bool covering
1892 ) const
1893 {
1894 double f,vx,vy,vw,vwc,vs,vd,x1,y1,x2,y2,x,y,cx,cy,cw,cs,d;
1895 emPanel * p, * cp;
1896 bool cc,vc,tooLarge,overlapped;
1897
1898 p=*pPanel;
1899 vx=*pVx;
1900 vy=*pVy;
1901 vw=*pVw;
1902
1903 vs=vw;
1904 f=p->GetHeight();
1905 if (f>1.0) vs*=f;
1906
1907 tooLarge=(vs>MaxSVPSize);
1908
1909 if (!covering && !tooLarge) return false;
1910 vc=(
1911 covering &&
1912 (p->CanvasColor.IsOpaque() || ((const emPanel*)p)->IsOpaque())
1913 );
1914
1915 p=p->LastChild;
1916 if (!p) return vc;
1917
1918 x1=(CurrentX+1E-4-vx)/vw;
1919 x2=(CurrentX+CurrentWidth-1E-4-vx)/vw;
1920 vwc=vw/CurrentPixelTallness;
1921 y1=(CurrentY+1E-4-vy)/vwc;
1922 y2=(CurrentY+CurrentHeight-1E-4-vy)/vwc;
1923 vd=1E+30;
1924 overlapped=false;
1925
1926 do {
1927 if (
1928 p->LayoutX<x2 && p->LayoutX+p->LayoutWidth>x1 &&
1929 p->LayoutY<y2 && p->LayoutY+p->LayoutHeight>y1
1930 ) {
1931 cc=true;
1932 if (
1933 !covering ||
1934 p->LayoutX>x1 || p->LayoutX+p->LayoutWidth<x2 ||
1935 p->LayoutY>y1 || p->LayoutY+p->LayoutHeight<y2
1936 ) {
1937 if (!tooLarge && vc) break;
1938 cc=false;
1939 }
1940 cp=p;
1941 cx=vx+p->LayoutX*vw;
1942 cy=vy+p->LayoutY*vwc;
1943 cw=p->LayoutWidth*vw;
1944 cc=FindBestSVPInTree(&cp,&cx,&cy,&cw,cc);
1945 if (!cc && !tooLarge && vc) break;
1946 cs=cw;
1947 f=cp->GetHeight();
1948 if (f>1.0) cs*=f;
1949 if (cc && cs<=MaxSVPSize) {
1950 if (tooLarge || !overlapped) {
1951 *pPanel=cp;
1952 *pVx=cx;
1953 *pVy=cy;
1954 *pVw=cw;
1955 }
1956 return true;
1957 }
1958 overlapped=true;
1959 if (tooLarge) {
1960 x=(x2+x1)*0.5;
1961 y=(y2+y1)*0.5;
1962 if (x<p->LayoutX) x-=p->LayoutX;
1963 else if (x>p->LayoutX+p->LayoutWidth) x-=p->LayoutX+p->LayoutWidth;
1964 else x=0.0;
1965 if (y<p->LayoutY) y-=p->LayoutY;
1966 else if (y>p->LayoutY+p->LayoutHeight) y-=p->LayoutY+p->LayoutHeight;
1967 else y=0.0;
1968 d=x*x+y*y;
1969 if (
1970 (cs<=MaxSVPSize && d-0.1<=vd) ||
1971 (vs>MaxSVPSize && cs<=vs)
1972 ) {
1973 *pPanel=cp;
1974 *pVx=cx;
1975 *pVy=cy;
1976 *pVw=cw;
1977 vd=d;
1978 vs=cs;
1979 vc=cc;
1980 }
1981 }
1982 }
1983 p=p->Prev;
1984 } while (p);
1985
1986 return vc;
1987 }
1988
1989
SwapViewPorts(bool swapFocus)1990 void emView::SwapViewPorts(bool swapFocus)
1991 {
1992 emView * w;
1993 emViewPort * vp;
1994 bool fcs;
1995
1996 w=PopupWindow;
1997 vp=w->CurrentViewPort;
1998 w->CurrentViewPort=CurrentViewPort;
1999 CurrentViewPort=vp;
2000 CurrentViewPort->CurrentView=this;
2001 w->CurrentViewPort->CurrentView=w;
2002 CurrentX=CurrentViewPort->HomeView->HomeX;
2003 CurrentY=CurrentViewPort->HomeView->HomeY;
2004 CurrentWidth=CurrentViewPort->HomeView->HomeWidth;
2005 CurrentHeight=CurrentViewPort->HomeView->HomeHeight;
2006 CurrentPixelTallness=CurrentViewPort->HomeView->HomePixelTallness;
2007 w->CurrentX=w->CurrentViewPort->HomeView->HomeX;
2008 w->CurrentY=w->CurrentViewPort->HomeView->HomeY;
2009 w->CurrentWidth=w->CurrentViewPort->HomeView->HomeWidth;
2010 w->CurrentHeight=w->CurrentViewPort->HomeView->HomeHeight;
2011 w->CurrentPixelTallness=w->CurrentViewPort->HomeView->HomePixelTallness;
2012 if (swapFocus) {
2013 fcs=Focused;
2014 SetFocused(w->Focused);
2015 w->SetFocused(fcs);
2016 }
2017 }
2018
2019
RecurseInput(emInputEvent & event,const emInputState & state)2020 void emView::RecurseInput(emInputEvent & event, const emInputState & state)
2021 {
2022 double mx,my,tx,ty;
2023 emInputEvent * ebase, * e;
2024 emPanel * panel, * child;
2025
2026 panel=SupremeViewedPanel;
2027 if (!panel) return;
2028
2029 NoEvent.Eat();
2030
2031 ebase=&event;
2032
2033 mx=state.GetMouseX();
2034 my=state.GetMouseY();
2035 if (ebase->IsMouseEvent()) {
2036 if (mx<panel->ClipX1 || mx>=panel->ClipX2 ||
2037 my<panel->ClipY1 || my>=panel->ClipY2) ebase=&NoEvent;
2038 }
2039 mx=(mx-panel->ViewedX)/panel->ViewedWidth;
2040 my=(my-panel->ViewedY)/panel->ViewedWidth*CurrentPixelTallness;
2041
2042 if (state.GetTouchCount()>0) {
2043 tx=state.GetTouchX(0);
2044 ty=state.GetTouchY(0);
2045 }
2046 else {
2047 tx=state.GetMouseX();
2048 ty=state.GetMouseY();
2049 }
2050 if (ebase->IsTouchEvent()) {
2051 if (tx<panel->ClipX1 || tx>=panel->ClipX2 ||
2052 ty<panel->ClipY1 || ty>=panel->ClipY2) ebase=&NoEvent;
2053 }
2054 tx=(tx-panel->ViewedX)/panel->ViewedWidth;
2055 ty=(ty-panel->ViewedY)/panel->ViewedWidth*CurrentPixelTallness;
2056
2057 for (;;) {
2058 if (panel->PendingInput) {
2059 e=ebase;
2060 if (!e->IsEmpty()) {
2061 if (e->IsMouseEvent()) {
2062 if (!panel->IsPointInSubstanceRect(mx,my)) {
2063 e=&NoEvent;
2064 }
2065 }
2066 else if (e->IsTouchEvent()) {
2067 if (!panel->IsPointInSubstanceRect(tx,ty)) {
2068 e=&NoEvent;
2069 }
2070 }
2071 else if (e->IsKeyboardEvent()) {
2072 if (!panel->InActivePath) {
2073 e=&NoEvent;
2074 }
2075 }
2076 }
2077 for (child=panel->LastChild; child; child=child->Prev) {
2078 RecurseInput(child,*e,state);
2079 if (RestartInputRecursion) return;
2080 }
2081 panel->PendingInput=0;
2082 panel->Input(*e,state,mx,my);
2083 if (RestartInputRecursion) return;
2084 }
2085 if (!panel->Parent) break;
2086 mx=mx*panel->LayoutWidth+panel->LayoutX;
2087 my=my*panel->LayoutWidth+panel->LayoutY;
2088 tx=tx*panel->LayoutWidth+panel->LayoutX;
2089 ty=ty*panel->LayoutWidth+panel->LayoutY;
2090 panel=panel->Parent;
2091 }
2092 }
2093
2094
RecurseInput(emPanel * panel,emInputEvent & event,const emInputState & state)2095 void emView::RecurseInput(
2096 emPanel * panel, emInputEvent & event, const emInputState & state
2097 )
2098 {
2099 double mx,my,tx,ty;
2100 emInputEvent * e;
2101 emPanel * child;
2102
2103 if (!panel->PendingInput) return;
2104
2105 if (panel->Viewed) {
2106 mx=(state.GetMouseX()-panel->ViewedX)/panel->ViewedWidth;
2107 my=(state.GetMouseY()-panel->ViewedY)/panel->ViewedWidth*CurrentPixelTallness;
2108 if (state.GetTouchCount()>0) {
2109 tx=(state.GetTouchX(0)-panel->ViewedX)/panel->ViewedWidth;
2110 ty=(state.GetTouchY(0)-panel->ViewedY)/panel->ViewedWidth*CurrentPixelTallness;
2111 }
2112 else {
2113 tx=mx;
2114 ty=my;
2115 }
2116 }
2117 else {
2118 mx=-1.0;
2119 my=-1.0;
2120 tx=-1.0;
2121 ty=-1.0;
2122 }
2123
2124 e=&event;
2125 if (!e->IsEmpty()) {
2126 if (e->IsMouseEvent()) {
2127 if (!panel->IsPointInSubstanceRect(mx,my)) {
2128 e=&NoEvent;
2129 }
2130 }
2131 else if (e->IsTouchEvent()) {
2132 if (!panel->IsPointInSubstanceRect(tx,ty)) {
2133 e=&NoEvent;
2134 }
2135 }
2136 else if (e->IsKeyboardEvent()) {
2137 if (!panel->InActivePath) {
2138 e=&NoEvent;
2139 }
2140 }
2141 }
2142
2143 for (child=panel->LastChild; child; child=child->Prev) {
2144 RecurseInput(child,*e,state);
2145 if (RestartInputRecursion) return;
2146 }
2147
2148 panel->PendingInput=0;
2149 panel->Input(*e,state,mx,my);
2150 }
2151
2152
InvalidateHighlight()2153 void emView::InvalidateHighlight()
2154 {
2155 if (
2156 !ActivePanel || !ActivePanel->Viewed || (
2157 (VFlags&VF_NO_ACTIVE_HIGHLIGHT)!=0 &&
2158 ((VFlags&VF_NO_FOCUS_HIGHLIGHT)!=0 || !Focused)
2159 )
2160 ) return;
2161 InvalidatePainting(); //??? too much
2162 }
2163
2164
PaintHighlight(const emPainter & painter) const2165 void emView::PaintHighlight(const emPainter & painter) const
2166 {
2167 emColor shadowColor,arrowColor;
2168 emPainter pnt;
2169 double cx1,cy1,cx2,cy2,vx,vy,vw,vh,sx,sy,sw,sh,sr,x1,y1,x2,y2;
2170 double goalX,goalY,lc,lh,lv,l,len,pc,pc2,pos,delta;
2171 int i,j,n,m;
2172
2173 //??? These things could be configurable.
2174 static const emColor highlightColor=emColor(255,255,255);
2175 static const emColor adherentHighlightColor=emColor(255,255,187);
2176 static const double arrowSize=11.0;
2177 static const double arrowDistance=55.0;
2178 static const double distanceFromPanel=2.0;
2179
2180 if (
2181 !ActivePanel || !ActivePanel->Viewed || (
2182 (VFlags&VF_NO_ACTIVE_HIGHLIGHT)!=0 &&
2183 ((VFlags&VF_NO_FOCUS_HIGHLIGHT)!=0 || !Focused)
2184 )
2185 ) return;
2186
2187 pnt=painter;
2188 pnt.SetScaling(1.0,1.0/CurrentPixelTallness);
2189
2190 vx=ActivePanel->GetViewedX();
2191 vy=ActivePanel->GetViewedY()*CurrentPixelTallness;
2192 vw=ActivePanel->GetViewedWidth();
2193 vh=ActivePanel->GetViewedHeight()*CurrentPixelTallness;
2194
2195 ((const emPanel*)ActivePanel)->GetSubstanceRect(&sx,&sy,&sw,&sh,&sr);
2196 sx=vx+sx*vw;
2197 sy=vy+sy*vw;
2198 sw*=vw;
2199 sh*=vw;
2200 sr*=vw;
2201 if (sw<0.0) sw=0.0; else if (sw>vw) sw=vw;
2202 if (sh<0.0) sh=0.0; else if (sh>vh) sh=vh;
2203 if (sx<vx) sx=vx; else if (sx>vx+vw-sw) sx=vx+vw-sw;
2204 if (sy<vy) sy=vy; else if (sy>vy+vh-sh) sy=vy+vh-sh;
2205 if (sr<0.0) sr=0.0;
2206 if (sr>sw*0.5) sr=sw*0.5;
2207 if (sr>sh*0.5) sr=sh*0.5;
2208 sx-=distanceFromPanel;
2209 sy-=distanceFromPanel;
2210 sw+=2*distanceFromPanel;
2211 sh+=2*distanceFromPanel;
2212 sr+=distanceFromPanel;
2213
2214 cx1=pnt.GetUserClipX1()-arrowSize*2.0;
2215 cy1=pnt.GetUserClipY1()-arrowSize*2.0;
2216 cx2=pnt.GetUserClipX2()+arrowSize*2.0;
2217 cy2=pnt.GetUserClipY2()+arrowSize*2.0;
2218 if (sx>=cx2 || sx+sw<=cx1 || sy>=cy2 || sy+sh<=cy1) return;
2219
2220 pnt.LeaveUserSpace();
2221
2222 shadowColor=emColor(0,0,0,192);
2223 if (ActivationAdherent) arrowColor=adherentHighlightColor;
2224 else arrowColor=highlightColor;
2225 if (!Focused || (VFlags&VF_NO_FOCUS_HIGHLIGHT)!=0) {
2226 shadowColor.SetAlpha((emByte)(shadowColor.GetAlpha()/3));
2227 arrowColor.SetAlpha((emByte)(arrowColor.GetAlpha()/3));
2228 }
2229
2230 x1=sx+sr;
2231 x2=sx+sw-sr;
2232 y1=sy+sr;
2233 y2=sy+sh-sr;
2234
2235 goalX=(x1+x2)*0.5;
2236 goalY=(y1+y2)*0.5;
2237
2238 lh=x2-x1;
2239 lv=y2-y1;
2240 lc=0.5*M_PI*sr;
2241
2242 pc=lc*0.5;
2243 if (lc>1E-10) {
2244 pc2=(lv*0.5+lc+lh*0.5)*0.5-lv*0.5;
2245 if (pc2<0.0) pc2=0.0;
2246 if (pc2>lc) pc2=lc;
2247 l=lc/(lc+emMin(lh,lv));
2248 pc=pc*(1.0-l)+pc2*l;
2249 }
2250
2251 for (i=0; i<4; i++) {
2252 switch (i) {
2253 case 0:
2254 pos=pc;
2255 len=(lc-pc)*2.0+lh;
2256 break;
2257 case 1:
2258 pos=lc+lh+lc-pc;
2259 len=pc*2.0+lv;
2260 break;
2261 case 2:
2262 pos=lc+lh+lc+lv+pc;
2263 len=(lc-pc)*2.0+lh;
2264 break;
2265 default:
2266 pos=lc+lh+lc+lv+lc+lh+lc-pc;
2267 len=pc*2.0+lv;
2268 break;
2269 }
2270
2271 n=(int)(emMin(len/arrowDistance,1E9)+0.5);
2272 if (n<1) n=1;
2273 for (m=1; m<n; m*=2);
2274 n&=(m|(m>>1)|(m>>2));
2275
2276 delta=len/n;
2277
2278 for (j=0; n>0; j=(j+1)&7) {
2279 if (!(j&1)) l=lc;
2280 else if (j&2) l=lv;
2281 else l=lh;
2282 m=(int)floor(1.0+(l-pos)/delta);
2283 if (m>0) {
2284 if (m>n) m=n;
2285 if (j&1) {
2286 PaintHighlightArrowsOnLine(
2287 pnt,
2288 j==1 ? x2 : j==3 ? x1-sr : j==5 ? x1 : x2+sr,
2289 j==1 ? y2+sr : j==3 ? y2 : j==5 ? y1-sr : y1,
2290 j==1 ? -1.0 : j==5 ? 1.0 : 0.0,
2291 j==3 ? -1.0 : j==7 ? 1.0 : 0.0,
2292 pos,delta,m,goalX,goalY,
2293 arrowSize,shadowColor,arrowColor
2294 );
2295 }
2296 else {
2297 PaintHighlightArrowsOnBow(
2298 pnt,
2299 j==2 || j==4 ? x1 : x2,
2300 j>=4 ? y1 : y2,
2301 sr,j/2,pos,delta,m,goalX,goalY,
2302 arrowSize,shadowColor,arrowColor
2303 );
2304 }
2305 pos+=delta*m;
2306 n-=m;
2307 }
2308 pos-=l;
2309 }
2310 }
2311
2312 pnt.EnterUserSpace();
2313 }
2314
2315
PaintHighlightArrowsOnLine(const emPainter & painter,double x,double y,double dx,double dy,double pos,double delta,int count,double goalX,double goalY,double arrowSize,emColor shadowColor,emColor arrowColor) const2316 void emView::PaintHighlightArrowsOnLine(
2317 const emPainter & painter, double x, double y,
2318 double dx, double dy, double pos, double delta,
2319 int count, double goalX, double goalY, double arrowSize,
2320 emColor shadowColor, emColor arrowColor
2321 ) const
2322 {
2323 double cx1,cy1,cx2,cy2,minPos,maxPos,t;
2324
2325 minPos=-1E100;
2326 maxPos=1E100;
2327
2328 cx1=painter.GetUserClipX1()-arrowSize*2.0;
2329 cx2=painter.GetUserClipX2()+arrowSize*2.0;
2330 if (dx>1E-10) {
2331 t=(cx1-x)/dx; if (minPos<t) minPos=t;
2332 t=(cx2-x)/dx; if (maxPos>t) maxPos=t;
2333 }
2334 else if (dx<-1E-10) {
2335 t=(cx2-x)/dx; if (minPos<t) minPos=t;
2336 t=(cx1-x)/dx; if (maxPos>t) maxPos=t;
2337 }
2338 else if (x>=cx2 || x<=cx1) {
2339 return;
2340 }
2341
2342 cy1=painter.GetUserClipY1()-arrowSize*2.0;
2343 cy2=painter.GetUserClipY2()+arrowSize*2.0;
2344 if (dy>1E-10) {
2345 t=(cy1-y)/dy; if (minPos<t) minPos=t;
2346 t=(cy2-y)/dy; if (maxPos>t) maxPos=t;
2347 }
2348 else if (dy<-1E-10) {
2349 t=(cy2-y)/dy; if (minPos<t) minPos=t;
2350 t=(cy1-y)/dy; if (maxPos>t) maxPos=t;
2351 }
2352 else if (y>=cy2 || y<=cy1) {
2353 return;
2354 }
2355
2356 if (pos<minPos) {
2357 t=ceil((minPos-pos)/delta);
2358 if (t>=(double)count) return;
2359 count-=(int)(t+0.5);
2360 pos+=t*delta;
2361 }
2362
2363 while (count>0 && pos<=maxPos) {
2364 PaintHighlightArrow(
2365 painter,x+dx*pos,y+dy*pos,
2366 goalX,goalY,arrowSize,
2367 shadowColor,arrowColor
2368 );
2369 pos+=delta;
2370 count--;
2371 }
2372 }
2373
2374
PaintHighlightArrowsOnBow(const emPainter & painter,double x,double y,double radius,int quadrant,double pos,double delta,int count,double goalX,double goalY,double arrowSize,emColor shadowColor,emColor arrowColor) const2375 void emView::PaintHighlightArrowsOnBow(
2376 const emPainter & painter, double x, double y, double radius,
2377 int quadrant, double pos, double delta, int count,
2378 double goalX, double goalY, double arrowSize,
2379 emColor shadowColor, emColor arrowColor
2380 ) const
2381 {
2382 double cx1,cy1,cx2,cy2,minPos,maxPos,t,a;
2383 int i;
2384
2385 minPos=-1E100;
2386 maxPos=1E100;
2387
2388 cx1=painter.GetUserClipX1()-arrowSize*2.0;
2389 cy1=painter.GetUserClipY1()-arrowSize*2.0;
2390 cx2=painter.GetUserClipX2()+arrowSize*2.0;
2391 cy2=painter.GetUserClipY2()+arrowSize*2.0;
2392
2393 cx1-=x;
2394 cy1-=y;
2395 cx2-=x;
2396 cy2-=y;
2397
2398 quadrant&=3;
2399 for (i=0; i<quadrant; i++) {
2400 t=cx1;
2401 cx1=cy1;
2402 cy1=-cx2;
2403 cx2=cy2;
2404 cy2=-t;
2405 }
2406
2407 if (cx1>=radius || cx2<=0.0) return;
2408 if (cy1>=radius || cy2<=0.0) return;
2409
2410 if (cx1>0.0) {
2411 t=acos(cx1/radius)*radius;
2412 if (maxPos>t) maxPos=t;
2413 }
2414 if (cx2<radius) {
2415 t=acos(cx2/radius)*radius;
2416 if (minPos<t) minPos=t;
2417 }
2418 if (cy1>0.0) {
2419 t=asin(cy1/radius)*radius;
2420 if (minPos<t) minPos=t;
2421 }
2422 if (cy2<radius) {
2423 t=asin(cy2/radius)*radius;
2424 if (maxPos>t) maxPos=t;
2425 }
2426
2427 if (pos<minPos) {
2428 t=ceil((minPos-pos)/delta);
2429 if (t>=(double)count) return;
2430 count-=(int)(t+0.5);
2431 pos+=t*delta;
2432 }
2433
2434 while (count>0 && pos<=maxPos) {
2435 a=quadrant*M_PI*0.5+pos/radius;
2436 PaintHighlightArrow(
2437 painter,
2438 x+cos(a)*radius,
2439 y+sin(a)*radius,
2440 goalX,goalY,arrowSize,
2441 shadowColor,arrowColor
2442 );
2443 pos+=delta;
2444 count--;
2445 }
2446 }
2447
2448
PaintHighlightArrow(const emPainter & painter,double x,double y,double goalX,double goalY,double arrowSize,emColor shadowColor,emColor arrowColor) const2449 void emView::PaintHighlightArrow(
2450 const emPainter & painter, double x, double y,
2451 double goalX, double goalY, double arrowSize,
2452 emColor shadowColor, emColor arrowColor
2453 ) const
2454 {
2455 double sxy[4*2],axy[4*2];
2456 double dx,dy,d,aw,ah,ag,sd;
2457
2458 dx=x-goalX;
2459 dy=y-goalY;
2460 d=sqrt(dx*dx+dy*dy);
2461 if (d<0.01) {
2462 dx=0;
2463 dy=1.0;
2464 }
2465 else {
2466 dx/=d;
2467 dy/=d;
2468 }
2469
2470 ah=arrowSize;
2471 ag=ah*0.8;
2472 aw=ah*0.5;
2473 sd=ah*0.2;
2474
2475 axy[0]=x;
2476 axy[1]=y;
2477 axy[2]=x+dx*ah-dy*aw*0.5;
2478 axy[3]=y+dy*ah+dx*aw*0.5;
2479 axy[4]=x+dx*ag;
2480 axy[5]=y+(dy*ag);
2481 axy[6]=x+dx*ah+dy*aw*0.5;
2482 axy[7]=y+(dy*ah-dx*aw*0.5);
2483
2484 sxy[0]=axy[0];
2485 sxy[1]=axy[1];
2486 sxy[2]=axy[2]+sd;
2487 sxy[3]=axy[3]+sd;
2488 sxy[4]=axy[4]+sd*ag/ah;
2489 sxy[5]=axy[5]+sd*ag/ah;
2490 sxy[6]=axy[6]+sd;
2491 sxy[7]=axy[7]+sd;
2492
2493 painter.PaintPolygon(sxy,4,shadowColor);
2494 painter.PaintPolygon(axy,4,arrowColor);
2495 }
2496
2497
SetSeekPos(emPanel * panel,const char * childName)2498 void emView::SetSeekPos(emPanel * panel, const char * childName)
2499 {
2500 if (!panel || !childName) childName="";
2501 if (SeekPosPanel!=panel) {
2502 if (SeekPosPanel) {
2503 SeekPosPanel->AddPendingNotice(
2504 emPanel::NF_SOUGHT_NAME_CHANGED|
2505 emPanel::NF_MEMORY_LIMIT_CHANGED
2506 );
2507 }
2508 SeekPosPanel=panel;
2509 SeekPosChildName=childName;
2510 if (SeekPosPanel) {
2511 SeekPosPanel->AddPendingNotice(
2512 emPanel::NF_SOUGHT_NAME_CHANGED|
2513 emPanel::NF_MEMORY_LIMIT_CHANGED
2514 );
2515 }
2516 }
2517 else if (panel && SeekPosChildName!=childName) {
2518 SeekPosChildName=childName;
2519 SeekPosPanel->AddPendingNotice(emPanel::NF_SOUGHT_NAME_CHANGED);
2520 }
2521 }
2522
2523
IsHopeForSeeking() const2524 bool emView::IsHopeForSeeking() const
2525 {
2526 return SeekPosPanel && SeekPosPanel->IsHopeForSeeking();
2527 }
2528
2529
UpdateEngineClass(emView & view)2530 emView::UpdateEngineClass::UpdateEngineClass(emView & view)
2531 : emEngine(view.GetScheduler()), View(view)
2532 {
2533 SetEnginePriority(emEngine::HIGH_PRIORITY);
2534 }
2535
2536
Cycle()2537 bool emView::UpdateEngineClass::Cycle()
2538 {
2539 View.Update();
2540 return false;
2541 }
2542
2543
EOIEngineClass(emView & view)2544 emView::EOIEngineClass::EOIEngineClass(emView & view)
2545 : emEngine(view.GetScheduler()), View(view)
2546 {
2547 CountDown=5;
2548 WakeUp();
2549 }
2550
2551
Cycle()2552 bool emView::EOIEngineClass::Cycle()
2553 {
2554 CountDown--;
2555 if (CountDown>0) return true;
2556 Signal(View.EOISignal);
2557 View.EOIEngine=NULL;
2558 delete this;
2559 return false;
2560 }
2561
2562
StressTestClass(emView & view)2563 emView::StressTestClass::StressTestClass(emView & view)
2564 : emEngine(view.GetScheduler()), View(view)
2565 {
2566 TCnt=128;
2567 TPos=0;
2568 TValid=0;
2569 T=new emUInt64[TCnt];
2570 FrameRate=0.0;
2571 FRUpdate=0;
2572 WakeUp();
2573 }
2574
2575
~StressTestClass()2576 emView::StressTestClass::~StressTestClass()
2577 {
2578 delete [] T;
2579 }
2580
2581
PaintInfo(const emPainter & painter)2582 void emView::StressTestClass::PaintInfo(const emPainter & painter)
2583 {
2584 char tmp[256];
2585 double x,y,w,h,ch;
2586
2587 sprintf(tmp,"Stress Test\n%5.1f Hz",FrameRate);
2588 x=View.CurrentX;
2589 y=View.CurrentY;
2590 ch=View.CurrentHeight/45;
2591 if (ch<10.0) ch=10.0;
2592 w=painter.GetTextSize(tmp,ch,true,0.0,&h);
2593 painter.PaintRect(x,y,w,h,emColor(255,0,255,128));
2594 painter.PaintTextBoxed(
2595 x,y,w,h,
2596 tmp,
2597 ch,
2598 emColor(255,255,0,192),
2599 0,
2600 EM_ALIGN_CENTER,
2601 EM_ALIGN_CENTER
2602 );
2603 }
2604
2605
Cycle()2606 bool emView::StressTestClass::Cycle()
2607 {
2608 emUInt64 clk,dt;
2609 int i;
2610
2611 clk=emGetClockMS();
2612 TPos=(TPos+1)%TCnt;
2613 T[TPos]=clk;
2614 if (TValid<TCnt) TValid++;
2615 if (clk-FRUpdate>100) {
2616 FrameRate=0.0;
2617 FRUpdate=clk;
2618 for (i=1; i<TValid; i++) {
2619 dt=clk-T[(TPos-i+TCnt)%TCnt];
2620 if (dt>1000 && i>0) break;
2621 FrameRate=(i)*1000.0/dt;
2622 }
2623 }
2624
2625 View.InvalidatePainting();
2626
2627 return true;
2628 }
2629
2630
2631 const double emView::MaxSVPSize=1E+12;
2632 const double emView::MaxSVPSearchSize=1E+14;
2633
2634
2635 //==============================================================================
2636 //================================= emViewPort =================================
2637 //==============================================================================
2638
emViewPort(emView & homeView)2639 emViewPort::emViewPort(emView & homeView)
2640 {
2641 HomeView=&homeView;
2642 CurrentView=&homeView;
2643 if (HomeView->DummyViewPort!=HomeView->HomeViewPort) {
2644 emFatalError("emViewPort: The view has already a view port.");
2645 }
2646 HomeView->HomeViewPort=this;
2647 HomeView->CurrentViewPort=this;
2648 }
2649
2650
~emViewPort()2651 emViewPort::~emViewPort()
2652 {
2653 if (HomeView) {
2654 if (HomeView->DummyViewPort==this) {
2655 emFatalError(
2656 "emViewPort::~emViewPort: Illegal destruction of dummy view port."
2657 );
2658 }
2659 if (HomeView!=CurrentView) {
2660 if (HomeView->PopupWindow) {
2661 HomeView->RawZoomOut();
2662 }
2663 else {
2664 emFatalError(
2665 "emViewPort::~emViewPort: Illegal destruction of popup view port."
2666 );
2667 }
2668 }
2669 HomeView->HomeViewPort=HomeView->DummyViewPort;
2670 HomeView->CurrentViewPort=HomeView->DummyViewPort;
2671 HomeView=NULL;
2672 CurrentView=NULL;
2673 }
2674 }
2675
2676
RequestFocus()2677 void emViewPort::RequestFocus()
2678 {
2679 SetViewFocused(true);
2680 }
2681
2682
IsSoftKeyboardShown() const2683 bool emViewPort::IsSoftKeyboardShown() const
2684 {
2685 return false;
2686 }
2687
2688
ShowSoftKeyboard(bool show)2689 void emViewPort::ShowSoftKeyboard(bool show)
2690 {
2691 }
2692
2693
GetInputClockMS() const2694 emUInt64 emViewPort::GetInputClockMS() const
2695 {
2696 return emGetClockMS();
2697 }
2698
2699
InputToView(emInputEvent & event,const emInputState & state)2700 void emViewPort::InputToView(
2701 emInputEvent & event, const emInputState & state
2702 )
2703 {
2704 if (!CurrentView->FirstVIF) CurrentView->Input(event,state);
2705 else CurrentView->FirstVIF->Input(event,state);
2706 }
2707
2708
InvalidateCursor()2709 void emViewPort::InvalidateCursor()
2710 {
2711 }
2712
2713
InvalidatePainting(double x,double y,double w,double h)2714 void emViewPort::InvalidatePainting(double x, double y, double w, double h)
2715 {
2716 }
2717
2718
IsSoftKeyboardShown()2719 bool emViewPort::IsSoftKeyboardShown()
2720 {
2721 return ((const emViewPort*)this)->IsSoftKeyboardShown();
2722 }
2723
2724
GetInputClockMS()2725 emUInt64 emViewPort::GetInputClockMS()
2726 {
2727 return ((const emViewPort*)this)->GetInputClockMS();
2728 }
2729
2730
emViewPort()2731 emViewPort::emViewPort()
2732 {
2733 HomeView=NULL;
2734 CurrentView=NULL;
2735 }
2736