mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 12:05:14 -04:00
Break up the giant InventoryScreen class to be more modular.
(separate table widget, and scrollbar widget)
This commit is contained in:
parent
aa4d06537b
commit
43752348bf
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
109
ClassicalSharp/2D/Screens/InventoryScreen.cs
Normal file
109
ClassicalSharp/2D/Screens/InventoryScreen.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
329
ClassicalSharp/2D/Widgets/TableWidget.cs
Normal file
329
ClassicalSharp/2D/Widgets/TableWidget.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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" />
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user