1 /*******************************************************************************
5 / Description: Experimental classes that implement particular column/field
6 / data types for use in BColumnListView.
8 / Copyright 2000+, Be Incorporated, All Rights Reserved
10 *******************************************************************************/
12 #include "ColumnTypes.h"
16 #include <parsedate.h>
20 #define kTEXT_MARGIN 8
23 const int64 kKB_SIZE
= 1024;
24 const int64 kMB_SIZE
= 1048576;
25 const int64 kGB_SIZE
= 1073741824;
26 const int64 kTB_SIZE
= kGB_SIZE
* kKB_SIZE
;
28 const char* kSIZE_FORMATS
[] = {
37 BTitledColumn::BTitledColumn(const char* title
, float width
, float minWidth
,
38 float maxWidth
, alignment align
)
40 BColumn(width
, minWidth
, maxWidth
, align
),
45 be_plain_font
->GetHeight(&fh
);
46 fFontHeight
= fh
.descent
+ fh
.leading
;
51 BTitledColumn::DrawTitle(BRect rect
, BView
* parent
)
53 float width
= rect
.Width() - (2 * kTEXT_MARGIN
);
54 BString
out_string(fTitle
);
56 parent
->TruncateString(&out_string
, B_TRUNCATE_END
, width
+ 2);
57 DrawString(out_string
.String(), parent
, rect
);
62 BTitledColumn::GetColumnName(BString
* into
) const
69 BTitledColumn::DrawString(const char* string
, BView
* parent
, BRect rect
)
71 float width
= rect
.Width() - (2 * kTEXT_MARGIN
);
76 parent
->GetFont(&font
);
77 font
.GetHeight(&finfo
);
78 y
= rect
.top
+ finfo
.ascent
79 + (rect
.Height() - ceilf(finfo
.ascent
+ finfo
.descent
)) / 2.0f
;
81 switch (Alignment()) {
84 parent
->MovePenTo(rect
.left
+ kTEXT_MARGIN
, y
);
88 parent
->MovePenTo(rect
.left
+ kTEXT_MARGIN
89 + ((width
- font
.StringWidth(string
)) / 2), y
);
93 parent
->MovePenTo(rect
.right
- kTEXT_MARGIN
94 - font
.StringWidth(string
), y
);
98 parent
->DrawString(string
);
103 BTitledColumn::SetTitle(const char* title
)
110 BTitledColumn::Title(BString
* forTitle
) const
113 forTitle
->SetTo(fTitle
.String());
118 BTitledColumn::FontHeight() const
125 BTitledColumn::GetPreferredWidth(BField
*_field
, BView
* parent
) const
127 return parent
->StringWidth(fTitle
.String()) + 2 * kTEXT_MARGIN
;
131 // #pragma mark - BStringField
134 BStringField::BStringField(const char* string
)
138 fClippedString(string
)
144 BStringField::SetString(const char* val
)
153 BStringField::String() const
155 return fString
.String();
160 BStringField::SetWidth(float width
)
167 BStringField::Width()
174 BStringField::SetClippedString(const char* val
)
176 fClippedString
= val
;
181 BStringField::HasClippedString() const
183 return !fClippedString
.IsEmpty();
188 BStringField::ClippedString()
190 return fClippedString
.String();
194 // #pragma mark - BStringColumn
197 BStringColumn::BStringColumn(const char* title
, float width
, float minWidth
,
198 float maxWidth
, uint32 truncate
, alignment align
)
200 BTitledColumn(title
, width
, minWidth
, maxWidth
, align
),
207 BStringColumn::DrawField(BField
* _field
, BRect rect
, BView
* parent
)
209 float width
= rect
.Width() - (2 * kTEXT_MARGIN
);
210 BStringField
* field
= static_cast<BStringField
*>(_field
);
211 float fieldWidth
= field
->Width();
212 bool updateNeeded
= width
!= fieldWidth
;
215 BString
out_string(field
->String());
216 float preferredWidth
= parent
->StringWidth(out_string
.String());
217 if (width
< preferredWidth
) {
218 parent
->TruncateString(&out_string
, fTruncate
, width
+ 2);
219 field
->SetClippedString(out_string
.String());
221 field
->SetClippedString("");
222 field
->SetWidth(width
);
225 DrawString(field
->HasClippedString()
226 ? field
->ClippedString()
227 : field
->String(), parent
, rect
);
232 BStringColumn::GetPreferredWidth(BField
*_field
, BView
* parent
) const
234 BStringField
* field
= static_cast<BStringField
*>(_field
);
235 return parent
->StringWidth(field
->String()) + 2 * kTEXT_MARGIN
;
240 BStringColumn::CompareFields(BField
* field1
, BField
* field2
)
242 return ICompare(((BStringField
*)field1
)->String(),
243 (((BStringField
*)field2
)->String()));
248 BStringColumn::AcceptsField(const BField
*field
) const
250 return static_cast<bool>(dynamic_cast<const BStringField
*>(field
));
254 // #pragma mark - BDateField
257 BDateField::BDateField(time_t* time
)
259 fTime(*localtime(time
)),
265 fSeconds
= mktime(&fTime
);
270 BDateField::SetWidth(float width
)
284 BDateField::SetClippedString(const char* string
)
286 fClippedString
= string
;
291 BDateField::ClippedString()
293 return fClippedString
.String();
298 BDateField::Seconds()
305 BDateField::UnixTime()
311 // #pragma mark - BDateColumn
314 BDateColumn::BDateColumn(const char* title
, float width
, float minWidth
,
315 float maxWidth
, alignment align
)
317 BTitledColumn(title
, width
, minWidth
, maxWidth
, align
),
323 const char *kTIME_FORMATS
[] = {
324 "%A, %B %d %Y, %I:%M:%S %p", // Monday, July 09 1997, 05:08:15 PM
325 "%a, %b %d %Y, %I:%M:%S %p", // Mon, Jul 09 1997, 05:08:15 PM
326 "%a, %b %d %Y, %I:%M %p", // Mon, Jul 09 1997, 05:08 PM
327 "%b %d %Y, %I:%M %p", // Jul 09 1997, 05:08 PM
328 "%m/%d/%y, %I:%M %p", // 07/09/97, 05:08 PM
329 "%m/%d/%y", // 07/09/97
335 BDateColumn::DrawField(BField
* _field
, BRect rect
, BView
* parent
)
337 float width
= rect
.Width() - (2 * kTEXT_MARGIN
);
338 BDateField
* field
= (BDateField
*)_field
;
340 if (field
->Width() != rect
.Width()) {
341 char dateString
[256];
342 time_t currentTime
= field
->UnixTime();
346 parent
->GetFont(&font
);
347 localtime_r(¤tTime
, &time_data
);
349 for (int32 index
= 0; ; index
++) {
350 if (!kTIME_FORMATS
[index
])
353 strftime(dateString
, 256, kTIME_FORMATS
[index
], &time_data
);
354 if (font
.StringWidth(dateString
) <= width
)
358 if (font
.StringWidth(dateString
) > width
) {
359 BString
out_string(dateString
);
361 parent
->TruncateString(&out_string
, B_TRUNCATE_MIDDLE
, width
+ 2);
362 strcpy(dateString
, out_string
.String());
364 field
->SetClippedString(dateString
);
365 field
->SetWidth(width
);
368 DrawString(field
->ClippedString(), parent
, rect
);
373 BDateColumn::CompareFields(BField
* field1
, BField
* field2
)
375 return((BDateField
*)field1
)->Seconds() - ((BDateField
*)field2
)->Seconds();
379 // #pragma mark - BSizeField
382 BSizeField::BSizeField(off_t size
)
390 BSizeField::SetSize(off_t size
)
403 // #pragma mark - BSizeColumn
406 BSizeColumn::BSizeColumn(const char* title
, float width
, float minWidth
,
407 float maxWidth
, alignment align
)
409 BTitledColumn(title
, width
, minWidth
, maxWidth
, align
)
415 BSizeColumn::DrawField(BField
* _field
, BRect rect
, BView
* parent
)
418 float width
= rect
.Width() - (2 * kTEXT_MARGIN
);
421 off_t size
= ((BSizeField
*)_field
)->Size();
423 parent
->GetFont(&font
);
424 if (size
< kKB_SIZE
) {
425 sprintf(str
, "%" B_PRId64
" bytes", size
);
426 if (font
.StringWidth(str
) > width
)
427 sprintf(str
, "%" B_PRId64
" B", size
);
431 if (size
>= kTB_SIZE
) {
433 float_value
= (float)size
/ kTB_SIZE
;
434 } else if (size
>= kGB_SIZE
) {
436 float_value
= (float)size
/ kGB_SIZE
;
437 } else if (size
>= kMB_SIZE
) {
439 float_value
= (float)size
/ kMB_SIZE
;
442 float_value
= (float)size
/ kKB_SIZE
;
445 for (int32 index
= 0; ; index
++) {
446 if (!kSIZE_FORMATS
[index
])
449 sprintf(str
, kSIZE_FORMATS
[index
], float_value
, suffix
);
450 // strip off an insignificant zero so we don't get readings
454 for (tmp
= str
; *tmp
; tmp
++) {
458 if (period
&& period
[1] && period
[2] == '0') {
459 // move the rest of the string over the insignificant zero
460 for (tmp
= &period
[2]; *tmp
; tmp
++)
463 if (font
.StringWidth(str
) <= width
)
469 parent
->TruncateString(&string
, B_TRUNCATE_MIDDLE
, width
+ 2);
470 DrawString(string
.String(), parent
, rect
);
475 BSizeColumn::CompareFields(BField
* field1
, BField
* field2
)
477 return ((BSizeField
*)field1
)->Size() - ((BSizeField
*)field2
)->Size();
481 // #pragma mark - BIntegerField
484 BIntegerField::BIntegerField(int32 number
)
492 BIntegerField::SetValue(int32 value
)
499 BIntegerField::Value()
505 // #pragma mark - BIntegerColumn
508 BIntegerColumn::BIntegerColumn(const char* title
, float width
, float minWidth
,
509 float maxWidth
, alignment align
)
511 BTitledColumn(title
, width
, minWidth
, maxWidth
, align
)
517 BIntegerColumn::DrawField(BField
*field
, BRect rect
, BView
* parent
)
520 float width
= rect
.Width() - (2 * kTEXT_MARGIN
);
523 sprintf(formatted
, "%d", (int)((BIntegerField
*)field
)->Value());
526 parent
->TruncateString(&string
, B_TRUNCATE_MIDDLE
, width
+ 2);
527 DrawString(string
.String(), parent
, rect
);
532 BIntegerColumn::CompareFields(BField
*field1
, BField
*field2
)
534 return (((BIntegerField
*)field1
)->Value() - ((BIntegerField
*)field2
)->Value());
538 // #pragma mark - GraphColumn
541 GraphColumn::GraphColumn(const char* name
, float width
, float minWidth
,
542 float maxWidth
, alignment align
)
544 BIntegerColumn(name
, width
, minWidth
, maxWidth
, align
)
550 GraphColumn::DrawField(BField
* field
, BRect rect
, BView
* parent
)
552 int number
= ((BIntegerField
*)field
)->Value();
559 BRect
graphRect(rect
);
560 graphRect
.InsetBy(5, 3);
561 parent
->StrokeRect(graphRect
);
563 graphRect
.InsetBy(1, 1);
564 float value
= graphRect
.Width() * (float)number
/ 100;
565 graphRect
.right
= graphRect
.left
+ value
;
566 parent
->SetHighColor(0, 0, 190);
567 parent
->FillRect(graphRect
);
570 parent
->SetDrawingMode(B_OP_INVERT
);
571 parent
->SetHighColor(128, 128, 128);
572 char numberString
[256];
573 sprintf(numberString
, "%d%%", number
);
575 float width
= be_plain_font
->StringWidth(numberString
);
576 parent
->MovePenTo(rect
.left
+ rect
.Width() / 2 - width
/ 2, rect
.bottom
- FontHeight());
577 parent
->DrawString(numberString
);
581 // #pragma mark - BBitmapField
584 BBitmapField::BBitmapField(BBitmap
* bitmap
)
592 BBitmapField::Bitmap()
599 BBitmapField::SetBitmap(BBitmap
* bitmap
)
605 // #pragma mark - BBitmapColumn
608 BBitmapColumn::BBitmapColumn(const char* title
, float width
, float minWidth
,
609 float maxWidth
, alignment align
)
611 BTitledColumn(title
, width
, minWidth
, maxWidth
, align
)
617 BBitmapColumn::DrawField(BField
* field
, BRect rect
, BView
* parent
)
619 BBitmapField
* bitmapField
= static_cast<BBitmapField
*>(field
);
620 const BBitmap
* bitmap
= bitmapField
->Bitmap();
622 if (bitmap
!= NULL
) {
624 BRect r
= bitmap
->Bounds();
625 float y
= rect
.top
+ ((rect
.Height() - r
.Height()) / 2);
627 switch (Alignment()) {
630 x
= rect
.left
+ kTEXT_MARGIN
;
634 x
= rect
.left
+ ((rect
.Width() - r
.Width()) / 2);
638 x
= rect
.right
- kTEXT_MARGIN
- r
.Width();
641 // setup drawing mode according to bitmap color space,
642 // restore previous mode after drawing
643 drawing_mode oldMode
= parent
->DrawingMode();
644 if (bitmap
->ColorSpace() == B_RGBA32
645 || bitmap
->ColorSpace() == B_RGBA32_BIG
) {
646 parent
->SetDrawingMode(B_OP_ALPHA
);
647 parent
->SetBlendingMode(B_PIXEL_ALPHA
, B_ALPHA_OVERLAY
);
649 parent
->SetDrawingMode(B_OP_OVER
);
652 parent
->DrawBitmap(bitmap
, BPoint(x
, y
));
654 parent
->SetDrawingMode(oldMode
);
660 BBitmapColumn::CompareFields(BField
* /*field1*/, BField
* /*field2*/)
662 // Comparing bitmaps doesn't really make sense...
668 BBitmapColumn::AcceptsField(const BField
*field
) const
670 return static_cast<bool>(dynamic_cast<const BBitmapField
*>(field
));