mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-27 19:10:44 +00:00
Update to v070r10 release.
byuu says: - added workaround to phoenix/Windows to prevent horizontal scrollbar always being visible on single-column ListBoxes - phoenix gains Window::geometry() - added code to save and restore window positions, as in bsnes/Qt. Positions are saved to bsnes-phoenix-geometry.cfg this time - resizing the main window will keep its position onscreen now There's one issue with GTK+, if you close a window and then call gtk_window_get_position(), it returns the previously set position rather than where you actually placed the window. My easy fix of calling gtk_window_get_position right before actually closing the window didn't work, so for now you'll have to live with it.
This commit is contained in:
parent
8a53e9ed22
commit
e2db2c24fc
@ -145,7 +145,7 @@ namespace nall {
|
||||
break;
|
||||
}
|
||||
|
||||
p_fd = ::open(filename, open_flags);
|
||||
p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
if(p_fd < 0) return false;
|
||||
|
||||
struct stat p_stat;
|
||||
|
@ -1,190 +1,221 @@
|
||||
#ifndef NALL_UPS_HPP
|
||||
#define NALL_UPS_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/crc32.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
namespace nall {
|
||||
class ups {
|
||||
public:
|
||||
enum result {
|
||||
ok,
|
||||
patch_unreadable,
|
||||
patch_unwritable,
|
||||
patch_invalid,
|
||||
input_invalid,
|
||||
output_invalid,
|
||||
patch_crc32_invalid,
|
||||
input_crc32_invalid,
|
||||
output_crc32_invalid,
|
||||
};
|
||||
|
||||
ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) {
|
||||
if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable;
|
||||
struct ups {
|
||||
enum class result_t : unsigned {
|
||||
unknown,
|
||||
success,
|
||||
patch_unwritable,
|
||||
patch_invalid,
|
||||
source_invalid,
|
||||
target_invalid,
|
||||
target_too_small,
|
||||
patch_checksum_invalid,
|
||||
source_checksum_invalid,
|
||||
target_checksum_invalid,
|
||||
};
|
||||
|
||||
crc32 = ~0;
|
||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
||||
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
|
||||
function<void (unsigned offset, unsigned length)> progress;
|
||||
|
||||
//header
|
||||
write('U');
|
||||
write('P');
|
||||
write('S');
|
||||
write('1');
|
||||
encptr(x_size);
|
||||
encptr(y_size);
|
||||
result_t create(
|
||||
const uint8_t *source_data_, unsigned source_length_,
|
||||
const uint8_t *target_data_, unsigned target_length_,
|
||||
const char *patch_filename
|
||||
) {
|
||||
source_data = (uint8_t*)source_data_, target_data = (uint8_t*)target_data_;
|
||||
source_length = source_length_, target_length = target_length_;
|
||||
source_offset = target_offset = 0;
|
||||
source_checksum = target_checksum = patch_checksum = ~0;
|
||||
|
||||
//body
|
||||
unsigned max_size = max(x_size, y_size);
|
||||
unsigned relative = 0;
|
||||
for(unsigned i = 0; i < max_size;) {
|
||||
uint8_t x = i < x_size ? x_data[i] : 0x00;
|
||||
uint8_t y = i < y_size ? y_data[i] : 0x00;
|
||||
if(patch_file.open(patch_filename, file::mode_write) == false) return result_t::patch_unwritable;
|
||||
|
||||
if(x == y) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
patch_write('U');
|
||||
patch_write('P');
|
||||
patch_write('S');
|
||||
patch_write('1');
|
||||
encode(source_length);
|
||||
encode(target_length);
|
||||
|
||||
encptr(i++ - relative);
|
||||
write(x ^ y);
|
||||
unsigned output_length = source_length > target_length ? source_length : target_length;
|
||||
unsigned relative = 0;
|
||||
for(unsigned offset = 0; offset < output_length;) {
|
||||
uint8_t x = source_read();
|
||||
uint8_t y = target_read();
|
||||
|
||||
while(true) {
|
||||
if(i >= max_size) {
|
||||
write(0x00);
|
||||
break;
|
||||
}
|
||||
|
||||
x = i < x_size ? x_data[i] : 0x00;
|
||||
y = i < y_size ? y_data[i] : 0x00;
|
||||
i++;
|
||||
write(x ^ y);
|
||||
if(x == y) break;
|
||||
}
|
||||
|
||||
relative = i;
|
||||
if(x == y) {
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//footer
|
||||
for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3));
|
||||
for(unsigned i = 0; i < 4; i++) write(y_crc32 >> (i << 3));
|
||||
uint32_t p_crc32 = ~crc32;
|
||||
for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3));
|
||||
encode(offset++ - relative);
|
||||
patch_write(x ^ y);
|
||||
|
||||
fp.close();
|
||||
return ok;
|
||||
}
|
||||
|
||||
ups::result apply(const uint8_t *p_data, unsigned p_size, const uint8_t *x_data, unsigned x_size, uint8_t *&y_data, unsigned &y_size) {
|
||||
if(p_size < 18) return patch_invalid;
|
||||
p_buffer = p_data;
|
||||
|
||||
crc32 = ~0;
|
||||
|
||||
//header
|
||||
if(read() != 'U') return patch_invalid;
|
||||
if(read() != 'P') return patch_invalid;
|
||||
if(read() != 'S') return patch_invalid;
|
||||
if(read() != '1') return patch_invalid;
|
||||
|
||||
unsigned px_size = decptr();
|
||||
unsigned py_size = decptr();
|
||||
|
||||
//mirror
|
||||
if(x_size != px_size && x_size != py_size) return input_invalid;
|
||||
y_size = (x_size == px_size) ? py_size : px_size;
|
||||
y_data = new uint8_t[y_size]();
|
||||
|
||||
for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i];
|
||||
for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00;
|
||||
|
||||
//body
|
||||
unsigned relative = 0;
|
||||
while(p_buffer < p_data + p_size - 12) {
|
||||
relative += decptr();
|
||||
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
if(x && relative < y_size) {
|
||||
uint8_t y = relative < x_size ? x_data[relative] : 0x00;
|
||||
y_data[relative] = x ^ y;
|
||||
}
|
||||
relative++;
|
||||
if(!x) break;
|
||||
}
|
||||
}
|
||||
|
||||
//footer
|
||||
unsigned px_crc32 = 0, py_crc32 = 0, pp_crc32 = 0;
|
||||
for(unsigned i = 0; i < 4; i++) px_crc32 |= read() << (i << 3);
|
||||
for(unsigned i = 0; i < 4; i++) py_crc32 |= read() << (i << 3);
|
||||
uint32_t p_crc32 = ~crc32;
|
||||
for(unsigned i = 0; i < 4; i++) pp_crc32 |= read() << (i << 3);
|
||||
|
||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
||||
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
|
||||
|
||||
if(px_size != py_size) {
|
||||
if(x_size == px_size && x_crc32 != px_crc32) return input_crc32_invalid;
|
||||
if(x_size == py_size && x_crc32 != py_crc32) return input_crc32_invalid;
|
||||
if(y_size == px_size && y_crc32 != px_crc32) return output_crc32_invalid;
|
||||
if(y_size == py_size && y_crc32 != py_crc32) return output_crc32_invalid;
|
||||
} else {
|
||||
if(x_crc32 != px_crc32 && x_crc32 != py_crc32) return input_crc32_invalid;
|
||||
if(y_crc32 != px_crc32 && y_crc32 != py_crc32) return output_crc32_invalid;
|
||||
if(x_crc32 == y_crc32 && px_crc32 != py_crc32) return output_crc32_invalid;
|
||||
if(x_crc32 != y_crc32 && px_crc32 == py_crc32) return output_crc32_invalid;
|
||||
}
|
||||
|
||||
if(p_crc32 != pp_crc32) return patch_crc32_invalid;
|
||||
return ok;
|
||||
}
|
||||
|
||||
private:
|
||||
file fp;
|
||||
uint32_t crc32;
|
||||
const uint8_t *p_buffer;
|
||||
|
||||
uint8_t read() {
|
||||
uint8_t n = *p_buffer++;
|
||||
crc32 = crc32_adjust(crc32, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
void write(uint8_t n) {
|
||||
fp.write(n);
|
||||
crc32 = crc32_adjust(crc32, n);
|
||||
}
|
||||
|
||||
void encptr(uint64_t offset) {
|
||||
while(true) {
|
||||
uint64_t x = offset & 0x7f;
|
||||
offset >>= 7;
|
||||
if(offset == 0) {
|
||||
write(0x80 | x);
|
||||
if(offset >= output_length) {
|
||||
patch_write(0x00);
|
||||
break;
|
||||
}
|
||||
write(x);
|
||||
offset--;
|
||||
|
||||
x = source_read();
|
||||
y = target_read();
|
||||
offset++;
|
||||
patch_write(x ^ y);
|
||||
if(x == y) break;
|
||||
}
|
||||
|
||||
relative = offset;
|
||||
}
|
||||
|
||||
source_checksum = ~source_checksum;
|
||||
target_checksum = ~target_checksum;
|
||||
for(unsigned i = 0; i < 4; i++) patch_write(source_checksum >> (i * 8));
|
||||
for(unsigned i = 0; i < 4; i++) patch_write(target_checksum >> (i * 8));
|
||||
uint32_t patch_result_checksum = ~patch_checksum;
|
||||
for(unsigned i = 0; i < 4; i++) patch_write(patch_result_checksum >> (i * 8));
|
||||
|
||||
patch_file.close();
|
||||
return result_t::success;
|
||||
}
|
||||
|
||||
result_t apply(
|
||||
const uint8_t *patch_data_, unsigned patch_length_,
|
||||
const uint8_t *source_data_, unsigned source_length_,
|
||||
uint8_t *target_data_, unsigned &target_length_
|
||||
) {
|
||||
patch_data = (uint8_t*)patch_data_, source_data = (uint8_t*)source_data_, target_data = target_data_;
|
||||
patch_length = patch_length_, source_length = source_length_, target_length = target_length_;
|
||||
patch_offset = source_offset = target_offset = 0;
|
||||
patch_checksum = source_checksum = target_checksum = ~0;
|
||||
|
||||
if(patch_length < 18) return result_t::patch_invalid;
|
||||
if(patch_read() != 'U') return result_t::patch_invalid;
|
||||
if(patch_read() != 'P') return result_t::patch_invalid;
|
||||
if(patch_read() != 'S') return result_t::patch_invalid;
|
||||
if(patch_read() != '1') return result_t::patch_invalid;
|
||||
|
||||
unsigned source_read_length = decode();
|
||||
unsigned target_read_length = decode();
|
||||
|
||||
if(source_length != source_read_length && source_length != target_read_length) return result_t::source_invalid;
|
||||
target_length_ = (source_length == source_read_length ? target_read_length : source_read_length);
|
||||
if(target_length < target_length_) return result_t::target_too_small;
|
||||
target_length = target_length_;
|
||||
|
||||
while(patch_offset < patch_length - 12) {
|
||||
unsigned length = decode();
|
||||
while(length--) target_write(source_read());
|
||||
while(true) {
|
||||
uint8_t patch_xor = patch_read();
|
||||
target_write(patch_xor ^ source_read());
|
||||
if(patch_xor == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t decptr() {
|
||||
uint64_t offset = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
offset += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
offset += shift;
|
||||
}
|
||||
return offset;
|
||||
uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0;
|
||||
for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8);
|
||||
for(unsigned i = 0; i < 4; i++) target_read_checksum |= patch_read() << (i * 8);
|
||||
uint32_t patch_result_checksum = ~patch_checksum;
|
||||
source_checksum = ~source_checksum;
|
||||
target_checksum = ~target_checksum;
|
||||
for(unsigned i = 0; i < 4; i++) patch_read_checksum |= patch_read() << (i * 8);
|
||||
|
||||
if(patch_result_checksum != patch_read_checksum) return result_t::patch_invalid;
|
||||
if(source_checksum == source_read_checksum && source_length == source_read_length) {
|
||||
if(target_checksum == target_read_checksum && target_length == target_read_length) return result_t::success;
|
||||
return result_t::target_invalid;
|
||||
} else if(source_checksum == target_read_checksum && source_length == target_read_length) {
|
||||
if(target_checksum == source_read_checksum && target_length == source_read_length) return result_t::success;
|
||||
return result_t::target_invalid;
|
||||
} else {
|
||||
return result_t::source_invalid;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t *patch_data, *source_data, *target_data;
|
||||
unsigned patch_length, source_length, target_length;
|
||||
unsigned patch_offset, source_offset, target_offset;
|
||||
unsigned patch_checksum, source_checksum, target_checksum;
|
||||
file patch_file;
|
||||
|
||||
uint8_t patch_read() {
|
||||
if(patch_offset < patch_length) {
|
||||
uint8_t n = patch_data[patch_offset++];
|
||||
patch_checksum = crc32_adjust(patch_checksum, n);
|
||||
return n;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
uint8_t source_read() {
|
||||
if(source_offset < source_length) {
|
||||
uint8_t n = source_data[source_offset++];
|
||||
source_checksum = crc32_adjust(source_checksum, n);
|
||||
return n;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
uint8_t target_read() {
|
||||
uint8_t result = 0x00;
|
||||
if(target_offset < target_length) {
|
||||
result = target_data[target_offset];
|
||||
target_checksum = crc32_adjust(target_checksum, result);
|
||||
}
|
||||
if(((target_offset++ & 255) == 0) && progress) {
|
||||
progress(target_offset, source_length > target_length ? source_length : target_length);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void patch_write(uint8_t n) {
|
||||
patch_file.write(n);
|
||||
patch_checksum = crc32_adjust(patch_checksum, n);
|
||||
}
|
||||
|
||||
void target_write(uint8_t n) {
|
||||
if(target_offset < target_length) {
|
||||
target_data[target_offset] = n;
|
||||
target_checksum = crc32_adjust(target_checksum, n);
|
||||
}
|
||||
if(((target_offset++ & 255) == 0) && progress) {
|
||||
progress(target_offset, source_length > target_length ? source_length : target_length);
|
||||
}
|
||||
}
|
||||
|
||||
void encode(uint64_t offset) {
|
||||
while(true) {
|
||||
uint64_t x = offset & 0x7f;
|
||||
offset >>= 7;
|
||||
if(offset == 0) {
|
||||
patch_write(0x80 | x);
|
||||
break;
|
||||
}
|
||||
patch_write(x);
|
||||
offset--;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t decode() {
|
||||
uint64_t offset = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = patch_read();
|
||||
offset += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
offset += shift;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -12,6 +12,13 @@ struct Object {
|
||||
Data *object;
|
||||
};
|
||||
|
||||
struct Geometry {
|
||||
unsigned x, y;
|
||||
unsigned width, height;
|
||||
inline Geometry() : x(0), y(0), width(0), height(0) {}
|
||||
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
@ -91,6 +98,7 @@ struct Window : Widget {
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool focused();
|
||||
void setFocused();
|
||||
Geometry geometry();
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setDefaultFont(Font &font);
|
||||
void setFont(Font &font);
|
||||
@ -188,7 +196,7 @@ struct ListBox : Widget {
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setProgress(unsigned progress);
|
||||
void setPosition(unsigned position);
|
||||
};
|
||||
|
||||
struct RadioBox : Widget {
|
||||
|
@ -6,7 +6,7 @@ void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width,
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
progress = progress <= 100 ? progress : 0;
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(object->widget), (double)progress / 100.0);
|
||||
void ProgressBar::setPosition(unsigned position) {
|
||||
position = position <= 100 ? position : 0;
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(object->widget), (double)position / 100.0);
|
||||
}
|
||||
|
@ -47,6 +47,13 @@ void Window::setFocused() {
|
||||
gtk_window_present(GTK_WINDOW(object->widget));
|
||||
}
|
||||
|
||||
Geometry Window::geometry() {
|
||||
gint x, y, width, height;
|
||||
gtk_window_get_position(GTK_WINDOW(object->widget), &x, &y);
|
||||
gtk_widget_get_size_request(object->formContainer, &width, &height);
|
||||
return Geometry(x, y, width, height);
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
gtk_window_move(GTK_WINDOW(object->widget), x, y);
|
||||
gtk_widget_set_size_request(object->formContainer, width, height);
|
||||
|
@ -6,8 +6,8 @@ void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width,
|
||||
progressBar->show();
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
progressBar->setValue(progress);
|
||||
void ProgressBar::setPosition(unsigned position) {
|
||||
progressBar->setValue(position);
|
||||
}
|
||||
|
||||
ProgressBar::ProgressBar() {
|
||||
|
@ -12,6 +12,13 @@ struct Object {
|
||||
Data *object;
|
||||
};
|
||||
|
||||
struct Geometry {
|
||||
unsigned x, y;
|
||||
unsigned width, height;
|
||||
inline Geometry() : x(0), y(0), width(0), height(0) {}
|
||||
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
@ -123,6 +130,7 @@ struct Widget : Object {
|
||||
struct Window : Widget {
|
||||
nall::function<bool ()> onClose;
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
Geometry geometry();
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setDefaultFont(Font &font);
|
||||
void setFont(Font &font);
|
||||
@ -240,7 +248,7 @@ struct ListBox : Widget {
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setProgress(unsigned progress);
|
||||
void setPosition(unsigned position);
|
||||
ProgressBar();
|
||||
//private:
|
||||
struct Data;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
** Meta object code from reading C++ file 'qt.moc.hpp'
|
||||
**
|
||||
** Created: Mon Oct 4 00:53:54 2010
|
||||
** Created: Wed Oct 6 18:50:06 2010
|
||||
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
|
@ -23,6 +23,10 @@ void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, con
|
||||
window->layout->addWidget(window->statusBar);
|
||||
}
|
||||
|
||||
Geometry Window::geometry() {
|
||||
return Geometry(window->x(), window->y(), window->container->width(), window->container->height());
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
window->container->setFixedSize(width, height);
|
||||
window->move(x, y);
|
||||
|
@ -65,6 +65,9 @@ void ListBox::addItem(const char *text) {
|
||||
utf16_t wtext(list[i]);
|
||||
ListView_SetItemText(widget->window, row, i, wtext);
|
||||
}
|
||||
|
||||
//workaround: when there is only one column, the horizontal scrollbar will always appear without this
|
||||
if(listBox->columns == 1) ListView_SetColumnWidth(widget->window, 0, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
|
||||
void ListBox::setItem(unsigned row, const char *text) {
|
||||
@ -74,6 +77,9 @@ void ListBox::setItem(unsigned row, const char *text) {
|
||||
utf16_t wtext(list[i]);
|
||||
ListView_SetItemText(widget->window, row, i, wtext);
|
||||
}
|
||||
|
||||
//workaround: when there is only one column, the horizontal scrollbar will always appear without this
|
||||
if(listBox->columns == 1) ListView_SetColumnWidth(widget->window, 0, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
|
||||
optional<unsigned> ListBox::selection() {
|
||||
|
@ -9,10 +9,10 @@ void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width,
|
||||
SendMessage(widget->window, PBM_SETSTEP, MAKEWPARAM(1, 0), 0);
|
||||
}
|
||||
|
||||
unsigned ProgressBar::progress() {
|
||||
unsigned ProgressBar::position() {
|
||||
return SendMessage(widget->window, PBM_GETPOS, 0, 0);
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
SendMessage(widget->window, PBM_SETPOS, (WPARAM)progress, 0);
|
||||
void ProgressBar::setPosition(unsigned position) {
|
||||
SendMessage(widget->window, PBM_SETPOS, (WPARAM)position, 0);
|
||||
}
|
||||
|
@ -26,6 +26,18 @@ void Window::setFont(Font &font) {
|
||||
SendMessage(window->status, WM_SETFONT, (WPARAM)font.font->font, 0);
|
||||
}
|
||||
|
||||
Geometry Window::geometry() {
|
||||
RECT position, size;
|
||||
GetWindowRect(widget->window, &position);
|
||||
GetClientRect(widget->window, &size);
|
||||
if(GetWindowLongPtr(window->status, GWL_STYLE) & WS_VISIBLE) {
|
||||
RECT status;
|
||||
GetClientRect(window->status, &status);
|
||||
size.bottom -= status.bottom - status.top;
|
||||
}
|
||||
return Geometry(position.left, position.top, size.right, size.bottom);
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
bool isVisible = visible();
|
||||
if(isVisible) setVisible(false);
|
||||
|
@ -11,6 +11,13 @@ private:
|
||||
virtual void unused();
|
||||
};
|
||||
|
||||
struct Geometry {
|
||||
unsigned x, y;
|
||||
unsigned width, height;
|
||||
inline Geometry() : x(0), y(0), width(0), height(0) {}
|
||||
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
@ -96,6 +103,7 @@ struct Window : Widget {
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setDefaultFont(Font &font);
|
||||
void setFont(Font &font);
|
||||
Geometry geometry();
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setTitle(const char *text);
|
||||
@ -198,8 +206,8 @@ struct ListBox : Widget {
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
unsigned progress();
|
||||
void setProgress(unsigned progress);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
};
|
||||
|
||||
struct RadioBox : Widget {
|
||||
|
@ -1,7 +1,7 @@
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "070.09";
|
||||
static const char Version[] = "070.10";
|
||||
static const unsigned SerializerVersion = 13;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,11 @@ using namespace ruby;
|
||||
#include <phoenix/phoenix.hpp>
|
||||
using namespace phoenix;
|
||||
|
||||
struct TopLevelWindow : Window {
|
||||
string name;
|
||||
string position;
|
||||
};
|
||||
|
||||
#include "interface.hpp"
|
||||
#include "config.hpp"
|
||||
#include "general/general.hpp"
|
||||
@ -24,13 +29,20 @@ using namespace phoenix;
|
||||
#include "cartridge/cartridge.hpp"
|
||||
|
||||
struct Application {
|
||||
array<Window*> windows;
|
||||
Font proportionalFont;
|
||||
Font proportionalFontBold;
|
||||
Font monospaceFont;
|
||||
|
||||
bool quit;
|
||||
void main(int argc, char **argv);
|
||||
|
||||
void addWindow(TopLevelWindow *window, const string &name, const string &position);
|
||||
|
||||
private:
|
||||
array<TopLevelWindow*> windows;
|
||||
configuration geometryConfig;
|
||||
void loadGeometry();
|
||||
void saveGeometry();
|
||||
};
|
||||
|
||||
extern Application application;
|
||||
|
@ -1,9 +1,8 @@
|
||||
FileBrowser fileBrowser;
|
||||
|
||||
void FileBrowser::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256);
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "FileBrowser", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5, height = Style::TextBoxHeight;
|
||||
|
||||
@ -13,7 +12,7 @@ void FileBrowser::create() {
|
||||
|
||||
contentsBox.create(*this, x, y, 630, 350); y += 350 + 5;
|
||||
|
||||
setGeometry(160, 160, 640, y);
|
||||
setGeometry(0, 0, 640, y);
|
||||
|
||||
pathBox.onActivate = []() { fileBrowser.setFolder(fileBrowser.pathBox.text()); };
|
||||
browseButton.onTick = { &FileBrowser::folderBrowse, this };
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct FileBrowser : Window {
|
||||
struct FileBrowser : TopLevelWindow {
|
||||
TextBox pathBox;
|
||||
Button browseButton;
|
||||
Button upButton;
|
||||
|
@ -1,9 +1,8 @@
|
||||
MainWindow mainWindow;
|
||||
|
||||
void MainWindow::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(128, 128, 595, 448, string(SNES::Info::Name, " v", SNES::Info::Version));
|
||||
setDefaultFont(application.proportionalFont);
|
||||
Window::create(0, 0, 595, 448, string(SNES::Info::Name, " v", SNES::Info::Version));
|
||||
application.addWindow(this, "MainWindow", "128,128");
|
||||
setFont(application.proportionalFontBold);
|
||||
setBackgroundColor(0, 0, 0);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct MainWindow : Window {
|
||||
struct MainWindow : TopLevelWindow {
|
||||
Menu system;
|
||||
MenuItem systemLoadCartridge;
|
||||
Menu systemLoadCartridgeSpecial;
|
||||
|
@ -2,9 +2,8 @@ SingleSlotLoader singleSlotLoader;
|
||||
DoubleSlotLoader doubleSlotLoader;
|
||||
|
||||
void SingleSlotLoader::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256);
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "SingleSlotLoader", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5, height = Style::TextBoxHeight, width = 365 + height;
|
||||
|
||||
@ -18,7 +17,7 @@ void SingleSlotLoader::create() {
|
||||
|
||||
okButton.create(*this, x + width - 90, y, 80, Style::ButtonHeight, "Ok"); y += Style::ButtonHeight + 5;
|
||||
|
||||
setGeometry(160, 160, width, y);
|
||||
setGeometry(0, 0, width, y);
|
||||
|
||||
baseBrowse.onTick = []() {
|
||||
fileBrowser.fileOpen(FileBrowser::Mode::Cartridge, [](string filename) {
|
||||
@ -88,9 +87,8 @@ void SingleSlotLoader::load() {
|
||||
//
|
||||
|
||||
void DoubleSlotLoader::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256);
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "DoubleSlotLoader", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5, height = Style::TextBoxHeight, width = 365 + height;
|
||||
|
||||
@ -108,7 +106,7 @@ void DoubleSlotLoader::create() {
|
||||
|
||||
okButton.create(*this, x + width - 90, y, 80, Style::ButtonHeight, "Ok"); y += Style::ButtonHeight + 5;
|
||||
|
||||
setGeometry(160, 160, width, y);
|
||||
setGeometry(0, 0, width, y);
|
||||
|
||||
baseBrowse.onTick = []() {
|
||||
fileBrowser.fileOpen(FileBrowser::Mode::Cartridge, [](string filename) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct SingleSlotLoader : Window {
|
||||
struct SingleSlotLoader : TopLevelWindow {
|
||||
Label baseLabel;
|
||||
TextBox basePath;
|
||||
Button baseBrowse;
|
||||
@ -16,7 +16,7 @@ struct SingleSlotLoader : Window {
|
||||
void load();
|
||||
};
|
||||
|
||||
struct DoubleSlotLoader : Window {
|
||||
struct DoubleSlotLoader : TopLevelWindow {
|
||||
Label baseLabel;
|
||||
TextBox basePath;
|
||||
Button baseBrowse;
|
||||
|
@ -40,6 +40,7 @@ void Application::main(int argc, char **argv) {
|
||||
if(config.input.driver == "") config.input.driver = input.default_driver();
|
||||
|
||||
palette.update();
|
||||
|
||||
mainWindow.create();
|
||||
fileBrowser.create();
|
||||
singleSlotLoader.create();
|
||||
@ -50,6 +51,9 @@ void Application::main(int argc, char **argv) {
|
||||
advancedSettings.create();
|
||||
cheatEditor.create();
|
||||
stateManager.create();
|
||||
loadGeometry();
|
||||
saveGeometry();
|
||||
|
||||
utility.setScale(config.video.scale);
|
||||
mainWindow.setVisible();
|
||||
OS::run();
|
||||
@ -111,6 +115,7 @@ void Application::main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
cartridge.unload();
|
||||
saveGeometry();
|
||||
foreach(window, windows) window->setVisible(false);
|
||||
OS::run();
|
||||
SNES::system.term();
|
||||
@ -121,7 +126,33 @@ void Application::main(int argc, char **argv) {
|
||||
input.term();
|
||||
}
|
||||
|
||||
void Application::addWindow(TopLevelWindow *window, const string &name, const string &position) {
|
||||
windows.append(window);
|
||||
window->setDefaultFont(proportionalFont);
|
||||
window->name = name;
|
||||
window->position = position;
|
||||
geometryConfig.attach(window->position, window->name);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
application.main(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Application::loadGeometry() {
|
||||
geometryConfig.load(string(config.path.user, "bsnes-phoenix-geometry.cfg"));
|
||||
foreach(window, windows) {
|
||||
lstring position;
|
||||
position.split(",", window->position);
|
||||
Geometry geom = window->geometry();
|
||||
window->setGeometry(strunsigned(position[0]), strunsigned(position[1]), geom.width, geom.height);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::saveGeometry() {
|
||||
foreach(window, windows) {
|
||||
Geometry geom = window->geometry();
|
||||
window->position = string(geom.x, ",", geom.y);
|
||||
}
|
||||
geometryConfig.save(string(config.path.user, "bsnes-phoenix-geometry.cfg"));
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
AdvancedSettings advancedSettings;
|
||||
|
||||
void AdvancedSettings::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256, "Advanced Settings");
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "AdvancedSettings", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5;
|
||||
|
||||
@ -27,7 +26,7 @@ void AdvancedSettings::create() {
|
||||
if(config.settings.focusPolicy == 1) focusPolicyIgnore.setChecked();
|
||||
if(config.settings.focusPolicy == 2) focusPolicyAllow.setChecked();
|
||||
|
||||
setGeometry(160, 160, 605, y);
|
||||
setGeometry(0, 0, 605, y);
|
||||
|
||||
lstring list;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct AdvancedSettings : Window {
|
||||
struct AdvancedSettings : TopLevelWindow {
|
||||
Label driverSelectionLabel;
|
||||
Label videoDriverLabel;
|
||||
ComboBox videoDriverBox;
|
||||
|
@ -1,9 +1,8 @@
|
||||
AudioSettings audioSettings;
|
||||
|
||||
void AudioSettings::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256, "Audio Settings");
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "AudioSettings", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5;
|
||||
|
||||
@ -29,5 +28,5 @@ void AudioSettings::create() {
|
||||
audioSettings.frequencyValue.setText(string(config.audio.inputFrequency, "hz"));
|
||||
};
|
||||
|
||||
setGeometry(160, 160, 440, y);
|
||||
setGeometry(0, 0, 440, y);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct AudioSettings : Window {
|
||||
struct AudioSettings : TopLevelWindow {
|
||||
Label volumeLabel;
|
||||
Label volumeValue;
|
||||
HorizontalSlider volumeSlider;
|
||||
|
@ -2,9 +2,8 @@ InputSettings inputSettings;
|
||||
static InputMapper::AbstractInput *activeInput = 0;
|
||||
|
||||
void InputSettings::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256, "Input Settings");
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "InputSettings", "160,160");
|
||||
setFont(application.proportionalFontBold);
|
||||
setStatusVisible();
|
||||
|
||||
@ -38,7 +37,7 @@ void InputSettings::create() {
|
||||
clearButton.create(*this, 515 - 85, y, 80, height, "Clear");
|
||||
y += height + 5;
|
||||
|
||||
setGeometry(160, 160, 515, y);
|
||||
setGeometry(0, 0, 515, y);
|
||||
|
||||
refreshDevices();
|
||||
portBox.onChange = { &InputSettings::refreshDevices, this };
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct InputSettings : Window {
|
||||
struct InputSettings : TopLevelWindow {
|
||||
Label portLabel;
|
||||
ComboBox portBox;
|
||||
Label deviceLabel;
|
||||
|
@ -1,9 +1,8 @@
|
||||
VideoSettings videoSettings;
|
||||
|
||||
void VideoSettings::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256, "Video Settings");
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "VideoSettings", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5, height = Style::TextBoxHeight;
|
||||
|
||||
@ -33,7 +32,7 @@ void VideoSettings::create() {
|
||||
shaderClear.create(*this, x + 430 - height - height - 5, y, height, height, "");
|
||||
shaderSelect.create(*this, x + 430 - height, y, height, height, "..."); y += height + 5;
|
||||
|
||||
setGeometry(160, 160, 440, y);
|
||||
setGeometry(0, 0, 440, y);
|
||||
|
||||
brightnessSlider.setPosition(config.video.brightness);
|
||||
contrastSlider.setPosition(config.video.contrast);
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct VideoSettings : Window {
|
||||
struct VideoSettings : TopLevelWindow {
|
||||
Label colorAdjustmentLabel;
|
||||
Label brightnessLabel;
|
||||
Label brightnessValue;
|
||||
|
@ -79,9 +79,8 @@ void CheatEditor::save(string filename) {
|
||||
}
|
||||
|
||||
void CheatEditor::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256, "Cheat Editor");
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "CheatEditor", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5, height = Style::ButtonHeight;
|
||||
|
||||
@ -99,7 +98,7 @@ void CheatEditor::create() {
|
||||
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);
|
||||
setGeometry(0, 0, 510, y);
|
||||
synchronize();
|
||||
|
||||
cheatList.onChange = { &CheatEditor::synchronize, this };
|
||||
@ -115,9 +114,8 @@ void CheatEditor::create() {
|
||||
};
|
||||
|
||||
//databaseWindow
|
||||
application.windows.append(&databaseWindow);
|
||||
databaseWindow.create(0, 0, 256, 256);
|
||||
databaseWindow.setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(&databaseWindow, "CheatDatabase", "192,192");
|
||||
|
||||
x = 5, y = 5;
|
||||
|
||||
@ -128,7 +126,7 @@ void CheatEditor::create() {
|
||||
databaseUnselectAll.create(databaseWindow, x + 105, y, 100, height, "Unselect All");
|
||||
databaseOk.create(databaseWindow, 605 - 80, y, 80, height, "Ok"); y += height + 5;
|
||||
|
||||
databaseWindow.setGeometry(192, 192, 610, y);
|
||||
databaseWindow.setGeometry(0, 0, 610, y);
|
||||
|
||||
databaseSelectAll.onTick = []() {
|
||||
for(unsigned i = 0; i < cheatEditor.databaseCode.size(); i++) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct CheatEditor : Window {
|
||||
struct CheatEditor : TopLevelWindow {
|
||||
ListBox cheatList;
|
||||
Label codeLabel;
|
||||
TextBox codeEdit;
|
||||
@ -8,7 +8,7 @@ struct CheatEditor : Window {
|
||||
Button clearAllButton;
|
||||
Button clearButton;
|
||||
|
||||
Window databaseWindow;
|
||||
TopLevelWindow databaseWindow;
|
||||
ListBox databaseList;
|
||||
lstring databaseCode;
|
||||
Button databaseSelectAll;
|
||||
|
@ -1,9 +1,8 @@
|
||||
StateManager stateManager;
|
||||
|
||||
void StateManager::create() {
|
||||
application.windows.append(this);
|
||||
Window::create(0, 0, 256, 256, "State Manager");
|
||||
setDefaultFont(application.proportionalFont);
|
||||
application.addWindow(this, "StateManager", "160,160");
|
||||
|
||||
unsigned x = 5, y = 5;
|
||||
|
||||
@ -17,7 +16,7 @@ void StateManager::create() {
|
||||
saveButton.create(*this, x + 505 - 85 - 85, y, 80, Style::ButtonHeight, "Save");
|
||||
eraseButton.create(*this, x + 505 - 85, y, 80, Style::ButtonHeight, "Erase"); y += Style::ButtonHeight + 5;
|
||||
|
||||
setGeometry(160, 160, 510, y);
|
||||
setGeometry(0, 0, 510, y);
|
||||
synchronize();
|
||||
|
||||
stateList.onActivate = { &StateManager::slotLoad, this };
|
||||
|
@ -1,4 +1,4 @@
|
||||
struct StateManager : Window {
|
||||
struct StateManager : TopLevelWindow {
|
||||
ListBox stateList;
|
||||
Label descLabel;
|
||||
TextBox descEdit;
|
||||
|
@ -66,7 +66,8 @@ void Utility::setScale(unsigned scale) {
|
||||
if(config.video.aspectRatioCorrection) width *= 32.0 / 23.0;
|
||||
}
|
||||
mainWindow.viewport.setGeometry(0, 0, width, height);
|
||||
mainWindow.setGeometry(128, 128, width, height);
|
||||
Geometry geom = mainWindow.geometry();
|
||||
mainWindow.setGeometry(geom.x, geom.y, width, height);
|
||||
}
|
||||
|
||||
void Utility::setShader() {
|
||||
|
Loading…
Reference in New Issue
Block a user