Skip to content

Commit 4f0e9ce

Browse files
committed
Focus; fix default focus model event propagation #52
fix #52 fix #49 fix #37 related #44
1 parent 7d7bfa4 commit 4f0e9ce

File tree

5 files changed

+134
-55
lines changed

5 files changed

+134
-55
lines changed

mint/Control.hx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,7 @@ class Control {
338338

339339
for(_child in children) {
340340

341-
//:todo: this filters by mouse but is a general function
342-
if(_child.contains(_x, _y) && _child.mouse_input && _child.visible) {
341+
if(_child.visible && _child.contains(_x, _y)) {
343342

344343
if(_child.depth >= highest_depth) {
345344
highest_child = _child;
@@ -788,7 +787,7 @@ class Control {
788787
if(canvas == this) return;
789788

790789
var _pre = canvas.captured == this;
791-
790+
792791
canvas.captured = this;
793792

794793
if(!_pre) oncaptured.emit(true);

mint/focus/Focus.hx

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class Focus {
88
public var canvas: mint.Canvas;
99

1010
public function new(_canvas:mint.Canvas) {
11-
11+
1212
canvas = _canvas;
1313

1414
canvas.onmousemove.listen(mousemove);
@@ -56,7 +56,7 @@ class Focus {
5656
function mousedown(e:MouseEvent, target:mint.Control) {
5757
if(canvas.focused != null && canvas.focused.mouse_input) {
5858
canvas.focused.mousedown(e);
59-
}
59+
}
6060

6161
if(marked_mouse()) canvas.marked.mousedown(e);
6262

@@ -65,7 +65,7 @@ class Focus {
6565
function mouseup(e:MouseEvent, target:mint.Control) {
6666
if(canvas.focused != null && canvas.focused.mouse_input) {
6767
canvas.focused.mouseup(e);
68-
}
68+
}
6969

7070
if(marked_mouse()) canvas.marked.mouseup(e);
7171

@@ -74,7 +74,7 @@ class Focus {
7474
function mousewheel(e:MouseEvent, target:mint.Control) {
7575
if(canvas.focused != null && canvas.focused.mouse_input) {
7676
canvas.focused.mousewheel(e);
77-
}
77+
}
7878

7979
if(marked_mouse()) canvas.marked.mousewheel(e);
8080

@@ -84,59 +84,77 @@ class Focus {
8484
return canvas.marked != canvas.focused && canvas.marked != null && canvas.marked.mouse_input;
8585
}
8686

87-
function mousemove(e:MouseEvent, target:mint.Control) {
87+
function get_markable(_target:mint.Control, _x:Float, _y:Float) {
88+
89+
var _highest = _target.topmost_child_at_point(_x, _y);
90+
91+
if(_highest == null && _highest == _target) {
92+
return null;
93+
}
8894

89-
if(canvas.ishovered) {
95+
// now if we have the highest possible control,
96+
// we have to walk backward up the tree,
97+
// looking for the highest one with mouse input
9098

91-
//first we check if the mouse is still inside the focused element
92-
var _marked = canvas.marked;
93-
if(_marked != null) {
99+
var _current = _highest;
100+
var _canvas = _target.canvas;
94101

95-
if(_marked.contains(e.x, e.y)) {
102+
while(true) {
96103

97-
var _target = _marked.parent;
98-
if(_target == null) _target = canvas;
104+
if(_current == null || _current == _canvas) {
105+
return _current;
106+
}
99107

100-
var _hovered = _target.topmost_child_at_point(e.x, e.y);
101-
if(_hovered != null && _hovered != _marked && _hovered != canvas) {
108+
if(_current.mouse_input) {
109+
return _current;
110+
}
102111

103-
//reset the previous
104-
unmark_control(_marked, e);
105-
//set the newly hovered one
106-
mark_control(_hovered, e);
107-
//change the focused item
108-
canvas.marked = _hovered;
112+
_current = _current.parent;
109113

110-
} //_hovered != null
114+
} //while
111115

112-
} else { //_marked.contains
116+
//unreachable?
117+
return null;
113118

114-
//unfocus the existing one
115-
unmark_control(_marked, e);
119+
} //get_markable
116120

117-
//find a new one, if any
118-
find_marked(e);
121+
function mousemove(e:MouseEvent, _) {
119122

120-
} //_marked inside
123+
var _mark_target = canvas;
124+
var _captured = canvas.captured;
121125

122-
} else { //_marked != null
126+
if(_captured != null && _captured.mouse_input) {
123127

124-
//nothing focused at the moment, check that the mouse is inside our canvas first
125-
if( canvas.ishovered ) {
126-
find_marked(e);
127-
} else {
128-
reset_marked(e);
129-
}
128+
var _markable = get_markable(_captured, e.x, e.y);
129+
130+
if(_markable != null) {
131+
mark_control(_markable, e);
132+
}
130133

131-
} //no currently marked
134+
if(marked_mouse()) canvas.marked.mousemove(e);
132135

133-
} //canvas.ishovered
136+
} else if(canvas.ishovered) {
134137

135-
if(canvas.focused != null && canvas.focused.mouse_input) {
136-
canvas.focused.mousemove(e);
137-
}
138+
//if the mouse has left the current marked control, unmark
139+
if(canvas.marked != null && !canvas.marked.contains(e.x, e.y)) {
140+
unmark_control(canvas.marked, e);
141+
}
142+
143+
// the focused control always gets the events
144+
if(canvas.focused != null && canvas.focused.mouse_input) {
145+
canvas.focused.mousemove(e);
146+
}
147+
148+
//get the marked control from the canvas
149+
var _markable = get_markable(canvas, e.x, e.y);
150+
151+
if(_markable != null) {
152+
mark_control(_markable, e);
153+
}
138154

139-
if(marked_mouse()) canvas.marked.mousemove(e);
155+
if(marked_mouse()) canvas.marked.mousemove(e);
156+
157+
} //canvas is hovered
140158

141159
} //mousemove
142160

@@ -146,7 +164,7 @@ class Focus {
146164
unmark_control(_control, e);
147165
}
148166

149-
} //reset_focus
167+
} //reset_marked
150168

151169
function get_focusable( _x:Float, _y:Float ) {
152170

@@ -172,7 +190,7 @@ class Focus {
172190

173191
function unmark_control(_control:Control, e:MouseEvent) {
174192

175-
if(_control != null) {
193+
if(_control != null && _control.ismarked) {
176194

177195
_control.unmark();
178196

@@ -184,14 +202,16 @@ class Focus {
184202

185203
function mark_control(_control:Control, e:MouseEvent) {
186204

187-
if(_control != null) {
205+
if(_control != null && !_control.ismarked) {
206+
207+
reset_marked(canvas.marked);
188208

189209
_control.mark();
190210

191211
if(_control.mouse_input) _control.mouseenter(e);
192212

193213
}
194214

195-
} //set_focused
215+
} //mark_control
196216

197217
}

tests/test_luxe/src/Main.hx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class Main extends luxe.Game {
8787
state.add( new tests.KitchenSink({ name:'state0' }) );
8888
state.add( new tests.Scrolling({ name:'state1' }) );
8989
state.add( new tests.Depth({ name:'state2' }) );
90+
state.add( new tests.Focus({ name:'state3' }) );
9091

9192
count = Lambda.count( state._states );
9293

tests/test_luxe/src/tests/Focus.hx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package tests;
2+
3+
import luxe.Color;
4+
import luxe.Vector;
5+
import luxe.Input;
6+
import luxe.Text;
7+
import luxe.States;
8+
9+
import mint.Control;
10+
import mint.types.Types;
11+
import mint.render.luxe.LuxeMintRender;
12+
import mint.render.luxe.Convert;
13+
import mint.render.luxe.Label;
14+
15+
import mint.layout.margins.Margins;
16+
17+
class Focus extends State {
18+
19+
var scroll: mint.Scroll;
20+
var scroll2: mint.Scroll;
21+
22+
override function onenter<T>(_:T) {
23+
24+
Main.disp.text = 'Test: Focus';
25+
26+
var _r0 = new mint.Scroll({
27+
parent: Main.canvas, name:'r0',
28+
x:20, y:20, w:256, h: 256,
29+
options: { color:new Color().rgb(0x000000) }
30+
});
31+
32+
var _l0 = new mint.Label({
33+
parent: _r0, name:'l0',
34+
x:0, y:0, w:256, h:264,
35+
options: {},
36+
mouse_input: true,
37+
text: 'HOVERS'
38+
});
39+
40+
_l0.onmouseenter.listen(function(_,_) { trace('enter ' + Luxe.time); });
41+
_l0.onmouseleave.listen(function(_,_) { trace('leave ' + Luxe.time); });
42+
43+
44+
} //onenter
45+
46+
override function onleave<T>(_:T) {
47+
48+
} //onleave
49+
50+
51+
} //Focus

tests/test_luxe/src/tests/KitchenSink.hx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import mint.types.Types;
1111
import mint.render.luxe.Convert;
1212
import mint.render.luxe.Label;
1313
import mint.layout.margins.Margins;
14+
import luxe.utils.Maths;
1415

1516
class KitchenSink extends State {
1617

@@ -257,12 +258,19 @@ class KitchenSink extends State {
257258

258259
function create_basics() {
259260

260-
new mint.Label({
261+
var _panel = new mint.Panel({
261262
parent: canvas,
263+
name: 'label_panel',
264+
x:5, y:5, w:100, h:42,
265+
mouse_input: false, //this is to test that mouse events land in the children when the parent has no mouse input
266+
});
267+
268+
new mint.Label({
269+
parent: _panel,
262270
name: 'labelmain',
263-
x:10, y:10, w:100, h:32,
264-
text: 'hello mint',
265-
align:left,
271+
x:0, y:0, w:100, h:42,
272+
text: 'mint label',
273+
align: center,
266274
text_size: 14,
267275
onclick: function(e,c) {trace('hello mint! ${Luxe.time}' );}
268276
});
@@ -308,17 +316,17 @@ class KitchenSink extends State {
308316
name : _s.name+'.label', text: '${_s.value}'
309317
});
310318

311-
_s.onchange.listen(function(_val,_) { _l.text = '$_val'; });
319+
_s.onchange.listen(function(_val,_) { _l.text = '${Maths.fixed(_val,3)}'; });
312320

313321
} //make_slider
314322

315323
make_slider('slider1', 10, 330, 128, 24, 0x9dca63, -100, 100, 0, 10, false);
316324
make_slider('slider2', 10, 357, 128, 24, 0x9dca63, 0, 100, 50, 1, false);
317325
make_slider('slider3', 10, 385, 128, 24, 0xf6007b, null, null, null, null, false);
318326

319-
make_slider('slider4', 14, 424, 32, 128, 0x9dca63, 0, 100, 20, 10, true);
320-
make_slider('slider5', 56, 424, 32, 128, 0x9dca63, 0, 100, 0.3, 1, true);
321-
make_slider('slider6', 98, 424, 32, 128, 0xf6007b, null, null, null, null, true);
327+
make_slider('slider4', 12, 424, 36, 128, 0x9dca63, 0, 100, 20, 10, true);
328+
make_slider('slider5', 56, 424, 36, 128, 0x9dca63, 0, 100, 0.3, 1, true);
329+
make_slider('slider6', 101, 424, 36, 128, 0xf6007b, null, null, null, null, true);
322330

323331
new mint.Button({
324332
parent: canvas,

0 commit comments

Comments
 (0)