Update to v070r06 release.

(there was no r05 release posted to the WIP thread)

byuu says:

- bsnes/phoenix uses XML for per-game cheat codes, markup is identical
  to the main database
- added clear and clear all buttons to the cheat code editor
- phoenix/GTK+ sets all child menu elements to match the parent menu font
- phoenix/Windows will draw a black canvas for the Viewport widget
  (phoenix/GTK+ still needs this)
This commit is contained in:
Tim Allen 2010-10-03 19:17:11 +11:00
parent 775c111fef
commit 96e9333ec2
15 changed files with 175 additions and 68 deletions

View File

@ -64,7 +64,7 @@ ifeq ($(platform),x)
install -D -m 755 out/bsnes $(DESTDIR)$(prefix)/bin/bsnes
install -D -m 644 ui-qt/data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
install -D -m 644 ui-qt/data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
gconftool-2 --type bool --set /desktop/gnome/interface/menus_have_icons true
# gconftool-2 --type bool --set /desktop/gnome/interface/menus_have_icons true
endif
uninstall:

View File

@ -8,13 +8,14 @@ namespace nall {
struct container {
virtual R operator()(P... p) const = 0;
virtual container* copy() const = 0;
virtual ~container() {}
} *callback;
struct global : container {
R (*function)(P...);
R operator()(P... p) const { return function(std::forward<P>(p)...); }
container* copy() const { return new global(function); }
global(R (*function_)(P...)) : function(function_) {}
global(R (*function)(P...)) : function(function) {}
};
template<typename C> struct member : container {
@ -22,15 +23,14 @@ namespace nall {
C *object;
R operator()(P... p) const { return (object->*function)(std::forward<P>(p)...); }
container* copy() const { return new member(function, object); }
member(R (C::*function_)(P...), C *object_) : function(function_), object(object_) {}
member(R (C::*function)(P...), C *object) : function(function), object(object) {}
};
template<typename L> struct lambda : container {
L *object;
R operator()(P... p) const { return (*object)(std::forward<P>(p)...); }
container* copy() const { return new lambda(*object); }
lambda(const L& object_) { object = new L(object_); }
~lambda() { delete object; }
L object;
R operator()(P... p) const { return object(std::forward<P>(p)...); }
container* copy() const { return new lambda(object); }
lambda(const L& object) : object(object) {}
};
public:
@ -38,8 +38,10 @@ namespace nall {
R operator()(P... p) const { return (*callback)(std::forward<P>(p)...); }
function& operator=(const function &source) {
if(callback) { delete callback; callback = 0; }
if(source.callback) callback = source.callback->copy();
if(this != &source) {
if(callback) { delete callback; callback = 0; }
if(source.callback) callback = source.callback->copy();
}
return *this;
}

View File

@ -75,10 +75,11 @@ inline string xml_element::parse() const {
if(strbegin(source, "<![CDATA[")) {
if(auto pos = strpos(source, "]]>")) {
string cdata = substr(source, 9, pos() - 9);
data << cdata;
offset += strlen(cdata);
if(pos() - 9 > 0) {
string cdata = substr(source, 9, pos() - 9);
data << cdata;
offset += strlen(cdata);
}
source += 9 + offset + 3;
continue;
} else {

View File

@ -30,11 +30,14 @@ inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
struct Action : Object {
void setFont(Font &font);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
Action();
//private:
struct Data;
Data *action;
};
struct Menu : Action {

View File

@ -1,14 +1,12 @@
static void Action_setFont(GtkWidget *widget, gpointer font) {
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
if(GTK_IS_CONTAINER(widget)) {
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, font);
if(font) {
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
if(GTK_IS_CONTAINER(widget)) {
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, (PangoFontDescription*)font);
}
}
}
void Action::setFont(Font &font) {
Action_setFont(object->widget, font.font->font);
}
bool Action::visible() {
return gtk_widget_get_visible(object->widget);
}
@ -25,25 +23,35 @@ void Action::setEnabled(bool enabled) {
gtk_widget_set_sensitive(object->widget, enabled);
}
Action::Action() {
action = new Action::Data;
action->font = 0;
}
void Menu::create(Window &parent, const char *text) {
action->font = parent.window->defaultFont;
object->menu = gtk_menu_new();
object->widget = gtk_menu_item_new_with_label(text);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(object->widget), object->menu);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_bar_append(parent.object->menu, object->widget);
gtk_widget_show(object->widget);
}
void Menu::create(Menu &parent, const char *text) {
action->font = parent.action->font;
object->menu = gtk_menu_new();
object->widget = gtk_menu_item_new_with_label(text);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(object->widget), object->menu);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
void MenuSeparator::create(Menu &parent) {
action->font = parent.action->font;
object->widget = gtk_separator_menu_item_new();
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
@ -53,8 +61,10 @@ static void MenuItem_tick(MenuItem *self) {
}
void MenuItem::create(Menu &parent, const char *text) {
action->font = parent.action->font;
object->widget = gtk_menu_item_new_with_label(text);
g_signal_connect_swapped(G_OBJECT(object->widget), "activate", G_CALLBACK(MenuItem_tick), (gpointer)this);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
@ -64,8 +74,10 @@ static void MenuCheckItem_tick(MenuCheckItem *self) {
}
void MenuCheckItem::create(Menu &parent, const char *text) {
action->font = parent.action->font;
object->widget = gtk_check_menu_item_new_with_label(text);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuCheckItem_tick), (gpointer)this);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
@ -86,18 +98,22 @@ static void MenuRadioItem_tick(MenuRadioItem *self) {
void MenuRadioItem::create(Menu &parent, const char *text) {
first = this;
action->font = parent.action->font;
object->parentMenu = &parent;
object->widget = gtk_radio_menu_item_new_with_label(0, text);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuRadioItem_tick), (gpointer)this);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
first = parent.first;
action->font = parent.action->font;
object->parentMenu = parent.object->parentMenu;
object->widget = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(first->object->widget), text);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuRadioItem_tick), (gpointer)this);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(object->parentMenu->object->menu), object->widget);
gtk_widget_show(object->widget);
}

View File

@ -17,6 +17,10 @@ struct Font::Data {
PangoFontDescription *font;
};
struct Action::Data {
Font *font;
};
struct Widget::Data {
Window *parent;
};

View File

@ -3,6 +3,14 @@ void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, un
widget->parent = &parent;
gtk_widget_set_double_buffered(object->widget, false);
gtk_widget_set_size_request(object->widget, width, height);
GdkColor color;
color.pixel = 0;
color.red = 0;
color.green = 0;
color.blue = 0;
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "070.04";
static const char Version[] = "070.06";
static const unsigned SerializerVersion = 13;
}
}

