tui_simpleauth.inc
8l_HeavyThing/tui_simpleauth.inc
	; ------------------------------------------------------------------------
	; HeavyThing x86_64 assembly language library and showcase programs
	; Copyright Â© 2015, 2016 2 Ton Digital 
	; Homepage: https://2ton.com.au/
	; Author: Jeff Marrison <jeff@2ton.com.au>
	;       
	; This file is part of the HeavyThing library.
	;       
	; HeavyThing is free software: you can redistribute it and/or modify
	; it under the terms of the GNU General Public License, or
	; (at your option) any later version.
	;       
	; HeavyThing is distributed in the hope that it will be useful, 
	; but WITHOUT ANY WARRANTY; without even the implied warranty of
	; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
	; GNU General Public License for more details.
	;       
	; You should have received a copy of the GNU General Public License along
	; with the HeavyThing library. If not, see <http://www.gnu.org/licenses/>.
	; ------------------------------------------------------------------------
	;       
	; tui_simpleauth.inc: simple auth screen
	;
	; we support user/pass, or single token based auth, and also provide a "new user"
	; form that has user/pass as well.
	;
	; we "descend" tui_object, but we add three virtual methods to deal with auth itself
	;
	; look and feel changes will require copying/modifying the new$/nvsetup goods
	;
	; NOTE: in a server environment, if you add objects to the top/bottom sections of the main
	; auth screen, you must _not_ alter the primary 3 children, or clone won't work properly
	; e.g. if you add to tui_simpleauth's first child (which is empty space above the authbox)
	; or you add to tui_simpleauth's last child, or alter the mid section's layout or add
	; to that, that is fine.
	; if you add any children anywhere to tui_simpleauth directly, clone will fail to find
	; the mid/panel out of its tui_object cloned version.
	;
	; ALSO NOTE: it does not make sense to clone this under anything but a "fresh" setup
	; e.g. if a clone occurs in any other state than "initial", results are undefined, haha
	; (this isn't a problem of course, because that is precisely the way it was designed to
	; work, but I figure it is worth noting)
	;


if used tui_simpleauth$vtable | defined include_everything

dalign
tui_simpleauth$vtable:
        dq      tui_simpleauth$cleanup, tui_simpleauth$clone, tui_background$draw, tui_object$redraw, tui_object$updatedisplaylist, tui_object$sizechanged
        dq      tui_object$timer, tui_object$layoutchanged, tui_object$move, tui_object$setfocus, tui_object$gotfocus, tui_object$lostfocus
        dq      tui_simpleauth$keyevent, tui_object$domodal, tui_object$endmodal, tui_object$exit, tui_object$calcbounds, tui_object$calcchildbounds
        dq      tui_object$appendchild, tui_object$appendbastard, tui_object$prependchild, tui_object$contains, tui_object$getchildindex
        dq      tui_object$removechild, tui_object$removebastard, tui_object$removeallchildren, tui_object$removeallbastards
        dq      tui_object$getobjectsunderpoint, tui_object$flatten, tui_object$firekeyevent, tui_object$ontab, tui_object$onshifttab
        dq      tui_object$setcursor, tui_object$showcursor, tui_object$hidecursor, tui_object$click, tui_object$clicked
	; our addon virtual methods that are tui_simpleauth-specific:
	dq	tui_simpleauth$allow_userpass, tui_simpleauth$allow_token, tui_simpleauth$create_newuser


tui_simpleauth_vuserpass = tui_vclicked + 8
tui_simpleauth_vtoken = tui_vclicked + 16
tui_simpleauth_vnewuser = tui_vclicked + 24

tui_simpleauth_authtype_ofs = tui_background_size
tui_simpleauth_onsuccess_ofs = tui_background_size + 8
tui_simpleauth_mid_ofs = tui_background_size + 16
tui_simpleauth_panel_ofs = tui_background_size + 24
tui_simpleauth_fail_ofs = tui_background_size + 32
tui_simpleauth_retrytime_ofs = tui_background_size + 40
tui_simpleauth_oldpanel_ofs = tui_background_size + 48
tui_simpleauth_timerptr_ofs = tui_background_size + 56

tui_simpleauth_size = tui_background_size + 64

end if


if used tui_simpleauth$new | defined include_everything
	; two arguments: edi == authtype, rsi == tui_object to fire up on success

	; authtype is one of:
tui_simpleauth_normal = 0
tui_simpleauth_newuser = 1
tui_simpleauth_token = 2

falign
tui_simpleauth$new:
	prolog	tui_simpleauth$new
	push	rbx rdi rsi
	mov	edi, tui_simpleauth_size
	call	heap$alloc
	mov	rbx, rax
	mov	rdi, rax
	movq	xmm0, [_math_onehundred]
	movq	xmm1, [_math_onehundred]
	mov	esi, ' '
	ansi_colors edx, 'lightgray', 'black'
	call	tui_background$init_dd
	mov	qword [rbx], tui_simpleauth$vtable
	pop	rsi rdi
	xor	ecx, ecx
	mov	edx, 3
	mov	[rbx+tui_simpleauth_authtype_ofs], rdi
	mov	[rbx+tui_simpleauth_onsuccess_ofs], rsi
	mov	[rbx+tui_simpleauth_mid_ofs], rcx
	mov	[rbx+tui_simpleauth_panel_ofs], rcx
	mov	[rbx+tui_simpleauth_fail_ofs], rcx
	mov	[rbx+tui_simpleauth_retrytime_ofs], rdx
	mov	[rbx+tui_simpleauth_oldpanel_ofs], rcx
	mov	[rbx+tui_simpleauth_timerptr_ofs], rcx
	mov	rdi, rbx
	call	tui_simpleauth$nvsetup
	mov	rax, rbx
	pop	rbx
	epilog

end if

if used tui_simpleauth$clone | defined include_everything
	; single argument in rdi: our tui_simpleauth object
falign
tui_simpleauth$clone:
	prolog	tui_simpleauth$clone
	push	rdi
	mov	edi, tui_simpleauth_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	mov	rsi, [rsp+8]
	call	tui_background$init_copy
	mov	rdi, [rsp]
	mov	rsi, [rsp+8]
	mov	rdx, [rsi+tui_simpleauth_retrytime_ofs]
	mov	rcx, [rsi+tui_simpleauth_authtype_ofs]
	mov	r8, [rsi+tui_simpleauth_onsuccess_ofs]
	xor	r9d, r9d
	mov	[rdi+tui_simpleauth_authtype_ofs], rcx
	mov	[rdi+tui_simpleauth_onsuccess_ofs], r8
	mov	[rdi+tui_simpleauth_mid_ofs], r9
	mov	[rdi+tui_simpleauth_panel_ofs], r9
	mov	[rdi+tui_simpleauth_fail_ofs], r9
	mov	[rdi+tui_simpleauth_retrytime_ofs], rdx
	mov	[rdi+tui_simpleauth_oldpanel_ofs], r9
	mov	[rdi+tui_simpleauth_timerptr_ofs], r9

	; so now, we know that mid is the second child, and panel is its first child
	mov	rsi, [rdi+tui_children_ofs]
	mov	rdx, [rsi+_list_first_ofs]
	mov	rdx, [rdx+_list_nextofs]
	mov	rcx, [rdx]			; mid
	mov	[rdi+tui_simpleauth_mid_ofs], rcx

	mov	rsi, [rcx+tui_children_ofs]

	mov	rdx, [rsi+_list_first_ofs]
	mov	rdx, [rdx]			; panel
	mov	[rdi+tui_simpleauth_panel_ofs], rdx

	; we need to set the panel's as varialbe so that it can link back to us:
	mov	[rdx+tui_authpanel_as_ofs], rdi

	mov	rax, rdi
	add	rsp, 16
	epilog

end if

if used tui_simpleauth$nvsetup | defined include_everything
	; single argument in rdi: our fresh tui_simpleauth object
