Compare commits

...

10 Commits

Author SHA1 Message Date
Pascal Abresch 2ddca713c6 Talkview.cpp: rename _chat and _message
No functional change intended
2021-12-22 19:13:02 +01:00
Pascal Abresch a3db234a9f Use Document colors in timeline 2021-12-22 19:13:00 +01:00
Pascal Abresch 3609bbea28 Remove popup show chatlog menu 2021-12-22 19:11:27 +01:00
Pascal Abresch 61907c08dd Sort rosterview (determenistic channel order 2021-12-22 19:11:27 +01:00
Pascal Abresch f0c6faa193 More consistent using of the Buddy term 2021-12-22 19:11:27 +01:00
Adrien Destugues 447f91d80d Handle detection of highlighted messages outside of TalkView 2021-12-22 18:50:46 +01:00
Adrien Destugues ba54032d17 Update userguide a bit
Fixes #49.
2021-12-22 18:07:37 +01:00
Adrien Destugues 408acef105 Colorize MUC items in the roster when there is activity
Fixes #68.
2021-12-22 14:39:52 +01:00
Adrien Destugues cd64eff494 Add some icons experiments 2021-11-20 09:55:40 +01:00
Adrien Destugues 6cd7d711be Update cmake minimum version to avoid a warning.
We don't need to support old cmake version, just use what's currently
available in Haiku.
2021-10-27 10:12:26 +02:00
26 changed files with 259 additions and 240 deletions

View File

@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 2.8)
cmake_minimum_required (VERSION 3.20)
# projectname is the same as the main-executable
project(Renga)

View File

