2 * Copyright 2003-2014, Haiku, Inc. All Rights Reserved.
3 * Copyright 2004-2005 yellowTAB GmbH. All Rights Reserverd.
4 * Copyright 2006 Bernd Korz. All Rights Reserved
5 * Distributed under the terms of the MIT License.
8 * Fernando Francisco de Oliveira
13 * Axel Dörfler, axeld@pinc-software.de
14 * Stephan Aßmus <superstippi@gmx.de>
18 #include "ShowImageWindow.h"
25 #include <Application.h>
27 #include <BitmapStream.h>
30 #include <Clipboard.h>
31 #include <ControlLook.h>
32 #include <DurationFormat.h>
35 #include <FilePanel.h>
40 #include <MessageRunner.h>
43 #include <RecentItems.h>
46 #include <ScrollView.h>
48 #include <SupportDefs.h>
49 #include <TranslationDefs.h>
50 #include <TranslationUtils.h>
51 #include <TranslatorRoster.h>
53 #include "ImageCache.h"
54 #include "ProgressWindow.h"
55 #include "ShowImageApp.h"
56 #include "ShowImageConstants.h"
57 #include "ShowImageStatusView.h"
58 #include "ShowImageView.h"
59 #include "ToolBarIcons.h"
62 // BMessage field names used in Save messages
63 const char* kTypeField
= "be:type";
64 const char* kTranslatorField
= "be:translator";
66 const bigtime_t kDefaultSlideShowDelay
= 3000000;
72 MSG_CAPTURE_MOUSE
= 'mCPM',
73 MSG_CHANGE_FOCUS
= 'mCFS',
74 MSG_WINDOW_QUIT
= 'mWQT',
75 MSG_OUTPUT_TYPE
= 'BTMN',
76 MSG_SAVE_PANEL
= 'mFSP',
77 MSG_CLEAR_SELECT
= 'mCSL',
78 MSG_SELECT_ALL
= 'mSAL',
79 MSG_SELECTION_MODE
= 'mSLM',
80 MSG_PAGE_FIRST
= 'mPGF',
81 MSG_PAGE_LAST
= 'mPGL',
82 MSG_PAGE_NEXT
= 'mPGN',
83 MSG_PAGE_PREV
= 'mPGP',
84 MSG_GOTO_PAGE
= 'mGTP',
86 MSG_ZOOM_OUT
= 'mZOU',
87 MSG_SCALE_BILINEAR
= 'mSBL',
88 MSG_DESKTOP_BACKGROUND
= 'mDBG',
89 MSG_ROTATE_90
= 'mR90',
90 MSG_ROTATE_270
= 'mR27',
91 MSG_FLIP_LEFT_TO_RIGHT
= 'mFLR',
92 MSG_FLIP_TOP_TO_BOTTOM
= 'mFTB',
93 MSG_SLIDE_SHOW_DELAY
= 'mSSD',
94 MSG_SHOW_CAPTION
= 'mSCP',
95 MSG_PAGE_SETUP
= 'mPSU',
96 MSG_PREPARE_PRINT
= 'mPPT',
97 MSG_GET_INFO
= 'mGFI',
98 MSG_SET_RATING
= 'mSRT',
99 kMsgFitToWindow
= 'mFtW',
100 kMsgOriginalSize
= 'mOSZ',
101 kMsgStretchToWindow
= 'mStW',
102 kMsgNextSlide
= 'mNxS',
103 kMsgToggleToolBar
= 'mTTB',
104 kMsgSlideToolBar
= 'mSTB',
105 kMsgFinishSlidingToolBar
= 'mFST'
109 // This is temporary solution for building BString with printf like format.
110 // will be removed in the future.
112 bs_printf(BString
* string
, const char* format
, ...)
117 va_start(ap
, format
);
118 vasprintf(&buf
, format
, ap
);
125 // #pragma mark -- ShowImageWindow
128 #undef B_TRANSLATION_CONTEXT
129 #define B_TRANSLATION_CONTEXT "Menus"
132 ShowImageWindow::ShowImageWindow(BRect frame
, const entry_ref
& ref
,
133 const BMessenger
& trackerMessenger
)
135 BWindow(frame
, "", B_DOCUMENT_WINDOW
, B_AUTO_UPDATE_SIZE_LIMITS
),
136 fNavigator(ref
, trackerMessenger
),
141 fSlideShowDelayMenu(NULL
),
145 fProgressWindow(new ProgressWindow()),
150 fPrintSettings(NULL
),
151 fSlideShowRunner(NULL
),
152 fSlideShowDelay(kDefaultSlideShowDelay
)
156 SetLayout(new BGroupLayout(B_VERTICAL
, 0));
159 fBar
= new BMenuBar("menu_bar");
161 float menuBarMinWidth
= fBar
->MinSize().width
;
164 // Add a content view so the tool bar can be moved outside of the
165 // visible portion without colliding with the menu bar.
167 BView
* contentView
= new BView(BRect(), "content", B_FOLLOW_NONE
, 0);
168 contentView
->SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
169 contentView
->SetExplicitMinSize(BSize(250, 100));
170 AddChild(contentView
);
172 // Create the tool bar
173 BRect viewFrame
= contentView
->Bounds();
174 viewFrame
.right
-= B_V_SCROLL_BAR_WIDTH
;
175 fToolBar
= new BToolBar(viewFrame
);
177 // Add the tool icons.
179 // fToolBar->AddAction(MSG_FILE_OPEN, be_app,
180 // tool_bar_icon(kIconDocumentOpen), B_TRANSLATE("Open" B_UTF8_ELLIPSIS));
181 fToolBar
->AddAction(MSG_FILE_PREV
, this,
182 tool_bar_icon(kIconGoPrevious
), B_TRANSLATE("Previous file"));
183 fToolBar
->AddAction(MSG_FILE_NEXT
, this, tool_bar_icon(kIconGoNext
),
184 B_TRANSLATE("Next file"));
185 BMessage
* fullScreenSlideShow
= new BMessage(MSG_SLIDE_SHOW
);
186 fullScreenSlideShow
->AddBool("full screen", true);
187 fToolBar
->AddAction(fullScreenSlideShow
, this,
188 tool_bar_icon(kIconMediaMovieLibrary
), B_TRANSLATE("Slide show"));
189 fToolBar
->AddSeparator();
190 fToolBar
->AddAction(MSG_SELECTION_MODE
, this,
191 tool_bar_icon(kIconDrawRectangularSelection
),
192 B_TRANSLATE("Selection mode"));
193 fToolBar
->AddSeparator();
194 fToolBar
->AddAction(kMsgOriginalSize
, this,
195 tool_bar_icon(kIconZoomOriginal
), B_TRANSLATE("Original size"), NULL
,
197 fToolBar
->AddAction(kMsgFitToWindow
, this,
198 tool_bar_icon(kIconZoomFitBest
), B_TRANSLATE("Fit to window"));
199 fToolBar
->AddAction(MSG_ZOOM_IN
, this, tool_bar_icon(kIconZoomIn
),
200 B_TRANSLATE("Zoom in"));
201 fToolBar
->AddAction(MSG_ZOOM_OUT
, this, tool_bar_icon(kIconZoomOut
),
202 B_TRANSLATE("Zoom out"));
203 fToolBar
->AddSeparator();
204 fToolBar
->AddAction(MSG_PAGE_PREV
, this, tool_bar_icon(kIconPagePrevious
),
205 B_TRANSLATE("Previous page"));
206 fToolBar
->AddAction(MSG_PAGE_NEXT
, this, tool_bar_icon(kIconPageNext
),
207 B_TRANSLATE("Next page"));
209 fToolBar
->AddAction(MSG_FULL_SCREEN
, this,
210 tool_bar_icon(kIconViewWindowed
), B_TRANSLATE("Leave full screen"));
211 fToolBar
->SetActionVisible(MSG_FULL_SCREEN
, false);
213 fToolBar
->ResizeTo(viewFrame
.Width(), fToolBar
->MinSize().height
);
215 contentView
->AddChild(fToolBar
);
218 viewFrame
.top
= fToolBar
->Frame().bottom
+ 1;
222 fToolBarVisible
= fShowToolBar
;
224 viewFrame
.bottom
= contentView
->Bounds().bottom
;
225 viewFrame
.bottom
-= B_H_SCROLL_BAR_HEIGHT
;
227 // create the image view
228 fImageView
= new ShowImageView(viewFrame
, "image_view", B_FOLLOW_ALL
,
229 B_WILL_DRAW
| B_FULL_UPDATE_ON_RESIZE
| B_PULSE_NEEDED
231 // wrap a scroll view around the view
232 fScrollView
= new BScrollView("image_scroller", fImageView
,
233 B_FOLLOW_ALL
, 0, true, true, B_PLAIN_BORDER
);
234 contentView
->AddChild(fScrollView
);
236 fStatusView
= new ShowImageStatusView(fScrollView
);
237 fScrollView
->AddChild(fStatusView
);
239 // Update minimum window size
240 float toolBarMinWidth
= fToolBar
->MinSize().width
;
241 SetSizeLimits(std::max(menuBarMinWidth
, toolBarMinWidth
), 100000, 100,
244 // finish creating the window
245 if (_LoadImage() != B_OK
) {
251 // add View menu here so it can access ShowImageView methods
252 BMenu
* menu
= new BMenu(B_TRANSLATE_CONTEXT("View", "Menus"));
253 _BuildViewMenu(menu
, false);
256 fBar
->AddItem(_BuildRatingMenu());
258 SetPulseRate(100000);
259 // every 1/10 second; ShowImageView needs it for marching ants
261 _MarkMenuItem(menu
, MSG_SELECTION_MODE
,
262 fImageView
->IsSelectionModeEnabled());
264 // Tell application object to query the clipboard
265 // and tell this window if it contains interesting data or not
266 be_app_messenger
.SendMessage(B_CLIPBOARD_CHANGED
);
268 // The window will be shown on screen automatically
273 ShowImageWindow::~ShowImageWindow()
275 fProgressWindow
->Lock();
276 fProgressWindow
->Quit();
283 ShowImageWindow::BuildContextMenu(BMenu
* menu
)
285 _BuildViewMenu(menu
, true);
290 ShowImageWindow::_BuildViewMenu(BMenu
* menu
, bool popupMenu
)
292 _AddItemMenu(menu
, B_TRANSLATE("Slide show"), MSG_SLIDE_SHOW
, 0, 0, this);
293 _MarkMenuItem(menu
, MSG_SLIDE_SHOW
, fSlideShowRunner
!= NULL
);
294 BMenu
* delayMenu
= new BMenu(B_TRANSLATE("Slide delay"));
295 if (fSlideShowDelayMenu
== NULL
)
296 fSlideShowDelayMenu
= delayMenu
;
298 delayMenu
->SetRadioMode(true);
300 int32 kDelays
[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 20};
301 for (uint32 i
= 0; i
< sizeof(kDelays
) / sizeof(kDelays
[0]); i
++) {
303 BDurationFormat format
;
305 format
.Format(text
, 0, kDelays
[i
] * 1000000LL);
307 _AddDelayItem(delayMenu
, text
.String(), kDelays
[i
] * 1000000LL);
309 menu
->AddItem(delayMenu
);
311 menu
->AddSeparatorItem();
313 _AddItemMenu(menu
, B_TRANSLATE("Original size"),
314 kMsgOriginalSize
, '1', 0, this);
315 _AddItemMenu(menu
, B_TRANSLATE("Fit to window"),
316 kMsgFitToWindow
, '0', 0, this);
317 _AddItemMenu(menu
, B_TRANSLATE("Zoom in"), MSG_ZOOM_IN
, '+', 0, this);
318 _AddItemMenu(menu
, B_TRANSLATE("Zoom out"), MSG_ZOOM_OUT
, '-', 0, this);
320 menu
->AddSeparatorItem();
322 if (!popupMenu
|| fFullScreen
) {
323 _AddItemMenu(menu
, B_TRANSLATE("High-quality zooming"),
324 MSG_SCALE_BILINEAR
, 0, 0, this);
325 _AddItemMenu(menu
, B_TRANSLATE("Stretch to window"),
326 kMsgStretchToWindow
, 0, 0, this);
328 menu
->AddSeparatorItem();
331 _AddItemMenu(menu
, B_TRANSLATE("Full screen"),
332 MSG_FULL_SCREEN
, B_ENTER
, 0, this);
333 _MarkMenuItem(menu
, MSG_FULL_SCREEN
, fFullScreen
);
335 _AddItemMenu(menu
, B_TRANSLATE("Show caption in full screen mode"),
336 MSG_SHOW_CAPTION
, 0, 0, this);
337 _MarkMenuItem(menu
, MSG_SHOW_CAPTION
, fShowCaption
);
339 _MarkMenuItem(menu
, MSG_SCALE_BILINEAR
, fImageView
->ScaleBilinear());
340 _MarkMenuItem(menu
, kMsgStretchToWindow
, fImageView
->StretchesToBounds());
343 _AddItemMenu(menu
, B_TRANSLATE("Show tool bar"), kMsgToggleToolBar
,
345 _MarkMenuItem(menu
, kMsgToggleToolBar
,
346 !fToolBar
->IsHidden(fToolBar
));
350 menu
->AddSeparatorItem();
351 _AddItemMenu(menu
, B_TRANSLATE("Use as background" B_UTF8_ELLIPSIS
),
352 MSG_DESKTOP_BACKGROUND
, 0, 0, this);
358 ShowImageWindow::_BuildRatingMenu()
360 fRatingMenu
= new BMenu(B_TRANSLATE("Rating"));
361 for (int32 i
= 1; i
<= 10; i
++) {
364 BMessage
* message
= new BMessage(MSG_SET_RATING
);
365 message
->AddInt32("rating", i
);
366 fRatingMenu
->AddItem(new BMenuItem(label
.String(), message
));
368 // NOTE: We may want to encapsulate the Rating menu within a more
369 // general "Attributes" menu.
375 ShowImageWindow::_AddMenus(BMenuBar
* bar
)
377 BMenu
* menu
= new BMenu(B_TRANSLATE("File"));
379 // Add recent files to "Open File" entry as sub-menu.
380 BMenuItem
* item
= new BMenuItem(BRecentFilesList::NewFileListMenu(
381 B_TRANSLATE("Open" B_UTF8_ELLIPSIS
), NULL
, NULL
, be_app
, 10, true,
382 NULL
, kApplicationSignature
), new BMessage(MSG_FILE_OPEN
));
383 item
->SetShortcut('O', 0);
384 item
->SetTarget(be_app
);
386 menu
->AddSeparatorItem();
388 BMenu
* menuSaveAs
= new BMenu(B_TRANSLATE("Save as" B_UTF8_ELLIPSIS
),
390 BTranslationUtils::AddTranslationItems(menuSaveAs
, B_TRANSLATOR_BITMAP
);
391 // Fill Save As submenu with all types that can be converted
392 // to from the Be bitmap image format
393 menu
->AddItem(menuSaveAs
);
394 _AddItemMenu(menu
, B_TRANSLATE("Close"), B_QUIT_REQUESTED
, 'W', 0, this);
395 _AddItemMenu(menu
, B_TRANSLATE("Move to Trash"), kMsgDeleteCurrentFile
, 'T', 0, this);
396 _AddItemMenu(menu
, B_TRANSLATE("Get info" B_UTF8_ELLIPSIS
),
397 MSG_GET_INFO
, 'I', 0, this);
398 menu
->AddSeparatorItem();
399 _AddItemMenu(menu
, B_TRANSLATE("Page setup" B_UTF8_ELLIPSIS
),
400 MSG_PAGE_SETUP
, 0, 0, this);
401 _AddItemMenu(menu
, B_TRANSLATE("Print" B_UTF8_ELLIPSIS
),
402 MSG_PREPARE_PRINT
, 'P', 0, this);
403 menu
->AddSeparatorItem();
404 _AddItemMenu(menu
, B_TRANSLATE("Quit"), B_QUIT_REQUESTED
, 'Q', 0, be_app
);
407 menu
= new BMenu(B_TRANSLATE("Edit"));
408 _AddItemMenu(menu
, B_TRANSLATE("Copy"), B_COPY
, 'C', 0, this, false);
409 menu
->AddSeparatorItem();
410 _AddItemMenu(menu
, B_TRANSLATE("Selection mode"), MSG_SELECTION_MODE
, 0, 0,
412 _AddItemMenu(menu
, B_TRANSLATE("Clear selection"),
413 MSG_CLEAR_SELECT
, 0, 0, this, false);
414 _AddItemMenu(menu
, B_TRANSLATE("Select all"),
415 MSG_SELECT_ALL
, 'A', 0, this);
418 menu
= fBrowseMenu
= new BMenu(B_TRANSLATE("Browse"));
419 _AddItemMenu(menu
, B_TRANSLATE("First page"),
420 MSG_PAGE_FIRST
, B_LEFT_ARROW
, B_SHIFT_KEY
, this);
421 _AddItemMenu(menu
, B_TRANSLATE("Last page"),
422 MSG_PAGE_LAST
, B_RIGHT_ARROW
, B_SHIFT_KEY
, this);
423 _AddItemMenu(menu
, B_TRANSLATE("Previous page"),
424 MSG_PAGE_PREV
, B_LEFT_ARROW
, 0, this);
425 _AddItemMenu(menu
, B_TRANSLATE("Next page"),
426 MSG_PAGE_NEXT
, B_RIGHT_ARROW
, 0, this);
427 fGoToPageMenu
= new BMenu(B_TRANSLATE("Go to page"));
428 fGoToPageMenu
->SetRadioMode(true);
429 menu
->AddItem(fGoToPageMenu
);
430 menu
->AddSeparatorItem();
431 _AddItemMenu(menu
, B_TRANSLATE("Previous file"),
432 MSG_FILE_PREV
, B_UP_ARROW
, 0, this);
433 _AddItemMenu(menu
, B_TRANSLATE("Next file"),
434 MSG_FILE_NEXT
, B_DOWN_ARROW
, 0, this);
437 menu
= new BMenu(B_TRANSLATE("Image"));
438 _AddItemMenu(menu
, B_TRANSLATE("Rotate clockwise"),
439 MSG_ROTATE_90
, 'R', 0, this);
440 _AddItemMenu(menu
, B_TRANSLATE("Rotate counterclockwise"),
441 MSG_ROTATE_270
, 'R', B_SHIFT_KEY
, this);
442 menu
->AddSeparatorItem();
443 _AddItemMenu(menu
, B_TRANSLATE("Flip left to right"),
444 MSG_FLIP_LEFT_TO_RIGHT
, 0, 0, this);
445 _AddItemMenu(menu
, B_TRANSLATE("Flip top to bottom"),
446 MSG_FLIP_TOP_TO_BOTTOM
, 0, 0, this);
447 menu
->AddSeparatorItem();
448 _AddItemMenu(menu
, B_TRANSLATE("Use as background" B_UTF8_ELLIPSIS
),
449 MSG_DESKTOP_BACKGROUND
, 0, 0, this);
456 ShowImageWindow::_AddItemMenu(BMenu
* menu
, const char* label
, uint32 what
,
457 char shortcut
, uint32 modifier
, const BHandler
* target
, bool enabled
)
459 BMenuItem
* item
= new BMenuItem(label
, new BMessage(what
), shortcut
,
463 item
->SetTarget(target
);
464 item
->SetEnabled(enabled
);
471 ShowImageWindow::_AddDelayItem(BMenu
* menu
, const char* label
, bigtime_t delay
)
473 BMessage
* message
= new BMessage(MSG_SLIDE_SHOW_DELAY
);
474 message
->AddInt64("delay", delay
);
476 BMenuItem
* item
= new BMenuItem(label
, message
, 0);
477 item
->SetTarget(this);
479 if (delay
== fSlideShowDelay
)
480 item
->SetMarked(true);
488 ShowImageWindow::_ResizeWindowToImage()
490 BBitmap
* bitmap
= fImageView
->Bitmap();
492 if (bitmap
== NULL
|| !screen
.IsValid())
495 // TODO: use View::GetPreferredSize() instead?
496 BRect
r(bitmap
->Bounds());
497 float width
= r
.Width() + B_V_SCROLL_BAR_WIDTH
;
498 float height
= r
.Height() + 1 + fBar
->Frame().Height()
499 + B_H_SCROLL_BAR_HEIGHT
;
501 BRect frame
= screen
.Frame();
502 const float windowBorder
= 5;
503 // dimensions so that window does not reach outside of screen
504 float maxWidth
= frame
.Width() + 1 - windowBorder
- Frame().left
;
505 float maxHeight
= frame
.Height() + 1 - windowBorder
- Frame().top
;
507 // We have to check size limits manually, otherwise
508 // menu bar will be too short for small images.
510 float minW
, maxW
, minH
, maxH
;
511 GetSizeLimits(&minW
, &maxW
, &minH
, &maxH
);
514 if (maxHeight
> maxH
)
521 if (width
> maxWidth
)
523 if (height
> maxHeight
)
526 ResizeTo(width
, height
);
531 ShowImageWindow::_ToggleMenuItem(uint32 what
)
534 BMenuItem
* item
= fBar
->FindItem(what
);
536 marked
= !item
->IsMarked();
537 item
->SetMarked(marked
);
539 fToolBar
->SetActionPressed(what
, marked
);
545 ShowImageWindow::_EnableMenuItem(BMenu
* menu
, uint32 what
, bool enable
)
547 BMenuItem
* item
= menu
->FindItem(what
);
548 if (item
&& item
->IsEnabled() != enable
)
549 item
->SetEnabled(enable
);
550 fToolBar
->SetActionEnabled(what
, enable
);
555 ShowImageWindow::_MarkMenuItem(BMenu
* menu
, uint32 what
, bool marked
)
557 BMenuItem
* item
= menu
->FindItem(what
);
558 if (item
&& item
->IsMarked() != marked
)
559 item
->SetMarked(marked
);
560 fToolBar
->SetActionPressed(what
, marked
);
565 ShowImageWindow::_MarkSlideShowDelay(bigtime_t delay
)
567 const int32 count
= fSlideShowDelayMenu
->CountItems();
568 for (int32 i
= 0; i
< count
; i
++) {
569 BMenuItem
* item
= fSlideShowDelayMenu
->ItemAt(i
);
572 if (item
->Message()->FindInt64("delay", &itemDelay
) == B_OK
573 && itemDelay
== delay
) {
574 item
->SetMarked(true);
583 ShowImageWindow::Zoom(BPoint origin
, float width
, float height
)
590 ShowImageWindow::MessageReceived(BMessage
* message
)
592 if (message
->WasDropped()) {
595 status_t status
= message
->GetInfo("refs", &type
, &count
);
596 if (status
== B_OK
&& type
== B_REF_TYPE
) {
597 message
->what
= B_REFS_RECEIVED
;
598 be_app
->PostMessage(message
);
602 switch (message
->what
) {
603 case kMsgImageCacheImageLoaded
:
605 fProgressWindow
->Stop();
607 BitmapOwner
* bitmapOwner
= NULL
;
608 message
->FindPointer("bitmapOwner", (void**)&bitmapOwner
);
610 bool first
= fImageView
->Bitmap() == NULL
;
612 message
->FindRef("ref", &ref
);
613 if (!first
&& ref
!= fNavigator
.CurrentRef()) {
614 // ignore older images
615 if (bitmapOwner
!= NULL
)
616 bitmapOwner
->ReleaseReference();
620 int32 page
= message
->FindInt32("page");
621 int32 pageCount
= message
->FindInt32("pageCount");
622 if (!first
&& page
!= fNavigator
.CurrentPage()) {
623 // ignore older pages
624 if (bitmapOwner
!= NULL
)
625 bitmapOwner
->ReleaseReference();
629 status_t status
= fImageView
->SetImage(message
);
630 if (status
!= B_OK
) {
631 if (bitmapOwner
!= NULL
)
632 bitmapOwner
->ReleaseReference();
636 // quit if file could not be opened
642 fImageType
= message
->FindString("type");
643 fNavigator
.SetTo(ref
, page
, pageCount
);
645 fImageView
->FitToBounds();
647 fImageView
->MakeFocus(true);
648 // to receive key messages
652 // Set width and height attributes of the currently showed file.
653 // This should only be a temporary solution.
654 _SaveWidthAndHeight();
658 case kMsgImageCacheProgressUpdate
:
661 if (message
->FindRef("ref", &ref
) == B_OK
662 && ref
== fNavigator
.CurrentRef()) {
663 message
->what
= kMsgProgressUpdate
;
664 fProgressWindow
->PostMessage(message
);
670 // If image has been modified due to a Cut or Paste
674 case MSG_OUTPUT_TYPE
:
675 // User clicked Save As then choose an output format
677 // If user doesn't already have a save panel open
682 // User specified where to save the output image
683 _SaveToFile(message
);
691 case MSG_UPDATE_STATUS
:
693 int32 pages
= fNavigator
.PageCount();
694 int32 currentPage
= fNavigator
.CurrentPage();
696 _EnableMenuItem(fBar
, MSG_PAGE_FIRST
,
697 fNavigator
.HasPreviousPage());
698 _EnableMenuItem(fBar
, MSG_PAGE_LAST
, fNavigator
.HasNextPage());
699 _EnableMenuItem(fBar
, MSG_PAGE_NEXT
, fNavigator
.HasNextPage());
700 _EnableMenuItem(fBar
, MSG_PAGE_PREV
, fNavigator
.HasPreviousPage());
701 fGoToPageMenu
->SetEnabled(pages
> 1);
703 _EnableMenuItem(fBar
, MSG_FILE_NEXT
, fNavigator
.HasNextFile());
704 _EnableMenuItem(fBar
, MSG_FILE_PREV
, fNavigator
.HasPreviousFile());
706 if (fGoToPageMenu
->CountItems() != pages
) {
707 // Only rebuild the submenu if the number of
708 // pages is different
710 while (fGoToPageMenu
->CountItems() > 0) {
711 // Remove all page numbers
712 delete fGoToPageMenu
->RemoveItem((int32
)0);
715 for (int32 i
= 1; i
<= pages
; i
++) {
716 // Fill Go To page submenu with an entry for each page
717 BMessage
* goTo
= new BMessage(MSG_GOTO_PAGE
);
718 goTo
->AddInt32("page", i
);
727 BMenuItem
* item
= new BMenuItem(strCaption
.String(), goTo
,
728 shortcut
, B_SHIFT_KEY
);
729 if (currentPage
== i
)
730 item
->SetMarked(true);
731 fGoToPageMenu
->AddItem(item
);
734 // Make sure the correct page is marked
735 BMenuItem
* currentItem
= fGoToPageMenu
->ItemAt(currentPage
- 1);
736 if (currentItem
!= NULL
&& !currentItem
->IsMarked())
737 currentItem
->SetMarked(true);
740 _UpdateStatusText(message
);
742 BPath
path(fImageView
->Image());
743 SetTitle(path
.Path());
747 case MSG_UPDATE_STATUS_TEXT
:
749 _UpdateStatusText(message
);
755 // The view sends this message when a selection is
756 // made or the selection is cleared so that the window
757 // can update the state of the appropriate menu items
759 if (message
->FindBool("has_selection", &enable
) == B_OK
) {
760 _EnableMenuItem(fBar
, B_COPY
, enable
);
761 _EnableMenuItem(fBar
, MSG_CLEAR_SELECT
, enable
);
767 fImageView
->CopySelectionToClipboard();
770 case MSG_SELECTION_MODE
:
772 bool selectionMode
= _ToggleMenuItem(MSG_SELECTION_MODE
);
773 fImageView
->SetSelectionMode(selectionMode
);
775 fImageView
->ClearSelection();
779 case MSG_CLEAR_SELECT
:
780 fImageView
->ClearSelection();
784 fImageView
->SelectAll();
788 if (_ClosePrompt() && fNavigator
.FirstPage())
793 if (_ClosePrompt() && fNavigator
.LastPage())
798 if (_ClosePrompt() && fNavigator
.NextPage())
803 if (_ClosePrompt() && fNavigator
.PreviousPage())
813 if (message
->FindInt32("page", &newPage
) != B_OK
)
816 int32 currentPage
= fNavigator
.CurrentPage();
817 int32 pages
= fNavigator
.PageCount();
819 // TODO: use radio mode instead!
820 if (newPage
> 0 && newPage
<= pages
) {
821 BMenuItem
* currentItem
= fGoToPageMenu
->ItemAt(currentPage
- 1);
822 BMenuItem
* newItem
= fGoToPageMenu
->ItemAt(newPage
- 1);
823 if (currentItem
!= NULL
&& newItem
!= NULL
) {
824 currentItem
->SetMarked(false);
825 newItem
->SetMarked(true);
826 if (fNavigator
.GoToPage(newPage
))
833 case kMsgFitToWindow
:
834 fImageView
->FitToBounds();
837 case kMsgStretchToWindow
:
838 fImageView
->SetStretchToBounds(
839 _ToggleMenuItem(kMsgStretchToWindow
));
843 if (_ClosePrompt() && fNavigator
.PreviousFile())
849 if (_ClosePrompt() && fNavigator
.NextFile())
853 case kMsgDeleteCurrentFile
:
855 if (fNavigator
.MoveFileToTrash())
858 PostMessage(B_QUIT_REQUESTED
);
863 fImageView
->Rotate(90);
867 fImageView
->Rotate(270);
870 case MSG_FLIP_LEFT_TO_RIGHT
:
871 fImageView
->Flip(true);
874 case MSG_FLIP_TOP_TO_BOTTOM
:
875 fImageView
->Flip(false);
879 _GetFileInfo(fNavigator
.CurrentRef());
884 bool fullScreen
= false;
885 message
->FindBool("full screen", &fullScreen
);
887 BMenuItem
* item
= fBar
->FindItem(message
->what
);
891 if (item
->IsMarked()) {
892 item
->SetMarked(false);
894 fToolBar
->SetActionPressed(MSG_SLIDE_SHOW
, false);
895 } else if (_ClosePrompt()) {
896 item
->SetMarked(true);
897 if (!fFullScreen
&& fullScreen
)
900 fToolBar
->SetActionPressed(MSG_SLIDE_SHOW
, true);
905 case kMsgStopSlideShow
:
907 BMenuItem
* item
= fBar
->FindItem(MSG_SLIDE_SHOW
);
909 item
->SetMarked(false);
912 fToolBar
->SetActionPressed(MSG_SLIDE_SHOW
, false);
916 case MSG_SLIDE_SHOW_DELAY
:
919 if (message
->FindInt64("delay", &delay
) == B_OK
) {
920 _SetSlideShowDelay(delay
);
921 // in case message is sent from popup menu
922 _MarkSlideShowDelay(delay
);
927 case MSG_FULL_SCREEN
:
931 case MSG_EXIT_FULL_SCREEN
:
936 case MSG_SHOW_CAPTION
:
938 fShowCaption
= _ToggleMenuItem(message
->what
);
939 ShowImageSettings
* settings
= my_app
->Settings();
941 if (settings
->Lock()) {
942 settings
->SetBool("ShowCaption", fShowCaption
);
946 fImageView
->SetShowCaption(fShowCaption
);
953 case MSG_PREPARE_PRINT
:
962 fImageView
->ZoomIn();
966 fImageView
->ZoomOut();
969 case MSG_UPDATE_STATUS_ZOOM
:
970 fStatusView
->SetZoom(fImageView
->Zoom());
973 case kMsgOriginalSize
:
974 if (message
->FindInt32("behavior") == BButton::B_TOGGLE_BEHAVIOR
) {
975 bool force
= (message
->FindInt32("be:value") == B_CONTROL_ON
);
976 fImageView
->ForceOriginalSize(force
);
980 fImageView
->SetZoom(1.0);
983 case MSG_SCALE_BILINEAR
:
984 fImageView
->SetScaleBilinear(_ToggleMenuItem(message
->what
));
987 case MSG_DESKTOP_BACKGROUND
:
989 BMessage
backgroundsMessage(B_REFS_RECEIVED
);
990 backgroundsMessage
.AddRef("refs", fImageView
->Image());
991 // This is used in the Backgrounds code for scaled placement
992 backgroundsMessage
.AddInt32("placement", 'scpl');
993 be_roster
->Launch("application/x-vnd.haiku-backgrounds",
994 &backgroundsMessage
);
1001 if (message
->FindInt32("rating", &rating
) != B_OK
)
1003 BFile
file(&fNavigator
.CurrentRef(), B_WRITE_ONLY
);
1004 if (file
.InitCheck() != B_OK
)
1006 file
.WriteAttr("Media:Rating", B_INT32_TYPE
, 0, &rating
,
1008 _UpdateRatingMenu();
1012 case kMsgToggleToolBar
:
1014 fShowToolBar
= _ToggleMenuItem(message
->what
);
1015 _SetToolBarVisible(fShowToolBar
, true);
1017 ShowImageSettings
* settings
= my_app
->Settings();
1019 if (settings
->Lock()) {
1020 settings
->SetBool("ShowToolBar", fShowToolBar
);
1025 case kShowToolBarIfEnabled
:
1028 if (message
->FindBool("show", &show
) != B_OK
)
1030 _SetToolBarVisible(fShowToolBar
&& show
, true);
1033 case kMsgSlideToolBar
:
1036 if (message
->FindFloat("offset", &offset
) == B_OK
) {
1037 fToolBar
->MoveBy(0, offset
);
1038 fScrollView
->ResizeBy(0, -offset
);
1039 fScrollView
->MoveBy(0, offset
);
1045 case kMsgFinishSlidingToolBar
:
1049 if (message
->FindFloat("offset", &offset
) == B_OK
1050 && message
->FindBool("show", &show
) == B_OK
) {
1051 // Compensate rounding errors with the final placement
1052 fToolBar
->MoveTo(fToolBar
->Frame().left
, offset
);
1055 BRect frame
= fToolBar
->Parent()->Bounds();
1056 frame
.top
= fToolBar
->Frame().bottom
+ 1;
1057 fScrollView
->MoveTo(fScrollView
->Frame().left
, frame
.top
);
1058 fScrollView
->ResizeTo(fScrollView
->Bounds().Width(),
1059 frame
.Height() + 1);
1065 BWindow::MessageReceived(message
);
1072 ShowImageWindow::_GetFileInfo(const entry_ref
& ref
)
1074 BMessage
message('Tinf');
1075 BMessenger
tracker("application/x-vnd.Be-TRAK");
1076 message
.AddRef("refs", &ref
);
1077 tracker
.SendMessage(&message
);
1082 ShowImageWindow::_UpdateStatusText(const BMessage
* message
)
1085 if (fImageView
->Bitmap() != NULL
) {
1086 BRect bounds
= fImageView
->Bitmap()->Bounds();
1087 frameText
<< bounds
.IntegerWidth() + 1
1088 << "x" << bounds
.IntegerHeight() + 1;
1091 if (fNavigator
.PageCount() > 1)
1092 pages
<< fNavigator
.CurrentPage() << "/" << fNavigator
.PageCount();
1093 fStatusView
->Update(fNavigator
.CurrentRef(), frameText
, pages
, fImageType
,
1094 fImageView
->Zoom());
1099 ShowImageWindow::_LoadError(const entry_ref
& ref
)
1101 // TODO: give a better error message!
1102 BAlert
* alert
= new BAlert(B_TRANSLATE_SYSTEM_NAME("ShowImage"),
1103 B_TRANSLATE_CONTEXT("Could not load image! Either the "
1104 "file or an image translator for it does not exist.",
1106 B_TRANSLATE_CONTEXT("OK", "Alerts"), NULL
, NULL
,
1107 B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
1108 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
1114 ShowImageWindow::_SaveAs(BMessage
* message
)
1116 // Read the translator and output type the user chose
1117 translator_id outTranslator
;
1119 if (message
->FindInt32(kTranslatorField
,
1120 reinterpret_cast<int32
*>(&outTranslator
)) != B_OK
1121 || message
->FindInt32(kTypeField
,
1122 reinterpret_cast<int32
*>(&outType
)) != B_OK
)
1125 // Add the chosen translator and output type to the
1126 // message that the save panel will send back
1127 BMessage
panelMsg(MSG_SAVE_PANEL
);
1128 panelMsg
.AddInt32(kTranslatorField
, outTranslator
);
1129 panelMsg
.AddInt32(kTypeField
, outType
);
1131 // Create save panel and show it
1132 BMessenger
target(this);
1133 fSavePanel
= new (std::nothrow
) BFilePanel(B_SAVE_PANEL
,
1134 &target
, NULL
, 0, false, &panelMsg
);
1138 // Retrieve save directory from settings;
1139 ShowImageSettings
* settings
= my_app
->Settings();
1140 if (settings
->Lock()) {
1141 fSavePanel
->SetPanelDirectory(
1142 settings
->GetString("SaveDirectory", NULL
));
1146 fSavePanel
->Window()->SetWorkspaces(B_CURRENT_WORKSPACE
);
1152 ShowImageWindow::_SaveToFile(BMessage
* message
)
1154 // Read in where the file should be saved
1156 if (message
->FindRef("directory", &dirRef
) != B_OK
)
1159 const char* filename
;
1160 if (message
->FindString("name", &filename
) != B_OK
)
1163 // Read in the translator and type to be used
1164 // to save the output image
1165 translator_id outTranslator
;
1167 if (message
->FindInt32(kTranslatorField
,
1168 reinterpret_cast<int32
*>(&outTranslator
)) != B_OK
1169 || message
->FindInt32(kTypeField
,
1170 reinterpret_cast<int32
*>(&outType
)) != B_OK
)
1173 // Find the translator_format information needed to
1174 // write a MIME attribute for the image file
1175 BTranslatorRoster
* roster
= BTranslatorRoster::Default();
1176 const translation_format
* outFormat
= NULL
;
1178 if (roster
->GetOutputFormats(outTranslator
, &outFormat
, &outCount
) != B_OK
1183 for (i
= 0; i
< outCount
; i
++) {
1184 if (outFormat
[i
].group
== B_TRANSLATOR_BITMAP
&& outFormat
[i
].type
1191 // Write out the image file
1192 BDirectory
dir(&dirRef
);
1193 fImageView
->SaveToFile(&dir
, filename
, NULL
, &outFormat
[i
]);
1195 // Store Save directory in settings;
1196 ShowImageSettings
* settings
= my_app
->Settings();
1197 if (settings
->Lock()) {
1198 BPath
path(&dirRef
);
1199 settings
->SetString("SaveDirectory", path
.Path());
1205 #undef B_TRANSLATION_CONTEXT
1206 #define B_TRANSLATION_CONTEXT "ClosePrompt"
1210 ShowImageWindow::_ClosePrompt()
1215 int32 count
= fNavigator
.PageCount();
1216 int32 page
= fNavigator
.CurrentPage();
1221 B_TRANSLATE("The document '%s' (page %d) has been changed. Do you "
1222 "want to close the document?"),
1223 fImageView
->Image()->name
, page
);
1226 B_TRANSLATE("The document '%s' has been changed. Do you want to "
1227 "close the document?"),
1228 fImageView
->Image()->name
);
1231 BAlert
* alert
= new BAlert(B_TRANSLATE("Close document"), prompt
.String(),
1232 B_TRANSLATE("Cancel"), B_TRANSLATE("Close"));
1233 alert
->SetShortcut(0, B_ESCAPE
);
1235 if (alert
->Go() == 0) {
1247 ShowImageWindow::_LoadImage(bool forward
)
1249 BMessenger
us(this);
1250 status_t status
= my_app
->DefaultCache().RetrieveImage(
1251 fNavigator
.CurrentRef(), fNavigator
.CurrentPage(), &us
);
1255 fProgressWindow
->Start(this);
1257 // Preload previous/next images - two in the navigation direction, one
1258 // in the opposite direction.
1260 entry_ref nextRef
= fNavigator
.CurrentRef();
1261 if (_PreloadImage(forward
, nextRef
))
1262 _PreloadImage(forward
, nextRef
);
1264 entry_ref previousRef
= fNavigator
.CurrentRef();
1265 _PreloadImage(!forward
, previousRef
);
1272 ShowImageWindow::_PreloadImage(bool forward
, entry_ref
& ref
)
1274 entry_ref currentRef
= ref
;
1275 if ((forward
&& !fNavigator
.GetNextFile(currentRef
, ref
))
1276 || (!forward
&& !fNavigator
.GetPreviousFile(currentRef
, ref
)))
1279 return my_app
->DefaultCache().RetrieveImage(ref
) == B_OK
;
1284 ShowImageWindow::_ToggleFullScreen()
1287 fFullScreen
= !fFullScreen
;
1290 fWindowFrame
= Frame();
1291 frame
= screen
.Frame();
1292 frame
.top
-= fBar
->Bounds().Height() + 1;
1293 frame
.right
+= B_V_SCROLL_BAR_WIDTH
;
1294 frame
.bottom
+= B_H_SCROLL_BAR_HEIGHT
;
1296 SetFlags(Flags() | B_NOT_RESIZABLE
| B_NOT_MOVABLE
);
1299 // make the window frontmost
1301 frame
= fWindowFrame
;
1303 SetFlags(Flags() & ~(B_NOT_RESIZABLE
| B_NOT_MOVABLE
));
1306 fToolBar
->SetActionVisible(MSG_FULL_SCREEN
, fFullScreen
);
1307 _SetToolBarVisible(!fFullScreen
&& fShowToolBar
);
1308 _SetToolBarBorder(!fFullScreen
);
1310 MoveTo(frame
.left
, frame
.top
);
1311 ResizeTo(frame
.Width(), frame
.Height());
1313 fImageView
->SetHideIdlingCursor(fFullScreen
);
1314 fImageView
->SetShowCaption(fFullScreen
&& fShowCaption
);
1317 // We need to manually relayout here, as the views are layouted
1318 // asynchronously, and FitToBounds() would still have the wrong size
1319 fImageView
->FitToBounds();
1324 ShowImageWindow::_ApplySettings()
1326 ShowImageSettings
* settings
= my_app
->Settings();
1328 if (settings
->Lock()) {
1329 fShowCaption
= settings
->GetBool("ShowCaption", fShowCaption
);
1330 fPrintOptions
.SetBounds(BRect(0, 0, 1023, 767));
1332 fSlideShowDelay
= settings
->GetTime("SlideShowDelay", fSlideShowDelay
);
1334 fPrintOptions
.SetOption((enum PrintOptions::Option
)settings
->GetInt32(
1335 "PO:Option", fPrintOptions
.Option()));
1336 fPrintOptions
.SetZoomFactor(
1337 settings
->GetFloat("PO:ZoomFactor", fPrintOptions
.ZoomFactor()));
1338 fPrintOptions
.SetDPI(settings
->GetFloat("PO:DPI", fPrintOptions
.DPI()));
1339 fPrintOptions
.SetWidth(
1340 settings
->GetFloat("PO:Width", fPrintOptions
.Width()));
1341 fPrintOptions
.SetHeight(
1342 settings
->GetFloat("PO:Height", fPrintOptions
.Height()));
1344 fShowToolBar
= settings
->GetBool("ShowToolBar", fShowToolBar
);
1352 ShowImageWindow::_SavePrintOptions()
1354 ShowImageSettings
* settings
= my_app
->Settings();
1356 if (settings
->Lock()) {
1357 settings
->SetInt32("PO:Option", fPrintOptions
.Option());
1358 settings
->SetFloat("PO:ZoomFactor", fPrintOptions
.ZoomFactor());
1359 settings
->SetFloat("PO:DPI", fPrintOptions
.DPI());
1360 settings
->SetFloat("PO:Width", fPrintOptions
.Width());
1361 settings
->SetFloat("PO:Height", fPrintOptions
.Height());
1368 ShowImageWindow::_PageSetup()
1370 BPrintJob
printJob(fImageView
->Image()->name
);
1371 if (fPrintSettings
!= NULL
)
1372 printJob
.SetSettings(new BMessage(*fPrintSettings
));
1374 status_t status
= printJob
.ConfigPage();
1375 if (status
== B_OK
) {
1376 delete fPrintSettings
;
1377 fPrintSettings
= printJob
.Settings();
1380 return status
== B_OK
;
1385 ShowImageWindow::_PrepareForPrint()
1387 if (fPrintSettings
== NULL
) {
1388 BPrintJob
printJob(fImageView
->Image()->name
);
1389 if (printJob
.ConfigJob() == B_OK
)
1390 fPrintSettings
= printJob
.Settings();
1393 fPrintOptions
.SetBounds(fImageView
->Bitmap()->Bounds());
1394 fPrintOptions
.SetWidth(fImageView
->Bitmap()->Bounds().Width() + 1);
1396 new PrintOptionsWindow(BPoint(Frame().left
+ 30, Frame().top
+ 50),
1397 &fPrintOptions
, this);
1402 ShowImageWindow::_Print(BMessage
* msg
)
1405 if (msg
->FindInt32("status", &st
) != B_OK
|| st
!= B_OK
)
1408 _SavePrintOptions();
1410 BPrintJob
printJob(fImageView
->Image()->name
);
1412 printJob
.SetSettings(new BMessage(*fPrintSettings
));
1414 if (printJob
.ConfigJob() == B_OK
) {
1415 delete fPrintSettings
;
1416 fPrintSettings
= printJob
.Settings();
1418 // first/lastPage is unused for now
1419 int32 firstPage
= printJob
.FirstPage();
1420 int32 lastPage
= printJob
.LastPage();
1421 BRect printableRect
= printJob
.PrintableRect();
1425 if (lastPage
< firstPage
)
1426 lastPage
= firstPage
;
1428 BBitmap
* bitmap
= fImageView
->Bitmap();
1429 float imageWidth
= bitmap
->Bounds().Width() + 1.0;
1430 float imageHeight
= bitmap
->Bounds().Height() + 1.0;
1433 switch (fPrintOptions
.Option()) {
1434 case PrintOptions::kFitToPage
: {
1435 float w1
= printableRect
.Width() + 1;
1436 float w2
= imageWidth
* (printableRect
.Height() + 1)
1443 case PrintOptions::kZoomFactor
:
1444 width
= imageWidth
* fPrintOptions
.ZoomFactor();
1446 case PrintOptions::kDPI
:
1447 width
= imageWidth
* 72.0 / fPrintOptions
.DPI();
1449 case PrintOptions::kWidth
:
1450 case PrintOptions::kHeight
:
1451 width
= fPrintOptions
.Width();
1455 // keep compiler silent; should not reach here
1459 // TODO: eventually print large images on several pages
1460 printJob
.BeginJob();
1461 fImageView
->SetScale(width
/ imageWidth
);
1462 // coordinates are relative to printable rectangle
1463 BRect
bounds(bitmap
->Bounds());
1464 printJob
.DrawView(fImageView
, bounds
, BPoint(0, 0));
1465 fImageView
->SetScale(1.0);
1466 printJob
.SpoolPage();
1467 printJob
.CommitJob();
1473 ShowImageWindow::_SetSlideShowDelay(bigtime_t delay
)
1475 if (fSlideShowDelay
== delay
)
1478 fSlideShowDelay
= delay
;
1480 ShowImageSettings
* settings
= my_app
->Settings();
1481 if (settings
->Lock()) {
1482 settings
->SetTime("SlideShowDelay", fSlideShowDelay
);
1486 if (fSlideShowRunner
!= NULL
)
1492 ShowImageWindow::_StartSlideShow()
1496 BMessage
nextSlide(kMsgNextSlide
);
1497 fSlideShowRunner
= new BMessageRunner(this, &nextSlide
, fSlideShowDelay
);
1502 ShowImageWindow::_StopSlideShow()
1504 if (fSlideShowRunner
!= NULL
) {
1505 delete fSlideShowRunner
;
1506 fSlideShowRunner
= NULL
;
1512 ShowImageWindow::_UpdateRatingMenu()
1514 BFile
file(&fNavigator
.CurrentRef(), B_READ_ONLY
);
1515 if (file
.InitCheck() != B_OK
)
1518 ssize_t size
= sizeof(rating
);
1519 if (file
.ReadAttr("Media:Rating", B_INT32_TYPE
, 0, &rating
, size
) != size
)
1521 // TODO: Finding the correct item could be more robust, like by looking
1522 // at the message of each item.
1523 for (int32 i
= 1; i
<= 10; i
++) {
1524 BMenuItem
* item
= fRatingMenu
->ItemAt(i
- 1);
1527 item
->SetMarked(i
== rating
);
1533 ShowImageWindow::_SaveWidthAndHeight()
1535 if (fNavigator
.CurrentPage() != 1)
1538 if (fImageView
->Bitmap() == NULL
)
1541 BRect bounds
= fImageView
->Bitmap()->Bounds();
1542 int32 width
= bounds
.IntegerWidth() + 1;
1543 int32 height
= bounds
.IntegerHeight() + 1;
1545 BNode
node(&fNavigator
.CurrentRef());
1546 if (node
.InitCheck() != B_OK
)
1549 const char* kWidthAttrName
= "Media:Width";
1550 const char* kHeightAttrName
= "Media:Height";
1553 ssize_t attrSize
= node
.ReadAttr(kWidthAttrName
, B_INT32_TYPE
, 0,
1554 &widthAttr
, sizeof(widthAttr
));
1555 if (attrSize
<= 0 || widthAttr
!= width
)
1556 node
.WriteAttr(kWidthAttrName
, B_INT32_TYPE
, 0, &width
, sizeof(width
));
1559 attrSize
= node
.ReadAttr(kHeightAttrName
, B_INT32_TYPE
, 0,
1560 &heightAttr
, sizeof(heightAttr
));
1561 if (attrSize
<= 0 || heightAttr
!= height
)
1562 node
.WriteAttr(kHeightAttrName
, B_INT32_TYPE
, 0, &height
, sizeof(height
));
1567 ShowImageWindow::_SetToolBarVisible(bool visible
, bool animate
)
1569 if (visible
== fToolBarVisible
)
1572 fToolBarVisible
= visible
;
1573 float diff
= fToolBar
->Bounds().Height() + 2;
1580 // Slide the controls into view. We do this with messages in order
1581 // not to block the window thread.
1582 const float kAnimationOffsets
[] = { 0.05, 0.2, 0.5, 0.2, 0.05 };
1583 const int32 steps
= sizeof(kAnimationOffsets
) / sizeof(float);
1584 for (int32 i
= 0; i
< steps
; i
++) {
1585 BMessage
message(kMsgSlideToolBar
);
1586 message
.AddFloat("offset", floorf(diff
* kAnimationOffsets
[i
]));
1587 PostMessage(&message
, this);
1589 BMessage
finalMessage(kMsgFinishSlidingToolBar
);
1590 finalMessage
.AddFloat("offset", visible
? 0 : diff
);
1591 finalMessage
.AddBool("show", visible
);
1592 PostMessage(&finalMessage
, this);
1594 fScrollView
->ResizeBy(0, -diff
);
1595 fScrollView
->MoveBy(0, diff
);
1596 fToolBar
->MoveBy(0, diff
);
1604 ShowImageWindow::_SetToolBarBorder(bool visible
)
1606 float inset
= visible
1607 ? ceilf(be_control_look
->DefaultItemSpacing() / 2) : 0;
1609 fToolBar
->GroupLayout()->SetInsets(inset
, 0, inset
, 0);
1614 ShowImageWindow::QuitRequested()
1617 // Don't allow this window to be closed if a save panel is open
1621 if (!_ClosePrompt())
1624 ShowImageSettings
* settings
= my_app
->Settings();
1625 if (settings
->Lock()) {
1627 settings
->SetRect("WindowFrame", fWindowFrame
);
1629 settings
->SetRect("WindowFrame", Frame());
1633 be_app
->PostMessage(MSG_WINDOW_HAS_QUIT
);