[REBOL] Re: field focus event
From: brett:codeconscious at: 20-Sep-2003 0:13
Mike Yaunish wrote:
> I am trying to find where I can drop some code into a view field the
> instant that the field becomes active.
Hi Mike,
I don't think there is any focus event as such that does this. However,
there are two functions that manage focus for VID fields: Focus and Unfocus.
These functions are quite small so the idea is to replace them with your own
version that generates your own events. I'll have a stab below.
The other way you could look at this (depending on what you are doing) is
instead of a function being called when focus changes you could have another
face poll (using a rate) system/view/focal-face to see if it is the face you
are interested in and do something while that is true. This might be useful
for some sort of interactive display. For the rest of the email, I'll go the
first route, to generate a focus events.
There is a little information on the Focus function here:
http://www.rebol.com/how-to/fields.html#sect3.5.
The trick with modifying the Focus function is to rebind it to the context
it was created within, which is ctx-text. How do I know that? A bit of
searching some time ago.
So the plan.
(1) Modify Focus to check the face it is given for two new facets - one for
pre-focus, one for post-focus. If they are not there carry on as normal. If
they are present then they would normally contain functions, but you could
have a simple value true/false. If the pre-focus facet evaluates to False or
None then exit the Focus function early, thereby cancelling it. Might be
handy for something!
(2) Modify Unfocus similarly. Pre-unfocus could be useful for validation -
see next point.
(3) Looking at the code for Unfocus I guess that no VID code expects a
return value from it, however it is useful for us. If Pre-unfocus is set to
none, the user
might want to prevent the field from being unfocussed - so if I pass that
back as a return from Unfocus, the Focus routine can be cancelled. Could be
handy for validation. If I pass a value back - all is well. I figure here I
may as well pass the face back that was unfocussed or if the window is just
opened a True.
I've added a local variable tmp-value to handle Unset! in both functions.
Now all this looks to be to be pretty good but I haven't tested/investigated
it thoroughly to see if it breaks other VID assumptions. Use at your own
risk! :^)
There is one other issue. When you close the window Unfocus is not called so
you will not get my Unfocus events generated when the user closes the
window. If you need this you will probably need an event function
(insert-event-func) to trap the close and call Unfocus.
Code below.
Regards,
Brett.
; -------------------------------------------------------
focus: func [
"Focuses key events on a specific face."
face
/no-show
/local tmp-face tmp-value
] bind [
; My pre-focus addition
if in face 'pre-focus [
; Call the pre-focus function, Cancel the focus if false/none.
if all [
not unset? set/any 'tmp-value face/pre-focus face
not tmp-value
] [exit]
]
; Another change, if unfocus was cancelled, cancel the focus.
if not unfocus [exit]
if not face [exit]
view*/focal-face: face
if not string? face/text [
face/text: either face/text [form face/text] [copy ""]
]
if none? face/line-list [
if face/para [face/para/scroll: 0x0]
view*/caret: tail face/text
]
if flag-face? face field [hilight-all face]
; My post-focus addition
if in face 'post-focus [face/post-focus face]
if not no-show [show face]
] in ctx-text 'view*
unfocus: func [
"Removes the current key event focus."
/local tmp-face tmp-value
] bind [
tmp-face: view*/focal-face
; My addition
if all [tmp-face in tmp-face 'pre-unfocus] [
; Call the pre-unfocus function, Cancel the focus if false/none.
if all [
not unset? set/any 'tmp-value tmp-face/pre-unfocus tmp-face
not tmp-value
] [
; This will mean that unfocus is cancelled.
return none
]
]
view*/focal-face: none
view*/caret: none
unlight-text
; My post-unfocus addition
if all [tmp-face in tmp-face 'post-unfocus] [
tmp-face/post-unfocus tmp-face
]
if tmp-face [show tmp-face]
; Another addition. Send back a true if we did unfocus.
any [tmp-face true]
] in ctx-text 'view*
; -------------------------------------------------------
; Test program
stylize/master [
log-field: field with [
pre-focus: func [face] [
print ["pre-focus" mold face/text]
]
post-focus: func [face] [
print ["post-focus" mold face/text]
]
pre-unfocus: func [face] [
print ["pre-unfocus" mold face/text]
]
post-unfocus: func [face] [
print ["post-unfocus" mold face/text]
]
]
]
view layout [
logfld: log-field "Log field 1"
logfld: log-field "Log field 2"
field "I change the colour of the box." with [
post-focus: does [
box1/color: green
show box1
]
post-unfocus: does [
box1/color: gray
show box1
]
]
box1: box 10x10 orange
field "You cannot focus me!" with [pre-focus: none]
field "Black hole" with [pre-unfocus: none]
]