falign
tui_simpleauth$nvsetup:
	prolog	tui_simpleauth$nvsetup
	; fill our screen
	push	rbx
	mov	rbx, rdi
	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	movq	xmm0, [_math_onehundred]
	movq	xmm1, [.half]
	call	tui_object$init_dd
	pop	rsi
	mov	qword [rsi], tui_object$simple_vtable
	mov	rdi, rbx
	mov	rdx, [rbx]
	call	qword [rdx+tui_vappendchild]
	; our midsection depends on what kind of auth we are presenting
	cmp	dword [rbx+tui_simpleauth_authtype_ofs], tui_simpleauth_newuser
	je	.mid_newuser
	cmp	dword [rbx+tui_simpleauth_authtype_ofs], tui_simpleauth_token
	je	.mid_token
	; otherwise, normal it is
	mov	edi, tui_object_size
	call	heap$alloc
	mov	[rbx+tui_simpleauth_mid_ofs], rax
	mov	rdi, rax
	movq	xmm0, [_math_onehundred]
	mov	esi, 6
	call	tui_object$init_di
	mov	rax, [rbx+tui_simpleauth_mid_ofs]
	mov	qword [rax], tui_object$simple_vtable
	mov	dword [rax+tui_horizalign_ofs], tui_align_center
	
	mov	edi, 38
	mov	esi, 6
	mov	rdx, rbx
	xor	ecx, ecx
	call	tui_authpanel$new
	mov	[rbx+tui_simpleauth_panel_ofs], rax
	mov	rdi, rax
	call	tui_authpanel$normalsetup
	jmp	.midready
dalign
.half	dq	50.0f
calign
.mid_newuser:
	mov	edi, tui_object_size
	call	heap$alloc
	mov	[rbx+tui_simpleauth_mid_ofs], rax
	mov	rdi, rax
	movq	xmm0, [_math_onehundred]
	mov	esi, 10
	call	tui_object$init_di
	mov	rax, [rbx+tui_simpleauth_mid_ofs]
	mov	qword [rax], tui_object$simple_vtable
	mov	dword [rax+tui_horizalign_ofs], tui_align_center

	mov	edi, 38
	mov	esi, 10
	mov	rdx, rbx
	xor	ecx, ecx
	call	tui_authpanel$new
	mov	[rbx+tui_simpleauth_panel_ofs], rax
	mov	rdi, rax
	call	tui_authpanel$newusersetup
	jmp	.midready

calign
.mid_token:
	mov	edi, tui_object_size
	call	heap$alloc
	mov	[rbx+tui_simpleauth_mid_ofs], rax
	mov	rdi, rax
	movq	xmm0, [_math_onehundred]
	mov	esi, 6
	call	tui_object$init_di
	mov	rax, [rbx+tui_simpleauth_mid_ofs]
	mov	qword [rax], tui_object$simple_vtable
	mov	dword [rax+tui_horizalign_ofs], tui_align_center

	mov	edi, 50
	mov	esi, 5
	mov	rdx, rbx
	xor	ecx, ecx
	call	tui_authpanel$new
	mov	[rbx+tui_simpleauth_panel_ofs], rax
	mov	rdi, rax
	call	tui_authpanel$tokensetup
	
calign
.midready:
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_panel_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	
	mov	rdi, rbx
	mov	rsi, [rbx+tui_simpleauth_mid_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	movq	xmm0, [_math_onehundred]
	; see the notes in tui_object.inc for why we do this one different
	; re: correcting rounding drops in height
	movq	xmm1, [.roundingerr]
	call	tui_object$init_dd

if defined tui_simpleauth_uglytesting
	; testing only
	mov	rsi, [rsp]
	mov	qword [rsi], tui_object$simple_vtable
	mov	dword [rsi+tui_layout_ofs], tui_layout_horizontal
	mov	dword [rsi+tui_vertalign_ofs], tui_align_bottom
	; create a newsticker to add to it
	movq	xmm0, [_math_onehundred]
	mov	rdi, .ticktext
	ansi_colors esi, 'lightgray', 'black'
	call	tui_newsticker$new_d
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	; end testing
end if


	pop	rsi
	mov	qword [rsi], tui_object$simple_vtable
	mov	rdi, rbx
	mov	rdx, [rbx]
	call	qword [rdx+tui_vappendchild]

	pop	rbx
	epilog
if defined tui_simpleauth_uglytesting
cleartext .ticktext, 'Best viewed with a 6 pack of beer, ha! ... size: 135x35 min, Mac OS X: iTerm2 or Terminal.app, Winblows: SecureCRT (ANSI colors enabled, rows/cols adjust, lucida console), Linux: all linux terms seem happy...'
end if

dalign
.roundingerr	dq	51.0f

end if

if used tui_simpleauth$cleanup | defined include_everything
	; single argument in rdi: our tui_simpleauth object
falign
tui_simpleauth$cleanup:
	prolog	tui_simpleauth$cleanup
	; special handling is required for our "dangling" children
	push	rdi
	cmp	qword [rdi+tui_simpleauth_timerptr_ofs], 0
	je	.notimer
	mov	rdi, [rdi+tui_simpleauth_timerptr_ofs]
	call	epoll$timer_clear
	mov	rdi, [rsp]
	mov	qword [rdi+tui_simpleauth_timerptr_ofs], 0
calign
.notimer:
	call	tui_object$cleanup
	mov	rsi, [rsp]
	cmp	qword [rsi+tui_simpleauth_fail_ofs], 0
	je	.nofail
	mov	rdi, [rsi+tui_simpleauth_panel_ofs]
	push	rdi
	mov	rsi, [rdi]
	call	qword [rsi+tui_vcleanup]
	pop	rdi
	call	heap$free
	mov	rsi, [rsp]
calign
.nofail:
	cmp	qword [rsi+tui_simpleauth_oldpanel_ofs], 0
	je	.noold
	mov	rdi, [rsi+tui_simpleauth_oldpanel_ofs]
	push	rdi
	mov	rsi, [rdi]
	call	qword [rsi+tui_vcleanup]
	pop	rdi
	call	heap$free
calign
.noold:
	add	rsp, 8
	epilog

end if


if used tui_simpleauth$keyevent | defined include_everything
	; three arguments: rdi == our tui_simpleauth object, esi == key, edx == esc_key
falign
tui_simpleauth$keyevent:
	prolog	tui_simpleauth$keyevent
	; my original C++ was catching ctrl-C here, but since all the higher level renderers do that anyway, leaving this
	; as an unhandled return in case I change my mind
	xor	eax, eax
	epilog

end if

if used tui_simpleauth$allow_userpass | defined include_everything
	; three arguments: rdi == our tui_simpleauth object, rsi == string username, rdx == string password
falign
tui_simpleauth$allow_userpass:
	prolog	tui_simpleauth$allow_userpass
	; default here is to deny
	xor	eax, eax
	epilog

end if

if used tui_simpleauth$allow_token | defined include_everything
	; two arguments: rdi == our tui_simpleauth object, rsi == string token
falign
tui_simpleauth$allow_token:
	prolog	tui_simpleauth$allow_token
	; default here is to deny
	xor	eax, eax
	epilog

end if


tui_simpleauth_newuserform = 99

if used tui_simpleauth$create_newuser | defined include_everything
	; three arguments: rdi == our tui_simpleauth object, rsi == string username, rdx == string password
	; NOTE: a null return for this == success, a string pointer return == denied, and the string itself is the error message
	; also note: the return is meant to be static, e.g. the calling handler below will not attempt to free it
	; changing it to dynamic should the need ever arise just needs modifying here and below for when it is called
falign
tui_simpleauth$create_newuser:
	prolog	tui_simpleauth$create_newuser
	; default is to return an error string
	mov	rax, .denied
	epilog
cleartext .denied, 'Fail: Administratively Prohibited'

end if




if used tui_simpleauth$enterpressed | defined include_everything
	; single argument in rdi: our tui_simpleauth object
	; this is called for the "submit" action, either we have a user/pass, or we have a token
falign
tui_simpleauth$enterpressed:
	prolog	tui_simpleauth$enterpressed
	push	rbx r12 r13
	mov	rbx, rdi
	cmp	dword [rdi+tui_simpleauth_authtype_ofs], tui_simpleauth_newuserform
	je	.newuserform
	cmp	dword [rdi+tui_simpleauth_authtype_ofs], tui_simpleauth_token
	je	.token
	; otherwise, normal or newuser
	mov	rax, [rdi+tui_simpleauth_panel_ofs]
	mov	rdi, [rax+tui_authpanel_username_ofs]
	mov	r13, [rax+tui_authpanel_password_ofs]
	call	tui_text$nvgettext
	mov	r12, rax
	mov	rdi, r13
	call	tui_text$nvgettext
	mov	rdx, rax
	mov	rsi, r12
	mov	rdi, rbx
	mov	r13, rax
	mov	rcx, [rbx]
	call	qword [rcx+tui_simpleauth_vuserpass]
	push	rax
	mov	rdi, r13
	call	heap$free_clear
	pop	rax
	mov	rdx, .t1
	jmp	.authed
cleartext .t1, 'Incorrect username or password'
calign
.token:
	mov	rax, [rdi+tui_simpleauth_panel_ofs]
	mov	rdi, [rax+tui_authpanel_token_ofs]
	call	tui_text$nvgettext
	mov	r12, rax
	mov	rsi, rax
	mov	rdi, rbx
	mov	rdx, [rbx]
	call	qword [rdx+tui_simpleauth_vtoken]
	mov	rdx, .t2
	jmp	.authed
cleartext .t2, 'Invalid access token'
cleartext .t3, 'Passwords do not match'
calign
.newuserform:
	; quick sidestep to make sure both password fields match
	mov	rax, [rdi+tui_simpleauth_panel_ofs]
	mov	rdi, [rax+tui_authpanel_username_ofs]
	mov	r13, [rax+tui_authpanel_password_ofs]
	push	qword [rax+tui_authpanel_token_ofs]
	call	tui_text$nvgettext
	mov	r12, rax
	mov	rdi, r13
	call	tui_text$nvgettext
	mov	r13, rax
	pop	rdi
	call	tui_text$nvgettext
	; compare both passwords
	push	rax
	mov	rdi, rax
	mov	rsi, r13
	call	string$equals
	test	eax, eax
	jz	.passwords_mismatch
	; otherwise, we can free the passdup entry
	pop	rdi
	call	heap$free_clear

	; now we can proceed with our simpleauth
	mov	rdi, rbx
	mov	rsi, r12
	mov	rdx, r13
	mov	rcx, [rbx]
	call	qword [rcx+tui_simpleauth_vnewuser]
	mov	rdi, r13
	mov	r13, rax
	call	heap$free_clear
	mov	rax, r13
	mov	rdx, .t1
	test	rax, rax
	jz	.success
	mov	rdi, rax
	mov	esi, [rbx+tui_simpleauth_retrytime_ofs]
	mov	rdx, rbx
if tui_simpleauth_newuserfail_exit
	mov	ecx, 1						; exit, not retry
else
	xor	ecx, ecx					; retry
end if
	call	tui_authfail$new
	mov	[rbx+tui_simpleauth_fail_ofs], rax
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_panel_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vremovechild]
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_fail_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	mov	rdi, rbx
	mov	rdx, [rdi]
	call	qword [rdx+tui_vhidecursor]
	; new user attempts shouldn't necessarily increase the retrytime
	; shl	dword [rbx+tui_simpleauth_retrytime_ofs], 1
	mov	rdi, r12
	call	heap$free
	pop	r13 r12 rbx
	epilog
