| [28120] | 1 | /* Copyright (C) 2024 Wildfire Games.
|
|---|
| [27965] | 2 | * This file is part of 0 A.D.
|
|---|
| [15300] | 3 | *
|
|---|
| [27965] | 4 | * 0 A.D. is free software: you can redistribute it and/or modify
|
|---|
| [15300] | 5 | * it under the terms of the GNU General Public License as published by
|
|---|
| 6 | * the Free Software Foundation, either version 2 of the License, or
|
|---|
| 7 | * (at your option) any later version.
|
|---|
| 8 | *
|
|---|
| [27965] | 9 | * 0 A.D. is distributed in the hope that it will be useful,
|
|---|
| [15300] | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 12 | * GNU General Public License for more details.
|
|---|
| 13 | *
|
|---|
| 14 | * You should have received a copy of the GNU General Public License
|
|---|
| [27965] | 15 | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|---|
| [15300] | 16 | */
|
|---|
| [16931] | 17 |
|
|---|
| [14098] | 18 | #include "precompiled.h"
|
|---|
| [16931] | 19 |
|
|---|
| [14098] | 20 | #include "COList.h"
|
|---|
| [16931] | 21 |
|
|---|
| [22931] | 22 | #include "gui/CGUI.h"
|
|---|
| [22941] | 23 | #include "gui/IGUIScrollBar.h"
|
|---|
| [23028] | 24 | #include "gui/SettingTypes/CGUIColor.h"
|
|---|
| 25 | #include "gui/SettingTypes/CGUIList.h"
|
|---|
| [14953] | 26 | #include "i18n/L10n.h"
|
|---|
| [14098] | 27 | #include "ps/CLogger.h"
|
|---|
| 28 |
|
|---|
| [22066] | 29 | const float SORT_SPRITE_DIM = 16.0f;
|
|---|
| [25152] | 30 | const CVector2D COLUMN_SHIFT = CVector2D(0, 4);
|
|---|
| [22066] | 31 |
|
|---|
| [23403] | 32 | const CStr COList::EventNameSelectionColumnChange = "SelectionColumnChange";
|
|---|
| 33 |
|
|---|
| [22741] | 34 | COList::COList(CGUI& pGUI)
|
|---|
| [23005] | 35 | : CList(pGUI),
|
|---|
| [25392] | 36 | m_SpriteHeading(this, "sprite_heading"),
|
|---|
| 37 | m_Sortable(this, "sortable"), // The actual sorting is done in JS for more versatility
|
|---|
| 38 | m_SelectedColumn(this, "selected_column"),
|
|---|
| 39 | m_SelectedColumnOrder(this, "selected_column_order"),
|
|---|
| 40 | m_SpriteAsc(this, "sprite_asc"), // Show the order of sorting
|
|---|
| 41 | m_SpriteDesc(this, "sprite_desc"),
|
|---|
| 42 | m_SpriteNotSorted(this, "sprite_not_sorted")
|
|---|
| [14098] | 43 | {
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | void COList::SetupText()
|
|---|
| 47 | {
|
|---|
| [25392] | 48 | m_ItemsYPositions.resize(m_List->m_Items.size() + 1);
|
|---|
| [14098] | 49 |
|
|---|
| 50 | // Delete all generated texts. Some could probably be saved,
|
|---|
| 51 | // but this is easier, and this function will never be called
|
|---|
| 52 | // continuously, or even often, so it'll probably be okay.
|
|---|
| 53 | m_GeneratedTexts.clear();
|
|---|
| 54 |
|
|---|
| [22066] | 55 | m_TotalAvailableColumnWidth = GetListRect().GetWidth();
|
|---|
| [14098] | 56 | // remove scrollbar if applicable
|
|---|
| [23005] | 57 | if (m_ScrollBar && GetScrollBar(0).GetStyle())
|
|---|
| [22066] | 58 | m_TotalAvailableColumnWidth -= GetScrollBar(0).GetStyle()->m_Width;
|
|---|
| [14098] | 59 |
|
|---|
| [22066] | 60 | m_HeadingHeight = SORT_SPRITE_DIM; // At least the size of the sorting sprite
|
|---|
| 61 |
|
|---|
| 62 | for (const COListColumn& column : m_Columns)
|
|---|
| [14098] | 63 | {
|
|---|
| [22066] | 64 | float width = column.m_Width;
|
|---|
| 65 | if (column.m_Width > 0 && column.m_Width < 1)
|
|---|
| 66 | width *= m_TotalAvailableColumnWidth;
|
|---|
| 67 |
|
|---|
| [14098] | 68 | CGUIString gui_string;
|
|---|
| [18652] | 69 | gui_string.SetValue(column.m_Heading);
|
|---|
| [22679] | 70 |
|
|---|
| [23009] | 71 | const CGUIText& text = AddText(gui_string, m_Font, width, m_BufferZone);
|
|---|
| [25152] | 72 | m_HeadingHeight = std::max(m_HeadingHeight, text.GetSize().Height + COLUMN_SHIFT.Y);
|
|---|
| [14098] | 73 | }
|
|---|
| 74 |
|
|---|
| 75 | // Generate texts
|
|---|
| 76 | float buffered_y = 0.f;
|
|---|
| 77 |
|
|---|
| [25392] | 78 | for (size_t i = 0; i < m_List->m_Items.size(); ++i)
|
|---|
| [14098] | 79 | {
|
|---|
| 80 | m_ItemsYPositions[i] = buffered_y;
|
|---|
| [19306] | 81 | float shift = 0.0f;
|
|---|
| [22066] | 82 | for (const COListColumn& column : m_Columns)
|
|---|
| [14098] | 83 | {
|
|---|
| [22066] | 84 | float width = column.m_Width;
|
|---|
| 85 | if (column.m_Width > 0 && column.m_Width < 1)
|
|---|
| 86 | width *= m_TotalAvailableColumnWidth;
|
|---|
| 87 |
|
|---|
| [22679] | 88 | CGUIText* text;
|
|---|
| [25392] | 89 | if (!column.m_List->m_Items[i].GetOriginalString().empty())
|
|---|
| 90 | text = &AddText(column.m_List->m_Items[i], m_Font, width, m_BufferZone);
|
|---|
| [19306] | 91 | else
|
|---|
| 92 | {
|
|---|
| 93 | // Minimum height of a space character of the current font size
|
|---|
| 94 | CGUIString align_string;
|
|---|
| 95 | align_string.SetValue(L" ");
|
|---|
| [23009] | 96 | text = &AddText(align_string, m_Font, width, m_BufferZone);
|
|---|
| [19306] | 97 | }
|
|---|
| [25143] | 98 | shift = std::max(shift, text->GetSize().Height);
|
|---|
| [14098] | 99 | }
|
|---|
| [19306] | 100 | buffered_y += shift;
|
|---|
| [14098] | 101 | }
|
|---|
| 102 |
|
|---|
| [25392] | 103 | m_ItemsYPositions[m_List->m_Items.size()] = buffered_y;
|
|---|
| [14098] | 104 |
|
|---|
| [23005] | 105 | if (m_ScrollBar)
|
|---|
| [14098] | 106 | {
|
|---|
| [18652] | 107 | CRect rect = GetListRect();
|
|---|
| [16931] | 108 | GetScrollBar(0).SetScrollRange(m_ItemsYPositions.back());
|
|---|
| [18652] | 109 | GetScrollBar(0).SetScrollSpace(rect.GetHeight());
|
|---|
| [14098] | 110 |
|
|---|
| [16931] | 111 | GetScrollBar(0).SetX(rect.right);
|
|---|
| 112 | GetScrollBar(0).SetY(rect.top);
|
|---|
| 113 | GetScrollBar(0).SetZ(GetBufferedZ());
|
|---|
| 114 | GetScrollBar(0).SetLength(rect.bottom - rect.top);
|
|---|
| [14098] | 115 | }
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 | CRect COList::GetListRect() const
|
|---|
| 119 | {
|
|---|
| [22066] | 120 | return m_CachedActualSize + CRect(0, m_HeadingHeight, 0, 0);
|
|---|
| [14098] | 121 | }
|
|---|
| 122 |
|
|---|
| [16931] | 123 | void COList::HandleMessage(SGUIMessage& Message)
|
|---|
| [14098] | 124 | {
|
|---|
| 125 | CList::HandleMessage(Message);
|
|---|
| [16781] | 126 |
|
|---|
| 127 | switch (Message.type)
|
|---|
| 128 | {
|
|---|
| [27384] | 129 |
|
|---|
| 130 | case GUIM_SETTINGS_UPDATED:
|
|---|
| 131 | {
|
|---|
| 132 | if (Message.value.find("heading_") == 0)
|
|---|
| 133 | SetupText();
|
|---|
| 134 | break;
|
|---|
| 135 | }
|
|---|
| 136 |
|
|---|
| [16781] | 137 | // If somebody clicks on the column heading
|
|---|
| 138 | case GUIM_MOUSE_PRESS_LEFT:
|
|---|
| 139 | {
|
|---|
| [23005] | 140 | if (!m_Sortable)
|
|---|
| [16781] | 141 | return;
|
|---|
| 142 |
|
|---|
| [25152] | 143 | const CVector2D& mouse = m_pGUI.GetMousePos();
|
|---|
| [16781] | 144 | if (!m_CachedActualSize.PointInside(mouse))
|
|---|
| 145 | return;
|
|---|
| [16931] | 146 |
|
|---|
| [16781] | 147 | float xpos = 0;
|
|---|
| [22066] | 148 | for (const COListColumn& column : m_Columns)
|
|---|
| [16781] | 149 | {
|
|---|
| [23005] | 150 | if (column.m_Hidden)
|
|---|
| [19353] | 151 | continue;
|
|---|
| 152 |
|
|---|
| [18652] | 153 | float width = column.m_Width;
|
|---|
| [16781] | 154 | // Check if it's a decimal value, and if so, assume relative positioning.
|
|---|
| [18652] | 155 | if (column.m_Width < 1 && column.m_Width > 0)
|
|---|
| 156 | width *= m_TotalAvailableColumnWidth;
|
|---|
| [25152] | 157 | CVector2D leftTopCorner = m_CachedActualSize.TopLeft() + CVector2D(xpos, 0);
|
|---|
| 158 | if (mouse.X >= leftTopCorner.X &&
|
|---|
| 159 | mouse.X < leftTopCorner.X + width &&
|
|---|
| 160 | mouse.Y < leftTopCorner.Y + m_HeadingHeight)
|
|---|
| [16781] | 161 | {
|
|---|
| [25392] | 162 | if (column.m_Id != static_cast<CStr>(m_SelectedColumn))
|
|---|
| [16781] | 163 | {
|
|---|
| [27398] | 164 | m_SelectedColumnOrder.Set(column.m_SortOrder, true);
|
|---|
| [23005] | 165 | CStr selected_column = column.m_Id;
|
|---|
| [25392] | 166 | m_SelectedColumn.Set(selected_column, true);
|
|---|
| [16781] | 167 | }
|
|---|
| 168 | else
|
|---|
| [25392] | 169 | m_SelectedColumnOrder.Set(-m_SelectedColumnOrder, true);
|
|---|
| [22765] | 170 |
|
|---|
| [23403] | 171 | ScriptEvent(EventNameSelectionColumnChange);
|
|---|
| [23005] | 172 | PlaySound(m_SoundSelected);
|
|---|
| [16781] | 173 | return;
|
|---|
| 174 | }
|
|---|
| 175 | xpos += width;
|
|---|
| 176 | }
|
|---|
| 177 | return;
|
|---|
| 178 | }
|
|---|
| 179 | default:
|
|---|
| 180 | return;
|
|---|
| 181 | }
|
|---|
| [14098] | 182 | }
|
|---|
| 183 |
|
|---|
| [25378] | 184 | bool COList::HandleAdditionalChildren(const XMBData& xmb, const XMBElement& child)
|
|---|
| [14098] | 185 | {
|
|---|
| [25378] | 186 | #define ELMT(x) int elmt_##x = xmb.GetElementID(#x)
|
|---|
| 187 | #define ATTR(x) int attr_##x = xmb.GetAttributeID(#x)
|
|---|
| [14953] | 188 | ELMT(item);
|
|---|
| [18652] | 189 | ELMT(column);
|
|---|
| [14953] | 190 | ELMT(translatableAttribute);
|
|---|
| 191 | ATTR(id);
|
|---|
| [15078] | 192 | ATTR(context);
|
|---|
| [14098] | 193 |
|
|---|
| 194 | if (child.GetNodeName() == elmt_item)
|
|---|
| 195 | {
|
|---|
| [24306] | 196 | CGUIString vlist;
|
|---|
| 197 | vlist.SetValue(child.GetText().FromUTF8());
|
|---|
| 198 | AddItem(vlist, vlist);
|
|---|
| [14098] | 199 | return true;
|
|---|
| 200 | }
|
|---|
| [18652] | 201 | else if (child.GetNodeName() == elmt_column)
|
|---|
| [14098] | 202 | {
|
|---|
| [25392] | 203 | CStr id;
|
|---|
| 204 | XERO_ITER_ATTR(child, attr)
|
|---|
| 205 | {
|
|---|
| 206 | if (attr.Name == attr_id)
|
|---|
| 207 | id = attr.Value;
|
|---|
| 208 | }
|
|---|
| [14098] | 209 |
|
|---|
| [25392] | 210 | COListColumn column(this, id);
|
|---|
| 211 |
|
|---|
| [16704] | 212 | for (XMBAttribute attr : child.GetAttributes())
|
|---|
| [14098] | 213 | {
|
|---|
| [25378] | 214 | std::string_view attr_name(xmb.GetAttributeStringView(attr.Name));
|
|---|
| [16931] | 215 | CStr attr_value(attr.Value);
|
|---|
| [14098] | 216 |
|
|---|
| [28120] | 217 | if (attr_name == "textcolor")
|
|---|
| [14098] | 218 | {
|
|---|
| [22801] | 219 | if (!CGUI::ParseString<CGUIColor>(&m_pGUI, attr_value.FromUTF8(), column.m_TextColor))
|
|---|
| [25375] | 220 | LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.data(), attr_value.c_str());
|
|---|
| [14098] | 221 | }
|
|---|
| [28135] | 222 | else if (attr_name == "textcolor_selected")
|
|---|
| 223 | {
|
|---|
| 224 | if (!CGUI::ParseString<CGUIColor>(&m_pGUI, attr_value.FromUTF8(), column.m_TextColorSelected))
|
|---|
| 225 | LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.data(), attr_value.c_str());
|
|---|
| 226 | }
|
|---|
| [19353] | 227 | else if (attr_name == "hidden")
|
|---|
| 228 | {
|
|---|
| [23005] | 229 | bool hidden = false;
|
|---|
| [22801] | 230 | if (!CGUI::ParseString<bool>(&m_pGUI, attr_value.FromUTF8(), hidden))
|
|---|
| [25375] | 231 | LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.data(), attr_value.c_str());
|
|---|
| [23005] | 232 | else
|
|---|
| [25392] | 233 | column.m_Hidden.Set(hidden, false);
|
|---|
| [19353] | 234 | }
|
|---|
| [14098] | 235 | else if (attr_name == "width")
|
|---|
| 236 | {
|
|---|
| 237 | float width;
|
|---|
| [22801] | 238 | if (!CGUI::ParseString<float>(&m_pGUI, attr_value.FromUTF8(), width))
|
|---|
| [25375] | 239 | LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name.data(), attr_value.c_str());
|
|---|
| [14098] | 240 | else
|
|---|
| 241 | {
|
|---|
| 242 | // Check if it's a relative value, and save as decimal if so.
|
|---|
| 243 | if (attr_value.find("%") != std::string::npos)
|
|---|
| 244 | width = width / 100.f;
|
|---|
| [18652] | 245 | column.m_Width = width;
|
|---|
| [14098] | 246 | }
|
|---|
| 247 | }
|
|---|
| 248 | else if (attr_name == "heading")
|
|---|
| 249 | {
|
|---|
| [27384] | 250 | column.m_Heading.Set(attr_value.FromUTF8(), false);
|
|---|
| [14098] | 251 | }
|
|---|
| [27398] | 252 | else if (attr_name == "sort_order")
|
|---|
| 253 | {
|
|---|
| 254 | column.m_SortOrder.Set(attr_value == "desc" ? -1 : 1, false);
|
|---|
| 255 | }
|
|---|
| [14098] | 256 | }
|
|---|
| 257 |
|
|---|
| [16704] | 258 | for (XMBElement grandchild : child.GetChildNodes())
|
|---|
| [14953] | 259 | {
|
|---|
| [16931] | 260 | if (grandchild.GetNodeName() != elmt_translatableAttribute)
|
|---|
| 261 | continue;
|
|---|
| 262 |
|
|---|
| 263 | CStr attributeName(grandchild.GetAttributes().GetNamedItem(attr_id));
|
|---|
| [18652] | 264 | // only the heading is translatable for list column
|
|---|
| [16931] | 265 | if (attributeName.empty() || attributeName != "heading")
|
|---|
| [14953] | 266 | {
|
|---|
| [18652] | 267 | LOGERROR("GUI: translatable attribute in olist column that isn't a heading. (object: %s)", this->GetPresentableName().c_str());
|
|---|
| [16931] | 268 | continue;
|
|---|
| [14953] | 269 | }
|
|---|
| [16931] | 270 |
|
|---|
| 271 | CStr value(grandchild.GetText());
|
|---|
| 272 | if (value.empty())
|
|---|
| 273 | continue;
|
|---|
| 274 |
|
|---|
| 275 | CStr context(grandchild.GetAttributes().GetNamedItem(attr_context)); // Read the context if any.
|
|---|
| 276 | if (!context.empty())
|
|---|
| 277 | {
|
|---|
| 278 | CStr translatedValue(g_L10n.TranslateWithContext(context, value));
|
|---|
| [27384] | 279 | column.m_Heading.Set(translatedValue.FromUTF8(), false);
|
|---|
| [16931] | 280 | }
|
|---|
| 281 | else
|
|---|
| 282 | {
|
|---|
| 283 | CStr translatedValue(g_L10n.Translate(value));
|
|---|
| [27384] | 284 | column.m_Heading.Set(translatedValue.FromUTF8(), false);
|
|---|
| [16931] | 285 | }
|
|---|
| [14953] | 286 | }
|
|---|
| 287 |
|
|---|
| [22638] | 288 | m_Columns.emplace_back(std::move(column));
|
|---|
| [14098] | 289 | return true;
|
|---|
| 290 | }
|
|---|
| [22638] | 291 |
|
|---|
| 292 | return false;
|
|---|
| [14098] | 293 | }
|
|---|
| 294 |
|
|---|
| [23005] | 295 | void COList::AdditionalChildrenHandled()
|
|---|
| [14098] | 296 | {
|
|---|
| [23005] | 297 | SetupText();
|
|---|
| 298 | }
|
|---|
| 299 |
|
|---|
| [25591] | 300 | void COList::DrawList(CCanvas2D& canvas, const int& selected, const CGUISpriteInstance& sprite, const CGUISpriteInstance& spriteOverlay,
|
|---|
| [25587] | 301 | const CGUISpriteInstance& spriteSelectArea, const CGUISpriteInstance& spriteSelectAreaOverlay, const CGUIColor& textColor)
|
|---|
| [23005] | 302 | {
|
|---|
| [16931] | 303 | CRect rect = GetListRect();
|
|---|
| [14098] | 304 |
|
|---|
| [25591] | 305 | m_pGUI.DrawSprite(sprite, canvas, rect);
|
|---|
| [22693] | 306 |
|
|---|
| [16931] | 307 | float scroll = 0.f;
|
|---|
| [23005] | 308 | if (m_ScrollBar)
|
|---|
| [16931] | 309 | scroll = GetScrollBar(0).GetPos();
|
|---|
| [14098] | 310 |
|
|---|
| [25587] | 311 | bool drawSelected = false;
|
|---|
| 312 | CRect rectSel;
|
|---|
| [16976] | 313 | // Draw item selection
|
|---|
| [16931] | 314 | if (selected != -1)
|
|---|
| 315 | {
|
|---|
| 316 | ENSURE(selected >= 0 && selected+1 < (int)m_ItemsYPositions.size());
|
|---|
| [14098] | 317 |
|
|---|
| [16931] | 318 | // Get rectangle of selection:
|
|---|
| [25587] | 319 | rectSel = CRect(
|
|---|
| 320 | rect.left, rect.top + m_ItemsYPositions[selected] - scroll,
|
|---|
| 321 | rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll);
|
|---|
| [14098] | 322 |
|
|---|
| [25587] | 323 | if (rectSel.top <= rect.bottom &&
|
|---|
| 324 | rectSel.bottom >= rect.top)
|
|---|
| [16931] | 325 | {
|
|---|
| [25587] | 326 | if (rectSel.bottom > rect.bottom)
|
|---|
| 327 | rectSel.bottom = rect.bottom;
|
|---|
| 328 | if (rectSel.top < rect.top)
|
|---|
| 329 | rectSel.top = rect.top;
|
|---|
| [14098] | 330 |
|
|---|
| [23005] | 331 | if (m_ScrollBar)
|
|---|
| [16931] | 332 | {
|
|---|
| 333 | // Remove any overlapping area of the scrollbar.
|
|---|
| [25587] | 334 | if (rectSel.right > GetScrollBar(0).GetOuterRect().left &&
|
|---|
| 335 | rectSel.right <= GetScrollBar(0).GetOuterRect().right)
|
|---|
| 336 | rectSel.right = GetScrollBar(0).GetOuterRect().left;
|
|---|
| [14098] | 337 |
|
|---|
| [25587] | 338 | if (rectSel.left >= GetScrollBar(0).GetOuterRect().left &&
|
|---|
| 339 | rectSel.left < GetScrollBar(0).GetOuterRect().right)
|
|---|
| 340 | rectSel.left = GetScrollBar(0).GetOuterRect().right;
|
|---|
| [14098] | 341 | }
|
|---|
| [16931] | 342 |
|
|---|
| [16976] | 343 | // Draw item selection
|
|---|
| [25591] | 344 | m_pGUI.DrawSprite(spriteSelectArea, canvas, rectSel);
|
|---|
| [25587] | 345 | drawSelected = true;
|
|---|
| [14098] | 346 | }
|
|---|
| [16931] | 347 | }
|
|---|
| [14098] | 348 |
|
|---|
| [16976] | 349 | // Draw line above column header
|
|---|
| [16931] | 350 | CRect rect_head(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right,
|
|---|
| [22066] | 351 | m_CachedActualSize.top + m_HeadingHeight);
|
|---|
| [25591] | 352 | m_pGUI.DrawSprite(m_SpriteHeading, canvas, rect_head);
|
|---|
| [14098] | 353 |
|
|---|
| [18694] | 354 | // Draw column headers
|
|---|
| [16931] | 355 | float xpos = 0;
|
|---|
| [23005] | 356 | size_t col = 0;
|
|---|
| 357 | for (const COListColumn& column : m_Columns)
|
|---|
| [16931] | 358 | {
|
|---|
| [23005] | 359 | if (column.m_Hidden)
|
|---|
| 360 | {
|
|---|
| 361 | ++col;
|
|---|
| [19353] | 362 | continue;
|
|---|
| [23005] | 363 | }
|
|---|
| [19353] | 364 |
|
|---|
| [16931] | 365 | // Check if it's a decimal value, and if so, assume relative positioning.
|
|---|
| [23005] | 366 | float width = column.m_Width;
|
|---|
| 367 | if (column.m_Width < 1 && column.m_Width > 0)
|
|---|
| [18652] | 368 | width *= m_TotalAvailableColumnWidth;
|
|---|
| [16781] | 369 |
|
|---|
| [25152] | 370 | CVector2D leftTopCorner = m_CachedActualSize.TopLeft() + CVector2D(xpos, 0);
|
|---|
| [16976] | 371 |
|
|---|
| 372 | // Draw sort arrows in colum header
|
|---|
| [23005] | 373 | if (m_Sortable)
|
|---|
| [18694] | 374 | {
|
|---|
| [24268] | 375 | const CGUISpriteInstance* pSprite;
|
|---|
| [25392] | 376 | if (*m_SelectedColumn == column.m_Id)
|
|---|
| [18694] | 377 | {
|
|---|
| [23005] | 378 | if (m_SelectedColumnOrder == 0)
|
|---|
| [18694] | 379 | LOGERROR("selected_column_order must not be 0");
|
|---|
| [14098] | 380 |
|
|---|
| [23005] | 381 | if (m_SelectedColumnOrder != -1)
|
|---|
| [25392] | 382 | pSprite = &*m_SpriteAsc;
|
|---|
| [18694] | 383 | else
|
|---|
| [25392] | 384 | pSprite = &*m_SpriteDesc;
|
|---|
| [18694] | 385 | }
|
|---|
| 386 | else
|
|---|
| [25392] | 387 | pSprite = &*m_SpriteNotSorted;
|
|---|
| [18694] | 388 |
|
|---|
| [25591] | 389 | m_pGUI.DrawSprite(*pSprite, canvas, CRect(leftTopCorner + CVector2D(width - SORT_SPRITE_DIM, 0), leftTopCorner + CVector2D(width, SORT_SPRITE_DIM)));
|
|---|
| [18694] | 390 | }
|
|---|
| 391 |
|
|---|
| [16976] | 392 | // Draw column header text
|
|---|
| [25591] | 393 | DrawText(canvas, col, textColor, leftTopCorner + COLUMN_SHIFT, rect_head);
|
|---|
| [16931] | 394 | xpos += width;
|
|---|
| [23005] | 395 | ++col;
|
|---|
| [16931] | 396 | }
|
|---|
| [14098] | 397 |
|
|---|
| [16976] | 398 | // Draw list items for each column
|
|---|
| [18652] | 399 | const size_t objectsCount = m_Columns.size();
|
|---|
| [25392] | 400 | for (size_t i = 0; i < m_List->m_Items.size(); ++i)
|
|---|
| [16931] | 401 | {
|
|---|
| 402 | if (m_ItemsYPositions[i+1] - scroll < 0 ||
|
|---|
| 403 | m_ItemsYPositions[i] - scroll > rect.GetHeight())
|
|---|
| 404 | continue;
|
|---|
| [16895] | 405 |
|
|---|
| [16931] | 406 | const float rowHeight = m_ItemsYPositions[i+1] - m_ItemsYPositions[i];
|
|---|
| [14098] | 407 |
|
|---|
| [16931] | 408 | // Clipping area (we'll have to substract the scrollbar)
|
|---|
| 409 | CRect cliparea = GetListRect();
|
|---|
| [14098] | 410 |
|
|---|
| [23005] | 411 | if (m_ScrollBar)
|
|---|
| [16931] | 412 | {
|
|---|
| 413 | if (cliparea.right > GetScrollBar(0).GetOuterRect().left &&
|
|---|
| 414 | cliparea.right <= GetScrollBar(0).GetOuterRect().right)
|
|---|
| 415 | cliparea.right = GetScrollBar(0).GetOuterRect().left;
|
|---|
| [14098] | 416 |
|
|---|
| [16931] | 417 | if (cliparea.left >= GetScrollBar(0).GetOuterRect().left &&
|
|---|
| 418 | cliparea.left < GetScrollBar(0).GetOuterRect().right)
|
|---|
| 419 | cliparea.left = GetScrollBar(0).GetOuterRect().right;
|
|---|
| 420 | }
|
|---|
| [16895] | 421 |
|
|---|
| [16976] | 422 | // Draw all items for that column
|
|---|
| [16931] | 423 | xpos = 0;
|
|---|
| [24268] | 424 | for (size_t colIdx = 0; colIdx < m_Columns.size(); ++colIdx)
|
|---|
| [16931] | 425 | {
|
|---|
| [24276] | 426 | const COListColumn& column = m_Columns[colIdx];
|
|---|
| [23005] | 427 | if (column.m_Hidden)
|
|---|
| [19353] | 428 | continue;
|
|---|
| 429 |
|
|---|
| [16931] | 430 | // Determine text position and width
|
|---|
| [25152] | 431 | const CVector2D textPos = rect.TopLeft() + CVector2D(xpos, -scroll + m_ItemsYPositions[i]);
|
|---|
| [16895] | 432 |
|
|---|
| [23005] | 433 | float width = column.m_Width;
|
|---|
| [16931] | 434 | // Check if it's a decimal value, and if so, assume relative positioning.
|
|---|
| [23005] | 435 | if (column.m_Width < 1 && column.m_Width > 0)
|
|---|
| [18652] | 436 | width *= m_TotalAvailableColumnWidth;
|
|---|
| [16895] | 437 |
|
|---|
| [16931] | 438 | // Clip text to the column (to prevent drawing text into the neighboring column)
|
|---|
| 439 | CRect cliparea2 = cliparea;
|
|---|
| [25152] | 440 | cliparea2.right = std::min(cliparea2.right, textPos.X + width);
|
|---|
| 441 | cliparea2.bottom = std::min(cliparea2.bottom, textPos.Y + rowHeight);
|
|---|
| [16931] | 442 |
|
|---|
| [28135] | 443 | const CGUIColor& finalTextColor = (drawSelected && static_cast<size_t>(selected) == i && column.m_TextColorSelected) ? column.m_TextColorSelected : column.m_TextColor;
|
|---|
| 444 |
|
|---|
| [16976] | 445 | // Draw list item
|
|---|
| [28135] | 446 | DrawText(canvas, objectsCount * (i +/*Heading*/1) + colIdx, finalTextColor, textPos, cliparea2);
|
|---|
| [16931] | 447 | xpos += width;
|
|---|
| [14098] | 448 | }
|
|---|
| 449 | }
|
|---|
| [25587] | 450 |
|
|---|
| 451 | // Draw scrollbars on top of the content
|
|---|
| 452 | if (m_ScrollBar)
|
|---|
| [25591] | 453 | IGUIScrollBarOwner::Draw(canvas);
|
|---|
| [25587] | 454 |
|
|---|
| 455 | // Draw the overlays last
|
|---|
| [25591] | 456 | m_pGUI.DrawSprite(spriteOverlay, canvas, rect);
|
|---|
| [25587] | 457 | if (drawSelected)
|
|---|
| [25591] | 458 | m_pGUI.DrawSprite(spriteSelectAreaOverlay, canvas, rectSel);
|
|---|
| [14098] | 459 | }
|
|---|