#include "stdafx.h" #include "Gui/ConLog.h" #include #include "Ini.h" #include #include LogWriter ConLog; LogFrame* ConLogFrame; wxCriticalSection g_cs_conlog; static const uint max_item_count = 500; static const uint buffer_size = 1024 * 64; struct LogPacket { wxString m_prefix; wxString m_text; wxString m_colour; LogPacket(const wxString& prefix, const wxString& text, const wxString& colour) : m_prefix(prefix) , m_text(text) , m_colour(colour) { } LogPacket() { } }; struct _LogBuffer : public MTPacketBuffer { _LogBuffer() : MTPacketBuffer(buffer_size) { } void _push(const LogPacket& data) { const u32 sprefix = data.m_prefix.Len(); const u32 stext = data.m_text.Len(); const u32 scolour = data.m_colour.Len(); m_buffer.Reserve( sizeof(u32) + sprefix + sizeof(u32) + stext + sizeof(u32) + scolour); u32 c_put = m_put; memcpy(&m_buffer[c_put], &sprefix, sizeof(u32)); c_put += sizeof(u32); memcpy(&m_buffer[c_put], data.m_prefix.c_str(), sprefix); c_put += sprefix; memcpy(&m_buffer[c_put], &stext, sizeof(u32)); c_put += sizeof(u32); memcpy(&m_buffer[c_put], data.m_text.c_str(), stext); c_put += stext; memcpy(&m_buffer[c_put], &scolour, sizeof(u32)); c_put += sizeof(u32); memcpy(&m_buffer[c_put], data.m_colour.c_str(), scolour); c_put += scolour; m_put = c_put; CheckBusy(); } LogPacket _pop() { LogPacket ret; u32 c_get = m_get; const u32& sprefix = *(u32*)&m_buffer[c_get]; c_get += sizeof(u32); if(sprefix) memcpy(wxStringBuffer(ret.m_prefix, sprefix), &m_buffer[c_get], sprefix); c_get += sprefix; const u32& stext = *(u32*)&m_buffer[c_get]; c_get += sizeof(u32); if(stext) memcpy(wxStringBuffer(ret.m_text, stext), &m_buffer[c_get], stext); c_get += stext; const u32& scolour = *(u32*)&m_buffer[c_get]; c_get += sizeof(u32); if(scolour) memcpy(wxStringBuffer(ret.m_colour, scolour), &m_buffer[c_get], scolour); c_get += scolour; m_get = c_get; if(!HasNewPacket()) Flush(); return ret; } } LogBuffer; LogWriter::LogWriter() { if(!m_logfile.Open(_PRGNAME_ ".log", wxFile::write)) { wxMessageBox("Cann't create log file! (" _PRGNAME_ ".log)", wxMessageBoxCaptionStr, wxICON_ERROR); } } void LogWriter::WriteToLog(wxString prefix, wxString value, wxString colour/*, wxColour bgcolour*/) { if(ThreadBase* thr = GetCurrentNamedThread()) { prefix = (prefix.IsEmpty() ? "" : prefix + " : ") + thr->GetThreadName(); } if(m_logfile.IsOpened()) m_logfile.Write((prefix.IsEmpty() ? wxString(wxEmptyString) : "[" + prefix + "]: ") + value + "\n"); if(!ConLogFrame) return; wxCriticalSectionLocker lock(g_cs_conlog); if(wxThread::IsMain()) { while(LogBuffer.IsBusy()) wxYieldIfNeeded(); } else { while(LogBuffer.IsBusy()) Sleep(1); } //if(LogBuffer.put == LogBuffer.get) LogBuffer.Flush(); LogBuffer.Push(LogPacket(prefix, value, colour)); } wxString FormatV(const wxString fmt, va_list args) { int length = 256; wxString str; for(;;) { str.Clear(); wxStringBuffer buf(str, length+1); memset(buf, 0, length+1); if(vsnprintf(buf, length, fmt, args) != -1) break; length *= 2; } return str; } void LogWriter::Write(const wxString fmt, ...) { va_list list; va_start(list, fmt); const wxString& frmt = FormatV(fmt, list); va_end(list); WriteToLog("!", frmt, "White"); } void LogWriter::Error(const wxString fmt, ...) { va_list list; va_start(list, fmt); const wxString& frmt = FormatV(fmt, list); va_end(list); WriteToLog("E", frmt, "Red"); } void LogWriter::Warning(const wxString fmt, ...) { va_list list; va_start(list, fmt); const wxString& frmt = FormatV(fmt, list); va_end(list); WriteToLog("W", frmt, "Yellow"); } void LogWriter::SkipLn() { WriteToLog(wxEmptyString, wxEmptyString, "Black"); } BEGIN_EVENT_TABLE(LogFrame, wxPanel) EVT_CLOSE(LogFrame::OnQuit) END_EVENT_TABLE() LogFrame::LogFrame(wxWindow* parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(600, 500)) , ThreadBase(false, "LogThread") , m_log(*new wxListView(this)) { m_log.InsertColumn(0, wxEmptyString); m_log.InsertColumn(1, "Log"); m_log.SetBackgroundColour(wxColour("Black")); wxBoxSizer& s_main = *new wxBoxSizer(wxVERTICAL); s_main.Add(&m_log, 1, wxEXPAND); SetSizer(&s_main); Layout(); Show(); ThreadBase::Start(); } LogFrame::~LogFrame() { } bool LogFrame::Close(bool force) { Stop(); ConLogFrame = NULL; return wxWindowBase::Close(force); } void LogFrame::Task() { while(!TestDestroy()) { if(!LogBuffer.HasNewPacket()) { Sleep(1); continue; } else { wxThread::Yield(); } const LogPacket item = LogBuffer.Pop(); while(m_log.GetItemCount() > max_item_count) { m_log.DeleteItem(0); wxThread::Yield(); } const int cur_item = m_log.GetItemCount(); m_log.InsertItem(cur_item, item.m_prefix); m_log.SetItem(cur_item, 1, item.m_text); m_log.SetItemTextColour(cur_item, item.m_colour); m_log.SetColumnWidth(0, -1); m_log.SetColumnWidth(1, -1); ::SendMessage((HWND)m_log.GetHWND(), WM_VSCROLL, SB_BOTTOM, 0); } LogBuffer.Flush(); } void LogFrame::OnQuit(wxCloseEvent& event) { Stop(); ConLogFrame = NULL; event.Skip(); }