calign
.passwords_mismatch:
	; free the passdup entry
	pop	rdi
	call	heap$free_clear
	mov	rdi, r13
	call	heap$free_clear
	mov	rdi, r12
	call	heap$free
	; fire up an authfailed
	mov	rdi, .t3
	mov	esi, 3			; 3 seconds at most
	; mov	esi, [rbx+tui_simpleauth_retrytime_ofs]
	mov	rdx, rbx
	xor	ecx, ecx
	call	tui_authfail$new
	mov	[rbx+tui_simpleauth_fail_ofs], rax
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_panel_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vremovechild]
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_fail_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	mov	rdi, rbx
	mov	rdx, [rdi]
	call	qword [rdx+tui_vhidecursor]
	; new user attempts shouldn't necessarily increase the retrytime
	; shl	dword [rbx+tui_simpleauth_retrytime_ofs], 1
	pop	r13 r12 rbx
	epilog
calign
.authed:
	test	eax, eax
	jnz	.success
	; otherwise, fire up an authfail dialog with a retry countdown
	mov	rdi, rdx
	mov	esi, [rbx+tui_simpleauth_retrytime_ofs]
	mov	rdx, rbx
	xor	ecx, ecx
	call	tui_authfail$new
	mov	[rbx+tui_simpleauth_fail_ofs], rax
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_panel_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vremovechild]
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_fail_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	mov	rdi, rbx
	mov	rdx, [rdi]
	call	qword [rdx+tui_vhidecursor]
	shl	dword [rbx+tui_simpleauth_retrytime_ofs], 1
	mov	rdi, r12
	call	heap$free
	pop	r13 r12 rbx
	epilog
calign
.success:
	; this is a bit of evilness here... we need to commit suicide, and add a cloned version
	; of our onsuccess ... this is kinda bad form, but it is either a timer handler or
	; keyevent, both of which will stack unwind cleanly even if the tui_object chain gets
	; all jacked up...

	; set our cursor back to home position for good measure, let our onsuccess deal with it
	; from there
	mov	rdi, rbx
	xor	esi, esi
	xor	edx, edx
	mov	rcx, [rdi]
	call	qword [rcx+tui_vsetcursor]
	
	; remove ourselves, and add our cloned onsuccess
	mov	rdi, [rbx+tui_parent_ofs]
	mov	rsi, rbx
	mov	rdx, [rdi]
	call	qword [rdx+tui_vremovechild]
	mov	rdi, [rbx+tui_simpleauth_onsuccess_ofs]
	mov	rsi, r12					; NOTE: we pass the username/token as an argument to clone here
	mov	rdx, [rbx+tui_parent_ofs]			; as well as our actual parent (useful for finding the top of the chain inside clone)
	mov	rcx, [rdi]
	call	qword [rcx+tui_vclone]
	mov	rdi, [rbx+tui_parent_ofs]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	; last but not least, *cough*, delete ourselves
	mov	rdi, rbx
	mov	rsi, [rdi]
	call	qword [rsi+tui_vcleanup]
	mov	rdi, rbx
	call	heap$free
	
	mov	rdi, r12
	call	heap$free

	pop	r13 r12 rbx
	epilog

end if


if used tui_simpleauth$canretry | defined include_everything
	; single argument in rdi: our tui_simpleauth object
	; this gets called after our countdown expires from tui_authfail
falign
tui_simpleauth$canretry:
	prolog	tui_simpleauth$canretry
	push	rbx
	mov	rbx, rdi
	mov	rdi, [rdi+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_fail_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vremovechild]
	mov	rdi, [rbx+tui_simpleauth_fail_ofs]
	mov	rsi, [rdi]
	call	qword [rsi+tui_vcleanup]
	mov	rdi, [rbx+tui_simpleauth_fail_ofs]
	call	heap$free
	mov	qword [rbx+tui_simpleauth_fail_ofs], 0
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_panel_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	mov	rdi, rbx
	mov	rsi, [rdi]
	call	qword [rsi+tui_vshowcursor]

	pop	rbx
	epilog

end if



if used tui_simpleauth$newuserclicked | defined include_everything
	; single argument in rdi: our tui_simpleauth object
