From 22c6ae695176ead7d736db8c69472d8ae89dc75f Mon Sep 17 00:00:00 2001 From: DarkWyrm Date: Wed, 7 Feb 2007 22:16:45 +0000 Subject: [PATCH] Forgot to add new files to the last checkin git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20114 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/resedit/BitmapView.cpp | 729 +++++++++++++++++++++++++++++ src/apps/resedit/BitmapView.h | 93 ++++ src/apps/resedit/ImageEditor.cpp | 113 +++++ src/apps/resedit/InlineEditor.cpp | 94 ++++ src/apps/resedit/InlineEditor.h | 27 ++ src/apps/resedit/InternalEditors.h | 85 ++++ src/apps/resedit/MiscEditors.cpp | 153 ++++++ src/apps/resedit/NumberEditors.cpp | 48 ++ src/apps/resedit/ResFields.cpp | 177 +++++++ src/apps/resedit/ResFields.h | 75 +++ 10 files changed, 1594 insertions(+) create mode 100644 src/apps/resedit/BitmapView.cpp create mode 100644 src/apps/resedit/BitmapView.h create mode 100644 src/apps/resedit/ImageEditor.cpp create mode 100644 src/apps/resedit/InlineEditor.cpp create mode 100644 src/apps/resedit/InlineEditor.h create mode 100644 src/apps/resedit/InternalEditors.h create mode 100644 src/apps/resedit/MiscEditors.cpp create mode 100644 src/apps/resedit/NumberEditors.cpp create mode 100644 src/apps/resedit/ResFields.cpp create mode 100644 src/apps/resedit/ResFields.h diff --git a/src/apps/resedit/BitmapView.cpp b/src/apps/resedit/BitmapView.cpp new file mode 100644 index 0000000000..aa1990cdd0 --- /dev/null +++ b/src/apps/resedit/BitmapView.cpp @@ -0,0 +1,729 @@ +#include "BitmapView.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO: Add support for labels + +#define M_REMOVE_IMAGE 'mrmi' +#define M_PASTE_IMAGE 'mpsi' + +enum +{ + CLIP_NONE=0, + CLIP_BEOS=1, + CLIP_SHOWIMAGE=2, + CLIP_PRODUCTIVE=3 +}; + +inline void SetRGBColor(rgb_color *col,uint8 r, uint8 g, uint8 b, uint8 a=255); + +void SetRGBColor(rgb_color *col,uint8 r, uint8 g, uint8 b, uint8 a) +{ + if(col) + { + col->red=r; + col->green=g; + col->blue=b; + col->alpha=a; + } +} + +BitmapView::BitmapView(BRect frame, const char *name, BMessage *mod, BBitmap *bitmap, + const char *label, border_style borderstyle,int32 resize,int32 flags) + : BView(frame, name, resize, flags) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + if(bitmap && bitmap->IsValid()) + fBitmap=bitmap; + else + fBitmap=NULL; + + if(mod) + SetMessage(mod); + + fLabel=label; + fBorderStyle=borderstyle; + fFixedSize=false; + fEnabled=true; + fRemovableBitmap=false; + fAcceptDrops=true; + fAcceptPaste=true; + fConstrainDrops=true; + fMaxWidth=100; + fMaxHeight=100; + + fPopUpMenu=new BPopUpMenu("deletepopup",false,false); + fPopUpMenu->AddItem(new BMenuItem("Close This Menu",new BMessage(B_CANCEL))); + fPopUpMenu->AddSeparatorItem(); + + fPasteItem=new BMenuItem("Paste Photo from Clipboard",new BMessage(M_PASTE_IMAGE)); + fPopUpMenu->AddItem(fPasteItem); + + fPopUpMenu->AddSeparatorItem(); + + fRemoveItem=new BMenuItem("Remove Photo",new BMessage(M_REMOVE_IMAGE)); + fPopUpMenu->AddItem(fRemoveItem); + + CalculateBitmapRect(); + + // Calculate the offsets for each of the words -- the phrase will be center justified + fNoPhotoWidths[0]=StringWidth("Drop"); + fNoPhotoWidths[1]=StringWidth("a"); + fNoPhotoWidths[2]=StringWidth("Photo"); + fNoPhotoWidths[3]=StringWidth("Here"); + + font_height fh; + GetFontHeight(&fh); + float totalheight=fh.ascent+fh.descent+fh.leading; + float yoffset=(Bounds().Height()-10-(totalheight*4))/2; + fNoPhotoOffsets[0].Set( (Bounds().Width()-fNoPhotoWidths[0])/2,totalheight+yoffset); + fNoPhotoOffsets[1].Set( (Bounds().Width()-fNoPhotoWidths[1])/2,fNoPhotoOffsets[0].y+totalheight); + fNoPhotoOffsets[2].Set( (Bounds().Width()-fNoPhotoWidths[2])/2,fNoPhotoOffsets[1].y+totalheight); + fNoPhotoOffsets[3].Set( (Bounds().Width()-fNoPhotoWidths[3])/2,fNoPhotoOffsets[2].y+totalheight); +} + +BitmapView::~BitmapView(void) +{ + delete fPopUpMenu; +} + +void BitmapView::AttachedToWindow(void) +{ + SetTarget((BHandler*)Window()); + fPopUpMenu->SetTargetForItems(this); +} + +void BitmapView::SetBitmap(BBitmap *bitmap) +{ + if(bitmap && bitmap->IsValid()) + { + if(fBitmap==bitmap) + return; + + fBitmap=bitmap; + } + else + { + if(fBitmap==NULL) + return; + + fBitmap=NULL; + } + + CalculateBitmapRect(); + if(!IsHidden()) + Invalidate(); +} + +void BitmapView::SetEnabled(bool value) +{ + if(fEnabled!=value) + { + fEnabled=value; + Invalidate(); + } +} + +/* +void BitmapView::SetLabel(const char *label) +{ + if(fLabel.Compare(label)!=0) + { + fLabel=label; + + CalculateBitmapRect(); + if(!IsHidden()) + Invalidate(); + } +} +*/ + +void BitmapView::SetStyle(border_style style) +{ + if(fBorderStyle!=style) + { + fBorderStyle=style; + + CalculateBitmapRect(); + if(!IsHidden()) + Invalidate(); + } +} + +void BitmapView::SetFixedSize(bool isfixed) +{ + if(fFixedSize!=isfixed) + { + fFixedSize=isfixed; + + CalculateBitmapRect(); + if(!IsHidden()) + Invalidate(); + } +} + +void BitmapView::MessageReceived(BMessage *msg) +{ + if(msg->WasDropped() && AcceptsDrops()) + { + // We'll handle two types of drops: those from Tracker and those from ShowImage + if(msg->what==B_SIMPLE_DATA) + { + int32 actions; + if(msg->FindInt32("be:actions",&actions)==B_OK) + { + // ShowImage drop. This is a negotiated drag&drop, so send a reply + BMessage reply(B_COPY_TARGET), response; + reply.AddString("be:types","image/jpeg"); + reply.AddString("be:types","image/png"); + + msg->SendReply(&reply,&response); + + // now, we've gotten the response + if(response.what==B_MIME_DATA) + { + // Obtain and translate the received data + uint8 *imagedata; + ssize_t datasize; + + // Try JPEG first + if(response.FindData("image/jpeg",B_MIME_DATA,(const void **)&imagedata,&datasize)!=B_OK) + { + // Try PNG next and piddle out if unsuccessful + if(response.FindData("image/png",B_PNG_FORMAT,(const void **)&imagedata,&datasize)!=B_OK) + return; + } + + // Set up to decode into memory + BMemoryIO memio(imagedata,datasize); + BTranslatorRoster *roster=BTranslatorRoster::Default(); + BBitmapStream bstream; + + if(roster->Translate(&memio,NULL,NULL,&bstream, B_TRANSLATOR_BITMAP)==B_OK) + { + BBitmap *bmp; + if(bstream.DetachBitmap(&bmp)!=B_OK) + return; + + SetBitmap(bmp); + + if(fConstrainDrops) + ConstrainBitmap(); + + Invoke(); + } + } + return; + } + + entry_ref ref; + if(msg->FindRef("refs",&ref)==B_OK) + { + // Tracker drop + BBitmap *bmp=BTranslationUtils::GetBitmap(&ref); + if(bmp) + { + SetBitmap(bmp); + + if(fConstrainDrops) + ConstrainBitmap(); + + Invoke(); + } + } + } + return; + } + + switch(msg->what) + { + case M_REMOVE_IMAGE: + { + BAlert *alert=new BAlert("Mr. Peeps!","This cannot be undone. Remove the image?","Remove", + "Cancel"); + int32 value=alert->Go(); + if(value==0) + { + SetBitmap(NULL); + + if(Target()) + { + BMessenger msgr(Target()); + + msgr.SendMessage(new BMessage(M_BITMAP_REMOVED)); + return; + } + } + } + case M_PASTE_IMAGE: + { + PasteBitmap(); + + Invoke(); + } + } + BView::MessageReceived(msg); +} + +void BitmapView::Draw(BRect rect) +{ + if(fBitmap) + DrawBitmap(fBitmap,fBitmap->Bounds(),fBitmapRect); + else + { + SetHighColor(0,0,0,80); + SetDrawingMode(B_OP_ALPHA); + DrawString("Drop",fNoPhotoOffsets[0]); + DrawString("a",fNoPhotoOffsets[1]); + DrawString("Photo",fNoPhotoOffsets[2]); + DrawString("Here",fNoPhotoOffsets[3]); + SetDrawingMode(B_OP_COPY); + } + + if(fBorderStyle==B_FANCY_BORDER) + { + rgb_color base= {216,216,216,255}; + rgb_color work; + + SetHighColor(base); + StrokeRect(Bounds().InsetByCopy(2,2)); + + BeginLineArray(12); + + BRect r(Bounds()); + + work=tint_color(base,B_DARKEN_2_TINT); + AddLine(r.LeftTop(),r.RightTop(),work); + AddLine(r.LeftTop(),r.LeftBottom(),work); + r.left++; + + work=tint_color(base,B_DARKEN_4_TINT); + AddLine(r.RightTop(),r.RightBottom(),work); + AddLine(r.LeftBottom(),r.RightBottom(),work); + + r.right--; + r.top++; + r.bottom--; + + + work=tint_color(base,B_LIGHTEN_MAX_TINT); + AddLine(r.LeftTop(),r.RightTop(),work); + AddLine(r.LeftTop(),r.LeftBottom(),work); + r.left++; + + work=tint_color(base,B_DARKEN_3_TINT); + AddLine(r.RightTop(),r.RightBottom(),work); + AddLine(r.LeftBottom(),r.RightBottom(),work); + + // this rect handled by the above StrokeRect, so inset a total of 2 pixels + r.left++; + r.right-=2; + r.top+=2; + r.bottom-=2; + + + work=tint_color(base,B_DARKEN_3_TINT); + AddLine(r.LeftTop(),r.RightTop(),work); + AddLine(r.LeftTop(),r.LeftBottom(),work); + r.left++; + + work=tint_color(base,B_LIGHTEN_MAX_TINT); + AddLine(r.RightTop(),r.RightBottom(),work); + AddLine(r.LeftBottom(),r.RightBottom(),work); + + r.right--; + r.top++; + r.bottom--; + EndLineArray(); + + SetHighColor(tint_color(base,B_DARKEN_2_TINT)); + StrokeRect(r); + } + else + { + // Plain border + SetHighColor(0,0,0); + StrokeRect(fBitmapRect); + } +} + +void BitmapView::MouseDown(BPoint pt) +{ + BPoint mousept; + uint32 buttons; + + GetMouse(&mousept,&buttons); + if(buttons & B_SECONDARY_MOUSE_BUTTON) + { + ConvertToScreen(&mousept); + + mousept.x= (mousept.x>5) ? mousept.x-5 : 0; + mousept.y= (mousept.y>5) ? mousept.y-5 : 0; + + if(AcceptsPaste() && ClipboardHasBitmap()) + fPasteItem->SetEnabled(true); + else + fPasteItem->SetEnabled(false); + + if(fRemovableBitmap && fBitmap) + fRemoveItem->SetEnabled(true); + else + fRemoveItem->SetEnabled(false); + + fPopUpMenu->Go(mousept,true,true,true); + } +} + +void BitmapView::FrameResized(float w, float h) +{ + CalculateBitmapRect(); +} + +void BitmapView::CalculateBitmapRect(void) +{ + if(!fBitmap || fFixedSize) + { + fBitmapRect=Bounds().InsetByCopy(1,1); + return; + } + +/* // Dynamic sizing algorithm + // 1) Check to see if either dimension is bigger than the view's display area + // 2) If smaller along both axes, make bitmap rect centered and return + // 3) Check to see if scaling is to be horizontal or vertical on basis of longer axis + // 4) Calculate scaling factor + // 5) Scale both axes down by scaling factor, accounting for border width + // 6) Center the rectangle in the direction of the smaller axis + + + uint8 borderwidth=(fBorderStyle==B_FANCY_BORDER)?5:1; + + BRect r(Bounds()); + r.InsetBy(borderwidth,borderwidth); + + if( (fBitmap->Bounds().Width()<=r.Width()) && + (fBitmap->Bounds().Height()<=r.Height()) ) + { + // Smaller than view, so just center and return + fBitmapRect=fBitmap->Bounds(); + fBitmapRect.OffsetBy( borderwidth+ + ((r.Width()-fBitmapRect.Width()-(borderwidth<<2))/2), + ((r.Height()-fBitmapRect.Height()-(borderwidth<<2))/2) ); + return; + } + + float multiplier=fBitmap->Bounds().Width()/fBitmap->Bounds().Height(); + float offset; + if(multiplier>1) + { + // Landscape orientation + + // Scale rectangle to bounds width and center height + r.bottom=r.top+(r.Width()/multiplier); + + offset= ((Bounds().Height()-(borderwidth<<1)) - r.Height())/2; + r.OffsetBy(0,offset); + } + else + { + // Portrait orientation + + // Scale rectangle to bounds height and center width + r.right=r.left+(r.Height()*multiplier); + + offset= ((Bounds().Width()-(borderwidth<<1)) - r.Width())/2; + r.OffsetBy(offset,0); + } + fBitmapRect=r; +*/ + + uint8 borderwidth=(fBorderStyle==B_FANCY_BORDER)?5:1; + + BRect r(Bounds()); + fBitmapRect= ScaleRectToFit(fBitmap->Bounds(),r.InsetByCopy(borderwidth,borderwidth)); +} + +void BitmapView::SetAcceptDrops(bool accept) +{ + fAcceptDrops=accept; +} + +void BitmapView::SetAcceptPaste(bool accept) +{ + fAcceptPaste=accept; +} + +void BitmapView::SetConstrainDrops(bool value) +{ + fConstrainDrops=value; +} + +void BitmapView::MaxBitmapSize(float *width, float *height) const +{ + *width=fMaxWidth; + *height=fMaxHeight; +} + +void BitmapView::SetMaxBitmapSize(const float &width, const float &height) +{ + fMaxWidth=width; + fMaxHeight=height; + + ConstrainBitmap(); +} + +void BitmapView::SetBitmapRemovable(bool isremovable) +{ + fRemovableBitmap=isremovable; +} + +void BitmapView::ConstrainBitmap(void) +{ + if(!fBitmap || fMaxWidth < 1 || fMaxHeight < 1) + return; + + BRect r=ScaleRectToFit(fBitmap->Bounds(),BRect(0,0,fMaxWidth-1,fMaxHeight-1)); + r.OffsetTo(0,0); + + BBitmap *scaled=new BBitmap(r,fBitmap->ColorSpace(),true); + BView *view=new BView(r,"drawview",0,0); + + scaled->Lock(); + scaled->AddChild(view); + view->DrawBitmap(fBitmap,fBitmap->Bounds(),scaled->Bounds()); + scaled->Unlock(); + + delete fBitmap; + fBitmap=new BBitmap(scaled,false); +} + +bool BitmapView::ClipboardHasBitmap(void) +{ + BMessage *clip=NULL,flattened; + uint8 clipval=CLIP_NONE; + bool returnval; + + if(be_clipboard->Lock()) + { + clip=be_clipboard->Data(); + if(!clip->IsEmpty()) + { + returnval=(clip->FindMessage("image/bitmap",&flattened)==B_OK); + if(returnval) + clipval=CLIP_BEOS; + else + { + BString string; + returnval=(clip->FindString("class",&string)==B_OK && string=="BBitmap"); + + // Try method Gobe Productive uses if that, too, didn't work + if(returnval) + clipval=CLIP_SHOWIMAGE; + else + { + returnval=(clip->FindMessage("image/x-vnd.Be-bitmap",&flattened)==B_OK); + if(returnval) + clipval=CLIP_SHOWIMAGE; + else + clipval=CLIP_NONE; + } + } + } + be_clipboard->Unlock(); + } + return (clipval!=CLIP_NONE)?true:false; +} + +BBitmap *BitmapView::BitmapFromClipboard(void) +{ + BMessage *clip=NULL,flattened; + BBitmap *bitmap; + + if(!be_clipboard->Lock()) + return NULL; + + clip=be_clipboard->Data(); + if(!clip) + return NULL; + + uint8 clipval=CLIP_NONE; + + // Try ArtPaint-style storage + status_t status=clip->FindMessage("image/bitmap",&flattened); + + // If that didn't work, try ShowImage-style + if(status!=B_OK) + { + BString string; + status=clip->FindString("class",&string); + + // Try method Gobe Productive uses if that, too, didn't work + if(status==B_OK && string=="BBitmap") + clipval=CLIP_SHOWIMAGE; + else + { + status=clip->FindMessage("image/x-vnd.Be-bitmap",&flattened); + if(status==B_OK) + clipval=CLIP_PRODUCTIVE; + else + clipval=CLIP_NONE; + } + } + else + clipval=CLIP_BEOS; + + be_clipboard->Unlock(); + + switch(clipval) + { + case CLIP_SHOWIMAGE: + { + // Showimage does it a slightly different way -- it dumps the BBitmap + // data directly to the clipboard message instead of packaging it in + // a bitmap like everyone else. + + if(!be_clipboard->Lock()) + return NULL; + + BMessage datamsg(*be_clipboard->Data()); + + be_clipboard->Unlock(); + + const void *buffer; + int32 bufferLength; + + BRect frame; + color_space cspace=B_NO_COLOR_SPACE; + + status=datamsg.FindRect("_frame",&frame); + if(status!=B_OK) + return NULL; + + status=datamsg.FindInt32("_cspace",(int32)cspace); + if(status!=B_OK) + return NULL; + cspace=B_RGBA32; + bitmap=new BBitmap(frame,cspace,true); + + status=datamsg.FindData("_data",B_RAW_TYPE,(const void **)&buffer, &bufferLength); + if(status!=B_OK) + { + delete bitmap; + return NULL; + } + + memcpy(bitmap->Bits(), buffer, bufferLength); + + return bitmap; + } + case CLIP_PRODUCTIVE: + // Productive doesn't name the packaged BBitmap data message the same, but + // uses exactly the same data format. + + case CLIP_BEOS: + { + const void *buffer; + int32 bufferLength; + + BRect frame; + color_space cspace=B_NO_COLOR_SPACE; + + status=flattened.FindRect("_frame",&frame); + if(status!=B_OK) + return NULL; + + status=flattened.FindInt32("_cspace",(int32)cspace); + if(status!=B_OK) + return NULL; + cspace=B_RGBA32; + bitmap=new BBitmap(frame,cspace,true); + + status=flattened.FindData("_data",B_RAW_TYPE,(const void **)&buffer, &bufferLength); + if(status!=B_OK) + { + delete bitmap; + return NULL; + } + + memcpy(bitmap->Bits(), buffer, bufferLength); + + return bitmap; + } + default: + return NULL; + } + + // shut the compiler up + return NULL; +} + +BRect ScaleRectToFit(const BRect &from, const BRect &to) +{ + // Dynamic sizing algorithm + // 1) Check to see if either dimension is bigger than the view's display area + // 2) If smaller along both axes, make bitmap rect centered and return + // 3) Check to see if scaling is to be horizontal or vertical on basis of longer axis + // 4) Calculate scaling factor + // 5) Scale both axes down by scaling factor, accounting for border width + // 6) Center the rectangle in the direction of the smaller axis + + if(!to.IsValid()) + return from; + if(!from.IsValid()) + return to; + + BRect r(to); + + if( (from.Width()<=r.Width()) && + (from.Height()<=r.Height()) ) + { + // Smaller than view, so just center and return + r=from; + r.OffsetBy( (to.Width()-r.Width())/2, (to.Height()-r.Height())/2 ); + return r; + } + + float multiplier=from.Width()/from.Height(); + if(multiplier>1) + { + // Landscape orientation + + // Scale rectangle to bounds width and center height + r.bottom=r.top+(r.Width()/multiplier); + + r.OffsetBy(0,(to.Height() - r.Height())/2); + } + else + { + // Portrait orientation + + // Scale rectangle to bounds height and center width + r.right=r.left+(r.Height()*multiplier); + + r.OffsetBy((to.Width() - r.Width())/2,0); + } + return r; +} + +void BitmapView::RemoveBitmap(void) +{ + SetBitmap(NULL); +} + +void BitmapView::PasteBitmap(void) +{ + BBitmap *bmp=BitmapFromClipboard(); + if(bmp) + SetBitmap(bmp); + + if(fConstrainDrops) + ConstrainBitmap(); +} diff --git a/src/apps/resedit/BitmapView.h b/src/apps/resedit/BitmapView.h new file mode 100644 index 0000000000..5c661b1c13 --- /dev/null +++ b/src/apps/resedit/BitmapView.h @@ -0,0 +1,93 @@ +#ifndef BMPVIEW_H +#define BMPVIEW_H + +#include +#include +#include +#include +#include +#include + +enum +{ + M_BITMAP_ADDED='mbma', + M_BITMAP_REMOVED='mbmr' +}; + +class BitmapView : public BView, public BInvoker +{ +public: + BitmapView(BRect frame, const char *name, BMessage *mod, BBitmap *bitmap, + const char *label = NULL, border_style = B_PLAIN_BORDER, + int32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, int32 flags = B_WILL_DRAW); + ~BitmapView(void); + virtual void AttachedToWindow(void); + + virtual void Draw(BRect rect); + virtual void MessageReceived(BMessage *msg); + virtual void MouseDown(BPoint pt); + virtual void FrameResized(float w, float h); + + virtual void SetBitmap(BBitmap *bitmap); + BBitmap *GetBitmap(void) const { return fBitmap; } + + bool IsEnabled(void) const { return fEnabled; } + virtual void SetEnabled(bool value); + +// const char *Label(void) const { return fLabel.String(); } +// virtual void SetLabel(const char *label); + + border_style Style(void) const { return fBorderStyle; } + virtual void SetStyle(border_style style); + + bool IsFixedSize(void) const { return fFixedSize; } + void SetFixedSize(bool isfixed); + + bool AcceptsDrops(void) const { return fAcceptDrops; } + virtual void SetAcceptDrops(bool accept); + + bool AcceptsPaste(void) const { return fAcceptPaste; } + virtual void SetAcceptPaste(bool accept); + + bool ConstrainsDrops(void) const { return fConstrainDrops; } + virtual void SetConstrainDrops(bool value); + + void MaxBitmapSize(float *width, float *height) const; + virtual void SetMaxBitmapSize(const float &width, const float &height); + + bool IsBitmapRemovable(void) const { return fRemovableBitmap; } + void SetBitmapRemovable(bool isremovable); + + void RemoveBitmap(void); + void PasteBitmap(void); + +private: + void CalculateBitmapRect(void); + void ConstrainBitmap(void); + + bool ClipboardHasBitmap(void); + BBitmap *BitmapFromClipboard(void); + + float fNoPhotoWidths[4]; + BPoint fNoPhotoOffsets[4]; + + BBitmap *fBitmap; + BRect fBitmapRect; + bool fEnabled; + BString fLabel; + border_style fBorderStyle; + bool fFixedSize; + bool fAcceptDrops; + bool fAcceptPaste; + bool fConstrainDrops; + float fMaxWidth, fMaxHeight; + bool fRemovableBitmap; + BPopUpMenu *fPopUpMenu; + uint32 fMouseButtons; + BMenuItem *fPasteItem; + BMenuItem *fRemoveItem; +}; + +BRect ScaleRectToFit(const BRect &from, const BRect &to); + +#endif diff --git a/src/apps/resedit/ImageEditor.cpp b/src/apps/resedit/ImageEditor.cpp new file mode 100644 index 0000000000..3bc910d627 --- /dev/null +++ b/src/apps/resedit/ImageEditor.cpp @@ -0,0 +1,113 @@ +#include "InternalEditors.h" +#include "BitmapView.h" +#include "ResourceData.h" +#include +#include + +#define M_IMAGE_CHANGED 'imch' + +ImageEditor::ImageEditor(const BRect &frame, ResourceData *data, BHandler *owner) + : Editor(frame, data, owner) +{ + SetFlags(Flags() | B_NOT_RESIZABLE | B_NOT_ZOOMABLE); + SetTitle(data->GetName()); + + // Set up the image and the viewer for such + BMemoryIO memio(data->GetData(),data->GetLength()); + fImage = BTranslationUtils::GetBitmap(&memio); + + BRect imgsize; + if (fImage) + imgsize = ScaleRectToFit(fImage->Bounds(),BRect(0,0,200,200)); + else + imgsize.Set(0,0,200,200); + + BView *back = new BView(Bounds(),"back",B_FOLLOW_ALL,B_WILL_DRAW); + back->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(back); + + BRect r; + + float labelwidth = be_plain_font->StringWidth("ID: "); + float strwidth = be_plain_font->StringWidth("(attr) "); + + font_height fh; + be_plain_font->GetHeight(&fh); + float strheight = fh.ascent + fh.descent + fh.leading + 5; + + fIDBox = new BTextControl(BRect(10,10,10 + (strwidth + labelwidth) + 15, + 10 + strheight), + "id","ID: ",data->GetIDString(), NULL); + fIDBox->SetDivider(labelwidth + 5); + back->AddChild(fIDBox); + + r = fIDBox->Frame(); + r.OffsetBy(r.Width() + 10, 0); + r.right = Bounds().right - 10; + fNameBox = new BTextControl(r,"name","Name: ",data->GetName(), NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fNameBox->SetDivider(be_plain_font->StringWidth("Name: ") + 5); + back->AddChild(fNameBox); + + r = imgsize; + + r.OffsetTo( (Bounds().Width() - r.Width()) / 2,fNameBox->Frame().bottom + 10); + fImageView = new BitmapView(r,"imageview",new BMessage(M_IMAGE_CHANGED),fImage, + NULL, B_PLAIN_BORDER, B_FOLLOW_NONE, + B_WILL_DRAW | B_FRAME_EVENTS); + back->AddChild(fImageView); + fImageView->SetConstrainDrops(false); + + // No limit on bitmap size + fImageView->SetMaxBitmapSize(0,0); + fImageView->SetBitmapRemovable(false); + + fOK = new BButton(BRect(10,10,11,11),"ok","Cancel",new BMessage(M_UPDATE_RESOURCE), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + fOK->ResizeToPreferred(); + fOK->SetLabel("OK"); + fOK->MakeDefault(true); + back->AddChild(fOK); + + fOK->MoveTo(Bounds().right - fOK->Bounds().Width() - 10, + Bounds().bottom - fOK->Bounds().Height() - 10); + r = fOK->Frame(); + + r.OffsetBy(-r.Width() - 10, 0); + fCancel = new BButton(r,"cancel","Cancel",new BMessage(B_QUIT_REQUESTED), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + back->AddChild(fCancel); + + ResizeTo(MAX(fImageView->Frame().right, fNameBox->Frame().right) + 20, + fImageView->Frame().bottom + fOK->Frame().Height() + 20); +} + + +ImageEditor::~ImageEditor(void) +{ + delete fImage; +} + + +void +ImageEditor::MessageReceived(BMessage *msg) +{ + if (msg->WasDropped()) { + fImageView->MessageReceived(msg); + } else if (msg->what == M_IMAGE_CHANGED) { + fImage = fImageView->GetBitmap(); + BRect r = ScaleRectToFit(fImage->Bounds(), BRect(0,0,200,200)); + fImageView->ResizeTo(r.Width(),r.Height()); + ResizeTo(MAX(fImageView->Frame().right, fNameBox->Frame().right) + 20, + fImageView->Frame().bottom + fOK->Frame().Height() + 20); + } else + BWindow::MessageReceived(msg); +} + + +void +ImageEditor::FrameResized(float w, float h) +{ + fImageView->MoveTo( (w - fImageView->Bounds().Width()) / 2, + fNameBox->Frame().bottom + 10); +} diff --git a/src/apps/resedit/InlineEditor.cpp b/src/apps/resedit/InlineEditor.cpp new file mode 100644 index 0000000000..67ca638504 --- /dev/null +++ b/src/apps/resedit/InlineEditor.cpp @@ -0,0 +1,94 @@ +#include "InlineEditor.h" +#include +#include + +class EditFilter : public BMessageFilter +{ +public: + EditFilter(BTextControl *textbox) + : BMessageFilter(B_PROGRAMMED_DELIVERY, B_ANY_SOURCE,B_KEY_DOWN) + { + fTextBox = textbox; + } + + ~EditFilter(void) + { + } + + filter_result Filter(BMessage *msg, BHandler **target) + { + int32 rawchar; + msg->FindInt32("raw_char",&rawchar); + + if (rawchar == B_ESCAPE) { + BLooper *loop = (*target)->Looper(); + if (loop) { + BMessenger msgr(loop); + msgr.SendMessage(B_QUIT_REQUESTED); + return B_SKIP_MESSAGE; + } + } else if (rawchar == B_ENTER) { + fTextBox->Invoke(); + return B_SKIP_MESSAGE; + } + return B_DISPATCH_MESSAGE; + } + +private: + BTextControl *fTextBox; + +}; + +InlineEditor::InlineEditor(BMessenger target, const BRect &frame, + const char *text) + : BWindow(frame,"InlineEditor",B_NO_BORDER_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, + B_ASYNCHRONOUS_CONTROLS), + fMessenger(target), + fCommand(M_INLINE_TEXT) +{ + fTextBox = new BTextControl(BRect(0,0,1,1), "inlinebox",NULL, text, + new BMessage(fCommand), B_FOLLOW_ALL, + B_WILL_DRAW); + AddChild(fTextBox); + fTextBox->SetDivider(0); + fTextBox->MakeFocus(true); + + fTextBox->ResizeToPreferred(); + fTextBox->ResizeTo(Bounds().Width(),fTextBox->Bounds().Height()); + ResizeTo(Bounds().Width(), fTextBox->Bounds().Height()); + + AddCommonFilter(new EditFilter(fTextBox)); +} + + +bool +InlineEditor::QuitRequested(void) +{ + return true; +} + + +void +InlineEditor::SetMessage(BMessage *msg) +{ + fCommand = msg ? msg->what : 0; + fTextBox->SetMessage(msg); +} + + +void +InlineEditor::MessageReceived(BMessage *msg) +{ + if (msg->what == fCommand) { + fMessenger.SendMessage(msg); + PostMessage(B_QUIT_REQUESTED); + } +} + +void +InlineEditor::WindowActivated(bool active) +{ + if (!active) + PostMessage(B_QUIT_REQUESTED); +} + diff --git a/src/apps/resedit/InlineEditor.h b/src/apps/resedit/InlineEditor.h new file mode 100644 index 0000000000..16359c02d5 --- /dev/null +++ b/src/apps/resedit/InlineEditor.h @@ -0,0 +1,27 @@ +#ifndef INLINE_EDITOR +#define INLINE_EDITOR + +#include +#include +#include + +#define M_INLINE_TEXT 'intx' + +class InlineEditor : public BWindow +{ +public: + InlineEditor(BMessenger target, const BRect &frame, + const char *text); + bool QuitRequested(void); + void SetMessage(BMessage *msg); + void MessageReceived(BMessage *msg); + void WindowActivated(bool active); + +private: + BTextControl *fTextBox; + BMessenger fMessenger; + uint32 fCommand; +}; + + +#endif diff --git a/src/apps/resedit/InternalEditors.h b/src/apps/resedit/InternalEditors.h new file mode 100644 index 0000000000..add55f58a0 --- /dev/null +++ b/src/apps/resedit/InternalEditors.h @@ -0,0 +1,85 @@ +#ifndef INTERNALEDITORS_H +#define INTERNALEDITORS_H + +#include +#include +#include +#include "Editor.h" + +class StringEditView : public BView +{ +public: + StringEditView(const BRect &frame); + ~StringEditView(void); + + void AttachedToWindow(void); + + const char * GetID(void) const { return fIDBox->Text(); } + void SetID(const char *idstring) { fIDBox->SetText(idstring); } + + const char * GetName(void) const { return fNameBox->Text(); } + void SetName(const char *name) { fNameBox->SetText(name); } + + const char * GetValue(void) const { return fValueBox->Text(); } + void SetValue(const char *value) { fValueBox->SetText(value); } + + void EnableID(const bool &value) { fIDBox->SetEnabled(value); } + bool IsIDEnabled(void) const { return fIDBox->IsEnabled(); } + + float GetPreferredWidth(void) const; + float GetPreferredHeight(void) const; + +private: + BTextControl *fIDBox, + *fNameBox, + *fValueBox; + + BButton *fCancel, + *fOK; +}; + +class DoubleEditor : public Editor +{ +public: + DoubleEditor(const BRect &frame, ResourceData *data, + BHandler *owner); + void MessageReceived(BMessage *msg); + +private: + StringEditView *fView; +}; + +class StringEditor : public Editor +{ +public: + StringEditor(const BRect &frame, ResourceData *data, + BHandler *owner); + void MessageReceived(BMessage *msg); + +private: + StringEditView *fView; +}; + +class BitmapView; + +class ImageEditor : public Editor +{ +public: + ImageEditor(const BRect &frame, ResourceData *data, + BHandler *owner); + ~ImageEditor(void); + void MessageReceived(BMessage *msg); + void FrameResized(float w, float h); + +private: + BTextControl *fIDBox; + BTextControl *fNameBox; + + BButton *fOK, + *fCancel; + + BBitmap *fImage; + BitmapView *fImageView; +}; + +#endif diff --git a/src/apps/resedit/MiscEditors.cpp b/src/apps/resedit/MiscEditors.cpp new file mode 100644 index 0000000000..162433b1da --- /dev/null +++ b/src/apps/resedit/MiscEditors.cpp @@ -0,0 +1,153 @@ +#include "InternalEditors.h" +#include "ResourceData.h" +#include +#include +#include +#include + +StringEditor::StringEditor(const BRect &frame, ResourceData *data, + BHandler *owner) + : Editor(frame, data, owner) +{ + if (data->GetName()) + SetTitle(data->GetName()); + + fView = new StringEditView(Bounds()); + AddChild(fView); + + if (data->IsAttribute()) + fView->EnableID(false); + else + fView->SetID(data->GetIDString()); + fView->SetName(data->GetName()); + fView->SetValue(data->GetData()); + + SetFlags(Flags() | B_NOT_V_RESIZABLE); +} + + +void +StringEditor::MessageReceived(BMessage *msg) +{ + if (msg->what == M_UPDATE_RESOURCE) { + // We have to have an ID, so if the squirrely developer didn't give us + // one, don't do anything + if (fView->GetID()) { + int32 newid = atol(fView->GetID()); + GetData()->SetID(newid); + } + GetData()->SetName(fView->GetName()); + GetData()->SetData(fView->GetValue(),strlen(fView->GetValue())); + + BMessage updatemsg(M_UPDATE_RESOURCE); + updatemsg.AddPointer("item",GetData()); + BMessenger msgr(GetOwner()); + msgr.SendMessage(&updatemsg); + PostMessage(B_QUIT_REQUESTED); + + } else { + Editor::MessageReceived(msg); + } +} + + +Editor::Editor(const BRect &frame, ResourceData *data, BHandler *owner) + : BWindow(frame, "Untitled", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS), + fResData(data), + fOwner(owner) +{ +} + + +Editor::~Editor(void) +{ +} + + +StringEditView::StringEditView(const BRect &frame) + : BView(frame, "edit", B_FOLLOW_ALL, B_WILL_DRAW) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BRect r; + + float labelwidth = be_plain_font->StringWidth("ID: "); + float strwidth = be_plain_font->StringWidth("(attr) "); + + font_height fh; + be_plain_font->GetHeight(&fh); + float strheight = fh.ascent + fh.descent + fh.leading + 5; + + fIDBox = new BTextControl(BRect(10,10,10 + (strwidth + labelwidth) + 15, + 10 + strheight), + "id","ID: ","", NULL); + fIDBox->SetDivider(labelwidth + 5); + AddChild(fIDBox); + + r = fIDBox->Frame(); + r.OffsetBy(r.Width() + 10, 0); + r.right = Bounds().right - 10; + fNameBox = new BTextControl(r,"name","Name: ","", NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fNameBox->SetDivider(be_plain_font->StringWidth("Name: ") + 5); + AddChild(fNameBox); + + r.OffsetBy(0,r.Height() + 10); + r.left = 10; + fValueBox = new BTextControl(r,"value","Value: ","", NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fValueBox->SetDivider(be_plain_font->StringWidth("Value: ") + 5); + AddChild(fValueBox); + + fOK = new BButton(BRect(10,10,11,11),"ok","Cancel",new BMessage(M_UPDATE_RESOURCE), + B_FOLLOW_RIGHT); + fOK->ResizeToPreferred(); + fOK->SetLabel("OK"); + fOK->MakeDefault(true); + AddChild(fOK); + + fOK->MoveTo(r.right - fOK->Bounds().Width(), r.bottom + 10); + r = fOK->Frame(); + r.OffsetBy(-r.Width() - 10, 0); + fCancel = new BButton(r,"cancel","Cancel",new BMessage(B_QUIT_REQUESTED), + B_FOLLOW_RIGHT); + AddChild(fCancel); +} + + +StringEditView::~StringEditView(void) +{ +} + + +void +StringEditView::AttachedToWindow(void) +{ + if (Bounds().Height() < fCancel->Frame().bottom + 10) + Window()->ResizeTo(Window()->Bounds().Width(), fCancel->Frame().bottom + 10); + + Window()->SetSizeLimits(Window()->Bounds().Width(), 30000, + Window()->Bounds().Height(), 30000); +} + + +float +StringEditView::GetPreferredWidth(void) const +{ + float idwidth = be_plain_font->StringWidth("ID: ") + + be_plain_font->StringWidth("(attr) ") + 15; + float namewidth = be_plain_font->StringWidth("Name: ") + + be_plain_font->StringWidth(fNameBox->Text()) + 15; + return idwidth + namewidth + 30; +} + + +float +StringEditView::GetPreferredHeight(void) const +{ + font_height fh; + be_plain_font->GetHeight(&fh); + float strheight = fh.ascent + fh.descent + fh.leading + 5; + return fOK->Frame().Height() + (strheight * 2) + 40; +} + diff --git a/src/apps/resedit/NumberEditors.cpp b/src/apps/resedit/NumberEditors.cpp new file mode 100644 index 0000000000..dfbb881772 --- /dev/null +++ b/src/apps/resedit/NumberEditors.cpp @@ -0,0 +1,48 @@ +#include "InternalEditors.h" +#include "ResourceData.h" +#include +#include +#include +#include + +DoubleEditor::DoubleEditor(const BRect &frame, ResourceData *data, + BHandler *owner) + : Editor(frame, data, owner) +{ + if (data->GetName()) + SetTitle(data->GetName()); + + fView = new StringEditView(Bounds()); + AddChild(fView); + + fView->SetID(data->GetIDString()); + fView->SetName(data->GetName()); + fView->SetValue(data->GetData()); +} + + +void +DoubleEditor::MessageReceived(BMessage *msg) +{ + if (msg->what == M_UPDATE_RESOURCE) { + // We have to have an ID, so if the squirrely developer didn't give us + // one, don't do anything + if (fView->GetID()) { + int32 newid = atol(fView->GetID()); + GetData()->SetID(newid); + } + + GetData()->SetName(fView->GetName()); + GetData()->SetData(fView->GetValue(),strlen(fView->GetValue())); + + BMessage updatemsg(M_UPDATE_RESOURCE); + updatemsg.AddPointer("item",GetData()); + BMessenger msgr(GetOwner()); + msgr.SendMessage(&updatemsg); + PostMessage(B_QUIT_REQUESTED); + + } else { + Editor::MessageReceived(msg); + } +} + diff --git a/src/apps/resedit/ResFields.cpp b/src/apps/resedit/ResFields.cpp new file mode 100644 index 0000000000..26d3f6eccf --- /dev/null +++ b/src/apps/resedit/ResFields.cpp @@ -0,0 +1,177 @@ +#include "ResFields.h" +#include "ResourceData.h" +#include +#include + +TypeCodeField::TypeCodeField(const type_code &code, ResourceData *data) + : BStringField(MakeTypeString(code).String()), + fTypeCode(code), + fData(data) +{ +} + + +PreviewField::PreviewField(void) +{ +} + + +PreviewField::~PreviewField(void) +{ +} + + +BitmapPreviewField::BitmapPreviewField(BBitmap *bitmap) +{ + fBitmap = bitmap; +} + + +BitmapPreviewField::~BitmapPreviewField(void) +{ + delete fBitmap; +} + + +void +BitmapPreviewField::DrawField(BRect rect, BView *parent) +{ + if (fBitmap) { + // Scale the fBitmap down to completely fit within the field's height + BRect drawrect(fBitmap->Bounds().OffsetToCopy(rect.LeftTop())); + if (drawrect.Height() > rect.Height()) { + drawrect = rect; + drawrect.right = drawrect.left + + (fBitmap->Bounds().Width() * + (rect.Height() / fBitmap->Bounds().Height())); + } + + parent->SetDrawingMode(B_OP_ALPHA); + parent->DrawBitmap(fBitmap, fBitmap->Bounds(), drawrect); + parent->SetDrawingMode(B_OP_COPY); + + BString out; + out << fBitmap->Bounds().IntegerWidth() << " x " + << fBitmap->Bounds().IntegerHeight() << " x " + << (int32(fBitmap->BytesPerRow() / fBitmap->Bounds().Width()) * 8); + + BRect stringrect = rect; + stringrect.right -= 10; + stringrect.left = stringrect.right - parent->StringWidth(out.String()); + if (stringrect.left < drawrect.right + 5) + stringrect.left = drawrect.right + 5; + + parent->TruncateString(&out, B_TRUNCATE_END, stringrect.Width()); + parent->DrawString(out.String(), stringrect.LeftTop()); + } +} + + +void +BitmapPreviewField::SetData(char *data, const size_t &length) +{ + BMemoryIO memio(data,length); + fBitmap = BTranslationUtils::GetBitmap(&memio); +} + + +IntegerPreviewField::IntegerPreviewField(const int64 &value) +{ + fValue = value; +} + + +IntegerPreviewField::~IntegerPreviewField(void) +{ +} + + +void +IntegerPreviewField::DrawField(BRect rect, BView *parent) +{ + BPoint point(rect.LeftBottom()); + point.y -= 2; + + BString string; + string << fValue; + parent->TruncateString(&string, B_TRUNCATE_MIDDLE, rect.Width() - 14); + parent->DrawString(string.String(), point); +} + + +void +IntegerPreviewField::SetData(char *data, const size_t &length) +{ + switch(length) { + case 8: { + fValue = *((int8*)data); + break; + } + case 16: { + fValue = *((int16*)data); + break; + } + case 32: { + fValue = *((int32*)data); + break; + } + case 64: { + fValue = *((int32*)data); + break; + } + default: { + break; + } + } +} + + +StringPreviewField::StringPreviewField(const char *string) +{ + fClipped = fString = string; +} + + +StringPreviewField::~StringPreviewField(void) +{ +} + + +void +StringPreviewField::DrawField(BRect rect, BView *parent) +{ + BPoint point(rect.LeftBottom()); + point.y -= 2; + + fClipped = fString; + parent->TruncateString(&fClipped, B_TRUNCATE_END, rect.Width() - 14); + parent->DrawString(fClipped.String(), point); +} + + +void +StringPreviewField::SetData(char *data, const size_t &length) +{ + char *temp = fString.LockBuffer(length + 2); + if (temp) + memcpy(temp, data, length); + temp[length] = '\0'; + fString.UnlockBuffer(); + fClipped = fString; +} + + +BString +MakeTypeString(int32 type) +{ + char typestring[7]; + char *typeptr = (char *) &type; + typestring[0] = '\''; + typestring[1] = typeptr[3]; + typestring[2] = typeptr[2]; + typestring[3] = typeptr[1]; + typestring[4] = typeptr[0]; + typestring[5] = '\''; + typestring[6] = '\0'; + return BString(typestring); +} diff --git a/src/apps/resedit/ResFields.h b/src/apps/resedit/ResFields.h new file mode 100644 index 0000000000..1f85a6fa98 --- /dev/null +++ b/src/apps/resedit/ResFields.h @@ -0,0 +1,75 @@ +#ifndef RESFIELDS_H +#define RESFIELDS_H + +#include +#include + +class ResourceData; + +class TypeCodeField : public BStringField +{ +public: + TypeCodeField(const type_code &code, ResourceData *data); + type_code GetTypeCode(void) const { return fTypeCode; } + ResourceData * GetResourceData(void) const { return fData; } + +private: + type_code fTypeCode; + ResourceData *fData; +}; + +// This is the base class for fields displaying the preview in the Data +// column of the main window. Each child class must implement all methods +class PreviewField : public BField +{ +public: + PreviewField(void); + virtual ~PreviewField(void); + virtual void DrawField(BRect rect, BView* parent) = 0; + virtual void SetData(char *data, const size_t &length) = 0; +}; + +// Unlike the BBitmapField class, this one actually takes ownership of the +// bitmap passed to it. This is good because the bitmap given to it is +// allocated by the Translation Kit. +class BitmapPreviewField : public PreviewField +{ +public: + BitmapPreviewField(BBitmap *bitmap); + virtual ~BitmapPreviewField(void); + virtual void DrawField(BRect rect, BView* parent); + virtual void SetData(char *data, const size_t &length); + +private: + BBitmap *fBitmap; +}; + +class IntegerPreviewField : public PreviewField +{ +public: + IntegerPreviewField(const int64 &value); + virtual ~IntegerPreviewField(void); + virtual void DrawField(BRect rect, BView* parent); + virtual void SetData(char *data, const size_t &length); + +private: + int64 fValue; +}; + + +class StringPreviewField : public PreviewField +{ +public: + StringPreviewField(const char *string); + virtual ~StringPreviewField(void); + virtual void DrawField(BRect rect, BView* parent); + virtual void SetData(char *data, const size_t &length); + +private: + BString fString; + BString fClipped; +}; + +BString MakeTypeString(int32 type); + +#endif