Break up the giant InventoryScreen class to be more modular.

(separate table widget, and scrollbar widget)
This commit is contained in:
UnknownShadow200 2017-10-14 23:24:01 +11:00
parent aa4d06537b
commit 43752348bf
7 changed files with 494 additions and 404 deletions

View File

@ -1,103 +0,0 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
using OpenTK.Input;
namespace ClassicalSharp.Gui.Screens {
public partial class InventoryScreen : Screen {
public override bool HandlesMouseMove(int mouseX, int mouseY) {
if (draggingMouse) {
mouseY -= TableY;
scrollY = (int)((mouseY - mouseOffset) / ScrollbarScale);
ClampScrollY();
return true;
}
selIndex = -1;
if (Contains(startX, startY + 3, blocksPerRow * blockSize,
maxRows * blockSize - 3 * 2, mouseX, mouseY)) {
for (int i = 0; i < blocksTable.Length; i++) {
int x, y;
GetCoords(i, out x, out y);
if (Contains(x, y, blockSize, blockSize, mouseX, mouseY)) {
selIndex = i;
break;
}
}
}
RecreateBlockInfoTexture();
return true;
}
public override bool HandlesMouseClick(int mouseX, int mouseY, MouseButton button) {
if (draggingMouse || game.Gui.hudScreen.hotbar.HandlesMouseClick(mouseX, mouseY, button))
return true;
int scrollX = TableX + TableWidth;
if (button == MouseButton.Left && mouseX >= scrollX && mouseX < scrollX + scrollWidth) {
ScrollbarClick(mouseY);
} else if (button == MouseButton.Left) {
if (selIndex != -1) {
game.Inventory.Selected = blocksTable[selIndex];
} else if (Contains(TableX, TableY, TableWidth, TableHeight, mouseX, mouseY)) {
return true;
}
bool hotbar = game.Input.ControlDown;
if (!hotbar)
game.Gui.SetNewScreen(null);
}
return true;
}
// We want the user to be able to press B to exit the inventory menu
// however since we use KeyRepeat = true, we must wait until the first time they released B
// before marking the next press as closing the menu
bool releasedInv;
public override bool HandlesKeyDown(Key key) {
if (key == game.Mapping(KeyBind.PauseOrExit)) {
game.Gui.SetNewScreen(null);
} else if (key == game.Mapping(KeyBind.Inventory) && releasedInv) {
game.Gui.SetNewScreen(null);
} else if (key == Key.Enter && selIndex != -1) {
game.Inventory.Selected = blocksTable[selIndex];
game.Gui.SetNewScreen(null);
} else if ((key == Key.Left || key == Key.Keypad4) && selIndex != -1) {
ArrowKeyMove(-1);
} else if ((key == Key.Right || key == Key.Keypad6) && selIndex != -1) {
ArrowKeyMove(1);
} else if ((key == Key.Up || key == Key.Keypad8) && selIndex != -1) {
ArrowKeyMove(-blocksPerRow);
} else if ((key == Key.Down || key == Key.Keypad2) && selIndex != -1) {
ArrowKeyMove(blocksPerRow);
} else if (game.Gui.hudScreen.hotbar.HandlesKeyDown(key)) {
}
return true;
}
public override bool HandlesKeyUp(Key key) {
if (key == game.Mapping(KeyBind.Inventory)) {
releasedInv = true; return true;
}
return game.Gui.hudScreen.hotbar.HandlesKeyUp(key);
}
void ArrowKeyMove(int delta) {
int startIndex = selIndex;
selIndex += delta;
if (selIndex < 0)
selIndex -= delta;
if (selIndex >= blocksTable.Length)
selIndex -= delta;
int scrollDelta = (selIndex / blocksPerRow) - (startIndex / blocksPerRow);
scrollY += scrollDelta;
ClampScrollY();
RecreateBlockInfoTexture();
MoveCursorToSelected();
}
}
}

View File

