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 <StringFormat.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 static const float kMinFontSize = 8.0f; 60 61 62 // #pragma mark - BCountView 63 64 65 BCountView::BCountView(BPoseView* view) 66 : 67 BView("CountVw", B_PULSE_NEEDED | B_WILL_DRAW), 68 fLastCount(-1), 69 fPoseView(view), 70 fShowingBarberPole(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::EndBarberPole() 117 { 118 if (!fShowingBarberPole) 119 return; 120 121 fShowingBarberPole = false; 122 Invalidate(); 123 } 124 125 126 void 127 BCountView::StartBarberPole() 128 { 129 AutoLock<BWindow> lock(Window()); 130 if (fShowingBarberPole) 131 return; 132 133 fShowingBarberPole = true; 134 fStartSpinningAfter = system_time() + kBarberPoleDelay; 135 // wait a bit before showing the barber pole 136 } 137 138 139 BRect 140 BCountView::BarberPoleInnerRect() const 141 { 142 BRect result = Bounds(); 143 result.InsetBy(3, 4); 144 result.left = result.right - 7; 145 result.bottom = result.top + 7; 146 return result; 147 } 148 149 150 BRect 151 BCountView::BarberPoleOuterRect() const 152 { 153 BRect result(BarberPoleInnerRect()); 154 result.InsetBy(-1, -1); 155 return result; 156 } 157 158 159 BRect 160 BCountView::TextInvalRect() const 161 { 162 BRect result = TextAndBarberPoleRect(); 163 164 // if the barber pole is not present, use its space for text 165 if (fShowingBarberPole) 166 result.right -= 10; 167 168 return result; 169 } 170 171 172 BRect 173 BCountView::TextAndBarberPoleRect() const 174 { 175 BRect result = Bounds(); 176 result.InsetBy(be_control_look->ComposeSpacing(B_USE_SMALL_SPACING) / 2, 177 floorf(result.Height() * 0.25f)); 178 179 return result; 180 } 181 182 183 void 184 BCountView::CheckCount() 185 { 186 // invalidate the count text area if necessary 187 if (fLastCount != fPoseView->CountItems()) { 188 fLastCount = fPoseView->CountItems(); 189 Invalidate(TextInvalRect()); 190 } 191 192 // invalidate barber pole area if necessary 193 TrySpinningBarberPole(); 194 } 195 196 197 void 198 BCountView::Draw(BRect updateRect) 199 { 200 BRect bounds(Bounds()); 201 202 rgb_color color = ViewColor(); 203 if (IsTypingAhead()) 204 color = ui_color(B_DOCUMENT_BACKGROUND_COLOR); 205 206 SetLowColor(color); 207 be_control_look->DrawBorder(this, bounds, updateRect, 208 color, B_PLAIN_BORDER, 0, 209 BControlLook::B_BOTTOM_BORDER | BControlLook::B_LEFT_BORDER); 210 be_control_look->DrawMenuBarBackground(this, bounds, updateRect, color); 211 212 BString itemString; 213 if (IsTypingAhead()) 214 itemString << TypeAhead(); 215 else if (IsFiltering()) { 216 itemString << fLastCount << " " << Filter(); 217 } else { 218 if (fLastCount == 0) 219 itemString << B_TRANSLATE("no items"); 220 else { 221 static BStringFormat format(B_TRANSLATE_COMMENT( 222 "{0, plural, one{# item} other{# items}}", 223 "Number of selected items: \"1 item\" or \"2 items\"")); 224 format.Format(itemString, fLastCount); 225 } 226 } 227 228 BRect textRect(TextInvalRect()); 229 230 TruncateString(&itemString, IsTypingAhead() ? B_TRUNCATE_BEGINNING 231 : IsFiltering() ? B_TRUNCATE_MIDDLE : B_TRUNCATE_END, 232 textRect.Width()); 233 234 if (IsTypingAhead()) { 235 // use a muted gray for the typeahead 236 SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR)); 237 } else 238 SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 239 240 MovePenTo(textRect.LeftBottom()); 241 DrawString(itemString.String()); 242 243 bounds.top++; 244 245 rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT); 246 rgb_color shadow = tint_color(ViewColor(), B_DARKEN_2_TINT); 247 248 BeginLineArray(fShowingBarberPole && !fStartSpinningAfter ? 9 : 5); 249 250 if (!fShowingBarberPole || fStartSpinningAfter) { 251 EndLineArray(); 252 return; 253 } 254 255 BRect barberPoleRect(BarberPoleOuterRect()); 256 257 AddLine(barberPoleRect.LeftTop(), barberPoleRect.RightTop(), shadow); 258 AddLine(barberPoleRect.LeftTop(), barberPoleRect.LeftBottom(), shadow); 259 AddLine(barberPoleRect.LeftBottom(), barberPoleRect.RightBottom(), light); 260 AddLine(barberPoleRect.RightBottom(), barberPoleRect.RightTop(), light); 261 EndLineArray(); 262 263 barberPoleRect.InsetBy(1, 1); 264 265 BRect destRect(fBarberPoleMap 266 ? fBarberPoleMap->Bounds() : BRect(0, 0, 0, 0)); 267 destRect.OffsetTo(barberPoleRect.LeftTop() 268 - BPoint(0, fLastBarberPoleOffset)); 269 fLastBarberPoleOffset -= 1; 270 if (fLastBarberPoleOffset < 0) 271 fLastBarberPoleOffset = 5; 272 273 BRegion region; 274 region.Set(BarberPoleInnerRect()); 275 ConstrainClippingRegion(®ion); 276 277 if (fBarberPoleMap) 278 DrawBitmap(fBarberPoleMap, destRect); 279 } 280 281 282 void 283 BCountView::MouseDown(BPoint) 284 { 285 BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window()); 286 ThrowOnAssert(window != NULL); 287 288 window->Activate(); 289 window->UpdateIfNeeded(); 290 291 if (fPoseView->IsFilePanel() || fPoseView->TargetModel() == NULL) 292 return; 293 294 if (!window->TargetModel()->IsRoot()) { 295 BDirMenu* menu = new BDirMenu(NULL, be_app, B_REFS_RECEIVED); 296 BEntry entry; 297 if (entry.SetTo(window->TargetModel()->EntryRef()) == B_OK) 298 menu->Populate(&entry, Window(), false, false, true, false, true); 299 else 300 menu->Populate(NULL, Window(), false, false, true, false, true); 301 302 BPoint point = Bounds().LeftBottom(); 303 point.y += 3; 304 ConvertToScreen(&point); 305 BRect clickToOpenRect(Bounds()); 306 ConvertToScreen(&clickToOpenRect); 307 menu->Go(point, true, true, clickToOpenRect); 308 delete menu; 309 } 310 } 311 312 313 void 314 BCountView::AttachedToWindow() 315 { 316 SetFont(be_plain_font); 317 SetFontSize(std::max(kMinFontSize, 318 ceilf(be_plain_font->Size() * 0.75f))); 319 320 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 321 SetLowUIColor(ViewUIColor()); 322 323 CheckCount(); 324 } 325 326 327 void 328 BCountView::SetTypeAhead(const char* string) 329 { 330 fTypeAheadString = string; 331 Invalidate(); 332 } 333 334 335 const char* 336 BCountView::TypeAhead() const 337 { 338 return fTypeAheadString.String(); 339 } 340 341 342 bool 343 BCountView::IsTypingAhead() const 344 { 345 return fTypeAheadString.Length() != 0; 346 } 347 348 349 void 350 BCountView::AddFilterCharacter(const char* character) 351 { 352 fFilterString.AppendChars(character, 1); 353 Invalidate(); 354 } 355 356 357 void 358 BCountView::RemoveFilterCharacter() 359 { 360 fFilterString.TruncateChars(fFilterString.CountChars() - 1); 361 Invalidate(); 362 } 363 364 365 void 366 BCountView::CancelFilter() 367 { 368 fFilterString.Truncate(0); 369 Invalidate(); 370 } 371 372 373 const char* 374 BCountView::Filter() const 375 { 376 return fFilterString.String(); 377 } 378 379 380 bool 381 BCountView::IsFiltering() const 382 { 383 return fFilterString.Length() > 0; 384 } 385