Cursor.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "Cursor.h"
  25. #include "Input.h"
  26. #include "Ptr.h"
  27. #include "ResourceCache.h"
  28. #include "StringUtils.h"
  29. #include "Texture2D.h"
  30. #include "DebugNew.h"
  31. namespace Urho3D
  32. {
  33. static const char* shapeNames[] =
  34. {
  35. "Normal",
  36. "ResizeVertical",
  37. "ResizeDiagonalTopRight",
  38. "ResizeHorizontal",
  39. "ResizeDiagonalTopLeft",
  40. "AcceptDrop",
  41. "RejectDrop",
  42. "Busy",
  43. 0
  44. };
  45. OBJECTTYPESTATIC(Cursor);
  46. Cursor::Cursor(Context* context) :
  47. BorderImage(context),
  48. shape_(CS_NORMAL)
  49. {
  50. // Show on top of all other UI elements
  51. priority_ = M_MAX_INT;
  52. for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
  53. {
  54. CursorShapeInfo& info = shapeInfos_[i];
  55. info.imageRect_ = IntRect::ZERO;
  56. info.hotSpot_ = IntVector2::ZERO;
  57. info.osCursor_ = 0;
  58. }
  59. }
  60. Cursor::~Cursor()
  61. {
  62. for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
  63. {
  64. CursorShapeInfo& info = shapeInfos_[i];
  65. if (info.osCursor_)
  66. {
  67. SDL_FreeCursor(info.osCursor_);
  68. info.osCursor_ = 0;
  69. }
  70. }
  71. }
  72. void Cursor::RegisterObject(Context* context)
  73. {
  74. context->RegisterFactory<Cursor>();
  75. COPY_BASE_ATTRIBUTES(Cursor, BorderImage);
  76. ACCESSOR_ATTRIBUTE(Cursor, VAR_VARIANTVECTOR, "Shapes", GetShapesAttr, SetShapesAttr, VariantVector, Variant::emptyVariantVector, AM_FILE);
  77. }
  78. void Cursor::DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot, bool osMouseVisible)
  79. {
  80. if (!image)
  81. return;
  82. ResourceCache* cache = GetSubsystem<ResourceCache>();
  83. CursorShapeInfo& info = shapeInfos_[shape];
  84. // Prefer to get the texture with same name from cache to prevent creating several copies of the texture
  85. if (cache->Exists(image->GetName()))
  86. info.texture_ = cache->GetResource<Texture2D>(image->GetName());
  87. else
  88. {
  89. Texture2D* texture = new Texture2D(context_);
  90. texture->Load(SharedPtr<Image>(image));
  91. info.texture_ = texture;
  92. }
  93. info.imageRect_ = imageRect;
  94. info.hotSpot_ = hotSpot;
  95. if (info.osCursor_)
  96. {
  97. SDL_FreeCursor(info.osCursor_);
  98. info.osCursor_ = 0;
  99. }
  100. if (osMouseVisible)
  101. {
  102. unsigned comp = image->GetComponents();
  103. int imageWidth = image->GetWidth();
  104. int width = imageRect.Width();
  105. int height = imageRect.Height();
  106. // Assume little-endian for all the supported platforms
  107. unsigned rMask = 0x000000ff;
  108. unsigned gMask = 0x0000ff00;
  109. unsigned bMask = 0x00ff0000;
  110. unsigned aMask = 0xff000000;
  111. SDL_Surface* surface = (comp >= 3 ? SDL_CreateRGBSurface(0, width, height, comp * 8, rMask, gMask, bMask, aMask) : 0);
  112. if (surface)
  113. {
  114. unsigned char* destination = reinterpret_cast<unsigned char*>(surface->pixels);
  115. unsigned char* source = image->GetData() + comp * (imageWidth * imageRect.top_ + imageRect.left_);
  116. for (int i = 0; i < height; ++i)
  117. {
  118. memcpy(destination, source, comp * width);
  119. destination += comp * width;
  120. source += comp * imageWidth;
  121. }
  122. info.osCursor_ = SDL_CreateColorCursor(surface, info.hotSpot_.x_, info.hotSpot_.y_);
  123. SDL_FreeSurface(surface);
  124. }
  125. }
  126. // Reset current shape if it was edited
  127. if (shape == shape_)
  128. {
  129. shape_ = CS_MAX_SHAPES;
  130. SetShape(shape);
  131. }
  132. }
  133. void Cursor::SetShape(CursorShape shape)
  134. {
  135. if (shape == shape_ || shape < CS_NORMAL || shape >= CS_MAX_SHAPES)
  136. return;
  137. shape_ = shape;
  138. CursorShapeInfo& info = shapeInfos_[shape_];
  139. texture_ = info.texture_;
  140. imageRect_ = info.imageRect_;
  141. SetSize(info.imageRect_.Size());
  142. if (info.osCursor_)
  143. SDL_SetCursor(info.osCursor_);
  144. }
  145. void Cursor::SetShapesAttr(VariantVector value)
  146. {
  147. unsigned index = 0;
  148. if (!value.Size())
  149. return;
  150. Input* input = GetSubsystem<Input>();
  151. bool osMouseVisible = input->IsMouseVisible();
  152. unsigned numShapes = value[index++].GetUInt();
  153. while (numShapes-- && (index + 4) <= value.Size())
  154. {
  155. CursorShape shape = (CursorShape)GetStringListIndex(value[index++].GetString().CString(), shapeNames, CS_MAX_SHAPES);
  156. if (shape != CS_MAX_SHAPES)
  157. {
  158. ResourceRef ref = value[index++].GetResourceRef();
  159. IntRect imageRect = value[index++].GetIntRect();
  160. IntVector2 hotSpot = value[index++].GetIntVector2();
  161. DefineShape(shape, GetSubsystem<ResourceCache>()->GetResource<Image>(ref.id_), imageRect, hotSpot, osMouseVisible);
  162. }
  163. else
  164. index += 3;
  165. }
  166. }
  167. VariantVector Cursor::GetShapesAttr() const
  168. {
  169. VariantVector ret;
  170. unsigned numShapes = 0;
  171. for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
  172. {
  173. if (shapeInfos_[i].imageRect_ != IntRect::ZERO)
  174. ++numShapes;
  175. }
  176. ret.Push(numShapes);
  177. for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
  178. {
  179. if (shapeInfos_[i].imageRect_ != IntRect::ZERO)
  180. {
  181. ret.Push(String(shapeNames[i]));
  182. ret.Push(GetResourceRef(shapeInfos_[i].texture_, Texture2D::GetTypeStatic()));
  183. ret.Push(shapeInfos_[i].imageRect_);
  184. ret.Push(shapeInfos_[i].hotSpot_);
  185. }
  186. }
  187. return ret;
  188. }
  189. void Cursor::GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexData, const IntRect& currentScissor)
  190. {
  191. unsigned initialSize = vertexData.Size();
  192. const IntVector2& offset = shapeInfos_[shape_].hotSpot_;
  193. Vector2 floatOffset(-(float)offset.x_, -(float)offset.y_);
  194. BorderImage::GetBatches(batches, vertexData, currentScissor);
  195. for (unsigned i = initialSize; i < vertexData.Size(); i += 6)
  196. {
  197. vertexData[i] += floatOffset.x_;
  198. vertexData[i + 1] += floatOffset.y_;
  199. }
  200. }
  201. }