@ -1,257 +0,0 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
using OpenTK.Input;
#if USE16_BIT
using BlockID = System.UInt16;
#else
using BlockID = System.Byte;
#endif
namespace ClassicalSharp.Gui.Screens {
public partial class InventoryScreen : Screen {
public InventoryScreen(Game game) : base(game) {
font = new Font(game.FontName, 16);
HandlesAllInput = true;
}
BlockID[] blocksTable;
Texture blockInfoTexture;
const int maxRows = 8;
int blocksPerRow {
get { return game.ClassicMode && !game.ClassicHacks ? 9 : 10; }
}
int selIndex, rows;
int startX, startY, blockSize;
float selBlockExpand;
readonly Font font;
StringBuffer buffer = new StringBuffer(128);
IsometricBlockDrawer drawer = new IsometricBlockDrawer();
int TableX { get { return startX - 5 - 10; } }
int TableY { get { return startY - 5 - 30; } }
int TableWidth { get { return blocksPerRow * blockSize + 10 + 20; } }
int TableHeight { get { return Math.Min(rows, maxRows) * blockSize + 10 + 40; } }
// These were sourced by taking a screenshot of vanilla
// Then using paint to extract the colour components
// Then using wolfram alpha to solve the glblendfunc equation
static FastColour topCol = new FastColour(34, 34, 34, 168);
static FastColour bottomCol = new FastColour(57, 57, 104, 202);
static FastColour topSelCol = new FastColour(255, 255, 255, 142);
static FastColour bottomSelCol = new FastColour(255, 255, 255, 192);
static VertexP3fT2fC4b[] vertices = new VertexP3fT2fC4b[8 * 10 * (4 * 4)];
int vb;
public override void Render(double delta) {
gfx.Draw2DQuad(TableX, TableY, TableWidth, TableHeight, topCol, bottomCol);
if (rows > maxRows)
DrawScrollbar();
if (selIndex != -1 && game.ClassicMode) {
int x, y;
GetCoords(selIndex, out x, out y);
float off = blockSize * 0.1f;
gfx.Draw2DQuad(x - off, y - off, blockSize + off * 2,
blockSize + off * 2, topSelCol, bottomSelCol);
}
gfx.Texturing = true;
gfx.SetBatchFormat(VertexFormat.P3fT2fC4b);
drawer.BeginBatch(game, vertices, vb);
for (int i = 0; i < blocksTable.Length; i++) {
int x, y;
if (!GetCoords(i, out x, out y)) continue;
// We want to always draw the selected block on top of others
if (i == selIndex) continue;
drawer.DrawBatch(blocksTable[i], blockSize * 0.7f / 2f,
x + blockSize / 2, y + blockSize / 2);
}
if (selIndex != -1) {
int x, y;
GetCoords(selIndex, out x, out y);
drawer.DrawBatch(blocksTable[selIndex], (blockSize + selBlockExpand) * 0.7f / 2,
x + blockSize / 2, y + blockSize / 2);
}
drawer.EndBatch();
if (blockInfoTexture.IsValid)
blockInfoTexture.Render(gfx);
gfx.Texturing = false;
}
bool GetCoords(int i, out int x, out int y) {
int col = i % blocksPerRow;
int row = i / blocksPerRow;
x = startX + blockSize * col;
y = startY + blockSize * row + 3;
y -= scrollY * blockSize;
row -= scrollY;
return row >= 0 && row < maxRows;
}
Point GetMouseCoords(int i) {
int x, y;
GetCoords(i, out x, out y);
x += blockSize / 2; y += blockSize / 2;
Point topLeft = game.PointToScreen(Point.Empty);
x += topLeft.X; y += topLeft.Y;
return new Point(x, y);
}
public override void Dispose() {
font.Dispose();
game.Events.BlockPermissionsChanged -= BlockPermissionsChanged;
game.Keyboard.KeyRepeat = false;
ContextLost();
game.Graphics.ContextLost -= ContextLost;
game.Graphics.ContextRecreated -= ContextRecreated;
}
public override void OnResize(int width, int height) {
blockSize = (int)(50 * Math.Sqrt(game.GuiInventoryScale));
selBlockExpand = (float)(25 * Math.Sqrt(game.GuiInventoryScale));
int rowsUsed = Math.Min(maxRows, rows);
startX = game.Width / 2 - (blockSize * blocksPerRow) / 2;
startY = game.Height / 2 - (rowsUsed * blockSize) / 2;
blockInfoTexture.X1 = startX + (blockSize * blocksPerRow) / 2 - blockInfoTexture.Width / 2;
blockInfoTexture.Y1 = startY - blockInfoTexture.Height - 5;
}
public override void Init() {
blockSize = (int)(50 * Math.Sqrt(game.GuiInventoryScale));
selBlockExpand = (float)(25 * Math.Sqrt(game.GuiInventoryScale));
game.Events.BlockPermissionsChanged += BlockPermissionsChanged;
ContextRecreated();
game.Graphics.ContextLost += ContextLost;
game.Graphics.ContextRecreated += ContextRecreated;
RecreateBlockTable();
SetBlockTo(game.Inventory.Selected);
game.Keyboard.KeyRepeat = true;
}
public void SetBlockTo(BlockID block) {
selIndex = IndexOfBlock(block);
scrollY = (selIndex / blocksPerRow) - (maxRows - 1);
ClampScrollY();
MoveCursorToSelected();
RecreateBlockInfoTexture();
}
int IndexOfBlock(BlockID block) {
for (int i = 0; i < blocksTable.Length; i++) {
if (blocksTable[i] == block) return i;
}
return -1;
}
void MoveCursorToSelected() {
if (selIndex == -1) return;
game.DesktopCursorPos = GetMouseCoords(selIndex);
}
void BlockPermissionsChanged(object sender, EventArgs e) {
RecreateBlockTable();
if (selIndex >= blocksTable.Length)
selIndex = blocksTable.Length - 1;
scrollY = selIndex / blocksPerRow;
ClampScrollY();
RecreateBlockInfoTexture();
}
void UpdateBlockInfoString(BlockID block) {
int index = 0;
buffer.Clear();
if (game.PureClassic) { buffer.Append(ref index, "Select block"); return; }
buffer.Append(ref index, "&f");
string value = BlockInfo.Name[block];
buffer.Append(ref index, value);
if (game.ClassicMode) return;
buffer.Append(ref index, " (ID ");
buffer.AppendNum(ref index, block);
buffer.Append(ref index, "&f, place ");
buffer.Append(ref index, BlockInfo.CanPlace[block] ? "&aYes" : "&cNo");
buffer.Append(ref index, "&f, delete ");
buffer.Append(ref index, BlockInfo.CanDelete[block] ? "&aYes" : "&cNo");
buffer.Append(ref index, "&f)");
}
int lastCreatedIndex = -1000;
void RecreateBlockInfoTexture() {
if (selIndex == lastCreatedIndex || blocksTable == null) return;
lastCreatedIndex = selIndex;
gfx.DeleteTexture(ref blockInfoTexture);
if (selIndex == -1) return;
BlockID block = blocksTable[selIndex];
UpdateBlockInfoString(block);
string value = buffer.ToString();
DrawTextArgs args = new DrawTextArgs(value, font, true);
Size size = game.Drawer2D.MeasureSize(ref args);
int x = startX + (blockSize * blocksPerRow) / 2 - size.Width / 2;
int y = startY - size.Height - 5;
args.SkipPartsCheck = true;
blockInfoTexture = game.Drawer2D.MakeTextTexture(ref args, x, y);
}
void RecreateBlockTable() {
int blocksCount = 0;
int count = game.UseCPE ? Block.Count : Block.OriginalCount;
for (int i = 0; i < count; i++) {
BlockID block = game.Inventory.Map[i];
if (Show(block)) blocksCount++;
}
rows = Utils.CeilDiv(blocksCount, blocksPerRow);
int rowsUsed = Math.Min(maxRows, rows);
startX = game.Width / 2 - (blockSize * blocksPerRow) / 2;
startY = game.Height / 2 - (rowsUsed * blockSize) / 2;
blocksTable = new BlockID[blocksCount];
int index = 0;
for (int i = 0; i < count; i++) {
BlockID block = game.Inventory.Map[i];
if (Show(block)) blocksTable[index++] = block;
}
}
bool Show(BlockID block) {
if (block == Block.Invalid) return false;
if (block < Block.CpeCount) {
int count = game.UseCPEBlocks ? Block.CpeCount : Block.OriginalCount;
return block < count;
}
return true;
}
protected override void ContextLost() {
gfx.DeleteVb(ref vb);
gfx.DeleteTexture(ref blockInfoTexture);
lastCreatedIndex = -1000;
}
protected override void ContextRecreated() {
vb = gfx.CreateDynamicVb(VertexFormat.P3fT2fC4b, vertices.Length);
RecreateBlockInfoTexture();
}
}
}

