Rewrote BAlert button layout routine. Made it much simpler, and it's now

also font sensitive (really, it wasn't before).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17861 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-06-16 16:22:53 +00:00
parent 60d1530802
commit 9a3c8b14fd
2 changed files with 214 additions and 306 deletions

View File

@ -1,52 +1,24 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2002, OpenBeOS
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: Alert.h
// Author: Erik Jaesler (erik@cgsoftware.com)
// Description: BAlert displays a modal alert window.
//------------------------------------------------------------------------------
/*
* Copyright 2001-2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Erik Jaesler (erik@cgsoftware.com)
*/
#ifndef _ALERT_H
#define _ALERT_H
// Standard Includes -----------------------------------------------------------
// System Includes -------------------------------------------------------------
#include <BeBuild.h>
#include <Window.h>
// Project Includes ------------------------------------------------------------
// Local Includes --------------------------------------------------------------
// Local Defines ---------------------------------------------------------------
// Globals ---------------------------------------------------------------------
class BBitmap;
class BButton;
class BInvoker;
class BTextView;
// enum for flavors of alert ---------------------------------------------------
// enum for flavors of alert
enum alert_type {
B_EMPTY_ALERT = 0,
B_INFO_ALERT,
@ -55,101 +27,81 @@ enum alert_type {
B_STOP_ALERT
};
enum button_spacing {
B_EVEN_SPACING = 0,
B_OFFSET_SPACING
};
// BAlert class ----------------------------------------------------------------
class BAlert : public BWindow
{
public:
BAlert( const char *title,
const char *text,
const char *button1,
const char *button2 = NULL,
const char *button3 = NULL,
button_width width = B_WIDTH_AS_USUAL,
alert_type type = B_INFO_ALERT);
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 = B_INFO_ALERT);
virtual ~BAlert();
// Archiving
BAlert(BMessage *data);
static BArchivable *Instantiate(BMessage *data);
virtual status_t Archive(BMessage *data, bool deep = true) const;
// BAlert guts
void SetShortcut(int32 button_index, char key);
char Shortcut(int32 button_index) const;
class BAlert : public BWindow {
public:
BAlert(const char* title, const char* text,
const char* button1, const char* button2 = NULL,
const char* button3 = NULL,
button_width width = B_WIDTH_AS_USUAL,
alert_type type = B_INFO_ALERT);
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 = B_INFO_ALERT);
virtual ~BAlert();
int32 Go();
status_t Go(BInvoker *invoker);
// Archiving
BAlert(BMessage *data);
static BArchivable *Instantiate(BMessage *data);
virtual status_t Archive(BMessage *data, bool deep = true) const;
virtual void MessageReceived(BMessage *an_event);
virtual void FrameResized(float new_width, float new_height);
BButton *ButtonAt(int32 index) const;
BTextView *TextView() const;
// BAlert guts
void SetShortcut(int32 button_index, char key);
char Shortcut(int32 button_index) const;
virtual BHandler *ResolveSpecifier(BMessage *msg,
int32 index,
BMessage *specifier,
int32 form,
const char *property);
virtual status_t GetSupportedSuites(BMessage *data);
int32 Go();
status_t Go(BInvoker *invoker);
virtual void DispatchMessage(BMessage *msg, BHandler *handler);
virtual void Quit();
virtual bool QuitRequested();
virtual void MessageReceived(BMessage *an_event);
virtual void FrameResized(float new_width, float new_height);
BButton* ButtonAt(int32 index) const;
BTextView* TextView() const;
static BPoint AlertPosition(float width, float height);
virtual BHandler* ResolveSpecifier(BMessage* message, int32 index,
BMessage* specifier, int32 form,
const char* property);
virtual status_t GetSupportedSuites(BMessage *data);
// Private or reserved ---------------------------------------------------------
virtual status_t Perform(perform_code d, void *arg);
virtual void DispatchMessage(BMessage* message, BHandler* handler);
virtual void Quit();
virtual bool QuitRequested();
private:
friend class _BAlertFilter_;
static BPoint AlertPosition(float width, float height);
virtual void _ReservedAlert1();
virtual void _ReservedAlert2();
virtual void _ReservedAlert3();
virtual status_t Perform(perform_code d, void *arg);
void InitObject(const char *text,
const char *button1,
const char *button2 = NULL,
const char *button3 = NULL,
button_width width = B_WIDTH_AS_USUAL,
button_spacing spacing = B_EVEN_SPACING,
alert_type type = B_INFO_ALERT);
BBitmap *InitIcon();
private:
friend class _BAlertFilter_;
sem_id fAlertSem;
int32 fAlertVal;
BButton *fButtons[3];
BTextView *fTextView;
char fKeys[3];
alert_type fMsgType;
button_width fButtonWidth;
BInvoker *fInvoker;
uint32 _reserved[4];
virtual void _ReservedAlert1();
virtual void _ReservedAlert2();
virtual void _ReservedAlert3();
void _InitObject(const char* text, const char* button1,
const char* button2 = NULL,
const char* button3 = NULL,
button_width width = B_WIDTH_AS_USUAL,
button_spacing spacing = B_EVEN_SPACING,
alert_type type = B_INFO_ALERT);
BBitmap* _InitIcon();
BButton* _CreateButton(int32 which, const char* label);
sem_id fAlertSem;
int32 fAlertValue;
BButton* fButtons[3];
BTextView* fTextView;
char fKeys[3];
alert_type fMsgType;
button_width fButtonWidth;
BInvoker* fInvoker;
uint32 _reserved[4];
};
//------------------------------------------------------------------------------
#endif // _ALERT_H
/*
* $Log $
*
* $Id $
*
*/

View File

@ -1,91 +1,69 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2002, OpenBeOS
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: Alert.cpp
// Author: Erik Jaesler (erik@cgsoftware.com)
// Description: BAlert displays a modal alert window.
//------------------------------------------------------------------------------
/*
* Copyright 2001-2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Erik Jaesler (erik@cgsoftware.com)
* Axel Dörfler, axeld@pinc-software.de
*/
// Standard Includes -----------------------------------------------------------
#include <string.h>
//! BAlert displays a modal alert window.
// System Includes -------------------------------------------------------------
#include <Alert.h>
#include <Autolock.h>
#include <Beep.h>
#include <Bitmap.h>
#include <Button.h>
#include <File.h>
#include <FindDirectory.h>
#include <Invoker.h>
#include <Looper.h>
#include <Message.h>
#include <MessageFilter.h>
#include <Alert.h>
#include <Bitmap.h>
#include <Button.h>
#include <Path.h>
#include <Resources.h>
#include <Screen.h>
#include <TextView.h>
#include <View.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include <Resources.h>
#include <Beep.h>
#include <Autolock.h>
#include <new>
#include <stdio.h>
#include <string.h>
//#define DEBUG_ALERT
#ifdef DEBUG_ALERT
#define FTRACE(x) fprintf(x)
# define FTRACE(x) fprintf(x)
#else
#define FTRACE(x) /* nothing */
# define FTRACE(x) /* nothing */
#endif
// Default size of the Alert window.
#define DEFAULT_RECT BRect(0, 0, 310, 75)
#define max(LHS, RHS) ((LHS) > (RHS) ? (LHS) : (RHS))
// Globals ---------------------------------------------------------------------
static const unsigned int kAlertButtonMsg = 'ALTB';
static const int kSemTimeOut = 50000;
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 kLeftOffset = 10;
static const int kTopOffset = 6;
static const int kBottomOffset = 8;
static const int kRightOffset = 8;
static const int kButtonSpacing = 6;
static const int kButtonOffsetSpacing = 62;
static const int kButtonUsualWidth = 75;
static const int kWindowIconOffset = 27;
static const int kWindowMinWidth = 310;
static const int kWindowMinOffset = 12;
static const int kWindowMinWidth = 310;
static const int kWindowOffsetMinWidth = 335;
static const int kIconStripeWidth = 30;
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;
static const int kTextButtonOffset = 10;
//------------------------------------------------------------------------------
class TAlertView : public BView {
public:
TAlertView(BRect frame);
@ -108,11 +86,6 @@ class TAlertView : public BView {
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 {
public:
_BAlertFilter_(BAlert* Alert);
@ -125,35 +98,26 @@ class _BAlertFilter_ : public BMessageFilter {
};
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)
const char *button2, const char *button3, button_width width,
alert_type type)
: BWindow(DEFAULT_RECT, title, B_MODAL_WINDOW,
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS)
{
InitObject(text, button1, button2, button3, width, B_EVEN_SPACING, type);
_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)
const char *button2, const char *button3, button_width width,
button_spacing spacing, alert_type type)
: BWindow(DEFAULT_RECT, title, B_MODAL_WINDOW,
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS)
{
InitObject(text, button1, button2, button3, width, spacing, type);
_InitObject(text, button1, button2, button3, width, spacing, type);
}
@ -170,7 +134,7 @@ BAlert::BAlert(BMessage* data)
{
fInvoker = NULL;
fAlertSem = -1;
fAlertVal = -1;
fAlertValue = -1;
fTextView = (BTextView*)FindView("_tv_");
@ -185,9 +149,9 @@ BAlert::BAlert(BMessage* data)
else if (fButtons[0])
SetDefaultButton(fButtons[0]);
TAlertView* master = (TAlertView*)FindView("_master_");
if (master)
master->SetBitmap(InitIcon());
TAlertView* view = (TAlertView*)FindView("_master_");
if (view)
view->SetBitmap(_InitIcon());
// Get keys
char key;
@ -309,7 +273,7 @@ BAlert::Go()
}
// Have to cache the value since we delete on Quit()
int32 value = fAlertVal;
int32 value = fAlertValue;
if (Lock())
Quit();
@ -345,7 +309,7 @@ BAlert::MessageReceived(BMessage* msg)
PostMessage(B_QUIT_REQUESTED);
} else {
// Created semaphore means were running synchronously
fAlertVal = which;
fAlertValue = which;
// TextAlertVar does release_sem() below, and then sets the
// member var. That doesn't make much sense to me, since we
@ -455,23 +419,23 @@ void BAlert::_ReservedAlert3() {}
void
BAlert::InitObject(const char* text, const char* button0, const char* button1,
const char* button2, button_width width, button_spacing spacing,
BAlert::_InitObject(const char* text, const char* button0, const char* button1,
const char* button2, button_width buttonWidth, button_spacing spacing,
alert_type type)
{
fInvoker = NULL;
fAlertSem = -1;
fAlertVal = -1;
fAlertValue = -1;
fButtons[0] = fButtons[1] = fButtons[2] = NULL;
fTextView = NULL;
fKeys[0] = fKeys[1] = fKeys[2] = 0;
fMsgType = type;
fButtonWidth = width;
fButtonWidth = buttonWidth;
// Set up the "_master_" view
TAlertView* masterView = new TAlertView(Bounds());
AddChild(masterView);
masterView->SetBitmap(InitIcon());
TAlertView* view = new TAlertView(Bounds());
AddChild(view);
view->SetBitmap(_InitIcon());
// Must have at least one button
if (button0 == NULL) {
@ -479,132 +443,89 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
button0 = "";
}
BMessage protoMsg(kAlertButtonMsg);
protoMsg.AddInt32("which", 0);
// Set up the buttons
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]);
++buttonCount;
if (button1) {
protoMsg.ReplaceInt32("which", 1);
fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b1_", button1,
new BMessage(protoMsg), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
int32 buttonCount = 1;
view->AddChild(fButtons[0] = _CreateButton(0, button0));
masterView->AddChild(fButtons[buttonCount]);
++buttonCount;
}
if (button2) {
protoMsg.ReplaceInt32("which", 2);
fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b2_", button2,
new BMessage(protoMsg), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
masterView->AddChild(fButtons[buttonCount]);
++buttonCount;
if (button1 != NULL) {
view->AddChild(fButtons[1] = _CreateButton(1, button1));
buttonCount++;
}
SetDefaultButton(fButtons[buttonCount - 1]);
if (button2 != NULL) {
view->AddChild(fButtons[2] = _CreateButton(2, button2));
buttonCount++;
}
// Find the widest button only if the widest value needs to be known.
float maxWidth = 0;
if (fButtonWidth == B_WIDTH_FROM_WIDEST) {
for (int i = 0; i < buttonCount; ++i) {
float temp = width_from_label(fButtons[i]);
maxWidth = max(maxWidth, temp);
float maxWidth = 0;
for (int i = 0; i < buttonCount; i++) {
float width = fButtons[i]->Bounds().Width();
if (width > maxWidth)
maxWidth = width;
}
// resize buttons
for (int i = 0; i < buttonCount; i++) {
fButtons[i]->ResizeTo(maxWidth, fButtons[i]->Bounds().Height());
}
}
for (int i = buttonCount - 1; i >= 0; --i) {
// Determine the button's size
float buttonWidth = 0, buttonHeight = 0;
fButtons[i]->GetPreferredSize(&buttonWidth, &buttonHeight);
if (fButtonWidth == B_WIDTH_FROM_WIDEST)
buttonWidth = maxWidth;
else if (fButtonWidth == B_WIDTH_FROM_LABEL)
buttonWidth = width_from_label(fButtons[i]);
else // B_WIDTH_AS_USUAL
buttonWidth = max(buttonWidth, kButtonUsualWidth);
fButtons[i]->ResizeTo(buttonWidth, buttonHeight);
float defaultButtonFrameWidth = -fButtons[buttonCount - 1]->Bounds().Width() / 2.0f;
SetDefaultButton(fButtons[buttonCount - 1]);
defaultButtonFrameWidth += fButtons[buttonCount - 1]->Bounds().Width() / 2.0f;
// Determine the button's placement
float buttonX, buttonY;
buttonY = Bounds().bottom - buttonHeight;
if (i == buttonCount - 1) {
// The right-most button
buttonX = Bounds().right - fButtons[i]->Frame().Width() -
kButtonRightOffset;
buttonY -= kDefButtonBottomOffset;
} else {
buttonX = fButtons[i + 1]->Frame().left -
fButtons[i]->Frame().Width() - kButtonSpaceOffset;
buttonY -= kButtonBottomOffset;
if (i == 0) {
if (spacing == B_OFFSET_SPACING) {
if (buttonCount == 3)
buttonX -= kButtonOffsetSpaceOffset;
else {
// If there are two buttons, the left wall of
// button0 needs to line up with the left wall
// of the TextView.
buttonX = (masterView->Bitmap()) ?
kTextIconOffset : kTextLeftOffset;
if (fButtons[i + 1]->Frame().left -
(buttonX + fButtons[i]->Frame().Width()) <
kButtonMinOffsetSpaceOffset) {
// Recompute buttonX using min offset space
// if using the current buttonX would not
// provide enough space or cause an overlap.
buttonX = fButtons[i + 1]->Frame().left -
fButtons[i]->Frame().Width() -
kButtonMinOffsetSpaceOffset;
}
}
} else if (buttonCount == 3)
buttonX -= 3;
}
}
fButtons[i]->MoveTo(buttonX, buttonY);
} // for (int i = buttonCount - 1; i >= 0; --i)
// Layout buttons
float fontFactor = be_plain_font->Size() / 11.0f;
for (int i = buttonCount - 1; i >= 0; --i) {
float x = -fButtons[i]->Bounds().Width();
if (i + 1 == buttonCount)
x += Bounds().right - kRightOffset + defaultButtonFrameWidth;
else
x += fButtons[i + 1]->Frame().left - kButtonSpacing;
if (buttonCount > 1 && i == 0 && spacing == B_OFFSET_SPACING)
x -= kButtonOffsetSpacing * fontFactor;
fButtons[i]->MoveTo(x, fButtons[i]->Frame().top);
}
// Adjust the window's width, if necessary
float totalWidth = kButtonRightOffset;
totalWidth += fButtons[buttonCount - 1]->Frame().right -
fButtons[0]->Frame().left;
if (masterView->Bitmap())
float totalWidth = kRightOffset + fButtons[buttonCount - 1]->Frame().right
- defaultButtonFrameWidth - fButtons[0]->Frame().left;
if (view->Bitmap())
totalWidth += kIconStripeWidth + kWindowIconOffset;
else
totalWidth += kWindowMinOffset;
if (spacing == B_OFFSET_SPACING) {
totalWidth -= 2;
if (buttonCount == 3)
totalWidth = max(kWindowOffsetMinWidth, totalWidth);
else
totalWidth = max(kWindowMinWidth, totalWidth);
} else {
totalWidth += 5;
totalWidth = max(kWindowMinWidth, totalWidth);
}
ResizeTo(totalWidth, Bounds().Height());
float width = (spacing == B_OFFSET_SPACING
? kWindowOffsetMinWidth : kWindowMinWidth) * fontFactor;
ResizeTo(max_c(totalWidth, width), Bounds().Height());
// Set up the text view
BRect textViewRect(kTextLeftOffset, kTextTopOffset,
Bounds().right - kTextRightOffset,
Bounds().bottom - kTextBottomOffset);
if (masterView->Bitmap())
BRect textViewRect(kLeftOffset, kTopOffset,
Bounds().right - kRightOffset,
fButtons[0]->Frame().top - kTextButtonOffset);
if (view->Bitmap())
textViewRect.left = kTextIconOffset;
fTextView = new BTextView(textViewRect, "_tv_", textViewRect,
fTextView = new BTextView(textViewRect, "_tv_",
textViewRect.OffsetByCopy(B_ORIGIN),
B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW);
masterView->AddChild(fTextView);
fTextView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
fTextView->SetText(text, strlen(text));
fTextView->MakeEditable(false);
fTextView->MakeSelectable(false);
fTextView->SetWordWrap(true);
view->AddChild(fTextView);
// Now resize the TextView vertically so that all the text is visible
float textHeight = fTextView->TextHeight(0, fTextView->CountLines());
@ -622,7 +543,7 @@ BAlert::InitObject(const char* text, const char* button0, const char* button1,
BBitmap*
BAlert::InitIcon()
BAlert::_InitIcon()
{
// After a bit of a search, I found the icons in app_server. =P
BBitmap* icon = NULL;
@ -665,8 +586,9 @@ BAlert::InitIcon()
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 (std::nothrow) BBitmap(BRect(0, 0, 31, 31), 0, B_CMAP8);
if (icon != NULL)
icon->SetBits(rawIcon, size, 0, B_CMAP8);
} else {
FTRACE((stderr, "BAlert::InitIcon() - Icon resource not found\n"));
}
@ -680,7 +602,7 @@ BAlert::InitIcon()
FTRACE((stderr, "BAlert::InitIcon() - find_directory failed: %s\n", strerror(status)));
}
if (!icon) {
if (icon == NULL) {
// If there's no icon, it's an empty alert indeed.
fMsgType = B_EMPTY_ALERT;
}
@ -689,7 +611,41 @@ BAlert::InitIcon()
}
//------------------------------------------------------------------------------
BButton*
BAlert::_CreateButton(int32 which, const char* label)
{
BMessage* message = new BMessage(kAlertButtonMsg);
if (message == NULL)
return NULL;
message->AddInt32("which", which);
BRect rect;
rect.top = Bounds().bottom - kBottomOffset;
rect.bottom = rect.top;
char name[32];
snprintf(name, sizeof(name), "_b%ld_", which);
BButton* button = new (std::nothrow) BButton(rect, name, label, message,
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
if (button == NULL)
return NULL;
float width, height;
button->GetPreferredSize(&width, &height);
if (fButtonWidth == B_WIDTH_AS_USUAL) {
float fontFactor = be_plain_font->Size() / 11.0f;
width = max_c(width, kButtonUsualWidth * fontFactor);
}
button->ResizeTo(width, height);
button->MoveBy(0.0f, -height);
return button;
}
// #pragma mark - TAlertView