Scaffolding of a multi-account StatusView

StatusView now allows the selecting of accounts through a MenuButton
with BitmapMenuItems― the button for selecting an account is nice and
discrete, just showing the bitmap of a protocol (in leiu of a label).
No functional changes, other than this menu.

I tried making all AccountsMenus use BitmapMenuItems, but that gets
unweildy pretty quickly― for now they remain in this menu. Maybe
optional ownership of bitmaps in BitmapMenuItems and caching of protocol
items would help.
This commit is contained in:
Jaidyn Ann 2021-08-02 21:59:44 -05:00
parent 930c500988
commit 6d8be225ca
9 changed files with 128 additions and 19 deletions

View File

@ -13,6 +13,7 @@ enum {
kToolIcon = 20, kToolIcon = 20,
kSearchIcon = 21, kSearchIcon = 21,
kAsteriskIcon = 22,
kProtocolSettingsTemplate = 1000, kProtocolSettingsTemplate = 1000,

View File

@ -37,6 +37,8 @@ ImageCache::ImageCache()
_LoadResource(kBusyReplicant, "kBusyReplicant"); _LoadResource(kBusyReplicant, "kBusyReplicant");
_LoadResource(kOfflineReplicant, "kOfflineReplicant"); _LoadResource(kOfflineReplicant, "kOfflineReplicant");
_LoadResource(kOnlineReplicant, "kOnlineReplicant"); _LoadResource(kOnlineReplicant, "kOnlineReplicant");
_LoadResource(kAsteriskIcon, "kAsteriskIcon");
} }

View File

@ -100,6 +100,7 @@ RDEFS = Cardie.rdef \
data/icons/replicant/MessageReceived.rdef \ data/icons/replicant/MessageReceived.rdef \
data/icons/replicant/Offline.rdef \ data/icons/replicant/Offline.rdef \
data/icons/replicant/Online.rdef \ data/icons/replicant/Online.rdef \
data/icons/misc/Asterisk.rdef \
data/icons/misc/People-1.rdef \ data/icons/misc/People-1.rdef \
data/icons/misc/People-2.rdef \ data/icons/misc/People-2.rdef \
data/icons/misc/People-3.rdef \ data/icons/misc/People-3.rdef \

View File

