Cursor.cpp 7.2 KB

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