falign
tui_simpleauth$newuserclicked:
	prolog	tui_simpleauth$newuserclicked
	push	rbx r12 r13
	mov	rbx, rdi

	; so really what we want to happen here is to replace the authpanel with a new authpanel, that has different
	; labels for the fields/button

	; and since it lives in mid, that would ordinarily be a simple swap out, BUT: things get interesting here
	; because the button action is fired when the button comes back up, and thus is a nested click event
	; from decently far down a stackchain, so we can't really just delete the authpanel and replace it quicksmart
	; which is why we have oldpanel :-)
	; this way, if we do swap them out, during our proper cleanup, oldpanel will _also_ get cleaned up if it
	; is set by this routine here
	; since we know that this can only happen once (there is no going back to the original panel after new user
	; is clicked)
	; we don't have to check much here

	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_panel_ofs]
	mov	[rbx+tui_simpleauth_oldpanel_ofs], rsi
	mov	rdx, [rdi]
	mov	r12, [rsi+tui_authpanel_username_ofs]
	mov	r13, [rsi+tui_authpanel_password_ofs]
	call	qword [rdx+tui_vremovechild]

	; now we need text representations of the username and password fields, in case they entered stuff there
	; before they hit new-user
	mov	rdi, r12
	call	tui_text$nvgettext
	mov	r12, rax
	mov	rdi, r13
	call	tui_text$nvgettext
	mov	r13, rax

	; now we can create our new authpanel
	mov	edi, 46
	mov	esi, 7
	mov	rdx, rbx
	mov	ecx, 1
	call	tui_authpanel$new
	mov	[rbx+tui_simpleauth_panel_ofs], rax
	mov	rdi, rax
	call	tui_authpanel$normalsetup
	; set their initial text
	mov	rdx, [rbx+tui_simpleauth_panel_ofs]
	mov	rsi, r12
	mov	rdi, [rdx+tui_authpanel_username_ofs]
	call	tui_text$nvsettext
	mov	rdx, [rbx+tui_simpleauth_panel_ofs]
	mov	rsi, r13
	mov	rdi, [rdx+tui_authpanel_password_ofs]
	call	tui_text$nvsettext
	; if any text was specified, it is possible that we need to auto-set the focus
	; to the first non-empty
	cmp	qword [r12], 0
	je	.skipfocus
	; otherwise, username was non-empty, so move focus
	mov	rdx, [rbx+tui_simpleauth_panel_ofs]
	mov	rdi, [rdx+tui_authpanel_username_ofs]
	mov	rsi, [rdi]
	call	qword [rsi+tui_vlostfocus]
	mov	rdx, [rbx+tui_simpleauth_panel_ofs]
	mov	rdi, [rdx+tui_authpanel_password_ofs]
	mov	rsi, [rdi]
	call	qword [rsi+tui_vgotfocus]
	cmp	qword [r13], 0
	je	.skipfocus
	; otherwise, password was also non-empty, move focus to passdup
	mov	rdx, [rbx+tui_simpleauth_panel_ofs]
	mov	rdi, [rdx+tui_authpanel_password_ofs]
	mov	rsi, [rdi]
	call	qword [rsi+tui_vlostfocus]
	mov	rdx, [rbx+tui_simpleauth_panel_ofs]
	mov	rdi, [rdx+tui_authpanel_token_ofs]
	mov	rsi, [rdi]
	call	qword [rsi+tui_vgotfocus]
