1 /*****************************************************************************/
3 // Written by Michael Wilber, OBOS Translation Kit Team
7 // BView class for showing images. Images can be dropped on this view
8 // from the tracker and images viewed in this view can be dragged
9 // to the tracker to be saved.
12 // Copyright (c) 2003 OpenBeOS Project
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 /*****************************************************************************/
34 #include "ImageView.h"
35 #include "Constants.h"
36 #include "StatusCheck.h"
37 #include "InspectorApp.h"
38 #include "TranslatorItem.h"
39 #include <Application.h>
45 #include <TranslationUtils.h>
46 #include <TranslatorRoster.h>
47 #include <BitmapStream.h>
50 #include <Directory.h>
54 #include <ScrollBar.h>
60 #define BORDER_WIDTH 16
61 #define BORDER_HEIGHT 16
64 #undef B_TRANSLATION_CONTEXT
65 #define B_TRANSLATION_CONTEXT "ImageView"
68 ImageView::ImageView(BRect rect
, const char *name
)
69 : BView(rect
, name
, B_FOLLOW_ALL
, B_WILL_DRAW
| B_FRAME_EVENTS
)
75 SetViewColor(192, 192, 192);
76 SetHighColor(0, 0, 0);
81 ImageView::~ImageView()
89 ImageView::AttachedToWindow()
96 ImageView::Draw(BRect rect
)
99 // Draw black rectangle around image
101 BRect(BORDER_WIDTH
- PEN_SIZE
,
102 BORDER_HEIGHT
- PEN_SIZE
,
103 fpbitmap
->Bounds().Width() + BORDER_WIDTH
+ PEN_SIZE
,
104 fpbitmap
->Bounds().Height() + BORDER_HEIGHT
+ PEN_SIZE
));
106 DrawBitmap(fpbitmap
, BPoint(BORDER_WIDTH
, BORDER_HEIGHT
));
119 ImageView::FrameResized(float width
, float height
)
129 ImageView::MouseDown(BPoint point
)
134 // Only accept left button clicks
135 BMessage
*pmsg
= Window()->CurrentMessage();
136 int32 button
= pmsg
->FindInt32("buttons");
137 if (button
!= B_PRIMARY_MOUSE_BUTTON
)
140 // Tell BeOS to setup a Drag/Drop operation
142 // (When the image is dropped, BeOS sends
143 // the following message to ImageWindow,
144 // which causes it to call ImageView::SetImage())
145 BMessage
msg(B_SIMPLE_DATA
);
146 msg
.AddInt32("be:actions", B_COPY_TARGET
);
147 msg
.AddString("be:filetypes", "application/octet-stream");
148 msg
.AddString("be:types", "application/octet-stream");
149 msg
.AddString("be:clip_name", "Bitmap");
151 DragMessage(&msg
, Bounds());
156 ImageView::MouseMoved(BPoint point
, uint32 state
, const BMessage
*pmsg
)
162 ImageView::MouseUp(BPoint point
)
168 ImageView::MessageReceived(BMessage
*pmsg
)
170 switch (pmsg
->what
) {
172 SaveImageAtDropLocation(pmsg
);
176 BView::MessageReceived(pmsg
);
183 ImageView::SaveImageAtDropLocation(BMessage
*pmsg
)
185 // Find the location and name of the drop and
186 // write the image file there
187 BBitmapStream
stream(fpbitmap
);
190 // throw an exception if this is assigned
191 // anything other than B_OK
195 chk
= pmsg
->FindRef("directory", &dirref
);
196 const char *filename
;
197 chk
= pmsg
->FindString("name", &filename
);
199 BDirectory
dir(&dirref
);
200 BFile
file(&dir
, filename
, B_WRITE_ONLY
| B_CREATE_FILE
);
201 chk
= file
.InitCheck();
203 BTranslatorRoster
*proster
= BTranslatorRoster::Default();
204 chk
= proster
->Translate(&stream
, NULL
, NULL
, &file
, B_TGA_FORMAT
);
206 } catch (StatusNotOKException
) {
207 BAlert
*palert
= new BAlert(NULL
,
208 B_TRANSLATE("Sorry, unable to write the image file."),
213 stream
.DetachBitmap(&fpbitmap
);
218 ImageView::AdjustScrollBars()
220 BRect rctview
= Bounds(), rctbitmap(0, 0, 0, 0);
222 rctbitmap
= fpbitmap
->Bounds();
225 BScrollBar
*psb
= ScrollBar(B_HORIZONTAL
);
227 range
= rctbitmap
.Width() + (BORDER_WIDTH
* 2) - rctview
.Width();
228 if (range
< 0) range
= 0;
229 prop
= rctview
.Width() / (rctbitmap
.Width() + (BORDER_WIDTH
* 2));
230 if (prop
> 1.0f
) prop
= 1.0f
;
231 psb
->SetRange(0, range
);
232 psb
->SetProportion(prop
);
233 psb
->SetSteps(10, 100);
236 psb
= ScrollBar(B_VERTICAL
);
238 range
= rctbitmap
.Height() + (BORDER_HEIGHT
* 2) - rctview
.Height();
239 if (range
< 0) range
= 0;
240 prop
= rctview
.Height() / (rctbitmap
.Height() + (BORDER_HEIGHT
* 2));
241 if (prop
> 1.0f
) prop
= 1.0f
;
242 psb
->SetRange(0, range
);
243 psb
->SetProportion(prop
);
244 psb
->SetSteps(10, 100);
249 struct ColorSpaceName
{
253 #define COLORSPACENAME(id) {id, #id}
256 // convert colorspace numerical value to
259 get_color_space_name(color_space colors
)
261 // print out colorspace if it matches an item in the list
262 const ColorSpaceName kcolorspaces
[] = {
263 COLORSPACENAME(B_NO_COLOR_SPACE
),
264 COLORSPACENAME(B_RGB32
),
265 COLORSPACENAME(B_RGBA32
),
266 COLORSPACENAME(B_RGB24
),
267 COLORSPACENAME(B_RGB16
),
268 COLORSPACENAME(B_RGB15
),
269 COLORSPACENAME(B_RGBA15
),
270 COLORSPACENAME(B_CMAP8
),
271 COLORSPACENAME(B_GRAY8
),
272 COLORSPACENAME(B_GRAY1
),
273 COLORSPACENAME(B_RGB32_BIG
),
274 COLORSPACENAME(B_RGBA32_BIG
),
275 COLORSPACENAME(B_RGB24_BIG
),
276 COLORSPACENAME(B_RGB16_BIG
),
277 COLORSPACENAME(B_RGB15_BIG
),
278 COLORSPACENAME(B_RGBA15_BIG
),
279 COLORSPACENAME(B_YCbCr422
),
280 COLORSPACENAME(B_YCbCr411
),
281 COLORSPACENAME(B_YCbCr444
),
282 COLORSPACENAME(B_YCbCr420
),
283 COLORSPACENAME(B_YUV422
),
284 COLORSPACENAME(B_YUV411
),
285 COLORSPACENAME(B_YUV444
),
286 COLORSPACENAME(B_YUV420
),
287 COLORSPACENAME(B_YUV9
),
288 COLORSPACENAME(B_YUV12
),
289 COLORSPACENAME(B_UVL24
),
290 COLORSPACENAME(B_UVL32
),
291 COLORSPACENAME(B_UVLA32
),
292 COLORSPACENAME(B_LAB24
),
293 COLORSPACENAME(B_LAB32
),
294 COLORSPACENAME(B_LABA32
),
295 COLORSPACENAME(B_HSI24
),
296 COLORSPACENAME(B_HSI32
),
297 COLORSPACENAME(B_HSIA32
),
298 COLORSPACENAME(B_HSV24
),
299 COLORSPACENAME(B_HSV32
),
300 COLORSPACENAME(B_HSVA32
),
301 COLORSPACENAME(B_HLS24
),
302 COLORSPACENAME(B_HLS32
),
303 COLORSPACENAME(B_HLSA32
),
304 COLORSPACENAME(B_CMY24
),
305 COLORSPACENAME(B_CMY32
),
306 COLORSPACENAME(B_CMYA32
),
307 COLORSPACENAME(B_CMYK32
)
309 const int32 kncolorspaces
= sizeof(kcolorspaces
) /
310 sizeof(ColorSpaceName
);
311 for (int32 i
= 0; i
< kncolorspaces
; i
++) {
312 if (colors
== kcolorspaces
[i
].id
)
313 return kcolorspaces
[i
].name
;
316 return B_TRANSLATE("Unknown");
320 // return a string of the passed number formated
321 // as a hexadecimal number in lowercase with a leading "0x"
323 hex_format(uint32 num
)
325 static char str
[11] = { 0 };
326 sprintf(str
, "0x%.8lx", num
);
332 // convert passed number to a string of 4 characters
333 // and return that string
335 char_format(uint32 num
)
337 static char str
[5] = { 0 };
338 uint32 bnum
= B_HOST_TO_BENDIAN_INT32(num
);
339 memcpy(str
, &bnum
, 4);
346 dump_translation_formats(BString
&bstr
, const translation_format
*pfmts
,
349 BString
*str1
= NULL
;
350 for (int i
= 0; i
< nfmts
; i
++) {
351 BString string
= B_TRANSLATE("\nType: '%1' (%2)\n"
357 string
.ReplaceFirst("%1", char_format(pfmts
[i
].type
));
358 string
.ReplaceFirst("%2", hex_format(pfmts
[i
].type
));
359 string
.ReplaceFirst("%3", char_format(pfmts
[i
].group
));
360 string
.ReplaceFirst("%4", hex_format(pfmts
[i
].group
));
361 char str2
[127] = { 0 };
362 sprintf(str2
, "%f", pfmts
[i
].quality
);
363 string
.ReplaceFirst("%5", str2
);
365 sprintf(str2
, "%f", pfmts
[i
].capability
);
366 string
.ReplaceFirst("%6", str2
);
367 string
.ReplaceFirst("%7", pfmts
[i
].MIME
);
368 string
.ReplaceFirst("%8", pfmts
[i
].name
);
370 str1
= new BString(string
);
372 str1
->Append(string
);
374 bstr
= str1
->String();
378 // Send information about the currently open image to the
379 // BApplication object so it can send it to the InfoWindow
381 ImageView::UpdateInfoWindow(const BPath
&path
, BMessage
&ioExtension
,
382 const translator_info
&tinfo
, BTranslatorRoster
*proster
)
384 BMessage
msg(M_INFO_WINDOW_TEXT
);
387 bstr
= B_TRANSLATE("Image: %1\n"
388 "Color Space: %2 (%3)\n"
389 "Dimensions: %4 x %5\n"
390 "Bytes per Row: %6\n"
395 "Type: '%10' (%11)\n"
396 "Translator ID: %12\n"
397 "Group: '%13' (%14)\n"
400 "\nExtension Info:\n");
401 bstr
.ReplaceFirst("%1", path
.Path());
402 color_space cs
= fpbitmap
->ColorSpace();
403 bstr
.ReplaceFirst("%2", get_color_space_name(cs
));
404 bstr
.ReplaceFirst("%3", hex_format(static_cast<uint32
>(cs
)));
405 char str2
[127] = { 0 };
406 sprintf(str2
, "%ld", fpbitmap
->Bounds().IntegerWidth() + 1);
407 bstr
.ReplaceFirst("%4", str2
);
409 sprintf(str2
, "%ld", fpbitmap
->Bounds().IntegerHeight() + 1);
410 bstr
.ReplaceFirst("%5", str2
);
412 sprintf(str2
, "%ld", fpbitmap
->BytesPerRow());
413 bstr
.ReplaceFirst("%6", str2
);
415 sprintf(str2
, "%ld", fpbitmap
->BitsLength());
416 bstr
.ReplaceFirst("%7", str2
);
417 bstr
.ReplaceFirst("%8", tinfo
.name
);
418 bstr
.ReplaceFirst("%9", tinfo
.MIME
);
419 bstr
.ReplaceFirst("%10", char_format(tinfo
.type
));
420 bstr
.ReplaceFirst("%11", hex_format(tinfo
.type
));
422 sprintf(str2
, "%ld", tinfo
.translator
);
423 bstr
.ReplaceFirst("%12", str2
);
424 bstr
.ReplaceFirst("%13", char_format(tinfo
.group
));
425 bstr
.ReplaceFirst("%14", hex_format(tinfo
.group
));
427 sprintf(str2
, "%f", tinfo
.quality
);
428 bstr
.ReplaceFirst("%15", str2
);
430 sprintf(str2
, "%f", tinfo
.capability
);
431 bstr
.ReplaceFirst("%16", str2
);
433 int32 document_count
= 0, document_index
= 0;
435 const char *tranname
= NULL
, *traninfo
= NULL
;
436 int32 tranversion
= 0;
438 if (ioExtension
.FindInt32("/documentCount", &document_count
) == B_OK
) {
439 BString str
= B_TRANSLATE("Number of Documents: %1\n"
440 "\nTranslator Used:\n"
444 char str2
[127] = { 0 };
445 sprintf(str2
, "%ld", document_count
);
446 str
.ReplaceFirst("%1", str2
);
447 str
.ReplaceFirst("%2", tranname
);
448 str
.ReplaceFirst("%3", traninfo
);
450 sprintf(str2
, "%d", (int)tranversion
);
451 str
.ReplaceFirst("%4", str2
);
452 bstr
.Append(str
.String());
455 if (ioExtension
.FindInt32("/documentIndex", &document_index
) == B_OK
) {
456 BString str
= B_TRANSLATE("Selected Document: %1\n"
457 "\nTranslator Used:\n"
461 char str2
[127] = { 0 };
462 sprintf(str2
, "%ld", document_index
);
463 str
.ReplaceFirst("%1", str2
);
464 str
.ReplaceFirst("%2", tranname
);
465 str
.ReplaceFirst("%3", traninfo
);
467 sprintf(str2
, "%d", (int)tranversion
);
468 str
.ReplaceFirst("%4", str2
);
469 bstr
.Append(str
.String());
472 if (proster
->GetTranslatorInfo(tinfo
.translator
, &tranname
,
473 &traninfo
, &tranversion
) == B_OK
) {
474 BString str
= B_TRANSLATE("\nTranslator Used:\n"
478 str
.ReplaceFirst("%1", tranname
);
479 str
.ReplaceFirst("%2", traninfo
);
480 char str2
[127] = { 0 };
481 sprintf(str2
, "%d", (int)tranversion
);
482 str
.ReplaceFirst("%3", str2
);
483 bstr
.Append(str
.String());
486 // Translator Input / Output Formats
487 int32 nins
= 0, nouts
= 0;
488 const translation_format
*pins
= NULL
, *pouts
= NULL
;
489 if (proster
->GetInputFormats(tinfo
.translator
, &pins
, &nins
) == B_OK
) {
490 bstr
<< B_TRANSLATE("\nInput Formats:");
491 dump_translation_formats(bstr
, pins
, nins
);
494 if (proster
->GetOutputFormats(tinfo
.translator
, &pouts
, &nouts
) == B_OK
) {
495 bstr
<< B_TRANSLATE("\nOutput Formats:");
496 dump_translation_formats(bstr
, pouts
, nouts
);
499 msg
.AddString("text", bstr
);
500 be_app
->PostMessage(&msg
);
505 ImageView::SelectTranslatorRoster(BTranslatorRoster
&roster
)
507 bool bNoneSelected
= true;
510 papp
= static_cast<InspectorApp
*>(be_app
);
512 BList
*plist
= papp
->GetTranslatorsList();
514 for (int32 i
= 0; i
< plist
->CountItems(); i
++) {
515 BTranslatorItem
*pitem
=
516 static_cast<BTranslatorItem
*>(plist
->ItemAt(i
));
517 if (pitem
->IsSelected()) {
518 bNoneSelected
= false;
519 roster
.AddTranslators(pitem
->Path());
526 return BTranslatorRoster::Default();
533 ImageView::SetImage(BMessage
*pmsg
)
535 // Replace current image with the image
536 // specified in the given BMessage
541 else if (pmsg
->FindRef("refs", &ref
) != B_OK
)
542 // If refs not found, just ignore the message
548 BFile
file(&ref
, B_READ_ONLY
);
549 chk
= file
.InitCheck();
551 BTranslatorRoster roster
, *proster
;
552 proster
= SelectTranslatorRoster(roster
);
556 // determine what type the image is
557 translator_info tinfo
;
558 BMessage ioExtension
;
559 if (ref
!= fcurrentRef
)
560 // if new image, reset to first document
562 chk
= ioExtension
.AddInt32("/documentIndex", fdocumentIndex
);
563 chk
= proster
->Identify(&file
, &ioExtension
, &tinfo
, 0, NULL
,
564 B_TRANSLATOR_BITMAP
);
566 // perform the actual translation
567 BBitmapStream outstream
;
568 chk
= proster
->Translate(&file
, &tinfo
, &ioExtension
, &outstream
,
569 B_TRANSLATOR_BITMAP
);
570 BBitmap
*pbitmap
= NULL
;
571 chk
= outstream
.DetachBitmap(&pbitmap
);
576 // need to keep the ref around if user wants to switch pages
577 int32 documentCount
= 0;
578 if (ioExtension
.FindInt32("/documentCount", &documentCount
) == B_OK
&&
580 fdocumentCount
= documentCount
;
584 // Set the name of the Window to reflect the file name
585 BWindow
*pwin
= Window();
588 if (entry
.InitCheck() == B_OK
) {
589 if (path
.SetTo(&entry
) == B_OK
)
590 pwin
->SetTitle(path
.Leaf());
592 pwin
->SetTitle(IMAGEWINDOW_TITLE
);
594 pwin
->SetTitle(IMAGEWINDOW_TITLE
);
595 UpdateInfoWindow(path
, ioExtension
, tinfo
, proster
);
597 // Resize parent window and set size limits to
598 // reflect the size of the new bitmap
600 BMenuBar
*pbar
= pwin
->KeyMenuBar();
601 width
= fpbitmap
->Bounds().Width() + B_V_SCROLL_BAR_WIDTH
+ (BORDER_WIDTH
* 2);
602 height
= fpbitmap
->Bounds().Height() +
603 pbar
->Bounds().Height() + B_H_SCROLL_BAR_HEIGHT
+ (BORDER_HEIGHT
* 2) + 1;
604 BScreen
*pscreen
= new BScreen(pwin
);
605 BRect rctscreen
= pscreen
->Frame();
606 if (width
> rctscreen
.Width())
607 width
= rctscreen
.Width();
608 if (height
> rctscreen
.Height())
609 height
= rctscreen
.Height();
610 pwin
->SetSizeLimits(B_V_SCROLL_BAR_WIDTH
* 4, width
,
611 pbar
->Bounds().Height() + (B_H_SCROLL_BAR_HEIGHT
* 4) + 1, height
);
612 pwin
->SetZoomLimits(width
, height
);
616 // Perform all of the hard work of resizing the
617 // window while taking into account the size of
618 // the screen, the tab and borders of the window
620 // HACK: Need to fix case where window un-zooms
621 // when the window is already the correct size
622 // for the current image
627 } catch (StatusNotOKException
) {
628 BAlert
*palert
= new BAlert(NULL
,
629 B_TRANSLATE("Sorry, unable to load the image."),
637 ImageView::FirstPage()
639 if (fdocumentIndex
!= 1) {
647 ImageView::LastPage()
649 if (fdocumentIndex
!= fdocumentCount
) {
650 fdocumentIndex
= fdocumentCount
;
657 ImageView::NextPage()
659 if (fdocumentIndex
< fdocumentCount
) {
667 ImageView::PrevPage()
669 if (fdocumentIndex
> 1) {