From f22fe14c4c6596df63b7bd811da69923d8c84972 Mon Sep 17 00:00:00 2001 From: Philippe Houdoin Date: Mon, 28 Feb 2011 19:37:16 +0000 Subject: [PATCH] * Implement "Load Image" popup menu. * Implement B_COPY_TARGET drop event. People is not (yet) ready to to be itself such target (copying a person picture to another one), though. * Remember the source type and MIME and use them to save the picture in same format when possible. * Avoid flickering when only focus is changing. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40740 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/people/PersonView.cpp | 5 +- src/apps/people/PictureView.cpp | 235 ++++++++++++++++++++++++++++---- src/apps/people/PictureView.h | 10 +- 3 files changed, 221 insertions(+), 29 deletions(-) diff --git a/src/apps/people/PersonView.cpp b/src/apps/people/PersonView.cpp index 32e3c82598..6e1da3bc14 100644 --- a/src/apps/people/PersonView.cpp +++ b/src/apps/people/PersonView.cpp @@ -305,8 +305,9 @@ PersonView::Save() if (fPictureView->Bitmap()) { BBitmapStream stream(fPictureView->Bitmap()); BTranslatorRoster* roster = BTranslatorRoster::Default(); - roster->Translate(&stream, NULL, NULL, fFile, B_JPEG_FORMAT, - B_TRANSLATOR_BITMAP); + roster->Translate(&stream, NULL, NULL, fFile, + fPictureView->SuggestedType(), B_TRANSLATOR_BITMAP, + fPictureView->SuggestedMIMEType()); } } } diff --git a/src/apps/people/PictureView.cpp b/src/apps/people/PictureView.cpp index 39d2773bb9..d829ce4c6e 100644 --- a/src/apps/people/PictureView.cpp +++ b/src/apps/people/PictureView.cpp @@ -13,14 +13,22 @@ #include #include +#include #include #include #include +#include +#include +#include #include #include #include +#include #include +#include #include +#include +#include #include #include #include @@ -71,7 +79,10 @@ PictureView::PictureView(float width, float height, const entry_ref* ref) fPicture(NULL), fOriginalPicture(NULL), fDefaultPicture(NULL), - fShowingPopUpMenu(false) + fShowingPopUpMenu(false), + fPictureType(0), + fFocusChanging(false), + fOpenPanel(new BFilePanel(B_OPEN_PANEL)) { SetViewColor(255, 255, 255); @@ -104,6 +115,8 @@ PictureView::~PictureView() delete fPicture; if (fOriginalPicture != fPicture) delete fOriginalPicture; + + delete fOpenPanel; } @@ -131,11 +144,10 @@ PictureView::Update(const entry_ref* ref) if (HasChanged()) return; - BBitmap* bitmap = BTranslationUtils::GetBitmap(ref); - _SetPicture(bitmap); - - delete fOriginalPicture; - fOriginalPicture = fPicture; + if (_LoadPicture(ref) == B_OK) { + delete fOriginalPicture; + fOriginalPicture = fPicture; + } } @@ -146,25 +158,44 @@ PictureView::Bitmap() } +uint32 +PictureView::SuggestedType() +{ + return fPictureType; +} + + +const char* +PictureView::SuggestedMIMEType() +{ + if (fPictureMIMEType == "") + return NULL; + + return fPictureMIMEType.String(); +} + + void PictureView::MessageReceived(BMessage* message) { switch (message->what) { + case B_REFS_RECEIVED: case B_SIMPLE_DATA: { entry_ref ref; if (message->FindRef("refs", &ref) != B_OK) break; - BBitmap* picture = BTranslationUtils::GetBitmap(&ref); - if (picture == NULL) - break; - - _SetPicture(picture); - MakeFocus(true); + if (_LoadPicture(&ref) == B_OK) + MakeFocus(true); break; } + case B_MIME_DATA: + printf("B_MIME_DATA:\n"); + message->PrintToStream(); + break; + case B_COPY_TARGET: _HandleDrop(message); break; @@ -174,6 +205,11 @@ PictureView::MessageReceived(BMessage* message) _SetPicture(NULL); break; + case kMsgLoadImage: + fOpenPanel->SetTarget(BMessenger(this)); + fOpenPanel->Show(); + break; + case kMsgPopUpMenuClosed: fShowingPopUpMenu = false; break; @@ -190,6 +226,19 @@ PictureView::Draw(BRect updateRect) { BRect rect = Bounds(); + // Draw the outer frame + rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); + if (IsFocus() && Window() && Window()->IsActive()) + SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); + else + SetHighColor(tint_color(base, B_DARKEN_3_TINT)); + StrokeRect(rect); + + if (fFocusChanging) { + printf("Draw(): focus changed...\n"); + return; + } + BBitmap* picture = fPicture ? fPicture : fDefaultPicture; if (picture != NULL) { // scale to fit and center picture in frame @@ -210,18 +259,11 @@ PictureView::Draw(BRect updateRect) SetHighColor(0, 0, 0, 24); } - DrawBitmapAsync(picture, srcRect, fPictureRect, B_FILTER_BITMAP_BILINEAR); + DrawBitmapAsync(picture, srcRect, fPictureRect, + B_FILTER_BITMAP_BILINEAR); SetDrawingMode(B_OP_OVER); } - - // Draw the outer frame - rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); - if (IsFocus() && Window() && Window()->IsActive()) - SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); - else - SetHighColor(tint_color(base, B_DARKEN_3_TINT)); - StrokeRect(rect); } @@ -238,9 +280,17 @@ PictureView::WindowActivated(bool active) void PictureView::MakeFocus(bool focused) { + if (focused == IsFocus()) + return; + BView::MakeFocus(focused); - Invalidate(); + if (Window()) { + fFocusChanging = true; + Invalidate(); + Flush(); + fFocusChanging = false; + } } @@ -402,11 +452,139 @@ PictureView::_BeginDrag(BPoint sourcePoint) void -PictureView::_HandleDrop(BMessage* message) +PictureView::_HandleDrop(BMessage* msg) { - // TODO - printf("PictureView::_HandleDrop(): \n"); - message->PrintToStream(); + printf("PictureControl::_HandleDrop(): \n"); + msg->PrintToStream(); + + entry_ref dirRef; + BString name, type; + bool saveToFile = msg->FindString("be:filetypes", &type) == B_OK + && msg->FindRef("directory", &dirRef) == B_OK + && msg->FindString("name", &name) == B_OK; + + bool sendInMessage = !saveToFile + && msg->FindString("be:types", &type) == B_OK; + + if (!sendInMessage && !saveToFile) + return; + + BBitmap* bitmap = fPicture; + if (bitmap == NULL) + return; + + BTranslatorRoster* roster = BTranslatorRoster::Default(); + if (roster == NULL) + return; + + BBitmapStream stream(bitmap); + + // find transaltion format asked for + translator_info* outInfo; + int32 outNumInfo; + bool found = false; + translation_format format; + + if (roster->GetTranslators(&stream, NULL, &outInfo, &outNumInfo) == B_OK) { + for (int32 i = 0; i < outNumInfo; i++) { + const translation_format* formats; + int32 formatCount; + roster->GetOutputFormats(outInfo[i].translator, &formats, + &formatCount); + for (int32 j = 0; j < formatCount; j++) { + if (strcmp(formats[j].MIME, type.String()) == 0) { + format = formats[j]; + found = true; + break; + } + } + } + } + + if (!found) { + stream.DetachBitmap(&bitmap); + return; + } + + if (sendInMessage) { + + BMessage reply(B_MIME_DATA); + BMallocIO memStream; + if (roster->Translate(&stream, NULL, NULL, &memStream, + format.type) == B_OK) { + reply.AddData(format.MIME, B_MIME_TYPE, memStream.Buffer(), + memStream.BufferLength()); + msg->SendReply(&reply); + } + + } else { + + BDirectory dir(&dirRef); + BFile file(&dir, name.String(), B_WRITE_ONLY | B_CREATE_FILE + | B_ERASE_FILE); + + if (file.InitCheck() == B_OK + && roster->Translate(&stream, NULL, NULL, &file, + format.type) == B_OK) { + BNodeInfo nodeInfo(&file); + if (nodeInfo.InitCheck() == B_OK) + nodeInfo.SetType(type.String()); + } else { + BString text = B_TRANSLATE("The file '%name%' could not " + "be written."); + text.ReplaceFirst("%name", name); + BAlert* alert = new BAlert(B_TRANSLATE("Error"), text.String(), + B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); + alert->Go(); + } + } + + // Detach, as we don't want our picture to be deleted + stream.DetachBitmap(&bitmap); +} + + +status_t +PictureView::_LoadPicture(const entry_ref* ref) +{ + BFile file; + status_t status = file.SetTo(ref, B_READ_ONLY); + if (status != B_OK) + return status; + + translator_info info; + memset(&info, 0, sizeof(translator_info)); + BMessage ioExtension; + + BTranslatorRoster* roster = BTranslatorRoster::Default(); + if (roster == NULL) + return B_ERROR; + + status = roster->Identify(&file, &ioExtension, &info, 0, NULL, + B_TRANSLATOR_BITMAP); + + BBitmapStream stream; + + if (status == B_OK) { + status = roster->Translate(&file, &info, &ioExtension, &stream, + B_TRANSLATOR_BITMAP); + } + if (status != B_OK) + return status; + + BBitmap* picture = NULL; + if (stream.DetachBitmap(&picture) != B_OK) + return B_ERROR; + + if (picture == NULL) + return B_ERROR; + + // Remember image format so we store using same + fPictureMIMEType = info.MIME; + fPictureType = info.type; + + _SetPicture(picture); + return B_OK; } @@ -418,6 +596,11 @@ PictureView::_SetPicture(BBitmap* picture) fPicture = picture; Invalidate(); + + if (picture == NULL) { + fPictureType = 0; + fPictureMIMEType = ""; + } } diff --git a/src/apps/people/PictureView.h b/src/apps/people/PictureView.h index 3e47bc25cf..9e8b45e759 100644 --- a/src/apps/people/PictureView.h +++ b/src/apps/people/PictureView.h @@ -10,11 +10,12 @@ #include +#include #include class BBitmap; - +class BFilePanel; const uint32 kMsgLoadImage = 'mLIM'; @@ -30,6 +31,8 @@ public: void Update(const entry_ref* ref); BBitmap* Bitmap(); + uint32 SuggestedType(); + const char* SuggestedMIMEType(); virtual void MessageReceived(BMessage* message); virtual void Draw(BRect updateRect); @@ -44,6 +47,7 @@ private: void _ShowPopUpMenu(BPoint screen); BBitmap* _CopyPicture(uint8 alpha); + status_t _LoadPicture(const entry_ref* ref); void _SetPicture(BBitmap* bitmap); BBitmap* fPicture; @@ -51,6 +55,10 @@ private: BBitmap* fDefaultPicture; bool fShowingPopUpMenu; BRect fPictureRect; + uint32 fPictureType; + BString fPictureMIMEType; + bool fFocusChanging; + BFilePanel* fOpenPanel; }; #endif