📄 uifltk-ui.cpp
字号:
/*************************************************************************** DSemu - The Next Generation ** Fltk user interface: Interface handlers [uifltk-ui.cpp] ** Copyright Imran Nazar, 2005; released under the BSD public licence. ** Fltk used under the terms of the LGPL. ***************************************************************************/#include <map>#include <FL/Fl.h>#include <FL/fl_draw.H>#include "uifltk.h"#include "plugin.h"#include "log.h"#include "w32compile.h"//---Static private class members, and a fair few of them------------------u8 *UIFltk::UI::outbuf;UIFltk::UI *UIFltk::ui=NULL;Fl_Menu_Bar *UIFltk::UI::mbar;Fl_Box *UIFltk::UI::sbarl, *UIFltk::UI::sbarr;Fl_Box *UIFltk::UI::display;Fl_Group *UIFltk::UI::mbarcon;std::map<int, UIFltk::UI::SubWindow*> UIFltk::UI::subwindows;std::deque<EventMsg> UIFltk::UI::events;MMU32Plugin *UIFltk::UI::mmu, *UIFltk::UI::mmuSub;CPUPlugin *UIFltk::UI::cpu, *UIFltk::UI::cpuSub;GPUPlugin *UIFltk::UI::gpu;APUPlugin *UIFltk::UI::apu;Plugin *UIFltk::UI::timer;std::string UIFltk::UI::ROMpath;int UIFltk::UI::loaded=0;int UIFltk::UI::running=0;int UIFltk::UI::stepping=0;int UIFltk::UI::frames=0;int UIFltk::UI::DSmode=0;uint64_t UIFltk::UI::timestamp=0;int UIFltk::UI::cpuStatMode=3;int UIFltk::UI::mmuDumpAddr=0x04000000;int UIFltk::UI::mmuDumpMode=1;u16 UIFltk::UI::keys=0xFFFF;REQPTR UIFltk::pRequest;UNREQPTR UIFltk::pUnrequest;UIFltk::UI::BkptWindow *UIFltk::UI::bkptWnd;int UIFltk::UI::bkptVisible=0;UIFltk::UI::LogWindow *UIFltk::UI::logWnd;int UIFltk::UI::logVisible=0;UIFltk::UI::AboutWindow *UIFltk::UI::aboutWnd;int UIFltk::UI::aboutVisible=0;// Used by the Events map to work out sorting order (sort on timestamp)bool operator<(const EventMsg &a, const EventMsg &b) { return a.getTime()<b.getTime(); } //---Handlers--------------------------------------------------------------// Initialise the windowUIFltk::UI::UI(int x, int y, int w, int h, const char *title) : Fl_Double_Window(x,y,w,h,title){ // We couldn't set these callbacks statically, so do it now. menu[MENU_FILE_OPENGBA].callback(cbOpenGBA, this); menu[MENU_FILE_OPENDS].callback(cbOpenDS, this); menu[MENU_FILE_CLOSE].callback(cbClose, this); menu[MENU_FILE_EXIT].callback(cbExit, this); menu[MENU_DEBUG_RUN].callback(cbRun, this); menu[MENU_DEBUG_RESET].callback(cbReset, this); menu[MENU_DEBUG_BKPT].callback(cbBkpt, this); menu[MENU_DEBUG_STEP].callback(cbStep, this); menu[MENU_DEBUG_ASTEP].callback(cbAStep, this); menu[MENU_VIEW_LOG].callback(cbLog, this); menu[MENU_HELP_ABOUT].callback(cbAbout, this); // Define the window controls begin(); display = new Fl_Box(0, 18, 240, 1); display->box(FL_NO_BOX); mbarcon = new Fl_Group(0, 0, 240, 18); mbarcon->box(FL_NO_BOX); mbarcon->begin(); mbar = new Fl_Menu_Bar(0, 0, 240, 18); mbar->copy(&menu[0]); mbar->box(FL_FLAT_BOX); mbar->align(FL_ALIGN_INSIDE|FL_ALIGN_TOP|FL_ALIGN_LEFT); mbarcon->end(); sbarl = new Fl_Box(0, 19, 56, 18); sbarl->box(FL_THIN_DOWN_BOX); sbarl->labelsize(11); sbarl->align(FL_ALIGN_INSIDE|FL_ALIGN_TOP|FL_ALIGN_LEFT); sbarr = new Fl_Box(56, 19, 184, 18, "Application loaded."); sbarr->box(FL_THIN_DOWN_BOX); sbarr->labelsize(11); sbarr->align(FL_ALIGN_INSIDE|FL_ALIGN_TOP|FL_ALIGN_LEFT); end(); Fl::visual(FL_RGB); resizable(display); // Set the minimal size of the window (at least menu and statusbar) size_range(240,37, 240,37); color(FL_BLACK); show(); logVisible=0; Logger::log(pluginName) << "Interface brought up.";}// Shut down interface: free up the log windowUIFltk::UI::~UI(){ if(logWnd) { logWnd->hide(); delete logWnd; logWnd=NULL; }}// Redraw window: fill the framebuffervoid UIFltk::UI::draw(){ Fl_Double_Window::draw(); if(loaded && outbuf) fl_draw_image(outbuf, 0,18, 240,160, 4);}// Make a subwindowint UIFltk::UI::subwinCreate(int xd, int yd, const char *title, u32 *buf){ int id; // Generate a random ID; if it's already in the map, make another. do id=(0xCAFE0003+(rand()&32767)); while(subwindows.find(id) != subwindows.end()); // Create a new entry in the subwindow map. subwindows[id] = new SubWindow(xd, yd, this); subwindows[id]->winID = id; subwindows[id]->buffer = buf; subwindows[id]->visible = 0; subwindows[id]->title = title; subwindows[id]->label(title); // Add the title to the View menu as a checkbox option. Fl_Menu_Item item={title,0,cbSub,0,0,0,0,11}; item.callback(cbSub,this); item.flags=FL_MENU_TOGGLE; menu.insert(menu.begin()+MENU_OPT-2, item); mbar->copy(&menu[0]); char str[64]; sprintf(str, "Subwindow %08X created.", id); Logger::log(pluginName) << str; return id;}// Refresh a subwindow; tell it to redraw itself.void UIFltk::UI::subwinRefresh(int id){ subwindows[id]->redraw();}// Run the emulation for a framevoid UIFltk::UI::execFrame(){ if(loaded && running) { int t, clk, frameclk=0, cyc; EventMsg ev; // Pop an event from the events queue, run until the time it says, // then do the action it says. Keep doing this until we run out of // time for this frame. do { if(!events.empty()) { ev = events.front(); events.pop_front(); t=ev.getTime()-timestamp;// printf("Time %lld: Executing %d cycles to %lld. Queue is %d entries.\n", timestamp, t, ev.getTime(), events.size()); clk=0; if(t) { do { if(DSmode) { cyc = cpu->exec(1); if(cyc>=0) clk+=cyc; else { timestamp -= cyc; events.push_front(EventMsg(ev)); cbRunI(); return; } cyc = cpu->exec(1); if(cyc>=0) clk+=cyc; else { timestamp -= cyc; events.push_front(EventMsg(ev)); cbRunI(); return; } cyc = cpuSub->exec(1); if(cyc<0) { events.push_front(EventMsg(ev)); cbRunI(); return; } } else { cyc = cpu->exec(t-clk); if(cyc >= 0) clk += cyc; else { // If we hit a breakpoint, the return will be negative. // Put the event back, because we didn't finish it yet. timestamp -= cyc;// printf("Breakpoint reached at %lld.\n", timestamp); events.push_front(EventMsg(ev)); cbRunI(); return; } } } while(clk<t); } timestamp = ev.getTime(); frameclk+=t; ev.callFunc(); } } while(frameclk < 228*1232); frames++; redraw(); }}// Run the emulation for at most one instructionvoid UIFltk::UI::execStep(){ static EventMsg ev; static int t=-8388608, subflag=0; int clk=0; // If there's no event to head towards, don't bother. if(!events.empty()) { ev = events.front(); t=ev.getTime()-timestamp;// printf("Time %lld: %d left to next event. Queue is %d entries.\n", timestamp, t, events.size()); // If this event is now, run the callback. if(t<=0) {// printf("Time reached. Popping event.\n"); events.pop_front(); ev.callFunc(); } // Execute "one clock"; will always run at least one instruction. if(DSmode && subflag) { clk = cpu->exec(1); cpuSub->exec(1); } else clk = cpu->exec(1); subflag=!subflag; t-=clk; timestamp+=clk;// eventPush(ev.getTime(), ev.getType(), ev.getFunc(), ev.getData()); } frames=0; redraw();}// If a plugin wants to know where the UI is, tell it.uint64_t UIFltk::UI::getTimestamp(){ return timestamp;}// Push an event into the queue at the back, and sort by timestamp.void UIFltk::UI::eventPush(u32 etime, int type, vfptr func, void *data){ events.push_back(EventMsg(timestamp+etime, type, func, data, 0)); std::sort(events.begin(), events.end());// printf("Pushed at %lld: In %d cycles, call %08X(%08X). %d in queue.\n", timestamp, etime, func, data, events.size());}// Window event handlerint UIFltk::UI::handle(int e){ int ret = Fl_Window::handle(e); // If there are any subwindows with the event ID, something made that // subwindow hidden. Update the status for that subwindow. if(subwindows.find(e) != subwindows.end()) { if(subwindows[e]->visible) cbSubI(subwindows[e]->title); } switch(e) { case FL_HIDE: if(loaded) cbCloseI(); break; case 0xBEEF0001: logVisible=1; cbLogI(); break; case 0xBEEF0002: aboutVisible=1; cbAboutI(); break; case 0xBEEF0003: bkptVisible=1; cbBkptI(); break; // If a key was hit, update REGKEYS. // TODO: Configurable keys case FL_KEYDOWN: if(loaded) { switch(Fl::event_key()) { case 'z': keys &= ~0x0001; break; case 'x': keys &= ~0x0002; break; case FL_BackSpace: keys &= ~0x0004; break; case FL_Enter: keys &= ~0x0008; break; case FL_Right: keys &= ~0x0010; break; case FL_Left: keys &= ~0x0020; break; case FL_Up: keys &= ~0x0040; break; case FL_Down: keys &= ~0x0080; break; case 's': keys &= ~0x0100; break; case 'a': keys &= ~0x0200; break; } } break; case FL_KEYUP: if(loaded) { switch(Fl::event_key()) { case 'z': keys |= 0x0001; break; case 'x': keys |= 0x0002; break; case FL_BackSpace: keys |= 0x0004; break; case FL_Enter: keys |= 0x0008; break; case FL_Right: keys |= 0x0010; break; case FL_Left: keys |= 0x0020; break; case FL_Up: keys |= 0x0040; break; case FL_Down: keys |= 0x0080; break; case 's': keys |= 0x0100; break; case 'a': keys |= 0x0200; break; } } break; } return ret;}// Update the status bar with the current FPSvoid UIFltk::UI::cbFPScount(void *in){ static char str[64]; if(((UIFltk::UI*)in)->frames) { sprintf(str, "%d fps", ((UIFltk::UI*)in)->frames); ((UIFltk::UI*)in)->sbarr->label(str); ((UIFltk::UI*)in)->frames=0; } Fl::repeat_timeout(1.0, cbFPScount);}// Key I/O accessorsu8 UIFltk::UI::keyRdB(u32 a){ switch(a&0xF) { case 0: return keys&0xFF; case 1: return keys>>8; default: return 0xFF; }}u16 UIFltk::UI::keyRdH(u32 a){ switch(a&0xE) { case 0: return keys; default: return 0xFFFF; }}u32 UIFltk::UI::keyRdW(u32 a){ switch(a&0xC) { case 0: return keys; default: return 0xFFFFFFFF; }}// TODO: Key input handlers are pending interruptsvoid UIFltk::UI::keyWrB(u32 a, u8 d){}void UIFltk::UI::keyWrH(u32 a, u16 d){}void UIFltk::UI::keyWrW(u32 a, u32 d){}/*** EOF: uifltk-ui.cpp **************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -