Cursor.cpp 6.8 KB

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