1 // Written in the D programming language.
2 /++
3  + Authors: KanzakiKino
4  + Copyright: KanzakiKino 2018
5  + License: LGPL-3.0
6 ++/
7 module w4d.widget.base.mouse;
8 
9 /// A template that declares methods related to Mouse.
10 template Mouse ()
11 {
12     protected Widget _hovered;
13 
14     protected void setHovered ( Widget child, vec2 pos )
15     {
16         auto temp = _hovered;
17         _hovered = child;
18 
19         if ( child !is temp ) {
20             if ( temp  ) temp .handleMouseEnter( false, pos );
21             if ( child ) child.handleMouseEnter(  true, pos );
22         }
23     }
24 
25     @property const(Cursor) cursor ()
26     {
27         return _hovered? _hovered.cursor: Cursor.Arrow;
28     }
29 
30 
31     @property isTracked ()
32     {
33         return _context && _context.tracked is this;
34     }
35     @property bool trackable ()
36     {
37         return true;
38     }
39     void track ()
40     {
41         if ( trackable ) {
42             enforce( _context, "WindowContext is null." );
43             _context.setTracked( this );
44         }
45     }
46     void refuseTrack ()
47     {
48         enforce( isTracked, "The widget has not been tracked." );
49         _context.setTracked( null );
50     }
51 
52 
53     bool handleMouseEnter ( bool entered, vec2 pos )
54     {
55         if ( _context.tracked && !isTracked ) {
56             return true;
57         }
58 
59         if ( entered ) {
60             enableState( WidgetState.Hovered );
61         } else {
62             setHovered( null, pos );
63             disableState( WidgetState.Hovered );
64         }
65         return false;
66     }
67 
68     bool handleMouseMove ( vec2 pos )
69     {
70         if ( !isTracked ) {
71             if ( _context.tracked ) {
72                 _context.tracked.handleMouseMove( pos );
73                 return true;
74             } else if ( auto target = findChildAt(pos) ) {
75                 setHovered( target, pos );
76                 if ( target.handleMouseMove( pos ) ) {
77                     return true;
78                 }
79             } else {
80                 setHovered( null, pos );
81             }
82         }
83         return false;
84     }
85 
86     bool handleMouseButton ( MouseButton btn, bool status, vec2 pos )
87     {
88         if ( !isTracked ) {
89             if ( _context.tracked ) {
90                 _context.tracked.handleMouseButton( btn, status, pos );
91                 return true;
92             } else if ( auto target = findChildAt(pos) ) {
93                 if ( target.handleMouseButton( btn, status, pos ) ) {
94                     return true;
95                 }
96                 if ( _context.tracked ) {
97                     return true;
98                 }
99             }
100         }
101 
102         if ( btn == MouseButton.Left && status ) {
103             enableState( WidgetState.Pressed );
104             track();
105             focus();
106         } else if ( btn == MouseButton.Left && !status ) {
107             if ( isTracked ) refuseTrack();
108             disableState( WidgetState.Pressed );
109         }
110         return false;
111     }
112 
113     bool handleMouseScroll ( vec2 amount, vec2 pos )
114     {
115         if ( !isTracked ) {
116             if ( _context.tracked ) {
117                 _context.tracked.handleMouseScroll( amount, pos );
118                 return true;
119             } else if ( auto target = findChildAt(pos) ) {
120                 if ( target.handleMouseScroll( amount, pos ) ) {
121                     return true;
122                 }
123             }
124         }
125         return false;
126     }
127 
128     void handleTracked ( bool a )
129     {
130         (a? &enableState: &disableState)( WidgetState.Tracked );
131     }
132 }