diff --git a/headers/os/interface/Alert.h b/headers/os/interface/Alert.h index 3020b41497..3ac24417b3 100644 --- a/headers/os/interface/Alert.h +++ b/headers/os/interface/Alert.h @@ -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 + #include @@ -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 fButtons; + std::vector fKeys; + uint8 fType; + uint8 fButtonSpacing; + uint8 fButtonWidth; + BInvoker* fInvoker; + uint32 _reserved[1]; }; + #endif // _ALERT_H diff --git a/src/kits/interface/Alert.cpp b/src/kits/interface/Alert.cpp index 19d093ab6a..8c373fd5b1 100644 --- a/src/kits/interface/Alert.cpp +++ b/src/kits/interface/Alert.cpp @@ -9,31 +9,28 @@ */ -// BAlert displays a modal alert window. +//! BAlert displays a modal alert window. -#include -#include -#include - #include -#include -#include + +#include + +#include + #include #include -#include +#include #include -#include #include -#include -#include -#include +#include +#include #include #include #include #include -#include -#include +#include +#include #include @@ -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(BLooper::LooperForThread(find_thread(NULL))); + BWindow* window = dynamic_cast( + 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(BLooper::LooperForThread(find_thread(NULL))); - const BRect frame = parent != NULL ? parent->Frame() : BScreen(this).Frame(); - MoveTo(dynamic_cast(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(BLooper::LooperForThread( + find_thread(NULL))); + const BRect frame = parent != NULL ? parent->Frame() + : BScreen(this).Frame(); + + MoveTo(static_cast(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_