get basic table to draw

This commit is contained in:
UnknownShadow200 2018-12-12 23:16:03 +11:00
parent 483fb591ed
commit 777f4fa88e
7 changed files with 452 additions and 402 deletions

View File

@ -594,6 +594,37 @@ Size2D Drawer2D_MeasureText(struct DrawTextArgs* args) {
return size; return size;
} }
void Drawer2D_DrawClippedText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y, int maxWidth) {
String str; char strBuffer[512];
struct DrawTextArgs part;
int i;
Size2D size = Drawer2D_MeasureText(args);
/* No clipping needed */
if (size.Width <= maxWidth) { Drawer2D_DrawText(bmp, args, x, y); return; }
String_InitArray(str, strBuffer);
String_Copy(&str, &args->Text);
String_Append(&str, '.');
part = *args;
for (i = str.length - 2; i > 0; i--) {
str.buffer[i] = '.';
/* skip over trailing spaces */
if (str.buffer[i - 1] == ' ') continue;
part.Text = String_UNSAFE_Substring(&str, 0, i + 2);
size = Drawer2D_MeasureText(&part);
if (size.Width <= maxWidth) { Drawer2D_DrawText(bmp, &part, x, y); return; }
/* If down to <= 2 chars, try omit trailing .. */
if (i > 2) continue;
part.Text = String_UNSAFE_Substring(&str, 0, i);
size = Drawer2D_MeasureText(&part);
if (size.Width <= maxWidth) { Drawer2D_DrawText(bmp, &part, x, y); return; }
}
}
/*########################################################################################################################* /*########################################################################################################################*
*---------------------------------------------------Drawer2D component----------------------------------------------------* *---------------------------------------------------Drawer2D component----------------------------------------------------*

View File

@ -58,6 +58,7 @@ void Drawer2D_Clear(Bitmap* bmp, BitmapCol col, int x, int y, int width, int hei
void Drawer2D_Underline(Bitmap* bmp, int x, int y, int width, int height, BitmapCol col); void Drawer2D_Underline(Bitmap* bmp, int x, int y, int width, int height, BitmapCol col);
void Drawer2D_DrawText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y); void Drawer2D_DrawText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y);
Size2D Drawer2D_MeasureText(struct DrawTextArgs* args); Size2D Drawer2D_MeasureText(struct DrawTextArgs* args);
void Drawer2D_DrawClippedText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y, int maxWidth);
int Drawer2D_FontHeight(const FontDesc* font, bool useShadow); int Drawer2D_FontHeight(const FontDesc* font, bool useShadow);
void Drawer2D_MakeTextTexture(struct Texture* tex, struct DrawTextArgs* args, int X, int Y); void Drawer2D_MakeTextTexture(struct Texture* tex, struct DrawTextArgs* args, int X, int Y);

View File

@ -8,6 +8,7 @@
#include "ExtMath.h" #include "ExtMath.h"
#include "Platform.h" #include "Platform.h"
#include "Stream.h" #include "Stream.h"
#include "Funcs.h"
/*########################################################################################################################* /*########################################################################################################################*
*---------------------------------------------------------Screen base-----------------------------------------------------* *---------------------------------------------------------Screen base-----------------------------------------------------*
@ -917,7 +918,9 @@ static struct ServersScreen {
LScreen_Layout LScreen_Layout
struct LInput IptName, IptHash; struct LInput IptName, IptHash;
struct LButton BtnBack, BtnConnect, BtnRefresh; struct LButton BtnBack, BtnConnect, BtnRefresh;
struct LWidget* _widgets[5]; struct LTable Table;
struct LWidget* _widgets[6];
FontDesc RowFont;
} ServersScreen_Instance; } ServersScreen_Instance;
static void ServersScreen_Connect(void* w, int x, int y) { static void ServersScreen_Connect(void* w, int x, int y) {
@ -937,6 +940,8 @@ static void ServersScreen_Refresh(void* w, int x, int y) {
static void ServersScreen_Init(struct LScreen* s_) { static void ServersScreen_Init(struct LScreen* s_) {
struct ServersScreen* s = (struct ServersScreen*)s_; struct ServersScreen* s = (struct ServersScreen*)s_;
Font_Make(&s->RowFont, &Drawer2D_FontName, 11, FONT_STYLE_NORMAL);
if (s->NumWidgets) return; if (s->NumWidgets) return;
s->Widgets = s->_widgets; s->Widgets = s->_widgets;
@ -944,12 +949,20 @@ static void ServersScreen_Init(struct LScreen* s_) {
LScreen_Input(s_, &s->IptHash, 475, false, "&gclassicube.net/server/play/..."); LScreen_Input(s_, &s->IptHash, 475, false, "&gclassicube.net/server/play/...");
LScreen_Button(s_, &s->BtnBack, 110, 30, "Back"); LScreen_Button(s_, &s->BtnBack, 110, 30, "Back");
LScreen_Button(s_, &s->BtnConnect, 110, 30, "Connect"); LScreen_Button(s_, &s->BtnConnect, 130, 30, "Connect");
LScreen_Button(s_, &s->BtnRefresh, 110, 30, "Refresh"); LScreen_Button(s_, &s->BtnRefresh, 110, 30, "Refresh");
s->BtnBack.OnClick = SwitchToMain; s->BtnBack.OnClick = SwitchToMain;
s->BtnConnect.OnClick = ServersScreen_Connect; s->BtnConnect.OnClick = ServersScreen_Connect;
s->BtnRefresh.OnClick = ServersScreen_Refresh; s->BtnRefresh.OnClick = ServersScreen_Refresh;
LTable_Init(&s->Table, &Launcher_TextFont, &s->RowFont);
s->Widgets[s->NumWidgets++] = (struct LWidget*)&s->Table;
}
static void ServersScreen_Free(struct LScreen* s_) {
struct ServersScreen* s = (struct ServersScreen*)s_;
Font_Free(&s->RowFont);
} }
static void ServersScreen_Reposition(struct LScreen* s_) { static void ServersScreen_Reposition(struct LScreen* s_) {
@ -960,6 +973,13 @@ static void ServersScreen_Reposition(struct LScreen* s_) {
LWidget_SetLocation(&s->BtnBack, ANCHOR_MAX, ANCHOR_MIN, 10, 10); LWidget_SetLocation(&s->BtnBack, ANCHOR_MAX, ANCHOR_MIN, 10, 10);
LWidget_SetLocation(&s->BtnConnect, ANCHOR_MAX, ANCHOR_MAX, 10, 10); LWidget_SetLocation(&s->BtnConnect, ANCHOR_MAX, ANCHOR_MAX, 10, 10);
LWidget_SetLocation(&s->BtnRefresh, ANCHOR_MAX, ANCHOR_MIN, 135, 10); LWidget_SetLocation(&s->BtnRefresh, ANCHOR_MAX, ANCHOR_MIN, 135, 10);
s->Table.Width = Game_Width - 10;
s->Table.Height = Game_Height - 100;
s->Table.Height = max(1, s->Table.Height);
LWidget_SetLocation(&s->Table, ANCHOR_MIN, ANCHOR_MIN, 10, 50);
LTable_Reposition(&s->Table);
} }
struct LScreen* ServersScreen_MakeInstance(void) { struct LScreen* ServersScreen_MakeInstance(void) {
@ -967,6 +987,7 @@ struct LScreen* ServersScreen_MakeInstance(void) {
LScreen_Reset((struct LScreen*)s); LScreen_Reset((struct LScreen*)s);
s->HidesBackground = true; s->HidesBackground = true;
s->Init = ServersScreen_Init; s->Init = ServersScreen_Init;
s->Free = ServersScreen_Free;
s->Reposition = ServersScreen_Reposition; s->Reposition = ServersScreen_Reposition;
return (struct LScreen*)s; return (struct LScreen*)s;
} }

View File

@ -370,6 +370,7 @@ static void FetchServersTask_Count(struct JsonContext* ctx) {
static void FetchServersTask_Next(struct JsonContext* ctx) { static void FetchServersTask_Next(struct JsonContext* ctx) {
curServer++; curServer++;
if (curServer < FetchServersTask.Servers) return;
ServerInfo_Init(curServer); ServerInfo_Init(curServer);
} }
@ -378,7 +379,8 @@ static void FetchServersTask_Handle(uint8_t* data, uint32_t len) {
if (!FetchServersTask.NumServers) return; if (!FetchServersTask.NumServers) return;
FetchServersTask.Servers = Mem_Alloc(FetchServersTask.NumServers, sizeof(struct ServerInfo), "servers list"); FetchServersTask.Servers = Mem_Alloc(FetchServersTask.NumServers, sizeof(struct ServerInfo), "servers list");
curServer = FetchServersTask.Servers - 1; /* -2 because servers is surrounded by a { */
curServer = FetchServersTask.Servers - 2;
Json_Handle(data, len, ServerInfo_Parse, NULL, FetchServersTask_Next); Json_Handle(data, len, ServerInfo_Parse, NULL, FetchServersTask_Next);
} }

