* PictureView is now keyboard navigable
* Alpha transparency of image is now respected * Add a popup menu to load an image or remove the current one. * The current picture can also be removed by pressing Delete key * ... or by dragging the image to desktop's Trash git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40668 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+282
-28
@@ -10,24 +10,68 @@
|
|||||||
#include "PictureView.h"
|
#include "PictureView.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <new>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <Bitmap.h>
|
#include <Bitmap.h>
|
||||||
|
#include <BitmapStream.h>
|
||||||
|
#include <Catalog.h>
|
||||||
#include <IconUtils.h>
|
#include <IconUtils.h>
|
||||||
#include <LayoutUtils.h>
|
#include <LayoutUtils.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
#include <MimeType.h>
|
#include <MimeType.h>
|
||||||
|
#include <TranslatorRoster.h>
|
||||||
#include <TranslationUtils.h>
|
#include <TranslationUtils.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
#include "PeopleApp.h" // for B_PERSON_MIMETYPE
|
#include "PeopleApp.h" // for B_PERSON_MIMETYPE
|
||||||
|
|
||||||
|
|
||||||
|
#undef B_TRANSLATE_CONTEXT
|
||||||
|
#define B_TRANSLATE_CONTEXT "People"
|
||||||
|
|
||||||
|
|
||||||
|
const uint32 kMsgPopUpMenuClosed = 'pmcl';
|
||||||
|
|
||||||
|
class PopUpMenu : public BPopUpMenu {
|
||||||
|
public:
|
||||||
|
PopUpMenu(const char* name, BMessenger target);
|
||||||
|
virtual ~PopUpMenu();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BMessenger fTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
PopUpMenu::PopUpMenu(const char* name, BMessenger target)
|
||||||
|
:
|
||||||
|
BPopUpMenu(name, false, false), fTarget(target)
|
||||||
|
{
|
||||||
|
SetAsyncAutoDestruct(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PopUpMenu::~PopUpMenu()
|
||||||
|
{
|
||||||
|
fTarget.SendMessage(kMsgPopUpMenuClosed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
using std::nothrow;
|
||||||
|
|
||||||
|
|
||||||
const float kPictureMargin = 6.0;
|
const float kPictureMargin = 6.0;
|
||||||
|
|
||||||
PictureView::PictureView(float width, float height, const entry_ref* ref)
|
PictureView::PictureView(float width, float height, const entry_ref* ref)
|
||||||
:
|
:
|
||||||
BView("pictureview", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
|
BView("pictureview", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE),
|
||||||
fPicture(NULL),
|
fPicture(NULL),
|
||||||
fOriginalPicture(NULL),
|
fOriginalPicture(NULL),
|
||||||
fDefaultPicture(NULL)
|
fDefaultPicture(NULL),
|
||||||
|
fShowingPopUpMenu(false)
|
||||||
{
|
{
|
||||||
SetViewColor(255, 255, 255);
|
SetViewColor(255, 255, 255);
|
||||||
|
|
||||||
@@ -57,8 +101,7 @@ PictureView::PictureView(float width, float height, const entry_ref* ref)
|
|||||||
PictureView::~PictureView()
|
PictureView::~PictureView()
|
||||||
{
|
{
|
||||||
delete fDefaultPicture;
|
delete fDefaultPicture;
|
||||||
if (fPicture != fDefaultPicture)
|
delete fPicture;
|
||||||
delete fPicture;
|
|
||||||
if (fOriginalPicture != fPicture)
|
if (fOriginalPicture != fPicture)
|
||||||
delete fOriginalPicture;
|
delete fOriginalPicture;
|
||||||
}
|
}
|
||||||
@@ -67,7 +110,7 @@ PictureView::~PictureView()
|
|||||||
bool
|
bool
|
||||||
PictureView::HasChanged()
|
PictureView::HasChanged()
|
||||||
{
|
{
|
||||||
return fOriginalPicture != fPicture;
|
return fPicture != fOriginalPicture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -77,12 +120,8 @@ PictureView::Revert()
|
|||||||
if (!HasChanged())
|
if (!HasChanged())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fPicture != fDefaultPicture)
|
_DeletePicture();
|
||||||
delete fPicture;
|
fPicture = fOriginalPicture;
|
||||||
|
|
||||||
fPicture = fOriginalPicture != NULL ?
|
|
||||||
fOriginalPicture : fDefaultPicture;
|
|
||||||
|
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +140,7 @@ PictureView::Update(const entry_ref* ref)
|
|||||||
BBitmap*
|
BBitmap*
|
||||||
PictureView::Bitmap()
|
PictureView::Bitmap()
|
||||||
{
|
{
|
||||||
return fPicture != fDefaultPicture ? fPicture : NULL;
|
return fPicture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -119,15 +158,26 @@ PictureView::MessageReceived(BMessage* message)
|
|||||||
if (picture == NULL)
|
if (picture == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (fPicture != fDefaultPicture
|
_DeletePicture();
|
||||||
&& fPicture != fOriginalPicture)
|
|
||||||
delete fPicture;
|
|
||||||
|
|
||||||
fPicture = picture;
|
fPicture = picture;
|
||||||
Invalidate();
|
MakeFocus(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case B_COPY_TARGET:
|
||||||
|
_HandleDrop(message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_DELETE:
|
||||||
|
case B_TRASH_TARGET:
|
||||||
|
_DeletePicture();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kMsgPopUpMenuClosed:
|
||||||
|
fShowingPopUpMenu = false;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BView::MessageReceived(message);
|
BView::MessageReceived(message);
|
||||||
break;
|
break;
|
||||||
@@ -142,12 +192,6 @@ PictureView::Draw(BRect updateRect)
|
|||||||
|
|
||||||
BBitmap* picture = fPicture ? fPicture : fDefaultPicture;
|
BBitmap* picture = fPicture ? fPicture : fDefaultPicture;
|
||||||
if (picture != NULL) {
|
if (picture != NULL) {
|
||||||
if (picture == fDefaultPicture) {
|
|
||||||
SetDrawingMode(B_OP_ALPHA);
|
|
||||||
SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
|
|
||||||
SetHighColor(0, 0, 0, 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale to fit and center picture in frame
|
// scale to fit and center picture in frame
|
||||||
BRect frame = rect.InsetByCopy(kPictureMargin, kPictureMargin);
|
BRect frame = rect.InsetByCopy(kPictureMargin, kPictureMargin);
|
||||||
BRect srcRect = picture->Bounds();
|
BRect srcRect = picture->Bounds();
|
||||||
@@ -156,17 +200,227 @@ PictureView::Draw(BRect updateRect)
|
|||||||
size.height = srcRect.Height() * size.width / srcRect.Width();
|
size.height = srcRect.Height() * size.width / srcRect.Width();
|
||||||
else
|
else
|
||||||
size.width = srcRect.Width() * size.height / srcRect.Height();
|
size.width = srcRect.Width() * size.height / srcRect.Height();
|
||||||
BRect dstRect = BLayoutUtils::AlignInFrame(frame, size,
|
|
||||||
|
fPictureRect = BLayoutUtils::AlignInFrame(frame, size,
|
||||||
BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER));
|
BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER));
|
||||||
|
|
||||||
DrawBitmapAsync(picture, srcRect, dstRect, B_FILTER_BITMAP_BILINEAR);
|
SetDrawingMode(B_OP_ALPHA);
|
||||||
|
if (picture == fDefaultPicture) {
|
||||||
|
SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
|
||||||
|
SetHighColor(0, 0, 0, 24);
|
||||||
|
}
|
||||||
|
|
||||||
if (picture == fDefaultPicture)
|
DrawBitmapAsync(picture, srcRect, fPictureRect, B_FILTER_BITMAP_BILINEAR);
|
||||||
SetDrawingMode(B_OP_OVER);
|
|
||||||
|
SetDrawingMode(B_OP_OVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the outer frame
|
// Draw the outer frame
|
||||||
rgb_color black = {0, 0, 0, 255};
|
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
SetHighColor(tint_color(black, B_LIGHTEN_2_TINT));
|
if (IsFocus() && Window() && Window()->IsActive())
|
||||||
|
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||||
|
else
|
||||||
|
SetHighColor(tint_color(base, B_DARKEN_3_TINT));
|
||||||
StrokeRect(rect);
|
StrokeRect(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PictureView::WindowActivated(bool active)
|
||||||
|
{
|
||||||
|
BView::WindowActivated(active);
|
||||||
|
|
||||||
|
if (IsFocus())
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PictureView::MakeFocus(bool focused)
|
||||||
|
{
|
||||||
|
BView::MakeFocus(focused);
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PictureView::MouseDown(BPoint position)
|
||||||
|
{
|
||||||
|
MakeFocus(true);
|
||||||
|
|
||||||
|
uint32 buttons = 0;
|
||||||
|
if (Window() != NULL && Window()->CurrentMessage() != NULL)
|
||||||
|
buttons = Window()->CurrentMessage()->FindInt32("buttons");
|
||||||
|
|
||||||
|
if (fPicture != NULL && fPictureRect.Contains(position)
|
||||||
|
&& (buttons
|
||||||
|
& (B_PRIMARY_MOUSE_BUTTON | B_SECONDARY_MOUSE_BUTTON)) != 0) {
|
||||||
|
|
||||||
|
_BeginDrag(position);
|
||||||
|
|
||||||
|
} else if (buttons == B_SECONDARY_MOUSE_BUTTON)
|
||||||
|
_ShowPopUpMenu(ConvertToScreen(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PictureView::KeyDown(const char* bytes, int32 numBytes)
|
||||||
|
{
|
||||||
|
if (numBytes != 1) {
|
||||||
|
BView::KeyDown(bytes, numBytes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*bytes) {
|
||||||
|
case B_DELETE:
|
||||||
|
_DeletePicture();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BView::KeyDown(bytes, numBytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PictureView::_ShowPopUpMenu(BPoint screen)
|
||||||
|
{
|
||||||
|
if (fShowingPopUpMenu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PopUpMenu* menu = new PopUpMenu("PopUpMenu", this);
|
||||||
|
|
||||||
|
BMenuItem* item = new BMenuItem(B_TRANSLATE("Load image" B_UTF8_ELLIPSIS),
|
||||||
|
new BMessage(kMsgLoadImage));
|
||||||
|
menu->AddItem(item);
|
||||||
|
|
||||||
|
item = new BMenuItem(B_TRANSLATE("Remove image"), new BMessage(B_DELETE));
|
||||||
|
item->SetEnabled(fPicture != NULL);
|
||||||
|
menu->AddItem(item);
|
||||||
|
|
||||||
|
menu->SetTargetForItems(this);
|
||||||
|
menu->Go(screen, true, true, true);
|
||||||
|
fShowingPopUpMenu = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BBitmap*
|
||||||
|
PictureView::_CopyPicture(uint8 alpha)
|
||||||
|
{
|
||||||
|
bool hasAlpha = alpha != 255;
|
||||||
|
|
||||||
|
if (!fPicture)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
BRect rect = fPictureRect.OffsetToCopy(B_ORIGIN);
|
||||||
|
BView view(rect, NULL, B_FOLLOW_NONE, B_WILL_DRAW);
|
||||||
|
BBitmap* bitmap = new(nothrow) BBitmap(rect, hasAlpha ? B_RGBA32
|
||||||
|
: fPicture->ColorSpace(), true);
|
||||||
|
if (bitmap == NULL || !bitmap->IsValid()) {
|
||||||
|
delete bitmap;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitmap->Lock()) {
|
||||||
|
bitmap->AddChild(&view);
|
||||||
|
if (hasAlpha) {
|
||||||
|
view.SetHighColor(0, 0, 0, 0);
|
||||||
|
view.FillRect(rect);
|
||||||
|
view.SetDrawingMode(B_OP_ALPHA);
|
||||||
|
view.SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
|
||||||
|
view.SetHighColor(0, 0, 0, alpha);
|
||||||
|
}
|
||||||
|
view.DrawBitmap(fPicture, fPicture->Bounds().OffsetToCopy(B_ORIGIN),
|
||||||
|
rect, B_FILTER_BITMAP_BILINEAR);
|
||||||
|
view.Sync();
|
||||||
|
bitmap->RemoveChild(&view);
|
||||||
|
bitmap->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PictureView::_BeginDrag(BPoint sourcePoint)
|
||||||
|
{
|
||||||
|
BBitmap* bitmap = _CopyPicture(128);
|
||||||
|
if (bitmap == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// fill the drag message
|
||||||
|
BMessage drag(B_SIMPLE_DATA);
|
||||||
|
drag.AddInt32("be:actions", B_COPY_TARGET);
|
||||||
|
drag.AddInt32("be:actions", B_TRASH_TARGET);
|
||||||
|
|
||||||
|
// name the clip after person name, if any
|
||||||
|
BString name = B_TRANSLATE("%name% picture");
|
||||||
|
name.ReplaceFirst("%name%", Window() ? Window()->Title() :
|
||||||
|
B_TRANSLATE("Unnamed person"));
|
||||||
|
drag.AddString("be:clip_name", name.String());
|
||||||
|
|
||||||
|
BTranslatorRoster* roster = BTranslatorRoster::Default();
|
||||||
|
if (roster == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int32 infoCount;
|
||||||
|
translator_info* info;
|
||||||
|
BBitmapStream stream(bitmap);
|
||||||
|
if (roster->GetTranslators(&stream, NULL, &info, &infoCount) == B_OK) {
|
||||||
|
for (int32 i = 0; i < infoCount; i++) {
|
||||||
|
const translation_format* formats;
|
||||||
|
int32 count;
|
||||||
|
roster->GetOutputFormats(info[i].translator, &formats, &count);
|
||||||
|
for (int32 j = 0; j < count; j++) {
|
||||||
|
if (strcmp(formats[j].MIME, "image/x-be-bitmap") != 0) {
|
||||||
|
// needed to send data in message
|
||||||
|
drag.AddString("be:types", formats[j].MIME);
|
||||||
|
// needed to pass data via file
|
||||||
|
drag.AddString("be:filetypes", formats[j].MIME);
|
||||||
|
drag.AddString("be:type_descriptions", formats[j].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.DetachBitmap(&bitmap);
|
||||||
|
|
||||||
|
// we also support "Passing Data via File" protocol
|
||||||
|
drag.AddString("be:types", B_FILE_MIME_TYPE);
|
||||||
|
|
||||||
|
sourcePoint -= fPictureRect.LeftTop();
|
||||||
|
|
||||||
|
SetMouseEventMask(B_POINTER_EVENTS);
|
||||||
|
|
||||||
|
DragMessage(&drag, bitmap, B_OP_ALPHA, sourcePoint);
|
||||||
|
bitmap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PictureView::_HandleDrop(BMessage* message)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
printf("PictureView::_HandleDrop(): \n");
|
||||||
|
message->PrintToStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PictureView::_DeletePicture()
|
||||||
|
{
|
||||||
|
if (fPicture == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fPicture != fOriginalPicture)
|
||||||
|
delete fPicture;
|
||||||
|
|
||||||
|
fPicture = NULL;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
class BBitmap;
|
class BBitmap;
|
||||||
|
|
||||||
|
|
||||||
|
const uint32 kMsgLoadImage = 'mLIM';
|
||||||
|
|
||||||
|
|
||||||
class PictureView : public BView {
|
class PictureView : public BView {
|
||||||
public:
|
public:
|
||||||
PictureView(float width, float height,
|
PictureView(float width, float height,
|
||||||
@@ -30,11 +33,24 @@ public:
|
|||||||
|
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
virtual void Draw(BRect updateRect);
|
virtual void Draw(BRect updateRect);
|
||||||
|
virtual void MouseDown(BPoint point);
|
||||||
|
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||||
|
virtual void WindowActivated(bool active);
|
||||||
|
virtual void MakeFocus(bool focused);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void _BeginDrag(BPoint sourcePoint);
|
||||||
|
void _HandleDrop(BMessage* message);
|
||||||
|
void _ShowPopUpMenu(BPoint screen);
|
||||||
|
BBitmap* _CopyPicture(uint8 alpha);
|
||||||
|
|
||||||
|
void _DeletePicture();
|
||||||
|
|
||||||
BBitmap* fPicture;
|
BBitmap* fPicture;
|
||||||
BBitmap* fOriginalPicture;
|
BBitmap* fOriginalPicture;
|
||||||
BBitmap* fDefaultPicture;
|
BBitmap* fDefaultPicture;
|
||||||
|
bool fShowingPopUpMenu;
|
||||||
|
BRect fPictureRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user