@ -11,28 +11,31 @@
#include <Bitmap.h> #include <Bitmap.h>
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <Message.h> #include <Message.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <PopUpMenu.h> #include <PopUpMenu.h>
#include <StringView.h>
#include <libinterface/BitmapMenuItem.h> #include <libinterface/BitmapMenuItem.h>
#include <libinterface/BitmapUtils.h> #include <libinterface/BitmapUtils.h>
#include <libinterface/BitmapView.h> #include <libinterface/BitmapView.h>
#include <libinterface/MenuButton.h>
#include "AccountManager.h" #include "AccountManager.h"
#include "ChatProtocolMessages.h"
#include "ImageCache.h" #include "ImageCache.h"
#include "NicknameTextControl.h" #include "NicknameTextControl.h"
#include "Server.h"
#include "StatusMenuItem.h" #include "StatusMenuItem.h"
#include "Utils.h" #include "Utils.h"
const int32 kSetNickname = 'stnk'; const int32 kSetNickname = 'SVnk';
const int32 kSelectAllAccounts = 'SVaa';
const int32 kSelectAccount = 'SVsa';
StatusView::StatusView(const char* name) StatusView::StatusView(const char* name, Server* server)
: :
BView(name, B_WILL_DRAW) BView(name, B_WILL_DRAW),
fServer(server)
{ {
// Nick name // Nick name
fNickname = new NicknameTextControl("Nickname", fNickname = new NicknameTextControl("Nickname",
@ -72,15 +75,26 @@ StatusView::StatusView(const char* name)
fAvatar->SetExplicitPreferredSize(BSize(50, 50)); fAvatar->SetExplicitPreferredSize(BSize(50, 50));
fAvatar->SetBitmap(ImageCache::Get()->GetImage("kPersonIcon")); fAvatar->SetBitmap(ImageCache::Get()->GetImage("kPersonIcon"));
// Changing the account used
fAccountsMenu = new BPopUpMenu("statusAccountsMenu", true, false);
fAccountsButton = new MenuButton("statusAccountsButton", "", new BMessage());
fAccountsButton->SetMenu(fAccountsMenu);
_PopulateAccountMenu();
BMessage selected(kSelectAllAccounts);
MessageReceived(&selected);
// Set layout // Set layout
BLayoutBuilder::Group<>(this, B_HORIZONTAL) BLayoutBuilder::Group<>(this, B_VERTICAL)
.AddGroup(B_VERTICAL) .AddGroup(B_HORIZONTAL)
.SetInsets(0)
.Add(statusField) .Add(statusField)
.Add(fAccountsButton)
.End()
.AddGroup(B_HORIZONTAL) .AddGroup(B_HORIZONTAL)
.Add(fNickname) .Add(fNickname)
.Add(fAvatar) .Add(fAvatar)
.End() .End()
.End()
.End(); .End();
} }
@ -106,7 +120,6 @@ StatusView::MessageReceived(BMessage* msg)
case kSetStatus: case kSetStatus:
{ {
int32 status; int32 status;
if (msg->FindInt32("status", &status) != B_OK) if (msg->FindInt32("status", &status) != B_OK)
return; return;
@ -114,6 +127,22 @@ StatusView::MessageReceived(BMessage* msg)
accountManager->SetStatus((UserStatus)status, ""); accountManager->SetStatus((UserStatus)status, "");
break; break;
} }
case kSelectAllAccounts:
case kSelectAccount:
{
int32 index = msg->FindInt32("index");
BitmapMenuItem* item = (BitmapMenuItem*)fAccountsMenu->ItemAt(index);
BBitmap* bitmap = item->Bitmap();
fAccountsButton->SetIcon(bitmap);
break;
}
case IM_MESSAGE:
{
int32 im_what = msg->GetInt32("im_what", 0);
if (im_what == IM_PROTOCOL_DISABLE || im_what == IM_PROTOCOL_READY)
_PopulateAccountMenu();
break;
}
default: default:
BView::MessageReceived(msg); BView::MessageReceived(msg);
} }
@ -146,3 +175,55 @@ StatusView::SetAvatarIcon(const BBitmap* bitmap)
if (bitmap != ImageCache::Get()->GetImage("kPersonIcon")) if (bitmap != ImageCache::Get()->GetImage("kPersonIcon"))
fAvatar->SetBitmap(bitmap); fAvatar->SetBitmap(bitmap);
} }
void
StatusView::_PopulateAccountMenu()
{
AccountInstances accounts = fServer->GetActiveAccounts();
BFont font;
GetFont(&font);
if (fAccountsMenu->FindItem(B_TRANSLATE("All")) == NULL) {
BBitmap* icon = ImageCache::Get()->GetImage("kAsteriskIcon");
BBitmap* resized = RescaleBitmap(icon, font.Size(), font.Size());
fAccountsMenu->AddItem(new BitmapMenuItem(B_TRANSLATE("All"),
new BMessage(kSelectAllAccounts), resized));
fAccountsMenu->FindItem(B_TRANSLATE("All"))->SetMarked(true);
}
// Add unpopulated entries
for (int i = 0; i < accounts.CountItems(); i++) {
BString name = accounts.KeyAt(i);
int64 instance = accounts.ValueAt(i);
ProtocolLooper* looper = fServer->GetProtocolLooper(instance);
if (looper == NULL || looper->Protocol() == NULL
|| fAccountsMenu->FindItem(name.String()) != NULL)
continue;
BBitmap* icon = looper->Protocol()->Icon();
BBitmap* resized = RescaleBitmap(icon, font.Size(), font.Size());
BMessage* selected = new BMessage(kSelectAccount);
selected->AddInt64("instance", instance);
fAccountsMenu->AddItem(new BitmapMenuItem(name.String(), selected,
resized));
}
// Remove disabled accounts
if (fAccountsMenu->CountItems() - 1 > accounts.CountItems()) {
fAccountsMenu->FindMarked()->SetMarked(false);
fAccountsMenu->ItemAt(0)->SetMarked(true);
BMessage select(kSelectAllAccounts);
MessageReceived(&select);
for (int i = 0; i < fAccountsMenu->CountItems(); i++) {
bool found = false;
accounts.ValueFor(BString(fAccountsMenu->ItemAt(i)->Label()), &found);
if (found == false)
fAccountsMenu->RemoveItem(i);
}
}
fAccountsMenu->SetTargetForItems(this);
}

