git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13194 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-06-17 01:45:51 +00:00
parent 587e093725
commit f56083d8c0
1 changed files with 270 additions and 308 deletions

View File

@ -51,44 +51,39 @@
#include <Autolock.h>
// Project Includes ------------------------------------------------------------
// Local Includes --------------------------------------------------------------
// Local Defines ---------------------------------------------------------------
// Default size of the Alert window.
#define DEFAULT_RECT BRect(0, 0, 310, 75)
#define max(LHS, RHS) ((LHS) > (RHS) ? (LHS) : (RHS))
// Globals ---------------------------------------------------------------------
const unsigned int kAlertButtonMsg = 'ALTB';
const int kSemTimeOut = 50000;
static const unsigned int kAlertButtonMsg = 'ALTB';
static const int kSemTimeOut = 50000;
const int kButtonBottomOffset = 9;
const int kDefButtonBottomOffset = 6;
const int kButtonRightOffset = 6;
const int kButtonSpaceOffset = 6;
const int kButtonOffsetSpaceOffset = 26;
const int kButtonMinOffsetSpaceOffset = kButtonOffsetSpaceOffset / 2;
const int kButtonLeftOffset = 62;
const int kButtonUsualWidth = 75;
static const int kButtonBottomOffset = 9;
static const int kDefButtonBottomOffset = 6;
static const int kButtonRightOffset = 6;
static const int kButtonSpaceOffset = 6;
static const int kButtonOffsetSpaceOffset = 26;
static const int kButtonMinOffsetSpaceOffset = kButtonOffsetSpaceOffset / 2;
static const int kButtonLeftOffset = 62;
static const int kButtonUsualWidth = 75;
const int kWindowIconOffset = 27;
const int kWindowMinWidth = 310;
const int kWindowMinOffset = 12;
const int kWindowOffsetMinWidth = 335;
static const int kWindowIconOffset = 27;
static const int kWindowMinWidth = 310;
static const int kWindowMinOffset = 12;
static const int kWindowOffsetMinWidth = 335;
const int kIconStripeWidth = 30;
static const int kIconStripeWidth = 30;
const int kTextLeftOffset = 10;
const int kTextIconOffset = kWindowIconOffset + kIconStripeWidth - 2;
const int kTextTopOffset = 6;
const int kTextRightOffset = 10;
const int kTextBottomOffset = 45;
static const int kTextLeftOffset = 10;
static const int kTextIconOffset = kWindowIconOffset + kIconStripeWidth - 2;
static const int kTextTopOffset = 6;
static const int kTextRightOffset = 10;
static const int kTextBottomOffset = 45;
//------------------------------------------------------------------------------
class TAlertView : public BView
{
class TAlertView : public BView {
public:
TAlertView(BRect frame);
TAlertView(BMessage* archive);
@ -109,13 +104,13 @@ class TAlertView : public BView
private:
BBitmap* fIconBitmap;
};
//------------------------------------------------------------------------------
// I'm making a guess based on the name and TextEntryAlert's implementation that
// this is a BMessageFilter. I'm not sure, but I think I actually prefer how
// TextEntryAlert does it, but there are clearly no message filtering functions
// on BAlert so here we go.
class _BAlertFilter_ : public BMessageFilter
{
class _BAlertFilter_ : public BMessageFilter {
public:
_BAlertFilter_(BAlert* Alert);
~_BAlertFilter_();
@ -125,10 +120,20 @@ class _BAlertFilter_ : public BMessageFilter
private:
BAlert* fAlert;
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static float
width_from_label(BButton *button)
{
// BButton::GetPreferredSize() does not return the minimum width
// required to fit the label. Thus, the width is computed here.
return button->StringWidth(button->Label()) + 20.0f;
}
// #pragma mark - BAlert
BAlert::BAlert(const char *title, const char *text, const char *button1,
const char *button2, const char *button3, button_width width,
alert_type type)
@ -137,7 +142,8 @@ BAlert::BAlert(const char *title, const char *text, const char *button1,
{
InitObject(text, button1, button2, button3, width, B_EVEN_SPACING, type);
}
//------------------------------------------------------------------------------
BAlert::BAlert(const char *title, const char *text, const char *button1,
const char *button2, const char *button3, button_width width,
button_spacing spacing, alert_type type)
@ -146,22 +152,19 @@ BAlert::BAlert(const char *title, const char *text, const char *button1,
{
InitObject(text, button1, button2, button3, width, spacing, type);
}
//------------------------------------------------------------------------------
BAlert::~BAlert()
{
// Probably not necessary, but it makes me feel better.
if (fAlertSem >= B_OK)
{
delete_sem(fAlertSem);
}
}
//------------------------------------------------------------------------------
BAlert::BAlert(BMessage* data)
: BWindow(data)
{
BAutolock Autolock(this);
if (Autolock.IsLocked())
{
fInvoker = NULL;
fAlertSem = -1;
fAlertVal = -1;
@ -179,16 +182,13 @@ BAlert::BAlert(BMessage* data)
else if (fButtons[0])
SetDefaultButton(fButtons[0]);
TAlertView* Master = (TAlertView*)FindView("_master_");
if (Master)
{
Master->SetBitmap(InitIcon());
}
TAlertView* master = (TAlertView*)FindView("_master_");
if (master)
master->SetBitmap(InitIcon());
// Get keys
char key;
for (int32 i = 0; i < 3; ++i)
{
for (int32 i = 0; i < 3; ++i) {
if (data->FindInt8("_but_key", i, (int8*)&key) == B_OK)
fKeys[i] = key;
}
@ -203,20 +203,21 @@ BAlert::BAlert(BMessage* data)
fButtonWidth = (button_width)temp;
AddCommonFilter(new _BAlertFilter_(this));
}
}
//------------------------------------------------------------------------------
BArchivable* BAlert::Instantiate(BMessage* data)
BArchivable*
BAlert::Instantiate(BMessage* data)
{
if (!validate_instantiation(data, "BAlert"))
{
return NULL;
}
return new BAlert(data);
}
//------------------------------------------------------------------------------
status_t BAlert::Archive(BMessage* data, bool deep) const
status_t
BAlert::Archive(BMessage* data, bool deep) const
{
BWindow::Archive(data, deep);
@ -230,8 +231,7 @@ status_t BAlert::Archive(BMessage* data, bool deep) const
data->AddInt32("_but_width", fButtonWidth);
// Stow the shortcut keys
if (fKeys[0] || fKeys[1] || fKeys[2])
{
if (fKeys[0] || fKeys[1] || fKeys[2]) {
// If we have any to save, we must save something for everyone so it
// doesn't get confusing on the unarchive.
data->AddInt8("_but_key", fKeys[0]);
@ -241,77 +241,75 @@ status_t BAlert::Archive(BMessage* data, bool deep) const
return B_OK;
}
//------------------------------------------------------------------------------
void BAlert::SetShortcut(int32 index, char key)
void
BAlert::SetShortcut(int32 index, char key)
{
if (index >= 0 && index < 3)
fKeys[index] = key;
}
//------------------------------------------------------------------------------
char BAlert::Shortcut(int32 index) const
char
BAlert::Shortcut(int32 index) const
{
if (index >= 0 && index < 3)
return fKeys[index];
return 0;
}
//------------------------------------------------------------------------------
int32 BAlert::Go()
int32
BAlert::Go()
{
fAlertSem = create_sem(0, "AlertSem");
if (fAlertSem < B_OK)
{
if (fAlertSem < B_OK) {
Quit();
return -1;
}
// Get the originating window, if it exists
BWindow* Window =
BWindow* window =
dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
Show();
// Heavily modified from TextEntryAlert code; the original didn't let the
// blocked window ever draw.
if (Window)
{
if (window) {
status_t err;
for (;;)
{
do
{
for (;;) {
do {
err = acquire_sem_etc(fAlertSem, 1, B_RELATIVE_TIMEOUT,
kSemTimeOut);
// We've (probably) had our time slice taken away from us
} while (err == B_INTERRUPTED);
if (err == B_BAD_SEM_ID)
{
if (err == B_BAD_SEM_ID) {
// Semaphore was finally nuked in MessageReceived
break;
}
Window->UpdateIfNeeded();
window->UpdateIfNeeded();
}
}
else
{
} else {
// No window to update, so just hang out until we're done.
while (acquire_sem(fAlertSem) == B_INTERRUPTED)
{
;
while (acquire_sem(fAlertSem) == B_INTERRUPTED) {
}
}
// Have to cache the value since we delete on Quit()
int32 value = fAlertVal;
if (Lock())
{
Quit();
}
return value;
}
//------------------------------------------------------------------------------
status_t BAlert::Go(BInvoker* invoker)
status_t
BAlert::Go(BInvoker* invoker)
{
// TODO: Add sound?
// It would be cool if we triggered a system sound depending on the type of
@ -320,29 +318,25 @@ status_t BAlert::Go(BInvoker* invoker)
Show();
return B_OK;
}
//------------------------------------------------------------------------------
void BAlert::MessageReceived(BMessage* msg)
void
BAlert::MessageReceived(BMessage* msg)
{
if (msg->what == kAlertButtonMsg)
{
if (msg->what != kAlertButtonMsg)
return BWindow::MessageReceived(msg);
int32 which;
if (msg->FindInt32("which", &which) == B_OK)
{
if (fAlertSem < B_OK)
{
if (msg->FindInt32("which", &which) == B_OK) {
if (fAlertSem < B_OK) {
// Semaphore hasn't been created; we're running asynchronous
if (fInvoker)
{
if (fInvoker) {
BMessage* out = fInvoker->Message();
if (out && (out->AddInt32("which", which) == B_OK ||
out->ReplaceInt32("which", which) == B_OK))
{
if (out && (out->AddInt32("which", which) == B_OK
|| out->ReplaceInt32("which", which) == B_OK))
fInvoker->Invoke();
}
}
}
else
{
} else {
// Created semaphore means were running synchronously
fAlertVal = which;
@ -355,73 +349,81 @@ void BAlert::MessageReceived(BMessage* msg)
fAlertSem = -1;
}
}
}
}
//------------------------------------------------------------------------------
void BAlert::FrameResized(float new_width, float new_height)
{
// DW: BAlerts are, by nature, not resizable. Do nothing.
BWindow::FrameResized(new_width, new_height);
}
//------------------------------------------------------------------------------
BButton* BAlert::ButtonAt(int32 index) const
void
BAlert::FrameResized(float newWidth, float newHeight)
{
BWindow::FrameResized(newWidth, newHeight);
}
BButton*
BAlert::ButtonAt(int32 index) const
{
BButton* Button = NULL;
if (index >= 0 && index < 3)
Button = fButtons[index];
return fButtons[index];
return Button;
return NULL;
}
//------------------------------------------------------------------------------
BTextView* BAlert::TextView() const
BTextView*
BAlert::TextView() const
{
return fTextView;
}
//------------------------------------------------------------------------------
BHandler* BAlert::ResolveSpecifier(BMessage* msg, int32 index,
BMessage* specifier, int32 form,
const char* property)
BHandler*
BAlert::ResolveSpecifier(BMessage* msg, int32 index,
BMessage* specifier, int32 form, const char* property)
{
// DW: Undocumented. A disassembly reveals that it calls the BWindow version
return BWindow::ResolveSpecifier(msg, index, specifier, form, property);
}
//------------------------------------------------------------------------------
status_t BAlert::GetSupportedSuites(BMessage* data)
status_t
BAlert::GetSupportedSuites(BMessage* data)
{
// DW: Undocumented, but testing reveals that it calls the BWindow version
return BWindow::GetSupportedSuites(data);
}
//------------------------------------------------------------------------------
void BAlert::DispatchMessage(BMessage* msg, BHandler* handler)
void
BAlert::DispatchMessage(BMessage* msg, BHandler* handler)
{
// DW: Undocumented. A disassembly reveals that it calls the BWindow version
BWindow::DispatchMessage(msg, handler);
}
//------------------------------------------------------------------------------
void BAlert::Quit()
void
BAlert::Quit()
{
// DW: Undocumented. A disassembly reveals that it calls the BWindow version
BWindow::Quit();
}
//------------------------------------------------------------------------------
bool BAlert::QuitRequested()
bool
BAlert::QuitRequested()
{
// DW: Undocumented. A disassembly reveals that it calls the BWindow version
return BWindow::QuitRequested();
}
//------------------------------------------------------------------------------
BPoint BAlert::AlertPosition(float width, float height)
BPoint
BAlert::AlertPosition(float width, float height)
{
BPoint result(100, 100);
BWindow* Window =
BWindow* window =
dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
BScreen Screen(Window);
BScreen screen(window);
BRect screenRect(0, 0, 640, 480);
if (Screen.IsValid())
screenRect = Screen.Frame();
if (screen.IsValid())
screenRect = screen.Frame();
// Horizontally, we're smack in the middle
result.x = (screenRect.Width() / 2.0) - (width / 2.0);
@ -431,45 +433,25 @@ BPoint BAlert::AlertPosition(float width, float height)
return result;
}
//------------------------------------------------------------------------------
status_t BAlert::Perform(perform_code d, void* arg)
status_t
BAlert::Perform(perform_code d, void* arg)
{
return BWindow::Perform(d, arg);
}
//------------------------------------------------------------------------------
void BAlert::_ReservedAlert1()
{
;
}
//------------------------------------------------------------------------------
void BAlert::_ReservedAlert2()
{
;
}
//------------------------------------------------------------------------------
void BAlert::_ReservedAlert3()
{
;
}
//------------------------------------------------------------------------------
float width_from_label(BButton *button)
{
// BButton::GetPreferredSize() does not return the minimum width
// required to fit the label. Thus, the width is computed here.
return button->StringWidth(button->Label()) + 20.0f;
}
//------------------------------------------------------------------------------
void BAlert::_ReservedAlert1() {}
void BAlert::_ReservedAlert2() {}
void BAlert::_ReservedAlert3() {}
void
BAlert::InitObject(const char* text, const char* button0, const char* button1,
const char* button2, button_width width, button_spacing spacing,
alert_type type)
{
BAutolock Autolock(this);
if (!Autolock.IsLocked())
// Bail out if a lock can't be acquired
return;
fInvoker = NULL;
fAlertSem = -1;
fAlertVal = -1;
@ -480,9 +462,9 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
fButtonWidth = width;
// Set up the "_master_" view
TAlertView* MasterView = new TAlertView(Bounds());
AddChild(MasterView);
MasterView->SetBitmap(InitIcon());
TAlertView* masterView = new TAlertView(Bounds());
AddChild(masterView);
masterView->SetBitmap(InitIcon());
// Must have at least one button
if (button0 == NULL) {
@ -496,7 +478,7 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
int buttonCount = 0;
fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b0_", button0,
new BMessage(ProtoMsg), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
MasterView->AddChild(fButtons[buttonCount]);
masterView->AddChild(fButtons[buttonCount]);
++buttonCount;
if (button1) {
@ -504,7 +486,7 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b1_", button1,
new BMessage(ProtoMsg), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
MasterView->AddChild(fButtons[buttonCount]);
masterView->AddChild(fButtons[buttonCount]);
++buttonCount;
}
if (button2) {
@ -512,7 +494,7 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b2_", button2,
new BMessage(ProtoMsg), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
MasterView->AddChild(fButtons[buttonCount]);
masterView->AddChild(fButtons[buttonCount]);
++buttonCount;
}
@ -559,7 +541,7 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
// If there are two buttons, the left wall of
// button0 needs to line up with the left wall
// of the TextView.
buttonX = (MasterView->Bitmap()) ?
buttonX = (masterView->Bitmap()) ?
kTextIconOffset : kTextLeftOffset;
if (fButtons[i + 1]->Frame().left -
(buttonX + fButtons[i]->Frame().Width()) <
@ -583,7 +565,7 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
float totalWidth = kButtonRightOffset;
totalWidth += fButtons[buttonCount - 1]->Frame().right -
fButtons[0]->Frame().left;
if (MasterView->Bitmap())
if (masterView->Bitmap())
totalWidth += kIconStripeWidth + kWindowIconOffset;
else
totalWidth += kWindowMinOffset;
@ -604,12 +586,12 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
BRect TextViewRect(kTextLeftOffset, kTextTopOffset,
Bounds().right - kTextRightOffset,
Bounds().bottom - kTextBottomOffset);
if (MasterView->Bitmap())
if (masterView->Bitmap())
TextViewRect.left = kTextIconOffset;
fTextView = new BTextView(TextViewRect, "_tv_", TextViewRect,
B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW);
MasterView->AddChild(fTextView);
masterView->AddChild(fTextView);
fTextView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
fTextView->SetText(text, strlen(text));
@ -630,37 +612,32 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
MoveTo(AlertPosition(Frame().Width(), Frame().Height()));
}
//------------------------------------------------------------------------------
BBitmap* BAlert::InitIcon()
BBitmap*
BAlert::InitIcon()
{
// After a bit of a search, I found the icons in app_server. =P
BBitmap* Icon = NULL;
BPath Path;
if (find_directory(B_BEOS_SERVERS_DIRECTORY, &Path) == B_OK)
{
Path.Append("app_server");
BFile File;
if (File.SetTo(Path.Path(), B_READ_ONLY) == B_OK)
{
BResources Resources;
if (Resources.SetTo(&File) == B_OK)
{
BBitmap* icon = NULL;
BPath path;
if (find_directory(B_BEOS_SERVERS_DIRECTORY, &path) == B_OK) {
path.Append("app_server");
BFile file;
if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK) {
BResources resources;
if (resources.SetTo(&file) == B_OK) {
// Which icon are we trying to load?
const char* iconName = ""; // Don't want any seg faults
switch (fMsgType)
{
switch (fMsgType) {
case B_INFO_ALERT:
iconName = "info";
break;
case B_IDEA_ALERT:
iconName = "idea";
break;
case B_WARNING_ALERT:
iconName = "warn";
break;
case B_STOP_ALERT:
iconName = "stop";
break;
@ -668,81 +645,79 @@ BBitmap* BAlert::InitIcon()
default:
// Alert type is either invalid or B_EMPTY_ALERT;
// either way, we're not going to load an icon
return Icon;
return NULL;
}
// Load the raw icon data
size_t size;
const void* rawIcon =
Resources.LoadResource('ICON', iconName, &size);
resources.LoadResource('ICON', iconName, &size);
if (rawIcon)
{
if (rawIcon) {
// Now build the bitmap
Icon = new BBitmap(BRect(0, 0, 31, 31), 0, B_CMAP8);
Icon->SetBits(rawIcon, size, 0, B_CMAP8);
icon = new BBitmap(BRect(0, 0, 31, 31), 0, B_CMAP8);
icon->SetBits(rawIcon, size, 0, B_CMAP8);
}
}
}
}
if (!Icon)
{
if (!icon) {
// If there's no icon, it's an empty alert indeed.
fMsgType = B_EMPTY_ALERT;
}
return Icon;
return icon;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// #pragma mark -
// #pragma mark TAlertView
// #pragma mark -
//------------------------------------------------------------------------------
// #pragma mark - TAlertView
TAlertView::TAlertView(BRect frame)
: BView(frame, "TAlertView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
fIconBitmap(NULL)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
//------------------------------------------------------------------------------
TAlertView::TAlertView(BMessage* archive)
: BView(archive),
fIconBitmap(NULL)
{
}
//------------------------------------------------------------------------------
TAlertView::~TAlertView()
{
if (fIconBitmap)
{
delete fIconBitmap;
}
}
//------------------------------------------------------------------------------
TAlertView* TAlertView::Instantiate(BMessage* archive)
TAlertView*
TAlertView::Instantiate(BMessage* archive)
{
if (!validate_instantiation(archive, "TAlertView"))
{
return NULL;
}
return new TAlertView(archive);
}
//------------------------------------------------------------------------------
status_t TAlertView::Archive(BMessage* archive, bool deep)
status_t
TAlertView::Archive(BMessage* archive, bool deep)
{
return BView::Archive(archive, deep);
}
//------------------------------------------------------------------------------
void TAlertView::Draw(BRect updateRect)
void
TAlertView::Draw(BRect updateRect)
{
// Here's the fun stuff
if (fIconBitmap)
{
if (fIconBitmap) {
BRect StripeRect = Bounds();
StripeRect.right = kIconStripeWidth;
SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
@ -753,36 +728,32 @@ void TAlertView::Draw(BRect updateRect)
SetDrawingMode(B_OP_COPY);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// #pragma mark -
// #pragma mark _BAlertFilter_
// #pragma mark -
//------------------------------------------------------------------------------
// #pragma mark - _BAlertFilter_
_BAlertFilter_::_BAlertFilter_(BAlert* Alert)
: BMessageFilter(B_KEY_DOWN),
fAlert(Alert)
{
}
//------------------------------------------------------------------------------
_BAlertFilter_::~_BAlertFilter_()
{
;
}
//------------------------------------------------------------------------------
filter_result _BAlertFilter_::Filter(BMessage* msg, BHandler** target)
filter_result
_BAlertFilter_::Filter(BMessage* msg, BHandler** target)
{
if (msg->what == B_KEY_DOWN)
{
if (msg->what == B_KEY_DOWN) {
char byte;
if (msg->FindInt8("byte", (int8*)&byte) == B_OK)
{
for (int i = 0; i < 3; ++i)
{
if (byte == fAlert->Shortcut(i) && fAlert->ButtonAt(i))
{
if (msg->FindInt8("byte", (int8*)&byte) == B_OK) {
for (int i = 0; i < 3; ++i) {
if (byte == fAlert->Shortcut(i) && fAlert->ButtonAt(i)) {
char space = ' ';
fAlert->ButtonAt(i)->KeyDown(&space, 1);
@ -794,12 +765,3 @@ filter_result _BAlertFilter_::Filter(BMessage* msg, BHandler** target)
return B_DISPATCH_MESSAGE;
}
//------------------------------------------------------------------------------
/*
* $Log $
*
* $Id $
*
*/