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