#include "mainframe.hpp" #include "debuggerapp.hpp" #include "prefs.hpp" #include "resource.hpp" #include "stdafx.hpp" #define WM_IDLEUPDATECMDUI 0x0363 // wParam == bDisableIfNoHandler enum { WM_STOP = WM_USER + 1, WM_RUN, WM_END }; enum { STARTING, RUNNING, STOPPED, ENDING }; IMPLEMENT_DYNAMIC(MainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(MainFrame, CFrameWnd) ON_WM_CREATE() ON_WM_SIZE() ON_WM_CLOSE() ON_WM_WINDOWPOSCHANGING() ON_COMMAND(ID_STOP, cmdStop) ON_COMMAND(ID_RUN, cmdRun) ON_COMMAND(ID_STEPOVER, cmdStepOver) ON_COMMAND(ID_STEPINTO, cmdStepInto) ON_COMMAND(ID_STEPOUT, cmdStepOut) ON_COMMAND(ID_END, cmdEnd) ON_UPDATE_COMMAND_UI(ID_STOP, updateCmdUI) ON_UPDATE_COMMAND_UI(ID_RUN, updateCmdUI) ON_UPDATE_COMMAND_UI(ID_STEPOVER, updateCmdUI) ON_UPDATE_COMMAND_UI(ID_STEPINTO, updateCmdUI) ON_UPDATE_COMMAND_UI(ID_STEPOUT, updateCmdUI) ON_UPDATE_COMMAND_UI(ID_END, updateCmdUI) END_MESSAGE_MAP() MainFrame::MainFrame() : state(STARTING), step_level(-1), cur_pos(0), cur_file(0) {} MainFrame::~MainFrame() { map::iterator it; for (it = files.begin(); it != files.end(); ++it) delete it->second; } int MainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { CFrameWnd::OnCreate(lpCreateStruct); prefs.open(); string tb = prefs.homeDir + "/cfg/dbg_toolbar.bmp"; //Toolbar HBITMAP toolbmp = (HBITMAP)LoadImage(0, tb.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_LOADMAP3DCOLORS); BITMAP bm; GetObject(toolbmp, sizeof(bm), &bm); int n = 0; UINT toolbuts[] = {ID_STOP, ID_RUN, ID_STEPOVER, ID_STEPINTO, ID_STEPOUT, ID_END}; int toolcnt = sizeof(toolbuts) / sizeof(UINT); for (int k = 0; k < toolcnt; ++k) if (toolbuts[k] != ID_SEPARATOR) ++n; SIZE imgsz, butsz; imgsz.cx = bm.bmWidth / n; imgsz.cy = bm.bmHeight; butsz.cx = imgsz.cx + 7; butsz.cy = imgsz.cy + 6; toolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS); toolBar.SetBitmap(toolbmp); toolBar.SetSizes(butsz, imgsz); toolBar.SetButtons(toolbuts, toolcnt); //Tabber tabber.Create(WS_VISIBLE | WS_CHILD | TCS_HOTTRACK, CRect(0, 0, 0, 0), this, 1); tabber.SetFont(&prefs.tabsFont); //Second tabber tabber2.Create(WS_VISIBLE | WS_CHILD | TCS_HOTTRACK, CRect(0, 0, 0, 0), this, 2); tabber2.SetFont(&prefs.tabsFont); //Debug Log debug_log.Create(WS_CHILD | WS_HSCROLL | WS_VSCROLL | ES_NOHIDESEL | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, CRect(0, 0, 0, 0), &tabber, 1); tabber.insert(0, &debug_log, "Debug log"); //Debug trees locals_tree.Create(WS_VISIBLE | WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, CRect(0, 0, 0, 0), &tabber2, 3); globals_tree.Create(WS_VISIBLE | WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, CRect(0, 0, 0, 0), &tabber2, 3); consts_tree.Create(WS_VISIBLE | WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, CRect(0, 0, 0, 0), &tabber2, 3); tabber2.insert(0, &locals_tree, "Locals"); tabber2.insert(1, &globals_tree, "Globals"); tabber2.insert(2, &consts_tree, "Consts"); tabber2.setCurrent(0); setState(STARTING); return 0; } void MainFrame::setState(int n) { state = n; SendMessageToDescendants(WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0, TRUE, TRUE); if (shouldRun()) { if (HWND app = ::FindWindow("Blitz Runtime Class", 0)) { ::SetActiveWindow(app); } } else { SetActiveWindow(); } } void MainFrame::OnClose() { cmdEnd(); } void MainFrame::OnSize(UINT type, int sw, int sh) { CFrameWnd::OnSize(type, sw, sh); CRect r, t; GetClientRect(&r); int x = r.left, y = r.top, w = r.Width(), h = r.Height(); toolBar.GetWindowRect(&t); y += t.Height(); h -= t.Height(); tabber.MoveWindow(x, y, w - 240, h); tabber2.MoveWindow(x + w - 240, y, 240, h); } void MainFrame::setRuntime(void* mod, void* env) { consts_tree.reset((Environ*)env); globals_tree.reset((Module*)mod, (Environ*)env); locals_tree.reset((Environ*)env); } void MainFrame::showCurStmt() { if (!cur_file) return; SourceFile* t = sourceFile(cur_file); int row = (cur_pos >> 16) & 0xffff, col = cur_pos & 0xffff; t->highLight(row, col); globals_tree.refresh(); locals_tree.refresh(); } void MainFrame::debugRun() { setState(RUNNING); } void MainFrame::debugStop() { step_level = locals_tree.size(); setState(STOPPED); showCurStmt(); } void MainFrame::debugStmt(int pos, const char* file) { cur_pos = pos; cur_file = file; if (shouldRun()) return; ::PostMessage(0, WM_STOP, 0, 0); } void MainFrame::debugEnter(void* frame, void* env, const char* func) { locals_tree.pushFrame(frame, env, func); if (locals_tree.size() > 1) return; globals_tree.refresh(); locals_tree.refresh(); setState(RUNNING); } void MainFrame::debugLeave() { locals_tree.popFrame(); } void MainFrame::debugMsg(const char* msg, bool serious) { if (serious) { ::MessageBox(0, msg, "Runtime Error", MB_OK | MB_ICONWARNING | MB_TOPMOST | MB_SETFOREGROUND); } else { ::MessageBox(0, msg, "Runtime Message", MB_OK | MB_ICONINFORMATION | MB_TOPMOST | MB_SETFOREGROUND); } } void MainFrame::debugLog(const char* msg) { debug_log.ReplaceSel(msg); debug_log.ReplaceSel("\n"); tabber.setCurrent(0); setState(state); } void MainFrame::debugSys(void* m) {} void MainFrame::cmdStop() { ::PostMessage(0, WM_STOP, 0, 0); } void MainFrame::cmdRun() { step_level = -1; ::PostMessage(0, WM_RUN, 0, 0); } void MainFrame::cmdEnd() { ::PostMessage(0, WM_END, 0, 0); setState(ENDING); } void MainFrame::cmdStepOver() { ::PostMessage(0, WM_RUN, 0, 0); } void MainFrame::cmdStepInto() { step_level = locals_tree.size() + 1; ::PostMessage(0, WM_RUN, 0, 0); } void MainFrame::cmdStepOut() { step_level = locals_tree.size() - 1; ::PostMessage(0, WM_RUN, 0, 0); } SourceFile* MainFrame::sourceFile(const char* file) { if (!file) file = ""; map::const_iterator it = files.find(file); if (it != files.end()) { tabber.setCurrent(file_tabs[file]); return it->second; } //crete new source file SourceFile* t = new SourceFile(); it = files.insert(make_pair(file, t)).first; int tab = files.size(); t->Create(WS_CHILD | WS_HSCROLL | WS_VSCROLL | ES_NOHIDESEL | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, CRect(0, 0, 0, 0), &tabber, 1); if (FILE* f = fopen(file, "rb")) { fseek(f, 0, SEEK_END); int sz = ftell(f); fseek(f, 0, SEEK_SET); char* buf = new char[sz + 1]; fread(buf, sz, 1, f); buf[sz] = 0; t->ReplaceSel(buf); delete[] buf; fclose(f); } file_tabs.insert(make_pair(file, tab)); if (const char* p = strrchr(file, '/')) file = p + 1; if (const char* p = strrchr(file, '\\')) file = p + 1; tabber.insert(tab, t, file); tabber.setCurrent(tab); return t; } void MainFrame::updateCmdUI(CCmdUI* ui) { if (state != RUNNING && state != STOPPED) { ui->Enable(false); return; } switch (ui->m_nID) { case ID_STOP: ui->Enable(shouldRun()); break; case ID_RUN: case ID_STEPOVER: case ID_STEPINTO: case ID_STEPOUT: ui->Enable(!shouldRun()); break; case ID_END: ui->Enable(true); break; } } void MainFrame::OnWindowPosChanging(WINDOWPOS* pos) { RECT rect; SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0); pos->x = rect.left; pos->cx = rect.right - pos->x; pos->cy = rect.bottom - pos->y; }