From 7913f90844e465306178c337ef5aa4813614d9ab Mon Sep 17 00:00:00 2001 From: TimePath Date: Wed, 26 Aug 2015 22:06:37 +1000 Subject: [PATCH] Graphical friends list --- gfx/menu/luma/skinvalues.txt | 2 + gfx/menu/luminos/skinvalues.txt | 2 + gfx/menu/wickedx/skinvalues.txt | 2 + gfx/menu/xaw/skinvalues.txt | 2 + qcsrc/common/mutators/mutator/social.qc | 6 +- qcsrc/common/mutators/mutator/social.qh | 14 +++ qcsrc/common/util.qc | 2 +- qcsrc/common/util.qh | 14 +-- qcsrc/menu/classes.inc | 1 + qcsrc/menu/skin-customizables.inc | 2 + qcsrc/menu/xonotic/dialog_social.qc | 116 ++++++++++++++++++++++++ qcsrc/menu/xonotic/mainwindow.qc | 6 ++ 12 files changed, 158 insertions(+), 11 deletions(-) create mode 100644 qcsrc/common/mutators/mutator/social.qh create mode 100644 qcsrc/menu/xonotic/dialog_social.qc diff --git a/gfx/menu/luma/skinvalues.txt b/gfx/menu/luma/skinvalues.txt index c997fea25..f9e5109b3 100644 --- a/gfx/menu/luma/skinvalues.txt +++ b/gfx/menu/luma/skinvalues.txt @@ -86,6 +86,7 @@ COLOR_DIALOG_MUTATORS '1 1 1' COLOR_DIALOG_MAPINFO '1 1 1' COLOR_DIALOG_USERBIND '1 1 1' COLOR_DIALOG_SINGLEPLAYER '1 1 1' +COLOR_DIALOG_SOCIAL '1 1 1' COLOR_DIALOG_CREDITS '1 1 1' COLOR_DIALOG_WEAPONS '1 1 1' COLOR_DIALOG_VIEW '1 1 1' @@ -112,6 +113,7 @@ POSITION_DIALOG_MULTIPLAYER '0.9 0.4 0' POSITION_DIALOG_SINGLEPLAYER '0.15 0.4 0' POSITION_DIALOG_SETTINGS '0.5 1 0' POSITION_DIALOG_CREDITS '-0.05 1.2 0' +POSITION_DIALOG_SOCIAL '0.5 1.2 0' POSITION_DIALOG_QUIT '1.05 1.2 0' // font diff --git a/gfx/menu/luminos/skinvalues.txt b/gfx/menu/luminos/skinvalues.txt index ca0384fb5..33b450b97 100755 --- a/gfx/menu/luminos/skinvalues.txt +++ b/gfx/menu/luminos/skinvalues.txt @@ -62,6 +62,7 @@ POSITION_DIALOG_MULTIPLAYER '0.9 0.4 0' POSITION_DIALOG_SINGLEPLAYER '0.15 0.4 0' POSITION_DIALOG_SETTINGS '0.5 1 0' POSITION_DIALOG_CREDITS '-0.05 1.2 0' +POSITION_DIALOG_SOCIAL '0.5 1.2 0' POSITION_DIALOG_QUIT '1.05 1.2 0' // tooltips @@ -185,6 +186,7 @@ COLOR_DIALOG_MUTATORS '1 1 1' COLOR_DIALOG_MAPINFO '1 1 1' COLOR_DIALOG_USERBIND '1 1 1' COLOR_DIALOG_SINGLEPLAYER '1 1 1' +COLOR_DIALOG_SOCIAL '1 1 1' COLOR_DIALOG_CREDITS '1 1 1' COLOR_DIALOG_WEAPONS '1 1 1' COLOR_DIALOG_VIEW '1 1 1' diff --git a/gfx/menu/wickedx/skinvalues.txt b/gfx/menu/wickedx/skinvalues.txt index b7011a0b0..0cefa564c 100644 --- a/gfx/menu/wickedx/skinvalues.txt +++ b/gfx/menu/wickedx/skinvalues.txt @@ -62,6 +62,7 @@ POSITION_DIALOG_MULTIPLAYER '0.8 0.4 0' POSITION_DIALOG_SINGLEPLAYER '0.2 0.4 0' POSITION_DIALOG_SETTINGS '0.5 0.95 0' POSITION_DIALOG_CREDITS '-0.05 1.2 0' +POSITION_DIALOG_SOCIAL '0.5 1.2 0' POSITION_DIALOG_QUIT '1.05 1.2 0' // tooltips @@ -185,6 +186,7 @@ COLOR_DIALOG_MUTATORS '1 1 1' COLOR_DIALOG_MAPINFO '1 1 1' COLOR_DIALOG_USERBIND '1 1 1' COLOR_DIALOG_SINGLEPLAYER '1 1 1' +COLOR_DIALOG_SOCIAL '1 1 1' COLOR_DIALOG_CREDITS '1 1 1' COLOR_DIALOG_WEAPONS '1 1 1' COLOR_DIALOG_VIEW '1 1 1' diff --git a/gfx/menu/xaw/skinvalues.txt b/gfx/menu/xaw/skinvalues.txt index 5f4bbaad4..788470b3c 100644 --- a/gfx/menu/xaw/skinvalues.txt +++ b/gfx/menu/xaw/skinvalues.txt @@ -29,6 +29,7 @@ COLOR_DIALOG_MUTATORS '1 1 1' COLOR_DIALOG_MAPINFO '1 1 1' COLOR_DIALOG_USERBIND '1 1 1' COLOR_DIALOG_SINGLEPLAYER '1 1 1' +COLOR_DIALOG_SOCIAL '1 1 1' COLOR_DIALOG_CREDITS '1 1 1' COLOR_DIALOG_WEAPONS '1 1 1' COLOR_DIALOG_VIEW '1 1 1' @@ -46,6 +47,7 @@ POSITION_DIALOG_MULTIPLAYER '0.9 0.5 0' POSITION_DIALOG_SINGLEPLAYER '0.1 0.1 0' POSITION_DIALOG_SETTINGS '0.1 0.9 0' POSITION_DIALOG_CREDITS '0.3 1.2 0' +POSITION_DIALOG_SOCIAL '0.6 1.2 0' POSITION_DIALOG_QUIT '0.9 1.2 0' // mouse diff --git a/qcsrc/common/mutators/mutator/social.qc b/qcsrc/common/mutators/mutator/social.qc index 52dd90a05..3ea0b0f9c 100644 --- a/qcsrc/common/mutators/mutator/social.qc +++ b/qcsrc/common/mutators/mutator/social.qc @@ -1,12 +1,11 @@ #ifdef MENUQC +#include "social.qh" REGISTER_MUTATOR(social, true); void Social_send(int to, string msg); string Social_invite_accept; -int Social_db = -1; - STATIC_INIT(Social) { Social_db = db_load("social.db"); } @@ -101,6 +100,7 @@ MUTATOR_HOOKFUNCTION(social, GameCommand) { int id = stoi(argv(1)); string nick = substring(cmd_string, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)); db_put(Social_db, itos(id), nick); + MUTATOR_CALLHOOK(Social_Add, id, nick); return true; } if (cmd_name == "sremove" && cmd_argc == 2) { @@ -109,7 +109,7 @@ MUTATOR_HOOKFUNCTION(social, GameCommand) { return true; } if (cmd_name == "slist") { - FOREACH_DB(Social_db, LAMBDA( + FOREACH_DB(Social_db, true, LAMBDA( printf("%s: %s\n", k, v); )); return true; diff --git a/qcsrc/common/mutators/mutator/social.qh b/qcsrc/common/mutators/mutator/social.qh new file mode 100644 index 000000000..f8cc8a7a1 --- /dev/null +++ b/qcsrc/common/mutators/mutator/social.qh @@ -0,0 +1,14 @@ +#ifdef MENUQC +#ifndef SOCIAL_H +#define SOCIAL_H +#include "../base.qh" +/** Called when a friend is added */ +#define EV_Social_Add(i, o) \ + /**/ i(int, mutator_argv_int_0) \ + /**/ i(string, mutator_argv_string_0) \ + /**/ +MUTATOR_HOOKABLE(Social_Add, EV_Social_Add); + +int Social_db = -1; +#endif +#endif diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index 6e14a7f5a..e0428d43f 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -349,7 +349,7 @@ void db_dump(int db, string pFilename) if (fh < 0) error(strcat("Can't dump DB to ", pFilename)); fputs(fh, "0\n"); - FOREACH_DB(db, LAMBDA( + FOREACH_DB(db, true, LAMBDA( fputs(fh, strcat("\\", k, "\\", v, "\n")); )); fclose(fh); diff --git a/qcsrc/common/util.qh b/qcsrc/common/util.qh index b4aa5b305..fc26e8a5d 100644 --- a/qcsrc/common/util.qh +++ b/qcsrc/common/util.qh @@ -90,23 +90,23 @@ void db_close(int db); string db_get(int db, string key); void db_put(int db, string key, string value); void db_delete(float db, string pKey); -#define FOREACH_INFO(s, f) do { \ +#define FOREACH_INFO(s, cond, f) do { \ string __s = s; \ int __m = tokenizebyseparator(__s, "\\"); \ for (int __j = 2; __j < __m; __j += 2) { \ - string k = argv(__j - 1), v = argv(__j); \ - f; \ + noref string k = argv(__j - 1), v = uri_unescape(argv(__j)); \ + if (cond) f; \ } \ } while (0) -#define FOREACH_BUF(db, f) do { \ +#define FOREACH_BUF(db, cond, f) do { \ int __db = db; \ int __n = buf_getsize(__db); \ for (int __i = 0; __i < __n; ++__i) { \ - f; \ + if (cond) f; \ } \ } while (0) -#define FOREACH_DB(db, f) do { \ - FOREACH_BUF(db, FOREACH_INFO(bufstr_get(__db, __i), f)); \ +#define FOREACH_DB(db, cond, f) do { \ + FOREACH_BUF(db, true, FOREACH_INFO(bufstr_get(__db, __i), cond, f)); \ } while (0) // stringbuffer loading/saving diff --git a/qcsrc/menu/classes.inc b/qcsrc/menu/classes.inc index aee7166e1..8e0d266e2 100644 --- a/qcsrc/menu/classes.inc +++ b/qcsrc/menu/classes.inc @@ -99,6 +99,7 @@ #include "xonotic/dialog_settings_video.qc" #include "xonotic/dialog_singleplayer.qc" #include "xonotic/dialog_singleplayer_winner.qc" +#include "xonotic/dialog_social.qc" #include "xonotic/dialog_teamselect.qc" #include "xonotic/gametypelist.qc" #include "xonotic/image.qc" diff --git a/qcsrc/menu/skin-customizables.inc b/qcsrc/menu/skin-customizables.inc index d5e1f82eb..a55a6cdf1 100644 --- a/qcsrc/menu/skin-customizables.inc +++ b/qcsrc/menu/skin-customizables.inc @@ -63,6 +63,7 @@ SKINBEGIN SKINVECTOR(COLOR_DIALOG_MAPINFO, '0.7 0.7 1'); SKINVECTOR(COLOR_DIALOG_USERBIND, '0.7 0.7 1'); SKINVECTOR(COLOR_DIALOG_SINGLEPLAYER, '1 1 0.7'); + SKINVECTOR(COLOR_DIALOG_SOCIAL, '1 1 1'); SKINVECTOR(COLOR_DIALOG_CREDITS, '0.7 0.7 1'); SKINVECTOR(COLOR_DIALOG_WEAPONS, '1 0.7 0.7'); SKINVECTOR(COLOR_DIALOG_VIEW, '1 0.7 0.7'); @@ -80,6 +81,7 @@ SKINBEGIN SKINVECTOR(POSITION_DIALOG_SINGLEPLAYER, '0.1 0.1 0'); SKINVECTOR(POSITION_DIALOG_SETTINGS, '0.1 0.9 0'); SKINVECTOR(POSITION_DIALOG_CREDITS, '0.3 1.2 0'); + SKINVECTOR(POSITION_DIALOG_SOCIAL, '0.5 1.2 0'); SKINVECTOR(POSITION_DIALOG_QUIT, '0.9 1.2 0'); // mouse diff --git a/qcsrc/menu/xonotic/dialog_social.qc b/qcsrc/menu/xonotic/dialog_social.qc new file mode 100644 index 000000000..28ebdef65 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_social.qc @@ -0,0 +1,116 @@ +#ifndef DIALOG_SOCIAL_H +#define DIALOG_SOCIAL_H + +#include "../../common/mutators/mutator/social.qh" +#include "datasource.qc" +CLASS(FriendSource, DataSource) + METHOD(FriendSource, getEntry, entity(int i, void(string name, string icon) returns)) + { + int idx = 0; + string name = string_null; + FOREACH_DB(Social_db, idx++ == i, LAMBDA( + name = v; + break; + )); + if (returns) returns(name, string_null); + return DataSource_true; + } + METHOD(FriendSource, reload, int(string filter)) { + int n = 0; + FOREACH_DB(Social_db, true, LAMBDA(++n)); + return n; + } +ENDCLASS(FriendSource) + +entity Social_inst; + +#include "listbox.qc" +CLASS(XonoticFriendsList, XonoticListBox) + ATTRIB(XonoticFriendsList, alphaBG, float, 0) + ATTRIB(XonoticFriendsList, itemAbsSize, vector, '0 0 0') + ATTRIB(XonoticFriendsList, origin, vector, '0 0 0') + ATTRIB(XonoticFriendsList, realFontSize, vector, '0 0 0') + ATTRIB(XonoticFriendsList, realUpperMargin, float, 0) + ATTRIB(XonoticFriendsList, rowsPerItem, float, 2) + ATTRIB(XonoticFriendsList, stringFilterBox, entity, NULL) + ATTRIB(XonoticFriendsList, stringFilter, string, string_null) + ATTRIB(XonoticFriendsList, typeToSearchString, string, string_null) + ATTRIB(XonoticFriendsList, typeToSearchTime, float, 0) + ATTRIB(XonoticFriendsList, source, DataSource, NULL) + ATTRIB(XonoticFriendsList, onChange, void(entity, entity), func_null) + ATTRIB(XonoticFriendsList, onChangeEntity, entity, NULL) + string XonoticFriendsList_cb_name; + void XonoticFriendsList_cb(string _name, string _icon) + { + XonoticFriendsList_cb_name = _name; + } + METHOD(XonoticFriendsList, drawListBoxItem, void(entity this, int i, vector absSize, bool isSelected, bool isFocused)) + { + if (!this.source) return; + if (!this.source.getEntry(i, XonoticFriendsList_cb)) return; + string name = XonoticFriendsList_cb_name; + if (isSelected) { + draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED); + } else if (isFocused) { + this.focusedItemAlpha = getFadedAlpha(this.focusedItemAlpha, SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED); + draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, this.focusedItemAlpha); + } + string s = draw_TextShortenToWidth(strdecolorize(name), 1, 0, this.realFontSize); + draw_Text(this.realUpperMargin * eY + (0.5 * this.realFontSize.x) * eX, s, this.realFontSize, '1 1 1', SKINALPHA_TEXT, 0); + } + METHOD(XonoticFriendsList, refilter, void(entity this)) + { + if (!this.source) { + this.nItems = 0; + return; + } + this.nItems = this.source.reload(this.stringFilter); + } + METHOD(XonoticFriendsList, resizeNotify, void(entity this, vector relOrigin, vector relSize, vector absOrigin, vector absSize)) + { + super.resizeNotify(this, relOrigin, relSize, absOrigin, absSize); + + this.itemAbsSize = '0 0 0'; + this.realFontSize_y = this.fontSize / (this.itemAbsSize_y = (absSize.y * this.itemHeight)); + this.realFontSize_x = this.fontSize / (this.itemAbsSize_x = (absSize.x * (1 - this.controlWidth))); + this.realUpperMargin = 0.5 * (1 - this.realFontSize.y); + } + INIT(XonoticFriendsList) { + Social_inst = this; + } + CONSTRUCTOR(XonoticFriendsList, DataSource _source) { + CONSTRUCT(XonoticFriendsList); + this.source = _source; + this.configureXonoticListBox(this); + this.refilter(this); + } +ENDCLASS(XonoticFriendsList) + +#include "dialog.qc" +CLASS(XonoticSocialDialog, XonoticDialog) + METHOD(XonoticSocialDialog, fill, void(entity)); + ATTRIB(XonoticSocialDialog, title, string, _("Social")) + ATTRIB(XonoticSocialDialog, color, vector, SKINCOLOR_DIALOG_SOCIAL) + ATTRIB(XonoticSocialDialog, intendedWidth, float, 0.5) + ATTRIB(XonoticSocialDialog, rows, float, 20) + ATTRIB(XonoticSocialDialog, columns, float, 2) + ATTRIB(XonoticSocialDialog, friendsList, XonoticFriendsList, NEW(XonoticFriendsList, NEW(FriendSource))) +ENDCLASS(XonoticSocialDialog) + +#endif + +#ifdef IMPLEMENTATION + +REGISTER_MUTATOR(social_refreshmenu, true); +MUTATOR_HOOKFUNCTION(social_refreshmenu, Social_Add) { + Social_inst.refilter(Social_inst); +} + +METHOD(XonoticSocialDialog, fill, void(entity this)) +{ + int + col = 0, width = 2; + this.gotoRC(this, 0, col); + this.TD(this, this.rows, width, this.friendsList); +} +#endif diff --git a/qcsrc/menu/xonotic/mainwindow.qc b/qcsrc/menu/xonotic/mainwindow.qc index eafa1842f..27cf68903 100644 --- a/qcsrc/menu/xonotic/mainwindow.qc +++ b/qcsrc/menu/xonotic/mainwindow.qc @@ -238,6 +238,12 @@ void MainWindow_configureMainWindow(entity me) n.setNexposee(n, i, SKINPOSITION_DIALOG_CREDITS, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); n.pullNexposee(n, i, eY * (SKINHEIGHT_TITLE * SKINFONTSIZE_TITLE / conheight)); + i = NEW(XonoticSocialDialog); + i.configureDialog(i); + n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + n.setNexposee(n, i, SKINPOSITION_DIALOG_SOCIAL, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); + n.pullNexposee(n, i, eY * (SKINHEIGHT_TITLE * SKINFONTSIZE_TITLE / conheight)); + i = NEW(XonoticQuitDialog); i.configureDialog(i); n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); -- 2.39.2