calign
.skipfocus:
	; clean those up
	mov	rdi, r13
	call	heap$free
	mov	rdi, r12
	call	heap$free

	; add that to our mid
	mov	rdi, [rbx+tui_simpleauth_mid_ofs]
	mov	rsi, [rbx+tui_simpleauth_panel_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	; last but not least, set our authtype to newuserform
	mov	dword [rbx+tui_simpleauth_authtype_ofs], tui_simpleauth_newuserform

	mov	rdi, rbx
	mov	rsi, [rdi]
	call	qword [rsi+tui_vshowcursor]
	
	pop	r13 r12 rbx
	epilog

end if




; ---------- the other goodies that the simpleauth screen needs:


if used tui_authfail$vtable | defined include_everything

dalign
tui_authfail$vtable:
        dq      tui_authfail$cleanup, tui_authfail$clone, tui_panel$draw, tui_object$redraw, tui_object$updatedisplaylist, tui_object$sizechanged
        dq      tui_authfail$timer, tui_object$layoutchanged, tui_object$move, tui_object$setfocus, tui_object$gotfocus, tui_object$lostfocus
        dq      tui_object$keyevent, tui_object$domodal, tui_object$endmodal, tui_object$exit, tui_object$calcbounds, tui_object$calcchildbounds
        dq      tui_panel$appendchild, tui_object$appendbastard, tui_panel$prependchild, tui_panel$contains, tui_panel$getchildindex
        dq      tui_panel$removechild, tui_object$removebastard, tui_object$removeallchildren, tui_object$removeallbastards
        dq      tui_object$getobjectsunderpoint, tui_object$flatten, tui_object$firekeyevent, tui_object$ontab, tui_object$onshifttab
        dq      tui_object$setcursor, tui_object$showcursor, tui_object$hidecursor, tui_object$click, tui_object$clicked

tui_authfail_as_ofs = tui_panel_size
tui_authfail_countdown_ofs = tui_panel_size + 8
tui_authfail_retrylabel_ofs = tui_panel_size + 16
tui_authfail_formatter_ofs = tui_panel_size + 24
tui_authfail_timerptr_ofs = tui_panel_size + 32
tui_authfail_exit_ofs = tui_panel_size + 40

tui_authfail_size = tui_panel_size + 48

end if

if used tui_authfail$new | defined include_everything
	; four arguments: rdi == string message to display, esi == retry time in seconds, rdx == tui_simpleauth object, ecx == bool as to whether we should exit after the countdown, or retry
falign
tui_authfail$new:
	prolog	tui_authfail$new
	sub	rsp, 40
	mov	[rsp], rdi
	mov	[rsp+8], rsi
	mov	[rsp+16], rdx
	mov	[rsp+32], rcx
	mov	edi, tui_authfail_size
	call	heap$alloc
	mov	qword [rax], tui_authfail$vtable
	mov	rdi, rax
	mov	esi, 38
	mov	edx, 6
	mov	[rsp+24], rax
	mov	rcx, .t1
	mov	r10, .t5
	cmp	dword [rsp+32], 0
	cmovne	rcx, r10
	ansi_colors r8d, 'black', 'cyan'
	ansi_colors r9d, 'black', 'cyan'
	call	tui_panel$init_ii
	mov	rax, [rsp+24]
	mov	rsi, [rsp+8]
	mov	rdx, [rsp+16]
	mov	rcx, [rsp+32]
	mov	[rax+tui_authfail_as_ofs], rdx
	mov	[rax+tui_authfail_exit_ofs], rcx
	cvtsi2sd xmm0, esi
	movq	rsi, xmm0
	mov	[rax+tui_authfail_countdown_ofs], rsi
	mov	qword [rax+tui_authfail_timerptr_ofs], 0
	movq	xmm0, [_math_onehundred]
	call	tui_hspacer$new_d
	mov	rdi, [rsp+24]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	mov	rax, [rsp+24]
	movq	xmm0, [_math_onehundred]
	mov	edi, 1
	mov	rsi, [rsp]
	mov	edx, [rax+tui_panel_titlecolors_ofs]
	mov	ecx, tui_textalign_center
	call	tui_label$new_di
	mov	rdi, [rsp+24]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	xor	edi, edi
	call	formatter$new
	mov	rdi, rax
	mov	rax, [rsp+24]
	mov	[rax+tui_authfail_formatter_ofs], rdi
	mov	rsi, .t2
	mov	rdx, .t4
	cmp	dword [rsp+32], 0
	cmovne	rsi, rdx
	mov	[rsp+16], rdi
	call	formatter$add_static
	mov	rdi, [rsp+16]
	mov	esi, double_string_fixed
	mov	edx, 1
	xor	ecx, ecx
	call	formatter$add_double
	mov	rdi, [rsp+16]
	mov	rsi, .t3
	call	formatter$add_static
	mov	rax, [rsp+24]
	mov	rdi, [rsp+16]
	movq	xmm0, [rax+tui_authfail_countdown_ofs]
	call	formatter$doit
	mov	[rsp+8], rax
	movq	xmm0, [_math_onehundred]
	mov	edi, 1
	mov	rsi, rax
	ansi_colors edx, 'venetianred', 'cyan'
	mov	ecx, tui_textalign_center
	call	tui_label$new_di
	mov	rdi, [rsp+24]
	mov	[rdi+tui_authfail_retrylabel_ofs], rax
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	mov	rdi, [rsp+8]
	call	heap$free
	; last but not least, fire up our timer
	mov	edi, 100
	mov	rsi, [rsp+24]
	call	epoll$timer_new
	mov	dword [rax+24], 2		; we don't want the epoll layer to kill us off
	mov	rdi, [rsp+24]
	mov	[rdi+tui_authfail_timerptr_ofs], rax
	
	mov	rax, [rsp+24]
	add	rsp, 40
	epilog
cleartext .t1, 'Authentication Failed'
cleartext .t2, 'Retry in '
cleartext .t3, '...'
cleartext .t4, 'Exit in '
cleartext .t5, 'Failed'

end if

if used tui_authfail$clone | defined include_everything
	; this shouldn't be called, and is only here for sanity
falign
tui_authfail$clone:
	prolog	tui_authfail$clone
	breakpoint
	epilog

end if

if used tui_authfail$cleanup | defined include_everything
	; single argument in rdi: our tui_authfail object
falign
tui_authfail$cleanup:
	prolog	tui_authfail$cleanup
	push	rdi
	mov	rdi, [rdi+tui_authfail_formatter_ofs]
	call	formatter$destroy
	pop	rdi
	; if we have a timerptr, we have to timer_clear it, otherwise, normal tui_panel cleanup will work fine
	cmp	qword [rdi+tui_authfail_timerptr_ofs], 0
	je	.simple
	push	rdi
	mov	rdi, [rdi+tui_authfail_timerptr_ofs]
	mov	qword [rdi+tui_authfail_timerptr_ofs], 0
	call	epoll$timer_clear
	pop	rdi
	call	tui_panel$cleanup
	epilog
calign
.simple:
	call	tui_panel$cleanup
	epilog

end if

if used tui_authfail$timer | defined include_everything
	; single argument in rdi: our tui_authfail object
falign
tui_authfail$timer:
	prolog	tui_authfail$timer
	xorpd	xmm1, xmm1
	movq	xmm0, [rdi+tui_authfail_countdown_ofs]
	subsd	xmm0, [.dotone]
	movq	[rdi+tui_authfail_countdown_ofs], xmm0
	ucomisd xmm0, xmm1
	jbe	.ready
	push	rdi
	mov	rdi, [rdi+tui_authfail_formatter_ofs]
	call	formatter$doit
	mov	rdi, [rsp]
	push	rax
	mov	rdi, [rdi+tui_authfail_retrylabel_ofs]
	mov	rsi, rax
	call	tui_label$nvsettext
	pop	rdi
	call	heap$free
	pop	rdi
	xor	eax, eax		; don't kill the timer
	epilog
calign
.ready:
	mov	qword [rdi+tui_authfail_timerptr_ofs], 0
	cmp	dword [rdi+tui_authfail_exit_ofs], 0
	jne	.doexit
	mov	rdi, [rdi+tui_authfail_as_ofs]
	call	tui_simpleauth$canretry
	mov	eax, 1			; kill the timer
	epilog
dalign
.dotone	dq	0.1f
calign
.doexit:
	mov	esi, 1
	mov	rdx, [rdi]
	call	qword [rdx+tui_vexit]
	mov	eax, 1			; kill the timer
	epilog

end if


if used tui_autheditor$vtable | defined include_everything

dalign
tui_autheditor$vtable:
        dq      tui_text$cleanup, tui_text$clone, tui_text$draw, tui_object$redraw, tui_object$updatedisplaylist, tui_object$sizechanged
        dq      tui_object$timer, tui_object$layoutchanged, tui_object$move, tui_object$setfocus, tui_text$gotfocus, tui_text$lostfocus
        dq      tui_text$keyevent, tui_object$domodal, tui_object$endmodal, tui_object$exit, tui_object$calcbounds, tui_object$calcchildbounds
        dq      tui_object$appendchild, tui_object$appendbastard, tui_object$prependchild, tui_object$contains, tui_object$getchildindex
        dq      tui_object$removechild, tui_object$removebastard, tui_object$removeallchildren, tui_object$removeallbastards
        dq      tui_object$getobjectsunderpoint, tui_object$flatten, tui_object$firekeyevent, tui_object$ontab, tui_object$onshifttab
        dq      tui_text$setcursor, tui_object$showcursor, tui_object$hidecursor, tui_object$click, tui_object$clicked
        ; we add one method to our vtable for onenter handling
        dq      tui_autheditor$onenter

end if

if used tui_autheditor$new | defined include_everything
	; six arguments: edi == width, esi == height, rdx == initialtext, ecx == colors, r8d == focuscolors, r9 == authpanel
falign
tui_autheditor$new:
	prolog	tui_autheditor$new
	push	r9
	mov	r9d, 1
	call	tui_text$new_ii
	mov	qword [rax], tui_autheditor$vtable
	pop	r9
	mov	[rax+tui_text_user_ofs], r9
	epilog

end if

if used tui_autheditor$onenter | defined include_everything
	; single argument in rdi: our tui_autheditor object
falign
tui_autheditor$onenter:
	prolog	tui_autheditor$onenter
	mov	rsi, rdi
	mov	rdi, [rdi+tui_text_user_ofs]
	call	tui_authpanel$enterpressed
	epilog

end if

if used tui_authpanel$vtable | defined include_everything

dalign
tui_authpanel$vtable:
        dq      tui_panel$cleanup, tui_authpanel$clone, tui_panel$draw, tui_object$redraw, tui_object$updatedisplaylist, tui_object$sizechanged
        dq      tui_object$timer, tui_object$layoutchanged, tui_object$move, tui_object$setfocus, tui_object$gotfocus, tui_object$lostfocus
        dq      tui_authpanel$keyevent, tui_object$domodal, tui_object$endmodal, tui_object$exit, tui_object$calcbounds, tui_object$calcchildbounds
        dq      tui_panel$appendchild, tui_object$appendbastard, tui_panel$prependchild, tui_panel$contains, tui_panel$getchildindex
        dq      tui_panel$removechild, tui_object$removebastard, tui_object$removeallchildren, tui_object$removeallbastards
        dq      tui_object$getobjectsunderpoint, tui_object$flatten, tui_object$firekeyevent, tui_authpanel$ontab, tui_authpanel$onshifttab
        dq      tui_object$setcursor, tui_object$showcursor, tui_object$hidecursor, tui_object$click, tui_authpanel$clicked

tui_authpanel_username_ofs = tui_panel_size
tui_authpanel_password_ofs = tui_panel_size + 8
tui_authpanel_token_ofs = tui_panel_size + 16			; also gets re-used as a duplicate pass entry for new user form
tui_authpanel_newuserbutton_ofs = tui_panel_size + 24
tui_authpanel_inputcolors_ofs = tui_panel_size + 32
tui_authpanel_focusinputcolors_ofs = tui_panel_size + 40
tui_authpanel_as_ofs = tui_panel_size + 48
tui_authpanel_newform_ofs = tui_panel_size + 56

tui_authpanel_size = tui_panel_size + 64

end if

if used tui_authpanel$new | defined include_everything
	; four arguments: edi == width, esi == height, rdx == pointer to the tui_simpleauth object, ecx == bool as to whether it is a new form or not
falign
tui_authpanel$new:
	prolog	tui_authpanel$new
	sub	rsp, 32
	mov	[rsp], rdi
	mov	[rsp+8], rsi
	mov	[rsp+16], rdx
	mov	[rsp+24], rcx
	mov	edi, tui_authpanel_size
	call	heap$alloc
	mov	qword [rax], tui_authpanel$vtable
	mov	rdi, rax
	mov	esi, [rsp]
	mov	edx, [rsp+8]
	mov	[rsp], rax
	mov	rcx, .t1
	mov	r10, .t2
	ansi_colors r8d, 'black', 'cyan'
	ansi_colors r9d, 'black', 'cyan'
	cmp	dword [rsp+24], 0
	cmove	rcx, r10
	call	tui_panel$init_ii
	mov	rax, [rsp]
	mov	rdx, [rsp+16]
	mov	ecx, [rsp+24]
	xor	r8d, r8d
	ansi_colors r9d, 'lightgray', 'black'
	ansi_colors r10d, 'yellow', 'blue'
	mov	qword [rax], tui_authpanel$vtable
	mov	[rax+tui_authpanel_username_ofs], r8
	mov	[rax+tui_authpanel_password_ofs], r8
	mov	[rax+tui_authpanel_token_ofs], r8
	mov	[rax+tui_authpanel_newuserbutton_ofs], r8
	mov	[rax+tui_authpanel_inputcolors_ofs], r9
	mov	[rax+tui_authpanel_focusinputcolors_ofs], r10
	mov	[rax+tui_authpanel_as_ofs], rdx
	mov	[rax+tui_authpanel_newform_ofs], rcx
	movq	xmm0, [_math_onehundred]
	call	tui_hspacer$new_d
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	mov	rax, [rsp]
	add	rsp, 32
	epilog
cleartext .t1, 'New User Form'
cleartext .t2, 'Authentication Required'

end if

if used tui_authpanel$clone | defined include_everything
	; single argument in rdi: our authpanel to clone
falign
tui_authpanel$clone:
	prolog	tui_authpanel$clone
	push	rdi
	mov	edi, tui_authpanel_size
	call	heap$alloc
	mov	qword [rax], tui_authpanel$vtable
	mov	rsi, [rsp]
	push	rax
	mov	rdi, rax
	call	tui_panel$init_copy
	; so now, we need to set our authpanel-specific state variables
	; NOTE: we cannot set the tui_authpanel_as_ofs yet, because we haven't been
	; added to our real parent yet, it is up to the clone from tui_simpleauth
	; to set that.

	mov	rdi, [rsp]
	mov	rsi, [rsp+8]

	mov	rdx, [rsi+tui_authpanel_inputcolors_ofs]
	mov	rcx, [rsi+tui_authpanel_focusinputcolors_ofs]
	mov	r8, [rsi+tui_authpanel_newform_ofs]
	mov	[rdi+tui_authpanel_inputcolors_ofs], rdx
	mov	[rdi+tui_authpanel_focusinputcolors_ofs], rcx
	mov	[rdi+tui_authpanel_newform_ofs], r8
	xor	edx, edx
	mov	[rdi+tui_authpanel_username_ofs], rdx
	mov	[rdi+tui_authpanel_password_ofs], rdx
	mov	[rdi+tui_authpanel_token_ofs], rdx
	mov	[rdi+tui_authpanel_newuserbutton_ofs], rdx

	mov	rdx, [rdi+tui_panel_guts_ofs]		; our inner guts object, who's tui_children_ofs list has the goods we are after
	mov	rdx, [rdx+tui_children_ofs]
	; see the notes atop re: cloning requirements here
	; the original must be in its INITIAL state, or bad things might happen here
	; so, if the source authpanel has a newuserbutton, then we know to copy the three
	; if it has a token, then the token only
	; otherwise, user and pass

	; for the autheditors:
	; each child in the list is a 100% wide horizontal layout, with its first child as the label
	; and the second child as the autheditor that we are interested in finding
	; for the button, it is a 100% wide vertical layout, with its only child as the one we are interested in

	cmp	qword [rsi+tui_authpanel_newuserbutton_ofs], 0
	jne	.newuserbutton
	cmp	qword [rsi+tui_authpanel_token_ofs], 0
	jne	.token
	; otherwise, username and password are in our guts list
	mov	rsi, [rdx+_list_first_ofs]

	; the first child in the authpanel guts is an hspacer, added by the original new call
	mov	rsi, [rsi+_list_nextofs]

	mov	rdx, [rsi]				; the 100% wide horizontal layout
	mov	rcx, [rdx+tui_children_ofs]		; its child list
	mov	r8, [rcx+_list_first_ofs]
	mov	r8, [r8+_list_nextofs]
	mov	rax, [r8]				; the username
	mov	[rdi+tui_authpanel_username_ofs], rax
	; we also need to set its tui_text_user_ofs back to our authpanel:
	mov	[rax+tui_text_user_ofs], rdi

	mov	rsi, [rsi+_list_nextofs]
	mov	rdx, [rsi]				; the 100% wide horizontal layout
	mov	rcx, [rdx+tui_children_ofs]		; its child list
	mov	r8, [rcx+_list_first_ofs]
	mov	r8, [r8+_list_nextofs]
	mov	rax, [r8]				; the password
	mov	[rdi+tui_authpanel_password_ofs], rax
	; set its linkback:
	mov	[rax+tui_text_user_ofs], rdi
	
	mov	rax, rdi
	add	rsp, 16
	epilog
calign
.token:
	mov	rsi, [rdx+_list_first_ofs]

	; the first child in the authpanel guts is an hspacer, added by the original new call
	mov	rsi, [rsi+_list_nextofs]

	mov	rdx, [rsi]				; the 100% wide horizontal layout
	mov	rcx, [rdx+tui_children_ofs]		; its child list
	mov	r8, [rcx+_list_first_ofs]
	mov	r8, [r8+_list_nextofs]
	mov	rax, [r8]				; the token
	mov	[rdi+tui_authpanel_token_ofs], rax
	; set its linkback:
	mov	[rax+tui_text_user_ofs], rdi

	mov	rax, rdi
	add	rsp, 16
	epilog
calign
.newuserbutton:
	mov	rsi, [rdx+_list_first_ofs]

	; the first child in the authpanel guts is an hspacer, added by the original new call
	mov	rsi, [rsi+_list_nextofs]

	mov	rdx, [rsi]				; the 100% wide horizontal layout
	mov	rcx, [rdx+tui_children_ofs]		; its child list
	mov	r8, [rcx+_list_first_ofs]
	mov	r8, [r8+_list_nextofs]
	mov	rax, [r8]				; the username
	mov	[rdi+tui_authpanel_username_ofs], rax
	; set its linkback:
	mov	[rax+tui_text_user_ofs], rdi

	mov	rsi, [rsi+_list_nextofs]
	mov	rdx, [rsi]				; the 100% wide horizontal layout
	mov	rcx, [rdx+tui_children_ofs]		; its child list
	mov	r8, [rcx+_list_first_ofs]
	mov	r8, [r8+_list_nextofs]
	mov	rax, [r8]				; the password
	mov	[rdi+tui_authpanel_password_ofs], rax
	; set its linkback:
	mov	[rax+tui_text_user_ofs], rdi
	
	; it has a hspacer next, so skip that one
	mov	rsi, [rsi+_list_nextofs]

	mov	rsi, [rsi+_list_nextofs]
	mov	rdx, [rsi]				; the 100% wide centered vertical layout
	mov	rcx, [rdx+tui_children_ofs]		; its child list
	mov	r8, [rcx+_list_first_ofs]
	mov	rax, [r8]				; the newuserbutton
	mov	[rdi+tui_authpanel_newuserbutton_ofs], rax

	mov	rax, rdi
	add	rsp, 16
	epilog
	
end if

if used tui_authpanel$normalsetup | defined include_everything
	; single argument in rdi: our tui_authpanel object
falign
tui_authpanel$normalsetup:
	prolog	tui_authpanel$normalsetup
	push	rbx
	mov	rbx, rdi
	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	mov	qword [rdi], tui_object$simple_vtable
	movq	xmm0, [_math_onehundred]
	mov	esi, 1
	call	tui_object$init_di
	mov	rdi, [rsp]
	mov	dword [rdi+tui_layout_ofs], tui_layout_horizontal
	
	mov	edi, 19
	mov	esi, 1
	mov	rdx, .t1
	mov	ecx, dword [rbx+tui_panel_titlecolors_ofs]
	mov	r8d, tui_textalign_left
	mov	r9d, 11
	mov	r10, .t2
	cmp	dword [rbx+tui_authpanel_newform_ofs], 0
	cmove	rdx, r10
	cmove	edi, r9d
	call	tui_label$new_ii

	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	edi, 24
	mov	esi, 1
	mov	rdx, .t5
	mov	ecx, [rbx+tui_authpanel_inputcolors_ofs]
	mov	r8d, [rbx+tui_authpanel_focusinputcolors_ofs]
	mov	r9, rbx
	call	tui_autheditor$new
	mov	[rbx+tui_authpanel_username_ofs], rax

	mov	dword [rax+tui_text_maxlen_ofs], 32
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	rdi, rbx
	pop	rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	; same again for the password
	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	mov	qword [rdi], tui_object$simple_vtable
	movq	xmm0, [_math_onehundred]
	mov	esi, 1
	call	tui_object$init_di
	mov	rdi, [rsp]
	mov	dword [rdi+tui_layout_ofs], tui_layout_horizontal
	
	mov	edi, 19
	mov	esi, 1
	mov	rdx, .t3
	mov	ecx, dword [rbx+tui_panel_titlecolors_ofs]
	mov	r8d, tui_textalign_left
	mov	r9d, 11
	mov	r10, .t4
	cmp	dword [rbx+tui_authpanel_newform_ofs], 0
	cmove	rdx, r10
	cmove	edi, r9d
	call	tui_label$new_ii

	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	edi, 24
	mov	esi, 1
	mov	rdx, .t5
	mov	ecx, [rbx+tui_authpanel_inputcolors_ofs]
	mov	r8d, [rbx+tui_authpanel_focusinputcolors_ofs]
	mov	r9, rbx
	call	tui_autheditor$new
	mov	[rbx+tui_authpanel_password_ofs], rax

	mov	dword [rax+tui_text_maxlen_ofs], 32
	mov	dword [rax+tui_text_pwdchar_ofs], 'X'
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	rdi, rbx
	pop	rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]


	; if we are a newform, add the password dup entry:
	cmp	dword [rbx+tui_authpanel_newform_ofs], 0
	je	.skip_passdup

	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	mov	qword [rdi], tui_object$simple_vtable
	movq	xmm0, [_math_onehundred]
	mov	esi, 1
	call	tui_object$init_di
	mov	rdi, [rsp]
	mov	dword [rdi+tui_layout_ofs], tui_layout_horizontal
	
	mov	edi, 19
	mov	esi, 1
	mov	rdx, .t6
	mov	ecx, dword [rbx+tui_panel_titlecolors_ofs]
	mov	r8d, tui_textalign_left
	call	tui_label$new_ii

	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	edi, 24
	mov	esi, 1
	mov	rdx, .t5
	mov	ecx, [rbx+tui_authpanel_inputcolors_ofs]
	mov	r8d, [rbx+tui_authpanel_focusinputcolors_ofs]
	mov	r9, rbx
	call	tui_autheditor$new
	mov	[rbx+tui_authpanel_token_ofs], rax

	mov	dword [rax+tui_text_maxlen_ofs], 32
	mov	dword [rax+tui_text_pwdchar_ofs], 'X'
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	rdi, rbx
	pop	rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]


