diff --git a/src/apps/showimage/PrintOptionsWindow.cpp b/src/apps/showimage/PrintOptionsWindow.cpp new file mode 100644 index 0000000000..1a2ed71a52 --- /dev/null +++ b/src/apps/showimage/PrintOptionsWindow.cpp @@ -0,0 +1,265 @@ +/*****************************************************************************/ +// PrintOptionsWindow +// Written by Fernando Francisco de Oliveira, Michael Wilber, Michael Pfeiffer +// +// PrintOptionsWindow.cpp +// +// +// Copyright (c) 2003 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include +#include +#include +#include // for sprintf +#include // for atof + +#include "PrintOptionsWindow.h" +#include "ShowImageConstants.h" + +PrintOptions::PrintOptions() + : fOption(kFitToPage) + , fZoomFactor(1.0) + , fDPI(72.0) + , fWidth(1024 / 72.0) + , fHeight(768 / 72.0) +{ +} + +void +PrintOptions::SetBounds(BRect rect) +{ + fBounds = rect; +} + +void +PrintOptions::SetZoomFactor(float f) +{ + fZoomFactor = f; + fDPI = 72.0 / fZoomFactor; +} + +void +PrintOptions::SetDPI(float dpi) +{ + fDPI = dpi; + fZoomFactor = 72.0 / dpi; +} + +void +PrintOptions::SetWidth(float w) +{ + fWidth = w; + fHeight = (fBounds.Height()+1) * w / (fBounds.Width()+1); +} + +void +PrintOptions::SetHeight(float h) +{ + fWidth = (fBounds.Width()+1) * h / (fBounds.Height()+1); + fHeight = h; +} + +PrintOptionsWindow::PrintOptionsWindow(BPoint at, PrintOptions *options, BWindow* listener) + : BWindow(BRect(at.x, at.y, at.x+300, at.y+200), "Print Options", + B_TITLED_WINDOW_LOOK, B_MODAL_SUBSET_WINDOW_FEEL, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE) + , fPrintOptions(options) + , fCurrentOptions(*options) + , fListener(listener) + , fStatus(B_ERROR) +{ + AddToSubset(listener); + Setup(); + Show(); +} + +PrintOptionsWindow::~PrintOptionsWindow() +{ + BMessage msg(MSG_PRINT); + msg.AddInt32("status", fStatus); + fListener.SendMessage(&msg); +} + +BRadioButton* +PrintOptionsWindow::AddRadioButton(BView* view, BPoint& at, const char* name, const char* label, uint32 what, bool selected) +{ + BRect rect(0, 0, 100, 20); + BRadioButton* button; + rect.OffsetBy(at); + button = new BRadioButton(rect, name, label, new BMessage(what)); + view->AddChild(button); + button->ResizeToPreferred(); + at.y += button->Bounds().Height() + kLineSkip; + button->SetValue(selected ? B_CONTROL_ON : B_CONTROL_OFF); + return button; +} + +BTextControl* +PrintOptionsWindow::AddTextControl(BView* view, BPoint& at, const char* name, const char* label, float value, float divider, uint32 what) +{ + BRect rect(0, 0, divider + 45, 20); + BTextControl* text; + rect.OffsetBy(at); + text = new BTextControl(rect, name, label, "", new BMessage(what)); + view->AddChild(text); + text->SetModificationMessage(new BMessage(what)); + text->SetDivider(divider); + text->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT); + SetValue(text, value); + at.y += text->Bounds().Height() + kLineSkip; + return text; +} + +void +PrintOptionsWindow::Setup() +{ + BRect rect(Bounds()); + BPoint at(kIndent, kIndent), textAt; + BString value; + enum PrintOptions::Option op = fCurrentOptions.Option(); + BRadioButton* rb; + BBox* line; + BButton* button; + + BBox *panel = new BBox(rect, "top_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + AddChild(panel); + + AddRadioButton(panel, at, "fit_to_page", "Fit Image to Page", kMsgFitToPageSelected, op == PrintOptions::kFitToPage); + textAt = at; + rb = AddRadioButton(panel, at, "zoom_factor", "Zoom Factor in %: ", kMsgZoomFactorSelected, op == PrintOptions::kZoomFactor); + textAt.x = rb->Bounds().right + 5; + fZoomFactor = AddTextControl(panel, textAt, "zoom_factor_text", "", fCurrentOptions.ZoomFactor()*100, 0, kMsgZoomFactorChanged); + + textAt = at; + rb = AddRadioButton(panel, at, "dpi", "DPI: ", kMsgDPISelected, op == PrintOptions::kDPI); + textAt.x = rb->Bounds().right + 5; + fDPI = AddTextControl(panel, textAt, "dpi_text", "", fCurrentOptions.DPI(), 0, kMsgDPIChanged); + + rb = AddRadioButton(panel, at, "width_and_height", "Resize To (in 1/72 Inches):", kMsgWidthAndHeightSelected, op == PrintOptions::kWidth || op == PrintOptions::kHeight); + at.x += 15; + textAt = at; + fWidth = AddTextControl(panel, textAt, "width", "Width: ", fCurrentOptions.Width(), 40, kMsgWidthChanged); + textAt = at; + textAt.x += fWidth->Bounds().Width() + 5; + fHeight = AddTextControl(panel, textAt, "height", "Height: ", fCurrentOptions.Height(), 40, kMsgHeightChanged); + + at.x = 0; + at.y = textAt.y; + line = new BBox(BRect(rect.left+3, at.y, rect.right-3, at.y + 1), NULL, + B_FOLLOW_LEFT | B_FOLLOW_TOP); + panel->AddChild(line); + + at.y += 10; + rect.OffsetBy(at); + button = new BButton(rect, "job setup", "Job Setup", new BMessage(kMsgJobSetup)); + panel->AddChild(button); + button->ResizeToPreferred(); + + SetDefaultButton(button); + + // resize window + ResizeTo(fHeight->Frame().right + kIndent, button->Frame().bottom + kIndent); + + // center button + button->MoveTo((Bounds().Width()-button->Bounds().Width())/2, button->Frame().top); +} + +enum PrintOptions::Option +PrintOptionsWindow::MsgToOption(uint32 what) { + switch (what) { + case kMsgFitToPageSelected: return PrintOptions::kFitToPage; + case kMsgZoomFactorSelected: return PrintOptions::kZoomFactor; + case kMsgDPISelected: return PrintOptions::kDPI; + case kMsgWidthAndHeightSelected: return PrintOptions::kWidth; + } + return PrintOptions::kFitToPage; +} + +bool +PrintOptionsWindow::GetValue(BTextControl* text, float* value) +{ + *value = atof(text->Text()); + return true; +} + +void +PrintOptionsWindow::SetValue(BTextControl* text, float value) +{ + BMessage* msg; + char s[80]; + sprintf(s, "%0.0f", value); + // prevent sending a notification when text is set + msg = new BMessage(*text->ModificationMessage()); + text->SetModificationMessage(NULL); + text->SetText(s); + text->SetModificationMessage(msg); +} + +void +PrintOptionsWindow::MessageReceived(BMessage* msg) +{ + float value; + switch (msg->what) { + case kMsgFitToPageSelected: + case kMsgZoomFactorSelected: + case kMsgDPISelected: + case kMsgWidthAndHeightSelected: + fCurrentOptions.SetOption(MsgToOption(msg->what)); + break; + + case kMsgZoomFactorChanged: + if (GetValue(fZoomFactor, &value) && fCurrentOptions.ZoomFactor() != value) { + fCurrentOptions.SetZoomFactor(value/100); + SetValue(fDPI, fCurrentOptions.DPI()); + } + break; + case kMsgDPIChanged: + if (GetValue(fDPI, &value) && fCurrentOptions.DPI() != value) { + fCurrentOptions.SetDPI(value); + SetValue(fZoomFactor, 100*fCurrentOptions.ZoomFactor()); + } + break; + case kMsgWidthChanged: + if (GetValue(fWidth, &value) && fCurrentOptions.Width() != value) { + fCurrentOptions.SetWidth(value); + SetValue(fHeight, fCurrentOptions.Height()); + } + break; + case kMsgHeightChanged: + if (GetValue(fHeight, &value) && fCurrentOptions.Height() != value) { + fCurrentOptions.SetHeight(value); + SetValue(fWidth, fCurrentOptions.Width()); + } + break; + + case kMsgJobSetup: + *fPrintOptions = fCurrentOptions; + fStatus = B_OK; + PostMessage(B_QUIT_REQUESTED); + break; + + default: + BWindow::MessageReceived(msg); + } +} diff --git a/src/apps/showimage/PrintOptionsWindow.h b/src/apps/showimage/PrintOptionsWindow.h new file mode 100644 index 0000000000..56c1e4bde0 --- /dev/null +++ b/src/apps/showimage/PrintOptionsWindow.h @@ -0,0 +1,119 @@ +/*****************************************************************************/ +// PrintOptionsWindow +// Written by Fernando Francisco de Oliveira, Michael Wilber, Michael Pfeiffer +// +// PrintOptionsWindow.h +// +// +// Copyright (c) 2003 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef _PrintOptionsWindow_h +#define _PrintOptionsWindow_h + +#include +#include +#include +#include +#include + +class PrintOptions { +public: + enum Option { + kFitToPage, + kZoomFactor, + kDPI, + kWidth, + kHeight + }; + + PrintOptions(); + + // bounds of the image + BRect Bounds() const { return fBounds; } + void SetBounds(BRect bounds); + + Option Option() const { return fOption; } + void SetOption(Option op) { fOption = op; } + // zoomFactor = 72.0 / dpi + float ZoomFactor() const { return fZoomFactor; } + void SetZoomFactor(float z); + float DPI() const { return fDPI; } + void SetDPI(float dpi); + // setting width/height updates height/width to keep aspect ratio + float Width() const { return fWidth; } + float Height() const { return fHeight; } + void SetWidth(float width); + void SetHeight(float height); + +private: + BRect fBounds; + Option fOption; + float fZoomFactor; + float fDPI; + float fWidth, fHeight; // 1/72 Inches +}; + +class PrintOptionsWindow : public BWindow +{ +public: + PrintOptionsWindow(BPoint at, PrintOptions* options, BWindow* listener); + ~PrintOptionsWindow(); + + void MessageReceived(BMessage* msg); + +private: + BRadioButton* AddRadioButton(BView* view, BPoint& at, const char* name, const char* label, uint32 what, bool selected); + BTextControl* AddTextControl(BView* view, BPoint& at, const char* name, const char* label, float value, float divider, uint32 what); + void Setup(); + enum PrintOptions::Option MsgToOption(uint32 what); + bool GetValue(BTextControl* text, float* value); + void SetValue(BTextControl* text, float value); + + enum { + kMsgOK = 'mPOW', + kMsgFitToPageSelected, + kMsgZoomFactorSelected, + kMsgDPISelected, + kMsgWidthAndHeightSelected, + + kMsgZoomFactorChanged, + kMsgDPIChanged, + kMsgWidthChanged, + kMsgHeightChanged, + + kMsgJobSetup, + + kIndent = 5, + kLineSkip = 5, + }; + + PrintOptions* fPrintOptions; + PrintOptions fCurrentOptions; + BMessenger fListener; + status_t fStatus; + BTextControl* fZoomFactor; + BTextControl* fDPI; + BTextControl* fWidth; + BTextControl* fHeight; +}; + +#endif diff --git a/src/apps/showimage/ShowImageConstants.h b/src/apps/showimage/ShowImageConstants.h index c189a20605..8daf5ac885 100644 --- a/src/apps/showimage/ShowImageConstants.h +++ b/src/apps/showimage/ShowImageConstants.h @@ -60,6 +60,12 @@ const uint32 MSG_SLIDE_SHOW_DELAY = 'mSSD'; const uint32 MSG_FULL_SCREEN = 'mFSC'; const uint32 MSG_UPDATE_RECENT_DOCUMENTS = 'mURD'; const uint32 MSG_SHOW_CAPTION = 'mSCP'; +const uint32 MSG_PAGE_SETUP = 'mPSU'; +const uint32 MSG_PREPARE_PRINT = 'mPPT'; +const uint32 MSG_PRINT = 'mPRT'; +const uint32 MSG_ZOOM_IN = 'mZIN'; +const uint32 MSG_ZOOM_OUT = 'mZOU'; +const uint32 MSG_ORIGINAL_SIZE = 'mOSZ'; extern const char *APP_SIG; diff --git a/src/apps/showimage/ShowImageView.cpp b/src/apps/showimage/ShowImageView.cpp index 55bebdce46..4d77344cf5 100644 --- a/src/apps/showimage/ShowImageView.cpp +++ b/src/apps/showimage/ShowImageView.cpp @@ -160,6 +160,7 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode, SetSlideShowDelay(3); // 3 seconds fBeginDrag = false; fShowCaption = false; + fZoom = 1.0; SetViewColor(B_TRANSPARENT_COLOR); SetHighColor(kborderColor); @@ -300,6 +301,19 @@ ShowImageView::GetBitmap() return fpBitmap; } +void +ShowImageView::GetName(BString *name) +{ + *name = ""; + BEntry entry(&fCurrentRef); + if (entry.InitCheck() == B_OK) { + char n[B_FILE_NAME_LENGTH]; + if (entry.GetName(n) == B_OK) { + name->SetTo(n); + } + } +} + void ShowImageView::GetPath(BString *name) { @@ -353,6 +367,7 @@ ShowImageView::AlignBitmap() const } } } else { + rect.right *= fZoom; rect.bottom *= fZoom; rect.OffsetBy(BORDER_WIDTH, BORDER_WIDTH); } rect.OffsetBy(PEN_SIZE, PEN_SIZE); @@ -421,7 +436,7 @@ ShowImageView::DrawCaption() width = font.StringWidth(fCaption.String())+1; // 1 for text shadow font.GetHeight(&fontHeight); height = fontHeight.ascent + fontHeight.descent; - // center text vertically + // center text horizontally pos.x = (bounds.left + bounds.right - width)/2; // flush bottom pos.y = bounds.bottom - fontHeight.descent - 5; @@ -456,26 +471,30 @@ void ShowImageView::Draw(BRect updateRect) { if (fpBitmap) { - BRect rect = AlignBitmap(); - Setup(rect); - - BRect border(rect); - border.InsetBy(-PEN_SIZE, -PEN_SIZE); - - DrawBorder(border); - - // Draw black rectangle around image - StrokeRect(border); - - // Draw image - DrawBitmap(fpBitmap, fpBitmap->Bounds(), rect); - - if (fShowCaption) { - DrawCaption(); - } - - if (fbHasSelection) { - DrawSelectionBox(fSelectionRect); + if (!IsPrinting()) { + BRect rect = AlignBitmap(); + Setup(rect); + + BRect border(rect); + border.InsetBy(-PEN_SIZE, -PEN_SIZE); + + DrawBorder(border); + + // Draw black rectangle around image + StrokeRect(border); + + // Draw image + DrawBitmap(fpBitmap, fpBitmap->Bounds(), rect); + + if (fShowCaption) { + DrawCaption(); + } + + if (fbHasSelection) { + DrawSelectionBox(fSelectionRect); + } + } else { + DrawBitmap(fpBitmap); } } } @@ -783,6 +802,7 @@ void ShowImageView::FixupScrollBars() { BScrollBar *psb; + if (fResizeToViewBounds) { psb = ScrollBar(B_HORIZONTAL); if (psb) psb->SetRange(0, 0); @@ -792,8 +812,10 @@ ShowImageView::FixupScrollBars() } BRect rctview = Bounds(), rctbitmap(0, 0, 0, 0); - if (fpBitmap) - rctbitmap = fpBitmap->Bounds(); + if (fpBitmap) { + BRect rect(AlignBitmap()); + rctbitmap.Set(0, 0, rect.Width(), rect.Height()); + } float prop, range; psb = ScrollBar(B_HORIZONTAL); @@ -914,6 +936,15 @@ ShowImageView::PrevPage() } } +int +ShowImageView::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); +} + void ShowImageView::GoToPage(int32 page) { @@ -928,73 +959,77 @@ ShowImageView::FreeEntries(BList* entries) { const int32 n = entries->CountItems(); for (int32 i = 0; i < n; i ++) { - BEntry* entry = (BEntry*)entries->ItemAt(i); - delete entry; + entry_ref* ref = (entry_ref*)entries->ItemAt(i); + delete ref; } entries->MakeEmpty(); } -// Notes: BDirectory::GetNextEntry() must not necessary -// return entries sorted by name, thou BFS does. bool -ShowImageView::FindNextImage(BEntry* image, bool next, bool rewind) +ShowImageView::FindNextImage(entry_ref* image, bool next, bool rewind) { ASSERT(next || !rewind); BEntry curImage(&fCurrentRef); - BEntry entry; + entry_ref entry, *ref; BDirectory parent; BList entries; - + bool found = false; + int32 cur; + if (curImage.GetParent(&parent) != B_OK) return false; - while (parent.GetNextEntry(&entry) == B_OK) { - if (rewind || entry == curImage) { - // start with first entry or found current image - if (next) { - // start with next entry - if (!rewind && parent.GetNextEntry(&entry) != B_OK) { - break; - } - // find next image in directory - do { - entry_ref ref; - if (entry.GetRef(&ref) == B_OK && IsImage(&ref)) { - *image = entry; - return true; - } - } while (parent.GetNextEntry(&entry) == B_OK); - } else { - // find previous image in directory - for (int32 i = entries.CountItems() - 1; i >= 0; i --) { - BEntry* entry = (BEntry*)entries.ItemAt(i); - entry_ref ref; - if (entry->GetRef(&ref) == B_OK && IsImage(&ref)) { - *image = *entry; - FreeEntries(&entries); - return true; - } - } - } - break; - } - if (!next) { - // record entries if we search for previous file - entries.AddItem(new BEntry(entry)); + while (parent.GetNextRef(&entry) == B_OK) { + if (entry != fCurrentRef) { + entries.AddItem(new entry_ref(entry)); + } else { + // insert current ref, so we can find it easily after sorting + entries.AddItem(&fCurrentRef); } } + + entries.SortItems(CompareEntries); + + cur = entries.IndexOf(&fCurrentRef); + ASSERT(cur >= 0); + + // remove it so FreeEntries() does not delete it + entries.RemoveItem(&fCurrentRef); + + if (next) { + // find the next image in the list + if (rewind) cur = 0; // start with first + for (; (ref = (entry_ref*)entries.ItemAt(cur)) != NULL; cur ++) { + if (IsImage(ref)) { + found = true; + *image = (const entry_ref)*ref; + break; + } + } + } else { + // find the previous image in the list + cur --; + for (; cur >= 0; cur --) { + ref = (entry_ref*)entries.ItemAt(cur); + if (IsImage(ref)) { + found = true; + *image = (const entry_ref)*ref; + break; + } + } + } + FreeEntries(&entries); - return false; + return found; } bool ShowImageView::ShowNextImage(bool next, bool rewind) { - BEntry image; entry_ref ref; - if (FindNextImage(&image, next, rewind) && image.GetRef(&ref) == B_OK) { - SetImage(&ref); + if (FindNextImage(&ref, next, rewind)) { + SetImage(&ref); return true; } return false; @@ -1018,6 +1053,28 @@ ShowImageView::FirstFile() return ShowNextImage(true, true); } +void +ShowImageView::SetZoom(float zoom) +{ + fZoom = zoom; + FixupScrollBars(); + Invalidate(); +} + +void +ShowImageView::ZoomIn() +{ + SetZoom(fZoom + 0.25); +} + +void +ShowImageView::ZoomOut() +{ + if (fZoom > 0.25) { + SetZoom(fZoom - 0.25); + } +} + void ShowImageView::SetSlideShowDelay(float seconds) { diff --git a/src/apps/showimage/ShowImageView.h b/src/apps/showimage/ShowImageView.h index a501561848..aa7521b60e 100644 --- a/src/apps/showimage/ShowImageView.h +++ b/src/apps/showimage/ShowImageView.h @@ -47,6 +47,7 @@ public: void SetShowCaption(bool show); void ResizeToViewBounds(bool resize); BBitmap *GetBitmap(); + void GetName(BString *name); void GetPath(BString *name); void FlushToLeftTop(); @@ -78,6 +79,9 @@ public: void SetSlideShowDelay(float seconds); void StartSlideShow(); void StopSlideShow(); + void SetZoom(float zoom); + void ZoomIn(); + void ZoomOut(); // Image manipulation void Rotate(int degree); // 90 and 270 only @@ -107,8 +111,9 @@ private: BPoint ViewToImage(BPoint p) const; BRect ImageToView(BRect r) const; bool IsImage(const entry_ref* pref); + static int CompareEntries(const void* a, const void* b); void FreeEntries(BList* entries); - bool FindNextImage(BEntry* entry, bool next, bool rewind); + bool FindNextImage(entry_ref* ref, bool next, bool rewind); bool ShowNextImage(bool next, bool rewind); bool FirstFile(); void ConstrainToImage(BPoint &point); @@ -128,6 +133,7 @@ private: int32 fDocumentIndex; int32 fDocumentCount; BBitmap *fpBitmap; + float fZoom; bool fResizeToViewBounds; float fLeft; // the origin of the image in the view float fTop; diff --git a/src/apps/showimage/ShowImageWindow.cpp b/src/apps/showimage/ShowImageWindow.cpp index 9a98d0611e..3ad8bf2baf 100644 --- a/src/apps/showimage/ShowImageWindow.cpp +++ b/src/apps/showimage/ShowImageWindow.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include "ShowImageConstants.h" #include "ShowImageWindow.h" @@ -56,6 +57,7 @@ ShowImageWindow::ShowImageWindow(const entry_ref *pref) fpSavePanel = NULL; fFullScreen = false; fShowCaption = true; // XXX what is best for default? + fPrintSettings = NULL; // create menu bar fpBar = new BMenuBar(BRect(0, 0, Bounds().right, 20), "menu_bar"); @@ -104,13 +106,13 @@ ShowImageWindow::ShowImageWindow(const entry_ref *pref) SetSizeLimits(250, 100000, 100, 100000); // finish creating window - UpdateTitle(); - fpImageView->SetImage(pref); - SetPulseRate(100000); // every 1/10 second; ShowImageView needs it for marching ants - if (InitCheck() == B_OK) { + UpdateTitle(); + + SetPulseRate(100000); // every 1/10 second; ShowImageView needs it for marching ants + fpImageView->FlushToLeftTop(); WindowRedimension(fpImageView->GetBitmap()); Show(); @@ -182,14 +184,17 @@ ShowImageWindow::LoadMenus(BMenuBar *pbar) fpOpenMenu->Superitem()->SetTarget(be_app); fpOpenMenu->Superitem()->SetShortcut('O', 0); pmenu->AddSeparatorItem(); - BMenu *pmenuSaveAs = new BMenu("Save As...", B_ITEMS_IN_COLUMN); + BMenu *pmenuSaveAs = new BMenu("Save As" B_UTF8_ELLIPSIS, B_ITEMS_IN_COLUMN); BTranslationUtils::AddTranslationItems(pmenuSaveAs, B_TRANSLATOR_BITMAP); // Fill Save As submenu with all types that can be converted // to from the Be bitmap image format pmenu->AddItem(pmenuSaveAs); AddItemMenu(pmenu, "Close", MSG_CLOSE, 'W', 0, 'W', true); pmenu->AddSeparatorItem(); - AddItemMenu(pmenu, "About ShowImage...", B_ABOUT_REQUESTED, 0, 0, 'A', true); + AddItemMenu(pmenu, "Page Setup" B_UTF8_ELLIPSIS, MSG_PAGE_SETUP, 0, 0, 'W', true); + AddItemMenu(pmenu, "Print" B_UTF8_ELLIPSIS, MSG_PREPARE_PRINT, 0, 0, 'W', true); + pmenu->AddSeparatorItem(); + AddItemMenu(pmenu, "About ShowImage" B_UTF8_ELLIPSIS, B_ABOUT_REQUESTED, 0, 0, 'A', true); pmenu->AddSeparatorItem(); AddItemMenu(pmenu, "Quit", B_QUIT_REQUESTED, 'Q', 0, 'A', true); pbar->AddItem(pmenu); @@ -250,6 +255,10 @@ ShowImageWindow::LoadMenus(BMenuBar *pbar) AddDelayItem(pDelay, "Twenty Seconds", 20, false); pmenu->AddItem(pDelay); pmenu->AddSeparatorItem(); + AddItemMenu(pmenu, "Original Size", MSG_ORIGINAL_SIZE, 0, 0, 'W', true); + AddItemMenu(pmenu, "Zoom In", MSG_ZOOM_IN, '+', 0, 'W', true); + AddItemMenu(pmenu, "Zoom Out", MSG_ZOOM_OUT, '-', 0, 'W', true); + pmenu->AddSeparatorItem(); AddItemMenu(pmenu, "Fit To Window Size", MSG_FIT_TO_WINDOW_SIZE, 0, 0, 'W', true); AddItemMenu(pmenu, "Full Screen", MSG_FULL_SCREEN, B_ENTER, 0, 'W', true); AddItemMenu(pmenu, "Show Caption in Full Screen Mode", MSG_SHOW_CAPTION, 0, 0, 'W', true); @@ -406,15 +415,21 @@ ShowImageWindow::MessageReceived(BMessage *pmsg) // Remove all page numbers delete fpGoToPageMenu->RemoveItem(0L); - for (int32 i = 1; i > 0 && i <= pages; i++) { + for (int32 i = 1; i <= pages; i++) { // Fill Go To page submenu with an entry for each page BMessage *pgomsg; + char shortcut = 0; pgomsg = new BMessage(MSG_GOTO_PAGE); pgomsg->AddInt32("page", i); BString strCaption; strCaption << i; BMenuItem *pitem; - pitem = new BMenuItem(strCaption.String(), pgomsg, 0); + if (i < 10) { + shortcut = '0' + i; + } else if (i == 10) { + shortcut = '0'; + } + pitem = new BMenuItem(strCaption.String(), pgomsg, shortcut); if (curPage == i) pitem->SetMarked(true); fpGoToPageMenu->AddItem(pitem); @@ -503,6 +518,9 @@ ShowImageWindow::MessageReceived(BMessage *pmsg) bool resize; resize = ToggleMenuItem(pmsg->what); fpImageView->ResizeToViewBounds(resize); + EnableMenuItem(MSG_ORIGINAL_SIZE, !resize); + EnableMenuItem(MSG_ZOOM_IN, !resize); + EnableMenuItem(MSG_ZOOM_OUT, !resize); } break; @@ -557,6 +575,26 @@ ShowImageWindow::MessageReceived(BMessage *pmsg) case MSG_UPDATE_RECENT_DOCUMENTS: UpdateRecentDocumentsMenu(); break; + + case MSG_PAGE_SETUP: + PageSetup(); + break; + case MSG_PREPARE_PRINT: + PrepareForPrint(); + break; + case MSG_PRINT: + Print(pmsg); + break; + + case MSG_ZOOM_IN: + fpImageView->ZoomIn(); + break; + case MSG_ZOOM_OUT: + fpImageView->ZoomOut(); + break; + case MSG_ORIGINAL_SIZE: + fpImageView->SetZoom(1.0); + break; default: BWindow::MessageReceived(pmsg); @@ -670,6 +708,106 @@ ShowImageWindow::ToggleFullScreen() ResizeTo(frame.Width(), frame.Height()); } +bool +ShowImageWindow::PageSetup() +{ + status_t st; + BString name; + fpImageView->GetName(&name); + BPrintJob printJob(name.String()); + if (fPrintSettings != NULL) { + printJob.SetSettings(new BMessage(*fPrintSettings)); + } + st = printJob.ConfigPage(); + if (st == B_OK) { + delete fPrintSettings; + fPrintSettings = printJob.Settings(); + } + return st == B_OK; +} + +void +ShowImageWindow::PrepareForPrint() +{ + if (fPrintSettings == NULL && !PageSetup()) { + return; + } + + fPrintOptions.SetBounds(fpImageView->GetBitmap()->Bounds()); + fPrintOptions.SetWidth(fpImageView->GetBitmap()->Bounds().Width()+1); + + new PrintOptionsWindow(BPoint(Frame().left+30, Frame().top+50), &fPrintOptions, this); +} + +void +ShowImageWindow::Print(BMessage *msg) +{ + status_t st; + if (msg->FindInt32("status", &st) != B_OK || st != B_OK) { + return; + } + + BString name; + fPrintOptions.SetBounds(fpImageView->GetBitmap()->Bounds()); + fpImageView->GetName(&name); + BPrintJob printJob(name.String()); + printJob.SetSettings(new BMessage(*fPrintSettings)); + if (printJob.ConfigJob() == B_OK) { + int32 firstPage; + int32 lastPage; + BRect printableRect = printJob.PrintableRect(); + float width, imageWidth, imageHeight, w1, w2; + BBitmap* bitmap; + + // first/lastPage is unused for now + firstPage = printJob.FirstPage(); + lastPage = printJob.LastPage(); + if (firstPage < 1) { + firstPage = 1; + } + if (lastPage < firstPage) { + lastPage = firstPage; + } + + bitmap = fpImageView->GetBitmap(); + imageWidth = bitmap->Bounds().Width() + 1.0; + imageHeight = bitmap->Bounds().Height() + 1.0; + + switch (fPrintOptions.Option()) { + case PrintOptions::kFitToPage: + w1 = printableRect.Width()+1; + w2 = imageWidth * (printableRect.Height() + 1) / imageHeight; + if (w2 < w1) { + width = w2; + } else { + width = w1; + } + break; + case PrintOptions::kZoomFactor: + width = imageWidth * fPrintOptions.ZoomFactor(); + break; + case PrintOptions::kDPI: + width = imageWidth * 72.0 / fPrintOptions.DPI(); + break; + case PrintOptions::kWidth: + case PrintOptions::kHeight: + width = fPrintOptions.Width(); + break; + default: + // keep compiler silent; should not reach here + width = imageWidth; + } + + // XXX: eventually print large images on several pages + printJob.BeginJob(); + fpImageView->SetScale(width / imageWidth); + printJob.DrawView(fpImageView, bitmap->Bounds(), BPoint(printableRect.left, printableRect.top)); + fpImageView->SetScale(1.0); + printJob.SpoolPage(); + printJob.CommitJob(); + } +} + bool ShowImageWindow::QuitRequested() { diff --git a/src/apps/showimage/ShowImageWindow.h b/src/apps/showimage/ShowImageWindow.h index f9153acfb1..3a4d0b75c6 100644 --- a/src/apps/showimage/ShowImageWindow.h +++ b/src/apps/showimage/ShowImageWindow.h @@ -34,6 +34,8 @@ #include #include +#include "PrintOptionsWindow.h" + class ShowImageView; class ShowImageStatusView; @@ -77,6 +79,9 @@ private: bool CanQuit(); // returns true if the window can be closed safely, false if not void ToggleFullScreen(); + bool PageSetup(); + void PrepareForPrint(); + void Print(BMessage *msg); BFilePanel *fpSavePanel; BMenuBar *fpBar; @@ -88,6 +93,8 @@ private: bool fFullScreen; BRect fWindowFrame; bool fShowCaption; + BMessage *fPrintSettings; + PrintOptions fPrintOptions; }; #endif /* _ShowImageWindow_h */ diff --git a/src/apps/showimage/ShowImageX.proj b/src/apps/showimage/ShowImageX.proj index 3116f6588d..7ec5b85f44 100644 Binary files a/src/apps/showimage/ShowImageX.proj and b/src/apps/showimage/ShowImageX.proj differ