1/*
2
3Preview
4
5Copyright (c) 2002 Haiku.
6
7Author:
8	Michael Pfeiffer
9
10Permission is hereby granted, free of charge, to any person obtaining a copy of
11this software and associated documentation files (the "Software"), to deal in
12the Software without restriction, including without limitation the rights to
13use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
14of the Software, and to permit persons to whom the Software is furnished to do
15so, subject to the following conditions:
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26THE SOFTWARE.
27
28*/
29
30#include <Debug.h>
31
32#include "Preview.h"
33
34// Implementation of PreviewPage
35PreviewPage::PreviewPage(int32 page, PrintJobPage* pjp)
36	: fPage(page)
37	, fPictures(NULL)
38	, fPoints(NULL)
39	, fRects(NULL)
40{
41	fNumberOfPictures = pjp->NumberOfPictures();
42	fPictures = new BPicture[fNumberOfPictures];
43	fPoints = new BPoint[fNumberOfPictures];
44	fRects = new BRect[fNumberOfPictures];
45	status_t rc = B_ERROR;
46	for (int32 i = 0; i < fNumberOfPictures &&
47		(rc = pjp->NextPicture(fPictures[i], fPoints[i], fRects[i])) == B_OK; i ++);
48	fStatus = rc;
49}
50
51PreviewPage::~PreviewPage() {
52	delete []fPictures;
53	delete []fPoints;
54	delete []fRects;
55}
56
57status_t PreviewPage::InitCheck() const {
58	return fStatus;
59}
60
61void PreviewPage::Draw(BView* view) {
62	ASSERT(fStatus == B_OK);
63	for (int32 i = 0; i < fNumberOfPictures; i ++) {
64		view->DrawPicture(&fPictures[i], fPoints[i]);
65		view->SetHighColor(255, 0, 0);
66		view->StrokeRect(fRects[i]);
67	}
68}
69
70// Implementation of PreviewView
71
72PreviewView::PreviewView(BFile* jobFile, BRect rect)
73	: BView(rect, "PreviewView", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS)
74	, fPage(0)
75	, fZoom(0)
76	, fReader(jobFile)
77	, fCachedPage(NULL)
78{
79}
80
81PreviewView::~PreviewView() {
82	delete fCachedPage;
83}
84
85// returns 2 ^ fZoom
86float PreviewView::ZoomFactor() const {
87	const int32 b = 4;
88	int32 zoom;
89	if (fZoom > 0) zoom = (1 << b) << fZoom;
90	else zoom = (1 << b) >> -fZoom;
91	return zoom / (float)(1 << b);
92}
93
94BRect PreviewView::PageRect() const {
95	float f = ZoomFactor();
96	BRect r = fReader.PaperRect();
97	r.left *= f; r.right *= f; r.top *= f; r.bottom *= f;
98	return r;
99}
100
101status_t PreviewView::InitCheck() const {
102	return fReader.InitCheck();
103}
104
105void PreviewView::Draw(BRect rect) {
106	if (fReader.InitCheck() == B_OK) {
107			// set zoom factor
108		SetScale(ZoomFactor());
109			// render picture(s) of current page
110		if (fCachedPage == NULL || fCachedPage->Page() != fPage) {
111			delete fCachedPage; fCachedPage = NULL;
112			PrintJobPage page;
113			if (fReader.GetPage(fPage, page) == B_OK)
114				fCachedPage = new PreviewPage(fPage, &page);
115		}
116		if (fCachedPage && fCachedPage->InitCheck() == B_OK)
117			fCachedPage->Draw(this);
118	}
119}
120
121void PreviewView::FrameResized(float width, float height) {
122	FixScrollbars();
123}
124
125bool PreviewView::ShowsFirstPage() const {
126	return fPage == 0;
127}
128
129bool PreviewView::ShowsLastPage() const {
130	return fPage == NumberOfPages() - 1;
131}
132
133int PreviewView::NumberOfPages() const {
134	return fReader.NumberOfPages();
135}
136
137void PreviewView::ShowNextPage() {
138	if (!ShowsLastPage()) {
139		fPage ++; Invalidate();
140	}
141}
142
143void PreviewView::ShowPrevPage() {
144	if (!ShowsFirstPage()) {
145		fPage --; Invalidate();
146	}
147}
148
149bool PreviewView::CanZoomIn() const {
150	return fZoom < 4;
151}
152
153bool PreviewView::CanZoomOut() const {
154	return fZoom > -2;
155}
156
157void PreviewView::ZoomIn() {
158	if (CanZoomIn()) {
159		fZoom ++; FixScrollbars(); Invalidate();
160	}
161}
162
163void PreviewView::ZoomOut() {
164	if (CanZoomOut()) {
165		fZoom --; FixScrollbars(); Invalidate();
166	}
167}
168
169void PreviewView::FixScrollbars() {
170	BRect frame = Bounds();
171	BScrollBar * scroll;
172	float x, y;
173	float bigStep, smallStep;
174	float width = PageRect().Width();
175	float height = PageRect().Height();
176	x = width - frame.Width();
177	if (x < 0.0) {
178		x = 0.0;
179	}
180	y = height - frame.Height();
181	if (y < 0.0) {
182		y = 0.0;
183	}
184
185	scroll = ScrollBar (B_HORIZONTAL);
186	scroll->SetRange (0.0, x);
187	scroll->SetProportion ((width - x) / width);
188	bigStep = frame.Width() - 2;
189	smallStep = bigStep / 10.;
190	scroll->SetSteps (smallStep, bigStep);
191
192	scroll = ScrollBar (B_VERTICAL);
193	scroll->SetRange (0.0, y);
194	scroll->SetProportion ((height - y) / height);
195	bigStep = frame.Height() - 2;
196	smallStep = bigStep / 10.;
197	scroll->SetSteps (smallStep, bigStep);
198}
199
200// Implementation of PreviewWindow
201
202PreviewWindow::PreviewWindow(BFile* jobFile)
203	: BWindow(BRect(20, 20, 400, 600), "Preview", B_DOCUMENT_WINDOW, 0)
204{
205	float top = 0;
206	float left = 10;
207
208	BRect r = Frame();
209	r.right = r.IntegerWidth() - B_V_SCROLL_BAR_WIDTH; r.left = 0;
210	r.bottom = r.IntegerHeight() - B_H_SCROLL_BAR_HEIGHT; r.top = 0;
211
212		// add navigation and zoom buttons
213	fNext = new BButton(BRect(left, top, left+10, top+10), "Next", "Next Page", new BMessage(MSG_NEXT_PAGE));
214	AddChild(fNext);
215	fNext->ResizeToPreferred();
216	left = fNext->Frame().right + 10;
217
218	fPrev = new BButton(BRect(left, top, left+10, top+10), "Prev", "Previous Page", new BMessage(MSG_PREV_PAGE));
219	AddChild(fPrev);
220	fPrev->ResizeToPreferred();
221	left = fPrev->Frame().right + 10;
222
223	fZoomIn = new BButton(BRect(left, top, left+10, top+10), "ZoomIn", "Zoom In", new BMessage(MSG_ZOOM_IN));
224	AddChild(fZoomIn);
225	fZoomIn->ResizeToPreferred();
226	left = fZoomIn->Frame().right + 10;
227
228	fZoomOut = new BButton(BRect(left, top, left+10, top+10), "ZoomOut", "Zoom Out", new BMessage(MSG_ZOOM_OUT));
229	AddChild(fZoomOut);
230	fZoomOut->ResizeToPreferred();
231	left = fZoomOut->Frame().right + 10;
232
233	top = fZoomOut->Frame().bottom + 5;
234
235		// add preview view
236	r.top = top;
237	fPreview = new PreviewView(jobFile, r);
238	fPreviewScroller = new BScrollView("PreviewScroller", fPreview, B_FOLLOW_ALL, 0, true, true, B_FANCY_BORDER);
239	fPreviewScroller->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
240	AddChild(fPreviewScroller);
241
242	if (fPreview->InitCheck() == B_OK) {
243		fPreview->FixScrollbars();
244		UpdateControls();
245		Show();
246	} else {
247		Quit();
248	}
249}
250
251void PreviewWindow::UpdateControls() {
252	fPrev->SetEnabled(!fPreview->ShowsFirstPage());
253	fNext->SetEnabled(!fPreview->ShowsLastPage());
254	fZoomIn->SetEnabled(fPreview->CanZoomIn());
255	fZoomOut->SetEnabled(fPreview->CanZoomOut());
256}
257
258void PreviewWindow::MessageReceived(BMessage* m) {
259	switch (m->what) {
260		case MSG_NEXT_PAGE: fPreview->ShowNextPage();
261			break;
262		case MSG_PREV_PAGE: fPreview->ShowPrevPage();
263			break;
264		case MSG_ZOOM_IN: fPreview->ZoomIn();
265			break;
266		case MSG_ZOOM_OUT: fPreview->ZoomOut();
267			break;
268		default:
269			inherited::MessageReceived(m); return;
270	}
271	UpdateControls();
272}
273
274#if 1
275
276// Standalone test preview application
277// Note to quit application press Command+Q
278
279#include <Application.h>
280
281class PreviewApp : public BApplication {
282public:
283	PreviewApp(const char* sig) : BApplication(sig) { }
284	void ArgvReceived(int32 argc, char* argv[]);
285};
286
287void PreviewApp::ArgvReceived(int32 argc, char* argv[]) {
288	for (int32 i = 1; i < argc; i ++) {
289		BFile jobFile(argv[i], B_READ_WRITE);
290		if (jobFile.InitCheck() == B_OK) {
291			new PreviewWindow(&jobFile);
292		}
293	}
294}
295
296int main(int argc, char* argv[]) {
297	PreviewApp app("application/x-vnd.obos.preview");
298	app.Run();
299}
300#endif
301