xref: /haiku/src/apps/haikudepot/ui/ScreenshotWindow.cpp (revision 97a8cc6cc21fbb8a61b395c79887486fcd589f80)
1d5ef985eSStephan Aßmus /*
2d5ef985eSStephan Aßmus  * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
339f99591SJulian Harnath  * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
488af15cfSAndrew Lindesay  * Copyright 2020-2024, Andrew Lindesay <apl@lindesay.co.nz>.
5d5ef985eSStephan Aßmus  * All rights reserved. Distributed under the terms of the MIT License.
6d5ef985eSStephan Aßmus  */
7d5ef985eSStephan Aßmus 
8d5ef985eSStephan Aßmus #include "ScreenshotWindow.h"
9d5ef985eSStephan Aßmus 
10d5ef985eSStephan Aßmus #include <algorithm>
11d5ef985eSStephan Aßmus 
12d5ef985eSStephan Aßmus #include <Autolock.h>
13d5ef985eSStephan Aßmus #include <Catalog.h>
14d5ef985eSStephan Aßmus #include <LayoutBuilder.h>
153ca9d5e9SJulian Harnath #include <MessageRunner.h>
16c210060fSJulian Harnath #include <StringView.h>
17d5ef985eSStephan Aßmus 
18c210060fSJulian Harnath #include "BarberPole.h"
19d5ef985eSStephan Aßmus #include "BitmapView.h"
20a9edb9bfSAndrew Lindesay #include "HaikuDepotConstants.h"
21f96d1f4dSAndrew Lindesay #include "Logger.h"
2288af15cfSAndrew Lindesay #include "Model.h"
23c65ff9f1SAndrew Lindesay #include "PackageUtils.h"
2466ee6532SAndrew Lindesay #include "SharedIcons.h"
25d5ef985eSStephan Aßmus #include "WebAppInterface.h"
26d5ef985eSStephan Aßmus 
27d5ef985eSStephan Aßmus 
28d5ef985eSStephan Aßmus #undef B_TRANSLATION_CONTEXT
29d5ef985eSStephan Aßmus #define B_TRANSLATION_CONTEXT "ScreenshotWindow"
30d5ef985eSStephan Aßmus 
31d5ef985eSStephan Aßmus 
3239f99591SJulian Harnath static const rgb_color kBackgroundColor = { 51, 102, 152, 255 };
3339f99591SJulian Harnath 	// Drawn as a border around the screenshots and also what's behind their
3439f99591SJulian Harnath 	// transparent regions
3539f99591SJulian Harnath 
3639f99591SJulian Harnath 
ScreenshotWindow(BWindow * parent,BRect frame,Model * model)3788af15cfSAndrew Lindesay ScreenshotWindow::ScreenshotWindow(BWindow* parent, BRect frame, Model* model)
38d5ef985eSStephan Aßmus 	:
39d5ef985eSStephan Aßmus 	BWindow(frame, B_TRANSLATE("Screenshot"),
40d5ef985eSStephan Aßmus 		B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL,
41d5ef985eSStephan Aßmus 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
423ca9d5e9SJulian Harnath 	fBarberPoleShown(false),
43d5ef985eSStephan Aßmus 	fDownloadPending(false),
4488af15cfSAndrew Lindesay 	fWorkerThread(-1),
4588af15cfSAndrew Lindesay 	fModel(model)
46d5ef985eSStephan Aßmus {
47d5ef985eSStephan Aßmus 	AddToSubset(parent);
48d5ef985eSStephan Aßmus 
49c210060fSJulian Harnath 	atomic_set(&fCurrentScreenshotIndex, 0);
50c210060fSJulian Harnath 
51c210060fSJulian Harnath 	fBarberPole = new BarberPole("barber pole");
523ca9d5e9SJulian Harnath 	fBarberPole->SetExplicitMaxSize(BSize(100, B_SIZE_UNLIMITED));
533ca9d5e9SJulian Harnath 	fBarberPole->Hide();
54c210060fSJulian Harnath 
55c210060fSJulian Harnath 	fIndexView = new BStringView("screenshot index", NULL);
56c210060fSJulian Harnath 
57c210060fSJulian Harnath 	fToolBar = new BToolBar();
58622e144fSJulian Harnath 	fToolBar->AddAction(MSG_PREVIOUS_SCREENSHOT, this,
5966ee6532SAndrew Lindesay 		SharedIcons::IconArrowLeft22Scaled()->Bitmap(), NULL, NULL);
6066ee6532SAndrew Lindesay 	fToolBar->AddAction(MSG_NEXT_SCREENSHOT, this, SharedIcons::IconArrowRight22Scaled()->Bitmap(),
61622e144fSJulian Harnath 		NULL, NULL);
62c210060fSJulian Harnath 	fToolBar->AddView(fIndexView);
63c210060fSJulian Harnath 	fToolBar->AddGlue();
64c210060fSJulian Harnath 	fToolBar->AddView(fBarberPole);
65c210060fSJulian Harnath 
66d5ef985eSStephan Aßmus 	fScreenshotView = new BitmapView("screenshot view");
67d5ef985eSStephan Aßmus 	fScreenshotView->SetExplicitMaxSize(
68d5ef985eSStephan Aßmus 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
69416c1160SJulian Harnath 	fScreenshotView->SetScaleBitmap(false);
70d5ef985eSStephan Aßmus 
712afa3f3bSStephan Aßmus 	BGroupView* groupView = new BGroupView(B_VERTICAL);
7239f99591SJulian Harnath 	groupView->SetViewColor(kBackgroundColor);
732afa3f3bSStephan Aßmus 
74d5ef985eSStephan Aßmus 	// Build layout
75c210060fSJulian Harnath 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
76622e144fSJulian Harnath 		.SetInsets(0, 3, 0, 0)
77c210060fSJulian Harnath 		.Add(fToolBar)
78622e144fSJulian Harnath 		.AddStrut(3)
792afa3f3bSStephan Aßmus 		.AddGroup(groupView)
80d5ef985eSStephan Aßmus 			.Add(fScreenshotView)
81d5ef985eSStephan Aßmus 			.SetInsets(B_USE_WINDOW_INSETS)
822afa3f3bSStephan Aßmus 		.End()
83d5ef985eSStephan Aßmus 	;
84d5ef985eSStephan Aßmus 
8539f99591SJulian Harnath 	fScreenshotView->SetLowColor(kBackgroundColor);
8666ee6532SAndrew Lindesay 		// Set after attaching all views to prevent it from being overridden
8739f99591SJulian Harnath 		// again by BitmapView::AllAttached()
8839f99591SJulian Harnath 
892afa3f3bSStephan Aßmus 	CenterOnScreen();
90d5ef985eSStephan Aßmus }
91d5ef985eSStephan Aßmus 
92d5ef985eSStephan Aßmus 
~ScreenshotWindow()93d5ef985eSStephan Aßmus ScreenshotWindow::~ScreenshotWindow()
94d5ef985eSStephan Aßmus {
95d5ef985eSStephan Aßmus 	BAutolock locker(&fLock);
96d5ef985eSStephan Aßmus 
97d5ef985eSStephan Aßmus 	if (fWorkerThread >= 0)
98d5ef985eSStephan Aßmus 		wait_for_thread(fWorkerThread, NULL);
99d5ef985eSStephan Aßmus }
100d5ef985eSStephan Aßmus 
101d5ef985eSStephan Aßmus 
102d5ef985eSStephan Aßmus bool
QuitRequested()103d5ef985eSStephan Aßmus ScreenshotWindow::QuitRequested()
104d5ef985eSStephan Aßmus {
105d5ef985eSStephan Aßmus 	if (fOnCloseTarget.IsValid() && fOnCloseMessage.what != 0)
106d5ef985eSStephan Aßmus 		fOnCloseTarget.SendMessage(&fOnCloseMessage);
107d5ef985eSStephan Aßmus 
108d5ef985eSStephan Aßmus 	Hide();
109d5ef985eSStephan Aßmus 	return false;
110d5ef985eSStephan Aßmus }
111d5ef985eSStephan Aßmus 
112d5ef985eSStephan Aßmus 
113d5ef985eSStephan Aßmus void
MessageReceived(BMessage * message)114d5ef985eSStephan Aßmus ScreenshotWindow::MessageReceived(BMessage* message)
115d5ef985eSStephan Aßmus {
116d5ef985eSStephan Aßmus 	switch (message->what) {
117c210060fSJulian Harnath 		case MSG_NEXT_SCREENSHOT:
118c210060fSJulian Harnath 		{
119c210060fSJulian Harnath 			atomic_add(&fCurrentScreenshotIndex, 1);
120c210060fSJulian Harnath 			_UpdateToolBar();
121c210060fSJulian Harnath 			_DownloadScreenshot();
122c210060fSJulian Harnath 			break;
123c210060fSJulian Harnath 		}
124c210060fSJulian Harnath 
125c210060fSJulian Harnath 		case MSG_PREVIOUS_SCREENSHOT:
126c210060fSJulian Harnath 			atomic_add(&fCurrentScreenshotIndex, -1);
127c210060fSJulian Harnath 			_UpdateToolBar();
128c210060fSJulian Harnath 			_DownloadScreenshot();
129c210060fSJulian Harnath 			break;
130c210060fSJulian Harnath 
131c210060fSJulian Harnath 		case MSG_DOWNLOAD_START:
1323ca9d5e9SJulian Harnath 			if (!fBarberPoleShown) {
133c210060fSJulian Harnath 				fBarberPole->Start();
1343ca9d5e9SJulian Harnath 				fBarberPole->Show();
1353ca9d5e9SJulian Harnath 				fBarberPoleShown = true;
1363ca9d5e9SJulian Harnath 			}
137c210060fSJulian Harnath 			break;
138c210060fSJulian Harnath 
139c210060fSJulian Harnath 		case MSG_DOWNLOAD_STOP:
1403ca9d5e9SJulian Harnath 			if (fBarberPoleShown) {
1413ca9d5e9SJulian Harnath 				fBarberPole->Hide();
142c210060fSJulian Harnath 				fBarberPole->Stop();
1433ca9d5e9SJulian Harnath 				fBarberPoleShown = true;
1443ca9d5e9SJulian Harnath 			}
145c210060fSJulian Harnath 			break;
146c210060fSJulian Harnath 
147d5ef985eSStephan Aßmus 		default:
148d5ef985eSStephan Aßmus 			BWindow::MessageReceived(message);
149d5ef985eSStephan Aßmus 			break;
150d5ef985eSStephan Aßmus 	}
151d5ef985eSStephan Aßmus }
152d5ef985eSStephan Aßmus 
153d5ef985eSStephan Aßmus 
154d5ef985eSStephan Aßmus void
SetOnCloseMessage(const BMessenger & messenger,const BMessage & message)155d5ef985eSStephan Aßmus ScreenshotWindow::SetOnCloseMessage(
156d5ef985eSStephan Aßmus 	const BMessenger& messenger, const BMessage& message)
157d5ef985eSStephan Aßmus {
158d5ef985eSStephan Aßmus 	fOnCloseTarget = messenger;
159d5ef985eSStephan Aßmus 	fOnCloseMessage = message;
160d5ef985eSStephan Aßmus }
161d5ef985eSStephan Aßmus 
162d5ef985eSStephan Aßmus 
163d5ef985eSStephan Aßmus void
SetPackage(const PackageInfoRef & package)164d5ef985eSStephan Aßmus ScreenshotWindow::SetPackage(const PackageInfoRef& package)
165d5ef985eSStephan Aßmus {
166c65ff9f1SAndrew Lindesay 	if (!package.IsSet())
167c65ff9f1SAndrew Lindesay 		HDFATAL("attempt to provide an unset package");
168c65ff9f1SAndrew Lindesay 
169d5ef985eSStephan Aßmus 	if (fPackage == package)
170d5ef985eSStephan Aßmus 		return;
171d5ef985eSStephan Aßmus 
172d5ef985eSStephan Aßmus 	fPackage = package;
173d5ef985eSStephan Aßmus 	BString title = B_TRANSLATE("Screenshot");
174c65ff9f1SAndrew Lindesay 	PackageUtils::TitleOrName(fPackage, title);
175d5ef985eSStephan Aßmus 	SetTitle(title);
176c210060fSJulian Harnath 
177c65ff9f1SAndrew Lindesay 	if (package.IsSet())
178c65ff9f1SAndrew Lindesay 		_DownloadScreenshot();
179c65ff9f1SAndrew Lindesay 
180c210060fSJulian Harnath 	atomic_set(&fCurrentScreenshotIndex, 0);
181c210060fSJulian Harnath 
182c210060fSJulian Harnath 	_UpdateToolBar();
183d5ef985eSStephan Aßmus }
184d5ef985eSStephan Aßmus 
185d5ef985eSStephan Aßmus 
186d5ef985eSStephan Aßmus // #pragma mark - private
187d5ef985eSStephan Aßmus 
188d5ef985eSStephan Aßmus 
189d5ef985eSStephan Aßmus void
_DownloadScreenshot()190d5ef985eSStephan Aßmus ScreenshotWindow::_DownloadScreenshot()
191d5ef985eSStephan Aßmus {
192d5ef985eSStephan Aßmus 	BAutolock locker(&fLock);
193d5ef985eSStephan Aßmus 
194d5ef985eSStephan Aßmus 	if (fWorkerThread >= 0) {
195d5ef985eSStephan Aßmus 		fDownloadPending = true;
196d5ef985eSStephan Aßmus 		return;
197d5ef985eSStephan Aßmus 	}
198d5ef985eSStephan Aßmus 
199d5ef985eSStephan Aßmus 	thread_id thread = spawn_thread(&_DownloadThreadEntry,
200d5ef985eSStephan Aßmus 		"Screenshot Loader", B_NORMAL_PRIORITY, this);
201d5ef985eSStephan Aßmus 	if (thread >= 0)
202d5ef985eSStephan Aßmus 		_SetWorkerThread(thread);
203d5ef985eSStephan Aßmus }
204d5ef985eSStephan Aßmus 
205d5ef985eSStephan Aßmus 
206d5ef985eSStephan Aßmus void
_SetWorkerThread(thread_id thread)207d5ef985eSStephan Aßmus ScreenshotWindow::_SetWorkerThread(thread_id thread)
208d5ef985eSStephan Aßmus {
209d5ef985eSStephan Aßmus 	if (!Lock())
210d5ef985eSStephan Aßmus 		return;
211d5ef985eSStephan Aßmus 
212d5ef985eSStephan Aßmus //	bool enabled = thread < 0;
213d5ef985eSStephan Aßmus //
214d5ef985eSStephan Aßmus //	fPreviewsButton->SetEnabled(enabled);
215d5ef985eSStephan Aßmus //	fNextButton->SetEnabled(enabled);
216d5ef985eSStephan Aßmus //	fCloseButton->SetEnabled(enabled);
217d5ef985eSStephan Aßmus 
218d5ef985eSStephan Aßmus 	if (thread >= 0) {
219d5ef985eSStephan Aßmus 		fWorkerThread = thread;
220d5ef985eSStephan Aßmus 		resume_thread(fWorkerThread);
221d5ef985eSStephan Aßmus 	} else {
222d5ef985eSStephan Aßmus 		fWorkerThread = -1;
223d5ef985eSStephan Aßmus 
224d5ef985eSStephan Aßmus 		if (fDownloadPending) {
225d5ef985eSStephan Aßmus 			_DownloadScreenshot();
226d5ef985eSStephan Aßmus 			fDownloadPending = false;
227d5ef985eSStephan Aßmus 		}
228d5ef985eSStephan Aßmus 	}
229d5ef985eSStephan Aßmus 
230d5ef985eSStephan Aßmus 	Unlock();
231d5ef985eSStephan Aßmus }
232d5ef985eSStephan Aßmus 
233d5ef985eSStephan Aßmus 
234d5ef985eSStephan Aßmus int32
_DownloadThreadEntry(void * data)235d5ef985eSStephan Aßmus ScreenshotWindow::_DownloadThreadEntry(void* data)
236d5ef985eSStephan Aßmus {
237d5ef985eSStephan Aßmus 	ScreenshotWindow* window
238d5ef985eSStephan Aßmus 		= reinterpret_cast<ScreenshotWindow*>(data);
239d5ef985eSStephan Aßmus 	window->_DownloadThread();
240d5ef985eSStephan Aßmus 	window->_SetWorkerThread(-1);
241d5ef985eSStephan Aßmus 	return 0;
242d5ef985eSStephan Aßmus }
243d5ef985eSStephan Aßmus 
244d5ef985eSStephan Aßmus 
245d5ef985eSStephan Aßmus void
_DownloadThread()246d5ef985eSStephan Aßmus ScreenshotWindow::_DownloadThread()
247d5ef985eSStephan Aßmus {
2489984ca59SAndrew Lindesay 	ScreenshotInfoRef info;
2499984ca59SAndrew Lindesay 
250d5ef985eSStephan Aßmus 	if (!Lock()) {
251fa5c8097SAndrew Lindesay 		HDERROR("failed to lock screenshot window");
252d5ef985eSStephan Aßmus 		return;
253d5ef985eSStephan Aßmus 	}
254d5ef985eSStephan Aßmus 
2552a36368bSMichael Lotz 	fScreenshotView->UnsetBitmap();
2561a5b7d9dSJessica Tallon 	_ResizeToFitAndCenter();
257d5ef985eSStephan Aßmus 
258779ab335SX512 	if (!fPackage.IsSet())
2599984ca59SAndrew Lindesay 		HDINFO("package not set");
2609984ca59SAndrew Lindesay 	else {
261*97a8cc6cSAndrew Lindesay 		PackageScreenshotInfoRef screenshotInfo = fPackage->ScreenshotInfo();
262*97a8cc6cSAndrew Lindesay 
263*97a8cc6cSAndrew Lindesay 		if (!screenshotInfo.IsSet() || screenshotInfo->Count() == 0) {
2649984ca59SAndrew Lindesay 			HDINFO("package has no screenshots");
265*97a8cc6cSAndrew Lindesay 		} else {
2669984ca59SAndrew Lindesay 			int32 index = atomic_get(&fCurrentScreenshotIndex);
267*97a8cc6cSAndrew Lindesay 			info = screenshotInfo->ScreenshotAtIndex(index);
2689984ca59SAndrew Lindesay 		}
2699984ca59SAndrew Lindesay 	}
270d5ef985eSStephan Aßmus 
271d5ef985eSStephan Aßmus 	Unlock();
272d5ef985eSStephan Aßmus 
273779ab335SX512 	if (!info.IsSet()) {
2749984ca59SAndrew Lindesay 		HDINFO("screenshot not set");
275d5ef985eSStephan Aßmus 		return;
276d5ef985eSStephan Aßmus 	}
277d5ef985eSStephan Aßmus 
2783ca9d5e9SJulian Harnath 	// Only indicate being busy with the download if it takes a little while
279c210060fSJulian Harnath 	BMessenger messenger(this);
2803ca9d5e9SJulian Harnath 	BMessageRunner delayedMessenger(messenger,
2813ca9d5e9SJulian Harnath 		new BMessage(MSG_DOWNLOAD_START),
2823ca9d5e9SJulian Harnath 		kProgressIndicatorDelay, 1);
283c210060fSJulian Harnath 
28466ee6532SAndrew Lindesay 	BitmapHolderRef screenshot;
28588af15cfSAndrew Lindesay 
286d5ef985eSStephan Aßmus 	// Retrieve screenshot from web-app
28788af15cfSAndrew Lindesay 	status_t status = fModel->GetPackageScreenshotRepository()->LoadScreenshot(
28866ee6532SAndrew Lindesay 		ScreenshotCoordinate(info->Code(), info->Width(), info->Height()), screenshot);
289c210060fSJulian Harnath 
2903ca9d5e9SJulian Harnath 	delayedMessenger.SetCount(0);
291c210060fSJulian Harnath 	messenger.SendMessage(MSG_DOWNLOAD_STOP);
292c210060fSJulian Harnath 
293d5ef985eSStephan Aßmus 	if (status == B_OK && Lock()) {
294fa5c8097SAndrew Lindesay 		HDINFO("got screenshot");
29588af15cfSAndrew Lindesay 		fScreenshot = screenshot;
2962a36368bSMichael Lotz 		fScreenshotView->SetBitmap(fScreenshot);
2972afa3f3bSStephan Aßmus 		_ResizeToFitAndCenter();
298d5ef985eSStephan Aßmus 		Unlock();
299fa5c8097SAndrew Lindesay 	} else
300fa5c8097SAndrew Lindesay 		HDERROR("failed to download screenshot");
301d5ef985eSStephan Aßmus }
3022afa3f3bSStephan Aßmus 
3032afa3f3bSStephan Aßmus 
3049984ca59SAndrew Lindesay BSize
_MaxWidthAndHeightOfAllScreenshots()3059984ca59SAndrew Lindesay ScreenshotWindow::_MaxWidthAndHeightOfAllScreenshots()
3069984ca59SAndrew Lindesay {
3079984ca59SAndrew Lindesay 	BSize size(0, 0);
3089984ca59SAndrew Lindesay 
3099984ca59SAndrew Lindesay 	// Find out dimensions of the largest screenshot of this package
310779ab335SX512 	if (fPackage.IsSet()) {
311*97a8cc6cSAndrew Lindesay 		PackageScreenshotInfoRef screenshotInfo = fPackage->ScreenshotInfo();
312*97a8cc6cSAndrew Lindesay 		int count = 0;
313*97a8cc6cSAndrew Lindesay 
314*97a8cc6cSAndrew Lindesay 		if (screenshotInfo.IsSet())
315*97a8cc6cSAndrew Lindesay 			count = screenshotInfo->Count();
316*97a8cc6cSAndrew Lindesay 
3179984ca59SAndrew Lindesay 		for(int32 i = 0; i < count; i++) {
318*97a8cc6cSAndrew Lindesay 			const ScreenshotInfoRef& screenshot = screenshotInfo->ScreenshotAtIndex(i);
319*97a8cc6cSAndrew Lindesay 
320*97a8cc6cSAndrew Lindesay 			if (screenshot.IsSet()) {
321*97a8cc6cSAndrew Lindesay 				float w = static_cast<float>(screenshot->Width());
322*97a8cc6cSAndrew Lindesay 				float h = static_cast<float>(screenshot->Height());
3239984ca59SAndrew Lindesay 				if (w > size.Width())
3249984ca59SAndrew Lindesay 					size.SetWidth(w);
3259984ca59SAndrew Lindesay 				if (h > size.Height())
3269984ca59SAndrew Lindesay 					size.SetHeight(h);
3279984ca59SAndrew Lindesay 			}
3289984ca59SAndrew Lindesay 		}
3299984ca59SAndrew Lindesay 	}
3309984ca59SAndrew Lindesay 
3319984ca59SAndrew Lindesay 	return size;
3329984ca59SAndrew Lindesay }
3339984ca59SAndrew Lindesay 
3349984ca59SAndrew Lindesay 
3352afa3f3bSStephan Aßmus void
_ResizeToFitAndCenter()3362afa3f3bSStephan Aßmus ScreenshotWindow::_ResizeToFitAndCenter()
3372afa3f3bSStephan Aßmus {
3389984ca59SAndrew Lindesay 	fScreenshotView->SetExplicitMinSize(_MaxWidthAndHeightOfAllScreenshots());
339416c1160SJulian Harnath 	Layout(false);
340416c1160SJulian Harnath 
341416c1160SJulian Harnath 	// TODO: Limit window size to screen size (with a little margin),
342416c1160SJulian Harnath 	//       the image should then become scrollable.
343416c1160SJulian Harnath 
3442afa3f3bSStephan Aßmus 	float minWidth;
3452afa3f3bSStephan Aßmus 	float minHeight;
3462afa3f3bSStephan Aßmus 	GetSizeLimits(&minWidth, NULL, &minHeight, NULL);
3472afa3f3bSStephan Aßmus 	ResizeTo(minWidth, minHeight);
3482afa3f3bSStephan Aßmus 	CenterOnScreen();
3492afa3f3bSStephan Aßmus }
350c210060fSJulian Harnath 
351c210060fSJulian Harnath 
352c210060fSJulian Harnath void
_UpdateToolBar()353c210060fSJulian Harnath ScreenshotWindow::_UpdateToolBar()
354c210060fSJulian Harnath {
355*97a8cc6cSAndrew Lindesay 	int32 numScreenshots = 0;
356*97a8cc6cSAndrew Lindesay 
357*97a8cc6cSAndrew Lindesay 	if (fPackage.IsSet()) {
358*97a8cc6cSAndrew Lindesay 		PackageScreenshotInfoRef screenshotInfo = fPackage->ScreenshotInfo();
359*97a8cc6cSAndrew Lindesay 		if (screenshotInfo.IsSet())
360*97a8cc6cSAndrew Lindesay 			numScreenshots = screenshotInfo->Count();
361*97a8cc6cSAndrew Lindesay 	}
362*97a8cc6cSAndrew Lindesay 
363416c1160SJulian Harnath 	const int32 currentIndex = atomic_get(&fCurrentScreenshotIndex);
364416c1160SJulian Harnath 
365c210060fSJulian Harnath 	fToolBar->SetActionEnabled(MSG_PREVIOUS_SCREENSHOT,
366c210060fSJulian Harnath 		currentIndex > 0);
367c210060fSJulian Harnath 	fToolBar->SetActionEnabled(MSG_NEXT_SCREENSHOT,
368416c1160SJulian Harnath 		currentIndex < numScreenshots - 1);
369c210060fSJulian Harnath 
370c210060fSJulian Harnath 	BString text;
371c210060fSJulian Harnath 	text << currentIndex + 1;
372c210060fSJulian Harnath 	text << " / ";
373416c1160SJulian Harnath 	text << numScreenshots;
374c210060fSJulian Harnath 	fIndexView->SetText(text);
375c210060fSJulian Harnath }
376