bsnes-libretro/hiro/extension/table-layout.cpp
Tim Allen 4d7bb510f2 Update to bsnes v107.1 release.
byuu says:

Don't let the point release fool you, there are many significant changes in this
release. I will be keeping bsnes releases using a point system until the new
higan release is ready.

Changelog:

  - GUI: added high DPI support
  - GUI: fixed the state manager image preview
  - Windows: added a new waveOut driver with support for dynamic rate control
  - Windows: corrected the XAudio 2.1 dynamic rate control support [BearOso]
  - Windows: corrected the Direct3D 9.0 fullscreen exclusive window centering
  - Windows: fixed XInput controller support on Windows 10
  - SFC: added high-level emulation for the DSP1, DSP2, DSP4, ST010, and Cx4
    coprocessors
  - SFC: fixed a slight rendering glitch in the intro to Megalomania

If the coprocessor firmware is missing, bsnes will fallback on HLE where it is
supported, which is everything other than SD Gundam GX and the two Hayazashi
Nidan Morita Shougi games.

The Windows dynamic rate control works best with Direct3D in fullscreen
exclusive mode. I recommend the waveOut driver over the XAudio 2.1 driver, as it
is not possible to target a single XAudio2 version on all Windows OS releases.
The waveOut driver should work everywhere out of the box.

Note that with DRC, the synchronization source is your monitor, so you will
want to be running at 60hz (NTSC) or 50hz (PAL). If you have an adaptive sync
monitor, you should instead use the WASAPI (exclusive) or ASIO audio driver.
2019-04-09 11:16:30 +10:00

442 lines
12 KiB
C++

