lsnes/generic/messagebuffer.cpp

214 lines
5.6 KiB
C++
Raw Normal View History

#include "messagebuffer.hpp"
messagebuffer::update_handler::~update_handler() throw()
{
}
messagebuffer::messagebuffer(size_t maxmessages, size_t windowsize) throw(std::bad_alloc, std::logic_error)
{
if(windowsize > maxmessages)
throw std::logic_error("Invalid window size");
if(maxmessages == 0)
throw std::logic_error("Invalid max message count");
first_present_message = 0;
next_message_number = 0;
window_start = 0;
max_messages = maxmessages;
window_size = windowsize;
scroll_frozen = false;
updates_frozen = false;
window_start_at_freeze = 0;
window_size_at_freeze = 0;
next_message_number_at_freeze = 0;
}
void messagebuffer::add_message(const std::string& msg) throw(std::bad_alloc, std::runtime_error)
{
messages[next_message_number++] = msg;
//If too many messages, erase one.
if(messages.size() > max_messages)
messages.erase(first_present_message++);
//Force scrolling if message in window got erased.
if(window_start < first_present_message) {
window_start = first_present_message;
send_notifications();
}
//Autoscrolling at the end.
if(!scroll_frozen && window_start + window_size + 1 == next_message_number) {
window_start++;
send_notifications();
}
}
const std::string& messagebuffer::get_message(size_t msgnum) throw(std::bad_alloc, std::logic_error)
{
if(!messages.count(msgnum))
throw std::logic_error("Invalid message number");
return messages[msgnum];
}
size_t messagebuffer::get_msg_first() throw()
{
return first_present_message;
}
size_t messagebuffer::get_msg_count() throw()
{
return next_message_number - first_present_message;
}
size_t messagebuffer::get_visible_first() throw()
{
return window_start;
}
size_t messagebuffer::get_visible_count() throw()
{
if(window_start + window_size > next_message_number)
return next_message_number - window_start;
else
return window_size;
}
bool messagebuffer::is_more_messages() throw()
{
return (window_start + window_size < next_message_number);
}
void messagebuffer::freeze_scrolling() throw()
{
scroll_frozen = true;
}
void messagebuffer::unfreeze_scrolling() throw()
{
scroll_frozen = false;
}
void messagebuffer::freeze_updates() throw()
{
updates_frozen = true;
window_size_at_freeze = window_size;
window_start_at_freeze = window_start;
next_message_number_at_freeze = next_message_number;
}
bool messagebuffer::unfreeze_updates() throw()
{
updates_frozen = false;
if(window_start_at_freeze < first_present_message)
return true;
uint64_t messages_visible_at_freeze;
uint64_t messages_visible_now;
if(window_start_at_freeze + window_size_at_freeze >= next_message_number_at_freeze)
messages_visible_at_freeze = next_message_number_at_freeze - window_start_at_freeze;
else
messages_visible_at_freeze = window_size_at_freeze;
messages_visible_now = get_visible_count();
if(messages_visible_now != messages_visible_at_freeze)
return true;
if(window_start_at_freeze != window_start)
return true;
return false;
}
void messagebuffer::scroll_beginning() throw(std::bad_alloc, std::runtime_error)
{
if(window_start == first_present_message)
return;
window_start = first_present_message;
send_notifications();
}
void messagebuffer::scroll_up_page() throw(std::bad_alloc, std::runtime_error)
{
if(window_start == first_present_message)
return;
if(window_start < first_present_message + window_size)
window_start = first_present_message;
else
window_start -= window_size;
send_notifications();
}
void messagebuffer::scroll_up_line() throw(std::bad_alloc, std::runtime_error)
{
if(window_start == first_present_message)
return;
window_start--;
send_notifications();
}
void messagebuffer::scroll_down_line() throw(std::bad_alloc, std::runtime_error)
{
if(window_start + window_size >= next_message_number)
return;
window_start++;
send_notifications();
}
void messagebuffer::scroll_down_page() throw(std::bad_alloc, std::runtime_error)
{
if(window_start + window_size >= next_message_number)
return;
window_start += window_size;
if(window_start + window_size >= next_message_number)
window_start = next_message_number - window_size;
send_notifications();
}
void messagebuffer::scroll_end() throw(std::bad_alloc, std::runtime_error)
{
if(first_present_message + window_size > next_message_number)
return;
window_start = next_message_number - window_size;
send_notifications();
}
void messagebuffer::register_handler(messagebuffer::update_handler& handler) throw(std::bad_alloc)
{
handlers.insert(&handler);
}
void messagebuffer::unregister_handler(messagebuffer::update_handler& handler) throw()
{
handlers.erase(&handler);
}
void messagebuffer::set_max_window_size(size_t windowsize) throw(std::bad_alloc, std::logic_error)
{
if(windowsize > max_messages)
throw std::logic_error("Invalid window size");
if(window_size > windowsize) {
//Shrink window.
size_t shrinkage = window_size - windowsize;
bool autoscrolling = !scroll_frozen && (window_start + window_size >= next_message_number);
if(autoscrolling && window_start + windowsize < next_message_number)
window_start = next_message_number - windowsize;
window_size = windowsize;
send_notifications();
} else if(window_size < windowsize) {
//Enlarge window.
size_t enlargement = windowsize - window_size;
if(first_present_message + windowsize >= next_message_number)
window_start = first_present_message;
else if(window_start + windowsize >= next_message_number)
window_start = next_message_number - windowsize;
window_size = windowsize;
send_notifications();
}
}
size_t messagebuffer::get_max_window_size() throw()
{
return window_size;
}
void messagebuffer::send_notifications()
{
if(updates_frozen)
return;
for(auto i : handlers)
i->messagebuffer_update();
}