1 /*****************************************************************************/
3 // Written by Michael Wilber
4 // Slide show code derived from ShowImage code, written by Michael Pfeiffer
11 // Permission is hereby granted, free of charge, to any person obtaining a
12 // copy of this software and associated documentation files (the "Software"),
13 // to deal in the Software without restriction, including without limitation
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 // and/or sell copies of the Software, and to permit persons to whom the
16 // Software is furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included
19 // in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 // DEALINGS IN THE SOFTWARE.
28 /*****************************************************************************/
31 #include "SlideShowSaver.h"
37 #include <BitmapStream.h>
39 #include <Directory.h>
43 #include <StringView.h>
44 #include <TranslatorRoster.h>
46 #include "SlideShowConfigView.h"
49 // Called by system to get the screen saver
50 extern "C" _EXPORT BScreenSaver
*
51 instantiate_screen_saver(BMessage
*message
, image_id id
)
53 return new SlideShowSaver(message
, id
);
56 // returns B_ERROR if problems reading ref
57 // B_OK if ref is not a directory
58 // B_OK + 1 if ref is a directory
60 ent_is_dir(const entry_ref
*ref
)
63 if (ent
.InitCheck() != B_OK
)
67 if (ent
.GetStat(&st
) != B_OK
)
70 return S_ISDIR(st
.st_mode
) ? (B_OK
+ 1) : B_OK
;
73 int CompareEntries(const void* a
, const void* b
)
78 return strcasecmp(r1
->name
, r2
->name
);
81 // Default settings for the Translator
82 LiveSetting gDefaultSettings
[] = {
83 LiveSetting(CHANGE_CAPTION
, SAVER_SETTING_CAPTION
, true),
84 // Show image caption by default
85 LiveSetting(CHANGE_BORDER
, SAVER_SETTING_BORDER
, true),
86 // Show image border by default
87 LiveSetting(CHANGE_DIRECTORY
, SAVER_SETTING_DIRECTORY
, "/boot/home"),
88 // Set default image directory to home
89 LiveSetting(CHANGE_DELAY
, SAVER_SETTING_DELAY
, (int32
) 3000)
90 // Default delay: 3 seconds
93 SlideShowSaver::SlideShowSaver(BMessage
*archive
, image_id image
)
95 BScreenSaver(archive
, image
), fLock("SlideShow Lock")
97 B_TRANSLATE_MARK_SYSTEM_NAME_VOID("SlideShowSaver");
104 fSettings
= new LiveSettings("SlideShowSaver_Settings",
105 gDefaultSettings
, sizeof(gDefaultSettings
) / sizeof(LiveSetting
));
106 fSettings
->LoadSettings();
107 // load settings from the settings file
109 fSettings
->AddObserver(this);
112 SlideShowSaver::~SlideShowSaver()
117 fSettings
->RemoveObserver(this);
118 fSettings
->Release();
121 // Called by fSettings to notify that someone has changed
122 // a setting. For example, if the user changes a setting
123 // on the config panel, this will be called to notify this
126 SlideShowSaver::SettingChanged(uint32 setting
)
135 case CHANGE_DIRECTORY
:
148 SlideShowSaver::UpdateTickSize()
150 // Tick size is in microseconds, but is stored in settings as
152 bigtime_t ticks
= static_cast<bigtime_t
>
153 (fSettings
->SetGetInt32(SAVER_SETTING_DELAY
)) * 1000;
160 SlideShowSaver::UpdateShowCaption()
162 fShowCaption
= fSettings
->SetGetBool(SAVER_SETTING_CAPTION
);
167 SlideShowSaver::UpdateShowBorder()
169 fShowBorder
= fSettings
->SetGetBool(SAVER_SETTING_BORDER
);
174 SlideShowSaver::UpdateDirectory()
176 status_t result
= B_OK
;
180 BString strDirectory
;
181 fSettings
->GetString(SAVER_SETTING_DIRECTORY
, strDirectory
);
182 BDirectory
dir(strDirectory
.String());
183 if (dir
.InitCheck() != B_OK
|| dir
.GetNextRef(&fCurrentRef
) != B_OK
)
185 // Use ShowNextImage to find which translatable image is
186 // alphabetically first in the given directory, and load it
187 if (result
== B_OK
&& ShowNextImage(true, true) == false)
190 fNewDirectory
= true;
198 SlideShowSaver::StartConfig(BView
*view
)
200 view
->AddChild(new SlideShowConfigView(
201 BRect(10, 10, 250, 300), "SlideShowSaver Config",
202 B_FOLLOW_ALL
, B_WILL_DRAW
, fSettings
->Acquire()));
206 SlideShowSaver::StartSaver(BView
*view
, bool preview
)
211 if (UpdateDirectory() != B_OK
)
214 // Read ticksize setting and set it as the delay
221 SlideShowSaver::Draw(BView
*view
, int32 frame
)
225 view
->SetLowColor(0, 0, 0);
226 view
->SetHighColor(192, 192, 192);
227 view
->SetViewColor(192, 192, 192);
229 bool bResult
= false;
230 if (fNewDirectory
== true) {
231 // Already have a bitmap on the first frame
234 bResult
= ShowNextImage(true, false);
235 // try rewinding to beginning
236 if (bResult
== false)
237 bResult
= ShowNextImage(true, true);
239 fNewDirectory
= false;
241 if (bResult
== true && fBitmap
!= NULL
) {
242 BRect
destRect(0, 0, fBitmap
->Bounds().Width(), fBitmap
->Bounds().Height()),
243 vwBounds
= view
->Bounds();
245 if (destRect
.Width() < vwBounds
.Width()) {
246 destRect
.OffsetBy((vwBounds
.Width() - destRect
.Width()) / 2, 0);
248 if (destRect
.Height() < vwBounds
.Height()) {
249 destRect
.OffsetBy(0, (vwBounds
.Height() - destRect
.Height()) / 2);
252 BRect border
= destRect
, bounds
= view
->Bounds();
254 view
->FillRect(BRect(0, 0, bounds
.right
, border
.top
-1), B_SOLID_LOW
);
256 view
->FillRect(BRect(0, border
.top
, border
.left
-1, border
.bottom
), B_SOLID_LOW
);
258 view
->FillRect(BRect(border
.right
+1, border
.top
, bounds
.right
, border
.bottom
), B_SOLID_LOW
);
260 view
->FillRect(BRect(0, border
.bottom
+1, bounds
.right
, bounds
.bottom
), B_SOLID_LOW
);
262 if (fShowBorder
== true) {
263 BRect strokeRect
= destRect
;
264 strokeRect
.InsetBy(-1, -1);
265 view
->StrokeRect(strokeRect
);
268 view
->DrawBitmap(fBitmap
, fBitmap
->Bounds(), destRect
);
270 if (fShowCaption
== true)
278 SlideShowSaver::SetImage(const entry_ref
*pref
)
286 BTranslatorRoster
*proster
= BTranslatorRoster::Default();
290 if (ent_is_dir(pref
) != B_OK
)
291 // if ref is erroneous or a directory, return error
294 BFile
file(&ref
, B_READ_ONLY
);
295 translator_info info
;
296 memset(&info
, 0, sizeof(translator_info
));
297 BMessage ioExtension
;
298 //if (ref != fCurrentRef)
299 // if new image, reset to first document
300 // fDocumentIndex = 1;
301 if (ioExtension
.AddInt32("/documentIndex", 1 /*fDocumentIndex*/) != B_OK
)
303 if (proster
->Identify(&file
, &ioExtension
, &info
, 0, NULL
,
304 B_TRANSLATOR_BITMAP
) != B_OK
)
307 // Translate image data and create a new ShowImage window
308 BBitmapStream outstream
;
309 if (proster
->Translate(&file
, &info
, &ioExtension
, &outstream
,
310 B_TRANSLATOR_BITMAP
) != B_OK
)
312 BBitmap
*newBitmap
= NULL
;
313 if (outstream
.DetachBitmap(&newBitmap
) != B_OK
)
316 // Now that I've successfully loaded the new bitmap,
317 // I can be sure it is safe to delete the old one,
318 // and clear everything
324 // Get path to use in caption
325 fCaption
= "<< Unable to read the path >>";
326 BEntry
entry(&fCurrentRef
);
327 if (entry
.InitCheck() == B_OK
) {
329 if (path
.InitCheck() == B_OK
) {
330 fCaption
= path
.Path();
337 // Function originally from Haiku ShowImage
339 SlideShowSaver::ShowNextImage(bool next
, bool rewind
)
342 entry_ref curRef
, imgRef
;
344 curRef
= fCurrentRef
;
345 found
= FindNextImage(&curRef
, &imgRef
, next
, rewind
);
347 // Keep trying to load images until:
348 // 1. The image loads successfully
349 // 2. The last file in the directory is found (for find next or find first)
350 // 3. The first file in the directory is found (for find prev)
351 // 4. The call to FindNextImage fails for any other reason
352 while (SetImage(&imgRef
) != B_OK
) {
354 found
= FindNextImage(&curRef
, &imgRef
, next
, false);
363 // Function taken from Haiku ShowImage,
364 // function originally written by Michael Pfeiffer
366 SlideShowSaver::IsImage(const entry_ref
*pref
)
371 if (ent_is_dir(pref
) != B_OK
)
372 // if ref is erroneous or a directory, return false
375 BFile
file(pref
, B_READ_ONLY
);
376 if (file
.InitCheck() != B_OK
)
379 BTranslatorRoster
*proster
= BTranslatorRoster::Default();
383 BMessage ioExtension
;
384 if (ioExtension
.AddInt32("/documentIndex", 1) != B_OK
)
387 translator_info info
;
388 memset(&info
, 0, sizeof(translator_info
));
389 if (proster
->Identify(&file
, &ioExtension
, &info
, 0, NULL
,
390 B_TRANSLATOR_BITMAP
) != B_OK
)
396 // Function taken from Haiku ShowImage,
397 // function originally written by Michael Pfeiffer
399 SlideShowSaver::FindNextImage(entry_ref
*in_current
, entry_ref
*out_image
, bool next
, bool rewind
)
401 // ASSERT(next || !rewind);
402 BEntry
curImage(in_current
);
403 entry_ref entry
, *ref
;
409 if (curImage
.GetParent(&parent
) != B_OK
)
412 while (parent
.GetNextRef(&entry
) == B_OK
) {
413 if (entry
!= *in_current
) {
414 entries
.AddItem(new entry_ref(entry
));
416 // insert current ref, so we can find it easily after sorting
417 entries
.AddItem(in_current
);
421 entries
.SortItems(CompareEntries
);
423 cur
= entries
.IndexOf(in_current
);
426 // remove it so FreeEntries() does not delete it
427 entries
.RemoveItem(in_current
);
430 // find the next image in the list
431 if (rewind
) cur
= 0; // start with first
432 for (; (ref
= (entry_ref
*)entries
.ItemAt(cur
)) != NULL
; cur
++) {
435 *out_image
= (const entry_ref
)*ref
;
440 // find the previous image in the list
442 for (; cur
>= 0; cur
--) {
443 ref
= (entry_ref
*)entries
.ItemAt(cur
);
446 *out_image
= (const entry_ref
)*ref
;
452 FreeEntries(&entries
);
456 // Function taken from Haiku ShowImage,
457 // function originally written by Michael Pfeiffer
459 SlideShowSaver::FreeEntries(BList
*entries
)
461 const int32 n
= entries
->CountItems();
462 for (int32 i
= 0; i
< n
; i
++) {
463 entry_ref
*ref
= (entry_ref
*)entries
->ItemAt(i
);
466 entries
->MakeEmpty();
470 SlideShowSaver::LayoutCaption(BView
*view
, BFont
&font
, BPoint
&pos
, BRect
&rect
)
472 font_height fontHeight
;
474 BRect
bounds(view
->Bounds());
475 font
= be_plain_font
;
476 width
= font
.StringWidth(fCaption
.String()) + 1; // 1 for text shadow
477 font
.GetHeight(&fontHeight
);
478 height
= fontHeight
.ascent
+ fontHeight
.descent
;
479 // center text horizontally
480 pos
.x
= (bounds
.left
+ bounds
.right
- width
)/2;
482 pos
.y
= bounds
.bottom
- fontHeight
.descent
- 5;
484 // background rectangle
485 rect
.Set(0, 0, (width
-1)+2, (height
-1)+2+1); // 2 for border and 1 for text shadow
487 rect
.OffsetBy(-1, -1-fontHeight
.ascent
); // -1 for border
491 SlideShowSaver::DrawCaption(BView
*view
)
496 LayoutCaption(view
, font
, pos
, rect
);
500 view
->SetDrawingMode(B_OP_ALPHA
);
501 view
->SetHighColor(0, 0, 255, 128);
502 view
->FillRect(rect
);
504 view
->SetDrawingMode(B_OP_OVER
);
505 view
->SetFont(&font
);
506 view
->SetLowColor(B_TRANSPARENT_COLOR
);
509 view
->SetHighColor(0, 0, 0);
511 view
->DrawString(fCaption
.String(), pos
);
514 view
->SetHighColor(255, 255, 0);
515 view
->DrawString(fCaption
.String(), pos
);