2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GUIButtonControl.h"
11 #include "GUIFontManager.h"
12 #include "input/actions/Action.h"
13 #include "input/actions/ActionIDs.h"
14 #include "input/mouse/MouseEvent.h"
18 CGUIButtonControl::CGUIButtonControl(int parentID
,
24 const CTextureInfo
& textureFocus
,
25 const CTextureInfo
& textureNoFocus
,
26 const CLabelInfo
& labelInfo
,
28 : CGUIControl(parentID
, controlID
, posX
, posY
, width
, height
),
29 m_imgFocus(CGUITexture::CreateTexture(posX
, posY
, width
, height
, textureFocus
)),
30 m_imgNoFocus(CGUITexture::CreateTexture(posX
, posY
, width
, height
, textureNoFocus
)),
36 wrapMultiline
? CGUILabel::OVER_FLOW_WRAP
: CGUILabel::OVER_FLOW_TRUNCATE
),
37 m_label2(posX
, posY
, width
, height
, labelInfo
)
44 ControlType
= GUICONTROL_BUTTON
;
47 CGUIButtonControl::CGUIButtonControl(const CGUIButtonControl
& control
)
48 : CGUIControl(control
),
49 m_imgFocus(control
.m_imgFocus
->Clone()),
50 m_imgNoFocus(control
.m_imgNoFocus
->Clone()),
51 m_focusCounter(control
.m_focusCounter
),
52 m_alpha(control
.m_alpha
),
53 m_minWidth(control
.m_minWidth
),
54 m_maxWidth(control
.m_maxWidth
),
55 m_info(control
.m_info
),
56 m_info2(control
.m_info2
),
57 m_label(control
.m_label
),
58 m_label2(control
.m_label2
),
59 m_clickActions(control
.m_clickActions
),
60 m_focusActions(control
.m_focusActions
),
61 m_unfocusActions(control
.m_unfocusActions
),
62 m_bSelected(control
.m_bSelected
)
66 void CGUIButtonControl::Process(unsigned int currentTime
, CDirtyRegionList
&dirtyregions
)
68 ProcessText(currentTime
);
71 m_imgFocus
->SetWidth(GetWidth());
72 m_imgFocus
->SetHeight(m_height
);
74 m_imgNoFocus
->SetWidth(GetWidth());
75 m_imgNoFocus
->SetHeight(m_height
);
80 unsigned int alphaChannel
= m_alpha
;
83 unsigned int alphaCounter
= m_focusCounter
+ 2;
84 if ((alphaCounter
% 128) >= 64)
85 alphaChannel
= alphaCounter
% 64;
87 alphaChannel
= 63 - (alphaCounter
% 64);
90 alphaChannel
= (unsigned int)((float)m_alpha
* (float)alphaChannel
/ 255.0f
);
92 if (m_imgFocus
->SetAlpha((unsigned char)alphaChannel
))
95 m_imgFocus
->SetVisible(true);
96 m_imgNoFocus
->SetVisible(false);
101 m_imgFocus
->SetVisible(false);
102 m_imgNoFocus
->SetVisible(true);
105 m_imgFocus
->Process(currentTime
);
106 m_imgNoFocus
->Process(currentTime
);
108 CGUIControl::Process(currentTime
, dirtyregions
);
111 void CGUIButtonControl::Render()
113 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetRenderOrder() ==
114 RENDER_ORDER_FRONT_TO_BACK
)
116 m_imgNoFocus
->Render();
117 m_imgFocus
->Render(-1);
121 m_imgFocus
->Render(-1);
122 m_imgNoFocus
->Render();
126 CGUIControl::Render();
129 void CGUIButtonControl::RenderText()
131 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetRenderOrder() ==
132 RENDER_ORDER_FRONT_TO_BACK
)
138 CGUILabel::COLOR
CGUIButtonControl::GetTextColor() const
141 return CGUILabel::COLOR_DISABLED
;
143 return CGUILabel::COLOR_FOCUSED
;
144 return CGUILabel::COLOR_TEXT
;
147 #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
148 float CGUIButtonControl::GetWidth() const
150 if (m_minWidth
&& m_minWidth
!= m_width
)
152 float txtWidth
= m_label
.GetTextWidth() + 2 * m_label
.GetLabelInfo().offsetX
;
153 if (m_label2
.GetTextWidth())
155 static const float min_space
= 10;
156 txtWidth
+= m_label2
.GetTextWidth() + 2 * m_label2
.GetLabelInfo().offsetX
+ min_space
;
158 float maxWidth
= m_maxWidth
? m_maxWidth
: txtWidth
;
159 return CLAMP(txtWidth
, m_minWidth
, maxWidth
);
164 void CGUIButtonControl::SetMinWidth(float minWidth
)
166 if (m_minWidth
!= minWidth
)
169 m_minWidth
= minWidth
;
172 void CGUIButtonControl::ProcessText(unsigned int currentTime
)
174 CRect labelRenderRect
= m_label
.GetRenderRect();
175 CRect label2RenderRect
= m_label2
.GetRenderRect();
177 float renderWidth
= GetWidth();
178 float renderTextWidth
= renderWidth
;
179 if (m_labelMaxWidth
> 0 && m_labelMaxWidth
< renderWidth
)
180 renderTextWidth
= m_labelMaxWidth
;
182 bool changed
= m_label
.SetMaxRect(m_posX
, m_posY
, renderTextWidth
, m_height
);
183 changed
|= m_label
.SetText(m_info
.GetLabel(m_parentID
));
184 changed
|= m_label
.SetScrolling(HasFocus());
185 changed
|= m_label2
.SetMaxRect(m_posX
, m_posY
, renderTextWidth
, m_height
);
186 changed
|= m_label2
.SetText(m_info2
.GetLabel(m_parentID
));
188 // text changed - images need resizing
189 if (m_minWidth
&& (m_label
.GetRenderRect() != labelRenderRect
))
192 // auto-width - adjust hitrect
193 if (m_minWidth
&& m_width
!= renderWidth
)
195 CRect rect
{m_posX
, m_posY
, m_posX
+ renderWidth
, m_posY
+ m_height
};
196 SetHitRect(rect
, m_hitColor
);
199 // render the second label if it exists
200 if (!m_info2
.GetLabel(m_parentID
).empty())
202 changed
|= m_label2
.SetAlign(XBFONT_RIGHT
| (m_label
.GetLabelInfo().align
& XBFONT_CENTER_Y
) | XBFONT_TRUNCATED
);
203 changed
|= m_label2
.SetScrolling(HasFocus());
205 // If overlapping was corrected - compare render rects to determine
206 // if they changed since last frame.
207 if (CGUILabel::CheckAndCorrectOverlap(m_label
, m_label2
))
208 changed
|= (m_label
.GetRenderRect() != labelRenderRect
||
209 m_label2
.GetRenderRect() != label2RenderRect
);
211 changed
|= m_label2
.SetColor(GetTextColor());
212 changed
|= m_label2
.Process(currentTime
);
214 changed
|= m_label
.SetColor(GetTextColor());
215 changed
|= m_label
.Process(currentTime
);
220 bool CGUIButtonControl::OnAction(const CAction
&action
)
222 if (action
.GetID() == ACTION_SELECT_ITEM
)
227 return CGUIControl::OnAction(action
);
230 bool CGUIButtonControl::OnMessage(CGUIMessage
& message
)
232 if (message
.GetControlId() == GetID())
234 if (message
.GetMessage() == GUI_MSG_LABEL_SET
)
236 SetLabel(message
.GetLabel());
239 if (message
.GetMessage() == GUI_MSG_LABEL2_SET
)
241 SetLabel2(message
.GetLabel());
244 if (message
.GetMessage() == GUI_MSG_IS_SELECTED
)
246 message
.SetParam1(m_bSelected
? 1 : 0);
249 if (message
.GetMessage() == GUI_MSG_SET_SELECTED
)
256 if (message
.GetMessage() == GUI_MSG_SET_DESELECTED
)
265 return CGUIControl::OnMessage(message
);
268 void CGUIButtonControl::AllocResources()
270 CGUIControl::AllocResources();
272 m_imgFocus
->AllocResources();
273 m_imgNoFocus
->AllocResources();
275 m_width
= m_imgFocus
->GetWidth();
277 m_height
= m_imgFocus
->GetHeight();
280 void CGUIButtonControl::FreeResources(bool immediately
)
282 CGUIControl::FreeResources(immediately
);
283 m_imgFocus
->FreeResources(immediately
);
284 m_imgNoFocus
->FreeResources(immediately
);
287 void CGUIButtonControl::DynamicResourceAlloc(bool bOnOff
)
289 CGUIControl::DynamicResourceAlloc(bOnOff
);
290 m_imgFocus
->DynamicResourceAlloc(bOnOff
);
291 m_imgNoFocus
->DynamicResourceAlloc(bOnOff
);
294 void CGUIButtonControl::SetInvalid()
296 CGUIControl::SetInvalid();
297 m_label
.SetInvalid();
298 m_label2
.SetInvalid();
299 m_imgFocus
->SetInvalid();
300 m_imgNoFocus
->SetInvalid();
303 void CGUIButtonControl::SetLabel(const std::string
&label
)
304 { // NOTE: No fallback for buttons at this point
305 if (m_info
.GetLabel(GetParentID(), false) != label
)
307 m_info
.SetLabel(label
, "", GetParentID());
312 void CGUIButtonControl::SetLabel2(const std::string
&label2
)
313 { // NOTE: No fallback for buttons at this point
314 if (m_info2
.GetLabel(GetParentID(), false) != label2
)
316 m_info2
.SetLabel(label2
, "", GetParentID());
321 void CGUIButtonControl::SetPosition(float posX
, float posY
)
323 CGUIControl::SetPosition(posX
, posY
);
324 m_imgFocus
->SetPosition(posX
, posY
);
325 m_imgNoFocus
->SetPosition(posX
, posY
);
328 void CGUIButtonControl::SetAlpha(unsigned char alpha
)
330 if (m_alpha
!= alpha
)
335 bool CGUIButtonControl::UpdateColors(const CGUIListItem
* item
)
337 bool changed
= CGUIControl::UpdateColors(nullptr);
338 changed
|= m_label
.UpdateColors();
339 changed
|= m_label2
.UpdateColors();
340 changed
|= m_imgFocus
->SetDiffuseColor(m_diffuseColor
);
341 changed
|= m_imgNoFocus
->SetDiffuseColor(m_diffuseColor
);
346 CRect
CGUIButtonControl::CalcRenderRegion() const
348 CRect buttonRect
= CGUIControl::CalcRenderRegion();
349 CRect textRect
= m_label
.GetRenderRect();
350 buttonRect
.Union(textRect
);
354 EVENT_RESULT
CGUIButtonControl::OnMouseEvent(const CPoint
& point
, const MOUSE::CMouseEvent
& event
)
356 if (event
.m_id
== ACTION_MOUSE_LEFT_CLICK
)
358 OnAction(CAction(ACTION_SELECT_ITEM
));
359 return EVENT_RESULT_HANDLED
;
361 return EVENT_RESULT_UNHANDLED
;
364 std::string
CGUIButtonControl::GetDescription() const
366 std::string
strLabel(m_info
.GetLabel(m_parentID
));
370 std::string
CGUIButtonControl::GetLabel2() const
372 std::string
strLabel(m_info2
.GetLabel(m_parentID
));
376 void CGUIButtonControl::PythonSetLabel(const std::string
& strFont
,
377 const std::string
& strText
,
378 KODI::UTILS::COLOR::Color textColor
,
379 KODI::UTILS::COLOR::Color shadowColor
,
380 KODI::UTILS::COLOR::Color focusedColor
)
382 m_label
.GetLabelInfo().font
= g_fontManager
.GetFont(strFont
);
383 m_label
.GetLabelInfo().textColor
= textColor
;
384 m_label
.GetLabelInfo().focusedColor
= focusedColor
;
385 m_label
.GetLabelInfo().shadowColor
= shadowColor
;
389 void CGUIButtonControl::PythonSetDisabledColor(KODI::UTILS::COLOR::Color disabledColor
)
391 m_label
.GetLabelInfo().disabledColor
= disabledColor
;
394 void CGUIButtonControl::OnClick()
396 // Save values, as the click message may deactivate the window
397 int controlID
= GetID();
398 int parentID
= GetParentID();
399 CGUIAction clickActions
= m_clickActions
;
401 // button selected, send a message
402 CGUIMessage
msg(GUI_MSG_CLICKED
, controlID
, parentID
, 0);
403 SendWindowMessage(msg
);
405 clickActions
.ExecuteActions(controlID
, parentID
);
408 void CGUIButtonControl::OnFocus()
410 m_focusActions
.ExecuteActions(GetID(), GetParentID());
413 void CGUIButtonControl::OnUnFocus()
415 m_unfocusActions
.ExecuteActions(GetID(), GetParentID());
418 void CGUIButtonControl::SetSelected(bool bSelected
)
420 if (m_bSelected
!= bSelected
)
422 m_bSelected
= bSelected
;