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