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