Remember video settings
[lsnes.git] / src / library / messagebuffer.cpp
blob543e297c2e7a9a9279fc871105215843e5bc510e
1 #include "messagebuffer.hpp"
3 messagebuffer::update_handler::~update_handler() throw()
7 messagebuffer::messagebuffer(size_t maxmessages, size_t windowsize) throw(std::bad_alloc, std::logic_error)
9 if(windowsize > maxmessages)
10 throw std::logic_error("Invalid window size");
11 if(maxmessages == 0)
12 throw std::logic_error("Invalid max message count");
13 first_present_message = 0;
14 next_message_number = 0;
15 window_start = 0;
16 max_messages = maxmessages;
17 window_size = windowsize;
18 scroll_frozen = false;
19 updates_frozen = false;
20 window_start_at_freeze = 0;
21 window_size_at_freeze = 0;
22 next_message_number_at_freeze = 0;
25 void messagebuffer::add_message(const std::string& msg) throw(std::bad_alloc, std::runtime_error)
27 messages_buf[next_message_number++] = msg;
28 //If too many messages, erase one.
29 if(messages_buf.size() > max_messages)
30 messages_buf.erase(first_present_message++);
31 //Force scrolling if message in window got erased.
32 if(window_start < first_present_message) {
33 window_start = first_present_message;
34 send_notifications();
36 //Autoscrolling at the end.
37 if(!scroll_frozen && window_start + window_size + 1 == next_message_number) {
38 window_start++;
39 send_notifications();
41 send_notifications();
44 const std::string& messagebuffer::get_message(size_t msgnum) throw(std::bad_alloc, std::logic_error)
46 if(!messages_buf.count(msgnum))
47 throw std::logic_error("Invalid message number");
48 return messages_buf[msgnum];
51 size_t messagebuffer::get_msg_first() throw()
53 return first_present_message;
56 size_t messagebuffer::get_msg_count() throw()
58 return next_message_number - first_present_message;
61 size_t messagebuffer::get_visible_first() throw()
63 return window_start;
66 size_t messagebuffer::get_visible_count() throw()
68 if(window_start + window_size > next_message_number)
69 return next_message_number - window_start;
70 else
71 return window_size;
74 bool messagebuffer::is_more_messages() throw()
76 return (window_start + window_size < next_message_number);
79 void messagebuffer::freeze_scrolling() throw()
81 scroll_frozen = true;
84 void messagebuffer::unfreeze_scrolling() throw()
86 scroll_frozen = false;
89 void messagebuffer::freeze_updates() throw()
91 updates_frozen = true;
92 window_size_at_freeze = window_size;
93 window_start_at_freeze = window_start;
94 next_message_number_at_freeze = next_message_number;
97 bool messagebuffer::unfreeze_updates() throw()
99 updates_frozen = false;
100 if(window_start_at_freeze < first_present_message)
101 return true;
102 uint64_t messages_visible_at_freeze;
103 uint64_t messages_visible_now;
104 if(window_start_at_freeze + window_size_at_freeze >= next_message_number_at_freeze)
105 messages_visible_at_freeze = next_message_number_at_freeze - window_start_at_freeze;
106 else
107 messages_visible_at_freeze = window_size_at_freeze;
108 messages_visible_now = get_visible_count();
109 if(messages_visible_now != messages_visible_at_freeze)
110 return true;
111 if(window_start_at_freeze != window_start)
112 return true;
113 return false;
116 void messagebuffer::scroll_beginning() throw(std::bad_alloc, std::runtime_error)
118 if(window_start == first_present_message)
119 return;
120 window_start = first_present_message;
121 send_notifications();
124 void messagebuffer::scroll_up_page() throw(std::bad_alloc, std::runtime_error)
126 if(window_start == first_present_message)
127 return;
128 if(window_start < first_present_message + window_size)
129 window_start = first_present_message;
130 else
131 window_start -= window_size;
132 send_notifications();
135 void messagebuffer::scroll_up_line() throw(std::bad_alloc, std::runtime_error)
137 if(window_start == first_present_message)
138 return;
139 window_start--;
140 send_notifications();
143 void messagebuffer::scroll_down_line() throw(std::bad_alloc, std::runtime_error)
145 if(window_start + window_size >= next_message_number)
146 return;
147 window_start++;
148 send_notifications();
151 void messagebuffer::scroll_down_page() throw(std::bad_alloc, std::runtime_error)
153 if(window_start + window_size >= next_message_number)
154 return;
155 window_start += window_size;
156 if(window_start + window_size >= next_message_number)
157 window_start = next_message_number - window_size;
158 send_notifications();
161 void messagebuffer::scroll_end() throw(std::bad_alloc, std::runtime_error)
163 if(first_present_message + window_size > next_message_number)
164 return;
165 window_start = next_message_number - window_size;
166 send_notifications();
169 void messagebuffer::register_handler(messagebuffer::update_handler& handler) throw(std::bad_alloc)
171 handlers.insert(&handler);
174 void messagebuffer::unregister_handler(messagebuffer::update_handler& handler) throw()
176 handlers.erase(&handler);
179 void messagebuffer::set_max_window_size(size_t windowsize) throw(std::bad_alloc, std::logic_error)
181 if(windowsize > max_messages)
182 throw std::logic_error("Invalid window size");
183 if(window_size > windowsize) {
184 //Shrink window.
185 bool autoscrolling = !scroll_frozen && (window_start + window_size >= next_message_number);
186 if(autoscrolling && window_start + windowsize < next_message_number)
187 window_start = next_message_number - windowsize;
188 window_size = windowsize;
189 send_notifications();
190 } else if(window_size < windowsize) {
191 //Enlarge window.
192 if(first_present_message + windowsize >= next_message_number)
193 window_start = first_present_message;
194 else if(window_start + windowsize >= next_message_number)
195 window_start = next_message_number - windowsize;
196 window_size = windowsize;
197 send_notifications();
201 size_t messagebuffer::get_max_window_size() throw()
203 return window_size;
206 void messagebuffer::send_notifications()
208 if(updates_frozen)
209 return;
210 for(auto i : handlers)
211 i->messagebuffer_update();
214 std::string messagebuffer::get_last_message()
216 if(messages_buf.empty())
217 return "";
218 return messages_buf.rbegin()->second;