mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-15 10:35:11 -04:00
get basic table to draw
This commit is contained in:
parent
483fb591ed
commit
777f4fa88e
@ -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----------------------------------------------------*
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.*/
|
||||||
|
767
src/LWidgets.c
767
src/LWidgets.c
@ -595,441 +595,374 @@ 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
|
||||||
|
#define SCROLLBAR_WIDTH 10
|
||||||
|
#define CELL_YPADDING 3
|
||||||
|
#define CELL_XPADDING 3
|
||||||
|
|
||||||
|
|
||||||
|
void LTable_DrawHeaders(struct LTable* w) {
|
||||||
|
BitmapCol gridCol = BITMAPCOL_CONST(20, 20, 10, 255);
|
||||||
|
struct DrawTextArgs args;
|
||||||
|
int i, x, y;
|
||||||
|
|
||||||
|
if (!Launcher_ClassicBackground) {
|
||||||
|
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 LTable_DrawRows(struct LTable* w) {
|
||||||
|
BitmapCol gridCol = BITMAPCOL_CONST(20, 20, 10, 255);
|
||||||
|
String str; char strBuffer[STRING_SIZE];
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (row >= FetchServersTask.NumServers) continue;
|
||||||
|
|
||||||
|
for (i = 0; i < w->NumColumns; i++) {
|
||||||
|
x += CELL_XPADDING;
|
||||||
|
args.Text.length = 0;
|
||||||
|
w->Columns[i].GetValue(&FetchServersTask.Servers[row], &args.Text);
|
||||||
|
|
||||||
|
Drawer2D_DrawClippedText(&Launcher_Framebuffer, &args,
|
||||||
|
x, y, w->Columns[i].Width);
|
||||||
|
x += w->Columns[i].Width + CELL_XPADDING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
PackedCol backGridCol = new PackedCol(20, 20, 10);
|
int DrawColumn(IDrawer2D drawer, string header, int columnI, int x, ColumnFilter filter) {
|
||||||
PackedCol foreGridCol = new PackedCol(40, 40, 40);
|
int y = table.Y + 3;
|
||||||
|
int maxWidth = table.ColumnWidths[columnI];
|
||||||
|
bool separator = columnI > 0;
|
||||||
|
|
||||||
int entryHeight, headerHeight;
|
DrawTextArgs args = new DrawTextArgs(header, titleFont, true);
|
||||||
int headerStartY, headerEndY;
|
TableEntry headerEntry = default(TableEntry);
|
||||||
int numEntries, maxIndex;
|
DrawColumnEntry(drawer, ref args, maxWidth, x, ref y, ref headerEntry);
|
||||||
Font font, titleFont;
|
maxIndex = table.Count;
|
||||||
|
|
||||||
void SetDrawData(IDrawer2D drawer, Font font, Font titleFont) {
|
y += 5;
|
||||||
this.font = font;
|
for (int i = table.CurrentIndex; i < table.Count; i++) {
|
||||||
this.titleFont = titleFont;
|
TableEntry entry = table.Get(i);
|
||||||
|
args = new DrawTextArgs(filter(entry), font, true);
|
||||||
|
|
||||||
headerHeight = drawer.FontHeight(titleFont, true);
|
if ((i == table.SelectedIndex || entry.Featured) && !separator) {
|
||||||
entryHeight = drawer.FontHeight(font, true);
|
int startY = y - 3;
|
||||||
|
int height = Math.Min(startY + (entryHeight + 4), table.Y + table.Height) - startY;
|
||||||
|
drawer.Clear(GetGridCol(entry.Featured, i == table.SelectedIndex), table.X, startY, table.Width, height);
|
||||||
|
}
|
||||||
|
if (!DrawColumnEntry(drawer, ref args, maxWidth, x, ref y, ref entry)) {
|
||||||
|
maxIndex = i; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (separator && !game.ClassicBackground) {
|
||||||
|
drawer.Clear(LauncherSkin.BackgroundCol, x - 7, table.Y, 2, table.Height);
|
||||||
|
}
|
||||||
|
return maxWidth + 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecalculateDrawData() {
|
PackedCol GetGridCol(bool featured, bool selected) {
|
||||||
for (int i = 0; i < table.ColumnWidths.Length; i++) {
|
if (featured) {
|
||||||
table.ColumnWidths[i] = table.DesiredColumnWidths[i];
|
if (selected) return new PackedCol(50, 53, 0);
|
||||||
Utils.Clamp(ref table.ColumnWidths[i], 20, game.Width - 20);
|
return new PackedCol(101, 107, 0);
|
||||||
}
|
|
||||||
table.Width = game.Width - table.X;
|
|
||||||
ResetEntries();
|
|
||||||
|
|
||||||
int y = table.Y + 3;
|
|
||||||
y += headerHeight + 2;
|
|
||||||
maxIndex = table.Count;
|
|
||||||
y += 5;
|
|
||||||
|
|
||||||
for (int i = table.CurrentIndex; i < table.Count; i++) {
|
|
||||||
if (y + entryHeight > table.Y + table.Height) {
|
|
||||||
maxIndex = i; return;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.entries[table.order[i]].Y = y;
|
|
||||||
table.entries[table.order[i]].Height = entryHeight;
|
|
||||||
y += entryHeight + 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
PackedCol foreGridCol = new PackedCol(40, 40, 40);
|
||||||
const int flagPadding = 15;
|
return foreGridCol;
|
||||||
void RedrawData(IDrawer2D drawer) {
|
|
||||||
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 maxWidth = table.ColumnWidths[columnI];
|
|
||||||
bool separator = columnI > 0;
|
|
||||||
|
|
||||||
DrawTextArgs args = new DrawTextArgs(header, titleFont, true);
|
|
||||||
TableEntry headerEntry = default(TableEntry);
|
|
||||||
DrawColumnEntry(drawer, ref args, maxWidth, x, ref y, ref headerEntry);
|
|
||||||
maxIndex = table.Count;
|
|
||||||
|
|
||||||
y += 5;
|
|
||||||
for (int i = table.CurrentIndex; i < table.Count; i++) {
|
|
||||||
TableEntry entry = table.Get(i);
|
|
||||||
args = new DrawTextArgs(filter(entry), font, true);
|
|
||||||
|
|
||||||
if ((i == table.SelectedIndex || entry.Featured) && !separator) {
|
|
||||||
int startY = y - 3;
|
|
||||||
int height = Math.Min(startY + (entryHeight + 4), table.Y + table.Height) - startY;
|
|
||||||
drawer.Clear(GetGridCol(entry.Featured, i == table.SelectedIndex), table.X, startY, table.Width, height);
|
|
||||||
}
|
|
||||||
if (!DrawColumnEntry(drawer, ref args, maxWidth, x, ref y, ref entry)) {
|
|
||||||
maxIndex = i; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (separator && !game.ClassicBackground) {
|
|
||||||
drawer.Clear(LauncherSkin.BackgroundCol, x - 7, table.Y, 2, table.Height);
|
|
||||||
}
|
|
||||||
return maxWidth + 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
PackedCol GetGridCol(bool featured, bool selected) {
|
|
||||||
if (featured) {
|
|
||||||
if (selected) return new PackedCol(50, 53, 0);
|
|
||||||
return new PackedCol(101, 107, 0);
|
|
||||||
}
|
|
||||||
return foreGridCol;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DrawColumnEntry(IDrawer2D drawer, ref DrawTextArgs args,
|
|
||||||
int maxWidth, int x, ref int y, ref TableEntry entry) {
|
|
||||||
Size size = drawer.MeasureText(ref args);
|
|
||||||
bool empty = args.Text == "";
|
|
||||||
if (empty)
|
|
||||||
size.Height = entryHeight;
|
|
||||||
if (y + size.Height > table.Y + table.Height) {
|
|
||||||
y = table.Y + table.Height + 2; return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Y = y; entry.Height = size.Height;
|
|
||||||
if (!empty) {
|
|
||||||
size.Width = Math.Min(maxWidth, size.Width);
|
|
||||||
args.SkipPartsCheck = false;
|
|
||||||
Drawer2DExt.DrawClippedText(ref args, drawer, x, y, maxWidth);
|
|
||||||
}
|
|
||||||
y += size.Height + 2;
|
|
||||||
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 {
|
bool DrawColumnEntry(IDrawer2D drawer, ref DrawTextArgs args, int maxWidth, int x, ref int y, ref TableEntry entry) {
|
||||||
public string Hash, Name, Players, Uptime, Software, RawUptime, Flag;
|
Size size = drawer.MeasureText(ref args);
|
||||||
public int Y, Height;
|
bool empty = args.Text == "";
|
||||||
public bool Featured;
|
if (empty)
|
||||||
|
size.Height = entryHeight;
|
||||||
|
if (y + size.Height > table.Y + table.Height) {
|
||||||
|
y = table.Y + table.Height + 2; return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Y = y; entry.Height = size.Height;
|
||||||
|
if (!empty) {
|
||||||
|
size.Width = Math.Min(maxWidth, size.Width);
|
||||||
|
args.SkipPartsCheck = false;
|
||||||
|
Drawer2DExt.DrawClippedText(ref args, drawer, x, y, maxWidth);
|
||||||
|
}
|
||||||
|
y += size.Height + 2;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void TableNeedsRedrawHandler();
|
|
||||||
|
|
||||||
TableView view;
|
|
||||||
public TableWidget(LauncherWindow window) : base(window) {
|
const int flagPadding = 15;
|
||||||
OnClick = HandleOnClick;
|
void DrawColumns(IDrawer2D drawer) {
|
||||||
view = new TableView();
|
int x = table.X + flagPadding + 5;
|
||||||
view.Init(window, this);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
int x, y, height;
|
||||||
|
x = w->X + w->Width - SCROLLBAR_WIDTH;
|
||||||
|
LTable_GetScrollbarCoords(w, &y, &height);
|
||||||
|
|
||||||
|
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) {
|
|
||||||
entries = new TableEntry[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;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string curFilter;
|
void TableNeedsRedrawHandler();
|
||||||
public void FilterEntries(string filter) {
|
|
||||||
curFilter = filter;
|
public TableNeedsRedrawHandler NeedRedraw;
|
||||||
Count = 0;
|
public Action<string> SelectedChanged;
|
||||||
for (int i = 0; i < entries.Length; i++) {
|
public int SelectedIndex = -1;
|
||||||
TableEntry entry = entries[i];
|
public string SelectedHash = "";
|
||||||
if (entry.Name.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0) {
|
public int CurrentIndex, Count;
|
||||||
order[Count++] = i;
|
|
||||||
}
|
internal TableEntry[] entries;
|
||||||
}
|
internal int[] order;
|
||||||
for (int i = Count; i < entries.Length; i++) {
|
internal List<ServerListEntry> servers;
|
||||||
order[i] = -100000;
|
internal TableEntry Get(int i) { return entries[order[i]]; }
|
||||||
|
|
||||||
|
void SetEntries(List<ServerListEntry> servers) {
|
||||||
|
entries = new TableEntry[servers.Count];
|
||||||
|
order = new int[servers.Count];
|
||||||
|
Count = entries.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
string curFilter;
|
||||||
|
void FilterEntries(string filter) {
|
||||||
|
curFilter = filter;
|
||||||
|
Count = 0;
|
||||||
|
for (int i = 0; i < entries.Length; i++) {
|
||||||
|
TableEntry entry = entries[i];
|
||||||
|
if (entry.Name.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0) {
|
||||||
|
order[Count++] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (int i = Count; i < entries.Length; i++) {
|
||||||
internal void GetScrollbarCoords(out int y, out int height) {
|
order[i] = -100000;
|
||||||
if (Count == 0) { y = 0; height = 0; return; }
|
|
||||||
|
|
||||||
float scale = Height / (float)Count;
|
|
||||||
y = (int)Math.Ceiling(CurrentIndex * scale);
|
|
||||||
height = (int)Math.Ceiling((view.maxIndex - CurrentIndex) * scale);
|
|
||||||
height = Math.Min(y + height, Height) - y;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetSelected(int index) {
|
static void LTable_GetScrollbarCoords(struct LTable* w, out int y, out int height) {
|
||||||
if (index >= view.maxIndex) CurrentIndex = index + 1 - view.numEntries;
|
if (Count == 0) { y = 0; height = 0; return; }
|
||||||
if (index < CurrentIndex) CurrentIndex = index;
|
|
||||||
if (index >= Count) index = Count - 1;
|
|
||||||
if (index < 0) index = 0;
|
|
||||||
|
|
||||||
SelectedHash = "";
|
float scale = Height / (float)Count;
|
||||||
SelectedIndex = index;
|
y = (int)Math.Ceiling(CurrentIndex * scale);
|
||||||
lastIndex = index;
|
height = (int)Math.Ceiling((view.maxIndex - CurrentIndex) * scale);
|
||||||
ClampIndex();
|
height = Math.Min(y + height, Height) - y;
|
||||||
|
}
|
||||||
|
|
||||||
if (Count > 0) {
|
void SetSelected(int index) {
|
||||||
TableEntry entry = Get(index);
|
if (index >= view.maxIndex) CurrentIndex = index + 1 - view.numEntries;
|
||||||
SelectedChanged(entry.Hash);
|
if (index < CurrentIndex) CurrentIndex = index;
|
||||||
SelectedHash = entry.Hash;
|
if (index >= Count) index = Count - 1;
|
||||||
}
|
if (index < 0) index = 0;
|
||||||
|
|
||||||
|
SelectedHash = "";
|
||||||
|
SelectedIndex = index;
|
||||||
|
lastIndex = index;
|
||||||
|
ClampIndex();
|
||||||
|
|
||||||
|
if (Count > 0) {
|
||||||
|
TableEntry entry = Get(index);
|
||||||
|
SelectedChanged(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() {
|
||||||
|
SortEntries(defComp, true);
|
||||||
|
}
|
||||||
|
|
||||||
public int[] ColumnWidths = new int[] { 320, 65, 65, 140 };
|
void SelectHeader(int mouseX, int mouseY) {
|
||||||
public int[] DesiredColumnWidths = new int[] { 320, 65, 65, 140 };
|
int x = X + 15;
|
||||||
|
for (int i = 0; i < ColumnWidths.Length; i++) {
|
||||||
public void SetDrawData(IDrawer2D drawer, Font font, Font titleFont,
|
x += ColumnWidths[i] + 10;
|
||||||
Anchor horAnchor, Anchor verAnchor, int x, int y) {
|
if (mouseX >= x - 8 && mouseX < x + 8) {
|
||||||
SetLocation(horAnchor, verAnchor, x, y);
|
DraggingColumn = i;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SelectHeader(int mouseX, int mouseY) {
|
|
||||||
int x = X + 15;
|
|
||||||
for (int i = 0; i < ColumnWidths.Length; i++) {
|
|
||||||
x += ColumnWidths[i] + 10;
|
|
||||||
if (mouseX >= x - 8 && mouseX < x + 8) {
|
|
||||||
DraggingColumn = i;
|
|
||||||
lastIndex = -10; return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TrySortColumns(mouseX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrySortColumns(int mouseX) {
|
|
||||||
int x = X + TableView.flagPadding;
|
|
||||||
if (mouseX >= x && mouseX < x + ColumnWidths[0]) {
|
|
||||||
SortEntries(nameComp, false); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
x += ColumnWidths[0] + 10;
|
|
||||||
if (mouseX >= x && mouseX < x + ColumnWidths[1]) {
|
|
||||||
SortEntries(playerComp, false); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
x += ColumnWidths[1] + 10;
|
|
||||||
if (mouseX >= x && mouseX < x + ColumnWidths[2]) {
|
|
||||||
SortEntries(uptimeComp, false); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
x += ColumnWidths[2] + 10;
|
|
||||||
if (mouseX >= x) {
|
|
||||||
SortEntries(softwareComp, false); return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortEntries(TableEntryComparer comparer, bool noRedraw) {
|
|
||||||
Array.Sort(entries, 0, entries.Length, comparer);
|
|
||||||
lastIndex = -10;
|
|
||||||
if (curFilter != null && curFilter.Length > 0) {
|
|
||||||
FilterEntries(curFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noRedraw) return;
|
|
||||||
comparer.Invert = !comparer.Invert;
|
|
||||||
SetSelected(SelectedHash);
|
|
||||||
NeedRedraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetSelectedServer(int mouseX, int mouseY) {
|
|
||||||
for (int i = 0; i < Count; i++) {
|
|
||||||
TableEntry entry = Get(i);
|
|
||||||
if (mouseY < entry.Y || mouseY >= entry.Y + entry.Height + 2) continue;
|
|
||||||
|
|
||||||
if (lastIndex == i && (DateTime.UtcNow - lastPress).TotalSeconds < 1) {
|
|
||||||
Window.ConnectToServer(servers, entry.Hash);
|
|
||||||
lastPress = DateTime.MinValue;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetSelected(i);
|
|
||||||
NeedRedraw();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleOnClick(int mouseX, int mouseY) {
|
|
||||||
if (mouseX >= Window.Width - 10) {
|
|
||||||
ScrollbarClick(mouseY);
|
|
||||||
DraggingScrollbar = true;
|
|
||||||
lastIndex = -10; return;
|
lastIndex = -10; return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
TrySortColumns(mouseX);
|
||||||
|
}
|
||||||
|
|
||||||
if (mouseY >= view.headerStartY && mouseY < view.headerEndY) {
|
void TrySortColumns(int mouseX) {
|
||||||
SelectHeader(mouseX, mouseY);
|
int x = X + TableView.flagPadding;
|
||||||
} else {
|
if (mouseX >= x && mouseX < x + ColumnWidths[0]) {
|
||||||
GetSelectedServer(mouseX, mouseY);
|
SortEntries(nameComp, false); return;
|
||||||
}
|
|
||||||
lastPress = DateTime.UtcNow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lastIndex = -10;
|
x += ColumnWidths[0] + 10;
|
||||||
DateTime lastPress;
|
if (mouseX >= x && mouseX < x + ColumnWidths[1]) {
|
||||||
public void MouseMove(int x, int y, int deltaX, int deltaY) {
|
SortEntries(playerComp, false); return;
|
||||||
if (DraggingScrollbar) {
|
|
||||||
y -= Y;
|
|
||||||
float scale = Height / (float)Count;
|
|
||||||
CurrentIndex = (int)((y - mouseOffset) / scale);
|
|
||||||
ClampIndex();
|
|
||||||
NeedRedraw();
|
|
||||||
} else if (DraggingColumn >= 0) {
|
|
||||||
if (x >= Window.Width - 20) return;
|
|
||||||
int col = DraggingColumn;
|
|
||||||
ColumnWidths[col] += deltaX;
|
|
||||||
Utils.Clamp(ref ColumnWidths[col], 20, Window.Width - 20);
|
|
||||||
DesiredColumnWidths[col] = ColumnWidths[col];
|
|
||||||
NeedRedraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollbarClick(int mouseY) {
|
x += ColumnWidths[1] + 10;
|
||||||
|
if (mouseX >= x && mouseX < x + ColumnWidths[2]) {
|
||||||
|
SortEntries(uptimeComp, false); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
x += ColumnWidths[2] + 10;
|
||||||
|
if (mouseX >= x) {
|
||||||
|
SortEntries(softwareComp, false); return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SortEntries(TableEntryComparer comparer, bool noRedraw) {
|
||||||
|
Array.Sort(entries, 0, entries.Length, comparer);
|
||||||
|
lastIndex = -10;
|
||||||
|
if (curFilter != null && curFilter.Length > 0) {
|
||||||
|
FilterEntries(curFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noRedraw) return;
|
||||||
|
comparer.Invert = !comparer.Invert;
|
||||||
|
SetSelected(SelectedHash);
|
||||||
|
NeedRedraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetSelectedServer(int mouseX, int mouseY) {
|
||||||
|
for (int i = 0; i < Count; i++) {
|
||||||
|
TableEntry entry = Get(i);
|
||||||
|
if (mouseY < entry.Y || mouseY >= entry.Y + entry.Height + 2) continue;
|
||||||
|
|
||||||
|
if (lastIndex == i) {
|
||||||
|
Launcher_ConnectToServer(entry.Hash);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSelected(i);
|
||||||
|
NeedRedraw();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseDown(int mouseX, int mouseY) {
|
||||||
|
if (mouseX >= Window.Width - 10) {
|
||||||
|
ScrollbarClick(mouseY);
|
||||||
|
DraggingScrollbar = true;
|
||||||
|
lastIndex = -10; return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouseY >= view.headerStartY && mouseY < view.headerEndY) {
|
||||||
|
SelectHeader(mouseX, mouseY);
|
||||||
|
} else {
|
||||||
|
GetSelectedServer(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int lastIndex = -10;
|
||||||
|
void MouseMove(int x, int y, int deltaX, int deltaY) {
|
||||||
|
if (DraggingScrollbar) {
|
||||||
|
y -= Y;
|
||||||
|
float scale = Height / (float)Count;
|
||||||
|
CurrentIndex = (int)((y - mouseOffset) / scale);
|
||||||
|
ClampIndex();
|
||||||
|
NeedRedraw();
|
||||||
|
} else if (DraggingColumn >= 0) {
|
||||||
|
if (x >= Window.Width - 20) return;
|
||||||
|
int col = DraggingColumn;
|
||||||
|
ColumnWidths[col] += deltaX;
|
||||||
|
Utils.Clamp(ref ColumnWidths[col], 20, Window.Width - 20);
|
||||||
|
NeedRedraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = <able_VTABLE;
|
||||||
|
w->Columns = tableColumns;
|
||||||
|
w->NumColumns = Array_Elems(tableColumns);
|
||||||
|
|
||||||
|
w->HdrFont = *hdrFont;
|
||||||
|
w->RowFont = *rowFont;
|
||||||
|
|
||||||
|
LTable_StopDragging(w);
|
||||||
|
LTable_Reposition(w);
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user