2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "GUITextBox.h"
22 #include "GUIInfoManager.h"
23 #include "utils/XBMCTinyXML.h"
24 #include "utils/MathUtils.h"
28 CGUITextBox::CGUITextBox(int parentID, int controlID, float posX, float posY, float width, float height,
29 const CLabelInfo& labelInfo, int scrollTime)
30 : CGUIControl(parentID, controlID, posX, posY, width, height)
31 , CGUITextLayout(labelInfo.font, true)
39 ControlType = GUICONTROL_TEXTBOX;
42 m_scrollTime = scrollTime;
43 m_autoScrollCondition = 0;
45 m_autoScrollDelay = 3000;
46 m_autoScrollDelayTime = 0;
47 m_autoScrollRepeatAnim = NULL;
50 CGUITextBox::CGUITextBox(const CGUITextBox &from)
51 : CGUIControl(from), CGUITextLayout(from)
53 m_pageControl = from.m_pageControl;
54 m_scrollTime = from.m_scrollTime;
55 m_autoScrollCondition = from.m_autoScrollCondition;
56 m_autoScrollTime = from.m_autoScrollTime;
57 m_autoScrollDelay = from.m_autoScrollDelay;
58 m_autoScrollRepeatAnim = NULL;
59 if (from.m_autoScrollRepeatAnim)
60 m_autoScrollRepeatAnim = new CAnimation(*from.m_autoScrollRepeatAnim);
61 m_label = from.m_label;
70 m_autoScrollDelayTime = 0;
71 ControlType = GUICONTROL_TEXTBOX;
74 CGUITextBox::~CGUITextBox(void)
76 delete m_autoScrollRepeatAnim;
77 m_autoScrollRepeatAnim = NULL;
80 bool CGUITextBox::UpdateColors()
82 bool changed = CGUIControl::UpdateColors();
83 changed |= m_label.UpdateColors();
88 void CGUITextBox::UpdateInfo(const CGUIListItem *item)
90 m_textColor = m_label.textColor;
91 if (!CGUITextLayout::Update(item ? m_info.GetItemLabel(item) : m_info.GetLabel(m_parentID), m_width))
92 return; // nothing changed
94 // needed update, so reset to the top of the textbox and update our sizing/page control
100 m_itemHeight = m_font ? m_font->GetLineHeight() : 10;
101 m_itemsPerPage = (unsigned int)(m_height / m_itemHeight);
106 void CGUITextBox::DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions)
108 CGUIControl::DoProcess(currentTime, dirtyregions);
110 // if not visible, we reset the autoscroll timer and positioning
111 if (!IsVisible() && m_autoScrollTime)
113 ResetAutoScrolling();
114 m_lastRenderTime = 0;
121 void CGUITextBox::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
123 // update our auto-scrolling as necessary
124 if (m_autoScrollTime && m_lines.size() > m_itemsPerPage)
126 if (!m_autoScrollCondition || g_infoManager.GetBoolValue(m_autoScrollCondition))
128 if (m_lastRenderTime)
129 m_autoScrollDelayTime += currentTime - m_lastRenderTime;
130 if (m_autoScrollDelayTime > (unsigned int)m_autoScrollDelay && m_scrollSpeed == 0)
131 { // delay is finished - start scrolling
133 if (m_offset < (int)m_lines.size() - m_itemsPerPage)
134 ScrollToOffset(m_offset + 1, true);
136 { // at the end, run a delay and restart
137 if (m_autoScrollRepeatAnim)
139 if (m_autoScrollRepeatAnim->GetState() == ANIM_STATE_NONE)
140 m_autoScrollRepeatAnim->QueueAnimation(ANIM_PROCESS_NORMAL);
141 else if (m_autoScrollRepeatAnim->GetState() == ANIM_STATE_APPLIED)
142 { // reset to the start of the list and start the scrolling again
145 ResetAutoScrolling();
151 else if (m_autoScrollCondition)
152 ResetAutoScrolling(); // conditional is false, so reset the autoscrolling
155 // render the repeat anim as appropriate
156 if (m_autoScrollRepeatAnim)
158 if (m_autoScrollRepeatAnim->GetProcess() != ANIM_PROCESS_NONE)
160 m_autoScrollRepeatAnim->Animate(currentTime, true);
161 TransformMatrix matrix;
162 m_autoScrollRepeatAnim->RenderAnimation(matrix);
163 m_cachedTextMatrix = g_graphicsContext.AddTransform(matrix);
166 // update our scroll position as necessary
167 if (m_scrollSpeed != 0)
170 if (m_lastRenderTime)
171 m_scrollOffset += m_scrollSpeed * (currentTime - m_lastRenderTime);
172 if ((m_scrollSpeed < 0 && m_scrollOffset < m_offset * m_itemHeight) ||
173 (m_scrollSpeed > 0 && m_scrollOffset > m_offset * m_itemHeight))
175 m_scrollOffset = m_offset * m_itemHeight;
178 m_lastRenderTime = currentTime;
182 CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), m_pageControl, MathUtils::round_int(m_scrollOffset / m_itemHeight));
183 SendWindowMessage(msg);
186 CGUIControl::Process(currentTime, dirtyregions);
188 if (m_autoScrollRepeatAnim)
189 g_graphicsContext.RemoveTransform();
192 void CGUITextBox::Render()
194 // render the repeat anim as appropriate
195 if (m_autoScrollRepeatAnim)
196 g_graphicsContext.SetTransform(m_cachedTextMatrix);
198 if (g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height))
200 // we offset our draw position to take into account scrolling and whether or not our focused
201 // item is offscreen "above" the list.
202 int offset = (int)(m_scrollOffset / m_itemHeight);
204 float posY = m_posY + offset * m_itemHeight - m_scrollOffset;
206 // alignment correction
207 if (m_label.align & XBFONT_CENTER_X)
208 posX += m_width * 0.5f;
209 if (m_label.align & XBFONT_RIGHT)
215 int current = offset;
216 while (posY < m_posY + m_height && current < (int)m_lines.size())
218 uint32_t align = m_label.align;
219 if (m_lines[current].m_text.size() && m_lines[current].m_carriageReturn)
220 align &= ~XBFONT_JUSTIFIED; // last line of a paragraph shouldn't be justified
221 m_font->DrawText(posX, posY + 2, m_colors, m_label.shadowColor, m_lines[current].m_text, align, m_width);
222 posY += m_itemHeight;
228 g_graphicsContext.RestoreClipRegion();
230 if (m_autoScrollRepeatAnim)
231 g_graphicsContext.RemoveTransform();
232 CGUIControl::Render();
235 bool CGUITextBox::OnMessage(CGUIMessage& message)
237 if (message.GetControlId() == GetID())
239 if (message.GetMessage() == GUI_MSG_LABEL_SET)
243 ResetAutoScrolling();
244 CGUITextLayout::Reset();
245 m_info.SetLabel(message.GetLabel(), "", GetParentID());
248 if (message.GetMessage() == GUI_MSG_LABEL_RESET)
252 ResetAutoScrolling();
253 CGUITextLayout::Reset();
256 CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_itemsPerPage, m_lines.size());
257 SendWindowMessage(msg);
261 if (message.GetMessage() == GUI_MSG_PAGE_CHANGE)
263 if (message.GetSenderId() == m_pageControl)
265 Scroll(message.GetParam1());
271 return CGUIControl::OnMessage(message);
274 void CGUITextBox::UpdatePageControl()
278 CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_itemsPerPage, m_lines.size());
279 SendWindowMessage(msg);
283 bool CGUITextBox::CanFocus() const
288 void CGUITextBox::SetPageControl(int pageControl)
290 m_pageControl = pageControl;
293 void CGUITextBox::SetInfo(const CGUIInfoLabel &infoLabel)
298 void CGUITextBox::Scroll(unsigned int offset)
300 ResetAutoScrolling();
301 if (m_lines.size() <= m_itemsPerPage)
302 return; // no need to scroll
303 if (offset > m_lines.size() - m_itemsPerPage)
304 offset = m_lines.size() - m_itemsPerPage; // on last page
305 ScrollToOffset(offset);
308 void CGUITextBox::ScrollToOffset(int offset, bool autoScroll)
310 m_scrollOffset = m_offset * m_itemHeight;
311 int timeToScroll = autoScroll ? m_autoScrollTime : m_scrollTime;
312 m_scrollSpeed = (offset * m_itemHeight - m_scrollOffset) / timeToScroll;
316 void CGUITextBox::SetAutoScrolling(const TiXmlNode *node)
319 const TiXmlElement *scroll = node->FirstChildElement("autoscroll");
322 scroll->Attribute("delay", &m_autoScrollDelay);
323 scroll->Attribute("time", &m_autoScrollTime);
324 if (scroll->FirstChild())
325 m_autoScrollCondition = g_infoManager.Register(scroll->FirstChild()->ValueStr(), GetParentID());
327 if (scroll->Attribute("repeat", &repeatTime))
328 m_autoScrollRepeatAnim = new CAnimation(CAnimation::CreateFader(100, 0, repeatTime, 1000));
332 void CGUITextBox::ResetAutoScrolling()
334 m_autoScrollDelayTime = 0;
335 if (m_autoScrollRepeatAnim)
336 m_autoScrollRepeatAnim->ResetAnimation();
339 unsigned int CGUITextBox::GetRows() const
341 return m_lines.size();
344 int CGUITextBox::GetCurrentPage() const
346 if (m_offset + m_itemsPerPage >= GetRows()) // last page
347 return (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage;
348 return m_offset / m_itemsPerPage + 1;
351 CStdString CGUITextBox::GetLabel(int info) const
356 case CONTAINER_NUM_PAGES:
357 label.Format("%u", (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage);
359 case CONTAINER_CURRENT_PAGE:
360 label.Format("%u", GetCurrentPage());
368 void CGUITextBox::UpdateVisibility(const CGUIListItem *item)
370 // we have to update the page control when we become visible
371 // as another control may be sharing the same page control when we're
373 bool wasVisible = IsVisible();
374 CGUIControl::UpdateVisibility(item);
375 if (IsVisible() && !wasVisible)