From 4032a89563f5cc5e5fabed66ad073f37f12aa530 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Jan 2022 11:00:28 +1100 Subject: [PATCH] WIP on merging TableWidget and InventoryScreen --- src/Screens.c | 398 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/Widgets.c | 368 +--------------------------------------------- src/Widgets.h | 1 + 3 files changed, 389 insertions(+), 378 deletions(-) diff --git a/src/Screens.c b/src/Screens.c index 4946702ce..52157de12 100644 --- a/src/Screens.c +++ b/src/Screens.c @@ -21,6 +21,7 @@ #include "World.h" #include "Input.h" #include "Utils.h" +#include "IsometricDrawer.h" #define CHAT_MAX_STATUS Array_Elems(Chat_Status) #define CHAT_MAX_BOTTOMRIGHT Array_Elems(Chat_BottomRight) @@ -1401,11 +1402,388 @@ static struct InventoryScreen { struct FontDesc font; struct TableWidget table; cc_bool releasedInv, deferredSelect; + + /* Table fields */ + int x, y, width, height; + cc_bool active; + cc_bool disabled; + cc_uint8 horAnchor, verAnchor; + int xOffset, yOffset; + Widget_LeftClick MenuClick; + int blocksCount, blocksPerRow; + int rowsTotal, rowsVisible; + int lastCreatedIndex; + int selectedIndex, cellSizeX, cellSizeY; + float selBlockExpand; + cc_bool pendingClose; + float scale; + + BlockID blocks[BLOCK_COUNT]; + struct ScrollbarWidget scroll; + struct Texture descTex; + int lastX, lastY, paddingX; + int paddingTopY, paddingMaxY; } InventoryScreen_Instance; +static int Table_X(struct InventoryScreen* s) { return s->x - s->paddingX; } +static int Table_Y(struct InventoryScreen* s) { return s->y - s->paddingTopY; } +static int Table_Width(struct InventoryScreen* s) { + return s->blocksPerRow * s->cellSizeX + s->paddingX * 2; +} +static int Table_Height(struct InventoryScreen* s) { + return s->rowsVisible * s->cellSizeY + s->paddingTopY + s->paddingMaxY; +} + +#define TABLE_MAX_VERTICES (8 * 10 * ISOMETRICDRAWER_MAXVERTICES) + +static cc_bool TableWidget_GetCoords(struct InventoryScreen* s, int i, int* cellX, int* cellY) { + int x, y; + x = i % s->blocksPerRow; + y = i / s->blocksPerRow - s->scroll.topRow; + + *cellX = s->x + s->cellSizeX * x; + *cellY = s->y + s->cellSizeY * y + 3; + return y >= 0 && y < s->rowsVisible; +} + +static void TableWidget_MoveCursorToSelected(struct InventoryScreen* s) { + int x, y, idx; + if (s->selectedIndex == -1) return; + + idx = s->selectedIndex; + TableWidget_GetCoords(s, idx, &x, &y); + + x += s->cellSizeX / 2; y += s->cellSizeY / 2; + Cursor_SetPosition(x, y); +} + +static void TableWidget_MakeBlockDesc(struct InventoryScreen* s, cc_string* desc, BlockID block) { + cc_string name; + int block_ = block; + if (Game_PureClassic) { String_AppendConst(desc, "Select block"); return; } + if (block == BLOCK_AIR) return; + + name = Block_UNSAFE_GetName(block); + String_AppendString(desc, &name); + if (Game_ClassicMode) return; + + String_Format1(desc, " (ID %i&f", &block_); + if (!Blocks.CanPlace[block]) { String_AppendConst(desc, ", place &cNo&f"); } + if (!Blocks.CanDelete[block]) { String_AppendConst(desc, ", delete &cNo&f"); } + String_Append(desc, ')'); +} + +static void TableWidget_UpdateDescTexPos(struct InventoryScreen* s) { + s->descTex.X = s->x + s->width / 2 - s->descTex.Width / 2; + s->descTex.Y = s->y - s->descTex.Height - 5; +} + +static void TableWidget_RecreateDescTex(struct InventoryScreen* s) { + BlockID block; + if (s->selectedIndex == s->lastCreatedIndex) return; + if (s->blocksCount == 0) return; + s->lastCreatedIndex = s->selectedIndex; + + block = s->selectedIndex == -1 ? BLOCK_AIR : s->blocks[s->selectedIndex]; + TableWidget_MakeDescTex(s, block); +} + +void TableWidget_MakeDescTex(struct InventoryScreen* s, BlockID block) { + cc_string desc; char descBuffer[STRING_SIZE * 2]; + struct DrawTextArgs args; + + Gfx_DeleteTexture(&s->descTex.ID); + String_InitArray(desc, descBuffer); + TableWidget_MakeBlockDesc(s, &desc, block); + if (!desc.length) return; + + DrawTextArgs_Make(&args, &desc, &s->font, true); + Drawer2D_MakeTextTexture(&s->descTex, &args); + TableWidget_UpdateDescTexPos(s); +} + +static cc_bool TableWidget_RowEmpty(struct InventoryScreen* s, int start) { + int i, end = min(start + s->blocksPerRow, Array_Elems(Inventory.Map)); + + for (i = start; i < end; i++) { + if (Inventory.Map[i] != BLOCK_AIR) return false; + } + return true; +} + +void TableWidget_RecreateBlocks(struct InventoryScreen* s) { + int i, max = Game_UseCPEBlocks ? BLOCK_COUNT : BLOCK_ORIGINAL_COUNT; + BlockID block; + s->blocksCount = 0; + + for (i = 0; i < Array_Elems(Inventory.Map); ) { + if ((i % s->blocksPerRow) == 0 && TableWidget_RowEmpty(s, i)) { + i += s->blocksPerRow; continue; + } + + block = Inventory.Map[i]; + if (block < max) { s->blocks[s->blocksCount++] = block; } + i++; + } + + s->rowsTotal = Math_CeilDiv(s->blocksCount, s->blocksPerRow); + Widget_Layout(s); +} + +static void TableWidget_Render(void* widget, double delta) { + struct InventoryScreen* s = (struct InventoryScreen*)widget; + struct VertexTextured vertices[TABLE_MAX_VERTICES]; + int cellSizeX, cellSizeY, size; + float off; + int i, x, y; + + /* These were sourced by taking a screenshot of vanilla */ + /* Then using paint to extract the color components */ + /* Then using wolfram alpha to solve the glblendfunc equation */ + PackedCol topBackColor = PackedCol_Make( 34, 34, 34, 168); + PackedCol bottomBackColor = PackedCol_Make( 57, 57, 104, 202); + PackedCol topSelColor = PackedCol_Make(255, 255, 255, 142); + PackedCol bottomSelColor = PackedCol_Make(255, 255, 255, 192); + + Gfx_Draw2DGradient(Table_X(s), Table_Y(s), + Table_Width(s), Table_Height(s), topBackColor, bottomBackColor); + + if (s->rowsVisible < s->rowsTotal) { + Elem_Render(&s->scroll, delta); + } + + cellSizeX = s->cellSizeX; + cellSizeY = s->cellSizeY; + if (s->selectedIndex != -1 && Game_ClassicMode && s->blocks[s->selectedIndex] != BLOCK_AIR) { + TableWidget_GetCoords(s, s->selectedIndex, &x, &y); + + /* TODO: Need two size arguments, in case X/Y dpi differs */ + off = cellSizeX * 0.1f; + size = (int)(cellSizeX + off * 2); + Gfx_Draw2DGradient((int)(x - off), (int)(y - off), + size, size, topSelColor, bottomSelColor); + } + Gfx_SetTexturing(true); + Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); + + IsometricDrawer_BeginBatch(vertices, s->vb); + for (i = 0; i < s->blocksCount; i++) { + if (!TableWidget_GetCoords(s, i, &x, &y)) continue; + + /* We want to always draw the selected block on top of others */ + /* TODO: Need two size arguments, in case X/Y dpi differs */ + if (i == s->selectedIndex) continue; + IsometricDrawer_DrawBatch(s->blocks[i], cellSizeX * 0.7f / 2.0f, + x + cellSizeX / 2, y + cellSizeY / 2); + } + + i = s->selectedIndex; + if (i != -1) { + TableWidget_GetCoords(s, i, &x, &y); + + IsometricDrawer_DrawBatch(s->blocks[i], + (cellSizeX + s->selBlockExpand) * 0.7f / 2.0f, + x + cellSizeX / 2, y + cellSizeY / 2); + } + IsometricDrawer_EndBatch(); + + if (s->descTex.ID) { Texture_Render(&s->descTex); } + Gfx_SetTexturing(false); +} + +static void TableWidget_Free(void* widget) { + struct InventoryScreen* s = (struct InventoryScreen*)widget; + Gfx_DeleteDynamicVb(&s->vb); + Gfx_DeleteTexture(&s->descTex.ID); + s->lastCreatedIndex = -1000; +} + +void TableWidget_Recreate(struct InventoryScreen* s) { + Elem_Free(s); + Gfx_RecreateDynamicVb(&s->vb, VERTEX_FORMAT_TEXTURED, TABLE_MAX_VERTICES); + TableWidget_RecreateDescTex(s); +} + +static void TableWidget_Reposition(void* widget) { + struct InventoryScreen* s = (struct InventoryScreen*)widget; + float scale = s->scale; + int cellSize; + + cellSize = (int)(50 * Math_SqrtF(scale)); + s->cellSizeX = Display_ScaleX(cellSize); + s->cellSizeY = Display_ScaleY(cellSize); + + s->selBlockExpand = 25.0f * Math_SqrtF(scale); + s->rowsVisible = min(8, s->rowsTotal); /* 8 rows max */ + + do { + s->width = s->cellSizeX * s->blocksPerRow; + s->height = s->cellSizeY * s->rowsVisible; + Widget_CalcPosition(s); + TableWidget_UpdateDescTexPos(s); + + /* Does the table fit on screen? */ + if (Game_ClassicMode || Table_Y(s) >= 0) break; + s->rowsVisible--; + } while (s->rowsVisible > 1); + + s->scroll.x = Table_X(s) + Table_Width(s); + s->scroll.y = Table_Y(s); + s->scroll.height = Table_Height(s); + s->scroll.rowsTotal = s->rowsTotal; + s->scroll.rowsVisible = s->rowsVisible; +} + +static void TableWidget_ScrollRelative(struct InventoryScreen* s, int delta) { + int start = s->selectedIndex, index = start; + index += delta; + if (index < 0) index -= delta; + if (index >= s->blocksCount) index -= delta; + s->selectedIndex = index; + + /* adjust scrollbar by number of rows moved up/down */ + s->scroll.topRow += (index / s->blocksPerRow) - (start / s->blocksPerRow); + ScrollbarWidget_ClampTopRow(&s->scroll); + + TableWidget_RecreateDescTex(s); + TableWidget_MoveCursorToSelected(s); +} + +static int TableWidget_PointerDown(void* widget, int id, int x, int y) { + struct InventoryScreen* s = (struct InventoryScreen*)widget; + s->pendingClose = false; + + if (Elem_HandlesPointerDown(&s->scroll, id, x, y)) { + return TOUCH_TYPE_GUI; + } else if (s->selectedIndex != -1 && s->blocks[s->selectedIndex] != BLOCK_AIR) { + Inventory_SetSelectedBlock(s->blocks[s->selectedIndex]); + s->pendingClose = true; + return TOUCH_TYPE_GUI; + } else if (Gui_Contains(Table_X(s), Table_Y(s), Table_Width(s), Table_Height(s), x, y)) { + return TOUCH_TYPE_GUI; + } + return false; +} + +static void TableWidget_PointerUp(void* widget, int id, int x, int y) { + struct InventoryScreen* s = (struct InventoryScreen*)widget; + Elem_OnPointerUp(&s->scroll, id, x, y); +} + +static int TableWidget_MouseScroll(void* widget, float delta) { + struct InventoryScreen* s = (struct InventoryScreen*)widget; + int origTopRow, index; + + cc_bool bounds = Gui_ContainsPointers(Table_X(s), Table_Y(s), + Table_Width(s) + s->scroll.width, Table_Height(s)); + if (!bounds) return false; + + origTopRow = s->scroll.topRow; + Elem_HandlesMouseScroll(&s->scroll, delta); + if (s->selectedIndex == -1) return true; + + index = s->selectedIndex; + index += (s->scroll.topRow - origTopRow) * s->blocksPerRow; + if (index >= s->blocksCount) index = -1; + + s->selectedIndex = index; + TableWidget_RecreateDescTex(s); + return true; +} + +static int TableWidget_PointerMove(void* widget, int id, int x, int y) { + struct InventoryScreen* s = (struct TableWidget*)widget; + int cellSizeX, cellSizeY, maxHeight; + int i, cellX, cellY; + + if (Elem_HandlesPointerMove(&s->scroll, id, x, y)) return true; + if (s->lastX == x && s->lastY == y) return true; + s->lastX = x; s->lastY = y; + + s->selectedIndex = -1; + cellSizeX = s->cellSizeX; + cellSizeY = s->cellSizeY; + maxHeight = cellSizeY * s->rowsVisible; + + if (Gui_Contains(s->x, s->y + 3, s->width, maxHeight - 3 * 2, x, y)) { + for (i = 0; i < s->blocksCount; i++) { + TableWidget_GetCoords(s, i, &cellX, &cellY); + + if (Gui_Contains(cellX, cellY, cellSizeX, cellSizeY, x, y)) { + s->selectedIndex = i; + break; + } + } + } + TableWidget_RecreateDescTex(s); + return true; +} + +static int TableWidget_KeyDown(void* widget, int key) { + struct InventoryScreen* s = (struct TableWidget*)widget; + if (s->selectedIndex == -1) return false; + + if (key == KEY_LEFT || key == KEY_KP4) { + TableWidget_ScrollRelative(s, -1); + } else if (key == KEY_RIGHT || key == KEY_KP6) { + TableWidget_ScrollRelative(s, 1); + } else if (key == KEY_UP || key == KEY_KP8) { + TableWidget_ScrollRelative(s, -s->blocksPerRow); + } else if (key == KEY_DOWN || key == KEY_KP2) { + TableWidget_ScrollRelative(s, s->blocksPerRow); + } else { + return false; + } + return true; +} + +void TableWidget_Create(struct InventoryScreen* s) { + Widget_Reset(s); + s->lastCreatedIndex = -1000; + ScrollbarWidget_Create(&s->scroll); + + s->horAnchor = ANCHOR_CENTRE; + s->verAnchor = ANCHOR_CENTRE; + s->lastX = -20; s->lastY = -20; + s->scale = 1; + + s->paddingX = Display_ScaleX(15); + s->paddingTopY = Display_ScaleY(15 + 20); + s->paddingMaxY = Display_ScaleX(15); +} + +void TableWidget_SetBlockTo(struct InventoryScreen* s, BlockID block) { + int i; + s->selectedIndex = -1; + + for (i = 0; i < s->blocksCount; i++) { + if (s->blocks[i] == block) s->selectedIndex = i; + } + /* When holding air, inventory should open at middle */ + if (block == BLOCK_AIR) s->selectedIndex = -1; + + s->scroll.topRow = s->selectedIndex / s->blocksPerRow; + s->scroll.topRow -= (s->rowsVisible - 1); + ScrollbarWidget_ClampTopRow(&s->scroll); + TableWidget_MoveCursorToSelected(s); + TableWidget_RecreateDescTex(s); +} + +void TableWidget_OnInventoryChanged(struct InventoryScreen* s) { + TableWidget_RecreateBlocks(s); + if (s->selectedIndex >= s->blocksCount) { + s->selectedIndex = s->blocksCount - 1; + } + s->lastX = -1; s->lastY = -1; + + s->scroll.topRow = s->selectedIndex / s->blocksPerRow; + ScrollbarWidget_ClampTopRow(&s->scroll); + TableWidget_RecreateDescTex(s); +} + static void InventoryScreen_OnBlockChanged(void* screen) { struct InventoryScreen* s = (struct InventoryScreen*)screen; - TableWidget_OnInventoryChanged(&s->table); + TableWidget_OnInventoryChanged(s); } static void InventoryScreen_ContextLost(void* screen) { @@ -1417,30 +1795,28 @@ static void InventoryScreen_ContextLost(void* screen) { static void InventoryScreen_ContextRecreated(void* screen) { struct InventoryScreen* s = (struct InventoryScreen*)screen; Gui_MakeBodyFont(&s->font); - TableWidget_Recreate(&s->table); + TableWidget_Recreate(s); } static void InventoryScreen_BuildMesh(void* screen) { } static void InventoryScreen_MoveToSelected(struct InventoryScreen* s) { - struct TableWidget* table = &s->table; - TableWidget_SetBlockTo(table, Inventory_SelectedBlock); - TableWidget_Recreate(table); + TableWidget_SetBlockTo(s, Inventory_SelectedBlock); + TableWidget_Recreate(s); s->deferredSelect = false; /* User is holding invalid block */ - if (table->selectedIndex == -1) { - TableWidget_MakeDescTex(table, Inventory_SelectedBlock); + if (s->selectedIndex == -1) { + TableWidget_MakeDescTex(s, Inventory_SelectedBlock); } } static void InventoryScreen_Init(void* screen) { struct InventoryScreen* s = (struct InventoryScreen*)screen; - TableWidget_Create(&s->table); - s->table.font = &s->font; - s->table.blocksPerRow = Inventory.BlocksPerRow; - TableWidget_RecreateBlocks(&s->table); + TableWidget_Create(s); + s->blocksPerRow = Inventory.BlocksPerRow; + TableWidget_RecreateBlocks(s); /* Can't immediately move to selected here, because cursor grabbed */ /* status might be toggled after InventoryScreen_Init() is called. */ diff --git a/src/Widgets.c b/src/Widgets.c index 6c73f70f4..8a6644631 100644 --- a/src/Widgets.c +++ b/src/Widgets.c @@ -255,7 +255,7 @@ void ButtonWidget_SetConst(struct ButtonWidget* w, const char* text, struct Font #define SCROLL_BAR_COL PackedCol_Make(100, 100, 100, 220) #define SCROLL_HOVER_COL PackedCol_Make(122, 122, 122, 220) -static void ScrollbarWidget_ClampTopRow(struct ScrollbarWidget* w) { +void ScrollbarWidget_ClampTopRow(struct ScrollbarWidget* w) { int maxTop = w->rowsTotal - w->rowsVisible; if (w->topRow >= maxTop) w->topRow = maxTop; if (w->topRow < 0) w->topRow = 0; @@ -629,372 +629,6 @@ void HotbarWidget_SetFont(struct HotbarWidget* w, struct FontDesc* font) { } -/*########################################################################################################################* -*-------------------------------------------------------TableWidget-------------------------------------------------------* -*#########################################################################################################################*/ -static int Table_X(struct TableWidget* w) { return w->x - w->paddingX; } -static int Table_Y(struct TableWidget* w) { return w->y - w->paddingTopY; } -static int Table_Width(struct TableWidget* w) { - return w->blocksPerRow * w->cellSizeX + w->paddingX * 2; -} -static int Table_Height(struct TableWidget* w) { - return w->rowsVisible * w->cellSizeY + w->paddingTopY + w->paddingMaxY; -} - -#define TABLE_MAX_VERTICES (8 * 10 * ISOMETRICDRAWER_MAXVERTICES) - -static cc_bool TableWidget_GetCoords(struct TableWidget* w, int i, int* cellX, int* cellY) { - int x, y; - x = i % w->blocksPerRow; - y = i / w->blocksPerRow - w->scroll.topRow; - - *cellX = w->x + w->cellSizeX * x; - *cellY = w->y + w->cellSizeY * y + 3; - return y >= 0 && y < w->rowsVisible; -} - -static void TableWidget_MoveCursorToSelected(struct TableWidget* w) { - int x, y, idx; - if (w->selectedIndex == -1) return; - - idx = w->selectedIndex; - TableWidget_GetCoords(w, idx, &x, &y); - - x += w->cellSizeX / 2; y += w->cellSizeY / 2; - Cursor_SetPosition(x, y); -} - -static void TableWidget_MakeBlockDesc(struct TableWidget* w, cc_string* desc, BlockID block) { - cc_string name; - int block_ = block; - if (Game_PureClassic) { String_AppendConst(desc, "Select block"); return; } - if (block == BLOCK_AIR) return; - - name = Block_UNSAFE_GetName(block); - String_AppendString(desc, &name); - if (Game_ClassicMode) return; - - String_Format1(desc, " (ID %i&f", &block_); - if (!Blocks.CanPlace[block]) { String_AppendConst(desc, ", place &cNo&f"); } - if (!Blocks.CanDelete[block]) { String_AppendConst(desc, ", delete &cNo&f"); } - String_Append(desc, ')'); -} - -static void TableWidget_UpdateDescTexPos(struct TableWidget* w) { - w->descTex.X = w->x + w->width / 2 - w->descTex.Width / 2; - w->descTex.Y = w->y - w->descTex.Height - 5; -} - -static void TableWidget_RecreateDescTex(struct TableWidget* w) { - BlockID block; - if (w->selectedIndex == w->lastCreatedIndex) return; - if (w->blocksCount == 0) return; - w->lastCreatedIndex = w->selectedIndex; - - block = w->selectedIndex == -1 ? BLOCK_AIR : w->blocks[w->selectedIndex]; - TableWidget_MakeDescTex(w, block); -} - -void TableWidget_MakeDescTex(struct TableWidget* w, BlockID block) { - cc_string desc; char descBuffer[STRING_SIZE * 2]; - struct DrawTextArgs args; - - Gfx_DeleteTexture(&w->descTex.ID); - String_InitArray(desc, descBuffer); - TableWidget_MakeBlockDesc(w, &desc, block); - if (!desc.length) return; - - DrawTextArgs_Make(&args, &desc, w->font, true); - Drawer2D_MakeTextTexture(&w->descTex, &args); - TableWidget_UpdateDescTexPos(w); -} - -static cc_bool TableWidget_RowEmpty(struct TableWidget* w, int start) { - int i, end = min(start + w->blocksPerRow, Array_Elems(Inventory.Map)); - - for (i = start; i < end; i++) { - if (Inventory.Map[i] != BLOCK_AIR) return false; - } - return true; -} - -void TableWidget_RecreateBlocks(struct TableWidget* w) { - int i, max = Game_UseCPEBlocks ? BLOCK_COUNT : BLOCK_ORIGINAL_COUNT; - BlockID block; - w->blocksCount = 0; - - for (i = 0; i < Array_Elems(Inventory.Map); ) { - if ((i % w->blocksPerRow) == 0 && TableWidget_RowEmpty(w, i)) { - i += w->blocksPerRow; continue; - } - - block = Inventory.Map[i]; - if (block < max) { w->blocks[w->blocksCount++] = block; } - i++; - } - - w->rowsTotal = Math_CeilDiv(w->blocksCount, w->blocksPerRow); - Widget_Layout(w); -} - -static void TableWidget_Render(void* widget, double delta) { - struct TableWidget* w = (struct TableWidget*)widget; - struct VertexTextured vertices[TABLE_MAX_VERTICES]; - int cellSizeX, cellSizeY, size; - float off; - int i, x, y; - - /* These were sourced by taking a screenshot of vanilla */ - /* Then using paint to extract the color components */ - /* Then using wolfram alpha to solve the glblendfunc equation */ - PackedCol topBackColor = PackedCol_Make( 34, 34, 34, 168); - PackedCol bottomBackColor = PackedCol_Make( 57, 57, 104, 202); - PackedCol topSelColor = PackedCol_Make(255, 255, 255, 142); - PackedCol bottomSelColor = PackedCol_Make(255, 255, 255, 192); - - Gfx_Draw2DGradient(Table_X(w), Table_Y(w), - Table_Width(w), Table_Height(w), topBackColor, bottomBackColor); - - if (w->rowsVisible < w->rowsTotal) { - Elem_Render(&w->scroll, delta); - } - - cellSizeX = w->cellSizeX; - cellSizeY = w->cellSizeY; - if (w->selectedIndex != -1 && Game_ClassicMode && w->blocks[w->selectedIndex] != BLOCK_AIR) { - TableWidget_GetCoords(w, w->selectedIndex, &x, &y); - - /* TODO: Need two size arguments, in case X/Y dpi differs */ - off = cellSizeX * 0.1f; - size = (int)(cellSizeX + off * 2); - Gfx_Draw2DGradient((int)(x - off), (int)(y - off), - size, size, topSelColor, bottomSelColor); - } - Gfx_SetTexturing(true); - Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); - - IsometricDrawer_BeginBatch(vertices, w->vb); - for (i = 0; i < w->blocksCount; i++) { - if (!TableWidget_GetCoords(w, i, &x, &y)) continue; - - /* We want to always draw the selected block on top of others */ - /* TODO: Need two size arguments, in case X/Y dpi differs */ - if (i == w->selectedIndex) continue; - IsometricDrawer_DrawBatch(w->blocks[i], cellSizeX * 0.7f / 2.0f, - x + cellSizeX / 2, y + cellSizeY / 2); - } - - i = w->selectedIndex; - if (i != -1) { - TableWidget_GetCoords(w, i, &x, &y); - - IsometricDrawer_DrawBatch(w->blocks[i], - (cellSizeX + w->selBlockExpand) * 0.7f / 2.0f, - x + cellSizeX / 2, y + cellSizeY / 2); - } - IsometricDrawer_EndBatch(); - - if (w->descTex.ID) { Texture_Render(&w->descTex); } - Gfx_SetTexturing(false); -} - -static void TableWidget_Free(void* widget) { - struct TableWidget* w = (struct TableWidget*)widget; - Gfx_DeleteDynamicVb(&w->vb); - Gfx_DeleteTexture(&w->descTex.ID); - w->lastCreatedIndex = -1000; -} - -void TableWidget_Recreate(struct TableWidget* w) { - Elem_Free(w); - Gfx_RecreateDynamicVb(&w->vb, VERTEX_FORMAT_TEXTURED, TABLE_MAX_VERTICES); - TableWidget_RecreateDescTex(w); -} - -static void TableWidget_Reposition(void* widget) { - struct TableWidget* w = (struct TableWidget*)widget; - float scale = w->scale; - int cellSize; - - cellSize = (int)(50 * Math_SqrtF(scale)); - w->cellSizeX = Display_ScaleX(cellSize); - w->cellSizeY = Display_ScaleY(cellSize); - - w->selBlockExpand = 25.0f * Math_SqrtF(scale); - w->rowsVisible = min(8, w->rowsTotal); /* 8 rows max */ - - do { - w->width = w->cellSizeX * w->blocksPerRow; - w->height = w->cellSizeY * w->rowsVisible; - Widget_CalcPosition(w); - TableWidget_UpdateDescTexPos(w); - - /* Does the table fit on screen? */ - if (Game_ClassicMode || Table_Y(w) >= 0) break; - w->rowsVisible--; - } while (w->rowsVisible > 1); - - w->scroll.x = Table_X(w) + Table_Width(w); - w->scroll.y = Table_Y(w); - w->scroll.height = Table_Height(w); - w->scroll.rowsTotal = w->rowsTotal; - w->scroll.rowsVisible = w->rowsVisible; -} - -static void TableWidget_ScrollRelative(struct TableWidget* w, int delta) { - int start = w->selectedIndex, index = start; - index += delta; - if (index < 0) index -= delta; - if (index >= w->blocksCount) index -= delta; - w->selectedIndex = index; - - /* adjust scrollbar by number of rows moved up/down */ - w->scroll.topRow += (index / w->blocksPerRow) - (start / w->blocksPerRow); - ScrollbarWidget_ClampTopRow(&w->scroll); - - TableWidget_RecreateDescTex(w); - TableWidget_MoveCursorToSelected(w); -} - -static int TableWidget_PointerDown(void* widget, int id, int x, int y) { - struct TableWidget* w = (struct TableWidget*)widget; - w->pendingClose = false; - - if (Elem_HandlesPointerDown(&w->scroll, id, x, y)) { - return TOUCH_TYPE_GUI; - } else if (w->selectedIndex != -1 && w->blocks[w->selectedIndex] != BLOCK_AIR) { - Inventory_SetSelectedBlock(w->blocks[w->selectedIndex]); - w->pendingClose = true; - return TOUCH_TYPE_GUI; - } else if (Gui_Contains(Table_X(w), Table_Y(w), Table_Width(w), Table_Height(w), x, y)) { - return TOUCH_TYPE_GUI; - } - return false; -} - -static void TableWidget_PointerUp(void* widget, int id, int x, int y) { - struct TableWidget* w = (struct TableWidget*)widget; - Elem_OnPointerUp(&w->scroll, id, x, y); -} - -static int TableWidget_MouseScroll(void* widget, float delta) { - struct TableWidget* w = (struct TableWidget*)widget; - int origTopRow, index; - - cc_bool bounds = Gui_ContainsPointers(Table_X(w), Table_Y(w), - Table_Width(w) + w->scroll.width, Table_Height(w)); - if (!bounds) return false; - - origTopRow = w->scroll.topRow; - Elem_HandlesMouseScroll(&w->scroll, delta); - if (w->selectedIndex == -1) return true; - - index = w->selectedIndex; - index += (w->scroll.topRow - origTopRow) * w->blocksPerRow; - if (index >= w->blocksCount) index = -1; - - w->selectedIndex = index; - TableWidget_RecreateDescTex(w); - return true; -} - -static int TableWidget_PointerMove(void* widget, int id, int x, int y) { - struct TableWidget* w = (struct TableWidget*)widget; - int cellSizeX, cellSizeY, maxHeight; - int i, cellX, cellY; - - if (Elem_HandlesPointerMove(&w->scroll, id, x, y)) return true; - if (w->lastX == x && w->lastY == y) return true; - w->lastX = x; w->lastY = y; - - w->selectedIndex = -1; - cellSizeX = w->cellSizeX; - cellSizeY = w->cellSizeY; - maxHeight = cellSizeY * w->rowsVisible; - - if (Gui_Contains(w->x, w->y + 3, w->width, maxHeight - 3 * 2, x, y)) { - for (i = 0; i < w->blocksCount; i++) { - TableWidget_GetCoords(w, i, &cellX, &cellY); - - if (Gui_Contains(cellX, cellY, cellSizeX, cellSizeY, x, y)) { - w->selectedIndex = i; - break; - } - } - } - TableWidget_RecreateDescTex(w); - return true; -} - -static int TableWidget_KeyDown(void* widget, int key) { - struct TableWidget* w = (struct TableWidget*)widget; - if (w->selectedIndex == -1) return false; - - if (key == KEY_LEFT || key == KEY_KP4) { - TableWidget_ScrollRelative(w, -1); - } else if (key == KEY_RIGHT || key == KEY_KP6) { - TableWidget_ScrollRelative(w, 1); - } else if (key == KEY_UP || key == KEY_KP8) { - TableWidget_ScrollRelative(w, -w->blocksPerRow); - } else if (key == KEY_DOWN || key == KEY_KP2) { - TableWidget_ScrollRelative(w, w->blocksPerRow); - } else { - return false; - } - return true; -} - -static const struct WidgetVTABLE TableWidget_VTABLE = { - TableWidget_Render, TableWidget_Free, TableWidget_Reposition, - TableWidget_KeyDown, Widget_InputUp, TableWidget_MouseScroll, - TableWidget_PointerDown, TableWidget_PointerUp, TableWidget_PointerMove -}; -void TableWidget_Create(struct TableWidget* w) { - Widget_Reset(w); - w->VTABLE = &TableWidget_VTABLE; - w->lastCreatedIndex = -1000; - ScrollbarWidget_Create(&w->scroll); - - w->horAnchor = ANCHOR_CENTRE; - w->verAnchor = ANCHOR_CENTRE; - w->lastX = -20; w->lastY = -20; - w->scale = 1; - - w->paddingX = Display_ScaleX(15); - w->paddingTopY = Display_ScaleY(15 + 20); - w->paddingMaxY = Display_ScaleX(15); -} - -void TableWidget_SetBlockTo(struct TableWidget* w, BlockID block) { - int i; - w->selectedIndex = -1; - - for (i = 0; i < w->blocksCount; i++) { - if (w->blocks[i] == block) w->selectedIndex = i; - } - /* When holding air, inventory should open at middle */ - if (block == BLOCK_AIR) w->selectedIndex = -1; - - w->scroll.topRow = w->selectedIndex / w->blocksPerRow; - w->scroll.topRow -= (w->rowsVisible - 1); - ScrollbarWidget_ClampTopRow(&w->scroll); - TableWidget_MoveCursorToSelected(w); - TableWidget_RecreateDescTex(w); -} - -void TableWidget_OnInventoryChanged(struct TableWidget* w) { - TableWidget_RecreateBlocks(w); - if (w->selectedIndex >= w->blocksCount) { - w->selectedIndex = w->blocksCount - 1; - } - w->lastX = -1; w->lastY = -1; - - w->scroll.topRow = w->selectedIndex / w->blocksPerRow; - ScrollbarWidget_ClampTopRow(&w->scroll); - TableWidget_RecreateDescTex(w); -} - - /*########################################################################################################################* *-------------------------------------------------------InputWidget-------------------------------------------------------* *#########################################################################################################################*/ diff --git a/src/Widgets.h b/src/Widgets.h index 5987af05a..dd0d0269f 100644 --- a/src/Widgets.h +++ b/src/Widgets.h @@ -62,6 +62,7 @@ struct ScrollbarWidget { }; /* Resets state of the given scrollbar widget to default. */ CC_NOINLINE void ScrollbarWidget_Create(struct ScrollbarWidget* w); +CC_NOINLINE void ScrollbarWidget_ClampTopRow(struct ScrollbarWidget* w); /* A row of blocks with a background. */ struct HotbarWidget {