View File

@ -103,6 +103,7 @@ void FetchUpdateTask_Run(bool release, bool d3d9);
extern struct FetchFlagsData { extern struct FetchFlagsData {
struct LWebTask Base; struct LWebTask Base;
int Count; /* Total number of flags. */
int NumDownloaded; /* Number of flags that have been downloaded. */ int NumDownloaded; /* Number of flags that have been downloaded. */
Bitmap* Bitmaps; /* Raw pixels for each downloaded flag. */ Bitmap* Bitmaps; /* Raw pixels for each downloaded flag. */
String* Names; /* Name for each downloaded flag.*/ String* Names; /* Name for each downloaded flag.*/

View File

@ -595,104 +595,76 @@ static int SoftwareColumn_Sort(struct ServerInfo* a, struct ServerInfo* b) {
} }
static struct LTableColumn tableColumns[4] = { static struct LTableColumn tableColumns[4] = {
{ "Name", 320, 320, NameColumn_Get, NameColumn_Sort }, { "Name", 320, NameColumn_Get, NameColumn_Sort },
{ "Players", 65, 65, PlayersColumn_Get, PlayersColumn_Sort }, { "Players", 65, PlayersColumn_Get, PlayersColumn_Sort },
{ "Uptime", 65, 65, UptimeColumn_Get, UptimeColumn_Sort }, { "Uptime", 65, UptimeColumn_Get, UptimeColumn_Sort },
{ "Software", 140, 140, SoftwareColumn_Get, SoftwareColumn_Sort } { "Software", 140, SoftwareColumn_Get, SoftwareColumn_Sort }
}; };
/* #define GRIDLINE_SIZE 2
PackedCol backGridCol = new PackedCol(20, 20, 10); #define SCROLLBAR_WIDTH 10
PackedCol foreGridCol = new PackedCol(40, 40, 40); #define CELL_YPADDING 3
#define CELL_XPADDING 3
int entryHeight, headerHeight;
int headerStartY, headerEndY;
int numEntries, maxIndex;
Font font, titleFont;
void SetDrawData(IDrawer2D drawer, Font font, Font titleFont) { void LTable_DrawHeaders(struct LTable* w) {
this.font = font; BitmapCol gridCol = BITMAPCOL_CONST(20, 20, 10, 255);
this.titleFont = titleFont; struct DrawTextArgs args;
int i, x, y;
headerHeight = drawer.FontHeight(titleFont, true); if (!Launcher_ClassicBackground) {
entryHeight = drawer.FontHeight(font, true); Drawer2D_Clear(&Launcher_Framebuffer, gridCol,
w->X, w->Y, w->Width, w->HdrHeight);
Drawer2D_Clear(&Launcher_Framebuffer, Launcher_BackgroundCol,
w->X, w->Y + w->HdrHeight, w->Width, GRIDLINE_SIZE);
}
DrawTextArgs_MakeEmpty(&args, &w->HdrFont, true);
x = w->X;
y = w->Y + CELL_YPADDING;
for (i = 0; i < w->NumColumns; i++) {
x += CELL_XPADDING;
args.Text = String_FromReadonly(w->Columns[i].Name);
Drawer2D_DrawClippedText(&Launcher_Framebuffer, &args,
x, y, w->Columns[i].Width);
x += w->Columns[i].Width + CELL_XPADDING;
}
} }
void RecalculateDrawData() { void LTable_DrawRows(struct LTable* w) {
for (int i = 0; i < table.ColumnWidths.Length; i++) { BitmapCol gridCol = BITMAPCOL_CONST(20, 20, 10, 255);
table.ColumnWidths[i] = table.DesiredColumnWidths[i]; String str; char strBuffer[STRING_SIZE];
Utils.Clamp(ref table.ColumnWidths[i], 20, game.Width - 20); struct DrawTextArgs args;
int i, x, y, row;
String_InitArray(str, strBuffer);
DrawTextArgs_Make(&args, &str, &w->RowFont, true);
y = w->RowBegY;
for (row = 0; row < w->VisibleRows; row++, y += w->RowHeight) {
x = w->X;
if (!Launcher_ClassicBackground) {
Drawer2D_Clear(&Launcher_Framebuffer, gridCol,
x, y, w->Width, w->RowHeight);
} }
table.Width = game.Width - table.X; if (row >= FetchServersTask.NumServers) continue;
ResetEntries();
int y = table.Y + 3; for (i = 0; i < w->NumColumns; i++) {
y += headerHeight + 2; x += CELL_XPADDING;
maxIndex = table.Count; args.Text.length = 0;
y += 5; w->Columns[i].GetValue(&FetchServersTask.Servers[row], &args.Text);
for (int i = table.CurrentIndex; i < table.Count; i++) { Drawer2D_DrawClippedText(&Launcher_Framebuffer, &args,
if (y + entryHeight > table.Y + table.Height) { x, y, w->Columns[i].Width);
maxIndex = i; return; x += w->Columns[i].Width + CELL_XPADDING;
}
table.entries[table.order[i]].Y = y;
table.entries[table.order[i]].Height = entryHeight;
y += entryHeight + 2;
} }
} }
}
const int flagPadding = 15; /*
void RedrawData(IDrawer2D drawer) { int DrawColumn(IDrawer2D drawer, string header, int columnI, int x, ColumnFilter filter) {
DrawGrid(drawer);
int x = table.X + flagPadding + 5;
x += DrawColumn(drawer, "Name", 0, x, filterName) + 5;
x += DrawColumn(drawer, "Players", 1, x, filterPlayers) + 5;
x += DrawColumn(drawer, "Uptime", 2, x, filterUptime) + 5;
x += DrawColumn(drawer, "Software", 3, x, filterSoftware) + 5;
DrawScrollbar(drawer);
DrawFlags();
}
void Redraw(IDrawer2D drawer) {
RecalculateDrawData();
RedrawData(drawer);
}
delegate string ColumnFilter(TableEntry entry);
// cache to avoid allocations every redraw
static string FilterName(TableEntry e) { return e.Name; } static ColumnFilter filterName = FilterName;
static string FilterPlayers(TableEntry e) { return e.Players; } static ColumnFilter filterPlayers = FilterPlayers;
static string FilterUptime(TableEntry e) { return e.Uptime; } static ColumnFilter filterUptime = FilterUptime;
static string FilterSoftware(TableEntry e) { return e.Software; } static ColumnFilter filterSoftware = FilterSoftware;
static FastBitmap GetFlag(string flag) {
List<string> flags = FetchFlagsTask.Flags;
List<FastBitmap> bitmaps = FetchFlagsTask.Bitmaps;
for (int i = 0; i < flags.Count; i++) {
if (flags[i] != flag) continue;
return i < bitmaps.Count ? bitmaps[i] : null;
}
return null;
}
public void DrawFlags() {
using (FastBitmap dst = game.LockBits()) {
for (int i = table.CurrentIndex; i < maxIndex; i++) {
TableEntry entry = table.Get(i);
FastBitmap flag = GetFlag(entry.Flag);
if (flag == null) continue;
int x = table.X, y = entry.Y;
Rectangle rect = new Rectangle(x + 2, y + 3, 16, 11);
BitmapDrawer.Draw(flag, dst, rect);
}
}
}
int DrawColumn(IDrawer2D drawer, string header, int columnI, int x, ColumnFilter filter) {
int y = table.Y + 3; int y = table.Y + 3;
int maxWidth = table.ColumnWidths[columnI]; int maxWidth = table.ColumnWidths[columnI];
bool separator = columnI > 0; bool separator = columnI > 0;
@ -720,18 +692,18 @@ void RecalculateDrawData() {
drawer.Clear(LauncherSkin.BackgroundCol, x - 7, table.Y, 2, table.Height); drawer.Clear(LauncherSkin.BackgroundCol, x - 7, table.Y, 2, table.Height);
} }
return maxWidth + 5; return maxWidth + 5;
} }
PackedCol GetGridCol(bool featured, bool selected) { PackedCol GetGridCol(bool featured, bool selected) {
if (featured) { if (featured) {
if (selected) return new PackedCol(50, 53, 0); if (selected) return new PackedCol(50, 53, 0);
return new PackedCol(101, 107, 0); return new PackedCol(101, 107, 0);
} }
PackedCol foreGridCol = new PackedCol(40, 40, 40);
return foreGridCol; return foreGridCol;
} }
bool DrawColumnEntry(IDrawer2D drawer, ref DrawTextArgs args, bool DrawColumnEntry(IDrawer2D drawer, ref DrawTextArgs args, int maxWidth, int x, ref int y, ref TableEntry entry) {
int maxWidth, int x, ref int y, ref TableEntry entry) {
Size size = drawer.MeasureText(ref args); Size size = drawer.MeasureText(ref args);
bool empty = args.Text == ""; bool empty = args.Text == "";
if (empty) if (empty)
@ -748,88 +720,85 @@ void RecalculateDrawData() {
} }
y += size.Height + 2; y += size.Height + 2;
return true; return true;
}
void ResetEntries() {
for (int i = 0; i < table.Count; i++) {
table.entries[i].Height = 0;
table.entries[i].Y = -10;
}
}
void DrawGrid(IDrawer2D drawer) {
if (!game.ClassicBackground)
drawer.Clear(LauncherSkin.BackgroundCol,
table.X, table.Y + headerHeight + 5, table.Width, 2);
headerStartY = table.Y;
headerEndY = table.Y + headerHeight + 5;
int startY = headerEndY + 3;
numEntries = (table.Y + table.Height - startY) / (entryHeight + 3);
}
void DrawScrollbar(IDrawer2D drawer) {
PackedCol col = game.ClassicBackground ? new PackedCol(80, 80, 80) : LauncherSkin.ButtonBorderCol;
drawer.Clear(col, game.Width - 10, table.Y, 10, table.Height);
col = game.ClassicBackground ? new PackedCol(160, 160, 160) : LauncherSkin.ButtonForeActiveCol;
int yOffset, height;
table.GetScrollbarCoords(out yOffset, out height);
drawer.Clear(col, game.Width - 10, table.Y + yOffset, 10, height);
}
}
} }
internal struct TableEntry {
public string Hash, Name, Players, Uptime, Software, RawUptime, Flag;
public int Y, Height; const int flagPadding = 15;
public bool Featured; void DrawColumns(IDrawer2D drawer) {
int x = table.X + flagPadding + 5;
x += DrawColumn(drawer, "Name", 0, x, filterName) + 5;
x += DrawColumn(drawer, "Players", 1, x, filterPlayers) + 5;
x += DrawColumn(drawer, "Uptime", 2, x, filterUptime) + 5;
x += DrawColumn(drawer, "Software", 3, x, filterSoftware) + 5;
} }
public delegate void TableNeedsRedrawHandler(); void DrawScrollbar(struct LTable* w) {
BitmapCol classicBack = BITMAPCOL_CONST( 80, 80, 80, 255);
BitmapCol classicScroll = BITMAPCOL_CONST(160, 160, 160, 255);
BitmapCol backCol = Launcher_ClassicBackground ? classicBack : Launcher_ButtonBorderCol;
BitmapCol scrollCol = Launcher_ClassicBackground ? classicScroll : Launcher_ButtonForeActiveCol;
TableView view; int x, y, height;
public TableWidget(LauncherWindow window) : base(window) { x = w->X + w->Width - SCROLLBAR_WIDTH;
OnClick = HandleOnClick; LTable_GetScrollbarCoords(w, &y, &height);
view = new TableView();
view.Init(window, this); Drawer2D_Clear(&Launcher_Framebuffer, backCol,
x, w->Y, SCROLLBAR_WIDTH, w->Height);
Drawer2D_Clear(&Launcher_Framebuffer, scrollCol,
x, w->Y + y, SCROLLBAR_WIDTH, height);
}
void Draw(IDrawer2D drawer) {
DrawGrid(drawer);
DrawColumns(drawer);
DrawScrollbar(drawer);
DrawFlags();
}
static Bitmap* GetFlag(const String* flag) {
int i = 0;
for (i = 0; i < FetchFlagsTask.Count; i++) {
if (!String_CaselessEquals(flag, &FetchFlagsTask.Names[i])) continue;
return &FetchFlagsTask.Bitmaps[i];
} }
return NULL;
}
public TableNeedsRedrawHandler NeedRedraw; void DrawFlags() {
public Action<string> SelectedChanged; for (int i = table.CurrentIndex; i < maxIndex; i++) {
public int SelectedIndex = -1; TableEntry entry = table.Get(i);
public string SelectedHash = ""; FastBitmap flag = GetFlag(entry.Flag);
public int CurrentIndex, Count; if (flag == null) continue;
internal TableEntry[] entries; int x = table.X, y = entry.Y;
internal int[] order; Rectangle rect = new Rectangle(x + 2, y + 3, 16, 11);
internal List<ServerListEntry> servers; BitmapDrawer.Draw(flag, dst, rect);
internal TableEntry Get(int i) { return entries[order[i]]; } }
}
public void SetEntries(List<ServerListEntry> servers) { void TableNeedsRedrawHandler();
public TableNeedsRedrawHandler NeedRedraw;
public Action<string> SelectedChanged;
public int SelectedIndex = -1;
public string SelectedHash = "";
public int CurrentIndex, Count;
internal TableEntry[] entries;
internal int[] order;
internal List<ServerListEntry> servers;
internal TableEntry Get(int i) { return entries[order[i]]; }
void SetEntries(List<ServerListEntry> servers) {
entries = new TableEntry[servers.Count]; entries = new TableEntry[servers.Count];
order = new int[servers.Count]; order = new int[servers.Count];
this.servers = servers;
for (int i = 0; i < servers.Count; i++) {
ServerListEntry e = servers[i];
TableEntry tableEntry = default(TableEntry);
tableEntry.Hash = e.Hash;
tableEntry.Name = e.Name;
tableEntry.Players = e.Players + "/" + e.MaxPlayers;
tableEntry.Software = e.Software;
tableEntry.Uptime = MakeUptime(e.Uptime);
tableEntry.RawUptime = e.Uptime;
tableEntry.Featured = e.Featured;
tableEntry.Flag = e.Flag;
entries[i] = tableEntry;
order[i] = i;
}
Count = entries.Length; Count = entries.Length;
} }
string curFilter; string curFilter;
public void FilterEntries(string filter) { void FilterEntries(string filter) {
curFilter = filter; curFilter = filter;
Count = 0; Count = 0;
for (int i = 0; i < entries.Length; i++) { for (int i = 0; i < entries.Length; i++) {
@ -841,18 +810,18 @@ public delegate void TableNeedsRedrawHandler();
for (int i = Count; i < entries.Length; i++) { for (int i = Count; i < entries.Length; i++) {
order[i] = -100000; order[i] = -100000;
} }
} }
internal void GetScrollbarCoords(out int y, out int height) { static void LTable_GetScrollbarCoords(struct LTable* w, out int y, out int height) {
if (Count == 0) { y = 0; height = 0; return; } if (Count == 0) { y = 0; height = 0; return; }
float scale = Height / (float)Count; float scale = Height / (float)Count;
y = (int)Math.Ceiling(CurrentIndex * scale); y = (int)Math.Ceiling(CurrentIndex * scale);
height = (int)Math.Ceiling((view.maxIndex - CurrentIndex) * scale); height = (int)Math.Ceiling((view.maxIndex - CurrentIndex) * scale);
height = Math.Min(y + height, Height) - y; height = Math.Min(y + height, Height) - y;
} }
public void SetSelected(int index) { void SetSelected(int index) {
if (index >= view.maxIndex) CurrentIndex = index + 1 - view.numEntries; if (index >= view.maxIndex) CurrentIndex = index + 1 - view.numEntries;
if (index < CurrentIndex) CurrentIndex = index; if (index < CurrentIndex) CurrentIndex = index;
if (index >= Count) index = Count - 1; if (index >= Count) index = Count - 1;
@ -868,69 +837,38 @@ public delegate void TableNeedsRedrawHandler();
SelectedChanged(entry.Hash); SelectedChanged(entry.Hash);
SelectedHash = entry.Hash; SelectedHash = entry.Hash;
} }
} }
public void SetSelected(string hash) { void SetSelected(string hash) {
SelectedIndex = -1; SelectedIndex = -1;
for (int i = 0; i < Count; i++) { for (int i = 0; i < Count; i++) {
if (Get(i).Hash != hash) continue; if (Get(i).Hash != hash) continue;
SetSelected(i); SetSelected(i);
return; return;
} }
} }
public void ClampIndex() { void ClampIndex() {
if (CurrentIndex > Count - view.numEntries) if (CurrentIndex > Count - view.numEntries)
CurrentIndex = Count - view.numEntries; CurrentIndex = Count - view.numEntries;
if (CurrentIndex < 0) if (CurrentIndex < 0)
CurrentIndex = 0; CurrentIndex = 0;
} }
string MakeUptime(string rawSeconds) { DefaultComparer defComp = new DefaultComparer();
TimeSpan t = TimeSpan.FromSeconds(Double.Parse(rawSeconds)); NameComparer nameComp = new NameComparer();
if (t.TotalHours >= 24 * 7) PlayersComparer playerComp = new PlayersComparer();
return (int)t.TotalDays + "d"; UptimeComparer uptimeComp = new UptimeComparer();
if (t.TotalHours >= 1) SoftwareComparer softwareComp = new SoftwareComparer();
return (int)t.TotalHours + "h"; internal int DraggingColumn = -1;
if (t.TotalMinutes >= 1) internal bool DraggingScrollbar = false;
return (int)t.TotalMinutes + "m"; internal int mouseOffset;
return (int)t.TotalSeconds + "s";
}
void SortDefault() {
public int[] ColumnWidths = new int[] { 320, 65, 65, 140 };
public int[] DesiredColumnWidths = new int[] { 320, 65, 65, 140 };
public void SetDrawData(IDrawer2D drawer, Font font, Font titleFont,
Anchor horAnchor, Anchor verAnchor, int x, int y) {
SetLocation(horAnchor, verAnchor, x, y);
view.SetDrawData(drawer, font, titleFont);
}
public void RecalculateDrawData() { view.RecalculateDrawData(); }
public void RedrawData(IDrawer2D drawer) { view.RedrawData(drawer); }
public void RedrawFlags() { view.DrawFlags(); }
public override void Redraw(IDrawer2D drawer) {
RecalculateDrawData();
RedrawData(drawer);
}
DefaultComparer defComp = new DefaultComparer();
NameComparer nameComp = new NameComparer();
PlayersComparer playerComp = new PlayersComparer();
UptimeComparer uptimeComp = new UptimeComparer();
SoftwareComparer softwareComp = new SoftwareComparer();
internal int DraggingColumn = -1;
internal bool DraggingScrollbar = false;
internal int mouseOffset;
public void SortDefault() {
SortEntries(defComp, true); SortEntries(defComp, true);
} }
void SelectHeader(int mouseX, int mouseY) { void SelectHeader(int mouseX, int mouseY) {
int x = X + 15; int x = X + 15;
for (int i = 0; i < ColumnWidths.Length; i++) { for (int i = 0; i < ColumnWidths.Length; i++) {
x += ColumnWidths[i] + 10; x += ColumnWidths[i] + 10;
@ -940,9 +878,9 @@ public delegate void TableNeedsRedrawHandler();
} }
} }
TrySortColumns(mouseX); TrySortColumns(mouseX);
} }
void TrySortColumns(int mouseX) { void TrySortColumns(int mouseX) {
int x = X + TableView.flagPadding; int x = X + TableView.flagPadding;
if (mouseX >= x && mouseX < x + ColumnWidths[0]) { if (mouseX >= x && mouseX < x + ColumnWidths[0]) {
SortEntries(nameComp, false); return; SortEntries(nameComp, false); return;
@ -962,9 +900,9 @@ public delegate void TableNeedsRedrawHandler();
if (mouseX >= x) { if (mouseX >= x) {
SortEntries(softwareComp, false); return; SortEntries(softwareComp, false); return;
} }
} }
void SortEntries(TableEntryComparer comparer, bool noRedraw) { void SortEntries(TableEntryComparer comparer, bool noRedraw) {
Array.Sort(entries, 0, entries.Length, comparer); Array.Sort(entries, 0, entries.Length, comparer);
lastIndex = -10; lastIndex = -10;
if (curFilter != null && curFilter.Length > 0) { if (curFilter != null && curFilter.Length > 0) {
@ -975,16 +913,15 @@ public delegate void TableNeedsRedrawHandler();
comparer.Invert = !comparer.Invert; comparer.Invert = !comparer.Invert;
SetSelected(SelectedHash); SetSelected(SelectedHash);
NeedRedraw(); NeedRedraw();
} }
void GetSelectedServer(int mouseX, int mouseY) { void GetSelectedServer(int mouseX, int mouseY) {
for (int i = 0; i < Count; i++) { for (int i = 0; i < Count; i++) {
TableEntry entry = Get(i); TableEntry entry = Get(i);
if (mouseY < entry.Y || mouseY >= entry.Y + entry.Height + 2) continue; if (mouseY < entry.Y || mouseY >= entry.Y + entry.Height + 2) continue;
if (lastIndex == i && (DateTime.UtcNow - lastPress).TotalSeconds < 1) { if (lastIndex == i) {
Window.ConnectToServer(servers, entry.Hash); Launcher_ConnectToServer(entry.Hash);
lastPress = DateTime.MinValue;
return; return;
} }
@ -992,9 +929,9 @@ public delegate void TableNeedsRedrawHandler();
NeedRedraw(); NeedRedraw();
break; break;
} }
} }
void HandleOnClick(int mouseX, int mouseY) { void MouseDown(int mouseX, int mouseY) {
if (mouseX >= Window.Width - 10) { if (mouseX >= Window.Width - 10) {
ScrollbarClick(mouseY); ScrollbarClick(mouseY);
DraggingScrollbar = true; DraggingScrollbar = true;
@ -1006,12 +943,10 @@ public delegate void TableNeedsRedrawHandler();
} else { } else {
GetSelectedServer(mouseX, mouseY); GetSelectedServer(mouseX, mouseY);
} }
lastPress = DateTime.UtcNow; }
}
int lastIndex = -10; int lastIndex = -10;
DateTime lastPress; void MouseMove(int x, int y, int deltaX, int deltaY) {
public void MouseMove(int x, int y, int deltaX, int deltaY) {
if (DraggingScrollbar) { if (DraggingScrollbar) {
y -= Y; y -= Y;
float scale = Height / (float)Count; float scale = Height / (float)Count;
@ -1023,13 +958,11 @@ public delegate void TableNeedsRedrawHandler();
int col = DraggingColumn; int col = DraggingColumn;
ColumnWidths[col] += deltaX; ColumnWidths[col] += deltaX;
Utils.Clamp(ref ColumnWidths[col], 20, Window.Width - 20); Utils.Clamp(ref ColumnWidths[col], 20, Window.Width - 20);
DesiredColumnWidths[col] = ColumnWidths[col];
NeedRedraw(); NeedRedraw();
} }
}
} void ScrollbarClick(int mouseY) {
void ScrollbarClick(int mouseY) {
mouseY -= Y; mouseY -= Y;
int y, height; int y, height;
GetScrollbarCoords(out y, out height); GetScrollbarCoords(out y, out height);
@ -1047,5 +980,45 @@ public delegate void TableNeedsRedrawHandler();
NeedRedraw(); NeedRedraw();
} }
} }
}
*/ */
void LTable_StopDragging(struct LTable* table) {
table->DraggingColumn = -1;
table->DraggingScrollbar = false;
table->MouseOffset = 0;
}
void LTable_Reposition(struct LTable* w) {
int rowsHeight;
w->HdrHeight = Drawer2D_FontHeight(&w->HdrFont, true) + CELL_YPADDING * 2;
w->RowHeight = Drawer2D_FontHeight(&w->RowFont, true) + CELL_YPADDING * 2;
w->RowBegY = w->Y + w->HdrHeight + GRIDLINE_SIZE;
rowsHeight = w->Height - (w->RowBegY - w->Y);
w->VisibleRows = Math_CeilDiv(rowsHeight, w->RowHeight);
}
static void LTable_Draw(void* widget) {
struct LTable* w = widget;
LTable_DrawHeaders(w);
LTable_DrawRows(w);
Launcher_Dirty = true;
}
static struct LWidgetVTABLE ltable_VTABLE = {
LTable_Draw,
NULL, NULL, /* Key */
NULL, NULL, /* Hover */
NULL, NULL /* Select */
};
void LTable_Init(struct LTable* w, const FontDesc* hdrFont, const FontDesc* rowFont) {
w->VTABLE = &ltable_VTABLE;
w->Columns = tableColumns;
w->NumColumns = Array_Elems(tableColumns);
w->HdrFont = *hdrFont;
w->RowFont = *rowFont;
LTable_StopDragging(w);
LTable_Reposition(w);
}

View File

@ -116,8 +116,8 @@ struct ServerInfo;
struct LTableColumn { struct LTableColumn {
/* Name of this column. */ /* Name of this column. */
const char* Name; const char* Name;
/* Current and default width of this column. */ /* Width of this column in pixels. */
int Width, DefaultWidth; int Width;
/* Gets the value of this column for the given row. */ /* Gets the value of this column for the given row. */
void (*GetValue)(struct ServerInfo* row, String* str); void (*GetValue)(struct ServerInfo* row, String* str);
/* Sorts two rows based on value of this column in both rows. */ /* Sorts two rows based on value of this column in both rows. */
@ -128,5 +128,26 @@ struct LTableColumn {
/* Represents a table of server entries. */ /* Represents a table of server entries. */
struct LTable { struct LTable {
LWidget_Layout LWidget_Layout
/* Columns of the table. */
struct LTableColumn* Columns;
/* Number of columns in the table. */
int NumColumns;
/* Fonts for text in header and rows. */
FontDesc RowFont, HdrFont;
/* Y start of rows and height of each row. */
int RowBegY, RowHeight;
/* Y height of headers. */
int HdrHeight;
/* Number of rows currently visible. */
int VisibleRows;
/* Index of column currently being dragged. */
int DraggingColumn;
/* Whether scrollbar is currently being dragged up or down. */
bool DraggingScrollbar;
int MouseOffset;
}; };
void LTable_Init(struct LTable* table, const FontDesc* hdrFont, const FontDesc* rowFont);
CC_NOINLINE void LTable_StopDragging(struct LTable* table);
void LTable_Reposition(struct LTable* table);
#endif #endif