mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement chat mode icons in chat window
This commit is contained in:
parent
22315a6e1d
commit
35ed03aa18
BIN
assets/voxygen/element/icons/chat/broadcast_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/broadcast_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/faction.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/faction.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/faction_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/faction_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/group.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/group.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/group_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/group_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/kill_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/kill_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/private_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/private_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/region.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/region.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/region_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/region_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/say.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/say.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/say_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/say_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/tell.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/tell.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/tell_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/tell_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/world.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/world.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/chat/world_small.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/chat/world_small.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -94,25 +94,28 @@ impl ChatMsg {
|
||||
}
|
||||
|
||||
pub fn to_bubble(&self) -> Option<(SpeechBubble, Uid)> {
|
||||
let tuple = match &self.chat_type {
|
||||
ChatType::Broadcast => None,
|
||||
ChatType::Private => None,
|
||||
ChatType::Kill => None,
|
||||
ChatType::Tell(u, _) => Some((SpeechBubbleIcon::Tell, u, None)),
|
||||
ChatType::Say(u) => Some((SpeechBubbleIcon::Say, u, None)),
|
||||
ChatType::Group(u, _s) => Some((SpeechBubbleIcon::Group, u, None)),
|
||||
ChatType::Faction(u, _s) => Some((SpeechBubbleIcon::Faction, u, None)),
|
||||
ChatType::Region(u) => Some((SpeechBubbleIcon::Region, u, None)),
|
||||
ChatType::World(u) => Some((SpeechBubbleIcon::World, u, None)),
|
||||
ChatType::Npc(u, r) => Some((SpeechBubbleIcon::None, u, Some(r))),
|
||||
};
|
||||
tuple.map(|(icon, from, npc_rand)| {
|
||||
if let Some(r) = npc_rand {
|
||||
(SpeechBubble::npc_new(self.message.clone(), *r, icon), *from)
|
||||
} else {
|
||||
(SpeechBubble::player_new(self.message.clone(), icon), *from)
|
||||
}
|
||||
})
|
||||
let icon = self.icon();
|
||||
if let ChatType::Npc(from, r) = self.chat_type {
|
||||
Some((SpeechBubble::npc_new(self.message.clone(), r, icon), from))
|
||||
} else {
|
||||
self.uid()
|
||||
.map(|from| (SpeechBubble::player_new(self.message.clone(), icon), from))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn icon(&self) -> SpeechBubbleIcon {
|
||||
match &self.chat_type {
|
||||
ChatType::Broadcast => SpeechBubbleIcon::Broadcast,
|
||||
ChatType::Private => SpeechBubbleIcon::Private,
|
||||
ChatType::Kill => SpeechBubbleIcon::Kill,
|
||||
ChatType::Tell(_u, _) => SpeechBubbleIcon::Tell,
|
||||
ChatType::Say(_u) => SpeechBubbleIcon::Say,
|
||||
ChatType::Group(_u, _s) => SpeechBubbleIcon::Group,
|
||||
ChatType::Faction(_u, _s) => SpeechBubbleIcon::Faction,
|
||||
ChatType::Region(_u) => SpeechBubbleIcon::Region,
|
||||
ChatType::World(_u) => SpeechBubbleIcon::World,
|
||||
ChatType::Npc(_u, _r) => SpeechBubbleIcon::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uid(&self) -> Option<Uid> {
|
||||
@ -174,6 +177,10 @@ pub enum SpeechBubbleIcon {
|
||||
Group,
|
||||
Faction,
|
||||
World,
|
||||
// Server chat types
|
||||
Broadcast,
|
||||
Private,
|
||||
Kill,
|
||||
// For NPCs
|
||||
Quest, // TODO not implemented
|
||||
Trade, // TODO not implemented
|
||||
|
@ -652,16 +652,18 @@ fn handle_help(
|
||||
if let Some(cmd) = scan_fmt_some!(&args, &action.arg_fmt(), ChatCommand) {
|
||||
server.notify_client(client, ServerMsg::private(String::from(cmd.help_string())));
|
||||
} else {
|
||||
let mut message = String::new();
|
||||
for cmd in CHAT_COMMANDS.iter() {
|
||||
if !cmd.needs_admin() || server.entity_is_admin(client) {
|
||||
server.notify_client(client, ServerMsg::private(String::from(cmd.help_string())));
|
||||
message += &cmd.help_string();
|
||||
message += "\n";
|
||||
}
|
||||
}
|
||||
let shortcuts = CHAT_SHORTCUTS.iter().fold(
|
||||
"Aditionally, you can use the following shortcuts:".to_string(),
|
||||
|s, (k, v)| format!("{}\n/{} => /{}", s, k, v.keyword()),
|
||||
);
|
||||
server.notify_client(client, ServerMsg::private(shortcuts.to_string()));
|
||||
message += "Additionally, you can use the following shortcuts:";
|
||||
for (k, v) in CHAT_SHORTCUTS.iter() {
|
||||
message += &format!(" /{} => /{}", k, v.keyword());
|
||||
}
|
||||
server.notify_client(client, ServerMsg::private(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@ use conrod_core::{
|
||||
self,
|
||||
cursor::{self, Index},
|
||||
},
|
||||
widget::{self, Button, Id, List, Rectangle, Text, TextEdit},
|
||||
widget_ids, Colorable, Positionable, Sizeable, Ui, UiCell, Widget, WidgetCommon,
|
||||
widget::{self, Button, Id, Image, List, Rectangle, Text, TextEdit},
|
||||
widget_ids, Color, Colorable, Positionable, Sizeable, Ui, UiCell, Widget, WidgetCommon,
|
||||
};
|
||||
use specs::world::WorldExt;
|
||||
use std::collections::VecDeque;
|
||||
@ -28,12 +28,15 @@ widget_ids! {
|
||||
chat_input,
|
||||
chat_input_bg,
|
||||
chat_arrow,
|
||||
completion_box,
|
||||
chat_icons[],
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_MESSAGES: usize = 100;
|
||||
|
||||
const CHAT_BOX_WIDTH: f64 = 470.0;
|
||||
const CHAT_BOX_HEIGHT: f64 = 174.0;
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Chat<'a> {
|
||||
new_messages: &'a mut VecDeque<ChatMsg>,
|
||||
@ -291,10 +294,10 @@ impl<'a> Widget for Chat<'a> {
|
||||
Dimension::Absolute(y) => y + 6.0,
|
||||
_ => 0.0,
|
||||
};
|
||||
Rectangle::fill([470.0, y])
|
||||
Rectangle::fill([CHAT_BOX_WIDTH, y])
|
||||
.rgba(0.0, 0.0, 0.0, transp + 0.1)
|
||||
.bottom_left_with_margins_on(ui.window, 10.0, 10.0)
|
||||
.w(470.0)
|
||||
.w(CHAT_BOX_WIDTH)
|
||||
.set(state.ids.chat_input_bg, ui);
|
||||
|
||||
if let Some(str) = text_edit
|
||||
@ -309,27 +312,8 @@ impl<'a> Widget for Chat<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let alias_of_uid = |uid| {
|
||||
self.client
|
||||
.player_list
|
||||
.get(uid)
|
||||
.map_or("<?>".to_string(), |player_info| {
|
||||
if player_info.is_admin {
|
||||
format!("ADMIN - {}", player_info.player_alias)
|
||||
} else {
|
||||
player_info.player_alias.to_string()
|
||||
}
|
||||
})
|
||||
};
|
||||
let message_format = |uid, message, group| {
|
||||
if let Some(group) = group {
|
||||
format!("{{{}}} [{}]: {}", group, alias_of_uid(uid), message)
|
||||
} else {
|
||||
format!("[{}]: {}", alias_of_uid(uid), message)
|
||||
}
|
||||
};
|
||||
// Message box
|
||||
Rectangle::fill([470.0, 174.0])
|
||||
Rectangle::fill([CHAT_BOX_WIDTH, CHAT_BOX_HEIGHT])
|
||||
.rgba(0.0, 0.0, 0.0, transp)
|
||||
.and(|r| {
|
||||
if input_focused {
|
||||
@ -338,49 +322,30 @@ impl<'a> Widget for Chat<'a> {
|
||||
r.bottom_left_with_margins_on(ui.window, 10.0, 10.0)
|
||||
}
|
||||
})
|
||||
.crop_kids()
|
||||
.set(state.ids.message_box_bg, ui);
|
||||
let (mut items, _) = List::flow_down(state.messages.len() + 1)
|
||||
.top_left_of(state.ids.message_box_bg)
|
||||
.w_h(470.0, 174.0)
|
||||
.top_left_with_margins_on(state.ids.message_box_bg, 0.0, 16.0)
|
||||
.w_h(CHAT_BOX_WIDTH, CHAT_BOX_HEIGHT)
|
||||
.scroll_kids_vertically()
|
||||
.set(state.ids.message_box, ui);
|
||||
if state.ids.chat_icons.len() < state.messages.len() {
|
||||
state.update(|s| {
|
||||
s.ids
|
||||
.chat_icons
|
||||
.resize(s.messages.len(), &mut ui.widget_id_generator())
|
||||
});
|
||||
}
|
||||
|
||||
while let Some(item) = items.next(ui) {
|
||||
// This would be easier if conrod used the v-metrics from rusttype.
|
||||
if item.i < state.messages.len() {
|
||||
let ChatMsg { chat_type, message } = &state.messages[item.i];
|
||||
let (color, msg) = match chat_type {
|
||||
ChatType::Private => (PRIVATE_COLOR, message.to_string()),
|
||||
ChatType::Broadcast => (BROADCAST_COLOR, message.to_string()),
|
||||
ChatType::Kill => (KILL_COLOR, message.to_string()),
|
||||
ChatType::Tell(from, to) => {
|
||||
let from_alias = alias_of_uid(&from);
|
||||
let to_alias = alias_of_uid(&to);
|
||||
if Some(from)
|
||||
== self
|
||||
.client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage()
|
||||
.get(self.client.entity())
|
||||
{
|
||||
(TELL_COLOR, format!("To [{}]: {}", to_alias, message))
|
||||
} else {
|
||||
(TELL_COLOR, format!("From [{}]: {}", from_alias, message))
|
||||
}
|
||||
},
|
||||
ChatType::Say(uid) => (SAY_COLOR, message_format(uid, message, None)),
|
||||
ChatType::Group(uid, s) => (GROUP_COLOR, message_format(uid, message, Some(s))),
|
||||
ChatType::Faction(uid, s) => {
|
||||
(FACTION_COLOR, message_format(uid, message, Some(s)))
|
||||
},
|
||||
ChatType::Region(uid) => (REGION_COLOR, message_format(uid, message, None)),
|
||||
ChatType::World(uid) => (WORLD_COLOR, message_format(uid, message, None)),
|
||||
ChatType::Npc(_uid, _r) => continue, // Should be filtered by hud/mod.rs
|
||||
};
|
||||
let (color, msg, icon) =
|
||||
render_chat_line(&state.messages[item.i], &self.imgs, &self.client);
|
||||
let text = Text::new(&msg)
|
||||
.font_size(self.fonts.opensans.scale(15))
|
||||
.font_id(self.fonts.opensans.conrod_id)
|
||||
.w(470.0)
|
||||
.w(CHAT_BOX_WIDTH - 16.0)
|
||||
.color(color)
|
||||
.line_spacing(2.0);
|
||||
// Add space between messages.
|
||||
@ -390,13 +355,19 @@ impl<'a> Widget for Chat<'a> {
|
||||
};
|
||||
let widget = text.h(y);
|
||||
item.set(widget, ui);
|
||||
let icon_id = state.ids.chat_icons[item.i];
|
||||
Image::new(icon)
|
||||
.w_h(16.0, 16.0)
|
||||
.top_left_with_margins_on(item.widget_id, 2.0, -16.0)
|
||||
.parent(state.ids.message_box_bg)
|
||||
.set(icon_id, ui);
|
||||
} else {
|
||||
// Spacer at bottom of the last message so that it is not cut off.
|
||||
// Needs to be larger than the space above.
|
||||
let widget = Text::new("")
|
||||
.font_size(self.fonts.opensans.scale(6))
|
||||
.font_id(self.fonts.opensans.conrod_id)
|
||||
.w(470.0);
|
||||
.w(CHAT_BOX_WIDTH);
|
||||
item.set(widget, ui);
|
||||
};
|
||||
}
|
||||
@ -409,6 +380,7 @@ impl<'a> Widget for Chat<'a> {
|
||||
.hover_image(self.imgs.chat_arrow_mo)
|
||||
.press_image(self.imgs.chat_arrow_press)
|
||||
.bottom_right_with_margins_on(state.ids.message_box_bg, 0.0, -22.0)
|
||||
.parent(id)
|
||||
.set(state.ids.chat_arrow, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
@ -511,3 +483,87 @@ fn cursor_offset_to_index(
|
||||
|
||||
cursor::index_before_char(infos, offset)
|
||||
}
|
||||
|
||||
fn render_chat_line(
|
||||
ChatMsg { chat_type, message }: &ChatMsg,
|
||||
imgs: &Imgs,
|
||||
client: &Client,
|
||||
) -> (Color, String, conrod_core::image::Id) {
|
||||
let alias_of_uid = |uid| {
|
||||
client
|
||||
.player_list
|
||||
.get(uid)
|
||||
.map_or("<?>".to_string(), |player_info| {
|
||||
if player_info.is_admin {
|
||||
format!("ADMIN - {}", player_info.player_alias)
|
||||
} else {
|
||||
player_info.player_alias.to_string()
|
||||
}
|
||||
})
|
||||
};
|
||||
let message_format = |uid, message, group| {
|
||||
if let Some(group) = group {
|
||||
format!("{{{}}} [{}]: {}", group, alias_of_uid(uid), message)
|
||||
} else {
|
||||
format!("[{}]: {}", alias_of_uid(uid), message)
|
||||
}
|
||||
};
|
||||
match chat_type {
|
||||
ChatType::Private => (PRIVATE_COLOR, message.to_string(), imgs.chat_private_small),
|
||||
ChatType::Broadcast => (
|
||||
BROADCAST_COLOR,
|
||||
message.to_string(),
|
||||
imgs.chat_broadcast_small,
|
||||
),
|
||||
ChatType::Kill => (KILL_COLOR, message.to_string(), imgs.chat_kill_small),
|
||||
ChatType::Tell(from, to) => {
|
||||
let from_alias = alias_of_uid(&from);
|
||||
let to_alias = alias_of_uid(&to);
|
||||
if Some(from)
|
||||
== client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<common::sync::Uid>()
|
||||
.get(client.entity())
|
||||
{
|
||||
(
|
||||
TELL_COLOR,
|
||||
format!("To [{}]: {}", to_alias, message),
|
||||
imgs.chat_tell_small,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
TELL_COLOR,
|
||||
format!("From [{}]: {}", from_alias, message),
|
||||
imgs.chat_tell_small,
|
||||
)
|
||||
}
|
||||
},
|
||||
ChatType::Say(uid) => (
|
||||
SAY_COLOR,
|
||||
message_format(uid, message, None),
|
||||
imgs.chat_say_small,
|
||||
),
|
||||
ChatType::Group(uid, s) => (
|
||||
GROUP_COLOR,
|
||||
message_format(uid, message, Some(s)),
|
||||
imgs.chat_group_small,
|
||||
),
|
||||
ChatType::Faction(uid, s) => (
|
||||
FACTION_COLOR,
|
||||
message_format(uid, message, Some(s)),
|
||||
imgs.chat_faction_small,
|
||||
),
|
||||
ChatType::Region(uid) => (
|
||||
REGION_COLOR,
|
||||
message_format(uid, message, None),
|
||||
imgs.chat_region_small,
|
||||
),
|
||||
ChatType::World(uid) => (
|
||||
WORLD_COLOR,
|
||||
message_format(uid, message, None),
|
||||
imgs.chat_world_small,
|
||||
),
|
||||
ChatType::Npc(_uid, _r) => panic!("NPCs can't talk"), // Should be filtered by hud/mod.rs
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,6 @@ image_ids! {
|
||||
chat_arrow_press: "voxygen.element.buttons.arrow_down_press",
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
<VoxelPixArtGraphic>
|
||||
|
||||
@ -298,6 +297,17 @@ image_ids! {
|
||||
dark_bubble_bottom_right: "voxygen.element.frames.bubble_dark.bottom_right",
|
||||
dark_bubble_tail: "voxygen.element.frames.bubble_dark.tail",
|
||||
|
||||
// Chat icons
|
||||
chat_broadcast_small: "voxygen.element.icons.chat.broadcast_small",
|
||||
chat_faction_small: "voxygen.element.icons.chat.faction_small",
|
||||
chat_group_small: "voxygen.element.icons.chat.group_small",
|
||||
chat_kill_small: "voxygen.element.icons.chat.kill_small",
|
||||
chat_private_small: "voxygen.element.icons.chat.private_small",
|
||||
chat_region_small: "voxygen.element.icons.chat.region_small",
|
||||
chat_say_small: "voxygen.element.icons.chat.say_small",
|
||||
chat_tell_small: "voxygen.element.icons.chat.tell_small",
|
||||
chat_world_small: "voxygen.element.icons.chat.world_small",
|
||||
|
||||
<BlankGraphic>
|
||||
nothing: (),
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ widget_ids! {
|
||||
speech_bubble_bottom,
|
||||
speech_bubble_bottom_right,
|
||||
speech_bubble_tail,
|
||||
speech_bubble_icon,
|
||||
|
||||
// Name
|
||||
name_bg,
|
||||
|
Loading…
Reference in New Issue
Block a user