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 #include "CountView.h" 38 39 #include <Application.h> 40 #include <Catalog.h> 41 #include <ControlLook.h> 42 #include <Locale.h> 43 44 #include "AutoLock.h" 45 #include "Bitmaps.h" 46 #include "ContainerWindow.h" 47 #include "DirMenu.h" 48 #include "PoseView.h" 49 #include "Utilities.h" 50 51 52 const bigtime_t kBarberPoleDelay = 500000; 53 54 55 #undef B_TRANSLATION_CONTEXT 56 #define B_TRANSLATION_CONTEXT "CountView" 57 58 BCountView::BCountView(BRect bounds, BPoseView* view) 59 : BView(bounds, "CountVw", B_FOLLOW_LEFT + B_FOLLOW_BOTTOM, 60 B_PULSE_NEEDED | B_WILL_DRAW), 61 fLastCount(-1), 62 fPoseView(view), 63 fShowingBarberPole(false), 64 fBorderHighlighted(false), 65 fBarberPoleMap(NULL), 66 fLastBarberPoleOffset(5), 67 fStartSpinningAfter(0), 68 fTypeAheadString(""), 69 fFilterString("") 70 { 71 GetTrackerResources()->GetBitmapResource(B_MESSAGE_TYPE, 72 R_BarberPoleBitmap, &fBarberPoleMap); 73 } 74 75 76 BCountView::~BCountView() 77 { 78 delete fBarberPoleMap; 79 } 80 81 82 void 83 BCountView::TrySpinningBarberPole() 84 { 85 if (!fShowingBarberPole) 86 return; 87 88 if (fStartSpinningAfter && system_time() < fStartSpinningAfter) 89 return; 90 91 // When the barber pole just starts spinning we need to invalidate 92 // the whole rectangle of text and barber pole. 93 // After this the text needs no updating since only the pole changes. 94 if (fStartSpinningAfter) { 95 fStartSpinningAfter = 0; 96 Invalidate(TextAndBarberPoleRect()); 97 } else 98 Invalidate(BarberPoleInnerRect()); 99 } 100 101 102 void 103 BCountView::Pulse() 104 { 105 TrySpinningBarberPole(); 106 } 107 108 109 void 110 BCountView::WindowActivated(bool active) 111 { 112 if (fBorderHighlighted) { 113 BRect dirty(Bounds()); 114 dirty.bottom = dirty.top; 115 Invalidate(dirty); 116 } 117 } 118 119 120 void 121 BCountView::EndBarberPole() 122 { 123 if (!fShowingBarberPole) 124 return; 125 126 fShowingBarberPole = false; 127 Invalidate(); 128 } 129 130 131 void 132 BCountView::StartBarberPole() 133 { 134 AutoLock<BWindow> lock(Window()); 135 if (fShowingBarberPole) 136 return; 137 138 fShowingBarberPole = true; 139 fStartSpinningAfter = system_time() + kBarberPoleDelay; 140 // wait a bit before showing the barber pole 141 } 142 143 144 BRect 145 BCountView::BarberPoleInnerRect() const 146 { 147 BRect result = Bounds(); 148 result.InsetBy(3, 4); 149 result.left = result.right - 7; 150 result.bottom = result.top + 7; 151 return result; 152 } 153 154 155 BRect 156 BCountView::BarberPoleOuterRect() const 157 { 158 BRect result(BarberPoleInnerRect()); 159 result.InsetBy(-1, -1); 160 return result; 161 } 162 163 164 BRect 165 BCountView::TextInvalRect() const 166 { 167 BRect result = Bounds(); 168 result.InsetBy(4, 2); 169 170 // if the barber pole is not present, use its space for text 171 if (fShowingBarberPole) 172 result.right -= 10; 173 174 return result; 175 } 176 177 178 BRect 179 BCountView::TextAndBarberPoleRect() const 180 { 181 BRect result = Bounds(); 182 result.InsetBy(4, 2); 183 184 return result; 185 } 186 187 188 void 189 BCountView::CheckCount() 190 { 191 // invalidate the count text area if necessary 192 if (fLastCount != fPoseView->CountItems()) { 193 fLastCount = fPoseView->CountItems(); 194 Invalidate(TextInvalRect()); 195 } 196 197 // invalidate barber pole area if necessary 198 TrySpinningBarberPole(); 199 } 200 201 202 void 203 BCountView::Draw(BRect updateRect) 204 { 205 BRect bounds(Bounds()); 206 207 if (be_control_look != NULL) { 208 rgb_color base = ViewColor(); 209 if (fBorderHighlighted && Window()->IsActive()) 210 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 211 else 212 SetHighColor(tint_color(base, B_DARKEN_2_TINT)); 213 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 214 bounds.top++; 215 be_control_look->DrawMenuBarBackground(this, bounds, updateRect, 216 ViewColor()); 217 } 218 219 BString itemString; 220 if (IsTypingAhead()) 221 itemString << TypeAhead(); 222 else if (IsFiltering()) { 223 itemString << fLastCount << " " << Filter(); 224 } else { 225 if (fLastCount == 0) 226 itemString << B_TRANSLATE("no items"); 227 else if (fLastCount == 1) 228 itemString << B_TRANSLATE("1 item"); 229 else { 230 itemString.SetTo(B_TRANSLATE("%num items")); 231 char numString[256]; 232 snprintf(numString, sizeof(numString), "%" B_PRId32, fLastCount); 233 itemString.ReplaceFirst("%num", numString); 234 } 235 } 236 237 BRect textRect(TextInvalRect()); 238 239 TruncateString(&itemString, IsTypingAhead() ? B_TRUNCATE_BEGINNING 240 : IsFiltering() ? B_TRUNCATE_MIDDLE : B_TRUNCATE_END, 241 textRect.Width()); 242 243 if (IsTypingAhead()) { 244 // use a muted gray for the typeahead 245 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 246 B_DARKEN_4_TINT)); 247 } else 248 SetHighColor(0, 0, 0); 249 250 MovePenTo(textRect.LeftBottom()); 251 DrawString(itemString.String()); 252 253 bounds.top++; 254 255 rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT); 256 rgb_color shadow = tint_color(ViewColor(), B_DARKEN_2_TINT); 257 rgb_color lightShadow = tint_color(ViewColor(), B_DARKEN_1_TINT); 258 259 BeginLineArray(fShowingBarberPole && !fStartSpinningAfter ? 9 : 5); 260 261 if (be_control_look == NULL) { 262 AddLine(bounds.LeftTop(), bounds.RightTop(), light); 263 AddLine(bounds.LeftTop(), bounds.LeftBottom(), light); 264 bounds.top--; 265 266 AddLine(bounds.LeftTop(), bounds.RightTop(), shadow); 267 AddLine(BPoint(bounds.right, bounds.top + 2), bounds.RightBottom(), 268 lightShadow); 269 AddLine(bounds.LeftBottom(), bounds.RightBottom(), lightShadow); 270 } 271 272 if (!fShowingBarberPole || fStartSpinningAfter) { 273 EndLineArray(); 274 return; 275 } 276 277 BRect barberPoleRect(BarberPoleOuterRect()); 278 279 AddLine(barberPoleRect.LeftTop(), barberPoleRect.RightTop(), shadow); 280 AddLine(barberPoleRect.LeftTop(), barberPoleRect.LeftBottom(), shadow); 281 AddLine(barberPoleRect.LeftBottom(), barberPoleRect.RightBottom(), light); 282 AddLine(barberPoleRect.RightBottom(), barberPoleRect.RightTop(), light); 283 EndLineArray(); 284 285 barberPoleRect.InsetBy(1, 1); 286 287 BRect destRect(fBarberPoleMap 288 ? fBarberPoleMap->Bounds() : BRect(0, 0, 0, 0)); 289 destRect.OffsetTo(barberPoleRect.LeftTop() 290 - BPoint(0, fLastBarberPoleOffset)); 291 fLastBarberPoleOffset -= 1; 292 if (fLastBarberPoleOffset < 0) 293 fLastBarberPoleOffset = 5; 294 295 BRegion region; 296 region.Set(BarberPoleInnerRect()); 297 ConstrainClippingRegion(®ion); 298 299 if (fBarberPoleMap) 300 DrawBitmap(fBarberPoleMap, destRect); 301 } 302 303 304 void 305 BCountView::MouseDown(BPoint) 306 { 307 BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window()); 308 window->Activate(); 309 window->UpdateIfNeeded(); 310 311 if (fPoseView->IsFilePanel() || !fPoseView->TargetModel()) 312 return; 313 314 if (!window->TargetModel()->IsRoot()) { 315 BDirMenu* menu = new BDirMenu(NULL, be_app, B_REFS_RECEIVED); 316 BEntry entry; 317 if (entry.SetTo(window->TargetModel()->EntryRef()) == B_OK) 318 menu->Populate(&entry, Window(), false, false, true, false, true); 319 else 320 menu->Populate(NULL, Window(), false, false, true, false, true); 321 322 BPoint point = Bounds().LeftBottom(); 323 point.y += 3; 324 ConvertToScreen(&point); 325 BRect clickToOpenRect(Bounds()); 326 ConvertToScreen(&clickToOpenRect); 327 menu->Go(point, true, true, clickToOpenRect); 328 delete menu; 329 } 330 } 331 332 333 void 334 BCountView::AttachedToWindow() 335 { 336 SetFont(be_plain_font); 337 SetFontSize(9); 338 339 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 340 SetLowColor(ViewColor()); 341 342 CheckCount(); 343 } 344 345 346 void 347 BCountView::SetTypeAhead(const char* string) 348 { 349 fTypeAheadString = string; 350 Invalidate(); 351 } 352 353 354 const char* 355 BCountView::TypeAhead() const 356 { 357 return fTypeAheadString.String(); 358 } 359 360 361 bool 362 BCountView::IsTypingAhead() const 363 { 364 return fTypeAheadString.Length() != 0; 365 } 366 367 368 void 369 BCountView::AddFilterCharacter(const char* character) 370 { 371 fFilterString.AppendChars(character, 1); 372 Invalidate(); 373 } 374 375 376 void 377 BCountView::RemoveFilterCharacter() 378 { 379 fFilterString.TruncateChars(fFilterString.CountChars() - 1); 380 Invalidate(); 381 } 382 383 384 void 385 BCountView::CancelFilter() 386 { 387 fFilterString.Truncate(0); 388 Invalidate(); 389 } 390 391 392 const char* 393 BCountView::Filter() const 394 { 395 return fFilterString.String(); 396 } 397 398 399 bool 400 BCountView::IsFiltering() const 401 { 402 return fFilterString.Length() > 0; 403 } 404 405 406 void 407 BCountView::SetBorderHighlighted(bool highlighted) 408 { 409 if (fBorderHighlighted == highlighted) 410 return; 411 412 fBorderHighlighted = highlighted; 413 BRect dirty(Bounds()); 414 dirty.bottom = dirty.top; 415 Invalidate(dirty); 416 } 417