#include "SlideShowSaver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <BitmapStream.h>
#include <Catalog.h>
#include <Directory.h>
#include <File.h>
#include <List.h>
#include <Path.h>
#include <StringView.h>
#include <TranslatorRoster.h>
#include "SlideShowConfigView.h"
extern "C" _EXPORT BScreenSaver *
instantiate_screen_saver(BMessage *message, image_id id)
{
return new SlideShowSaver(message, id);
}
status_t
ent_is_dir(const entry_ref *ref)
{
BEntry ent(ref);
if (ent.InitCheck() != B_OK)
return B_ERROR;
struct stat st;
if (ent.GetStat(&st) != B_OK)
return B_ERROR;
return S_ISDIR(st.st_mode) ? (B_OK + 1) : B_OK;
}
int CompareEntries(const void* a, const void* b)
{
entry_ref *r1, *r2;
r1 = *(entry_ref**)a;
r2 = *(entry_ref**)b;
return strcasecmp(r1->name, r2->name);
}
LiveSetting gDefaultSettings[] = {
LiveSetting(CHANGE_CAPTION, SAVER_SETTING_CAPTION, true),
LiveSetting(CHANGE_BORDER, SAVER_SETTING_BORDER, true),
LiveSetting(CHANGE_DIRECTORY, SAVER_SETTING_DIRECTORY, "/boot/home"),
LiveSetting(CHANGE_DELAY, SAVER_SETTING_DELAY, (int32) 3000)
};
SlideShowSaver::SlideShowSaver(BMessage *archive, image_id image)
:
BScreenSaver(archive, image), fLock("SlideShow Lock")
{
B_TRANSLATE_MARK_SYSTEM_NAME_VOID("SlideShowSaver");
fNewDirectory = true;
fBitmap = NULL;
fShowBorder = true;
fShowCaption = true;
fSettings = new LiveSettings("SlideShowSaver_Settings",
gDefaultSettings, sizeof(gDefaultSettings) / sizeof(LiveSetting));
fSettings->LoadSettings();
fSettings->AddObserver(this);
}
SlideShowSaver::~SlideShowSaver()
{
delete fBitmap;
fBitmap = NULL;
fSettings->RemoveObserver(this);
fSettings->Release();
}
void
SlideShowSaver::SettingChanged(uint32 setting)
{
switch (setting) {
case CHANGE_CAPTION:
UpdateShowCaption();
break;
case CHANGE_BORDER:
UpdateShowBorder();
break;
case CHANGE_DIRECTORY:
UpdateDirectory();
break;
case CHANGE_DELAY:
UpdateTickSize();
break;
default:
break;
}
}
status_t
SlideShowSaver::UpdateTickSize()
{
bigtime_t ticks = static_cast<bigtime_t>
(fSettings->SetGetInt32(SAVER_SETTING_DELAY)) * 1000;
SetTickSize(ticks);
return B_OK;
}
status_t
SlideShowSaver::UpdateShowCaption()
{
fShowCaption = fSettings->SetGetBool(SAVER_SETTING_CAPTION);
return B_OK;
}
status_t
SlideShowSaver::UpdateShowBorder()
{
fShowBorder = fSettings->SetGetBool(SAVER_SETTING_BORDER);
return B_OK;
}
status_t
SlideShowSaver::UpdateDirectory()
{
status_t result = B_OK;
fLock.Lock();
BString strDirectory;
fSettings->GetString(SAVER_SETTING_DIRECTORY, strDirectory);
BDirectory dir(strDirectory.String());
if (dir.InitCheck() != B_OK || dir.GetNextRef(&fCurrentRef) != B_OK)
result = B_ERROR;
if (result == B_OK && ShowNextImage(true, true) == false)
result = B_ERROR;
fNewDirectory = true;
fLock.Unlock();
return result;
}
void
SlideShowSaver::StartConfig(BView *view)
{
view->AddChild(new SlideShowConfigView(
BRect(10, 10, 250, 300), "SlideShowSaver Config",
B_FOLLOW_ALL, B_WILL_DRAW, fSettings->Acquire()));
}
status_t
SlideShowSaver::StartSaver(BView *view, bool preview)
{
UpdateShowCaption();
UpdateShowBorder();
if (UpdateDirectory() != B_OK)
return B_ERROR;
UpdateTickSize();
return B_OK;
}
void
SlideShowSaver::Draw(BView *view, int32 frame)
{
fLock.Lock();
view->SetLowColor(0, 0, 0);
view->SetHighColor(192, 192, 192);
view->SetViewColor(192, 192, 192);
bool bResult = false;
if (fNewDirectory == true) {
bResult = true;
} else {
bResult = ShowNextImage(true, false);
if (bResult == false)
bResult = ShowNextImage(true, true);
}
fNewDirectory = false;
if (bResult == true && fBitmap != NULL) {
BRect destRect(0, 0, fBitmap->Bounds().Width(), fBitmap->Bounds().Height()),
vwBounds = view->Bounds();
if (destRect.Width() < vwBounds.Width()) {
destRect.OffsetBy((vwBounds.Width() - destRect.Width()) / 2, 0);
}
if (destRect.Height() < vwBounds.Height()) {
destRect.OffsetBy(0, (vwBounds.Height() - destRect.Height()) / 2);
}
BRect border = destRect, bounds = view->Bounds();
view->FillRect(BRect(0, 0, bounds.right, border.top-1), B_SOLID_LOW);
view->FillRect(BRect(0, border.top, border.left-1, border.bottom), B_SOLID_LOW);
view->FillRect(BRect(border.right+1, border.top, bounds.right, border.bottom), B_SOLID_LOW);
view->FillRect(BRect(0, border.bottom+1, bounds.right, bounds.bottom), B_SOLID_LOW);
if (fShowBorder == true) {
BRect strokeRect = destRect;
strokeRect.InsetBy(-1, -1);
view->StrokeRect(strokeRect);
}
view->DrawBitmap(fBitmap, fBitmap->Bounds(), destRect);
if (fShowCaption == true)
DrawCaption(view);
}
fLock.Unlock();
}
status_t
SlideShowSaver::SetImage(const entry_ref *pref)
{
entry_ref ref;
if (!pref)
ref = fCurrentRef;
else
ref = *pref;
BTranslatorRoster *proster = BTranslatorRoster::Default();
if (!proster)
return B_ERROR;
if (ent_is_dir(pref) != B_OK)
return B_ERROR;
BFile file(&ref, B_READ_ONLY);
translator_info info;
memset(&info, 0, sizeof(translator_info));
BMessage ioExtension;
if (ioExtension.AddInt32("/documentIndex", 1 ) != B_OK)
return B_ERROR;
if (proster->Identify(&file, &ioExtension, &info, 0, NULL,
B_TRANSLATOR_BITMAP) != B_OK)
return B_ERROR;
BBitmapStream outstream;
if (proster->Translate(&file, &info, &ioExtension, &outstream,
B_TRANSLATOR_BITMAP) != B_OK)
return B_ERROR;
BBitmap *newBitmap = NULL;
if (outstream.DetachBitmap(&newBitmap) != B_OK)
return B_ERROR;
delete fBitmap;
fBitmap = newBitmap;
newBitmap = NULL;
fCurrentRef = ref;
fCaption = "<< Unable to read the path >>";
BEntry entry(&fCurrentRef);
if (entry.InitCheck() == B_OK) {
BPath path(&entry);
if (path.InitCheck() == B_OK) {
fCaption = path.Path();
}
}
return B_OK;
}
bool
SlideShowSaver::ShowNextImage(bool next, bool rewind)
{
bool found;
entry_ref curRef, imgRef;
curRef = fCurrentRef;
found = FindNextImage(&curRef, &imgRef, next, rewind);
if (found) {
while (SetImage(&imgRef) != B_OK) {
curRef = imgRef;
found = FindNextImage(&curRef, &imgRef, next, false);
if (!found)
return false;
}
return true;
}
return false;
}
bool
SlideShowSaver::IsImage(const entry_ref *pref)
{
if (!pref)
return false;
if (ent_is_dir(pref) != B_OK)
return false;
BFile file(pref, B_READ_ONLY);
if (file.InitCheck() != B_OK)
return false;
BTranslatorRoster *proster = BTranslatorRoster::Default();
if (!proster)
return false;
BMessage ioExtension;
if (ioExtension.AddInt32("/documentIndex", 1) != B_OK)
return false;
translator_info info;
memset(&info, 0, sizeof(translator_info));
if (proster->Identify(&file, &ioExtension, &info, 0, NULL,
B_TRANSLATOR_BITMAP) != B_OK)
return false;
return true;
}
bool
SlideShowSaver::FindNextImage(entry_ref *in_current, entry_ref *out_image, bool next, bool rewind)
{
BEntry curImage(in_current);
entry_ref entry, *ref;
BDirectory parent;
BList entries;
bool found = false;
int32 cur;
if (curImage.GetParent(&parent) != B_OK)
return false;
while (parent.GetNextRef(&entry) == B_OK) {
if (entry != *in_current) {
entries.AddItem(new entry_ref(entry));
} else {
entries.AddItem(in_current);
}
}
entries.SortItems(CompareEntries);
cur = entries.IndexOf(in_current);
entries.RemoveItem(in_current);
if (next) {
if (rewind) cur = 0;
for (; (ref = (entry_ref*)entries.ItemAt(cur)) != NULL; cur ++) {
if (IsImage(ref)) {
found = true;
*out_image = (const entry_ref)*ref;
break;
}
}
} else {
cur --;
for (; cur >= 0; cur --) {
ref = (entry_ref*)entries.ItemAt(cur);
if (IsImage(ref)) {
found = true;
*out_image = (const entry_ref)*ref;
break;
}
}
}
FreeEntries(&entries);
return found;
}
void
SlideShowSaver::FreeEntries(BList *entries)
{
const int32 n = entries->CountItems();
for (int32 i = 0; i < n; i ++) {
entry_ref *ref = (entry_ref *)entries->ItemAt(i);
delete ref;
}
entries->MakeEmpty();
}
void
SlideShowSaver::LayoutCaption(BView *view, BFont &font, BPoint &pos, BRect &rect)
{
font_height fontHeight;
float width, height;
BRect bounds(view->Bounds());
font = be_plain_font;
width = font.StringWidth(fCaption.String()) + 1;
font.GetHeight(&fontHeight);
height = fontHeight.ascent + fontHeight.descent;
pos.x = (bounds.left + bounds.right - width)/2;
pos.y = bounds.bottom - fontHeight.descent - 5;
rect.Set(0, 0, (width-1)+2, (height-1)+2+1);
rect.OffsetTo(pos);
rect.OffsetBy(-1, -1-fontHeight.ascent);
}
void
SlideShowSaver::DrawCaption(BView *view)
{
BFont font;
BPoint pos;
BRect rect;
LayoutCaption(view, font, pos, rect);
view->PushState();
view->SetDrawingMode(B_OP_ALPHA);
view->SetHighColor(0, 0, 255, 128);
view->FillRect(rect);
view->SetDrawingMode(B_OP_OVER);
view->SetFont(&font);
view->SetLowColor(B_TRANSPARENT_COLOR);
pos += BPoint(1, 1);
view->SetHighColor(0, 0, 0);
view->SetPenSize(1);
view->DrawString(fCaption.String(), pos);
pos -= BPoint(1, 1);
view->SetHighColor(255, 255, 0);
view->DrawString(fCaption.String(), pos);
view->PopState();
}