Keymap: Put status icons inside menu fields

Draw warning and stop icons on top of the menu fields instead.
Remove conflict views, create a new file to hold StatusMenuField
and StatusMenuItem. Set the icon with them instead.

Change-Id: If6c00199f24ac4f4fc789f12cc6cdcd7a912418f
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7209
Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
John Scipione 2023-12-04 20:55:54 -05:00 committed by waddlesplash
parent f99596f4e3
commit 4fc18643b9
5 changed files with 425 additions and 275 deletions

View File

@ -18,6 +18,7 @@ Preference Keymap :
KeymapListItem.cpp
KeymapWindow.cpp
ModifierKeysWindow.cpp
StatusMenuField.cpp
: be tracker localestub shared [ TargetLibstdc++ ]
: Keymap.rdef
@ -29,4 +30,5 @@ DoCatalogs Keymap :
KeyboardLayoutView.cpp
KeymapWindow.cpp
ModifierKeysWindow.cpp
StatusMenuField.cpp
;

View File

@ -14,14 +14,10 @@
#include <stdlib.h>
#include <string.h>
#include <Bitmap.h>
#include <Button.h>
#include <Catalog.h>
#include <CheckBox.h>
#include <ControlLook.h>
#include <FindDirectory.h>
#include <IconUtils.h>
#include <InterfaceDefs.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <MenuField.h>
@ -35,13 +31,7 @@
#include <StringView.h>
#include "KeymapApplication.h"
#ifdef DEBUG_ALERT
# define FTRACE(x) fprintf(x)
#else
# define FTRACE(x) /* nothing */
#endif
#include "StatusMenuField.h"
enum {
@ -79,125 +69,6 @@ static const int32 kDisabled = -1;
#define B_TRANSLATION_CONTEXT "Modifier keys window"
// #pragma mark - ConflictView
ConflictView::ConflictView(const char* name)
:
BView(BRect(BPoint(0, 0), be_control_look->ComposeIconSize(B_MINI_ICON)),
name, B_FOLLOW_NONE, B_WILL_DRAW),
fIcon(NULL),
fStopIcon(NULL),
fWarnIcon(NULL)
{
_FillIcons();
}
ConflictView::~ConflictView()
{
delete fStopIcon;
delete fWarnIcon;
}
void
ConflictView::Draw(BRect updateRect)
{
// Draw background
if (Parent())
SetLowColor(Parent()->ViewColor());
else
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
FillRect(updateRect, B_SOLID_LOW);
if (fIcon == NULL)
return;
// Draw icon
SetDrawingMode(B_OP_ALPHA);
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
DrawBitmapAsync(fIcon, BPoint(0, 0));
}
// get the icon
BBitmap*
ConflictView::Icon()
{
return fIcon;
}
// show or hide the stop icon
void
ConflictView::SetStopIcon(bool show)
{
fIcon = show ? fStopIcon : NULL;
const char* tip = show ? B_TRANSLATE("Error: duplicate keys") : NULL;
SetToolTip(tip);
}
// show or hide the warn icon
void
ConflictView::SetWarnIcon(bool show)
{
fIcon = show ? fWarnIcon : NULL;
const char* tip = show ? B_TRANSLATE("Warning: left and right key roles do not match") : NULL;
SetToolTip(tip);
}
// #pragma mark - ConflictView private methods
// fill out the icons with the stop and warn symbols from app_server
void
ConflictView::_FillIcons()
{
if (fStopIcon == NULL) {
// Allocate the fStopIcon bitmap
fStopIcon = new (std::nothrow) BBitmap(Bounds(), 0, B_RGBA32);
if (fStopIcon == NULL || fStopIcon->InitCheck() != B_OK) {
FTRACE((stderr, "_FillIcons() - No memory for stop bitmap\n"));
delete fStopIcon;
fStopIcon = NULL;
return;
}
// load dialog-error icon bitmap
if (BIconUtils::GetSystemIcon("dialog-error", fStopIcon) != B_OK) {
delete fStopIcon;
fStopIcon = NULL;
return;
}
}
if (fWarnIcon == NULL) {
// Allocate the fWarnIcon bitmap
fWarnIcon = new (std::nothrow) BBitmap(Bounds(), 0, B_RGBA32);
if (fWarnIcon == NULL || fWarnIcon->InitCheck() != B_OK) {
FTRACE((stderr, "_FillIcons() - No memory for warn bitmap\n"));
delete fWarnIcon;
fWarnIcon = NULL;
return;
}
// load dialog-warning icon bitmap
if (BIconUtils::GetSystemIcon("dialog-warning", fWarnIcon) != B_OK) {
delete fWarnIcon;
fWarnIcon = NULL;
return;
}
}
}
// #pragma mark - ModifierKeysWindow
ModifierKeysWindow::ModifierKeysWindow()
:
BWindow(BRect(0, 0, 360, 220), B_TRANSLATE("Modifier keys"),
@ -216,41 +87,17 @@ ModifierKeysWindow::ModifierKeysWindow()
keyLabel->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
keyLabel->SetFont(be_bold_font);
BMenuField* capsMenuField;
_CreateMenuField(&fCapsMenu, &capsMenuField, MENU_ITEM_CAPS,
_CreateMenuField(&fCapsMenu, (BMenuField**)&fCapsField, MENU_ITEM_CAPS,
B_TRANSLATE_COMMENT("Caps Lock:", "Caps Lock key role name"));
BMenuField* shiftMenuField;
_CreateMenuField(&fShiftMenu, &shiftMenuField, MENU_ITEM_SHIFT,
_CreateMenuField(&fShiftMenu, (BMenuField**)&fShiftField, MENU_ITEM_SHIFT,
B_TRANSLATE_COMMENT("Shift:", "Shift key role name"));
BMenuField* controlMenuField;
_CreateMenuField(&fControlMenu, &controlMenuField, MENU_ITEM_CONTROL,
_CreateMenuField(&fControlMenu, (BMenuField**)&fControlField, MENU_ITEM_CONTROL,
B_TRANSLATE_COMMENT("Control:", "Control key role name"));
BMenuField* optionMenuField;
_CreateMenuField(&fOptionMenu, &optionMenuField, MENU_ITEM_OPTION,
_CreateMenuField(&fOptionMenu,(BMenuField**) &fOptionField, MENU_ITEM_OPTION,
B_TRANSLATE_COMMENT("Option:", "Option key role name"));
BMenuField* commandMenuField;
_CreateMenuField(&fCommandMenu, &commandMenuField, MENU_ITEM_COMMAND,
_CreateMenuField(&fCommandMenu, (BMenuField**)&fCommandField, MENU_ITEM_COMMAND,
B_TRANSLATE_COMMENT("Command:", "Command key role name"));
fCapsConflictView = new ConflictView("caps lock warning view");
fCapsConflictView->SetExplicitMaxSize(fCapsConflictView->Bounds().Size());
fShiftConflictView = new ConflictView("shift warning view");
fShiftConflictView->SetExplicitMaxSize(fShiftConflictView->Bounds().Size());
fControlConflictView = new ConflictView("control warning view");
fControlConflictView->SetExplicitMaxSize(fControlConflictView->Bounds().Size());
fOptionConflictView = new ConflictView("option warning view");
fOptionConflictView->SetExplicitMaxSize(fOptionConflictView->Bounds().Size());
fCommandConflictView = new ConflictView("command warning view");
fCommandConflictView->SetExplicitMaxSize(fCommandConflictView->Bounds().Size());
fCancelButton = new BButton("cancelButton", B_TRANSLATE("Cancel"),
new BMessage(B_QUIT_REQUESTED));
@ -267,34 +114,29 @@ ModifierKeysWindow::ModifierKeysWindow()
.Add(keyRole, 0, 0)
.Add(keyLabel, 1, 0)
.Add(capsMenuField->CreateLabelLayoutItem(), 0, 1)
.Add(fCapsField->CreateLabelLayoutItem(), 0, 1)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 1)
.Add(capsMenuField->CreateMenuBarLayoutItem())
.Add(fCapsConflictView)
.Add(fCapsField->CreateMenuBarLayoutItem())
.End()
.Add(shiftMenuField->CreateLabelLayoutItem(), 0, 2)
.Add(fShiftField->CreateLabelLayoutItem(), 0, 2)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 2)
.Add(shiftMenuField->CreateMenuBarLayoutItem())
.Add(fShiftConflictView)
.Add(fShiftField->CreateMenuBarLayoutItem())
.End()
.Add(controlMenuField->CreateLabelLayoutItem(), 0, 3)
.Add(fControlField->CreateLabelLayoutItem(), 0, 3)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 3)
.Add(controlMenuField->CreateMenuBarLayoutItem())
.Add(fControlConflictView)
.Add(fControlField->CreateMenuBarLayoutItem())
.End()
.Add(optionMenuField->CreateLabelLayoutItem(), 0, 4)
.Add(fOptionField->CreateLabelLayoutItem(), 0, 4)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 4)
.Add(optionMenuField->CreateMenuBarLayoutItem())
.Add(fOptionConflictView)
.Add(fOptionField->CreateMenuBarLayoutItem())
.End()
.Add(commandMenuField->CreateLabelLayoutItem(), 0, 5)
.Add(fCommandField->CreateLabelLayoutItem(), 0, 5)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1, 5)
.Add(commandMenuField->CreateMenuBarLayoutItem())
.Add(fCommandConflictView)
.Add(fCommandField->CreateMenuBarLayoutItem())
.End()
.End()
@ -384,6 +226,9 @@ ModifierKeysWindow::MessageReceived(BMessage* message)
BMessage* updateModifiers = new BMessage(kMsgUpdateModifierKeys);
if (fCurrentMap->caps_key != fSavedMap->caps_key)
updateModifiers->AddUInt32("caps_key", fCurrentMap->caps_key);
if (fCurrentMap->left_shift_key != fSavedMap->left_shift_key)
updateModifiers->AddUInt32("left_shift_key", fCurrentMap->left_shift_key);
@ -408,9 +253,6 @@ ModifierKeysWindow::MessageReceived(BMessage* message)
if (fCurrentMap->right_command_key != fSavedMap->right_command_key)
updateModifiers->AddUInt32("right_command_key", fCurrentMap->right_command_key);
if (fCurrentMap->caps_key != fSavedMap->caps_key)
updateModifiers->AddUInt32("caps_key", fCurrentMap->caps_key);
// KeymapWindow updates the modifiers
be_app->PostMessage(updateModifiers);
@ -461,7 +303,7 @@ ModifierKeysWindow::_CreateMenuField(BPopUpMenu** _menu, BMenuField** _menuField
menu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_VERTICAL_UNSET));
BMenuField* menuField = new BMenuField(label, menu);
BMenuField* menuField = new StatusMenuField(label, menu);
menuField->SetAlignment(B_ALIGN_RIGHT);
*_menu = menu;
@ -472,42 +314,41 @@ ModifierKeysWindow::_CreateMenuField(BPopUpMenu** _menu, BMenuField** _menuField
void
ModifierKeysWindow::_MarkMenuItems()
{
_MarkMenuItem(fCapsMenu, fCapsConflictView,
fCurrentMap->caps_key, fCurrentMap->caps_key);
_MarkMenuItem(fShiftMenu, fShiftConflictView,
fCurrentMap->left_shift_key, fCurrentMap->right_shift_key);
_MarkMenuItem(fControlMenu, fControlConflictView,
fCurrentMap->left_control_key, fCurrentMap->right_control_key);
_MarkMenuItem(fOptionMenu, fOptionConflictView,
fCurrentMap->left_option_key, fCurrentMap->right_option_key);
_MarkMenuItem(fCommandMenu, fCommandConflictView,
fCurrentMap->left_command_key, fCurrentMap->right_command_key);
_MarkMenuItem("caps lock", fCapsMenu, fCurrentMap->caps_key, fCurrentMap->caps_key);
// mark but don't set unmatched for Caps Lock
fShiftField->SetUnmatched(_MarkMenuItem("shift", fShiftMenu,
fCurrentMap->left_shift_key, fCurrentMap->right_shift_key) == false);
fControlField->SetUnmatched(_MarkMenuItem("control", fControlMenu,
fCurrentMap->left_control_key, fCurrentMap->right_control_key) == false);
fOptionField->SetUnmatched(_MarkMenuItem("option", fOptionMenu,
fCurrentMap->left_option_key, fCurrentMap->right_option_key) == false);
fCommandField->SetUnmatched(_MarkMenuItem("command", fCommandMenu,
fCurrentMap->left_command_key, fCurrentMap->right_command_key) == false);
}
void
ModifierKeysWindow::_MarkMenuItem(BPopUpMenu* menu, ConflictView* conflictView,
uint32 leftKey, uint32 rightKey)
bool
ModifierKeysWindow::_MarkMenuItem(const char* role, BPopUpMenu* menu, uint32 left, uint32 right)
{
for (int32 key = MENU_ITEM_FIRST; key <= MENU_ITEM_LAST; key++) {
if (key == MENU_ITEM_SEPARATOR)
continue;
if (leftKey == _KeyToKeyCode(key) && rightKey == _KeyToKeyCode(key, true))
uint32 leftKey = _KeyToKeyCode(key);
uint32 rightKey = _KeyToKeyCode(key, true);
if (leftKey != rightKey && key == MENU_ITEM_CAPS) {
// mark Caps Lock on Caps Lock role if either left or right is caps
// otherwise mark Caps Lock if left side is caps
uint32 capsKey = _KeyToKeyCode(MENU_ITEM_CAPS);
if (strcmp(role, "caps lock") == 0 && (left == capsKey || right == capsKey))
menu->ItemAt(key)->SetMarked(true);
else if (left == capsKey)
menu->ItemAt(key)->SetMarked(true);
} else if (left == leftKey && right == rightKey)
menu->ItemAt(key)->SetMarked(true);
}
// no conflict
if (menu->FindMarked() != NULL)
return;
// set the warning icon
BBitmap* icon = conflictView->Icon();
conflictView->SetWarnIcon(icon == NULL);
// if there was a change invalidate the view
if (icon != conflictView->Icon())
conflictView->Invalidate();
return menu->FindMarked() != NULL;
}
@ -541,12 +382,12 @@ ModifierKeysWindow::_KeyToString(int32 key)
return B_TRANSLATE_COMMENT("Disabled", "Do nothing");
}
return "";
return B_EMPTY_STRING;
}
// get the keycode for a modifier key
uint32
int32
ModifierKeysWindow::_KeyToKeyCode(int32 key, bool right)
{
switch (key) {
@ -586,23 +427,20 @@ void
ModifierKeysWindow::_ValidateDuplicateKeys()
{
uint32 dupMask = _DuplicateKeys();
_ValidateDuplicateKey(fCapsConflictView, CAPS_KEY & dupMask);
_ValidateDuplicateKey(fShiftConflictView, SHIFT_KEY & dupMask);
_ValidateDuplicateKey(fControlConflictView, CONTROL_KEY & dupMask);
_ValidateDuplicateKey(fOptionConflictView, OPTION_KEY & dupMask);
_ValidateDuplicateKey(fCommandConflictView, COMMAND_KEY & dupMask);
_ValidateDuplicateKey(fCapsField, CAPS_KEY & dupMask);
_ValidateDuplicateKey(fShiftField, SHIFT_KEY & dupMask);
_ValidateDuplicateKey(fControlField, CONTROL_KEY & dupMask);
_ValidateDuplicateKey(fOptionField, OPTION_KEY & dupMask);
_ValidateDuplicateKey(fCommandField, COMMAND_KEY & dupMask);
fOkButton->SetEnabled(dupMask == 0);
}
void
ModifierKeysWindow::_ValidateDuplicateKey(ConflictView* view, uint32 mask)
ModifierKeysWindow::_ValidateDuplicateKey(StatusMenuField* field, uint32 mask)
{
BBitmap* icon = view->Icon();
view->SetStopIcon(mask != 0);
// if there was a change invalidate the view
if (icon != view->Icon())
view->Invalidate();
if (mask != 0) // don't override if false
field->SetDuplicate(true);
}
@ -687,6 +525,8 @@ ModifierKeysWindow::_DuplicateKeys()
if (left == kUnset && (right == kUnset || right == kDisabled))
continue;
// left or right is set
if (left == testLeft || right == testRight) {
duplicateMask |= 1 << testKey;
duplicateMask |= 1 << key;
@ -698,34 +538,10 @@ ModifierKeysWindow::_DuplicateKeys()
}
void
ModifierKeysWindow::_HideShowStatusIcons()
{
_ToggleStatusIcon(fCapsConflictView);
_ToggleStatusIcon(fShiftConflictView);
_ToggleStatusIcon(fControlConflictView);
_ToggleStatusIcon(fOptionConflictView);
_ToggleStatusIcon(fCommandConflictView);
}
void
ModifierKeysWindow::_ToggleStatusIcon(ConflictView* view)
{
if (view->Icon() == NULL) {
if (!view->IsHidden())
view->Hide();
} else {
if (view->IsHidden())
view->Show();
}
}
void
ModifierKeysWindow::_UpdateStatus()
{
_ValidateDuplicateKeys();
// the order is important
_MarkMenuItems();
_HideShowStatusIcons();
_ValidateDuplicateKeys();
}

View File

@ -10,32 +10,13 @@
#define MODIFIER_KEYS_WINDOW_H
#include <View.h>
#include <Window.h>
class BButton;
class BMenuField;
class BPopUpMenu;
class ConflictView : public BView {
public:
ConflictView(const char* name);
~ConflictView();
virtual void Draw(BRect updateRect);
BBitmap* Icon();
void SetStopIcon(bool show);
void SetWarnIcon(bool show);
private:
void _FillIcons();
BBitmap* fIcon;
BBitmap* fStopIcon;
BBitmap* fWarnIcon;
};
class StatusMenuField;
class ModifierKeysWindow : public BWindow {
@ -49,17 +30,13 @@ private:
void _CreateMenuField(BPopUpMenu** _menu, BMenuField** _field,
uint32 key, const char* label);
void _MarkMenuItems();
void _MarkMenuItem(BPopUpMenu* menu, ConflictView* conflictView,
uint32 leftKey, uint32 rightKey);
bool _MarkMenuItem(const char*, BPopUpMenu*, uint32 l, uint32 r);
const char* _KeyToString(int32 key);
uint32 _KeyToKeyCode(int32 key,
bool right = false);
int32 _KeyToKeyCode(int32 key, bool right = false);
int32 _LastKey();
void _ValidateDuplicateKeys();
void _ValidateDuplicateKey(ConflictView* view, uint32 mask);
void _ValidateDuplicateKey(StatusMenuField*, uint32);
uint32 _DuplicateKeys();
void _HideShowStatusIcons();
void _ToggleStatusIcon(ConflictView* view);
void _UpdateStatus();
BPopUpMenu* fCapsMenu;
@ -68,11 +45,11 @@ private:
BPopUpMenu* fOptionMenu;
BPopUpMenu* fCommandMenu;
ConflictView* fCapsConflictView;
ConflictView* fShiftConflictView;
ConflictView* fControlConflictView;
ConflictView* fOptionConflictView;
ConflictView* fCommandConflictView;
StatusMenuField* fCapsField;
StatusMenuField* fShiftField;
StatusMenuField* fControlField;
StatusMenuField* fOptionField;
StatusMenuField* fCommandField;
BButton* fRevertButton;
BButton* fCancelButton;

View File

@ -0,0 +1,283 @@
/*
* Copyright 2023 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* John Scipione, jscipione@gmail.com
*/
#include "StatusMenuField.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Bitmap.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <IconUtils.h>
#include <InterfaceDefs.h>
#include <LayoutUtils.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Modifier keys window"
#ifdef DEBUG_ALERT
# define FTRACE(x) fprintf(x)
#else
# define FTRACE(x) /* nothing */
#endif
static const char* kDuplicate = "duplicate";
static const char* kUnmatched = "unmatched";
// #pragma mark - StatusMenuItem
StatusMenuItem::StatusMenuItem(const char* name, BMessage* message)
:
BMenuItem(name, message),
fIcon(NULL)
{
}
StatusMenuItem::StatusMenuItem(BMessage* archive)
:
BMenuItem(archive),
fIcon(NULL)
{
}
BArchivable*
StatusMenuItem::Instantiate(BMessage* data)
{
if (validate_instantiation(data, "StatusMenuItem"))
return new StatusMenuItem(data);
return NULL;
}
status_t
StatusMenuItem::Archive(BMessage* data, bool deep) const
{
status_t result = BMenuItem::Archive(data, deep);
return result;
}
void
StatusMenuItem::DrawContent()
{
if (fIcon == NULL)
return BMenuItem::DrawContent();
// blend transparency
Menu()->SetDrawingMode(B_OP_ALPHA);
Menu()->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
// draw bitmap
Menu()->DrawBitmapAsync(fIcon, IconRect().LeftTop());
BMenuItem::DrawContent();
}
void
StatusMenuItem::GetContentSize(float* _width, float* _height)
{
float width;
float height;
BMenuItem::GetContentSize(&width, &height);
// prevent label from drawing over icon
if (_width != NULL)
*_width = Menu()->Bounds().Width() - IconRect().Width() - Spacing() * 4;
if (_height != NULL)
*_height = height;
}
BBitmap*
StatusMenuItem::Icon()
{
return fIcon;
}
void
StatusMenuItem::SetIcon(BBitmap* icon)
{
fIcon = icon;
}
BRect
StatusMenuItem::IconRect()
{
BRect bounds(Menu()->Bounds());
bounds.top += roundf(Spacing() / 2); // center inside menu field vertically
bounds.right -= Spacing() * 3; // move inside menu field horizontally
return BLayoutUtils::AlignInFrame(bounds, IconSize(),
BAlignment(B_ALIGN_RIGHT, B_ALIGN_TOP));
}
BSize
StatusMenuItem::IconSize()
{
return be_control_look->ComposeIconSize(B_MINI_ICON);
}
float
StatusMenuItem::Spacing()
{
return be_control_look->DefaultLabelSpacing();
}
// #pragma mark - StatusMenuField
StatusMenuField::StatusMenuField(const char* label, BMenu* menu)
:
BMenuField(label, menu),
fStatus(B_EMPTY_STRING),
fStopIcon(NULL),
fWarnIcon(NULL)
{
_FillIcons();
}
StatusMenuField::~StatusMenuField()
{
delete fStopIcon;
delete fWarnIcon;
}
void
StatusMenuField::SetDuplicate(bool on)
{
ShowStopIcon(on);
on ? SetStatus(kDuplicate) : ClearStatus();
Invalidate();
}
void
StatusMenuField::SetUnmatched(bool on)
{
ShowWarnIcon(on);
on ? SetStatus(kUnmatched) : ClearStatus();
Invalidate();
}
void
StatusMenuField::ShowStopIcon(bool show)
{
// show or hide the stop icon
StatusMenuItem* item = dynamic_cast<StatusMenuItem*>(MenuItem());
if (item != NULL)
item->SetIcon(show ? fStopIcon : NULL);
}
void
StatusMenuField::ShowWarnIcon(bool show)
{
// show or hide the warn icon
StatusMenuItem* item = dynamic_cast<StatusMenuItem*>(MenuItem());
if (item != NULL)
item->SetIcon(show ? fWarnIcon : NULL);
}
void
StatusMenuField::ClearStatus()
{
fStatus = B_EMPTY_STRING;
SetToolTip((const char*)NULL);
}
void
StatusMenuField::SetStatus(BString status)
{
fStatus = status;
const char* tooltip = B_EMPTY_STRING;
if (fStatus == kDuplicate)
tooltip = B_TRANSLATE("Error: duplicate keys");
else if (fStatus == kUnmatched)
tooltip = B_TRANSLATE("Warning: left and right key roles do not match");
SetToolTip(tooltip);
}
// #pragma mark - StatusMenuField private methods
void
StatusMenuField::_FillIcons()
{
// fill out the icons with the stop and warn icons from app_server
// TODO find better icons
if (fStopIcon == NULL) {
// allocate the fStopIcon bitmap
fStopIcon = new (std::nothrow) BBitmap(_IconRect(), 0, B_RGBA32);
if (fStopIcon == NULL || fStopIcon->InitCheck() != B_OK) {
FTRACE((stderr, "MKW::_FillIcons() - No memory for stop bitmap\n"));
delete fStopIcon;
fStopIcon = NULL;
return;
}
// load dialog-error icon bitmap
if (BIconUtils::GetSystemIcon("dialog-error", fStopIcon) != B_OK) {
delete fStopIcon;
fStopIcon = NULL;
return;
}
}
if (fWarnIcon == NULL) {
// allocate the fWarnIcon bitmap
fWarnIcon = new (std::nothrow) BBitmap(_IconRect(), 0, B_RGBA32);
if (fWarnIcon == NULL || fWarnIcon->InitCheck() != B_OK) {
FTRACE((stderr, "MKW::_FillIcons() - No memory for warn bitmap\n"));
delete fWarnIcon;
fWarnIcon = NULL;
return;
}
// load dialog-warning icon bitmap
if (BIconUtils::GetSystemIcon("dialog-warning", fWarnIcon) != B_OK) {
delete fWarnIcon;
fWarnIcon = NULL;
return;
}
}
}
BRect
StatusMenuField::_IconRect()
{
BSize iconSize = be_control_look->ComposeIconSize(B_MINI_ICON);
return BRect(0, 0, iconSize.Width() - 1, iconSize.Height() - 1);
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2023 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* John Scipione, jscipione@gmail.com
*/
#ifndef STATUS_MENU_FIELD_H
#define STATUS_MENU_FIELD_H
#include <MenuField.h>
#include <MenuItem.h>
#include <String.h>
class BBitmap;
class StatusMenuItem : public BMenuItem {
public:
StatusMenuItem(const char* name, BMessage* message = NULL);
StatusMenuItem(BMessage* archive);
static BArchivable* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage* archive,
bool deep = true) const;
virtual void DrawContent();
virtual void GetContentSize(float* _width, float* _height);
BBitmap* Icon();
virtual void SetIcon(BBitmap* icon);
BRect IconRect();
BSize IconSize();
float Spacing();
private:
BBitmap* fIcon;
};
class StatusMenuField : public BMenuField {
public:
StatusMenuField(const char*, BMenu*);
~StatusMenuField();
virtual void SetDuplicate(bool on);
virtual void SetUnmatched(bool on);
BString Status() { return fStatus; };
virtual void ClearStatus();
virtual void SetStatus(BString status);
protected:
virtual void ShowStopIcon(bool show);
virtual void ShowWarnIcon(bool show);
private:
void _FillIcons();
BRect _IconRect();
private:
BString fStatus;
BBitmap* fStopIcon;
BBitmap* fWarnIcon;
};
#endif // STATUS_MENU_FIELD_H