2 * Copyright (c) 1999-2000, Eric Moon.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "StatusView.h"
35 #include "cortex_ui.h"
36 #include "RouteAppNodeManager.h"
37 #include "TipManager.h"
41 #include <MessageRunner.h>
45 #include <ScrollBar.h>
50 __USE_CORTEX_NAMESPACE
53 #define D_ALLOC(x) //PRINT(x)
54 #define D_HOOK(x) //PRINT(x)
55 #define D_MESSAGE(x) //PRINT(x)
56 #define D_OPERATION(x) //PRINT(x)
58 // -------------------------------------------------------- //
60 // -------------------------------------------------------- //
62 const bigtime_t TICK_PERIOD
= 50000;
63 const bigtime_t TEXT_DECAY_DELAY
= 10 * 1000 * 1000;
64 const bigtime_t TEXT_DECAY_TIME
= 3 * 1000 * 1000;
66 // width: 8, height:12, color_space: B_CMAP8
67 const unsigned char ERROR_ICON_BITS
[] = {
68 0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,
69 0xff,0x00,0xfa,0xfa,0x00,0xff,0xff,0xff,
70 0x00,0x3f,0x3f,0xfa,0xfa,0x00,0xff,0xff,
71 0x00,0xf9,0xf9,0x3f,0x5d,0x00,0xff,0xff,
72 0x00,0xf9,0xf9,0x5d,0x5d,0x00,0xff,0xff,
73 0x00,0xf9,0xf9,0x5d,0x5d,0x00,0xff,0xff,
74 0x00,0x00,0xf9,0x5d,0x00,0x00,0xff,0xff,
75 0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,
76 0x00,0xf9,0x00,0x00,0x5d,0x00,0xff,0xff,
77 0x00,0xf9,0xf9,0x5d,0x5d,0x00,0xff,0xff,
78 0x00,0x00,0xf9,0x5d,0x00,0x00,0x0f,0xff,
79 0xff,0xff,0x00,0x00,0x00,0x0f,0x0f,0x0f,
82 // width: 8, height:12, color_space: B_CMAP8
83 const unsigned char INFO_ICON_BITS
[] = {
84 0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xff,
85 0xff,0x00,0x21,0x21,0x21,0x00,0xff,0xff,
86 0xff,0x00,0x21,0x92,0x25,0x00,0xff,0xff,
87 0xff,0x00,0x21,0x25,0x25,0x00,0xff,0xff,
88 0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xff,
89 0xff,0x00,0x92,0x92,0x25,0x00,0xff,0xff,
90 0xff,0x00,0x21,0x21,0x25,0x00,0xff,0xff,
91 0xff,0x00,0x21,0x21,0x25,0x00,0xff,0xff,
92 0x00,0x00,0x21,0x21,0x25,0x00,0x00,0xff,
93 0x00,0xbe,0x21,0x21,0x92,0xbe,0x25,0x00,
94 0x00,0x00,0x21,0x21,0x21,0x25,0x00,0x0f,
95 0xff,0xff,0x00,0x00,0x00,0x00,0x0f,0x0f,
98 // -------------------------------------------------------- //
100 // -------------------------------------------------------- //
102 StatusView::StatusView(
104 RouteAppNodeManager
*manager
,
105 BScrollBar
*scrollBar
)
106 : BStringView(frame
, "StatusView", "", B_FOLLOW_LEFT
| B_FOLLOW_BOTTOM
,
107 B_FRAME_EVENTS
| B_WILL_DRAW
),
108 m_scrollBar(scrollBar
),
117 D_ALLOC(("StatusView::StatusView()\n"));
119 SetViewColor(B_TRANSPARENT_COLOR
);
120 SetFont(be_plain_font
);
122 allocBackBitmap(frame
.Width(), frame
.Height());
125 StatusView::~StatusView() {
126 D_ALLOC(("StatusView::~ParameterContainerView()\n"));
128 // get the tip manager instance and reset
129 TipManager
*manager
= TipManager::Instance();
130 manager
->removeAll(this);
137 // -------------------------------------------------------- //
138 // *** BScrollView impl
139 // -------------------------------------------------------- //
141 void StatusView::AttachedToWindow() {
142 D_HOOK(("StatusView::AttachedToWindow()\n"));
145 m_manager
->setLogTarget(BMessenger(this, Window()));
148 allocBackBitmap(Bounds().Width(), Bounds().Height());
151 void StatusView::Draw(
153 D_HOOK(("StatusView::Draw()\n"));
156 drawInto(this, updateRect
);
159 m_backBitmap
->Lock();
160 drawInto(m_backView
, updateRect
);
162 m_backBitmap
->Unlock();
166 SetDrawingMode(B_OP_COPY
);
167 DrawBitmap(m_backBitmap
, updateRect
, updateRect
);
171 void StatusView::FrameResized(
174 D_HOOK(("StatusView::FrameResized()\n"));
176 allocBackBitmap(width
, height
);
178 // get the tip manager instance and reset
179 TipManager
*manager
= TipManager::Instance();
180 manager
->removeAll(this);
182 // re-truncate the string if necessary
183 BString text
= m_fullText
;
184 if (be_plain_font
->StringWidth(text
.String()) > Bounds().Width() - 25.0) {
185 be_plain_font
->TruncateString(&text
, B_TRUNCATE_END
,
186 Bounds().Width() - 25.0);
187 manager
->setTip(m_fullText
.String(), this);
189 BStringView::SetText(text
.String());
191 float minWidth
, maxWidth
, minHeight
, maxHeight
;
192 Window()->GetSizeLimits(&minWidth
, &maxWidth
, &minHeight
, &maxHeight
);
193 minWidth
= width
+ 6 * B_V_SCROLL_BAR_WIDTH
;
194 Window()->SetSizeLimits(minWidth
, maxWidth
, minHeight
, maxHeight
);
197 void StatusView::MessageReceived(
199 D_MESSAGE(("StatusView::MessageReceived()\n"));
201 switch (message
->what
) {
206 case RouteAppNodeManager::M_LOG
: {
207 D_MESSAGE((" -> RouteAppNodeManager::M_LOG\n"));
210 if (message
->FindString("title", &title
) != B_OK
) {
213 BString details
, line
;
214 for (int32 i
= 0; message
->FindString("line", i
, &line
) == B_OK
; i
++) {
215 if (details
.CountChars() > 0) {
220 status_t error
= B_OK
;
221 message
->FindInt32("error", &error
);
222 setMessage(title
, details
, error
);
226 BStringView::MessageReceived(message
);
231 void StatusView::MouseDown(
233 D_HOOK(("StatusView::MouseDown()\n"));
236 if (Window()->CurrentMessage()->FindInt32("buttons", &buttons
) != B_OK
) {
237 buttons
= B_PRIMARY_MOUSE_BUTTON
;
240 if (buttons
== B_PRIMARY_MOUSE_BUTTON
) {
242 BRect
dragRect(Bounds());
243 dragRect
.left
= dragRect
.right
- 10.0;
244 if (dragRect
.Contains(point
)) {
247 SetMouseEventMask(B_POINTER_EVENTS
,
248 B_LOCK_WINDOW_FOCUS
| B_NO_POINTER_HISTORY
);
253 void StatusView::MouseMoved(
256 const BMessage
*message
) {
257 D_HOOK(("StatusView::MouseMoved()\n"));
260 float x
= point
.x
- (Bounds().right
- 5.0);
261 if ((Bounds().Width() + x
) <= 16.0) {
265 && ((m_scrollBar
->Bounds().Width() - x
) <= (6 * B_V_SCROLL_BAR_WIDTH
))) {
270 r
.left
= r
.right
- 5.0;
276 m_scrollBar
->ResizeBy(-x
, 0.0);
277 m_scrollBar
->MoveBy(x
, 0.0);
282 void StatusView::MouseUp(
284 D_HOOK(("StatusView::MouseUp()\n"));
289 // -------------------------------------------------------- //
290 // *** internal operations
291 // -------------------------------------------------------- //
294 StatusView::drawInto(BView
*v
, BRect updateRect
)
297 D_OPERATION(("StatusView::drawInto(%.1f, %.1f)\n", r
.Width(), r
.Height()));
299 // draw border (minus right edge, which the scrollbar draws)
300 v
->SetDrawingMode(B_OP_COPY
);
301 v
->BeginLineArray(8);
302 v
->AddLine(r
.LeftTop(), r
.RightTop(), M_MED_GRAY_COLOR
);
303 BPoint rtop
= r
.RightTop();
305 v
->AddLine(rtop
, r
.RightBottom(), tint_color(M_MED_GRAY_COLOR
, B_LIGHTEN_1_TINT
));
306 v
->AddLine(r
.RightBottom(), r
.LeftBottom(), M_MED_GRAY_COLOR
);
307 v
->AddLine(r
.LeftBottom(), r
.LeftTop(), M_MED_GRAY_COLOR
);
309 v
->AddLine(r
.LeftTop(), r
.RightTop(), M_LIGHT_GRAY_COLOR
);
312 v
->AddLine(rtop
, r
.RightBottom(), M_GRAY_COLOR
);
313 v
->AddLine(r
.RightBottom(), r
.LeftBottom(), tint_color(M_MED_GRAY_COLOR
, B_LIGHTEN_1_TINT
));
314 v
->AddLine(r
.LeftBottom(), r
.LeftTop(), M_LIGHT_GRAY_COLOR
);
317 v
->SetLowColor(M_GRAY_COLOR
);
318 v
->FillRect(r
, B_SOLID_LOW
);
321 v
->SetDrawingMode(B_OP_ALPHA
);
322 v
->SetHighColor(0, 0, 0, uchar(255 * m_opacity
));
326 v
->SetBlendingMode(B_CONSTANT_ALPHA
, B_ALPHA_OVERLAY
);
327 BPoint p
= r
.LeftTop();
329 v
->DrawBitmap(m_icon
, p
);
335 be_plain_font
->GetHeight(&fh
);
336 r
.bottom
= Bounds().bottom
- fh
.descent
337 - (Bounds().Height() - fh
.ascent
- fh
.descent
) / 2;
338 v
->MovePenTo(r
.LeftBottom());
339 v
->DrawString(Text());
341 // draw resize dragger
342 v
->SetDrawingMode(B_OP_OVER
);
345 r
.left
= r
.right
- 2.0;
348 for (int32 i
= 0; i
< r
.IntegerHeight(); i
+= 3) {
349 BPoint p
= r
.LeftTop() + BPoint(0.0, i
);
350 v
->SetHighColor(M_MED_GRAY_COLOR
);
351 v
->StrokeLine(p
, p
, B_SOLID_HIGH
);
352 p
+= BPoint(1.0, 1.0);
353 v
->SetHighColor(M_WHITE_COLOR
);
354 v
->StrokeLine(p
, p
, B_SOLID_HIGH
);
360 void StatusView::setMessage(
364 D_OPERATION(("StatusView::setMessage(%s)\n", title
.String()));
366 // get the tip manager instance and reset
367 TipManager
*manager
= TipManager::Instance();
368 manager
->removeAll(this);
370 // append error string
372 title
<< " (" << strerror(error
) << ")";
375 // truncate if necessary
376 bool truncated
= false;
378 if (be_plain_font
->StringWidth(title
.String()) > Bounds().Width() - 25.0) {
379 be_plain_font
->TruncateString(&title
, B_TRUNCATE_END
,
380 Bounds().Width() - 25.0);
383 BStringView::SetText(title
.String());
385 if (truncated
|| details
.CountChars() > 0) {
386 BString tip
= m_fullText
;
387 if (details
.CountChars() > 0) {
388 tip
<< "\n" << details
;
390 manager
->setTip(tip
.String(), this);
400 BRect
iconRect(0.0, 0.0, 7.0, 11.0);
401 m_icon
= new BBitmap(iconRect
, B_CMAP8
);
402 m_icon
->SetBits(ERROR_ICON_BITS
, 96, 0, B_CMAP8
);
410 BRect
iconRect(0.0, 0.0, 7.0, 11.0);
411 m_icon
= new BBitmap(iconRect
, B_CMAP8
);
412 m_icon
->SetBits(INFO_ICON_BITS
, 96, 0, B_CMAP8
);
419 void StatusView::setErrorMessage(
422 D_OPERATION(("StatusView::setErrorMessage(%s)\n",
425 // get the tip manager instance and reset
426 TipManager
*manager
= TipManager::Instance();
427 manager
->removeAll(this);
429 // truncate if necessary
431 if (be_plain_font
->StringWidth(text
.String()) > Bounds().Width() - 25.0) {
432 be_plain_font
->TruncateString(&text
, B_TRUNCATE_END
,
433 Bounds().Width() - 25.0);
434 manager
->setTip(m_fullText
.String(), this);
436 BStringView::SetText(text
.String());
445 BRect
iconRect(0.0, 0.0, 7.0, 11.0);
446 m_icon
= new BBitmap(iconRect
, B_CMAP8
);
447 m_icon
->SetBits(ERROR_ICON_BITS
, 96, 0, B_CMAP8
);
455 BRect
iconRect(0.0, 0.0, 7.0, 11.0);
456 m_icon
= new BBitmap(iconRect
, B_CMAP8
);
457 m_icon
->SetBits(INFO_ICON_BITS
, 96, 0, B_CMAP8
);
464 void StatusView::startFade() {
465 D_OPERATION(("StatusView::startFade()\n"));
468 m_decayDelay
= TEXT_DECAY_DELAY
;
470 m_clock
= new BMessageRunner(
472 new BMessage('Tick'),
477 void StatusView::fadeTick() {
478 D_HOOK(("StatusView::fadeTick()\n"));
480 if (m_opacity
> 0.0) {
481 if(m_decayDelay
> 0) {
482 m_decayDelay
-= TICK_PERIOD
;
486 float steps
= static_cast<float>(TEXT_DECAY_TIME
)
487 / static_cast<float>(TICK_PERIOD
);
488 m_opacity
-= (1.0 / steps
);
489 if (m_opacity
< 0.001) {
499 // get the tip manager instance and reset
500 TipManager
*manager
= TipManager::Instance();
501 manager
->removeAll(this);
505 void StatusView::allocBackBitmap(float width
, float height
) {
506 D_OPERATION(("StatusView::allocBackBitmap(%.1f, %.1f)\n", width
, height
));
509 if(width
<= 0.0 || height
<= 0.0)
513 // see if the bitmap needs to be expanded
514 BRect b
= m_backBitmap
->Bounds();
515 if(b
.Width() >= width
&& b
.Height() >= height
)
518 // it does; clean up:
522 BRect
b(0.0, 0.0, width
, height
);
523 m_backBitmap
= new BBitmap(b
, B_RGB32
, true);
525 D_OPERATION(("StatusView::allocBackBitmap(): failed to allocate\n"));
529 m_backView
= new BView(b
, 0, B_FOLLOW_NONE
, B_WILL_DRAW
);
530 m_backBitmap
->AddChild(m_backView
);
534 void StatusView::freeBackBitmap() {
543 // END -- ParameterContainerView.cpp --