1 //------------------------------------------------------------------------------
2 // emSvgFilePanel.cpp
3 //
4 // Copyright (C) 2010-2011,2014-2016 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 <emSvg/emSvgFilePanel.h>
22 #include <emCore/emRes.h>
23 #include <emCore/emToolkit.h>
24
25
emSvgFilePanel(ParentArg parent,const emString & name,emSvgFileModel * fileModel,bool updateFileModel)26 emSvgFilePanel::emSvgFilePanel(
27 ParentArg parent, const emString & name, emSvgFileModel * fileModel,
28 bool updateFileModel
29 )
30 : emFilePanel(parent,name),
31 JobDelayTimer(GetScheduler()),
32 IconTimer(GetScheduler())
33 {
34 ServerModel=emSvgServerModel::Acquire(GetRootContext());
35 Job=NULL;
36 JobUpToDate=false;
37 JobDelayStartTime=emGetClockMS();
38 RenderIcon=emGetInsResImage(GetRootContext(),"emPs","rendering.tga");
39 ShowIcon=false;
40 AddWakeUpSignal(GetVirFileStateSignal());
41 AddWakeUpSignal(JobDelayTimer.GetSignal());
42 AddWakeUpSignal(IconTimer.GetSignal());
43 SetFileModel(fileModel,updateFileModel);
44 }
45
46
~emSvgFilePanel()47 emSvgFilePanel::~emSvgFilePanel()
48 {
49 ClearSvgDisplay();
50 }
51
52
SetFileModel(emFileModel * fileModel,bool updateFileModel)53 void emSvgFilePanel::SetFileModel(
54 emFileModel * fileModel, bool updateFileModel
55 )
56 {
57 if (fileModel && (dynamic_cast<emSvgFileModel*>(fileModel))==NULL) {
58 fileModel=NULL;
59 }
60 emFilePanel::SetFileModel(fileModel,updateFileModel);
61 }
62
63
GetIconFileName() const64 emString emSvgFilePanel::GetIconFileName() const
65 {
66 return "drawing.tga";
67 }
68
69
GetEssenceRect(double * pX,double * pY,double * pW,double * pH) const70 void emSvgFilePanel::GetEssenceRect(
71 double * pX, double * pY, double * pW, double * pH
72 ) const
73 {
74 if (IsVFSGood() && RenderError.IsEmpty()) {
75 GetOutputRect(pX,pY,pW,pH);
76 }
77 else {
78 emFilePanel::GetEssenceRect(pX,pY,pW,pH);
79 }
80 }
81
82
Cycle()83 bool emSvgFilePanel::Cycle()
84 {
85 if (IsSignaled(GetVirFileStateSignal())) {
86 InvalidateControlPanel(); //??? very cheap solution, but okay for now.
87 ClearSvgDisplay();
88 }
89
90 UpdateSvgDisplay(false);
91
92 return emFilePanel::Cycle();
93 }
94
95
Notice(NoticeFlags flags)96 void emSvgFilePanel::Notice(NoticeFlags flags)
97 {
98 if (flags&NF_VIEWING_CHANGED) {
99 UpdateSvgDisplay(true);
100 }
101 if (flags&NF_UPDATE_PRIORITY_CHANGED) {
102 if (Job) {
103 ServerModel->SetJobPriority(Job,GetUpdatePriority());
104 }
105 }
106 emFilePanel::Notice(flags);
107 }
108
109
IsOpaque() const110 bool emSvgFilePanel::IsOpaque() const
111 {
112 if (!IsVFSGood()) {
113 return emFilePanel::IsOpaque();
114 }
115 else if (!RenderError.IsEmpty()) {
116 return true;
117 }
118 else {
119 return false;
120 }
121 }
122
123
Paint(const emPainter & painter,emColor canvasColor) const124 void emSvgFilePanel::Paint(const emPainter & painter, emColor canvasColor) const
125 {
126 static const emColor RENDER_COLOR=emColor(0xEEEEFFFF);
127 emSvgFileModel * fm;
128 double fw,fh,ox,oy,ow,oh,sx,sy,sw,sh,ix,iy,iw,ih,t;
129 emColor c;
130
131 if (!IsVFSGood()) {
132 emFilePanel::Paint(painter,canvasColor);
133 return;
134 }
135
136 if (!RenderError.IsEmpty()) {
137 c.Set(128,0,0);
138 painter.Clear(c,canvasColor);
139 painter.PaintTextBoxed(
140 0.05,
141 GetHeight()*0.15,
142 0.9,
143 GetHeight()*0.1,
144 "Rendering Failed",
145 GetHeight()*0.1,
146 emColor(204,136,0),
147 c,
148 EM_ALIGN_CENTER,
149 EM_ALIGN_LEFT,
150 1.0
151 );
152 painter.PaintTextBoxed(
153 0.05,
154 GetHeight()*0.3,
155 0.9,
156 GetHeight()*0.4,
157 RenderError,
158 GetHeight()*0.4,
159 emColor(255,255,0),
160 c,
161 EM_ALIGN_CENTER,
162 EM_ALIGN_LEFT,
163 1.0
164 );
165 return;
166 }
167
168 GetOutputRect(&ox,&oy,&ow,&oh);
169
170 if (Img.IsEmpty()) {
171 painter.PaintRect(
172 ox,oy,ow,oh,
173 RENDER_COLOR,
174 canvasColor
175 );
176 canvasColor=RENDER_COLOR;
177 }
178 else {
179 fm=(emSvgFileModel*)GetFileModel();
180 fw=fm->GetWidth();
181 fh=fm->GetHeight();
182 sx=ox+SrcX*ow/fw;
183 sy=oy+SrcY*oh/fh;
184 sw=SrcW*ow/fw;
185 sh=SrcH*oh/fh;
186 emPainter(
187 painter,
188 painter.GetOriginX()+ox*painter.GetScaleX(),
189 painter.GetOriginY()+oy*painter.GetScaleY(),
190 painter.GetOriginX()+(ox+ow)*painter.GetScaleX(),
191 painter.GetOriginY()+(oy+oh)*painter.GetScaleY()
192 ).PaintImage(
193 sx,sy,sw,sh,
194 Img,
195 255,
196 canvasColor
197 );
198 if (sy>oy) painter.PaintRect(
199 ox,oy,ow,sy-oy,
200 RENDER_COLOR,
201 canvasColor
202 );
203 if (sx>ox) painter.PaintRect(
204 ox,emMax(sy,oy),sx-ox,emMin(sy+sh,oy+oh)-emMax(sy,oy),
205 RENDER_COLOR,
206 canvasColor
207 );
208 if (sx+sw<ox+ow) painter.PaintRect(
209 sx+sw,emMax(sy,oy),ox+ow-sx-sw,emMin(sy+sh,oy+oh)-emMax(sy,oy),
210 RENDER_COLOR,
211 canvasColor
212 );
213 if (sy+sh<oy+oh) painter.PaintRect(
214 ox,sy+sh,ow,oy+oh-sy-sh,
215 RENDER_COLOR,
216 canvasColor
217 );
218 canvasColor=0;
219 }
220
221 if (ShowIcon) {
222 iw=ViewToPanelDeltaX(RenderIcon.GetWidth());
223 if (iw>ow) iw=ow;
224 ih=RenderIcon.GetHeight()*iw/RenderIcon.GetWidth();
225 if (ih>oh) { iw=iw/ih*oh; ih=oh; }
226 t=sqrt(oh*iw/ih)/5;
227 if (iw>t) { ih=ih/iw*t; iw=t; }
228 ix=ViewToPanelX(GetClipX1());
229 iy=ViewToPanelY(GetClipY1());
230 if (ix<ox) ix=ox;
231 if (iy<oy) iy=oy;
232 if (ix>ox+ow-iw) ix=ox+ow-iw;
233 if (iy>oy+oh-ih) iy=oy+oh-ih;
234 painter.PaintImage(ix,iy,iw,ih,RenderIcon,255,canvasColor);
235 }
236 }
237
238
CreateControlPanel(ParentArg parent,const emString & name)239 emPanel * emSvgFilePanel::CreateControlPanel(
240 ParentArg parent, const emString & name
241 )
242 {
243 emSvgFileModel * fm;
244 emLinearLayout * mainLayout;
245 emLinearGroup * grp;
246 emTextField * tf;
247
248 if (IsVFSGood()) {
249 fm=(emSvgFileModel*)GetFileModel();
250 mainLayout=new emLinearLayout(parent,name);
251 mainLayout->SetMinChildTallness(0.03);
252 mainLayout->SetMaxChildTallness(0.6);
253 mainLayout->SetAlignment(EM_ALIGN_TOP_LEFT);
254 grp=new emLinearGroup(
255 mainLayout,
256 "",
257 "SVG File Info"
258 );
259 grp->SetOrientationThresholdTallness(0.07);
260 tf=new emTextField(
261 grp,
262 "title",
263 "Title",
264 emString(),
265 emImage(),
266 fm->GetTitle()
267 );
268 tf->SetMultiLineMode();
269 tf=new emTextField(
270 grp,
271 "desc",
272 "Description",
273 emString(),
274 emImage(),
275 fm->GetDescription()
276 );
277 tf->SetMultiLineMode();
278 tf=new emTextField(
279 grp,
280 "size",
281 "Default Size (Pixels)",
282 emString(),
283 emImage(),
284 emString::Format(
285 "%lg x %lg",
286 fm->GetWidth(),
287 fm->GetHeight()
288 )
289 );
290 return mainLayout;
291 }
292 else {
293 return emFilePanel::CreateControlPanel(parent,name);
294 }
295 }
296
297
GetOutputRect(double * pX,double * pY,double * pW,double * pH) const298 void emSvgFilePanel::GetOutputRect(
299 double * pX, double * pY, double * pW, double * pH
300 ) const
301 {
302 const emSvgFileModel * fm;
303 double x,y,w,h,d,fw,fh;
304
305 if (IsVFSGood()) {
306 fm=(const emSvgFileModel*)GetFileModel();
307 fw=fm->GetWidth();
308 fh=fm->GetHeight();
309 }
310 else {
311 fw=4.0;
312 fh=3.0;
313 }
314 x=0;
315 y=0;
316 w=1;
317 h=GetHeight();
318 if (fw*h>=fh*w) {
319 d=w*fh/fw;
320 y+=(h-d)/2;
321 h=d;
322 }
323 else {
324 d=h*fw/fh;
325 x+=(w-d)/2;
326 w=d;
327 }
328 *pX=x;
329 *pY=y;
330 *pW=w;
331 *pH=h;
332 }
333
334
ClearSvgDisplay()335 void emSvgFilePanel::ClearSvgDisplay()
336 {
337 if (Job) {
338 ServerModel->CloseJob(Job);
339 Job=NULL;
340 }
341 if (!JobImg.IsEmpty()) {
342 JobImg.Clear();
343 }
344 if (!Img.IsEmpty()) {
345 Img.Clear();
346 InvalidatePainting();
347 }
348 if (!RenderError.IsEmpty()) {
349 RenderError.Clear();
350 InvalidatePainting();
351 }
352 JobUpToDate=false;
353 IconTimer.Stop(true);
354 ShowIcon=false;
355 }
356
357
UpdateSvgDisplay(bool viewingChanged)358 void emSvgFilePanel::UpdateSvgDisplay(bool viewingChanged)
359 {
360 emSvgFileModel * fm;
361 double fw,fh,ox,oy,ow,oh,ix,iy,iw,ih,sx,sy,sw,sh,qx1,qx2,qy1,qy2,q;
362 emUInt64 tm,dt;
363
364 if (!IsVFSGood()) return;
365 if (!RenderError.IsEmpty()) return;
366 if (!IsViewed()) return;
367
368 if (JobUpToDate) JobDelayStartTime=emGetClockMS();
369 if (viewingChanged) JobUpToDate=false;
370
371 if (Job) {
372 switch (ServerModel->GetJobState(Job)) {
373 case emSvgServerModel::JS_WAITING:
374 case emSvgServerModel::JS_RUNNING:
375 if (!ShowIcon && !IconTimer.IsRunning()) {
376 ShowIcon=true;
377 InvalidatePainting();
378 }
379 return;
380 case emSvgServerModel::JS_ERROR:
381 RenderError=ServerModel->GetJobErrorText(Job);
382 if (RenderError.IsEmpty()) RenderError="unknown error";
383 ServerModel->CloseJob(Job);
384 Job=NULL;
385 JobImg.Clear();
386 Img.Clear();
387 JobUpToDate=false;
388 IconTimer.Stop(true);
389 ShowIcon=false;
390 InvalidatePainting();
391 return;
392 case emSvgServerModel::JS_SUCCESS:
393 ServerModel->CloseJob(Job);
394 Job=NULL;
395 Img=JobImg;
396 SrcX=JobSrcX;
397 SrcY=JobSrcY;
398 SrcW=JobSrcW;
399 SrcH=JobSrcH;
400 JobImg.Clear();
401 if (JobUpToDate) {
402 IconTimer.Stop(true);
403 ShowIcon=false;
404 }
405 JobDelayStartTime=emGetClockMS();
406 InvalidatePainting();
407 break;
408 }
409 }
410
411 if (JobUpToDate) return;
412
413 fm=(emSvgFileModel*)GetFileModel();
414 fw=fm->GetWidth();
415 fh=fm->GetHeight();
416
417 GetOutputRect(&ox,&oy,&ow,&oh);
418 ox=PanelToViewX(ox);
419 oy=PanelToViewY(oy);
420 ow=PanelToViewDeltaX(ow);
421 oh=PanelToViewDeltaY(oh);
422
423 ix=floor(emMax(GetClipX1(),ox));
424 iy=floor(emMax(GetClipY1(),oy));
425 iw=ceil(emMin(GetClipX2(),ox+ow))-ix;
426 ih=ceil(emMin(GetClipY2(),oy+oh))-iy;
427
428 sx=(ix-ox)*fw/ow;
429 sy=(iy-oy)*fh/oh;
430 sw=iw*fw/ow;
431 sh=ih*fh/oh;
432
433 if (iw<1.0 || ih<1.0) {
434 Img.Clear();
435 SrcX=sx;
436 SrcY=sy;
437 SrcW=sw;
438 SrcH=sh;
439 InvalidatePainting();
440 JobUpToDate=true;
441 return;
442 }
443
444 if (!Img.IsEmpty()) {
445 qx1=emMax(SrcX,sx);
446 qx2=emMin(SrcX+SrcW,sx+sw);
447 qy1=emMax(SrcY,sy);
448 qy2=emMin(SrcY+SrcH,sy+sh);
449 if (qx2<qx1) qx2=qx1;
450 if (qy2<qy1) qy2=qy1;
451 q=(qx2-qx1)*(qy2-qy1)/(sw*sh);
452 q=(q-0.9)*10.0;
453 if (q>0.0 && Img.GetWidth()/SrcW>0.9*iw/sw) {
454 dt=(emUInt64)(q*q*500.0+0.5);
455 tm=emGetClockMS();
456 if (JobDelayStartTime+dt>tm) {
457 JobDelayTimer.Start(JobDelayStartTime+dt-tm);
458 return;
459 }
460 }
461 }
462
463 JobSrcX=sx;
464 JobSrcY=sy;
465 JobSrcW=sw;
466 JobSrcH=sh;
467 JobImg.Setup((int)(iw+0.5),(int)(ih+0.5),3);
468
469 Job=ServerModel->StartRenderJob(
470 fm->GetSvgHandle(),
471 JobSrcX,
472 JobSrcY,
473 JobSrcW,
474 JobSrcH,
475 emColor(0xffffffff),
476 &JobImg,
477 GetUpdatePriority(),
478 this
479 );
480 if (!ShowIcon) IconTimer.Start(500);
481 JobUpToDate=true;
482 }
483