From: TimePath Date: Mon, 24 Aug 2015 03:03:57 +0000 (+1000) Subject: Merge branch 'master' into TimePath/guide X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=e68c2c11558605fc7bc12a37f6317f28ae8143fc;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into TimePath/guide --- e68c2c11558605fc7bc12a37f6317f28ae8143fc diff --cc qcsrc/common/buffs.qh index 87dff12a0c,ddf5722816..e0bda4c677 --- a/qcsrc/common/buffs.qh +++ b/qcsrc/common/buffs.qh @@@ -33,12 -33,8 +33,11 @@@ CLASS(Buff, Pickup ATTRIB(Buff, m_prettyName, string, "Buff") ATTRIB(Buff, m_skin, int, 0) ATTRIB(Buff, m_sprite, string, "") - METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) - void Buff_display(entity this, void(string name, string icon) returns) { ++ METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) { + returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name)); + } #ifdef SVQC - METHOD(Buff, m_time, float(entity)) + METHOD(Buff, m_time, float(entity)); float Buff_m_time(entity this) { return cvar(strcat("g_buffs_", this.netname, "_time")); } #endif ENDCLASS(Buff) diff --cc qcsrc/common/items/item.qh index a976da5caa,0b17f35b2c..16db397285 --- a/qcsrc/common/items/item.qh +++ b/qcsrc/common/items/item.qh @@@ -5,14 -5,8 +5,12 @@@ /** If you register a new item, make sure to add it to all.inc */ CLASS(GameItem, Object) ATTRIB(GameItem, m_id, int, 0) - METHOD(GameItem, show, void(entity this)); - void GameItem_show(entity this) { print("A game item\n"); } + ATTRIB(GameItem, m_name, string, string_null) + ATTRIB(GameItem, m_icon, string, string_null) - METHOD(GameItem, display, void(entity this, void(string name, string icon) returns)) - void GameItem_display(entity this, void(string name, string icon) returns) { ++ METHOD(GameItem, display, void(entity this, void(string name, string icon) returns)) { + returns(this.m_name, this.m_icon ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.m_icon) : string_null); + } - METHOD(GameItem, show, void(entity this)) - void GameItem_show(entity this) { print("A game item\n"); } ++ METHOD(GameItem, show, void(entity this)) { print("A game item\n"); } void ITEM_HANDLE(Show, entity this) { this.show(this); } ENDCLASS(GameItem) diff --cc qcsrc/common/mapinfo.qh index b8efb9d90c,e9979379c9..19799df740 --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@@ -19,13 -19,6 +19,13 @@@ CLASS(Gametype, Object ATTRIB(Gametype, model2, string, string_null) /** game type description */ ATTRIB(Gametype, gametype_description, string, string_null) + - METHOD(Gametype, describe, string(entity this)) - string Gametype_describe(entity this) { return this.gametype_description; } ++ METHOD(Gametype, describe, string(entity this)) { return this.gametype_description; } + - METHOD(Gametype, display, void(entity this, void(string name, string icon) returns)) - void Gametype_display(entity this, void(string, string) returns) { returns(this.message, strcat("gametype_", this.mdl)); } ++ METHOD(Gametype, display, void(entity this, void(string name, string icon) returns)) { ++ returns(this.message, strcat("gametype_", this.mdl)); ++ } + CONSTRUCTOR(Gametype, string hname, string sname, string g_name, bool gteamplay, string defaults, string gdescription) { CONSTRUCT(Gametype); diff --cc qcsrc/common/nades.qh index b876c86c9c,01eb7fff2c..50f2e57e80 --- a/qcsrc/common/nades.qh +++ b/qcsrc/common/nades.qh @@@ -37,10 -36,6 +37,9 @@@ CLASS(Nade, Object ATTRIB(Nade, m_icon, string, "nade_normal") ATTRIBARRAY(Nade, m_projectile, int, 2) ATTRIBARRAY(Nade, m_trail, string, 2) - METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) - void Nade_display(entity this, void(string name, string icon) returns) { ++ METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) { + returns(this.m_name, sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.m_icon)); + } ENDCLASS(Nade) REGISTER_NADE(NULL); diff --cc qcsrc/common/oo.qh index 3cbd8450df,add63b0cd8..3c7237ef40 --- a/qcsrc/common/oo.qh +++ b/qcsrc/common/oo.qh @@@ -116,21 -115,7 +117,21 @@@ STATIC_INIT(RegisterClasses) { Register #define spawn_static(this) #define spawn_1(this) #define _vtbl NULL -CLASS(Object, ); ENDCLASS(Object) +CLASS(Object, ); - METHOD(Object, describe, string(entity this)) - string Object_describe(entity this) { ++ METHOD(Object, describe, string(entity this)) { + string s = _("No description"); + if (cvar("developer")) { + for (int i = 0, n = numentityfields(); i < n; ++i) { + string value = getentityfieldstring(i, this); + if (value != "") s = sprintf("%s\n%s = %s", s, entityfieldname(i), value); + } + } + return s; + } - METHOD(Object, display, void(entity this, void(string name, string icon) returns)) - void Object_display(entity this, void(string name, string icon) returns) { returns(sprintf("entity %i", this), "nopreview_map"); } ++ METHOD(Object, display, void(entity this, void(string name, string icon) returns)) { ++ returns(sprintf("entity %i", this), "nopreview_map"); ++ } +ENDCLASS(Object) #undef spawn_static #undef spawn_1 #undef _vtbl diff --cc qcsrc/common/weapons/all.qh index e1ff03941c,ac839a53a0..4b6a714499 --- a/qcsrc/common/weapons/all.qh +++ b/qcsrc/common/weapons/all.qh @@@ -183,11 -183,6 +183,10 @@@ CLASS(Weapon, Object /** M: wepname : human readable name */ ATTRIB(Weapon, message, string, "AOL CD Thrower"); - METHOD(Weapon, display, void(entity this, void(string name, string icon) returns)) - void Weapon_display(entity this, void(string name, string icon) returns) { ++ METHOD(Weapon, display, void(entity this, void(string name, string icon) returns)) { + returns(this.message, this.model2 ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.model2) : string_null); + } + CONSTRUCTOR(Weapon, bool(int) function, .int ammotype, diff --cc qcsrc/menu/xonotic/datasource.qc index 3c484e3ceb,0000000000..db3b77a016 mode 100644,000000..100644 --- a/qcsrc/menu/xonotic/datasource.qc +++ b/qcsrc/menu/xonotic/datasource.qc @@@ -1,23 -1,0 +1,23 @@@ +#ifndef DATASOURCE_H +#define DATASOURCE_H +CLASS(DataSource, Object) + /** + * get entry `i` passing `name` and `icon` through `returns` if it is not null + * returns `DataSource_false` if out of bounds + * otherwise returns an entity or `DataSource_true` + */ - METHOD(DataSource, getEntry, entity(int i, void(string name, string icon) returns)) ++ METHOD(DataSource, getEntry, entity(int i, void(string name, string icon) returns)); + /** return the index of the first match for `find`. optional */ - METHOD(DataSource, indexOf, int(string find)) ++ METHOD(DataSource, indexOf, int(string find)); + /** reload all entries matching `filter` returning how many matches were found */ - METHOD(DataSource, reload, int(string filter)) ++ METHOD(DataSource, reload, int(string filter)); + /** cleanup on shutdown. optional */ - METHOD(DataSource, destroy, void(entity)) ++ METHOD(DataSource, destroy, void(entity)); + entity DataSource_true; + entity DataSource_false; + INIT_STATIC(DataSource) { + DataSource_true = NEW(Object); + DataSource_false = NULL; + } +ENDCLASS(DataSource) +#endif diff --cc qcsrc/menu/xonotic/dialog_media_guide.qc index e16a48780b,0000000000..1e208ce1b6 mode 100644,000000..100644 --- a/qcsrc/menu/xonotic/dialog_media_guide.qc +++ b/qcsrc/menu/xonotic/dialog_media_guide.qc @@@ -1,254 -1,0 +1,233 @@@ +#ifndef DIALOG_MEDIA_GUIDE_H +#define DIALOG_MEDIA_GUIDE_H +#include "datasource.qc" + +#define TOPICS(X) \ + X(NEW(GametypeSource), _("Gametypes"), "gametype_dm") \ + X(NEW(WeaponSource), _("Weapons"), "gametype_ka") \ + X(NEW(ItemSource), _("Items"), "gametype_kh") \ + X(NEW(BuffSource), _("Buffs"), "gametype_dom") \ + X(NEW(NadeSource), _("Nades"), "gametype_ft") \ + X(NEW(MapSource), _("Maps"), "gametype_ctf") \ + if (cvar("developer")) X(NEW(DebugSource), _("Debug"), "gametype_ons") \ + /**/ +CLASS(TopicSource, DataSource) - METHOD(TopicSource, getEntry, entity(int, void(string, string))) - entity TopicSource_getEntry(int i, void(string, string) returns) { ++ METHOD(TopicSource, getEntry, entity(int i, void(string, string) returns)) { + int idx = 0; + #define TOPIC(src, name, icon) if (idx++ == i) { if (returns) returns(name, icon); return DataSource_true; } + TOPICS(TOPIC); + #undef TOPIC + if (returns) returns("undefined", "undefined"); + return DataSource_false; + } - METHOD(TopicSource, reload, int(string)) - int TopicSource_reload(string filter) { ++ METHOD(TopicSource, reload, int(string filter)) { + int n = 0; + #define TOPIC(src, name, icon) n++; + TOPICS(TOPIC); + #undef TOPIC + return n; + } +ENDCLASS(TopicSource) + +CLASS(DebugSource, DataSource) + .entity nextdebug; + entity find_debug() { + entity head = NULL, tail = NULL; + for (entity it = NULL; (it = nextent(it)); ) { + if (!it.instanceOfObject) continue; + if (it.instanceOfItem) continue; + if (it.classname == "Object") continue; + if (it.classname == "vtbl") continue; + if (!tail) { + tail = head = it; + } else { + tail.nextdebug = it; + tail = it; + } + } + return head; + } + string DebugSource_activeFilter = ""; - METHOD(DebugSource, getEntry, entity(int, void(string, string))) - entity DebugSource_getEntry(int i, void(string, string) returns) { ++ METHOD(DebugSource, getEntry, entity(int i, void(string, string) returns)) { + int idx = 0; + entity e; + for (e = find_debug(); e; e = e.nextdebug) { + if (strstrofs(sprintf("entity %i", e), DebugSource_activeFilter, 0) < 0) continue; + if (idx++ == i) break; + } + if (returns) e.display(e, returns); + return e; + } - METHOD(DebugSource, reload, int(string)) - int DebugSource_reload(string filter) { ++ METHOD(DebugSource, reload, int(string filter)) { + DebugSource_activeFilter = filter; + int idx = 0; + entity e; + for (e = find_debug(); e; e = e.nextdebug) { + if (strstrofs(sprintf("entity %i", e), DebugSource_activeFilter, 0) < 0) continue; + idx++; + } + return idx; + } +ENDCLASS(DebugSource) + +#include "../../common/mapinfo.qh" +CLASS(GametypeSource, DataSource) - METHOD(GametypeSource, getEntry, entity(int, void(string, string))) - entity GametypeSource_getEntry(int i, void(string, string) returns) { ++ METHOD(GametypeSource, getEntry, entity(int i, void(string, string) returns)) { + entity e = MAPINFO_TYPES[i]; + if (returns) e.display(e, returns); + return e; + } - METHOD(GametypeSource, reload, int(string)) - int GametypeSource_reload(string filter) { return MAPINFO_TYPE_COUNT; } ++ METHOD(GametypeSource, reload, int(string filter)) { return MAPINFO_TYPE_COUNT; } +ENDCLASS(GametypeSource) + +#include "../../common/items/all.qh" +CLASS(ItemSource, DataSource) - METHOD(ItemSource, getEntry, entity(int, void(string, string))) - entity ItemSource_getEntry(int i, void(string, string) returns) { ++ METHOD(ItemSource, getEntry, entity(int i, void(string, string) returns)) { + entity e = ITEMS[i]; + if (returns) e.display(e, returns); + return e; + } - METHOD(ItemSource, reload, int(string)) - int ItemSource_reload(string filter) { return ITEM_COUNT; } ++ METHOD(ItemSource, reload, int(string filter)) { return ITEM_COUNT; } +ENDCLASS(ItemSource) + +#include "../../common/buffs.qh" +CLASS(BuffSource, DataSource) - METHOD(BuffSource, getEntry, entity(int, void(string, string))) - entity BuffSource_getEntry(int i, void(string, string) returns) { ++ METHOD(BuffSource, getEntry, entity(int i, void(string, string) returns)) { + entity e = BUFFS[i]; + if (returns) e.display(e, returns); + return e; + } - METHOD(BuffSource, reload, int(string)) - int BuffSource_reload(string filter) { return BUFFS_COUNT; } ++ METHOD(BuffSource, reload, int(string filter)) { return BUFFS_COUNT; } +ENDCLASS(BuffSource) + +#include "../../common/nades.qh" +CLASS(NadeSource, DataSource) - METHOD(NadeSource, getEntry, entity(int, void(string, string))) - entity NadeSource_getEntry(int i, void(string, string) returns) { ++ METHOD(NadeSource, getEntry, entity(int i, void(string, string) returns)) { + entity e = NADES[i]; + if (returns) e.display(e, returns); + return e; + } - METHOD(NadeSource, reload, int(string)) - int NadeSource_reload(string filter) { return NADES_COUNT; } ++ METHOD(NadeSource, reload, int(string filter)) { return NADES_COUNT; } +ENDCLASS(NadeSource) + +#include "../../common/weapons/all.qh" +CLASS(WeaponSource, DataSource) - METHOD(WeaponSource, getEntry, entity(int, void(string, string))) - entity WeaponSource_getEntry(int i, void(string, string) returns) { ++ METHOD(WeaponSource, getEntry, entity(int i, void(string, string) returns)) { + entity e = weapon_info[i]; + if (returns) e.display(e, returns); + return e; + } - METHOD(WeaponSource, reload, int(string)) - int WeaponSource_reload(string filter) { return WEP_COUNT; } ++ METHOD(WeaponSource, reload, int(string filter)) { return WEP_COUNT; } +ENDCLASS(WeaponSource) + +CLASS(MapSource, DataSource) - METHOD(MapSource, getEntry, entity(int, void(string, string))) - entity MapSource_getEntry(int i, void(string, string) returns) - { ++ METHOD(MapSource, getEntry, entity(int i, void(string, string) returns)) { + if (!MapInfo_Get_ByID(i)) return DataSource_false; + string path = strcat("/maps/", MapInfo_Map_bspname); + string img = draw_PictureSize(path) ? path : "nopreview_map"; + if (returns) returns(MapInfo_Map_titlestring, img); + MapInfo_ClearTemps(); + return DataSource_true; + } - METHOD(MapSource, indexOf, int(string)) - int MapSource_indexOf(string s) - { ++ METHOD(MapSource, indexOf, int(string s)) { + MapInfo_FindName(s); + return MapInfo_FindName_firstResult; + } - METHOD(MapSource, reload, int(string)) - int MapSource_reload(string s) - { ++ METHOD(MapSource, reload, int(string s)) { + MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 0); + if (s) MapInfo_FilterString(s); + return MapInfo_count; + } - METHOD(MapSource, destroy, void(entity)) - void MapSource_destroy(entity this) { MapInfo_Shutdown(); } ++ METHOD(MapSource, destroy, void(entity this)) { MapInfo_Shutdown(); } +ENDCLASS(MapSource) + +#include "dialog_media_guide_topics.qc" +#include "dialog_media_guide_entries.qc" +#include "dialog_media_guide_description.qc" +#include "tab.qc" +CLASS(XonoticGuideTab, XonoticTab) + ATTRIB(XonoticGuideTab, rows, float, 21) + ATTRIB(XonoticGuideTab, columns, float, 6) + ATTRIB(XonoticGuideTab, intendedWidth, float, 1) - METHOD(XonoticGuideTab, fill, void(entity)) - METHOD(XonoticGuideTab, topicChangeNotify, void(entity, entity)) - METHOD(XonoticGuideTab, entryChangeNotify, void(entity, entity)) ++ METHOD(XonoticGuideTab, fill, void(entity)); ++ METHOD(XonoticGuideTab, topicChangeNotify, void(entity, entity)); ++ METHOD(XonoticGuideTab, entryChangeNotify, void(entity, entity)); + + ATTRIB(XonoticGuideTab, topicList, entity, NEW(XonoticTopicList, NEW(TopicSource))) + ATTRIB(XonoticGuideTab, entryList, entity, NEW(XonoticEntryList, NULL)) + ATTRIB(XonoticGuideTab, descriptionPane, entity, NEW(XonoticGuideDescription)) + + INIT(XonoticGuideTab) { + this.configureDialog(this); + } +ENDCLASS(XonoticGuideTab) +#endif + +#ifdef IMPLEMENTATION + +void XonoticGuideTab_fill(entity this) +{ + entity topics = this.topicList; + topics.onChange = XonoticGuideTab_topicChangeNotify; + topics.onChangeEntity = this; + entity entries = this.entryList; + entries.onChange = XonoticGuideTab_entryChangeNotify; + entries.onChangeEntity = this; + entity filter = entries.stringFilterBox = makeXonoticInputBox(false, string_null); + filter.keyDown = MapList_StringFilterBox_keyDown; + filter.onChange = MapList_StringFilterBox_Change; + filter.onChangeEntity = entries; + entries.controlledTextbox = filter; + entity description = this.descriptionPane; + + int + col = 0, width = 1.5; + this.gotoRC(this, 0, col); + this.TD(this, 1, width, makeXonoticHeaderLabel(_("Topic"))); + this.TR(this); + this.TD(this, this.rows - 1, width, topics); + + col += width, width = 2; + this.gotoRC(this, 0, col); this.setFirstColumn(this, this.currentColumn); + this.TD(this, 1, width, makeXonoticHeaderLabel(_("Entry"))); + this.TR(this); + this.TD(this, this.rows - 1 - 1, width, entries); + this.gotoRC(this, this.rows - 1, col); + this.TD(this, 1, 0.3, makeXonoticTextLabel(0, _("Filter:"))); + this.TD(this, 1, width - 0.3, filter); + + col += width, width = 2.5; + this.gotoRC(this, 0, col); this.setFirstColumn(this, this.currentColumn); + this.TD(this, 1, width, makeXonoticHeaderLabel(_("Description"))); + this.TR(this); + this.TD(this, this.rows - 1, width, description); + + this.topicChangeNotify(topics, this); +} + +void XonoticGuideTab_topicChangeNotify(entity, entity this) +{ + entity topics = this.topicList; + entity entries = this.entryList; + int i = topics.selectedItem; + int idx = 0; + entity found = NULL; + #define TOPIC(src, name, icon) if (idx++ == i) { static entity e; if (!e) e = src; found = e; break; } + do { TOPICS(TOPIC); } while (0); + #undef TOPIC + entries.source = found; + entries.refilter(entries); + entries.setSelected(entries, 0); +} + +void XonoticGuideTab_entryChangeNotify(entity, entity this) +{ + entity desc = this.descriptionPane; + entity entries = this.entryList; + entity e = entries.source.getEntry(entries.selectedItem, func_null); + string s = e.describe(e); + if (cvar("developer")) { s = sprintf("entity %i\n%s", e, s); } + desc.setDescription(desc, s); +} + +#endif diff --cc qcsrc/menu/xonotic/dialog_media_guide_description.qc index 6b1e596cd7,0000000000..cb94cfa53a mode 100644,000000..100644 --- a/qcsrc/menu/xonotic/dialog_media_guide_description.qc +++ b/qcsrc/menu/xonotic/dialog_media_guide_description.qc @@@ -1,56 -1,0 +1,52 @@@ +#ifndef DIALOG_MEDIA_GUIDE_DESCRIPTION_H +#define DIALOG_MEDIA_GUIDE_DESCRIPTION_H +#include "credits.qc" +CLASS(XonoticGuideDescription, XonoticListBox) + ATTRIB(XonoticGuideDescription, rowsPerItem, float, 1) + ATTRIB(XonoticGuideDescription, selectionDoesntMatter, bool, true) + - METHOD(XonoticGuideDescription, setDescription, void(entity, string)) ++ METHOD(XonoticGuideDescription, setDescription, void(entity, string)); + ATTRIB(XonoticGuideDescription, description, string, string_null) + - METHOD(XonoticGuideDescription, resizeNotify, void(entity, vector, vector, vector, vector)) - void XonoticGuideDescription_resizeNotify(entity this, vector relOrigin, vector relSize, vector absOrigin, vector absSize) - { ++ METHOD(XonoticGuideDescription, resizeNotify, void(entity this, vector relOrigin, vector relSize, vector absOrigin, vector absSize)) { + super.resizeNotify(this, relOrigin, relSize, absOrigin, absSize); + + this.realFontSize_y = this.fontSize / (absSize.y * this.itemHeight); + this.realFontSize_x = this.fontSize / (absSize.x * (1 - this.controlWidth)); + this.realUpperMargin = 0.5 * (1 - this.realFontSize.y); + this.setDescription(this, this.description); + } + + INIT(XonoticGuideDescription) { + this.configureXonoticListBox(this); + } + + ATTRIB(XonoticGuideDescription, descriptionWrapped, string, string_null) + void XonoticGuideDescription_setDescription(entity this, string desc) + { + string current = this.description; + if (current && current != desc) strunzone(current); + this.description = strzone(desc); + + string currentWrapped = this.descriptionWrapped; + if (currentWrapped) strunzone(currentWrapped); + string wrapped = ""; + for (int i = 0, n = tokenizebyseparator(desc, "\n"); i < n; ++i) { + string line = ""; + for (getWrappedLine_remaining = argv(i); getWrappedLine_remaining; ) { + string s = getWrappedLine(1, this.realFontSize, draw_TextWidth_WithColors); + line = sprintf("%s\n%s", line, s); + } + wrapped = strcat(wrapped, line); + } + this.descriptionWrapped = strzone(wrapped); + + this.nItems = tokenizebyseparator(wrapped, "\n"); + } + - METHOD(XonoticGuideDescription, drawListBoxItem, void(entity, int, vector, bool, bool)) - void XonoticGuideDescription_drawListBoxItem(entity this, int i, vector absSize, bool isSelected, bool isFocused) - { ++ METHOD(XonoticGuideDescription, drawListBoxItem, void(entity this, int i, vector absSize, bool isSelected, bool isFocused)) { + tokenizebyseparator(this.descriptionWrapped, "\n"); + draw_Text(this.realUpperMargin * eY, argv(i), this.realFontSize, '1 1 1', 1, 0); + } +ENDCLASS(XonoticGuideDescription) +#endif diff --cc qcsrc/menu/xonotic/dialog_media_guide_entries.qc index 1c2faa7bb1,0000000000..b131b61ea8 mode 100644,000000..100644 --- a/qcsrc/menu/xonotic/dialog_media_guide_entries.qc +++ b/qcsrc/menu/xonotic/dialog_media_guide_entries.qc @@@ -1,127 -1,0 +1,127 @@@ +#ifndef DIALOG_MEDIA_GUIDE_ENTRIES_H +#define DIALOG_MEDIA_GUIDE_ENTRIES_H +#include "datasource.qc" +#include "listbox.qc" +CLASS(XonoticEntryList, XonoticListBox) + ATTRIB(XonoticEntryList, alphaBG, float, 0) + ATTRIB(XonoticEntryList, itemAbsSize, vector, '0 0 0') + ATTRIB(XonoticEntryList, origin, vector, '0 0 0') + ATTRIB(XonoticEntryList, realFontSize, vector, '0 0 0') + ATTRIB(XonoticEntryList, realUpperMargin1, float, 0) + ATTRIB(XonoticEntryList, realUpperMargin2, float, 0) + ATTRIB(XonoticEntryList, rowsPerItem, float, 4) + ATTRIB(XonoticEntryList, stringFilterBox, entity, NULL) + ATTRIB(XonoticEntryList, stringFilter, string, string_null) + ATTRIB(XonoticEntryList, typeToSearchString, string, string_null) + ATTRIB(XonoticEntryList, typeToSearchTime, float, 0) + - METHOD(XonoticEntryList, drawListBoxItem, void(entity, int, vector, bool, bool)) - METHOD(XonoticEntryList, keyDown, float(entity, float, float, float)) - METHOD(XonoticEntryList, refilter, void(entity)) - METHOD(XonoticEntryList, resizeNotify, void(entity, vector, vector, vector, vector)) - METHOD(XonoticEntryList, setSelected, void(entity, int)) ++ METHOD(XonoticEntryList, drawListBoxItem, void(entity, int, vector, bool, bool)); ++ METHOD(XonoticEntryList, keyDown, float(entity, float, float, float)); ++ METHOD(XonoticEntryList, refilter, void(entity)); ++ METHOD(XonoticEntryList, resizeNotify, void(entity, vector, vector, vector, vector)); ++ METHOD(XonoticEntryList, setSelected, void(entity, int)); + + ATTRIB(XonoticEntryList, source, DataSource, NULL) + + CONSTRUCTOR(XonoticEntryList, DataSource _source) { + CONSTRUCT(XonoticEntryList); + this.source = _source; + this.configureXonoticListBox(this); + this.refilter(this); + } + +ENDCLASS(XonoticEntryList) +#endif + +#ifdef IMPLEMENTATION + +string XonoticEntryList_cb_name, XonoticEntryList_cb_icon; +void XonoticEntryList_cb(string _name, string _icon) { + XonoticEntryList_cb_name = _name; + XonoticEntryList_cb_icon = _icon; +} + +void XonoticEntryList_drawListBoxItem(entity this, int i, vector absSize, bool isSelected, bool isFocused) +{ + if (!this.source) return; + if (!this.source.getEntry(i, XonoticEntryList_cb)) return; + string name = XonoticEntryList_cb_name; + string icon = XonoticEntryList_cb_icon; + 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); + } + vector sz = draw_PictureSize(icon); + if (!sz) sz = '1 1 0'; + float szr = sz.x / sz.y; + if (strstrofs(icon, "map", 0) >= 0) szr = 4 / 3; + float asr = this.itemAbsSize.x / this.itemAbsSize.y; + sz.y = 1; sz.x = szr / asr; + draw_Picture('0 0 0', icon, sz, '1 1 1', SKINALPHA_LISTBOX_SELECTED); + string s = draw_TextShortenToWidth(strdecolorize(name), 1 - sz.x - 2 * this.realFontSize.x, 0, this.realFontSize); + draw_Text(this.realUpperMargin1 * eY + (sz.x + 0.5 * this.realFontSize.x) * eX, s, this.realFontSize, '1 1 1', SKINALPHA_TEXT, 0); +} + +float XonoticEntryList_keyDown(entity this, float scan, float ascii, float shift) +{ + if (this.nItems <= 0) { + return super.keyDown(this, scan, ascii, shift); + } else if ((ascii >= 32 || scan == K_BACKSPACE) && this.source.indexOf) { + string save; + if (scan == K_BACKSPACE) { + save = substring(this.typeToSearchString, 0, strlen(this.typeToSearchString) - 1); + } else { + string ch = chr(ascii); + save = (time > this.typeToSearchTime) ? ch : strcat(this.typeToSearchString, ch); + } + if (this.typeToSearchString) strunzone(this.typeToSearchString); + this.typeToSearchString = strzone(save); + this.typeToSearchTime = time + 0.5; + if (strlen(this.typeToSearchString)) { + int idx = this.source.indexOf(this.typeToSearchString); + if (idx >= 0) this.setSelected(this, idx); + } + } else if (shift & S_CTRL && scan == 'f') { + this.parent.setFocus(this.parent, this.stringFilterBox); + } else if (shift & S_CTRL && scan == 'u') { + this.stringFilterBox.setText(this.stringFilterBox, ""); + if (this.stringFilter) strunzone(this.stringFilter); + this.stringFilter = string_null; + this.refilter(this); + } + return super.keyDown(this, scan, ascii, shift); +} + +void XonoticEntryList_refilter(entity this) +{ + if (!this.source) { + this.nItems = 0; + return; + } + this.nItems = this.source.reload(this.stringFilter); + for (int i = 0, n = this.nItems; i < n; ++i) { + if (this.source.getEntry(i, XonoticEntryList_cb)) { + draw_PreloadPicture(XonoticEntryList_cb_icon); + } + } +} + +void XonoticEntryList_resizeNotify(entity this, vector relOrigin, vector relSize, vector absOrigin, vector absSize) +{ + this.itemAbsSize = '0 0 0'; + super.resizeNotify(this, relOrigin, relSize, absOrigin, absSize); + + 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.realUpperMargin1 = 0.5 * (1 - 2.5 * this.realFontSize.y); + this.realUpperMargin2 = this.realUpperMargin1 + 1.5 * this.realFontSize.y; +} + +void XonoticEntryList_setSelected(entity this, int i) +{ + super.setSelected(this, i); + this.onChange(this, this.onChangeEntity); +} +#endif diff --cc qcsrc/menu/xonotic/dialog_media_guide_topics.qc index 7168185ccb,0000000000..6121deadcb mode 100644,000000..100644 --- a/qcsrc/menu/xonotic/dialog_media_guide_topics.qc +++ b/qcsrc/menu/xonotic/dialog_media_guide_topics.qc @@@ -1,94 -1,0 +1,94 @@@ +#ifndef DIALOG_MEDIA_GUIDE_TOPICS_H +#define DIALOG_MEDIA_GUIDE_TOPICS_H +#include "datasource.qc" +#include "listbox.qc" +CLASS(XonoticTopicList, XonoticListBox) + ATTRIB(XonoticTopicList, columnIconOrigin, float, 0) + ATTRIB(XonoticTopicList, columnIconSize, float, 0) + ATTRIB(XonoticTopicList, columnNameOrigin, float, 0) + ATTRIB(XonoticTopicList, columnNameSize, float, 0) + ATTRIB(XonoticTopicList, realFontSize, vector, '0 0 0') + ATTRIB(XonoticTopicList, realUpperMargin, float, 0) + ATTRIB(XonoticTopicList, rowsPerItem, float, 3) + - METHOD(XonoticTopicList, clickListBoxItem, void(entity, float, vector)) - METHOD(XonoticTopicList, drawListBoxItem, void(entity, int, vector, bool, bool)) - METHOD(XonoticTopicList, keyDown, bool(entity, float, float, float)) - METHOD(XonoticTopicList, resizeNotify, void(entity, vector, vector, vector, vector)) - METHOD(XonoticTopicList, setSelected, void(entity, int)) ++ METHOD(XonoticTopicList, clickListBoxItem, void(entity, float, vector)); ++ METHOD(XonoticTopicList, drawListBoxItem, void(entity, int, vector, bool, bool)); ++ METHOD(XonoticTopicList, keyDown, bool(entity, float, float, float)); ++ METHOD(XonoticTopicList, resizeNotify, void(entity, vector, vector, vector, vector)); ++ METHOD(XonoticTopicList, setSelected, void(entity, int)); + + ATTRIB(XonoticTopicList, source, DataSource, NULL) + + CONSTRUCTOR(XonoticTopicList, DataSource _source) { + CONSTRUCT(XonoticTopicList); + this.source = _source; + this.nItems = _source.reload(""); + this.configureXonoticListBox(this); + } +ENDCLASS(XonoticTopicList) +#endif + +#ifdef IMPLEMENTATION + +void XonoticTopicList_clickListBoxItem(entity this, float i, vector where) +{ + m_play_click_sound(MENU_SOUND_SELECT); +} + +string XonoticTopicList_cb_name, XonoticTopicList_cb_icon; +void XonoticTopicList_cb(string _name, string _icon) { + XonoticTopicList_cb_name = _name; + XonoticTopicList_cb_icon = _icon; +} + +void XonoticTopicList_drawListBoxItem(entity this, int i, vector absSize, bool isSelected, bool isFocused) +{ + if (!this.source) return; + if (!this.source.getEntry(i, XonoticTopicList_cb)) return; + string icon = XonoticTopicList_cb_icon; + string name = XonoticTopicList_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); + } + draw_Picture(this.columnIconOrigin * eX, icon, this.columnIconSize * eX + eY, '1 1 1', SKINALPHA_LISTBOX_SELECTED); + vector save_fontscale = draw_fontscale; + float f = draw_CondensedFontFactor(name, false, this.realFontSize, 1); + draw_fontscale.x *= f; + vector fs = this.realFontSize; + fs.x *= f; + draw_Text(this.realUpperMargin * eY + this.columnNameOrigin * eX, name, fs, '1 1 1', SKINALPHA_TEXT, 0); + draw_fontscale = save_fontscale; +} + +bool XonoticTopicList_keyDown(entity this, float scan, float ascii, float shift) +{ + if (scan == K_ENTER || scan == K_KP_ENTER) { + m_play_click_sound(MENU_SOUND_EXECUTE); + return true; + } + return super.keyDown(this, scan, ascii, shift); +} + +void XonoticTopicList_resizeNotify(entity this, vector relOrigin, vector relSize, vector absOrigin, vector absSize) +{ + this.itemAbsSize = '0 0 0'; + super.resizeNotify(this, relOrigin, relSize, absOrigin, absSize); + + 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); + this.columnIconOrigin = 0; + this.columnIconSize = this.itemAbsSize.y / this.itemAbsSize.x; + this.columnNameOrigin = this.columnIconOrigin + this.columnIconSize + (0.5 * this.realFontSize.x); + this.columnNameSize = 1 - this.columnIconSize - (1.5 * this.realFontSize.x); +} + +void XonoticTopicList_setSelected(entity this, int i) +{ + super.setSelected(this, i); + this.onChange(this, this.onChangeEntity); +} +#endif diff --cc qcsrc/menu/xonotic/dialog_multiplayer_media.qc index 0000d1d608,abecd1ed5b..40c434aff7 --- a/qcsrc/menu/xonotic/dialog_multiplayer_media.qc +++ b/qcsrc/menu/xonotic/dialog_multiplayer_media.qc @@@ -2,10 -2,10 +2,10 @@@ #define DIALOG_MULTIPLAYER_MEDIA_H #include "tab.qc" CLASS(XonoticMediaTab, XonoticTab) - METHOD(XonoticMediaTab, fill, void(entity)) + METHOD(XonoticMediaTab, fill, void(entity)); ATTRIB(XonoticMediaTab, intendedWidth, float, 0.9) ATTRIB(XonoticMediaTab, rows, float, 23) - ATTRIB(XonoticMediaTab, columns, float, 3) + ATTRIB(XonoticMediaTab, columns, float, 4) ATTRIB(XonoticMediaTab, name, string, "Media") ENDCLASS(XonoticMediaTab) entity makeXonoticMediaTab();