BAlert: use layout API, allow any number of buttons.
* Added default constructor; you can now alter the complete behavior via setters, and also add buttons afterwards.
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
/*
|
||||
* Copyright 2001-2014 Haiku, Inc. All rights reserved.
|
||||
* Copyright 2001-2015 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _ALERT_H
|
||||
#define _ALERT_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
|
||||
@@ -26,78 +28,97 @@ enum button_spacing {
|
||||
|
||||
class BBitmap;
|
||||
class BButton;
|
||||
class BGroupLayout;
|
||||
class BInvoker;
|
||||
class BTextView;
|
||||
class TAlertView;
|
||||
|
||||
|
||||
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();
|
||||
BAlert();
|
||||
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);
|
||||
BAlert(BMessage* data);
|
||||
virtual ~BAlert();
|
||||
|
||||
// Archiving
|
||||
BAlert(BMessage* data);
|
||||
static BArchivable *Instantiate(BMessage* data);
|
||||
virtual status_t Archive(BMessage* data, bool deep = true) const;
|
||||
// Archiving
|
||||
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;
|
||||
// BAlert guts
|
||||
alert_type Type() const;
|
||||
void SetType(alert_type type);
|
||||
void SetIcon(BBitmap* bitmap);
|
||||
void SetText(const char* text);
|
||||
void SetButtonSpacing(button_spacing spacing);
|
||||
void SetButtonWidth(button_width width);
|
||||
|
||||
int32 Go();
|
||||
status_t Go(BInvoker* invoker);
|
||||
void SetShortcut(int32 buttonIndex, char key);
|
||||
char Shortcut(int32 buttonIndex) const;
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void FrameResized(float new_width, float new_height);
|
||||
BButton* ButtonAt(int32 index) const;
|
||||
BTextView* TextView() const;
|
||||
int32 Go();
|
||||
status_t Go(BInvoker* invoker);
|
||||
|
||||
virtual BHandler* ResolveSpecifier(BMessage* message, int32 index,
|
||||
BMessage* specifier, int32 what,
|
||||
const char* property);
|
||||
virtual status_t GetSupportedSuites(BMessage* data);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void FrameResized(float newWidth, float newHeight);
|
||||
|
||||
virtual void DispatchMessage(BMessage* message, BHandler* handler);
|
||||
virtual void Quit();
|
||||
virtual bool QuitRequested();
|
||||
void AddButton(const char* label, char key = 0);
|
||||
int32 CountButtons() const;
|
||||
BButton* ButtonAt(int32 index) const;
|
||||
|
||||
static BPoint AlertPosition(float width, float height);
|
||||
BTextView* TextView() const;
|
||||
|
||||
virtual status_t Perform(perform_code d, void* arg);
|
||||
virtual BHandler* ResolveSpecifier(BMessage* message, int32 index,
|
||||
BMessage* specifier, int32 form,
|
||||
const char* property);
|
||||
virtual status_t GetSupportedSuites(BMessage* data);
|
||||
|
||||
virtual void DispatchMessage(BMessage* message,
|
||||
BHandler* handler);
|
||||
virtual void Quit();
|
||||
virtual bool QuitRequested();
|
||||
|
||||
virtual status_t Perform(perform_code d, void* arg);
|
||||
|
||||
static BPoint AlertPosition(float width, float height);
|
||||
|
||||
private:
|
||||
friend class _BAlertFilter_;
|
||||
virtual void _ReservedAlert1();
|
||||
virtual void _ReservedAlert2();
|
||||
virtual void _ReservedAlert3();
|
||||
|
||||
virtual void _ReservedAlert1();
|
||||
virtual void _ReservedAlert2();
|
||||
virtual void _ReservedAlert3();
|
||||
void _Init(const char* text, const char* button1,
|
||||
const char* button2, const char* button3,
|
||||
button_width width, button_spacing spacing,
|
||||
alert_type type);
|
||||
BBitmap* _CreateTypeIcon();
|
||||
BButton* _CreateButton(int32 which, const char* label);
|
||||
void _Prepare();
|
||||
|
||||
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];
|
||||
private:
|
||||
sem_id fAlertSem;
|
||||
int32 fAlertValue;
|
||||
TAlertView* fIconView;
|
||||
BTextView* fTextView;
|
||||
BGroupLayout* fButtonLayout;
|
||||
std::vector<BButton*> fButtons;
|
||||
std::vector<char> fKeys;
|
||||
uint8 fType;
|
||||
uint8 fButtonSpacing;
|
||||
uint8 fButtonWidth;
|
||||
BInvoker* fInvoker;
|
||||
uint32 _reserved[1];
|
||||
};
|
||||
|
||||
|
||||
#endif // _ALERT_H
|
||||
|
||||
+299
-302
@@ -9,31 +9,28 @@
|
||||
*/
|
||||
|
||||
|
||||
// BAlert displays a modal alert window.
|
||||
//! BAlert displays a modal alert window.
|
||||
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Autolock.h>
|
||||
#include <Beep.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Button.h>
|
||||
#include <File.h>
|
||||
#include <ControlLook.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Font.h>
|
||||
#include <IconUtils.h>
|
||||
#include <Invoker.h>
|
||||
#include <Looper.h>
|
||||
#include <Message.h>
|
||||
#include <LayoutBuilder.h>
|
||||
#include <MenuField.h>
|
||||
#include <MessageFilter.h>
|
||||
#include <Path.h>
|
||||
#include <Resources.h>
|
||||
#include <Screen.h>
|
||||
#include <TextView.h>
|
||||
#include <View.h>
|
||||
#include <String.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include <binary_compatibility/Interface.h>
|
||||
|
||||
@@ -42,111 +39,102 @@
|
||||
#ifdef DEBUG_ALERT
|
||||
# define FTRACE(x) fprintf(x)
|
||||
#else
|
||||
# define FTRACE(x) /* nothing */
|
||||
# define FTRACE(x) ;
|
||||
#endif
|
||||
|
||||
// Default size of the Alert window.
|
||||
#define DEFAULT_RECT BRect(0, 0, 310, 75)
|
||||
#define max(LHS, RHS) ((LHS) > (RHS) ? (LHS) : (RHS))
|
||||
|
||||
class TAlertView : public BView {
|
||||
public:
|
||||
TAlertView();
|
||||
TAlertView(BMessage* archive);
|
||||
~TAlertView();
|
||||
|
||||
static TAlertView* Instantiate(BMessage* archive);
|
||||
virtual status_t Archive(BMessage* archive,
|
||||
bool deep = true) const;
|
||||
|
||||
virtual void GetPreferredSize(float* _width, float* _height);
|
||||
virtual BSize MaxSize();
|
||||
virtual void Draw(BRect updateRect);
|
||||
|
||||
void SetBitmap(BBitmap* Icon)
|
||||
{ fIconBitmap = Icon; }
|
||||
BBitmap* Bitmap()
|
||||
{ return fIconBitmap; }
|
||||
|
||||
private:
|
||||
BBitmap* fIconBitmap;
|
||||
};
|
||||
|
||||
|
||||
class _BAlertFilter_ : public BMessageFilter {
|
||||
public:
|
||||
_BAlertFilter_(BAlert* Alert);
|
||||
~_BAlertFilter_();
|
||||
|
||||
virtual filter_result Filter(BMessage* msg, BHandler** target);
|
||||
|
||||
private:
|
||||
BAlert* fAlert;
|
||||
};
|
||||
|
||||
|
||||
static const unsigned int kAlertButtonMsg = 'ALTB';
|
||||
static const int kSemTimeOut = 50000;
|
||||
|
||||
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 kButtonUsualWidth = 55;
|
||||
static const int kIconStripeWidth = 30;
|
||||
|
||||
static const int kWindowIconOffset = 27;
|
||||
static const int kWindowMinOffset = 12;
|
||||
static const int kWindowMinWidth = 310;
|
||||
static const int kWindowOffsetMinWidth = 335;
|
||||
|
||||
static const int kIconStripeWidth = 30;
|
||||
|
||||
static const int kTextButtonOffset = 10;
|
||||
|
||||
static inline int32
|
||||
icon_layout_scale()
|
||||
{
|
||||
#ifdef __HAIKU__
|
||||
return max_c(1, ((int32)be_plain_font->Size() + 15) / 16);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
class TAlertView : public BView {
|
||||
public:
|
||||
TAlertView(BRect frame);
|
||||
TAlertView(BMessage* archive);
|
||||
~TAlertView();
|
||||
|
||||
static TAlertView* Instantiate(BMessage* archive);
|
||||
virtual status_t Archive(BMessage* archive, bool deep = true) const;
|
||||
|
||||
virtual void Draw(BRect updateRect);
|
||||
|
||||
// These functions (or something analogous) are missing from libbe.so's
|
||||
// dump. I can only assume that the bitmap is a public var in the
|
||||
// original implementation -- or BAlert is a friend of TAlertView.
|
||||
// Neither one is necessary, since I can just add these.
|
||||
void SetBitmap(BBitmap* Icon) { fIconBitmap = Icon; }
|
||||
BBitmap* Bitmap() { return fIconBitmap; }
|
||||
|
||||
private:
|
||||
BBitmap* fIconBitmap;
|
||||
};
|
||||
|
||||
class _BAlertFilter_ : public BMessageFilter {
|
||||
public:
|
||||
_BAlertFilter_(BAlert* Alert);
|
||||
~_BAlertFilter_();
|
||||
|
||||
virtual filter_result Filter(BMessage* msg, BHandler** target);
|
||||
|
||||
private:
|
||||
BAlert* fAlert;
|
||||
};
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
// #pragma mark - BAlert
|
||||
BAlert::BAlert()
|
||||
:
|
||||
BWindow(BRect(0, 0, 100, 100), "", B_MODAL_WINDOW,
|
||||
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS)
|
||||
{
|
||||
_Init(NULL, NULL, NULL, NULL, B_WIDTH_FROM_WIDEST, B_EVEN_SPACING,
|
||||
B_INFO_ALERT);
|
||||
}
|
||||
|
||||
|
||||
BAlert::BAlert(const char *title, const char *text, const char *button1,
|
||||
const char *button2, const char *button3, button_width width,
|
||||
alert_type type)
|
||||
: BWindow(DEFAULT_RECT, title, B_MODAL_WINDOW,
|
||||
:
|
||||
BWindow(BRect(0, 0, 100, 100), title, B_MODAL_WINDOW,
|
||||
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS)
|
||||
{
|
||||
_InitObject(text, button1, button2, button3, width, B_EVEN_SPACING, type);
|
||||
_Init(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)
|
||||
: BWindow(DEFAULT_RECT, title, B_MODAL_WINDOW,
|
||||
:
|
||||
BWindow(BRect(0, 0, 100, 100), title, B_MODAL_WINDOW,
|
||||
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS)
|
||||
{
|
||||
_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);
|
||||
_Init(text, button1, button2, button3, width, spacing, type);
|
||||
}
|
||||
|
||||
|
||||
BAlert::BAlert(BMessage* data)
|
||||
: BWindow(data)
|
||||
:
|
||||
BWindow(data)
|
||||
{
|
||||
fInvoker = NULL;
|
||||
fAlertSem = -1;
|
||||
@@ -154,20 +142,12 @@ BAlert::BAlert(BMessage* data)
|
||||
|
||||
fTextView = (BTextView*)FindView("_tv_");
|
||||
|
||||
fButtons[0] = (BButton*)FindView("_b0_");
|
||||
fButtons[1] = (BButton*)FindView("_b1_");
|
||||
fButtons[2] = (BButton*)FindView("_b2_");
|
||||
|
||||
if (fButtons[2])
|
||||
SetDefaultButton(fButtons[2]);
|
||||
else if (fButtons[1])
|
||||
SetDefaultButton(fButtons[1]);
|
||||
else if (fButtons[0])
|
||||
SetDefaultButton(fButtons[0]);
|
||||
// TODO: window loses default button on dearchive!
|
||||
// TODO: ButtonAt() doesn't work afterwards (also affects shortcuts)
|
||||
|
||||
TAlertView* view = (TAlertView*)FindView("_master_");
|
||||
if (view)
|
||||
view->SetBitmap(_InitIcon());
|
||||
view->SetBitmap(_CreateTypeIcon());
|
||||
|
||||
// Get keys
|
||||
char key;
|
||||
@@ -176,19 +156,18 @@ BAlert::BAlert(BMessage* data)
|
||||
fKeys[i] = key;
|
||||
}
|
||||
|
||||
int32 temp;
|
||||
// Get alert type
|
||||
if (data->FindInt32("_atype", &temp) == B_OK)
|
||||
fMsgType = (alert_type)temp;
|
||||
|
||||
// Get button width
|
||||
if (data->FindInt32("_but_width", &temp) == B_OK)
|
||||
fButtonWidth = (button_width)temp;
|
||||
|
||||
AddCommonFilter(new(std::nothrow) _BAlertFilter_(this));
|
||||
}
|
||||
|
||||
|
||||
BAlert::~BAlert()
|
||||
{
|
||||
// Probably not necessary, but it makes me feel better.
|
||||
if (fAlertSem >= B_OK)
|
||||
delete_sem(fAlertSem);
|
||||
}
|
||||
|
||||
|
||||
BArchivable*
|
||||
BAlert::Instantiate(BMessage* data)
|
||||
{
|
||||
@@ -210,7 +189,7 @@ BAlert::Archive(BMessage* data, bool deep) const
|
||||
|
||||
// Stow the alert type
|
||||
if (ret == B_OK)
|
||||
ret = data->AddInt32("_atype", fMsgType);
|
||||
ret = data->AddInt32("_atype", fType);
|
||||
|
||||
// Stow the button width
|
||||
if (ret == B_OK)
|
||||
@@ -232,10 +211,52 @@ BAlert::Archive(BMessage* data, bool deep) const
|
||||
}
|
||||
|
||||
|
||||
alert_type
|
||||
BAlert::Type() const
|
||||
{
|
||||
return (alert_type)fType;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BAlert::SetType(alert_type type)
|
||||
{
|
||||
fType = type;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BAlert::SetText(const char* text)
|
||||
{
|
||||
TextView()->SetText(text);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BAlert::SetIcon(BBitmap* bitmap)
|
||||
{
|
||||
fIconView->SetBitmap(bitmap);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BAlert::SetButtonSpacing(button_spacing spacing)
|
||||
{
|
||||
fButtonSpacing = spacing;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BAlert::SetButtonWidth(button_width width)
|
||||
{
|
||||
fButtonWidth = width;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BAlert::SetShortcut(int32 index, char key)
|
||||
{
|
||||
if (index >= 0 && index < 3)
|
||||
if (index >= 0 && (size_t)index < fKeys.size())
|
||||
fKeys[index] = key;
|
||||
}
|
||||
|
||||
@@ -243,7 +264,8 @@ BAlert::SetShortcut(int32 index, char key)
|
||||
char
|
||||
BAlert::Shortcut(int32 index) const
|
||||
{
|
||||
if (index >= 0 && index < 3)
|
||||
|
||||
if (index >= 0 && (size_t)index < fKeys.size())
|
||||
return fKeys[index];
|
||||
|
||||
return 0;
|
||||
@@ -254,29 +276,28 @@ int32
|
||||
BAlert::Go()
|
||||
{
|
||||
fAlertSem = create_sem(0, "AlertSem");
|
||||
if (fAlertSem < B_OK) {
|
||||
if (fAlertSem < 0) {
|
||||
Quit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the originating window, if it exists
|
||||
BWindow* window =
|
||||
dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
|
||||
BWindow* window = dynamic_cast<BWindow*>(
|
||||
BLooper::LooperForThread(find_thread(NULL)));
|
||||
|
||||
_Prepare();
|
||||
Show();
|
||||
|
||||
// Heavily modified from TextEntryAlert code; the original didn't let the
|
||||
// blocked window ever draw.
|
||||
if (window) {
|
||||
status_t err;
|
||||
if (window != NULL) {
|
||||
status_t status;
|
||||
for (;;) {
|
||||
do {
|
||||
err = acquire_sem_etc(fAlertSem, 1, B_RELATIVE_TIMEOUT,
|
||||
kSemTimeOut);
|
||||
status = acquire_sem_etc(fAlertSem, 1, B_RELATIVE_TIMEOUT,
|
||||
kSemTimeOut);
|
||||
// We've (probably) had our time slice taken away from us
|
||||
} while (err == B_INTERRUPTED);
|
||||
} while (status == B_INTERRUPTED);
|
||||
|
||||
if (err == B_BAD_SEM_ID) {
|
||||
if (status == B_BAD_SEM_ID) {
|
||||
// Semaphore was finally nuked in MessageReceived
|
||||
break;
|
||||
}
|
||||
@@ -301,19 +322,20 @@ status_t
|
||||
BAlert::Go(BInvoker* invoker)
|
||||
{
|
||||
fInvoker = invoker;
|
||||
_Prepare();
|
||||
Show();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BAlert::MessageReceived(BMessage* message)
|
||||
BAlert::MessageReceived(BMessage* msg)
|
||||
{
|
||||
if (message->what != kAlertButtonMsg)
|
||||
return BWindow::MessageReceived(message);
|
||||
if (msg->what != kAlertButtonMsg)
|
||||
return BWindow::MessageReceived(msg);
|
||||
|
||||
int32 which;
|
||||
if (message->FindInt32("which", &which) == B_OK) {
|
||||
if (msg->FindInt32("which", &which) == B_OK) {
|
||||
if (fAlertSem < B_OK) {
|
||||
// Semaphore hasn't been created; we're running asynchronous
|
||||
if (fInvoker) {
|
||||
@@ -346,10 +368,31 @@ BAlert::FrameResized(float newWidth, float newHeight)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BAlert::AddButton(const char* label, char key)
|
||||
{
|
||||
if (label == NULL || label[0] == '\0')
|
||||
return;
|
||||
|
||||
BButton* button = _CreateButton(fButtons.size(), label);
|
||||
fButtons.push_back(button);
|
||||
fKeys.push_back(key);
|
||||
|
||||
fButtonLayout->AddView(button);
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
BAlert::CountButtons() const
|
||||
{
|
||||
return (int32)fButtons.size();
|
||||
}
|
||||
|
||||
|
||||
BButton*
|
||||
BAlert::ButtonAt(int32 index) const
|
||||
{
|
||||
if (index >= 0 && index < 3)
|
||||
if (index >= 0 && (size_t)index < fButtons.size())
|
||||
return fButtons[index];
|
||||
|
||||
return NULL;
|
||||
@@ -364,11 +407,10 @@ BAlert::TextView() const
|
||||
|
||||
|
||||
BHandler*
|
||||
BAlert::ResolveSpecifier(BMessage* message, int32 index,
|
||||
BMessage* specifier, int32 what, const char* property)
|
||||
BAlert::ResolveSpecifier(BMessage* msg, int32 index,
|
||||
BMessage* specifier, int32 form, const char* property)
|
||||
{
|
||||
return BWindow::ResolveSpecifier(message, index, specifier, what,
|
||||
property);
|
||||
return BWindow::ResolveSpecifier(msg, index, specifier, form, property);
|
||||
}
|
||||
|
||||
|
||||
@@ -400,7 +442,7 @@ BAlert::QuitRequested()
|
||||
}
|
||||
|
||||
|
||||
// This method is deprecated, do not use
|
||||
//! This method is deprecated, do not use - use BWindow::CenterIn() instead.
|
||||
BPoint
|
||||
BAlert::AlertPosition(float width, float height)
|
||||
{
|
||||
@@ -429,11 +471,9 @@ BAlert::Perform(perform_code code, void* _data)
|
||||
{
|
||||
switch (code) {
|
||||
case PERFORM_CODE_SET_LAYOUT:
|
||||
{
|
||||
perform_data_set_layout* data = (perform_data_set_layout*)_data;
|
||||
BAlert::SetLayout(data->layout);
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return BWindow::Perform(code, _data);
|
||||
@@ -446,185 +486,79 @@ void BAlert::_ReservedAlert3() {}
|
||||
|
||||
|
||||
void
|
||||
BAlert::_InitObject(const char* text, const char* button0, const char* button1,
|
||||
BAlert::_Init(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;
|
||||
fAlertValue = -1;
|
||||
fButtons[0] = fButtons[1] = fButtons[2] = NULL;
|
||||
fTextView = NULL;
|
||||
fKeys[0] = fKeys[1] = fKeys[2] = 0;
|
||||
fMsgType = type;
|
||||
fButtonWidth = buttonWidth;
|
||||
|
||||
// Set up the "_master_" view
|
||||
TAlertView* view = new(std::nothrow) TAlertView(Bounds());
|
||||
if (view == NULL)
|
||||
return;
|
||||
|
||||
AddChild(view);
|
||||
view->SetBitmap(_InitIcon());
|
||||
|
||||
// Must have at least one button
|
||||
if (button0 == NULL) {
|
||||
debugger("BAlerts must have at least one button.");
|
||||
button0 = "";
|
||||
}
|
||||
|
||||
// Set up the buttons
|
||||
|
||||
int32 buttonCount = 1;
|
||||
view->AddChild(fButtons[0] = _CreateButton(0, button0));
|
||||
|
||||
if (button1 != NULL) {
|
||||
view->AddChild(fButtons[1] = _CreateButton(1, button1));
|
||||
buttonCount++;
|
||||
}
|
||||
|
||||
if (button2 != NULL) {
|
||||
view->AddChild(fButtons[2] = _CreateButton(2, button2));
|
||||
buttonCount++;
|
||||
}
|
||||
|
||||
// Find the widest button only if the widest value needs to be known.
|
||||
|
||||
if (fButtonWidth == B_WIDTH_FROM_WIDEST) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
float defaultButtonFrameWidth
|
||||
= -fButtons[buttonCount - 1]->Bounds().Width() / 2.0f;
|
||||
SetDefaultButton(fButtons[buttonCount - 1]);
|
||||
defaultButtonFrameWidth
|
||||
+= fButtons[buttonCount - 1]->Bounds().Width() / 2.0f;
|
||||
|
||||
// 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
|
||||
|
||||
int32 iconLayoutScale = icon_layout_scale();
|
||||
float totalWidth = kRightOffset + fButtons[buttonCount - 1]->Frame().right
|
||||
- defaultButtonFrameWidth - fButtons[0]->Frame().left;
|
||||
if (view->Bitmap())
|
||||
totalWidth += (kIconStripeWidth + kWindowIconOffset) * iconLayoutScale;
|
||||
else
|
||||
totalWidth += kWindowMinOffset;
|
||||
|
||||
float width = (spacing == B_OFFSET_SPACING
|
||||
? kWindowOffsetMinWidth : kWindowMinWidth) * fontFactor;
|
||||
|
||||
ResizeTo(max_c(totalWidth, width), Bounds().Height());
|
||||
|
||||
// Set up the text view
|
||||
|
||||
BRect textViewRect(kLeftOffset, kTopOffset,
|
||||
Bounds().right - kRightOffset,
|
||||
fButtons[0]->Frame().top - kTextButtonOffset);
|
||||
if (view->Bitmap())
|
||||
textViewRect.left = (kWindowIconOffset
|
||||
+ kIconStripeWidth) * iconLayoutScale - 2;
|
||||
|
||||
fTextView = new(std::nothrow) BTextView(textViewRect, "_tv_",
|
||||
textViewRect.OffsetByCopy(B_ORIGIN),
|
||||
B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW);
|
||||
if (fTextView == NULL)
|
||||
return;
|
||||
fIconView = new TAlertView();
|
||||
|
||||
fTextView = new BTextView("_tv_");
|
||||
fTextView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
|
||||
fTextView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
|
||||
fTextView->SetText(text, strlen(text));
|
||||
fTextView->MakeEditable(false);
|
||||
fTextView->MakeSelectable(false);
|
||||
fTextView->SetWordWrap(true);
|
||||
view->AddChild(fTextView);
|
||||
fTextView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
|
||||
|
||||
// Now resize the TextView vertically so that all the text is visible
|
||||
float textHeight = fTextView->TextHeight(0, fTextView->CountLines());
|
||||
textViewRect.OffsetTo(0, 0);
|
||||
textHeight -= textViewRect.Height();
|
||||
ResizeBy(0, textHeight);
|
||||
fTextView->ResizeBy(0, textHeight);
|
||||
textViewRect.bottom += textHeight;
|
||||
fTextView->SetTextRect(textViewRect);
|
||||
fButtonLayout = new BGroupLayout(B_HORIZONTAL);
|
||||
|
||||
AddCommonFilter(new(std::nothrow) _BAlertFilter_(this));
|
||||
SetType(type);
|
||||
SetButtonWidth(buttonWidth);
|
||||
SetButtonSpacing(spacing);
|
||||
SetText(text);
|
||||
|
||||
// Position the alert so that it is centered vertically but offset a bit
|
||||
// horizontally in the parent window's frame or, if unavailable, the
|
||||
// screen frame.
|
||||
BWindow* parent =
|
||||
dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
|
||||
const BRect frame = parent != NULL ? parent->Frame() : BScreen(this).Frame();
|
||||
MoveTo(dynamic_cast<BWindow*>(this)->AlertPosition(frame));
|
||||
BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0)
|
||||
.Add(fIconView)
|
||||
.AddGroup(B_VERTICAL)
|
||||
.SetInsets(B_USE_DEFAULT_SPACING)
|
||||
.Add(fTextView)
|
||||
.AddGroup(B_HORIZONTAL, 0)
|
||||
.AddGlue()
|
||||
.Add(fButtonLayout);
|
||||
|
||||
AddButton(button0);
|
||||
AddButton(button1);
|
||||
AddButton(button2);
|
||||
}
|
||||
|
||||
|
||||
BBitmap*
|
||||
BAlert::_InitIcon()
|
||||
BAlert::_CreateTypeIcon()
|
||||
{
|
||||
// Save the desired alert type and set it to "empty" until
|
||||
// loading the icon was successful
|
||||
alert_type alertType = fMsgType;
|
||||
fMsgType = B_EMPTY_ALERT;
|
||||
if (Type() == B_EMPTY_ALERT)
|
||||
return NULL;
|
||||
|
||||
// After a bit of a search, I found the icons in app_server. =P
|
||||
// The icons are in the app_server resources
|
||||
BBitmap* icon = NULL;
|
||||
BPath path;
|
||||
status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path);
|
||||
if (status < B_OK) {
|
||||
FTRACE((stderr, "BAlert::_InitIcon() - find_directory failed: %s\n",
|
||||
strerror(status)));
|
||||
if (status != B_OK) {
|
||||
FTRACE((stderr, "BAlert::_CreateTypeIcon() - find_directory "
|
||||
"failed: %s\n", strerror(status)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path.Append("app_server");
|
||||
BFile file;
|
||||
status = file.SetTo(path.Path(), B_READ_ONLY);
|
||||
if (status < B_OK) {
|
||||
FTRACE((stderr, "BAlert::_InitIcon() - BFile init failed: %s\n",
|
||||
if (status != B_OK) {
|
||||
FTRACE((stderr, "BAlert::_CreateTypeIcon() - BFile init failed: %s\n",
|
||||
strerror(status)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BResources resources;
|
||||
status = resources.SetTo(&file);
|
||||
if (status < B_OK) {
|
||||
FTRACE((stderr, "BAlert::_InitIcon() - BResources init failed: %s\n",
|
||||
strerror(status)));
|
||||
if (status != B_OK) {
|
||||
FTRACE((stderr, "BAlert::_CreateTypeIcon() - BResources init "
|
||||
"failed: %s\n", strerror(status)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Which icon are we trying to load?
|
||||
const char* iconName = ""; // Don't want any seg faults
|
||||
switch (alertType) {
|
||||
const char* iconName;
|
||||
switch (fType) {
|
||||
case B_INFO_ALERT:
|
||||
iconName = "info";
|
||||
break;
|
||||
@@ -649,7 +583,7 @@ BAlert::_InitIcon()
|
||||
icon = new(std::nothrow) BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1),
|
||||
0, B_RGBA32);
|
||||
if (icon == NULL || icon->InitCheck() < B_OK) {
|
||||
FTRACE((stderr, "BAlert::_InitIcon() - No memory for bitmap\n"));
|
||||
FTRACE((stderr, "BAlert::_CreateTypeIcon() - No memory for bitmap\n"));
|
||||
delete icon;
|
||||
return NULL;
|
||||
}
|
||||
@@ -658,39 +592,28 @@ BAlert::_InitIcon()
|
||||
size_t size = 0;
|
||||
const uint8* rawIcon;
|
||||
|
||||
#ifdef __HAIKU__
|
||||
// Try to load vector icon
|
||||
rawIcon = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE,
|
||||
iconName, &size);
|
||||
if (rawIcon != NULL
|
||||
&& BIconUtils::GetVectorIcon(rawIcon, size, icon) == B_OK) {
|
||||
// We have an icon, restore the saved alert type
|
||||
fMsgType = alertType;
|
||||
return icon;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fall back to bitmap icon
|
||||
rawIcon = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE,
|
||||
iconName, &size);
|
||||
if (rawIcon == NULL) {
|
||||
FTRACE((stderr, "BAlert::_InitIcon() - Icon resource not found\n"));
|
||||
FTRACE((stderr, "BAlert::_CreateTypeIcon() - Icon resource not found\n"));
|
||||
delete icon;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Handle color space conversion
|
||||
#ifdef __HAIKU__
|
||||
if (icon->ColorSpace() != B_CMAP8) {
|
||||
BIconUtils::ConvertFromCMAP8(rawIcon, iconSize, iconSize,
|
||||
iconSize, icon);
|
||||
}
|
||||
#else
|
||||
icon->SetBits(rawIcon, iconSize, 0, B_CMAP8);
|
||||
#endif
|
||||
|
||||
// We have an icon, restore the saved alert type
|
||||
fMsgType = alertType;
|
||||
|
||||
return icon;
|
||||
}
|
||||
@@ -705,46 +628,95 @@ BAlert::_CreateButton(int32 which, const char* label)
|
||||
|
||||
message->AddInt32("which", which);
|
||||
|
||||
BRect rect;
|
||||
rect.top = Bounds().bottom - kBottomOffset;
|
||||
rect.bottom = rect.top;
|
||||
|
||||
char name[32];
|
||||
snprintf(name, sizeof(name), "_b%" B_PRId32 "_", which);
|
||||
|
||||
BButton* button = new(std::nothrow) BButton(rect, name, label, message,
|
||||
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
|
||||
if (button == NULL)
|
||||
return NULL;
|
||||
return new(std::nothrow) BButton(name, label, message);
|
||||
}
|
||||
|
||||
float width, height;
|
||||
button->GetPreferredSize(&width, &height);
|
||||
|
||||
/*! Tweaks the layout according to the configuration.
|
||||
*/
|
||||
void
|
||||
BAlert::_Prepare()
|
||||
{
|
||||
// Must have at least one button
|
||||
if (CountButtons() == 0)
|
||||
debugger("BAlerts must have at least one button.");
|
||||
|
||||
SetDefaultButton(ButtonAt(CountButtons() - 1));
|
||||
|
||||
float fontFactor = be_plain_font->Size() / 11.0f;
|
||||
|
||||
if (fIconView->Bitmap() == NULL)
|
||||
fIconView->SetBitmap(_CreateTypeIcon());
|
||||
|
||||
if (fButtonWidth == B_WIDTH_AS_USUAL) {
|
||||
float fontFactor = be_plain_font->Size() / 11.0f;
|
||||
width = max_c(width, kButtonUsualWidth * fontFactor);
|
||||
float usualWidth = kButtonUsualWidth * fontFactor;
|
||||
|
||||
for (int32 index = 0; index < CountButtons(); index++) {
|
||||
BButton* button = ButtonAt(index);
|
||||
if (button->MinSize().width < usualWidth)
|
||||
button->SetExplicitSize(BSize(usualWidth, B_SIZE_UNSET));
|
||||
}
|
||||
} else if (fButtonWidth == B_WIDTH_FROM_WIDEST) {
|
||||
// Get width of widest label
|
||||
float maxWidth = 0;
|
||||
for (int32 index = 0; index < CountButtons(); index++) {
|
||||
BButton* button = ButtonAt(index);
|
||||
float width;
|
||||
button->GetPreferredSize(&width, NULL);
|
||||
|
||||
if (width > maxWidth)
|
||||
maxWidth = width;
|
||||
}
|
||||
for (int32 index = 0; index < CountButtons(); index++) {
|
||||
BButton* button = ButtonAt(index);
|
||||
button->SetExplicitSize(BSize(maxWidth, B_SIZE_UNSET));
|
||||
}
|
||||
}
|
||||
|
||||
button->ResizeTo(width, height);
|
||||
button->MoveBy(0.0f, -height);
|
||||
return button;
|
||||
if (fButtonSpacing == B_OFFSET_SPACING && CountButtons() > 1) {
|
||||
// Insert some strut
|
||||
fButtonLayout->AddItem(1, BSpaceLayoutItem::CreateHorizontalStrut(
|
||||
kButtonOffsetSpacing * fontFactor));
|
||||
}
|
||||
|
||||
// Position the alert so that it is centered vertically but offset a bit
|
||||
// horizontally in the parent window's frame or, if unavailable, the
|
||||
// screen frame.
|
||||
float minWindowWidth = (fButtonSpacing == B_OFFSET_SPACING
|
||||
? kWindowOffsetMinWidth : kWindowMinWidth) * fontFactor;
|
||||
GetLayout()->SetExplicitMinSize(BSize(minWindowWidth, B_SIZE_UNSET));
|
||||
|
||||
ResizeToPreferred();
|
||||
|
||||
BWindow* parent = dynamic_cast<BWindow*>(BLooper::LooperForThread(
|
||||
find_thread(NULL)));
|
||||
const BRect frame = parent != NULL ? parent->Frame()
|
||||
: BScreen(this).Frame();
|
||||
|
||||
MoveTo(static_cast<BWindow*>(this)->AlertPosition(frame));
|
||||
// Hidden by BAlert::AlertPosition()
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - TAlertView
|
||||
|
||||
|
||||
TAlertView::TAlertView(BRect frame)
|
||||
: BView(frame, "TAlertView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
|
||||
fIconBitmap(NULL)
|
||||
TAlertView::TAlertView()
|
||||
:
|
||||
BView("TAlertView", B_WILL_DRAW),
|
||||
fIconBitmap(NULL)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
}
|
||||
|
||||
|
||||
TAlertView::TAlertView(BMessage* archive)
|
||||
: BView(archive),
|
||||
fIconBitmap(NULL)
|
||||
:
|
||||
BView(archive),
|
||||
fIconBitmap(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -772,10 +744,37 @@ TAlertView::Archive(BMessage* archive, bool deep) const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TAlertView::GetPreferredSize(float* _width, float* _height)
|
||||
{
|
||||
int32 scale = icon_layout_scale();
|
||||
|
||||
if (_width != NULL) {
|
||||
if (fIconBitmap != NULL)
|
||||
*_width = 18 * scale + fIconBitmap->Bounds().Width();
|
||||
else
|
||||
*_width = 0;
|
||||
}
|
||||
if (_height != NULL) {
|
||||
if (fIconBitmap != NULL)
|
||||
*_height = 6 * scale + fIconBitmap->Bounds().Height();
|
||||
else
|
||||
*_height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BSize
|
||||
TAlertView::MaxSize()
|
||||
{
|
||||
return BSize(MinSize().width, B_SIZE_UNLIMITED);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TAlertView::Draw(BRect updateRect)
|
||||
{
|
||||
if (!fIconBitmap)
|
||||
if (fIconBitmap == NULL)
|
||||
return;
|
||||
|
||||
// Here's the fun stuff
|
||||
@@ -789,11 +788,9 @@ TAlertView::Draw(BRect updateRect)
|
||||
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
||||
DrawBitmapAsync(fIconBitmap, BPoint(18 * iconLayoutScale,
|
||||
6 * iconLayoutScale));
|
||||
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// #pragma mark - _BAlertFilter_
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user