///////////////////////////////////////////////////////////////// // // gui/wx.cc // $Id: wx.cc,v 1.6 2002-08-25 15:51:45 vruppert Exp $ // // wxWindows VGA display for Bochs. wx.cc implements a custom // wxPanel called a MyPanel, which has methods to display // text and VGA graphics on the panel. Normally, a MyPanel // is instantiated within a MyFrame created by wxmain.cc, but // this is not a requirement. // // The separation between wxmain.cc and wx.cc is as follows: // - wx.cc implements a VGA display screen using wxWindows. It is // is the wxWindows equivalent of x.cc, win32.cc, macos.cc, etc. // wx.cc includes bochs.h and has access to all Bochs devices. // The VGA panel accepts only paint, key, and mouse events. As it // receives events, it builds BxEvents and places them into a // thread-safe BxEvent queue. The simulation thread periodically // processes events from the BxEvent queue (bx_gui_c::handle_events) // and notifies the appropriate emulated I/O device. // - wxmain.cc implements a Bochs configuration interface, which is // the wxWindows equivalent of control.cc. wxmain creates a // frame with several menus and a toolbar, and allows the user to // choose the machine configuration and start the simulation. // ///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// // includes ////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "wx/image.h" #include "bochs.h" #include "gui/icon_bochs.h" #include "osdep.h" #include "font/vga.bitmap.h" // shared elements between wxmain.cc and this file #include "wxmain.h" ////////////////////////////////////////////////////////////// // constants ////////////////////////////////////////////////////////////// #define LOG_THIS bx_gui. ////////////////////////////////////////////////////////////// // data for wx gui ////////////////////////////////////////////////////////////// static char *wxScreen = NULL; wxCriticalSection wxScreen_lock; static long wxScreenX = 0; static long wxScreenY = 0; static long wxTileX = 0; static long wxTileY = 0; static unsigned long wxCursorX = 0; static unsigned long wxCursorY = 0; static unsigned long wxMouseCaptured = 0; struct { unsigned char red; unsigned char green; unsigned char blue; } wxBochsPalette[256]; wxCriticalSection event_thread_lock; BxEvent event_queue[MAX_EVENTS]; unsigned long num_events = 0; ////////////////////////////////////////////////////////////// // and now, the code ////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// // define the MyPanel which implements the VGA screen ////////////////////////////////////////////////////////////// BEGIN_EVENT_TABLE(MyPanel, wxPanel) EVT_KEY_DOWN(MyPanel::OnKeyDown) EVT_KEY_UP(MyPanel::OnKeyUp) EVT_PAINT(MyPanel::OnPaint) END_EVENT_TABLE() void MyPanel::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); //PrepareDC(dc); wxCriticalSectionLocker lock(wxScreen_lock); IFDBG_VGA(wxLogDebug ("MyPanel::OnPaint called with wxScreen = %p", wxScreen)); if(wxScreen != NULL) { wxPoint pt = GetClientAreaOrigin(); wxImage screenImage(wxScreenX, wxScreenY, (unsigned char *)wxScreen, TRUE); dc.DrawBitmap(screenImage.ConvertToBitmap(), pt.x, pt.y, FALSE); } } void MyPanel::MyRefresh () { #if defined(__WXMSW__) // For some reason, on windows the postevent trick does not // cause a paint event. Refresh(FALSE); #else wxPaintEvent event; wxPostEvent (this, event); #endif } void MyPanel::ReadConfiguration () { char *bochsrc; long style = wxOPEN; wxFileDialog *fdialog = new wxFileDialog (this, "Read configuration", "", "", "*.*", style); if (fdialog->ShowModal() == wxID_OK) { bochsrc = (char *)fdialog->GetPath().c_str (); bx_read_configuration(bochsrc); } delete fdialog; } void MyPanel::SaveConfiguration () { char *bochsrc; long style = wxSAVE | wxOVERWRITE_PROMPT; wxFileDialog *fdialog = new wxFileDialog (this, "Save configuration", "", "", "*.*", style); if (fdialog->ShowModal() == wxID_OK) { bochsrc = (char *)fdialog->GetPath().c_str (); bx_write_configuration(bochsrc, 1); } delete fdialog; } void MyPanel::OnKeyDown(wxKeyEvent& event) { if(event.GetKeyCode() == WXK_F12) { if(wxMouseCaptured) { ReleaseMouse(); wxMouseCaptured = FALSE; } else { CaptureMouse(); wxMouseCaptured = TRUE; } return; } wxCriticalSectionLocker lock(event_thread_lock); if(num_events < MAX_EVENTS) { event_queue[num_events].type = BX_ASYNC_EVT_KEY; fillBxKeyEvent (event, event_queue[num_events].u.key, false); num_events++; } } void MyPanel::OnKeyUp(wxKeyEvent& event) { wxCriticalSectionLocker lock(event_thread_lock); if(num_events < MAX_EVENTS) { event_queue[num_events].type = BX_ASYNC_EVT_KEY; fillBxKeyEvent (event, event_queue[num_events].u.key, true); num_events++; } } /// copied right out of gui/x.cc static char wxAsciiKey[0x5f] = { // !"#$%&' BX_KEY_SPACE, BX_KEY_1, BX_KEY_SINGLE_QUOTE, BX_KEY_3, BX_KEY_4, BX_KEY_5, BX_KEY_7, BX_KEY_SINGLE_QUOTE, // ()*+,-./ BX_KEY_9, BX_KEY_0, BX_KEY_8, BX_KEY_EQUALS, BX_KEY_COMMA, BX_KEY_MINUS, BX_KEY_PERIOD, BX_KEY_SLASH, // 01234567 BX_KEY_0, BX_KEY_1, BX_KEY_2, BX_KEY_3, BX_KEY_4, BX_KEY_5, BX_KEY_6, BX_KEY_7, // 89:;<=>? BX_KEY_8, BX_KEY_9, BX_KEY_SEMICOLON, BX_KEY_SEMICOLON, BX_KEY_COMMA, BX_KEY_EQUALS, BX_KEY_PERIOD, BX_KEY_SLASH, // @ABCDEFG BX_KEY_2, BX_KEY_A, BX_KEY_B, BX_KEY_C, BX_KEY_D, BX_KEY_E, BX_KEY_F, BX_KEY_G, // HIJKLMNO BX_KEY_H, BX_KEY_I, BX_KEY_J, BX_KEY_K, BX_KEY_L, BX_KEY_M, BX_KEY_N, BX_KEY_O, // PQRSTUVW BX_KEY_P, BX_KEY_Q, BX_KEY_R, BX_KEY_S, BX_KEY_T, BX_KEY_U, BX_KEY_V, BX_KEY_W, // XYZ[\]^_ BX_KEY_X, BX_KEY_Y, BX_KEY_Z, BX_KEY_LEFT_BRACKET, BX_KEY_BACKSLASH, BX_KEY_RIGHT_BRACKET, BX_KEY_6, BX_KEY_MINUS, // `abcdefg BX_KEY_GRAVE, BX_KEY_A, BX_KEY_B, BX_KEY_C, BX_KEY_D, BX_KEY_E, BX_KEY_F, BX_KEY_G, // hijklmno BX_KEY_H, BX_KEY_I, BX_KEY_J, BX_KEY_K, BX_KEY_L, BX_KEY_M, BX_KEY_N, BX_KEY_O, // pqrstuvw BX_KEY_P, BX_KEY_Q, BX_KEY_R, BX_KEY_S, BX_KEY_T, BX_KEY_U, BX_KEY_V, BX_KEY_W, // xyz{|}~ BX_KEY_X, BX_KEY_Y, BX_KEY_Z, BX_KEY_LEFT_BRACKET, BX_KEY_BACKSLASH, BX_KEY_RIGHT_BRACKET, BX_KEY_GRAVE }; // MS Windows specific key mapping, which uses wxKeyEvent::m_rawCode & 2. Boolean MyPanel::fillBxKeyEvent_MSW (wxKeyEvent& wxev, BxKeyEvent& bxev, Boolean release) { #if defined(wxHAS_RAW_KEY_CODES) && defined(__WXMSW__) IFDBG_KEY(wxLogDebug ("fillBxKeyEvent_MSW. key code %d, raw codes %d %d", wxev.m_keyCode, wxev.m_rawCode, wxev.m_rawFlags)); // this code was grabbed from gui/win32.cpp Bit32u lParam = wxev.m_rawFlags; Bit32u key = HIWORD (lParam) & 0x01FF; bxev.bx_key = 0x0000; if (((key & 0x0100) && ((key & 0x01ff) != 0x0145)) | ((key & 0x01ff) == 0x45)) { // Its an extended key bxev.bx_key = 0xE000; } // Its a key bxev.bx_key |= (key & 0x00FF) | (release? 0x80 : 0x00); bxev.raw_scancode = true; return true; #else return false; #endif } #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__) // get those keysym definitions #include #endif // GTK specific key mapping, which uses wxKeyEvent::m_rawCode. Boolean MyPanel::fillBxKeyEvent_GTK (wxKeyEvent& wxev, BxKeyEvent& bxev, Boolean release) { #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__) IFDBG_KEY(wxLogDebug ("fillBxKeyEvent_GTK. key code %d, raw codes %d %d", wxev.m_keyCode, wxev.m_rawCode, wxev.m_rawFlags)); // GTK has only 16bit key codes Bit16u keysym = (Bit32u) wxev.m_rawCode; Bit32u bx_key = 0; // since the GDK_* symbols are very much like the X11 symbols (possibly // identical), I'm using code that is copied from gui/x.cc. if (keysym >= GDK_space && keysym < GDK_asciitilde) { // use nice ASCII conversion table, based on x.cc bx_key = wxAsciiKey[keysym - GDK_space]; } else switch (keysym) { case GDK_KP_1: #ifdef GDK_KP_End case GDK_KP_End: #endif bx_key = BX_KEY_KP_END; break; case GDK_KP_2: #ifdef GDK_KP_Down case GDK_KP_Down: #endif bx_key = BX_KEY_KP_DOWN; break; case GDK_KP_3: #ifdef GDK_KP_Page_Down case GDK_KP_Page_Down: #endif bx_key = BX_KEY_KP_PAGE_DOWN; break; case GDK_KP_4: #ifdef GDK_KP_Left case GDK_KP_Left: #endif bx_key = BX_KEY_KP_LEFT; break; case GDK_KP_5: bx_key = BX_KEY_KP_5; break; case GDK_KP_6: #ifdef GDK_KP_Right case GDK_KP_Right: #endif bx_key = BX_KEY_KP_RIGHT; break; case GDK_KP_7: #ifdef GDK_KP_Home case GDK_KP_Home: #endif bx_key = BX_KEY_KP_HOME; break; case GDK_KP_8: #ifdef GDK_KP_Up case GDK_KP_Up: #endif bx_key = BX_KEY_KP_UP; break; case GDK_KP_9: #ifdef GDK_KP_Page_Up case GDK_KP_Page_Up: #endif bx_key = BX_KEY_KP_PAGE_UP; break; case GDK_KP_0: #ifdef GDK_KP_Insert case GDK_KP_Insert: #endif bx_key = BX_KEY_KP_INSERT; break; case GDK_KP_Decimal: #ifdef GDK_KP_Delete case GDK_KP_Delete: #endif bx_key = BX_KEY_KP_DELETE; break; #ifdef GDK_KP_Enter case GDK_KP_Enter: bx_key = BX_KEY_KP_ENTER; break; #endif case GDK_KP_Subtract: bx_key = BX_KEY_KP_SUBTRACT; break; case GDK_KP_Add: bx_key = BX_KEY_KP_ADD; break; case GDK_KP_Multiply: bx_key = BX_KEY_KP_MULTIPLY; break; case GDK_KP_Divide: bx_key = BX_KEY_KP_DIVIDE; break; case GDK_Up: bx_key = BX_KEY_UP; break; case GDK_Down: bx_key = BX_KEY_DOWN; break; case GDK_Left: bx_key = BX_KEY_LEFT; break; case GDK_Right: bx_key = BX_KEY_RIGHT; break; case GDK_Delete: bx_key = BX_KEY_DELETE; break; case GDK_BackSpace: bx_key = BX_KEY_BACKSPACE; break; case GDK_Tab: bx_key = BX_KEY_TAB; break; case GDK_Return: bx_key = BX_KEY_ENTER; break; case GDK_Escape: bx_key = BX_KEY_ESC; break; case GDK_F1: bx_key = BX_KEY_F1; break; case GDK_F2: bx_key = BX_KEY_F2; break; case GDK_F3: bx_key = BX_KEY_F3; break; case GDK_F4: bx_key = BX_KEY_F4; break; case GDK_F5: bx_key = BX_KEY_F5; break; case GDK_F6: bx_key = BX_KEY_F6; break; case GDK_F7: bx_key = BX_KEY_F7; break; case GDK_F8: bx_key = BX_KEY_F8; break; case GDK_F9: bx_key = BX_KEY_F9; break; case GDK_F10: bx_key = BX_KEY_F10; break; case GDK_F11: bx_key = BX_KEY_F11; break; case GDK_F12: bx_key = BX_KEY_F12; break; case GDK_Control_L: bx_key = BX_KEY_CTRL_L; break; case GDK_Shift_L: bx_key = BX_KEY_SHIFT_L; break; case GDK_Shift_R: bx_key = BX_KEY_SHIFT_R; break; case GDK_Caps_Lock: bx_key = BX_KEY_CAPS_LOCK; break; case GDK_Num_Lock: bx_key = BX_KEY_NUM_LOCK; break; case GDK_Alt_L: bx_key = BX_KEY_ALT_L; break; case GDK_Insert: bx_key = BX_KEY_INSERT; break; case GDK_Home: bx_key = BX_KEY_HOME; break; case GDK_End: bx_key = BX_KEY_END; break; case GDK_Page_Up: bx_key = BX_KEY_PAGE_UP; break; case GDK_Page_Down: bx_key = BX_KEY_PAGE_DOWN; break; default: wxLogError( "fillBxKeyEvent_GTK(): keysym %x unhandled!", (unsigned) keysym ); return BX_KEY_UNHANDLED; } bxev.bx_key = bx_key | (release? BX_KEY_RELEASED : BX_KEY_PRESSED); bxev.raw_scancode = false; return true; #else // if GTK toolkit return false; #endif } Boolean MyPanel::fillBxKeyEvent (wxKeyEvent& wxev, BxKeyEvent& bxev, Boolean release) { // Use raw codes if they are available. Raw codes are a nonstandard addition // to the wxWindows library. At present, the only way to use the "RAW_CODES" // mode is to apply Bryce's "patch.wx-raw-keycodes" patch to the wxWindows // sources and recompile. This patch, or something like it, should appear in // future wxWindows versions. #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXMSW__) return fillBxKeyEvent_MSW (wxev, bxev, release); #endif #if defined (wxHAS_RAW_KEY_CODES) && defined(__WXGTK__) return fillBxKeyEvent_GTK (wxev, bxev, release); #endif // otherwise fall back to using portable WXK_* keycodes. Not all keys // can be mapped correctly using WXK_* codes but it should be usable. IFDBG_KEY (wxLogDebug ("fillBxKeyEvent. key code %d", wxev.m_keyCode)); Bit32u key = wxev.m_keyCode; Bit32u bx_key; if(key >= WXK_SPACE && key < WXK_DELETE) { bx_key = wxAsciiKey[key - WXK_SPACE]; } else { // handle extended keys here switch(key) { case WXK_BACK: bx_key = BX_KEY_BACKSPACE; break; case WXK_TAB: bx_key = BX_KEY_TAB; break; case WXK_RETURN: bx_key = BX_KEY_ENTER; break; case WXK_ESCAPE: bx_key = BX_KEY_ESC; break; case WXK_DELETE: bx_key = BX_KEY_DELETE; break; case WXK_SHIFT: bx_key = BX_KEY_SHIFT_L; break; case WXK_CONTROL: bx_key = BX_KEY_CTRL_L; break; case WXK_ALT: bx_key = BX_KEY_ALT_L; break; case WXK_MENU: bx_key = BX_KEY_MENU; break; case WXK_PAUSE: bx_key = BX_KEY_PAUSE; break; case WXK_PRIOR: bx_key = BX_KEY_PAGE_UP; break; case WXK_NEXT: bx_key = BX_KEY_PAGE_DOWN; break; case WXK_END: bx_key = BX_KEY_END; break; case WXK_HOME: bx_key = BX_KEY_HOME; break; case WXK_LEFT: bx_key = BX_KEY_LEFT; break; case WXK_UP: bx_key = BX_KEY_UP; break; case WXK_RIGHT: bx_key = BX_KEY_RIGHT; break; case WXK_DOWN: bx_key = BX_KEY_DOWN; break; case WXK_INSERT: bx_key = BX_KEY_INSERT; break; case WXK_NUMPAD0: bx_key = BX_KEY_KP_INSERT; break; case WXK_NUMPAD1: bx_key = BX_KEY_KP_END; break; case WXK_NUMPAD2: bx_key = BX_KEY_KP_DOWN; break; case WXK_NUMPAD3: bx_key = BX_KEY_KP_PAGE_DOWN; break; case WXK_NUMPAD4: bx_key = BX_KEY_KP_LEFT; break; case WXK_NUMPAD5: bx_key = BX_KEY_KP_5; break; case WXK_NUMPAD6: bx_key = BX_KEY_KP_RIGHT; break; case WXK_NUMPAD7: bx_key = BX_KEY_KP_HOME; break; case WXK_NUMPAD8: bx_key = BX_KEY_KP_UP; break; case WXK_NUMPAD9: bx_key = BX_KEY_KP_PAGE_UP; break; case WXK_F1: bx_key = BX_KEY_F1; break; case WXK_F2: bx_key = BX_KEY_F2; break; case WXK_F3: bx_key = BX_KEY_F3; break; case WXK_F4: bx_key = BX_KEY_F4; break; case WXK_F5: bx_key = BX_KEY_F5; break; case WXK_F6: bx_key = BX_KEY_F6; break; case WXK_F7: bx_key = BX_KEY_F7; break; case WXK_F8: bx_key = BX_KEY_F8; break; case WXK_F9: bx_key = BX_KEY_F9; break; case WXK_F10: bx_key = BX_KEY_F10; break; case WXK_F11: bx_key = BX_KEY_F11; break; case WXK_F12: bx_key = BX_KEY_F12; break; case WXK_NUMLOCK: bx_key = BX_KEY_NUM_LOCK; break; case WXK_SCROLL: bx_key = BX_KEY_SCRL_LOCK; break; case WXK_DECIMAL: bx_key = BX_KEY_PERIOD; break; case WXK_SUBTRACT: bx_key = BX_KEY_MINUS; break; case WXK_ADD: bx_key = BX_KEY_EQUALS; break; case WXK_MULTIPLY: bx_key = BX_KEY_KP_MULTIPLY; break; case WXK_DIVIDE: bx_key = BX_KEY_KP_DIVIDE; break; case WXK_NUMPAD_ENTER: bx_key = BX_KEY_KP_ENTER; break; case WXK_NUMPAD_HOME: bx_key = BX_KEY_KP_HOME; break; case WXK_NUMPAD_LEFT: bx_key = BX_KEY_KP_LEFT; break; case WXK_NUMPAD_UP: bx_key = BX_KEY_KP_UP; break; case WXK_NUMPAD_RIGHT: bx_key = BX_KEY_KP_RIGHT; break; case WXK_NUMPAD_DOWN: bx_key = BX_KEY_KP_DOWN; break; case WXK_NUMPAD_PRIOR: bx_key = BX_KEY_KP_PAGE_UP; break; case WXK_NUMPAD_PAGEUP: bx_key = BX_KEY_KP_PAGE_UP; break; case WXK_NUMPAD_NEXT: bx_key = BX_KEY_KP_PAGE_DOWN; break; case WXK_NUMPAD_PAGEDOWN: bx_key = BX_KEY_KP_PAGE_DOWN; break; case WXK_NUMPAD_END: bx_key = BX_KEY_KP_END; break; case WXK_NUMPAD_BEGIN: bx_key = BX_KEY_KP_HOME; break; case WXK_NUMPAD_INSERT: bx_key = BX_KEY_KP_INSERT; break; case WXK_NUMPAD_DELETE: bx_key = BX_KEY_KP_DELETE; break; case WXK_NUMPAD_EQUAL: bx_key = BX_KEY_KP_ENTER; break; case WXK_NUMPAD_MULTIPLY: bx_key = BX_KEY_KP_MULTIPLY; break; case WXK_NUMPAD_SUBTRACT: bx_key = BX_KEY_KP_SUBTRACT; break; case WXK_NUMPAD_DECIMAL: bx_key = BX_KEY_KP_DELETE; break; case WXK_NUMPAD_DIVIDE: bx_key = BX_KEY_KP_DIVIDE; break; // Keys not handled by wxMSW case 192: bx_key = BX_KEY_GRAVE; break; // `~ case 219: bx_key = BX_KEY_LEFT_BRACKET; break; // [{ case 221: bx_key = BX_KEY_RIGHT_BRACKET; break; // ]} case 220: bx_key = BX_KEY_BACKSLASH; break; // \| case 186: bx_key = BX_KEY_SEMICOLON; break; // ;: case 222: bx_key = BX_KEY_SINGLE_QUOTE; break; // '" case 188: bx_key = BX_KEY_COMMA; break; // ,< case 191: bx_key = BX_KEY_SLASH; break; // /? default: wxLogMessage("Unhandled key event: %i (0x%x)", key, key); return 0; } } IFDBG_KEY (wxLogDebug ("fillBxKeyEvent: after remapping, key=%d", bx_key)); bxev.bx_key = bx_key | (release? BX_KEY_RELEASED : BX_KEY_PRESSED); bxev.raw_scancode = false; return true; } ////////////////////////////////////////////////////////////// // fill in methods of bx_gui ////////////////////////////////////////////////////////////// void bx_gui_c::specific_init(bx_gui_c *th, int argc, char **argv, unsigned tilewidth, unsigned tileheight, unsigned headerbar_y) { th->put("NGUI"); if (bx_options.Oprivate_colormap->get ()) { BX_INFO(("private_colormap option ignored.")); } for(int i = 0; i < 256; i++) { wxBochsPalette[i].red = 0; wxBochsPalette[i].green = 0; wxBochsPalette[i].blue = 0; } wxScreenX = 640; wxScreenY = 480; wxCriticalSectionLocker lock(wxScreen_lock); wxScreen = (char *)malloc(wxScreenX * wxScreenY * 3); memset(wxScreen, 0, wxScreenX * wxScreenY * 3); wxTileX = tilewidth; wxTileY = tileheight; } // ::HANDLE_EVENTS() // // Called periodically (vga_update_interval in .bochsrc) so the // the gui code can poll for keyboard, mouse, and other // relevant events. void bx_gui_c::handle_events(void) { wxCriticalSectionLocker lock(event_thread_lock); Bit32u bx_key = 0; for(unsigned int i = 0; i < num_events; i++) { switch(event_queue[i].type) { case BX_ASYNC_EVT_TOOLBAR: switch (event_queue[i].u.toolbar.button) { case BX_TOOLBAR_FLOPPYA: floppyA_handler (); break; case BX_TOOLBAR_FLOPPYB: floppyB_handler (); break; case BX_TOOLBAR_CDROMD: cdromD_handler (); break; case BX_TOOLBAR_RESET: reset_handler (); break; case BX_TOOLBAR_POWER: power_handler (); break; case BX_TOOLBAR_COPY: copy_handler (); break; case BX_TOOLBAR_PASTE: paste_handler (); break; case BX_TOOLBAR_SNAPSHOT: snapshot_handler (); break; case BX_TOOLBAR_CONFIG: config_handler (); break; case BX_TOOLBAR_MOUSE_EN: toggle_mouse_enable (); break; case BX_TOOLBAR_USER: userbutton_handler (); break; default: wxLogDebug ("unknown toolbar id %d", event_queue[i].u.toolbar.button); } break; case BX_ASYNC_EVT_KEY: bx_key = event_queue[i].u.key.bx_key; if (event_queue[i].u.key.raw_scancode) { // event contains raw scancodes: use put_scancode Bit8u scancode; if (bx_key & 0xFF00) { // for extended keys scancode = 0xFF & (bx_key>>8); IFDBG_KEY (wxLogDebug ("sending raw scancode 0x%02x (extended key)", (int)scancode)); bx_devices.keyboard->put_scancode (&scancode, 1); } scancode = 0xFF & bx_key; IFDBG_KEY (wxLogDebug ("sending raw scancode 0x%02x", (int)scancode)); bx_devices.keyboard->put_scancode (&scancode, 1); } else { // event contains BX_KEY_* codes: use gen_scancode IFDBG_KEY (wxLogDebug ("sending key event 0x%02x", bx_key)); bx_devices.keyboard->gen_scancode(bx_key); } break; default: wxLogError ("handle_events received unhandled event type %d in queue", (int)event_queue[i].type); } } num_events = 0; } // ::FLUSH() // // Called periodically, requesting that the gui code flush all pending // screen update requests. void bx_gui_c::flush(void) { } // ::CLEAR_SCREEN() // // Called to request that the VGA region is cleared. Don't // clear the area that defines the headerbar. void bx_gui_c::clear_screen(void) { wxCriticalSectionLocker lock(wxScreen_lock); memset(wxScreen, 0, wxScreenX * wxScreenY * 3); } static void UpdateScreen(char *newBits, int x, int y, int width, int height) { wxCriticalSectionLocker lock(wxScreen_lock); if(wxScreen != NULL) { for(int i = 0; i < height; i++) { for(int c = 0; c < width; c++) { wxScreen[(y * wxScreenX * 3) + ((x+c) * 3)] = wxBochsPalette[newBits[(i * width) + c]].red; wxScreen[(y * wxScreenX * 3) + ((x+c) * 3) + 1] = wxBochsPalette[newBits[(i * width) + c]].green; wxScreen[(y * wxScreenX * 3) + ((x+c) * 3) + 2] = wxBochsPalette[newBits[(i * width) + c]].blue; } y++; } } } static void DrawBochsBitmap(int x, int y, int width, int height, char *bmap, char color) { char vgaPallet[] = { (char)0x00, //Black (char)0x01, //Dark Blue (char)0x02, //Dark Green (char)0x03, //Dark Cyan (char)0x04, //Dark Red (char)0x05, //Dark Magenta (char)0x06, //Brown (char)0x07, //Light Gray (char)0x38, //Dark Gray (char)0x09, //Light Blue (char)0x12, //Green (char)0x1B, //Cyan (char)0x24, //Light Red (char)0x2D, //Magenta (char)0x36, //Yellow (char)0x3F //White }; char bgcolor = vgaPallet[(color >> 4) & 0xF]; char fgcolor = vgaPallet[color & 0xF]; char *newBits = (char *)malloc(width * height); memset(newBits, 0, (width * height)); for(int i = 0; i < (width * height) / 8; i++) { newBits[i * 8 + 0] = (bmap[i] & 0x01) ? fgcolor : bgcolor; newBits[i * 8 + 1] = (bmap[i] & 0x02) ? fgcolor : bgcolor; newBits[i * 8 + 2] = (bmap[i] & 0x04) ? fgcolor : bgcolor; newBits[i * 8 + 3] = (bmap[i] & 0x08) ? fgcolor : bgcolor; newBits[i * 8 + 4] = (bmap[i] & 0x10) ? fgcolor : bgcolor; newBits[i * 8 + 5] = (bmap[i] & 0x20) ? fgcolor : bgcolor; newBits[i * 8 + 6] = (bmap[i] & 0x40) ? fgcolor : bgcolor; newBits[i * 8 + 7] = (bmap[i] & 0x80) ? fgcolor : bgcolor; } UpdateScreen(newBits, x, y, width, height); free(newBits); } // ::TEXT_UPDATE() // // Called in a VGA text mode, to update the screen with // new content. // // old_text: array of character/attributes making up the contents // of the screen from the last call. See below // new_text: array of character/attributes making up the current // contents, which should now be displayed. See below // // format of old_text & new_text: each is 4000 bytes long. // This represents 80 characters wide by 25 high, with // each character being 2 bytes. The first by is the // character value, the second is the attribute byte. // I currently don't handle the attribute byte. // // cursor_x: new x location of cursor // cursor_y: new y location of cursor void bx_gui_c::text_update(Bit8u *old_text, Bit8u *new_text, unsigned long cursor_x, unsigned long cursor_y, Bit16u cursor_state, unsigned nrows) { IFDBG_VGA(wxLogDebug ("text_update")); Bit8u cs_start = (cursor_state >> 8) & 0x3f; Bit8u cs_end = cursor_state & 0x1f; unsigned char cChar; unsigned int ncols = wxScreenX / 8; unsigned int nchars = ncols * nrows; if((wxCursorY * ncols + wxCursorX) < nchars) { cChar = new_text[(wxCursorY * ncols + wxCursorX) * 2]; DrawBochsBitmap(wxCursorX * 8, wxCursorY * 16, 8, 16, (char *)&bx_vgafont[cChar].data, new_text[((wxCursorY * ncols + wxCursorX) * 2) + 1]); } for(int i = 0; i < nchars * 2; i += 2) { if((old_text[i] != new_text[i]) || (old_text[i+1] != new_text[i+1])) { cChar = new_text[i]; int x = (i / 2) % ncols; int y = (i / 2) / ncols; DrawBochsBitmap(x * 8, y * 16, 8, 16, (char *)&bx_vgafont[cChar].data, new_text[i+1]); } } wxCursorX = cursor_x; wxCursorY = cursor_y; if(((cursor_y * ncols + cursor_x) < nchars) && (cs_start <= cs_end)) { cChar = new_text[(cursor_y * ncols + cursor_x) * 2]; char cAttr = new_text[((cursor_y * ncols + cursor_x) * 2) + 1]; cAttr = ((cAttr >> 4) & 0xF) + ((cAttr & 0xF) << 4); DrawBochsBitmap(wxCursorX * 8, wxCursorY * 16, 8, 16, (char *)&bx_vgafont[cChar].data, cAttr); } thePanel->MyRefresh (); } // ::PALETTE_CHANGE() // // Allocate a color in the native GUI, for this color, and put // it in the colormap location 'index'. // returns: 0=no screen update needed (color map change has direct effect) // 1=screen updated needed (redraw using current colormap) Boolean bx_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue) { IFDBG_VGA(wxLogDebug ("palette_change")); wxBochsPalette[index].red = red; wxBochsPalette[index].green = green; wxBochsPalette[index].blue = blue; return(0); } // ::GRAPHICS_TILE_UPDATE() // // Called to request that a tile of graphics be drawn to the // screen, since info in this region has changed. // // tile: array of 8bit values representing a block of pixels with // dimension equal to the 'tilewidth' & 'tileheight' parameters to // ::specific_init(). Each value specifies an index into the // array of colors you allocated for ::palette_change() // x0: x origin of tile // y0: y origin of tile // // note: origin of tile and of window based on (0,0) being in the upper // left of the window. void bx_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0) { IFDBG_VGA (wxLogDebug ("graphics_tile_update")); UpdateScreen((char *)tile, x0, y0, wxTileX, wxTileY); //thePanel->MyRefresh (); } // ::DIMENSION_UPDATE() // // Called when the VGA mode changes it's X,Y dimensions. // Resize the window to this size, but you need to add on // the height of the headerbar to the Y value. // // x: new VGA x size // y: new VGA y size (add headerbar_y parameter from ::specific_init(). void bx_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight) { IFDBG_VGA (wxLogDebug ("dimension_update")); wxCriticalSectionLocker lock(wxScreen_lock); if (fheight > 0) { if (fheight != 16) { y = y * 16 / fheight; } } wxScreenX = x; wxScreenY = y; wxScreen = (char *)realloc(wxScreen, wxScreenX * wxScreenY * 3); wxASSERT (wxScreen != NULL); //theFrame->SetSize(-1, -1, wxScreenX + 6, wxScreenY + 100, 0); //wxSize size = theFrame->GetToolBar()->GetToolSize(); theFrame->SetClientSize(wxScreenX, wxScreenY); // + size.GetHeight()); //thePanel->MyRefresh (); } // ::CREATE_BITMAP() // // Create a monochrome bitmap of size 'xdim' by 'ydim', which will // be drawn in the headerbar. Return an integer ID to the bitmap, // with which the bitmap can be referenced later. // // bmap: packed 8 pixels-per-byte bitmap. The pixel order is: // bit0 is the left most pixel, bit7 is the right most pixel. // xdim: x dimension of bitmap // ydim: y dimension of bitmap unsigned bx_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim) { UNUSED(bmap); UNUSED(xdim); UNUSED(ydim); return(0); } // ::HEADERBAR_BITMAP() // // Called to install a bitmap in the bochs headerbar (toolbar). // // bmap_id: will correspond to an ID returned from // ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT // or BX_GRAVITY_RIGHT, meaning install the bitmap in the next // available leftmost or rightmost space. // alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT, // meaning install the bitmap in the next // available leftmost or rightmost space. // f: a 'C' function pointer to callback when the mouse is clicked in // the boundaries of this bitmap. unsigned bx_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void)) { UNUSED(bmap_id); UNUSED(alignment); UNUSED(f); return(0); } // ::SHOW_HEADERBAR() // // Show (redraw) the current headerbar, which is composed of // currently installed bitmaps. void bx_gui_c::show_headerbar(void) { } // ::REPLACE_BITMAP() // // Replace the bitmap installed in the headerbar ID slot 'hbar_id', // with the one specified by 'bmap_id'. 'bmap_id' will have // been generated by ::create_bitmap(). The old and new bitmap // must be of the same size. This allows the bitmap the user // sees to change, when some action occurs. For example when // the user presses on the floppy icon, it then displays // the ejected status. // // hbar_id: headerbar slot ID // bmap_id: bitmap ID void bx_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id) { UNUSED(hbar_id); UNUSED(bmap_id); } // ::EXIT() // // Called before bochs terminates, to allow for a graceful // exit from the native GUI mechanism. void bx_gui_c::exit(void) { BX_INFO(("bx_gui_c::exit() not implemented yet.")); } void bx_gui_c::mouse_enabled_changed_specific (Boolean val) { } int bx_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes) { UNUSED(bytes); UNUSED(nbytes); return 0; } int bx_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len) { UNUSED(text_snapshot); UNUSED(len); return 0; } #if 0 ////////////// /* This is basically the old wx.cc from June 2001. In March 2002, when Psyon and I started working on wxWindows again, the wx.cc was crashing and I didn't understand why. So I started over again in wxmain.cc, and we hacked it until it worked. */ // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #include #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "config.h" extern "C" { // siminterface needs stdio.h #include } #include "osdep.h" #include "control.h" #include "siminterface.h" #include "gui/wx.h" // I wanted to make this a static member of ParamEditor, but it gave me // link errors so I just put it outside for now. wxHashTable paramEditorsById; // event table for ParamEditor and subclasses BEGIN_EVENT_TABLE(ParamEditor, wxPanel) //EVT_CHECKBOX (-1, ParamEditor::OnEvent) //EVT_CHOICE (-1, ParamEditor::OnEvent) //EVT_TEXT(-1, ParamEditor::OnEvent) //EVT_TEXT_ENTER(-1, ParamEditor::OnEvent) END_EVENT_TABLE() // event table for wxFrame BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(ID_Quit, MyFrame::OnQuit) EVT_MENU(ID_StartBochs, MyFrame::HandleEvent) EVT_MENU(ID_ApplyAction, MyFrame::HandleEvent) EVT_MENU(ID_RevertAction, MyFrame::HandleEvent) EVT_MENU(ID_ReadConfig, MyFrame::HandleEvent) EVT_MENU(ID_WriteConfig, MyFrame::HandleEvent) EVT_MENU(ID_WriteConfigAs, MyFrame::HandleEvent) END_EVENT_TABLE() // event table for MyPanel BEGIN_EVENT_TABLE(MyPanel, wxScrolledWindow) EVT_BUTTON (ID_StartBochs, MyPanel::HandleEvent) EVT_BUTTON (ID_ApplyAction, MyPanel::HandleEvent) EVT_BUTTON (ID_RevertAction, MyPanel::HandleEvent) // do not call event handlers for the ParamEditors //EVT_CHECKBOX (ID_Check1, MyPanel::HandleEvent) //EVT_CHOICE (ID_Choice1, MyPanel::HandleEvent) //EVT_COMBOBOX (ID_Combo1, MyPanel::HandleEvent) //EVT_TEXT (ID_Combo1, MyPanel::HandleEvent) END_EVENT_TABLE() // event table for BochsEventHandler and subclasses BEGIN_EVENT_TABLE(BochsEventHandler, wxEvtHandler) EVT_MENU (-1, BochsEventHandler::OnEvent) END_EVENT_TABLE() MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame((wxFrame *)NULL, -1, title, pos, size) { bochsThread = NULL; wxMenu *menuFile = new wxMenu; menuFile->Append( ID_StartBochs, "&Start Bochs..." ); menuFile->AppendSeparator(); menuFile->Append( ID_ReadConfig, "Read Configuration File" ); menuFile->Append( ID_WriteConfig, "Write Configuration" ); menuFile->Append( ID_WriteConfigAs, "Write Configuration As..." ); menuFile->AppendSeparator(); menuFile->Append( ID_Quit, "E&xit" ); wxMenuBar *menuBar = new wxMenuBar; menuBar->Append( menuFile, "&File" ); SetMenuBar( menuBar ); CreateStatusBar(); SetStatusText( "Bochs Controls" ); int width=500, height=3000; panel = new MyPanel ( this, this, -1, wxPoint(0,0), wxSize(width,height) ); panel->SetScrollbars( 10, 10, width/10, height/10 ); } void MyFrame::HandleEvent (wxCommandEvent& event) { panel->HandleEvent (event); } void MyFrame::StartBochsThread () { if (bochsThread == NULL) { printf ("Starting bochs thread\n"); bochsThread = new BochsThread (); bochsThread->Create (); bochsThread->Run (); } else { wxMessageBox ( "Can't start Bochs simulator, because it is already running", "Already Running", wxOK | wxICON_ERROR); } } int MyFrame::ReadConfiguration (int ask_name) { char oldrc_cstr[CPANEL_PATH_LEN]; int found_default = 1; if (SIM->get_default_rc (oldrc_cstr, CPANEL_PATH_LEN) < 0) { found_default = 0; oldrc_cstr[0] = 0; } wxString oldrc (oldrc_cstr), newrc = oldrc; if (!found_default) { if (!ask_name) return -1; newrc = ::wxFileSelector ("Load which configuration file?", "", oldrc, "", "", wxOPEN); } if (newrc.IsEmpty () || (newrc == "none")) return 0; if (SIM->read_rc ((char *)newrc.c_str ()) < 0) { wxMessageBox ("Error loading configuration file"); return -1; } panel->forAllEditors (ID_RevertAction, paramEditorsById); return 0; } int MyFrame::WriteConfiguration (int ask_name) { char oldrc_cstr[CPANEL_PATH_LEN]; int found_default = 1; if (SIM->get_default_rc (oldrc_cstr, CPANEL_PATH_LEN) < 0) { found_default = 0; oldrc_cstr[0] = 0; } wxString oldrc (oldrc_cstr), newrc = oldrc; if (ask_name || !found_default) { newrc = ::wxFileSelector ("Save Configuration As", "", oldrc, "", "", wxSAVE | wxOVERWRITE_PROMPT); } if (newrc.IsEmpty () || (newrc == "none")) return 0; if (SIM->write_rc ((char *)newrc.c_str (), 1) < 0) { wxMessageBox ("Error while saving configuration file"); return -1; } return 0; } // static function version that can be referred to by function pointer int MyFrame::ProcessBochsEvent (void *class_ptr, int id) { printf ("MyFrame::ProcessBochsEvent\n"); MyFrame *f = (MyFrame *)class_ptr; f->ProcessBochsEvent2 (id); return 0; } int MyFrame::ProcessBochsEvent2 (int code) { printf ("MyFrame::ProcessBochsEvent2\n"); switch (code) { case NOTIFY_CODE_LOGMSG: if (0) { // dumb static choices for now, I'll fix it once I get it to work // // this code works if the gui thread calls it, but it's doing bad // things when it gets called from the bochs thread. // I know it's legal for a non-GUI thread to enter a mutex, update // an object like "m_frame->WriteText(msg)" and then leave the mutex. // But this code puts up a modal dialog and waits for user input. // If you comment out the mutex code, you get: // GLib-WARNING **: g_main_run(): called recursively from within a source's check() or prepare() member or from a second thread, iteration not possible // And if you uncomment the mutex, it displays the dialog correctly // but then clicking on it does nothing...deadlock. // Maybe this must be resolved by posting a message between threads // instead. wxMutexGuiEnter(); static wxString choices[] = { "Die", "Continue", "Continue and Disable" }; char prefix[512], msg[512]; int level; assert (SIM->log_msg_2 (prefix, &level, msg, sizeof(msg)) >= 0); wxString string; string.Printf ("%s", msg); int choice = ::wxGetSingleChoiceIndex ( string, wxString (SIM->get_log_level_name (level)), 3, choices); wxMutexGuiLeave(); printf ("you chose %d\n", choice); } else { //////////// temporary! still implement this with stdin/stdout /////////// int level; char prefix[512], msg[512]; assert (SIM->log_msg_2 (prefix, &level, msg, sizeof(msg)) >= 0); fprintf (stderr, "========================================================================\n"); fprintf (stderr, "Event type: %s\n", SIM->get_log_level_name (level)); fprintf (stderr, "Device: %s\n", prefix); fprintf (stderr, "Message: %s\n\n", msg); fprintf (stderr, "A %s has occurred. Do you want to:\n", SIM->get_log_level_name (level)); fprintf (stderr, " cont - continue execution\n"); fprintf (stderr, " alwayscont - continue execution, and don't ask again.\n"); fprintf (stderr, " This affects only %s events from device %s\n", SIM->get_log_level_name (level), prefix); fprintf (stderr, " die - stop execution now\n"); int choice; extern int ask_menu (char *prompt, int n_choices, char *choice[], int the_default, int *out); char *log_action_ask_choices[] = { "cont", "alwayscont", "die" }; int log_action_n_choices = 3; if (ask_menu ("Choose cont, alwayscont, or die. [%s] ", 3, log_action_ask_choices, 2, &choice) < 0) return SIM->notify_return(-1); // return 0 for continue, 1 for alwayscontinue, 2 for die. SIM->notify_return(choice); } break; default: fprintf (stderr, "Control panel: notify callback called with unknown code %04x\n", code); } } void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { Close( TRUE ); if (bochsThread != NULL) bochsThread->Delete (); } BochsEventHandler *bochsEventHandler; BochsEventHandler::BochsEventHandler () { printf ("BochsEventHandler::BochsEventHandler\n"); } void BochsEventHandler::OnEvent (wxCommandEvent& evt) { printf ("BochsEventHandler::OnEvent called with event id=%d\n", evt.GetId ()); } int wxid_count = ID_LAST_STATIC_ASSIGNED_ID; IMPLEMENT_APP(BochsApp) bool BochsApp::OnInit() { // do bochs initialization first siminterface_init (); MyFrame *frame = new MyFrame( "Bochs Control Panel", wxPoint(50,50), wxSize(450,340) ); SIM->set_notify_callback (frame->ProcessBochsEvent, frame); bochsEventHandler = new BochsEventHandler (); frame->Show( TRUE ); SetTopWindow( frame ); return TRUE; } void MyPanel::HandleEvent (wxCommandEvent& evt) { int id = evt.GetId (); printf ("Handle event with event id %d\n", id); switch (id) { case ID_StartBochs: frame->StartBochsThread (); break; case ID_ApplyAction: case ID_RevertAction: forAllEditors (id, paramEditorsById); break; case ID_ReadConfig: frame->ReadConfiguration (1); break; case ID_WriteConfig: frame->WriteConfiguration (0); break; case ID_WriteConfigAs: frame->WriteConfiguration (1); break; default: printf ("HandleEvent called with id=%d\n", id); } } void MyPanel::forAllEditors (int evt_id, wxHashTable& hash) { printf ("MyPanel::forAllEditors"); // iterate over editors in the editors hashtable hash.BeginFind (); wxNode *node; while (node = hash.Next ()) { ParamEditor *editor = (ParamEditor *)node->Data (); editor->Action (evt_id); } } void * BochsThread::Entry (void) { int argc=1; char *argv[] = {"bochs"}; bx_continue_after_control_panel (argc, argv); return NULL; } MyPanel::MyPanel (MyFrame *frame, wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER | wxTAB_TRAVERSAL, "Bochs Controls" ) { this->frame = frame; // the parent constructor makes this panel a child of frame, with // proper size. (void) new wxButton (this, ID_StartBochs, "Start Bochs", wxPoint (10, 10)); (void) new wxButton (this, ID_ApplyAction, "Apply", wxPoint (110, 10)); (void) new wxButton (this, ID_RevertAction, "Revert", wxPoint (210, 10)); //wxCheckBox *check1 = new wxCheckBox (this, ID_Check1, "Checkbox", wxPoint (10, 50)); //wxString choices[] = { "apple", "orange", "banana" }; //wxChoice *choice1 = new wxChoice (this, ID_Choice1, wxPoint (10, 80), wxSize (80, 30), 3, choices); //wxComboBox *combo1 = new wxComboBox (this, ID_Combo1, "Default Combo String", wxPoint (10, 130), wxSize (180, 80), 3, choices); //text1 = new wxStaticText (this, ID_Text1, "no text yet", wxPoint (0, 160)); frame->ReadConfiguration (0); buildParamList (10, 40); // grab all the settings from siminterface into the GUI forAllEditors (ID_RevertAction, paramEditorsById); } MyPanel::~MyPanel() { } void MyPanel::buildParamList (int x, int y) { // get a list of parameters int min, max; SIM->get_param_id_range (&min, &max); for (int i=min; i<=max; i++) { bx_param_c *param = SIM->get_param ((bx_id) i); if (param != NULL) { printf ("param %d is called %s\n", i, param->get_name ()); new wxStaticText (this, i, param->get_name (), wxPoint (x, y)); int wxid = wxid_count++; ParamEditor *editor = ParamEditor::createEditor (param, this, wxid, x+120, y); y+=30; } } } ///////////////////////////////////////////////////////////////////////// // Parameter editor classes ///////////////////////////////////////////////////////////////////////// ParamEditor::ParamEditor (bx_param_c *param, wxWindow *parent, wxWindowID id, int x, int y) : wxPanel(parent, id, wxPoint(x, y), wxSize (300, 30)) { printf ("ParamEditor::ParamEditor\n"); this->param = param; //wxString text = wxString (param->get_name ()); //new wxStaticText (parent, id, text, wxPoint (x, y)); } ParamEditor * ParamEditor::createEditor (bx_param_c *param, wxWindow *parent, wxWindowID id, int x, int y) { printf ("ParamEditor::createEditor\n"); Bit8u type = param->get_type (); ParamEditor *it = NULL; switch (type) { case BXT_PARAM_BOOL: it = new ParamEditorBool (param, parent, id, x, y); break; case BXT_PARAM_NUM: it = new ParamEditorNum (param, parent, id, x, y); break; case BXT_PARAM_STRING: it = new ParamEditorString (param, parent, id, x, y); break; case BXT_PARAM_ENUM: it = new ParamEditorEnum (param, parent, id, x, y); break; case BXT_LIST: it = new ParamEditorList (param, parent, id, x, y); break; default: printf ("ParamEditor::createEditor with unknown type %d\n", type); it = NULL; } paramEditorsById.Put (id, it); return it; } ParamEditorBool::ParamEditorBool (bx_param_c *param, wxWindow *parent, wxWindowID id, int x, int y) : ParamEditor (param, parent, id, x, y) { component = new wxCheckBox (this, id, "", wxPoint (0, 0)); } void ParamEditorBool::Action (int evt_id) { printf ("ParamEditorBool::Action\n"); bx_param_bool_c *param = (bx_param_bool_c *) get_param (); switch (evt_id) { case ID_ApplyAction: param->set (component->GetValue ()); break; case ID_RevertAction: component->SetValue (param->get ()); break; default: wxASSERT (0); } } ParamEditorNum::ParamEditorNum (bx_param_c *param, wxWindow *parent, wxWindowID id, int x, int y) : ParamEditor (param, parent, id, x, y) { // background color helps to visualize the borders of the panel //SetBackgroundColour (wxColour ("red")); bx_param_num_c *num = (bx_param_num_c *)param; wxString text; text.Printf ("%d", num->get ()); component = new wxTextCtrl (this, id, text, wxPoint (-1, -1), wxSize (-1, -1), wxTE_PROCESS_ENTER|wxTE_PROCESS_TAB); } void ParamEditorNum::Action (int evt_id) { printf ("ParamEditorNum::Action\n"); bx_param_num_c *param = (bx_param_num_c *) get_param (); int base = param->get_base (); wxASSERT (base==10 || base==16); switch (evt_id) { case ID_ApplyAction: { const char *string = component->GetValue ().c_str (); int n, status; if (base==10) status = wxSscanf (string, "%d", &n); else status = wxSscanf (string, "%x", &n); if (status != 1) { printf ("Invalid number in %s, value = '%s'\n", param->get_name (), string); return; } param->set (n); } break; case ID_RevertAction: { int n = param->get (); wxString string; if (base == 10) string.Printf ("%d", n); else string.Printf ("%x", n); component->SetValue (string); } break; default: wxASSERT (0); } } ParamEditorString::ParamEditorString (bx_param_c *param, wxWindow *parent, wxWindowID id, int x, int y) : ParamEditor (param, parent, id, x, y) { //SetBackgroundColour (wxColour ("red")); bx_param_string_c *string = (bx_param_string_c *)param; wxString text = wxString (string->getptr ()); component = new wxTextCtrl (this, id, text, wxPoint (-1, -1), wxSize (-1, -1), wxTE_PROCESS_ENTER); } void ParamEditorString::Action (int evt_id) { bx_param_string_c *param = (bx_param_string_c *) get_param (); const char *string; switch (evt_id) { case ID_ApplyAction: string = component->GetValue ().c_str (); param->set ((char *)string); break; case ID_RevertAction: component->SetValue (wxString (param->getptr ())); break; default: wxASSERT (0); } } ParamEditorEnum::ParamEditorEnum (bx_param_c *genericparam, wxWindow *parent, wxWindowID id, int x, int y) : ParamEditor (genericparam, parent, id, x, y) { //SetBackgroundColour (wxColour ("red")); // build the array of choices bx_param_enum_c *param = (bx_param_enum_c *) genericparam; n_choices = param->get_max () - param->get_min () + 1; choices = new wxString[n_choices]; for (int i=0; iget_choice (i); component = new wxChoice (this, id, wxPoint (-1, -1), wxSize (-1, -1), n_choices, choices); } void ParamEditorEnum::Action (int evt_id) { printf ("ParamEditorEnum::Action\n"); bx_param_enum_c *param = (bx_param_enum_c *) get_param (); int min = param->get_min (); switch (evt_id) { case ID_ApplyAction: param->set (min + component->GetSelection ()); break; case ID_RevertAction: component->SetSelection (param->get () - min); break; default: wxASSERT (0); } } ParamEditorList::ParamEditorList (bx_param_c *genericparam, wxWindow *parent, wxWindowID id, int x, int y) : ParamEditor (genericparam, parent, id, x, y) { //SetBackgroundColour (wxColour ("red")); bx_list_c *param = (bx_list_c *) genericparam; component = new wxStaticText (this, id, "list param not implemented", wxPoint (-1, -1)); } void ParamEditorList::Action (int evt_id) { printf ("ParamEditorList::Action\n"); } bx_param_c * ParamEditor::get_param () { printf ("You called get_param on ParamEditor %p\n", this); printf ("My param value is %p\n", this->param); return this->param; } void ParamEditor::OnEvent (wxCommandEvent& evt) { // if you want to run some action on the object that sent this event, // see the code below. #if 0 int id = evt.GetId (); wxObject *object = evt.GetEventObject (); printf ("ParamEditor::OnEvent, id=%d, object=%p\n", id, object); ParamEditor *genericeditor = (ParamEditor *) paramEditorsById.Get (id); if (genericeditor == NULL) { printf ("I couldn't find the parameter editor for id=%d\n", id); return; } bx_param_c *genericparam = genericeditor->get_param (); wxASSERT (genericparam != NULL); printf ("This event will be sent to %s\n", genericparam->get_name ()); genericeditor->Action (evt); #endif } #endif