1 #include "GeomCtrl.h"
2 
3 namespace Upp {
4 
5 #define IMAGECLASS PlotterImg
6 #define IMAGEFILE  <Geom/Ctrl/PlotterCtrl.iml>
7 #include           <Draw/iml.h>
8 
9 #define LLOG(x) RLOG(x)
10 #define LLOGBLOCK(x) RLOGBLOCK(x)
11 
ViewPlot(PlotterCtrl & ctrl,int extra_gap)12 PlotterCtrl::ViewPlot::ViewPlot(PlotterCtrl& ctrl, int extra_gap)
13 : viewdraw(&ctrl)
14 {
15 	Plotter::Set(viewdraw, ctrl.scale, ctrl.delta, extra_gap);
16 	PathMap(&PathStyleMap::App());
17 }
18 
ViewPlot(PlotterCtrl & ctrl,Pointf scale,Pointf delta,int extra_gap)19 PlotterCtrl::ViewPlot::ViewPlot(PlotterCtrl& ctrl, Pointf scale, Pointf delta, int extra_gap)
20 : viewdraw(&ctrl)
21 {
22 	Plotter::Set(viewdraw, scale, delta, extra_gap);
23 	PathMap(&PathStyleMap::App());
24 }
25 
ViewPlot(PlotterCtrl & ctrl,const Matrixf & preform,int extra_gap)26 PlotterCtrl::ViewPlot::ViewPlot(PlotterCtrl& ctrl, const Matrixf& preform, int extra_gap)
27 : viewdraw(&ctrl)
28 {
29 	Plotter::Set(viewdraw, ctrl.scale, ctrl.delta, extra_gap);
30 	Plotter::Set(viewdraw, preform * physical, extra_gap);
31 	PathMap(&PathStyleMap::App());
32 }
33 
PlotterCtrl()34 PlotterCtrl::PlotterCtrl()
35 : extent(Null)
36 , scale(1, 1)
37 , delta(0, 0)
38 , push_scale(1, 1)
39 , push_delta(0, 0)
40 , max_scale(Null, Null)
41 , aspect(1)
42 , enable_lock(true)
43 , gap(10, 10, 10, 10)
44 , rev_x(false)
45 , rev_y(false)
46 , aspect_lock(false)
47 , halign(ALIGN_CENTER)
48 , valign(ALIGN_CENTER)
49 , old_size(Null)
50 //, paint_draw(NULL)
51 , buffer_paint(false)
52 , buffer_pan(false)
53 , pan_offset(0, 0)
54 , show_scroll(true)
55 , lock_drag_drop(false)
56 , lock_short_drag_drop(false)
57 , is_painting(false)
58 , background(White())
59 , drag_mode(DRAG_NONE)
60 , reset_push(false)
61 {
62 	hscroll  .NoAutoHide().NoAutoDisable();
63 	vscroll  .NoAutoHide().NoAutoDisable();
64 	horz_in  .SetImage(PlotterImg::view_zoom_in())       .NoWantFocus() <<= THISBACK(UserZoomInX);
65 	horz_out .SetImage(PlotterImg::view_zoom_out())      .NoWantFocus() <<= THISBACK(UserZoomOutX);
66 	horz_full.SetImage(PlotterImg::view_zoom_horz_full()).NoWantFocus() <<= THISBACK(UserZoomFullX);
67 	vert_in  .SetImage(PlotterImg::view_zoom_in())       .NoWantFocus() <<= THISBACK(UserZoomInY);
68 	vert_out .SetImage(PlotterImg::view_zoom_out())      .NoWantFocus() <<= THISBACK(UserZoomOutY);
69 	vert_full.SetImage(PlotterImg::view_zoom_vert_full()).NoWantFocus() <<= THISBACK(UserZoomFullY);
70 	full     .SetImage(PlotterImg::view_zoom_full_icon()).NoWantFocus() <<= THISBACK(UserZoomFull);
71 	AddFrame(*this);
72 	hscroll <<= THISBACK(OnHScroll);
73 	vscroll <<= THISBACK(OnVScroll);
74 	hscroll.WhenLeftClick = vscroll.WhenLeftClick = THISBACK(DoSetFocus);
75 	hscroll.SetLine(50);
76 	vscroll.SetLine(50);
77 }
78 
~PlotterCtrl()79 PlotterCtrl::~PlotterCtrl() {}
80 
Layout()81 void PlotterCtrl::Layout()
82 {
83 	Size phys_size(0, 0);
84 	if(extent.right > extent.left)
85 		phys_size.cx = fround(fabs(extent.Width() * scale.cx));
86 	if(extent.bottom > extent.top)
87 		phys_size.cy = fround(fabs(extent.Height() * scale.cy));
88 	Size ocli = old_size;
89 	Size cli = old_size = GetSize();
90 	phys_size += gap.TopLeft() + gap.BottomRight();
91 	hscroll.Set(hscroll, cli.cx, phys_size.cx);
92 	vscroll.Set(vscroll, cli.cy, phys_size.cy);
93 	if(!IsNull(ocli))
94 	{
95 		Size dlog = cli - ocli;
96 		Pointf pos = delta;
97 		switch(halign)
98 		{
99 		case ALIGN_LEFT:  break;
100 		default:          pos.x += dlog.cx * 0.5; break;
101 		case ALIGN_RIGHT: pos.x += dlog.cx; break;
102 		}
103 		switch(valign)
104 		{
105 		case ALIGN_TOP:    break;
106 		default:           pos.y += dlog.cy * 0.5; break;
107 		case ALIGN_BOTTOM: pos.y += dlog.cy; break;
108 		}
109 		if(pos != delta)
110 		{
111 			SetDelta(pos);
112 			WhenZoom();
113 		}
114 	}
115 	RefreshBuffer();
116 }
117 
FrameAdd(Ctrl & ctrl)118 void PlotterCtrl::FrameAdd(Ctrl& ctrl)
119 {
120 	ctrl
121 	<< (Ctrl&)vscroll << vert_in << vert_out << vert_full
122 	<< (Ctrl&)hscroll << horz_in << horz_out << horz_full
123 	<< full;
124 }
125 
FrameRemove()126 void PlotterCtrl::FrameRemove()
127 {
128 	vscroll.Remove();
129 	vert_in.Remove();
130 	vert_out.Remove();
131 	vert_full.Remove();
132 	hscroll.Remove();
133 	horz_in.Remove();
134 	horz_out.Remove();
135 	horz_full.Remove();
136 	full.Remove();
137 }
138 
FrameLayout(Rect & rc)139 void PlotterCtrl::FrameLayout(Rect& rc)
140 {
141 	int box = (show_scroll ? ScrollBarSize() : 0);
142 	Rect out = rc;
143 	rc.right -= box;
144 	rc.bottom -= box;
145 	int sbx = (IsAspectLocked() ? 0 : box);
146 	vscroll  .SetFrameRect(rc.right, rc.top, box, rc.Height() - 3 * sbx);
147 	vert_in  .SetFrameRect(rc.right, rc.bottom - 3 * sbx, box, sbx);
148 	vert_in  .Enable(sbx);
149 	vert_out .SetFrameRect(rc.right, rc.bottom - 2 * sbx, box, sbx);
150 	vert_out .Enable(sbx);
151 	vert_full.SetFrameRect(rc.right, rc.bottom - sbx, box, sbx);
152 	hscroll  .SetFrameRect(rc.left, rc.bottom, rc.Width() - 3 * sbx, box);
153 	horz_in  .SetFrameRect(rc.right - 3 * sbx, rc.bottom, sbx, box);
154 	horz_in  .Enable(sbx);
155 	horz_out .SetFrameRect(rc.right - 2 * sbx, rc.bottom, sbx, box);
156 	horz_out .Enable(sbx);
157 	horz_full.SetFrameRect(rc.right - sbx, rc.bottom, sbx, box);
158 	full     .SetFrameRect(rc.right, rc.bottom, box, box);
159 	full     .SetImage(sbx ? PlotterImg::view_zoom_full_icon_old() : PlotterImg::view_zoom_full_icon());
160 }
161 
FrameAddSize(Size & sz)162 void PlotterCtrl::FrameAddSize(Size& sz)
163 {
164 	int box = (show_scroll ? ScrollBarSize() : 0);
165 	sz += box;
166 }
167 
FromClient(const Rect & rc) const168 Rectf PlotterCtrl::FromClient(const Rect& rc) const
169 {
170 	if(IsNull(rc))
171 		return Null;
172 	Rectf c = (Rectf(rc) - delta) / scale;
173 	if(scale.cx < 0)
174 		Swap(c.left, c.right);
175 	if(scale.cy < 0)
176 		Swap(c.top,  c.bottom);
177 	return c;
178 }
179 
ToClient(const Rectf & rc) const180 Rect PlotterCtrl::ToClient(const Rectf& rc) const
181 {
182 	if(IsNull(rc))
183 		return Null;
184 	Rect out = RectfToRect(rc * scale + delta);
185 	if(scale.cx < 0)
186 		Swap(out.left, out.right);
187 	if(scale.cy < 0)
188 		Swap(out.top, out.bottom);
189 	return out;
190 }
191 
GetAvgScale() const192 double PlotterCtrl::GetAvgScale() const
193 {
194 	return (fabs(scale.cx) + fabs(scale.cy)) * 0.5;
195 }
196 
SetAspectRatio(double a)197 void PlotterCtrl::SetAspectRatio(double a)
198 {
199 	aspect = a;
200 	ZoomFull();
201 	WhenRescan();
202 }
203 
EnableLock(bool e)204 void PlotterCtrl::EnableLock(bool e)
205 {
206 	enable_lock = e;
207 	WhenRescan();
208 }
209 
SetExtent(const Rectf & e)210 void PlotterCtrl::SetExtent(const Rectf& e)
211 {
212 	if(e != extent)
213 	{
214 		extent = e;
215 		Pointf d = delta;
216 		Layout();
217 		SetDelta(d);
218 	}
219 }
220 
PanOffset(Point o)221 void PlotterCtrl::PanOffset(Point o)
222 {
223 	if(pan_offset != o) {
224 		pan_offset = o;
225 		Refresh();
226 	}
227 }
228 
ScrollInto(Rectf rc)229 void PlotterCtrl::ScrollInto(Rectf rc)
230 {
231 	Rectf view = GetViewRect();
232 	Sizef shift(0, 0);
233 	if(rc.Width() > view.Width())
234 		shift.cx = (rc.left + rc.right - view.left - view.right) / 2;
235 	else if(rc.left < view.left)
236 		shift.cx = rc.left - view.left;
237 	else if(rc.right > view.right)
238 		shift.cx = rc.right - view.right;
239 	if(rc.Height() > view.Height())
240 		shift.cy = (rc.top + rc.bottom - view.top - view.bottom) / 2;
241 	else if(rc.top < view.top)
242 		shift.cy = rc.top - view.top;
243 	else if(rc.bottom > view.bottom)
244 		shift.cy = rc.bottom - view.bottom;
245 	if(shift.cx || shift.cy)
246 	{
247 		Pointf new_pos = delta - shift * scale;
248 		AdjustPos(new_pos, Point(Null));
249 		if(new_pos != delta)
250 			SetDelta(new_pos);
251 	}
252 }
253 
ScrollInto(Pointf pt)254 void PlotterCtrl::ScrollInto(Pointf pt)
255 {
256 	ScrollInto(Rectf(pt, Sizef(0, 0)));
257 }
258 
SetScale(Sizef s)259 void PlotterCtrl::SetScale(Sizef s)
260 {
261 	Size half = GetSize() >> 1;
262 	Pointf mid = FromClient(Point(half));
263 	SetZoom(s, Sizef(half) - Sizef(mid) * s);
264 }
265 
SetDelta(Pointf d)266 void PlotterCtrl::SetDelta(Pointf d)
267 {
268 	LLOG("PlotterCtrl::SetDelta");
269 	DragHide();
270 	delta = d;
271 //	AdjustPos(delta, Null);
272 	if(!IsNull(extent))
273 	{
274 		Rectf sx = extent * scale;
275 		if(scale.cx < 0) Swap(sx.left, sx.right);
276 		if(scale.cy < 0) Swap(sx.top, sx.bottom);
277 		Size sb(gap.left - fround(delta.x + sx.left), gap.top - fround(delta.y + sx.top));
278 		hscroll.Set(sb.cx);
279 		vscroll.Set(sb.cy);
280 		RefreshBuffer();
281 		UpdateMousePos();
282 	}
283 }
284 
SetZoom(Sizef s,Pointf d)285 void PlotterCtrl::SetZoom(Sizef s, Pointf d)
286 {
287 	Sizef mid(GetSize() >> 1);
288 	scale = AdjustScale(s);
289 	Layout();
290 	SetDelta(mid - (mid - d) * (scale / s));
291 	WhenZoom();
292 	WhenRescan();
293 }
294 
SetZoom(double s,Pointf d)295 void PlotterCtrl::SetZoom(double s, Pointf d)
296 {
297 	ASSERT(IsAspectLocked());
298 	double a = (aspect_lock ? 1 : aspect);
299 	SetZoom(Sizef(rev_x ? -s : s, (rev_y ? -s : s) * a), d);
300 	Layout();
301 	SetDelta(d);
302 	WhenZoom();
303 	WhenRescan();
304 }
305 
GetPhysicalZoom() const306 Sizef PlotterCtrl::GetPhysicalZoom() const
307 {
308 	Size client = GetSize();
309 	Size ppm = GetPixelsPerMeter(ScreenInfo());
310 	Sizef vrc = fpmax(GetViewRect().Size(), Sizef(1e-20, 1e-20));
311 	return Sizef(client) / Sizef(ppm) / vrc;
312 }
313 
AdjustScale(Sizef sc) const314 Sizef PlotterCtrl::AdjustScale(Sizef sc) const
315 {
316 	if(max_scale.cx > 0 && fabs(sc.cx) >= max_scale.cx)
317 		sc.cx = (sc.cx >= 0 ? max_scale.cx : -max_scale.cx);
318 	if(max_scale.cy > 0 && fabs(sc.cy) >= max_scale.cy)
319 		sc.cy = (sc.cy >= 0 ? max_scale.cy : -max_scale.cy);
320 	return sc;
321 }
322 
AdjustPos(Pointf & d,Point scpos) const323 void PlotterCtrl::AdjustPos(Pointf& d, Point scpos) const
324 {
325 	Rectf c = extent * scale;
326 	if(rev_x)
327 		Swap(c.left, c.right);
328 	if(rev_y)
329 		Swap(c.top, c.bottom);
330 	Size sz = GetSize();
331 	if(c.Width() <= sz.cx - gap.left - gap.right)
332 		switch(halign)
333 		{
334 		case ALIGN_LEFT:   d.x = gap.left - c.left; break;
335 		default:           d.x = (sz.cx + gap.left - gap.right - c.left - c.right) / 2; break;
336 		case ALIGN_RIGHT:  d.x = sz.cx - gap.right - c.right; break;
337 		}
338 	else
339 	{
340 		if(!IsNull(scpos))
341 			d.x = gap.left - scpos.x - c.left;
342 		d.x = minmax(d.x, sz.cx - gap.right - c.right, gap.left - c.left);
343 	}
344 	if(c.Height() <= sz.cy - gap.top - gap.bottom)
345 		switch(valign)
346 		{
347 		case ALIGN_TOP:    d.y = gap.top - c.top; break;
348 		default:           d.y = (sz.cy + gap.top - gap.bottom - c.top - c.bottom) / 2; break;
349 		case ALIGN_BOTTOM: d.y = sz.cy - gap.top - c.bottom; break;
350 		}
351 	else
352 	{
353 		if(!IsNull(scpos))
354 			d.y = gap.top - scpos.y - c.top;
355 		d.y = minmax(d.y, sz.cy - gap.bottom - c.bottom, gap.top - c.top);
356 	}
357 }
358 
AdjustPos(Point scpos,int xymask)359 void PlotterCtrl::AdjustPos(Point scpos, int xymask)
360 {
361 	if(!IsNull(extent))
362 	{
363 		Pointf d = delta;
364 		AdjustPos(d, scpos);
365 		if(xymask & 1) delta.x = d.x;
366 		if(xymask & 2) delta.y = d.y;
367 		RefreshBuffer();
368 		UpdateMousePos();
369 	}
370 }
371 
OnHScroll()372 void PlotterCtrl::OnHScroll()
373 {
374 	AdjustPos(Point(hscroll, vscroll), 1);
375 	WhenUserZoom();
376 }
377 
OnVScroll()378 void PlotterCtrl::OnVScroll()
379 {
380 	AdjustPos(Point(hscroll, vscroll), 2);
381 	WhenUserZoom();
382 }
383 
GetSc() const384 Pointf PlotterCtrl::GetSc() const
385 {
386 //	if(IsNull(extent))
387 //		return Pointf(0, 0);
388 	Pointf sc;
389 	Size cli = GetSize();
390 //	if(fabs(extent.Width() * scale.cx) <= cli.cx - gap.left - gap.right)
391 //		sc.x = (extent.left + extent.right) / 2;
392 //	else
393 	sc.x = ((cli.cx >> 1) - delta.x) / scale.cx;
394 //	if(fabs(extent.Height() * scale.cy) <= cli.cy - gap.top - gap.bottom)
395 //		sc.y = (extent.top + extent.bottom) / 2;
396 //	else
397 	sc.y = ((cli.cy >> 1) - delta.y) / scale.cy;
398 	return sc;
399 }
400 
SetSc(Pointf center)401 void PlotterCtrl::SetSc(Pointf center)
402 {
403 	if(!IsNull(center) && !IsNull(extent))
404 		SetDelta(Sizef(GetSize() >> 1) - Sizef(center) * scale);
405 }
406 
SetZoomSc(Sizef new_scale)407 void PlotterCtrl::SetZoomSc(Sizef new_scale)
408 {
409 	new_scale = AdjustScale(new_scale);
410 	SetZoom(new_scale, Sizef(GetSize() >> 1) - Sizef(GetSc()) * new_scale);
411 }
412 
SetZoomSc(double s)413 void PlotterCtrl::SetZoomSc(double s)
414 {
415 	ASSERT(IsAspectLocked());
416 	SetZoomSc(rev_x ? -s : s, (rev_y ? -s : s) * (aspect_lock ? 1 : aspect));
417 }
418 
SetAspectLock(bool a)419 void PlotterCtrl::SetAspectLock(bool a)
420 {
421 	aspect_lock = a;
422 	RefreshParentLayout();
423 	if(IsAspectLocked())
424 		Zoom(GetViewRect(), false, true);
425 	WhenRescan();
426 }
427 
ZoomInX()428 void PlotterCtrl::ZoomInX()
429 {
430 	SetZoomSc(scale.cx * 2, scale.cy);
431 }
432 
ZoomOutX()433 void PlotterCtrl::ZoomOutX()
434 {
435 	SetZoomSc(scale.cx / 2, scale.cy);
436 }
437 
ZoomX(double min,double max,bool add_gap)438 void PlotterCtrl::ZoomX(double min, double max, bool add_gap)
439 {
440 	if(min != max)
441 	{
442 		int gl = (add_gap ? gap.left : 0), gr = (add_gap ? gap.right : 0);
443 		int s = GetSize().cx;
444 		double sc = (rev_x ? -1 : 1) * (s - gl - gr) / (max - min);
445 		double dx = (rev_x ? s - gr : gl) - sc * min;
446 		SetZoom(Pointf(sc, scale.cy), Pointf(dx, delta.y));
447 	}
448 }
449 
ZoomInY()450 void PlotterCtrl::ZoomInY()
451 {
452 	SetZoomSc(scale.cx, scale.cy * 2);
453 }
454 
ZoomOutY()455 void PlotterCtrl::ZoomOutY()
456 {
457 	SetZoomSc(scale.cx, scale.cy / 2);
458 }
459 
ZoomY(double min,double max,bool add_gap)460 void PlotterCtrl::ZoomY(double min, double max, bool add_gap)
461 {
462 	if(min != max) {
463 		int gt = (add_gap ? gap.top : 0), gb = (add_gap ? gap.bottom : 0);
464 		int s = GetSize().cy;
465 		double sc = (rev_y ? -1 : 1) * (s - gt - gb) / (max - min);
466 		double dx = (rev_y ? s - gb : gt) - sc * min;
467 		SetZoom(Pointf(scale.cx, sc), Pointf(delta.x, dx));
468 	}
469 }
470 
Zoom(const Rectf & rc,bool keep_ratio,bool add_gap)471 void PlotterCtrl::Zoom(const Rectf& rc, bool keep_ratio, bool add_gap)
472 {
473 	if(rc.right < rc.left && rc.bottom < rc.top)
474 		return;
475 	Rectf tmp = rc;
476 	if(tmp.right  < tmp.left) tmp.left = tmp.right  = 0;
477 	if(tmp.bottom < tmp.top)  tmp.top  = tmp.bottom = 0;
478 	Rect g = (add_gap ? gap : Rect(0, 0, 0, 0));
479 	double use_aspect = (aspect_lock ? 1.0 : aspect);
480 	if(use_aspect || keep_ratio) {
481 		Size avail = GetSize() - g.TopLeft() - g.BottomRight();
482 		Sizef size = tmp.Size();
483 		double d = Abs(size * scale) % Sizef(avail);
484 		if(d >= 0) {
485 			d /= 2 * avail.cx * fabs(scale.cy);
486 			tmp.top -= d;
487 			tmp.bottom += d;
488 		}
489 		else {
490 			d /= -2 * avail.cy * fabs(scale.cx);
491 			tmp.left -= d;
492 			tmp.right += d;
493 		}
494 	}
495 	if(use_aspect) {
496 		Rect inset = Rect(GetSize()).Deflated(g);
497 		Point inc = inset.CenterPoint();
498 		Sizef sc;
499 		Pointf dl;
500 		sc.cx = tmp.Width() <= 1e-20 ? scale.cx : inset.Width() / tmp.Width();
501 		sc.cy = sc.cx * use_aspect;
502 		if(rev_x) { sc.cx = -sc.cx; Swap(tmp.left, tmp.right); }
503 		if(rev_y) { sc.cy = -sc.cy; Swap(tmp.top, tmp.bottom); }
504 		Pointf tmpc = tmp.CenterPoint();
505 		switch(halign) {
506 			case ALIGN_LEFT:   dl.x = inset.left - sc.cx * tmp.left; break;
507 			case ALIGN_RIGHT:  dl.x = inset.right - sc.cx * tmp.right; break;
508 			default:           dl.x = inc.x - sc.cx * tmpc.x; break;
509 		}
510 		switch(valign) {
511 			case ALIGN_TOP:    dl.y = inset.top - sc.cy * tmp.top; break;
512 			case ALIGN_BOTTOM: dl.y = inset.bottom - sc.cy * tmp.bottom; break;
513 			default:           dl.y = inc.y - sc.cy * tmpc.y; break;
514 		}
515 		SetZoom(sc, dl);
516 //		AdjustPos(Null);
517 	}
518 	else {
519 		if(rc.left < rc.right)  ZoomX(tmp.left, tmp.right);
520 		if(rc.top  < rc.bottom) ZoomY(tmp.top,  tmp.bottom);
521 	}
522 }
523 
BeginBufferPaint()524 ImageDraw& PlotterCtrl::BeginBufferPaint()
525 {
526 	LLOGBLOCK("PlotterCtrl::BeginBufferPaint");
527 	ASSERT(!is_painting);
528 	paint_buffer = Null;
529 	Size sz = max(GetSize(), Size(1, 1));
530 //	paint_buffer = Image(max(GetSize(), Size(1, 1)));
531 	LLOG("-> size = " << sz);
532 	paint_draw = new ImageDraw(sz);
533 	paint_draw->DrawRect(sz, background);
534 	is_painting = true;
535 	abort_repaint = false;
536 	return *paint_draw;
537 }
538 
EndBufferPaint()539 void PlotterCtrl::EndBufferPaint()
540 {
541 	LLOGBLOCK("PlotterCtrl::EndBufferPaint");
542 	ASSERT(is_painting);
543 	Plotter plotter(*paint_draw, scale, delta);
544 	plotter.PathMap(&PathStyleMap::App());
545 	if(drag_drop) {
546 		lock_drag_drop = true;
547 		drag_drop->Plot(plotter);
548 		lock_drag_drop = false;
549 	}
550 	if(abort_repaint) {
551 		RLOG("PlotterCtrl::EndBufferPaint -> abort_repaint");
552 	}
553 	else
554 		paint_buffer = *paint_draw;
555 	paint_draw.Clear();
556 	is_painting = false;
557 	//PostRefresh();
558 }
559 
PostRefresh()560 void PlotterCtrl::PostRefresh()
561 {
562 	tcb_refresh.KillSet(1, THISBACK(Refresh0));
563 }
564 
Paint(Draw & draw)565 void PlotterCtrl::Paint(Draw& draw)
566 {
567 	int level = draw.GetCloffLevel();
568 	try {
569 		LLOGBLOCK("PlotterCtrl::Paint");
570 		bool shown = IsDragging();
571 		Rect clip = draw.GetPaintRect();
572 		LLOG("PlotterCtrl::Paint @ " << GetSysTime() << ": level = " << level
573 		<< ", rect = " << clip << ", dragging = " << shown << ", painting = " << is_painting);
574 		DragHide();
575 		if(is_painting) {
576 	#ifdef PLATFORM_WIN32
577 			if(!paint_buffer.IsEmpty()) {
578 				LLOG("-> blit paint_buffer");
579 				SystemDraw *sdraw = dynamic_cast<SystemDraw *>(&draw);
580 				if(!sdraw || !BitBlt(*sdraw, pan_offset, *paint_draw, paint_buffer.GetSize())) {
581 					LLOG("-> blit error");
582 				}
583 			}
584 	#endif
585 		}
586 		else {
587 			if(buffer_paint && !draw.Dots()) {
588 				Size size = GetSize();
589 				if(paint_buffer.IsEmpty() || paint_buffer.GetSize() != size) {
590 					LLOG("-> refresh paint buffer");
591 					Draw& idraw = BeginBufferPaint();
592 					try {
593 						Plotter plotter(idraw, scale, delta);
594 						plotter.PathMap(&PathStyleMap::App());
595 						Plot(plotter);
596 					}
597 					catch(Exc e) {
598 						RLOG("PlotterCtrl::Paint: exception in Plot: " << e);
599 					}
600 					catch(...) {
601 						RLOG("PlotterCtrl::Paint: unknown exception in Plot");
602 					}
603 					EndBufferPaint();
604 				}
605 				if(!paint_buffer.IsEmpty() && paint_buffer.GetSize() == size) {
606 					LLOG("-> DrawImage paint_buffer");
607 					draw.DrawImage(pan_offset.x, pan_offset.y, paint_buffer);
608 				}
609 			}
610 			else {
611 				LLOG("-> Plot (direct)");
612 				draw.DrawRect(clip, background);
613 				Plotter plotter(draw, scale, delta + Pointf(pan_offset));
614 				plotter.PathMap(&PathStyleMap::App());
615 				Plot(plotter);
616 				if(drag_drop) {
617 					lock_drag_drop = true;
618 					drag_drop->Plot(plotter);
619 					lock_drag_drop = false;
620 				}
621 			}
622 		}
623 		if(shown)
624 			DragShow();
625 	}
626 	catch(Exc e) {
627 		RLOG("PlotterCtrl::Paint: exception: " << e);
628 	}
629 	RLOG("//PlotterCtrl::Paint: level = " << draw.GetCloffLevel());
630 	ASSERT(level == draw.GetCloffLevel());
631 }
632 
633 /*
634 void PlotterCtrl::AsyncPaint()
635 {
636 	if(paint_draw && !paint_buffer.IsEmpty())
637 	{
638 //		ViewDraw vdraw(this);
639 //		BitBlt(vdraw, Point(0, 0), *paint_draw, paint_buffer.GetRect());
640 	}
641 }
642 */
643 
RefreshBuffer()644 void PlotterCtrl::RefreshBuffer()
645 {
646 	LLOGBLOCK("PlotterCtrl::RefreshBuffer");
647 	if(IsBufferPaint()) {
648 		if(!is_painting)
649 			paint_buffer.Clear();
650 		else {
651 			RLOG("PlotterCtrl::RefreshBuffer / is_painting -> abort_repaint");
652 			abort_repaint = true;
653 			AbortPlot();
654 		}
655 	}
656 	Refresh();
657 }
658 
RefreshBuffer(const Rect & rc)659 void PlotterCtrl::RefreshBuffer(const Rect& rc)
660 {
661 	LLOGBLOCK("PlotterCtrl::RefreshBuffer");
662 	if(IsBufferPaint()) {
663 		if(!is_painting)
664 			paint_buffer.Clear();
665 		else {
666 			RLOG("PlotterCtrl::RefreshBuffer(rc) / is_painting -> abort_repaint");
667 			abort_repaint = true;
668 			AbortPlot();
669 		}
670 	}
671 	Refresh(rc);
672 }
673 
CursorImage(Point pt,dword keyflags)674 Image PlotterCtrl::CursorImage(Point pt, dword keyflags)
675 {
676 	Image out = Image::Arrow();
677 	int dm = drag_mode;
678 	if(!IsDragging()) {
679 		dm = (drag_drop ? DRAG_CUSTOM
680 		: keyflags & K_SHIFT ? DRAG_ZOOM_IN
681 		: keyflags & K_CTRL ? DRAG_ZOOM_OUT
682 		: DRAG_PAN);
683 	}
684 
685 	switch(dm) {
686 		case DRAG_CUSTOM: {
687 			lock_drag_drop = true;
688 			out = drag_drop->Cursor(FromClient(pt), keyflags, IsDragging());
689 			lock_drag_drop = false;
690 			break;
691 		}
692 		case DRAG_ZOOM_IN: {
693 			out = PlotterImg::view_zoom_in();
694 			break;
695 		}
696 		case DRAG_ZOOM_OUT: {
697 			out = PlotterImg::view_zoom_out();
698 			break;
699 		}
700 		case DRAG_PAN: {
701 			if(IsDragging())
702 				out = PlotterImg::view_pan();
703 			break;
704 		}
705 	}
706 
707 	return out;
708 }
709 
SyncPush()710 void PlotterCtrl::SyncPush()
711 {
712 	push_scale = scale;
713 	push_delta = delta;
714 }
715 
Push(Point pt,dword keyflags)716 bool PlotterCtrl::Push(Point pt, dword keyflags)
717 {
718 	bool push = false;
719 	reset_push = false;
720 	SyncPush();
721 	drag_start = FromPushClient(pt);
722 	if(drag_drop && drag_drop->Push(drag_start, keyflags))
723 		drag_mode = DRAG_CUSTOM;
724 	else if(!reset_push && keyflags & K_MOUSELEFT) {
725 		if(keyflags & K_SHIFT)
726 			drag_mode = DRAG_ZOOM_IN;
727 		else if(keyflags & K_CTRL)
728 			drag_mode = DRAG_ZOOM_OUT;
729 		else
730 			drag_mode = DRAG_PAN;
731 	}
732 	else
733 		drag_mode = DRAG_NONE;
734 	return true;
735 }
736 
Drag(Point start,Point prev,Point curr,dword keyflags)737 void PlotterCtrl::Drag(Point start, Point prev, Point curr, dword keyflags)
738 {
739 	LLOG("PlotterCtrl::Drag(" << start << "; prev = " << prev << ", curr = " << curr << ", flags = " << FormatIntHex(keyflags));
740 //	LLOG("PlotterCtrl::Drag, short = " << ~short_drag_drop << ", " << (~short_drag_drop
741 //		? typeid(*short_drag_drop).name() : "NULL") << ", long = " << ~drag_drop << ", "
742 //		<< (~drag_drop ? typeid(*drag_drop).name() : "NULL"));
743 	switch(drag_mode) {
744 		case DRAG_ZOOM_IN:
745 		case DRAG_ZOOM_OUT: {
746 			Rect rc_prev = Null, rc_curr = Null;
747 			if(!IsNull(prev)) rc_prev = RectSort(start, prev);
748 			if(!IsNull(curr)) rc_curr = RectSort(start, curr);
749 			ViewDraw draw(this);
750 			DrawDragDropRect(draw, rc_prev, rc_curr, 2);
751 			break;
752 		}
753 		case DRAG_PAN: {
754 			if(!IsNull(curr)) {
755 				PanOffset(curr - start);
756 				WhenUserZoom();
757 			}
758 			break;
759 		}
760 		case DRAG_CUSTOM: {
761 			lock_drag_drop = true;
762 //			LLOG("PlotterCtrl::Drag->drag_drop::Drag");
763 			drag_drop->Drag(drag_start, FromPushClientNull(prev), FromPushClientNull(curr), keyflags);
764 //			LLOG("//PlotterCtrl::Drag->drag_drop::Drag");
765 			lock_drag_drop = false;
766 			break;
767 		}
768 	}
769 //	LLOG("//PlotterCtrl::Drag");
770 }
771 
Drop(Point start,Point end,dword keyflags)772 void PlotterCtrl::Drop(Point start, Point end, dword keyflags)
773 {
774 	if(drag_mode == DRAG_CUSTOM) {
775 		if(drag_drop)
776 			drag_drop->Drop(drag_start, FromPushClient(end), keyflags);
777 	}
778 	else {
779 		Rect rc = RectSort(start, end);
780 		Rectf log = FromClient(rc);
781 		Pointf log_center = log.CenterPoint();
782 		Rectf view = GetViewRect();
783 		double ratio = max(1e-10, fpabsmax(log.Size() / view.GetSize()));
784 		switch(drag_mode) {
785 			case DRAG_ZOOM_IN: {
786 				Sizef new_scale = GetScale() / ratio;
787 				Pointf new_delta = Sizef(GetSize() >> 1) - Sizef(log_center) * new_scale;
788 				SetZoom(new_scale, new_delta);
789 				break;
790 			}
791 			case DRAG_ZOOM_OUT: {
792 				Point scr_center = ToClient(log_center);
793 				Sizef new_scale = GetScale() * ratio;
794 				Pointf new_delta = Pointf(scr_center) - Sizef(view.CenterPoint()) * new_scale;
795 				SetZoom(new_scale, new_delta);
796 				break;
797 			}
798 			case DRAG_PAN: {
799 				SetDelta(push_delta + Sizef(end - start));
800 				PanOffset(Point(0, 0));
801 				break;
802 			}
803 		}
804 		WhenUserZoom();
805 	}
806 	drag_mode = DRAG_NONE;
807 }
808 
Click(Point pt,dword keyflags)809 void PlotterCtrl::Click(Point pt, dword keyflags)
810 {
811 	if(drag_drop && drag_mode == DRAG_CUSTOM)
812 		drag_drop->Click(FromPushClient(pt), keyflags);
813 }
814 
Cancel()815 void PlotterCtrl::Cancel()
816 {
817 	PanOffset(Size(0, 0));
818 	if(drag_drop && drag_mode == DRAG_CUSTOM) {
819 		drag_drop->Cancel();
820 	}
821 	WhenUserZoom();
822 }
823 
Key(dword key,int repcnt)824 bool PlotterCtrl::Key(dword key, int repcnt)
825 {
826 	bool dd_key = false;
827 	if(drag_drop) {
828 		lock_drag_drop = true;
829 		dd_key = drag_drop->Key(key);
830 		lock_drag_drop = false;
831 	}
832 	if(dd_key)
833 		return true;
834 	if(hscroll.HorzKey(key))
835 	{
836 		OnHScroll();
837 		return true;
838 	}
839 	if(vscroll.VertKey(key))
840 	{
841 		OnVScroll();
842 		return true;
843 	}
844 	switch(key)
845 	{
846 	case K_ADD:      ZoomIn();  return true;
847 	case K_SUBTRACT: ZoomOut(); return true;
848 	}
849 	return DragDropCtrl::Key(key, repcnt);
850 }
851 
MouseWheel(Point p,int zdelta,dword keyflags)852 void PlotterCtrl::MouseWheel(Point p, int zdelta, dword keyflags)
853 {
854 	if(keyflags & K_SHIFT) {
855 		hscroll.Wheel(zdelta, 3);
856 		OnHScroll();
857 	}
858 	else if(keyflags && K_CTRL) {
859 		vscroll.Wheel(zdelta, 3);
860 		OnVScroll();
861 	}
862 	else {
863 		if(!Rect(GetSize()).Contains(p))
864 			p = GetSize() >> 1;
865 		Pointf logpos = FromClient(p);
866 		int zlim = minmax(zdelta, -1200, +1200);
867 		double factor = exp(zlim * (M_LN2 / 120));
868 		Sizef new_scale = GetScale() * factor;
869 		Pointf new_delta = Pointf(p) - Sizef(logpos) * new_scale;
870 		SetZoom(new_scale, new_delta);
871 		WhenUserZoom();
872 	}
873 }
874 
MouseMove(Point pt,dword keyflags)875 void PlotterCtrl::MouseMove(Point pt, dword keyflags)
876 {
877 	UpdateMousePos();
878 	DragDropCtrl::MouseMove(pt, keyflags);
879 }
880 
UpdateMousePos()881 void PlotterCtrl::UpdateMousePos()
882 {
883 	mouse_pos = FromClient(UPP::GetMousePos() - Size(GetScreenView().TopLeft()));
884 	RefreshPos();
885 	WhenMousePos();
886 }
887 
PickDragDrop(One<PlotterDragDrop> dd)888 void PlotterCtrl::PickDragDrop(One<PlotterDragDrop> dd)
889 {
890 	ASSERT(!lock_short_drag_drop && !lock_drag_drop);
891 	DragStop();
892 	drag_drop = dd;
893 	RefreshDragDrop();
894 	WhenRescan();
895 }
896 
ClearDragDrop()897 One<PlotterDragDrop> PlotterCtrl::ClearDragDrop()
898 {
899 	ASSERT(!lock_drag_drop);
900 	One<PlotterDragDrop> out = drag_drop;
901 	drag_drop.Clear();
902 	RefreshDragDrop();
903 	WhenRescan();
904 	return out;
905 }
906 
ToolView(Bar & bar)907 void PlotterCtrl::ToolView(Bar& bar)
908 {
909 	if(IsAspectLocked()) {
910 		ToolViewZoomIn(bar);
911 		ToolViewZoomOut(bar);
912 		ToolViewZoomFull(bar);
913 		bar.Separator();
914 	}
915 	else {
916 		ToolViewZoomInX(bar);
917 		ToolViewZoomOutX(bar);
918 		ToolViewZoomFullX(bar);
919 		bar.MenuSeparator();
920 		ToolViewZoomInY(bar);
921 		ToolViewZoomOutY(bar);
922 		ToolViewZoomFullY(bar);
923 		bar.MenuSeparator();
924 		ToolViewZoomIn(bar);
925 		ToolViewZoomOut(bar);
926 		ToolViewZoomFull(bar);
927 	}
928 	if(!aspect && enable_lock)
929 		ToolViewAspectLock(bar);
930 	ToolViewPan(bar);
931 }
932 
ToolViewZoomInX(Bar & bar)933 void PlotterCtrl::ToolViewZoomInX(Bar& bar)
934 {
935 	bar.AddMenu(t_("Zoom in horz."), PlotterImg::view_zoom_in(), THISBACK(OnViewZoomInX))
936 		.Help(t_("Zoom in horizontally"));
937 }
938 
OnViewZoomInX()939 void PlotterCtrl::OnViewZoomInX()
940 {
941 	UserZoomInX();
942 }
943 
ToolViewZoomOutX(Bar & bar)944 void PlotterCtrl::ToolViewZoomOutX(Bar& bar)
945 {
946 	bar.AddMenu(t_("Zoom out horz."), PlotterImg::view_zoom_out(), THISBACK(OnViewZoomOutX))
947 		.Help(t_("Zoom out horizontally"));
948 }
949 
OnViewZoomOutX()950 void PlotterCtrl::OnViewZoomOutX()
951 {
952 	UserZoomOutX();
953 }
954 
ToolViewZoomFullX(Bar & bar)955 void PlotterCtrl::ToolViewZoomFullX(Bar& bar)
956 {
957 	bar.AddMenu(t_("Zoom full horz."), PlotterImg::view_zoom_horz_full(), THISBACK(OnViewZoomFullX))
958 		.Help(t_("Display full x axis range in view"));
959 }
960 
OnViewZoomFullX()961 void PlotterCtrl::OnViewZoomFullX()
962 {
963 	UserZoomFullX();
964 }
965 
ToolViewZoomInY(Bar & bar)966 void PlotterCtrl::ToolViewZoomInY(Bar& bar)
967 {
968 	bar.AddMenu(t_("Zoom in vert."), PlotterImg::view_zoom_in(), THISBACK(OnViewZoomInY))
969 		.Help(t_("Zoom in vertically"));
970 }
971 
OnViewZoomInY()972 void PlotterCtrl::OnViewZoomInY()
973 {
974 	UserZoomInY();
975 }
976 
ToolViewZoomOutY(Bar & bar)977 void PlotterCtrl::ToolViewZoomOutY(Bar& bar)
978 {
979 	bar.AddMenu(t_("Zoom out vert."), PlotterImg::view_zoom_out(), THISBACK(OnViewZoomOutY))
980 		.Help(t_("Zoom out vertically"));
981 }
982 
OnViewZoomOutY()983 void PlotterCtrl::OnViewZoomOutY()
984 {
985 	UserZoomOutY();
986 }
987 
ToolViewZoomFullY(Bar & bar)988 void PlotterCtrl::ToolViewZoomFullY(Bar& bar)
989 {
990 	bar.AddMenu(t_("Zoom full vert."), PlotterImg::view_zoom_vert_full(), THISBACK(OnViewZoomFullY))
991 		.Help(t_("Display full y axis range in view"));
992 }
993 
OnViewZoomFullY()994 void PlotterCtrl::OnViewZoomFullY()
995 {
996 	UserZoomFullY();
997 }
998 
ToolViewZoomOut(Bar & bar)999 void PlotterCtrl::ToolViewZoomOut(Bar& bar)
1000 {
1001 	bar.Add(t_("Zoom out"), PlotterImg::view_zoom_out(), THISBACK(OnViewZoomOut))
1002 		.Check(IsDragDrop<ZoomOutDragDrop>(this))
1003 		.Help(t_("Zoom out current view"));
1004 }
1005 
OnViewZoomOut()1006 void PlotterCtrl::OnViewZoomOut()
1007 {
1008 	if(!IsDragDrop<ZoomOutDragDrop>(this))
1009 		PickDragDrop(new ZoomOutDragDrop(*this));
1010 	else
1011 		UserZoomOut();
1012 }
1013 
ToolViewZoomFull(Bar & bar)1014 void PlotterCtrl::ToolViewZoomFull(Bar& bar)
1015 {
1016 	bar.Add(t_("Zoom full"),
1017 		aspect ? PlotterImg::view_zoom_full() : PlotterImg::view_zoom_full_old(),
1018 		THISBACK(OnViewZoomFull))
1019 		.Help(t_("Zoom everything into view"));
1020 }
1021 
OnViewZoomFull()1022 void PlotterCtrl::OnViewZoomFull()
1023 {
1024 	UserZoomFull();
1025 }
1026 
ToolViewZoomIn(Bar & bar)1027 void PlotterCtrl::ToolViewZoomIn(Bar& bar)
1028 {
1029 	bar.Add(t_("Zoom in"), PlotterImg::view_zoom_in(), THISBACK(OnViewZoomIn))
1030 		.Check(IsDragDrop<ZoomInDragDrop>(this))
1031 		.Help(t_("Zoom in current view (click to zoom in 2x, drag & drop to zoom in area)"));
1032 }
1033 
OnViewZoomIn()1034 void PlotterCtrl::OnViewZoomIn()
1035 {
1036 	if(!IsDragDrop<ZoomInDragDrop>(this))
1037 		PickDragDrop(new ZoomInDragDrop(*this));
1038 	else
1039 		UserZoomIn();
1040 }
1041 
ToolViewAspectLock(Bar & bar)1042 void PlotterCtrl::ToolViewAspectLock(Bar& bar)
1043 {
1044 	bar.Add(!aspect, t_("Lock aspect ratio"), PlotterImg::view_aspect_lock(), THISBACK(OnViewAspectLock))
1045 		.Check(aspect_lock)
1046 		.Help(t_("Keep temporarily x and y scale factors in sync"));
1047 }
1048 
OnViewAspectLock()1049 void PlotterCtrl::OnViewAspectLock()
1050 {
1051 	UserAspectLock();
1052 }
1053 
ToolViewPan(Bar & bar)1054 void PlotterCtrl::ToolViewPan(Bar& bar)
1055 {
1056 	bar.Add(t_("Pan"), PlotterImg::view_pan(), THISBACK(OnViewPan))
1057 		.Check(IsDragDrop<PanDragDrop>(this))
1058 		.Help(t_("Drag & drop view position"));
1059 }
1060 
OnViewPan()1061 void PlotterCtrl::OnViewPan()
1062 {
1063 	if(!IsDragDrop<PanDragDrop>(this))
1064 		PickDragDrop(new PanDragDrop(*this));
1065 	else
1066 		ClearDragDrop();
1067 }
1068 
UserAspectLock()1069 void PlotterCtrl::UserAspectLock()
1070 {
1071 	SetAspectLock(!IsAspectLock());
1072 	WhenUserZoom();
1073 }
1074 
UserZoomInX()1075 void PlotterCtrl::UserZoomInX()
1076 {
1077 	ZoomInX();
1078 	WhenUserZoom();
1079 }
1080 
UserZoomOutX()1081 void PlotterCtrl::UserZoomOutX()
1082 {
1083 	ZoomOutX();
1084 	WhenUserZoom();
1085 }
1086 
UserZoomFullX()1087 void PlotterCtrl::UserZoomFullX()
1088 {
1089 	if(extent.left < extent.right)
1090 	{
1091 		ZoomX(extent.left, extent.right);
1092 		WhenUserZoom();
1093 	}
1094 }
1095 
UserZoomX(double min,double max)1096 void PlotterCtrl::UserZoomX(double min, double max)
1097 {
1098 	ZoomX(min, max);
1099 	WhenUserZoom();
1100 }
1101 
UserZoomInY()1102 void PlotterCtrl::UserZoomInY()
1103 {
1104 	ZoomInY();
1105 	WhenUserZoom();
1106 }
1107 
UserZoomOutY()1108 void PlotterCtrl::UserZoomOutY()
1109 {
1110 	ZoomOutY();
1111 	WhenUserZoom();
1112 }
1113 
UserZoomFullY()1114 void PlotterCtrl::UserZoomFullY()
1115 {
1116 	if(extent.top < extent.bottom)
1117 	{
1118 		ZoomY(extent.top, extent.bottom);
1119 		WhenUserZoom();
1120 	}
1121 }
1122 
UserZoomY(double min,double max)1123 void PlotterCtrl::UserZoomY(double min, double max)
1124 {
1125 	ZoomY(min, max);
1126 	WhenUserZoom();
1127 }
1128 
UserZoomIn()1129 void PlotterCtrl::UserZoomIn()
1130 {
1131 	ZoomInX();
1132 	ZoomInY();
1133 	WhenUserZoom();
1134 }
1135 
UserZoomOut()1136 void PlotterCtrl::UserZoomOut()
1137 {
1138 	ZoomOutX();
1139 	ZoomOutY();
1140 	WhenUserZoom();
1141 }
1142 
UserZoomFull()1143 void PlotterCtrl::UserZoomFull()
1144 {
1145 	Zoom(extent, false);
1146 	WhenUserZoom();
1147 }
1148 
UserZoom(const Rectf & rc,bool keep_ratio)1149 void PlotterCtrl::UserZoom(const Rectf& rc, bool keep_ratio)
1150 {
1151 	Zoom(rc, keep_ratio);
1152 	WhenUserZoom();
1153 }
1154 
1155 //////////////////////////////////////////////////////////////////////
1156 // PlotterDragDrop::
1157 
Drag(Pointf pt,Pointf prev,Pointf curr,dword keyflags)1158 void PlotterDragDrop::Drag(Pointf pt, Pointf prev, Pointf curr, dword keyflags)
1159 {
1160 	Rectf rc_prev = (IsNull(prev) ? Rectf(Null) : SortRectf(pt, prev));
1161 	Rectf rc_curr = (IsNull(curr) ? Rectf(Null) : SortRectf(pt, curr));
1162 	if(rc_prev != rc_curr)
1163 		DragRect(rc_prev, rc_curr, keyflags);
1164 }
1165 
DragRect(const Rectf & prev,const Rectf & curr,dword keyflags)1166 void PlotterDragDrop::DragRect(const Rectf& prev, const Rectf& curr, dword keyflags)
1167 {
1168 	PlotterCtrl& ctrl = GetOwner();
1169 	PlotterCtrl::ViewPlot plot(ctrl);
1170 	PlotDragRect(plot, prev);
1171 	PlotDragRect(plot, curr);
1172 }
1173 
Drop(Pointf pt,Pointf end,dword keyflags)1174 void PlotterDragDrop::Drop(Pointf pt, Pointf end, dword keyflags)
1175 {
1176 	DropRect(SortRectf(pt, end), keyflags);
1177 }
1178 
1179 //////////////////////////////////////////////////////////////////////
1180 // ZoomInDragDrop::
1181 
Cursor(Pointf pt,dword keyflags,bool dragging) const1182 Image ZoomInDragDrop::Cursor(Pointf pt, dword keyflags, bool dragging) const
1183 {
1184 	return keyflags & K_CTRL && !owner.IsAspectRatio()
1185 		? PlotterImg::view_zoom_in_aniso() : PlotterImg::view_zoom_in();
1186 }
1187 
DropRect(const Rectf & rc,dword keyflags)1188 void ZoomInDragDrop::DropRect(const Rectf& rc, dword keyflags)
1189 {
1190 	owner.Zoom(rc, !(keyflags & K_CTRL) || owner.IsAspectRatio());
1191 	owner.WhenUserZoom();
1192 }
1193 
Click(Pointf pt,dword keyflags)1194 void ZoomInDragDrop::Click(Pointf pt, dword keyflags)
1195 {
1196 	PlotterCtrl& owner = GetOwner();
1197 	Pointf d = Sizef(owner.GetSize()) / Abs(4.0 * owner.GetScale());
1198 	owner.Zoom(Rectf(pt - d, pt + d), true);
1199 	owner.WhenUserZoom();
1200 }
1201 
1202 //////////////////////////////////////////////////////////////////////
1203 // ZoomOutDragDrop::
1204 
Cursor(Pointf pt,dword keyflags,bool dragging) const1205 Image ZoomOutDragDrop::Cursor(Pointf pt, dword keyflags, bool dragging) const
1206 {
1207 	return PlotterImg::view_zoom_out();
1208 }
1209 
Push(Pointf pt,dword keyflags)1210 bool ZoomOutDragDrop::Push(Pointf pt, dword keyflags)
1211 {
1212 	return true;
1213 }
1214 
DropRect(const Rectf & rc,dword keyflags)1215 void ZoomOutDragDrop::DropRect(const Rectf& rc, dword keyflags)
1216 {
1217 	Rectf view_rc = owner.GetViewRect();
1218 	Rect screen_rc = owner.ToClient(rc);
1219 	Sizef new_scale = (Sizef)max(screen_rc.Size(), Size(10, 10)) / view_rc.Size();
1220 	double aspect = owner.GetAspectRatio();
1221 	if(aspect != 0)
1222 		new_scale = max(new_scale, Sizef(new_scale.cy / aspect, new_scale.cx * aspect));
1223 	if(owner.IsReversedX()) new_scale.cx = -new_scale.cx;
1224 	if(owner.IsReversedY()) new_scale.cy = -new_scale.cy;
1225 	Pointf new_delta = Pointf(screen_rc.CenterPoint()) - new_scale * Sizef(view_rc.CenterPoint());
1226 	owner.SetZoom(new_scale, new_delta);
1227 	owner.WhenUserZoom();
1228 }
1229 
Click(Pointf pt,dword keyflags)1230 void ZoomOutDragDrop::Click(Pointf pt, dword keyflags)
1231 {
1232 	Rectf rc = GetOwner().GetViewRect();
1233 	rc.Inflate(rc.Size() * 0.5);
1234 	owner.Zoom(rc + pt - rc.CenterPoint());
1235 	owner.WhenUserZoom();
1236 }
1237 
1238 //////////////////////////////////////////////////////////////////////
1239 // PanDragDrop::
1240 
Cursor(Pointf pt,dword keyflags,bool dragging) const1241 Image PanDragDrop::Cursor(Pointf pt, dword keyflags, bool dragging) const
1242 {
1243 	return PlotterImg::view_pan();
1244 }
1245 
Push(Pointf pt,dword keyflags)1246 bool PanDragDrop::Push(Pointf pt, dword keyflags)
1247 {
1248 	return true;
1249 }
1250 
Drag(Pointf start,Pointf prev,Pointf curr,dword keyflags)1251 void PanDragDrop::Drag(Pointf start, Pointf prev, Pointf curr, dword keyflags)
1252 {
1253 	PlotterCtrl& owner = GetOwner();
1254 	if(!IsNull(curr))
1255 		owner.PanOffset(PointfToPoint((curr - start) * owner.GetPushScale()));
1256 }
1257 
Drop(Pointf start,Pointf end,dword keyflags)1258 void PanDragDrop::Drop(Pointf start, Pointf end, dword keyflags)
1259 {
1260 	PlotterCtrl& owner = GetOwner();
1261 	owner.SetDelta(owner.GetDelta() + (end - start) * owner.GetPushScale());
1262 	owner.PanOffset(Point(0, 0));
1263 	owner.WhenUserZoom();
1264 }
1265 
Cancel()1266 void PanDragDrop::Cancel()
1267 {
1268 	GetOwner().PanOffset(Point(0, 0));
1269 }
1270 
1271 }
1272