Cursor.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. extern const char* UI_CATEGORY;
  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>(UI_CATEGORY);
  75. COPY_BASE_ATTRIBUTES(Cursor, BorderImage);
  76. UPDATE_ATTRIBUTE_DEFAULT_VALUE(Cursor, "Priority", M_MAX_INT);
  77. ACCESSOR_ATTRIBUTE(Cursor, VAR_VARIANTVECTOR, "Shapes", GetShapesAttr, SetShapesAttr, VariantVector, Variant::emptyVariantVector, AM_FILE);
  78. }
  79. void Cursor::DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot, bool osMouseVisible)
  80. {
  81. if (!image)
  82. return;
  83. ResourceCache* cache = GetSubsystem<ResourceCache>();
  84. CursorShapeInfo& info = shapeInfos_[shape];
  85. // Prefer to get the texture with same name from cache to prevent creating several copies of the texture
  86. if (cache->Exists(image->GetName()))
  87. info.texture_ = cache->GetResource<Texture2D>(image->GetName());
  88. else
  89. {
  90. Texture2D* texture = new Texture2D(context_);
  91. texture->Load(SharedPtr<Image>(image));
  92. info.texture_ = texture;
  93. }
  94. info.imageRect_ = imageRect;
  95. info.hotSpot_ = hotSpot;
  96. if (info.osCursor_)
  97. {
  98. SDL_FreeCursor(info.osCursor_);
  99. info.osCursor_ = 0;
  100. }
  101. if (osMouseVisible)
  102. {
  103. unsigned comp = image->GetComponents();
  104. int imageWidth = image->GetWidth();
  105. int width = imageRect.Width();
  106. int height = imageRect.Height();
  107. // Assume little-endian for all the supported platforms
  108. unsigned rMask = 0x000000ff;
  109. unsigned gMask = 0x0000ff00;
  110. unsigned bMask = 0x00ff0000;
  111. unsigned aMask = 0xff000000;
  112. SDL_Surface* surface = (comp >= 3 ? SDL_CreateRGBSurface(0, width, height, comp * 8, rMask, gMask, bMask, aMask) : 0);
  113. if (surface)
  114. {
  115. unsigned char* destination = reinterpret_cast<unsigned char*>(surface->pixels);
  116. unsigned char* source = image->GetData() + comp * (imageWidth * imageRect.top_ + imageRect.left_);
  117. for (int i = 0; i < height; ++i)
  118. {
  119. memcpy(destination, source, comp * width);
  120. destination += comp * width;
  121. source += comp * imageWidth;
  122. }
  123. info.osCursor_ = SDL_CreateColorCursor(surface, info.hotSpot_.x_, info.hotSpot_.y_);
  124. SDL_FreeSurface(surface);
  125. }
  126. }
  127. // Reset current shape if it was edited
  128. if (shape == shape_)
  129. {
  130. shape_ = CS_MAX_SHAPES;
  131. SetShape(shape);
  132. }
  133. }
  134. void Cursor::SetShape(CursorShape shape)
  135. {
  136. if (shape == shape_ || shape < CS_NORMAL || shape >= CS_MAX_SHAPES)
  137. return;
  138. shape_ = shape;
  139. CursorShapeInfo& info = shapeInfos_[shape_];
  140. texture_ = info.texture_;
  141. imageRect_ = info.imageRect_;
  142. SetSize(info.imageRect_.Size());
  143. if (info.osCursor_)
  144. SDL_SetCursor(info.osCursor_);
  145. }
  146. void Cursor::SetShapesAttr(VariantVector value)
  147. {
  148. unsigned index = 0;
  149. if (!value.Size())
  150. return;
  151. Input* input = GetSubsystem<Input>();
  152. bool osMouseVisible = input->IsMouseVisible();
  153. unsigned numShapes = value[index++].GetUInt();
  154. while (numShapes-- && (index + 4) <= value.Size())
  155. {
  156. CursorShape shape = (CursorShape)GetStringListIndex(value[index++].GetString().CString(), shapeNames, CS_MAX_SHAPES);
  157. if (shape != CS_MAX_SHAPES)
  158. {
  159. ResourceRef ref = value[index++].GetResourceRef();
  160. IntRect imageRect = value[index++].GetIntRect();
  161. IntVector2 hotSpot = value[index++].GetIntVector2();
  162. DefineShape(shape, GetSubsystem<ResourceCache>()->GetResource<Image>(ref.id_), imageRect, hotSpot, osMouseVisible);
  163. }
  164. else
  165. index += 3;
  166. }
  167. }
  168. VariantVector Cursor::GetShapesAttr() const
  169. {
  170. VariantVector ret;
  171. unsigned numShapes = 0;
  172. for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
  173. {
  174. if (shapeInfos_[i].imageRect_ != IntRect::ZERO)
  175. ++numShapes;
  176. }
  177. ret.Push(numShapes);
  178. for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
  179. {
  180. if (shapeInfos_[i].imageRect_ != IntRect::ZERO)
  181. {
  182. ret.Push(String(shapeNames[i]));
  183. ret.Push(GetResourceRef(shapeInfos_[i].texture_, Texture2D::GetTypeStatic()));
  184. ret.Push(shapeInfos_[i].imageRect_);
  185. ret.Push(shapeInfos_[i].hotSpot_);
  186. }
  187. }
  188. return ret;
  189. }
  190. void Cursor::GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexData, const IntRect& currentScissor)
  191. {
  192. unsigned initialSize = vertexData.Size();
  193. const IntVector2& offset = shapeInfos_[shape_].hotSpot_;
  194. Vector2 floatOffset(-(float)offset.x_, -(float)offset.y_);
  195. BorderImage::GetBatches(batches, vertexData, currentScissor);
  196. for (unsigned i = initialSize; i < vertexData.Size(); i += 6)
  197. {
  198. vertexData[i] += floatOffset.x_;
  199. vertexData[i + 1] += floatOffset.y_;
  200. }
  201. }
  202. }