View File

@ -4,7 +4,7 @@ ui_objects += $(if $(call streq,$(platform),win),resource)
# platform
ifeq ($(platform),x)
flags += -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`
phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`)
link += `pkg-config --libs gtk+-2.0`
# flags += -DPHOENIX_QT `pkg-config --cflags QtCore QtGui`
# link += `pkg-config --libs QtCore QtGui`
@ -15,13 +15,16 @@ ifeq ($(platform),x)
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx)
phoenix_compile = $(call compile,-DPHOENIX_QT)
link +=
ruby :=
ruby += audio.openal
ruby += input.carbon
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win)
flags += -DPHOENIX_WINDOWS
phoenix_compile = $(call compile,-DPHOENIX_WINDOWS)
link +=
ruby := video.direct3d video.wgl video.directdraw video.gdi
@ -54,18 +57,19 @@ rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c)
# rules
objects := $(ui_objects) $(objects)
obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/*)
obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/general/*)
obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/tools/*)
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/settings/*)
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*)
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*)
obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*)
obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/*); $(phoenix_compile)
obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/general/*); $(phoenix_compile)
obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/tools/*); $(phoenix_compile)
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/settings/*); $(phoenix_compile)
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*); $(phoenix_compile)
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*); $(phoenix_compile)
obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*); $(phoenix_compile)
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
$(call compile,$(rubydef) $(rubyflags))
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
$(phoenix_compile)
obj/resource.o: $(ui)/resource.rc
windres $(ui)/resource.rc obj/resource.o

View File

@ -22,8 +22,8 @@ void Configuration::create() {
attach(video.region = 0, "video.region");
attach(video.scale = 2, "video.scale");
attach(video.aspectRatioCorrection = true, "video.aspectRatioCorrection");
attach(video.contrast = 100, "video.contrast");
attach(video.brightness = 100, "video.brightness");
attach(video.contrast = 100, "video.contrast");
attach(video.gamma = 100, "video.gamma");
attach(video.useGammaRamp = true, "video.useGammaRamp");

View File

@ -16,8 +16,8 @@ struct Configuration : public configuration {
bool region;
unsigned scale;
bool aspectRatioCorrection;
unsigned contrast;
unsigned brightness;
unsigned contrast;
unsigned gamma;
bool useGammaRamp;
} video;

View File

@ -10,14 +10,14 @@ void VideoSettings::create() {
colorAdjustmentLabel.create(*this, x, y, 430, Style::LabelHeight, "Color Adjustment :."); y += Style::LabelHeight + 5;
colorAdjustmentLabel.setFont(application.proportionalFontBold);
contrastLabel.create (*this, x, y, 80, Style::SliderHeight, "Contrast:");
contrastValue.create (*this, x + 80, y, 50, Style::SliderHeight, "100%");
contrastSlider.create (*this, x + 130, y, 300, Style::SliderHeight, 201); y += Style::SliderHeight;
brightnessLabel.create (*this, x, y, 80, Style::SliderHeight, "Brightness:");
brightnessValue.create (*this, x + 80, y, 40, Style::SliderHeight, "100%");
brightnessSlider.create(*this, x + 130, y, 300, Style::SliderHeight, 201); y += Style::SliderHeight;
contrastLabel.create (*this, x, y, 80, Style::SliderHeight, "Contrast:");
contrastValue.create (*this, x + 80, y, 50, Style::SliderHeight, "100%");
contrastSlider.create (*this, x + 130, y, 300, Style::SliderHeight, 201); y += Style::SliderHeight;
gammaLabel.create (*this, x, y, 80, Style::SliderHeight, "Gamma:");
gammaValue.create (*this, x + 80, y, 50, Style::SliderHeight, "100%");
gammaSlider.create (*this, x + 130, y, 300, Style::SliderHeight, 201); y += Style::SliderHeight + 5;
@ -35,8 +35,8 @@ void VideoSettings::create() {
setGeometry(160, 160, 440, y);
contrastSlider.setPosition(config.video.contrast);
brightnessSlider.setPosition(config.video.brightness);
contrastSlider.setPosition(config.video.contrast);
gammaSlider.setPosition(config.video.gamma);
gammaRampCheck.setChecked(config.video.useGammaRamp);
@ -59,12 +59,12 @@ void VideoSettings::create() {
}
void VideoSettings::adjust() {
contrastValue.setText(string(contrastSlider.position(), "%"));
brightnessValue.setText(string(brightnessSlider.position(), "%"));
contrastValue.setText(string(contrastSlider.position(), "%"));
gammaValue.setText(string(gammaSlider.position(), "%"));
config.video.contrast = contrastSlider.position();
config.video.brightness = brightnessSlider.position();
config.video.contrast = contrastSlider.position();
config.video.gamma = gammaSlider.position();
config.video.useGammaRamp = gammaRampCheck.checked();
palette.update();

View File

@ -1,11 +1,11 @@
struct VideoSettings : Window {
Label colorAdjustmentLabel;
Label contrastLabel;
Label contrastValue;
HorizontalSlider contrastSlider;
Label brightnessLabel;
Label brightnessValue;
HorizontalSlider brightnessSlider;
Label contrastLabel;
Label contrastValue;
HorizontalSlider contrastSlider;
Label gammaLabel;
Label gammaValue;
HorizontalSlider gammaSlider;

View File

@ -11,41 +11,68 @@ void CheatEditor::load(string filename) {
cheatText[i][3] = "";
}
unsigned n = 0;
string data;
if(data.readfile(string(filename, ".bsv"))) {
lstring list;
list.split("\n", data);
for(unsigned i = 0; i < 128 && i < list.size(); i++) {
lstring part;
part.split("{}", list[i]);
cheatText[i][1] = part[0];
cheatText[i][2] = part[1];
cheatText[i][3] = part[2];
SNES::cheat[i].enabled = (cheatText[i][1] != " ");
SNES::cheat[i] = cheatText[i][2];
data.readfile(string(filename, ".cht"));
xml_element document = xml_parse(data);
foreach(head, document.element) {
if(head.name == "cartridge") {
foreach(node, head.element) {
if(node.name == "cheat") {
bool enabled = false;
string description;
string code;
foreach(attribute, node.attribute) {
if(attribute.name == "enabled") enabled = (attribute.parse() == "true");
}
foreach(element, node.element) {
if(element.name == "description") description = element.parse();
else if(element.name == "code") code.append(string(element.parse(), "+"));
}
code.rtrim("+");
SNES::cheat[n].enabled = enabled;
SNES::cheat[n] = code;
cheatText[n][1] = (enabled == false ? " " : "*");
cheatText[n][2] = code;
cheatText[n][3] = description;
if(++n >= 128) break;
}
}
}
}
refresh();
synchronize();
}
void CheatEditor::save(string filename) {
bool savesPresent = false;
for(unsigned i = 0; i < 128; i++) {
signed lastSave = -1;
for(signed i = 127; i >= 0; i--) {
if(cheatText[i][2] != "" || cheatText[i][3] != "") {
savesPresent = true;
lastSave = i;
break;
}
}
if(savesPresent == false) {
unlink(string(filename, ".bsv"));
if(lastSave == -1) {
unlink(string(filename, ".cht"));
return;
}
file fp;
if(fp.open(string(filename, ".bsv"), file::mode_write)) {
for(unsigned i = 0; i < 128; i++) {
fp.print(string(cheatText[i][1], "{}", cheatText[i][2], "{}", cheatText[i][3], "\n"));
if(fp.open(string(filename, ".cht"), file::mode_write)) {
fp.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
fp.print(string("<cartridge sha256=\"", SNES::cartridge.sha256(), "\">\n"));
for(unsigned i = 0; i <= lastSave; i++) {
fp.print(string(" <cheat enabled=\"", cheatText[i][1] == " " ? "false" : "true", "\">\n"));
fp.print(string(" <description><![CDATA[", cheatText[i][3], "]]></description>\n"));
lstring list;
list.split("+", cheatText[i][2]);
foreach(code, list) {
fp.print(string(" <code>", code, "</code>\n"));
}
fp.print(string(" </cheat>\n"));
}
fp.print("</cartridge>\n");
fp.close();
}
@ -58,9 +85,9 @@ void CheatEditor::create() {
Window::create(0, 0, 256, 256, "Cheat Editor");
setDefaultFont(application.proportionalFont);
unsigned x = 5, y = 5;
unsigned x = 5, y = 5, height = Style::ButtonHeight;
cheatList.create(*this, x, y, 500, 250, "Slot\tOn\tCode\tDescription"); y += 255;
cheatList.create(*this, x, y, 500, 250, "Slot\tCode\tDescription"); y += 255;
cheatList.setHeaderVisible();
codeLabel.create(*this, x, y, 80, Style::TextBoxHeight, "Code(s):");
@ -69,25 +96,33 @@ void CheatEditor::create() {
descLabel.create(*this, x, y, 80, Style::TextBoxHeight, "Description:");
descEdit.create (*this, x + 80, y, 420, Style::TextBoxHeight); y+= Style::TextBoxHeight + 5;
clearAllButton.create(*this, x + 505 - 85 - 85, y, 80, height, "Clear All");
clearButton.create(*this, x + 505 - 85, y, 80, height, "Clear"); y += height + 5;
setGeometry(160, 160, 510, y);
synchronize();
cheatList.onActivate = { &CheatEditor::toggle, this };
cheatList.onChange = { &CheatEditor::synchronize, this };
codeEdit.onChange = descEdit.onChange = { &CheatEditor::bind, this };
clearAllButton.onTick = { &CheatEditor::clearAll, this };
clearButton.onTick = { &CheatEditor::clear, this };
}
void CheatEditor::synchronize() {
clearAllButton.setEnabled(SNES::cartridge.loaded());
if(auto position = cheatList.selection()) {
codeEdit.setText(cheatText[position()][2]);
descEdit.setText(cheatText[position()][3]);
codeEdit.setEnabled(true);
descEdit.setEnabled(true);
clearButton.setEnabled(true);
} else {
codeEdit.setText("");
descEdit.setText("");
codeEdit.setEnabled(false);
descEdit.setEnabled(false);
clearButton.setEnabled(false);
}
}
@ -100,7 +135,7 @@ void CheatEditor::refresh() {
if(list.size() > 1) cheatCode.append("...");
cheatList.setItem(i, string(
cheatText[i][0], "\t", cheatText[i][1], "\t", cheatCode, "\t", cheatText[i][3]
cheatText[i][0], cheatText[i][1], "\t", cheatCode, "\t", cheatText[i][3]
));
}
cheatList.resizeColumnsToContent();
@ -109,7 +144,7 @@ void CheatEditor::refresh() {
void CheatEditor::toggle() {
if(auto position = cheatList.selection()) {
if(cheatText[position()][1] == " ") {
cheatText[position()][1] = "X";
cheatText[position()][1] = "*";
SNES::cheat[position()].enabled = true;
} else {
cheatText[position()][1] = " ";
@ -127,3 +162,33 @@ void CheatEditor::bind() {
refresh();
}
}
void CheatEditor::clearAll() {
if(MessageWindow::question(cheatEditor, "Permanently erase all entered cheat codes?", MessageWindow::Buttons::YesNo) == MessageWindow::Response::Yes) {
for(unsigned i = 0; i < 128; i++) {
SNES::cheat[i].enabled = false;
SNES::cheat[i] = "";
cheatText[i][1] = " ";
cheatText[i][2] = "";
cheatText[i][3] = "";
}
SNES::cheat.synchronize();
refresh();
codeEdit.setText("");
descEdit.setText("");
}
}
void CheatEditor::clear() {
if(auto position = cheatList.selection()) {
SNES::cheat[position()].enabled = false;
SNES::cheat[position()] = "";
cheatText[position()][1] = " ";
cheatText[position()][2] = "";
cheatText[position()][3] = "";
SNES::cheat.synchronize();
refresh();
codeEdit.setText("");
descEdit.setText("");
}
}

View File

@ -4,6 +4,8 @@ struct CheatEditor : Window {
TextBox codeEdit;
Label descLabel;
TextBox descEdit;
Button clearAllButton;
Button clearButton;
void load(string filename);
void save(string filename);
@ -15,6 +17,8 @@ private:
void refresh();
void toggle();
void bind();
void clearAll();
void clear();
};
extern CheatEditor cheatEditor;