calign
.skip_passdup:
	; set the focus for the username input field

	mov	rdi, [rbx+tui_authpanel_username_ofs]
	mov	rsi, [rdi]
	call	qword [rsi+tui_vgotfocus]

	pop	rbx
	epilog
cleartext .t1, ' Desired Username: '
cleartext .t2, ' Username: '
cleartext .t3, ' Desired Password: '
cleartext .t4, ' Password: '
cleartext .t5, ''
cleartext .t6, ' Re-type Password: '

end if

if used tui_authpanel$newusersetup | defined include_everything
	; single argument in rdi: our tui_authpanel object
falign
tui_authpanel$newusersetup:
	prolog	tui_authpanel$newusersetup
	push	rbx
	mov	rbx, rdi
	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	mov	qword [rdi], tui_object$simple_vtable
	movq	xmm0, [_math_onehundred]
	mov	esi, 1
	call	tui_object$init_di
	mov	rdi, [rsp]
	mov	dword [rdi+tui_layout_ofs], tui_layout_horizontal
	
	mov	edi, 11
	mov	esi, 1
	mov	rdx, .t1
	mov	ecx, dword [rbx+tui_panel_titlecolors_ofs]
	mov	r8d, tui_textalign_left
	call	tui_label$new_ii

	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	edi, 24
	mov	esi, 1
	mov	rdx, .t3
	mov	ecx, [rbx+tui_authpanel_inputcolors_ofs]
	mov	r8d, [rbx+tui_authpanel_focusinputcolors_ofs]
	mov	r9, rbx
	call	tui_autheditor$new
	mov	[rbx+tui_authpanel_username_ofs], rax

	mov	dword [rax+tui_text_maxlen_ofs], 32
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	rdi, rbx
	pop	rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	; same again for the password
	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	mov	qword [rdi], tui_object$simple_vtable
	movq	xmm0, [_math_onehundred]
	mov	esi, 1
	call	tui_object$init_di
	mov	rdi, [rsp]
	mov	dword [rdi+tui_layout_ofs], tui_layout_horizontal
	
	mov	edi, 11
	mov	esi, 1
	mov	rdx, .t2
	mov	ecx, dword [rbx+tui_panel_titlecolors_ofs]
	mov	r8d, tui_textalign_left
	call	tui_label$new_ii

	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	edi, 24
	mov	esi, 1
	mov	rdx, .t3
	mov	ecx, [rbx+tui_authpanel_inputcolors_ofs]
	mov	r8d, [rbx+tui_authpanel_focusinputcolors_ofs]
	mov	r9, rbx
	call	tui_autheditor$new
	mov	[rbx+tui_authpanel_password_ofs], rax

	mov	dword [rax+tui_text_maxlen_ofs], 32
	mov	dword [rax+tui_text_pwdchar_ofs], 'X'
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	rdi, rbx
	pop	rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	; give the username field focus

	mov	rdi, [rbx+tui_authpanel_username_ofs]
	mov	rsi, [rdi]
	call	qword [rsi+tui_vgotfocus]

	; add a new user button as well
	movq	xmm0, [_math_onehundred]
	call	tui_hspacer$new_d
	mov	rdi, rbx
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	mov	qword [rdi], tui_object$simple_vtable
	movq	xmm0, [_math_onehundred]
	mov	esi, 4
	call	tui_object$init_di
	mov	rdi, [rsp]
	mov	dword [rdi+tui_horizalign_ofs], tui_align_center

	; invert our inputcolors for the button
	mov	eax, [rbx+tui_authpanel_inputcolors_ofs]
	xchg	ah, al
	
	mov	rdi, .t4
	mov	esi, [rbx+tui_panel_titlecolors_ofs]
	mov	edx, eax
	mov	ecx, [rbx+tui_authpanel_focusinputcolors_ofs]
	call	tui_button$new

	mov	[rbx+tui_authpanel_newuserbutton_ofs], rax
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	rdi, rbx
	pop	rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]
	
	pop	rbx
	epilog
