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 <ControlLook.h> 41 42 #include "AutoLock.h" 43 #include "Bitmaps.h" 44 #include "ContainerWindow.h" 45 #include "DirMenu.h" 46 #include "PoseView.h" 47 48 49 const bigtime_t kBarberPoleDelay = 500000; 50 51 52 BCountView::BCountView(BRect bounds, BPoseView* view) 53 : BView(bounds, "CountVw", B_FOLLOW_LEFT + B_FOLLOW_BOTTOM, 54 B_PULSE_NEEDED | B_WILL_DRAW), 55 fLastCount(-1), 56 fPoseView(view), 57 fShowingBarberPole(false), 58 fBorderHighlighted(false), 59 fBarberPoleMap(NULL), 60 fLastBarberPoleOffset(5), 61 fStartSpinningAfter(0), 62 fTypeAheadString("") 63 { 64 GetTrackerResources()->GetBitmapResource(B_MESSAGE_TYPE, 65 kResBarberPoleBitmap, &fBarberPoleMap); 66 } 67 68 69 BCountView::~BCountView() 70 { 71 delete fBarberPoleMap; 72 } 73 74 75 void 76 BCountView::TrySpinningBarberPole() 77 { 78 if (!fShowingBarberPole) 79 return; 80 81 if (fStartSpinningAfter && system_time() < fStartSpinningAfter) 82 return; 83 84 // When the barber pole just starts spinning we need to invalidate 85 // the whole rectangle of text and barber pole. 86 // After this the text needs no updating since only the pole changes. 87 if (fStartSpinningAfter) { 88 fStartSpinningAfter = 0; 89 Invalidate(TextAndBarberPoleRect()); 90 } else 91 Invalidate(BarberPoleInnerRect()); 92 } 93 94 95 void 96 BCountView::Pulse() 97 { 98 TrySpinningBarberPole(); 99 } 100 101 102 void 103 BCountView::WindowActivated(bool active) 104 { 105 if (fBorderHighlighted) { 106 BRect dirty(Bounds()); 107 dirty.bottom = dirty.top; 108 Invalidate(dirty); 109 } 110 } 111 112 113 void 114 BCountView::EndBarberPole() 115 { 116 if (!fShowingBarberPole) 117 return; 118 119 fShowingBarberPole = false; 120 Invalidate(); 121 } 122 123 124 void 125 BCountView::StartBarberPole() 126 { 127 AutoLock<BWindow> lock(Window()); 128 if (fShowingBarberPole) 129 return; 130 131 fShowingBarberPole = true; 132 fStartSpinningAfter = system_time() + kBarberPoleDelay; 133 // wait a bit before showing the barber pole 134 } 135 136 137 BRect 138 BCountView::BarberPoleInnerRect() const 139 { 140 BRect result = Bounds(); 141 result.InsetBy(3, 4); 142 result.left = result.right - 7; 143 result.bottom = result.top + 7; 144 return result; 145 } 146 147 148 BRect 149 BCountView::BarberPoleOuterRect() const 150 { 151 BRect result(BarberPoleInnerRect()); 152 result.InsetBy(-1, -1); 153 return result; 154 } 155 156 157 BRect 158 BCountView::TextInvalRect() const 159 { 160 BRect result = Bounds(); 161 result.InsetBy(4, 2); 162 163 // if the barber pole is not present, use its space for text 164 if (fShowingBarberPole) 165 result.right -= 10; 166 167 return result; 168 } 169 170 171 BRect 172 BCountView::TextAndBarberPoleRect() const 173 { 174 BRect result = Bounds(); 175 result.InsetBy(4, 2); 176 177 return result; 178 } 179 180 181 void 182 BCountView::CheckCount() 183 { 184 // invalidate the count text area if necessary 185 if (fLastCount != fPoseView->CountItems()) { 186 fLastCount = fPoseView->CountItems(); 187 Invalidate(TextInvalRect()); 188 } 189 // invalidate barber pole area if necessary 190 TrySpinningBarberPole(); 191 } 192 193 194 void 195 BCountView::Draw(BRect updateRect) 196 { 197 BRect bounds(Bounds()); 198 199 if (be_control_look != NULL) { 200 rgb_color base = ViewColor(); 201 if (fBorderHighlighted && Window()->IsActive()) 202 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 203 else 204 SetHighColor(tint_color(base, B_DARKEN_2_TINT)); 205 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 206 bounds.top++; 207 be_control_look->DrawMenuBarBackground(this, bounds, updateRect, 208 ViewColor()); 209 } 210 211 BString itemString; 212 if (!IsTypingAhead()) { 213 if (fLastCount == 0) 214 itemString << "no items"; 215 else if (fLastCount == 1) 216 itemString << "1 item"; 217 else 218 itemString << fLastCount << " items"; 219 } else 220 itemString << TypeAhead(); 221 222 BString string(itemString); 223 BRect textRect(TextInvalRect()); 224 225 TruncateString(&string, B_TRUNCATE_END, textRect.Width()); 226 227 if (IsTypingAhead()) { 228 // use a muted gray for the typeahead 229 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_4_TINT)); 230 } else 231 SetHighColor(0, 0, 0); 232 233 MovePenTo(textRect.LeftBottom()); 234 DrawString(string.String()); 235 236 bounds.top++; 237 238 rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT); 239 rgb_color shadow = tint_color(ViewColor(), B_DARKEN_2_TINT); 240 rgb_color lightShadow = tint_color(ViewColor(), B_DARKEN_1_TINT); 241 242 BeginLineArray(fShowingBarberPole && !fStartSpinningAfter ? 9 : 5); 243 244 if (be_control_look == NULL) { 245 AddLine(bounds.LeftTop(), bounds.RightTop(), light); 246 AddLine(bounds.LeftTop(), bounds.LeftBottom(), light); 247 bounds.top--; 248 249 AddLine(bounds.LeftTop(), bounds.RightTop(), shadow); 250 AddLine(BPoint(bounds.right, bounds.top + 2), bounds.RightBottom(), lightShadow); 251 AddLine(bounds.LeftBottom(), bounds.RightBottom(), lightShadow); 252 } 253 254 if (!fShowingBarberPole || fStartSpinningAfter) { 255 EndLineArray(); 256 return; 257 } 258 259 BRect barberPoleRect(BarberPoleOuterRect()); 260 261 AddLine(barberPoleRect.LeftTop(), barberPoleRect.RightTop(), shadow); 262 AddLine(barberPoleRect.LeftTop(), barberPoleRect.LeftBottom(), shadow); 263 AddLine(barberPoleRect.LeftBottom(), barberPoleRect.RightBottom(), light); 264 AddLine(barberPoleRect.RightBottom(), barberPoleRect.RightTop(), light); 265 EndLineArray(); 266 267 barberPoleRect.InsetBy(1, 1); 268 269 BRect destRect(fBarberPoleMap ? fBarberPoleMap->Bounds() : BRect(0, 0, 0, 0)); 270 destRect.OffsetTo(barberPoleRect.LeftTop() - BPoint(0, fLastBarberPoleOffset)); 271 fLastBarberPoleOffset -= 1; 272 if (fLastBarberPoleOffset < 0) 273 fLastBarberPoleOffset = 5; 274 275 BRegion region; 276 region.Set(BarberPoleInnerRect()); 277 ConstrainClippingRegion(®ion); 278 279 if (fBarberPoleMap) 280 DrawBitmap(fBarberPoleMap, destRect); 281 } 282 283 284 void 285 BCountView::MouseDown(BPoint) 286 { 287 BContainerWindow *window = dynamic_cast<BContainerWindow *>(Window()); 288 window->Activate(); 289 window->UpdateIfNeeded(); 290 291 if (fPoseView->IsFilePanel() || !fPoseView->TargetModel()) 292 return; 293 294 if (!window->TargetModel()->IsRoot()) { 295 BDirMenu *menu = new BDirMenu(NULL, 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 menu->SetTargetForItems(be_app); 303 BPoint pop_pt = Bounds().LeftBottom(); 304 pop_pt.y += 3; 305 ConvertToScreen(&pop_pt); 306 BRect mouse_rect(Bounds()); 307 ConvertToScreen(&mouse_rect); 308 menu->Go(pop_pt, true, true, mouse_rect); 309 delete menu; 310 } 311 } 312 313 314 void 315 BCountView::AttachedToWindow() 316 { 317 SetFont(be_plain_font); 318 SetFontSize(9); 319 320 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 321 SetLowColor(ViewColor()); 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::SetBorderHighlighted(bool highlighted) 351 { 352 if (fBorderHighlighted == highlighted) 353 return; 354 355 fBorderHighlighted = highlighted; 356 BRect dirty(Bounds()); 357 dirty.bottom = dirty.top; 358 Invalidate(dirty); 359 } 360