1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "GUIResizeControl.h"
10 
11 #include "GUIMessage.h"
12 #include "input/Key.h"
13 #include "utils/TimeUtils.h"
14 
15 // time to reset accelerated cursors (digital movement)
16 #define MOVE_TIME_OUT 500L
17 
CGUIResizeControl(int parentID,int controlID,float posX,float posY,float width,float height,const CTextureInfo & textureFocus,const CTextureInfo & textureNoFocus)18 CGUIResizeControl::CGUIResizeControl(int parentID,
19                                      int controlID,
20                                      float posX,
21                                      float posY,
22                                      float width,
23                                      float height,
24                                      const CTextureInfo& textureFocus,
25                                      const CTextureInfo& textureNoFocus)
26   : CGUIControl(parentID, controlID, posX, posY, width, height),
27     m_imgFocus(CGUITexture::CreateTexture(posX, posY, width, height, textureFocus)),
28     m_imgNoFocus(CGUITexture::CreateTexture(posX, posY, width, height, textureNoFocus))
29 {
30   m_frameCounter = 0;
31   m_lastMoveTime = 0;
32   m_fSpeed = 1.0;
33   m_fAnalogSpeed = 2.0f; //! @todo implement correct analog speed
34   m_fAcceleration = 0.2f; //! @todo implement correct computation of acceleration
35   m_fMaxSpeed = 10.0;  //! @todo implement correct computation of maxspeed
36   ControlType = GUICONTROL_RESIZE;
37   SetLimits(0, 0, 720, 576); // defaults
38   m_nDirection = DIRECTION_NONE;
39 }
40 
CGUIResizeControl(const CGUIResizeControl & control)41 CGUIResizeControl::CGUIResizeControl(const CGUIResizeControl& control)
42   : CGUIControl(control),
43     m_imgFocus(control.m_imgFocus->Clone()),
44     m_imgNoFocus(control.m_imgNoFocus->Clone()),
45     m_frameCounter(control.m_frameCounter),
46     m_lastMoveTime(control.m_lastMoveTime),
47     m_nDirection(control.m_nDirection),
48     m_fSpeed(control.m_fSpeed),
49     m_fAnalogSpeed(control.m_fAnalogSpeed),
50     m_fMaxSpeed(control.m_fMaxSpeed),
51     m_fAcceleration(control.m_fAcceleration),
52     m_x1(control.m_x1),
53     m_x2(control.m_x2),
54     m_y1(control.m_y1),
55     m_y2(control.m_y2)
56 {
57 }
58 
Process(unsigned int currentTime,CDirtyRegionList & dirtyregions)59 void CGUIResizeControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
60 {
61   if (m_bInvalidated)
62   {
63     m_imgFocus->SetWidth(m_width);
64     m_imgFocus->SetHeight(m_height);
65 
66     m_imgNoFocus->SetWidth(m_width);
67     m_imgNoFocus->SetHeight(m_height);
68   }
69   if (HasFocus())
70   {
71     unsigned int alphaCounter = m_frameCounter + 2;
72     unsigned int alphaChannel;
73     if ((alphaCounter % 128) >= 64)
74       alphaChannel = alphaCounter % 64;
75     else
76       alphaChannel = 63 - (alphaCounter % 64);
77 
78     alphaChannel += 192;
79     if (SetAlpha( (unsigned char)alphaChannel ))
80       MarkDirtyRegion();
81     m_imgFocus->SetVisible(true);
82     m_imgNoFocus->SetVisible(false);
83     m_frameCounter++;
84   }
85   else
86   {
87     if (SetAlpha(0xff))
88       MarkDirtyRegion();
89     m_imgFocus->SetVisible(false);
90     m_imgNoFocus->SetVisible(true);
91   }
92   m_imgFocus->Process(currentTime);
93   m_imgNoFocus->Process(currentTime);
94   CGUIControl::Process(currentTime, dirtyregions);
95 }
96 
Render()97 void CGUIResizeControl::Render()
98 {
99   m_imgFocus->Render();
100   m_imgNoFocus->Render();
101   CGUIControl::Render();
102 }
103 
OnAction(const CAction & action)104 bool CGUIResizeControl::OnAction(const CAction &action)
105 {
106   if (action.GetID() == ACTION_SELECT_ITEM)
107   {
108     // button selected - send message to parent
109     CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID());
110     SendWindowMessage(message);
111     return true;
112   }
113   if (action.GetID() == ACTION_ANALOG_MOVE)
114   {
115     Resize(m_fAnalogSpeed*action.GetAmount(), -m_fAnalogSpeed*action.GetAmount(1));
116     return true;
117   }
118   return CGUIControl::OnAction(action);
119 }
120 
OnUp()121 void CGUIResizeControl::OnUp()
122 {
123   UpdateSpeed(DIRECTION_UP);
124   Resize(0, -m_fSpeed);
125 }
126 
OnDown()127 void CGUIResizeControl::OnDown()
128 {
129   UpdateSpeed(DIRECTION_DOWN);
130   Resize(0, m_fSpeed);
131 }
132 
OnLeft()133 void CGUIResizeControl::OnLeft()
134 {
135   UpdateSpeed(DIRECTION_LEFT);
136   Resize(-m_fSpeed, 0);
137 }
138 
OnRight()139 void CGUIResizeControl::OnRight()
140 {
141   UpdateSpeed(DIRECTION_RIGHT);
142   Resize(m_fSpeed, 0);
143 }
144 
OnMouseEvent(const CPoint & point,const CMouseEvent & event)145 EVENT_RESULT CGUIResizeControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
146 {
147   if (event.m_id == ACTION_MOUSE_DRAG)
148   {
149     if (event.m_state == 1)
150     { // grab exclusive access
151       CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
152       SendWindowMessage(msg);
153     }
154     else if (event.m_state == 3)
155     { // release exclusive access
156       CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
157       SendWindowMessage(msg);
158     }
159     Resize(event.m_offsetX, event.m_offsetY);
160     return EVENT_RESULT_HANDLED;
161   }
162   return EVENT_RESULT_UNHANDLED;
163 }
164 
UpdateSpeed(int nDirection)165 void CGUIResizeControl::UpdateSpeed(int nDirection)
166 {
167   if (CTimeUtils::GetFrameTime() - m_lastMoveTime > MOVE_TIME_OUT)
168   {
169     m_fSpeed = 1;
170     m_nDirection = DIRECTION_NONE;
171   }
172   m_lastMoveTime = CTimeUtils::GetFrameTime();
173   if (nDirection == m_nDirection)
174   { // accelerate
175     m_fSpeed += m_fAcceleration;
176     if (m_fSpeed > m_fMaxSpeed) m_fSpeed = m_fMaxSpeed;
177   }
178   else
179   { // reset direction and speed
180     m_fSpeed = 1;
181     m_nDirection = nDirection;
182   }
183 }
184 
AllocResources()185 void CGUIResizeControl::AllocResources()
186 {
187   CGUIControl::AllocResources();
188   m_frameCounter = 0;
189   m_imgFocus->AllocResources();
190   m_imgNoFocus->AllocResources();
191   m_width = m_imgFocus->GetWidth();
192   m_height = m_imgFocus->GetHeight();
193 }
194 
FreeResources(bool immediately)195 void CGUIResizeControl::FreeResources(bool immediately)
196 {
197   CGUIControl::FreeResources(immediately);
198   m_imgFocus->FreeResources(immediately);
199   m_imgNoFocus->FreeResources(immediately);
200 }
201 
DynamicResourceAlloc(bool bOnOff)202 void CGUIResizeControl::DynamicResourceAlloc(bool bOnOff)
203 {
204   CGUIControl::DynamicResourceAlloc(bOnOff);
205   m_imgFocus->DynamicResourceAlloc(bOnOff);
206   m_imgNoFocus->DynamicResourceAlloc(bOnOff);
207 }
208 
SetInvalid()209 void CGUIResizeControl::SetInvalid()
210 {
211   CGUIControl::SetInvalid();
212   m_imgFocus->SetInvalid();
213   m_imgNoFocus->SetInvalid();
214 }
215 
Resize(float x,float y)216 void CGUIResizeControl::Resize(float x, float y)
217 {
218   float width = m_width + x;
219   float height = m_height + y;
220   // check if we are within the bounds
221   if (width < m_x1) width = m_x1;
222   if (height < m_y1) height = m_y1;
223   if (width > m_x2) width = m_x2;
224   if (height > m_y2) height = m_y2;
225   // ok, now set the default size of the resize control
226   SetWidth(width);
227   SetHeight(height);
228 }
229 
SetPosition(float posX,float posY)230 void CGUIResizeControl::SetPosition(float posX, float posY)
231 {
232   CGUIControl::SetPosition(posX, posY);
233   m_imgFocus->SetPosition(posX, posY);
234   m_imgNoFocus->SetPosition(posX, posY);
235 }
236 
SetAlpha(unsigned char alpha)237 bool CGUIResizeControl::SetAlpha(unsigned char alpha)
238 {
239   return m_imgFocus->SetAlpha(alpha) | m_imgNoFocus->SetAlpha(alpha);
240 }
241 
UpdateColors()242 bool CGUIResizeControl::UpdateColors()
243 {
244   bool changed = CGUIControl::UpdateColors();
245   changed |= m_imgFocus->SetDiffuseColor(m_diffuseColor);
246   changed |= m_imgNoFocus->SetDiffuseColor(m_diffuseColor);
247 
248   return changed;
249 }
250 
SetLimits(float x1,float y1,float x2,float y2)251 void CGUIResizeControl::SetLimits(float x1, float y1, float x2, float y2)
252 {
253   m_x1 = x1;
254   m_y1 = y1;
255   m_x2 = x2;
256   m_y2 = y2;
257 }
258