Start porting SpecialInputWidget to C.

This commit is contained in:
UnknownShadow200 2017-10-21 15:36:11 +11:00
parent a69a285222
commit 82c464b426
9 changed files with 253 additions and 13 deletions

View File

@ -10,6 +10,7 @@ Copyright 2017 ClassicalSharp | Licensed under BSD-3
#include "2DStructs.h" #include "2DStructs.h"
#include "Texture.h" #include "Texture.h"
typedef struct DrawTextArgs_ { String Text; FontDesc Font; bool UseShadow; } DrawTextArgs;
void DrawTextArgs_Make(DrawTextArgs* args, STRING_REF String* text, FontDesc* font, bool useShadow); void DrawTextArgs_Make(DrawTextArgs* args, STRING_REF String* text, FontDesc* font, bool useShadow);
const float Offset = 1.3f; const float Offset = 1.3f;

View File

@ -101,7 +101,7 @@ void Gui_Reset(void) {
void Gui_Free(void) { void Gui_Free(void) {
Event_UnregisterStream(&TextureEvents_FileChanged, Gui_FileChanged); Event_UnregisterStream(&TextureEvents_FileChanged, Gui_FileChanged);
Gui_SetScreen(NULL); Gui_SetNewScreen(NULL);
Gui_Status->Base.Free(&Gui_Status->Base); Gui_Status->Base.Free(&Gui_Status->Base);
if (Gui_Active != NULL) { if (Gui_Active != NULL) {
@ -129,10 +129,11 @@ Screen* Gui_GetUnderlyingScreen(void) {
return Gui_Active == NULL ? Gui_HUD : Gui_Active; return Gui_Active == NULL ? Gui_HUD : Gui_Active;
} }
void Gui_SetScreen(Screen* screen) { void Gui_SetScreen(Screen* screen, bool freeOld) {
game.Input.ScreenChanged(activeScreen, screen); game.Input.ScreenChanged(Gui_Active, screen);
if (activeScreen != NULL && disposeOld) if (Gui_Active != NULL && freeOld) {
activeScreen.Dispose(); Gui_Active->Base.Free(&Gui_Active->Base);
}
if (screen == NULL) { if (screen == NULL) {
hudScreen.GainFocus(); hudScreen.GainFocus();
@ -146,6 +147,8 @@ void Gui_SetScreen(Screen* screen) {
Gui_Active = screen; Gui_Active = screen;
} }
void Gui_SetNewScreen(Screen* screen) { Gui_SetScreen(screen, true); }
void Gui_RefreshHud(void) { void Gui_RefreshHud(void) {
Gui_HUD->Base.Recreate(&Gui_HUD->Base); Gui_HUD->Base.Recreate(&Gui_HUD->Base);
} }

View File

@ -96,7 +96,8 @@ Screen* Gui_GetActiveScreen(void);
/* Gets the non-overlay screen that the user is currently interacting with. /* Gets the non-overlay screen that the user is currently interacting with.
This means if an overlay is active, it will return the screen under it. */ This means if an overlay is active, it will return the screen under it. */
Screen* Gui_GetUnderlyingScreen(void); Screen* Gui_GetUnderlyingScreen(void);
void Gui_SetScreen(Screen* screen); void Gui_SetScreen(Screen* screen, bool freeOld);
void Gui_SetNewScreen(Screen* screen);
void Gui_RefreshHud(void); void Gui_RefreshHud(void);
void Gui_ShowOverlay(Screen* overlay); void Gui_ShowOverlay(Screen* overlay);
void Gui_RenderGui(Real64 delta); void Gui_RenderGui(Real64 delta);

View File

@ -83,3 +83,6 @@ void ClickableScreen_Create(ClickableScreen* screen) {
screen->LastX = -1; screen->LastY = -1; screen->LastX = -1; screen->LastY = -1;
screen->OnWidgetSelected = ClickableScreen_DefaultWidgetSelected; screen->OnWidgetSelected = ClickableScreen_DefaultWidgetSelected;
} }
Screen AA;
extern Screen* InventoryScreen_Unsafe_RawPointer = &AA;

View File

@ -16,4 +16,6 @@ typedef struct ClickableScreen_ {
} ClickableScreen; } ClickableScreen;
void ClickableScreen_Create(ClickableScreen* screen); void ClickableScreen_Create(ClickableScreen* screen);
/* Raw pointer to inventory screen. DO NOT USE THIS. Use InventoryScreen_GetInstance() */
extern Screen* InventoryScreen_Unsafe_RawPointer;
#endif #endif

View File

@ -46,7 +46,6 @@ typedef UInt8 Face;
typedef UInt8 SkinType; typedef UInt8 SkinType;
typedef struct FontDesc_ { void* Handle; UInt16 Size, Style; } FontDesc; typedef struct FontDesc_ { void* Handle; UInt16 Size, Style; } FontDesc;
typedef struct DrawTextArgs_ { String Text; FontDesc Font; bool UseShadow; } DrawTextArgs;
#define UInt8_MaxValue ((UInt8)0xFF) #define UInt8_MaxValue ((UInt8)0xFF)
#define Int16_MaxValue ((Int16)0x7FFF) #define Int16_MaxValue ((Int16)0x7FFF)

View File

@ -9,6 +9,7 @@
#include "IsometricDrawer.h" #include "IsometricDrawer.h"
#include "Utils.h" #include "Utils.h"
#include "ModelCache.h" #include "ModelCache.h"
#include "Screens.h"
void Widget_SetLocation(Widget* widget, Anchor horAnchor, Anchor verAnchor, Int32 xOffset, Int32 yOffset) { void Widget_SetLocation(Widget* widget, Anchor horAnchor, Anchor verAnchor, Int32 xOffset, Int32 yOffset) {
widget->HorAnchor = horAnchor; widget->VerAnchor = verAnchor; widget->HorAnchor = horAnchor; widget->VerAnchor = verAnchor;
@ -429,8 +430,8 @@ bool HotbarWidget_HandlesKeyUp(GuiElement* elem, Key key) {
bool HotbarWidget_HandlesMouseDown(GuiElement* elem, Int32 x, Int32 y, MouseButton btn) { bool HotbarWidget_HandlesMouseDown(GuiElement* elem, Int32 x, Int32 y, MouseButton btn) {
Widget* w = (Widget*)elem; Widget* w = (Widget*)elem;
if (btn != MouseButton_Left || !Gui_Contains(w->X, w->Y, w->Width, w->Height, x, y)) return false; if (btn != MouseButton_Left || !Gui_Contains(w->X, w->Y, w->Width, w->Height, x, y)) return false;
InventoryScreen screen = game.Gui.ActiveScreen as InventoryScreen; Screen* screen = Gui_GetActiveScreen();
if (screen == null) return false; if (screen != InventoryScreen_Unsafe_RawPointer) return false;
HotbarWidget* widget = (HotbarWidget*)elem; HotbarWidget* widget = (HotbarWidget*)elem;
Int32 width = (Int32)(widget->ElemSize * widget->BorderSize); Int32 width = (Int32)(widget->ElemSize * widget->BorderSize);
@ -834,3 +835,233 @@ void TableWidget_OnInventoryChanged(TableWidget* widget) {
ScrollbarWidget_ClampScrollY(&widget->Scroll); ScrollbarWidget_ClampScrollY(&widget->Scroll);
TableWidget_RecreateDescTex(widget); TableWidget_RecreateDescTex(widget);
} }
void SpecialInputWidget_UpdateCols(SpecialInputWidget* widget) {
elements[0] = new SpecialInputTab("Colours", 10, 4, GetColourString());
Redraw();
SpecialInputWidget_SetActive(widget, widget->Base.Active);
}
void SpecialInputWidget_SetActive(SpecialInputWidget* widget, bool active) {
widget->Base.Active = active;
widget->Base.Height = active ? widget->Tex.Height : 0;
}
void SpecialInputWidget_Redraw(SpecialInputWidget* widget) {
SpecialInputWidget_Make(widget, &widget->Tabs[widget->SelectedIndex]);
widget->Base.Width = widget->Tex.Width;
widget->Base.Height = widget->Tex.Height;
}
void SpecialInputWidget_Make(SpecialInputWidget* widget, SpecialInputTab* e) {
Size2D sizes = stackalloc Size[e.Contents.Length / e.CharsPerItem];
MeasureContentSizes(e, font, sizes);
Size2D bodySize = CalculateContentSize(e, sizes, out elementSize);
Int32 titleWidth = MeasureTitles(font);
Int32 titleHeight = widget->Tabs[0].TitleSize.Height;
Size2D size = Size2D_Make(max(bodySize.Width, titleWidth), bodySize.Height + titleHeight);
Gfx_DeleteTexture(&widget->Tex.ID);
Bitmap bmp;
Bitmap_AllocatePow2(&bmp, size.Width, size.Height);
Drawer2D_Begin(&bmp);
DrawTitles(drawer, font);
PackedCol col = PACKEDCOL_CONST(30, 30, 30, 200);
Drawer2D_Clear(col, 0, titleHeight, size.Width, bodySize.Height);
DrawContent(drawer, font, e, titleHeight);
texture = drawer.Make2DTexture(bmp, size, X, Y);
Drawer2D_End();
}
bool IntersectsHeader(int widgetX, int widgetY) {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
for (int i = 0; i < elements.Length; i++) {
Size size = elements[i].TitleSize;
bounds.Width = size.Width; bounds.Height = size.Height;
if (bounds.Contains(widgetX, widgetY)) {
selectedIndex = i;
return true;
}
bounds.X += size.Width;
}
return false;
}
void IntersectsBody(int widgetX, int widgetY) {
widgetY -= elements[0].TitleSize.Height;
widgetX /= elementSize.Width; widgetY /= elementSize.Height;
SpecialInputTab e = elements[selectedIndex];
int index = widgetY * e.ItemsPerRow + widgetX;
if (index * e.CharsPerItem < e.Contents.Length) {
if (selectedIndex == 0) {
// TODO: need to insert characters that don't affect caret index, adjust caret colour
input.Append(e.Contents[index * e.CharsPerItem]);
input.Append(e.Contents[index * e.CharsPerItem + 1]);
} else {
input.Append(e.Contents[index]);
}
}
}
bool SpecialInputWidget_HandlesMouseClick(GuiElement* elem, Int32 x, Int32 y, MouseButton btn) {
SpecialInputWidget* widget = (SpecialInputWidget*)elem;
x -= widget->Base.X; y -= widget->Base.Y;
if (IntersectsHeader(x, y)) {
Redraw();
} else {
IntersectsBody(x, y);
}
return true;
}
void SpecialInputTab_Init(SpecialInputTab* tab, STRING_REF String title,
Int32 itemsPerRow, Int32 charsPerItem, STRING_REF String contents) {
tab->Title = title;
tab->TitleSize = Size2D_Empty;
tab->Contents = contents;
tab->ItemsPerRow = itemsPerRow;
tab->CharsPerItem = charsPerItem;
}
void SpecialInputWidget_InitTabs(SpecialInputWidget* widget) {
String title_cols = String_FromConstant("Colours");
SpecialInputTab_Init(&widget->Tabs[0], &title_cols, 10, 4, GetColourString());
String title_math = String_FromConstant("Math");
String tab_math = String_FromConstant("\x9F\xAB\xAC\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xFB\xFC\xFD");
SpecialInputTab_Init(&widget->Tabs[1], &title_math, 16, 1, &tab_math);
String title_line = String_FromConstant("Line/Box");
String tab_line = String_FromConstant("\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFE");
SpecialInputTab_Init(&widget->Tabs[2], &title_line, 17, 1, &tab_line);
String title_letters = String_FromConstant("Letters");
String tab_letters = String_FromConstant("\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\xA0\xA1\xA2\xA3\xA4\xA5");
SpecialInputTab_Init(&widget->Tabs[3], &title_letters, 17, 1, &tab_letters);
String title_other = String_FromConstant("Other");
String tab_other = String_FromConstant("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F\x9B\x9C\x9D\x9E\xA6\xA7\xA8\xA9\xAA\xAD\xAE\xAF\xF9\xFA");
SpecialInputTab_Init(&widget->Tabs[4], &title_other, 16, 1, &tab_other);
}
string GetColourString() {
int count = 0;
for (int i = ' '; i <= '~'; i++) {
if (i >= 'A' && i <= 'F') continue;
if (IDrawer2D.Cols[i].A > 0) count++;
}
StringBuffer buffer = new StringBuffer(count * 4);
int index = 0;
for (int i = ' '; i <= '~'; i++) {
if (i >= 'A' && i <= 'F') continue;
if (IDrawer2D.Cols[i].A == 0) continue;
buffer.Append(ref index, '&').Append(ref index, (char)i)
.Append(ref index, '%').Append(ref index, (char)i);
}
return buffer.ToString();
}
void SpecialInputWidget_MeasureContentSizes(SpecialInputTab* e, FontDesc* font, Size2D* sizes) {
string s = new String('\0', e.CharsPerItem);
DrawTextArgs args;
DrawTextArgs_Make(&args, &s, font, false);
// avoid allocating temporary strings here
fixed(char* ptr = s) {
for (int i = 0; i < e.Contents.Length; i += e.CharsPerItem) {
for (int j = 0; j < e.CharsPerItem; j++)
ptr[j] = e.Contents[i + j];
sizes[i / e.CharsPerItem] = game.Drawer2D.MeasureSize(ref args);
}
}
}
Size2D SpecialInputWidget_CalculateContentSize(SpecialInputTab* e, Size2D* sizes, Size2D* elemSize) {
*elemSize = Size2D_Empty;
Int32 i;
for (i = 0; i < e->Contents.length; i += e->CharsPerItem) {
elemSize->Width = max(elemSize->Width, sizes[i / e->CharsPerItem].Width);
}
elemSize->Width += contentSpacing;
elemSize->Height = sizes[0].Height + contentSpacing;
Int32 rows = Math_CeilDiv(e->Contents.length / e->CharsPerItem, e->ItemsPerRow);
return Size2D_Make(elemSize->Width * e->ItemsPerRow, elemSize->Height * rows);
}
const int titleSpacing = 10, contentSpacing = 5;
int MeasureTitles(Font font) {
int totalWidth = 0;
DrawTextArgs args = new DrawTextArgs(null, font, false);
for (int i = 0; i < elements.Length; i++) {
args.Text = elements[i].Title;
elements[i].TitleSize = game.Drawer2D.MeasureSize(ref args);
elements[i].TitleSize.Width += titleSpacing;
totalWidth += elements[i].TitleSize.Width;
}
return totalWidth;
}
void DrawTitles(IDrawer2D drawer, Font font) {
int x = 0;
DrawTextArgs args = new DrawTextArgs(null, font, false);
for (int i = 0; i < elements.Length; i++) {
args.Text = elements[i].Title;
FastColour col = i == selectedIndex ? new FastColour(30, 30, 30, 200) :
new FastColour(0, 0, 0, 127);
Size size = elements[i].TitleSize;
drawer.Clear(col, x, 0, size.Width, size.Height);
drawer.DrawText(ref args, x + titleSpacing / 2, 0);
x += size.Width;
}
}
void DrawContent(IDrawer2D drawer, Font font, SpecialInputTab e, int yOffset) {
string s = new String('\0', e.CharsPerItem);
int wrap = e.ItemsPerRow;
DrawTextArgs args = new DrawTextArgs(s, font, false);
fixed(char* ptr = s) {
for (int i = 0; i < e.Contents.Length; i += e.CharsPerItem) {
for (int j = 0; j < e.CharsPerItem; j++)
ptr[j] = e.Contents[i + j];
int item = i / e.CharsPerItem;
int x = (item % wrap) * elementSize.Width, y = (item / wrap) * elementSize.Height;
y += yOffset;
drawer.DrawText(ref args, x, y);
}
}
}
void SpecialInputWidget_Init(GuiElement* elem) {
SpecialInputWidget* widget = (SpecialInputWidget*)elem;
widget->Base.X = 5; widget->Base.Y = 5;
SpecialInputWidget_InitTabs(widget);
SpecialInputWidget_Redraw(widget);
SpecialInputWidget_SetActive(widget->Base.Active);
}
void SpecialInputWidget_Render(GuiElement* elem, Real64 delta) {
SpecialInputWidget* widget = (SpecialInputWidget*)elem;
Texture_Render(&widget->Tex);
}
void SpecialInputWidget_Free(GuiElement* elem) {
SpecialInputWidget* widget = (SpecialInputWidget*)elem;
Gfx_DeleteTexture(&widget->Tex.ID);
}
void SpecialInputWidget_Create(SpecialInputWidget* widget, FontDesc* font, InputWidget input) {
Widget_Init(&widget->Base);
widget->Base.VerAnchor = ANCHOR_BOTTOM_OR_RIGHT;
widget->Font = *font;
widget->AppendFunc = input;
}

View File

@ -102,17 +102,17 @@ void SpecialInputTab_Init(SpecialInputTab* tab, STRING_REF String* title,
typedef struct SpecialInputWidget_ { typedef struct SpecialInputWidget_ {
Widget Base; Widget Base;
Size2D ElementSize;
Int32 SelectedIndex;
SpecialInputAppendFunc AppendFunc;
Texture Tex; Texture Tex;
FontDesc Font; FontDesc Font;
SpecialInputAppendFunc AppendFunc;
Size2D ElementSize;
SpecialInputTab Tabs[5]; SpecialInputTab Tabs[5];
} SpecialInputWidget; } SpecialInputWidget;
void SpecialInputWidget_Create(SpecialInputWidget* widget, FontDesc* font, SpecialInputAppendFunc appendFunc); void SpecialInputWidget_Create(SpecialInputWidget* widget, FontDesc* font, SpecialInputAppendFunc appendFunc);
void SpecialInputWidget_UpdateColours(SpecialInputWidget* widget); void SpecialInputWidget_UpdateColours(SpecialInputWidget* widget);
void SpecialInputWidget_SetActive(SpecialInputWidget* widget, bool active); void SpecialInputWidget_SetActive(SpecialInputWidget* widget, bool active);
void SpecialInputWidget_Redraw(SpecialInputWidget* widget);
#define INPUTWIDGET_MAX_LINES 4 #define INPUTWIDGET_MAX_LINES 4

View File

@ -20,7 +20,7 @@ void ErrorHandler_Init(void) {
/* TODO: Open log file */ /* TODO: Open log file */
} }
void ErrorHandler_Log(String msg) { void ErrorHandler_Log(STRING_TRANSIENT String* msg) {
/* TODO: write to log file */ /* TODO: write to log file */
} }