Update to v075r03 release.

byuu says:

Changelog:
- added full HexEditor widget to phoenix/Qt (has dynamic scrollbar like
  phoenix/GTK, but does not yet support page up/down scrolling)
- optimized debugger to look great with either phoenix/GTK or phoenix/Qt
- fixed phoenix/Qt fullscreen mode (had to allow resizing of the layout,
  and resize the container)
- fixed phoenix/Qt Window::setBackgroundColor() bug that was making
  statusbar invisible
- entering fullscreen now captures mouse, leaving fullscreen releases it
  - so by default, no cursor in fullscreen mode now
- F12 key was assigned the task of toggling mouse capture,
  Tools->Capture Mouse was removed
- above change allows toggling mouse capture in fullscreen if you like

It wasn't my idea, but toggling the mouse capture in fullscreen also hiding the mouse cursor is what I call genius design. Two birds with one stone, and very intuitive.

Also, the default GUI on Linux for bsnes and bgameboy is now Qt, instead
of GTK+. I did this because Qt's fullscreen is far more stable, and
I fixed up the remaining bugs anyway.
This commit is contained in:
Tim Allen 2011-02-02 21:35:15 +11:00
parent 012cdd4b14
commit a136378a7b
19 changed files with 313 additions and 34 deletions

View File

@ -22,7 +22,7 @@ namespace nall {
template<typename T> typename T::type public_cast<T>::value;
template<typename T, typename T::type P> struct public_cast<T, P> : public_cast<T> {
template<typename T, typename T::type P> struct public_cast<T, P> {
static typename T::type value;
};

175
bsnes/phoenix/qt/hexeditor.cpp Executable file
View File

@ -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;
}

View File

@ -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"

View File

@ -208,6 +208,21 @@ struct EditBox : Widget {
Data *editBox;
};
struct HexEditor : Widget {
nall::function<uint8_t (unsigned)> onRead;
nall::function<void (unsigned, uint8_t)> 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<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);

View File

@ -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<void*>(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:

View File

@ -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

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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()) {

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -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)