#if defined(Hiro_TableLayout)
auto mTableLayout::alignment() const -> Alignment {
return state.alignment;
}
auto mTableLayout::append(sSizable sizable, Size size) -> type& {
for(auto& cell : state.cells) {
if(cell->state.sizable == sizable) return *this;
}
TableLayoutCell cell;
cell->setSizable(sizable);
cell->setSize(size);
cell->setParent(this, cellCount());
state.cells.append(cell);
return *this;
}
auto mTableLayout::cell(uint position) const -> TableLayoutCell {
return state.cells(position, {});
}
auto mTableLayout::cell(uint x, uint y) const -> TableLayoutCell {
if(auto cell = state.cells(y * columnCount() + x, {})) return cell;
return {};
}
auto mTableLayout::cell(sSizable sizable) const -> TableLayoutCell {
for(auto& cell : state.cells) {
if(cell->state.sizable == sizable) return cell;
}
return {};
}
auto mTableLayout::cells() const -> vector<TableLayoutCell> {
return state.cells;
}
auto mTableLayout::cellCount() const -> uint {
return state.cells.size();
}
auto mTableLayout::column(uint position) const -> TableLayoutColumn {
return state.columns(position, {});
}
auto mTableLayout::columns() const -> vector<TableLayoutColumn> {
return state.columns;
}
auto mTableLayout::columnCount() const -> uint {
return state.columns.size();
}
auto mTableLayout::destruct() -> void {
for(auto& cell : state.cells) cell->destruct();
for(auto& column : state.columns) column->destruct();
for(auto& row : state.rows) row->destruct();
mSizable::destruct();
}
auto mTableLayout::minimumSize() const -> Size {
float minimumWidth = 0;
for(uint x : range(columnCount())) {
float width = 0;
auto column = this->column(x);
for(uint y : range(rowCount())) {
auto row = this->row(y);
auto cell = this->cell(x, y);
if(cell.size().width() == Size::Minimum || cell.size().width() == Size::Maximum) {
width = max(width, cell.sizable()->minimumSize().width());
} else {
width = max(width, cell.size().width());
}
}
minimumWidth += width;
if(x != columnCount() - 1) minimumWidth += column.spacing();
}
float minimumHeight = 0;
for(uint y : range(rowCount())) {
float height = 0;
auto row = this->row(y);
for(uint x : range(columnCount())) {
auto column = this->column(x);
auto cell = this->cell(x, y);
if(cell.size().height() == Size::Minimum || cell.size().height() == Size::Maximum) {
height = max(height, cell.sizable()->minimumSize().height());
} else {
height = max(height, cell.size().height());
}
}
minimumHeight += height;
if(y != rowCount() - 1) minimumHeight += row.spacing();
}
return {
padding().x() + minimumWidth + padding().width(),
padding().y() + minimumHeight + padding().height()
};
}
auto mTableLayout::padding() const -> Geometry {
return state.padding;
}
auto mTableLayout::remove(sSizable sizable) -> type& {
for(auto& cell : state.cells) {
if(cell->state.sizable == sizable) return remove(cell);
}
return *this;
}
auto mTableLayout::remove(sTableLayoutCell cell) -> type& {
if(cell->parent() != this) return *this;
auto offset = cell->offset();
cell->setParent();
state.cells.remove(offset);
for(uint n : range(offset, cellCount())) state.cells[n]->adjustOffset(-1);
return synchronize();
}
auto mTableLayout::reset() -> type& {
while(state.cells) remove(state.cells.right());
return synchronize();
}
auto mTableLayout::resize() -> type& {
setGeometry(geometry());
return *this;
}
auto mTableLayout::row(uint position) const -> TableLayoutRow {
return state.rows(position, {});
}
auto mTableLayout::rows() const -> vector<TableLayoutRow> {
return state.rows;
}
auto mTableLayout::rowCount() const -> uint {
return state.rows.size();
}
auto mTableLayout::setAlignment(Alignment alignment) -> type& {
state.alignment = alignment;
return synchronize();
}
auto mTableLayout::setEnabled(bool enabled) -> type& {
mSizable::setEnabled(enabled);
for(auto& cell : state.cells) cell.setEnabled(cell.enabled());
return *this;
}
auto mTableLayout::setFont(const Font& font) -> type& {
mSizable::setFont(font);
for(auto& cell : state.cells) cell.setFont(cell.font());
return *this;
}
auto mTableLayout::setGeometry(Geometry requestedGeometry) -> type& {
//if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
auto geometry = requestedGeometry;
geometry.setX(geometry.x() + padding().x());
geometry.setY(geometry.y() + padding().y());
geometry.setWidth (geometry.width() - padding().x() - padding().width());
geometry.setHeight(geometry.height() - padding().y() - padding().height());
vector<float> widths;
widths.resize(columnCount());
uint maximumWidths = 0;
for(uint x : range(columnCount())) {
float width = 0;
auto column = this->column(x);
for(uint y : range(rowCount())) {
auto row = this->row(y);
auto cell = this->cell(x, y);
if(cell.size().width() == Size::Maximum) {
width = Size::Maximum;
maximumWidths++;
break;
}
if(cell.size().width() == Size::Minimum) {
width = max(width, cell.sizable()->minimumSize().width());
} else {
width = max(width, cell.size().width());
}
}
widths[x] = width;
}
vector<float> heights;
heights.resize(rowCount());
uint maximumHeights = 0;
for(uint y : range(rowCount())) {
float height = 0;
auto row = this->row(y);
for(uint x : range(columnCount())) {
auto column = this->column(x);
auto cell = this->cell(x, y);
if(cell.size().height() == Size::Maximum) {
height = Size::Maximum;
maximumHeights++;
break;
}
if(cell.size().height() == Size::Minimum) {
height = max(height, cell.sizable()->minimumSize().height());
} else {
height = max(height, cell.size().height());
}
}
heights[y] = height;
}
float fixedWidth = 0;
for(uint x : range(columnCount())) {
if(widths[x] != Size::Maximum) fixedWidth += widths[x];
if(x != columnCount() - 1) fixedWidth += column(x)->spacing();
}
float maximumWidth = (geometry.width() - fixedWidth) / maximumWidths;
for(auto& width : widths) {
if(width == Size::Maximum) width = maximumWidth;
}
float fixedHeight = 0;
for(uint y : range(rowCount())) {
if(heights[y] != Size::Maximum) fixedHeight += heights[y];
if(y != rowCount() - 1) fixedHeight += row(y)->spacing();
}
float maximumHeight = (geometry.height() - fixedHeight) / maximumHeights;
for(auto& height : heights) {
if(height == Size::Maximum) height = maximumHeight;
}
float geometryY = geometry.y();
for(uint y : range(rowCount())) {
float geometryX = geometry.x();
auto row = this->row(y);
for(uint x : range(columnCount())) {
auto column = this->column(x);
auto cell = this->cell(x, y);
float geometryWidth = widths [x];
float geometryHeight = heights[y];
auto alignment = cell.alignment();
if(!alignment) alignment = column.alignment();
if(!alignment) alignment = row.alignment();
if(!alignment) alignment = this->alignment();
if(!alignment) alignment = {0.0, 0.5};
float cellWidth = cell.size().width();
if(cellWidth == Size::Minimum) cellWidth = cell.sizable()->minimumSize().width();
if(cellWidth == Size::Maximum) cellWidth = geometryWidth;
cellWidth = min(cellWidth, geometryWidth);
float cellHeight = cell.size().height();
if(cellHeight == Size::Minimum) cellHeight = cell.sizable()->minimumSize().height();
if(cellHeight == Size::Maximum) cellHeight = geometryHeight;
cellHeight = min(cellHeight, geometryHeight);
float cellX = geometryX + alignment.horizontal() * (geometryWidth - cellWidth);
float cellY = geometryY + alignment.vertical() * (geometryHeight - cellHeight);
cell.sizable()->setGeometry({cellX, cellY, cellWidth, cellHeight});
geometryX += widths[x] + column.spacing();
}
geometryY += heights[y] + row.spacing();
}
mSizable::setGeometry(requestedGeometry);
return *this;
}
auto mTableLayout::setPadding(Geometry padding) -> type& {
state.padding = padding;
return synchronize();
}
auto mTableLayout::setParent(mObject* parent, int offset) -> type& {
for(auto& cell : reverse(state.cells)) cell->destruct();
for(auto& column : reverse(state.columns)) column->destruct();
for(auto& row : reverse(state.rows)) row->destruct();
mObject::setParent(parent, offset);
for(auto& cell : state.cells) cell->setParent(this, cell->offset());
for(auto& column : state.columns) column->setParent(this, column->offset());
for(auto& row : state.rows) row->setParent(this, row->offset());
return *this;
}
auto mTableLayout::setSize(Size size) -> type& {
state.size = size;
state.columns.reset();
state.rows.reset();
for(auto x : range(size.width())) state.columns.append(TableLayoutColumn());
for(auto y : range(size.height())) state.rows.append(TableLayoutRow());
return synchronize();
}
auto mTableLayout::setVisible(bool visible) -> type& {
mSizable::setVisible(visible);
for(auto& cell : state.cells) cell.setVisible(cell.visible());
return synchronize();
}
auto mTableLayout::size() const -> Size {
return state.size;
}
auto mTableLayout::synchronize() -> type& {
setGeometry(geometry());
return *this;
}
//
auto mTableLayoutColumn::alignment() const -> Alignment {
return state.alignment;
}
auto mTableLayoutColumn::setAlignment(Alignment alignment) -> type& {
state.alignment = alignment;
return synchronize();
}
auto mTableLayoutColumn::setSpacing(float spacing) -> type& {
state.spacing = spacing;
return synchronize();
}
auto mTableLayoutColumn::spacing() const -> float {
return state.spacing;
}
auto mTableLayoutColumn::synchronize() -> type& {
if(auto parent = this->parent()) {
if(auto tableLayout = dynamic_cast<mTableLayout*>(parent)) {
tableLayout->synchronize();
}
}
return *this;
}
//
auto mTableLayoutRow::alignment() const -> Alignment {
return state.alignment;
}
auto mTableLayoutRow::setAlignment(Alignment alignment) -> type& {
state.alignment = alignment;
return synchronize();
}
auto mTableLayoutRow::setSpacing(float spacing) -> type& {
state.spacing = spacing;
return synchronize();
}
auto mTableLayoutRow::spacing() const -> float {
return state.spacing;
}
auto mTableLayoutRow::synchronize() -> type& {
if(auto parent = this->parent()) {
if(auto tableLayout = dynamic_cast<mTableLayout*>(parent)) {
tableLayout->synchronize();
}
}
return *this;
}
//
auto mTableLayoutCell::alignment() const -> Alignment {
return state.alignment;
}
auto mTableLayoutCell::destruct() -> void {
if(auto& sizable = state.sizable) sizable->destruct();
mObject::destruct();
}
auto mTableLayoutCell::setAlignment(Alignment alignment) -> type& {
state.alignment = alignment;
return synchronize();
}
auto mTableLayoutCell::setEnabled(bool enabled) -> type& {
mObject::setEnabled(enabled);
state.sizable->setEnabled(state.sizable->enabled());
return *this;
}
auto mTableLayoutCell::setFont(const Font& font) -> type& {
mObject::setFont(font);
state.sizable->setFont(state.sizable->font());
return *this;
}
auto mTableLayoutCell::setParent(mObject* parent, int offset) -> type& {
state.sizable->destruct();
mObject::setParent(parent, offset);
state.sizable->setParent(this, 0);
return *this;
}
auto mTableLayoutCell::setSizable(sSizable sizable) -> type& {
state.sizable = sizable;
state.sizable->setParent(this, 0);
return synchronize();
}
auto mTableLayoutCell::setSize(Size size) -> type& {
state.size = size;
return synchronize();
}
auto mTableLayoutCell::setVisible(bool visible) -> type& {
mObject::setVisible(visible);
state.sizable->setVisible(state.sizable->visible());
return *this;
}
auto mTableLayoutCell::sizable() const -> Sizable {
return state.sizable ? state.sizable : Sizable();
}
auto mTableLayoutCell::size() const -> Size {
return state.size;
}
auto mTableLayoutCell::synchronize() -> type& {
if(auto parent = this->parent()) {
if(auto tableLayout = dynamic_cast<mTableLayout*>(parent)) {
tableLayout->synchronize();
}
}
return *this;
}
#endif