Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add display chat manager, notifications support outside game_display
The functionality of tracking observers and displaying chat messages is moved to a manager class, which the gui owns. The functionality of displaying notifications is similarly moved out of the game_display and to a private namespace. (Static singleton pattern seems okay here since there really won't need to be more than one of these for a single application, it seems.)
- Loading branch information
Showing
25 changed files
with
612 additions
and
447 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
/* | ||
Copyright (C) 2014 by Chris Beck <render787@gmail.com> | ||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/ | ||
This program is free software; you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation; either version 2 of the License, or | ||
(at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY. | ||
See the COPYING file for more details. | ||
*/ | ||
|
||
#include "display_chat_manager.hpp" | ||
#include "global.hpp" | ||
|
||
#include "display.hpp" | ||
#include "font.hpp" | ||
#include "game_board.hpp" // <-- only needed for is_observer() | ||
#include "game_preferences.hpp" | ||
#include "log.hpp" | ||
#include "marked-up_text.hpp" | ||
#include "notifications.hpp" | ||
#include "sound.hpp" | ||
#include "serialization/string_utils.hpp" | ||
|
||
#include <boost/cstdint.hpp> | ||
#include <boost/foreach.hpp> | ||
#include "SDL_timer.h" | ||
#include "SDL_video.h" | ||
|
||
static lg::log_domain log_engine("engine"); | ||
#define ERR_NG LOG_STREAM(err, log_engine) | ||
|
||
using boost::uint32_t; | ||
|
||
namespace { | ||
const int chat_message_border = 5; | ||
const int chat_message_x = 10; | ||
const SDL_Color chat_message_color = {255,255,255,255}; | ||
const SDL_Color chat_message_bg = {0,0,0,140}; | ||
} | ||
|
||
display_chat_manager::chat_message::chat_message(int speaker, int h) | ||
: speaker_handle(speaker), handle(h), created_at(SDL_GetTicks()) | ||
{} | ||
|
||
|
||
void display_chat_manager::add_chat_message(const time_t& time, const std::string& speaker, | ||
int side, const std::string& message, events::chat_handler::MESSAGE_TYPE type, | ||
bool bell) | ||
{ | ||
const bool whisper = speaker.find("whisper: ") == 0; | ||
std::string sender = speaker; | ||
if (whisper) { | ||
sender.assign(speaker, 9, speaker.size()); | ||
} | ||
if (!preferences::parse_should_show_lobby_join(sender, message)) return; | ||
if (preferences::is_ignored(sender)) return; | ||
|
||
preferences::parse_admin_authentication(sender, message); | ||
|
||
bool is_observer = false; | ||
{ //TODO: Clean this block up somehow | ||
|
||
const game_board * board = dynamic_cast<const game_board*>(&my_disp_.get_disp_context()); | ||
|
||
if (board) { | ||
is_observer = board->is_observer(); | ||
} | ||
} | ||
|
||
if (bell) { | ||
if ((type == events::chat_handler::MESSAGE_PRIVATE && (!is_observer || whisper)) | ||
|| utils::word_match(message, preferences::login())) { | ||
sound::play_UI_sound(game_config::sounds::receive_message_highlight); | ||
} else if (preferences::is_friend(sender)) { | ||
sound::play_UI_sound(game_config::sounds::receive_message_friend); | ||
} else if (sender == "server") { | ||
sound::play_UI_sound(game_config::sounds::receive_message_server); | ||
} else { | ||
sound::play_UI_sound(game_config::sounds::receive_message); | ||
} | ||
} | ||
|
||
bool action = false; | ||
|
||
std::string msg; | ||
|
||
if (message.find("/me ") == 0) { | ||
msg.assign(message, 4, message.size()); | ||
action = true; | ||
} else { | ||
msg += message; | ||
} | ||
|
||
try { | ||
// We've had a joker who send an invalid utf-8 message to crash clients | ||
// so now catch the exception and ignore the message. | ||
msg = font::word_wrap_text(msg,font::SIZE_SMALL,my_disp_.map_outside_area().w*3/4); | ||
} catch (utf8::invalid_utf8_exception&) { | ||
ERR_NG << "Invalid utf-8 found, chat message is ignored." << std::endl; | ||
return; | ||
} | ||
|
||
int ypos = chat_message_x; | ||
for(std::vector<chat_message>::const_iterator m = chat_messages_.begin(); m != chat_messages_.end(); ++m) { | ||
ypos += std::max(font::get_floating_label_rect(m->handle).h, | ||
font::get_floating_label_rect(m->speaker_handle).h); | ||
} | ||
SDL_Color speaker_color = {255,255,255,255}; | ||
if(side >= 1) { | ||
speaker_color = int_to_color(team::get_side_color_range(side).mid()); | ||
} | ||
|
||
SDL_Color message_color = chat_message_color; | ||
std::stringstream str; | ||
std::stringstream message_str; | ||
|
||
if(type == events::chat_handler::MESSAGE_PUBLIC) { | ||
if(action) { | ||
str << "<" << speaker << " " << msg << ">"; | ||
message_color = speaker_color; | ||
message_str << " "; | ||
} else { | ||
if (!speaker.empty()) | ||
str << "<" << speaker << ">"; | ||
message_str << msg; | ||
} | ||
} else { | ||
if(action) { | ||
str << "*" << speaker << " " << msg << "*"; | ||
message_color = speaker_color; | ||
message_str << " "; | ||
} else { | ||
if (!speaker.empty()) | ||
str << "*" << speaker << "*"; | ||
message_str << msg; | ||
} | ||
} | ||
|
||
// Prepend message with timestamp. | ||
std::stringstream message_complete; | ||
message_complete << preferences::get_chat_timestamp(time) << str.str(); | ||
|
||
const SDL_Rect rect = my_disp_.map_outside_area(); | ||
|
||
font::floating_label spk_flabel(message_complete.str()); | ||
spk_flabel.set_font_size(font::SIZE_SMALL); | ||
spk_flabel.set_color(speaker_color); | ||
spk_flabel.set_position(rect.x + chat_message_x, rect.y + ypos); | ||
spk_flabel.set_clip_rect(rect); | ||
spk_flabel.set_alignment(font::LEFT_ALIGN); | ||
spk_flabel.set_bg_color(chat_message_bg); | ||
spk_flabel.set_border_size(chat_message_border); | ||
spk_flabel.use_markup(false); | ||
|
||
int speaker_handle = font::add_floating_label(spk_flabel); | ||
|
||
font::floating_label msg_flabel(message_str.str()); | ||
msg_flabel.set_font_size(font::SIZE_SMALL); | ||
msg_flabel.set_color(message_color); | ||
msg_flabel.set_position(rect.x + chat_message_x + font::get_floating_label_rect(speaker_handle).w, | ||
rect.y + ypos); | ||
msg_flabel.set_clip_rect(rect); | ||
msg_flabel.set_alignment(font::LEFT_ALIGN); | ||
msg_flabel.set_bg_color(chat_message_bg); | ||
msg_flabel.set_border_size(chat_message_border); | ||
msg_flabel.use_markup(false); | ||
|
||
int message_handle = font::add_floating_label(msg_flabel); | ||
|
||
// Send system notification if appropriate. | ||
notifications::send_notification(speaker, message); | ||
|
||
chat_messages_.push_back(chat_message(speaker_handle,message_handle)); | ||
|
||
prune_chat_messages(); | ||
} | ||
|
||
void display_chat_manager::prune_chat_messages(bool remove_all) | ||
{ | ||
const unsigned message_aging = preferences::chat_message_aging(); | ||
const unsigned message_ttl = remove_all ? 0 : message_aging * 60 * 1000; | ||
const unsigned max_chat_messages = preferences::chat_lines(); | ||
int movement = 0; | ||
|
||
if(message_aging != 0 || remove_all || chat_messages_.size() > max_chat_messages) { | ||
while (!chat_messages_.empty() && | ||
(chat_messages_.front().created_at + message_ttl < SDL_GetTicks() || | ||
chat_messages_.size() > max_chat_messages)) | ||
{ | ||
const chat_message &old = chat_messages_.front(); | ||
movement += font::get_floating_label_rect(old.handle).h; | ||
font::remove_floating_label(old.speaker_handle); | ||
font::remove_floating_label(old.handle); | ||
chat_messages_.erase(chat_messages_.begin()); | ||
} | ||
} | ||
|
||
BOOST_FOREACH(const chat_message &cm, chat_messages_) { | ||
font::move_floating_label(cm.speaker_handle, 0, - movement); | ||
font::move_floating_label(cm.handle, 0, - movement); | ||
} | ||
} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
Copyright (C) 2014 by Chris Beck <render787@gmail.com> | ||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/ | ||
This program is free software; you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation; either version 2 of the License, or | ||
(at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY. | ||
See the COPYING file for more details. | ||
*/ | ||
|
||
#ifndef INCL_DISPLAY_CHAT_MGR_HPP_ | ||
#define INCL_DISPLAY_CHAT_MGR_HPP_ | ||
|
||
#include "chat_events.hpp" | ||
|
||
#include <boost/cstdint.hpp> | ||
#include <ctime> | ||
#include <set> | ||
#include <string> | ||
#include <vector> | ||
|
||
class display; | ||
|
||
class display_chat_manager { | ||
public: | ||
display_chat_manager(display & disp) : my_disp_(disp) {} | ||
|
||
void add_observer(const std::string& name) { observers_.insert(name); } | ||
void remove_observer(const std::string& name) { observers_.erase(name); } | ||
const std::set<std::string>& observers() const { return observers_; } | ||
|
||
void add_chat_message(const time_t& time, const std::string& speaker, | ||
int side, const std::string& msg, events::chat_handler::MESSAGE_TYPE type, bool bell); | ||
void clear_chat_messages() { prune_chat_messages(true); } | ||
|
||
friend class game_display; //needed because it calls prune_chat_message | ||
private: | ||
std::set<std::string> observers_; | ||
|
||
struct chat_message | ||
{ | ||
chat_message(int speaker, int h); | ||
|
||
int speaker_handle; | ||
int handle; | ||
boost::uint32_t created_at; | ||
}; | ||
|
||
void prune_chat_messages(bool remove_all=false); | ||
|
||
std::vector<chat_message> chat_messages_; | ||
|
||
display & my_disp_; | ||
}; | ||
|
||
#endif |
Oops, something went wrong.