cleartext .t1, ' Username: '
cleartext .t2, ' Password: '
cleartext .t3, ''
cleartext .t4, 'New User'

end if

if used tui_authpanel$tokensetup | defined include_everything
	; single argument in rdi: our tui_authpanel object
falign
tui_authpanel$tokensetup:
	prolog	tui_authpanel$tokensetup
	push	rbx
	mov	rbx, rdi
	mov	edi, tui_object_size
	call	heap$alloc
	push	rax
	mov	rdi, rax
	mov	qword [rdi], tui_object$simple_vtable
	movq	xmm0, [_math_onehundred]
	mov	esi, 1
	call	tui_object$init_di
	mov	rdi, [rsp]
	mov	dword [rdi+tui_layout_ofs], tui_layout_horizontal
	
	mov	edi, 15
	mov	esi, 1
	mov	rdx, .t1
	mov	ecx, dword [rbx+tui_panel_titlecolors_ofs]
	mov	r8d, tui_textalign_left
	call	tui_label$new_ii

	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	edi, 32
	mov	esi, 1
	mov	rdx, .t2
	mov	ecx, [rbx+tui_authpanel_inputcolors_ofs]
	mov	r8d, [rbx+tui_authpanel_focusinputcolors_ofs]
	mov	r9, rbx
	call	tui_autheditor$new
	mov	[rbx+tui_authpanel_token_ofs], rax
	
	mov	dword [rax+tui_text_pwdchar_ofs], 'X'
	mov	dword [rax+tui_text_maxlen_ofs], 64
	mov	rdi, [rsp]
	mov	rsi, rax
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	rdi, rbx
	pop	rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vappendchild]

	mov	rdi, [rbx+tui_authpanel_token_ofs]
	mov	rsi, [rdi]
	call	qword [rsi+tui_vgotfocus]

	pop	rbx
	epilog
cleartext .t1, ' Access Token: '
cleartext .t2, ''

end if

if used tui_authpanel$keyevent | defined include_everything
	; three arguments: rdi == our tui_authpanel object, esi == key, edx == esc_key
falign
tui_authpanel$keyevent:
	prolog	tui_authpanel$keyevent
	; ok, so we want a few different "overrides" here...
	; if the up or down arrows come through, treat them as tab/shifttab
	cmp	edx, 0x41	; up arrow
	je	.uparrow
	cmp	edx, 0x42	; down arrow
	je	.downarrow
	; if we receive an enter key, the only it will be unhandled by the autheditor
	; is if the newuser button has the focus when it is pressed, so _swallow_ it
	; and same with left/right arrows
	cmp	edx, 0x43	; right arrow
	je	.swallow
	cmp	edx, 0x44	; left arrow
	je	.swallow
	cmp	edx, 13
	je	.swallow
	xor	eax, eax	; unhandled
	epilog
