1 /*****************************************************************************/ 2 // ShowImageView 3 // Written by Fernando Francisco de Oliveira, Michael Wilber 4 // 5 // ShowImageView.cpp 6 // 7 // 8 // Copyright (c) 2003 OpenBeOS Project 9 // 10 // Permission is hereby granted, free of charge, to any person obtaining a 11 // copy of this software and associated documentation files (the "Software"), 12 // to deal in the Software without restriction, including without limitation 13 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 14 // and/or sell copies of the Software, and to permit persons to whom the 15 // Software is furnished to do so, subject to the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be included 18 // in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 // DEALINGS IN THE SOFTWARE. 27 /*****************************************************************************/ 28 29 #include <stdio.h> 30 #include <Message.h> 31 #include <ScrollBar.h> 32 #include <StopWatch.h> 33 #include <Alert.h> 34 #include <MenuBar.h> 35 #include <MenuItem.h> 36 #include <File.h> 37 #include <Bitmap.h> 38 #include <TranslatorRoster.h> 39 #include <BitmapStream.h> 40 #include <Rect.h> 41 #include <SupportDefs.h> 42 43 #include "ShowImageConstants.h" 44 #include "ShowImageView.h" 45 46 #ifndef min 47 #define min(a,b) ((a)>(b)?(b):(a)) 48 #endif 49 #ifndef max 50 #define max(a,b) ((a)>(b)?(a):(b)) 51 #endif 52 53 #define BORDER_WIDTH 16 54 #define BORDER_HEIGHT 16 55 #define PEN_SIZE 1.0f 56 const rgb_color kborderColor = { 0, 0, 0, 255 }; 57 58 ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode, 59 uint32 flags) 60 : BView(rect, name, resizingMode, flags) 61 { 62 fpbitmap = NULL; 63 fdocumentIndex = 1; 64 fdocumentCount = 1; 65 fbhasSelection = false; 66 67 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 68 SetHighColor(kborderColor); 69 SetPenSize(PEN_SIZE); 70 } 71 72 ShowImageView::~ShowImageView() 73 { 74 delete fpbitmap; 75 fpbitmap = NULL; 76 } 77 78 void 79 ShowImageView::SetImage(const entry_ref *pref) 80 { 81 ClearViewBitmap(); 82 delete fpbitmap; 83 fpbitmap = NULL; 84 85 entry_ref ref; 86 if (!pref) 87 ref = fcurrentRef; 88 else 89 ref = *pref; 90 91 BTranslatorRoster *proster = BTranslatorRoster::Default(); 92 if (!proster) 93 return; 94 BFile file(&ref, B_READ_ONLY); 95 translator_info info; 96 memset(&info, 0, sizeof(translator_info)); 97 BMessage ioExtension; 98 if (ref != fcurrentRef) 99 // if new image, reset to first document 100 fdocumentIndex = 1; 101 if (ioExtension.AddInt32("/documentIndex", fdocumentIndex) != B_OK) 102 return; 103 if (proster->Identify(&file, &ioExtension, &info, 0, NULL, 104 B_TRANSLATOR_BITMAP) != B_OK) 105 return; 106 107 // Translate image data and create a new ShowImage window 108 BBitmapStream outstream; 109 if (proster->Translate(&file, &info, &ioExtension, &outstream, 110 B_TRANSLATOR_BITMAP) != B_OK) 111 return; 112 if (outstream.DetachBitmap(&fpbitmap) != B_OK) 113 return; 114 fcurrentRef = ref; 115 116 // get the number of documents (pages) if it has been supplied 117 int32 documentCount = 0; 118 if (ioExtension.FindInt32("/documentCount", &documentCount) == B_OK && 119 documentCount > 0) 120 fdocumentCount = documentCount; 121 else 122 fdocumentCount = 1; 123 124 // send message to parent about new image 125 BMessage msg(MSG_UPDATE_STATUS); 126 msg.AddString("status", info.name); 127 BMessenger msgr(Window()); 128 msgr.SendMessage(&msg); 129 130 SetViewBitmap(fpbitmap, fpbitmap->Bounds(), 131 BRect(BORDER_WIDTH, BORDER_HEIGHT, 132 fpbitmap->Bounds().Width() + BORDER_WIDTH, 133 fpbitmap->Bounds().Height() + BORDER_HEIGHT), 134 B_FOLLOW_TOP | B_FOLLOW_LEFT, 0 135 ); 136 137 FixupScrollBars(); 138 Invalidate(); 139 } 140 141 BBitmap * 142 ShowImageView::GetBitmap() 143 { 144 return fpbitmap; 145 } 146 147 void 148 ShowImageView::AttachedToWindow() 149 { 150 FixupScrollBars(); 151 } 152 153 void 154 ShowImageView::Draw(BRect updateRect) 155 { 156 if (fpbitmap) { 157 // Draw black rectangle around image 158 StrokeRect( 159 BRect(BORDER_WIDTH - PEN_SIZE, 160 BORDER_HEIGHT - PEN_SIZE, 161 fpbitmap->Bounds().Width() + BORDER_WIDTH + PEN_SIZE, 162 fpbitmap->Bounds().Height() + BORDER_HEIGHT + PEN_SIZE)); 163 164 if (fbhasSelection) 165 DrawSelectionBox(fselectionRect); 166 } 167 } 168 169 void 170 ShowImageView::DrawSelectionBox(BRect &rect) 171 { 172 // TODO: Make my own pattern to mimic the 173 // marching ants in Be's ShowImage? 174 175 StrokeRect(rect, B_MIXED_COLORS); 176 Sync(); 177 } 178 179 void 180 ShowImageView::ClearSelectionBox(BRect &rect) 181 { 182 BRect bitmapRect = rect; 183 if (!bitmapRect.IsValid()) 184 printf("Invalid Rect\n"); 185 186 bitmapRect.OffsetBy(-(BORDER_WIDTH), -(BORDER_HEIGHT)); 187 DrawBitmapAsync(fpbitmap, bitmapRect, rect); 188 // don't draw the bitmap immediately, more drawing 189 // almost always comes after this function is used 190 } 191 192 void 193 ShowImageView::FrameResized(float /* width */, float /* height */) 194 { 195 FixupScrollBars(); 196 } 197 198 void 199 ShowImageView::ConstrainToImage(BPoint &point) 200 { 201 point.ConstrainTo( 202 BRect( 203 BORDER_WIDTH, BORDER_HEIGHT, 204 fpbitmap->Bounds().Width() + BORDER_WIDTH, 205 fpbitmap->Bounds().Height() + BORDER_HEIGHT 206 ) 207 ); 208 } 209 210 void 211 ShowImageView::MouseDown(BPoint point) 212 { 213 // TODO: Need to handle the case where user clicks 214 // inside an existing selection and starts a drag operation 215 216 if (fbhasSelection) 217 ClearSelectionBox(fselectionRect); 218 219 fbhasSelection = false; 220 221 if (!fpbitmap) { 222 // Can't select anything if there is no image 223 Invalidate(); 224 return; 225 } 226 227 BPoint firstPoint, secondPoint; 228 firstPoint = point; 229 ConstrainToImage(firstPoint); 230 secondPoint = firstPoint; 231 232 BRect curSel, lastSel; 233 234 BMessage *pmsg = Window()->CurrentMessage(); 235 uint32 buttons = static_cast<uint32>(pmsg->FindInt32("buttons")); 236 bool bfirst = true; 237 // While any combination of mouse buttons is down, 238 // allow the user to size their selection. When all 239 // mouse buttons are up, the loop ends, and the selection 240 // has been made. 241 while (buttons) { 242 ConstrainToImage(secondPoint); 243 244 // make a BRect that passes IsValid() 245 curSel.left = min(firstPoint.x, secondPoint.x); 246 curSel.top = min(firstPoint.y, secondPoint.y); 247 curSel.right = max(firstPoint.x, secondPoint.x); 248 curSel.bottom = max(firstPoint.y, secondPoint.y); 249 250 if (!bfirst && curSel != lastSel) 251 ClearSelectionBox(lastSel); 252 if (curSel != lastSel) 253 DrawSelectionBox(curSel); 254 255 snooze(25 * 1000); 256 lastSel = curSel; 257 GetMouse(&secondPoint, &buttons); 258 bfirst = false; 259 } 260 261 if (curSel.IntegerWidth() < 2 && curSel.IntegerHeight() < 2) { 262 // The user must select at least 2 pixels 263 fbhasSelection = false; 264 Invalidate(); 265 } else { 266 fselectionRect = curSel; 267 fbhasSelection = true; 268 } 269 } 270 271 void 272 ShowImageView::MouseMoved(BPoint point, uint32 state, const BMessage *pmsg) 273 { 274 } 275 276 void 277 ShowImageView::MouseUp(BPoint point) 278 { 279 } 280 281 void 282 ShowImageView::MessageReceived(BMessage *pmsg) 283 { 284 switch (pmsg->what) { 285 default: 286 BView::MessageReceived(pmsg); 287 break; 288 } 289 } 290 291 void 292 ShowImageView::FixupScrollBars() 293 { 294 BRect rctview = Bounds(), rctbitmap(0, 0, 0, 0); 295 if (fpbitmap) 296 rctbitmap = fpbitmap->Bounds(); 297 298 float prop, range; 299 BScrollBar *psb = ScrollBar(B_HORIZONTAL); 300 if (psb) { 301 range = rctbitmap.Width() + (BORDER_WIDTH * 2) - rctview.Width(); 302 if (range < 0) range = 0; 303 prop = rctview.Width() / (rctbitmap.Width() + (BORDER_WIDTH * 2)); 304 if (prop > 1.0f) prop = 1.0f; 305 psb->SetRange(0, range); 306 psb->SetProportion(prop); 307 psb->SetSteps(10, 100); 308 } 309 310 psb = ScrollBar(B_VERTICAL); 311 if (psb) { 312 range = rctbitmap.Height() + (BORDER_HEIGHT * 2) - rctview.Height(); 313 if (range < 0) range = 0; 314 prop = rctview.Height() / (rctbitmap.Height() + (BORDER_HEIGHT * 2)); 315 if (prop > 1.0f) prop = 1.0f; 316 psb->SetRange(0, range); 317 psb->SetProportion(prop); 318 psb->SetSteps(10, 100); 319 } 320 } 321 322 int32 323 ShowImageView::CurrentPage() 324 { 325 return fdocumentIndex; 326 } 327 328 int32 329 ShowImageView::PageCount() 330 { 331 return fdocumentCount; 332 } 333 334 void 335 ShowImageView::FirstPage() 336 { 337 if (fdocumentIndex != 1) { 338 fdocumentIndex = 1; 339 SetImage(NULL); 340 } 341 } 342 343 void 344 ShowImageView::LastPage() 345 { 346 if (fdocumentIndex != fdocumentCount) { 347 fdocumentIndex = fdocumentCount; 348 SetImage(NULL); 349 } 350 } 351 352 void 353 ShowImageView::NextPage() 354 { 355 if (fdocumentIndex < fdocumentCount) { 356 fdocumentIndex++; 357 SetImage(NULL); 358 } 359 } 360 361 void 362 ShowImageView::PrevPage() 363 { 364 if (fdocumentIndex > 1) { 365 fdocumentIndex--; 366 SetImage(NULL); 367 } 368 } 369