xref: /haiku/src/kits/tracker/CountView.cpp (revision a4ef4a49150f118d47324242917a596a3f8f8bd5)
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(&region);
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