View File

@ -12,11 +12,13 @@
class BPopUpMenu; class BPopUpMenu;
class BitmapView; class BitmapView;
class MenuButton;
class NicknameTextControl; class NicknameTextControl;
class Server;
class StatusView : public BView { class StatusView : public BView {
public: public:
StatusView(const char* name); StatusView(const char* name, Server* server);
virtual void AttachedToWindow(); virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* msg); virtual void MessageReceived(BMessage* msg);
@ -26,9 +28,16 @@ public:
void SetAvatarIcon(const BBitmap* bitmap); void SetAvatarIcon(const BBitmap* bitmap);
private: private:
BPopUpMenu* fStatusMenu; void _PopulateAccountMenu();
NicknameTextControl* fNickname; NicknameTextControl* fNickname;
BitmapView* fAvatar; BitmapView* fAvatar;
BPopUpMenu* fStatusMenu;
MenuButton* fAccountsButton;
BPopUpMenu* fAccountsMenu;
Server* fServer;
}; };
#endif // _STATUS_VIEW_H #endif // _STATUS_VIEW_H

View File

@ -53,12 +53,12 @@ MainWindow::MainWindow()
fRosterWindow(NULL), fRosterWindow(NULL),
fServer(NULL) fServer(NULL)
{ {
_InitInterface();
// Filter messages using Server // Filter messages using Server
fServer = new Server(); fServer = new Server();
AddFilter(fServer); AddFilter(fServer);
_InitInterface();
//TODO check for errors here //TODO check for errors here
ReplicantStatusView::InstallReplicant(); ReplicantStatusView::InstallReplicant();
} }
@ -283,8 +283,12 @@ MainWindow::ImMessage(BMessage* msg)
if (fConversation == NULL) if (fConversation == NULL)
fChatView->MessageReceived(msg); fChatView->MessageReceived(msg);
_ToggleMenuItems(); _ToggleMenuItems();
fStatusView->MessageReceived(msg);
break; break;
} }
case IM_PROTOCOL_DISABLE:
fStatusView->MessageReceived(msg);
break;
} }
} }
@ -423,7 +427,7 @@ MainWindow::_InitInterface()
{ {
// Left side of window, Roomlist + Status // Left side of window, Roomlist + Status
fListView = new ConversationListView("roomList"); fListView = new ConversationListView("roomList");
fStatusView = new StatusView("statusView"); fStatusView = new StatusView("statusView", fServer);
fSplitView = new BSplitView(B_HORIZONTAL, 0); fSplitView = new BSplitView(B_HORIZONTAL, 0);
// Right-side of window, Chat + Textbox // Right-side of window, Chat + Textbox

BIN
data/icons/misc/Asterisk Normal file

Binary file not shown.

View File

@ -0,0 +1,11 @@
#include "application/AppResources.h"
resource(kAsteriskIcon) #'VICN' array {
$"6E6369660404006603005900020004020080FF80FF80FF80020006020000003C"
$"6000C000000000004C000048A0002580FF80A300B300010A0FB7FEB620B923B5"
$"D0B939B659B81FB670B8D5B75CB852B7A2B7CFB69CB75AB7A2B6D2B75CB785B6"
$"70B66EB659B684B5D0B7A6B620B786B501B81CB501030A0001001245D9190000"
$"000000004607C0CBB8BFCA27CC01178010040A0101001245D919000000000000"
$"4607C0CBE8BFCA57CC01178010040A0301000245D9190000000000004607C0CB"
$"E8BFCA57CC"
};

View File

@ -29,7 +29,7 @@ public:
virtual void DrawContent(void); virtual void DrawContent(void);
virtual void SetBitmap(BBitmap *bitmap); virtual void SetBitmap(BBitmap *bitmap);
BBitmap* Bitmap(void) const; BBitmap* Bitmap(void) const { return fBitmap; }
private: private:
BBitmap *fBitmap; BBitmap *fBitmap;