1 #include "RasterBaseCtrl.h"
2 #include "RasterCtrl.h"
3 
4 #define BackColor SColorFace()
5 
6 ///////////////////////////////////////////////////////////////////////////////////////////////
7 // constructor
RasterBaseCtrl(RasterCtrl * t,bool hScroll,bool vScroll)8 RasterBaseCtrl::RasterBaseCtrl(RasterCtrl *t, bool hScroll, bool vScroll)
9 {
10 	// connects to associated RasterCtrl
11 	rasterCtrl = t;
12 
13 	// whether control has scrollbars
14 	hasHScrollBar = hScroll;
15 	hasVScrollBar = vScroll;
16 
17 	// adds scrollbar
18 	if(hasHScrollBar)
19 	{
20 		AddFrame(hScrollBar.Horz());
21 		hScrollBar <<= THISBACK(OnScroll);
22 	}
23 	if(hasVScrollBar)
24 	{
25 		AddFrame(vScrollBar.Vert());
26 		vScrollBar <<= THISBACK(OnScroll);
27 	}
28 
29 	// marks cache as invalid
30 	imageCache.SetValid(false);
31 
32 } // END constructor class RasterBaseCtrl
33 
34 ///////////////////////////////////////////////////////////////////////////////////////////////
35 // destructor
~RasterBaseCtrl()36 RasterBaseCtrl::~RasterBaseCtrl()
37 {
38 } // END destructor class RasterBaseCtrl
39 
40 ///////////////////////////////////////////////////////////////////////////////////////////////
41 // middle mouse button pan handlers
MiddleDown(Point p,dword keyflags)42 void RasterBaseCtrl::MiddleDown(Point p, dword keyflags)
43 {
44 	panPoint = p;
45 	panHScroll = hScrollBar.Get();
46 	panVScroll = vScrollBar.Get();
47 
48 } // END RasterBaseCtrl::MiddleDown()
49 
MouseMove(Point p,dword keyflags)50 void RasterBaseCtrl::MouseMove(Point p, dword keyflags)
51 {
52 	// reacts only to moves with middle button pressed
53 	if(!(keyflags & K_MOUSEMIDDLE))
54 		return;
55 
56 	// gets distance between current and pan point
57 	int dx = panPoint.x - p.x + panHScroll;
58 	int dy = panPoint.y - p.y + panVScroll;
59 
60 	// gets max scrolling values
61 	int hMax = hScrollBar.GetTotal();
62 	int vMax = vScrollBar.GetTotal();
63 
64 	// sets new pan position
65 	if(dx < 0) dx = 0;
66 	if(dx > hMax) dx = hMax;
67 	if(dy < 0) dy = 0;
68 	if(dy > vMax) dy = vMax;
69 	hScrollBar.Set(dx);
70 	vScrollBar.Set(dy);
71 
72 	Refresh();
73 
74 } // END RasterBaseCtrl::MouseMove()
75 
CursorImage(Point p,dword keyflags)76 Image RasterBaseCtrl::CursorImage(Point p, dword keyflags)
77 {
78 	if(keyflags & K_MOUSEMIDDLE)
79 		return Image::Hand();
80 	else
81 		return Image::Arrow();
82 
83 }
84 
85 ///////////////////////////////////////////////////////////////////////////////////////////////
86 // mouse wheel handler
MouseWheel(Point p,int zdelta,dword keyflags)87 void RasterBaseCtrl::MouseWheel(Point p, int zdelta, dword keyflags)
88 {
89 	int max = vScrollBar.GetTotal();
90 	int step = max / 100;
91 	if(step <= 0)
92 		step = 1;
93 	int newPos = vScrollBar.Get();
94 	if(zdelta < 0)
95 		newPos += step;
96 	else
97 		newPos -= step;
98 	if(newPos > max)
99 		newPos = max;
100 	if(newPos < 0)
101 		newPos = 0;
102 	vScrollBar.Set(newPos);
103 
104 	Refresh();
105 
106 } // END RasterBaseCtrl::MouseWheel()
107 
108 ///////////////////////////////////////////////////////////////////////////////////////////////
109 // repaint images on image cache
PaintCache()110 void RasterBaseCtrl::PaintCache()
111 {
112 	Array<Rect> rects;
113 
114 	// backups old imageCache positions inside the full tiff image
115 	int oldCacheLeft = cacheLeft;
116 	int oldCacheTop = cacheTop;
117 
118 	// calculate new imageCache position inside the full tiff image
119 	if(hScrollBar.IsVisible())
120 		cacheLeft = hScrollBar.Get();
121 	else
122 		cacheLeft = 0;
123 	if(vScrollBar.IsVisible())
124 		cacheTop = vScrollBar.Get();
125 	else
126 		cacheTop = 0;
127 
128 	// if cache is not valid OR scrolled out a full window, gets full cache area
129 	if(
130 		!imageCache.IsValid() ||
131 		abs(oldCacheLeft-cacheLeft) >= imageCache.GetWidth() ||
132 		abs(oldCacheTop-cacheTop) >= imageCache.GetHeight()
133 	)
134 	{
135 		rects.Add(Rect(imageCache.GetSize()));
136 		imageCache.SetValid(true);
137 		oldCacheLeft = oldCacheTop = 0;
138 	}
139 	else
140 	{
141 		// shifts imageCache
142 		imageCache.Scroll(Size(oldCacheLeft-cacheLeft, oldCacheTop-cacheTop));
143 
144 		// calculates the (1 or 2) rects that must be repainted
145 		int startLine = 0;
146 		int endLine = imageCache.GetHeight();
147 
148 		// top rectangle, if any
149 		if(cacheTop < oldCacheTop)
150 		{
151 			rects.Add(Rect(0, 0, imageCache.GetWidth(), oldCacheTop-cacheTop));
152 			startLine += oldCacheTop-cacheTop;
153 		}
154 		// bottom rectangle, if any
155 		else if(cacheTop > oldCacheTop)
156 		{
157 			rects.Add(Rect(0, imageCache.GetHeight()-(cacheTop-oldCacheTop), imageCache.GetWidth(), imageCache.GetHeight()));
158 			endLine += oldCacheTop-cacheTop;
159 		}
160 		// left rectangle, if any
161 		if(cacheLeft < oldCacheLeft)
162 			rects.Add(Rect(0, startLine, oldCacheLeft - cacheLeft, endLine));
163 		else if(cacheLeft > oldCacheLeft)
164 			rects.Add(Rect(imageCache.GetWidth()-(cacheLeft-oldCacheLeft), startLine, imageCache.GetWidth(), endLine));
165 	}
166 
167 	// gets the image pages
168 	Array<MemoryRaster>&pages = rasterCtrl->GetPages();
169 
170 	// scans the tiff pages to see if some of them fits in
171 	// rectangles that must be repainted
172 	int currentTop = 0;
173 	for(int i = 0 ; i < pages.GetCount() ; i++)
174 	{
175 		// translates current top of page in view coordinates
176 		int viewCurrentTop = iscale(currentTop, imageScale, 1000);
177 
178 		// gets current page
179 		MemoryRaster &page = pages[i];
180 
181 		// gets current page size and translates it in view coordinates
182 		Rect viewPageRect(
183 			-cacheLeft,
184 			-cacheTop + viewCurrentTop,
185 			iscale(page.GetSize().cx, imageScale, 1000) - cacheLeft,
186 			iscale(page.GetSize().cy, imageScale, 1000) - cacheTop + viewCurrentTop
187 		);
188 
189 		// now scans the rectangles that must be repainted
190 		// and checks if current page has some area on it
191 		for(int iRect = 0; iRect < rects.GetCount(); iRect++)
192 		{
193 			// gets current rectangle
194 			Rect rect = rects[iRect];
195 
196 			// intersects with page rect
197 			rect.Intersect(viewPageRect);
198 
199 			// if intersection is not empty, do repaint the stuff
200 			if(!rect.IsEmpty())
201 			{
202 				// gets back the tiff rectangle
203 				Rect tiffRect(
204 					iscale(rect.left + cacheLeft, 1000, imageScale),
205 					iscale(rect.top + cacheTop, 1000, imageScale) - currentTop,
206 					iscale(rect.right + cacheLeft, 1000, imageScale),
207 					iscale(rect.bottom + cacheTop, 1000, imageScale) -currentTop
208 				);
209 
210 				// rescales the image area
211 				ImageEncoder t;
212 				Rescale(t, rect.GetSize(), page, tiffRect);
213 
214 				// and copies insiede the cache area
215 				Image img = Image(t);
216 				ASSERT(rect.top >= 0 && rect.top + img.GetHeight() <= imageCache.GetHeight());
217 				ASSERT(rect.left >= 0 && rect.left + img.GetWidth() <= imageCache.GetWidth());
218 				imageCache.Copy(Point(rect.left, rect.top), Rect(0, 0, img.GetWidth(), img.GetHeight()), img);
219 			}
220 		}
221 		currentTop += page.GetHeight() + iscale(10, 1000, imageScale);
222 	}
223 
224 
225 } // END RasterBaseCtrl::PaintCache()
226 
227 ///////////////////////////////////////////////////////////////////////////////////////////////
228 // paint routine
Paint(Draw & d)229 void RasterBaseCtrl::Paint(Draw &d)
230 {
231 	// clears background
232 	d.DrawRect(GetSize(), SColorFace());
233 
234 	// if no image opened, does nothing
235 	if(!rasterCtrl->IsOpened())
236 		return;
237 
238 	// paints image inside cache, if needed
239 	PaintCache();
240 
241 	// paints image cache inside control
242 	if(imageCache.GetWidth() >= GetSize().cx)
243 		imageCache.Paint(d, Point(0, 0));
244 	else
245 		imageCache.Paint(d, Point((GetSize().cx - imageCache.GetWidth()) / 2, 0));
246 
247 } // END RasterBaseCtrl::Paint()
248 
249 ///////////////////////////////////////////////////////////////////////////////////////////////
250 // scrollbar handler
OnScroll(void)251 void RasterBaseCtrl::OnScroll(void)
252 {
253 	Refresh();
254 
255 } // END RasterBaseCtrl::OnScroll()
256 
257 ///////////////////////////////////////////////////////////////////////////////////////////////
258 // handles changes in images or ctrl
Layout(void)259 void RasterBaseCtrl::Layout(void)
260 {
261 	// this to avoid recursion
262 	static bool inside = false;
263 
264 	// if no image opened, hides scrollbar and return
265 	if(!rasterCtrl->IsOpened())
266 	{
267 		hScrollBar.Hide();
268 		vScrollBar.Hide();
269 		return;
270 	}
271 
272 	// if already doing layout, just return
273 	if(inside)
274 		return;
275 
276 	// marks inside layout
277 	inside = true;
278 
279 	// stores scroll positions, in order to go on right position
280 	// after zoom operations
281 	int hScrollPos = hScrollBar.Get();
282 	int hScrollMax = hScrollBar.GetTotal();
283 	int vScrollPos = vScrollBar.Get();
284 	int vScrollMax = vScrollBar.GetTotal();
285 
286 	// gets the image pages
287 	Array<MemoryRaster>&pages = rasterCtrl->GetPages();
288 
289 	// calculates max width and height
290 	// and total Tiff height, for all pages, with no gaps by now
291 	int rasterWidth = 0;
292 	int rasterHeight = 0;
293 	int maxHeight = 0;
294 	int pageCount = pages.GetCount();
295 	for(int i = 0 ; i < pageCount ; i++)
296 	{
297 		// gets page size
298 		Size sz = pages[i].GetSize();
299 
300 		// updates width, maximum height and total height
301 		if(sz.cx > rasterWidth)
302 			rasterWidth = sz.cx;
303 		if(sz.cy > maxHeight)
304 			maxHeight = sz.cy;
305 		rasterHeight += sz.cy;
306 	}
307 
308 	// calculates image scale factor
309 	imageScale = CalcScale(imageScale, rasterWidth, maxHeight);
310 
311 	// stops layouting if imagescale is null
312 	if(!imageScale)
313 	{
314 		inside = false;
315 		return;
316 	}
317 
318 	// now calculate gaps to be exactly 10 pixels in every zoom factor
319 	int gapSize = iscale(10, 1000, imageScale);
320 
321 	// adds total gaps sizes to total height
322 	rasterHeight += (pageCount -1) * gapSize;
323 
324 	// and finally, sets up scrollbars and shows them
325 	// and calculate cache sizes
326 	int scaledRasterHeight = iscale(rasterHeight, imageScale, 1000);
327 	int cacheHeight;
328 	vScrollBar.SetPage(GetSize().cy);
329 	vScrollBar.SetTotal(scaledRasterHeight);
330 	if(vScrollMax)
331 		vScrollBar.Set(iscale(vScrollPos, scaledRasterHeight, vScrollMax));
332 	else
333 		vScrollBar.Set(0);
334 	if(GetSize().cy <= scaledRasterHeight)
335 	{
336 		if(hasVScrollBar)
337 			vScrollBar.Show();
338 		cacheHeight = GetSize().cy;
339 	}
340 	else
341 	{
342 		vScrollBar.Hide();
343 		cacheHeight = scaledRasterHeight;
344 	}
345 	int scaledRasterWidth = iscale(rasterWidth, imageScale, 1000);
346 	int cacheWidth;
347 	hScrollBar.SetPage(GetSize().cx);
348 	hScrollBar.SetTotal(scaledRasterWidth);
349 	if(hScrollMax)
350 		hScrollBar.Set(iscale(hScrollPos, scaledRasterWidth, hScrollMax));
351 	else
352 		hScrollBar.Set(0);
353 	if(GetSize().cx <= scaledRasterWidth)
354 	{
355 		if(hasHScrollBar)
356 			hScrollBar.Show();
357 		cacheWidth = GetSize().cx;
358 	}
359 	else
360 	{
361 		hScrollBar.Hide();
362 		cacheWidth = scaledRasterWidth;
363 	}
364 
365 	// creates cache image, empty by now
366 	imageCache.Init(Size(cacheWidth, cacheHeight));
367 
368 	// updates image
369 	Refresh();
370 
371 	// mark layout terminated
372 	inside = false;
373 
374 } // END RasterBaseCtrl::Layout()
375