#ifndef CC_GUI_H #define CC_GUI_H #include "Core.h" /* Describes and manages 2D GUI elements on screen. Copyright 2014-2023 ClassiCube | Licensed under BSD-3 */ enum GuiAnchor { ANCHOR_MIN, /* = offset */ ANCHOR_CENTRE, /* = (axis/2) - (size/2) - offset; */ ANCHOR_MAX, /* = axis - size - offset */ ANCHOR_CENTRE_MIN, /* = (axis/2) + offset */ ANCHOR_CENTRE_MAX /* = (axis/2) - size - offset */ }; struct IGameComponent; struct VertexTextured; struct FontDesc; struct Widget; extern struct IGameComponent Gui_Component; CC_VAR extern struct _GuiData { /* The list of screens currently shown. */ struct Screen** Screens; /* The number of screens currently shown. */ int ScreensCount; /* Whether vanilla Minecraft Classic gui texture is used. */ cc_bool ClassicTexture; /* Whether tab list is laid out like vanilla Minecraft Classic. */ cc_bool ClassicTabList; /* Whether menus are laid out like vanilla Minecraft Classic. */ cc_bool ClassicMenu; /* Whether classic-style chat screen is used */ cc_bool ClassicChat; /* Maximum number of visible chatlines on screen. Can be 0. */ int Chatlines; /* Whether clicking on a chatline inserts it into chat input. */ cc_bool ClickableChat; /* Whether pressing tab in chat input attempts to autocomplete player names. */ cc_bool TabAutocomplete; /* Whether FPS counter (and other info) is shown in top left. */ cc_bool ShowFPS; /* Whether classic-style inventory is used */ cc_bool ClassicInventory; float RawHotbarScale, RawChatScale, RawInventoryScale, RawCrosshairScale; GfxResourceID GuiTex, GuiClassicTex, IconsTex, TouchTex; int DefaultLines; int _unused; float RawTouchScale; /* The highest priority screen that has grabbed input. */ struct Screen* InputGrab; /* Whether chat automatically scales based on window size. */ cc_bool AutoScaleChat; /* Whether the touch UI is currently being displayed */ cc_bool TouchUI; } Gui; #ifdef CC_BUILD_TOUCH #define Gui_TouchUI Gui.TouchUI #else #define Gui_TouchUI false #endif float Gui_Scale(float value); float Gui_GetHotbarScale(void); float Gui_GetInventoryScale(void); float Gui_GetChatScale(void); float Gui_GetCrosshairScale(void); CC_NOINLINE void Gui_MakeTitleFont(struct FontDesc* font); CC_NOINLINE void Gui_MakeBodyFont(struct FontDesc* font); /* Functions for a Screen instance. */ struct ScreenVTABLE { /* Initialises persistent state. */ void (*Init)(void* elem); /* Updates this screen, called every frame just before Render(). */ void (*Update)(void* elem, float delta); /* Frees/releases persistent state. */ void (*Free)(void* elem); /* Draws this screen and its widgets on screen. */ void (*Render)(void* elem, float delta); /* Builds the vertex mesh for all the widgets in the screen. */ void (*BuildMesh)(void* elem); /* Returns non-zero if an input press is handled. */ int (*HandlesInputDown)(void* elem, int key); /* Called when an input key or button is released */ void (*OnInputUp)(void* elem, int key); /* Returns non-zero if a key character press is handled. */ int (*HandlesKeyPress)(void* elem, char keyChar); /* Returns non-zero if on-screen keyboard text changed is handled. */ int (*HandlesTextChanged)(void* elem, const cc_string* str); /* Returns non-zero if a pointer press is handled. */ int (*HandlesPointerDown)(void* elem, int id, int x, int y); /* Called when a pointer is released. */ void (*OnPointerUp)(void* elem, int id, int x, int y); /* Returns non-zero if a pointer movement is handled. */ int (*HandlesPointerMove)(void* elem, int id, int x, int y); /* Returns non-zero if a mouse wheel scroll is handled. */ int (*HandlesMouseScroll)(void* elem, float delta); /* Positions widgets on screen. Typically called on window resize. */ void (*Layout)(void* elem); /* Destroys graphics resources. (textures, vertex buffers, etc) */ void (*ContextLost)(void* elem); /* Allocates graphics resources. (textures, vertex buffers, etc) */ void (*ContextRecreated)(void* elem); /* Returns non-zero if a pad axis update is handled. */ int (*HandlesPadAxis)(void* elem, int axis, float x, float y); }; #define Screen_Body const struct ScreenVTABLE* VTABLE; \ cc_bool grabsInput; /* Whether this screen grabs input. Causes the cursor to become visible. */ \ cc_bool blocksWorld; /* Whether this screen completely and opaquely covers the game world behind it. */ \ cc_bool closable; /* Whether this screen is automatically closed when pressing Escape */ \ cc_bool dirty; /* Whether this screens needs to have its mesh rebuilt. */ \ int maxVertices; GfxResourceID vb; /* Vertex buffer storing the contents of the screen */ \ struct Widget** widgets; int numWidgets; /* The widgets/individual elements in the screen */ \ int selectedI, maxWidgets; /* Represents a container of widgets and other 2D elements. May cover entire window. */ struct Screen { Screen_Body }; /* Calls Widget_Render2 on each widget in the screen. */ void Screen_Render2Widgets(void* screen, float delta); void Screen_UpdateVb(void* screen); struct VertexTextured* Screen_LockVb(void* screen); int Screen_DoPointerDown(void* screen, int id, int x, int y); int Screen_CalcDefaultMaxVertices(void* screen); /* Default mesh building implementation for a screen */ /* (Locks vb, calls Widget_BuildMesh on each widget, then unlocks vb) */ void Screen_BuildMesh(void* screen); /* Default layout implementation for a screen */ /* (Calls Widget_Layout on each widget) */ void Screen_Layout(void* screen); /* Default context lost implementation for a screen */ /* (Deletes vb, then calls Elem_Free on each widget) */ void Screen_ContextLost(void* screen); /* Default input down implementation for a screen */ /* (returns true if key is NOT a function key) */ int Screen_InputDown(void* screen, int key); /* Default input up implementation for a screen */ /* (does nothing) */ void Screen_InputUp(void* screen, int key); /* Default pointer release implementation for a screen */ /* (does nothing) */ void Screen_PointerUp(void* s, int id, int x, int y); typedef void (*Widget_LeftClick)(void* screen, void* widget); union WidgetMeta { int val; void* ptr; }; struct WidgetVTABLE { /* Draws this widget on-screen. */ void (*Render)(void* elem, float delta); /* Destroys allocated graphics resources. */ void (*Free)(void* elem); /* Positions this widget on-screen. */ void (*Reposition)(void* elem); /* Returns non-zero if an input press is handled. */ int (*HandlesKeyDown)(void* elem, int key); /* Called when an input key or button is released. */ void (*OnInputUp)(void* elem, int key); /* Returns non-zero if a mouse wheel scroll is handled. */ int (*HandlesMouseScroll)(void* elem, float delta); /* Returns non-zero if a pointer press is handled. */ int (*HandlesPointerDown)(void* elem, int id, int x, int y); /* Called when a pointer is released. */ void (*OnPointerUp)(void* elem, int id, int x, int y); /* Returns non-zero if a pointer movement is handled. */ int (*HandlesPointerMove)(void* elem, int id, int x, int y); /* Builds the mesh of vertices for this widget. */ void (*BuildMesh)(void* elem, struct VertexTextured** vertices); /* Draws this widget on-screen. */ int (*Render2)(void* elem, int offset); /* Returns the maximum number of vertices this widget may use */ int (*GetMaxVertices)(void* elem); /* Returns non-zero if a pad axis update is handled. */ int (*HandlesPadAxis)(void* elem, int axis, float x, float y); }; #define Widget_Body const struct WidgetVTABLE* VTABLE; \ int x, y, width, height; /* Top left corner, and dimensions, of this widget */ \ cc_bool active; /* Whether this widget is currently being moused over */ \ cc_uint8 flags; /* Flags controlling the widget's interactability */ \ cc_uint8 horAnchor, verAnchor; /* The reference point for when this widget is resized */ \ int xOffset, yOffset; /* Offset from the reference point */ \ Widget_LeftClick MenuClick; \ union WidgetMeta meta; /* Whether a widget is prevented from being interacted with */ #define WIDGET_FLAG_DISABLED 0x01 /* Whether a widget can be selected via up/down */ #define WIDGET_FLAG_SELECTABLE 0x02 /* Whether for dual screen builds, this widget still appears on */ /* the main game screen instead of the dedicated UI screen */ #define WIDGET_FLAG_MAINSCREEN 0x04 #ifdef CC_BUILD_DUALSCREEN #define Window_UI Window_Alt #else #define Window_UI Window_Main #endif /* Represents an individual 2D gui component. */ struct Widget { Widget_Body }; void Widget_SetLocation(void* widget, cc_uint8 horAnchor, cc_uint8 verAnchor, int xOffset, int yOffset); /* Calculates where this widget should be on-screen based on its attributes. */ /* These attributes are width/height, horAnchor/verAnchor, xOffset/yOffset */ void Widget_CalcPosition(void* widget); /* Resets Widget struct fields to 0/NULL (except VTABLE) */ void Widget_Reset(void* widget); /* Returns non-zero if the given point is located within the bounds of the widget. */ int Widget_Contains(void* widget, int x, int y); /* Sets whether the widget is prevented from being interacted with */ void Widget_SetDisabled(void* widget, int disabled); /* Higher priority handles input first and draws on top */ /* NOTE: Values are 5 apart to allow plugins to insert custom screens */ enum GuiPriority { GUI_PRIORITY_DISCONNECT = 60, GUI_PRIORITY_OLDLOADING = 55, GUI_PRIORITY_MENUINPUT = 57, GUI_PRIORITY_MENU = 50, GUI_PRIORITY_TOUCHMORE = 45, GUI_PRIORITY_URLWARNING = 40, GUI_PRIORITY_TEXPACK = 35, GUI_PRIORITY_TEXIDS = 30, GUI_PRIORITY_TOUCH = 25, GUI_PRIORITY_INVENTORY = 20, GUI_PRIORITY_TABLIST = 17, GUI_PRIORITY_CHAT = 15, GUI_PRIORITY_HUD = 10, GUI_PRIORITY_LOADING = 5 }; #define GUI_MAX_SCREENS 10 extern struct Screen* Gui_Screens[GUI_MAX_SCREENS]; /* Calculates position of an element on a particular axis */ /* For example, to calculate X position of a text widget on screen */ int Gui_CalcPos(cc_uint8 anchor, int offset, int size, int axisLen); /* Returns non-zero if the given rectangle contains the given point. */ int Gui_Contains(int recX, int recY, int width, int height, int x, int y); /* Returns non-zero if one or more pointers lie within the given rectangle. */ int Gui_ContainsPointers(int x, int y, int width, int height); /* Shows HUD and Status screens. */ void Gui_ShowDefault(void); #ifdef CC_BUILD_TOUCH /* Sets whether touch UI should be displayed or not */ void Gui_SetTouchUI(cc_bool enabled); #endif /* (internal) Removes the screen from the screens list. */ /* NOTE: This does NOT perform the usual 'screens changed' behaviour. */ void Gui_RemoveCore(struct Screen* s); /* Removes the screen from the screens list. */ CC_API void Gui_Remove(struct Screen* screen); /* Inserts a screen into the screen lists with the given priority. */ /* NOTE: If there is an existing screen with the same priority, it is removed. */ CC_API void Gui_Add(struct Screen* screen, int priority); /* Returns highest priority screen that has grabbed input. */ CC_API struct Screen* Gui_GetInputGrab(void); /* Returns highest priority screen that blocks world rendering. */ struct Screen* Gui_GetBlocksWorld(void); /* Returns highest priority screen that is closable. */ struct Screen* Gui_GetClosable(void); /* Returns screen with the given priority */ CC_API struct Screen* Gui_GetScreen(int priority); void Gui_UpdateInputGrab(void); void Gui_ShowPauseMenu(void); void Gui_LayoutAll(void); void Gui_RefreshAll(void); void Gui_Refresh(struct Screen* s); void Gui_RenderGui(float delta); #define TEXTATLAS_MAX_WIDTHS 16 struct TextAtlas { struct Texture tex; int offset, curX; float uScale; short widths[TEXTATLAS_MAX_WIDTHS]; short offsets[TEXTATLAS_MAX_WIDTHS]; }; void TextAtlas_Make(struct TextAtlas* atlas, const cc_string* chars, struct FontDesc* font, const cc_string* prefix); void TextAtlas_Free(struct TextAtlas* atlas); void TextAtlas_Add(struct TextAtlas* atlas, int charI, struct VertexTextured** vertices); void TextAtlas_AddInt(struct TextAtlas* atlas, int value, struct VertexTextured** vertices); #define Elem_Render(elem, delta) (elem)->VTABLE->Render(elem, delta) #define Elem_Free(elem) (elem)->VTABLE->Free(elem) #define Elem_HandlesKeyPress(elem, key) (elem)->VTABLE->HandlesKeyPress(elem, key) #define Elem_HandlesKeyDown(elem, key) (elem)->VTABLE->HandlesKeyDown(elem, key) #define Elem_OnInputUp(elem, key) (elem)->VTABLE->OnInputUp(elem, key) #define Elem_HandlesMouseScroll(elem, delta) (elem)->VTABLE->HandlesMouseScroll(elem, delta) #define Elem_HandlesPointerDown(elem, id, x, y) (elem)->VTABLE->HandlesPointerDown(elem, id, x, y) #define Elem_OnPointerUp(elem, id, x, y) (elem)->VTABLE->OnPointerUp(elem, id, x, y) #define Elem_HandlesPointerMove(elem, id, x, y) (elem)->VTABLE->HandlesPointerMove(elem, id, x, y) #define Elem_HandlesPadAxis(elem, axis, x, y) (elem)->VTABLE->HandlesPadAxis(elem, axis, x, y) #define Widget_BuildMesh(widget, vertices) (widget)->VTABLE->BuildMesh(widget, vertices) #define Widget_Render2(widget, offset) (widget)->VTABLE->Render2(widget, offset) #define Widget_Layout(widget) (widget)->VTABLE->Reposition(widget) #endif