xref: /haiku/src/kits/tracker/CountView.cpp (revision 9642f7705b27e5c270c15fa526d14e1848c2c27d)
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 <MessageFormat.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 
60 
61 //	#pragma mark - BCountView
62 
63 
64 BCountView::BCountView(BPoseView* view)
65 	:
66 	BView("CountVw", B_PULSE_NEEDED | B_WILL_DRAW),
67 	fLastCount(-1),
68 	fPoseView(view),
69 	fShowingBarberPole(false),
70 	fBarberPoleMap(NULL),
71 	fLastBarberPoleOffset(5),
72 	fStartSpinningAfter(0),
73 	fTypeAheadString(""),
74 	fFilterString("")
75 {
76  	GetTrackerResources()->GetBitmapResource(B_MESSAGE_TYPE,
77  		R_BarberPoleBitmap, &fBarberPoleMap);
78 }
79 
80 
81 BCountView::~BCountView()
82 {
83 	delete fBarberPoleMap;
84 }
85 
86 
87 void
88 BCountView::TrySpinningBarberPole()
89 {
90 	if (!fShowingBarberPole)
91 		return;
92 
93 	if (fStartSpinningAfter && system_time() < fStartSpinningAfter)
94 		return;
95 
96 	// When the barber pole just starts spinning we need to invalidate
97 	// the whole rectangle of text and barber pole.
98 	// After this the text needs no updating since only the pole changes.
99 	if (fStartSpinningAfter) {
100 		fStartSpinningAfter = 0;
101 		Invalidate(TextAndBarberPoleRect());
102 	} else
103 		Invalidate(BarberPoleInnerRect());
104 }
105 
106 
107 void
108 BCountView::Pulse()
109 {
110 	TrySpinningBarberPole();
111 }
112 
113 
114 void
115 BCountView::EndBarberPole()
116 {
117 	if (!fShowingBarberPole)
118 		return;
119 
120 	fShowingBarberPole = false;
121 	Invalidate();
122 }
123 
124 
125 void
126 BCountView::StartBarberPole()
127 {
128 	AutoLock<BWindow> lock(Window());
129 	if (fShowingBarberPole)
130 		return;
131 
132 	fShowingBarberPole = true;
133 	fStartSpinningAfter = system_time() + kBarberPoleDelay;
134 		// wait a bit before showing the barber pole
135 }
136 
137 
138 BRect
139 BCountView::BarberPoleInnerRect() const
140 {
141 	BRect result = Bounds();
142 	result.InsetBy(3, 4);
143 	result.left = result.right - 7;
144 	result.bottom = result.top + 7;
145 	return result;
146 }
147 
148 
149 BRect
150 BCountView::BarberPoleOuterRect() const
151 {
152 	BRect result(BarberPoleInnerRect());
153 	result.InsetBy(-1, -1);
154 	return result;
155 }
156 
157 
158 BRect
159 BCountView::TextInvalRect() const
160 {
161 	BRect result = Bounds();
162 	result.InsetBy(4, 3);
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(4, 3);
177 
178 	return result;
179 }
180 
181 
182 void
183 BCountView::CheckCount()
184 {
185 	// invalidate the count text area if necessary
186 	if (fLastCount != fPoseView->CountItems()) {
187 		fLastCount = fPoseView->CountItems();
188 		Invalidate(TextInvalRect());
189 	}
190 
191 	// invalidate barber pole area if necessary
192 	TrySpinningBarberPole();
193 }
194 
195 
196 void
197 BCountView::Draw(BRect updateRect)
198 {
199 	BRect bounds(Bounds());
200 
201 	rgb_color color = ViewColor();
202 	if (IsTypingAhead())
203 		color = ui_color(B_DOCUMENT_BACKGROUND_COLOR);
204 
205 	SetLowColor(color);
206 	be_control_look->DrawBorder(this, bounds, updateRect,
207 		color, B_PLAIN_BORDER, 0,
208 		BControlLook::B_BOTTOM_BORDER | BControlLook::B_LEFT_BORDER);
209 	be_control_look->DrawMenuBarBackground(this, bounds, updateRect, color);
210 
211 	BString itemString;
212 	if (IsTypingAhead())
213 		itemString << TypeAhead();
214 	else if (IsFiltering()) {
215 		itemString << fLastCount << " " << Filter();
216 	} else {
217 		if (fLastCount == 0)
218 			itemString << B_TRANSLATE("no items");
219 		else {
220 			static BMessageFormat format(B_TRANSLATE_COMMENT(
221 				"{0, plural, one{# item} other{# items}}",
222 				"Number of selected items: \"1 item\" or \"2 items\""));
223 			format.Format(itemString, fLastCount);
224 		}
225 	}
226 
227 	BRect textRect(TextInvalRect());
228 
229 	TruncateString(&itemString, IsTypingAhead() ? B_TRUNCATE_BEGINNING
230 			: IsFiltering() ? B_TRUNCATE_MIDDLE : B_TRUNCATE_END,
231 		textRect.Width());
232 
233 	if (IsTypingAhead()) {
234 		// use a muted gray for the typeahead
235 		SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR));
236 	} else
237 		SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
238 
239 	MovePenTo(textRect.LeftBottom());
240 	DrawString(itemString.String());
241 
242 	bounds.top++;
243 
244 	rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT);
245 	rgb_color shadow = tint_color(ViewColor(), B_DARKEN_2_TINT);
246 	rgb_color lightShadow = tint_color(ViewColor(), B_DARKEN_1_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(&region);
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(9);
318 
319 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
320 	SetLowUIColor(ViewUIColor());
321 
322 	CheckCount();
323 }
324 
325 
326 void
327 BCountView::SetTypeAhead(const char* string)
328 {
329 	fTypeAheadString = string;
330 	Invalidate();
331 }
332 
333 
334 const char*
335 BCountView::TypeAhead() const
336 {
337 	return fTypeAheadString.String();
338 }
339 
340 
341 bool
342 BCountView::IsTypingAhead() const
343 {
344 	return fTypeAheadString.Length() != 0;
345 }
346 
347 
348 void
349 BCountView::AddFilterCharacter(const char* character)
350 {
351 	fFilterString.AppendChars(character, 1);
352 	Invalidate();
353 }
354 
355 
356 void
357 BCountView::RemoveFilterCharacter()
358 {
359 	fFilterString.TruncateChars(fFilterString.CountChars() - 1);
360 	Invalidate();
361 }
362 
363 
364 void
365 BCountView::CancelFilter()
366 {
367 	fFilterString.Truncate(0);
368 	Invalidate();
369 }
370 
371 
372 const char*
373 BCountView::Filter() const
374 {
375 	return fFilterString.String();
376 }
377 
378 
379 bool
380 BCountView::IsFiltering() const
381 {
382 	return fFilterString.Length() > 0;
383 }
384