xref: /haiku/src/kits/tracker/CountView.cpp (revision 151343ebc86cf0ce61a6c7789f853dff35c57e9c)
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 <StringFormat.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 BStringFormat 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 
247 	BeginLineArray(fShowingBarberPole && !fStartSpinningAfter ? 9 : 5);
248 
249 	if (!fShowingBarberPole || fStartSpinningAfter) {
250 		EndLineArray();
251 		return;
252 	}
253 
254 	BRect barberPoleRect(BarberPoleOuterRect());
255 
256 	AddLine(barberPoleRect.LeftTop(), barberPoleRect.RightTop(), shadow);
257 	AddLine(barberPoleRect.LeftTop(), barberPoleRect.LeftBottom(), shadow);
258 	AddLine(barberPoleRect.LeftBottom(), barberPoleRect.RightBottom(), light);
259 	AddLine(barberPoleRect.RightBottom(), barberPoleRect.RightTop(), light);
260 	EndLineArray();
261 
262 	barberPoleRect.InsetBy(1, 1);
263 
264 	BRect destRect(fBarberPoleMap
265 		? fBarberPoleMap->Bounds() : BRect(0, 0, 0, 0));
266 	destRect.OffsetTo(barberPoleRect.LeftTop()
267 		- BPoint(0, fLastBarberPoleOffset));
268 	fLastBarberPoleOffset -= 1;
269 	if (fLastBarberPoleOffset < 0)
270 		fLastBarberPoleOffset = 5;
271 
272 	BRegion region;
273 	region.Set(BarberPoleInnerRect());
274 	ConstrainClippingRegion(&region);
275 
276 	if (fBarberPoleMap)
277 		DrawBitmap(fBarberPoleMap, destRect);
278 }
279 
280 
281 void
282 BCountView::MouseDown(BPoint)
283 {
284 	BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
285 	ThrowOnAssert(window != NULL);
286 
287 	window->Activate();
288 	window->UpdateIfNeeded();
289 
290 	if (fPoseView->IsFilePanel() || fPoseView->TargetModel() == NULL)
291 		return;
292 
293 	if (!window->TargetModel()->IsRoot()) {
294 		BDirMenu* menu = new BDirMenu(NULL, be_app, B_REFS_RECEIVED);
295 		BEntry entry;
296 		if (entry.SetTo(window->TargetModel()->EntryRef()) == B_OK)
297 			menu->Populate(&entry, Window(), false, false, true, false, true);
298 		else
299 			menu->Populate(NULL, Window(), false, false, true, false, true);
300 
301 		BPoint point = Bounds().LeftBottom();
302 		point.y += 3;
303 		ConvertToScreen(&point);
304 		BRect clickToOpenRect(Bounds());
305 		ConvertToScreen(&clickToOpenRect);
306 		menu->Go(point, true, true, clickToOpenRect);
307 		delete menu;
308 	}
309 }
310 
311 
312 void
313 BCountView::AttachedToWindow()
314 {
315 	SetFont(be_plain_font);
316 	SetFontSize(9);
317 
318 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
319 	SetLowUIColor(ViewUIColor());
320 
321 	CheckCount();
322 }
323 
324 
325 void
326 BCountView::SetTypeAhead(const char* string)
327 {
328 	fTypeAheadString = string;
329 	Invalidate();
330 }
331 
332 
333 const char*
334 BCountView::TypeAhead() const
335 {
336 	return fTypeAheadString.String();
337 }
338 
339 
340 bool
341 BCountView::IsTypingAhead() const
342 {
343 	return fTypeAheadString.Length() != 0;
344 }
345 
346 
347 void
348 BCountView::AddFilterCharacter(const char* character)
349 {
350 	fFilterString.AppendChars(character, 1);
351 	Invalidate();
352 }
353 
354 
355 void
356 BCountView::RemoveFilterCharacter()
357 {
358 	fFilterString.TruncateChars(fFilterString.CountChars() - 1);
359 	Invalidate();
360 }
361 
362 
363 void
364 BCountView::CancelFilter()
365 {
366 	fFilterString.Truncate(0);
367 	Invalidate();
368 }
369 
370 
371 const char*
372 BCountView::Filter() const
373 {
374 	return fFilterString.String();
375 }
376 
377 
378 bool
379 BCountView::IsFiltering() const
380 {
381 	return fFilterString.Length() > 0;
382 }
383