diff options
author | AlTheKiller <AlTheKiller@svn> | 2009-09-23 01:49:50 +0000 |
---|---|---|
committer | AlTheKiller <AlTheKiller@svn> | 2009-09-23 01:49:50 +0000 |
commit | 45285e8a9300cd754a760560640b75b09f98035e (patch) | |
tree | ad9f093885ad5c98e9dd4156674e7691c22ed0a2 /guilib/GUIWindow.cpp |
step 3/4: Move linuxport to trunk. How'd I get roped into this?
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@23097 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
Diffstat (limited to 'guilib/GUIWindow.cpp')
-rw-r--r-- | guilib/GUIWindow.cpp | 1022 |
1 files changed, 1022 insertions, 0 deletions
diff --git a/guilib/GUIWindow.cpp b/guilib/GUIWindow.cpp new file mode 100644 index 0000000000..30c7a90b7f --- /dev/null +++ b/guilib/GUIWindow.cpp @@ -0,0 +1,1022 @@ +/* + * Copyright (C) 2005-2008 Team XBMC + * http://www.xbmc.org + * + * This Program 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, or (at your option) + * any later version. + * + * This Program 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 XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "system.h" +#include "GUIWindow.h" +#include "GUIWindowManager.h" +#include "Key.h" +#include "LocalizeStrings.h" +#include "Settings.h" +#include "GUIControlFactory.h" +#include "GUIControlGroup.h" +#include "GUIControlProfiler.h" +#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY +#include "GUIEditControl.h" +#endif + +#include "SkinInfo.h" +#include "utils/GUIInfoManager.h" +#include "utils/log.h" +#include "utils/SingleLock.h" +#include "ButtonTranslator.h" +#include "XMLUtils.h" +#include "MouseStat.h" + +#ifdef HAS_PERFORMANCE_SAMPLE +#include "utils/PerformanceSample.h" +#endif + +using namespace std; + +CGUIWindow::CGUIWindow(int id, const CStdString &xmlFile) +{ + SetID(id); + m_xmlFile = xmlFile; + m_idRange = 1; + m_lastControlID = 0; + m_bRelativeCoords = false; + m_overlayState = OVERLAY_STATE_PARENT_WINDOW; // Use parent or previous window's state + m_coordsRes = g_guiSettings.m_LookAndFeelResolution; + m_isDialog = false; + m_needsScaling = true; + m_windowLoaded = false; + m_loadOnDemand = true; + m_renderOrder = 0; + m_dynamicResourceAlloc = true; + m_previousWindow = WINDOW_INVALID; + m_animationsEnabled = true; + m_manualRunActions = false; +} + +CGUIWindow::~CGUIWindow(void) +{} + +bool CGUIWindow::Load(const CStdString& strFileName, bool bContainsPath) +{ +#ifdef HAS_PERFORMANCE_SAMPLE + CPerformanceSample aSample("WindowLoad-" + strFileName, true); +#endif + + if (m_windowLoaded) + return true; // no point loading if it's already there + + LARGE_INTEGER start; + QueryPerformanceCounter(&start); + + RESOLUTION resToUse = RES_INVALID; + CLog::Log(LOGINFO, "Loading skin file: %s", strFileName.c_str()); + TiXmlDocument xmlDoc; + // Find appropriate skin folder + resolution to load from + CStdString strPath; + CStdString strLowerPath; + if (bContainsPath) + strPath = strFileName; + else + { + // FIXME: strLowerPath needs to eventually go since resToUse can get incorrectly overridden + strLowerPath = g_SkinInfo.GetSkinPath(CStdString(strFileName).ToLower(), &resToUse); + strPath = g_SkinInfo.GetSkinPath(strFileName, &resToUse); + } + + if (!bContainsPath) + m_coordsRes = resToUse; + + bool ret = LoadXML(strPath.c_str(), strLowerPath.c_str()); + + LARGE_INTEGER end, freq; + QueryPerformanceCounter(&end); + QueryPerformanceFrequency(&freq); + CLog::Log(LOGDEBUG,"Load %s: %.2fms", m_xmlFile.c_str(), 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart); + + return ret; +} + +bool CGUIWindow::LoadXML(const CStdString &strPath, const CStdString &strLowerPath) +{ + TiXmlDocument xmlDoc; + if ( !xmlDoc.LoadFile(strPath) && !xmlDoc.LoadFile(CStdString(strPath).ToLower()) && !xmlDoc.LoadFile(strLowerPath)) + { + CLog::Log(LOGERROR, "unable to load:%s, Line %d\n%s", strPath.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc()); + SetID(WINDOW_INVALID); + return false; + } + + return Load(xmlDoc); +} + +bool CGUIWindow::Load(TiXmlDocument &xmlDoc) +{ + TiXmlElement* pRootElement = xmlDoc.RootElement(); + if (strcmpi(pRootElement->Value(), "window")) + { + CLog::Log(LOGERROR, "file : XML file doesnt contain <window>"); + return false; + } + + // set the scaling resolution so that any control creation or initialisation can + // be done with respect to the correct aspect ratio + g_graphicsContext.SetScalingResolution(m_coordsRes, 0, 0, m_needsScaling); + + // Resolve any includes that may be present + g_SkinInfo.ResolveIncludes(pRootElement); + // now load in the skin file + SetDefaults(); + + + CGUIControlFactory::GetMultipleString(pRootElement, "onload", m_loadActions); + CGUIControlFactory::GetMultipleString(pRootElement, "onunload", m_unloadActions); + + TiXmlElement *pChild = pRootElement->FirstChildElement(); + while (pChild) + { + CStdString strValue = pChild->Value(); + if (strValue == "type" && pChild->FirstChild()) + { + // if we have are a window type (ie not a dialog), and we have <type>dialog</type> + // then make this window act like a dialog + if (!IsDialog() && strcmpi(pChild->FirstChild()->Value(), "dialog") == 0) + m_isDialog = true; + } + else if (strValue == "previouswindow" && pChild->FirstChild()) + { + m_previousWindow = CButtonTranslator::TranslateWindowString(pChild->FirstChild()->Value()); + } + else if (strValue == "defaultcontrol" && pChild->FirstChild()) + { + const char *always = pChild->Attribute("always"); + if (always && strcmpi(always, "true") == 0) + m_defaultAlways = true; + m_defaultControl = atoi(pChild->FirstChild()->Value()); + } + else if (strValue == "visible" && pChild->FirstChild()) + { + CGUIControlFactory::GetConditionalVisibility(pRootElement, m_visibleCondition); + } + else if (strValue == "animation" && pChild->FirstChild()) + { + FRECT rect = { 0, 0, (float)g_settings.m_ResInfo[m_coordsRes].iWidth, (float)g_settings.m_ResInfo[m_coordsRes].iHeight }; + CAnimation anim; + anim.Create(pChild, rect); + m_animations.push_back(anim); + } + else if (strValue == "zorder" && pChild->FirstChild()) + { + m_renderOrder = atoi(pChild->FirstChild()->Value()); + } + else if (strValue == "coordinates") + { + // resolve any includes within coordinates tag (such as multiple origin includes) + g_SkinInfo.ResolveIncludes(pChild); + TiXmlNode* pSystem = pChild->FirstChild("system"); + if (pSystem) + { + int iCoordinateSystem = atoi(pSystem->FirstChild()->Value()); + m_bRelativeCoords = (iCoordinateSystem == 1); + } + + CGUIControlFactory::GetFloat(pChild, "posx", m_posX); + CGUIControlFactory::GetFloat(pChild, "posy", m_posY); + + TiXmlElement *originElement = pChild->FirstChildElement("origin"); + while (originElement) + { + COrigin origin; + g_SkinInfo.ResolveConstant(originElement->Attribute("x"), origin.x); + g_SkinInfo.ResolveConstant(originElement->Attribute("y"), origin.y); + if (originElement->FirstChild()) + origin.condition = g_infoManager.TranslateString(originElement->FirstChild()->Value()); + m_origins.push_back(origin); + originElement = originElement->NextSiblingElement("origin"); + } + } + else if (strValue == "camera") + { // z is fixed + g_SkinInfo.ResolveConstant(pChild->Attribute("x"), m_camera.x); + g_SkinInfo.ResolveConstant(pChild->Attribute("y"), m_camera.y); + m_hasCamera = true; + } + else if (strValue == "controls") + { + // resolve any includes within controls tag (such as whole <control> includes) + g_SkinInfo.ResolveIncludes(pChild); + + TiXmlElement *pControl = pChild->FirstChildElement(); + while (pControl) + { + if (strcmpi(pControl->Value(), "control") == 0) + { + LoadControl(pControl, NULL); + } + pControl = pControl->NextSiblingElement(); + } + } + else if (strValue == "allowoverlay") + { + bool overlay = false; + if (XMLUtils::GetBoolean(pRootElement, "allowoverlay", overlay)) + m_overlayState = overlay ? OVERLAY_STATE_SHOWN : OVERLAY_STATE_HIDDEN; + } + + pChild = pChild->NextSiblingElement(); + } + LoadAdditionalTags(pRootElement); + + m_windowLoaded = true; + OnWindowLoaded(); + return true; +} + +void CGUIWindow::LoadControl(TiXmlElement* pControl, CGUIControlGroup *pGroup) +{ + // get control type + CGUIControlFactory factory; + + FRECT rect = { 0, 0, (float)g_settings.m_ResInfo[m_coordsRes].iWidth, (float)g_settings.m_ResInfo[m_coordsRes].iHeight }; + if (pGroup) + { + rect.left = pGroup->GetXPosition(); + rect.top = pGroup->GetYPosition(); + rect.right = rect.left + pGroup->GetWidth(); + rect.bottom = rect.top + pGroup->GetHeight(); + } + CGUIControl* pGUIControl = factory.Create(GetID(), rect, pControl); + if (pGUIControl) + { + float maxX = pGUIControl->GetXPosition() + pGUIControl->GetWidth(); + if (maxX > m_width) + { + m_width = maxX; + } + + float maxY = pGUIControl->GetYPosition() + pGUIControl->GetHeight(); + if (maxY > m_height) + { + m_height = maxY; + } + // if we are in a group, add to the group, else add to our window + if (pGroup) + pGroup->AddControl(pGUIControl); + else + AddControl(pGUIControl); + // if the new control is a group, then add it's controls + if (pGUIControl->IsGroup()) + { + TiXmlElement *pSubControl = pControl->FirstChildElement("control"); + while (pSubControl) + { + LoadControl(pSubControl, (CGUIControlGroup *)pGUIControl); + pSubControl = pSubControl->NextSiblingElement("control"); + } + } + } +} + +void CGUIWindow::OnWindowLoaded() +{ + DynamicResourceAlloc(true); +} + +void CGUIWindow::CenterWindow() +{ + if (m_bRelativeCoords) + { + m_posX = (g_settings.m_ResInfo[m_coordsRes].iWidth - GetWidth()) / 2; + m_posY = (g_settings.m_ResInfo[m_coordsRes].iHeight - GetHeight()) / 2; + } +} + +void CGUIWindow::Render() +{ + // If we're rendering from a different thread, then we should wait for the main + // app thread to finish AllocResources(), as dynamic resources (images in particular) + // will try and be allocated from 2 different threads, which causes nasty things + // to occur. + if (!m_bAllocated) return; + + // find our origin point + float posX = m_posX; + float posY = m_posY; + for (unsigned int i = 0; i < m_origins.size(); i++) + { + // no condition implies true + if (!m_origins[i].condition || g_infoManager.GetBool(m_origins[i].condition, GetID())) + { // found origin + posX = m_origins[i].x; + posY = m_origins[i].y; + break; + } + } + g_graphicsContext.SetRenderingResolution(m_coordsRes, posX, posY, m_needsScaling); + if (m_hasCamera) + g_graphicsContext.SetCameraPosition(m_camera); + + DWORD currentTime = timeGetTime(); + // render our window animation - returns false if it needs to stop rendering + if (!RenderAnimation(currentTime)) + return; + + for (iControls i = m_children.begin(); i != m_children.end(); ++i) + { + CGUIControl *pControl = *i; + if (pControl) + { + GUIPROFILER_VISIBILITY_BEGIN(pControl); + pControl->UpdateVisibility(); + GUIPROFILER_VISIBILITY_END(pControl); + pControl->DoRender(currentTime); + } + } + if (CGUIControlProfiler::IsRunning()) CGUIControlProfiler::Instance().EndFrame(); + m_hasRendered = true; +} + +void CGUIWindow::Close(bool forceClose) +{ + CLog::Log(LOGERROR,"%s - should never be called on the base class!", __FUNCTION__); +} + +bool CGUIWindow::OnAction(const CAction &action) +{ + if (action.id == ACTION_MOUSE) + return OnMouseAction(); + + CGUIControl *focusedControl = GetFocusedControl(); + if (focusedControl) + return focusedControl->OnAction(action); + + // no control has focus? + // set focus to the default control then + CGUIMessage msg(GUI_MSG_SETFOCUS, GetID(), m_defaultControl); + OnMessage(msg); + return false; +} + +// OnMouseAction - called by OnAction() +bool CGUIWindow::OnMouseAction() +{ + // we need to convert the mouse coordinates to window coordinates + float posX = m_posX; + float posY = m_posY; + for (unsigned int i = 0; i < m_origins.size(); i++) + { + // no condition implies true + if (!m_origins[i].condition || g_infoManager.GetBool(m_origins[i].condition, GetID())) + { // found origin + posX = m_origins[i].x; + posY = m_origins[i].y; + break; + } + } + g_graphicsContext.SetScalingResolution(m_coordsRes, posX, posY, m_needsScaling); + CPoint mousePoint(g_Mouse.GetLocation()); + g_graphicsContext.InvertFinalCoords(mousePoint.x, mousePoint.y); + m_transform.InverseTransformPosition(mousePoint.x, mousePoint.y); + + bool bHandled = false; + // check if we have exclusive access + if (g_Mouse.GetExclusiveWindowID() == GetID()) + { // we have exclusive access to the mouse... + CGUIControl *pControl = (CGUIControl *)GetControl(g_Mouse.GetExclusiveControlID()); + if (pControl) + { // this control has exclusive access to the mouse + HandleMouse(pControl, mousePoint + g_Mouse.GetExclusiveOffset()); + return true; + } + } + + // run through the controls, and unfocus all those that aren't under the pointer, + for (iControls i = m_children.begin(); i != m_children.end(); ++i) + { + CGUIControl *pControl = *i; + pControl->UnfocusFromPoint(mousePoint); + } + // and find which one is under the pointer + // go through in reverse order to make sure we start with the ones on top + bool controlUnderPointer(false); + for (vector<CGUIControl *>::reverse_iterator i = m_children.rbegin(); i != m_children.rend(); ++i) + { + CGUIControl *pControl = *i; + CGUIControl *focusableControl = NULL; + CPoint controlPoint; + if (pControl->CanFocusFromPoint(mousePoint, &focusableControl, controlPoint)) + { + controlUnderPointer = focusableControl->OnMouseOver(controlPoint); + bHandled = HandleMouse(focusableControl, controlPoint); + if (bHandled || controlUnderPointer) + break; + } + } + if (!bHandled) + { // haven't handled this action - call the window message handlers + bHandled = OnMouse(mousePoint); + } + // and unfocus everything otherwise + if (!controlUnderPointer) + m_focusedControl = 0; + + return bHandled; +} + +// Handles any mouse actions that are not handled by a control +// default is to go back a window on a right click. +// This function should be overridden for other windows +bool CGUIWindow::OnMouse(const CPoint &point) +{ + if (g_Mouse.bClick[MOUSE_RIGHT_BUTTON]) + { // no control found to absorb this click - go to previous menu + CAction action; + action.id = ACTION_PREVIOUS_MENU; + return OnAction(action); + } + return false; +} + +bool CGUIWindow::HandleMouse(CGUIControl *pControl, const CPoint &point) +{ + if (g_Mouse.bClick[MOUSE_LEFT_BUTTON]) + { // Left click + return pControl->OnMouseClick(MOUSE_LEFT_BUTTON, point); + } + else if (g_Mouse.bClick[MOUSE_RIGHT_BUTTON]) + { // Right click + return pControl->OnMouseClick(MOUSE_RIGHT_BUTTON, point); + } + else if (g_Mouse.bClick[MOUSE_MIDDLE_BUTTON]) + { // Middle click + return pControl->OnMouseClick(MOUSE_MIDDLE_BUTTON, point); + } + else if (g_Mouse.bDoubleClick[MOUSE_LEFT_BUTTON]) + { // Left double click + return pControl->OnMouseDoubleClick(MOUSE_LEFT_BUTTON, point); + } + else if (g_Mouse.bHold[MOUSE_LEFT_BUTTON] && g_Mouse.HasMoved(true)) + { // Mouse Drag + return pControl->OnMouseDrag(g_Mouse.GetLastMove(), point); + } + else if (g_Mouse.GetWheel()) + { // Mouse wheel + return pControl->OnMouseWheel(g_Mouse.GetWheel(), point); + } + // no mouse stuff done other than movement + return false; +} + +/// \brief Called on window open. +/// * Restores the control state(s) +/// * Sets initial visibility of controls +/// * Queue WindowOpen animation +/// * Set overlay state +/// Override this function and do any window-specific initialisation such +/// as filling control contents and setting control focus before +/// calling the base method. +void CGUIWindow::OnInitWindow() +{ + // set our rendered state + m_hasRendered = false; + ResetAnimations(); // we need to reset our animations as those windows that don't dynamically allocate + // need their anims reset. An alternative solution is turning off all non-dynamic + // allocation (which in some respects may be nicer, but it kills hdd spindown and the like) + + // set our initial control visibility before restoring control state and + // focusing the default control, and again afterward to make sure that + // any controls that depend on the state of the focused control (and or on + // control states) are active. + SetInitialVisibility(); + RestoreControlStates(); + SetInitialVisibility(); + QueueAnimation(ANIM_TYPE_WINDOW_OPEN); + m_gWindowManager.ShowOverlay(m_overlayState); + + if (!m_manualRunActions) + { + RunLoadActions(); + } +} + +// Called on window close. +// * Executes the window close animation(s) +// * Saves control state(s) +// Override this function and call the base class before doing any dynamic memory freeing +void CGUIWindow::OnDeinitWindow(int nextWindowID) +{ + if (!m_manualRunActions) + { + RunUnloadActions(); + } + + if (nextWindowID != WINDOW_FULLSCREEN_VIDEO) + { + // Dialog animations are handled in Close() rather than here + if (HasAnimation(ANIM_TYPE_WINDOW_CLOSE) && !IsDialog() && IsActive()) + { + // Perform the window out effect + QueueAnimation(ANIM_TYPE_WINDOW_CLOSE); + while (IsAnimating(ANIM_TYPE_WINDOW_CLOSE)) + { + m_gWindowManager.Process(true); + } + } + } + SaveControlStates(); +} + +bool CGUIWindow::OnMessage(CGUIMessage& message) +{ + switch ( message.GetMessage() ) + { + case GUI_MSG_WINDOW_INIT: + { + CLog::Log(LOGDEBUG, "------ Window Init (%s) ------", m_xmlFile.c_str()); + if (m_dynamicResourceAlloc || !m_bAllocated) AllocResources(); + OnInitWindow(); + return true; + } + break; + + case GUI_MSG_WINDOW_DEINIT: + { + CLog::Log(LOGDEBUG, "------ Window Deinit (%s) ------", m_xmlFile.c_str()); + OnDeinitWindow(message.GetParam1()); + // now free the window + if (m_dynamicResourceAlloc) FreeResources(); + return true; + } + break; + + case GUI_MSG_CLICKED: + { + // a specific control was clicked + CLICK_EVENT clickEvent = m_mapClickEvents[ message.GetSenderId() ]; + + // determine if there are any handlers for this event + if (clickEvent.HasAHandler()) + { + // fire the message to all handlers + clickEvent.Fire(message); + } + break; + } + + case GUI_MSG_SELCHANGED: + { + // a selection within a specific control has changed + SELECTED_EVENT selectedEvent = m_mapSelectedEvents[ message.GetSenderId() ]; + + // determine if there are any handlers for this event + if (selectedEvent.HasAHandler()) + { + // fire the message to all handlers + selectedEvent.Fire(message); + } + break; + } + case GUI_MSG_FOCUSED: + { // a control has been focused + if (HasID(message.GetSenderId())) + { + m_focusedControl = message.GetControlId(); + return true; + } + break; + } + case GUI_MSG_LOSTFOCUS: + { + // nothing to do at the window level when we lose focus + return true; + } + case GUI_MSG_MOVE: + { + if (HasID(message.GetSenderId())) + return OnMove(message.GetControlId(), message.GetParam1()); + break; + } + case GUI_MSG_SETFOCUS: + { +// CLog::Log(LOGDEBUG,"set focus to control:%i window:%i (%i)\n", message.GetControlId(),message.GetSenderId(), GetID()); + if ( message.GetControlId() ) + { + // first unfocus the current control + CGUIControl *control = GetFocusedControl(); + if (control) + { + CGUIMessage msgLostFocus(GUI_MSG_LOSTFOCUS, GetID(), control->GetID(), message.GetControlId()); + control->OnMessage(msgLostFocus); + } + + // get the control to focus + CGUIControl* pFocusedControl = GetFirstFocusableControl(message.GetControlId()); + if (!pFocusedControl) pFocusedControl = (CGUIControl *)GetControl(message.GetControlId()); + + // and focus it + if (pFocusedControl) + return pFocusedControl->OnMessage(message); + } + return true; + } + break; + case GUI_MSG_NOTIFY_ALL: + { + // only process those notifications that come from this window, or those intended for every window + if (HasID(message.GetSenderId()) || !message.GetSenderId()) + { + if (message.GetParam1() == GUI_MSG_PAGE_CHANGE || + message.GetParam1() == GUI_MSG_REFRESH_THUMBS || + message.GetParam1() == GUI_MSG_REFRESH_LIST) + { // alter the message accordingly, and send to all controls + for (iControls it = m_children.begin(); it != m_children.end(); ++it) + { + CGUIControl *control = *it; + CGUIMessage msg(message.GetParam1(), message.GetControlId(), control->GetID(), message.GetParam2()); + control->OnMessage(msg); + } + } + if (message.GetParam1() == GUI_MSG_INVALIDATE) + { + SetInvalid(); + return true; + } + } + } + break; + } + + return SendControlMessage(message); +} + +void CGUIWindow::AllocResources(bool forceLoad /*= FALSE */) +{ + CSingleLock lock(g_graphicsContext); + + LARGE_INTEGER start; + QueryPerformanceCounter(&start); + + // load skin xml file + bool bHasPath=false; + if (m_xmlFile.Find("\\") > -1 || m_xmlFile.Find("/") > -1 ) + bHasPath = true; + if (m_xmlFile.size() && (forceLoad || m_loadOnDemand || !m_windowLoaded)) + Load(m_xmlFile,bHasPath); + + LARGE_INTEGER slend; + QueryPerformanceCounter(&slend); + + // and now allocate resources + CGUIControlGroup::AllocResources(); + + LARGE_INTEGER end, freq; + QueryPerformanceCounter(&end); + QueryPerformanceFrequency(&freq); + CLog::Log(LOGDEBUG,"Alloc resources: %.2fms (%.2f ms skin load)", 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart, 1000.f * (slend.QuadPart - start.QuadPart) / freq.QuadPart); + + m_bAllocated = true; +} + +void CGUIWindow::FreeResources(bool forceUnload /*= FALSE */) +{ + m_bAllocated = false; + CGUIControlGroup::FreeResources(); + //g_TextureManager.Dump(); + // unload the skin + if (m_loadOnDemand || forceUnload) ClearAll(); +} + +void CGUIWindow::DynamicResourceAlloc(bool bOnOff) +{ + m_dynamicResourceAlloc = bOnOff; + CGUIControlGroup::DynamicResourceAlloc(bOnOff); +} + +void CGUIWindow::ClearAll() +{ + OnWindowUnload(); + CGUIControlGroup::ClearAll(); + m_windowLoaded = false; + m_dynamicResourceAlloc = true; +} + +bool CGUIWindow::Initialize() +{ + return Load(m_xmlFile); +} + +void CGUIWindow::SetInitialVisibility() +{ + // reset our info manager caches + g_infoManager.ResetCache(); + CGUIControlGroup::SetInitialVisibility(); +} + +bool CGUIWindow::IsActive() const +{ + return m_gWindowManager.IsWindowActive(GetID()); +} + +bool CGUIWindow::CheckAnimation(ANIMATION_TYPE animType) +{ + // special cases first + if (animType == ANIM_TYPE_WINDOW_CLOSE) + { + if (!m_bAllocated || !m_hasRendered) // can't render an animation if we aren't allocated or haven't rendered + return false; + // make sure we update our visibility prior to queuing the window close anim + for (unsigned int i = 0; i < m_children.size(); i++) + m_children[i]->UpdateVisibility(); + } + return true; +} + +bool CGUIWindow::IsAnimating(ANIMATION_TYPE animType) +{ + if (!m_animationsEnabled) + return false; + return CGUIControlGroup::IsAnimating(animType); +} + +bool CGUIWindow::RenderAnimation(DWORD time) +{ + g_graphicsContext.ResetWindowTransform(); + if (m_animationsEnabled) + CGUIControlGroup::Animate(time); + else + m_transform.Reset(); + return true; +} + +void CGUIWindow::DisableAnimations() +{ + m_animationsEnabled = false; +} + +// returns true if the control group with id groupID has controlID as +// its focused control +bool CGUIWindow::ControlGroupHasFocus(int groupID, int controlID) +{ + // 1. Run through and get control with groupID (assume unique) + // 2. Get it's selected item. + CGUIControl *group = GetFirstFocusableControl(groupID); + if (!group) group = (CGUIControl *)GetControl(groupID); + + if (group && group->IsGroup()) + { + if (controlID == 0) + { // just want to know if the group is focused + return group->HasFocus(); + } + else + { + CGUIMessage message(GUI_MSG_ITEM_SELECTED, GetID(), group->GetID()); + group->OnMessage(message); + return (controlID == (int) message.GetParam1()); + } + } + return false; +} + +void CGUIWindow::SaveControlStates() +{ + ResetControlStates(); + if (!m_defaultAlways) + m_lastControlID = GetFocusedControlID(); + for (iControls it = m_children.begin(); it != m_children.end(); ++it) + (*it)->SaveStates(m_controlStates); +} + +void CGUIWindow::RestoreControlStates() +{ + for (vector<CControlState>::iterator it = m_controlStates.begin(); it != m_controlStates.end(); ++it) + { + CGUIMessage message(GUI_MSG_ITEM_SELECT, GetID(), (*it).m_id, (*it).m_data); + OnMessage(message); + } + int focusControl = (!m_defaultAlways && m_lastControlID) ? m_lastControlID : m_defaultControl; + SET_CONTROL_FOCUS(focusControl, 0); +} + +void CGUIWindow::ResetControlStates() +{ + m_lastControlID = 0; + m_focusedControl = 0; + m_controlStates.clear(); +} + +bool CGUIWindow::OnMove(int fromControl, int moveAction) +{ + const CGUIControl *control = GetFirstFocusableControl(fromControl); + if (!control) control = GetControl(fromControl); + if (!control) + { // no current control?? + CLog::Log(LOGERROR, "Unable to find control %i in window %u", + fromControl, GetID()); + return false; + } + vector<int> moveHistory; + int nextControl = fromControl; + while (control) + { // grab the next control direction + moveHistory.push_back(nextControl); + nextControl = control->GetNextControl(moveAction); + // check our history - if the nextControl is in it, we can't focus it + for (unsigned int i = 0; i < moveHistory.size(); i++) + { + if (nextControl == moveHistory[i]) + return false; // no control to focus so do nothing + } + control = GetFirstFocusableControl(nextControl); + if (control) + break; // found a focusable control + control = GetControl(nextControl); // grab the next control and try again + } + if (!control) + return false; // no control to focus + // if we get here we have our new control so focus it (and unfocus the current control) + SET_CONTROL_FOCUS(nextControl, 0); + return true; +} + +void CGUIWindow::SetDefaults() +{ + m_renderOrder = 0; + m_defaultAlways = false; + m_defaultControl = 0; + m_bRelativeCoords = false; + m_posX = m_posY = m_width = m_height = 0; + m_overlayState = OVERLAY_STATE_PARENT_WINDOW; // Use parent or previous window's state + m_visibleCondition = 0; + m_previousWindow = WINDOW_INVALID; + m_animations.clear(); + m_origins.clear(); + m_hasCamera = false; + m_animationsEnabled = true; +} + +FRECT CGUIWindow::GetScaledBounds() const +{ + CSingleLock lock(g_graphicsContext); + g_graphicsContext.SetScalingResolution(m_coordsRes, m_posX, m_posY, m_needsScaling); + FRECT rect = {0, 0, m_width, m_height}; + float z = 0; + g_graphicsContext.ScaleFinalCoords(rect.left, rect.top, z); + g_graphicsContext.ScaleFinalCoords(rect.right, rect.bottom, z); + return rect; +} + +void CGUIWindow::OnEditChanged(int id, CStdString &text) +{ + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), id); + OnMessage(msg); + text = msg.GetLabel(); +} + +bool CGUIWindow::SendMessage(int message, int id, int param1 /* = 0*/, int param2 /* = 0*/) +{ + CGUIMessage msg(message, GetID(), id, param1, param2); + return OnMessage(msg); +} + +#ifdef _DEBUG +void CGUIWindow::DumpTextureUse() +{ + CLog::Log(LOGDEBUG, "%s for window %u", __FUNCTION__, GetID()); + CGUIControlGroup::DumpTextureUse(); +} +#endif + +void CGUIWindow::ChangeButtonToEdit(int id, bool singleLabel /* = false*/) +{ +#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY + CGUIControl *name = (CGUIControl *)GetControl(id); + if (name && name->GetControlType() == CGUIControl::GUICONTROL_BUTTON) + { // change it to an edit control + CGUIEditControl *edit = new CGUIEditControl(*(const CGUIButtonControl *)name); + if (edit) + { + if (singleLabel) + edit->SetLabel(""); + InsertControl(edit, name); + RemoveControl(name); + name->FreeResources(); + delete name; + } + } +#endif +} + +void CGUIWindow::SetProperty(const CStdString &strKey, const char *strValue) +{ + m_mapProperties[strKey] = strValue; +} + +void CGUIWindow::SetProperty(const CStdString &strKey, const CStdString &strValue) +{ + m_mapProperties[strKey] = strValue; +} + +void CGUIWindow::SetProperty(const CStdString &strKey, int nVal) +{ + CStdString strVal; + strVal.Format("%d",nVal); + SetProperty(strKey, strVal); +} + +void CGUIWindow::SetProperty(const CStdString &strKey, bool bVal) +{ + SetProperty(strKey, bVal?"1":"0"); +} + +void CGUIWindow::SetProperty(const CStdString &strKey, double dVal) +{ + CStdString strVal; + strVal.Format("%f",dVal); + SetProperty(strKey, strVal); +} + +CStdString CGUIWindow::GetProperty(const CStdString &strKey) const +{ + std::map<CStdString,CStdString,icompare>::const_iterator iter = m_mapProperties.find(strKey); + if (iter == m_mapProperties.end()) + return ""; + + return iter->second; +} + +int CGUIWindow::GetPropertyInt(const CStdString &strKey) const +{ + return atoi(GetProperty(strKey).c_str()) ; +} + +bool CGUIWindow::GetPropertyBOOL(const CStdString &strKey) const +{ + return GetProperty(strKey) == "1"; +} + +double CGUIWindow::GetPropertyDouble(const CStdString &strKey) const +{ + return atof(GetProperty(strKey).c_str()) ; +} + +bool CGUIWindow::HasProperty(const CStdString &strKey) const +{ + std::map<CStdString,CStdString,icompare>::const_iterator iter = m_mapProperties.find(strKey); + if (iter == m_mapProperties.end()) + return FALSE; + + return TRUE; + } + +void CGUIWindow::ClearProperty(const CStdString &strKey) +{ + std::map<CStdString,CStdString,icompare>::iterator iter = m_mapProperties.find(strKey); + if (iter != m_mapProperties.end()) + m_mapProperties.erase(iter); +} + +void CGUIWindow::ClearProperties() +{ + m_mapProperties.clear(); +} + +void CGUIWindow::RunActions(std::vector<CGUIActionDescriptor>& actions) +{ + vector<CGUIActionDescriptor> tempActions = actions; + + // and execute our actions + for (unsigned int i = 0; i < tempActions.size(); i++) + { + CGUIMessage message(GUI_MSG_EXECUTE, 0, GetID()); + message.SetAction(tempActions[i]); + g_graphicsContext.SendMessage(message); + } +} + +void CGUIWindow::SetRunActionsManually() +{ + m_manualRunActions = true; +} + +void CGUIWindow::RunLoadActions() +{ + RunActions(m_loadActions); +} + +void CGUIWindow::RunUnloadActions() +{ + RunActions(m_unloadActions); +} |