1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 // defines the status area drawn in the bottom left corner of a Tracker window 36 37 38 #include "CountView.h" 39 40 #include <Application.h> 41 #include <Catalog.h> 42 #include <ControlLook.h> 43 #include <Locale.h> 44 45 #include "AutoLock.h" 46 #include "Bitmaps.h" 47 #include "ContainerWindow.h" 48 #include "DirMenu.h" 49 #include "PoseView.h" 50 #include "Utilities.h" 51 52 53 #undef B_TRANSLATION_CONTEXT 54 #define B_TRANSLATION_CONTEXT "CountView" 55 56 57 const bigtime_t kBarberPoleDelay = 500000; 58 59 60 // #pragma mark - BCountView 61 62 63 BCountView::BCountView(BRect bounds, BPoseView* view) 64 : 65 BView(bounds, "CountVw", B_FOLLOW_LEFT + B_FOLLOW_BOTTOM, 66 B_PULSE_NEEDED | B_WILL_DRAW), 67 fLastCount(-1), 68 fPoseView(view), 69 fShowingBarberPole(false), 70 fBorderHighlighted(false), 71 fBarberPoleMap(NULL), 72 fLastBarberPoleOffset(5), 73 fStartSpinningAfter(0), 74 fTypeAheadString(""), 75 fFilterString("") 76 { 77 GetTrackerResources()->GetBitmapResource(B_MESSAGE_TYPE, 78 R_BarberPoleBitmap, &fBarberPoleMap); 79 } 80 81 82 BCountView::~BCountView() 83 { 84 delete fBarberPoleMap; 85 } 86 87 88 void 89 BCountView::TrySpinningBarberPole() 90 { 91 if (!fShowingBarberPole) 92 return; 93 94 if (fStartSpinningAfter && system_time() < fStartSpinningAfter) 95 return; 96 97 // When the barber pole just starts spinning we need to invalidate 98 // the whole rectangle of text and barber pole. 99 // After this the text needs no updating since only the pole changes. 100 if (fStartSpinningAfter) { 101 fStartSpinningAfter = 0; 102 Invalidate(TextAndBarberPoleRect()); 103 } else 104 Invalidate(BarberPoleInnerRect()); 105 } 106 107 108 void 109 BCountView::Pulse() 110 { 111 TrySpinningBarberPole(); 112 } 113 114 115 void 116 BCountView::WindowActivated(bool active) 117 { 118 if (fBorderHighlighted) { 119 BRect dirty(Bounds()); 120 dirty.bottom = dirty.top; 121 Invalidate(dirty); 122 } 123 } 124 125 126 void 127 BCountView::EndBarberPole() 128 { 129 if (!fShowingBarberPole) 130 return; 131 132 fShowingBarberPole = false; 133 Invalidate(); 134 } 135 136 137 void 138 BCountView::StartBarberPole() 139 { 140 AutoLock<BWindow> lock(Window()); 141 if (fShowingBarberPole) 142 return; 143 144 fShowingBarberPole = true; 145 fStartSpinningAfter = system_time() + kBarberPoleDelay; 146 // wait a bit before showing the barber pole 147 } 148 149 150 BRect 151 BCountView::BarberPoleInnerRect() const 152 { 153 BRect result = Bounds(); 154 result.InsetBy(3, 4); 155 result.left = result.right - 7; 156 result.bottom = result.top + 7; 157 return result; 158 } 159 160 161 BRect 162 BCountView::BarberPoleOuterRect() const 163 { 164 BRect result(BarberPoleInnerRect()); 165 result.InsetBy(-1, -1); 166 return result; 167 } 168 169 170 BRect 171 BCountView::TextInvalRect() const 172 { 173 BRect result = Bounds(); 174 result.InsetBy(4, 2); 175 176 // if the barber pole is not present, use its space for text 177 if (fShowingBarberPole) 178 result.right -= 10; 179 180 return result; 181 } 182 183 184 BRect 185 BCountView::TextAndBarberPoleRect() const 186 { 187 BRect result = Bounds(); 188 result.InsetBy(4, 2); 189 190 return result; 191 } 192 193 194 void 195 BCountView::CheckCount() 196 { 197 // invalidate the count text area if necessary 198 if (fLastCount != fPoseView->CountItems()) { 199 fLastCount = fPoseView->CountItems(); 200 Invalidate(TextInvalRect()); 201 } 202 203 // invalidate barber pole area if necessary 204 TrySpinningBarberPole(); 205 } 206 207 208 void 209 BCountView::Draw(BRect updateRect) 210 { 211 BRect bounds(Bounds()); 212 213 if (be_control_look != NULL) { 214 rgb_color base = ViewColor(); 215 if (fBorderHighlighted && Window()->IsActive()) 216 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 217 else 218 SetHighColor(tint_color(base, B_DARKEN_2_TINT)); 219 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 220 bounds.top++; 221 be_control_look->DrawMenuBarBackground(this, bounds, updateRect, 222 ViewColor()); 223 } 224 225 BString itemString; 226 if (IsTypingAhead()) 227 itemString << TypeAhead(); 228 else if (IsFiltering()) { 229 itemString << fLastCount << " " << Filter(); 230 } else { 231 if (fLastCount == 0) 232 itemString << B_TRANSLATE("no items"); 233 else if (fLastCount == 1) 234 itemString << B_TRANSLATE("1 item"); 235 else { 236 itemString.SetTo(B_TRANSLATE("%num items")); 237 char numString[256]; 238 snprintf(numString, sizeof(numString), "%" B_PRId32, fLastCount); 239 itemString.ReplaceFirst("%num", numString); 240 } 241 } 242 243 BRect textRect(TextInvalRect()); 244 245 TruncateString(&itemString, IsTypingAhead() ? B_TRUNCATE_BEGINNING 246 : IsFiltering() ? B_TRUNCATE_MIDDLE : B_TRUNCATE_END, 247 textRect.Width()); 248 249 if (IsTypingAhead()) { 250 // use a muted gray for the typeahead 251 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 252 B_DARKEN_4_TINT)); 253 } else 254 SetHighColor(0, 0, 0); 255 256 MovePenTo(textRect.LeftBottom()); 257 DrawString(itemString.String()); 258 259 bounds.top++; 260 261 rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT); 262 rgb_color shadow = tint_color(ViewColor(), B_DARKEN_2_TINT); 263 rgb_color lightShadow = tint_color(ViewColor(), B_DARKEN_1_TINT); 264 265 BeginLineArray(fShowingBarberPole && !fStartSpinningAfter ? 9 : 5); 266 267 if (be_control_look == NULL) { 268 AddLine(bounds.LeftTop(), bounds.RightTop(), light); 269 AddLine(bounds.LeftTop(), bounds.LeftBottom(), light); 270 bounds.top--; 271 272 AddLine(bounds.LeftTop(), bounds.RightTop(), shadow); 273 AddLine(BPoint(bounds.right, bounds.top + 2), bounds.RightBottom(), 274 lightShadow); 275 AddLine(bounds.LeftBottom(), bounds.RightBottom(), lightShadow); 276 } 277 278 if (!fShowingBarberPole || fStartSpinningAfter) { 279 EndLineArray(); 280 return; 281 } 282 283 BRect barberPoleRect(BarberPoleOuterRect()); 284 285 AddLine(barberPoleRect.LeftTop(), barberPoleRect.RightTop(), shadow); 286 AddLine(barberPoleRect.LeftTop(), barberPoleRect.LeftBottom(), shadow); 287 AddLine(barberPoleRect.LeftBottom(), barberPoleRect.RightBottom(), light); 288 AddLine(barberPoleRect.RightBottom(), barberPoleRect.RightTop(), light); 289 EndLineArray(); 290 291 barberPoleRect.InsetBy(1, 1); 292 293 BRect destRect(fBarberPoleMap 294 ? fBarberPoleMap->Bounds() : BRect(0, 0, 0, 0)); 295 destRect.OffsetTo(barberPoleRect.LeftTop() 296 - BPoint(0, fLastBarberPoleOffset)); 297 fLastBarberPoleOffset -= 1; 298 if (fLastBarberPoleOffset < 0) 299 fLastBarberPoleOffset = 5; 300 301 BRegion region; 302 region.Set(BarberPoleInnerRect()); 303 ConstrainClippingRegion(®ion); 304 305 if (fBarberPoleMap) 306 DrawBitmap(fBarberPoleMap, destRect); 307 } 308 309 310 void 311 BCountView::MouseDown(BPoint) 312 { 313 BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window()); 314 window->Activate(); 315 window->UpdateIfNeeded(); 316 317 if (fPoseView->IsFilePanel() || fPoseView->TargetModel() == NULL) 318 return; 319 320 if (!window->TargetModel()->IsRoot()) { 321 BDirMenu* menu = new BDirMenu(NULL, be_app, B_REFS_RECEIVED); 322 BEntry entry; 323 if (entry.SetTo(window->TargetModel()->EntryRef()) == B_OK) 324 menu->Populate(&entry, Window(), false, false, true, false, true); 325 else 326 menu->Populate(NULL, Window(), false, false, true, false, true); 327 328 BPoint point = Bounds().LeftBottom(); 329 point.y += 3; 330 ConvertToScreen(&point); 331 BRect clickToOpenRect(Bounds()); 332 ConvertToScreen(&clickToOpenRect); 333 menu->Go(point, true, true, clickToOpenRect); 334 delete menu; 335 } 336 } 337 338 339 void 340 BCountView::AttachedToWindow() 341 { 342 SetFont(be_plain_font); 343 SetFontSize(9); 344 345 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 346 SetLowColor(ViewColor()); 347 348 CheckCount(); 349 } 350 351 352 void 353 BCountView::SetTypeAhead(const char* string) 354 { 355 fTypeAheadString = string; 356 Invalidate(); 357 } 358 359 360 const char* 361 BCountView::TypeAhead() const 362 { 363 return fTypeAheadString.String(); 364 } 365 366 367 bool 368 BCountView::IsTypingAhead() const 369 { 370 return fTypeAheadString.Length() != 0; 371 } 372 373 374 void 375 BCountView::AddFilterCharacter(const char* character) 376 { 377 fFilterString.AppendChars(character, 1); 378 Invalidate(); 379 } 380 381 382 void 383 BCountView::RemoveFilterCharacter() 384 { 385 fFilterString.TruncateChars(fFilterString.CountChars() - 1); 386 Invalidate(); 387 } 388 389 390 void 391 BCountView::CancelFilter() 392 { 393 fFilterString.Truncate(0); 394 Invalidate(); 395 } 396 397 398 const char* 399 BCountView::Filter() const 400 { 401 return fFilterString.String(); 402 } 403 404 405 bool 406 BCountView::IsFiltering() const 407 { 408 return fFilterString.Length() > 0; 409 } 410 411 412 void 413 BCountView::SetBorderHighlighted(bool highlighted) 414 { 415 if (fBorderHighlighted == highlighted) 416 return; 417 418 fBorderHighlighted = highlighted; 419 BRect dirty(Bounds()); 420 dirty.bottom = dirty.top; 421 Invalidate(dirty); 422 } 423