calign
.swallow:
	mov	eax, 1
	epilog
calign
.uparrow:
	; hmmm, should we be using our vtable for these?
	call	tui_authpanel$onshifttab
	mov	eax, 1
	epilog
calign
.downarrow:
	call	tui_authpanel$ontab
	mov	eax, 1
	epilog

end if


if used tui_authpanel$ontab | defined include_everything
	; single argument in rdi: our tui_authpanel object
falign
tui_authpanel$ontab:
	prolog	tui_authpanel$ontab
	mov	rsi, [rdi+tui_authpanel_username_ofs]
	test	rsi, rsi
	jz	.nousername
	cmp	dword [rsi+tui_text_focussed_ofs], 0
	je	.nousername
	push	qword [rdi+tui_authpanel_password_ofs]
	mov	rdi, rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vlostfocus]
	pop	rdi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.nousername:
	mov	rsi, [rdi+tui_authpanel_password_ofs]
	test	rsi, rsi
	jz	.nopassword
	cmp	dword [rsi+tui_text_focussed_ofs], 0
	je	.nopassword
	push	rdi
	mov	rdi, rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vlostfocus]
	pop	rdi
	cmp	qword [rdi+tui_authpanel_newuserbutton_ofs], 0
	jne	.newuserbutton
	cmp	dword [rdi+tui_authpanel_newform_ofs], 0
	jne	.newform
	mov	rdi, [rdi+tui_authpanel_username_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.newform:
	mov	rdi, [rdi+tui_authpanel_token_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.newuserbutton:
	push	rdi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vhidecursor]
	pop	rdi
	mov	rdi, [rdi+tui_authpanel_newuserbutton_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.nopassword:
	cmp	dword [rdi+tui_authpanel_newform_ofs], 0
	jne	.newform2
	mov	rsi, [rdi+tui_authpanel_newuserbutton_ofs]
	test	rsi, rsi
	jz	.nothingtodo
	cmp	dword [rsi+tui_button_focussed_ofs], 0
	je	.nothingtodo
	push	rdi
	push	qword [rdi+tui_authpanel_username_ofs]
	mov	rdi, rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vlostfocus]
	pop	rdi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	pop	rdi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vshowcursor]
	epilog
calign
.newform2:
	push	rdi
	mov	rdi, [rdi+tui_authpanel_token_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vlostfocus]
	pop	rdi
	mov	rdi, [rdi+tui_authpanel_username_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.nothingtodo:
	epilog

end if

if used tui_authpanel$onshifttab | defined include_everything
	; single argument in rdi: our tui_authpanel object
falign
tui_authpanel$onshifttab:
	prolog	tui_authpanel$onshifttab
	mov	rsi, [rdi+tui_authpanel_username_ofs]
	test	rsi, rsi
	jz	.nousername
	cmp	dword [rsi+tui_text_focussed_ofs], 0
	je	.nousername
	push	rdi
	mov	rdi, rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vlostfocus]
	pop	rdi
	cmp	dword [rdi+tui_authpanel_newform_ofs], 0
	jne	.username_token
	cmp	qword [rdi+tui_authpanel_newuserbutton_ofs], 0
	jne	.newuserbutton
	mov	rdi, [rdi+tui_authpanel_password_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.username_token:
	mov	rdi, [rdi+tui_authpanel_token_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.newuserbutton:
	push	rdi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vhidecursor]
	pop	rdi
	mov	rdi, [rdi+tui_authpanel_newuserbutton_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.nousername:
	mov	rsi, [rdi+tui_authpanel_password_ofs]
	test	rsi, rsi
	jz	.nopassword
	cmp	dword[ rsi+tui_text_focussed_ofs], 0
	je	.nopassword
	push	qword [rdi+tui_authpanel_username_ofs]
	mov	rdi, rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vlostfocus]
	pop	rdi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.nopassword:
	cmp	dword [rdi+tui_authpanel_newform_ofs], 0
	jne	.nopassword_token
	mov	rsi, [rdi+tui_authpanel_newuserbutton_ofs]
	test	rsi, rsi
	jz	.nothingtodo
	cmp	dword [rsi+tui_button_focussed_ofs], 0
	je	.nothingtodo
	push	rdi
	push	qword [rdi+tui_authpanel_password_ofs]
	mov	rdi, rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vlostfocus]
	pop	rdi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	pop	rdi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vshowcursor]
	epilog
calign
.nopassword_token:
	mov	rsi, [rdi+tui_authpanel_token_ofs]
	test	rsi, rsi
	jz	.nothingtodo
	cmp	dword [rsi+tui_text_focussed_ofs], 0
	je	.nothingtodo
	; else, up to the password field
	push	rdi
	mov	rdi, rsi
	mov	rdx, [rdi]
	call	qword [rdx+tui_vlostfocus]
	pop	rdi
	mov	rdi, [rdi+tui_authpanel_password_ofs]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vgotfocus]
	epilog
calign
.nothingtodo:
	epilog

end if

if used tui_authpanel$enterpressed | defined include_everything
	; two arguments: rdi == our tui_authpanel object, rsi == the tui_autheditor that has focus and sent us the event
falign
tui_authpanel$enterpressed:
	prolog	tui_authpanel$enterpressed
	; if they hit enter on the username, and the password is not-yet-filled, change focus to the password
	cmp	qword [rdi+tui_authpanel_username_ofs], 0
	je	.submit
	cmp	qword [rdi+tui_authpanel_password_ofs], 0
	je	.submit
	; the username must be non-empty as well
	push	rdi
	mov	rdi, [rdi+tui_authpanel_username_ofs]
	call	tui_text$nvgettext
	push	qword [rax]
	mov	rdi, rax
	call	heap$free
	pop	rcx rdi
	test	rcx, rcx
	jz	.dotab
	; if it is a newform, then we also need to check to make sure the retype password is also set
	cmp	dword [rdi+tui_authpanel_newform_ofs], 0
	jne	.newform
	push	rdi
	mov	rdi, [rdi+tui_authpanel_password_ofs]
	call	tui_text$nvgettext
	push	qword [rax]
	mov	rdi, rax
	call	heap$free
	pop	rcx rdi
	test	rcx, rcx
	jnz	.submit
calign
.dotab:
	mov	rdx, [rdi]
	call	qword [rdx+tui_vontab]
	epilog
calign
.newform:
	sub	rsp, 24
	mov	[rsp], rdi
	mov	rdi, [rdi+tui_authpanel_password_ofs]
	call	tui_text$nvgettext
	mov	[rsp+8], rax
	mov	rdi, [rsp]
	cmp	qword [rax], 0
	je	.newform_tab
	mov	rdi, rax
	call	heap$free
	mov	rdi, [rsp]
	mov	rdi, [rdi+tui_authpanel_token_ofs]
	call	tui_text$nvgettext
	mov	[rsp+8], rax
	mov	rdi, [rsp]
	cmp	qword [rax], 0
	je	.newform_tab
	mov	rdi, rax
	call	heap$free
	mov	rdi, [rsp]
	add	rsp, 24
	jmp	.submit
calign
.newform_tab:
	mov	rdi, [rsp+8]
	call	heap$free
	mov	rdi, [rsp]
	mov	rdx, [rdi]
	call	qword [rdx+tui_vontab]
	add	rsp, 24
	epilog
calign
.submit:
	mov	rdi, [rdi+tui_authpanel_as_ofs]
	call	tui_simpleauth$enterpressed
	epilog

end if

if used tui_authpanel$clicked | defined include_everything
	; two arguments: rdi == our tui_authpanel object, rsi == tui_object that got clicked
falign
tui_authpanel$clicked:
	prolog	tui_authpanel$clicked
	; pass this backward to the simpleauth screen object, it can only mean the new user button was clicked
	; so we don't bother to check that rsi really is the newuserbutton
	mov	rdi, [rdi+tui_authpanel_as_ofs]
	call	tui_simpleauth$newuserclicked
	epilog

end if
