Index: ps/trunk/binaries/data/mods/mod/gui/common/modern/styles.xml
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/common/modern/styles.xml (revision 22065)
+++ ps/trunk/binaries/data/mods/mod/gui/common/modern/styles.xml (revision 22066)
@@ -1,203 +1,201 @@
Index: ps/trunk/binaries/data/mods/mod/gui/gui.rnc
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/gui.rnc (revision 22065)
+++ ps/trunk/binaries/data/mods/mod/gui/gui.rnc (revision 22066)
@@ -1,289 +1,288 @@
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
##
# NOTE: To modify this Relax NG grammar, edit the Relax NG Compact (.rnc) file
# and use a converter tool like trang to generate the Relax NG XML (.rng) file
##
start = object | objects | setup | sprites | styles
##
# Types #
##
# xsd:boolean could be used instead of this definition,
# though it considers "1" & "0" as valid values.
bool = "true" | "false"
align = "left" | "center" | "right"
valign = "top" | "center" | "bottom"
wrapmode = "repeat" | "mirrored_repeat" | "clamp_to_edge"
coord = xsd:string { pattern = "-?\d*\.?\d+%?([\+\-]\d*\.?\d+%?)*" }
clientarea = list { coord, coord, coord, coord }
# color can be a name or "R G B A" format string
rgba = list { xsd:integer { minInclusive = "0" maxInclusive = "255" },
xsd:integer { minInclusive = "0" maxInclusive = "255" },
xsd:integer { minInclusive = "0" maxInclusive = "255" },
xsd:integer { minInclusive = "0" maxInclusive = "255" }?}
ccolor = rgba | xsd:string { pattern = "[A-Za-z]+" }
size = list { xsd:decimal, xsd:decimal }
pos = list { xsd:decimal, xsd:decimal }
rect = list { xsd:decimal, xsd:decimal, xsd:decimal, xsd:decimal }
##
# Defines #
##
unique_settings =
attribute name { text }?,
[ a:defaultValue = "empty" ] attribute type { text }?,
attribute style { text }?
# This could probably be made more specific/strict
# with more information regarding the use/meaning
# of these attributes.
base_settings =
attribute absolute { bool }?&
attribute enable { bool }?&
attribute ghost { bool }?&
attribute hidden { bool }?&
attribute size { clientarea }?&
attribute z { xsd:decimal }?
# Defaults are not put in here, because it ruins the concept of styles.
ex_settings =
attribute anchor { valign }?&
attribute auto_scroll { bool }?&
attribute buffer_zone { xsd:decimal }?&
attribute buffer_width { xsd:decimal }?&
attribute button_width { xsd:decimal }?&
attribute checked { bool }?&
attribute clip { bool }?&
attribute dropdown_size { xsd:decimal }?&
attribute dropdown_buffer { xsd:decimal }?&
attribute minimum_visible_items { xsd:nonNegativeInteger }?&
attribute enabled { bool }?&
attribute font { text }?&
attribute format_x { text }?&
attribute format_y { text }?&
attribute fov_wedge_color { ccolor }?&
- attribute heading_height { text }?&
attribute hotkey { text }?&
attribute cell_id { xsd:integer }?&
attribute independent { bool }?&
attribute input_initvalue_destroyed_at_focus { bool }?&
attribute mask { bool }?&
attribute mask_char { xsd:string { minLength = "1" maxLength = "1" } }?&
attribute max_length { xsd:nonNegativeInteger }?&
attribute maxwidth { xsd:decimal }? &
attribute multiline { bool }?&
attribute offset { pos }?&
attribute readonly { bool }?&
attribute scrollbar { bool }?&
attribute scrollbar_style { text }?&
attribute scroll_bottom { bool }?&
attribute scroll_top { bool }?&
attribute selected_column { text }?&
attribute selected_column_order { text }?&
attribute sortable { bool }?&
attribute sound_closed { text }?&
attribute sound_disabled { text }?&
attribute sound_enter { text }?&
attribute sound_leave { text }?&
attribute sound_opened { text }?&
attribute sound_pressed { text }?&
attribute sound_selected { text }?&
attribute sprite { text }?&
attribute sprite2 { text }?&
attribute sprite_asc { text }?&
attribute sprite_heading { text }?&
attribute sprite_bar { text }?&
attribute sprite_background { text }?&
attribute sprite_desc { text }?&
attribute sprite_disabled { text }?&
attribute sprite_list { text }?&
attribute sprite2_disabled { text }?&
attribute sprite_not_sorted { text }?&
attribute sprite_over { text }?&
attribute sprite2_over { text }?&
attribute sprite_pressed { text }?&
attribute sprite2_pressed { text }?&
attribute sprite_selectarea { text }?&
attribute square_side { xsd:decimal }?&
attribute textcolor { ccolor }?&
attribute textcolor_disabled { ccolor }?&
attribute textcolor_over { ccolor }?&
attribute textcolor_pressed { ccolor }?&
attribute textcolor_selected { ccolor }?&
attribute text_align { align }?&
attribute text_valign { valign }?&
attribute tooltip { text }?&
attribute tooltip_style { text }?
##
# Objects #
##
objects = element objects { (script | object)* }
script =
element script {
text &
attribute file { text }? &
attribute directory { text }?
}
object =
element object {
((object
| action
| \attribute
| column
| \include
| item
| repeat
| translatableAttribute)*
| text),
unique_settings,
base_settings,
ex_settings
}
action =
element action {
text,
attribute on { text },
attribute file { text }?
}
\attribute =
element attribute {
(keep | translate)*,
attribute id { text }
}
column =
element column {
translatableAttribute?,
(
attribute id { text }&
attribute color { ccolor }?&
attribute heading { text }?&
attribute width { text }?&
attribute hidden { bool }?
)
}
\include =
element include {
attribute file { text }|
attribute directory { text }
}
item =
element item {
text,
attribute enabled { bool }?
}
keep = element keep { text }
repeat =
element repeat {
object+,
attribute count { xsd:nonNegativeInteger },
attribute var { text }?
}
translate = element translate { text }
translatableAttribute =
element translatableAttribute {
text,
(
attribute id { text }&
attribute comment { text }?&
attribute context { text }?
)
}
##
# Styles #
##
styles = element styles { style* }
style =
element style {
attribute name { text },
base_settings,
ex_settings
}
##
# Setup #
##
setup = element setup { (icon | scrollbar | tooltip | color)* }
scrollbar =
element scrollbar {
attribute name { text }&
attribute width { xsd:decimal }&
attribute alwaysshown { bool }?&
attribute maximum_bar_size { xsd:decimal }?&
attribute minimum_bar_size { xsd:decimal }?&
attribute scroll_wheel { bool }?&
attribute show_edge_buttons { bool }?&
attribute sprite_button_top { text }?&
attribute sprite_button_top_pressed { text }?&
attribute sprite_button_top_disabled { text }?&
attribute sprite_button_top_over { text }?&
attribute sprite_button_bottom { text }?&
attribute sprite_button_bottom_pressed { text }?&
attribute sprite_button_bottom_disabled { text }?&
attribute sprite_button_bottom_over { text }?&
attribute sprite_bar_vertical { text }?&
attribute sprite_bar_vertical_over { text }?&
attribute sprite_bar_vertical_pressed { text }?&
attribute sprite_back_vertical { text }?
}
icon =
element icon {
attribute name { text }&
attribute size { size }&
attribute sprite { text }&
attribute cell_id { text }?
}
tooltip =
element tooltip {
attribute name { text }&
attribute sprite { text }?&
attribute anchor { valign }?&
attribute axis_color { ccolor }?&
attribute axis_width { xsd:decimal { minInclusive = "0" } }?&
attribute buffer_zone { xsd:decimal }?&
attribute font { text }?&
attribute maxwidth { xsd:decimal }?&
attribute offset { pos }?&
attribute textcolor { ccolor }?&
attribute delay { xsd:integer }?&
attribute use_object { text }?&
attribute hide_object { bool }?
}
color =
element color {
rgba,
attribute name { text }
}
##
# Sprites #
##
sprites = element sprites { sprite* }
sprite =
element sprite {
(effect?, image+),
attribute name { text }
}
image =
element image {
effect?,
(
attribute texture { text }?&
attribute size { clientarea }?&
attribute texture_size { clientarea }?&
attribute real_texture_placement { rect }?&
attribute cell_size { size }?&
attribute backcolor { ccolor }?&
attribute bordercolor { ccolor }?&
attribute border { bool }?&
attribute z_level { xsd:float }?&
attribute fixed_h_aspect_ratio { xsd:decimal }?&
attribute round_coordinates { bool }?&
attribute wrap_mode { wrapmode }?
)
}
effect =
element effect {
attribute add_color { ccolor }?,
attribute grayscale { empty }?
}
Index: ps/trunk/binaries/data/mods/mod/gui/gui.rng
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/gui.rng (revision 22065)
+++ ps/trunk/binaries/data/mods/mod/gui/gui.rng (revision 22066)
@@ -1,885 +1,882 @@
true
false
left
center
right
top
center
bottom
repeat
mirrored_repeat
clamp_to_edge
-?\d*\.?\d+%?([\+\-]\d*\.?\d+%?)*
0
255
0
255
0
255
0
255
[A-Za-z]+
0
-
-
-
1
1
Index: ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json (revision 22065)
+++ ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json (revision 22066)
@@ -1,254 +1,255 @@
{
"Title": "Programming",
"Content": [
{
"Title": "Programming managers",
"List": [
{"nick": "Acumen", "name": "Stuart Walpole"},
{"nick": "Dak Lozar", "name": "Dave Loeser"},
{"nick": "h20", "name": "Daniel Wilhelm"},
{"nick": "Janwas", "name": "Jan Wassenberg"},
{"nick": "Raj", "name": "Raj Sharma"}
]
},
{
"Subtitle": "Special thanks to",
"List": [
{"nick": "Ykkrosh", "name": "Philip Taylor"},
{"nick": "leper", "name": "Georg Kilzer"}
]
},
{
"List": [
{"nick": "01d55"},
{"nick": "Acumen", "name": "Stuart Walpole"},
{"name": "Adrian Fatol"},
{"nick": "AI-Amsterdam"},
{"nick": "Alan", "name": "Alan Kemp"},
{"nick": "aBothe", "name": "Alexander Bothe"},
{"nick": "alpha123", "name": "Peter P. Cannici"},
{"nick": "andy5995", "name": "Andy Alt"},
{"nick": "Angen"},
{"nick": "ArnH", "name": "Arno Hemelhof"},
{"nick": "Aurium", "name": "Aurélio Heckert"},
{"nick": "badmadblacksad", "name": "Martin F"},
{"name": "Mikołaj \"Bajter\" Korcz"},
{"nick": "bb", "name": "Bouke Jansen"},
{"nick": "Ben", "name": "Ben Vinegar"},
{"nick": "Bird"},
{"nick": "Blue", "name": "Richard Welsh"},
{"nick": "bmwiedemann"},
{"nick": "boeseRaupe", "name": "Michael Kluge"},
{"nick": "bog_dan_ro", "name": "BogDan Vatra"},
{"nick": "Bonk", "name": "Christopher Ebbert"},
{"nick": "borg-", "name": "Estevan Borges Martins"},
{"nick": "Boudica"},
{"nick": "Caius", "name": "Lars Kemmann"},
{"nick": "Calefaction", "name": "Matt Holmes"},
{"nick": "Calvinh", "name": "Carl-Johan Höiby"},
{"nick": "causative", "name": "Bart Parkis"},
{"name": "Cédric Houbart"},
{"nick": "Chakakhan", "name": "Kenny Long"},
{"nick": "Clockwork-Muse", "name": "Stephen A. Imhoff"},
{"nick": "Cracker78", "name": "Chad Heim"},
{"nick": "Crynux", "name": "Stephen J. Fewer"},
{"nick": "cwprogger"},
{"nick": "Dak Lozar", "name": "Dave Loeser"},
{"nick": "dalerank", "name": "Sergey Kushnirenko"},
{"nick": "dan", "name": "Dan Strandberg"},
{"name": "Daniel Trevitz"},
{"nick": "DanCar", "name": "Daniel Cardenas"},
{"nick": "danger89", "name": "Melroy van den Berg"},
{"nick": "Dariost", "name": "Dario Ostuni"},
{"nick": "Dave", "name": "David Protasowski"},
{"nick": "dax", "name": "Dacian Fiordean"},
{"nick": "deebee", "name": "Deepak Anthony"},
{"nick": "Deiz"},
{"nick": "Dietger", "name": "Dietger van Antwerpen"},
{"nick": "dp304"},
{"nick": "dpiquet", "name": "Damien Piquet"},
{"nick": "dumbo"},
{"nick": "Dunedan", "name": "Daniel Roschka"},
{"nick": "dvangennip", "name": "Doménique"},
{"nick": "Echelon9", "name": "Rhys Kidd"},
{"nick": "echotangoecho"},
{"nick": "eihrul", "name": "Lee Salzman"},
{"nick": "elexis", "name": "Alexander Heinsius"},
{"nick": "EmjeR", "name": "Matthijs de Rijk"},
{"nick": "EMontana"},
{"nick": "ericb"},
{"nick": "evanssthomas", "name": "Evans Thomas"},
{"nick": "Evulant", "name": "Alexander S."},
{"nick": "fabio", "name": "Fabio Pedretti"},
{"nick": "falsevision", "name": "Mahdi Khodadadifard"},
{"nick": "fatherbushido", "name": "Nicolas Tisserand"},
{"nick": "fcxSanya", "name": "Alexander Olkhovskiy"},
{"nick": "FeXoR", "name": "Florian Finke"},
{"nick": "Fire Giant", "name": "Malte Schwarzkopf"},
{"name": "Fork AD"},
{"nick": "fpre", "name": "Frederick Stallmeyer"},
{"nick": "freenity", "name": "Anton Galitch"},
{"nick": "Gallaecio", "name": "Adrián Chaves"},
{"nick": "gbish (aka Iny)", "name": "Grant Bishop"},
{"nick": "Gee", "name": "Gustav Larsson"},
+ {"nick": "Gentz", "name": "Hal Gentz"},
{"nick": "gerbilOFdoom"},
{"nick": "godlikeldh"},
{"nick": "greybeard", "name": "Joe Cocovich"},
{"nick": "grillaz"},
{"nick": "Grugnas", "name": "Giuseppe Tranchese"},
{"nick": "gudo"},
{"nick": "Guuts", "name": "Matthew Guttag"},
{"name": "Samuel Guarnieri"},
{"nick": "Hannibal_Baraq", "name": "Clive Juhász S."},
{"nick": "Haommin"},
{"nick": "h20", "name": "Daniel Wilhelm"},
{"nick": "historic_bruno", "name": "Ben Brian"},
{"nick": "idanwin"},
{"nick": "Imarok", "name": "J. S."},
{"nick": "infyquest", "name": "Vijay Kiran Kamuju"},
{"nick": "IronNerd", "name": "Matthew McMullan"},
{"nick": "Itms", "name": "Nicolas Auvray"},
{"nick": "Jaison", "name": "Marco tom Suden"},
{"nick": "jammus", "name": "James Scott"},
{"nick": "javiergodas", "name": "Javier Godas Vieitez"},
{"nick": "Jgwman"},
{"nick": "JonBaer", "name": "Jon Baer"},
{"nick": "Josh", "name": "Joshua J. Bakita"},
{"nick": "joskar", "name": "Johnny Oskarsson"},
{"nick": "jP_wanN", "name": "Jonas Platte"},
{"nick": "Jubalbarca", "name": "James Baillie"},
{"nick": "JubJub", "name": "Sebastian Vetter"},
{"nick": "jurgemaister"},
{"nick": "kabzerek", "name": "Grzegorz Kabza"},
{"nick": "Kai", "name": "Kai Chen"},
{"name": "Kareem Ergawy"},
{"nick": "kevmo", "name": "Kevin Caffrey"},
{"nick": "kezz", "name": "Graeme Kerry"},
{"nick": "kingadami", "name": "Adam Winsor"},
{"nick": "kingbasil", "name": "Giannis Fafalios"},
{"nick": "lafferjm", "name": "Justin Lafferty"},
{"nick": "LeanderH", "name": "Leander Hemelhof"},
{"nick": "leper", "name": "Georg Kilzer"},
{"nick": "LittleDev"},
{"nick": "livingaftermidnight", "name": "Will Dull"},
{"nick": "Louhike"},
{"nick": "lsdh"},
{"nick": "Ludovic", "name": "Ludovic Rousseau"},
{"nick": "madmax", "name": "Abhijit Nandy"},
{"nick": "madpilot", "name": "Guido Falsi"},
{"nick": "m0l0t0ph", "name": "Christoph Gielisch"},
{"nick": "markcho"},
{"nick": "MarkT", "name": "Mark Thompson"},
{"nick": "Markus"},
{"nick": "Matei", "name": "Matei Zaharia"},
{"nick": "Mate-86", "name": "Mate Kovacs"},
{"nick": "MattDoerksen", "name": "Matt Doerksen"},
{"nick": "mattlott", "name": "Matt Lott"},
{"nick": "maveric", "name": "Anton Protko"},
{"nick": "Micnasty", "name": "Travis Gorkin"},
{"nick": "mimo"},
{"nick": "mk12", "name": "Mitchell Kember"},
{"nick": "mmayfield45", "name": "Michael Mayfield"},
{"nick": "mmoanis", "name": "Mohamed Moanis"},
{"nick": "Molotov", "name": "Dario Alvarez"},
{"nick": "mpmoreti", "name": "Marcos Paulo Moreti"},
{"nick": "mreiland", "name": "Michael Reiland"},
{"nick": "myconid"},
{"nick": "nd3c3nt", "name": "Gavin Fowler"},
{"nick": "niektb", "name": "Niek ten Brinke"},
{"nick": "njm"},
{"nick": "NoMonkey", "name": "John Mena"},
{"nick": "notpete", "name": "Rich Cross"},
{"nick": "nwtour"},
{"nick": "odoaker", "name": "Ágoston Sipos"},
{"nick": "Offensive ePeen", "name": "Jared Ryan Bills"},
{"nick": "Ols", "name": "Oliver Whiteman"},
{"nick": "olsner", "name": "Simon Brenner"},
{"nick": "OptimusShepard", "name": "Pirmin Stanglmeier"},
{"nick": "otero"},
{"nick": "nani", "name": "S. N."},
{"nick": "Nescio"},
{"name": "Nick Owens"},
{"nick": "Palaxin", "name": "David A. Freitag"},
{"name": "Paul Withers"},
{"nick": "paulobezerr", "name": "Paulo George Gomes Bezerra"},
{"nick": "pcpa", "name": "Paulo Andrade"},
{"nick": "Pendingchaos"},
{"nick": "PeteVasi", "name": "Pete Vasiliauskas"},
{"nick": "pilino1234"},
{"nick": "PingvinBetyar", "name": "Schronk Tamás"},
{"nick": "plugwash", "name": "Peter Michael Green"},
{"nick": "Polakrity"},
{"nick": "Poya", "name": "Poya Manouchehri"},
{"name": "Quentin Pradet"},
{"nick": "prefect", "name": "Nicolai Hähnle"},
{"nick": "pstumpf", "name": "Pascal Stumpf"},
{"name": "André Puel"},
{"nick": "Prodigal Son"},
{"nick": "pyrolink", "name": "Andrew Decker"},
{"nick": "quantumstate", "name": "Jonathan Waller"},
{"nick": "QuickShot", "name": "Walter Krawec"},
{"nick": "quonter"},
{"nick": "qwertz"},
{"nick": "Radagast"},
{"nick": "Raj", "name": "Raj Sharma"},
{"nick": "rapidelectron", "name": "Christian Weihsbach"},
{"nick": "RedFox", "name": "Jorma Rebane"},
{"nick": "RefinedCode"},
{"nick": "Riemer"},
{"name": "Rolf Sievers"},
{"nick": "s0600204", "name": "Matthew Norwood"},
{"nick": "sacha_vrand", "name": "Sacha Vrand"},
{"nick": "SafaAlfulaij"},
{"nick": "Sandarac"},
{"nick": "sanderd17", "name": "Sander Deryckere"},
{"nick": "sathyam", "name": "Sathyam Vellal"},
{"nick": "sbirmi", "name": "Sharad Birmiwal"},
{"nick": "sbte", "name": "Sven Baars"},
{"nick": "scroogie", "name": "André Gemünd"},
{"nick": "scythetwirler", "name": "Casey X."},
{"nick": "serveurix"},
{"nick": "Shane", "name": "Shane Grant"},
{"nick": "Silk", "name": "Josh Godsiff"},
{"nick": "silure"},
{"nick": "Simikolon", "name": "Yannick & Simon"},
{"nick": "smiley", "name": "M. L."},
{"nick": "Spahbod", "name": "Omid Davoodi"},
{"nick": "stanislas69", "name": "Stanislas Dolcini"},
{"nick": "Stefan"},
{"nick": "stilz", "name": "Sławomir Zborowski"},
{"nick": "stwf", "name": "Steven Fuchs"},
{"nick": "svott", "name": "Sven Ott"},
{"nick": "t4nk004"},
{"nick": "tbm", "name": "Martin Michlmayr"},
{"nick": "tau"},
{"nick": "Teiresias"},
{"nick": "temple"},
{"nick": "texane"},
{"nick": "thamlett", "name": "Timothy Hamlett"},
{"nick": "thedrunkyak", "name": "Dan Fuhr"},
{"nick": "TrinityDeath", "name": "Jethro Lu"},
{"nick": "triumvir", "name": "Corin Schedler"},
{"nick": "trompetin17", "name": "Juan Guillermo"},
{"nick": "user1", "name": "A. C."},
{"nick": "usey11"},
{"nick": "vincent_c", "name": "Vincent Cheng"},
{"nick": "vladislavbelov", "name": "Vladislav Belov"},
{"nick": "vts", "name": "Jeroen DR"},
{"nick": "WhiteTreePaladin", "name": "Brian Ashley"},
{"nick": "wraitii", "name": "Lancelot de Ferrière le Vayer"},
{"nick": "Xentelian", "name": "Mark Strawson"},
{"nick": "Xienen", "name": "Dayle Flowers"},
{"nick": "xtizer", "name": "Matt Green"},
{"nick": "yashi", "name": "Yasushi Shoji"},
{"nick": "Ykkrosh", "name": "Philip Taylor"},
{"nick": "Yves"},
{"nick": "Zeusthor", "name": "Jeffrey Tavares"},
{"nick": "zoot"},
{"nick": "zsol", "name": "Zsolt Dollenstein"},
{"nick": "ztamas", "name": "Tamas Zolnai"},
{"nick": "Zyi", "name": "Charles De Meulenaer"}
]
}
]
}
Index: ps/trunk/source/gui/COList.cpp
===================================================================
--- ps/trunk/source/gui/COList.cpp (revision 22065)
+++ ps/trunk/source/gui/COList.cpp (revision 22066)
@@ -1,486 +1,490 @@
-/* Copyright (C) 2017 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "COList.h"
#include "i18n/L10n.h"
#include "ps/CLogger.h"
#include "soundmanager/ISoundManager.h"
+const float SORT_SPRITE_DIM = 16.0f;
+const CPos COLUMN_SHIFT = CPos(0, 4);
+
COList::COList() : CList()
{
AddSetting(GUIST_CGUISpriteInstance, "sprite_heading");
- AddSetting(GUIST_float, "heading_height");
AddSetting(GUIST_bool, "sortable"); // The actual sorting is done in JS for more versatility
AddSetting(GUIST_CStr, "selected_column");
AddSetting(GUIST_int, "selected_column_order");
AddSetting(GUIST_CGUISpriteInstance, "sprite_asc"); // Show the order of sorting
AddSetting(GUIST_CGUISpriteInstance, "sprite_desc");
AddSetting(GUIST_CGUISpriteInstance, "sprite_not_sorted");
}
void COList::SetupText()
{
if (!GetGUI())
return;
CGUIList* pList;
GUI::GetSettingPointer(this, "list", pList);
m_ItemsYPositions.resize(pList->m_Items.size() + 1);
// Delete all generated texts. Some could probably be saved,
// but this is easier, and this function will never be called
// continuously, or even often, so it'll probably be okay.
for (SGUIText* const& t : m_GeneratedTexts)
delete t;
m_GeneratedTexts.clear();
CStrW font;
if (GUI::GetSetting(this, "font", font) != PSRETURN_OK || font.empty())
// Use the default if none is specified
// TODO Gee: (2004-08-14) Don't define standard like this. Do it with the default style.
font = L"default";
bool scrollbar;
GUI::GetSetting(this, "scrollbar", scrollbar);
- float width = GetListRect().GetWidth();
+ m_TotalAvailableColumnWidth = GetListRect().GetWidth();
// remove scrollbar if applicable
if (scrollbar && GetScrollBar(0).GetStyle())
- width -= GetScrollBar(0).GetStyle()->m_Width;
-
- m_TotalAvailableColumnWidth = width;
+ m_TotalAvailableColumnWidth -= GetScrollBar(0).GetStyle()->m_Width;
float buffer_zone = 0.f;
GUI::GetSetting(this, "buffer_zone", buffer_zone);
- for (COListColumn column : m_Columns)
+ m_HeadingHeight = SORT_SPRITE_DIM; // At least the size of the sorting sprite
+
+ for (const COListColumn& column : m_Columns)
{
+ float width = column.m_Width;
+ if (column.m_Width > 0 && column.m_Width < 1)
+ width *= m_TotalAvailableColumnWidth;
+
SGUIText* text = new SGUIText();
CGUIString gui_string;
gui_string.SetValue(column.m_Heading);
*text = GetGUI()->GenerateText(gui_string, font, width, buffer_zone, this);
AddText(text);
+ m_HeadingHeight = std::max(m_HeadingHeight, text->m_Size.cy + COLUMN_SHIFT.y);
}
// Generate texts
float buffered_y = 0.f;
for (size_t i = 0; i < pList->m_Items.size(); ++i)
{
m_ItemsYPositions[i] = buffered_y;
float shift = 0.0f;
- for (size_t c = 0; c < m_Columns.size(); ++c)
+ for (const COListColumn& column : m_Columns)
{
+ float width = column.m_Width;
+ if (column.m_Width > 0 && column.m_Width < 1)
+ width *= m_TotalAvailableColumnWidth;
+
CGUIList* pList_c;
- GUI::GetSettingPointer(this, "list_" + m_Columns[c].m_Id, pList_c);
+ GUI::GetSettingPointer(this, "list_" + column.m_Id, pList_c);
SGUIText* text = new SGUIText();
if (!pList_c->m_Items[i].GetOriginalString().empty())
*text = GetGUI()->GenerateText(pList_c->m_Items[i], font, width, buffer_zone, this);
else
{
// Minimum height of a space character of the current font size
CGUIString align_string;
align_string.SetValue(L" ");
*text = GetGUI()->GenerateText(align_string, font, width, buffer_zone, this);
}
shift = std::max(shift, text->m_Size.cy);
AddText(text);
}
buffered_y += shift;
}
m_ItemsYPositions[pList->m_Items.size()] = buffered_y;
if (scrollbar)
{
CRect rect = GetListRect();
GetScrollBar(0).SetScrollRange(m_ItemsYPositions.back());
GetScrollBar(0).SetScrollSpace(rect.GetHeight());
GetScrollBar(0).SetX(rect.right);
GetScrollBar(0).SetY(rect.top);
GetScrollBar(0).SetZ(GetBufferedZ());
GetScrollBar(0).SetLength(rect.bottom - rect.top);
}
}
CRect COList::GetListRect() const
{
- float headingHeight;
- GUI::GetSetting(this, "heading_height", headingHeight);
- return m_CachedActualSize + CRect(0, headingHeight, 0, 0);
+ return m_CachedActualSize + CRect(0, m_HeadingHeight, 0, 0);
}
void COList::HandleMessage(SGUIMessage& Message)
{
CList::HandleMessage(Message);
switch (Message.type)
{
// If somebody clicks on the column heading
case GUIM_MOUSE_PRESS_LEFT:
{
bool sortable;
GUI::GetSetting(this, "sortable", sortable);
if (!sortable)
return;
CPos mouse = GetMousePos();
if (!m_CachedActualSize.PointInside(mouse))
return;
CStr selectedColumn;
GUI::GetSetting(this, "selected_column", selectedColumn);
int selectedColumnOrder;
GUI::GetSetting(this, "selected_column_order", selectedColumnOrder);
- float headingHeight;
- GUI::GetSetting(this, "heading_height", headingHeight);
float xpos = 0;
- for (COListColumn column : m_Columns)
+ for (const COListColumn& column : m_Columns)
{
bool hidden = false;
GUI::GetSetting(this, "hidden_" + column.m_Id, hidden);
if (hidden)
continue;
float width = column.m_Width;
// Check if it's a decimal value, and if so, assume relative positioning.
if (column.m_Width < 1 && column.m_Width > 0)
width *= m_TotalAvailableColumnWidth;
CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 0);
if (mouse.x >= leftTopCorner.x &&
mouse.x < leftTopCorner.x + width &&
- mouse.y < leftTopCorner.y + headingHeight)
+ mouse.y < leftTopCorner.y + m_HeadingHeight)
{
if (column.m_Id != selectedColumn)
{
selectedColumnOrder = 1;
selectedColumn = column.m_Id;
}
else
selectedColumnOrder = -selectedColumnOrder;
GUI::SetSetting(this, "selected_column", column.m_Id);
GUI::SetSetting(this, "selected_column_order", selectedColumnOrder);
ScriptEvent("selectioncolumnchange");
CStrW soundPath;
if (g_SoundManager && GUI::GetSetting(this, "sound_selected", soundPath) == PSRETURN_OK && !soundPath.empty())
g_SoundManager->PlayAsUI(soundPath.c_str(), false);
return;
}
xpos += width;
}
return;
}
default:
return;
}
}
bool COList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile)
{
#define ELMT(x) int elmt_##x = pFile->GetElementID(#x)
#define ATTR(x) int attr_##x = pFile->GetAttributeID(#x)
ELMT(item);
ELMT(column);
ELMT(translatableAttribute);
ATTR(id);
ATTR(context);
if (child.GetNodeName() == elmt_item)
{
AddItem(child.GetText().FromUTF8(), child.GetText().FromUTF8());
return true;
}
else if (child.GetNodeName() == elmt_column)
{
COListColumn column;
bool hidden = false;
for (XMBAttribute attr : child.GetAttributes())
{
CStr attr_name(pFile->GetAttributeString(attr.Name));
CStr attr_value(attr.Value);
if (attr_name == "color")
{
CColor color;
if (!GUI::ParseString(attr_value.FromUTF8(), color))
LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str());
else
column.m_TextColor = color;
}
else if (attr_name == "id")
{
column.m_Id = attr_value;
}
else if (attr_name == "hidden")
{
if (!GUI::ParseString(attr_value.FromUTF8(), hidden))
LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str());
}
else if (attr_name == "width")
{
float width;
if (!GUI::ParseString(attr_value.FromUTF8(), width))
LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.c_str(), attr_value.c_str());
else
{
// Check if it's a relative value, and save as decimal if so.
if (attr_value.find("%") != std::string::npos)
width = width / 100.f;
column.m_Width = width;
}
}
else if (attr_name == "heading")
{
column.m_Heading = attr_value.FromUTF8();
}
}
for (XMBElement grandchild : child.GetChildNodes())
{
if (grandchild.GetNodeName() != elmt_translatableAttribute)
continue;
CStr attributeName(grandchild.GetAttributes().GetNamedItem(attr_id));
// only the heading is translatable for list column
if (attributeName.empty() || attributeName != "heading")
{
LOGERROR("GUI: translatable attribute in olist column that isn't a heading. (object: %s)", this->GetPresentableName().c_str());
continue;
}
CStr value(grandchild.GetText());
if (value.empty())
continue;
CStr context(grandchild.GetAttributes().GetNamedItem(attr_context)); // Read the context if any.
if (!context.empty())
{
CStr translatedValue(g_L10n.TranslateWithContext(context, value));
column.m_Heading = translatedValue.FromUTF8();
}
else
{
CStr translatedValue(g_L10n.Translate(value));
column.m_Heading = translatedValue.FromUTF8();
}
}
m_Columns.push_back(column);
AddSetting(GUIST_CGUIList, "list_" + column.m_Id);
AddSetting(GUIST_bool, "hidden_" + column.m_Id);
GUI::SetSetting(this, "hidden_" + column.m_Id, hidden);
SetupText();
return true;
}
else
{
return false;
}
}
void COList::DrawList(const int& selected, const CStr& _sprite, const CStr& _sprite_selected, const CStr& _textcolor)
{
float bz = GetBufferedZ();
bool scrollbar;
GUI::GetSetting(this, "scrollbar", scrollbar);
if (scrollbar)
IGUIScrollBarOwner::Draw();
if (!GetGUI())
return;
CRect rect = GetListRect();
CGUISpriteInstance* sprite = NULL;
CGUISpriteInstance* sprite_selectarea = NULL;
int cell_id;
GUI::GetSettingPointer(this, _sprite, sprite);
GUI::GetSettingPointer(this, _sprite_selected, sprite_selectarea);
GUI::GetSetting(this, "cell_id", cell_id);
CGUIList* pList;
GUI::GetSettingPointer(this, "list", pList);
GetGUI()->DrawSprite(*sprite, cell_id, bz, rect);
float scroll = 0.f;
if (scrollbar)
scroll = GetScrollBar(0).GetPos();
// Draw item selection
if (selected != -1)
{
ENSURE(selected >= 0 && selected+1 < (int)m_ItemsYPositions.size());
// Get rectangle of selection:
CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll,
rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll);
if (rect_sel.top <= rect.bottom &&
rect_sel.bottom >= rect.top)
{
if (rect_sel.bottom > rect.bottom)
rect_sel.bottom = rect.bottom;
if (rect_sel.top < rect.top)
rect_sel.top = rect.top;
if (scrollbar)
{
// Remove any overlapping area of the scrollbar.
if (rect_sel.right > GetScrollBar(0).GetOuterRect().left &&
rect_sel.right <= GetScrollBar(0).GetOuterRect().right)
rect_sel.right = GetScrollBar(0).GetOuterRect().left;
if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left &&
rect_sel.left < GetScrollBar(0).GetOuterRect().right)
rect_sel.left = GetScrollBar(0).GetOuterRect().right;
}
// Draw item selection
GetGUI()->DrawSprite(*sprite_selectarea, cell_id, bz+0.05f, rect_sel);
}
}
- float headingHeight;
- GUI::GetSetting(this, "heading_height", headingHeight);
-
// Draw line above column header
CGUISpriteInstance* sprite_heading = NULL;
GUI::GetSettingPointer(this, "sprite_heading", sprite_heading);
CRect rect_head(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right,
- m_CachedActualSize.top + headingHeight);
+ m_CachedActualSize.top + m_HeadingHeight);
GetGUI()->DrawSprite(*sprite_heading, cell_id, bz, rect_head);
// Draw column headers
bool sortable;
GUI::GetSetting(this, "sortable", sortable);
CStr selectedColumn;
GUI::GetSetting(this, "selected_column", selectedColumn);
int selectedColumnOrder;
GUI::GetSetting(this, "selected_column_order", selectedColumnOrder);
CColor color;
GUI::GetSetting(this, _textcolor, color);
float xpos = 0;
for (size_t col = 0; col < m_Columns.size(); ++col)
{
bool hidden = false;
GUI::GetSetting(this, "hidden_" + m_Columns[col].m_Id, hidden);
if (hidden)
continue;
// Check if it's a decimal value, and if so, assume relative positioning.
float width = m_Columns[col].m_Width;
if (m_Columns[col].m_Width < 1 && m_Columns[col].m_Width > 0)
width *= m_TotalAvailableColumnWidth;
CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 0);
// Draw sort arrows in colum header
if (sortable)
{
CGUISpriteInstance* sprite;
if (selectedColumn == m_Columns[col].m_Id)
{
if (selectedColumnOrder == 0)
LOGERROR("selected_column_order must not be 0");
if (selectedColumnOrder != -1)
GUI::GetSettingPointer(this, "sprite_asc", sprite);
else
GUI::GetSettingPointer(this, "sprite_desc", sprite);
}
else
GUI::GetSettingPointer(this, "sprite_not_sorted", sprite);
- GetGUI()->DrawSprite(*sprite, cell_id, bz + 0.1f, CRect(leftTopCorner + CPos(width - 16, 0), leftTopCorner + CPos(width, 16)));
+ GetGUI()->DrawSprite(*sprite, cell_id, bz + 0.1f, CRect(leftTopCorner + CPos(width - SORT_SPRITE_DIM, 0), leftTopCorner + CPos(width, SORT_SPRITE_DIM)));
}
// Draw column header text
- DrawText(col, color, leftTopCorner + CPos(0, 4), bz + 0.1f, rect_head);
+ DrawText(col, color, leftTopCorner + COLUMN_SHIFT, bz + 0.1f, rect_head);
xpos += width;
}
// Draw list items for each column
const size_t objectsCount = m_Columns.size();
for (size_t i = 0; i < pList->m_Items.size(); ++i)
{
if (m_ItemsYPositions[i+1] - scroll < 0 ||
m_ItemsYPositions[i] - scroll > rect.GetHeight())
continue;
const float rowHeight = m_ItemsYPositions[i+1] - m_ItemsYPositions[i];
// Clipping area (we'll have to substract the scrollbar)
CRect cliparea = GetListRect();
if (scrollbar)
{
if (cliparea.right > GetScrollBar(0).GetOuterRect().left &&
cliparea.right <= GetScrollBar(0).GetOuterRect().right)
cliparea.right = GetScrollBar(0).GetOuterRect().left;
if (cliparea.left >= GetScrollBar(0).GetOuterRect().left &&
cliparea.left < GetScrollBar(0).GetOuterRect().right)
cliparea.left = GetScrollBar(0).GetOuterRect().right;
}
// Draw all items for that column
xpos = 0;
for (size_t col = 0; col < objectsCount; ++col)
{
bool hidden = false;
GUI::GetSetting(this, "hidden_" + m_Columns[col].m_Id, hidden);
if (hidden)
continue;
// Determine text position and width
const CPos textPos = rect.TopLeft() + CPos(xpos, -scroll + m_ItemsYPositions[i]);
float width = m_Columns[col].m_Width;
// Check if it's a decimal value, and if so, assume relative positioning.
if (m_Columns[col].m_Width < 1 && m_Columns[col].m_Width > 0)
width *= m_TotalAvailableColumnWidth;
// Clip text to the column (to prevent drawing text into the neighboring column)
CRect cliparea2 = cliparea;
cliparea2.right = std::min(cliparea2.right, textPos.x + width);
cliparea2.bottom = std::min(cliparea2.bottom, textPos.y + rowHeight);
// Draw list item
DrawText(objectsCount * (i +/*Heading*/1) + col, m_Columns[col].m_TextColor, textPos, bz + 0.1f, cliparea2);
xpos += width;
}
}
}
Index: ps/trunk/source/gui/COList.h
===================================================================
--- ps/trunk/source/gui/COList.h (revision 22065)
+++ ps/trunk/source/gui/COList.h (revision 22066)
@@ -1,73 +1,74 @@
-/* Copyright (C) 2016 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_COLIST
#define INCLUDED_COLIST
#include "GUI.h"
#include "CList.h"
/**
* Represents a column.
*/
struct COListColumn
{
CColor m_TextColor;
CStr m_Id;
float m_Width;
CStrW m_Heading;
};
/**
* Multi-column list. One row can be selected by the user.
* Individual cells are clipped if the contained text is too long.
*
* The list can be sorted dynamically by JS code when a
* heading is clicked.
* A scroll-bar will appear when needed.
*/
class COList : public CList
{
GUI_OBJECT(COList)
public:
COList();
protected:
void SetupText();
void HandleMessage(SGUIMessage& Message);
/**
* Handle the \- tag.
*/
virtual bool HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile);
void DrawList(const int& selected, const CStr& _sprite, const CStr& _sprite_selected, const CStr& _textcolor);
virtual CRect GetListRect() const;
/**
* Available columns.
*/
std::vector m_Columns;
private:
// Width of space available for columns
float m_TotalAvailableColumnWidth;
+ float m_HeadingHeight;
};
#endif // INCLUDED_COLIST