Lots more work on making the frame aui stuff functional.
[dolphin.git] / Source / Core / DolphinWX / Src / LogWindow.cpp
blob884d29f92cbe64afe8f9e65a3ce18d62d4958349
1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
19 #include <wx/wx.h>
20 #include <wx/button.h>
21 #include <wx/textctrl.h>
22 #include <wx/listbox.h>
23 #include <wx/checklst.h>
24 #include <wx/strconv.h>
26 #include "Core.h" // for Core::GetState()
27 #include "LogWindow.h"
28 #include "ConsoleListener.h"
29 #include "Console.h"
30 #include "FileUtil.h"
33 // Milliseconds between msgQueue flushes to wxTextCtrl
34 #define UPDATETIME 200
36 BEGIN_EVENT_TABLE(CLogWindow, wxPanel)
37 EVT_CLOSE(CLogWindow::OnClose)
38 EVT_TEXT_ENTER(IDM_SUBMITCMD, CLogWindow::OnSubmit)
39 EVT_BUTTON(IDM_CLEARLOG, CLogWindow::OnClear)
40 EVT_BUTTON(IDM_TOGGLEALL, CLogWindow::OnToggleAll)
41 EVT_RADIOBOX(IDM_VERBOSITY, CLogWindow::OnOptionsCheck)
42 EVT_CHOICE(IDM_FONT, CLogWindow::OnOptionsCheck)
43 EVT_CHECKBOX(IDM_WRAPLINE, CLogWindow::OnOptionsCheck)
44 EVT_CHECKBOX(IDM_WRITEFILE, CLogWindow::OnOptionsCheck)
45 EVT_CHECKBOX(IDM_WRITECONSOLE, CLogWindow::OnOptionsCheck)
46 EVT_CHECKBOX(IDM_WRITEWINDOW, CLogWindow::OnOptionsCheck)
47 EVT_CHECKLISTBOX(IDM_LOGCHECKS, CLogWindow::OnLogCheck)
48 EVT_TIMER(IDTM_UPDATELOG, CLogWindow::OnLogTimer)
49 END_EVENT_TABLE()
51 CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos,
52 const wxSize& size, long style, const wxString& name)
53 : wxPanel(parent, id, pos, size, style, name)
54 , Parent(parent) , m_LogAccess(true)
55 , m_Log(NULL), m_cmdline(NULL), m_FontChoice(NULL)
56 , m_LogSection(1)
57 #ifdef __linux__
58 , m_SJISConv(wxFONTENCODING_EUC_JP)
59 #else
60 , m_SJISConv(wxFONTENCODING_SHIFT_JIS)
61 #endif
63 m_LogManager = LogManager::GetInstance();
64 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
65 m_LogManager->addListener((LogTypes::LOG_TYPE)i, this);
66 m_fileLog = m_LogManager->getFileListener();
67 m_console = m_LogManager->getConsoleListener();
69 CreateGUIControls();
71 LoadSettings();
74 void CLogWindow::CreateGUIControls()
76 // Verbosity
77 wxArrayString wxLevels, wxLevelsUse;
78 wxLevels.Add(wxT("Notice"));
79 wxLevels.Add(wxT("Error"));
80 wxLevels.Add(wxT("Warning"));
81 wxLevels.Add(wxT("Info"));
82 wxLevels.Add(wxT("Debug"));
83 for (int i = 0; i < MAX_LOGLEVEL; ++i) wxLevelsUse.Add(wxString::Format(wxT("%s"), wxLevels.Item(i).c_str()));
84 m_verbosity = new wxRadioBox(this, IDM_VERBOSITY, wxT("Verbosity"), wxDefaultPosition, wxDefaultSize, wxLevelsUse, 0, wxRA_SPECIFY_ROWS, wxDefaultValidator);
85 // Don't take up so much space
86 m_verbosity->SetFont(wxFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
88 // Font
89 m_FontChoice = new wxChoice(this, IDM_FONT, wxDefaultPosition, wxDefaultSize, 0, NULL, 0, wxDefaultValidator);
91 m_FontChoice->Append(wxT("Default font"));
92 m_FontChoice->Append(wxT("Monospaced font"));
93 m_FontChoice->Append(wxT("Selected font"));
94 m_FontChoice->SetSelection(0);
95 // wxTextCtrl *Tmp = CreateTextCtrl(this);
96 // DefaultFont = Tmp->GetFont();
97 // Tmp->Destroy();
98 MonoSpaceFont.SetNativeFontInfoUserDesc(wxString::FromAscii("lucida console windows-1252"));
99 Font.push_back(DefaultFont);
100 Font.push_back(MonoSpaceFont);
101 Font.push_back(DebuggerFont);
103 // Options
104 wxCheckBox * m_WrapLine = new wxCheckBox(this, IDM_WRAPLINE, wxT("Word Wrap"));
105 m_writeFileCB = new wxCheckBox(this, IDM_WRITEFILE, wxT("Write to File"), wxDefaultPosition, wxDefaultSize, 0);
106 m_writeConsoleCB = new wxCheckBox(this, IDM_WRITECONSOLE, wxT("Write to Console"), wxDefaultPosition, wxDefaultSize, 0);
107 m_writeWindowCB = new wxCheckBox(this, IDM_WRITEWINDOW, wxT("Write to Window ->"), wxDefaultPosition, wxDefaultSize, 0);
109 m_checks = new wxCheckListBox(this, IDM_LOGCHECKS, wxDefaultPosition, wxDefaultSize);
111 // Log viewer and submit row
112 m_Log = CreateTextCtrl(this, IDM_LOG, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
113 m_cmdline = new wxTextCtrl(this, IDM_SUBMITCMD, wxEmptyString, wxDefaultPosition, wxDefaultSize,
114 wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
115 //m_cmdline->SetFont(DebuggerFont);
117 // Sizers
118 sUber = new wxBoxSizer(wxHORIZONTAL); // whole plane
119 sLeft = new wxBoxSizer(wxVERTICAL); // left sizer
120 sRight = new wxBoxSizer(wxVERTICAL); // right sizer
121 sRightBottom = new wxBoxSizer(wxHORIZONTAL); // submit row
122 // Left side: buttons (-submit), options, and log type selection
123 wxStaticBoxSizer* sbLeftOptions = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Options"));
125 wxBoxSizer* sLogCtrl = new wxBoxSizer(wxHORIZONTAL);
126 sLogCtrl->Add(new wxButton(this, IDM_TOGGLEALL, wxT("Toggle all"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT), 1);
127 sLogCtrl->Add(new wxButton(this, IDM_CLEARLOG, wxT("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT), 1);
129 sbLeftOptions->Add(m_FontChoice, 0, (wxDOWN), 1);
130 sbLeftOptions->Add(m_WrapLine, 0, (wxDOWN), 1);
131 sbLeftOptions->Add(m_writeFileCB, 0, (wxDOWN), 1);
132 sbLeftOptions->Add(m_writeConsoleCB, 0, (wxDOWN), 1);
133 sbLeftOptions->Add(m_writeWindowCB, 0);
135 sLeft->Add(m_verbosity, 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
136 sLeft->Add(sbLeftOptions, 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
137 sLeft->Add(sLogCtrl, 0, wxEXPAND);
138 sLeft->Add(m_checks, 1, wxEXPAND);
140 PopulateRight();
142 sUber->Add(sLeft, 0, wxEXPAND);
143 sUber->Add(sRight, 1, wxEXPAND);
144 this->SetSizer(sUber);
146 // Settings
147 // SetAffirmativeId(IDM_SUBMITCMD);
148 UpdateChecks();
149 m_cmdline->SetFocus();
151 m_LogTimer = new wxTimer(this, IDTM_UPDATELOG);
152 m_LogTimer->Start(UPDATETIME);
155 CLogWindow::~CLogWindow()
157 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
159 m_LogManager->removeListener((LogTypes::LOG_TYPE)i, this);
161 m_LogTimer->Stop();
162 delete m_LogTimer;
165 void CLogWindow::OnClose(wxCloseEvent& event)
167 SaveSettings();
168 wxGetApp().GetCFrame()->ToggleLogWindow(false);
169 event.Skip();
172 void CLogWindow::SaveSettings()
174 IniFile ini;
175 ini.Set("LogWindow", "x", Parent->m_Mgr->GetPane(wxT("Pane 1")).rect.GetWidth());
176 ini.Set("LogWindow", "y", Parent->m_Mgr->GetPane(wxT("Pane 1")).rect.GetHeight());
177 ini.Set("LogWindow", "pos", Parent->m_Mgr->GetPane(wxT("Pane 1")).dock_direction);
178 ini.Set("Options", "Verbosity", m_verbosity->GetSelection() + 1);
179 ini.Set("Options", "Font", m_FontChoice->GetSelection());
180 ini.Set("Options", "WriteToFile", m_writeFile);
181 ini.Set("Options", "WriteToConsole", m_writeConsole);
182 ini.Set("Options", "WriteToWindow", m_writeWindow);
183 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
184 ini.Set("Logs", m_LogManager->getShortName((LogTypes::LOG_TYPE)i), m_checks->IsChecked(i));
185 ini.Save(File::GetUserPath(F_LOGGERCONFIG_IDX));
188 void CLogWindow::LoadSettings()
190 IniFile ini;
191 ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX));
192 int verbosity,font;
193 ini.Get("Options", "Verbosity", &verbosity, 0);
194 if (verbosity < 1) verbosity = 1;
195 if (verbosity > MAX_LOGLEVEL) verbosity = MAX_LOGLEVEL;
196 m_verbosity->SetSelection(verbosity - 1);
197 ini.Get("Options", "Font", &font, 0);
198 m_FontChoice->SetSelection(font);
199 if (m_FontChoice->GetSelection() < (int)Font.size())
200 m_Log->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, Font.at(m_FontChoice->GetSelection())));
201 ini.Get("Options", "WriteToFile", &m_writeFile, true);
202 m_writeFileCB->SetValue(m_writeFile);
203 ini.Get("Options", "WriteToConsole", &m_writeConsole, true);
204 m_writeConsoleCB->SetValue(m_writeConsole);
205 ini.Get("Options", "WriteToWindow", &m_writeWindow, true);
206 m_writeWindowCB->SetValue(m_writeWindow);
207 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
209 bool enable;
210 ini.Get("Logs", m_LogManager->getShortName((LogTypes::LOG_TYPE)i), &enable, true);
212 if (m_writeWindow && enable)
213 m_LogManager->addListener((LogTypes::LOG_TYPE)i, this);
214 else
215 m_LogManager->removeListener((LogTypes::LOG_TYPE)i, this);
217 if (m_writeFile && enable)
218 m_LogManager->addListener((LogTypes::LOG_TYPE)i, m_fileLog);
219 else
220 m_LogManager->removeListener((LogTypes::LOG_TYPE)i, m_fileLog);
222 if (m_writeConsole && enable)
223 m_LogManager->addListener((LogTypes::LOG_TYPE)i, m_console);
224 else
225 m_LogManager->removeListener((LogTypes::LOG_TYPE)i, m_console);
226 m_LogManager->setLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity));
228 UpdateChecks();
231 void CLogWindow::OnSubmit(wxCommandEvent& WXUNUSED (event))
233 if (!m_cmdline) return;
234 Console_Submit(m_cmdline->GetValue().To8BitData());
235 m_cmdline->SetValue(wxEmptyString);
236 NotifyUpdate();
239 void CLogWindow::OnClear(wxCommandEvent& WXUNUSED (event))
241 m_Log->Clear();
243 m_LogSection.Enter();
244 int msgQueueSize = (int)msgQueue.size();
245 for (int i = 0; i < msgQueueSize; i++)
246 msgQueue.pop();
247 m_LogSection.Leave();
249 m_console->ClearScreen();
250 NOTICE_LOG(CONSOLE, "Console cleared");
251 NotifyUpdate();
254 // Enable or disable all boxes for the current verbosity level and save the changes.
255 void CLogWindow::OnToggleAll(wxCommandEvent& WXUNUSED (event))
257 static bool enableAll = false;
258 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
260 ToggleLog(i, enableAll);
263 SaveSettings();
264 enableAll = !enableAll;
267 // Append checkboxes and update checked groups.
268 void CLogWindow::UpdateChecks()
270 // This is only run once to append checkboxes to the wxCheckListBox.
271 if (m_checks->GetCount() == 0)
273 // [F|RES] hide the window while we fill it... wxwidgets gets trouble
274 // if you don't do it (at least the win version)
275 m_checks->Freeze();
277 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
279 m_checks->Append(wxString::FromAscii(m_LogManager->getFullName( (LogTypes::LOG_TYPE)i )));
281 m_checks->Thaw();
284 m_checks->Freeze();
285 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
287 m_checks->Check(i,
288 m_LogManager->isListener((LogTypes::LOG_TYPE)i, this) ||
289 m_LogManager->isListener((LogTypes::LOG_TYPE)i, m_console) ||
290 m_LogManager->isListener((LogTypes::LOG_TYPE)i, m_fileLog));
292 m_checks->Thaw();
295 void CLogWindow::UnPopulateRight()
297 sRight->Detach(m_Log);
298 sRight->Detach(sRightBottom);
299 sRightBottom = new wxBoxSizer(wxHORIZONTAL);
301 void CLogWindow::PopulateRight()
303 sRightBottom->Add(m_cmdline, 1, wxEXPAND);
304 sRight->Add(m_Log, 1, wxEXPAND | wxSHRINK);
305 sRight->Add(sRightBottom, 0, wxEXPAND);
306 this->Layout();
309 wxTextCtrl* CLogWindow::CreateTextCtrl(wxPanel* parent, wxWindowID id, long Style)
311 wxTextCtrl* TC = new wxTextCtrl(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, Style);
312 TC->SetBackgroundColour(*wxBLACK);
313 if (m_FontChoice)
315 if (m_FontChoice->GetSelection() < (int)Font.size())
316 TC->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, Font.at(m_FontChoice->GetSelection())));
318 return TC;
321 // When an option is changed, save the change
322 void CLogWindow::OnOptionsCheck(wxCommandEvent& event)
324 wxString Text;
326 switch (event.GetId())
328 case IDM_VERBOSITY:
330 // get selection
331 int v = m_verbosity->GetSelection() + 1;
332 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
334 m_LogManager->setLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)v);
337 break;
339 case IDM_WRAPLINE:
340 // SetWindowStyleFlag doesn't fully work, we need to redraw the window
341 //m_Log->SetWindowStyleFlag(m_Log->GetWindowStyleFlag() ^ wxTE_DONTWRAP);
342 /* Notice: To retain the colors when changing word wrapping we need to
343 loop through every letter with GetStyle and then reapply them letter by letter */
344 // Prevent m_Log access while it's being destroyed
345 m_LogAccess = false;
346 UnPopulateRight();
347 Text = m_Log->GetValue();
348 m_Log->Destroy();
349 switch (event.IsChecked())
351 case 0: m_Log = CreateTextCtrl(this, IDM_LOG, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP); break;
352 case 1: m_Log = CreateTextCtrl(this, IDM_LOG, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | wxTE_WORDWRAP); break;
354 m_Log->SetDefaultStyle(wxTextAttr(*wxWHITE));
355 m_Log->AppendText(Text);
356 PopulateRight();
357 m_LogAccess = true;
358 break;
360 case IDM_FONT:
361 // Update selected font
362 Font.at(Font.size()-1) = DebuggerFont;
363 m_Log->SetStyle(0, m_Log->GetLastPosition(), wxTextAttr(wxNullColour, wxNullColour, Font.at(event.GetSelection())));
364 m_Log->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, Font.at(event.GetSelection())));
365 break;
367 case IDM_WRITEFILE:
368 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
370 m_writeFile = event.IsChecked();
371 if (m_checks->IsChecked(i))
373 if (m_writeFile)
374 m_LogManager->addListener((LogTypes::LOG_TYPE)i, m_fileLog);
375 else
376 m_LogManager->removeListener((LogTypes::LOG_TYPE)i, m_fileLog);
379 break;
381 case IDM_WRITEWINDOW:
382 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
384 m_writeWindow = event.IsChecked();
385 if (m_checks->IsChecked(i))
387 if (m_writeWindow)
388 m_LogManager->addListener((LogTypes::LOG_TYPE)i, this);
389 else
390 m_LogManager->removeListener((LogTypes::LOG_TYPE)i, this);
393 break;
395 case IDM_WRITECONSOLE:
396 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
398 m_writeConsole = event.IsChecked();
399 if (m_checks->IsChecked(i))
401 if (m_writeConsole)
402 m_LogManager->addListener((LogTypes::LOG_TYPE)i, m_console);
403 else
404 m_LogManager->removeListener((LogTypes::LOG_TYPE)i, m_console);
408 if (m_writeConsole && !m_console->IsOpen())
409 wxGetApp().GetCFrame()->ToggleConsole(true);
410 else if (!m_writeConsole && m_console->IsOpen())
411 wxGetApp().GetCFrame()->ToggleConsole(false);
413 break;
415 SaveSettings();
418 // When a checkbox is changed
419 void CLogWindow::OnLogCheck(wxCommandEvent& event)
421 int i = event.GetInt();
422 ToggleLog(i, m_checks->IsChecked(i));
424 SaveSettings();
427 void CLogWindow::ToggleLog(int _logType, bool enable)
429 LogTypes::LOG_TYPE logType = (LogTypes::LOG_TYPE)_logType;
431 m_checks->Check(_logType, enable);
433 m_LogManager->setEnable(logType, enable);
435 if (enable)
437 if (m_writeWindow)
438 m_LogManager->addListener(logType, this);
439 if (m_writeFile)
440 m_LogManager->addListener(logType, m_fileLog);
441 if (m_writeConsole)
442 m_LogManager->addListener(logType, m_console);
444 else
446 m_LogManager->removeListener(logType, this);
447 m_LogManager->removeListener(logType, m_fileLog);
448 m_LogManager->removeListener(logType, m_console);
452 void CLogWindow::OnLogTimer(wxTimerEvent& WXUNUSED(event))
454 if (!m_LogAccess) return;
456 //m_Log->Freeze();
457 UpdateLog();
458 // Better auto scroll than wxTE_AUTO_SCROLL
459 if (msgQueue.size() > 0)
461 m_Log->ScrollLines(1);
462 m_Log->ShowPosition( m_Log->GetLastPosition() );
464 //m_Log->Thaw();
467 void CLogWindow::NotifyUpdate()
469 UpdateChecks();
470 //UpdateLog();
473 void CLogWindow::UpdateLog()
475 if (!m_LogAccess) return;
476 if (!m_Log) return;
478 m_LogTimer->Stop();
479 wxString collected_text;
481 m_LogSection.Enter();
482 // Rough estimate
483 collected_text.reserve(100 * msgQueue.size());
484 int msgQueueSize = (int)msgQueue.size();
485 for (int i = 0; i < msgQueueSize; i++)
487 switch (msgQueue.front().first)
489 // red
490 case ERROR_LEVEL:
491 m_Log->SetDefaultStyle(wxTextAttr(*wxRED));
492 break;
493 // yellow
494 case WARNING_LEVEL:
495 m_Log->SetDefaultStyle(wxTextAttr(wxColour(255, 255, 0)));
496 break;
497 // green
498 case NOTICE_LEVEL:
499 m_Log->SetDefaultStyle(wxTextAttr(*wxGREEN));
500 break;
501 // cyan
502 case INFO_LEVEL:
503 m_Log->SetDefaultStyle(wxTextAttr(*wxCYAN));
504 break;
505 // light gray
506 case DEBUG_LEVEL:
507 m_Log->SetDefaultStyle(wxTextAttr(wxColour(211, 211, 211)));
508 break;
509 // white
510 default:
511 m_Log->SetDefaultStyle(wxTextAttr(*wxWHITE));
512 break;
514 if (msgQueue.front().second.size())
516 int j = m_Log->GetLastPosition();
517 m_Log->AppendText(msgQueue.front().second);
518 // White timestamp
519 m_Log->SetStyle(j, j + 9, wxTextAttr(*wxWHITE));
521 collected_text.Append(msgQueue.front().second);
522 msgQueue.pop();
524 m_LogSection.Leave();
525 // Write all text at once, needs multiple SetStyle, may not be better
526 //if (collected_text.size()) m_Log->AppendText(collected_text);
527 // Return in 0.2 seconds
528 m_LogTimer->Start(UPDATETIME);
531 void CLogWindow::Log(LogTypes::LOG_LEVELS level, const char *text)
533 m_LogSection.Enter();
534 if (msgQueue.size() >= 100)
535 msgQueue.pop();
536 msgQueue.push(std::pair<u8, wxString>((u8)level, wxString(text, m_SJISConv)));
537 m_LogSection.Leave();