@ -45,7 +45,7 @@ int RosterView::ListComparison(const void *a, const void *b) {
}
void RosterView::AttachedToWindow() {
// superclass call
// superclass call
BOutlineListView::AttachedToWindow();
// on double-click
@ -58,11 +58,10 @@ void RosterView::AttachedToWindow() {
_message_item = new BMenuItem("Send Message" B_UTF8_ELLIPSIS, new BMessage(JAB_OPEN_MESSAGE));
_change_user_item = new BMenuItem("Edit Buddy", new BMessage(JAB_OPEN_EDIT_BUDDY_WINDOW));
_remove_user_item = new BMenuItem("Remove Buddy", new BMessage(JAB_REMOVE_BUDDY));
_user_info_item = new BMenuItem("Get User Info", new BMessage(JAB_USER_INFO));
_user_chatlog_item = new BMenuItem("Show Chat Log", new BMessage(JAB_SHOW_CHATLOG));
_user_info_item = new BMenuItem("Get Buddy Info", new BMessage(JAB_USER_INFO));
_presence = new BMenu("Presence");
_subscribe_presence = new BMenuItem("Subscribe", new BMessage(JAB_SUBSCRIBE_PRESENCE));
_unsubscribe_presence = new BMenuItem("Unsubscribe", new BMessage(JAB_UNSUBSCRIBE_PRESENCE));
@ -77,8 +76,6 @@ void RosterView::AttachedToWindow() {
_popup->AddSeparatorItem();
_popup->AddItem(_user_info_item);
_popup->AddSeparatorItem();
_popup->AddItem(_user_chatlog_item);
_popup->AddSeparatorItem();
_popup->AddItem(_presence);
// create top level lists
@ -88,7 +85,7 @@ void RosterView::AttachedToWindow() {
AddItem(_offline = new RosterSuperitem("Offline"));
AddItem(_transports = new RosterSuperitem("Live Transports"));
AddItem(_bookmarks = new RosterSuperitem("Group chats"));
// make maps (BUGBUG better way to do two-way map?)
_item_to_status_map[_offline] = UserID::OFFLINE;
_item_to_status_map[_online] = UserID::ONLINE;
@ -108,7 +105,7 @@ void RosterView::AttachedToWindow() {
_status_to_item_map[UserID::UNKNOWN] = _unknown;
_status_to_item_map[UserID::TRANSPORT_ONLINE] = _transports;
_status_to_item_map[UserID::UNACCEPTED] = _unaccepted;
// BUGBUG events
_presence->SetTargetForItems(Window());
_popup->SetTargetForItems(Window());
@ -120,7 +117,7 @@ void RosterView::AttachedToWindow() {
RosterItem *RosterView::CurrentItemSelection() {
int32 index = CurrentSelection();
if (index >= 0) {
return dynamic_cast<RosterItem *>(ItemAt(index));
} else {
@ -131,7 +128,7 @@ RosterItem *RosterView::CurrentItemSelection() {
BookmarkItem* RosterView::CurrentBookmarkSelection()
{
int32 index = CurrentSelection();
if (index >= 0) {
return dynamic_cast<BookmarkItem *>(ItemAt(index));
} else {
@ -153,10 +150,10 @@ void RosterView::MouseDown(BPoint point) {
if (buttons & B_SECONDARY_MOUSE_BUTTON) {
// update menu before presentation
UpdatePopUpMenu();
BPoint screen_point(point);
ConvertToScreen(&screen_point);
BRect r(screen_point.x - 4, screen_point.y - 20, screen_point.x + 24, screen_point.y + 4);
_popup->Go(screen_point, true, true, r, false);
//_popup->Go(screen_point, true, true, false);
@ -168,12 +165,12 @@ void RosterView::RemoveSelected() {
// numeric and object based selections
int32 selected = CurrentSelection();
RosterItem *item = CurrentItemSelection();
if (item == NULL) {
// not a roster item, won't remove
return;
}
// remove item from view
RemoveItem(CurrentSelection());
@ -271,41 +268,64 @@ void RosterView::LinkTransport(const UserID *added_transport) {
AddUnder(new TransportItem(added_transport), _transports);
}
static int compareStrings(const char* a, const char* b)
{
// FIXME use ICU locale aware comparison instead
int icompare = strcasecmp(a, b);
if (icompare != 0)
return icompare;
// In case the names are case-insensitive-equal, still sort them in a
// predictible way
return strcmp(a, b);
}
int32 CompareBookmarks(const BListItem* first, const BListItem* second) {
gloox::JID firstBookmark = dynamic_cast<const BookmarkItem*>(first)->GetUserID();
gloox::JID secondBookmark = dynamic_cast<const BookmarkItem*>(second)->GetUserID();
return compareStrings(firstBookmark.full().c_str(), secondBookmark.full().c_str());
}
void RosterView::LinkBookmark(const gloox::JID& added_bookmark, BString name) {
int32 index = FindBookmark(added_bookmark);
if (index < 0)
if (index < 0) {
AddUnder(new BookmarkItem(added_bookmark, name), _bookmarks);
else {
SortItemsUnder(_bookmarks, true, &CompareBookmarks);
} else {
BookmarkItem* item = dynamic_cast<BookmarkItem*>(FullListItemAt(index));
item->Update(this, be_plain_font);
Invalidate(ItemFrame(index));
}
}
void RosterView::UnlinkUser(const gloox::JID& removed_user) {
// does user exist
int32 index = FindUser(removed_user);
if (index >= 0) {
RemoveItem(index);
RemoveItem(index);
}
}
void RosterView::UnlinkTransport(const gloox::JID& removed_transport) {
// does transport exist
int32 index = FindTransport(removed_transport);
if (index >= 0) {
RemoveItem(index);
RemoveItem(index);
}
}
void RosterView::UnlinkBookmark(const gloox::JID& removed_bookmark) {
// does transport exist
int32 index = FindBookmark(removed_bookmark);
if (index >= 0) {
RemoveItem(index);
RemoveItem(index);
}
}
@ -317,7 +337,7 @@ int32 RosterView::FindUser(const gloox::JID& compare_user) {
if (item == NULL || item->StalePointer()) {
continue;
}
// compare against RosterView
if (item->GetUserID()->JID().bare() == compare_user.bare()) {
return i;
@ -336,7 +356,7 @@ int32 RosterView::FindTransport(const gloox::JID& compare_transport) {
if (item == NULL) {
continue;
}
// compare against RosterView
if (item->GetUserID()->JID() == compare_transport) {
return i;
@ -357,7 +377,7 @@ int32 RosterView::FindBookmark(const gloox::JID& compare_jid)
if (item == NULL) {
continue;
}
// compare against RosterView
if (item->GetUserID() == compare_jid) {
return i;
@ -390,7 +410,6 @@ void RosterView::UpdatePopUpMenu() {
_remove_user_item->SetEnabled(true);
_user_info_item->SetEnabled(true);
_user_chatlog_item->SetEnabled(BlabberSettings::Instance()->Tag("autoopen-chatlog"));
_presence->SetEnabled(true);
@ -415,7 +434,6 @@ void RosterView::UpdatePopUpMenu() {
_remove_user_item->SetEnabled(true);
_user_info_item->SetEnabled(false);
_user_chatlog_item->SetEnabled(false);
_presence->SetEnabled(false);
} else {
@ -432,7 +450,6 @@ void RosterView::UpdatePopUpMenu() {
_remove_user_item->SetEnabled(false);
_user_info_item->SetEnabled(false);
_user_chatlog_item->SetEnabled(false);
_presence->SetEnabled(false);
}
@ -458,7 +475,7 @@ void RosterView::UpdateRoster() {
for (int i = 0; i < FullListCountItems(); ++i) {
RosterItem *item = dynamic_cast<RosterItem *>(FullListItemAt(i));
TransportItem *transport_item = dynamic_cast<TransportItem *>(FullListItemAt(i));
// skip illegal entries
if (item == NULL && transport_item == NULL) {
continue;
@ -472,14 +489,14 @@ void RosterView::UpdateRoster() {
goto RESET;
}
// change of statuses
if (item->GetUserID()->OnlineStatus() != _item_to_status_map[Superitem(item)]) {
UserID::online_status old_status = _item_to_status_map[Superitem(item)];
// remove the item from the current superitem...
RemoveItem(i);
// and add it to the appropriate one
AddUnder(item, _status_to_item_map[item->GetUserID()->OnlineStatus()]);
@ -489,9 +506,9 @@ void RosterView::UpdateRoster() {
} else if (item->GetUserID()->OnlineStatus() == UserID::OFFLINE && item->GetUserID()->IsUser() && old_status == UserID::ONLINE) {
SoundSystem::Instance()->PlayUserOfflineSound();
}
goto RESET;
}
}
// clean it
InvalidateItem(i);
@ -507,7 +524,7 @@ void RosterView::UpdateRoster() {
if (transport_item->GetUserID()->OnlineStatus() != _item_to_status_map[Superitem(transport_item)]) {
// remove the item from the current superitem...
RemoveItem(i);
// and add it to the appropriate one
if (transport_item->GetUserID()->OnlineStatus() == UserID::TRANSPORT_ONLINE) {
AddUnder(transport_item, _status_to_item_map[transport_item->GetUserID()->OnlineStatus()]);
@ -519,9 +536,9 @@ void RosterView::UpdateRoster() {
} else if (transport_item->GetUserID()->OnlineStatus() == UserID::OFFLINE) {
SoundSystem::Instance()->PlayUserOfflineSound();
}
goto RESET;
}
}
// clean it
InvalidateItem(i);

View File

@ -62,7 +62,6 @@ private:
BMenuItem *_change_user_item;
BMenuItem *_remove_user_item;
BMenuItem *_user_info_item;
BMenuItem *_user_chatlog_item;
BMenu *_presence;
BMenuItem *_subscribe_presence;

View File

@ -14,6 +14,7 @@
#include <File.h>
#include <FindDirectory.h>
#include <Notification.h>
#include <Path.h>
#include <interface/Window.h>
@ -456,10 +457,7 @@ TalkManager::handleMUCMessage(gloox::MUCRoom *room,
{
TalkView *window = NULL;
string group_username;
// clear out text
group_username = msg.from().resource();
string group_username = msg.from().resource();
window = fGroupMap.at(room);
// submit the chat
@ -469,7 +467,28 @@ TalkManager::handleMUCMessage(gloox::MUCRoom *room,
if (group_username.empty()) {
window->AddToTalk("System:", msg.body(), TalkView::OTHER);
} else {
window->NewMessage(group_username, msg.body());
bool highlight;
// Highlight messages when they mention the nickname
// TODO also use metadata in the message that may indicate an highlight
if (BString(msg.body().c_str()).IFindFirst(room->nick().c_str()) != B_ERROR) {
// NOTE: This will erronously pop up for backlog messages aswell, can be improved
// once we have MAM
BNotification notification(B_INFORMATION_NOTIFICATION);
notification.SetGroup(room->name().c_str());
notification.SetTitle(group_username.c_str());
notification.SetContent(msg.body().c_str());
notification.Send();
BlabberMainWindow::Instance()->FlagBookmarkItem(msg.from().bare(),
BookmarkItem::NICKNAME_HIGHLIGHT);
highlight = true;
} else {
BlabberMainWindow::Instance()->FlagBookmarkItem(msg.from().bare(),
BookmarkItem::ACTIVITY);
highlight = false;
}
window->NewMessage(group_username, msg.body(), highlight);
}
window->UnlockLooper();
}
@ -497,7 +516,7 @@ TalkManager::handleMUCSubject(gloox::MUCRoom *room,
window->LockLooper();
window->SetStatus(subject);
if (!nick.empty()) {
// Do it only for topic chnages (not for the initial topic setting)
// Do it only for topic changes (not for the initial topic setting)
window->AddToTalk(nick, topic.String(), TalkView::OTHER);
}
window->UnlockLooper();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -39,36 +39,41 @@ using this client as natural as any other you're used to.
As such, let's look at Renga!
<a NAME="logging">
<font FACE="Courier New"><b><u><h1 ALIGN=CENTER>Logging In</h1></u></b></font>
<center><font SIZE=-2><a HREF="#top">top</a></font></center>
<h1 ALIGN=CENTER>Logging In</h1>
<a href="#top">top</a>
<p>When you first run Renga, you will be presented with a window like this:
<p>When you first run Renga, you will be presented with a window like this:</p>
<p ALIGN=CENTER><img SRC="login-pane.png">
<div ALIGN=CENTER><img SRC="login-pane.png"></div>
<p>If you've used XMPP in the past then this should look familiar to you. Just
enter the login information you've always used. If you haven't seen the nickname field
before, this is used as a friendly name only for yourself in chat windows. Nobody else will see this
information so it's not critical. As an expert, you'll probably want to check the Auto-login box as well.
information so it's not critical. As an expert, you'll probably want to check the Auto-login box as well.</p>
<p>If you're new to XMPP, this is an important step in getting online. You'll want
to decide on your official username! Here is what all the fields mean:
<p>If you're new to XMPP, you need to create an account. This is an important step in getting online.
You'll want to decide on your official username! Here is what all the fields mean:</p>
<ul>
<li><b>Nickname:</b> This is a friendly name for yourself. It'll only be used in your chat windows and no one else will see it, so feel free to change it to fit your mood.
<li><b>Username:</b> This is the username you will be officially referred to with.
<li><b>Password:</b> Your password.
<li><b>Create This Account:</b> If this is a new account for you, check this box and the account will be created (if possible) before you log in. In the future, when you login with the same username, you want to keep this box unchecked.
<li><b>Auto-login:</b> This is a handy option if you just want Renga to log you in with your last entered username/password automatically. It's quicker than entering in your information all the time, but also less secure. If you're on a single-user machine, this is a recommended option.
<li><b>Nickname:</b> This is a friendly name for yourself. Other people will see it, and you can change it each time you connect.</li>
<li><b>Username:</b> This is the username you will be officially referred to with. You cannot change this once you picked one.</li>
<li><b>Password:</b> Your password.</li>
<li><b>Auto-login:</b> This is a handy option if you just want Renga to log you in with your
last entered username/password automatically. It's quicker than entering in your
information all the time, but also less secure. If you're on a single-user machine, this
is a recommended option.</li>
</ul>
<p>There are also some rules you should know about how Auto-login works in specific situations. Here they are:
<p>To create your account, use the "Create an account" button and follow the instructions. You will
need to pick a server to host your account, or you can let Renga select one for you.</p>
<p>There are also some rules you should know about how Auto-login works in specific situations. Here they are:</p>
<ul>
<li><b>Normal login:</b> In the "normal" situation, running Renga will cause the login process to initiate for the last username/password you tried logging in with.
<li><b>Failed login:</b> If Auto-login fails to log you in because your last username/password is, or is no longer, valid then the login screen will appear and allow you to correct any mistakes.
<li><b>Multiple logins:</b> If you already have another instance of Renga running on the machine, Auto-login will not run for that second instance. The reason is that logging you in with the same name as the one already running will cause the first to disconnect. Not convenient!
<li><b>Change login:</b> If you use Auto-login, but you want to change your username and log in under another address (stalkers again?), simply logout by selecting "Log Off" from the File menu.
<li><b>Normal login:</b> In the "normal" situation, running Renga will cause the login process to initiate for the last username/password you tried logging in with.</li>
<li><b>Failed login:</b> If Auto-login fails to log you in because your last username/password is, or is no longer, valid then the login screen will appear and allow you to correct any mistakes.</li>
<li><b>Multiple logins:</b> If you already have another instance of Renga running on the machine, Auto-login will not run for that second instance. Having two copies of the application running for the same account on the same machine would just be confusing.</li>
<li><b>Change login:</b> If you use Auto-login, but you want to change your username and log in under another address (stalkers again?), simply logout by selecting "Log Off" from the File menu. </li>
</ul>
<a NAME="im">
@ -77,9 +82,9 @@ to decide on your official username! Here is what all the fields mean:
<p>Congratulations, you're logged in! Your login window has now transformed and looks like:
<p ALIGN=CENTER><img SRC="logged-in.png" HSPACE=5><img SRC="logged-in-with-friends.png">
<p ALIGN=CENTER><img SRC="logged-in-with-friends.png"></p>
<p>This is your buddy list, or "roster" as the XMPP group likes to call it. This is where you'll see your friends and family, their online status and more. If you just created your account, it will appear empty. So let's fill it up!
<p>On the left is your buddy list, or "roster" as the XMPP group likes to call it. This is where you'll see your friends and family, their online status and more. If you just created your account, it will appear empty. So let's fill it up!
<p>There are two basic concepts when dealing with this list: <i>roster</i> and <i>presence</i>. While many external chat systems
treat these concepts as one entity, XMPP keeps them separate. What you need to rememeber is that even if you add a friend to your list (<i>roster</i>), you don't automatically begin seeing their online status (<i>presence</i>). You need to ask for it.
@ -105,56 +110,17 @@ Next, you want to add a nickname, a casual name that tends to be less cryptic th
If you've gotten acceptance, you've probably already noticed that the user is now either in the online or offline list and their color is green (dark or light) or red. Bet you can't guess what this means? ;-)
Right! The greens are for online, red is for offline. The <b><font COLOR=005500>darker shade of green</font></b> means the user is online, but is either away from their computer or does not want to be distrubed. <b><font COLOR=00CC00>The lighter shade of green</font></b> signifies their open for chat. Usually, after being granted presence, the user is online because, well, how else could they have accepted your presence?
<p>Great! So the user is online. Now what? You want to chat is what! Isn't that why you downloaded this program? :-) There are two options for chatting:
<p>Great! So the user is online. Now what? You want to chat is what! Isn't that why you downloaded this program? :-)</p>
<ul>
<li><b>Message-based or ICQ-style chat:</b> ICQ users will be familiar with this, and frankly no one else. Message-based chat lets you send a single message and then your window will go away. It's quick, it's easy and it can be annoying for the receiving user. :-) ICQ users should also note one difference in implementation: XMPP will queue multiple, unanswered messages in the same window alleviating the pain of a billion windows to read through and answer separately! The ICQ-style of messages can be handy for quick messages that require no, or little response. They can be handy because the window goes away when you respond to one.
<li><b>Scrolling chat or AOL-style chat:</b> This is what most users are familiar with as it's used by AOL, and uncommonly ICQ. It's a one-on-one chat, you and one other user, with messages scrolling on the top of the window and an area below to enter your next message. This is the most pleasant way to communicate long conversations.
</ul>
<p>The chatting happens on the right part of the main window. At the bottom is a text input where you can send your messages. Above that is a list of previous messages for the current conversation. To chat with different people, simple select them on the left panel.</p>
<p>While the messaging and chat paradigms are different, the window will look mostly the same:
<p ALIGN=CENTER><img SRC="chat-screen.png">
<p>Make sure you understand that little note on the lower left. When newlines are allowed, simply hitting <b>Enter</b> inserts a raw newline into your message, otherwise it sends the message. <b>Command-Enter</b> always performs the opposite operation.
<p>If you want to send a long message with multiple lines, remember to use <b>Command-Enter</b> to insert a newline (since pressing <b>Enter</b> will send the current message to the other user). If you are not happy with that, you can exchange the two in the preferences window.</p>
<a NAME="chatfeatures">
<font FACE="Courier New"><b><u><h1 ALIGN=CENTER>Chat Features</h1></u></b></font>
<center><font SIZE=-2><a HREF="#top">top</a></font></center>
<p>There are several fun chat features available in Renga. The first you might notice are <i>Canned Quips</i>. These are pre-generated messages that you define. You usually want to type phrases and exclamations you say a lot. As an example, these are my usual quips:
<ul>
<li>For more information about Rapture In Venice, go to http://www.users.uswest.net/~jblanco.
<li>Sup.
<li>What's that? You say Renga still hasn't crashed yet? Not surprising.
<li>blue screen of death
</ul>
<p>I've included four messages, but you can use up to nine. Each message is associated with a <b>Command-number</b> key, so <i>"Message #4"</i> is triggered with <b>Command-4</b>. So easy. :-)
You can edit your canned quips in the preferences panel under the <i>"Messaging"</i> tab.
<p>You'll notice that next to each message there is a checkbox as seen below:
<p ALIGN=CENTER><img SRC="preferences-panel.png">
<p>This is the <i>quick-fire</i> option and it affects how messages are included in your chat session:
<ul>
<li><b>When checked:</b> This means the message will be <i>"quick-fired."</i> Basically, when you hit the hotkey the message will be sent with no regard to what you already have in your outgoing message box. It's great for when you need to send the same message many times but don't want to cut-and-paste your current message to send it.
<li><b>When unchecked:</b> This means the message will be pasted in your outgoing message box wherever your cursor currently is.
</ul>
<p>As an example, I'm always having to tell people where my website is (whether they ask or not...heh heh)! I've set up my first message for quick-fire. So, if I'm in the middle of a sentence and I see the need to send the information out immediately, Command-1 sends it. Notice how my current message is unaffected:
<p ALIGN=CENTER><img SRC="quick-fired-message.png"><br><font SIZE=-2>- I've just pressed <b>Command-1</b> -</font>
<p>On the other hand, my fourth quip, "blue screen of death," is not a standalone message. The problem is I always have to type this phrase when explaining to strangers how much better <font COLOR=BLUE>B</font><font COLOR=RED>e</font>OS is than Windows! Seeing that I've had carpal-tunnel problems in the past typing this exact phrase thousands of times a day, I did't make it a quick-fire and instead include it in messages that are part of larger sentences as shown:
<p ALIGN=CENTER><img SRC="non-quick-fired-message.png"><br><font SIZE=-2>- I've just pressed <b>Command-4</b> -</font>
<p>Renga also supports what's known as <i>"/me syntax"</i>. This is when you want to type a message but want to make it as part of an action. It's almost always used for humorous purposes. Here's an example:
<p>Renga supports what's known as <i>"/me syntax"</i>. This is when you want to type a message but want to make it as part of an action. It's almost always used for humorous purposes. Here's an example:
<p ALIGN=CENTER><img SRC="me-syntax.png"><br><font SIZE=-2>- Note how /me makes my message an action -</font>
@ -162,18 +128,9 @@ You can edit your canned quips in the preferences panel under the <i>"Messaging"
<ul><tt>/me <i>your action</i></tt></ul>
<p>Here's exactly how I generated the previous example:
<p>Here's exactly how I generated the previous example:
<ul><tt>/me is saddened by your remark. :(</tt></ul>
<p>In addition to <i>"/me syntax"</i>, Renga supports other IRC-like and not so IRC-like <i>"slash"</i> commands:
<ul>
<li><b>/me message</b> - As stated above, instead of sending a message you convey an action you are fictionally or non-fictionally performing.
<li><b>/alert message</b> - When you have an urgent need to get your recipient's attention, precede your usual message with /alert and the window will be activated on the receiver's side as well as a sound played.
</ul>
<p>For some, <b>/alert</b> can be annoying as it can easily be abused. This feature can be turned off in the <i>"Chat Rules"</i> section of the preferences panel.
<ul><tt>/me does a barrel roll</tt></ul>
<p>A feature that is new with Jabber for <font COLOR=RED>B</font><font COLOR=BLUE>e</font>OS v1.2 is chat history. In any chat window, hold down the Command key and use the up and down arrows to scroll through the history of your last 50 messages. This is handy when your buddy misses a message or you just want to accentuate it! ;-)
@ -215,24 +172,20 @@ You can edit your canned quips in the preferences panel under the <i>"Messaging"
</ul>
<a NAME="transports">
<font FACE="Courier New"><b><u><h1 ALIGN=CENTER>XMPP Transports: Gateways to External Chat Systems</h1></u></b></font>
<center><font SIZE=-2><a HREF="#top">top</a></font></center>
<h1 ALIGN=CENTER>XMPP Transports: Gateways to External Chat Systems</h1>
<a HREF="#top">top</a>
<p>If XMPP was just another new chat system, then everyone would just be a little more ill. :-) But, in fact, XMPP is not. While it does support it's own network of users who can communicate with each other along with other things like sending files, XMPP allows it's users to talk directly with users of other chat clients! A little discussion about how it's done is in order.
<p>If XMPP was just another new chat system, then everyone would just be a little more ill. :-)
But, in fact, XMPP is not. While it does support it's own network of users who can communicate
with each other along with other things like sending files, XMPP allows it's users to talk directly
with users of other chat clients! A little discussion about how it's done is in order.</p>
<p>If you're familiar with other <font COLOR=BLUE>B</font><font COLOR=RED>e</font>OS apps such as GimICQ and BeAIM, you know that getting unofficial chat clients for popular chat systems is not a new thing. Anything on the Internet is hackable, so there's no reason to believe AOL and ICQ have secured their networks better than any hackable e-commerce system.
Well, these unofficial clients are just that -- clients. GimICQ only lets you talk to other ICQ users, BeAIM the same with AOL users. However, XMPP lets you talk to both of these systems and more!
<p>As with GimICQ and BeAIM, the idea is that you have a login to the external system already. What you do is <i>register</i> your login information with the XMPP transport that's responsible for talking with that system. Once complete, you can chat with AOL users just as easily as you can with XMPP users themselves.
<p>When you've registered with a transport, Renga has now become just like a login to another chat service. If you registered as "BeMan" under AOL, then anyone on AOL, or XMPP, who sends a message to your AOL address will reach you on your Renga client. Basically, you are using one client with one main login (your Jabber ID) and extra virtual logins (your AOL, etc... logins). Everything is completely transparent from now on.
<p>Lets try it. Go to your preferences panel and click the <i>"Transports"</i> tab. Let's pretend you want to register with the AOL transport (Feel free to go ahead and register with whichever transport you'd like to right now).
Assuming your username and password is <i>"BjorkLover"</i> and <i>"fulloflove"</i>, select the AOL transport and enter the information in as above:
<p ALIGN=CENTER><img SRC="aol-registering.png">
<p>Hit "Register".
<p>If you're familiar with other <font COLOR=BLUE>B</font><font COLOR=RED>e</font>OS apps such as
GimICQ and BeAIM, you know that getting unofficial chat clients for popular chat systems is not a
new thing. Anything on the Internet is hackable, so there's no reason to believe AOL and ICQ have
secured their networks better than any hackable e-commerce system.
Well, these unofficial clients are just that -- clients. GimICQ only lets you talk to other ICQ
users, BeAIM the same with AOL users. However, XMPP lets you talk to both of these systems and more!</p>
<p>Here's where I have to give my disclaimers. You may remember the very public chat wars that went on between AOL Instant Messenger and MSN Messenger a while back. Basically, Microsoft was trying to hack the AOL chat protocol so that MSN Messenger users could talk to AOL users and vice-versa. AOL would have none of it and in what was a hilarious coding war, the cycle began:
@ -255,24 +208,22 @@ if a transport doesn't work with Renga, it's probabably not the client's fault.
<p>Given a happy world where all transports work, you'll also want to add these external users to your roster. This is done the same as when adding XMPP users, except you want to change the menu to reflect what chat system they're using. Notice that the instructions on the "Add New Buddy" screen will change as you flip through the systems.
<p>The most common use of these bridging technologies is to access IRC discussion channels. Since
the IRC protocol does not change a lot, this seems to work better than bridging with other places.</p>
<p>To access an IRC channel, you need to mangle its name a bit. For example to join the #haiku
channel on irc.oftc.net you would use the address #haiku%irc.oftc.net@irc.jabberfr.org. Once joined,
this works like any other XMPP group chat.</p>
<a NAME="further">
<font FACE="Courier New"><b><u><h1 ALIGN=CENTER>Further Exploration</h1></u></b></font>
<center><font SIZE=-2><a HREF="#top">top</a></font></center>
<p>There are several other features that XMPP offers, as well as many nuances that are specific to Renga. The big one being changing your own online status. But I'll leave these all for you to explore! :-) If it's not easy enough to figure out on your own, then Rapture In Venice has failed you as a developer. So be confident!
<p>If you're a registered user, feel free to ask me for help. Rapture In Venice's contact information can be found below, but since this is a chat client the most fun way to get in touch is through XMPP! As I said before, my Jabber ID is rapture@jabber.org. I hope this user manual is a friendly springboard to the world of XMPP and Renga. Have fun!
<p>If you run into problems (or just want to say hi), you can find the Renga developers on our XMPP chat room renga@chat.jabberfr.org.</p>
<a NAME="cause">
<font FACE="Courier New"><b><u><h1 ALIGN=CENTER>The Rapture In Venice Cause</h1></u></b></font>
<center><font SIZE=-2><a HREF="#top">top</a></font></center>
<p>Rapture In Venice was born to help <font COLOR=BLUE>B</font><font COLOR=RED>e</font>OS become the #1 desktop OS on the consumer market. A lofty goal, but Be, Inc. started it. :-) As such, Rapture In Venice needs your support. If we're going to be able to create top quality applications that help bolster the existing <font COLOR=BLUE>B</font><font COLOR=RED>e</font>OS library, we need you to support us back.
Below is how you can get in contact with Rapture In Venice with question, tips, business proposals and whatever else you may need. As always, thank you for choosing Rapture In Venice.
<ul>
<p>Rapture In Venice<br>2663 S. Moore Dr. #B<br>Lakewood CO 80227<br>(720) 962-0898<br><a HREF="mailto:jblanco@uswest.net">jblanco@uswest.net</a><br><a HREF="http://www.users.uswest.net/~jblanco">http://www.users.uswest.net/~jblanco</a>
</ul>
<p>I hope this user manual is a friendly springboard to the world of XMPP and Renga. Have fun!
</body>

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Adrien Destugues <pulkomandy@pulkomandy.tk>
* Copyright 2019-2021 Adrien Destugues <pulkomandy@pulkomandy.tk>
*
* Distributed under terms of the MIT license.
*/
@ -17,18 +17,23 @@
#include "ui/HVIFUtil.h"
BBitmap *BookmarkItem::_online_icon = NULL;
BBitmap *BookmarkItem::_unknown_icon = NULL;
BookmarkItem::BookmarkItem(const gloox::JID& userid, BString name)
: BStringItem(name)
, _userid(userid)
, fFlags(0)
{
}
BookmarkItem::~BookmarkItem() {
}
void BookmarkItem::DrawItem(BView *owner, BRect frame, __attribute__((unused)) bool complete)
{
// get online status
@ -42,7 +47,7 @@ void BookmarkItem::DrawItem(BView *owner, BRect frame, __attribute__((unused)) b
BRect selectionFrame = frame;
selectionFrame.left = 0;
if (IsSelected()) {
owner->SetHighUIColor(B_LIST_SELECTED_BACKGROUND_COLOR);
owner->SetHighUIColor(B_LIST_SELECTED_BACKGROUND_COLOR);
} else {
owner->SetHighColor(owner->ViewColor());
}
@ -67,12 +72,16 @@ void BookmarkItem::DrawItem(BView *owner, BRect frame, __attribute__((unused)) b
if (name.IsEmpty())
name = _userid.full().c_str();
// TODO: set font color based on recent activity
if (IsSelected()) {
owner->SetHighUIColor(B_LIST_SELECTED_ITEM_TEXT_COLOR);
} else {
// When the room is active, we can clear the flags
fFlags = 0;
} else if (fFlags & NICKNAME_HIGHLIGHT)
owner->SetHighUIColor(B_FAILURE_COLOR);
else if (fFlags & ACTIVITY)
owner->SetHighUIColor(B_SUCCESS_COLOR);
else
owner->SetHighUIColor(B_LIST_ITEM_TEXT_COLOR);
}
// construct text positioning, keeping space for the icon on the left
font_height fh;
@ -82,6 +91,7 @@ void BookmarkItem::DrawItem(BView *owner, BRect frame, __attribute__((unused)) b
owner->DrawString(name, BPoint(frame.left + height, frame.bottom - fh.descent));
}
void BookmarkItem::Update(BView *owner, const BFont *font)
{
BListItem::Update(owner, font);
@ -107,6 +117,7 @@ void BookmarkItem::Update(BView *owner, const BFont *font)
}
}
const gloox::JID& BookmarkItem::GetUserID() const {
return _userid;
}

View File

@ -1,14 +1,10 @@
/*
* BookmarkkItem.h
* Copyright (C) 2019 Adrien Destugues <pulkomandy@pulkomandy.tk>
* Copyright 2019-2021 Adrien Destugues <pulkomandy@pulkomandy.tk>
*
* Distributed under terms of the MIT license.
*/
/** @file
* Bookmark (group chat) entries of the RosterView widget
*/
#pragma once
#include <Bitmap.h>
@ -18,19 +14,29 @@
#include "../jabber/UserID.h"
class BookmarkItem : public BStringItem {
public:
BookmarkItem(const gloox::JID& userid, BString name);
~BookmarkItem();
BookmarkItem(const gloox::JID& userid, BString name);
~BookmarkItem();
void DrawItem(BView *owner, BRect frame, bool complete = false);
virtual void Update(BView *owner, const BFont *font);
const gloox::JID& GetUserID() const;
void DrawItem(BView *owner, BRect frame, bool complete = false);
virtual void Update(BView *owner, const BFont *font);
const gloox::JID& GetUserID() const;
enum Flags {
NICKNAME_HIGHLIGHT = 1,
ACTIVITY = 2
};
void SetFlag(uint32 flag) { fFlags |= flag; }
private:
const gloox::JID _userid;
static BBitmap *_online_icon;
static BBitmap *_unknown_icon;
const gloox::JID _userid;
int32 fFlags;
static BBitmap* _online_icon;
static BBitmap* _unknown_icon;
};

View File

@ -19,7 +19,7 @@
#include "../jabber/Messages.h"
BuddyInfoWindow::BuddyInfoWindow(UserID *querying_user)
: BWindow(BRect(0, 0, 0, 0), "User Information", B_TITLED_WINDOW,
: BWindow(BRect(0, 0, 0, 0), "Buddy Information", B_TITLED_WINDOW,
B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS)
, fJID(querying_user->Handle().c_str())
{

View File

@ -19,7 +19,7 @@
#include "../jabber/TalkManager.h"
ChangeNameWindow::ChangeNameWindow(const gloox::JID& changing_user, BString oldName)
: BWindow(BRect(0, 0, 100, 100), "Changing User Name", B_TITLED_WINDOW,
: BWindow(BRect(0, 0, 100, 100), "Change Buddy Name", B_TITLED_WINDOW,
B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
_changing_user(changing_user)
{
@ -29,15 +29,15 @@ ChangeNameWindow::ChangeNameWindow(const gloox::JID& changing_user, BString oldN
AddChild(full_view);
BStringView *query = new BStringView(NULL, "Specify the new \"Nickname\" you'd like to use:");
_handle = new BTextControl(NULL, NULL, "", NULL);
if (BlabberSettings::Instance()->Data("last-talk-sent-to")) {
_handle->SetText(BlabberSettings::Instance()->Data("last-talk-sent-to"));
} else {
_handle->SetText("somebody@jabber.org");
}
BButton *cancel = new BButton("cancel", "Nevermind", new BMessage(JAB_CANCEL));
cancel->SetTarget(this);
@ -77,7 +77,7 @@ void ChangeNameWindow::MessageReceived(BMessage *msg) {
return;
}
// re-add to roster
JabberSpeak::Instance()->SetFriendlyName(_changing_user, _handle->Text());

View File

@ -1057,6 +1057,26 @@ void BlabberMainWindow::SetCustomStatus(string status) {
}
void
BlabberMainWindow::FlagBookmarkItem(const gloox::JID& room, uint32 flags)
{
int32 pos = _roster->FindBookmark(room);
if (pos < 0)
return;
auto* item = dynamic_cast<BookmarkItem*>(_roster->FullListItemAt(pos));
item->SetFlag(flags);
// Need to redo a FindItem because there is no FullListInvalidateItem, so we need to convert the
// FullList index returned by FindBookmark to a BListView index...
int32 listIndex = _roster->IndexOf(item);
// ... and this can fail if the item is in a collapsed part of the list
if (listIndex < 0)
return;
_roster->InvalidateItem(listIndex);
}
void
BlabberMainWindow::AddTalkView(TalkView* view)
{

View File

@ -15,6 +15,8 @@
#include <TextControl.h>
#include <Window.h>
#include <gloox/instantmucroom.h>
#include "ui/PictureView.h"
#include "jabber/RosterView.h"
@ -41,6 +43,7 @@ public:
void ShowLogin();
void SetCustomStatus(std::string status);
void FlagBookmarkItem(const gloox::JID& room, uint32 flags);
protected:
BlabberMainWindow(BRect frame);

View File

@ -14,7 +14,6 @@
#include <GroupLayout.h>
#include <GroupView.h>
#include <LayoutBuilder.h>
#include <Notification.h>
#include <Roster.h>
#include <storage/Path.h>
#include <SplitView.h>
@ -65,31 +64,31 @@ TalkView::TalkView(const gloox::JID *user, string group_room,
_status_view = new StatusView();
_status_view->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
_chat = new ChatTextView("chat", B_WILL_DRAW | B_FRAME_EVENTS);
_chat_scroller = new BScrollView("chat_scroller", _chat, B_WILL_DRAW, false, true);
_chat->TargetedByScrollView(_chat_scroller);
_chat->SetFontSize(12.0);
_chat->SetWordWrap(true);
_chat->SetStylable(true);
_chat->MakeEditable(false);
timeline = new ChatTextView("timeline", B_WILL_DRAW | B_FRAME_EVENTS);
timelineScroller = new BScrollView("timelineScroller", timeline, B_WILL_DRAW, false, true);
timeline->TargetedByScrollView(timelineScroller);
timeline->SetFontSize(12.0);
timeline->SetWordWrap(true);
timeline->SetStylable(true);
timeline->MakeEditable(false);
// message control
rgb_color text_color = ui_color(B_PANEL_TEXT_COLOR);
BFont text_font(be_plain_font);
_message = new BTextView("message", &text_font, &text_color, B_WILL_DRAW);
_message_scroller = new BScrollView("message_scroller", _message, B_WILL_DRAW, false, false);
messageInput = new BTextView("messageInput", &text_font, &text_color, B_WILL_DRAW);
messageInputScroller = new BScrollView("messageInputScroller", messageInput, B_WILL_DRAW, false, false);
_message->TargetedByScrollView(_message_scroller);
_message->SetWordWrap(true);
messageInput->TargetedByScrollView(messageInputScroller);
messageInput->SetWordWrap(true);
// editing filter for messaging
_message->AddFilter(new EditingFilter(_message, this));
messageInput->AddFilter(new EditingFilter(messageInput, this));
// handle splits
BSplitView* _split_talk = new BSplitView(B_VERTICAL);
_split_talk->AddChild(_chat_scroller);
_split_talk->AddChild(_message_scroller);
_split_talk->AddChild(timelineScroller);
_split_talk->AddChild(messageInputScroller);
_split_talk->SetItemWeight(0, 12, false);
_split_talk->SetItemWeight(1, 1, false);
_split_talk->SetSpacing(0);
@ -119,7 +118,7 @@ TalkView::TalkView(const gloox::JID *user, string group_room,
AddChild(_split_group_people);
AddChild(_status_view);
_message->MakeFocus(true);
messageInput->MakeFocus(true);
// generate window title
char buffer[1024];
@ -185,8 +184,8 @@ void TalkView::FrameResized(float width, float height)
{
BView::FrameResized(width, height);
BRect chat_rect = _chat->Frame();
BRect message_rect = _message->Frame();
BRect chat_rect = timeline->Frame();
BRect message_rect = messageInput->Frame();
chat_rect.OffsetTo(B_ORIGIN);
message_rect.OffsetTo(B_ORIGIN);
@ -194,11 +193,11 @@ void TalkView::FrameResized(float width, float height)
chat_rect.InsetBy(2.0, 2.0);
message_rect.InsetBy(2.0, 2.0);
_chat->SetTextRect(chat_rect);
_message->SetTextRect(message_rect);
timeline->SetTextRect(chat_rect);
messageInput->SetTextRect(message_rect);
_chat->Invalidate();
_chat_scroller->Invalidate();
timeline->Invalidate();
timelineScroller->Invalidate();
}
@ -281,7 +280,7 @@ void TalkView::MessageReceived(BMessage *msg) {
}
case JAB_CHAT_SENT: {
string message = _message->Text();
string message = messageInput->Text();
// eliminate empty messages
if (message.empty())
@ -292,17 +291,17 @@ void TalkView::MessageReceived(BMessage *msg) {
// we go through main app?
gloox::MUCRoom* room = (gloox::MUCRoom*)TalkManager::Instance()
->IsExistingWindowToGroup(GetGroupRoom());
room->send(_message->Text());
room->send(messageInput->Text());
} else
_session->send(_message->Text());
_session->send(messageInput->Text());
// user part
NewMessage(message);
// GUI
_message->ScrollToOffset(0);
_message->SetText("");
_message->MakeFocus(true);
messageInput->ScrollToOffset(0);
messageInput->SetText("");
messageInput->MakeFocus(true);
break;
}
@ -339,7 +338,7 @@ string TalkView::OurRepresentation() {
}
void TalkView::AddToTalk(string username, string message, user_type type) {
void TalkView::AddToTalk(string username, string message, user_type type, bool highlight) {
// transform local identity
if (IsGroupChat() && type == LOCAL)
username = _group_username;
@ -373,24 +372,24 @@ void TalkView::AddToTalk(string username, string message, user_type type) {
rgb_color blue = {0, 0, 255, 255};
rgb_color red = {255, 0, 0, 255};
rgb_color orange = {205, 113, 57, 255};
rgb_color message_color = ui_color(B_PANEL_TEXT_COLOR);
rgb_color bg_color = ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color highlight = mix_color(message_color, orange, 200);
rgb_color messageColor = ui_color(B_DOCUMENT_TEXT_COLOR);
rgb_color backgroundColor = ui_color(B_DOCUMENT_BACKGROUND_COLOR);
rgb_color highlightColor = mix_color(messageColor, orange, 200);
// TODO figure out a goood threshold here, this seems to work for me,
// but it may not for others
if (abs(blue.Brightness() - bg_color.Brightness()) < 45)
if (abs(blue.Brightness() - backgroundColor.Brightness()) < 45)
blue = { 128, 137, 252, 255 };
if (abs(red.Brightness() - bg_color.Brightness()) < 45)
if (abs(red.Brightness() - backgroundColor.Brightness()) < 45)
red = { 249, 84, 87, 255 };
// some runs to play with
text_run tr_thick_blue = {0, thick, blue};
text_run tr_thick_red = {0, thick, red};
text_run tr_thick_black = {0, thick, message_color};
text_run tr_thick_highlight = {0, thick, highlight};
text_run tr_thin_black = {0, thin, message_color};
text_run tr_thick_black = {0, thick, messageColor};
text_run tr_thick_highlight = {0, thick, highlightColor};
text_run tr_thin_black = {0, thin, messageColor};
// some run array to play with (simple)
text_run_array tra_thick_blue = {1, {tr_thick_blue}};
@ -409,18 +408,18 @@ void TalkView::AddToTalk(string username, string message, user_type type) {
BString messageString = BString(message.c_str());
if (BlabberSettings::Instance()->Tag("show-timestamp"))
_chat->Insert(_chat->TextLength(), time_stamp.c_str(), time_stamp.size(), &tra_thin_black);
timeline->Insert(timeline->TextLength(), time_stamp.c_str(), time_stamp.size(), &tra_thin_black);
if (messageString.StartsWith("/me ")) {
messageString.ReplaceFirst("/me", username.c_str());
if (type == MAIN_RECIPIENT)
_chat->Insert(_chat->TextLength(), messageString, messageString.Length(), &tra_thick_blue);
timeline->Insert(timeline->TextLength(), messageString, messageString.Length(), &tra_thick_blue);
else
_chat->Insert(_chat->TextLength(), messageString, messageString.Length(), &tra_thick_red);
timeline->Insert(timeline->TextLength(), messageString, messageString.Length(), &tra_thick_red);
_chat->Insert(_chat->TextLength(), "\n", 1, &tra_thin_black);
timeline->Insert(timeline->TextLength(), "\n", 1, &tra_thin_black);
if (type == LOCAL)
_chat->ScrollTo(0.0, _chat->Bounds().bottom);
timeline->ScrollTo(0.0, timeline->Bounds().bottom);
return;
}
@ -429,35 +428,29 @@ void TalkView::AddToTalk(string username, string message, user_type type) {
if (!IsGroupChat() || !BlabberSettings::Instance()->Tag("exclude-groupchat-sounds"))
SoundSystem::Instance()->PlayMessageSound();
_chat->Insert(_chat->TextLength(), username.c_str(), username.size(), &tra_thick_blue);
_chat->Insert(_chat->TextLength(), ": ", 2, &tra_thin_black);
timeline->Insert(timeline->TextLength(), username.c_str(), username.size(), &tra_thick_blue);
timeline->Insert(timeline->TextLength(), ": ", 2, &tra_thin_black);
// Highlight messages when they mention the nickname
if (messageString.IFindFirst(_group_username.c_str()) != B_ERROR) {
// NOTE: This will erronously pop up for backlog messages aswell, can be improved once we have MAM
BNotification notification(B_INFORMATION_NOTIFICATION);
notification.SetGroup(GetGroupRoom().c_str());
notification.SetTitle(username.c_str());
notification.SetContent(message.c_str());
notification.Send();
if (highlight) {
GenerateHyperlinkText(message, tr_thick_highlight, &this_array);
} else {
GenerateHyperlinkText(message, tr_thin_black, &this_array);
}
} else if (type == LOCAL) {
_chat->Insert(_chat->TextLength(), username.c_str(), username.size(), &tra_thick_red);
_chat->Insert(_chat->TextLength(), ": ", 2, &tra_thin_black);
timeline->Insert(timeline->TextLength(), username.c_str(), username.size(), &tra_thick_red);
timeline->Insert(timeline->TextLength(), ": ", 2, &tra_thin_black);
GenerateHyperlinkText(message, tr_thin_black, &this_array);
} else { // SYSTEM messages
GenerateHyperlinkText(message, tr_thick_black, &this_array);
}
_chat->Insert(_chat->TextLength(), message.c_str(), message.size(), this_array);
timeline->Insert(timeline->TextLength(), message.c_str(), message.size(), this_array);
free(this_array);
_chat->Insert(_chat->TextLength(), "\n", 1, &tra_thin_black);
timeline->Insert(timeline->TextLength(), "\n", 1, &tra_thin_black);
if (type == LOCAL)
_chat->ScrollTo(0.0, _chat->Bounds().bottom);
timeline->ScrollTo(0.0, timeline->Bounds().bottom);
}
@ -475,11 +468,11 @@ void TalkView::NewMessage(string new_message) {
}
void TalkView::NewMessage(string username, string new_message) {
void TalkView::NewMessage(string username, string new_message, bool highlight) {
if (username == _group_username)
AddToTalk(username.c_str(), new_message, LOCAL);
AddToTalk(username.c_str(), new_message, LOCAL, highlight);
else
AddToTalk(username.c_str(), new_message, MAIN_RECIPIENT);
AddToTalk(username.c_str(), new_message, MAIN_RECIPIENT, highlight);
}
@ -798,13 +791,13 @@ void TalkView::RevealPreviousHistory() {
return;
if (_chat_index == -1)
_chat_buffer = _message->Text();
_chat_buffer = messageInput->Text();
// go back
++_chat_index;
// update text
_message->SetText(_chat_history[_chat_index].c_str());
messageInput->SetText(_chat_history[_chat_index].c_str());
}
@ -818,10 +811,10 @@ void TalkView::RevealNextHistory() {
// last buffer
if (_chat_index == -1) {
_message->SetText(_chat_buffer.c_str());
messageInput->SetText(_chat_buffer.c_str());
} else {
// update text
_message->SetText(_chat_history[_chat_index].c_str());
messageInput->SetText(_chat_history[_chat_index].c_str());
}
}

View File

@ -52,9 +52,9 @@ public:
void MessageReceived(BMessage *msg) override;
std::string OurRepresentation();
void AddToTalk(std::string username, std::string message, user_type type);
void AddToTalk(std::string username, std::string message, user_type type, bool highlight = false);
void NewMessage(std::string new_message);
void NewMessage(std::string username, std::string new_message);
void NewMessage(std::string username, std::string new_message, bool highlight);
bool NewlinesAllowed();
@ -89,10 +89,10 @@ private:
// GUI
StatusView *_status_view;
BScrollView *_chat_scroller;
BScrollView *_message_scroller;
ChatTextView *_chat;
BTextView *_message;
BScrollView *timelineScroller;
BScrollView *messageInputScroller;
ChatTextView *timeline;
BTextView *messageInput;
BListView *_people;