Make various instance stuff to take references to other instance objs
[lsnes.git] / src / platform / wxwidgets / messages.cpp
blobff91610a07d3b1b7411cb0da9c5deb9ae08b444b
1 #include "platform/wxwidgets/window_messages.hpp"
2 #include "platform/wxwidgets/platform.hpp"
3 #include "platform/wxwidgets/loadsave.hpp"
4 #include <wx/clipbrd.h>
6 #include "library/minmax.hpp"
7 #include "core/window.hpp"
8 #include "core/project.hpp"
10 #define MAXMESSAGES 20
11 #define PANELWIDTH 48
12 #define COMMAND_HISTORY_SIZE 500
14 wxwin_messages::panel::panel(wxwin_messages* _parent, unsigned lines)
15 : text_framebuffer_panel(_parent, PANELWIDTH, lines, wxID_ANY, NULL)
17 parent = _parent;
18 auto pcell = get_cell();
19 line_separation = pcell.second;
20 line_clicked = 0;
21 line_current = 0;
22 mouse_held = false;
23 ilines = lines;
24 this->Connect(wxEVT_SIZE, wxSizeEventHandler(wxwin_messages::panel::on_resize), NULL, this);
25 this->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxwin_messages::panel::on_mouse), NULL, this);
26 this->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxwin_messages::panel::on_mouse), NULL, this);
27 this->Connect(wxEVT_MOTION, wxMouseEventHandler(wxwin_messages::panel::on_mouse), NULL, this);
28 this->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(wxwin_messages::panel::on_mouse), NULL, this);
30 SetMinSize(wxSize(PANELWIDTH * pcell.first, lines * pcell.second));
33 void wxwin_messages::panel::on_mouse(wxMouseEvent& e)
35 //Handle mouse wheels first.
36 if(e.GetWheelRotation() && e.GetWheelDelta()) {
37 int unit = e.GetWheelDelta();
38 scroll_acc += e.GetWheelRotation();
39 while(scroll_acc <= -unit) {
40 threads::alock h(platform::msgbuf_lock());
41 platform::msgbuf.scroll_down_line();
42 scroll_acc += unit;
44 while(scroll_acc >= e.GetWheelDelta()) {
45 threads::alock h(platform::msgbuf_lock());
46 platform::msgbuf.scroll_up_line();
47 scroll_acc -= unit;
51 uint64_t gfirst;
53 threads::alock h(platform::msgbuf_lock());
54 gfirst = platform::msgbuf.get_visible_first();
56 uint64_t local_line = e.GetY() / line_separation;
57 uint64_t global_line = gfirst + local_line;
58 if(e.RightDown()) {
59 line_clicked = global_line;
60 mouse_held = true;
61 return;
62 } else if(e.RightUp()) {
63 line_declicked = global_line;
64 mouse_held = false;
65 wxMenu menu;
66 menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxwin_messages::panel::on_menu),
67 NULL, this);
68 menu.Append(wxID_COPY, wxT("Copy to clipboard"));
69 menu.Append(wxID_SAVE, wxT("Save to file"));
70 PopupMenu(&menu);
71 } else {
72 line_current = global_line;
74 Refresh();
77 void wxwin_messages::panel::on_menu(wxCommandEvent& e)
79 std::string str;
80 uint64_t m = min(line_clicked, line_declicked);
81 uint64_t M = max(line_clicked, line_declicked);
82 size_t lines = 0;
84 threads::alock h(platform::msgbuf_lock());
85 for(uint64_t i = m; i <= M; i++) {
86 try {
87 std::string mline = platform::msgbuf.get_message(i);
88 if(lines == 1) str += "\n";
89 str += mline;
90 if(lines >= 1) str += "\n";
91 lines++;
92 } catch(...) {
96 switch(e.GetId()) {
97 case wxID_COPY:
98 if (wxTheClipboard->Open()) {
99 wxTheClipboard->SetData(new wxTextDataObject(towxstring(str)));
100 wxTheClipboard->Close();
102 break;
103 case wxID_SAVE:
104 try {
105 std::string filename = choose_file_save(this, "Save messages to",
106 lsnes_instance.project.otherpath(), filetype_textfile);
107 std::ofstream s(filename, std::ios::app);
108 if(!s) throw std::runtime_error("Error opening output file");
109 if(lines == 1) str += "\n";
110 s << str;
111 if(!s) throw std::runtime_error("Error writing output file");
112 } catch(canceled_exception& e) {
113 } catch(std::exception& e) {
114 wxMessageBox(towxstring(e.what()), _T("Error creating file"), wxICON_EXCLAMATION | wxOK,
115 this);
117 break;
121 wxSize wxwin_messages::panel::DoGetBestSize() const
123 return wxSize(80 * 8, ilines * 16);
126 wxwin_messages::wxwin_messages()
127 : wxFrame(NULL, wxID_ANY, wxT("lsnes: Messages"), wxDefaultPosition, wxSize(-1, -1),
128 wxMINIMIZE_BOX | wxCLOSE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN |
129 wxRESIZE_BORDER)
131 wxBoxSizer* top_s = new wxBoxSizer(wxVERTICAL);
132 SetSizer(top_s);
133 top_s->Add(mpanel = new panel(this, MAXMESSAGES), 1, wxEXPAND);
134 platform::msgbuf.set_max_window_size(MAXMESSAGES);
136 wxFlexGridSizer* buttons_s = new wxFlexGridSizer(1, 6, 0, 0);
137 wxButton* beginning, * pageup, * lineup, * linedown, * pagedown, * end;
138 buttons_s->Add(beginning = new wxButton(this, wxID_ANY, wxT("Beginning")), 1, wxGROW);
139 buttons_s->Add(pageup = new wxButton(this, wxID_ANY, wxT("Page Up")), 1, wxGROW);
140 buttons_s->Add(lineup = new wxButton(this, wxID_ANY, wxT("Line Up")), 1, wxGROW);
141 buttons_s->Add(linedown = new wxButton(this, wxID_ANY, wxT("Line Down")), 1, wxGROW);
142 buttons_s->Add(pagedown = new wxButton(this, wxID_ANY, wxT("Page Down")), 1, wxGROW);
143 buttons_s->Add(end = new wxButton(this, wxID_ANY, wxT("End")), 1, wxGROW);
144 beginning->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwin_messages::on_scroll_home),
145 NULL, this);
146 pageup->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwin_messages::on_scroll_pageup),
147 NULL, this);
148 lineup->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwin_messages::on_scroll_lineup),
149 NULL, this);
150 linedown->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwin_messages::on_scroll_linedown),
151 NULL, this);
152 pagedown->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwin_messages::on_scroll_pagedown),
153 NULL, this);
154 end->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwin_messages::on_scroll_end),
155 NULL, this);
156 top_s->Add(buttons_s, 0, wxGROW);
158 wxBoxSizer* cmd_s = new wxBoxSizer(wxHORIZONTAL);
159 wxButton* execute;
160 cmd_s->Add(command = new wxComboBox(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize,
161 0, NULL, wxTE_PROCESS_ENTER), 1, wxEXPAND);
162 cmd_s->Add(execute = new wxButton(this, wxID_ANY, wxT("Execute")), 0, wxGROW);
163 command->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(wxwin_messages::on_execute),
164 NULL, this);
165 execute->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxwin_messages::on_execute),
166 NULL, this);
167 cmd_s->SetSizeHints(this);
168 top_s->Add(cmd_s, 0, wxGROW);
170 Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(wxwin_messages::on_close));
171 //Very nasty hack.
172 wxSize tmp = mpanel->GetMinSize();
173 mpanel->SetMinSize(mpanel->DoGetBestSize());
174 top_s->SetSizeHints(this);
175 wxSize tmp2 = GetClientSize();
176 mpanel->SetMinSize(tmp);
177 top_s->SetSizeHints(this);
178 SetClientSize(tmp2);
181 wxwin_messages::~wxwin_messages()
185 void wxwin_messages::panel::prepare_paint()
187 int y = 0;
188 uint64_t lines, first;
189 uint64_t xm = min(line_clicked, line_current);
190 uint64_t xM = max(line_clicked, line_current);
191 std::vector<std::string> msgs;
193 threads::alock h(platform::msgbuf_lock());
194 lines = platform::msgbuf.get_visible_count();
195 first = platform::msgbuf.get_visible_first();
196 msgs.resize(lines);
197 for(size_t i = 0; i < lines; i++)
198 msgs[i] = platform::msgbuf.get_message(first + i);
200 auto size = get_characters();
201 for(size_t i = 0; i < lines; i++) {
202 uint64_t global_line = first + i;
203 bool sel = (global_line >= xm && global_line <= xM) && mouse_held;
204 std::string& msg = msgs[i];
205 uint32_t fg = sel ? 0x0000FF : 0x000000;
206 uint32_t bg = sel ? 0x000000 : 0xFFFFFF;
207 write(msg, size.first, 0, i, fg, bg);
208 y += 1;
212 void wxwin_messages::panel::on_resize(wxSizeEvent& e)
214 wxSize newsize = e.GetSize();
215 auto tcell = get_cell();
216 size_t lines = newsize.y / tcell.second;
217 size_t linelen = newsize.x / tcell.first;
218 if(lines < 1) lines = 1;
219 if(linelen < 1) linelen = 1;
220 platform::msgbuf.set_max_window_size(lines);
221 set_size(linelen, lines);
222 request_paint();
223 e.Skip();
226 void wxwin_messages::on_close(wxCloseEvent& e)
228 if(wxwidgets_exiting)
229 return;
230 e.Veto();
231 Hide();
234 void wxwin_messages::reshow()
236 Show();
239 void wxwin_messages::on_scroll_home(wxCommandEvent& e)
241 threads::alock h(platform::msgbuf_lock());
242 platform::msgbuf.scroll_beginning();
245 void wxwin_messages::on_scroll_pageup(wxCommandEvent& e)
247 threads::alock h(platform::msgbuf_lock());
248 platform::msgbuf.scroll_up_page();
251 void wxwin_messages::on_scroll_lineup(wxCommandEvent& e)
253 threads::alock h(platform::msgbuf_lock());
254 platform::msgbuf.scroll_up_line();
257 void wxwin_messages::on_scroll_linedown(wxCommandEvent& e)
259 threads::alock h(platform::msgbuf_lock());
260 platform::msgbuf.scroll_down_line();
263 void wxwin_messages::on_scroll_pagedown(wxCommandEvent& e)
265 threads::alock h(platform::msgbuf_lock());
266 platform::msgbuf.scroll_down_page();
269 void wxwin_messages::on_scroll_end(wxCommandEvent& e)
271 threads::alock h(platform::msgbuf_lock());
272 platform::msgbuf.scroll_end();
275 void wxwin_messages::on_execute(wxCommandEvent& e)
277 std::string cmd = tostdstring(command->GetValue());
278 if(cmd == "")
279 return;
280 command->Insert(towxstring(cmd), 0);
281 //If command is already there, delete the previous.
282 for(unsigned i = 1; i < command->GetCount(); i++)
283 if(tostdstring(command->GetString(i)) == cmd) {
284 command->Delete(i);
285 break;
287 //Delete old commands to prevent box becoming unmageable.
288 if(command->GetCount() > COMMAND_HISTORY_SIZE)
289 command->Delete(command->GetCount() - 1);
290 lsnes_instance.iqueue.queue(cmd);
293 void wxwin_messages::notify_update() throw()
295 mpanel->request_paint();
298 bool wxwin_messages::ShouldPreventAppExit() const
300 return false;