Recieving of formatted messages (by font-face)

Now addons can format messages with new slots accepted by
IM_MESSAGE_RECEIVED: "face_start," "face_length," and "face".

The first two deal with the position of the face-change by character
offset in the string, and the last being the face flag affected.
This commit is contained in:
Jaidyn Ann 2021-08-13 12:39:47 -05:00
parent ad869c8972
commit 29a94bcf65
5 changed files with 145 additions and 8 deletions

View File

@ -75,8 +75,12 @@ enum im_what_code {
printed in chat.
If chat_id is ommitted, the message is sent to the protocol's system
buffer, rather than a specific conversation.
face_start and face_length specify the location of formatted text in
the body, and "face" is the desired font face. Unsupported in bulk,
i.e., IM_LOGS_RECEIVED.
Requires: String "body"
Allows: String "chat_id", String "user_id", String "user_name" */
Allows: String "chat_id", String "user_id", String "user_name",
int32s "face_start", int32s "face_length", uint16s "face" */
IM_MESSAGE_RECEIVED = 22,
/*! Logs received →App

View File

@ -418,6 +418,12 @@ ConversationView::_AppendMessage(BMessage* msg)
}
// … else we're jamming a message into this view no matter what it takes!
if (msg->HasInt32("face_start") == true) {
_AppendFormattedMessage(msg);
return;
}
// For unformatted (normal or bulk) messages
BStringList user_ids, user_names, bodies;
if (msg->FindStrings("body", &bodies) != B_OK)
return;
@ -464,9 +470,118 @@ ConversationView::_AppendMessage(BMessage* msg)
}
void
ConversationView::_AppendFormattedMessage(BMessage* msg)
{
int64 timeInt;
BString user_id;
BString user_name;
BString body;
rgb_color userColor = ui_color(B_PANEL_TEXT_COLOR);
if (msg->FindString("body", &body) != B_OK)
return;
if (msg->FindInt64("when", &timeInt) != B_OK)
timeInt = (int64)time(NULL);
if (msg->FindString("user_id", &user_id) == B_OK)
if (fConversation != NULL) {
User* user = fConversation->UserById(user_id);
if (user != NULL) {
user_name = user->GetName();
userColor = user->fItemColor;
}
else
user_name = user_id;
}
else if (msg->FindString("user_name", &user_name) != B_OK) {
fReceiveView->AppendGeneric(body);
return;
}
fReceiveView->AppendTimestamp(timeInt);
fReceiveView->AppendUserstamp(user_name, userColor);
// And here we append the body…
uint16 face = 0;
UInt16IntMap face_indices;
rgb_color color = ui_color(B_PANEL_TEXT_COLOR);
BFont font;
for (int i = 0; i < body.CountChars(); i++) {
_EnableStartingFaces(msg, i, &face, &face_indices);
if (face == B_REGULAR_FACE) {
font = BFont();
face = 0;
}
else if (face > 0) {
font.SetFace(face);
}
int32 bytes;
const char* curChar = body.CharAt(i, &bytes);
char append[bytes];
for (int i = 0; i < bytes; i++)
append[i] = curChar[i];
append[bytes] = '\0';
fReceiveView->Append(append, color, &font);
_DisableEndingFaces(msg, &face, &face_indices);
}
fReceiveView->Append("\n");
}
void
ConversationView::_EnableStartingFaces(BMessage* msg, int32 index, uint16* face,
UInt16IntMap* indices)
{
int32 face_start;
int32 face_length;
uint16 newFace;
int32 i = 0;
while (msg->FindInt32("face_start", i, &face_start) == B_OK) {
if (face_start == index) {
if (msg->FindInt32("face_length", i, &face_length) != B_OK)
continue;
if (msg->FindUInt16("face", i, &newFace) != B_OK)
continue;
*face |= newFace;
indices->AddItem(newFace, face_length);
}
i++;
}
}
void
ConversationView::_DisableEndingFaces(BMessage* msg, uint16* face,
UInt16IntMap* indices)
{
for (int32 i = 0; i < indices->CountItems(); i++) {
uint16 key = indices->KeyAt(i);
int32 value = indices->ValueAt(i) - 1;
indices->RemoveItemAt(i);
if (value <= 0) {
*face = *face & ~key;
if (indices->CountItems() == 0)
*face = B_REGULAR_FACE;
}
else
indices->AddItem(key, value);
}
}
void
ConversationView::_UserMessage(const char* format, const char* bodyFormat,
BMessage* msg)
BMessage* msg)
{
BString user_id;
BString user_name = msg->FindString("user_name");

View File

@ -26,6 +26,8 @@ class UserListView;
const uint32 kClearText = 'CVct';
typedef KeyMap<uint16, int32> UInt16IntMap;
class ConversationView : public BGroupView, public Observer, public Notifier {
public:
@ -55,6 +57,13 @@ private:
bool _AppendOrEnqueueMessage(BMessage* msg);
void _AppendMessage(BMessage* msg);
void _AppendFormattedMessage(BMessage* msg);
// Helper functions for _AppendFormattedMessage()
void _EnableStartingFaces(BMessage* msg, int32 index,
uint16* face, UInt16IntMap* indices);
void _DisableEndingFaces(BMessage* msg, uint16* face,
UInt16IntMap* indices);
void _UserMessage(const char* format, const char* bodyFormat,
BMessage* msg);

View File

@ -24,9 +24,7 @@ RenderView::AppendMessage(const char* nick, const char* message,
if (BString(message).IsEmpty() == true) return;
AppendTimestamp(time);
Append("<", nameColor);
Append(nick);
Append("> ", nameColor);
AppendUserstamp(nick, nameColor);
Append(message);
if (BString(message).EndsWith("\n") == false) Append("\n");
@ -43,6 +41,15 @@ RenderView::AppendGeneric(const char* message)
}
void
RenderView::AppendUserstamp(const char* nick, rgb_color nameColor)
{
Append("<", nameColor, B_BOLD_FACE);
Append(nick, nameColor, B_BOLD_FACE);
Append("> ", nameColor, B_BOLD_FACE);
}
void
RenderView::AppendTimestamp(time_t time)
{
@ -55,17 +62,18 @@ RenderView::AppendTimestamp(time_t time)
BString stamp("――― %date% ―――\n");
stamp.ReplaceAll("%date%", datestamp);
Append(stamp.String(), ui_color(B_PANEL_TEXT_COLOR), B_ITALIC_FACE);
Append(stamp.String(), ui_color(B_PANEL_TEXT_COLOR),
B_ITALIC_FACE | B_BOLD_FACE);
fLastDay = tm->tm_yday;
fLastYear = tm->tm_year;
}
if (time == 0) {
Append("[xx:xx] ", ui_color(B_LINK_HOVER_COLOR));
Append("[xx:xx] ", ui_color(B_LINK_HOVER_COLOR), B_BOLD_FACE);
return;
}
char timestamp[9] = { '\0' };
strftime(timestamp, 8, "[%H:%M] ", tm);
Append(timestamp, ui_color(B_LINK_HOVER_COLOR));
Append(timestamp, ui_color(B_LINK_HOVER_COLOR), B_BOLD_FACE);
}

View File

@ -15,6 +15,7 @@ public:
void AppendMessage(const char* nick, const char* message,
rgb_color nameColor, time_t time = 0);
void AppendGeneric(const char* message);
void AppendUserstamp(const char* nick, rgb_color nameColor);
void AppendTimestamp(time_t time = 0);
private: