diff --git a/bsnes/nall/public_cast.hpp b/bsnes/nall/public_cast.hpp index dab437c4..331800e1 100755 --- a/bsnes/nall/public_cast.hpp +++ b/bsnes/nall/public_cast.hpp @@ -22,7 +22,7 @@ namespace nall { template typename T::type public_cast::value; - template struct public_cast : public_cast { + template struct public_cast { static typename T::type value; }; diff --git a/bsnes/phoenix/qt/hexeditor.cpp b/bsnes/phoenix/qt/hexeditor.cpp new file mode 100755 index 00000000..ced36120 --- /dev/null +++ b/bsnes/phoenix/qt/hexeditor.cpp @@ -0,0 +1,175 @@ +void HexEditor::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) { + hexEditor->setParent(parent.window->container); + hexEditor->setGeometry(x, y, width, height); + if(parent.window->defaultFont) hexEditor->setFont(*parent.window->defaultFont); + + hexEditor->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + hexEditor->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + hexEditor->layout = new QHBoxLayout; + hexEditor->layout->setAlignment(Qt::AlignRight); + hexEditor->layout->setMargin(0); + hexEditor->layout->setSpacing(0); + hexEditor->setLayout(hexEditor->layout); + + hexEditor->scrollBar = new QScrollBar(Qt::Vertical); + hexEditor->scrollBar->setSingleStep(1); + hexEditor->layout->addWidget(hexEditor->scrollBar); + + hexEditor->scrollBar->connect( + hexEditor->scrollBar, SIGNAL(actionTriggered(int)), hexEditor, SLOT(scrollEvent()) + ); + hexEditor->show(); +} + +void HexEditor::setSize(unsigned size) { + hexEditor->size = size; + bool indivisible = (hexEditor->size % hexEditor->columns) != 0; //add one for incomplete row + hexEditor->scrollBar->setRange(0, hexEditor->size / hexEditor->columns + indivisible - hexEditor->rows); +} + +void HexEditor::setOffset(unsigned offset) { + object->locked = true; + hexEditor->offset = offset; + hexEditor->scrollBar->setSliderPosition(hexEditor->offset / hexEditor->columns); + object->locked = false; +} + +void HexEditor::setColumns(unsigned columns) { + hexEditor->columns = columns; +} + +void HexEditor::setRows(unsigned rows) { + hexEditor->rows = rows; + hexEditor->scrollBar->setPageStep(hexEditor->rows); +} + +void HexEditor::update() { + if(!onRead) { + hexEditor->setPlainText(""); + return; + } + + unsigned cursorPosition = hexEditor->textCursor().position(); + + string output; + unsigned offset = hexEditor->offset; + for(unsigned row = 0; row < hexEditor->rows; row++) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(unsigned column = 0; column < hexEditor->columns; column++) { + if(offset < hexEditor->size) { + uint8_t data = onRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 }; + ansidata.append(buffer); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= hexEditor->size) break; + if(row != hexEditor->rows - 1) output.append("\n"); + } + + hexEditor->setPlainText((const char*)output); + QTextCursor cursor = hexEditor->textCursor(); + cursor.setPosition(cursorPosition); + hexEditor->setTextCursor(cursor); +} + +void HexEditor::Data::keyPressEvent(QKeyEvent *event) { + if(!self.onRead || !self.onWrite) return; + + QTextCursor cursor = textCursor(); + unsigned lineWidth = 10 + (columns * 3) + 1 + (columns) + 1; + unsigned cursorY = cursor.position() / lineWidth; + unsigned cursorX = cursor.position() % lineWidth; + + unsigned nibble; + switch(event->key()) { + case Qt::Key_0: nibble = 0; break; + case Qt::Key_1: nibble = 1; break; + case Qt::Key_2: nibble = 2; break; + case Qt::Key_3: nibble = 3; break; + case Qt::Key_4: nibble = 4; break; + case Qt::Key_5: nibble = 5; break; + case Qt::Key_6: nibble = 6; break; + case Qt::Key_7: nibble = 7; break; + case Qt::Key_8: nibble = 8; break; + case Qt::Key_9: nibble = 9; break; + case Qt::Key_A: nibble = 10; break; + case Qt::Key_B: nibble = 11; break; + case Qt::Key_C: nibble = 12; break; + case Qt::Key_D: nibble = 13; break; + case Qt::Key_E: nibble = 14; break; + case Qt::Key_F: nibble = 15; break; + default: { + //allow navigation keys to move cursor, but block text input + setTextInteractionFlags(Qt::TextInteractionFlags( + Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse + )); + QTextEdit::keyPressEvent(event); + setTextInteractionFlags(Qt::TextEditorInteraction); + return; + } + } + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < columns) { + //not in ANSI region + unsigned currentOffset = offset + (cursorY * columns + cursorX); + + if(currentOffset >= size) return; //do not edit past end of file + uint8_t data = self.onRead(currentOffset); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (nibble << 0); + } else { + data = (data & 0x0f) | (nibble << 4); + } + self.onWrite(currentOffset, data); + + //auto-advance cursor to next nibble/byte + unsigned step = 1; + if(cursorNibble && cursorX != columns - 1) step = 2; + cursor.setPosition(cursor.position() + step); + setTextCursor(cursor); + + //refresh output to reflect modified data + self.update(); + } + } + } +} + +void HexEditor::Data::scrollEvent() { + if(self.object->locked) return; + unsigned currentOffset = scrollBar->sliderPosition(); + offset = currentOffset * columns; + self.update(); +} + +HexEditor::HexEditor() { + hexEditor = new HexEditor::Data(*this); + widget->widget = hexEditor; + + hexEditor->size = 0; + hexEditor->offset = 0; + hexEditor->columns = 16; + hexEditor->rows = 16; +} diff --git a/bsnes/phoenix/qt/qt.cpp b/bsnes/phoenix/qt/qt.cpp index 203b4b6f..fe7d88bd 100755 --- a/bsnes/phoenix/qt/qt.cpp +++ b/bsnes/phoenix/qt/qt.cpp @@ -17,6 +17,7 @@ namespace phoenix { #include "checkbox.cpp" #include "combobox.cpp" #include "editbox.cpp" +#include "hexeditor.cpp" #include "horizontalslider.cpp" #include "label.cpp" #include "listbox.cpp" diff --git a/bsnes/phoenix/qt/qt.hpp b/bsnes/phoenix/qt/qt.hpp index ab5d1790..fa67cea7 100755 --- a/bsnes/phoenix/qt/qt.hpp +++ b/bsnes/phoenix/qt/qt.hpp @@ -208,6 +208,21 @@ struct EditBox : Widget { Data *editBox; }; +struct HexEditor : Widget { + nall::function onRead; + nall::function onWrite; + void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height); + void setSize(unsigned size); + void setOffset(unsigned offset); + void setColumns(unsigned columns); + void setRows(unsigned rows); + void update(); + HexEditor(); +//private: + struct Data; + Data *hexEditor; +}; + struct HorizontalSlider : Widget { nall::function onChange; void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length); diff --git a/bsnes/phoenix/qt/qt.moc b/bsnes/phoenix/qt/qt.moc index 2328d758..ba4d6d98 100755 --- a/bsnes/phoenix/qt/qt.moc +++ b/bsnes/phoenix/qt/qt.moc @@ -1,7 +1,7 @@ /**************************************************************************** ** Meta object code from reading C++ file 'qt.moc.hpp' ** -** Created: Tue Jan 18 03:30:57 2011 +** Created: Mon Jan 31 08:47:12 2011 ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) ** ** WARNING! All changes made in this file will be lost! @@ -527,6 +527,65 @@ int EditBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a) } return _id; } +static const uint qt_meta_data_HexEditor__Data[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 17, 16, 16, 16, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_HexEditor__Data[] = { + "HexEditor::Data\0\0scrollEvent()\0" +}; + +const QMetaObject HexEditor::Data::staticMetaObject = { + { &QTextEdit::staticMetaObject, qt_meta_stringdata_HexEditor__Data, + qt_meta_data_HexEditor__Data, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &HexEditor::Data::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *HexEditor::Data::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *HexEditor::Data::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_HexEditor__Data)) + return static_cast(const_cast< Data*>(this)); + return QTextEdit::qt_metacast(_clname); +} + +int HexEditor::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QTextEdit::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: scrollEvent(); break; + default: ; + } + _id -= 1; + } + return _id; +} static const uint qt_meta_data_HorizontalSlider__Data[] = { // content: diff --git a/bsnes/phoenix/qt/qt.moc.hpp b/bsnes/phoenix/qt/qt.moc.hpp index 8beaed5e..bf847702 100755 --- a/bsnes/phoenix/qt/qt.moc.hpp +++ b/bsnes/phoenix/qt/qt.moc.hpp @@ -184,6 +184,27 @@ public slots: } }; +struct HexEditor::Data : public QTextEdit { + Q_OBJECT + +public: + HexEditor &self; + QHBoxLayout *layout; + QScrollBar *scrollBar; + unsigned size; + unsigned offset; + unsigned columns; + unsigned rows; + + void keyPressEvent(QKeyEvent*); + + Data(HexEditor &self) : self(self) { + } + +public slots: + void scrollEvent(); +}; + struct HorizontalSlider::Data : public QSlider { Q_OBJECT diff --git a/bsnes/phoenix/qt/window.cpp b/bsnes/phoenix/qt/window.cpp index a6be2af3..2e367f57 100755 --- a/bsnes/phoenix/qt/window.cpp +++ b/bsnes/phoenix/qt/window.cpp @@ -45,8 +45,8 @@ void Window::setFont(Font &font) { void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) { QPalette palette; palette.setColor(QPalette::Window, QColor(red, green, blue)); - window->setPalette(palette); - window->setAutoFillBackground(true); + window->container->setPalette(palette); + window->container->setAutoFillBackground(true); } void Window::setTitle(const string &text) { @@ -77,8 +77,11 @@ bool Window::fullscreen() { void Window::setFullscreen(bool fullscreen) { if(fullscreen == false) { + window->layout->setSizeConstraint(QLayout::SetFixedSize); window->showNormal(); } else { + window->layout->setSizeConstraint(QLayout::SetNoConstraint); + window->container->setFixedSize(OS::desktopWidth(), OS::desktopHeight()); window->showFullScreen(); } diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 87042eef..e8a9d661 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "075.02"; + static const char Version[] = "075.03"; static const unsigned SerializerVersion = 18; } } diff --git a/bsnes/ui-gameboy/Makefile b/bsnes/ui-gameboy/Makefile index f4d548f8..21207639 100755 --- a/bsnes/ui-gameboy/Makefile +++ b/bsnes/ui-gameboy/Makefile @@ -5,10 +5,11 @@ ui_objects += ruby phoenix # platform ifeq ($(platform),x) - phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`) - link += `pkg-config --libs gtk+-2.0` -# phoenix_compile = $(call compile,-DPHOENIX_QT `pkg-config --cflags QtCore QtGui`) -# link += `pkg-config --libs QtCore QtGui` +# phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`) +# link += `pkg-config --libs gtk+-2.0` + + phoenix_compile = $(call compile,-DPHOENIX_QT `pkg-config --cflags QtCore QtGui`) + link += `pkg-config --libs QtCore QtGui` ruby := video.glx video.xv video.sdl ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao diff --git a/bsnes/ui/Makefile b/bsnes/ui/Makefile index 0919aa8a..062f730f 100755 --- a/bsnes/ui/Makefile +++ b/bsnes/ui/Makefile @@ -7,10 +7,11 @@ ui_objects += $(if $(call streq,$(platform),win),resource) # platform ifeq ($(platform),x) - phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`) - link += `pkg-config --libs gtk+-2.0` -# phoenix_compile = $(call compile,-DPHOENIX_QT `pkg-config --cflags QtCore QtGui`) -# link += `pkg-config --libs QtCore QtGui` +# phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`) +# link += `pkg-config --libs gtk+-2.0` + + phoenix_compile = $(call compile,-DPHOENIX_QT `pkg-config --cflags QtCore QtGui`) + link += `pkg-config --libs QtCore QtGui` ruby := video.glx video.xv video.sdl ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao diff --git a/bsnes/ui/debugger/console.cpp b/bsnes/ui/debugger/console.cpp index 39994a4e..0bac0fac 100755 --- a/bsnes/ui/debugger/console.cpp +++ b/bsnes/ui/debugger/console.cpp @@ -5,7 +5,7 @@ void Console::create() { application.addWindow(this, "Debugger.Console", "192,192"); unsigned x = 5, y = 5; - output.create(*this, x, y, 580, 328); x += 580 + 5; + output.create(*this, x, y, 580, 338); x += 580 + 5; output.setFont(application.monospaceFont); output.setEditable(false); @@ -16,9 +16,9 @@ void Console::create() { traceCPU.setChecked(true); traceSMP.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace S-SMP"); y += Style::CheckBoxHeight; - clearConsole.create(*this, x, 338 - Style::ButtonHeight - 5, 120, Style::ButtonHeight, "Clear console"); + clearConsole.create(*this, x, 348 - Style::ButtonHeight - 5, 120, Style::ButtonHeight, "Clear console"); - setGeometry(0, 0, 710, 338); + setGeometry(0, 0, 715, 348); onClose = []() { debugger.showConsole.setChecked(false); diff --git a/bsnes/ui/debugger/cpu/debugger.cpp b/bsnes/ui/debugger/cpu/debugger.cpp index 8d095fa0..954e224a 100755 --- a/bsnes/ui/debugger/cpu/debugger.cpp +++ b/bsnes/ui/debugger/cpu/debugger.cpp @@ -5,7 +5,7 @@ void CPUDebugger::create() { application.addWindow(this, "Debugger.CPUdebugger", "192,192"); unsigned x = 5, y = 5; - output.create(*this, x, y, 400, 200); x += 400 + 5; + output.create(*this, x, y, 400, 210); x += 400 + 5; output.setFont(application.monospaceFont); output.setEditable(false); @@ -14,7 +14,7 @@ void CPUDebugger::create() { proceed.create(*this, x, y, 80, Style::ButtonHeight, "Proceed"); y += Style::ButtonHeight; proceed.setEnabled(false); - setGeometry(0, 0, 490, 205); + setGeometry(0, 0, 495, 220); onClose = []() { debugger.showCPUDebugger.setChecked(false); diff --git a/bsnes/ui/debugger/smp/debugger.cpp b/bsnes/ui/debugger/smp/debugger.cpp index ae15b1fe..934decb9 100755 --- a/bsnes/ui/debugger/smp/debugger.cpp +++ b/bsnes/ui/debugger/smp/debugger.cpp @@ -5,7 +5,7 @@ void SMPDebugger::create() { application.addWindow(this, "Debugger.SMPDebugger", "192,192"); unsigned x = 5, y = 5; - output.create(*this, x, y, 400, 200); x += 400 + 5; + output.create(*this, x, y, 400, 210); x += 400 + 5; output.setFont(application.monospaceFont); output.setEditable(false); @@ -14,7 +14,7 @@ void SMPDebugger::create() { proceed.create(*this, x, y, 80, Style::ButtonHeight, "Proceed"); y += Style::ButtonHeight; proceed.setEnabled(false); - setGeometry(0, 0, 490, 205); + setGeometry(0, 0, 495, 220); onClose = []() { debugger.showSMPDebugger.setChecked(false); diff --git a/bsnes/ui/debugger/tools/breakpoint-editor.cpp b/bsnes/ui/debugger/tools/breakpoint-editor.cpp index 0154b20d..5cbfafaf 100755 --- a/bsnes/ui/debugger/tools/breakpoint-editor.cpp +++ b/bsnes/ui/debugger/tools/breakpoint-editor.cpp @@ -20,7 +20,7 @@ void BreakpointEditor::create() { enableBox[n].onTick = [n]() { breakpointEditor.toggleBreakpoint(n); }; } - setGeometry(0, 0, 305, y); + setGeometry(0, 0, 310, y); runToBreakpoint.onTick = []() { if(breakpointEditor.runToBreakpoint.checked()) { diff --git a/bsnes/ui/debugger/tools/memory-editor.cpp b/bsnes/ui/debugger/tools/memory-editor.cpp index d4009e70..5dac42fe 100755 --- a/bsnes/ui/debugger/tools/memory-editor.cpp +++ b/bsnes/ui/debugger/tools/memory-editor.cpp @@ -5,7 +5,7 @@ void MemoryEditor::create() { application.addWindow(this, "Debugger.MemoryEditor", "192,192"); unsigned x = 5, y = 5; - editor.create(*this, x, y, 470, 210); x += 470 + 5; + editor.create(*this, x, y, 475, 220); x += 475 + 5; editor.setFont(application.monospaceFont); editor.setColumns(16); editor.setRows(16); @@ -21,7 +21,7 @@ void MemoryEditor::create() { refreshButton.create(*this, x, y, 80, Style::ButtonHeight, "Refresh"); y += Style::ButtonHeight; - setGeometry(0, 0, 560, 220); + setGeometry(0, 0, 570, 230); onClose = []() { debugger.showMemoryEditor.setChecked(false); diff --git a/bsnes/ui/general/main-window.cpp b/bsnes/ui/general/main-window.cpp index e5f770c5..592ffbc2 100755 --- a/bsnes/ui/general/main-window.cpp +++ b/bsnes/ui/general/main-window.cpp @@ -91,12 +91,10 @@ void MainWindow::create() { toolsStateLoad4.create(toolsStateLoad, "Slot 4"); toolsStateLoad5.create(toolsStateLoad, "Slot 5"); toolsSeparator1.create(tools); - toolsCaptureMouse.create(tools, "Capture Mouse"); - toolsSeparator2.create(tools); toolsCheatEditor.create(tools, "Cheat Editor ..."); toolsStateManager.create(tools, "State Manager ..."); #if defined(DEBUGGER) - toolsSeparator3.create(tools); + toolsSeparator2.create(tools); toolsDebugger.create(tools, "Debugger ..."); #endif @@ -190,8 +188,6 @@ void MainWindow::create() { toolsStateLoad4.onTick = []() { utility.loadState(4); }; toolsStateLoad5.onTick = []() { utility.loadState(5); }; - toolsCaptureMouse.onTick = []() { input.acquire(); }; - toolsCheatEditor.onTick = []() { cheatEditor.setVisible(); }; toolsStateManager.onTick = []() { stateManager.setVisible(); }; @@ -223,12 +219,10 @@ void MainWindow::synchronize() { systemReset.setEnabled(false); toolsStateSave.setEnabled(false); toolsStateLoad.setEnabled(false); - toolsCaptureMouse.setEnabled(false); } else { systemPower.setEnabled(true); systemReset.setEnabled(true); toolsStateSave.setEnabled(true); toolsStateLoad.setEnabled(true); - toolsCaptureMouse.setEnabled(true); } } diff --git a/bsnes/ui/general/main-window.hpp b/bsnes/ui/general/main-window.hpp index e64822ae..a06b16c8 100755 --- a/bsnes/ui/general/main-window.hpp +++ b/bsnes/ui/general/main-window.hpp @@ -61,12 +61,10 @@ struct MainWindow : TopLevelWindow { MenuItem toolsStateLoad4; MenuItem toolsStateLoad5; MenuSeparator toolsSeparator1; - MenuItem toolsCaptureMouse; - MenuSeparator toolsSeparator2; MenuItem toolsCheatEditor; MenuItem toolsStateManager; #if defined(DEBUGGER) - MenuSeparator toolsSeparator3; + MenuSeparator toolsSeparator2; MenuItem toolsDebugger; #endif diff --git a/bsnes/ui/input/hotkeys.cpp b/bsnes/ui/input/hotkeys.cpp index 23b1b619..198792de 100755 --- a/bsnes/ui/input/hotkeys.cpp +++ b/bsnes/ui/input/hotkeys.cpp @@ -6,7 +6,6 @@ void InputMapper::poll_hotkeys(unsigned scancode, int16_t value) { if(value) { //key pressed - if(scancode == keyboard(0)[Keyboard::Escape]) input.unacquire(); if(mainWindow.focused() == false) return; //save states @@ -28,10 +27,20 @@ void InputMapper::poll_hotkeys(unsigned scancode, int16_t value) { utility.showMessage({ "Slot ", activeSlot, " selected" }); } + //fullscreen if(scancode == keyboard(0)[Keyboard::F11]) { utility.setFullscreen(!mainWindow.fullscreen()); } + //mouse capture + if(scancode == keyboard(0)[Keyboard::F12]) { + if(input.acquired() == false) { + input.acquire(); + } else { + input.unacquire(); + } + } + //pause if(scancode == keyboard(0)[Keyboard::P]) { application.pause = !application.pause; diff --git a/bsnes/ui/utility/utility.cpp b/bsnes/ui/utility/utility.cpp index f9cdffed..12a31e41 100755 --- a/bsnes/ui/utility/utility.cpp +++ b/bsnes/ui/utility/utility.cpp @@ -80,8 +80,10 @@ void Utility::setFullscreen(bool fullscreen) { mainWindow.setStatusVisible(!fullscreen); mainWindow.setFullscreen(fullscreen); if(fullscreen == false) { + input.unacquire(); setScale(); } else { + input.acquire(); unsigned width, height; switch(config.video.fullscreenScale) { default: case 0: { //center (even multiple of base height)