View File

@ -0,0 +1,109 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Drawing;
using ClassicalSharp.Gui.Widgets;
using OpenTK.Input;
namespace ClassicalSharp.Gui.Screens {
public partial class InventoryScreen : Screen {
TableWidget table;
Font font;
public InventoryScreen(Game game) : base(game) {
font = new Font(game.FontName, 16);
HandlesAllInput = true;
}
public override void Init() {
InitTableWidget();
game.Events.BlockPermissionsChanged += OnBlockChanged;
game.Events.BlockDefinitionChanged += OnBlockChanged;
game.Keyboard.KeyRepeat = true;
game.Graphics.ContextLost += ContextLost;
game.Graphics.ContextRecreated += ContextRecreated;
}
void InitTableWidget() {
table = new TableWidget(game);
table.font = font;
table.ElementsPerRow = game.ClassicMode && !game.ClassicHacks ? 9 : 10;
table.Init();
}
public override void Render(double delta) { table.Render(delta); }
public override void OnResize(int width, int height) { table.Reposition(); }
public override void Dispose() {
font.Dispose();
table.Dispose();
game.Events.BlockPermissionsChanged -= OnBlockChanged;
game.Events.BlockDefinitionChanged -= OnBlockChanged;
game.Keyboard.KeyRepeat = false;
game.Graphics.ContextLost -= ContextLost;
game.Graphics.ContextRecreated -= ContextRecreated;
}
void OnBlockChanged(object sender, EventArgs e) {
table.OnInventoryChanged();
}
protected override void ContextLost() { table.Dispose(); }
protected override void ContextRecreated() { table.Recreate(); }
public override bool HandlesMouseMove(int mouseX, int mouseY) {
return table.HandlesMouseMove(mouseX, mouseY);
}
public override bool HandlesMouseClick(int mouseX, int mouseY, MouseButton button) {
if (table.scroll.draggingMouse || game.Gui.hudScreen.hotbar.HandlesMouseClick(mouseX, mouseY, button))
return true;
bool handled = table.HandlesMouseClick(mouseX, mouseY, button);
if ((!handled || table.PendingClose) && button == MouseButton.Left) {
bool hotbar = game.Input.ControlDown;
if (!hotbar) game.Gui.SetNewScreen(null);
}
return true;
}
public override bool HandlesMouseScroll(float delta) {
bool hotbar = game.Input.AltDown || game.Input.ControlDown || game.Input.ShiftDown;
if (hotbar) return false;
return table.HandlesMouseScroll(delta);
}
public override bool HandlesMouseUp(int mouseX, int mouseY, MouseButton button) {
return table.HandlesMouseUp(mouseX, mouseY, button);
}
// We want the user to be able to press B to exit the inventory menu
// however since we use KeyRepeat = true, we must wait until the first time they released B
// before marking the next press as closing the menu
bool releasedInv;
public override bool HandlesKeyDown(Key key) {
if (key == game.Mapping(KeyBind.PauseOrExit)) {
game.Gui.SetNewScreen(null);
} else if (key == game.Mapping(KeyBind.Inventory) && releasedInv) {
game.Gui.SetNewScreen(null);
} else if (key == Key.Enter && table.SelectedIndex != -1) {
game.Inventory.Selected = table.Elements[table.SelectedIndex];
game.Gui.SetNewScreen(null);
} else if (table.HandlesKeyDown(key)) {
} else {
game.Gui.hudScreen.hotbar.HandlesKeyDown(key);
}
return true;
}
public override bool HandlesKeyUp(Key key) {
if (key == game.Mapping(KeyBind.Inventory)) {
releasedInv = true; return true;
}
return game.Gui.hudScreen.hotbar.HandlesKeyUp(key);
}
}
}

