Use BCardLayout instead of manual BView switching
Structures MainWindow around a Conversations→BLayoutItem map & BCardLayout, instead of directly removing and adding ConversationViews every time.
This commit is contained in:
parent
eb60c94d68
commit
6f01818e8a
|
@ -14,6 +14,7 @@
|
|||
#include <Application.h>
|
||||
#include <Alert.h>
|
||||
#include <Beep.h>
|
||||
#include <CardLayout.h>
|
||||
#include <Catalog.h>
|
||||
#include <LayoutBuilder.h>
|
||||
#include <MenuBar.h>
|
||||
|
@ -87,6 +88,15 @@ MainWindow::Start()
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::Show()
|
||||
{
|
||||
if (fChatLayout->CountItems() == 0)
|
||||
SetConversation(NULL);
|
||||
BWindow::Show();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MainWindow::QuitRequested()
|
||||
{
|
||||
|
@ -101,14 +111,20 @@ MainWindow::QuitRequested()
|
|||
button_index = alert->Go();
|
||||
}
|
||||
|
||||
AppPreferences::Get()->MainWindowListWeight
|
||||
= fSplitView->ItemWeight((int32)0);
|
||||
AppPreferences::Get()->MainWindowChatWeight
|
||||
= fSplitView->ItemWeight((int32)1);
|
||||
AppPreferences::Get()->MainWindowRect = Frame();
|
||||
_SaveWeights();
|
||||
|
||||
if (button_index == 0) {
|
||||
fServer->Quit();
|
||||
|
||||
// ConversationViews will be removed by Server's deletion of Conversations,
|
||||
// but some special views (protocol logs, the blank ConversationView)
|
||||
// must be done manually
|
||||
for (int i = fChatLayout->CountItems() - 1; i >= 0; i--)
|
||||
fChatLayout->RemoveItem(i);
|
||||
fChatLayout->RemoveSelf();
|
||||
delete fChatLayout;
|
||||
|
||||
AppPreferences::Get()->Save();
|
||||
ReplicantStatusView::RemoveReplicant();
|
||||
be_app->PostMessage(B_QUIT_REQUESTED);
|
||||
|
@ -282,6 +298,7 @@ MainWindow::MessageReceived(BMessage* message)
|
|||
}
|
||||
case APP_SHOW_HELP:
|
||||
{
|
||||
// Borrowed from HaikuArchives/Calendar's _ShowHelp()
|
||||
BPathFinder pathFinder;
|
||||
BStringList paths;
|
||||
BPath path;
|
||||
|
@ -394,79 +411,52 @@ MainWindow::WorkspaceActivated(int32 workspace, bool active)
|
|||
void
|
||||
MainWindow::SetConversation(Conversation* chat)
|
||||
{
|
||||
fConversation = chat;
|
||||
if (chat != NULL) {
|
||||
SetConversationView(chat->GetView());
|
||||
if (chat == NULL) {
|
||||
SetTitle(APP_NAME);
|
||||
SetConversationView(fBackupChatView);
|
||||
return;
|
||||
}
|
||||
|
||||
_EnsureConversationView(chat);
|
||||
|
||||
bool found = false;
|
||||
BLayoutItem* item = fChatList.ValueFor(chat, &found);
|
||||
if (found == false)
|
||||
return;
|
||||
|
||||
BString title(chat->GetName());
|
||||
title << " ― " << APP_NAME;
|
||||
SetTitle(title.String());
|
||||
}
|
||||
else {
|
||||
SetConversationView(fBackupChatView);
|
||||
SetTitle(APP_NAME);
|
||||
}
|
||||
|
||||
// Remove "Protocol" menu
|
||||
BMenuItem* chatMenuItem = fMenuBar->FindItem(B_TRANSLATE("Chat"));
|
||||
BMenuItem* protocolMenuItem = fMenuBar->FindItem(B_TRANSLATE("Protocol"));
|
||||
if (protocolMenuItem != NULL)
|
||||
fMenuBar->RemoveItem(protocolMenuItem);
|
||||
|
||||
// Populate new "Protocol" menu if need be
|
||||
BMenu* protocolMenu = _CreateProtocolMenu();
|
||||
if (protocolMenu != NULL)
|
||||
fMenuBar->AddItem(protocolMenu, fMenuBar->IndexOf(chatMenuItem) + 1);
|
||||
|
||||
_SaveWeights();
|
||||
fConversation = chat;
|
||||
fChatLayout->SetVisibleItem(item);
|
||||
_ApplyWeights();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::SetConversationView(ConversationView* chatView)
|
||||
MainWindow::SetConversationView(ConversationView* view)
|
||||
{
|
||||
// Save split weights
|
||||
float weightChat = fRightView->ItemWeight((int32)0);
|
||||
float weightSend = fRightView->ItemWeight((int32)1);
|
||||
float horizChat, horizList, vertChat, vertSend;
|
||||
fChatView->GetWeights(&horizChat, &horizList, &vertChat, &vertSend);
|
||||
int32 index = fChatLayout->IndexOfView(view);
|
||||
if (index < 0) {
|
||||
BLayoutItem* item = fChatLayout->AddView(view);
|
||||
fChatLayout->SetVisibleItem(item);
|
||||
} else
|
||||
fChatLayout->SetVisibleItem(index);
|
||||
|
||||
fRightView->RemoveChild(fRightView->FindView("chatView"));
|
||||
fChatView = chatView;
|
||||
|
||||
fRightView->AddChild(fChatView, 9);
|
||||
|
||||
// Remove "Protocol" menu
|
||||
BMenuItem* chatMenuItem = fMenuBar->FindItem("Protocol");
|
||||
BMenu* chatMenu;
|
||||
if (chatMenuItem != NULL && (chatMenu = chatMenuItem->Submenu()) != NULL)
|
||||
fMenuBar->RemoveItem(chatMenu);
|
||||
|
||||
// Add and populate "Protocol" menu, if appropriate
|
||||
if (fConversation != NULL) {
|
||||
ProtocolLooper* looper = fConversation->GetProtocolLooper();
|
||||
BObjectList<BMessage> menuItems = looper->Protocol()->MenuBarItems();
|
||||
for (int i = 0; i < menuItems.CountItems(); i++) {
|
||||
BMessage* itemMsg = menuItems.ItemAt(i);
|
||||
BMessage* msg = new BMessage(*itemMsg);
|
||||
BMessage toSend;
|
||||
msg->FindMessage("_msg", &toSend);
|
||||
toSend.AddString("chat_id", fConversation->GetId());
|
||||
toSend.AddInt64("instance", looper->GetInstance());
|
||||
msg->ReplaceMessage("_msg", &toSend);
|
||||
|
||||
BMenuItem* item = new BMenuItem(msg);
|
||||
if (item == NULL)
|
||||
continue;
|
||||
if (msg->GetBool("x_to_protocol", true) == true)
|
||||
item->SetTarget(looper);
|
||||
else
|
||||
item->SetTarget(this);
|
||||
chatMenu->AddItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply saved weights
|
||||
fSplitView->SetItemWeight(0, AppPreferences::Get()->MainWindowListWeight, true);
|
||||
fSplitView->SetItemWeight(1, AppPreferences::Get()->MainWindowChatWeight, true);
|
||||
fChatView->SetWeights(horizChat, horizList, vertChat, vertSend);
|
||||
if (weightChat * weightSend != 0) {
|
||||
fRightView->SetItemWeight(0, weightChat, true);
|
||||
fRightView->SetItemWeight(1, weightSend, true);
|
||||
}
|
||||
|
||||
// Save ChatView weights to settings
|
||||
AppPreferences::Get()->ChatViewHorizChatWeight = horizChat;
|
||||
AppPreferences::Get()->ChatViewHorizListWeight = horizList;
|
||||
AppPreferences::Get()->ChatViewVertChatWeight = vertChat;
|
||||
AppPreferences::Get()->ChatViewVertSendWeight = vertSend;
|
||||
_ApplyWeights();
|
||||
}
|
||||
|
||||
|
||||
|
@ -475,6 +465,13 @@ MainWindow::RemoveConversation(Conversation* chat)
|
|||
{
|
||||
SetConversation(NULL);
|
||||
|
||||
bool found = false;
|
||||
BLayoutItem* item = fChatList.ValueFor(chat, &found);
|
||||
if (item != NULL)
|
||||
item->RemoveSelf();
|
||||
if (found == true)
|
||||
fChatList.RemoveItemFor(chat);
|
||||
|
||||
int32 index = fListView->IndexOf(chat->GetListItem());
|
||||
if (index > 0)
|
||||
index--;
|
||||
|
@ -506,17 +503,8 @@ MainWindow::_InitInterface()
|
|||
true, false, B_NO_BORDER);
|
||||
|
||||
// Right-side of window, Chat + Textbox
|
||||
fRightView = new BSplitView(B_VERTICAL, 0);
|
||||
fChatLayout = new BCardLayout();
|
||||
fBackupChatView = new ConversationView();
|
||||
fChatView = fBackupChatView;
|
||||
|
||||
// Load weights from settings
|
||||
float horizChat, horizList, vertChat, vertSend;
|
||||
horizChat = AppPreferences::Get()->ChatViewHorizChatWeight;
|
||||
horizList = AppPreferences::Get()->ChatViewHorizListWeight;
|
||||
vertChat = AppPreferences::Get()->ChatViewVertChatWeight;
|
||||
vertSend = AppPreferences::Get()->ChatViewVertSendWeight;
|
||||
fChatView->SetWeights(horizChat, horizList, vertChat, vertSend);
|
||||
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL)
|
||||
.Add((fMenuBar = _CreateMenuBar()))
|
||||
|
@ -527,12 +515,11 @@ MainWindow::_InitInterface()
|
|||
.Add(listScroll, 1)
|
||||
.Add(fStatusView)
|
||||
.End()
|
||||
.Add(fRightView, 5)
|
||||
.Add(fChatLayout, 5)
|
||||
.End()
|
||||
.End()
|
||||
.End();
|
||||
|
||||
SetConversation(NULL);
|
||||
_ToggleMenuItems();
|
||||
}
|
||||
|
||||
|
@ -630,6 +617,40 @@ MainWindow::_RefreshAccountsMenu()
|
|||
}
|
||||
|
||||
|
||||
BMenu*
|
||||
MainWindow::_CreateProtocolMenu()
|
||||
{
|
||||
if (fConversation == NULL)
|
||||
return NULL;
|
||||
|
||||
ProtocolLooper* looper = fConversation->GetProtocolLooper();
|
||||
BObjectList<BMessage> menuItems = looper->Protocol()->MenuBarItems();
|
||||
if (menuItems.CountItems() == 0)
|
||||
return NULL;
|
||||
|
||||
BMenu* menu = new BMenu(B_TRANSLATE("Protocol"));
|
||||
for (int i = 0; i < menuItems.CountItems(); i++) {
|
||||
BMessage* itemMsg = menuItems.ItemAt(i);
|
||||
BMessage* msg = new BMessage(*itemMsg);
|
||||
BMessage toSend;
|
||||
msg->FindMessage("_msg", &toSend);
|
||||
toSend.AddString("chat_id", fConversation->GetId());
|
||||
toSend.AddInt64("instance", looper->GetInstance());
|
||||
msg->ReplaceMessage("_msg", &toSend);
|
||||
|
||||
BMenuItem* item = new BMenuItem(msg);
|
||||
if (item == NULL)
|
||||
continue;
|
||||
if (msg->GetBool("x_to_protocol", true) == true)
|
||||
item->SetTarget(looper);
|
||||
else
|
||||
item->SetTarget(this);
|
||||
menu->AddItem(item);
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::_ToggleMenuItems()
|
||||
{
|
||||
|
@ -661,10 +682,12 @@ MainWindow::_ToggleMenuItems()
|
|||
ConversationItem*
|
||||
MainWindow::_EnsureConversationItem(BMessage* msg)
|
||||
{
|
||||
ChatMap chats = fServer->Conversations();
|
||||
|
||||
BString chat_id = msg->FindString("chat_id");
|
||||
Conversation* chat = fServer->ConversationById(chat_id, msg->FindInt64("instance"));
|
||||
|
||||
_EnsureConversationView(chat);
|
||||
|
||||
// Add conversation item if necessary, return it
|
||||
ConversationItem* item;
|
||||
if (chat != NULL && (item = chat->GetListItem()) != NULL) {
|
||||
if (fListView->HasItem(item))
|
||||
|
@ -682,6 +705,62 @@ MainWindow::_EnsureConversationItem(BMessage* msg)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::_EnsureConversationView(Conversation* chat)
|
||||
{
|
||||
// Add conversation's view if necessary
|
||||
bool added = false;
|
||||
fChatList.ValueFor(chat, &added);
|
||||
|
||||
if (added == false) {
|
||||
BLayoutItem* item = fChatLayout->AddView(chat->GetView());
|
||||
if (item != NULL)
|
||||
fChatList.AddItem(chat, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::_ApplyWeights()
|
||||
{
|
||||
// Chat-list and chat-view splitter
|
||||
fSplitView->SetItemWeight(0, AppPreferences::Get()->MainWindowListWeight, true);
|
||||
fSplitView->SetItemWeight(1, AppPreferences::Get()->MainWindowChatWeight, true);
|
||||
|
||||
// Chat-view's weights
|
||||
float horizChat, horizList, vertChat, vertSend;
|
||||
horizChat = AppPreferences::Get()->ChatViewHorizChatWeight;
|
||||
horizList = AppPreferences::Get()->ChatViewHorizListWeight;
|
||||
vertChat = AppPreferences::Get()->ChatViewVertChatWeight;
|
||||
vertSend = AppPreferences::Get()->ChatViewVertSendWeight;
|
||||
|
||||
BLayoutItem* item = fChatLayout->VisibleItem();
|
||||
if (item != NULL)
|
||||
((ConversationView*)item->View())->SetWeights(horizChat, horizList, vertChat, vertSend);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::_SaveWeights()
|
||||
{
|
||||
// Chat-list and chat-view splitter
|
||||
AppPreferences::Get()->MainWindowListWeight = fSplitView->ItemWeight((int32)0);
|
||||
AppPreferences::Get()->MainWindowChatWeight = fSplitView->ItemWeight((int32)1);
|
||||
|
||||
// ChatView's weights
|
||||
float horizChat, horizList, vertChat, vertSend;
|
||||
BLayoutItem* item = fChatLayout->VisibleItem();
|
||||
if (item == NULL)
|
||||
return;
|
||||
((ConversationView*)item->View())->GetWeights(&horizChat, &horizList, &vertChat, &vertSend);
|
||||
|
||||
AppPreferences::Get()->ChatViewHorizChatWeight = horizChat;
|
||||
AppPreferences::Get()->ChatViewHorizListWeight = horizList;
|
||||
AppPreferences::Get()->ChatViewVertChatWeight = vertChat;
|
||||
AppPreferences::Get()->ChatViewVertSendWeight = vertSend;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MainWindow::_PopulateWithAccounts(BMenu* menu, ProtocolSettings* settings)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright 2021, Jaidyn Levesque. All rights reserved.
|
||||
* Copyright 2009-2011, Andrea Anzani. All rights reserved.
|
||||
* Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved.
|
||||
* Copyright 2021-2022, Jaidyn Levesque. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _MAIN_WINDOW_H
|
||||
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "Server.h"
|
||||
|
||||
class BCardLayout;
|
||||
class BLayoutItem;
|
||||
class BMenu;
|
||||
class BSplitView;
|
||||
class BTextView;
|
||||
|
@ -31,6 +33,7 @@ public:
|
|||
MainWindow();
|
||||
|
||||
void Start();
|
||||
void Show();
|
||||
virtual bool QuitRequested();
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
@ -40,7 +43,7 @@ public:
|
|||
bool active);
|
||||
|
||||
void SetConversation(Conversation* chat);
|
||||
void SetConversationView(ConversationView* chatView);
|
||||
void SetConversationView(ConversationView* view);
|
||||
void RemoveConversation(Conversation* chat);
|
||||
void SortConversation(Conversation* chat);
|
||||
|
||||
|
@ -52,11 +55,16 @@ private:
|
|||
BMenuBar* _CreateMenuBar();
|
||||
BMenu* _CreateAccountsMenu();
|
||||
void _RefreshAccountsMenu();
|
||||
BMenu* _CreateProtocolMenu();
|
||||
|
||||
void _ToggleMenuItems();
|
||||
|
||||
ConversationItem*
|
||||
_EnsureConversationItem(BMessage* msg);
|
||||
void _EnsureConversationView(Conversation* chat);
|
||||
|
||||
void _ApplyWeights();
|
||||
void _SaveWeights();
|
||||
|
||||
bool _PopulateWithAccounts(BMenu* menu,
|
||||
ProtocolSettings* settings);
|
||||
|
@ -67,15 +75,16 @@ private:
|
|||
bool fWorkspaceChanged;
|
||||
BMenuBar* fMenuBar;
|
||||
|
||||
KeyMap<Conversation*, BLayoutItem*> fChatList;
|
||||
|
||||
// Left panel, chat list
|
||||
ConversationListView* fListView;
|
||||
StatusView* fStatusView;
|
||||
BSplitView* fSplitView;
|
||||
|
||||
// Right panel, chat
|
||||
BSplitView* fRightView;
|
||||
BCardLayout* fChatLayout;
|
||||
Conversation* fConversation;
|
||||
ConversationView* fChatView;
|
||||
ConversationView* fBackupChatView;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ public:
|
|||
void AddItem(KEY k, TYPE t);
|
||||
|
||||
TYPE ValueFor(KEY, bool* found = NULL) const;
|
||||
KEY KeyFor(TYPE, bool* found = NULL) const;
|
||||
|
||||
TYPE RemoveItemAt(int32 position);
|
||||
TYPE RemoveItemFor(KEY);
|
||||
|
@ -68,6 +69,20 @@ KeyMap<KEY, TYPE>::ValueFor(KEY k, bool* found) const
|
|||
}
|
||||
|
||||
|
||||
template<class KEY, class TYPE>
|
||||
inline KEY
|
||||
KeyMap<KEY, TYPE>::KeyFor(TYPE v, bool* found) const
|
||||
{
|
||||
*found = false;
|
||||
for (int32 i = 0; i < CountItems(); i++)
|
||||
if (ValueAt(i) == v) {
|
||||
*found = true;
|
||||
return KeyAt(i);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
template<class KEY, class TYPE>
|
||||
inline TYPE
|
||||
KeyMap<KEY, TYPE>::RemoveItemAt(int32 position)
|
||||
|
|
Ŝarĝante…
Reference in New Issue