1 module fluid.backend.simpledisplay;
2 
3 version (Have_arsd_official_simpledisplay):
4 
5 debug (Fluid_BuildMessages) {
6     pragma(msg, "Fluid: Building with arsd.simpledisplay support");
7 }
8 
9 import arsd.simpledisplay;
10 
11 import std.algorithm;
12 import std.datetime.stopwatch;
13 
14 import fluid.backend;
15 
16 
17 @safe:
18 
19 
20 private {
21     alias Rectangle = fluid.backend.Rectangle;
22     alias Color = fluid.backend.Color;
23     alias Image = fluid.backend.Image;
24     alias MouseButton = fluid.backend.MouseButton;
25 }
26 
27 class SimpledisplayBackend : FluidBackend {
28 
29     SimpleWindow window;
30 
31     private enum InputState {
32         up,
33         pressed,
34         down,
35         released,
36         repeated,
37     }
38 
39     private {
40 
41         Vector2 _mousePosition;
42         int _dpi;
43         float _scale = 1;
44         bool _hasJustResized;
45         StopWatch _stopWatch;
46         float _deltaTime;
47         Rectangle _scissors;
48         bool _scissorsEnabled;
49         FluidMouseCursor _cursor;
50 
51         TextureReaper _reaper;
52 
53         /// Recent input events for each keyboard and mouse.
54         InputState[KeyboardKey.max+1] _keyboardState;
55         InputState[MouseButton.max+1] _mouseState;
56         // gamepads?
57 
58         /// Characters typed by the user, awaiting consumption.
59         const(dchar)[] _characterQueue;
60 
61         // Missing from simpledisplay at the time of writing
62         extern(C) void function(GLint x, GLint y, GLsizei width, GLsizei height) glScissor;
63 
64     }
65 
66     // TODO non-openGL backend, maybe...
67 
68     /// Initialize the backend using the given window.
69     ///
70     /// Make sure to call `SimpledisplayBackend.poll()` *after* the Fluid `draw` call, and only do it once per frame,
71     /// other Fluid might not be able to keep itself up to date with latest events.
72     ///
73     /// Please note Fluid will register its own event handlers, so if you
74     /// intend to use them, you should make sure to call whatever value was set previously.
75     ///
76     /// ---
77     /// auto oldMouseHandler = window.handleMouseEvent;
78     /// window.handleMouseEvent = (MouseEvent event) {
79     ///     oldMouseHandler(event);
80     ///     // ... do your stuff ...
81     /// };
82     /// ---
83     ///
84     /// Gamepad input is not supported for simpledisplay.
85     this(SimpleWindow window) {
86 
87         this.window = window;
88 
89         () @trusted {
90             this.glScissor = cast(typeof(glScissor)) glbindGetProcAddress("glScissor");
91         }();
92 
93         updateDPI();
94         _stopWatch.start();
95 
96         auto oldMouseHandler = window.handleMouseEvent;
97         auto oldKeyHandler = window.handleKeyEvent;
98         auto oldCharHandler = window.handleCharEvent;
99         auto oldWindowResized = window.windowResized;
100         auto oldOnDpiChanged = window.onDpiChanged;
101 
102         // Register a mouse handler
103         this.window.handleMouseEvent = (MouseEvent event) {
104 
105             if (oldMouseHandler) oldMouseHandler(event);
106 
107             final switch (event.type) {
108 
109                 // Update mouse position
110                 case event.type.motion:
111                     _mousePosition = Vector2(event.x, event.y);
112                     return;
113 
114                 // Update button state
115                 case event.type.buttonPressed:
116                     _mouseState[event.button.toFluid] = InputState.pressed;
117                     return;
118 
119                 case event.type.buttonReleased:
120                     _mouseState[event.button.toFluid] = InputState.released;
121                     return;
122 
123             }
124 
125         };
126 
127         // Register a keyboard handler
128         this.window.handleKeyEvent = (KeyEvent event) {
129 
130             if (oldKeyHandler) oldKeyHandler(event);
131 
132             const key = event.key.toFluid;
133 
134             // Released
135             if (!event.pressed)
136                 _keyboardState[key] = InputState.released;
137 
138             // Repeat
139             else if (isDown(key))
140                 _keyboardState[key] = InputState.repeated;
141 
142             // Pressed
143             else
144                 _keyboardState[key] = InputState.pressed;
145 
146         };
147 
148         // Register character handler
149         this.window.handleCharEvent = (dchar character) {
150 
151             import std.uni;
152 
153             if (oldCharHandler) oldCharHandler(character);
154 
155             // Ignore control characters
156             if (character.isControl) return;
157 
158             // Send new characters
159             _characterQueue ~= character;
160 
161         };
162 
163         // Register a resize handler
164         this.window.windowResized = (int width, int height) {
165 
166             if (oldWindowResized) oldWindowResized(width, height);
167 
168             // Update window size
169             _hasJustResized = true;
170             glViewport(0, 0, width, height);
171 
172         };
173 
174         this.window.onDpiChanged = () {
175 
176             if (oldOnDpiChanged) oldOnDpiChanged();
177 
178             // Update window size
179             _hasJustResized = true;
180             updateDPI();
181 
182         };
183 
184     }
185 
186     bool isPressed(MouseButton button) const {
187 
188         return _mouseState[button] == InputState.pressed;
189 
190     }
191 
192     bool isReleased(MouseButton button) const {
193 
194         return _mouseState[button] == InputState.released;
195 
196     }
197 
198     bool isDown(MouseButton button) const {
199 
200         return _mouseState[button].among(InputState.pressed, InputState.down) != 0;
201 
202     }
203 
204     bool isUp(MouseButton button) const {
205 
206         return _mouseState[button].among(InputState.released, InputState.up) != 0;
207 
208     }
209 
210     bool isPressed(KeyboardKey key) const {
211 
212         return _keyboardState[key] == InputState.pressed;
213 
214     }
215 
216     bool isReleased(KeyboardKey key) const {
217 
218         return _keyboardState[key] == InputState.released;
219 
220     }
221 
222     bool isDown(KeyboardKey key) const {
223 
224         return _keyboardState[key].among(InputState.pressed, InputState.repeated, InputState.down) != 0;
225 
226     }
227 
228     bool isUp(KeyboardKey key) const {
229 
230         return _keyboardState[key].among(InputState.released, InputState.up) != 0;
231 
232     }
233 
234     bool isRepeated(KeyboardKey key) const {
235 
236         return _keyboardState[key] == InputState.repeated;
237 
238     }
239 
240 
241     dchar inputCharacter() {
242 
243         // No characters in queue
244         if (_characterQueue.length == 0)
245             return '\0';
246 
247         // Pop the first character
248         auto result = _characterQueue[0];
249         _characterQueue = _characterQueue[1..$];
250         return result;
251 
252     }
253 
254     int isPressed(GamepadButton button) const
255         => 0;
256     int isReleased(GamepadButton button) const
257         => 0;
258     int isDown(GamepadButton button) const
259         => 0;
260     int isUp(GamepadButton button) const
261         => 1;
262     int isRepeated(GamepadButton button) const
263         => 0;
264 
265     private void updateDPI() @trusted {
266 
267         _dpi = either(window.actualDpi, 96);
268 
269     }
270 
271     /// Update event state. To be called *after* drawing.
272     void poll() {
273 
274         // Calculate delta time
275         _deltaTime = _stopWatch.peek.total!"msecs" / 1000f;
276         _stopWatch.reset();
277 
278         // Reset frame state
279         _hasJustResized = false;
280         _characterQueue = null;
281 
282         foreach (ref state; _keyboardState) {
283             if (state == state.pressed) state = state.down;
284             if (state == state.repeated) state = state.down;
285             if (state == state.released) state = state.up;
286         }
287 
288         foreach (ref state; _mouseState) {
289             if (state == state.pressed) state = state.down;
290             if (state == state.released) state = state.up;
291         }
292 
293     }
294 
295     Vector2 mousePosition(Vector2 position) @trusted {
296 
297         auto positionRay = toSdpyCoords(position);
298         window.warpMouse(cast(int) positionRay.x, cast(int) positionRay.y);
299         return _mousePosition = position;
300 
301     }
302 
303     Vector2 mousePosition() const @trusted {
304 
305         return toFluidCoords(_mousePosition);
306 
307     }
308 
309     float deltaTime() const @trusted {
310 
311         return _deltaTime;
312 
313     }
314 
315     bool hasJustResized() const @trusted {
316 
317         return _hasJustResized;
318 
319     }
320 
321     Vector2 windowSize(Vector2 size) @trusted {
322 
323         auto sizeRay = toSdpyCoords(size);
324         window.resize(cast(int) sizeRay.x, cast(int) sizeRay.y);
325         return size;
326 
327     }
328 
329     Vector2 windowSize() const @trusted {
330 
331         return toFluidCoords(Vector2(window.width, window.height));
332 
333     }
334 
335     /// Convert window coordinates to OpenGL coordinates; done *after* toSdpyCoords.
336     Vector2 toGL(Vector2 coords) {
337 
338         return Vector2(
339             coords.x / window.width * 2 - 1,
340             1 - coords.y / window.height * 2
341         );
342 
343     }
344 
345     /// Create a vertex at given screenspace position
346     void vertex(Vector2 coords) @trusted {
347 
348         glVertex2f(toGL(coords).tupleof);
349 
350     }
351 
352     float scale() const {
353 
354         return _scale;
355 
356     }
357 
358     float scale(float value) {
359 
360         return _scale = value;
361 
362     }
363 
364     Vector2 dpi() const @trusted {
365 
366         return Vector2(_dpi, _dpi) * scale;
367 
368     }
369 
370     Vector2 toSdpyCoords(Vector2 position) const @trusted {
371 
372         return Vector2(position.x * hidpiScale.x, position.y * hidpiScale.y);
373 
374     }
375 
376     Rectangle toSdpyCoords(Rectangle rec) const @trusted {
377 
378         return Rectangle(
379             rec.x * hidpiScale.x,
380             rec.y * hidpiScale.y,
381             rec.width * hidpiScale.x,
382             rec.height * hidpiScale.y,
383         );
384 
385     }
386 
387     Vector2 toFluidCoords(Vector2 position) const @trusted {
388 
389         return Vector2(position.x / hidpiScale.x, position.y / hidpiScale.y);
390 
391     }
392 
393     Vector2 toFluidCoords(float x, float y) const @trusted {
394 
395         return Vector2(x / hidpiScale.x, y / hidpiScale.y);
396 
397     }
398 
399     Rectangle toFluidCoords(Rectangle rec) const @trusted {
400 
401         return Rectangle(
402             rec.x / hidpiScale.x,
403             rec.y / hidpiScale.y,
404             rec.width / hidpiScale.x,
405             rec.height / hidpiScale.y,
406         );
407 
408     }
409 
410     Rectangle area(Rectangle rect) @trusted {
411 
412         auto rectRay = toSdpyCoords(rect);
413 
414         glEnable(GL_SCISSOR_TEST);
415         glScissor(
416             cast(int) rectRay.x,
417             cast(int) (window.height - rectRay.y - rectRay.height),
418             cast(int) rectRay.width,
419             cast(int) rectRay.height,
420         );
421         _scissorsEnabled = true;
422 
423         return _scissors = rect;
424 
425     }
426 
427     Rectangle area() const {
428 
429         if (_scissorsEnabled)
430             return _scissors;
431         else
432             return Rectangle(0, 0, windowSize.tupleof);
433 
434     }
435 
436     void restoreArea() @trusted {
437 
438         glDisable(GL_SCISSOR_TEST);
439         _scissorsEnabled = false;
440 
441     }
442 
443     FluidMouseCursor mouseCursor(FluidMouseCursor cursor) @trusted {
444 
445         // Hide the cursor
446         if (cursor.system == cursor.system.none) {
447             window.hideCursor();
448         }
449 
450         // Show the cursor
451         else {
452             window.showCursor();
453             window.cursor = cursor.toSimpleDisplay;
454         }
455 
456         return _cursor = cursor;
457 
458     }
459 
460     FluidMouseCursor mouseCursor() const {
461 
462         return _cursor;
463 
464     }
465 
466     TextureReaper* reaper() return scope {
467 
468         return &_reaper;
469 
470     }
471 
472     Texture loadTexture(Image image) @system {
473 
474         Texture result;
475         result.width = image.width;
476         result.height = image.height;
477 
478         // Create an OpenGL texture
479         glGenTextures(1, &result.id);
480         glBindTexture(GL_TEXTURE_2D, result.id);
481 
482         // Prepare the tombstone
483         result.tombstone = reaper.makeTombstone(this, result.id);
484 
485         // No filtering
486         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
487         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
488 
489         // Repeat on
490         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
491         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
492 
493         // Upload the data
494         glTexImage2D(
495 
496             // 2D texture, no mipmaps, four channels
497             GL_TEXTURE_2D, 0, GL_RGBA,
498 
499             // Size
500             image.width, image.height,
501 
502             // No border
503             0,
504 
505             // Formatted as R8B8G8A8
506             GL_RGBA, GL_UNSIGNED_BYTE, image.pixels.ptr,
507 
508         );
509 
510         // Unbind the texture
511         glBindTexture(GL_TEXTURE_2D, 0);
512 
513         return result;
514 
515     }
516 
517     Image loadImage(string filename) @system {
518 
519         version (Have_arsd_official_image_files) {
520 
521             import arsd.image;
522 
523             // Load the image
524             auto image = loadImageFromFile(filename).getAsTrueColorImage;
525 
526             // Convert to a Fluid image
527             Image result;
528             result.pixels = cast(Color[]) image.imageData.bytes;
529             result.width = image.width;
530             result.height = image.height;
531             return result;
532 
533         }
534 
535         else assert(false, "arsd-official:image_files is required to load images from files");
536 
537     }
538 
539     Texture loadTexture(string filename) @system {
540 
541         return loadTexture(loadImage(filename));
542 
543     }
544 
545     /// Destroy a texture
546     void unloadTexture(uint id) @system {
547 
548         if (id == 0) return;
549 
550         glDeleteTextures(1, &id);
551 
552     }
553 
554     private void openglDraw() @trusted {
555 
556         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
557         glEnable(GL_BLEND);
558         glLoadIdentity();
559 
560         // This must be present, otherwise the AMD Linux driver will hang when the window is resized. I don't have the
561         // slightest clue why.
562         if (auto error = glGetError()) {
563             import std.stdio;
564             debug writeln(error);
565         }
566 
567     }
568 
569     void drawLine(Vector2 start, Vector2 end, Color color) @trusted {
570 
571         openglDraw();
572         glBegin(GL_LINES);
573 
574         glColor4ub(color.tupleof);
575         vertex(toSdpyCoords(start));
576         vertex(toSdpyCoords(end));
577 
578         glEnd();
579 
580     }
581 
582     void drawTriangle(Vector2 a, Vector2 b, Vector2 c, Color color) @trusted {
583 
584         openglDraw();
585         glBegin(GL_TRIANGLES);
586         glColor4ub(color.tupleof);
587         vertex(toSdpyCoords(a));
588         vertex(toSdpyCoords(b));
589         vertex(toSdpyCoords(c));
590         glEnd();
591 
592     }
593 
594     void drawRectangle(Rectangle rectangle, Color color) @trusted {
595 
596         drawRectangleImpl(toSdpyCoords(rectangle), color);
597 
598     }
599 
600     private void drawRectangleImpl(Rectangle rectangle, Color color) @trusted {
601 
602         import fluid.utils;
603 
604         openglDraw();
605         glBegin(GL_TRIANGLES);
606         glColor4ub(color.tupleof);
607 
608         //  d--c
609         //  | /|
610         //  |/ |
611         //  a--b
612         const a = start(rectangle) + Vector2(0, rectangle.height);
613         const b = end(rectangle);
614         const d = start(rectangle);
615         const c = start(rectangle) + Vector2(rectangle.width, 0);
616 
617         // First triangle
618         glTexCoord2f(0, 0);
619         vertex(d);
620         glTexCoord2f(0, 1);
621         vertex(a);
622         glTexCoord2f(1, 0);
623         vertex(c);
624 
625         // Second triangle
626         glTexCoord2f(1, 0);
627         vertex(c);
628         glTexCoord2f(0, 1);
629         vertex(a);
630         glTexCoord2f(1, 1);
631         vertex(b);
632 
633         glEnd();
634 
635     }
636 
637     void drawTexture(Texture texture, Rectangle rectangle, Color tint, string altText) @trusted
638     in (false)
639     do {
640 
641         // TODO filtering?
642         drawTextureImpl(texture, rectangle, tint, altText, true);
643 
644     }
645 
646     void drawTextureAlign(Texture texture, Rectangle rectangle, Color tint, string altText) @trusted
647     in (false)
648     do {
649 
650         drawTextureImpl(texture, rectangle, tint, altText, true);
651 
652     }
653 
654     @trusted
655     private void drawTextureImpl(Texture texture, Rectangle rectangle, Color tint, string altText, bool alignPixels) {
656 
657         import std.math;
658 
659         rectangle = toSdpyCoords(rectangle);
660 
661         if (alignPixels) {
662             rectangle.x = floor(rectangle.x);
663             rectangle.y = floor(rectangle.y);
664         }
665 
666         glEnable(GL_TEXTURE_2D);
667         glBindTexture(GL_TEXTURE_2D, texture.id);
668         drawRectangleImpl(rectangle, tint);
669         glBindTexture(GL_TEXTURE_2D, 0);
670 
671     }
672 
673 }
674 
675 MouseButton toFluid(arsd.simpledisplay.MouseButton button) {
676 
677      switch (button) {
678 
679         default:
680         case button.none: return MouseButton.none;
681         case button.left: return MouseButton.left;
682         case button.middle: return MouseButton.middle;
683         case button.right: return MouseButton.right;
684         case button.wheelUp: return MouseButton.scrollUp;
685         case button.wheelDown: return MouseButton.scrollDown;
686         case button.backButton: return MouseButton.back;
687         case button.forwardButton: return MouseButton.forward;
688 
689     }
690 
691 }
692 
693 KeyboardKey toFluid(arsd.simpledisplay.Key key) {
694 
695      switch (key) {
696 
697         default: return KeyboardKey.none;
698         case key.Escape: return KeyboardKey.escape;
699         case key.Backspace: return KeyboardKey.backspace;
700         case key.F1: return KeyboardKey.f1;
701         case key.F2: return KeyboardKey.f2;
702         case key.F3: return KeyboardKey.f3;
703         case key.F4: return KeyboardKey.f4;
704         case key.F5: return KeyboardKey.f5;
705         case key.F6: return KeyboardKey.f6;
706         case key.F7: return KeyboardKey.f7;
707         case key.F8: return KeyboardKey.f8;
708         case key.F9: return KeyboardKey.f9;
709         case key.F10: return KeyboardKey.f10;
710         case key.F11: return KeyboardKey.f11;
711         case key.F12: return KeyboardKey.f12;
712         case key.PrintScreen: return KeyboardKey.printScreen;
713         case key.ScrollLock: return KeyboardKey.scrollLock;
714         case key.Pause: return KeyboardKey.pause;
715         case key.Grave: return KeyboardKey.grave;
716         case key.N0: return KeyboardKey.digit0;
717         case key.N1: return KeyboardKey.digit1;
718         case key.N2: return KeyboardKey.digit2;
719         case key.N3: return KeyboardKey.digit3;
720         case key.N4: return KeyboardKey.digit4;
721         case key.N5: return KeyboardKey.digit5;
722         case key.N6: return KeyboardKey.digit6;
723         case key.N7: return KeyboardKey.digit7;
724         case key.N8: return KeyboardKey.digit8;
725         case key.N9: return KeyboardKey.digit9;
726         case key.Dash: return KeyboardKey.dash;
727         case key.Equals: return KeyboardKey.equal;
728         case key.Backslash: return KeyboardKey.backslash;
729         case key.Insert: return KeyboardKey.insert;
730         case key.Home: return KeyboardKey.home;
731         case key.PageUp: return KeyboardKey.pageUp;
732         case key.PageDown: return KeyboardKey.pageDown;
733         case key.Delete: return KeyboardKey.del;
734         case key.End: return KeyboardKey.end;
735         case key.Up: return KeyboardKey.up;
736         case key.Down: return KeyboardKey.down;
737         case key.Left: return KeyboardKey.left;
738         case key.Right: return KeyboardKey.right;
739         case key.Tab: return KeyboardKey.tab;
740         case key.Q: return KeyboardKey.q;
741         case key.W: return KeyboardKey.w;
742         case key.E: return KeyboardKey.e;
743         case key.R: return KeyboardKey.r;
744         case key.T: return KeyboardKey.t;
745         case key.Y: return KeyboardKey.y;
746         case key.U: return KeyboardKey.u;
747         case key.I: return KeyboardKey.i;
748         case key.O: return KeyboardKey.o;
749         case key.P: return KeyboardKey.p;
750         case key.LeftBracket: return KeyboardKey.leftBracket;
751         case key.RightBracket: return KeyboardKey.rightBracket;
752         case key.CapsLock: return KeyboardKey.capsLock;
753         case key.A: return KeyboardKey.a;
754         case key.S: return KeyboardKey.s;
755         case key.D: return KeyboardKey.d;
756         case key.F: return KeyboardKey.f;
757         case key.G: return KeyboardKey.g;
758         case key.H: return KeyboardKey.h;
759         case key.J: return KeyboardKey.j;
760         case key.K: return KeyboardKey.k;
761         case key.L: return KeyboardKey.l;
762         case key.Semicolon: return KeyboardKey.semicolon;
763         case key.Apostrophe: return KeyboardKey.apostrophe;
764         case key.Enter: return KeyboardKey.enter;
765         case key.Shift: return KeyboardKey.leftShift;
766         case key.Z: return KeyboardKey.z;
767         case key.X: return KeyboardKey.x;
768         case key.C: return KeyboardKey.c;
769         case key.V: return KeyboardKey.v;
770         case key.B: return KeyboardKey.b;
771         case key.N: return KeyboardKey.n;
772         case key.M: return KeyboardKey.m;
773         case key.Comma: return KeyboardKey.comma;
774         case key.Period: return KeyboardKey.period;
775         case key.Slash: return KeyboardKey.slash;
776         case key.Shift_r: return KeyboardKey.rightShift;
777         case key.Ctrl: return KeyboardKey.leftControl;
778         case key.Windows: return KeyboardKey.leftSuper;
779         case key.Alt: return KeyboardKey.leftAlt;
780         case key.Space: return KeyboardKey.space;
781         case key.Alt_r: return KeyboardKey.rightAlt;
782         case key.Windows_r: return KeyboardKey.rightSuper;
783         case key.Menu: return KeyboardKey.contextMenu;
784         case key.Ctrl_r: return KeyboardKey.rightControl;
785         case key.NumLock: return KeyboardKey.numLock;
786         case key.Divide: return KeyboardKey.keypadDivide;
787         case key.Multiply: return KeyboardKey.keypadMultiply;
788         case key.Minus: return KeyboardKey.keypadSubtract;
789         case key.Plus: return KeyboardKey.keypadSum;
790         case key.PadEnter: return KeyboardKey.keypadEnter;
791         case key.Pad0: return KeyboardKey.keypad0;
792         case key.Pad1: return KeyboardKey.keypad1;
793         case key.Pad2: return KeyboardKey.keypad2;
794         case key.Pad3: return KeyboardKey.keypad3;
795         case key.Pad4: return KeyboardKey.keypad4;
796         case key.Pad5: return KeyboardKey.keypad5;
797         case key.Pad6: return KeyboardKey.keypad6;
798         case key.Pad7: return KeyboardKey.keypad7;
799         case key.Pad8: return KeyboardKey.keypad8;
800         case key.Pad9: return KeyboardKey.keypad9;
801         case key.PadDot: return KeyboardKey.keypadDecimal;
802 
803     }
804 
805 }
806 
807 MouseCursor toSimpleDisplay(FluidMouseCursor cursor) @trusted {
808 
809     switch (cursor.system) {
810 
811         default:
812         case cursor.system.systemDefault:
813         case cursor.system.none:
814             return GenericCursor.Default;
815 
816         case cursor.system.pointer: return GenericCursor.Hand;
817         case cursor.system.crosshair: return GenericCursor.Cross;
818         case cursor.system.text: return GenericCursor.Text;
819         case cursor.system.allScroll: return GenericCursor.Move;
820         case cursor.system.resizeEW: return GenericCursor.SizeWe;
821         case cursor.system.resizeNS: return GenericCursor.SizeNs;
822         case cursor.system.resizeNESW: return GenericCursor.SizeNesw;
823         case cursor.system.resizeNWSE: return GenericCursor.SizeNwse;
824         case cursor.system.notAllowed: return GenericCursor.NotAllowed;
825 
826     }
827 
828 }