View File

@ -1,24 +1,38 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Drawing;
using OpenTK.Input;
namespace ClassicalSharp.Gui.Screens {
public partial class InventoryScreen : Screen {
namespace ClassicalSharp.Gui.Widgets {
public sealed class ScrollbarWidget : Widget {
public ScrollbarWidget(Game game) : base(game) {
Width = scrollWidth;
}
public int TotalRows, ScrollY;
public void ClampScrollY() {
int maxRows = TotalRows - TableWidget.MaxRowsDisplayed;
if (ScrollY >= maxRows) ScrollY = maxRows;
if (ScrollY < 0) ScrollY = 0;
}
public override void Init() { }
public override void Dispose() { }
const int scrollWidth = 22, scrollBorder = 2, nubsWidth = 3;
static FastColour scrollBackCol = new FastColour(10, 10, 10, 220);
static FastColour scrollBarCol = new FastColour(100, 100, 100, 220);
static FastColour scrollHoverCol = new FastColour(122, 122, 122, 220);
float ScrollbarScale { get { return (TableHeight - scrollBorder * 2) / (float)rows; } }
float ScrollbarScale { get { return (Height - scrollBorder * 2) / (float)TotalRows; } }
void DrawScrollbar() {
int x = TableX + TableWidth, width = scrollWidth;
gfx.Draw2DQuad(x, TableY, width, TableHeight, scrollBackCol);
public override void Render(double delta) {
int x = X, width = Width;
gfx.Draw2DQuad(x, Y, width, Height, scrollBackCol);
int y, height;
GetScrollbarCoords(out y, out height);
x += scrollBorder; width -= scrollBorder * 2; y += TableY;
x += scrollBorder; width -= scrollBorder * 2; y += Y;
bool hovered = game.Mouse.Y >= y && game.Mouse.Y < (y + height) &&
game.Mouse.X >= x && game.Mouse.X < (x + width);
@ -35,50 +49,50 @@ namespace ClassicalSharp.Gui.Screens {
void GetScrollbarCoords(out int y, out int height) {
float scale = ScrollbarScale;
y = (int)Math.Ceiling(scrollY * scale) + scrollBorder;
height = (int)Math.Ceiling(maxRows * scale);
height = Math.Min(y + height, TableHeight - scrollBorder) - y;
y = (int)Math.Ceiling(ScrollY * scale) + scrollBorder;
height = (int)Math.Ceiling(TableWidget.MaxRowsDisplayed * scale);
height = Math.Min(y + height, Height - scrollBorder) - y;
}
float invAcc;
public override bool HandlesMouseScroll(float delta) {
bool bounds = Contains(TableX - scrollWidth, TableY, TableWidth + scrollWidth,
TableHeight, game.Mouse.X, game.Mouse.Y);
bool hotbar = game.Input.AltDown || game.Input.ControlDown || game.Input.ShiftDown;
if (!bounds || hotbar) return false;
int rowY = (selIndex / blocksPerRow) - scrollY;
int steps = Utils.AccumulateWheelDelta(ref invAcc, delta);
scrollY -= steps;
ScrollY -= steps;
ClampScrollY();
if (selIndex == - 1) return true;
selIndex = scrollY * blocksPerRow + (selIndex % blocksPerRow);
for (int row = 0; row < rowY; row++) {
selIndex += blocksPerRow;
}
if (selIndex >= blocksTable.Length)
selIndex = -1;
RecreateBlockInfoTexture();
return true;
}
int scrollY;
void ClampScrollY() {
if (scrollY >= rows - maxRows) scrollY = rows - maxRows;
if (scrollY < 0) scrollY = 0;
public override bool HandlesMouseMove(int mouseX, int mouseY) {
if (draggingMouse) {
mouseY -= Y;
ScrollY = (int)((mouseY - mouseOffset) / ScrollbarScale);
ClampScrollY();
return true;
}
return false;
}
public override bool HandlesMouseClick(int mouseX, int mouseY, MouseButton button) {
if (draggingMouse) return true;
if (button != MouseButton.Left) return false;
if (mouseX >= X && mouseX < X + Width) {
ScrollbarClick(mouseY);
return true;
}
return false;
}
void ScrollbarClick(int mouseY) {
mouseY -= TableY;
mouseY -= Y;
int y, height;
GetScrollbarCoords(out y, out height);
if (mouseY < y) {
scrollY -= maxRows;
ScrollY -= TableWidget.MaxRowsDisplayed;
} else if (mouseY >= y + height) {
scrollY += maxRows;
ScrollY += TableWidget.MaxRowsDisplayed;
} else {
draggingMouse = true;
mouseOffset = mouseY - y;
@ -86,9 +100,8 @@ namespace ClassicalSharp.Gui.Screens {
ClampScrollY();
}
bool draggingMouse = false;
internal bool draggingMouse = false;
int mouseOffset = 0;
public override bool HandlesMouseUp(int mouseX, int mouseY, MouseButton button) {
draggingMouse = false;
mouseOffset = 0;

View File

@ -0,0 +1,329 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
using OpenTK.Input;
#if USE16_BIT
using BlockID = System.UInt16;
#else
using BlockID = System.Byte;
#endif
namespace ClassicalSharp.Gui.Widgets {
public sealed class TableWidget : Widget {
public TableWidget(Game game) : base(game) { }
public const int MaxRowsDisplayed = 8;
public BlockID[] Elements;
public int ElementsPerRow;
public int SelectedIndex;
public Font font;
internal ScrollbarWidget scroll;
public bool PendingClose;
Texture blockInfoTexture;
int totalRows, blockSize;
float selBlockExpand;
StringBuffer buffer = new StringBuffer(128);
IsometricBlockDrawer drawer = new IsometricBlockDrawer();
int TableX { get { return X - 5 - 10; } }
int TableY { get { return Y - 5 - 30; } }
int TableWidth { get { return ElementsPerRow * blockSize + 10 + 20; } }
int TableHeight { get { return Math.Min(totalRows, MaxRowsDisplayed) * blockSize + 10 + 40; } }
// These were sourced by taking a screenshot of vanilla
// Then using paint to extract the colour components
// Then using wolfram alpha to solve the glblendfunc equation
static FastColour topCol = new FastColour(34, 34, 34, 168);
static FastColour bottomCol = new FastColour(57, 57, 104, 202);
static FastColour topSelCol = new FastColour(255, 255, 255, 142);
static FastColour bottomSelCol = new FastColour(255, 255, 255, 192);
static VertexP3fT2fC4b[] vertices = new VertexP3fT2fC4b[8 * 10 * (4 * 4)];
int vb;
public override void Render(double delta) {
gfx.Draw2DQuad(TableX, TableY, TableWidth, TableHeight, topCol, bottomCol);
if (totalRows > MaxRowsDisplayed) scroll.Render(delta);
if (SelectedIndex != -1 && game.ClassicMode) {
int x, y;
GetCoords(SelectedIndex, out x, out y);
float off = blockSize * 0.1f;
gfx.Draw2DQuad(x - off, y - off, blockSize + off * 2,
blockSize + off * 2, topSelCol, bottomSelCol);
}
gfx.Texturing = true;
gfx.SetBatchFormat(VertexFormat.P3fT2fC4b);
drawer.BeginBatch(game, vertices, vb);
for (int i = 0; i < Elements.Length; i++) {
int x, y;
if (!GetCoords(i, out x, out y)) continue;
// We want to always draw the selected block on top of others
if (i == SelectedIndex) continue;
drawer.DrawBatch(Elements[i], blockSize * 0.7f / 2f,
x + blockSize / 2, y + blockSize / 2);
}
if (SelectedIndex != -1) {
int x, y;
GetCoords(SelectedIndex, out x, out y);
drawer.DrawBatch(Elements[SelectedIndex], (blockSize + selBlockExpand) * 0.7f / 2,
x + blockSize / 2, y + blockSize / 2);
}
drawer.EndBatch();
if (blockInfoTexture.IsValid)
blockInfoTexture.Render(gfx);
gfx.Texturing = false;
}
bool GetCoords(int i, out int screenX, out int screenY) {
int x = i % ElementsPerRow, y = i / ElementsPerRow;
screenX = X + blockSize * x;
screenY = Y + blockSize * y + 3;
screenY -= scroll.ScrollY * blockSize;
y -= scroll.ScrollY;
return y >= 0 && y < MaxRowsDisplayed;
}
Point GetMouseCoords(int i) {
int x, y;
GetCoords(i, out x, out y);
x += blockSize / 2; y += blockSize / 2;
Point topLeft = game.PointToScreen(Point.Empty);
x += topLeft.X; y += topLeft.Y;
return new Point(x, y);
}
public override void Init() {
scroll = new ScrollbarWidget(game);
RecreateElements();
Reposition();
SetBlockTo(game.Inventory.Selected);
Recreate();
}
public override void Dispose() {
gfx.DeleteVb(ref vb);
gfx.DeleteTexture(ref blockInfoTexture);
lastCreatedIndex = -1000;
}
public override void Recreate() {
Dispose();
vb = gfx.CreateDynamicVb(VertexFormat.P3fT2fC4b, vertices.Length);
RecreateBlockInfoTexture();
}
public override void Reposition() {
blockSize = (int)(50 * Math.Sqrt(game.GuiInventoryScale));
selBlockExpand = (float)(25 * Math.Sqrt(game.GuiInventoryScale));
int rowsDisplayed = Math.Min(MaxRowsDisplayed, totalRows);
X = game.Width / 2 - (blockSize * ElementsPerRow) / 2;
Y = game.Height / 2 - (rowsDisplayed * blockSize) / 2;
blockInfoTexture.X1 = X + (blockSize * ElementsPerRow) / 2 - blockInfoTexture.Width / 2;
blockInfoTexture.Y1 = Y - blockInfoTexture.Height - 5;
UpdateScrollbarPosition();
}
void UpdateScrollbarPosition() {
scroll.X = TableX + TableWidth;
scroll.Y = TableY;
scroll.Height = TableHeight;
scroll.TotalRows = totalRows;
}
public void SetBlockTo(BlockID block) {
SelectedIndex = -1;
for (int i = 0; i < Elements.Length; i++) {
if (Elements[i] == block) SelectedIndex = i;
}
scroll.ScrollY = (SelectedIndex / ElementsPerRow) - (MaxRowsDisplayed - 1);
scroll.ClampScrollY();
MoveCursorToSelected();
RecreateBlockInfoTexture();
}
public void OnInventoryChanged() {
RecreateElements();
if (SelectedIndex >= Elements.Length)
SelectedIndex = Elements.Length - 1;
scroll.ScrollY = SelectedIndex / ElementsPerRow;
scroll.ClampScrollY();
RecreateBlockInfoTexture();
}
void MoveCursorToSelected() {
if (SelectedIndex == -1) return;
game.DesktopCursorPos = GetMouseCoords(SelectedIndex);
}
void UpdateBlockInfoString(BlockID block) {
int index = 0;
buffer.Clear();
if (game.PureClassic) { buffer.Append(ref index, "Select block"); return; }
buffer.Append(ref index, "&f");
string value = BlockInfo.Name[block];
buffer.Append(ref index, value);
if (game.ClassicMode) return;
buffer.Append(ref index, " (ID ");
buffer.AppendNum(ref index, block);
buffer.Append(ref index, "&f, place ");
buffer.Append(ref index, BlockInfo.CanPlace[block] ? "&aYes" : "&cNo");
buffer.Append(ref index, "&f, delete ");
buffer.Append(ref index, BlockInfo.CanDelete[block] ? "&aYes" : "&cNo");
buffer.Append(ref index, "&f)");
}
int lastCreatedIndex = -1000;
void RecreateBlockInfoTexture() {
if (SelectedIndex == lastCreatedIndex || Elements == null) return;
lastCreatedIndex = SelectedIndex;
gfx.DeleteTexture(ref blockInfoTexture);
if (SelectedIndex == -1) return;
BlockID block = Elements[SelectedIndex];
UpdateBlockInfoString(block);
string value = buffer.ToString();
DrawTextArgs args = new DrawTextArgs(value, font, true);
Size size = game.Drawer2D.MeasureSize(ref args);
int x = X + (blockSize * ElementsPerRow) / 2 - size.Width / 2;
int y = Y - size.Height - 5;
args.SkipPartsCheck = true;
blockInfoTexture = game.Drawer2D.MakeTextTexture(ref args, x, y);
}
void RecreateElements() {
int totalElements = 0;
int count = game.UseCPE ? Block.Count : Block.OriginalCount;
for (int i = 0; i < count; i++) {
BlockID block = game.Inventory.Map[i];
if (Show(block)) totalElements++;
}
totalRows = Utils.CeilDiv(totalElements, ElementsPerRow);
UpdateScrollbarPosition();
int rowsDisplayed = Math.Min(MaxRowsDisplayed, totalRows);
X = game.Width / 2 - (blockSize * ElementsPerRow) / 2;
Y = game.Height / 2 - (rowsDisplayed * blockSize) / 2;
Elements = new BlockID[totalElements];
int index = 0;
for (int i = 0; i < count; i++) {
BlockID block = game.Inventory.Map[i];
if (Show(block)) Elements[index++] = block;
}
}
bool Show(BlockID block) {
if (block == Block.Invalid) return false;
if (block < Block.CpeCount) {
int count = game.UseCPEBlocks ? Block.CpeCount : Block.OriginalCount;
return block < count;
}
return true;
}
public override bool HandlesMouseMove(int mouseX, int mouseY) {
if (scroll.HandlesMouseMove(mouseX, mouseY)) return true;
SelectedIndex = -1;
if (Contains(X, Y + 3, ElementsPerRow * blockSize,
MaxRowsDisplayed * blockSize - 3 * 2, mouseX, mouseY)) {
for (int i = 0; i < Elements.Length; i++) {
int x, y;
GetCoords(i, out x, out y);
if (Contains(x, y, blockSize, blockSize, mouseX, mouseY)) {
SelectedIndex = i;
break;
}
}
}
RecreateBlockInfoTexture();
return true;
}
public override bool HandlesMouseClick(int mouseX, int mouseY, MouseButton button) {
PendingClose = false;
if (button != MouseButton.Left) return false;
if (scroll.HandlesMouseClick(mouseX, mouseY, button)) {
return true;
} else if (SelectedIndex != -1) {
game.Inventory.Selected = Elements[SelectedIndex];
PendingClose = true;
return true;
} else if (Contains(TableX, TableY, TableWidth, TableHeight, mouseX, mouseY)) {
return true;
}
return false;
}
public override bool HandlesKeyDown(Key key) {
if (SelectedIndex == -1) return false;
if (key == Key.Left || key == Key.Keypad4) {
ScrollRelative(-1);
} else if (key == Key.Right || key == Key.Keypad6) {
ScrollRelative(1);
} else if (key == Key.Up || key == Key.Keypad8) {
ScrollRelative(-ElementsPerRow);
} else if (key == Key.Down || key == Key.Keypad2) {
ScrollRelative(ElementsPerRow);
} else {
return false;
}
return true;
}
void ScrollRelative(int delta) {
int startIndex = SelectedIndex;
SelectedIndex += delta;
if (SelectedIndex < 0) SelectedIndex -= delta;
if (SelectedIndex >= Elements.Length) SelectedIndex -= delta;
int scrollDelta = (SelectedIndex / ElementsPerRow) - (startIndex / ElementsPerRow);
scroll.ScrollY += scrollDelta;
scroll.ClampScrollY();
RecreateBlockInfoTexture();
MoveCursorToSelected();
}
public override bool HandlesMouseScroll(float delta) {
int startScrollY = scroll.ScrollY;
bool bounds = Contains(TableX - scroll.Width, TableY, TableWidth + scroll.Width,
TableHeight, game.Mouse.X, game.Mouse.Y);
if (!bounds) return false;
scroll.HandlesMouseScroll(delta);
if (SelectedIndex == - 1) return true;
SelectedIndex += (scroll.ScrollY - startScrollY) * ElementsPerRow;
if (SelectedIndex >= Elements.Length) SelectedIndex = -1;
RecreateBlockInfoTexture();
return true;
}
public override bool HandlesMouseUp(int mouseX, int mouseY, MouseButton button) {
return scroll.HandlesMouseUp(mouseX, mouseY, button);
}
}
}

View File

@ -87,13 +87,11 @@
<Compile Include="2D\Screens\ClickableScreen.cs" />
<Compile Include="2D\Screens\DeathScreen.cs" />
<Compile Include="2D\Screens\DisconnectScreen.cs" />
<Compile Include="2D\Screens\InventoryScreen.cs" />
<Compile Include="2D\Screens\Overlays\Overlay.cs" />
<Compile Include="2D\Screens\Overlays\TexIdsOverlay.cs" />
<Compile Include="2D\Screens\Overlays\WarningOverlay.cs" />
<Compile Include="2D\Screens\StatusScreen.cs" />
<Compile Include="2D\Screens\Inventory\InventoryScreen.cs" />
<Compile Include="2D\Screens\Inventory\InventoryScreen.Input.cs" />
<Compile Include="2D\Screens\Inventory\InventoryScreen.Scrolling.cs" />
<Compile Include="2D\Screens\LoadingMapScreen.cs" />
<Compile Include="2D\Screens\MenuScreen.cs" />
<Compile Include="2D\Screens\Menu\ClassicOptionsScreen.cs" />
@ -135,7 +133,9 @@
<Compile Include="2D\Widgets\PlayerList\ExtPlayerListWidget.cs" />
<Compile Include="2D\Widgets\PlayerList\NormalPlayerListWidget.cs" />
<Compile Include="2D\Widgets\PlayerList\PlayerListWidget.cs" />
<Compile Include="2D\Widgets\ScrollbarWidget.cs" />
<Compile Include="2D\Widgets\SurvivalHotbarWidget.cs" />
<Compile Include="2D\Widgets\TableWidget.cs" />
<Compile Include="2D\Widgets\TextWidget.cs" />
<Compile Include="2D\Widgets\Widget.cs" />
<Compile Include="Audio\AudioPlayer.cs" />
@ -328,7 +328,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="2D\Drawing" />
<Folder Include="2D\Screens\Inventory" />
<Folder Include="2D\Screens\Overlays" />
<Folder Include="2D\Utils" />
<Folder Include="2D\Screens" />

View File

@ -1,5 +1,5 @@
#ifndef CS_DATETIME_H
#define CS_DATETIME_H
#ifndef CS_WORDWRAP_H
#define CS_WORDWRAP_H
#include "Typedefs.h"
#include "String.h"
/* Allows wrapping a single line of text into multiple lines.