/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "GUIListItemLayout.h" #include "FileItem.h" #include "GUIControlFactory.h" #include "GUIImage.h" #include "GUIInfoManager.h" #include "GUIListLabel.h" #include "utils/XBMCTinyXML.h" using namespace KODI::GUILIB; CGUIListItemLayout::CGUIListItemLayout() : m_group(0, 0, 0, 0, 0, 0) { m_group.SetPushUpdates(true); } CGUIListItemLayout::CGUIListItemLayout(const CGUIListItemLayout& from) : CGUIListItemLayout(from, nullptr) { } CGUIListItemLayout::CGUIListItemLayout(const CGUIListItemLayout& from, CGUIControl* control) : m_group(from.m_group), m_width(from.m_width), m_height(from.m_height), m_focused(from.m_focused), m_condition(from.m_condition), m_isPlaying(from.m_isPlaying), m_infoUpdateMillis(from.m_infoUpdateMillis) { m_group.SetParentControl(control); m_infoUpdateTimeout.Set(m_infoUpdateMillis); // m_group was just created, cloned controls with resources must be allocated // before use m_group.AllocResources(); } bool CGUIListItemLayout::IsAnimating(ANIMATION_TYPE animType) { return m_group.IsAnimating(animType); } void CGUIListItemLayout::ResetAnimation(ANIMATION_TYPE animType) { return m_group.ResetAnimation(animType); } float CGUIListItemLayout::Size(ORIENTATION orientation) const { return (orientation == HORIZONTAL) ? m_width : m_height; } void CGUIListItemLayout::Process(CGUIListItem *item, int parentID, unsigned int currentTime, CDirtyRegionList &dirtyregions) { if (m_invalidated) { // need to update our item m_invalidated = false; // could use a dynamic cast here if RTTI was enabled. As it's not, // let's use a static cast with a virtual base function CFileItem *fileItem = item->IsFileItem() ? static_cast(item) : new CFileItem(*item); m_isPlaying.Update(INFO::DEFAULT_CONTEXT, item); m_group.SetInvalid(); m_group.UpdateInfo(fileItem); // delete our temporary fileitem if (!item->IsFileItem()) delete fileItem; m_infoUpdateTimeout.Set(m_infoUpdateMillis); } else if (m_infoUpdateTimeout.IsTimePast()) { m_isPlaying.Update(INFO::DEFAULT_CONTEXT, item); m_group.UpdateInfo(item); m_infoUpdateTimeout.Set(m_infoUpdateMillis); } // update visibility, and render m_group.SetState(item->IsSelected() || m_isPlaying, m_focused); m_group.UpdateVisibility(item); m_group.DoProcess(currentTime, dirtyregions); } void CGUIListItemLayout::Render(CGUIListItem *item, int parentID) { m_group.DoRender(); } void CGUIListItemLayout::SetFocusedItem(unsigned int focus) { m_group.SetFocusedItem(focus); } unsigned int CGUIListItemLayout::GetFocusedItem() const { return m_group.GetFocusedItem(); } void CGUIListItemLayout::SetWidth(float width) { if (m_width != width) { m_group.EnlargeWidth(width - m_width); m_width = width; SetInvalid(); } } void CGUIListItemLayout::SetHeight(float height) { if (m_height != height) { m_group.EnlargeHeight(height - m_height); m_height = height; SetInvalid(); } } void CGUIListItemLayout::SelectItemFromPoint(const CPoint &point) { m_group.SelectItemFromPoint(point); } bool CGUIListItemLayout::MoveLeft() { return m_group.MoveLeft(); } bool CGUIListItemLayout::MoveRight() { return m_group.MoveRight(); } bool CGUIListItemLayout::CheckCondition() { return !m_condition || m_condition->Get(INFO::DEFAULT_CONTEXT); } void CGUIListItemLayout::LoadControl(TiXmlElement *child, CGUIControlGroup *group) { if (!group) return; CRect rect(group->GetXPosition(), group->GetYPosition(), group->GetXPosition() + group->GetWidth(), group->GetYPosition() + group->GetHeight()); CGUIControlFactory factory; CGUIControl *control = factory.Create(0, rect, child, true); // true indicating we're inside a list for the // different label control + defaults. if (control) { group->AddControl(control); if (control->IsGroup()) { TiXmlElement *grandChild = child->FirstChildElement("control"); while (grandChild) { LoadControl(grandChild, static_cast(control)); grandChild = grandChild->NextSiblingElement("control"); } } } } void CGUIListItemLayout::LoadLayout(TiXmlElement *layout, int context, bool focused, float maxWidth, float maxHeight) { m_focused = focused; layout->QueryFloatAttribute("width", &m_width); layout->QueryFloatAttribute("height", &m_height); const char *condition = layout->Attribute("condition"); if (condition) m_condition = CServiceBroker::GetGUI()->GetInfoManager().Register(condition, context); unsigned int infoupdatemillis = 0; layout->QueryUnsignedAttribute("infoupdate", &infoupdatemillis); if (infoupdatemillis > 0) m_infoUpdateMillis = std::chrono::milliseconds(infoupdatemillis); m_infoUpdateTimeout.Set(m_infoUpdateMillis); m_isPlaying.Parse("listitem.isplaying", context); // ensure width and height are valid if (!m_width) m_width = maxWidth; if (!m_height) m_height = maxHeight; m_width = std::max(1.0f, m_width); m_height = std::max(1.0f, m_height); m_group.SetWidth(m_width); m_group.SetHeight(m_height); TiXmlElement *child = layout->FirstChildElement("control"); while (child) { LoadControl(child, &m_group); child = child->NextSiblingElement("control"); } } //#ifdef GUILIB_PYTHON_COMPATIBILITY void CGUIListItemLayout::CreateListControlLayouts(float width, float height, bool focused, const CLabelInfo &labelInfo, const CLabelInfo &labelInfo2, const CTextureInfo &texture, const CTextureInfo &textureFocus, float texHeight, float iconWidth, float iconHeight, const std::string &nofocusCondition, const std::string &focusCondition) { m_width = width; m_height = height; m_focused = focused; m_isPlaying.Parse("listitem.isplaying", 0); CGUIImage *tex = new CGUIImage(0, 0, 0, 0, width, texHeight, texture); tex->SetVisibleCondition(nofocusCondition); m_group.AddControl(tex); if (focused) { CGUIImage *tex = new CGUIImage(0, 0, 0, 0, width, texHeight, textureFocus); tex->SetVisibleCondition(focusCondition); m_group.AddControl(tex); } CGUIImage *image = new CGUIImage(0, 0, 8, 0, iconWidth, texHeight, CTextureInfo("")); image->SetInfo(GUIINFO::CGUIInfoLabel("$INFO[ListItem.Icon]", "", m_group.GetParentID())); image->SetAspectRatio(CAspectRatio::AR_KEEP); m_group.AddControl(image); float x = iconWidth + labelInfo.offsetX + 10; CGUIListLabel *label = new CGUIListLabel(0, 0, x, labelInfo.offsetY, width - x - 18, height, labelInfo, GUIINFO::CGUIInfoLabel("$INFO[ListItem.Label]", "", m_group.GetParentID()), CGUIControl::FOCUS); m_group.AddControl(label); x = labelInfo2.offsetX ? labelInfo2.offsetX : m_width - 16; label = new CGUIListLabel(0, 0, x, labelInfo2.offsetY, x - iconWidth - 20, height, labelInfo2, GUIINFO::CGUIInfoLabel("$INFO[ListItem.Label2]", "", m_group.GetParentID()), CGUIControl::FOCUS); m_group.AddControl(label); } //#endif void CGUIListItemLayout::FreeResources(bool immediately) { m_group.FreeResources(immediately); } #ifdef _DEBUG void CGUIListItemLayout::DumpTextureUse() { m_group.DumpTextureUse(); } #endif