a2d/desktop/desktop_main.s
Joshua Bell 2415869008 Add Control Panel DA.
* Desktop pattern
* Double-click speed
* Joystick calibration
* Insertion point blink speed

Settings live in LCBANK1 at $FF80 and are persisted directly to DESKTOP2 when the DA closes. DeskTop itself is modified to pull values from there. IP blink routines are improved to not slow down when the mouse pointer is over the window.

Fixes #2, #31, #72
2019-07-30 21:22:28 -07:00

16430 lines
416 KiB
ArmAsm

;;; ============================================================
;;; DeskTop - Main Memory Segment
;;;
;;; Compiled as part of desktop.s
;;; ============================================================
;;; ============================================================
;;; Segment loaded into MAIN $4000-$BEFF
;;; ============================================================
.proc desktop_main
dst_path_buf := $1FC0
dynamic_routine_800 := $0800
dynamic_routine_5000 := $5000
dynamic_routine_7000 := $7000
dynamic_routine_9000 := $9000
dynamic_routine_disk_copy = 0
dynamic_routine_format_erase = 1
dynamic_routine_selector1 = 2
dynamic_routine_common = 3
dynamic_routine_file_copy = 4
dynamic_routine_file_delete = 5
dynamic_routine_selector2 = 6
dynamic_routine_restore5000 = 7
dynamic_routine_restore9000 = 8
.org $4000
;; Jump table
;; Entries marked with * are used by DAs
;; "Exported" by desktop.inc
JT_MAIN_LOOP: jmp enter_main_loop
JT_MGTK_RELAY: jmp MGTK_RELAY
JT_SIZE_STRING: jmp compose_blocks_string
JT_DATE_STRING: jmp compose_date_string
JT_SELECT_WINDOW: jmp select_and_refresh_window
JT_AUXLOAD: jmp AuxLoad
JT_EJECT: jmp cmd_eject
JT_REDRAW_ALL: jmp redraw_windows ; *
JT_ITK_RELAY: jmp ITK_RELAY
JT_LOAD_OVL: jmp load_dynamic_routine
JT_CLEAR_SELECTION: jmp clear_selection ; *
JT_MLI_RELAY: jmp MLI_RELAY ; *
JT_COPY_TO_BUF: jmp LoadWindowIconTable
JT_COPY_FROM_BUF: jmp StoreWindowIconTable
JT_NOOP: jmp cmd_noop
JT_FILE_TYPE_STRING: jmp compose_file_type_string
JT_SHOW_ALERT0: jmp ShowAlert
JT_SHOW_ALERT: jmp ShowAlertOption
JT_LAUNCH_FILE: jmp launch_file
JT_CUR_POINTER: jmp set_pointer_cursor ; *
JT_CUR_WATCH: jmp set_watch_cursor
JT_RESTORE_OVL: jmp restore_dynamic_routine
JT_COLOR_MODE: jmp set_color_mode ; *
JT_MONO_MODE: jmp set_mono_mode ; *
JT_RESTORE_SYS: jmp restore_system ; *
.assert JUMP_TABLE_MAIN_LOOP = JT_MAIN_LOOP, error, "Jump table mismatch"
.assert JUMP_TABLE_RESTORE_SYS = JT_RESTORE_SYS, error, "Jump table mismatch"
;; Main Loop
.proc enter_main_loop
cli
;; Add icons (presumably desktop ones?)
ldx #0
iloop: cpx cached_window_icon_count
beq skip
txa
pha
lda cached_window_icon_list,x
jsr icon_entry_lookup
ldy #IconTK::ADD_ICON
jsr ITK_RELAY ; icon entry addr in A,X
pla
tax
inx
jmp iloop
skip: copy #0, cached_window_id
jsr StoreWindowIconTable
;; Clear various flags
lda #0
sta LD2A9
sta double_click_flag
sta loop_counter
sta LE26F
;; Pending error message?
lda pending_alert
beq main_loop
tay
jsr ShowAlert
;; Main loop
main_loop:
jsr reset_grafport3
inc loop_counter
inc loop_counter
lda loop_counter
cmp machine_type ; for per-machine timing
bcc :+
copy #0, loop_counter
jsr show_clock
;; Poll drives for updates
jsr check_disk_inserted_ejected
beq :+
jsr L40E0 ; conditionally ???
: jsr L464E
;; Get an event
jsr get_event
lda event_kind
;; Is it a button-down event? (including w/ modifiers)
cmp #MGTK::EventKind::button_down
beq click
cmp #MGTK::EventKind::apple_key
bne :+
click: jsr handle_click
jmp main_loop
;; Is it a key down event?
: cmp #MGTK::EventKind::key_down
bne :+
jsr handle_keydown
jmp main_loop
;; Is it an update event?
: cmp #MGTK::EventKind::update
bne :+
jsr reset_grafport3
copy active_window_id, L40F0
copy #$80, L40F1
jsr L410D
: jmp main_loop
loop_counter:
.byte 0
;;; --------------------------------------------------
L40E0: tsx
stx saved_stack
sta menu_click_params::item_num
jsr cmd_check_single_drive_by_menu
copy #0, menu_click_params::item_num
rts
L40F0: .byte $00
L40F1: .byte $00
redraw_windows:
jsr reset_grafport3
copy active_window_id, L40F0
copy #$00, L40F1
L4100: jsr peek_event
lda event_kind
cmp #MGTK::EventKind::update
bne L412B
jsr get_event
L410D: jsr L4113
jmp L4100
L4113: MGTK_RELAY_CALL MGTK::BeginUpdate, event_window_id
bne L4151 ; did not really need updating
jsr update_window
MGTK_RELAY_CALL MGTK::EndUpdate
rts
L412B: jsr LoadDesktopIconTable
lda L40F0
sta active_window_id
beq L4143
bit running_da_flag
bmi L4143
jsr redraw_selected_icons
L4143: bit L40F1
bpl L4151
ITK_RELAY_CALL IconTK::REDRAW_ICONS
L4151: rts
.endproc
main_loop := enter_main_loop::main_loop
redraw_windows := enter_main_loop::redraw_windows
;;; ============================================================
draw_window_header_flag: .byte 0
.proc update_window
lda event_window_id
cmp #9 ; only handle windows 1...8
bcc L415B
rts
L415B: sta active_window_id
jsr LoadActiveWindowIconTable
copy #$80, draw_window_header_flag
copy cached_window_id, getwinport_params2::window_id
jsr get_port2
jsr draw_window_header
lda active_window_id
jsr copy_window_portbits
jsr OverwriteWindowPort
lda active_window_id
jsr window_lookup
stax $06
ldy #22
sub16in ($06),y, grafport2::viewloc::ycoord, L4242
cmp16 L4242, #15
bpl L41CB
jsr offset_grafport2
ldx #11
ldy #31
copy grafport2,x, ($06),y
dey
dex
copy grafport2,x, ($06),y
ldx #3
ldy #23
copy grafport2,x, ($06),y
dey
dex
copy grafport2,x, ($06),y
L41CB: ldx cached_window_id
dex
lda win_view_by_table,x
bpl by_icon
jsr L6C19
copy #0, draw_window_header_flag
lda active_window_id
jmp assign_window_portbits
by_icon:
copy cached_window_id, getwinport_params2::window_id
jsr get_set_port2
jsr cached_icons_screen_to_window
COPY_BLOCK grafport2::cliprect, tmp_rect
copy #0, L4241
L41FE: lda L4241
cmp cached_window_icon_count
beq L4227
tax
copy cached_window_icon_list,x, icon_param
ITK_RELAY_CALL IconTK::ICON_IN_RECT, icon_param
beq :+
ITK_RELAY_CALL IconTK::REDRAW_ICON, icon_param
: inc L4241
jmp L41FE
L4227: copy #0, draw_window_header_flag
copy cached_window_id, getwinport_params2::window_id
jsr get_set_port2
jsr cached_icons_window_to_screen
lda active_window_id
jsr assign_window_portbits
jmp reset_grafport3
L4241: .byte 0
L4242: .word 0
.endproc
;;; ============================================================
.proc redraw_selected_icons
lda selected_icon_count
bne :+
bail: rts
: copy #0, num
lda selected_window_index
beq desktop
cmp active_window_id
bne bail
copy active_window_id, getwinport_params2::window_id
jsr get_port2
cmp #MGTK::Error::window_obscured
beq done
jsr offset_grafport2_and_set
COPY_BLOCK grafport2::cliprect, tmp_rect
;; Redraw selected icons in window
window: lda num
cmp selected_icon_count
beq done
tax
copy selected_icon_list,x, icon_param
jsr icon_screen_to_window
ITK_RELAY_CALL IconTK::ICON_IN_RECT, icon_param
beq :+
ITK_RELAY_CALL IconTK::REDRAW_ICON, icon_param
: lda icon_param
jsr icon_window_to_screen
inc num
jmp window
done: jmp reset_grafport3
;; Redraw selected icons on desktop
desktop:
lda num
cmp selected_icon_count
beq done
tax
copy selected_icon_list,x, icon_param
ITK_RELAY_CALL IconTK::REDRAW_ICON, icon_param
inc num
jmp desktop
num: .byte 0
.endproc
;;; ============================================================
;;; Menu Dispatch
.proc handle_keydown_impl
;; Keep in sync with desktop_aux::menu_item_id_*
;; jump table for menu item handlers
dispatch_table:
;; Apple menu (1)
menu1_start := *
.addr cmd_about
.addr cmd_noop ; --------
.repeat ::max_desk_acc_count
.addr cmd_deskacc
.endrepeat
;; File menu (2)
menu2_start := *
.addr cmd_new_folder
.addr cmd_open
.addr cmd_close
.addr cmd_close_all
.addr cmd_select_all
.addr cmd_noop ; --------
.addr cmd_get_info
.addr cmd_rename_icon
.addr cmd_noop ; --------
.addr cmd_copy_file
.addr cmd_delete_file
.addr cmd_noop ; --------
.addr cmd_quit
;; Selector menu (3)
menu3_start := *
.addr cmd_selector_action
.addr cmd_selector_action
.addr cmd_selector_action
.addr cmd_selector_action
.addr cmd_noop ; --------
.addr cmd_selector_item
.addr cmd_selector_item
.addr cmd_selector_item
.addr cmd_selector_item
.addr cmd_selector_item
.addr cmd_selector_item
.addr cmd_selector_item
.addr cmd_selector_item
;; View menu (4)
menu4_start := *
.addr cmd_view_by_icon
.addr cmd_view_by_name
.addr cmd_view_by_date
.addr cmd_view_by_size
.addr cmd_view_by_type
;; Special menu (5)
menu5_start := *
.addr cmd_check_drives
.addr cmd_check_drive
.addr cmd_eject
.addr cmd_noop ; --------
.addr cmd_format_disk
.addr cmd_erase_disk
.addr cmd_disk_copy
.addr cmd_noop ; --------
.addr cmd_lock
.addr cmd_unlock
.addr cmd_get_size
;; 6/7 unused
menu6_start := *
menu7_start := *
;; Startup menu (8)
menu8_start := *
.addr cmd_startup_item
.addr cmd_startup_item
.addr cmd_startup_item
.addr cmd_startup_item
.addr cmd_startup_item
.addr cmd_startup_item
.addr cmd_startup_item
menu_end := *
;; indexed by menu id-1
offset_table:
.byte menu1_start - dispatch_table
.byte menu2_start - dispatch_table
.byte menu3_start - dispatch_table
.byte menu4_start - dispatch_table
.byte menu5_start - dispatch_table
.byte menu6_start - dispatch_table
.byte menu7_start - dispatch_table
.byte menu8_start - dispatch_table
.byte menu_end - dispatch_table
;; Set if there are open windows
flag: .byte $00
;; Handle accelerator keys
handle_keydown:
lda event_modifiers
bne :+ ; either OA or SA ?
jmp menu_accelerators ; nope
: cmp #3 ; both OA + SA ?
bne :+ ; nope
rts
;; Non-menu keys
: lda event_key
jsr upcase_char
cmp #'H' ; OA-H (Highlight Icon)
bne :+
jmp cmd_higlight
: bit flag
bpl menu_accelerators
cmp #'G' ; OA-G (Resize)
bne :+
jmp cmd_resize
: cmp #'M' ; OA-M (Move)
bne :+
jmp cmd_move
: cmp #'X' ; OA-X (Scroll)
bne :+
jmp cmd_scroll
: cmp #CHAR_DELETE ; OA-Delete (Delete)
bne :+
jmp cmd_delete_selection
: cmp #'`' ; OA-` (Cycle Windows)
beq cycle
cmp #CHAR_TAB ; OA-Tab (Cycle Windows)
bne menu_accelerators
cycle: jmp cmd_cycle_windows
menu_accelerators:
copy event_key, LE25C
lda event_modifiers
beq :+
lda #1
: sta LE25D
copy #$80, menu_kbd_flag ; note that source is keyboard
MGTK_RELAY_CALL MGTK::MenuKey, menu_click_params
menu_dispatch2:
ldx menu_click_params::menu_id
bne :+
rts
: dex ; x has top level menu id
lda offset_table,x
tax
ldy menu_click_params::item_num
dey
tya
asl a
sta proc_addr
txa
clc
adc proc_addr
tax
copy16 dispatch_table,x, proc_addr
jsr call_proc
MGTK_RELAY_CALL MGTK::HiliteMenu, menu_click_params
rts
call_proc:
tsx
stx saved_stack
proc_addr := *+1
jmp dummy1234 ; self-modified
.endproc
handle_keydown := handle_keydown_impl::handle_keydown
menu_dispatch2 := handle_keydown_impl::menu_dispatch2
menu_dispatch_flag := handle_keydown_impl::flag
;;; ============================================================
;;; Handle click
.proc handle_click
tsx
stx saved_stack
MGTK_RELAY_CALL MGTK::FindWindow, event_coords
lda findwindow_which_area
bne not_desktop
;; Click on desktop
jsr detect_double_click
sta double_click_flag
copy #0, findwindow_window_id
ITK_RELAY_CALL IconTK::FIND_ICON, event_coords
lda findicon_which_icon
beq :+
jmp handle_volume_icon_click
: jmp L68AA
not_desktop:
cmp #MGTK::Area::menubar ; menu?
bne not_menu
copy #0, menu_kbd_flag ; note that source is not keyboard
MGTK_RELAY_CALL MGTK::MenuSelect, menu_click_params
jmp menu_dispatch2
not_menu:
pha ; which window - active or not?
lda active_window_id
cmp findwindow_window_id
beq handle_active_window_click
pla
jmp handle_inactive_window_click
.endproc
;;; ============================================================
;;; Inputs: MGTK::Area pushed to stack
.proc handle_active_window_click
pla
cmp #MGTK::Area::content
bne :+
jsr detect_double_click
sta double_click_flag
jmp handle_client_click
: cmp #MGTK::Area::dragbar
bne :+
jmp handle_title_click
: cmp #MGTK::Area::grow_box
bne :+
jmp handle_resize_click
: cmp #MGTK::Area::close_box
bne :+
jmp handle_close_click
: rts
.endproc
;;; ============================================================
;;; Inputs: window_id to activate in findwindow_window_id
.proc handle_inactive_window_click
ptr := $6
jmp start
winid: .byte 0
start: jsr clear_selection
;; Select window's corresponding volume icon.
;; (Doesn't work for folder icons as only the active
;; window and desktop can have selections.)
ldx findwindow_window_id
dex
lda window_to_dir_icon_table,x
bmi continue ; $FF = dir icon freed
sta icon_param
lda icon_param
jsr icon_entry_lookup
stax ptr
ldy #IconEntry::state ; set state to open
lda (ptr),y
beq continue
ora #icon_entry_open_mask
sta (ptr),y
iny ; IconEntry::win_type
lda (ptr),y
and #icon_entry_winid_mask
sta winid
jsr zero_grafport5_coords
ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, icon_param
jsr reset_grafport3
copy winid, selected_window_index
copy #1, selected_icon_count
copy icon_param, selected_icon_list
;; Actually make the window active.
continue:
MGTK_RELAY_CALL MGTK::SelectWindow, findwindow_window_id
copy findwindow_window_id, active_window_id
jsr LoadActiveWindowIconTable
jsr L6C19
jsr LoadDesktopIconTable
copy #MGTK::checkitem_uncheck, checkitem_params::check
MGTK_RELAY_CALL MGTK::CheckItem, checkitem_params
ldx active_window_id
dex
lda win_view_by_table,x
and #$0F ; mask off menu item number
sta checkitem_params::menu_item
inc checkitem_params::menu_item
copy #MGTK::checkitem_check, checkitem_params::check
MGTK_RELAY_CALL MGTK::CheckItem, checkitem_params
rts
.endproc
;;; ============================================================
.proc get_set_port2
MGTK_RELAY_CALL MGTK::GetWinPort, getwinport_params2
MGTK_RELAY_CALL MGTK::SetPort, grafport2
rts
.endproc
.proc get_port2
MGTK_RELAY_CALL MGTK::GetWinPort, getwinport_params2
rts
.endproc
.proc reset_grafport3
MGTK_RELAY_CALL MGTK::InitPort, grafport3
MGTK_RELAY_CALL MGTK::SetPort, grafport3
rts
.endproc
;;; ============================================================
.proc redraw_windows_and_desktop
jsr redraw_windows
ITK_RELAY_CALL IconTK::REDRAW_ICONS
rts
.endproc
;;; ============================================================
;;; Update table tracking disk-in-device status, determine if
;;; there was a change (insertion or ejection).
;;; Output: 0 if no change,
.proc check_disk_inserted_ejected
lda disk_in_device_table
beq done
jsr check_disks_in_devices
ldx disk_in_device_table
: lda disk_in_device_table,x
cmp last_disk_in_devices_table,x
bne changed
dex
bne :-
done: return #0
changed:
copy disk_in_device_table,x, last_disk_in_devices_table,x
lda removable_device_table,x
ldy DEVCNT
: cmp DEVLST,y
beq :+
dey
bpl :-
rts
: tya
clc
adc #$03
rts
.endproc
;;; ============================================================
max_removable_devices = 8
removable_device_table:
.byte 0 ; num entries
.res max_removable_devices, 0
;;; Updated by check_disks_in_devices
disk_in_device_table:
.byte 0 ; num entries
.res max_removable_devices, 0
;;; Snapshot of previous results; used to detect changes.
last_disk_in_devices_table:
.byte 0 ; num entries
.res max_removable_devices, 0
;;; ============================================================
.proc check_disks_in_devices
ptr := $6
status_buffer := $800
ldx removable_device_table
beq done
stx disk_in_device_table
: lda removable_device_table,x
jsr check_disk_in_drive
sta disk_in_device_table,x
dex
bne :-
done: rts
check_disk_in_drive:
sta unit_number
txa
pha
tya
pha
sp_addr := $0A
lda unit_number
jsr find_smartport_dispatch_address
bne notsp ; not SmartPort
stx status_unit_num
;; Execute SmartPort call
jsr smartport_call
.byte $00 ; $00 = STATUS
.addr status_params
lda status_buffer
and #$10 ; general status byte, $10 = disk in drive
beq notsp
lda #$FF
bne finish
notsp: lda #0 ; not SmartPort (or no disk in drive)
finish: sta result
pla
tay
pla
tax
return result
smartport_call:
jmp (sp_addr)
unit_number:
.byte 0
result: .byte 0
;; params for call
.proc status_params
param_count: .byte 3
unit_num: .byte 1
list_ptr: .addr status_buffer
status_code: .byte 0
.endproc
status_unit_num := status_params::unit_num
.endproc
;;; ============================================================
.proc L464E
lda num_selector_list_items
beq :+
bit LD344
bmi L4666
jsr enable_selector_menu_items
jmp L4666
: bit LD344
bmi L4666
jsr disable_selector_menu_items
L4666: lda selected_icon_count
beq L46A8
lda selected_window_index
bne L4691
lda selected_icon_count
cmp #2
bcs L4697
lda selected_icon_list
cmp trash_icon_num
bne L468B
jsr disable_eject_menu_item
jsr disable_file_menu_items
copy #0, LE26F
rts
L468B: jsr enable_eject_menu_item
jmp L469A
L4691: jsr disable_eject_menu_item
jmp L469A
L4697: jsr enable_eject_menu_item
L469A: bit LE26F
bmi L46A7
jsr enable_file_menu_items
copy #$80, LE26F
L46A7: rts
L46A8: bit LE26F
bmi L46AE
rts
L46AE: jsr disable_eject_menu_item
jsr disable_file_menu_items
copy #$00, LE26F
rts
.endproc
.proc MLI_RELAY
sty call
stax params
sta ALTZPOFF
sta ROMIN2
jsr MLI
call: .byte $00
params: .addr dummy0000
sta ALTZPON
tax
lda LCBANK1
lda LCBANK1
txa
rts
.endproc
.macro MLI_RELAY_CALL call, addr
yax_call desktop_main::MLI_RELAY, call, addr
.endmacro
;;; ============================================================
;;; Launch file (double-click) ???
.proc launch_file
path := $220
jmp begin
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params, path
begin:
jsr set_watch_cursor
;; Compose window path plus icon path
ldx #$FF
: inx
copy buf_win_path,x, path,x
cpx buf_win_path
bne :-
inx
copy #'/', path,x
ldy #0
: iny
inx
copy buf_filename2,y, path,x
cpy buf_filename2
bne :-
stx path
;; Get the file info to determine type.
MLI_RELAY_CALL GET_FILE_INFO, get_file_info_params
beq :+
jsr ShowAlert
rts
;; Check file type.
: copy get_file_info_params::file_type, fto_type
copy16 get_file_info_params::aux_type, fto_auxtype
copy16 get_file_info_params::blocks_used, fto_blocks
jsr check_file_type_overrides
cmp #FT_BASIC
bne :+
jsr check_basic_system ; Only launch if BASIC.SYSTEM is found
jmp launch
: cmp #FT_BINARY
bne :+
lda BUTN0 ; Only launch if a button is down
ora BUTN1 ; BUG: Never gets this far ???
bmi launch
jsr set_pointer_cursor
rts
: cmp #FT_SYSTEM
beq launch
cmp #APP_FILE_TYPE
beq launch
cmp #FT_GRAPHICS
bne :+
addr_jump invoke_desk_acc, str_preview_fot
: cmp #FT_TEXT
bne :+
addr_jump invoke_desk_acc, str_preview_txt
: cmp #FT_FONT
bne :+
addr_jump invoke_desk_acc, str_preview_fnt
: cmp #DA_FILE_TYPE
bne :+
addr_jump invoke_desk_acc, path
: lda #ERR_FILE_NOT_OPENABLE
jsr show_alert_and_fail
launch: ITK_RELAY_CALL IconTK::REMOVE_ALL, 0 ; volume icons
MGTK_RELAY_CALL MGTK::CloseAll
MGTK_RELAY_CALL MGTK::SetMenu, blank_menu
ldx buf_win_path
: copy buf_win_path,x, path,x
dex
bpl :-
ldx buf_filename2
: copy buf_filename2,x, INVOKER_FILENAME,x
dex
bpl :-
copy16 #INVOKER, reset_and_invoke_target
jmp reset_and_invoke
;;; --------------------------------------------------
.proc check_basic_system_impl
path := $1800
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params2, path
start: ldx buf_win_path
stx path_length
: copy buf_win_path,x, path,x
dex
bpl :-
inc path
ldx path
copy #'/', path,x
loop:
;; Append BASIC.SYSTEM to path and check for file.
ldx path
ldy #0
: inx
iny
copy str_basic_system,y, path,x
cpy str_basic_system
bne :-
stx path
MLI_RELAY_CALL GET_FILE_INFO, get_file_info_params2
bne not_found
rts
;; Pop off a path segment and try again.
not_found:
ldx path_length
: lda path,x
cmp #'/'
beq found_slash
dex
bne :-
no_bs: lda #ERR_BASIC_SYS_NOT_FOUND
show_alert_and_fail:
jsr ShowAlert
pla ; pop caller address, return to its caller
pla
rts
found_slash:
cpx #$01
beq no_bs
stx path
dex
stx path_length
jmp loop
path_length:
.byte 0
str_basic_system:
PASCAL_STRING "Basic.system"
.endproc
check_basic_system := check_basic_system_impl::start
show_alert_and_fail := check_basic_system_impl::show_alert_and_fail
;;; --------------------------------------------------
.endproc
;;; ============================================================
.proc upcase_char
cmp #'a'
bcc done
cmp #'z'+1
bcs done
and #CASE_MASK
done: rts
.endproc
;;; ============================================================
L485D: .word $E000
L485F: .word $D000
;;; ============================================================
set_watch_cursor:
jsr hide_cursor
MGTK_RELAY_CALL MGTK::SetCursor, watch_cursor
jsr show_cursor
rts
set_pointer_cursor:
jsr hide_cursor
MGTK_RELAY_CALL MGTK::SetCursor, pointer_cursor
jsr show_cursor
rts
hide_cursor:
MGTK_RELAY_CALL MGTK::HideCursor
rts
show_cursor:
MGTK_RELAY_CALL MGTK::ShowCursor
rts
;;; ============================================================
.proc restore_device_list
ldx devlst_backup
inx
: copy devlst_backup,x, DEVLST-1,x
dex
bpl :-
rts
.endproc
.proc warning_dialog_proc_num
sta warning_dialog_num
yax_call invoke_dialog_proc, index_warning_dialog, warning_dialog_num
rts
.endproc
copy16 #main_loop, L48E4
L48E4 := *+1
jmp dummy1234 ; self-modified
get_event:
MGTK_RELAY_CALL MGTK::GetEvent, event_params
rts
peek_event:
MGTK_RELAY_CALL MGTK::PeekEvent, event_params
rts
set_penmode_xor:
MGTK_RELAY_CALL MGTK::SetPenMode, penXOR
rts
set_penmode_copy:
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
rts
;;; ============================================================
.proc cmd_noop
rts
.endproc
;;; ============================================================
.proc cmd_selector_action
jsr set_watch_cursor
lda #dynamic_routine_selector1
jsr load_dynamic_routine
bmi done
lda menu_click_params::item_num
cmp #3 ; 1 = Add, 2 = Edit (need more overlays)
bcs :+ ; 3 = Delete, 4 = Run (can skip)
lda #dynamic_routine_selector2
jsr load_dynamic_routine
bmi done
lda #dynamic_routine_common
jsr load_dynamic_routine
bmi done
: jsr set_pointer_cursor
;; Invoke routine
lda menu_click_params::item_num
jsr dynamic_routine_9000
sta result
jsr set_watch_cursor
;; Restore from overlays
lda #dynamic_routine_restore9000
jsr restore_dynamic_routine
lda menu_click_params::item_num
cmp #4 ; 4 = Run ?
bne done
;; "Run" command
lda result
bpl done
jsr make_ramcard_prefixed_path
jsr strip_path_segments
jsr get_copied_to_ramcard_flag
bpl L497A
jsr jt_run
bmi done
jsr L4968
done: jsr set_pointer_cursor
jsr redraw_windows_and_desktop
rts
.proc L4968
jsr make_ramcard_prefixed_path
COPY_STRING $840, buf_win_path
jmp launch_buf_win_path
.endproc
L497A: jsr make_ramcard_prefixed_path
COPY_STRING $800, buf_win_path
jsr launch_buf_win_path
jmp done
result: .byte 0
.endproc
;;; ============================================================
.proc cmd_selector_item_impl
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params3, $220
start:
jmp L49A6
entry_num:
.byte 0
L49A6: lda menu_click_params::item_num
sec
sbc #6 ; 4 items + separator (and make 0 based)
sta entry_num
jsr a_times_16
addax #run_list_entries, $06
ldy #$0F ; flag byte following name
lda ($06),y
asl a
bmi not_downloaded ; bit 6
bcc L49E0 ; bit 7
jsr get_copied_to_ramcard_flag
beq not_downloaded
lda entry_num
jsr check_downloaded_path
beq L49ED
lda entry_num
jsr L4A47
jsr jt_run
bpl L49ED
jmp redraw_windows_and_desktop
L49E0: jsr get_copied_to_ramcard_flag
beq not_downloaded
lda entry_num
jsr check_downloaded_path ; was-downloaded flag check?
bne not_downloaded
L49ED: lda entry_num
jsr compose_downloaded_entry_path
stax $06
jmp L4A0A
not_downloaded:
lda entry_num
jsr a_times_64
addax #run_list_paths, $06
L4A0A: ldy #$00
lda ($06),y
tay
L4A0F: lda ($06),y
sta buf_win_path,y
dey
bpl L4A0F
;; fall through
.proc launch_buf_win_path
;; Find last '/'
ldy buf_win_path
: lda buf_win_path,y
cmp #'/'
beq :+
dey
bpl :-
: dey
sty slash_index
;; Copy filename to buf_filename2
ldx #0
iny
: iny
inx
lda buf_win_path,y
sta buf_filename2,x
cpy buf_win_path
bne :-
;; Truncate path
stx buf_filename2
lda slash_index
sta buf_win_path
lda #0
jmp launch_file
slash_index:
.byte 0
.endproc
;;; --------------------------------------------------
;; Copy entry path to $800
.proc L4A47
pha
jsr a_times_64
addax #run_list_paths, $06
ldy #0
lda ($06),y
tay
: lda ($06),y
sta $800,y
dey
bpl :-
pla
;; Copy "down loaded" path to $840
jsr compose_downloaded_entry_path
stax $08
ldy #0
lda ($08),y
tay
: lda ($08),y
sta $840,y
dey
bpl :-
;; fall through
.endproc
;; Strip segment off path at $800
.proc strip_path_segments
ldy $800
: lda $800,y
cmp #'/'
beq :+
dey
bne :-
: dey
sty $800
;; Strip segment off path at $840
ldy $840
: lda $840,y
cmp #'/'
beq :+
dey
bne :-
: dey
sty $840
;; Return addresses in $6 and $8
copy16 #$800, $06
copy16 #$840, $08
jsr copy_paths_and_split_name
rts
.endproc
;;; --------------------------------------------------
;;; Append last two path segments of buf_win_path to
;;; ramcard_prefix, result left at $840
.proc make_ramcard_prefixed_path
;; Copy window path to $800
ldy buf_win_path
: lda buf_win_path,y
sta $800,y
dey
bpl :-
addr_call copy_ramcard_prefix, $840
;; Find last '/' in path...
ldy $800
: lda $800,y
cmp #'/'
beq :+
dey
bne :-
;; And back up one more path segment...
: dey
: lda $800,y
cmp #'/'
beq :+
dey
bne :-
: dey
ldx $840
: iny
inx
lda $800,y
sta $840,x
cpy $800
bne :-
rts
.endproc
.proc check_downloaded_path
jsr compose_downloaded_entry_path
stax get_file_info_params3::pathname
MLI_RELAY_CALL GET_FILE_INFO, get_file_info_params3
rts
.endproc
.endproc
cmd_selector_item := cmd_selector_item_impl::start
launch_buf_win_path := cmd_selector_item_impl::launch_buf_win_path
strip_path_segments := cmd_selector_item_impl::strip_path_segments
make_ramcard_prefixed_path := cmd_selector_item_impl::make_ramcard_prefixed_path
;;; ============================================================
;;; Get "copied to RAM card" flag from Main LC Bank 2.
.proc get_copied_to_ramcard_flag
sta ALTZPOFF
lda LCBANK2
lda LCBANK2
lda copied_to_ramcard_flag
tax
sta ALTZPON
lda LCBANK1
lda LCBANK1
txa
rts
.endproc
.proc copy_ramcard_prefix
stax @destptr
sta ALTZPOFF
lda LCBANK2
lda LCBANK2
ldx ramcard_prefix
: lda ramcard_prefix,x
@destptr := *+1
sta dummy1234,x
dex
bpl :-
sta ALTZPON
lda LCBANK1
lda LCBANK1
rts
.endproc
.proc copy_desktop_orig_prefix
stax @destptr
sta ALTZPOFF
lda LCBANK2
lda LCBANK2
ldx desktop_orig_prefix
: lda desktop_orig_prefix,x
@destptr := *+1
sta dummy1234,x
dex
bpl :-
sta ALTZPON
lda LCBANK1
lda LCBANK1
rts
.endproc
;;; ============================================================
;;; For entry copied ("down loaded") to RAM card, compose path
;;; using RAM card prefix plus last two segments of path
;;; (e.g. "/RAM" + "/" + "MOUSEPAINT/MP.SYSTEM") into path_buffer
.proc compose_downloaded_entry_path
sta entry_num
;; Initialize buffer
addr_call copy_ramcard_prefix, path_buffer
;; Find entry path
lda entry_num
jsr a_times_64
addax #run_list_paths, $06
ldy #0
lda ($06),y
sta prefix_length
;; Walk back one segment
tay
: lda ($06),y
and #CHAR_MASK
cmp #'/'
beq :+
dey
bne :-
: dey
;; Walk back a second segment
: lda ($06),y
and #CHAR_MASK
cmp #'/'
beq :+
dey
bne :-
: dey
;; Append last two segments to path
ldx path_buffer
: inx
iny
lda ($06),y
sta path_buffer,x
cpy prefix_length
bne :-
stx path_buffer
ldax #path_buffer
rts
entry_num:
.byte 0
prefix_length:
.byte 0
.endproc
;;; ============================================================
.proc cmd_about
yax_call invoke_dialog_proc, index_about_dialog, $0000
jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
.proc cmd_deskacc_impl
ptr := $6
.define prefix "Desk.acc/"
prefix_length = .strlen(prefix)
str_desk_acc:
PASCAL_STRING prefix, prefix_length + 15
start: jsr reset_grafport3
jsr set_watch_cursor
;; Find DA name
lda menu_click_params::item_num ; menu item index (1-based)
sec
sbc #3 ; About and separator before first item
jsr a_times_16
addax #desk_acc_names, ptr
;; Compute total length
ldy #0
lda (ptr),y
tay
clc
adc #prefix_length
pha
tax
;; Append name to path
: lda ($06),y
sta str_desk_acc,x
dex
dey
bne :-
pla
sta str_desk_acc ; update length
;; Convert spaces to periods
ldx str_desk_acc
: lda str_desk_acc,x
cmp #' '
bne nope
lda #'.'
sta str_desk_acc,x
nope: dex
bne :-
ldax #str_desk_acc
;; fall through
.endproc
cmd_deskacc := cmd_deskacc_impl::start
;;; ============================================================
;;; Invoke Desk Accessory
;;; Input: A,X = address of pathnane buffer
.proc invoke_desk_acc
stax open_pathname
;; Load the DA
jsr open
bmi done
lda open_ref_num
sta read_ref_num
sta close_ref_num
jsr read
jsr close
copy #$80, running_da_flag
;; Invoke it
jsr set_pointer_cursor
jsr reset_grafport3
jsr DA_LOAD_ADDRESS
lda #0
sta running_da_flag
;; Restore state
jsr reset_grafport3
jsr redraw_windows_and_desktop
done: jsr set_pointer_cursor
rts
open: yax_call MLI_RELAY, OPEN, open_params
bne :+
rts
: lda #warning_msg_insert_system_disk
jsr warning_dialog_proc_num
beq open ; ok, so try again
return #$FF ; cancel, so fail
read: yax_jump MLI_RELAY, READ, read_params
close: yax_jump MLI_RELAY, CLOSE, close_params
zp_use_flag1:
.byte $80
DEFINE_OPEN_PARAMS open_params, 0, DA_IO_BUFFER
open_ref_num := open_params::ref_num
open_pathname := open_params::pathname
DEFINE_READ_PARAMS read_params, DA_LOAD_ADDRESS, DA_MAX_SIZE
read_ref_num := read_params::ref_num
DEFINE_CLOSE_PARAMS close_params
close_ref_num := close_params::ref_num
.endproc
;;; ============================================================
;; high bit set while a DA is running
running_da_flag:
.byte 0
;;; ============================================================
.proc cmd_copy_file
jsr set_watch_cursor
lda #dynamic_routine_common
jsr load_dynamic_routine
bmi L4CD6
lda #dynamic_routine_file_copy
jsr load_dynamic_routine
bmi L4CD6
jsr set_pointer_cursor
lda #$00
jsr dynamic_routine_5000
pha
jsr set_watch_cursor
lda #dynamic_routine_restore5000
jsr restore_dynamic_routine
jsr set_pointer_cursor
pla
bpl :+
jmp L4CD6
;; --------------------------------------------------
: jsr copy_paths_and_split_name
jsr redraw_windows_and_desktop
jsr jt_copy_file
L4CD6: pha
jsr set_pointer_cursor
pla
bpl :+
jmp redraw_windows_and_desktop
: addr_call find_window_for_path, path_buf4
beq :+
pha
jsr update_used_free_for_vol_windows
pla
jmp select_and_refresh_window
;; --------------------------------------------------
;; Update used/free for windows for same vol as path_buf4
: ldy #1
@loop: iny
lda path_buf4,y
cmp #'/'
beq :+
cpy path_buf4
bne @loop
iny
: dey
sty path_buf4
addr_call find_windows_for_prefix, path_buf4
ldax #path_buf4
ldy path_buf4
jsr update_vol_used_free_for_found_windows
jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
;;; Copy string at ($6) to path_buf3, string at ($8) to path_buf4,
;;; split filename off path_buf4 and store in filename_buf
.proc copy_paths_and_split_name
;; Copy string at $6 to path_buf3
ldy #0
lda ($06),y
tay
: lda ($06),y
sta path_buf3,y
dey
bpl :-
;; Copy string at $8 to path_buf4
ldy #0
lda ($08),y
tay
: lda ($08),y
sta path_buf4,y
dey
bpl :-
addr_call find_last_path_segment, path_buf4
;; Copy filename part to buf
ldx #1
iny
iny
: lda path_buf4,y
sta filename_buf,x
cpy path_buf4
beq :+
iny
inx
jmp :-
: stx filename_buf
;; And remove from path_buf4
lda path_buf4
sec
sbc filename_buf
sta path_buf4
dec path_buf4
rts
.endproc
;;; ============================================================
.proc cmd_delete_file
jsr set_watch_cursor
lda #dynamic_routine_common
jsr load_dynamic_routine
bmi L4D9D
lda #dynamic_routine_file_delete
jsr load_dynamic_routine
bmi L4D9D
jsr set_pointer_cursor
lda #$01
jsr dynamic_routine_5000
pha
jsr set_watch_cursor
lda #dynamic_routine_restore5000
jsr restore_dynamic_routine
jsr set_pointer_cursor
pla
bpl :+
jmp L4D9D
: ldy #0
lda ($06),y
tay
: lda ($06),y
sta path_buf3,y
dey
bpl :-
jsr redraw_windows_and_desktop
jsr jt_delete_file
L4D9D: pha
jsr set_pointer_cursor
pla
bpl :+
jmp redraw_windows_and_desktop
: addr_call find_last_path_segment, path_buf3
sty path_buf3
addr_call find_window_for_path, path_buf3
beq :+
pha
jsr update_used_free_for_vol_windows
pla
jmp select_and_refresh_window
;; --------------------------------------------------
;; Update used/free for windows for same vol as path_buf3
: ldy #1
@loop: iny
lda path_buf3,y
cmp #'/'
beq :+
cpy path_buf3
bne @loop
iny
: dey
sty path_buf3
addr_call find_windows_for_prefix, path_buf3
ldax #path_buf3
ldy path_buf3
jsr update_vol_used_free_for_found_windows
jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
;;; Helper for "Open" actions - if Apple-key is down, record
;;; the parent window to close.
.proc set_window_to_close_after_open
lda BUTN0 ; Modifier down?
ora BUTN1
bmi :+ ; Yep
lda #0
beq store ; always
: lda selected_window_index
store: sta window_id_to_close
rts
.endproc
;;; ============================================================
.proc cmd_open
ptr := $06
;; Source window to close?
jsr set_window_to_close_after_open
ldx #0
stx dir_count
L4DEC: cpx selected_icon_count
bne :+
;; Were any directories opened?
lda dir_count
beq done
jsr clear_selection
;; Close previous active window, depending on source/modifiers
bit menu_kbd_flag ; If keyboard (Apple-O) ignore. (see issue #9)
bmi done ; Yep, ignore.
jsr close_window_after_open
done: rts
: txa
pha
lda selected_icon_list,x
jsr icon_entry_lookup
stax ptr
ldy #IconEntry::win_type
lda (ptr),y
and #icon_entry_type_mask
cmp #icon_entry_type_trash
beq next_file
cmp #icon_entry_type_dir
bne maybe_open_file
;; Directory
ldy #0
lda (ptr),y
jsr open_folder_or_volume_icon
inc dir_count
next_file:
pla
tax
inx
jmp L4DEC
;; File (executable or data)
maybe_open_file:
sta L4E71
lda selected_icon_count
cmp #2 ; multiple files open?
bcs next_file ; don't try to invoke
pla
lda active_window_id
jsr window_path_lookup
stax $06
ldy #0
lda ($06),y
tay
L4E34: lda ($06),y
sta buf_win_path,y
dey
bpl L4E34
lda selected_icon_list
jsr icon_entry_lookup
stax $06
ldy #$09
lda ($06),y
tax
clc
adc #$09
tay
dex
dey
L4E51: lda ($06),y
sta buf_filename2-1,x
dey
dex
bne L4E51
ldy #$09
lda ($06),y
tax
dex
dex
stx buf_filename2
lda L4E71
cmp #$20
bcc L4E6E
lda L4E71
L4E6E: jmp launch_file
L4E71: .byte 0
;; Count of opened volumes/folders; if non-zero,
;; selection must be cleared before finishing.
dir_count:
.byte 0
last_active_window_id:
.byte 0
.endproc
;;; ============================================================
;;; Close parent window after open, if needed. Done by activating then closing.
;;; Modifies findwindow_window_id
.proc close_window_after_open
lda window_id_to_close
beq done
pha
sta findwindow_window_id
jsr handle_inactive_window_click
pla
jsr close_window
done: rts
.endproc
;;; ============================================================
.proc cmd_close
icon_ptr := $06
lda active_window_id
bne :+
rts
: jmp close_window
.endproc
;;; ============================================================
.proc cmd_close_all
lda active_window_id ; current window
beq done ; nope, done!
jsr close_window ; close it...
jmp cmd_close_all ; and try again
done: rts
.endproc
;;; ============================================================
.proc cmd_disk_copy
lda #dynamic_routine_disk_copy
jsr load_dynamic_routine
bmi fail
jmp dynamic_routine_800
fail: rts
.endproc
;;; ============================================================
.proc cmd_new_folder_impl
ptr := $06
.proc new_folder_dialog_params
phase: .byte 0 ; window_id?
win_path_ptr: .word 0
.endproc
;; access = destroy/rename/write/read
DEFINE_CREATE_PARAMS create_params, path_buffer, ACCESS_DEFAULT, FT_DIRECTORY,, ST_LINKED_DIRECTORY
path_buffer:
.res 65, 0 ; buffer is used elsewhere too
start: copy active_window_id, new_folder_dialog_params::phase
yax_call invoke_dialog_proc, index_new_folder_dialog, new_folder_dialog_params
L4FC6: lda active_window_id
beq L4FD4
jsr window_path_lookup
stax new_folder_dialog_params::win_path_ptr
L4FD4: copy #$80, new_folder_dialog_params::phase
yax_call invoke_dialog_proc, index_new_folder_dialog, new_folder_dialog_params
beq :+
jmp done ; Cancelled
: stx ptr+1
stx name_ptr+1
sty ptr
sty name_ptr
;; Copy path
ldy #0
lda (ptr),y
tay
: lda (ptr),y
sta path_buffer,y
dey
bpl :-
;; Create with current date
COPY_STRUCT DateTime, DATELO, create_params::create_date
;; Create folder
MLI_RELAY_CALL CREATE, create_params
beq success
;; Failure
jsr ShowAlert
copy16 name_ptr, new_folder_dialog_params::win_path_ptr
jmp L4FC6
success:
copy #$40, new_folder_dialog_params::phase
yax_call invoke_dialog_proc, index_new_folder_dialog, new_folder_dialog_params
addr_call find_last_path_segment, path_buffer
sty path_buffer
addr_call find_window_for_path, path_buffer
beq done
jsr select_and_refresh_window
;; TODO: Select new folder
;; * LoadActiveWindowIconTable
;; * Iterate icons
;; * Compare name w/ name from dialog
;; * If match, make it selected
;; TODO: Scroll into view
done: jmp redraw_windows_and_desktop
name_ptr:
.addr 0
.endproc
cmd_new_folder := cmd_new_folder_impl::start
path_buffer := cmd_new_folder_impl::path_buffer ; ???
;;; ============================================================
.proc cmd_check_or_eject
buffer := $1800
eject:
lda #$80
bne common ; always
check: lda #0
common: sta eject_flag
;; Ensure that volumes are selected
lda selected_window_index
beq :+
done: rts
;; And if there's only one, it's not Trash
: lda selected_icon_count
beq done
cmp #1 ; single selection
bne :+
lda selected_icon_list
cmp trash_icon_num ; if it's Trash, skip it
beq done
;; Record non-Trash selected volume icons to a buffer
: lda #0
tax
tay
loop1: lda selected_icon_list,y
cmp trash_icon_num
beq :+
sta buffer,x
inx
: iny
cpy selected_icon_count
bne loop1
dex
stx count
;; Do the ejection
bit eject_flag
bpl :+
jsr jt_eject
:
;; Check each of the recorded volumes
loop2: ldx count
lda buffer,x
sta drive_to_refresh ; icon number
jsr cmd_check_single_drive_by_icon_number
dec count
bpl loop2
;; And finish up nicely
jmp redraw_windows_and_desktop
count: .byte 0
eject_flag:
.byte 0
.endproc
cmd_eject := cmd_check_or_eject::eject
cmd_check_drive := cmd_check_or_eject::check
;;; ============================================================
.proc cmd_quit_impl
;; TODO: Assumes prefix is retained. Compose correct path.
quit_code_io := $800
quit_code_addr := $1000
quit_code_size := $400
DEFINE_OPEN_PARAMS open_params, str_quit_code, quit_code_io
DEFINE_READ_PARAMS read_params, quit_code_addr, quit_code_size
DEFINE_CLOSE_PARAMS close_params
str_quit_code: PASCAL_STRING "Quit.tmp"
reset_handler:
;; Restore DeskTop Main expected state...
sta ALTZPON
lda LCBANK1
lda LCBANK1
start:
MLI_RELAY_CALL OPEN, open_params
bne fail
lda open_params::ref_num
sta read_params::ref_num
sta close_params::ref_num
MLI_RELAY_CALL READ, read_params
MLI_RELAY_CALL CLOSE, close_params
;; Restore system state: devices, /RAM, ROM/ZP banks.
jsr restore_system
quit: jmp quit_code_addr
fail: jsr ShowAlert
rts
.endproc
cmd_quit := cmd_quit_impl::start
reset_handler := cmd_quit_impl::reset_handler
;;; ============================================================
;;; Exit DHR, restore device list, reformat /RAM.
;;; Returns with ALTZPOFF and ROM banked in.
.proc restore_system
jsr restore_device_list
;; Switch back to main ZP, preserving return address.
pla
tax
pla
sta ALTZPOFF
pha
txa
pha
;; Switch back to color DHR mode
jsr set_color_mode
;; Exit graphics mode entirely
lda ROMIN2
jsr SETVID
jsr SETKBD
jsr INIT
jsr HOME
sta TXTSET
sta LOWSCR
sta LORES
sta MIXCLR
sta DHIRESOFF
sta CLRALTCHAR
sta CLR80VID
sta CLR80COL
;; Restore /RAM if possible.
jmp maybe_reformat_ram
.endproc
;;; ============================================================
.proc cmd_view_by_icon
ldx active_window_id
bne :+
rts
: dex
lda win_view_by_table,x
bne :+ ; not by icon
rts
;; View by icon
entry:
: jsr LoadActiveWindowIconTable
ldx #$00
txa
: cpx cached_window_icon_count
beq :+
sta cached_window_icon_list,x
inx
jmp :-
: sta cached_window_icon_count
lda #0
ldx active_window_id
dex
sta win_view_by_table,x
jsr update_view_menu_check
copy active_window_id, getwinport_params2::window_id
jsr get_port2
jsr offset_grafport2_and_set
jsr set_penmode_copy
MGTK_RELAY_CALL MGTK::PaintRect, grafport2::cliprect
lda active_window_id
jsr compute_window_dimensions
stax L51EB
sty L51ED
lda active_window_id
jsr window_lookup
stax $06
ldy #$1F
lda #$00
L5162: sta ($06),y
dey
cpy #$1B
bne L5162
ldy #$23
ldx #$03
L516D: lda L51EB,x
sta ($06),y
dey
dex
bpl L516D
lda active_window_id
jsr create_file_icon_ep2
copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
jsr cached_icons_screen_to_window
copy #0, L51EF
L518D: lda L51EF
cmp cached_window_icon_count
beq L51A7
tax
lda cached_window_icon_list,x
jsr icon_entry_lookup
ldy #IconTK::ADD_ICON
jsr ITK_RELAY ; icon entry addr in A,X
inc L51EF
jmp L518D
L51A7: jsr reset_grafport3
jsr cached_icons_window_to_screen
jsr StoreWindowIconTable
jsr update_scrollbars
lda selected_window_index
beq finish
lda selected_icon_count
beq finish
sta L51EF
L51C0: ldx L51EF
lda selected_icon_count,x
sta icon_param
jsr icon_screen_to_window
jsr offset_grafport2_and_set
ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, icon_param
lda icon_param
jsr icon_window_to_screen
dec L51EF
bne L51C0
finish: jmp LoadDesktopIconTable
L51EB: .word 0
L51ED: .byte 0
.byte 0
L51EF: .byte 0
.endproc
;;; ============================================================
.proc view_by_nonicon_common
ldx active_window_id
dex
sta win_view_by_table,x
jsr LoadActiveWindowIconTable
jsr sort_records
jsr StoreWindowIconTable
copy active_window_id, getwinport_params2::window_id
jsr get_port2
jsr offset_grafport2_and_set
jsr set_penmode_copy
MGTK_RELAY_CALL MGTK::PaintRect, grafport2::cliprect
lda active_window_id
jsr compute_window_dimensions
stax L5263
sty L5265
lda active_window_id
jsr window_lookup
stax $06
ldy #$1F
lda #$00
L523B: sta ($06),y
dey
cpy #$1B
bne L523B
ldy #$23
ldx #$03
L5246: lda L5263,x
sta ($06),y
dey
dex
bpl L5246
copy #$80, draw_window_header_flag
jsr reset_grafport3
jsr L6C19
jsr update_scrollbars
copy #0, draw_window_header_flag
rts
L5263: .word 0
L5265: .byte 0
.byte 0
.endproc
;;; ============================================================
.proc cmd_view_by_name
ldx active_window_id
bne :+
rts
: dex
lda win_view_by_table,x
cmp #view_by_name
bne :+
rts
: cmp #$00
bne :+
jsr close_active_window
: jsr update_view_menu_check
lda #view_by_name
jmp view_by_nonicon_common
.endproc
;;; ============================================================
.proc cmd_view_by_date
ldx active_window_id
bne :+
rts
: dex
lda win_view_by_table,x
cmp #view_by_date
bne :+
rts
: cmp #$00
bne :+
jsr close_active_window
: jsr update_view_menu_check
lda #view_by_date
jmp view_by_nonicon_common
.endproc
;;; ============================================================
.proc cmd_view_by_size
ldx active_window_id
bne :+
rts
: dex
lda win_view_by_table,x
cmp #view_by_size
bne :+
rts
: cmp #$00
bne :+
jsr close_active_window
: jsr update_view_menu_check
lda #view_by_size
jmp view_by_nonicon_common
.endproc
;;; ============================================================
.proc cmd_view_by_type
ldx active_window_id
bne :+
rts
: dex
lda win_view_by_table,x
cmp #view_by_type
bne :+
rts
: cmp #$00
bne :+
jsr close_active_window
: jsr update_view_menu_check
lda #view_by_type
jmp view_by_nonicon_common
.endproc
;;; ============================================================
.proc update_view_menu_check
;; Uncheck last checked
lda #MGTK::checkitem_uncheck
sta checkitem_params::check
MGTK_RELAY_CALL MGTK::CheckItem, checkitem_params
;; Check the new one
lda menu_click_params::item_num ; index of View menu item to check
sta checkitem_params::menu_item
lda #MGTK::checkitem_check
sta checkitem_params::check
MGTK_RELAY_CALL MGTK::CheckItem, checkitem_params
rts
.endproc
;;; ============================================================
.proc close_active_window
ITK_RELAY_CALL IconTK::CLOSE_WINDOW, active_window_id
jsr LoadActiveWindowIconTable
lda icon_count
sec
sbc cached_window_icon_count
sta icon_count
jsr free_cached_window_icons
done: jsr StoreWindowIconTable
jmp LoadDesktopIconTable
.endproc
;;; ============================================================
.proc free_cached_window_icons
copy #0, index
loop: ldx index
cpx cached_window_icon_count
beq done
lda cached_window_icon_list,x
pha
jsr FreeIcon
pla
jsr find_window_for_dir_icon
bne :+
copy #$FF, window_to_dir_icon_table,x ; $FF = dir icon freed
: ldx index
copy #0, cached_window_icon_list,x
inc index
bne loop
done: rts
index: .byte 0
.endproc
;;; ============================================================
;;; Set after format, erase, failed open, etc.
;;; Used by 'cmd_check_single_drive_by_XXX'; may be unit number
;;; or device index depending on call site.
drive_to_refresh:
.byte 0
;;; ============================================================
.proc cmd_format_disk
lda #dynamic_routine_format_erase
jsr load_dynamic_routine
bmi fail
lda #$04
jsr dynamic_routine_800
bne :+
stx drive_to_refresh ; unit number
jsr redraw_windows_and_desktop
jsr cmd_check_single_drive_by_unit_number
: jmp redraw_windows_and_desktop
fail: rts
.endproc
;;; ============================================================
.proc cmd_erase_disk
lda #dynamic_routine_format_erase
jsr load_dynamic_routine
bmi done
lda #$05
jsr dynamic_routine_800
bne done
stx drive_to_refresh ; unit number
jsr redraw_windows_and_desktop
jsr cmd_check_single_drive_by_unit_number
done: jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
.proc cmd_get_info
jsr jt_get_info
jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
.proc cmd_get_size
jsr jt_get_size
jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
.proc cmd_unlock
jsr jt_unlock
jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
.proc cmd_lock
jsr jt_lock
jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
.proc cmd_delete_selection
copy trash_icon_num, drag_drop_param
jmp process_drop
.endproc
;;; ============================================================
.proc cmd_rename_icon
jsr jt_rename_icon
pha
jsr redraw_windows_and_desktop
pla
beq :+
rts
: lda selected_window_index
bne common
;; Volume icon on desktop
;; Copy selected icons (except Trash)
ldx #0
ldy #0
loop: lda selected_icon_list,x
cmp #1 ; Trash
beq :+
sta selected_vol_icon_list,y
iny
: inx
cpx selected_icon_count
bne loop
sty selected_vol_icon_count
common: copy #$FF, counter ; immediately incremented to 0
;; Loop over selection
next_icon:
inc counter
lda counter
cmp selected_icon_count
bne not_done
lda selected_window_index
bne :+
jmp finish_with_vols
: jmp select_and_refresh_window
not_done:
tax
lda selected_icon_list,x
jsr find_window_for_dir_icon
bne next_icon ; not found
inx ; 0-based index to 1-based window_id
txa
jsr window_path_lookup
stax $06
ldy #0
lda ($06),y
tay
lda $06
jsr find_windows_for_prefix
lda found_windows_count
beq next_icon
L53EF: dec found_windows_count
ldx found_windows_count
lda found_windows_list,x
cmp active_window_id
beq L5403
sta findwindow_window_id
jsr handle_inactive_window_click
L5403: jsr close_window
lda found_windows_count
bne L53EF
jmp next_icon
finish_with_vols:
ldx selected_vol_icon_count
jmp next_vol
: lda selected_vol_icon_list,x
sta drive_to_refresh ; icon number
jsr cmd_check_single_drive_by_icon_number
ldx selected_vol_icon_count
dec selected_vol_icon_count
next_vol:
dex
bpl :-
jmp redraw_windows_and_desktop
counter:
.byte 0
selected_vol_icon_count:
.byte 0
selected_vol_icon_list:
.res 9, 0
.endproc
;;; ============================================================
;;; Handle keyboard-based icon selection ("highlighting")
.proc cmd_higlight
jmp L544D
L5444: .byte 0
L5445: .byte 0
L5446: .byte 0
L5447: .byte 0
L5448: .byte 0
L5449: .byte 0
L544A: .byte 0
.byte 0
.byte 0
L544D:
copy #0, $1800
lda active_window_id
bne L545A
jmp L54C5
L545A: tax
dex
lda win_view_by_table,x
bpl L5464 ; by icon
jmp L54C5
;; View by icon
L5464: jsr LoadActiveWindowIconTable
lda active_window_id
jsr window_lookup
stax $06
ldy #MGTK::Winfo::port+MGTK::GrafPort::maprect
L5479: lda ($06),y
sta tmp_rect-(MGTK::Winfo::port+MGTK::GrafPort::maprect),y
iny
cpy #MGTK::Winfo::port+MGTK::GrafPort::maprect+8
bne L5479
ldx #$00
L5485: cpx cached_window_icon_count
beq L54BD
txa
pha
lda cached_window_icon_list,x
sta icon_param
jsr icon_screen_to_window
ITK_RELAY_CALL IconTK::ICON_IN_RECT, icon_param
pha
lda icon_param
jsr icon_window_to_screen
pla
beq L54B7
pla
pha
tax
lda cached_window_icon_list,x
ldx $1800
sta $1801,x
inc $1800
L54B7: pla
tax
inx
jmp L5485
;; No window icons
L54BD: jsr LoadDesktopIconTable
L54C5: ldx $1800
ldy #$00
L54CA: lda cached_window_icon_list,y
sta $1801,x
iny
inx
cpy cached_window_icon_count
bne L54CA
lda $1800
clc
adc cached_window_icon_count
sta $1800
copy #0, L544A
ldax #$03FF
L54EA: sta L5444,x
dex
bpl L54EA
L54F0: ldx L544A
L54F3: lda $1801,x
asl a
tay
copy16 icon_entry_address_table,y, $06
ldy #$06
lda ($06),y
cmp L5447
beq L5510
bcc L5532
jmp L5547
L5510: dey
lda ($06),y
cmp L5446
beq L551D
bcc L5532
jmp L5547
L551D: dey
lda ($06),y
cmp L5445
beq L552A
bcc L5532
jmp L5547
L552A: dey
lda ($06),y
cmp L5444
bcs L5547
L5532: lda $1801,x
stx L5449
sta L5448
ldy #$03
L553D: lda ($06),y
sta L5444-3,y
iny
cpy #$07
bne L553D
L5547: inx
cpx $1800
bne L54F3
ldx L544A
lda $1801,x
tay
lda L5448
sta $1801,x
ldx L5449
tya
sta $1801,x
ldax #$03FF
L5565: sta L5444,x
dex
bpl L5565
inc L544A
ldx L544A
cpx $1800
beq L5579
jmp L54F0
L5579: copy #0, L544A
jsr clear_selection
L5581: jsr L55F0
L5584: jsr get_event
lda event_kind
cmp #MGTK::EventKind::key_down
beq L5595
cmp #MGTK::EventKind::button_down
bne L5584
jmp L55D1
L5595: lda event_params+MGTK::Event::key
and #CHAR_MASK
cmp #CHAR_RETURN
beq L55D1
cmp #CHAR_ESCAPE
beq L55D1
cmp #CHAR_LEFT
beq L55BE
cmp #CHAR_RIGHT
bne L5584
ldx L544A
inx
cpx $1800
bne L55B5
ldx #$00
L55B5: stx L544A
jsr L562C
jmp L5581
L55BE: ldx L544A
dex
bpl L55C8
ldx $1800
dex
L55C8: stx L544A
jsr L562C
jmp L5581
L55D1: ldx L544A
lda $1801,x
sta selected_icon_list
jsr icon_entry_lookup
stax $06
ldy #IconEntry::win_type
lda ($06),y
and #icon_entry_winid_mask
sta selected_window_index
lda #1
sta selected_icon_count
rts
L55F0: ldx L544A
lda $1801,x
sta icon_param
jsr icon_entry_lookup
stax $06
ldy #IconEntry::win_type
lda ($06),y
and #icon_entry_winid_mask
sta getwinport_params2::window_id
beq L5614
jsr L56F9
lda icon_param
jsr icon_screen_to_window
L5614: ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, icon_param
lda getwinport_params2::window_id
beq L562B
lda icon_param
jsr icon_window_to_screen
jsr reset_grafport3
L562B: rts
L562C: lda icon_param
jsr icon_entry_lookup
stax $06
ldy #IconEntry::win_type
lda ($06),y
and #icon_entry_winid_mask
sta getwinport_params2::window_id
beq L564A
jsr L56F9
lda icon_param
jsr icon_screen_to_window
L564A: ITK_RELAY_CALL IconTK::UNHIGHLIGHT_ICON, icon_param
lda getwinport_params2::window_id
beq L5661
lda icon_param
jsr icon_window_to_screen
jsr reset_grafport3
L5661: rts
.endproc
;;; ============================================================
.proc cmd_select_all
lda selected_icon_count
beq L566A
jsr clear_selection
L566A: ldx active_window_id
beq L5676
dex
lda win_view_by_table,x
bpl L5676 ; view by icons
rts
L5676: jsr LoadActiveWindowIconTable
lda cached_window_icon_count
bne L5687
jmp L56F0
L5687: ldx cached_window_icon_count
dex
L568B: copy cached_window_icon_list,x, selected_icon_list,x
dex
bpl L568B
copy cached_window_icon_count, selected_icon_count
copy active_window_id, selected_window_index
copy selected_window_index, LE22C
beq L56AB
jsr L56F9
L56AB: lda selected_icon_count
sta L56F8
dec L56F8
L56B4: ldx L56F8
copy selected_icon_list,x, icon_param2
jsr icon_entry_lookup
stax $06
lda LE22C
beq L56CF
lda icon_param2
jsr icon_screen_to_window
L56CF: ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, icon_param2
lda LE22C
beq L56E3
lda icon_param2
jsr icon_window_to_screen
L56E3: dec L56F8
bpl L56B4
lda selected_window_index
beq L56F0
jsr reset_grafport3
L56F0: jmp LoadDesktopIconTable
L56F8: .byte 0
.endproc
;;; ============================================================
.proc L56F9
sta getwinport_params2::window_id
jsr get_port2
jmp offset_grafport2_and_set
.endproc
;;; ============================================================
;;; Initiate keyboard-based resizing
.proc cmd_resize
MGTK_RELAY_CALL MGTK::KeyboardMouse
jmp handle_resize_click
.endproc
;;; ============================================================
;;; Initiate keyboard-based window moving
.proc cmd_move
MGTK_RELAY_CALL MGTK::KeyboardMouse
jmp handle_title_click
.endproc
;;; ============================================================
;;; Cycle Through Windows
.proc cmd_cycle_windows
;; Need at least two windows to cycle.
lda num_open_windows
cmp #2
bcc done
ldx active_window_id
;; Search upwards through window-icon map to find next.
;; ID is 1-based, table is 0-based, so don't need to start
;; with an increment
loop: cpx #8
bne :+
ldx #0
: lda window_to_dir_icon_table,x
bne found ; 0 = window free
inx
bne loop ; always
found: inx
stx findwindow_window_id
jmp handle_inactive_window_click
done: rts
.endproc
;;; ============================================================
;;; Keyboard-based scrolling of window contents
.proc cmd_scroll
jsr get_active_window_scroll_info
loop: jsr get_event
lda event_kind
cmp #MGTK::EventKind::button_down
beq done
cmp #MGTK::EventKind::key_down
bne loop
lda event_key
cmp #CHAR_RETURN
beq done
cmp #CHAR_ESCAPE
bne :+
done: jmp LoadDesktopIconTable
;; Horizontal ok?
: bit horiz_scroll_flag
bmi :+
jmp vertical
: cmp #CHAR_RIGHT
bne :+
jsr scroll_right
jmp loop
: cmp #CHAR_LEFT
bne vertical
jsr scroll_left
jmp loop
;; Vertical ok?
vertical:
bit vert_scroll_flag
bmi :+
jmp loop
: cmp #CHAR_DOWN
bne :+
jsr scroll_down
jmp loop
: cmp #CHAR_UP
bne loop
jsr scroll_up
jmp loop
.endproc
;;; ============================================================
.proc get_active_window_scroll_info
jsr LoadActiveWindowIconTable
ldx active_window_id
dex
lda win_view_by_table,x
sta active_window_view_by
jsr get_active_window_hscroll_info
sta horiz_scroll_pos
stx horiz_scroll_max
sty horiz_scroll_flag
jsr get_active_window_vscroll_info
sta vert_scroll_pos
stx vert_scroll_max
sty vert_scroll_flag
rts
.endproc
;;; ============================================================
scroll_right: ; elevator right / contents left
lda horiz_scroll_pos
ldx horiz_scroll_max
jsr do_scroll_right
sta horiz_scroll_pos
rts
scroll_left: ; elevator left / contents right
lda horiz_scroll_pos
jsr do_scroll_left
sta horiz_scroll_pos
rts
scroll_down: ; elevator down / contents up
lda vert_scroll_pos
ldx vert_scroll_max
jsr do_scroll_down
sta vert_scroll_pos
rts
scroll_up: ; elevator up / contents down
lda vert_scroll_pos
jsr do_scroll_up
sta vert_scroll_pos
rts
horiz_scroll_flag: .byte 0 ; can scroll horiz?
vert_scroll_flag: .byte 0 ; can scroll vert?
horiz_scroll_pos: .byte 0
horiz_scroll_max: .byte 0
vert_scroll_pos: .byte 0
vert_scroll_max: .byte 0
.proc do_scroll_right
stx max
cmp max
beq :+
sta updatethumb_stash
inc updatethumb_stash
copy #MGTK::Ctl::horizontal_scroll_bar, updatethumb_which_ctl
jsr update_scroll_thumb
lda updatethumb_stash
: rts
max: .byte 0
.endproc
.proc do_scroll_left
beq :+
sta updatethumb_stash
dec updatethumb_stash
copy #MGTK::Ctl::horizontal_scroll_bar, updatethumb_which_ctl
jsr update_scroll_thumb
lda updatethumb_stash
: rts
.byte 0
.endproc
.proc do_scroll_down
stx max
cmp max
beq :+
sta updatethumb_stash
inc updatethumb_stash
copy #MGTK::Ctl::vertical_scroll_bar, updatethumb_which_ctl
jsr update_scroll_thumb
lda updatethumb_stash
: rts
max: .byte 0
.endproc
.proc do_scroll_up
beq :+
sta updatethumb_stash
dec updatethumb_stash
copy #MGTK::Ctl::vertical_scroll_bar, updatethumb_which_ctl
jsr update_scroll_thumb
lda updatethumb_stash
: rts
.byte 0
.endproc
;;; Output: A = hscroll pos, X = hscroll max, Y = hscroll active flag (high bit)
.proc get_active_window_hscroll_info
ptr := $06
lda active_window_id
jsr window_lookup
stax ptr
ldy #MGTK::Winfo::hthumbmax
lda (ptr),y
tax
iny ; hthumbpos
lda (ptr),y
pha
ldy #MGTK::Winfo::hscroll
lda (ptr),y
and #$01 ; active flag
clc
ror a
ror a ; shift to high bit
tay
pla
rts
.endproc
;;; Output: A = vscroll pos, X = vscroll max, Y = vscroll active flag (high bit)
.proc get_active_window_vscroll_info
ptr := $06
lda active_window_id
jsr window_lookup
stax ptr
ldy #MGTK::Winfo::vthumbmax
lda (ptr),y
tax
iny
lda (ptr),y
pha
ldy #MGTK::Winfo::vscroll
lda (ptr),y
and #$01 ; active flag
clc
ror a
ror a ; shift to high bit
tay
pla
rts
.endproc
;;; ============================================================
.proc cmd_check_drives
copy #0, pending_alert
jsr LoadDesktopIconTable
jsr cmd_close_all
jsr clear_selection
ldx cached_window_icon_count
dex
L5916: lda cached_window_icon_list,x
cmp trash_icon_num
beq L5942
txa
pha
lda cached_window_icon_list,x
sta icon_param
copy #0, cached_window_icon_list,x
ITK_RELAY_CALL IconTK::REMOVE_ICON, icon_param
lda icon_param
jsr FreeIcon
dec cached_window_icon_count
dec icon_count
pla
tax
L5942: dex
bpl L5916
;; Enumerate DEVLST in reverse order (most important volumes first)
ldy DEVCNT
sty devlst_index
@loop: ldy devlst_index
inc cached_window_icon_count
inc icon_count
lda #0
sta device_to_icon_map,y
lda DEVLST,y
ldx cached_window_icon_count
jsr create_volume_icon ; A = unit num, Y = device num, X = icon index
cmp #ERR_DUPLICATE_VOLUME
bne :+
lda #ERR_DUPLICATE_VOL_NAME
sta pending_alert
: dec devlst_index
lda devlst_index
bpl @loop
ldx #0
L5976: cpx cached_window_icon_count
bne L5986
lda pending_alert
beq L5983
jsr ShowAlert
L5983: jmp StoreWindowIconTable
L5986: txa
pha
lda cached_window_icon_list,x
cmp trash_icon_num
beq L5998
jsr icon_entry_lookup
ldy #IconTK::ADD_ICON
jsr ITK_RELAY ; icon entry addr in A,X
L5998: pla
tax
inx
jmp L5976
.endproc
;;; ============================================================
devlst_index:
.byte 0
pending_alert:
.byte 0
;;; ============================================================
;;; Check > [drive] command - obsolete, but core still used
;;; following Format (etc)
;;;
.proc cmd_check_single_drive
;; index in DEVLST
devlst_index := menu_click_params::item_num
;; Check Drive command
by_menu:
lda #$00
beq start
;; After format/erase
by_unit_number:
lda #$80
bne start
;; After open/eject/rename
by_icon_number:
lda #$C0
start: sta check_drive_flags
jsr LoadDesktopIconTable
bit check_drive_flags
bpl explicit_command
bvc after_format_erase
;;; --------------------------------------------------
;;; After an Open/Eject/Rename action
;; Map icon number to index in DEVLST
lda drive_to_refresh
ldy #15
: cmp device_to_icon_map,y
beq :+
dey
bpl :-
: sty previous_icon_count ; BUG: overwritten?
sty devlst_index
jmp common
;;; --------------------------------------------------
;;; After a Format/Erase action
after_format_erase:
;; Map unit number to index in DEVLST
ldy DEVCNT
lda drive_to_refresh
: cmp DEVLST,y
beq :+
dey
bpl :-
iny
: sty previous_icon_count ; BUG: overwritten?
sty devlst_index
jmp common
;;; --------------------------------------------------
;;; Check Drive command
explicit_command:
;; Map menu number to index in DEVLST
lda menu_click_params::item_num
sec
sbc #3
sta devlst_index
;;; --------------------------------------------------
common:
ldy devlst_index
lda device_to_icon_map,y
bne :+
jmp not_in_map
;; Close any associated windows.
;; A = icon number
: jsr icon_entry_lookup
addax #IconEntry::len, $06
ptr := $06
path_buf := $1F00
;; Copy volume path to $1F00
ldy #0
lda (ptr),y
tay
: lda (ptr),y
sta path_buf,y
dey
bpl :-
;; Find all windows with path as prefix, and close them.
dec path_buf
lda #'/'
sta path_buf+1
ldax #path_buf
ldy path_buf
jsr find_windows_for_prefix
lda found_windows_count
beq not_in_map
close_loop:
ldx found_windows_count
beq not_in_map
dex
lda found_windows_list,x
cmp active_window_id
beq :+
sta findwindow_window_id
jsr handle_inactive_window_click
: jsr close_window
dec found_windows_count
jmp close_loop
not_in_map:
jsr redraw_windows_and_desktop
jsr clear_selection
jsr LoadDesktopIconTable
lda devlst_index
tay
pha
lda device_to_icon_map,y
sta icon_param
beq :+
jsr remove_icon_from_window
dec icon_count
lda icon_param
jsr FreeIcon
jsr reset_grafport3
ITK_RELAY_CALL IconTK::REMOVE_ICON, icon_param
: lda cached_window_icon_count
sta previous_icon_count
inc cached_window_icon_count
inc icon_count
pla
tay
lda DEVLST,y
ldx icon_param ; preserve icon index if known
bne :+
ldx cached_window_icon_count
: jsr create_volume_icon ; A = unit num, Y = device num, X = icon index
bit check_drive_flags
bmi add_icon
;; Explicit command
and #$FF ; check create_volume_icon results
beq add_icon
cmp #$2F ; there was an error ($2F = ???)
beq add_icon
pha
jsr StoreWindowIconTable
pla
jsr ShowAlert
rts
add_icon:
lda cached_window_icon_count
cmp previous_icon_count
beq :+
;; If a new icon was added, more work is needed.
ldx cached_window_icon_count
dex
lda cached_window_icon_list,x
jsr icon_entry_lookup
ldy #IconTK::ADD_ICON
jsr ITK_RELAY ; icon entry addr in A,X
: jsr StoreWindowIconTable
jmp redraw_windows_and_desktop
previous_icon_count:
.byte 0
;;; 0 = command, $80 = format/erase, $C0 = open/eject/rename
check_drive_flags:
.byte 0
.endproc
cmd_check_single_drive_by_menu := cmd_check_single_drive::by_menu
cmd_check_single_drive_by_unit_number := cmd_check_single_drive::by_unit_number
cmd_check_single_drive_by_icon_number := cmd_check_single_drive::by_icon_number
;;; ============================================================
.proc cmd_startup_item
ldx menu_click_params::item_num
dex
txa
asl a
asl a
asl a
clc
adc #6
tax
lda startup_menu_item_1,x
sec
sbc #'0'
clc
adc #>$C000 ; compute $Cn00
sta reset_and_invoke_target+1
lda #<$0000
sta reset_and_invoke_target
;; fall through
.endproc
;; also invoked by launcher code
.proc reset_and_invoke
;; Restore system state: devices, /RAM, ROM/ZP banks.
jsr restore_system
;; also used by launcher code
target := *+1
jmp dummy0000 ; self-modified
.endproc
reset_and_invoke_target := reset_and_invoke::target
;;; ============================================================
active_window_view_by:
.byte 0
.proc handle_client_click
jsr LoadActiveWindowIconTable
ldx active_window_id
dex
lda win_view_by_table,x
sta active_window_view_by
;; Restore event coords (following detect_double_click)
COPY_STRUCT MGTK::Point, saved_event_coords, event_coords
MGTK_RELAY_CALL MGTK::FindControl, event_coords
lda findcontrol_which_ctl
bne :+
jmp handle_content_click ; 0 = ctl_not_a_control
: bit double_click_flag
bmi :+
jmp done_client_click ; ignore double click
: cmp #MGTK::Ctl::dead_zone
bne :+
rts
: cmp #MGTK::Ctl::vertical_scroll_bar
bne horiz
;; Vertical scrollbar
lda active_window_id
jsr window_lookup
stax $06
ldy #$05
lda ($06),y
and #$01
bne :+
jmp done_client_click
: jsr get_active_window_scroll_info
lda findcontrol_which_part
cmp #MGTK::Part::thumb
bne :+
jsr do_track_thumb
jmp done_client_click
: cmp #MGTK::Part::up_arrow
bne :+
up: jsr scroll_up
lda #MGTK::Part::up_arrow
jsr check_control_repeat
bpl up
jmp done_client_click
: cmp #MGTK::Part::down_arrow
bne :+
down: jsr scroll_down
lda #MGTK::Part::down_arrow
jsr check_control_repeat
bpl down
jmp done_client_click
: cmp #MGTK::Part::page_down
beq pgdn
pgup: jsr L638C
lda #MGTK::Part::page_up
jsr check_control_repeat
bpl pgup
jmp done_client_click
pgdn: jsr L63EC
lda #MGTK::Part::page_down
jsr check_control_repeat
bpl pgdn
jmp done_client_click
;; Horizontal scrollbar
horiz: lda active_window_id
jsr window_lookup
stax $06
ldy #$04
lda ($06),y
and #$01
bne :+
jmp done_client_click
: jsr get_active_window_scroll_info
lda findcontrol_which_part
cmp #MGTK::Part::thumb
bne :+
jsr do_track_thumb
jmp done_client_click
: cmp #MGTK::Part::left_arrow
bne :+
left: jsr scroll_left
lda #MGTK::Part::left_arrow
jsr check_control_repeat
bpl left
jmp done_client_click
: cmp #MGTK::Part::right_arrow
bne :+
rght: jsr scroll_right
lda #MGTK::Part::right_arrow
jsr check_control_repeat
bpl rght
jmp done_client_click
: cmp #MGTK::Part::page_right
beq pgrt
pglt: jsr L6451
lda #MGTK::Part::page_left
jsr check_control_repeat
bpl pglt
jmp done_client_click
pgrt: jsr L64B0
lda #MGTK::Part::page_right
jsr check_control_repeat
bpl pgrt
jmp done_client_click
done_client_click:
jsr StoreWindowIconTable
jmp LoadDesktopIconTable
.endproc
;;; ============================================================
.proc do_track_thumb
lda findcontrol_which_ctl
sta trackthumb_which_ctl
MGTK_RELAY_CALL MGTK::TrackThumb, trackthumb_params
lda trackthumb_thumbmoved
bne :+
rts
: jsr update_scroll_thumb
jsr StoreWindowIconTable
jmp LoadDesktopIconTable
.endproc
;;; ============================================================
.proc update_scroll_thumb
copy updatethumb_stash, updatethumb_thumbpos
MGTK_RELAY_CALL MGTK::UpdateThumb, updatethumb_params
jsr apply_active_winfo_to_grafport2
jsr L84D1
bit active_window_view_by
bmi :+ ; list view, no icons
jsr cached_icons_window_to_screen
: copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
MGTK_RELAY_CALL MGTK::PaintRect, grafport2::cliprect
jsr reset_grafport3
jmp L6C19
.endproc
;;; ============================================================
;;; Handle mouse held down on scroll arrow/pager
.proc check_control_repeat
sta ctl
jsr peek_event
lda event_kind
cmp #MGTK::EventKind::drag
beq :+
bail: return #$FF ; high bit set = not repeating
: MGTK_RELAY_CALL MGTK::FindControl, event_coords
lda findcontrol_which_ctl
beq bail
cmp #MGTK::Ctl::dead_zone
beq bail
lda findcontrol_which_part
cmp ctl
bne bail
return #0 ; high bit set = repeating
ctl: .byte 0
.endproc
;;; ============================================================
.proc handle_content_click
;; Subsequent action was not triggered by a menu, so hilite is not
;; necessary. https://github.com/inexorabletash/a2d/issues/139
copy #$FF, menu_click_params::menu_id
bit active_window_view_by
bpl :+
jmp clear_selection
: copy active_window_id, findicon_window_id
ITK_RELAY_CALL IconTK::FIND_ICON, findicon_params
lda findicon_which_icon
bne handle_file_icon_click
jsr L5F13
jmp swap_in_desktop_icon_table
.endproc
;;; ============================================================
.proc handle_file_icon_click_impl
icon_num: .byte 0
start: sta icon_num
ldx selected_icon_count
beq L5CFB
dex
lda icon_num
L5CE6: cmp selected_icon_list,x
beq L5CF0
dex
bpl L5CE6
bmi L5CFB
L5CF0: bit double_click_flag
bmi L5CF8
jmp handle_double_click
L5CF8: jmp start_icon_drag
;; Open-Apple: Extend selection (if in same window)
L5CFB: bit BUTN0
bpl replace
lda selected_window_index
cmp active_window_id ; same window?
beq :+ ; if so, retain selection
replace:
jsr clear_selection
: ldx selected_icon_count
lda icon_num
sta selected_icon_list,x
inc selected_icon_count
copy active_window_id, selected_window_index
copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
copy icon_num, icon_param
jsr icon_screen_to_window
jsr offset_grafport2_and_set
ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, icon_param
copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
lda icon_num
jsr icon_window_to_screen
jsr reset_grafport3
bit double_click_flag
bmi start_icon_drag
jmp handle_double_click
;; --------------------------------------------------
start_icon_drag:
copy icon_num, drag_drop_param
ITK_RELAY_CALL IconTK::DRAG_HIGHLIGHTED, drag_drop_param
tax
lda drag_drop_param
beq desktop
process_drop:
jsr jt_drop
;; Failed?
cmp #$FF
bne :+
jsr swap_in_desktop_icon_table
jmp redraw_windows_and_desktop
;; Was a move?
: bit move_flag
bpl :+
;; Update source vol's contents
jsr update_active_window
;; fall through
;; Dropped on trash?
: lda drag_drop_param
cmp trash_icon_num
bne :+
;; Update used/free for same-vol windows
jsr update_active_window
jmp redraw_windows_and_desktop
;; Dropped on icon?
: lda drag_drop_param
bmi :+
;; Update used/free for same-vol windows
jsr update_vol_free_used_for_icon
jmp redraw_windows_and_desktop
;; Dropped on window!
: and #$7F ; mask off window number
pha
jsr update_used_free_for_vol_windows
pla
jsr select_and_refresh_window
jmp redraw_windows_and_desktop
;; --------------------------------------------------
desktop:
cpx #$02
bne :+
jmp swap_in_desktop_icon_table
: cpx #$FF
beq L5DF7
copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
jsr cached_icons_screen_to_window
jsr offset_grafport2_and_set
ldx selected_icon_count
dex
: txa
pha
lda selected_icon_list,x
sta redraw_icon_param
ITK_RELAY_CALL IconTK::REDRAW_ICON, redraw_icon_param
pla
tax
dex
bpl :-
copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
jsr update_scrollbars
jsr cached_icons_window_to_screen
jsr reset_grafport3
;;; Used as additional entry point
swap_in_desktop_icon_table:
jsr StoreWindowIconTable
jmp LoadDesktopIconTable
L5DF7: ldx saved_stack
txs
rts
handle_double_click:
;; Source window to close?
jsr set_window_to_close_after_open
lda icon_num ; after a double-click (on file or folder)
jsr icon_entry_lookup
stax $06
ldy #IconEntry::win_type
lda ($06),y
and #icon_entry_type_mask
cmp #icon_entry_type_trash
beq done
cmp #icon_entry_type_dir
bne file
;; Directory
lda icon_num
jsr open_folder_or_volume_icon
bmi done
jsr swap_in_desktop_icon_table
;; If Option (Solid-Apple) key is down, close previous window.
jsr close_window_after_open
done: rts
;; File (executable or data)
file: sta L5E77
lda active_window_id
jsr window_path_lookup
stax $06
ldy #$00
lda ($06),y
tay
L5E3A: lda ($06),y
sta buf_win_path,y
dey
bpl L5E3A
lda icon_num
jsr icon_entry_lookup
stax $06
ldy #$09
lda ($06),y
tax
clc
adc #$09
tay
dex
dey
L5E57: lda ($06),y
sta buf_filename2-1,x
dey
dex
bne L5E57
ldy #$09
lda ($06),y
tax
dex
dex
stx buf_filename2
lda L5E77
cmp #$20
bcc L5E74
lda L5E77
L5E74: jmp launch_file ; when double-clicked
.proc update_active_window
lda active_window_id
jsr update_used_free_for_vol_windows
lda active_window_id
jmp select_and_refresh_window
.endproc
L5E77: .byte 0
.endproc
handle_file_icon_click := handle_file_icon_click_impl::start
swap_in_desktop_icon_table := handle_file_icon_click_impl::swap_in_desktop_icon_table
process_drop := handle_file_icon_click_impl::process_drop
;;; ============================================================
.proc select_and_refresh_window
sta window_id
jsr redraw_windows_and_desktop
jsr clear_selection
lda window_id
cmp active_window_id
beq :+
sta findwindow_window_id
jsr handle_inactive_window_click ; bring to front
: copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
jsr set_penmode_copy
MGTK_RELAY_CALL MGTK::PaintRect, grafport2::cliprect
ldx active_window_id
dex
lda window_to_dir_icon_table,x
;; BUG: What if dir icon is freed? ($FF)
pha
jsr L7345
lda window_id
tax
dex
lda win_view_by_table,x
bmi :+ ; list view, not icons
jsr close_active_window
: lda active_window_id
jsr window_path_lookup
ptr := $06
stax ptr
ldy #0
lda (ptr),y
tay
: lda (ptr),y
sta open_dir_path_buf,y
dey
bpl :-
pla
jsr open_directory
jsr cmd_view_by_icon::entry
jsr StoreWindowIconTable
jsr LoadActiveWindowIconTable
copy active_window_id, getwinport_params2::window_id
jsr get_port2
jsr draw_window_header
lda #0
ldx active_window_id
sta win_view_by_table-1,x
copy #1, menu_click_params::item_num
jsr update_view_menu_check
jmp LoadDesktopIconTable
window_id:
.byte 0
.endproc
;;; ============================================================
;;; Drag Selection
.proc L5F13_impl
pt1: DEFINE_POINT 0, 0
pt2: DEFINE_POINT 0, 0
start: copy16 #notpenXOR, $06
jsr L60D5
ldx #.sizeof(MGTK::Point)-1
L5F20: lda event_coords,x
sta pt1,x
sta pt2,x
dex
bpl L5F20
jsr peek_event
lda event_kind
cmp #MGTK::EventKind::drag
beq L5F3F
bit BUTN0
bmi L5F3E
jsr clear_selection
L5F3E: rts
L5F3F: jsr clear_selection
copy active_window_id, getwinport_params2::window_id
jsr get_port2
jsr offset_grafport2_and_set
ldx #$03
L5F50: lda pt1,x
sta tmp_rect::x1,x
lda pt2,x
sta tmp_rect::x2,x
dex
bpl L5F50
jsr set_penmode_xor
MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
L5F6B: jsr peek_event
lda event_kind
cmp #MGTK::EventKind::drag
beq L5FC5
MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
ldx #$00
L5F80: cpx cached_window_icon_count
bne L5F88
jmp reset_grafport3
L5F88: txa
pha
lda cached_window_icon_list,x
sta icon_param
jsr icon_screen_to_window
ITK_RELAY_CALL IconTK::ICON_IN_RECT, icon_param
beq L5FB9
ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, icon_param
ldx selected_icon_count
inc selected_icon_count
copy icon_param, selected_icon_list,x
copy active_window_id, selected_window_index
L5FB9: lda icon_param
jsr icon_window_to_screen
pla
tax
inx
jmp L5F80
L5FC5: jsr L60D5
sub16 event_xcoord, L60CF, L60CB
sub16 event_ycoord, L60D1, L60CD
lda L60CC
bpl L5FFE
lda L60CB
eor #$FF
sta L60CB
inc L60CB
L5FFE: lda L60CE
bpl L600E
lda L60CD
eor #$FF
sta L60CD
inc L60CD
L600E: lda L60CB
cmp #$05
bcs L601F
lda L60CD
cmp #$05
bcs L601F
jmp L5F6B
L601F: MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
COPY_STRUCT MGTK::Point, event_coords, L60CF
cmp16 event_xcoord, tmp_rect::x2
bpl L6068
cmp16 event_xcoord, tmp_rect::x1
bmi L6054
bit L60D3
bpl L6068
L6054: copy16 event_xcoord, tmp_rect::x1
copy #$80, L60D3
jmp L6079
L6068: copy16 event_xcoord, tmp_rect::x2
copy #0, L60D3
L6079: cmp16 event_ycoord, tmp_rect::y2
bpl L60AE
cmp16 event_ycoord, tmp_rect::y1
bmi L609A
bit L60D4
bpl L60AE
L609A: copy16 event_ycoord, tmp_rect::y1
copy #$80, L60D4
jmp L60BF
L60AE: copy16 event_ycoord, tmp_rect::y2
copy #0, L60D4
L60BF: MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
jmp L5F6B
L60CB: .byte 0
L60CC: .byte 0
L60CD: .byte 0
L60CE: .byte 0
L60CF: .word 0
L60D1: .word 0
L60D3: .byte 0
L60D4: .byte 0
L60D5: jsr push_pointers
jmp icon_ptr_screen_to_window
.endproc
L5F13 := L5F13_impl::start
;;; ============================================================
.proc handle_title_click
ptr := $06
jmp :+
: copy active_window_id, event_params
MGTK_RELAY_CALL MGTK::FrontWindow, active_window_id
lda active_window_id
jsr copy_window_portbits
MGTK_RELAY_CALL MGTK::DragWindow, event_params
lda active_window_id
jsr window_lookup
stax ptr
ldy #MGTK::Winfo::port + MGTK::GrafPort::viewloc + MGTK::Point::ycoord
lda (ptr),y
cmp #$19 ; ???
bcs :+
lda #$19
sta (ptr),y
: ldy #MGTK::Winfo::port + MGTK::GrafPort::viewloc + MGTK::Point::xcoord
sub16in (ptr),y, port_copy+MGTK::GrafPort::viewloc+MGTK::Point::xcoord, deltax
iny
sub16in (ptr),y, port_copy+MGTK::GrafPort::viewloc+MGTK::Point::ycoord, deltay
ldx active_window_id
dex
lda win_view_by_table,x
beq :+ ; view by icon
rts
;; Update icon positions
: jsr LoadActiveWindowIconTable
ldx #0
next: cpx cached_window_icon_count
bne :+
jsr StoreWindowIconTable
jsr LoadDesktopIconTable
jmp done
: txa
pha
lda cached_window_icon_list,x
jsr icon_entry_lookup
stax ptr
ldy #IconEntry::iconx
add16in (ptr),y, deltax, (ptr),y
iny
add16in (ptr),y, deltay, (ptr),y
pla
tax
inx
jmp next
done: rts
deltax: .word 0
deltay: .word 0
.endproc
;;; ============================================================
.proc handle_resize_click
copy active_window_id, event_params
MGTK_RELAY_CALL MGTK::GrowWindow, event_params
jsr redraw_windows_and_desktop
jsr LoadActiveWindowIconTable
jsr cached_icons_screen_to_window
jsr update_scrollbars
jsr cached_icons_window_to_screen
jsr LoadDesktopIconTable
jmp reset_grafport3
.endproc
;;; ============================================================
handle_close_click:
lda active_window_id
MGTK_RELAY_CALL MGTK::TrackGoAway, trackgoaway_params
lda trackgoaway_params::goaway
bne close_window
rts
.proc close_window
icon_ptr := $06
jsr LoadActiveWindowIconTable
jsr clear_selection
ldx active_window_id
dex
lda win_view_by_table,x
bmi iter ; list view, not icons
lda icon_count
sec
sbc cached_window_icon_count
sta icon_count
ITK_RELAY_CALL IconTK::CLOSE_WINDOW, active_window_id
jsr free_cached_window_icons
iter: dec num_open_windows
ldx #0
txa
: sta cached_window_icon_list,x
cpx cached_window_icon_count
beq cont
inx
jmp :-
cont: sta cached_window_icon_count
jsr StoreWindowIconTable
MGTK_RELAY_CALL MGTK::CloseWindow, active_window_id
;; Unhilight dir (vol/folder) icon, if present
ldx active_window_id
dex
lda window_to_dir_icon_table,x
bmi no_icon ; $FF = dir icon freed
sta icon_param
jsr icon_entry_lookup
stax icon_ptr
ldy #IconEntry::state
lda (icon_ptr),y
and #icon_entry_winid_mask
beq no_icon ; ???
ldy #IconEntry::win_type
lda (icon_ptr),y
and #AS_BYTE(~icon_entry_open_mask) ; clear open_flag
sta (icon_ptr),y
and #icon_entry_winid_mask
sta selected_window_index
jsr zero_grafport5_coords
ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, icon_param
jsr reset_grafport3
copy #1, selected_icon_count
copy icon_param, selected_icon_list
ldx active_window_id
dex
lda window_to_dir_icon_table,x
jsr L7345
;; Animate closing into dir (vol/folder) icon
ldx active_window_id
dex
lda window_to_dir_icon_table,x
inx
jsr animate_window_close
no_icon:
ldx active_window_id
dex
lda #0
sta window_to_dir_icon_table,x ; 0 = window free
sta win_view_by_table,x
MGTK_RELAY_CALL MGTK::FrontWindow, active_window_id
jsr LoadDesktopIconTable
lda #MGTK::checkitem_uncheck
sta checkitem_params::check
MGTK_RELAY_CALL MGTK::CheckItem, checkitem_params
jsr update_window_menu_items
jmp redraw_windows_and_desktop
.endproc
;;; ============================================================
.proc L62BC
cmp #$01
bcc L62C2
bne L62C5
L62C2: return #0
L62C5: sta L638B
stx L6386
sty L638A
cmp L6386
bcc L62D5
tya
rts
L62D5: lda #$00
sta L6385
sta L6389
clc
ror L6386
ror L6385
clc
ror L638A
ror L6389
lda #$00
sta L6383
sta L6387
sta L6384
sta L6388
L62F9: lda L6384
cmp L638B
beq L630F
bcc L6309
jsr L6319
jmp L62F9
L6309: jsr L634E
jmp L62F9
L630F: lda L6388
cmp #$01
bcs L6318
lda #$01
L6318: rts
L6319: sub16 L6383, L6385, L6383
sub16 L6387, L6389, L6387
clc
ror L6386
ror L6385
clc
ror L638A
ror L6389
rts
L634E: add16 L6383, L6385, L6383
add16 L6387, L6389, L6387
clc
ror L6386
ror L6385
clc
ror L638A
ror L6389
rts
L6383: .byte 0
L6384: .byte 0
L6385: .byte 0
L6386: .byte 0
L6387: .byte 0
L6388: .byte 0
L6389: .byte 0
L638A: .byte 0
L638B: .byte 0
.endproc
;;; ============================================================
.proc L638C
jsr L650F
sty L63E9
jsr L644C
sta L63E8
sub16_8 grafport2::cliprect::y1, L63E8, L63EA
cmp16 L63EA, iconbb_rect+MGTK::Rect::y1
bmi L63C1
ldax L63EA
jmp L63C7
L63C1: ldax iconbb_rect+MGTK::Rect::y1
L63C7: stax grafport2::cliprect::y1
add16_8 grafport2::cliprect::y1, L63E9, grafport2::cliprect::y2
jsr assign_active_window_cliprect
jsr update_scrollbars
jmp L6556
L63E8: .byte 0
L63E9: .byte 0
L63EA: .word 0
.endproc
;;; ============================================================
.proc L63EC
jsr L650F
sty L6449
jsr L644C
sta L6448
add16_8 grafport2::cliprect::y2, L6448, L644A
cmp16 L644A, iconbb_rect+MGTK::Rect::y2
bpl L6421
ldax L644A
jmp L6427
L6421: ldax iconbb_rect+MGTK::Rect::y2
L6427: stax grafport2::cliprect::y2
sub16_8 grafport2::cliprect::y2, L6449, grafport2::cliprect::y1
jsr assign_active_window_cliprect
jsr update_scrollbars
jmp L6556
L6448: .byte 0
L6449: .byte 0
L644A: .word 0
.endproc
;;; ============================================================
.proc L644C
tya
sec
sbc #$0E
rts
.endproc
;;; ============================================================
.proc L6451
jsr L650F
stax L64AC
sub16 grafport2::cliprect::x1, L64AC, L64AE
cmp16 L64AE, iconbb_rect+MGTK::Rect::x1
bmi L6484
ldax L64AE
jmp L648A
L6484: ldax iconbb_rect+MGTK::Rect::x1
L648A: stax grafport2::cliprect::x1
add16 grafport2::cliprect::x1, L64AC, grafport2::cliprect::x2
jsr assign_active_window_cliprect
jsr update_scrollbars
jmp L6556
L64AC: .word 0
L64AE: .word 0
.endproc
;;; ============================================================
.proc L64B0
jsr L650F
stax L650B
add16 grafport2::cliprect::x2, L650B, L650D
cmp16 L650D, iconbb_rect+MGTK::Rect::x2
bpl L64E3
ldax L650D
jmp L64E9
L64E3: ldax iconbb_rect+MGTK::Rect::x2
L64E9: stax grafport2::cliprect::x2
sub16 grafport2::cliprect::x2, L650B, grafport2::cliprect::x1
jsr assign_active_window_cliprect
jsr update_scrollbars
jmp L6556
L650B: .word 0
L650D: .word 0
.endproc
.proc L650F
bit active_window_view_by
bmi :+ ; list view, not icons
jsr cached_icons_screen_to_window
: jsr apply_active_winfo_to_grafport2
jsr compute_icons_bbox
lda active_window_id
jmp compute_window_dimensions
.endproc
.proc apply_active_winfo_to_grafport2
ptr := $06
lda active_window_id
jsr window_lookup
addax #MGTK::Winfo::port, ptr
ldy #.sizeof(MGTK::GrafPort) + 1 ; ???
: lda (ptr),y
sta grafport2,y
dey
bpl :-
rts
.endproc
.proc assign_active_window_cliprect
ptr := $6
lda active_window_id
jsr window_lookup
stax ptr
ldy #MGTK::Winfo::port + MGTK::GrafPort::maprect + 7
ldx #7
: lda grafport2::cliprect,x
sta (ptr),y
dey
dex
bpl :-
rts
.endproc
.proc L6556
bit active_window_view_by
bmi :+
jsr cached_icons_window_to_screen
: MGTK_RELAY_CALL MGTK::PaintRect, grafport2::cliprect
jsr reset_grafport3
jmp L6C19
.endproc
;;; ============================================================
.proc update_hthumb
winfo_ptr := $06
lda active_window_id
jsr compute_window_dimensions
stax win_width
lda active_window_id
jsr window_lookup
stax winfo_ptr
ldy #MGTK::Winfo::hthumbmax
lda (winfo_ptr),y
tay
sub16 iconbb_rect+MGTK::Rect::x2, iconbb_rect+MGTK::Rect::x1, delta
sub16 delta, win_width, delta
lsr16 delta ; / 2
ldx delta
sub16 grafport2::cliprect::x1, iconbb_rect+MGTK::Rect::x1, delta
bpl pos
lda #0
beq neg ; always
pos: cmp16 grafport2::cliprect::x2, iconbb_rect+MGTK::Rect::x2
bmi L65E2
tya
jmp L65EE
L65E2: lsr16 delta ; / 2
lda delta
neg: jsr L62BC
L65EE: sta updatethumb_thumbpos
lda #MGTK::Ctl::horizontal_scroll_bar
sta updatethumb_which_ctl
MGTK_RELAY_CALL MGTK::UpdateThumb, updatethumb_params
rts
win_width:
.word 0
delta: .word 0
.endproc
;;; ============================================================
.proc update_vthumb
winfo_ptr := $06
lda active_window_id
jsr compute_window_dimensions
sty win_height
lda active_window_id
jsr window_lookup
stax winfo_ptr
ldy #MGTK::Winfo::vthumbmax
lda (winfo_ptr),y
tay
sub16 iconbb_rect+MGTK::Rect::y2, iconbb_rect+MGTK::Rect::y1, delta
sub16_8 delta, win_height, delta
lsr16 delta ; / 4
lsr16 delta
ldx delta
sub16 grafport2::cliprect::y1, iconbb_rect+MGTK::Rect::y1, delta
bpl pos
lda #0
beq neg ; always
pos: cmp16 grafport2::cliprect::y2, iconbb_rect+MGTK::Rect::y2
bmi L667B
tya
jmp L668D
L667B: lsr16 delta ; / 4
lsr16 delta
lda delta
neg: jsr L62BC
L668D: sta updatethumb_thumbpos
lda #MGTK::Ctl::vertical_scroll_bar
sta updatethumb_which_ctl
MGTK_RELAY_CALL MGTK::UpdateThumb, updatethumb_params
rts
win_height:
.byte 0
delta: .word 0
.endproc
;;; ============================================================
.proc update_window_menu_items
ldx active_window_id
beq disable_menu_items
jmp check_view_menu_items
disable_menu_items:
copy #MGTK::disablemenu_disable, disablemenu_params::disable
MGTK_RELAY_CALL MGTK::DisableMenu, disablemenu_params
copy #MGTK::disableitem_disable, disableitem_params::disable
copy #menu_id_file, disableitem_params::menu_id
copy #desktop_aux::menu_item_id_new_folder, disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
copy #desktop_aux::menu_item_id_close, disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
copy #desktop_aux::menu_item_id_close_all, disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
copy #0, menu_dispatch_flag
rts
check_view_menu_items:
dex
lda win_view_by_table,x
and #$0F ; mask off menu item number
tax
inx
stx checkitem_params::menu_item
lda #MGTK::checkitem_check
sta checkitem_params::check
MGTK_RELAY_CALL MGTK::CheckItem, checkitem_params
rts
.endproc
;;; ============================================================
;;; Disable menu items for operating on a selected file
.proc disable_file_menu_items
copy #MGTK::disableitem_disable, disableitem_params::disable
;; File
copy #menu_id_file, disableitem_params::menu_id
lda #desktop_aux::menu_item_id_open
jsr disable_menu_item
lda #desktop_aux::menu_item_id_get_info
jsr disable_menu_item
lda #desktop_aux::menu_item_id_rename_icon
jsr disable_menu_item
;; Special
copy #menu_id_special, disableitem_params::menu_id
lda #desktop_aux::menu_item_id_lock
jsr disable_menu_item
lda #desktop_aux::menu_item_id_unlock
jsr disable_menu_item
lda #desktop_aux::menu_item_id_get_size
jsr disable_menu_item
rts
disable_menu_item:
sta disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
rts
.endproc
;;; ============================================================
.proc enable_file_menu_items
copy #MGTK::disableitem_enable, disableitem_params::disable
;; File
copy #menu_id_file, disableitem_params::menu_id
lda #desktop_aux::menu_item_id_open
jsr enable_menu_item
lda #desktop_aux::menu_item_id_get_info
jsr enable_menu_item
lda #desktop_aux::menu_item_id_rename_icon
jsr enable_menu_item
;; Special
copy #menu_id_special, disableitem_params::menu_id
lda #desktop_aux::menu_item_id_lock
jsr enable_menu_item
lda #desktop_aux::menu_item_id_unlock
jsr enable_menu_item
lda #desktop_aux::menu_item_id_get_size
jsr enable_menu_item
rts
enable_menu_item:
sta disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
rts
.endproc
;;; ============================================================
.proc toggle_eject_menu_item
enable:
copy #MGTK::disableitem_enable, disableitem_params::disable
jmp :+
disable:
copy #MGTK::disableitem_disable, disableitem_params::disable
: copy #menu_id_special, disableitem_params::menu_id
copy #desktop_aux::menu_item_id_eject, disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
copy #menu_id_special, disableitem_params::menu_id
copy #desktop_aux::menu_item_id_check_drive, disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
rts
.endproc
enable_eject_menu_item := toggle_eject_menu_item::enable
disable_eject_menu_item := toggle_eject_menu_item::disable
;;; ============================================================
.proc toggle_selector_menu_items
disable:
copy #MGTK::disableitem_disable, disableitem_params::disable
jmp :+
enable:
copy #MGTK::disableitem_enable, disableitem_params::disable
: copy #menu_id_selector, disableitem_params::menu_id
lda #menu_item_id_selector_edit
jsr configure_menu_item
lda #menu_item_id_selector_delete
jsr configure_menu_item
lda #menu_item_id_selector_run
jsr configure_menu_item
copy #$80, LD344
rts
configure_menu_item:
sta disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
rts
.endproc
enable_selector_menu_items := toggle_selector_menu_items::enable
disable_selector_menu_items := toggle_selector_menu_items::disable
;;; ============================================================
.proc handle_volume_icon_click
lda selected_icon_count
bne L67DF
jmp set_selection
L67DF: tax
dex
lda findicon_which_icon
L67E4: cmp selected_icon_list,x
beq L67EE
dex
bpl L67E4
bmi L67F6
L67EE: bit double_click_flag
bmi L6834
jmp L6880
L67F6: bit BUTN0
bpl replace_selection
;; Add clicked icon to selection
lda selected_window_index
bne replace_selection
ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, findicon_which_icon
ldx selected_icon_count
lda findicon_which_icon
sta selected_icon_list,x
inc selected_icon_count
jmp L6834
;; Replace selection with clicked icon
replace_selection:
jsr clear_selection
;; Set selection to clicked icon
set_selection:
ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, findicon_which_icon
copy #1, selected_icon_count
copy findicon_which_icon, selected_icon_list
copy #0, selected_window_index
L6834: bit double_click_flag
bpl L6880
;; Drag of volume icon
copy findicon_which_icon, drag_drop_param
ITK_RELAY_CALL IconTK::DRAG_HIGHLIGHTED, drag_drop_param
tax
lda drag_drop_param
beq L6878
jsr jt_drop
cmp #$FF
bne L6858
jmp redraw_windows_and_desktop
L6858: lda drag_drop_param
cmp trash_icon_num
bne L6863
jmp redraw_windows_and_desktop
L6863: lda drag_drop_param
bpl L6872
and #$7F
pha
jsr update_used_free_for_vol_windows
pla
jmp select_and_refresh_window
L6872: jsr update_vol_free_used_for_icon
jmp redraw_windows_and_desktop
L6878: txa
cmp #2
bne L688F
jmp redraw_windows_and_desktop
;; Double-click on volume icon
L6880: lda findicon_which_icon
cmp trash_icon_num
beq L688E
jsr open_folder_or_volume_icon
jsr StoreWindowIconTable
L688E: rts
L688F: ldx selected_icon_count
dex
L6893: txa
pha
copy selected_icon_list,x, icon_param3
ITK_RELAY_CALL IconTK::REDRAW_ICON, icon_param3
pla
tax
dex
bpl L6893
rts
.endproc
;;; ============================================================
.proc L68AA
jsr reset_grafport3
bit BUTN0
bpl L68B3
rts
L68B3: jsr clear_selection
ldx #3
L68B8: lda event_coords,x
sta tmp_rect::x1,x
sta tmp_rect::x2,x
dex
bpl L68B8
jsr peek_event
lda event_kind
cmp #MGTK::EventKind::drag
beq L68CF
rts
L68CF: MGTK_RELAY_CALL MGTK::SetPattern, checkerboard_pattern
jsr set_penmode_xor
MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
L68E4: jsr peek_event
lda event_kind
cmp #MGTK::EventKind::drag
beq L6932
MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
ldx #0
L68F9: cpx cached_window_icon_count
bne :+
lda #0
sta selected_window_index
rts
: txa
pha
copy cached_window_icon_list,x, icon_param
ITK_RELAY_CALL IconTK::ICON_IN_RECT, icon_param
beq L692C
ITK_RELAY_CALL IconTK::HIGHLIGHT_ICON, icon_param
ldx selected_icon_count
inc selected_icon_count
copy icon_param, selected_icon_list,x
L692C: pla
tax
inx
jmp L68F9
L6932: sub16 event_xcoord, L6A39, L6A35
sub16 event_ycoord, L6A3B, L6A37
lda L6A36
bpl L6968
lda L6A35
eor #$FF
sta L6A35
inc L6A35
L6968: lda L6A38
bpl L6978
lda L6A37
eor #$FF
sta L6A37
inc L6A37
L6978: lda L6A35
cmp #$05
bcs L6989
lda L6A37
cmp #$05
bcs L6989
jmp L68E4
L6989: MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
COPY_STRUCT MGTK::Point, event_coords, L6A39
cmp16 event_xcoord, tmp_rect::x2
bpl L69D2
cmp16 event_xcoord, tmp_rect::x1
bmi L69BE
bit L6A3D
bpl L69D2
L69BE: copy16 event_xcoord, tmp_rect::x1
copy #$80, L6A3D
jmp L69E3
L69D2: copy16 event_xcoord, tmp_rect::x2
copy #0, L6A3D
L69E3: cmp16 event_ycoord, tmp_rect::y2
bpl L6A18
cmp16 event_ycoord, tmp_rect::y1
bmi L6A04
bit L6A3E
bpl L6A18
L6A04: copy16 event_ycoord, tmp_rect::y1
copy #$80, L6A3E
jmp L6A29
L6A18: copy16 event_ycoord, tmp_rect::y2
copy #0, L6A3E
L6A29: MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
jmp L68E4
L6A35: .byte 0
L6A36: .byte 0
L6A37: .byte 0
L6A38: .byte 0
L6A39: .word 0
L6A3B: .word 0
L6A3D: .byte 0
L6A3E: .byte 0
.endproc
;;; ============================================================
;;; Update used/free values for windows related to volume icon
;;; Input: icon number in A
.proc update_vol_free_used_for_icon
ptr := $6
path_buf := $220
jsr find_window_for_dir_icon
beq L6A80 ; found
;; Not in the map. Look for related windows.
jsr icon_entry_lookup
addax #IconEntry::len, ptr
ldy #0
lda (ptr),y
tay
dey
L6A5C: lda (ptr),y
sta path_buf,y
dey
bpl L6A5C
dec path_buf
lda #'/'
sta path_buf+1
ldax #path_buf
ldy path_buf
jsr find_windows_for_prefix
ldax #path_buf
ldy path_buf
jmp update_vol_used_free_for_found_windows
;; Found it in the map.
L6A80: inx
txa
pha
jsr update_used_free_for_vol_windows
pla
jmp select_and_refresh_window
.endproc
;;; ============================================================
;;; Open a folder/volume icon
;;; Input: A = icon
;;; Note: stack will be restored via saved_stack on failure
.proc open_folder_or_volume_icon
ptr := $06
sta icon_params2
jsr StoreWindowIconTable
lda icon_params2
;; Already an open window for the icon?
ldx #7
: cmp window_to_dir_icon_table,x
beq found_win
dex
bpl :-
jmp no_linked_win
;; --------------------------------------------------
;; There is an existing window associated with icon.
found_win:
;; Is it the active window? If so, done!
inx
cpx active_window_id
bne :+
rts
;; Otherwise, bring the window to the front.
: stx cached_window_id
jsr LoadWindowIconTable
jsr update_icon
lda icon_params2
ldx window_icon_to_filerecord_list
dex
: cmp window_icon_to_filerecord_list+1,x
beq :+
dex
bpl :-
jsr open_directory
: MGTK_RELAY_CALL MGTK::SelectWindow, cached_window_id
lda cached_window_id
sta active_window_id
jsr L6C19
jsr redraw_windows
jmp LoadDesktopIconTable
;; --------------------------------------------------
;; No associated window - check for matching path.
no_linked_win:
;; Compute the path (will be needed anyway).
lda icon_params2
jsr icon_entry_lookup
stax ptr
jsr compose_icon_full_path
addr_call find_window_for_path, open_dir_path_buf
beq no_win
;; Found a match - associate the window.
tax
dex ; 1-based to 0-based
copy icon_params2, window_to_dir_icon_table,x
jmp found_win
;; --------------------------------------------------
;; No window - need to open one.
no_win:
;; Is there a free window?
lda num_open_windows
cmp #8
bcc :+
;; Nope, show error.
lda #warning_msg_too_many_windows
jsr warning_dialog_proc_num
ldx saved_stack
txs
rts
;; Search window-icon map to find an unused window.
: ldx #0
: lda window_to_dir_icon_table,x
beq :+ ; 0 = window free
inx
jmp :-
;; Map the window to its source icon
: lda icon_params2
sta window_to_dir_icon_table,x
inx ; 0-based to 1-based
stx cached_window_id
jsr LoadWindowIconTable
;; Update View and other menus
inc num_open_windows
ldx cached_window_id
dex
copy #0, win_view_by_table,x
lda num_open_windows ; Was there already a window open?
cmp #2
bcs :+ ; yes, no need to enable file menu
jsr enable_various_file_menu_items
jmp update_view
: copy #0, checkitem_params::check
jsr check_item
update_view:
lda #desktop_aux::menu_item_id_view_by_icon
sta checkitem_params::menu_item
sta checkitem_params::check
jsr check_item
jsr update_icon
;; Set path, size, contents, and volume free/used.
jsr prepare_new_window
;; Create the window
lda cached_window_id
jsr window_lookup ; A,X points at Winfo
ldy #MGTK::OpenWindow
jsr MGTK_RELAY
copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
jsr draw_window_header
;; Restore and add the icons
jsr cached_icons_screen_to_window
copy #0, num
: lda num
cmp cached_window_icon_count
beq done
tax
lda cached_window_icon_list,x
jsr icon_entry_lookup ; A,X points at IconEntry
ldy #IconTK::ADD_ICON
jsr ITK_RELAY ; icon entry addr in A,X
inc num
jmp :-
;; Finish up
done: copy cached_window_id, active_window_id
jsr update_scrollbars
jsr cached_icons_window_to_screen
jsr StoreWindowIconTable
jsr LoadDesktopIconTable
jmp reset_grafport3
;;; Common code to update the dir (vol/folder) icon.
.proc update_icon
lda icon_params2
jsr icon_entry_lookup
stax ptr
ldy #IconEntry::win_type
lda (ptr),y
ora #icon_entry_open_mask ; set open_flag
sta (ptr),y
ldy #IconEntry::win_type ; get window id
lda (ptr),y
and #icon_entry_winid_mask
sta getwinport_params2::window_id
beq :+ ; window 0 = desktop
cmp active_window_id ; prep to redraw windowed (file) icon
bne done ; but only if active window
jsr get_set_port2
jsr offset_grafport2_and_set
lda icon_params2
jsr icon_screen_to_window
: ITK_RELAY_CALL IconTK::REDRAW_ICON, icon_params2
lda getwinport_params2::window_id
beq done ; skip if on desktop
lda icon_params2 ; restore from drawing
jsr icon_window_to_screen
jsr reset_grafport3
done: rts
.endproc
num: .byte 0
.endproc
;;; ============================================================
.proc check_item
MGTK_RELAY_CALL MGTK::CheckItem, checkitem_params
rts
.endproc
;;; ============================================================
.proc L6C19
ldx cached_window_id
dex
lda win_view_by_table,x
bmi L6C25 ; list view, not icons
jmp L6CCD
;; List view
L6C25: jsr push_pointers
copy cached_window_id, getwinport_params2::window_id
jsr get_set_port2
bit draw_window_header_flag
bmi :+
jsr draw_window_header
: lda cached_window_id
sta getwinport_params2::window_id
jsr get_port2
bit draw_window_header_flag
bmi :+
jsr offset_grafport2_and_set
: ldx cached_window_id
dex
lda window_to_dir_icon_table,x
;; BUG: What if dir icon is freed? ($FF)
ldx #0
L6C53: cmp window_icon_to_filerecord_list+1,x
beq L6C5F
inx
cpx window_icon_to_filerecord_list
bne L6C53
rts
L6C5F: txa
asl a
tax
lda window_filerecord_table,x
sta LE71D
sta $06
lda window_filerecord_table+1,x
sta LE71D+1
sta $06+1
lda LCBANK2
lda LCBANK2
ldy #$00
lda ($06),y
tay
lda LCBANK1
lda LCBANK1
tya
sta LE71F
inc LE71D
bne L6C8F
inc LE71D+1
;; First row
.proc L6C8F
lda #16
sta pos_col_name::ycoord
sta pos_col_type::ycoord
sta pos_col_size::ycoord
sta pos_col_date::ycoord
lda #0
sta pos_col_name::ycoord+1
sta pos_col_type::ycoord+1
sta pos_col_size::ycoord+1
sta pos_col_date::ycoord+1
lda #0
sta rows_done
rloop: lda rows_done
cmp cached_window_icon_count
beq done
tax
lda cached_window_icon_list,x
jsr L813F
inc rows_done
jmp rloop
done: jsr reset_grafport3
jsr pop_pointers
rts
rows_done:
.byte 0
.endproc
;; Icon view
L6CCD: copy cached_window_id, getwinport_params2::window_id
jsr get_set_port2
bit draw_window_header_flag
bmi :+
jsr draw_window_header
: jsr cached_icons_screen_to_window
jsr offset_grafport2_and_set
COPY_BLOCK grafport2::cliprect, tmp_rect
ldx #0
txa
pha
L6CF3: cpx cached_window_icon_count
bne L6D09
pla
jsr reset_grafport3
copy cached_window_id, getwinport_params2::window_id
jsr get_set_port2
jsr cached_icons_window_to_screen
rts
L6D09: txa
pha
lda cached_window_icon_list,x
sta icon_param
ITK_RELAY_CALL IconTK::ICON_IN_RECT, icon_param
beq L6D25
ITK_RELAY_CALL IconTK::REDRAW_ICON, icon_param
L6D25: pla
tax
inx
jmp L6CF3
.endproc
;;; ============================================================
.proc clear_selection
lda selected_icon_count
bne L6D31
rts
L6D31: copy #0, L6DB0
copy selected_window_index, tmp_rect ; ???
beq L6D7D
cmp active_window_id
beq L6D4D
jsr zero_grafport5_coords
copy #0, tmp_rect
beq L6D56
L6D4D: sta getwinport_params2::window_id
jsr get_set_port2
jsr offset_grafport2_and_set
L6D56: lda L6DB0
cmp selected_icon_count
beq L6D9B
tax
lda selected_icon_list,x
sta icon_param
jsr icon_screen_to_window
ITK_RELAY_CALL IconTK::UNHIGHLIGHT_ICON, icon_param
lda icon_param
jsr icon_window_to_screen
inc L6DB0
jmp L6D56
L6D7D: lda L6DB0
cmp selected_icon_count
beq L6D9B
tax
lda selected_icon_list,x
sta icon_param
ITK_RELAY_CALL IconTK::UNHIGHLIGHT_ICON, icon_param
inc L6DB0
jmp L6D7D
L6D9B: lda #0
ldx selected_icon_count
dex
: sta selected_icon_list,x
dex
bpl :-
sta selected_icon_count
sta selected_window_index
jmp reset_grafport3
L6DB0: .byte 0
.endproc
;;; ============================================================
.proc update_scrollbars
ldx active_window_id
dex
lda win_view_by_table,x
bmi :+ ; list view, not icons
jsr compute_icons_bbox
jmp config_port
;; List view
: jsr cached_icons_screen_to_window
jsr compute_icons_bbox
jsr cached_icons_window_to_screen
config_port:
copy active_window_id, getwinport_params2::window_id
jsr get_set_port2
;; check horizontal bounds
cmp16 iconbb_rect+MGTK::Rect::x1, grafport2::cliprect::x1
bmi activate_hscroll
cmp16 grafport2::cliprect::x2, iconbb_rect+MGTK::Rect::x2
bmi activate_hscroll
;; deactivate horizontal scrollbar
copy #MGTK::Ctl::horizontal_scroll_bar, activatectl_which_ctl
copy #MGTK::activatectl_deactivate, activatectl_activate
jsr activate_ctl
jmp check_vscroll
activate_hscroll:
;; activate horizontal scrollbar
copy #MGTK::Ctl::horizontal_scroll_bar, activatectl_which_ctl
copy #MGTK::activatectl_activate, activatectl_activate
jsr activate_ctl
jsr update_hthumb
check_vscroll:
;; check vertical bounds
cmp16 iconbb_rect+MGTK::Rect::y1, grafport2::cliprect::y1
bmi activate_vscroll
cmp16 grafport2::cliprect::y2, iconbb_rect+MGTK::Rect::y2
bmi activate_vscroll
;; deactivate vertical scrollbar
copy #MGTK::Ctl::vertical_scroll_bar, activatectl_which_ctl
copy #MGTK::activatectl_deactivate, activatectl_activate
jsr activate_ctl
rts
activate_vscroll:
;; activate vertical scrollbar
copy #MGTK::Ctl::vertical_scroll_bar, activatectl_which_ctl
copy #MGTK::activatectl_activate, activatectl_activate
jsr activate_ctl
jmp update_vthumb
activate_ctl:
MGTK_RELAY_CALL MGTK::ActivateCtl, activatectl_params
rts
.endproc
;;; ============================================================
.proc cached_icons_screen_to_window
lda #0
sta count
loop: lda count
cmp cached_window_icon_count
beq done
tax
lda cached_window_icon_list,x
jsr icon_screen_to_window
inc count
jmp loop
done: rts
count: .byte 0
.endproc
;;; ============================================================
.proc cached_icons_window_to_screen
lda #0
sta index
loop: lda index
cmp cached_window_icon_count
beq done
tax
lda cached_window_icon_list,x
jsr icon_window_to_screen
inc index
jmp loop
done: rts
index: .byte 0
.endproc
;;; ============================================================
.proc offset_grafport2_impl
flag_clear:
lda #$80
beq :+
flag_set:
lda #0
: sta flag
add16 grafport2::viewloc::ycoord, #15, grafport2::viewloc::ycoord
add16 grafport2::cliprect::y1, #15, grafport2::cliprect::y1
bit flag
bmi done
MGTK_RELAY_CALL MGTK::SetPort, grafport2
done: rts
flag: .byte 0
.endproc
offset_grafport2 := offset_grafport2_impl::flag_clear
offset_grafport2_and_set := offset_grafport2_impl::flag_set
;;; ============================================================
.proc enable_various_file_menu_items
copy #MGTK::disablemenu_enable, disablemenu_params::disable
MGTK_RELAY_CALL MGTK::DisableMenu, disablemenu_params
copy #MGTK::disableitem_enable, disableitem_params::disable
copy #menu_id_file, disableitem_params::menu_id
copy #desktop_aux::menu_item_id_new_folder, disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
copy #desktop_aux::menu_item_id_close, disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
copy #desktop_aux::menu_item_id_close_all, disableitem_params::menu_item
MGTK_RELAY_CALL MGTK::DisableItem, disableitem_params
copy #$80, menu_dispatch_flag
rts
.endproc
;;; ============================================================
;;; Refresh vol used/free for windows of same volume as win in A.
;;; Input: A = window id
.proc update_used_free_for_vol_windows
ptr := $6
jsr window_path_lookup
sta ptr
sta pathptr
stx ptr+1
stx pathptr+1
ldy #0 ; length offset
lda (ptr),y
sta pathlen
iny
loop: iny ; start at 2nd character
lda (ptr),y
cmp #'/'
beq found
cpy pathlen
beq finish
jmp loop
found: dey
finish: sty pathlen
addr_call_indirect find_windows_for_prefix, ptr ; ???
ldax pathptr
ldy pathlen
jmp update_vol_used_free_for_found_windows
pathptr: .addr 0
pathlen: .byte 0
.endproc
;;; ============================================================
;;; Update used/free for results of find_window[s]_for_prefix
.proc update_vol_used_free_for_found_windows
ptr := $6
stax ptr
sty path_buffer
: lda (ptr),y
sta path_buffer,y
dey
bne :-
jsr get_vol_free_used
bne done
lda found_windows_count
beq done
loop: dec found_windows_count
bmi done
ldx found_windows_count
lda found_windows_list,x
sec
sbc #1
asl a
tax
copy16 vol_kb_used, window_k_used_table,x
copy16 vol_kb_free, window_k_free_table,x
jmp loop
done: rts
.endproc
;;; ============================================================
;;; Find position of last segment of path at (A,X), return in Y.
;;; For "/a/b", Y points at "/a"; if volume path, unchanged.
.proc find_last_path_segment
ptr := $A
stax ptr
;; Find last slash in string
ldy #0
lda (ptr),y
tay
: lda (ptr),y
cmp #'/'
beq slash
dey
bpl :-
;; Oops - no slash
ldy #1
;; Restore original string
restore:
dey
lda (ptr),y
tay
rts
;; Are we left with "/" ?
slash: cpy #1
beq restore
dey
rts
.endproc
;;; ============================================================
;; If 'set' version called, length in Y; otherwise use str len
.proc find_windows
ptr := $6
set: stax ptr
lda #$80
bne start
unset: stax ptr
lda #0
start: sta exact_match_flag
bit exact_match_flag
bpl :+
ldy #0 ; Use full length
lda (ptr),y
tay
: sty path_buffer
;; Copy ptr to path_buffer
: lda (ptr),y
sta path_buffer,y
dey
bne :-
lda #0
sta found_windows_count
sta window_num
loop: inc window_num
lda window_num
cmp #9 ; windows are 1-8
bcc check_window
bit exact_match_flag
bpl :+
lda #0
: rts
check_window:
jsr window_lookup
stax ptr
ldy #MGTK::Winfo::status
lda (ptr),y
beq loop
lda window_num
jsr window_path_lookup
stax ptr
ldy #0
lda (ptr),y
tay
cmp path_buffer
beq :+
bit exact_match_flag
bmi loop
ldy path_buffer
iny
lda (ptr),y
cmp #'/'
bne loop
dey
: lda (ptr),y
cmp path_buffer,y
bne loop
dey
bne :-
bit exact_match_flag
bmi done
ldx found_windows_count
lda window_num
sta found_windows_list,x
inc found_windows_count
jmp loop
done: return window_num
window_num:
.byte 0
exact_match_flag:
.byte 0
.endproc
find_window_for_path := find_windows::set
find_windows_for_prefix := find_windows::unset
found_windows_count:
.byte 0
found_windows_list:
.res 8
;;; ============================================================
.proc open_directory
jmp start
DEFINE_OPEN_PARAMS open_params, path_buffer, $800
DEFINE_READ_PARAMS read_params, $0C00, $200
DEFINE_CLOSE_PARAMS close_params
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params4, path_buffer
.byte 0
vol_kb_free: .word 0
vol_kb_used: .word 0
entry_length:
.byte 0
L70C0: .byte $00
L70C1: .byte $00
L70C2: .byte $00
L70C3: .byte $00
L70C4: .byte $00
.proc start
sta L72A7
jsr push_pointers
COPY_BYTES 65, open_dir_path_buf, path_buffer
jsr do_open
lda open_params::ref_num
sta read_params::ref_num
sta close_params::ref_num
jsr do_read
jsr L72E2
ldx #0
: lda $0C00+SubdirectoryHeader::entry_length,x
sta entry_length,x
inx
cpx #4
bne :-
sub16 L485D, L485F, L72A8
ldx #$05
L710A: lsr16 L72A8
dex
cpx #$00
bne L710A
lda L70C2
bne L7147
lda icon_count
clc
adc L70C1
bcs L7147
cmp #$7C
bcs L7147
sub16_8 L72A8, DEVCNT, L72A8
cmp16 L72A8, L70C1
bcs L7169
L7147: lda num_open_windows
jsr mark_icons_not_opened_1
dec num_open_windows
jsr redraw_windows_and_desktop
jsr do_close
lda active_window_id
beq L715F
lda #$03
bne L7161
L715F: lda #warning_msg_window_must_be_closed2
L7161: jsr warning_dialog_proc_num
ldx saved_stack
txs
rts
record_ptr := $06
L7169: copy16 L485F, record_ptr
lda window_icon_to_filerecord_list
asl a
tax
copy16 record_ptr, window_filerecord_table,x
ldx window_icon_to_filerecord_list
lda L72A7
sta window_icon_to_filerecord_list+1,x
inc window_icon_to_filerecord_list
lda L70C1
;; Store entry count
pha
lda LCBANK2
lda LCBANK2
ldy #$00
pla
sta (record_ptr),y
lda LCBANK1
lda LCBANK1
copy #$FF, L70C4
copy #$00, L70C3
entry_ptr := $08
copy16 #$0C00 + SubdirectoryHeader::storage_type_name_length, entry_ptr
;; Advance past entry count
inc record_ptr
lda record_ptr
bne do_entry
inc record_ptr+1
;; Record is temporarily constructed at $1F00 then copied into place.
record := $1F00
record_size := $20
do_entry:
inc L70C4
lda L70C4
cmp L70C1
bne L71CB
jmp L7296
L71CB: inc L70C3
lda L70C3
cmp L70C0
beq L71E7
add16_8 entry_ptr, entry_length, entry_ptr
jmp L71F7
L71E7: copy #$00, L70C3
copy16 #$0C04, entry_ptr
jsr do_read
L71F7: ldx #$00
ldy #$00
lda (entry_ptr),y
and #$0F
sta record,x
bne L7223
inc L70C3
lda L70C3
cmp L70C0
bne L7212
jmp L71E7
L7212: add16_8 entry_ptr, entry_length, entry_ptr
jmp L71F7
L7223: iny
inx
;; See FileRecord struct for record structure
;; TODO: Determine if this case adjustment is necessary
txa
pha
tya
pha
addr_call_indirect adjust_fileentry_case, entry_ptr
pla
tay
pla
tax
;; name, file_type
: lda (entry_ptr),y
sta record,x
iny
inx
cpx #FileEntry::file_type+1 ; name and type
bne :-
;; blocks
ldy #FileEntry::blocks_used
lda (entry_ptr),y
sta record,x
inx
iny
lda (entry_ptr),y
sta record,x
;; creation date/time
ldy #FileEntry::creation_date
inx
: lda (entry_ptr),y
sta record,x
inx
iny
cpy #FileEntry::creation_date+4
bne :-
;; modification date/time
ldy #FileEntry::mod_date
: lda (entry_ptr),y
sta record,x
inx
iny
cpy #FileEntry::mod_date+4
bne :-
;; access
ldy #FileEntry::access
lda (entry_ptr),y
sta record,x
inx
;; header pointer
ldy #FileEntry::header_pointer
lda (entry_ptr),y
sta record,x
inx
iny
lda (entry_ptr),y
sta record,x
inx
;; aux type
ldy #FileEntry::aux_type
lda (entry_ptr),y
sta record,x
inx
iny
lda (entry_ptr),y
sta record,x
;; Copy entry composed at $1F00 to buffer in Aux LC Bank 2
lda LCBANK2
lda LCBANK2
ldx #record_size-1
ldy #record_size-1
: lda record,x
sta (record_ptr),y
dex
dey
bpl :-
lda LCBANK1
lda LCBANK1
lda #record_size
clc
adc record_ptr
sta record_ptr
bcc L7293
inc record_ptr+1
L7293: jmp do_entry
L7296: copy16 record_ptr, L485F
jsr do_close
jsr pop_pointers
rts
L72A7: .byte 0
L72A8: .word 0
.endproc
;;; --------------------------------------------------
.proc do_open
MLI_RELAY_CALL OPEN, open_params
beq done
jsr ShowAlert
jsr mark_icons_not_opened_2
lda selected_window_index
bne :+
lda icon_params2
sta drive_to_refresh ; icon number
jsr cmd_check_single_drive_by_icon_number
: ldx saved_stack
txs
done: rts
.endproc
;;; --------------------------------------------------
do_read:
MLI_RELAY_CALL READ, read_params
rts
do_close:
MLI_RELAY_CALL CLOSE, close_params
rts
;;; --------------------------------------------------
L72E2: lda $0C04
and #$F0
cmp #$F0
beq get_vol_free_used
rts
get_vol_free_used:
MLI_RELAY_CALL GET_FILE_INFO, get_file_info_params4
beq :+
rts
;; aux = total blocks
: copy16 get_file_info_params4::aux_type, vol_kb_used
;; total - used = free
sub16 get_file_info_params4::aux_type, get_file_info_params4::blocks_used, vol_kb_free
sub16 vol_kb_used, vol_kb_free, vol_kb_used ; total - free = used
lsr16 vol_kb_free
php
lsr16 vol_kb_used
plp
bcc :+
inc16 vol_kb_used
: return #0
.endproc
vol_kb_free := open_directory::vol_kb_free
vol_kb_used := open_directory::vol_kb_used
get_vol_free_used := open_directory::get_vol_free_used
;;; ============================================================
;;; ???
.proc L7345
sta L7445
ldx #0
L734A: lda window_icon_to_filerecord_list+1,x
cmp L7445
beq :+
inx
cpx #8
bne L734A
rts
: stx L7446
dex
: inx
lda window_icon_to_filerecord_list+2,x
sta window_icon_to_filerecord_list+1,x
cpx window_icon_to_filerecord_list
bne :-
dec window_icon_to_filerecord_list
lda L7446
cmp window_icon_to_filerecord_list
bne :+
ldx L7446
asl a
tax
copy16 window_filerecord_table,x, L485F
rts
: lda L7446
asl a
tax
copy16 window_filerecord_table,x, $06
inx
inx
copy16 window_filerecord_table,x, $08
ldy #$00
jsr push_pointers
L73A5: lda LCBANK2
lda LCBANK2
lda ($08),y
sta ($06),y
lda LCBANK1
lda LCBANK1
inc16 $06
inc16 $08
lda $08+1
cmp L485F+1
bne L73A5
lda $08
cmp L485F
bne L73A5
jsr pop_pointers
lda window_icon_to_filerecord_list
asl a
tax
sub16 L485F, window_filerecord_table,x, L7447
inc L7446
L73ED: lda L7446
cmp window_icon_to_filerecord_list
bne :+
jmp L7429
: lda L7446
asl a
tax
sub16 window_filerecord_table+2,x, window_filerecord_table,x, L7449
add16 window_filerecord_table-2,x, L7449, window_filerecord_table,x
inc L7446
jmp L73ED
L7429: lda window_icon_to_filerecord_list
sec
sbc #$01
asl a
tax
add16 window_filerecord_table,x, L7447, L485F
rts
L7445: .byte 0
L7446: .byte 0
L7447: .word 0
L7449: .word 0
.endproc
;;; ============================================================
;;; Compute full path for icon
;;; Inputs: IconEntry pointer in $06
;;; Outputs: open_dir_path_buf has full path
;;; Exceptions: if path too long, shows error and restores saved_stack
.proc compose_icon_full_path
icon_ptr := $06
name_ptr := $06
jsr push_pointers
ldy #IconEntry::win_type
lda (icon_ptr),y
pha
add16 icon_ptr, #IconEntry::len, name_ptr
pla
and #icon_entry_winid_mask
bne has_parent ; A = window_id
;; --------------------------------------------------
;; Desktop (volume) icon - no parent path
;; Copy name, including leading/trailing spaces
ldy #0
lda (name_ptr),y
tay ; Y = length
: lda (name_ptr),y
sta open_dir_path_buf,y
dey
bpl :-
copy #'/', open_dir_path_buf+1 ; Replace leading space with '/'
dec open_dir_path_buf ; Remove trailing space
jsr pop_pointers
rts
;; --------------------------------------------------
;; Windowed (folder) icon - has parent path
has_parent:
parent_path_ptr := $08
jsr window_path_lookup
stax parent_path_ptr
ldy #0
lda (parent_path_ptr),y
clc
adc (name_ptr),y
cmp #67 ; Max path length is 64; title has leading/trailing spaces
bcc :+
lda #ERR_INVALID_PATHNAME
jsr ShowAlert
jsr mark_icons_not_opened_2
dec num_open_windows
ldx saved_stack
txs
rts
;; Copy parent path to open_dir_path_buf
: ldy #0
lda (parent_path_ptr),y
tay
: lda (parent_path_ptr),y
sta open_dir_path_buf,y
dey
bpl :-
;; Suffix with '/'
lda #'/'
inc open_dir_path_buf
ldx open_dir_path_buf
sta open_dir_path_buf,x
;; Append icon name
ldy #0
lda (name_ptr),y
clc
adc open_dir_path_buf
sta open_dir_path_buf
dec open_dir_path_buf ; discount leading/trailing spaces
dec open_dir_path_buf
iny
: iny ; skip leading space immediately
inx
lda (name_ptr),y
sta open_dir_path_buf,x
cpx open_dir_path_buf
bne :-
jsr pop_pointers
rts
.endproc
;;; ============================================================
;;; Set up path and coords for new window, contents and free/used.
;;; Inputs: IconEntry pointer in $06, new window_id in cached_window_id,
;;; open_dir_path_buf has full path
;;; Outputs: Winfo configured, window path table entry set
.proc prepare_new_window
icon_ptr := $06
;; Copy icon name to window title (including leading/trailing spaces)
.scope
name_ptr := icon_ptr
title_ptr := $08
jsr push_pointers
lda cached_window_id
asl a
tax
copy16 window_title_addr_table,x, title_ptr
add16 icon_ptr, #IconEntry::len, name_ptr
ldy #0
lda (name_ptr),y
tay
: lda (name_ptr),y
sta (title_ptr),y
dey
bpl :-
jsr pop_pointers
.endscope
;; --------------------------------------------------
path_ptr := $08
;; Copy previously composed path into window path
lda cached_window_id
jsr window_path_lookup
stax path_ptr
ldy open_dir_path_buf
: lda open_dir_path_buf,y
sta (path_ptr),y
dey
bpl :-
;; --------------------------------------------------
winfo_ptr := $06
;; Set window coordinates
lda cached_window_id
jsr window_lookup
stax winfo_ptr
ldy #MGTK::Winfo::port
;; xcoord = (window_id-1) * 16 + 5
;; ycoord = (window_id-1) * 8 + 27
lda cached_window_id
sec
sbc #1 ; * 16
asl a
asl a
asl a
asl a
pha
adc #5
sta (winfo_ptr),y ; viewloc::xcoord
iny
lda #0
sta (winfo_ptr),y
iny
pla
lsr a ; / 2
clc
adc #27
sta (winfo_ptr),y ; viewloc::ycoord
iny
lda #0
sta (winfo_ptr),y
;; Map rect
lda #0
ldy #MGTK::Winfo::port + MGTK::GrafPort::maprect + 3
ldx #3
: sta (winfo_ptr),y
dey
dex
bpl :-
;; Scrollbars
ldy #MGTK::Winfo::hscroll
lda (winfo_ptr),y
and #AS_BYTE(~MGTK::Scroll::option_active)
sta (winfo_ptr),y
iny ; vscroll
lda (winfo_ptr),y
and #AS_BYTE(~MGTK::Scroll::option_active)
sta (winfo_ptr),y
lda #0
ldy #MGTK::Winfo::hthumbpos
sta (winfo_ptr),y
ldy #MGTK::Winfo::vthumbpos
sta (winfo_ptr),y
;; --------------------------------------------------
lda icon_params2
jsr open_directory
lda icon_params2
jsr icon_entry_lookup
stax icon_ptr
ldy #IconEntry::win_type
lda (icon_ptr),y
and #icon_entry_winid_mask
beq :+
;; Windowed (folder) icon
tax
dex
txa
asl a
tax
copy16 window_k_used_table,x, vol_kb_used
copy16 window_k_free_table,x, vol_kb_free
;; Desktop (volume) icon
: ldx cached_window_id
dex
txa
asl a
tax
copy16 vol_kb_used, window_k_used_table,x
copy16 vol_kb_free, window_k_free_table,x
lda cached_window_id
jsr create_file_icon_ep1
rts
.endproc
;;; ============================================================
;;; File Icon Entry Construction
.proc create_file_icon
icon_x_spacing = 80
icon_y_spacing = 32
window_id: .byte 0
iconbits: .addr 0
icon_type: .byte 0
icon_height: .word 0
L7625: .byte 0 ; ???
max_icon_height = 17
initial_coords: ; first icon in window
DEFINE_POINT 52,16 + max_icon_height, initial_coords
row_coords: ; first icon in current row
DEFINE_POINT 0, 0, row_coords
icons_per_row:
.byte 5
icons_this_row:
.byte 0
icon_coords:
DEFINE_POINT 0, 0, icon_coords
flag: .byte 0 ; ???
.proc ep1 ; entry point #1 ???
pha
lda #0
beq L7647
ep2: pha ; entry point #2 ???
ldx cached_window_id
dex
lda window_to_dir_icon_table,x
;; TODO: Guaranteed to exist?
sta icon_params2
lda #$80
L7647: sta flag
pla
sta window_id
jsr push_pointers
COPY_STRUCT MGTK::Point, initial_coords, row_coords
lda #0
sta icons_this_row
sta L7625
ldx #3
: sta icon_coords,x
dex
bpl :-
lda icon_params2
ldx window_icon_to_filerecord_list
dex
: cmp window_icon_to_filerecord_list+1,x
beq :+
dex
bpl :-
rts
: txa
asl a
tax
copy16 window_filerecord_table,x, $06
lda LCBANK2
lda LCBANK2
ldy #0
lda ($06),y
sta L7764
lda LCBANK1
lda LCBANK1
inc $06
lda $06
bne L76A4
inc $06+1
L76A4: lda cached_window_id
sta active_window_id
L76AA: lda L7625
cmp L7764
beq L76BB
jsr alloc_and_populate_file_icon
inc L7625
jmp L76AA
L76BB: bit flag
bpl :+
jsr pop_pointers
rts
: jsr compute_icons_bbox
lda window_id
jsr window_lookup
stax $06
ldy #$16
lda iconbb_rect+MGTK::Rect::y2
sec
sbc ($06),y
sta iconbb_rect+MGTK::Rect::y2
lda iconbb_rect+MGTK::Rect::y2+1
sbc #0
sta iconbb_rect+MGTK::Rect::y2+1
cmp16 iconbb_rect+MGTK::Rect::x2, #170
bmi L7705
cmp16 iconbb_rect+MGTK::Rect::x2, #450
bpl L770C
ldax iconbb_rect+MGTK::Rect::x2
jmp L7710
L7705: addr_jump L7710, $00AA
L770C: ldax #450
L7710: ldy #$20
sta ($06),y
txa
iny
sta ($06),y
cmp16 iconbb_rect+MGTK::Rect::y2, #50
bmi L7739
cmp16 iconbb_rect+MGTK::Rect::y2, #108
bpl L7740
ldax iconbb_rect+MGTK::Rect::y2
jmp L7744
L7739: addr_jump L7744, $0032
L7740: ldax #108
L7744: ldy #$22
sta ($06),y
txa
iny
sta ($06),y
lda L7767
ldy #$06
sta ($06),y
ldy #$08
sta ($06),y
lda icon_params2
ldx window_id
jsr animate_window_open
jsr pop_pointers
rts
L7764: .byte $00,$00,$00
L7767: .byte $14
.endproc
;;; ============================================================
;;; Create icon
.proc alloc_and_populate_file_icon
file_entry := $6
icon_entry := $8
name_tmp := $1800
inc icon_count
jsr AllocateIcon
ldx cached_window_icon_count
inc cached_window_icon_count
sta cached_window_icon_list,x
jsr icon_entry_lookup
stax icon_entry
lda LCBANK2
lda LCBANK2
;; Copy the name (offset by 2 for count and leading space)
ldy #FileRecord::name
lda (file_entry),y
sta name_tmp
iny
ldx #0
: lda (file_entry),y
sta name_tmp+2,x
inx
iny
cpx name_tmp
bne :-
inc name_tmp ; length += 2 for leading/trailing spaces
inc name_tmp
lda #' ' ; leading space
sta name_tmp+1
ldx name_tmp
sta name_tmp,x ; trailing space
;; Check file type
ldy #FileRecord::file_type
lda (file_entry),y
;; Handle several classes of overrides
sta fto_type
ldy #FileRecord::aux_type
copy16in (file_entry),y, fto_auxtype
ldy #FileRecord::blocks
copy16in (file_entry),y, fto_blocks
jsr check_file_type_overrides
;; Distinguish *.SYSTEM files as apps (use $01) from other
;; type=SYS files (use $FF).
cmp #FT_SYSTEM
bne got_type
ldy #FileRecord::name
lda (file_entry),y
tay
ldx str_sys_suffix
cloop: lda (file_entry),y
jsr upcase_char
cmp str_sys_suffix,x
bne not_app
dey
beq not_app
dex
bne cloop
is_app:
lda #APP_FILE_TYPE ; overloaded meaning in icon tables
bne got_type ; always
str_sys_suffix:
PASCAL_STRING ".SYSTEM"
not_app:
lda #$FF
;; fall through
got_type:
tay
;; Figure out icon type
lda LCBANK1
lda LCBANK1
tya
jsr find_icon_details_for_file_type
ldy #IconEntry::len
ldx #0
L77F0: lda name_tmp,x
sta (icon_entry),y
iny
inx
cpx name_tmp
bne L77F0
lda name_tmp,x
sta (icon_entry),y
;; Assign location
ldx #0
ldy #IconEntry::iconx
: lda row_coords,x
sta (icon_entry),y
inx
iny
cpx #.sizeof(MGTK::Point)
bne :-
;; Include y-offset
ldy #IconEntry::icony
sub16in (icon_entry),y, icon_height, (icon_entry),y
lda cached_window_icon_count
cmp icons_per_row
beq L781A
bcs L7826
L781A: copy16 row_coords::xcoord, icon_coords::xcoord
L7826: copy16 row_coords::ycoord, icon_coords::ycoord
inc icons_this_row
lda icons_this_row
cmp icons_per_row
bne L7862
;; Next row (and initial column) if necessary
add16 row_coords::ycoord, #32, row_coords::ycoord
copy16 initial_coords::xcoord, row_coords::xcoord
lda #0
sta icons_this_row
jmp L7870
;; Next column otherwise
L7862: lda row_coords::xcoord
clc
adc #icon_x_spacing
sta row_coords::xcoord
bcc L7870
inc row_coords::xcoord+1
L7870: lda cached_window_id
ora icon_type
ldy #IconEntry::win_type
sta (icon_entry),y
ldy #IconEntry::iconbits
copy16in iconbits, (icon_entry),y
ldx cached_window_icon_count
dex
lda cached_window_icon_list,x
jsr icon_window_to_screen
add16 file_entry, #icon_y_spacing, file_entry
rts
.endproc
;;; ============================================================
;;; Special case: $01 is used for App-like SYS files.
.proc find_icon_details_for_file_type
ptr := $6
sta file_type
jsr push_pointers
;; Find index of file type
copy16 #type_table, ptr
ldy #num_file_types-1
: lda (ptr),y
cmp file_type
beq found
dey
bpl :-
ldy #0 ; default is first entry (FT_TYPELESS)
found:
;; Look up icon type
copy16 #icon_type_table, ptr
lda (ptr),y
sta icon_type
tya
asl a
tay
;; Look up icon definition
copy16 #type_icons_table, ptr
copy16in (ptr),y, iconbits
;; Icon height will be needed too
copy16 iconbits, ptr
ldy #IconDefinition::maprect + MGTK::Rect::y2
copy16in (ptr),y, icon_height
jsr pop_pointers
rts
file_type:
.byte 0
.endproc
.endproc
create_file_icon_ep2 := create_file_icon::ep1::ep2
create_file_icon_ep1 := create_file_icon::ep1
;;; ============================================================
;;; Check file type for possible overrides
;;; Input: fto_type, fto_auxtype, fto_blocks populated
;;; Output: A is filetype to use (for icons, open/preview, etc)
.proc check_file_type_overrides
ptr := $06
jsr push_pointers
copy16 #fto_table, ptr
loop: ldy #0 ; type_mask, or $00 if done
lda (ptr),y
bne :+
jsr pop_pointers
lda fto_type
rts
;; Check type (with mask)
: and fto_type ; A = type & type_mask
iny ; ASSERT: Y = FTORecord::type
cmp (ptr),y ; type check
bne next
;; Flags
iny ; ASSERT: Y = FTORecord::flags
lda (ptr),y
sta flags
;; Does Aux Type matter, and if so does it match?
bit flags
bpl blocks ; bit 7 = compare aux
iny ; ASSERT: Y = FTORecord::aux
lda fto_auxtype
cmp (ptr),y
bne next
iny
lda fto_auxtype+1
cmp (ptr),y
bne next
;; Does Block Count matter, and if so does it match?
blocks: bit flags
bvc match ; bit 6 = compare blocks
ldy #FTORecord::blocks
lda fto_blocks
cmp (ptr),y
bne next
iny
lda fto_blocks+1
cmp (ptr),y
bne next
;; Have a match
match: ldy #FTORecord::newtype
lda (ptr),y
sta fto_type
;; Next entry
next: add16 ptr, #.sizeof(FTORecord), ptr
jmp loop
flags: .byte 0
.endproc
;;; ============================================================
;;; Draw header (items/k in disk/k available/lines)
.proc draw_window_header
;; Compute header coords
;; x coords
lda grafport2::cliprect::x1
sta header_line_left::xcoord
clc
adc #5
sta items_label_pos::xcoord
lda grafport2::cliprect::x1+1
sta header_line_left::xcoord+1
adc #0
sta items_label_pos::xcoord+1
;; y coords
lda grafport2::cliprect::y1
clc
adc #12
sta header_line_left::ycoord
sta header_line_right::ycoord
lda grafport2::cliprect::y1+1
adc #0
sta header_line_left::ycoord+1
sta header_line_right::ycoord+1
;; Draw top line
MGTK_RELAY_CALL MGTK::MoveTo, header_line_left
copy16 grafport2::cliprect::x2, header_line_right::xcoord
jsr set_penmode_xor
MGTK_RELAY_CALL MGTK::LineTo, header_line_right
;; Offset down by 2px
lda header_line_left::ycoord
clc
adc #2
sta header_line_left::ycoord
sta header_line_right::ycoord
lda header_line_left::ycoord+1
adc #0
sta header_line_left::ycoord+1
sta header_line_right::ycoord+1
;; Draw bottom line
MGTK_RELAY_CALL MGTK::MoveTo, header_line_left
MGTK_RELAY_CALL MGTK::LineTo, header_line_right
;; Baseline for header text
add16 grafport2::cliprect::y1, #10, items_label_pos::ycoord
;; Draw "XXX Items"
lda cached_window_icon_count
ldx #0
jsr int_to_string
lda cached_window_icon_count
cmp #2 ; plural?
bcs :+
dec str_items ; remove trailing s
: MGTK_RELAY_CALL MGTK::MoveTo, items_label_pos
jsr draw_int_string
addr_call draw_pascal_string, str_items
lda cached_window_icon_count
cmp #2
bcs :+
inc str_items ; restore trailing s
;; Draw "XXXK in disk"
: jsr calc_header_coords
ldx active_window_id
dex ; index 0 is window 1
txa
asl a
tax
lda window_k_used_table,x
tay
lda window_k_used_table+1,x
tax
tya
jsr int_to_string
MGTK_RELAY_CALL MGTK::MoveTo, pos_k_in_disk
jsr draw_int_string
addr_call draw_pascal_string, str_k_in_disk
;; Draw "XXXK available"
ldx active_window_id
dex ; index 0 is window 1
txa
asl a
tax
lda window_k_free_table,x
tay
lda window_k_free_table+1,x
tax
tya
jsr int_to_string
MGTK_RELAY_CALL MGTK::MoveTo, pos_k_available
jsr draw_int_string
addr_call draw_pascal_string, str_k_available
rts
;;; --------------------------------------------------
.proc calc_header_coords
;; Width of window
sub16 grafport2::cliprect::x2, grafport2::cliprect::x1, xcoord
;; Is there room to spread things out?
sub16 xcoord, width_items_label, xcoord
bpl :+
jmp skipcenter
: sub16 xcoord, width_right_labels, xcoord
bpl :+
jmp skipcenter
;; Yes - center "k in disk"
: add16 width_left_labels, xcoord, pos_k_available::xcoord
lda xcoord+1
beq :+
lda xcoord
cmp #24 ; threshold
bcc nosub
: sub16 pos_k_available::xcoord, #12, pos_k_available::xcoord
nosub: lsr16 xcoord ; divide by 2 to center
add16 width_items_label_padded, xcoord, pos_k_in_disk::xcoord
jmp finish
;; No - just squish things together
skipcenter:
copy16 width_items_label_padded, pos_k_in_disk::xcoord
copy16 width_left_labels, pos_k_available::xcoord
finish:
add16 pos_k_in_disk::xcoord, grafport2::cliprect::x1, pos_k_in_disk::xcoord
add16 pos_k_available::xcoord, grafport2::cliprect::x1, pos_k_available::xcoord
;; Update y coords
lda items_label_pos::ycoord
sta pos_k_in_disk::ycoord
sta pos_k_available::ycoord
lda items_label_pos::ycoord+1
sta pos_k_in_disk::ycoord+1
sta pos_k_available::ycoord+1
rts
.endproc ; calc_header_coords
draw_int_string:
addr_jump draw_pascal_string, str_from_int
xcoord:
.word 0
.endproc ; draw_window_header
;;; ============================================================
;;; Input: 16-bit unsigned number in A,X
;;; Output: length-prefixed string in str_from_int
.proc int_to_string
stax value
lda #0
sta nonzero_flag
ldy #0 ; y = position in string
ldx #0 ; x = which power index is subtracted (*2)
;; For each power of ten
loop: lda #0
sta digit
;; Keep subtracting/incrementing until zero is hit
sloop: cmp16 value, powers,x
bcc break
inc digit
sub16 value, powers,x, value
jmp sloop
break: lda digit
bne not_pad
bit nonzero_flag
bpl next
;; Convert to ASCII
not_pad:
ora #'0'
pha
copy #$80, nonzero_flag
pla
;; Place the character, move to next
iny
sta str_from_int,y
next: inx
inx
cpx #8 ; up to 4 digits (*2) via subtraction
beq done
jmp loop
done: lda value ; handle last digit
ora #'0'
iny
sta str_from_int,y
sty str_from_int
rts
powers: .word 10000, 1000, 100, 10
value: .word 0 ; remaining value as subtraction proceeds
digit: .byte 0 ; current digit being accumulated
nonzero_flag: ; high bit set once a non-zero digit seen
.byte 0
.endproc ; int_to_string
;;; ============================================================
;;; Compute bounding box for icons within cached window
iconbb_rect:
DEFINE_RECT 0,0,0,0,iconbb_rect
.proc compute_icons_bbox_impl
cur_icon_pos:
DEFINE_POINT 0,0,cur_icon_pos
entry_ptr := $06
kIntMax = $7FFF
kPadTop = 15
kPadLeft = 50
kPadBottom = 32
kPadRight = 50
start: ldx #3
lda #0
: sta iconbb_rect::x2,x
dex
bpl :-
sta icon_num
lda #<kIntMax
sta iconbb_rect::x1
sta iconbb_rect+MGTK::Rect::y1
lda #>kIntMax
sta iconbb_rect::x1+1
sta iconbb_rect+MGTK::Rect::y1+1
ldx cached_window_id
dex
lda win_view_by_table,x
bpl L7BCB ; icon view
;; List view
lda cached_window_icon_count
bne L7BA1
L7B96: ldax #$0300
L7B9A: sta iconbb_rect::x1,x
dex
bpl L7B9A
rts
;; iconbb_rect::x2 = 360
;; iconbb_rect::y2 = (A + 2) * 8
L7BA1: clc
adc #2
ldx #0
stx hi
asl a
rol hi
asl a
rol hi
asl a
rol hi
sta iconbb_rect::y2
lda hi
sta iconbb_rect::y2+1
copy16 #360, iconbb_rect::x2
jmp L7B96
;; Icon view
L7BCB: lda cached_window_icon_count
cmp #1
bne check_icon
;; First icon - copy coords
lda cached_window_icon_list
jsr icon_entry_lookup
stax entry_ptr
ldy #IconEntry::iconx+.sizeof(MGTK::Point)-1
ldx #.sizeof(MGTK::Point)-1
: lda (entry_ptr),y
sta iconbb_rect::x1,x
sta iconbb_rect::x2,x
dey
dex
bpl :-
jmp finish
check_icon:
lda icon_num
cmp cached_window_icon_count
bne more
finish: lda iconbb_rect::x2
clc
adc #kPadRight
sta iconbb_rect::x2
bcc :+
inc iconbb_rect::x2+1
: lda iconbb_rect::y2
clc
adc #kPadBottom
sta iconbb_rect::y2
bcc :+
inc iconbb_rect::y2+1
: sub16 iconbb_rect::x1, #kPadLeft, iconbb_rect::x1
sub16 iconbb_rect::y1, #kPadTop, iconbb_rect::y1
rts
more: tax
lda cached_window_icon_list,x
jsr icon_entry_lookup
stax entry_ptr
ldy #IconEntry::win_type
lda (entry_ptr),y
and #icon_entry_winid_mask
cmp hi ; BUG: from old code that iterated all icons???
bne :+
inc icon_num
jmp check_icon
: ldy #IconEntry::iconx+.sizeof(MGTK::Point)-1
ldx #.sizeof(MGTK::Point)-1
: lda (entry_ptr),y
sta cur_icon_pos::xcoord,x
dey
dex
bpl :-
;; --------------------------------------------------
;; Compare X coords
bit iconbb_rect::x1+1 ; negative?
bmi pt0x_neg
bit cur_icon_pos::xcoord+1
bmi adjust_pt0_x
;; X: cur and pt0 are positive
cmp16 cur_icon_pos::xcoord, iconbb_rect::x1
bmi adjust_pt0_x
cmp16 cur_icon_pos::xcoord, iconbb_rect::x2
bpl adjust_pt1_x
jmp compare_y
pt0x_neg:
bit cur_icon_pos::xcoord+1
bmi bothx_neg
;; X: cur positive, pt0 negative
bit iconbb_rect::x2+1
bmi compare_y
cmp16 cur_icon_pos::xcoord, iconbb_rect::x2
bmi compare_y
jmp adjust_pt1_x
;; X: cur and pt0 are negative
bothx_neg:
cmp16 cur_icon_pos::xcoord, iconbb_rect::x1
bmi adjust_pt0_x
cmp16 cur_icon_pos::xcoord, iconbb_rect::x2
bmi compare_y
adjust_pt1_x:
copy16 cur_icon_pos::xcoord, iconbb_rect::x2
jmp compare_y
adjust_pt0_x:
copy16 cur_icon_pos::xcoord, iconbb_rect::x1
;; --------------------------------------------------
;; Compare Y coords
compare_y:
bit iconbb_rect::y1+1
bmi pt0y_neg
bit cur_icon_pos::ycoord+1
bmi adjust_pt0_y
;; Y: cur and pt0 are positive
cmp16 cur_icon_pos::ycoord, iconbb_rect::y1
bmi adjust_pt0_y
cmp16 cur_icon_pos::ycoord, iconbb_rect::y2
bpl adjust_pt1_y
jmp next
pt0y_neg:
bit cur_icon_pos::ycoord+1
bmi bothy_neg
;; Y: cur positive, pt0 negative
bit iconbb_rect::y2+1
bmi next
cmp16 cur_icon_pos::ycoord, iconbb_rect::y2
bmi next
jmp adjust_pt1_y
;; Y: cur and pt0 are negative
bothy_neg:
cmp16 cur_icon_pos::ycoord, iconbb_rect::y1
bmi adjust_pt0_y
cmp16 cur_icon_pos::ycoord, iconbb_rect::y2
bmi next
adjust_pt1_y:
copy16 cur_icon_pos::ycoord, iconbb_rect::y2
jmp next
adjust_pt0_y:
copy16 cur_icon_pos::ycoord, iconbb_rect::y1
next: inc icon_num
jmp check_icon
icon_num:
.byte 0
hi: .byte 0
.endproc
compute_icons_bbox := compute_icons_bbox_impl::start
;;; ============================================================
;;; Compute dimensions of window
;;; Input: A = window
;;; Output: A,X = width, Y = height
.proc compute_window_dimensions
ptr := $06
jsr window_lookup
stax ptr
;; Copy window's maprect
ldy #MGTK::Winfo::port + MGTK::GrafPort::maprect + .sizeof(MGTK::Rect)-1
ldx #.sizeof(MGTK::Rect)-1
: lda (ptr),y
sta rect,x
dey
dex
bpl :-
;; Push delta-X
lda rect+MGTK::Rect::x2
sec
sbc rect+MGTK::Rect::x1
pha
lda rect+MGTK::Rect::x2+1
sbc rect+MGTK::Rect::x1+1
pha
;; Push delta-Y
lda rect+MGTK::Rect::y2
sec
sbc rect+MGTK::Rect::y1
pha
lda rect+MGTK::Rect::y2+1
sbc rect+MGTK::Rect::y1+1
;; high byte is discarded
pla
tay
pla
tax
pla
rts
rect: DEFINE_RECT 0,0,0,0
.endproc
;;; ============================================================
.proc sort_records
ptr := $06
record_num := $800
list_start_ptr := $801
num_records := $803
;; $804 = scratch byte
index := $805
jmp start
start: ldx cached_window_id
dex
lda window_to_dir_icon_table,x
;; BUG: What if dir icon is freed? ($FF)
ldx #0
: cmp window_icon_to_filerecord_list+1,x
beq found
inx
cpx window_icon_to_filerecord_list
bne :-
rts
found: txa
asl a
tax
lda window_filerecord_table,x ; Ptr points at start of record
sta ptr
sta list_start_ptr
lda window_filerecord_table+1,x
sta ptr+1
sta list_start_ptr+1
lda LCBANK2 ; Start copying records
lda LCBANK2
lda #0 ; Number copied
sta record_num
tay
lda (ptr),y ; Number to copy
sta num_records
inc ptr ; Point past number
inc list_start_ptr
bne loop
inc ptr+1
inc list_start_ptr+1
loop: lda record_num
cmp num_records
beq break
jsr ptr_calc
ldy #0
lda (ptr),y
and #$7F ; mask off high bit
sta (ptr),y ; mark as ???
ldy #FileRecord::modification_date ; ???
lda (ptr),y
bne next
iny
lda (ptr),y ; modification_date hi
bne next
lda #$01 ; if no mod date, set hi to 1 ???
sta (ptr),y
next: inc record_num
jmp loop
break: lda LCBANK1 ; Done copying records
lda LCBANK1
;; --------------------------------------------------
;; What sort order?
ldx cached_window_id
dex
lda win_view_by_table,x
cmp #view_by_name
beq :+
jmp check_date
:
;; By Name
;; Sorted in increasing lexicographical order
.scope
name := $807
name_size = $F
name_len := $804
lda LCBANK2
lda LCBANK2
;; Set up highest value ("ZZZZZZZZZZZZZZZ")
lda #'Z'
ldx #name_size
: sta name+1,x
dex
bpl :-
lda #0
sta index
sta record_num
loop: lda index
cmp num_records
bne iloop
jmp finish_view_change
iloop: jsr ptr_calc
;; Check record for mark
ldy #0
lda (ptr),y
bmi inext
;; Compare names
and #NAME_LENGTH_MASK
sta name_len
ldy #1
cloop: lda (ptr),y
jsr upcase_char
cmp name,y
beq :+
bcs inext
jmp place
: iny
cpy #$10
bne cloop
jmp inext
;; if less than
place: lda record_num
sta $0806
ldx #name_size
lda #' '
: sta name+1,x
dex
bpl :-
ldy name_len
: lda (ptr),y
jsr upcase_char
sta name,y
dey
bne :-
inext: inc record_num
lda record_num
cmp num_records
beq :+
jmp iloop
: inc index
lda $0806
sta record_num
jsr ptr_calc
;; Mark record
ldy #0
lda (ptr),y
ora #$80
sta (ptr),y
lda #'Z'
ldx #15
: sta $0808,x
dex
bpl :-
ldx index
dex
ldy $0806
iny
jsr L812B
lda #0
sta record_num
jmp loop
.endscope
;; --------------------------------------------------
check_date:
cmp #view_by_date
beq :+
jmp check_size
:
;; By Date
;; Sorted by decreasing date
.scope
date := $0808
lda LCBANK2
lda LCBANK2
lda #0
sta date
sta date+1
sta index
sta record_num
loop: lda index
cmp num_records
bne iloop
jmp finish_view_change
iloop: jsr ptr_calc
;; Check record for mark
ldy #0
lda (ptr),y
bmi inext
;; Compare dates
ldy #FileRecord::modification_date
copy16in (ptr),y, date_a
copy16 date, date_b
jsr compare_dates
beq inext
bcc inext
;; if greater than
place: ldy #FileRecord::modification_date+1
lda (ptr),y
sta date+1
dey
lda (ptr),y
sta date
lda record_num
sta $0806
inext: inc record_num
lda record_num
cmp num_records
beq next
jmp iloop
next: inc index
lda $0806
sta record_num
jsr ptr_calc
;; Mark record
ldy #0
lda (ptr),y
ora #$80
sta (ptr),y
lda #0
sta date
sta date+1
ldx index
dex
ldy $0806
iny
jsr L812B
copy #0, record_num
jmp loop
.endscope
;; --------------------------------------------------
check_size:
cmp #view_by_size
beq :+
jmp check_type
:
;; By Size
;; Sorted by decreasing size
.scope
size := $0808
lda LCBANK2
lda LCBANK2
lda #0
sta size
sta size+1
sta index
sta record_num
loop: lda index
cmp num_records
bne iloop
jmp finish_view_change
iloop: jsr ptr_calc
;; Check record for mark
ldy #0
lda (ptr),y
bmi inext
ldy #FileRecord::blocks+1
lda (ptr),y
cmp size+1 ; hi byte
beq :+
bcs place
: dey
lda (ptr),y
cmp size ; lo byte
beq place
bcc inext
;; if greater than
place: copy16in (ptr),y, size
lda record_num
sta $0806
inext: inc record_num
lda record_num
cmp num_records
beq next
jmp iloop
next: inc index
lda $0806
sta record_num
jsr ptr_calc
;; Mark record
ldy #0
lda (ptr),y
ora #$80
sta (ptr),y
lda #0
sta size
sta size+1
ldx index
dex
ldy $0806
iny
jsr L812B
lda #0
sta record_num
jmp loop
lda LCBANK1
lda LCBANK1
copy16 #84, pos_col_name::xcoord
copy16 #203, pos_col_type::xcoord
lda #0
sta pos_col_size::xcoord
sta pos_col_size::xcoord+1
copy16 #231, pos_col_date::xcoord
lda LCBANK2
lda LCBANK2
jmp finish_view_change
.endscope
;; --------------------------------------------------
check_type:
cmp #view_by_type
beq :+
rts
:
;; By Type
;; Types are ordered by type_table
.scope
type_table_copy := $807
;; Copy type_table prefixed by length to $807
copy16 #type_table, $08
copy #num_file_types, type_table_copy
ldy #num_file_types-1
: lda ($08),y
sta type_table_copy+1,y
dey
bne :-
lda LCBANK2
lda LCBANK2
lda #0
sta index
sta record_num
copy #$FF, $0806
loop: lda index
cmp num_records
bne iloop
jmp finish_view_change
iloop: jsr ptr_calc
;; Check record for mark
ldy #0
lda (ptr),y
bmi inext
;; Compare types
ldy #FileRecord::file_type
lda (ptr),y
ldx type_table_copy
cpx #0
beq place
cmp type_table_copy+1,x
bne inext
place: lda record_num
sta $0806
jmp L809E
inext: inc record_num
lda record_num
cmp num_records
beq next
jmp iloop
next: lda $0806
cmp #$FF
bne L809E
dec type_table_copy ; size of table
lda #0
sta record_num
jmp iloop
L809E: inc index
lda $0806
sta record_num
jsr ptr_calc
;; Mark record
ldy #0
lda (ptr),y
ora #$80
sta (ptr),y
ldx index
dex
ldy $0806
iny
jsr L812B
copy #0, record_num
copy #$FF, $0806
jmp loop
.endscope
;;; --------------------------------------------------
;;; ptr = list_start_ptr + ($800 * .sizeof(FileRecord))
.proc ptr_calc
ptr := $6
hi := $0804
lda #0
sta hi
lda record_num
asl a
rol hi
asl a
rol hi
asl a
rol hi
asl a
rol hi
asl a
rol hi
clc
adc list_start_ptr
sta ptr
lda list_start_ptr+1
adc hi
sta ptr+1
rts
.endproc
;;; --------------------------------------------------
date_a: .word 0
date_b: .word 0
.proc compare_dates
ptr := $0A
copy16 #parsed_a, ptr
ldax date_a
jsr parse_date
copy16 #parsed_b, ptr
ldax date_b
jsr parse_date
lda year_a+1
cmp year_b+1
bne done
lda year_a
cmp year_b
bne done
lda month_a
cmp month_b
bne done
lda day_a
cmp day_b
done: rts
parsed_a:
year_a: .word 0
month_a:.byte 0
day_a: .byte 0
parsed_b:
year_b: .word 0
month_b:.byte 0
day_b: .byte 0
.endproc
;;; --------------------------------------------------
;;; ???
.proc finish_view_change
ptr := $06
copy #0, record_num
loop: lda record_num
cmp num_records
beq done
jsr ptr_calc
ldy #$00
lda (ptr),y
and #$7F
sta (ptr),y
ldy #$17
lda (ptr),y
bne :+
iny
lda (ptr),y
cmp #$01
bne :+
lda #$00
sta (ptr),y
: inc record_num
jmp loop
done: lda LCBANK1
lda LCBANK1
rts
.endproc
;;; --------------------------------------------------
;;; ???
.proc L812B
lda LCBANK1
lda LCBANK1
tya
sta cached_window_icon_list,x
lda LCBANK2
lda LCBANK2
rts
.endproc
.endproc
;;; ============================================================
.proc L813F_impl
L813C: .byte 0
.byte 0
L813E: .byte 8
start: ldy #$00
tax
dex
txa
sty L813C
asl a
rol L813C
asl a
rol L813C
asl a
rol L813C
asl a
rol L813C
asl a
rol L813C
clc
adc LE71D
sta $06
lda LE71D+1
adc L813C
sta $06+1
lda LCBANK2
lda LCBANK2
ldy #$1F
L8171: lda ($06),y
sta LEC43,y
dey
bpl L8171
lda LCBANK1
lda LCBANK1
ldx #$31
lda #' '
L8183: sta text_buffer2::data-1,x
dex
bpl L8183
copy #0, text_buffer2::length
lda pos_col_type::ycoord
clc
adc L813E
sta pos_col_type::ycoord
bcc L819D
inc pos_col_type::ycoord+1
L819D: lda pos_col_size::ycoord
clc
adc L813E
sta pos_col_size::ycoord
bcc L81AC
inc pos_col_size::ycoord+1
L81AC: lda pos_col_date::ycoord
clc
adc L813E
sta pos_col_date::ycoord
bcc L81BB
inc pos_col_date::ycoord+1
L81BB: cmp16 pos_col_name::ycoord, grafport2::cliprect::y2
bmi L81D9
lda pos_col_name::ycoord
clc
adc L813E
sta pos_col_name::ycoord
bcc L81D8
inc pos_col_name::ycoord+1
L81D8: rts
L81D9: lda pos_col_name::ycoord
clc
adc L813E
sta pos_col_name::ycoord
bcc L81E8
inc pos_col_name::ycoord+1
L81E8: cmp16 pos_col_name::ycoord, grafport2::cliprect::y1
bpl L81F7
rts
L81F7: jsr prepare_col_name
addr_call SetPosDrawText, pos_col_name
jsr prepare_col_type
addr_call SetPosDrawText, pos_col_type
jsr prepare_col_size
addr_call SetPosDrawText, pos_col_size
jsr compose_date_string
addr_jump SetPosDrawText, pos_col_date
.endproc
L813F := L813F_impl::start
;;; ============================================================
.proc prepare_col_name
lda LEC43
and #$0F
sta text_buffer2::length
tax
loop: lda LEC43,x
sta text_buffer2::data,x
dex
bne loop
lda #' '
sta text_buffer2::data
inc text_buffer2::length
rts
.endproc
.proc prepare_col_type
lda LEC53
jsr compose_file_type_string
;; BUG: should be 4 not 5???
COPY_BYTES 5, str_file_type, text_buffer2::data-1
rts
.endproc
.proc prepare_col_size
ldax LEC54
;; fall through
.endproc
;;; ============================================================
;;; Populate text_buffer2 with " 12345 Blocks"
.proc compose_blocks_string
stax value
jsr int_to_string
;; Leading space
ldx #1
stx text_buffer2::length
copy #' ', text_buffer2::data
;; Append number
ldy #0
: lda str_from_int+1,y
sta text_buffer2::data,x ; data follows length
iny
inx
cpy str_from_int
bne :-
;; Append suffix
ldy #0
: lda suffix+1, y
sta text_buffer2::data,x
iny
inx
cpy suffix
bne :-
;; If singular, drop trailing 's'
;; Block or Blocks?
lda value+1
cmp #>1
bne :+
lda value
cmp #<1
bne :+
dex
: stx text_buffer2::length
done: rts
suffix: PASCAL_STRING " Blocks"
value: .word 0
.endproc
;;; ============================================================
.proc compose_date_string
ldx #21
lda #' '
: sta text_buffer2::data-1,x
dex
bpl :-
lda #1
sta text_buffer2::length
copy16 #text_buffer2::length, $8
lda date ; any bits set?
ora date+1
bne append_date_strings
sta month ; 0 is "no date" string
jmp append_month_string
append_date_strings:
copy16 #parsed_date, $0A
ldax date
jsr parse_date
jsr append_month_string
addr_call concatenate_date_part, str_space
jsr append_day_string
addr_call concatenate_date_part, str_space
jmp append_year_string
.proc append_day_string
lda day
ldx #0
jsr int_to_string
addr_jump concatenate_date_part, str_from_int
.endproc
.proc append_month_string
lda month
asl a
tay
lda month_table+1,y
tax
lda month_table,y
jmp concatenate_date_part
.endproc
.proc append_year_string
ldax year
jsr int_to_string
addr_jump concatenate_date_part, str_from_int
.endproc
parsed_date:
year: .word 0
month: .byte 0
day: .byte 0
month_table:
.addr str_no_date
.addr str_jan,str_feb,str_mar,str_apr,str_may,str_jun
.addr str_jul,str_aug,str_sep,str_oct,str_nov,str_dec
str_no_date:
PASCAL_STRING "no date"
str_jan:PASCAL_STRING "January"
str_feb:PASCAL_STRING "February"
str_mar:PASCAL_STRING "March"
str_apr:PASCAL_STRING "April"
str_may:PASCAL_STRING "May"
str_jun:PASCAL_STRING "June"
str_jul:PASCAL_STRING "July"
str_aug:PASCAL_STRING "August"
str_sep:PASCAL_STRING "September"
str_oct:PASCAL_STRING "October"
str_nov:PASCAL_STRING "November"
str_dec:PASCAL_STRING "December"
str_space:
PASCAL_STRING " "
.proc concatenate_date_part
stax $06
ldy #$00
lda ($08),y
sta concat_len
clc
adc ($06),y
sta ($08),y
lda ($06),y
sta @compare_y
: inc concat_len
iny
lda ($06),y
sty tmp
ldy concat_len
sta ($08),y
ldy tmp
@compare_y := *+1
cpy #0 ; self-modified
bcc :-
rts
tmp: .byte 0
concat_len:
.byte 0
.endproc
.endproc
;;; ============================================================
;;; Parse date
;;; Input: A,X = Date lo/hi
;;; $0A points at {year:.word, month:.byte, day:.byte} to be filled
.proc parse_date
ptr := $0A
;; TODO: Handle ProDOS 2.5 extended dates
;; (additional year bits packed into time bytes)
stax date
;; Null date? Leave as all zeros.
ora date+1 ; null date?
bne year
ldy #3
: sta (ptr),y
dey
bpl :-
rts
;; Year
year: lda date+1 ; First, calculate year-1900
lsr a
php ; Save Carry bit
cmp #40 ; Per ProDOS Tech Note #28, 0-39 is 2000-2039
bcs :+
adc #100
: adc #<1900
ldy #0
sta (ptr),y
iny
lda #0
adc #>1900
sta (ptr),y
;; Month
month: plp ; Restore Carry bit
lda date
ror a
lsr a
lsr a
lsr a
lsr a
ldy #2
sta (ptr),y
;; Day
day: lda date
and #%00011111
ldy #3
sta (ptr),y
rts
date: .word 0
.endproc
;;; ============================================================
.proc L84D1
jsr push_pointers
bit active_window_view_by
bmi L84DC
jsr cached_icons_screen_to_window
L84DC: sub16 grafport2::cliprect::x2, grafport2::cliprect::x1, L85F8
sub16 grafport2::cliprect::y2, grafport2::cliprect::y1, L85FA
lda event_kind
cmp #MGTK::EventKind::button_down
bne L850C
asl a
bne L850E
L850C: lda #$00
L850E: sta L85F1
lda active_window_id
jsr window_lookup
stax $06
lda #$06
clc
adc L85F1
tay
lda ($06),y
pha
jsr compute_icons_bbox
ldx L85F1
sub16 iconbb_rect::x2,x, iconbb_rect::x1,x, L85F2
ldx L85F1
sub16 L85F2, L85F8,x, L85F2
bpl L8562
lda L85F8,x
sta L85F2
lda L85F9,x
sta L85F3
L8562: lsr16 L85F2
lsr16 L85F2
lda L85F2
tay
pla
tax
lda event_params+1
jsr L62BC
ldx #$00
stx L85F2
asl a
rol L85F2
asl a
rol L85F2
ldx L85F1
clc
adc iconbb_rect::x1,x
sta grafport2::cliprect::x1,x
lda L85F2
adc iconbb_rect::x1+1,x
sta grafport2::cliprect::x1+1,x
lda active_window_id
jsr compute_window_dimensions
stax L85F4
sty L85F6
lda L85F1
beq L85C3
add16_8 grafport2::cliprect::y1, L85F6, grafport2::cliprect::y2
jmp L85D6
L85C3: add16 grafport2::cliprect::x1, L85F4, grafport2::cliprect::x2
L85D6: lda active_window_id
jsr window_lookup
stax $06
ldy #$23
ldx #$07
L85E4: lda grafport2::cliprect::x1,x
sta ($06),y
dey
dex
bpl L85E4
jsr pop_pointers
rts
L85F1: .byte 0
L85F2: .byte 0
L85F3: .byte 0
L85F4: .word 0
L85F6: .byte 0
.byte 0
L85F8: .byte 0
L85F9: .byte 0
L85FA: .word 0
.endproc
;;; ============================================================
;;; A = A * 16, high bits into X
.proc a_times_16
ldx #0
stx tmp
asl a
rol tmp
asl a
rol tmp
asl a
rol tmp
asl a
rol tmp
ldx tmp
rts
tmp: .byte 0
.endproc
;;; ============================================================
;;; A = A * 64, high bits into X
.proc a_times_64
ldx #$00
stx tmp
asl a
rol tmp
asl a
rol tmp
asl a
rol tmp
asl a
rol tmp
asl a
rol tmp
asl a
rol tmp
ldx tmp
rts
tmp: .byte 0
.endproc
;;; ============================================================
;;; Look up file address. Index in A, address in A,X.
.proc icon_entry_lookup
asl a
tax
lda icon_entry_address_table,x
pha
lda icon_entry_address_table+1,x
tax
pla
rts
.endproc
;;; ============================================================
;;; Look up window. Index in A, address in A,X.
.proc window_lookup
asl a
tax
lda win_table,x
pha
lda win_table+1,x
tax
pla
rts
.endproc
;;; ============================================================
;;; Look up window address. Index in A, address in A,X.
.proc window_path_lookup
asl a
tax
lda window_path_addr_table,x
pha
lda window_path_addr_table+1,x
tax
pla
rts
.endproc
;;; ============================================================
.proc compose_file_type_string
ptr := $06
sta file_type
copy16 #type_table, ptr
ldy #num_file_types-1
: lda (ptr),y
cmp file_type
beq found
dey
bpl :-
jmp not_found
;; Found - copy string from table
found: tya
asl a
asl a
tay
copy16 #type_names_table, ptr
ldx #0
: lda (ptr),y
sta str_file_type+1,x
iny
inx
cpx #4
bne :-
stx str_file_type
rts
;; Type not found - use generic " $xx"
not_found:
copy #4, str_file_type
copy #' ', str_file_type+1
copy #'$', str_file_type+2
lda file_type
lsr a
lsr a
lsr a
lsr a
tax
copy hex_digits,x, str_file_type+3
lda file_type
and #$0F
tax
copy hex_digits,x, str_file_type+4
rts
file_type:
.byte 0
.endproc
;;; ============================================================
;;; Draw text, pascal string address in A,X
.proc draw_pascal_string
params := $6
textptr := $6
textlen := $8
stax textptr
ldy #0
lda (textptr),y
beq exit
sta textlen
inc16 textptr
MGTK_RELAY_CALL MGTK::DrawText, params
exit: rts
.endproc
;;; ============================================================
;;; Measure text, pascal string address in A,X; result in A,X
.proc measure_text1
ptr := $6
len := $8
result := $9
stax ptr
ldy #0
lda (ptr),y
sta len
inc16 ptr
MGTK_RELAY_CALL MGTK::TextWidth, ptr
ldax result
rts
.endproc
;;; ============================================================
;;; Pushes two words from $6/$8 to stack
.proc push_pointers
ptr := $6
pla ; stash return address
sta addr
pla
sta addr+1
ldx #0 ; copy 4 bytes from $8 to stack
loop: lda ptr,x
pha
inx
cpx #4
bne loop
lda addr+1 ; restore return address
pha
lda addr
pha
rts
addr: .addr 0
.endproc
;;; ============================================================
;;; Pops two words from stack to $6/$8
.proc pop_pointers
ptr := $6
pla ; stash return address
sta addr
pla
sta addr+1
ldx #3 ; copy 4 bytes from stack to $6
loop: pla
sta ptr,x
dex
cpx #$FF ; why not bpl ???
bne loop
lda addr+1 ; restore return address to stack
pha
lda addr
pha
rts
addr: .addr 0
.endproc
;;; ============================================================
port_copy:
.res .sizeof(MGTK::GrafPort)+1, 0
.proc copy_window_portbits
ptr := $6
tay
jsr push_pointers
tya
jsr window_lookup
stax ptr
ldx #0
ldy #MGTK::Winfo::port
: lda (ptr),y
sta port_copy,x
iny
inx
cpx #.sizeof(MGTK::GrafPort)
bne :-
jsr pop_pointers
rts
.endproc
.proc assign_window_portbits
ptr := $6
tay
jsr push_pointers
tya
jsr window_lookup
stax ptr
ldx #0
ldy #MGTK::Winfo::port
: lda port_copy,x
sta (ptr),y
iny
inx
cpx #.sizeof(MGTK::GrafPort)
bne :-
jsr pop_pointers
rts
.endproc
;;; ============================================================
;;; Convert icon's coordinates from window to screen
;;; (icon index in A, active window)
.proc icon_window_to_screen
entry_ptr := $6
winfo_ptr := $8
tay
jsr push_pointers
tya
jsr icon_entry_lookup
stax entry_ptr
lda active_window_id
jsr window_lookup
stax winfo_ptr
;; Screen space
ldy #MGTK::Winfo::port + MGTK::GrafPort::viewloc + 3
ldx #3
: lda (winfo_ptr),y
sta pos_screen,x
dey
dex
bpl :-
;; Window space
ldy #MGTK::Winfo::port + MGTK::GrafPort::maprect + 3
ldx #3
: lda (winfo_ptr),y
sta pos_win,x
dey
dex
bpl :-
;; iconx
ldy #IconEntry::iconx
add16in (entry_ptr),y, pos_screen, (entry_ptr),y
iny
;; icony
add16in (entry_ptr),y, pos_screen+2, (entry_ptr),y
;; iconx
ldy #IconEntry::iconx
sub16in (entry_ptr),y, pos_win, (entry_ptr),y
iny
;; icony
sub16in (entry_ptr),y, pos_win+2, (entry_ptr),y
jsr pop_pointers
rts
pos_screen: .word 0, 0
pos_win: .word 0, 0
.endproc
;;; ============================================================
;;; Convert icon's coordinates from screen to window
;;; (icon index in A, active window)
.proc icon_screen_to_window
tay
jsr push_pointers
tya
jsr icon_entry_lookup
stax $06
;; fall through
.endproc
;;; Convert icon's coordinates from screen to window
;;; (icon entry pointer in $6, active window)
.proc icon_ptr_screen_to_window
entry_ptr := $6
winfo_ptr := $8
lda active_window_id
jsr window_lookup
stax winfo_ptr
ldy #MGTK::Winfo::port + MGTK::GrafPort::viewloc + 3
ldx #3
: lda (winfo_ptr),y
sta pos_screen,x
dey
dex
bpl :-
ldy #MGTK::Winfo::port + MGTK::GrafPort::maprect + 3
ldx #3
: lda (winfo_ptr),y
sta pos_win,x
dey
dex
bpl :-
;; iconx
ldy #IconEntry::iconx
sub16in (entry_ptr),y, pos_screen, (entry_ptr),y
iny
;; icony
sub16in (entry_ptr),y, pos_screen+2, (entry_ptr),y
;; iconx
ldy #IconEntry::iconx
add16in (entry_ptr),y, pos_win, (entry_ptr),y
iny
;; icony
add16in (entry_ptr),y, pos_win+2, (entry_ptr),y
jsr pop_pointers
rts
pos_screen: .word 0, 0
pos_win: .word 0, 0
.endproc
;;; ============================================================
.proc zero_grafport5_coords
lda #0
tax
: sta grafport5::cliprect::x1,x
sta grafport5::viewloc::xcoord,x
sta grafport5::cliprect::x2,x
inx
cpx #4
bne :-
MGTK_RELAY_CALL MGTK::SetPort, grafport5
rts
.endproc
;;; ============================================================
;;; Input: A = unit_number
;;; Output: A =
;;; 0 = Disk II
;;; 1 = SmartPort, RAM Disk
;;; 2 = SmartPort, Fixed (e.g. ProFile)
;;; 3 = SmartPort, Removable (e.g. UniDisk 3.5)
;;; 4 = AppleTalk file share
;;; 5 = unknown / RAM-based driver
device_type_to_icon_address_table:
.addr floppy140_icon
.addr ramdisk_icon
.addr profile_icon
.addr floppy800_icon
.addr fileshare_icon
.addr profile_icon ; unknown
.proc get_device_type
slot_addr := $0A
sta unit_number
cmp #$3E ; Glen E. Bredon's RAM.DRV.SYSTEM
beq ram
;; Look at "ID Nibble" (mostly bogus)
and #%00001111 ; look at low nibble
bne :+ ; 0 = Disk II
rts
;; Look up driver address
: lda unit_number
jsr device_driver_address
bne unk ; RAM-based driver: just use default
lda #$00
sta slot_addr ; point at $Cn00 for firmware lookups
;; Probe firmware ID bytes
ldy #$FF ; $CnFF: $00=Disk II, $FF=13-sector, else=block
lda (slot_addr),y
bne :+
rts ; 0 = Disk II
: ldy #$07 ; SmartPort signature byte ($Cn07)
lda (slot_addr),y ; $00 = SmartPort
bne unk
ldy #$FB ; SmartPort ID Type Byte ($CnFB)
lda (slot_addr),y ; bit 0 = is RAM Card?
and #%00000001
beq :+
ram: return #device_type_ramdisk
: lda unit_number ; low nibble is high nibble of $CnFE
;; Old heuristic. Invalid on UDC, etc.
;; and #%00001111
;; cmp #DT_REMOVABLE
;; Better heuristic, but still invalid on UDC, Virtual II, etc.
;; and #%00001000 ; bit 3 = is removable?
;; So instead, just assume <=1600 blocks is a 3.5" floppy
jsr get_block_count
bcs hd
stax blocks
cmp16 blocks, #1601
bcs hd
return #device_type_removable
;; Try AppleTalk
unk: MLI_RELAY_CALL READ_BLOCK, block_params
beq hd
cmp #ERR_NETWORK_ERROR
bne hd
return #device_type_fileshare
hd: return #device_type_profile
DEFINE_READ_BLOCK_PARAMS block_params, $800, 2
unit_number := block_params::unit_num
blocks: .word 0
.endproc
;;; ============================================================
;;; Get the block count for a given unit number.
;;; Input: A=unit_number
;;; Output: C=0, blocks in A,X on success, C=1 on error
.proc get_block_count_impl
DEFINE_ON_LINE_PARAMS on_line_params,, buffer
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params, path
start: sta on_line_params::unit_num
MLI_RELAY_CALL ON_LINE, on_line_params
bne error
;; Prefix the path with '/'
lda buffer
and #%00001111 ; mask off name length
clc
adc #1 ; account for '/'
sta path
copy #'/', buffer
MLI_RELAY_CALL GET_FILE_INFO, get_file_info_params
bne error
ldax get_file_info_params::aux_type
clc
rts
error: sec
rts
path: .byte 0 ; becomes length-prefixed path
buffer: .res 16, 0 ; length overwritten with '/'
.endproc
get_block_count := get_block_count_impl::start
;;; ============================================================
;;; Create Volume Icon
;;; Input: A = unit number, X = icon num, Y = index in DEVLST
;;; Output: 0 on success, ProDOS error code on failure
cvi_data_buffer := $800
DEFINE_ON_LINE_PARAMS on_line_params,, cvi_data_buffer
.proc create_volume_icon
max_icon_width = 53
max_icon_height = 15
sta unit_number
dex ; icon numbers are 1-based, and Trash is #1,
dex ; so make this 0-based
stx icon_index
sty devlst_index
and #$F0
sta on_line_params::unit_num
MLI_RELAY_CALL ON_LINE, on_line_params
beq success
error: pha ; save error
ldy devlst_index ; remove unit from list
lda #0
sta device_to_icon_map,y
dec cached_window_icon_count
dec icon_count
pla
rts
success:
lda cvi_data_buffer ; dr/slot/name_len
and #NAME_LENGTH_MASK
bne create_icon
lda cvi_data_buffer+1 ; if name len is zero, second byte is error
jmp error
create_icon:
icon_ptr := $6
icon_defn_ptr := $8
jsr push_pointers
jsr AllocateIcon
ldy devlst_index
sta device_to_icon_map,y
jsr icon_entry_lookup
stax icon_ptr
;; Copy name, with leading/trailing space
lda cvi_data_buffer
and #NAME_LENGTH_MASK
sta cvi_data_buffer
addr_call adjust_volname_case, cvi_data_buffer
ldy #IconEntry::name
copy #' ', (icon_ptr),y ; leading space
iny
ldx #0
: lda cvi_data_buffer+1,x
sta (icon_ptr),y
iny
inx
cpx cvi_data_buffer
bne :-
copy #' ', (icon_ptr),y ; trailing space
inx ; for leading/trailing space
inx
txa
ldy #IconEntry::len
sta (icon_ptr),y
;; ----------------------------------------
;; Figure out icon
lda unit_number
jsr get_device_type
asl ; * 2
tax
ldy #IconEntry::iconbits
lda device_type_to_icon_address_table,x
sta icon_defn_ptr
sta (icon_ptr),y
iny
lda device_type_to_icon_address_table+1,x
sta icon_defn_ptr+1
sta (icon_ptr),y
;; ----------------------------------------
;; Assign icon type
ldy #IconEntry::win_type
lda #0
sta (icon_ptr),y
inc devlst_index
;; Assign icon coordinates
lda icon_index
asl ; * 4 = .sizeof(MGTK::Point)
asl
tax
ldy #IconEntry::iconx
: lda desktop_icon_coords_table,x
sta (icon_ptr),y
inx
iny
cpy #IconEntry::iconbits
bne :-
;; Center it horizontally
ldy #IconDefinition::maprect + MGTK::Rect::x2
sub16in #max_icon_width, (icon_defn_ptr),y, offset
lsr16 offset ; offset = (max_width - icon_width) / 2
ldy #IconEntry::iconx
add16in (icon_ptr),y, offset, (icon_ptr),y
;; Adjust vertically
ldy #IconDefinition::maprect + MGTK::Rect::y2
sub16in #max_icon_height, (icon_defn_ptr),y, offset
ldy #IconEntry::icony
add16in (icon_ptr),y, offset, (icon_ptr),y
;; Assign icon number
ldx cached_window_icon_count
dex
ldy #IconEntry::id
lda (icon_ptr),y
sta cached_window_icon_list,x
jsr pop_pointers
return #0
unit_number: .byte 0
devlst_index: .byte 0
icon_index: .byte 0
offset: .word 0
;;; Icons are placed places in order as specified by caller
;;; in X. (Reverse DEVLST order, so most important is first.)
;;;
;;; +-------------------------+
;;; | 1 |
;;; | 2 |
;;; | 3 |
;;; | 4 |
;;; | 13 12 11 5 |
;;; | 10 9 8 7 6 Trash |
;;; +-------------------------+
trash_iconx = 506
trash_icony = 160
deltay = 29
desktop_icon_coords_table:
DEFINE_POINT 490,15 + deltay*0 ; 1
DEFINE_POINT 490,15 + deltay*1 ; 2
DEFINE_POINT 490,15 + deltay*2 ; 3
DEFINE_POINT 490,15 + deltay*3 ; 4
DEFINE_POINT 490,15 + deltay*4 ; 5
DEFINE_POINT 400,trash_icony+2 ; 6
DEFINE_POINT 310,trash_icony+2 ; 7
DEFINE_POINT 220,trash_icony+2 ; 8
DEFINE_POINT 130,trash_icony+2 ; 9
DEFINE_POINT 40,trash_icony+2 ; 10
DEFINE_POINT 400,15 + deltay*4 ; 11
DEFINE_POINT 310,15 + deltay*4 ; 12
DEFINE_POINT 220,15 + deltay*4 ; 13
;; Maximum of 13 devices:
;; 7 slots * 2 drives = 14 (size of DEVLST)
;; ... but RAM in Slot 3 Drive 2 is disconnected.
.endproc
;;; ============================================================
.proc remove_icon_from_window
ldx cached_window_icon_count
dex
: cmp cached_window_icon_list,x
beq remove
dex
bpl :-
rts
remove: lda cached_window_icon_list+1,x
sta cached_window_icon_list,x
inx
cpx cached_window_icon_count
bne remove
dec cached_window_icon_count
ldx cached_window_icon_count
lda #0
sta cached_window_icon_list,x
rts
.endproc
;;; ============================================================
;;; Search the window->dir_icon mapping table.
;;; Inputs: A = icon number
;;; Outputs: Z=1 && N=0 if found, X = index (0-7), A unchanged
.proc find_window_for_dir_icon
ldx #7
: cmp window_to_dir_icon_table,x
beq done
dex
bpl :-
done: rts
.endproc
;;; ============================================================
.proc mark_icons_not_opened
ptr := $6
L8B19: jsr push_pointers
jmp start
L8B1F: lda icon_params2
bne :+
rts
: jsr push_pointers
lda icon_params2
jsr L7345 ; ???
;; fall through
;; Find open window for the icon
start: lda icon_params2
jsr find_window_for_dir_icon
bne skip ; not found
;; If found, remove from the table
;; TODO: should this be $FF instead?
copy #0, window_to_dir_icon_table,x
;; Update the icon and redraw
skip: lda icon_params2
jsr icon_entry_lookup
stax ptr
ldy #IconEntry::win_type
lda (ptr),y
and #AS_BYTE(~icon_entry_open_mask) ; clear open_flag
sta (ptr),y
jsr redraw_selected_icons
jsr pop_pointers
rts
.endproc
mark_icons_not_opened_1 := mark_icons_not_opened::L8B19
mark_icons_not_opened_2 := mark_icons_not_opened::L8B1F
;;; ============================================================
.proc animate_window
ptr := $06
rect_table := $800
close: ldy #$80
bne :+
open: ldy #$00
: sty close_flag
sta icon_id
stx window_id
txa
;; Get window rect
jsr window_lookup
stax ptr
lda #$14
clc
adc #$23
tay
ldx #.sizeof(MGTK::GrafPort)-1
: lda (ptr),y
sta grafport2,x
dey
dex
bpl :-
;; Get icon position
lda icon_id
jsr icon_entry_lookup
stax ptr
ldy #IconEntry::iconx
lda (ptr),y ; x lo
clc
adc #7
sta rect_table
sta rect_table+4
iny
lda (ptr),y
adc #0
sta rect_table+1
sta rect_table+5
iny
lda (ptr),y
clc
adc #7
sta rect_table+2
sta rect_table+6
iny
lda (ptr),y ; y hi
adc #0
sta rect_table+3
sta rect_table+7
ldy #11 * .sizeof(MGTK::Rect) + 3
ldx #3
: lda grafport2,x
sta rect_table,y
dey
dex
bpl :-
sub16 grafport2::cliprect::x2, grafport2::cliprect::x1, L8D54
sub16 grafport2::cliprect::y2, grafport2::cliprect::y1, L8D56
add16 $0858, L8D54, $085C
add16 $085A, L8D56, $085E
lda #$00
sta L8D4E
sta L8D4F
sta L8D4D
sub16 $0858, rect_table, L8D50
sub16 $085A, $0802, L8D52
bit L8D51
bpl L8C6A
copy #$80, L8D4E
lda L8D50
eor #$FF
sta L8D50
lda L8D51
eor #$FF
sta L8D51
inc16 L8D50
L8C6A: bit L8D53
bpl L8C8C
copy #$80, L8D4F
lda L8D52
eor #$FF
sta L8D52
lda L8D53
eor #$FF
sta L8D53
inc16 L8D52
L8C8C: lsr16 L8D50
lsr16 L8D52
lsr16 L8D54
lsr16 L8D56
lda #$0A
sec
sbc L8D4D
asl a
asl a
asl a
tax
bit L8D4E
bpl :+
sub16 rect_table, L8D50, rect_table,x
jmp L8CDC
: add16 rect_table, L8D50, rect_table,x
L8CDC: bit L8D4F
bpl L8CF7
sub16 $0802, L8D52, $0802,x
jmp L8D0A
L8CF7: add16 rect_table+2, L8D52, rect_table+2,x
L8D0A: add16 rect_table,x, L8D54, rect_table+4,x ; right
add16 rect_table+2,x, L8D56, rect_table+6,x ; bottom
inc L8D4D
lda L8D4D
cmp #10
beq :+
jmp L8C8C
: bit close_flag
bmi :+
jsr animate_window_open_impl
rts
: jsr animate_window_close_impl
rts
close_flag:
.byte 0
icon_id:
.byte 0
window_id:
.byte 0
L8D4D: .byte 0
L8D4E: .byte 0
L8D4F: .byte 0
L8D50: .byte 0
L8D51: .byte 0
L8D52: .byte 0
L8D53: .byte 0
L8D54: .word 0
L8D56: .word 0
.endproc
animate_window_close := animate_window::close
animate_window_open := animate_window::open
;;; ============================================================
.proc animate_window_open_impl
rect_table := $800
lda #0
sta step
jsr reset_grafport3
MGTK_RELAY_CALL MGTK::SetPattern, checkerboard_pattern
jsr set_penmode_xor
loop: lda step
cmp #12
bcs erase
;; Compute offset into rect table
asl a
asl a
asl a
clc
adc #7
tax
;; Copy rect to draw
ldy #7
: lda rect_table,x
sta tmp_rect,y
dex
dey
bpl :-
jsr draw_anim_window_rect
;; Compute offset into rect table
erase: lda step
sec
sbc #2
bmi next
asl a ; * 8 (size of Rect)
asl a
asl a
clc
adc #$07
tax
;; Copy rect to erase
ldy #.sizeof(MGTK::Rect)-1
: lda rect_table,x
sta tmp_rect,y
dex
dey
bpl :-
jsr draw_anim_window_rect
next: inc step
lda step
cmp #$0E
bne loop
rts
step: .byte 0
.endproc
;;; ============================================================
.proc animate_window_close_impl
rect_table := $800
lda #11
sta step
jsr reset_grafport3
MGTK_RELAY_CALL MGTK::SetPattern, checkerboard_pattern
jsr set_penmode_xor
loop: lda step
bmi erase
beq erase
;; Compute offset into rect table
asl a ; * 8 (size of Rect)
asl a
asl a
clc
adc #$07
tax
;; Copy rect to draw
ldy #.sizeof(MGTK::Rect)-1
: lda rect_table,x
sta tmp_rect,y
dex
dey
bpl :-
jsr draw_anim_window_rect
;; Compute offset into rect table
erase: lda step
clc
adc #2
cmp #13
bcs next
asl a
asl a
asl a
clc
adc #$07
tax
;; Copy rect to erase
ldy #.sizeof(MGTK::Rect)-1
: lda rect_table,x
sta tmp_rect,y
dex
dey
bpl :-
jsr draw_anim_window_rect
next: dec step
lda step
cmp #AS_BYTE(-3)
bne loop
rts
step: .byte 0
.endproc
;;; ============================================================
.proc draw_anim_window_rect
MGTK_RELAY_CALL MGTK::FrameRect, tmp_rect
rts
.endproc
;;; ============================================================
;;; Dynamically load parts of Desktop2
;;; Call load_dynamic_routine or restore_dynamic_routine
;;; with A set to routine number (0-8); routine is loaded
;;; from DeskTop2 file to target address. Returns with
;;; minus flag set on failure.
;;; Routines are:
;;; 0 = disk copy - A$ 800,L$ 200
;;; 1 = format/erase disk - A$ 800,L$1400 call w/ A = 4 = format, A = 5 = erase
;;; 2 = selector actions (all) - A$9000,L$1000
;;; 3 = common file dialog - A$5000,L$2000
;;; 4 = part of copy file - A$7000,L$ 800
;;; 5 = part of delete file - A$7000,L$ 800
;;; 6 = selector add/edit - L$7000,L$ 800
;;; 7 = restore 1 - A$5000,L$2800 (restore $5000...$77FF)
;;; 8 = restore 2 - A$9000,L$1000 (restore $9000...$9FFF)
;;;
;;; Routines 2-6 need appropriate "restore routines" applied when complete.
.proc load_dynamic_routine_impl
pos_table:
.dword $00012FE0,$000160E0,$000174E0,$000184E0,$0001A4E0
.dword $0001ACE0,$0001B4E0,$0000B780,$0000F780
len_table:
.word $0200,$1400,$1000,$2000,$0800,$0800,$0800,$2800,$1000
addr_table:
.addr $0800,$0800,$9000,$5000,$7000,$7000,$7000,$5000,$9000
DEFINE_OPEN_PARAMS open_params, str_desktop2, $1C00
str_desktop2:
PASCAL_STRING "DeskTop2"
DEFINE_SET_MARK_PARAMS set_mark_params, 0
DEFINE_READ_PARAMS read_params, 0, 0
DEFINE_CLOSE_PARAMS close_params
restore_flag:
.byte 0
;; Called with routine # in A
load: pha ; entry point with bit clear
copy #0, restore_flag
beq :+ ; always
restore:
pha
copy #$80, restore_flag ; entry point with bit set
: pla
asl a ; y = A * 2 (to index into word table)
tay
asl a ; x = A * 4 (to index into dword table)
tax
lda pos_table,x
sta set_mark_params::position
lda pos_table+1,x
sta set_mark_params::position+1
lda pos_table+2,x
sta set_mark_params::position+2
copy16 len_table,y, read_params::request_count
copy16 addr_table,y, read_params::data_buffer
open: MLI_RELAY_CALL OPEN, open_params
beq :+
lda #warning_msg_insert_system_disk
ora restore_flag ; high bit set = no cancel
jsr warning_dialog_proc_num
beq open
return #$FF ; failed
: lda open_params::ref_num
sta read_params::ref_num
sta set_mark_params::ref_num
MLI_RELAY_CALL SET_MARK, set_mark_params
MLI_RELAY_CALL READ, read_params
MLI_RELAY_CALL CLOSE, close_params
rts
.endproc
load_dynamic_routine := load_dynamic_routine_impl::load
restore_dynamic_routine := load_dynamic_routine_impl::restore
;;; ============================================================
.proc show_clock
lda MACHID
and #1 ; bit 0 = clock card
bne :+
rts
: MLI_RELAY_CALL GET_TIME, 0
;; Assumes call from main loop, where grafport3 is initialized.
MGTK_RELAY_CALL MGTK::SetTextBG, desktop_aux::textbg_white
MGTK_RELAY_CALL MGTK::MoveTo, pos_clock
;; --------------------------------------------------
;; Day of Week
lda DATEHI ; Year-1900 (bits 15-9)
lsr a
php ; Save Carry bit
cmp #40 ; Per ProDOS Tech Note #18, 0-39 is 2000-2039
bcs :+
adc #100
: tay
plp ; Restore Carry bit
lda DATELO ; Month (bits 8-5)
ror
lsr
lsr
lsr
lsr
tax
lda DATELO ; Day (bits 0-4)
and #%00011111
jsr day_of_week
asl ; * 4
asl
clc
adc #<dow_strings
sta dow_str_params::addr
lda #0
adc #>dow_strings
sta dow_str_params::addr+1
MGTK_RELAY_CALL MGTK::DrawText, dow_str_params
;; --------------------------------------------------
;; Time
lda TIMEHI ; Hours
and #%00011111
pha ; Save hours
bne :+ ; 0 -> 12
clc
adc #12
: cmp #13 ; make 12-hour
bcc :+
sec
sbc #12
: ldx #0
jsr int_to_string
addr_call draw_text1, str_from_int
addr_call draw_text1, str_colon
lda TIMELO
and #%00111111
pha
cmp #10
bcs :+
addr_call draw_text1, str_zero
: pla
ldx #0
jsr int_to_string
addr_call draw_text1, str_from_int
pla ; Restore hours
cmp #12
bcs :+
addr_jump draw_text1, str_am
: addr_jump draw_text1, str_pm
.endproc
;;; Day of the Week calculation (valid 1900-03-01 to 2155-12-31)
;;; c/o http://6502.org/source/misc/dow.htm
;;; Inputs: Y = year (0=1900), X = month (1=Jan), A = day (1...31)
;;; Output: A = weekday (0=Sunday)
.proc day_of_week
tmp := $06
cpx #3 ; Year starts in March to bypass
bcs :+ ; leap year problem
dey ; If Jan or Feb, decrement year
: eor #$7F ; Invert A so carry works right
cpy #200 ; Carry will be 1 if 22nd century
adc month_offset_table-1,X ; A is now day+month offset
sta tmp
tya ; Get the year
jsr mod7 ; Do a modulo to prevent overflow
sbc tmp ; Combine with day+month
sta tmp
tya ; Get the year again
lsr ; Divide it by 4
lsr
clc ; Add it to y+m+d and fall through
adc tmp
mod7: adc #7 ; Returns (A+3) modulo 7
bcc mod7 ; for A in 0..255
rts
.endproc
;;; ============================================================
.proc set_color_mode
;; AppleColor Card - Mode 2 (Color 140x192)
sta SET80VID
lda AN3_OFF
lda AN3_ON
lda AN3_OFF
lda AN3_ON
lda AN3_OFF
;; IIgs?
jsr test_iigs
bcc iigs
;; Le Chat Mauve - COL140 mode
;; (AN3 off, HR1 off, HR2 off, HR3 off)
;; Skip on IIgs since emulators (KEGS/GSport/GSplus) crash.
sta HR2_OFF
sta HR3_OFF
bcs done
;; Apple IIgs - DHR Color
iigs: lda NEWVIDEO
and #<~(1<<5) ; Color
sta NEWVIDEO
done: rts
.endproc
.proc set_mono_mode
;; AppleColor Card - Mode 1 (Monochrome 560x192)
sta CLR80VID
lda AN3_OFF
lda AN3_ON
lda AN3_OFF
lda AN3_ON
sta SET80VID
lda AN3_OFF
;; IIgs?
jsr test_iigs
bcc iigs
;; Le Chat Mauve - BW560 mode
;; (AN3 off, HR1 off, HR2 on, HR3 on)
;; Skip on IIgs since emulators (KEGS/GSport/GSplus) crash.
sta HR2_ON
sta HR3_ON
bcs done
;; Apple IIgs - DHR B&W
iigs: lda NEWVIDEO
ora #(1<<5) ; B&W
sta NEWVIDEO
done: rts
.endproc
;;; Returns with carry clear if IIgs, set otherwise.
.proc test_iigs
lda ROMIN2
sec
jsr ID_BYTE_FE1F
lda LCBANK1
lda LCBANK1
rts
.endproc
;;; ============================================================
;;; Operations performed on selection
;;;
;;; These operate on the entire selection recursively, e.g.
;;; computing size, deleting, copying, etc., and share common
;;; logic.
.enum PromptResult
ok = 0
cancel = 1
yes = 2
no = 3
all = 4
.endenum
;;; ============================================================
jt_drop: jmp do_drop
jt_get_info: jmp do_get_info ; cmd_get_info
jt_lock: jmp do_lock ; cmd_lock
jt_unlock: jmp do_unlock ; cmd_unlock
jt_rename_icon: jmp do_rename_icon ; cmd_rename_icon
jt_eject: jmp do_eject ; cmd_eject ???
jt_copy_file: jmp do_copy_file ; cmd_copy_file
jt_delete_file: jmp do_delete_file ; cmd_delete_file
jt_run: jmp do_run ; cmd_selector_action / Run
jt_get_size: jmp do_get_size ; cmd_get_size
;;; --------------------------------------------------
.enum DeleteDialogLifecycle
open = 0
populate = 1
confirm = 2 ; confirmation before deleting
show = 3
locked = 4 ; confirm deletion of locked file
close = 5
trash = 6 ; open, but from trash path ???
.endenum
;;; --------------------------------------------------
.proc operations
do_copy_file:
copy #0, operation_flags ; copy/delete
tsx
stx stack_stash
jsr prep_callbacks_for_size_or_count
jsr do_copy_dialog_phase
jsr size_or_count_process_selected_file
jsr prep_callbacks_for_copy
do_run2:
copy #$FF, LE05B
copy #0, delete_skip_decrement_flag
jsr copy_file_for_run
jsr done_dialog_phase1
.proc finish_operation
jsr redraw_desktop_and_windows
return #0
.endproc
do_delete_file:
copy #0, operation_flags ; copy/delete
tsx
stx stack_stash
jsr prep_callbacks_for_size_or_count
lda #DeleteDialogLifecycle::open
jsr do_delete_dialog_phase
jsr size_or_count_process_selected_file
jsr done_dialog_phase2
jsr prep_callbacks_for_delete
jsr delete_process_selected_file
jsr done_dialog_phase1
jmp finish_operation
do_run:
copy #$80, run_flag
copy #%11000000, operation_flags ; get size
tsx
stx stack_stash
jsr prep_callbacks_for_size_or_count
jsr do_download_dialog_phase
jsr size_or_count_process_selected_file
jsr L99BC
jmp do_run2
;;; --------------------------------------------------
;;; Lock
do_lock:
jsr L8FDD
jmp finish_operation
do_unlock:
jsr L8FE1
jmp finish_operation
.proc get_icon_entry_win_type
asl a
tay
copy16 icon_entry_address_table,y, $06
ldy #IconEntry::win_type
lda ($06),y
rts
.endproc
;;; --------------------------------------------------
.proc do_get_size
copy #0, run_flag
copy #%11000000, operation_flags ; get size
jmp L8FEB
.endproc
.proc do_drop
lda drag_drop_param
cmp #1 ; Trash (BUG: Should use trash_icon_num)
bne :+
lda #$80
bne set ; always
: lda #$00
set: sta delete_flag
copy #0, operation_flags ; copy/delete
jmp L8FEB
.endproc
;; common for lock/unlock
L8FDD: lda #$00 ; unlock
beq :+
L8FE1: lda #$80 ; lock
: sta unlock_flag
copy #%10000000, operation_flags ; lock/unlock
L8FEB: tsx
stx stack_stash
copy #0, delete_skip_decrement_flag
jsr prep_grafport3
lda operation_flags
beq :+ ; copy/delete
jmp begin_operation
;; Copy or delete
: bit delete_flag
bpl compute_target_prefix ; copy
;; Delete - is it a volume?
lda selected_window_index
beq :+
jmp begin_operation
;; Yes - eject it!
: pla
pla
jmp JT_EJECT
;;; --------------------------------------------------
;;; For drop onto window/icon, compute target prefix.
;; Is drop on a window or an icon?
;; hi bit clear = target is an icon
;; hi bit set = target is a window; get window number
compute_target_prefix:
lda drag_drop_param
bpl check_icon_drop_type
;; Drop is on a window
and #%01111111 ; get window id
asl a
tax
copy16 window_path_addr_table,x, $08
copy16 #empty_string, $06
jsr join_paths
jmp L9076
;; Drop is on an icon.
;; Is drop on a volume or a file?
;; (lower 4 bits are containing window id)
check_icon_drop_type:
jsr get_icon_entry_win_type
and #icon_entry_winid_mask
beq drop_on_volume_icon ; 0 = desktop (so, volume icon)
;; Drop is on a file icon.
asl a
tax
copy16 window_path_addr_table,x, $08
lda drag_drop_param
jsr icon_entry_name_lookup
jsr join_paths
jmp L9076
;; Drop is on a volume icon.
;;
drop_on_volume_icon:
lda drag_drop_param
;; Prefix name with '/'
jsr icon_entry_name_lookup
ldy #1
lda #'/'
sta ($06),y
;; Copy to path_buf3
dey
lda ($06),y
sta @compare
sta path_buf3,y
: iny
lda ($06),y
sta path_buf3,y
@compare := *+1
cpy #0 ; self-modified
bne :-
;; Restore ' ' to name prefix
ldy #1
lda #' '
sta ($06),y
L9076: ldy #$FF
: iny
copy path_buf3,y, path_buf4,y
cpy path_buf3
bne :-
lda path_buf4
beq begin_operation
dec path_buf4
;; fall through
;;; --------------------------------------------------
;;; Start the actual operation
.proc begin_operation
copy #0, L97E4
jsr prep_callbacks_for_size_or_count
bit operation_flags
bvs @size
bmi @lock
bit delete_flag
bmi @trash
;; Copy or Move - compare src/dst paths (etc)
jsr get_window_path_ptr
jsr check_move_or_copy
sta move_flag
jsr do_copy_dialog_phase
jmp iterate_selection
@trash: lda #DeleteDialogLifecycle::trash
jsr do_delete_dialog_phase
jmp iterate_selection
@lock: jsr do_lock_dialog_phase
jmp iterate_selection
@size: jsr do_get_size_dialog_phase
jmp iterate_selection
;;; Perform operation
L90BA: bit operation_flags
bvs @size
bmi @lock
bit delete_flag
bmi @trash
jsr prep_callbacks_for_copy
jmp iterate_selection
@trash: jsr prep_callbacks_for_delete
jmp iterate_selection
@lock: jsr prep_callbacks_for_lock
jmp iterate_selection
@size: jsr get_size_rts2 ; no-op ???
jmp iterate_selection
iterate_selection:
lda selected_icon_count
bne :+
jmp finish
: ldx #0
stx icon_count
loop: jsr get_window_path_ptr
ldx icon_count
lda selected_icon_list,x
cmp #1 ; icon #1 is always Trash (BUG: should use trash_icon_num)
beq next_icon
jsr icon_entry_name_lookup
jsr join_paths
;; Shrink name to remove trailing ' '
lda path_buf3
beq :+
dec path_buf3
:
lda L97E4
beq L913D
bit operation_flags
bmi @lock_or_size
bit delete_flag
bmi :+
jsr copy_process_selected_file
jmp next_icon
: jsr delete_process_selected_file
jmp next_icon
@lock_or_size:
bvs @size ; size?
jsr lock_process_selected_file
jmp next_icon
@size: jsr size_or_count_process_selected_file
jmp next_icon
L913D: jsr size_or_count_process_selected_file
next_icon:
inc icon_count
ldx icon_count
cpx selected_icon_count
bne loop
lda L97E4
bne finish
inc L97E4
bit operation_flags
bmi @lock_or_size
bit delete_flag
bpl not_trash
@lock_or_size:
jsr done_dialog_phase2
bit operation_flags
bvs finish
not_trash:
jmp L90BA
finish: jsr done_dialog_phase1
return #0
icon_count:
.byte 0
.endproc
empty_string:
.byte 0
.endproc ; operations
do_delete_file := operations::do_delete_file
do_run := operations::do_run
do_copy_file := operations::do_copy_file
do_lock := operations::do_lock
do_unlock := operations::do_unlock
do_get_size := operations::do_get_size
do_drop := operations::do_drop
;;; ============================================================
done_dialog_phase0:
dialog_phase0_callback := *+1
jmp dummy0000
done_dialog_phase1:
dialog_phase1_callback := *+1
jmp dummy0000
done_dialog_phase2:
dialog_phase2_callback := *+1
jmp dummy0000
done_dialog_phase3:
dialog_phase3_callback := *+1
jmp dummy0000
stack_stash:
.byte 0
;; $80 = lock/unlock
;; $C0 = get size/run (easily probed with oVerflow flag)
;; $00 = copy/delete
operation_flags:
.byte 0
;; high bit set = delete, clear = copy
delete_flag:
.byte 0
;; high bit set = move, clear = copy
move_flag:
.byte 0
;; high bit set = unlock, clear = lock
unlock_flag:
.byte 0
;; high bit set = from Selector > Run command (download???)
;; high bit clear = Get Size
run_flag:
.byte 0
all_flag:
.byte 0
;;; ============================================================
;;; For icon index in A, put pointer to name in $6
.proc icon_entry_name_lookup
asl a
tay
add16 icon_entry_address_table,y, #IconEntry::len, $06
rts
.endproc
;;; ============================================================
.proc join_paths
str1 := $8
str2 := $6
buf := path_buf3
ldx #0
ldy #0
lda (str1),y
beq do_str2
;; Copy $8 (str1)
sta @len
: iny
inx
lda (str1),y
sta buf,x
@len := *+1
cpy #0 ; self-modified
bne :-
do_str2:
;; Add path separator
inx
lda #'/'
sta buf,x
;; Append $6 (str2)
ldy #0
lda (str2),y
beq done
sta @len
iny
: iny
inx
lda (str2),y
sta buf,x
@len := *+1
cpy #0 ; self-modified
bne :-
done: stx buf
rts
.endproc
;;; ============================================================
.proc prep_grafport3
yax_call JT_MGTK_RELAY, MGTK::InitPort, grafport3
yax_call JT_MGTK_RELAY, MGTK::SetPort, grafport3
rts
.endproc
.proc redraw_desktop_and_windows
jsr JT_REDRAW_ALL
yax_call JT_ITK_RELAY, IconTK::REDRAW_ICONS, 0
rts
.endproc
.proc get_window_path_ptr
ptr := $08
copy16 #nullptr, ptr ; ptr to empty string???
lda selected_window_index
beq done
asl a
tax
copy16 window_path_addr_table,x, ptr
lda #0
done: rts
nullptr:
.addr 0
.endproc
;;; ============================================================
.proc do_eject
lda selected_icon_count
bne :+
rts
: ldx selected_icon_count
stx $800
dex
: lda selected_icon_list,x
sta $0801,x
dex
bpl :-
jsr JT_CLEAR_SELECTION
ldx #0
stx index
loop: ldx index
lda $0801,x
cmp #$01
beq :+
jsr smartport_eject
: inc index
ldx index
cpx $800
bne loop
rts
index: .byte 0
.endproc
;;; ============================================================
.proc smartport_eject
ptr := $6
sta @compare
ldy #0
: lda device_to_icon_map,y
@compare := *+1
cmp #0
beq found
cpy DEVCNT
beq exit
iny
bne :-
exit: rts
found: lda DEVLST,y ;
sta unit_number
;; Compute SmartPort dispatch address
smartport_addr := $0A
jsr find_smartport_dispatch_address
bne exit ; not SP
stx control_unit_number
;; Execute SmartPort call
jsr smartport_call
.byte $04 ; $04 = CONTROL
.addr control_params
rts
smartport_call:
jmp (smartport_addr)
.proc control_params
param_count: .byte 3
unit_number: .byte 0
control_list: .addr list
control_code: .byte 4 ; Eject disk
.endproc
control_unit_number := control_params::unit_number
list: .word 0 ; 0 items in list
unit_number:
.byte 0
.endproc
;;; ============================================================
;;; "Get Info" dialog state and logic
;;; ============================================================
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params5, $220
DEFINE_READ_BLOCK_PARAMS block_params, $800, $A
.proc get_info_dialog_params
L92E3: .byte 0
L92E4: .word 0
L92E6: .byte 0
.endproc
;;; ============================================================
;;; Look up device driver address.
;;; Input: A = unit number
;;; Output: $0A/$0B ptr to driver; Z set if $CnXX
.proc device_driver_address
slot_addr := $0A
and #%11110000 ; mask off drive/slot
clc
ror ; 0DSSS000
ror ; 00DSSS00
ror ; 000DSSS0
tax ; = slot * 2 + (drive == 2 ? 0x10 + 0x00)
lda DEVADR,x
sta slot_addr
lda DEVADR+1,x
sta slot_addr+1
and #$F0 ; is it $Cn ?
cmp #$C0 ; leave Z flag set if so
rts
.endproc
;;; ============================================================
;;; Look up SmartPort dispatch address.
;;; Input: A = unit number
;;; Output: Z=1 if SP, $0A/$0B dispatch address, X = SP unit num
;;; Z=0 if not SP
.proc find_smartport_dispatch_address
sp_addr := $0A
sta unit_number ; DSSSnnnn
;; Get device driver address
jsr device_driver_address
bne exit ; RAM-based driver
;; Find actual address
copy #0, sp_addr ; point at $Cn00 for firmware lookups
ldy #$07 ; SmartPort signature byte ($Cn07)
lda (sp_addr),y ; $00 = SmartPort
bne exit
ldy #$FB ; SmartPort ID Type Byte ($CnFB)
lda (sp_addr),y
and #$7F ; bit 7 = is Extended
bne exit
;; Locate SmartPort entry point: $Cn00 + ($CnFF) + 3
ldy #$FF
lda (sp_addr),y
clc
adc #3
sta sp_addr
;; Figure out SmartPort control unit number in X
ldx #1 ; start with unit 1
bit unit_number ; high bit is D
bpl :+
inx ; X = 1 or 2 (for Drive 1 or 2)
: lda unit_number
and #%01110000 ; 0SSSnnnn
lsr
lsr
lsr
lsr
sta mapped_slot ; 00000SSS
lda sp_addr+1 ; $Cn
and #%00001111 ; $0n
cmp mapped_slot ; equal = not remapped
beq :+
inx ; now X = 3 or 4
inx
: lda #0 ; exit with Z set on success
exit: rts
unit_number:
.byte 0
mapped_slot: ; from unit_number, not driver
.byte 0
.endproc
;;; ============================================================
;;; Get Info
.proc do_get_info
path_buf := $220
ptr := $6
lda selected_icon_count
bne :+
rts
: copy #0, get_info_dialog_params::L92E6
jsr prep_grafport3
loop: ldx get_info_dialog_params::L92E6
cpx selected_icon_count
bne :+
jmp done
: lda selected_window_index
beq vol_icon
;; File icon
asl a
tax
copy16 window_path_addr_table,x, $08
ldx get_info_dialog_params::L92E6
lda selected_icon_list,x
jsr icon_entry_name_lookup
jsr join_paths
ldy #0 ; Copy name to path_buf
: lda path_buf3,y
sta path_buf,y
iny
cpy path_buf
bne :-
dec path_buf
jmp common
;; Volume icon
vol_icon:
ldx get_info_dialog_params::L92E6
lda selected_icon_list,x
cmp #1 ; trash icon?
bne :+
jmp next
: jsr icon_entry_name_lookup
ldy #0
: lda (ptr),y
sta path_buf,y
iny
cpy path_buf
bne :-
dec path_buf
lda #'/'
sta path_buf+1
;; Try to get file info
common: MLI_RELAY_CALL GET_FILE_INFO, get_file_info_params5
beq :+
jsr show_error_alert
beq common
:
lda selected_window_index
beq vol_icon2
;; File icon
copy #$80, get_info_dialog_params::L92E3
lda get_info_dialog_params::L92E6
clc
adc #1
cmp selected_icon_count
beq :+
inc get_info_dialog_params::L92E3
inc get_info_dialog_params::L92E3
: jsr run_get_info_dialog_proc
jmp common2
vol_icon2:
copy #$81, get_info_dialog_params::L92E3
lda get_info_dialog_params::L92E6
clc
adc #1
cmp selected_icon_count
beq :+
inc get_info_dialog_params::L92E3
inc get_info_dialog_params::L92E3
: jsr run_get_info_dialog_proc
copy #0, write_protected_flag
ldx get_info_dialog_params::L92E6
lda selected_icon_list,x
;; Map icon to unit number
ldy #15
: cmp device_to_icon_map,y
beq :+
dey
bpl :-
jmp common2
: lda DEVLST,y
sta block_params::unit_num
MLI_RELAY_CALL READ_BLOCK, block_params
bne common2
MLI_RELAY_CALL WRITE_BLOCK, block_params
cmp #ERR_WRITE_PROTECTED
bne common2
copy #$80, write_protected_flag
common2:
ldx get_info_dialog_params::L92E6
lda selected_icon_list,x
jsr icon_entry_name_lookup
copy #1, get_info_dialog_params::L92E3
copy16 ptr, get_info_dialog_params::L92E4
jsr run_get_info_dialog_proc
copy #2, get_info_dialog_params::L92E3
lda selected_window_index
bne is_file
bit write_protected_flag
bmi is_protected
copy #0, get_info_dialog_params::L92E4
beq L9428 ; always
is_protected:
copy #1, get_info_dialog_params::L92E4
bne L9428 ; always
is_file:
lda get_file_info_params5::access
and #ACCESS_DEFAULT
cmp #ACCESS_DEFAULT
beq L9423
copy #1, get_info_dialog_params::L92E4
bne L9428 ; always
L9423: copy #0, get_info_dialog_params::L92E4
L9428: jsr run_get_info_dialog_proc
jmp L942F
write_protected_flag:
.byte 0
L942F: copy #3, get_info_dialog_params::L92E3
;; Compose " 12345 Blocks" or " 12345 / 67890 Blocks" string
buf := $220
copy #0, buf
lda selected_window_index ; volume?
bne do_suffix ; nope
;; ProDOS TRM 4.4.5:
;; "When file information about a volume directory is requested, the
;; total number of blocks on the volume is returned in the aux_type
;; field and the total blocks for all files is returned in blocks_used.
lda get_file_info_params5::aux_type
sec
sbc get_file_info_params5::blocks_used
pha
lda get_file_info_params5::aux_type+1
sbc get_file_info_params5::blocks_used+1
tax
pla
jsr JT_SIZE_STRING
;; text_buffer2 now has " 12345 Blocks" (free space)
;; Copy number and leading/trailing space into buf
ldx buf
ldy #0
: inx
lda text_buffer2::data,y
cmp #'B' ; stop at 'B' in "Blocks"
beq slash
sta buf,x
iny
cpy text_buffer2::length
bne :-
;; Append '/' to buf
slash: lda #'/'
sta buf,x
stx buf
do_suffix:
lda selected_window_index ; volume?
bne :+ ; nope
;; Load up the total volume size...
ldax get_file_info_params5::aux_type
jmp compute_suffix
;; Load up the file size
: ldax get_file_info_params5::blocks_used
;; Compute " 12345 Blocks" (either result or suffix)
compute_suffix:
jsr JT_SIZE_STRING
;; Append latest to buffer
ldx buf
ldy #1
: inx
lda text_buffer2::data-1,y
sta buf,x
cpy text_buffer2::length
beq :+
iny
bne :-
: stx buf
;; TODO: Compose directly into path_buf4.
ldx buf
: lda buf,x
sta path_buf4,x
dex
bpl :-
copy16 #path_buf4, get_info_dialog_params::L92E4
jsr run_get_info_dialog_proc
copy #4, get_info_dialog_params::L92E3
copy16 get_file_info_params5::create_date, date
jsr JT_DATE_STRING
copy16 #text_buffer2::length, get_info_dialog_params::L92E4
jsr run_get_info_dialog_proc
copy #5, get_info_dialog_params::L92E3
copy16 get_file_info_params5::mod_date, date
jsr JT_DATE_STRING
copy16 #text_buffer2::length, get_info_dialog_params::L92E4
jsr run_get_info_dialog_proc
copy #6, get_info_dialog_params::L92E3
lda selected_window_index
bne L9519
COPY_STRING str_vol, str_file_type
bmi L951F ; always
L9519: lda get_file_info_params5::file_type
jsr JT_FILE_TYPE_STRING
L951F: copy16 #str_file_type, get_info_dialog_params::L92E4
jsr run_get_info_dialog_proc
bne done
next: inc get_info_dialog_params::L92E6
jmp loop
done: copy #0, path_buf4
rts
str_vol:
PASCAL_STRING " VOL"
.proc run_get_info_dialog_proc
yax_call invoke_dialog_proc, index_get_info_dialog, get_info_dialog_params
rts
.endproc
.endproc
;;; ============================================================
.proc do_rename_icon_impl
src_path_buf := $220
DEFINE_RENAME_PARAMS rename_params, src_path_buf, dst_path_buf
rename_dialog_params:
.byte 0
.addr $1F00
start:
copy #0, L9706
L9576: lda L9706
cmp selected_icon_count
bne L9581
return #0
L9581: ldx L9706
lda selected_icon_list,x
cmp #$01
bne L9591
inc L9706
jmp L9576
L9591: lda selected_window_index
beq L95C2
asl a
tax
copy16 window_path_addr_table,x, $08
ldx L9706
lda selected_icon_list,x
jsr icon_entry_name_lookup
jsr join_paths
ldy #$00
L95B0: lda path_buf3,y
sta src_path_buf,y
iny
cpy src_path_buf
bne L95B0
dec src_path_buf
jmp L95E0
L95C2: ldx L9706
lda selected_icon_list,x
jsr icon_entry_name_lookup
ldy #$00
L95CD: lda ($06),y
sta src_path_buf,y
iny
cpy src_path_buf
bne L95CD
dec src_path_buf
lda #'/'
sta src_path_buf+1
L95E0: ldx L9706
lda selected_icon_list,x
jsr icon_entry_name_lookup
ldy #$00
lda ($06),y
tay
L95EE: lda ($06),y
sta $1F12,y
dey
bpl L95EE
ldy #$00
lda ($06),y
tay
dey
sec
sbc #$02
sta $1F00
L9602: lda ($06),y
sta $1F00-1,y
dey
cpy #$01
bne L9602
lda #$00
jsr L96F8
L9611: lda #$80
jsr L96F8
beq L962F
L9618: ldx L9706
lda selected_icon_list,x
jsr icon_entry_name_lookup
ldy $1F12
L9624: lda $1F12,y
sta ($06),y
dey
bpl L9624
return #$FF
L962F: sty $08
sty L9707
stx $08+1
stx L9708
lda selected_window_index
beq L964D
asl a
tax
copy16 window_path_addr_table,x, $06
jmp L9655
L964D: copy16 #L9705, $06
L9655: ldy #$00
lda ($06),y
tay
L965A: lda ($06),y
sta dst_path_buf,y
dey
bpl L965A
inc dst_path_buf
ldx dst_path_buf
lda #'/'
sta dst_path_buf,x
ldy #$00
lda ($08),y
sta L9709
L9674: inx
iny
lda ($08),y
sta dst_path_buf,x
cpy L9709
bne L9674
stx dst_path_buf
MLI_RELAY_CALL RENAME, rename_params
beq L969E
jsr JT_SHOW_ALERT0
bne L9696
jmp L9611
L9696: lda #$40
jsr L96F8
jmp L9618
L969E: lda #$40
jsr L96F8
ldx L9706
lda selected_icon_list,x
sta icon_param2
yax_call JT_ITK_RELAY, IconTK::ERASE_ICON, icon_param2
copy16 L9707, $08
ldx L9706
lda selected_icon_list,x
jsr icon_entry_name_lookup
ldy #$00
lda ($08),y
clc
adc #$02
sta ($06),y
lda ($08),y
tay
inc16 $06
L96DA: lda ($08),y
sta ($06),y
dey
bne L96DA
dec $06
lda $06
cmp #$FF
bne L96EB
dec $06+1
L96EB: lda ($06),y
tay
lda #' '
sta ($06),y
inc L9706
jmp L9576
L96F8: sta rename_dialog_params
yax_call invoke_dialog_proc, index_rename_dialog, rename_dialog_params
rts
L9705: .byte $00
L9706: .byte $00
L9707: .byte $00
L9708: .byte $00
L9709: .byte $00
.endproc
do_rename_icon := do_rename_icon_impl::start
;;; ============================================================
src_path_buf := $220
DEFINE_OPEN_PARAMS open_src_dir_params, src_path_buf, $800
DEFINE_READ_PARAMS read_src_dir_header_params, pointers_buf, 4 ; dir header: skip block pointers
pointers_buf: .res 4, 0
DEFINE_CLOSE_PARAMS close_src_dir_params
DEFINE_READ_PARAMS read_src_dir_entry_params, file_entry_buf, .sizeof(FileEntry)
DEFINE_READ_PARAMS read_src_dir_skip5_params, skip5_buf, 5 ; ???
skip5_buf: .res 5, 0
buf_size = $AC0
DEFINE_CLOSE_PARAMS close_src_params
DEFINE_CLOSE_PARAMS close_dst_params
DEFINE_DESTROY_PARAMS destroy_params, src_path_buf
DEFINE_OPEN_PARAMS open_src_params, src_path_buf, $0D00
DEFINE_OPEN_PARAMS open_dst_params, dst_path_buf, $1100
DEFINE_READ_PARAMS read_src_params, $1500, buf_size
DEFINE_WRITE_PARAMS write_dst_params, $1500, buf_size
DEFINE_CREATE_PARAMS create_params3, dst_path_buf, ACCESS_DEFAULT
DEFINE_CREATE_PARAMS create_params2, dst_path_buf
.byte 0,0
DEFINE_GET_FILE_INFO_PARAMS src_file_info_params, src_path_buf
DEFINE_GET_FILE_INFO_PARAMS dst_file_info_params, dst_path_buf
DEFINE_SET_EOF_PARAMS set_eof_params, 0
DEFINE_SET_MARK_PARAMS mark_src_params, 0
DEFINE_SET_MARK_PARAMS mark_dst_params, 0
DEFINE_ON_LINE_PARAMS on_line_params2,, $800
;;; ============================================================
file_entry_buf: .res .sizeof(FileEntry), 0
;; overlayed indirect jump table
op_jt_addrs_size := 6
op_jt_addrs:
op_jt_addr1: .addr copy_process_directory_entry ; defaults are for copy
op_jt_addr2: .addr copy_pop_directory
op_jt_addr3: .addr do_nothing
do_nothing: rts
L97E4: .byte $00
.proc push_entry_count
ldx entry_count_stack_index
lda entries_to_skip
sta entry_count_stack,x
inx
stx entry_count_stack_index
rts
.endproc
.proc pop_entry_count
ldx entry_count_stack_index
dex
lda entry_count_stack,x
sta entries_to_skip
stx entry_count_stack_index
rts
.endproc
.proc open_src_dir
lda #0
sta entries_read
sta entries_read_this_block
@retry: MLI_RELAY_CALL OPEN, open_src_dir_params
beq :+
ldx #$80
jsr JT_SHOW_ALERT
beq @retry
jmp close_files_cancel_dialog
: lda open_src_dir_params::ref_num
sta op_ref_num
sta read_src_dir_header_params::ref_num
@retry2:MLI_RELAY_CALL READ, read_src_dir_header_params
beq :+
ldx #$80
jsr JT_SHOW_ALERT
beq @retry2
jmp close_files_cancel_dialog
: jmp read_file_entry
.endproc
.proc close_src_dir
lda op_ref_num
sta close_src_dir_params::ref_num
@retry: MLI_RELAY_CALL CLOSE, close_src_dir_params
beq :+
ldx #$80
jsr JT_SHOW_ALERT
beq @retry
jmp close_files_cancel_dialog
: rts
.endproc
.proc read_file_entry
inc entries_read
lda op_ref_num
sta read_src_dir_entry_params::ref_num
@retry: MLI_RELAY_CALL READ, read_src_dir_entry_params
beq :+
cmp #ERR_END_OF_FILE
beq eof
ldx #$80
jsr JT_SHOW_ALERT
beq @retry
jmp close_files_cancel_dialog
: inc entries_read_this_block
lda entries_read_this_block
cmp num_entries_per_block
bcc :+
copy #0, entries_read_this_block
copy op_ref_num, read_src_dir_skip5_params::ref_num
MLI_RELAY_CALL READ, read_src_dir_skip5_params
: return #0
eof: return #$FF
.endproc
;;; ============================================================
.proc prep_to_open_dir
lda entries_read
sta entries_to_skip
jsr close_src_dir
jsr push_entry_count
jsr append_to_src_path
jmp open_src_dir
.endproc
;;; Given this tree with b,c,e selected:
;;; b
;;; c/
;;; d/
;;; e
;;; f
;;; Visit call sequence:
;;; * op_jt1 c
;;; * op_jt1 c/d
;;; * op_jt3 c/d
;;; * op_jt2 c
;;;
;;; Visiting individual files is done via direct calls, not the
;;; overlayed jump table. Order is:
;;;
;;; * call: b
;;; * op_jt1 on c
;;; * call: c/d
;;; * op_jt1 on c/d
;;; * call: c/d/e
;;; * op_jt3 on c/d
;;; * op_jt2 on c
;;; * call: c
;;; * call: f
;;; (3x final calls ???)
.proc finish_dir
jsr close_src_dir
jsr op_jt3 ; third - called when exiting dir
jsr remove_src_path_segment
jsr pop_entry_count
jsr open_src_dir
jsr sub
jmp op_jt2 ; second - called when exited dir
sub: lda entries_read
cmp entries_to_skip
beq done
jsr read_file_entry
jmp sub
done: rts
.endproc
.proc process_dir
copy #0, process_depth
jsr open_src_dir
loop: jsr read_file_entry
bne end_dir
addr_call adjust_fileentry_case, file_entry_buf
lda file_entry_buf + FileEntry::storage_type_name_length
beq loop
and #NAME_LENGTH_MASK
sta file_entry_buf
copy #0, cancel_descent_flag
jsr op_jt1 ; first - called when visiting dir
lda cancel_descent_flag
bne loop
lda file_entry_buf + FileEntry::file_type
cmp #FT_DIRECTORY
bne loop
jsr prep_to_open_dir
inc process_depth
jmp loop
end_dir:
lda process_depth
beq L9920
jsr finish_dir
dec process_depth
jmp loop
L9920: jmp close_src_dir
.endproc
cancel_descent_flag: .byte 0
op_jt1: jmp (op_jt_addr1)
op_jt2: jmp (op_jt_addr2)
op_jt3: jmp (op_jt_addr3)
;;; ============================================================
;;; "Copy" (including Drag/Drop/Move) files state and logic
;;; ============================================================
;;; copy_process_selected_file
;;; - called for each file in selection; calls process_dir to recurse
;;; copy_process_directory_entry
;;; - c/o process_dir for each file in dir; skips if dir, copies otherwise
;;; copy_pop_directory
;;; - c/o process_dir when exiting dir; pops path segment
;;; maybe_finish_file_move
;;; - c/o process_dir after exiting; deletes dir if moving
;;; Overlays for copy operation (op_jt_addrs)
callbacks_for_copy:
.addr copy_process_directory_entry
.addr copy_pop_directory
.addr maybe_finish_file_move
.enum CopyDialogLifecycle
open = 0
populate = 1
show = 2
exists = 3 ; show "file exists" prompt
too_large = 4 ; show "too large" prompt
close = 5
.endenum
.proc copy_dialog_params
phase: .byte 0
count: .addr 0
.addr src_path_buf
.addr dst_path_buf
.endproc
.proc do_copy_dialog_phase
copy #CopyDialogLifecycle::open, copy_dialog_params::phase
copy16 #copy_dialog_phase0_callback1, dialog_phase0_callback
copy16 #copy_dialog_phase1_callback1, dialog_phase1_callback
jmp run_copy_dialog_proc
.endproc
.proc copy_dialog_phase0_callback1
stax copy_dialog_params::count
copy #CopyDialogLifecycle::populate, copy_dialog_params::phase
jmp run_copy_dialog_proc
.endproc
.proc prep_callbacks_for_copy
ldy #op_jt_addrs_size-1
: copy callbacks_for_copy,y, op_jt_addrs,y
dey
bpl :-
lda #0
sta LA425
sta all_flag
rts
.endproc
.proc copy_dialog_phase1_callback1
copy #CopyDialogLifecycle::close, copy_dialog_params::phase
jmp run_copy_dialog_proc
.endproc
.proc do_download_dialog_phase
copy #CopyDialogLifecycle::open, copy_dialog_params::phase
copy16 #copy_dialog_phase0_callback2, dialog_phase0_callback
copy16 #copy_dialog_phase1_callback2, dialog_phase1_callback
yax_call invoke_dialog_proc, index_download_dialog, copy_dialog_params
rts
.endproc
.proc copy_dialog_phase0_callback2
stax copy_dialog_params::count
copy #CopyDialogLifecycle::populate, copy_dialog_params::phase
yax_call invoke_dialog_proc, index_download_dialog, copy_dialog_params
rts
.endproc
.proc L99BC
copy #$80, all_flag
ldy #op_jt_addrs_size-1
: copy callbacks_for_copy,y, op_jt_addrs,y
dey
bpl :-
copy #0, LA425
copy16 #copy_dialog_phase3_callback, dialog_phase3_callback
rts
.endproc
.proc copy_dialog_phase1_callback2
copy #CopyDialogLifecycle::exists, copy_dialog_params::phase
yax_call invoke_dialog_proc, index_download_dialog, copy_dialog_params
rts
.endproc
.proc copy_dialog_phase3_callback
copy #CopyDialogLifecycle::too_large, copy_dialog_params::phase
yax_call invoke_dialog_proc, index_download_dialog, copy_dialog_params
cmp #PromptResult::yes
bne cancel
rts
.endproc
cancel: jmp close_files_cancel_dialog
;;; ============================================================
;;; Handle copying of a selected file.
;;; Calls into the recursion logic of |process_dir| as necessary.
.proc copy_process_selected_file
copy #$80, LE05B
copy #0, delete_skip_decrement_flag
beq :+ ; always
for_run:
lda #$FF
: sta is_run_flag
copy #CopyDialogLifecycle::show, copy_dialog_params::phase
jsr copy_paths_to_src_and_dst_paths
bit operation_flags
bvc @not_run
jsr check_vol_blocks_free ; dst is a volume path (RAM Card)
@not_run:
bit LE05B
bpl get_src_info ; never taken ???
bvs L9A50
lda is_run_flag
bne :+
lda selected_window_index ; dragging from window?
bne :+
jmp copy_dir
: ldx dst_path_buf
ldy src_path_slash_index
dey
: iny
inx
lda src_path_buf,y
sta dst_path_buf,x
cpy src_path_buf
bne :-
stx dst_path_buf
jmp get_src_info
;; Append filename to dst_path_buf
L9A50: ldx dst_path_buf
lda #'/'
sta dst_path_buf+1,x
inc dst_path_buf
ldy #0
ldx dst_path_buf
: iny
inx
lda filename_buf,y
sta dst_path_buf,x
cpy filename_buf
bne :-
stx dst_path_buf
get_src_info:
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
: lda src_file_info_params::storage_type
cmp #ST_VOLUME_DIRECTORY
beq is_dir
cmp #ST_LINKED_DIRECTORY
beq is_dir
lda #$00
beq store
is_dir: jsr decrement_op_file_count
lda #$FF
store: sta is_dir_flag
jsr dec_file_count_and_run_copy_dialog_proc
;; Copy access, file_type, aux_type, storage_type
ldy #7
: lda src_file_info_params,y
sta create_params2,y
dey
cpy #2
bne :-
copy #ACCESS_DEFAULT, create_params2::access
lda LE05B
beq create_ok ; never taken ???
jsr check_space_and_show_prompt
bcs done
;; Copy create_time/create_date
ldy #17
ldx #11
: lda src_file_info_params,y
sta create_params2,x
dex
dey
cpy #13
bne :-
;; If a volume, need to create a subdir instead
lda create_params2::storage_type
cmp #ST_VOLUME_DIRECTORY
bne do_create
lda #ST_LINKED_DIRECTORY
sta create_params2::storage_type
do_create:
MLI_RELAY_CALL CREATE, create_params2
beq create_ok
cmp #ERR_DUPLICATE_FILENAME
bne err
bit all_flag
bmi do_it
copy #CopyDialogLifecycle::exists, copy_dialog_params::phase
jsr run_copy_dialog_proc
pha
copy #CopyDialogLifecycle::show, copy_dialog_params::phase
pla
cmp #PromptResult::yes
beq do_it
cmp #PromptResult::no
beq done
cmp #PromptResult::all
bne cancel
copy #$80, all_flag
do_it: jsr apply_file_info_and_size
jmp create_ok
;; PromptResult::cancel
cancel: jmp close_files_cancel_dialog
err: jsr show_error_alert
jmp do_create ; retry
create_ok:
lda is_dir_flag
beq copy_file
copy_dir: ; also used when dragging a volume icon
jsr process_dir
jmp maybe_finish_file_move
done: rts
copy_file:
jsr do_file_copy
jmp maybe_finish_file_move
is_dir_flag:
.byte 0
is_run_flag:
.byte 0
.endproc
copy_file_for_run := copy_process_selected_file::for_run
;;; ============================================================
src_path_slash_index:
.byte 0
;;; ============================================================
copy_pop_directory:
jmp remove_dst_path_segment
;;; ============================================================
;;; If moving, delete src file/directory.
.proc maybe_finish_file_move
;; Copy or move?
bit move_flag
bpl done
;; Was a move - delete file
@retry: MLI_RELAY_CALL DESTROY, destroy_params
beq done
cmp #ERR_ACCESS_ERROR
bne :+
jsr unlock_src_file
beq @retry
bne done ; silently leave file
: jsr show_error_alert
jmp @retry
done: rts
.endproc
;;; ============================================================
;;; Called by |process_dir| to process a single file
.proc copy_process_directory_entry
jsr check_escape_key_down
beq :+
jmp close_files_cancel_dialog
: lda file_entry_buf + FileEntry::file_type
cmp #FT_DIRECTORY
bne regular_file
;; Directory
jsr append_to_src_path
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
: jsr append_to_dst_path
jsr dec_file_count_and_run_copy_dialog_proc
jsr decrement_op_file_count
jsr try_create_dst
bcs :+
jsr remove_src_path_segment
jmp done
: jsr remove_dst_path_segment
jsr remove_src_path_segment
copy #$FF, cancel_descent_flag
jmp done
;; File
regular_file:
jsr append_to_dst_path
jsr append_to_src_path
jsr dec_file_count_and_run_copy_dialog_proc
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
: jsr check_space_and_show_prompt
bcc :+
jmp close_files_cancel_dialog
: jsr remove_src_path_segment
jsr try_create_dst
bcs :+
jsr append_to_src_path
jsr do_file_copy
jsr maybe_finish_file_move
jsr remove_src_path_segment
: jsr remove_dst_path_segment
done: rts
.endproc
;;; ============================================================
.proc run_copy_dialog_proc
yax_call invoke_dialog_proc, index_copy_dialog, copy_dialog_params
rts
.endproc
;;; ============================================================
.proc check_vol_blocks_free
@retry: MLI_RELAY_CALL GET_FILE_INFO, dst_file_info_params
beq :+
jsr show_error_alert_dst
jmp @retry
: sub16 dst_file_info_params::aux_type, dst_file_info_params::blocks_used, blocks_free
cmp16 blocks_free, op_block_count
bcs :+
jmp done_dialog_phase3
: rts
blocks_free:
.word 0
.endproc
;;; ============================================================
.proc check_space_and_show_prompt
jsr check_space
bcc done
copy #CopyDialogLifecycle::too_large, copy_dialog_params::phase
jsr run_copy_dialog_proc
beq :+
jmp close_files_cancel_dialog
: copy #CopyDialogLifecycle::exists, copy_dialog_params::phase
sec
done: rts
.proc check_space
;; Size of source
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
;; If destination doesn't exist, 0 blocks will be reclaimed.
: lda #0
sta existing_size
sta existing_size+1
;; Does destination exist?
@retry2:MLI_RELAY_CALL GET_FILE_INFO, dst_file_info_params
beq got_exist_size
cmp #ERR_FILE_NOT_FOUND
beq :+
jsr show_error_alert_dst ; retry if destination not present
jmp @retry2
got_exist_size:
copy16 dst_file_info_params::blocks_used, existing_size
;; Compute destination volume path
: lda dst_path_buf
sta saved_length
ldy #1 ; search for second '/'
: iny
cpy dst_path_buf
bcs has_room
lda dst_path_buf,y
cmp #'/'
bne :-
tya
sta dst_path_buf
sta vol_path_length
;; Total blocks/used blocks on destination volume
@retry: MLI_RELAY_CALL GET_FILE_INFO, dst_file_info_params
beq got_info
pha ; on failure, restore path
lda saved_length ; in case copy is aborted
sta dst_path_buf
pla
jsr show_error_alert_dst
jmp @retry ; BUG: Does this need to assign length again???
got_info:
;; aux = total blocks
sub16 dst_file_info_params::aux_type, dst_file_info_params::blocks_used, blocks_free
add16 blocks_free, existing_size, blocks_free
cmp16 blocks_free, src_file_info_params::blocks_used
bcs has_room
;; not enough room
sec
bcs :+
has_room:
clc
: lda saved_length
sta dst_path_buf
rts
blocks_free:
.word 0
saved_length:
.byte 0
vol_path_length:
.byte 0
existing_size:
.word 0
.endproc
.endproc
;;; ============================================================
;;; Actual byte-for-byte file copy routine
.proc do_file_copy
jsr decrement_op_file_count
lda #0
sta src_dst_exclusive_flag
sta src_eof_flag
sta mark_src_params::position
sta mark_src_params::position+1
sta mark_src_params::position+2
sta mark_dst_params::position
sta mark_dst_params::position+1
sta mark_dst_params::position+2
jsr open_src
jsr copy_src_ref_num
jsr open_dst
beq :+
;; Destination not available; note it, can prompt later
copy #$FF, src_dst_exclusive_flag
bne read ; always
: jsr copy_dst_ref_num
;; Read
read: jsr read_src
bit src_dst_exclusive_flag
bpl write
jsr close_src ; swap if necessary
: jsr open_dst
bne :-
jsr copy_dst_ref_num
MLI_RELAY_CALL SET_MARK, mark_dst_params
;; Write
write: bit src_eof_flag
bmi eof
jsr write_dst
bit src_dst_exclusive_flag
bpl read
jsr close_dst ; swap if necessary
jsr open_src
jsr copy_src_ref_num
MLI_RELAY_CALL SET_MARK, mark_src_params
beq read
copy #$FF, src_eof_flag
jmp read
;; EOF
eof: jsr close_dst
bit src_dst_exclusive_flag
bmi :+
jsr close_src
: jsr copy_file_info
jmp set_dst_file_info
.proc open_src
@retry: MLI_RELAY_CALL OPEN, open_src_params
beq :+
jsr show_error_alert
jmp @retry
: rts
.endproc
.proc copy_src_ref_num
lda open_src_params::ref_num
sta read_src_params::ref_num
sta close_src_params::ref_num
sta mark_src_params::ref_num
rts
.endproc
.proc open_dst
@retry: MLI_RELAY_CALL OPEN, open_dst_params
beq done
cmp #ERR_VOL_NOT_FOUND
beq not_found
jsr show_error_alert_dst
jmp @retry
not_found:
jsr show_error_alert_dst
lda #ERR_VOL_NOT_FOUND
done: rts
.endproc
.proc copy_dst_ref_num
lda open_dst_params::ref_num
sta write_dst_params::ref_num
sta close_dst_params::ref_num
sta mark_dst_params::ref_num
rts
.endproc
.proc read_src
copy16 #buf_size, read_src_params::request_count
@retry: MLI_RELAY_CALL READ, read_src_params
beq :+
cmp #ERR_END_OF_FILE
beq eof
jsr show_error_alert
jmp @retry
: copy16 read_src_params::trans_count, write_dst_params::request_count
ora read_src_params::trans_count
bne :+
eof: copy #$FF, src_eof_flag
: MLI_RELAY_CALL GET_MARK, mark_src_params
rts
.endproc
.proc write_dst
@retry: MLI_RELAY_CALL WRITE, write_dst_params
beq :+
jsr show_error_alert_dst
jmp @retry
: MLI_RELAY_CALL GET_MARK, mark_dst_params
rts
.endproc
.proc close_dst
MLI_RELAY_CALL CLOSE, close_dst_params
rts
.endproc
.proc close_src
MLI_RELAY_CALL CLOSE, close_src_params
rts
.endproc
;; Set if src/dst can't be open simultaneously.
src_dst_exclusive_flag:
.byte 0
src_eof_flag:
.byte 0
.endproc
;;; ============================================================
.proc try_create_dst
;; Copy file_type, aux_type, storage_type
ldx #7
: lda src_file_info_params,x
sta create_params3,x
dex
cpx #3
bne :-
create: MLI_RELAY_CALL CREATE, create_params3
beq success
cmp #ERR_DUPLICATE_FILENAME
bne err
bit all_flag
bmi yes
copy #CopyDialogLifecycle::exists, copy_dialog_params::phase
yax_call invoke_dialog_proc, index_copy_dialog, copy_dialog_params
pha
copy #CopyDialogLifecycle::show, copy_dialog_params::phase
pla
cmp #PromptResult::yes
beq yes
cmp #PromptResult::no
beq failure
cmp #PromptResult::all
bne cancel
copy #$80, all_flag
yes: jsr apply_file_info_and_size
jmp success
cancel: jmp close_files_cancel_dialog
err: jsr show_error_alert_dst
jmp create
success:
clc
rts
failure:
sec
rts
.endproc
;;; ============================================================
;;; Delete/Trash files dialog state and logic
;;; ============================================================
;;; delete_process_selected_file
;;; - called for each file in selection; calls process_dir to recurse
;;; delete_process_directory_entry
;;; - c/o process_dir for each file in dir; skips if dir, deletes otherwise
;;; delete_finish_directory
;;; - c/o process_dir when exiting dir; deletes it
;;; Overlays for delete operation (op_jt_addrs)
callbacks_for_delete:
.addr delete_process_directory_entry
.addr do_nothing
.addr delete_finish_directory
.proc delete_dialog_params
phase: .byte 0
count: .word 0
.addr src_path_buf
.endproc
.proc do_delete_dialog_phase
sta delete_dialog_params::phase
copy16 #confirm_delete_dialog, dialog_phase2_callback
copy16 #populate_delete_dialog, dialog_phase0_callback
jsr run_delete_dialog_proc
copy16 #L9ED3, dialog_phase1_callback
rts
.proc populate_delete_dialog
stax delete_dialog_params::count
copy #DeleteDialogLifecycle::populate, delete_dialog_params::phase
jmp run_delete_dialog_proc
.endproc
.proc confirm_delete_dialog
copy #DeleteDialogLifecycle::confirm, delete_dialog_params::phase
jsr run_delete_dialog_proc
beq :+
jmp close_files_cancel_dialog
: rts
.endproc
.endproc
;;; ============================================================
.proc prep_callbacks_for_delete
ldy #op_jt_addrs_size-1
: copy callbacks_for_delete,y, op_jt_addrs,y
dey
bpl :-
lda #0
sta LA425
sta all_flag
rts
.endproc
.proc L9ED3
copy #DeleteDialogLifecycle::close, delete_dialog_params::phase
jmp run_delete_dialog_proc
.endproc
;;; ============================================================
;;; Handle deletion of a selected file.
;;; Calls into the recursion logic of |process_dir| as necessary.
.proc delete_process_selected_file
copy #DeleteDialogLifecycle::show, delete_dialog_params::phase
jsr copy_paths_to_src_and_dst_paths
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
;; Check if it's a regular file or directory
: lda src_file_info_params::storage_type
sta storage_type
cmp #ST_LINKED_DIRECTORY
beq :+
lda #0
beq store
: lda #$FF
store: sta is_dir_flag
beq do_destroy
;; Recurse, and process directory
jsr process_dir
;; Was it a directory?
lda storage_type
cmp #ST_LINKED_DIRECTORY
bne :+
copy #$FF, storage_type ; is this re-checked?
: jmp do_destroy
;; Written, not read???
is_dir_flag:
.byte 0
storage_type:
.byte 0
do_destroy:
bit delete_skip_decrement_flag
bmi :+
jsr dec_file_count_and_run_delete_dialog_proc
: jsr decrement_op_file_count
retry: MLI_RELAY_CALL DESTROY, destroy_params
beq done
cmp #ERR_ACCESS_ERROR
bne error
bit all_flag
bmi do_it
copy #DeleteDialogLifecycle::locked, delete_dialog_params::phase
jsr run_delete_dialog_proc
pha
copy #DeleteDialogLifecycle::show, delete_dialog_params::phase
pla
cmp #PromptResult::no
beq done
cmp #PromptResult::yes
beq do_it
cmp #PromptResult::all
bne :+
copy #$80, all_flag
bne do_it ; always
: jmp close_files_cancel_dialog
do_it: jsr unlock_src_file
bne done
jmp retry
done: rts
error: jsr show_error_alert
jmp retry
.endproc
.proc unlock_src_file
MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
lda src_file_info_params::access
and #$80
bne done
lda #ACCESS_DEFAULT
sta src_file_info_params::access
copy #7, src_file_info_params ; param count for SET_FILE_INFO
MLI_RELAY_CALL SET_FILE_INFO, src_file_info_params
copy #$A, src_file_info_params ; param count for GET_FILE_INFO
lda #0 ; success
done: rts
.endproc
;;; ============================================================
;;; Called by |process_dir| to process a single file
.proc delete_process_directory_entry
;; Cancel if escape pressed
jsr check_escape_key_down
beq :+
jmp close_files_cancel_dialog
: jsr append_to_src_path
bit delete_skip_decrement_flag
bmi :+
jsr dec_file_count_and_run_delete_dialog_proc
: jsr decrement_op_file_count
;; Check file type
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
;; Directories will be processed separately
: lda src_file_info_params::storage_type
cmp #ST_LINKED_DIRECTORY
beq next_file
loop: MLI_RELAY_CALL DESTROY, destroy_params
beq next_file
cmp #ERR_ACCESS_ERROR
bne err
bit all_flag
bmi unlock
copy #DeleteDialogLifecycle::locked, delete_dialog_params::phase
yax_call invoke_dialog_proc, index_delete_dialog, delete_dialog_params
pha
copy #DeleteDialogLifecycle::show, delete_dialog_params::phase
pla
cmp #PromptResult::no
beq next_file
cmp #PromptResult::yes
beq unlock
cmp #PromptResult::all
bne :+
copy #$80, all_flag
bne unlock ; always
;; PromptResult::cancel
: jmp close_files_cancel_dialog
unlock: copy #ACCESS_DEFAULT, src_file_info_params::access
copy #7, src_file_info_params ; param count for SET_FILE_INFO
MLI_RELAY_CALL SET_FILE_INFO, src_file_info_params
copy #$A,src_file_info_params ; param count for GET_FILE_INFO
jmp loop
err: jsr show_error_alert
jmp loop
next_file:
jmp remove_src_path_segment
.endproc
;;; ============================================================
;;; Delete directory when exiting via traversal
.proc delete_finish_directory
@retry: MLI_RELAY_CALL DESTROY, destroy_params
beq done
cmp #ERR_ACCESS_ERROR
beq done
jsr show_error_alert
jmp @retry
done: rts
.endproc
.proc run_delete_dialog_proc
yax_call invoke_dialog_proc, index_delete_dialog, delete_dialog_params
rts
.endproc
;;; ============================================================
;;; "Lock"/"Unlock" dialog state and logic
;;; ============================================================
;;; lock_process_selected_file
;;; - called for each file in selection; calls process_dir to recurse
;;; lock_process_directory_entry
;;; - c/o process_dir for each file in dir; skips if dir, locks otherwise
;;; Overlays for lock/unlock operation (op_jt_addrs)
callbacks_for_lock:
.addr lock_process_directory_entry
.addr do_nothing
.addr do_nothing
.enum LockDialogLifecycle
open = 0 ; opening window, initial label
populate = 1 ; show operation details (e.g. file count)
loop = 2 ; draw buttons, input loop
operation = 3 ; performing operation
close = 4 ; destroy window
.endenum
.proc lock_unlock_dialog_params
phase: .byte 0
files_remaining_count:
.word 0
.addr src_path_buf
.endproc
.proc do_lock_dialog_phase
copy #LockDialogLifecycle::open, lock_unlock_dialog_params::phase
bit unlock_flag
bpl :+
;; Unlock
copy16 #unlock_dialog_phase2_callback, dialog_phase2_callback
copy16 #unlock_dialog_phase0_callback, dialog_phase0_callback
jsr unlock_dialog_lifecycle
copy16 #close_unlock_dialog, dialog_phase1_callback
rts
;; Lock
: copy16 #lock_dialog_phase2_callback, dialog_phase2_callback
copy16 #lock_dialog_phase0_callback, dialog_phase0_callback
jsr lock_dialog_lifecycle
copy16 #close_lock_dialog, dialog_phase1_callback
rts
.endproc
.proc lock_dialog_phase0_callback
stax lock_unlock_dialog_params::files_remaining_count
copy #LockDialogLifecycle::populate, lock_unlock_dialog_params::phase
jmp lock_dialog_lifecycle
.endproc
.proc unlock_dialog_phase0_callback
stax lock_unlock_dialog_params::files_remaining_count
copy #LockDialogLifecycle::populate, lock_unlock_dialog_params::phase
jmp unlock_dialog_lifecycle
.endproc
.proc lock_dialog_phase2_callback
copy #LockDialogLifecycle::loop, lock_unlock_dialog_params::phase
jsr lock_dialog_lifecycle
beq :+
jmp close_files_cancel_dialog
: rts
.endproc
.proc unlock_dialog_phase2_callback
copy #LockDialogLifecycle::loop, lock_unlock_dialog_params::phase
jsr unlock_dialog_lifecycle
beq :+
jmp close_files_cancel_dialog
: rts
.endproc
.proc prep_callbacks_for_lock
copy #0, LA425
ldy #op_jt_addrs_size-1
: copy callbacks_for_lock,y, op_jt_addrs,y
dey
bpl :-
rts
.endproc
.proc close_lock_dialog
copy #LockDialogLifecycle::close, lock_unlock_dialog_params::phase
jmp lock_dialog_lifecycle
.endproc
.proc close_unlock_dialog
copy #LockDialogLifecycle::close, lock_unlock_dialog_params::phase
jmp unlock_dialog_lifecycle
.endproc
lock_dialog_lifecycle:
yax_call invoke_dialog_proc, index_lock_dialog, lock_unlock_dialog_params
rts
unlock_dialog_lifecycle:
yax_call invoke_dialog_proc, index_unlock_dialog, lock_unlock_dialog_params
rts
;;; ============================================================
;;; Handle locking of a selected file.
;;; Calls into the recursion logic of |process_dir| as necessary.
.proc lock_process_selected_file
copy #LockDialogLifecycle::operation, lock_unlock_dialog_params::phase
jsr copy_paths_to_src_and_dst_paths
ldx dst_path_buf
ldy src_path_slash_index
dey
LA123: iny
inx
lda src_path_buf,y
sta dst_path_buf,x
cpy src_path_buf
bne LA123
stx dst_path_buf
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
: lda src_file_info_params::storage_type
sta storage_type
cmp #ST_VOLUME_DIRECTORY
beq is_dir
cmp #ST_LINKED_DIRECTORY
beq is_dir
lda #$00
beq store
is_dir: lda #$FF
store: sta is_dir_flag
beq do_lock
;; Process files in directory
jsr process_dir
;; If this wasn't a volume directory, lock it too
lda storage_type
cmp #ST_VOLUME_DIRECTORY
bne do_lock
rts
;; Written, not read???
is_dir_flag:
.byte 0
storage_type:
.byte 0
do_lock:
jsr lock_file_common
jmp append_to_src_path
.endproc
;;; ============================================================
;;; Called by |process_dir| to process a single file
lock_process_directory_entry:
jsr append_to_src_path
;; fall through
.proc lock_file_common
jsr update_dialog
jsr decrement_op_file_count
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
: lda src_file_info_params::storage_type
cmp #ST_VOLUME_DIRECTORY
beq ok
cmp #ST_LINKED_DIRECTORY
beq ok
bit unlock_flag
bpl :+
lda #ACCESS_DEFAULT
bne set
: lda #ACCESS_LOCKED
set: sta src_file_info_params::access
: copy #7, src_file_info_params ; param count for SET_FILE_INFO
MLI_RELAY_CALL SET_FILE_INFO, src_file_info_params
pha
copy #$A, src_file_info_params ; param count for GET_FILE_INFO
pla
beq ok
jsr show_error_alert
jmp :-
ok: jmp remove_src_path_segment
update_dialog:
sub16 op_file_count, #1, lock_unlock_dialog_params::files_remaining_count
bit unlock_flag
bpl LA1DC
jmp unlock_dialog_lifecycle
LA1DC: jmp lock_dialog_lifecycle
.endproc
;;; ============================================================
;;; "Get Size" dialog state and logic
;;; ============================================================
;;; Logic also used for "count" operation which precedes most
;;; other operations (copy, delete, lock, unlock) to populate
;;; confirmation dialog.
.proc get_size_dialog_params
phase: .byte 0
.addr op_file_count, op_block_count
.endproc
do_get_size_dialog_phase:
copy #0, get_size_dialog_params::phase
copy16 #get_size_dialog_phase2_callback, dialog_phase2_callback
copy16 #get_size_dialog_phase0_callback, dialog_phase0_callback
yax_call invoke_dialog_proc, index_get_size_dialog, get_size_dialog_params
copy16 #get_size_dialog_phase1_callback, dialog_phase1_callback
rts
.proc get_size_dialog_phase0_callback
copy #1, get_size_dialog_params::phase
yax_call invoke_dialog_proc, index_get_size_dialog, get_size_dialog_params
;; fall through
.endproc
get_size_rts1:
rts
.proc get_size_dialog_phase2_callback
copy #2, get_size_dialog_params::phase
yax_call invoke_dialog_proc, index_get_size_dialog, get_size_dialog_params
beq get_size_rts1
jmp close_files_cancel_dialog
.endproc
.proc get_size_dialog_phase1_callback
copy #3, get_size_dialog_params::phase
yax_call invoke_dialog_proc, index_get_size_dialog, get_size_dialog_params
.endproc
get_size_rts2:
rts
;;; ============================================================
;;; Most operations start by doing a traversal to just count
;;; the files.
;;; Overlays for size operation (op_jt_addrs)
callbacks_for_size_or_count:
.addr size_or_count_process_directory_entry
.addr do_nothing
.addr do_nothing
.proc prep_callbacks_for_size_or_count
copy #0, LA425
ldy #op_jt_addrs_size-1
: copy callbacks_for_size_or_count,y, op_jt_addrs,y
dey
bpl :-
lda #0
sta op_file_count
sta op_file_count+1
sta op_block_count
sta op_block_count+1
rts
.endproc
;;; ============================================================
;;; Handle sizing (or just counting) of a selected file.
;;; Calls into the recursion logic of |process_dir| as necessary.
.proc size_or_count_process_selected_file
jsr copy_paths_to_src_and_dst_paths
@retry: MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
beq :+
jsr show_error_alert
jmp @retry
: copy src_file_info_params::storage_type, storage_type
cmp #ST_VOLUME_DIRECTORY
beq is_dir
cmp #ST_LINKED_DIRECTORY
beq is_dir
lda #0
beq store ; always
is_dir: lda #$FF
store: sta is_dir_flag
beq do_sum_file_size ; if not a dir
jsr process_dir
lda storage_type
cmp #ST_VOLUME_DIRECTORY
bne do_sum_file_size ; if a subdirectory
rts
;; Written, not read???
is_dir_flag:
.byte 0
storage_type:
.byte 0
do_sum_file_size:
jmp size_or_count_process_directory_entry
.endproc
;;; ============================================================
;;; Called by |process_dir| to process a single file
size_or_count_process_directory_entry:
bit operation_flags
bvc :+ ; not size
;; If operation is "get size", add the block count to the sum
jsr append_to_src_path
MLI_RELAY_CALL GET_FILE_INFO, src_file_info_params
bne :+
add16 op_block_count, src_file_info_params::blocks_used, op_block_count
: inc16 op_file_count
bit operation_flags
bvc :+ ; not size
jsr remove_src_path_segment
: ldax op_file_count
jmp done_dialog_phase0
op_file_count:
.word 0
op_block_count:
.word 0
;;; ============================================================
.proc decrement_op_file_count
dec16 op_file_count
rts
.endproc
;;; ============================================================
;;; Append name at file_entry_buf to path at src_path_buf
.proc append_to_src_path
path := src_path_buf
lda file_entry_buf
bne :+
rts
: ldx #0
ldy path
copy #'/', path+1,y
iny
loop: cpx file_entry_buf
bcs done
lda file_entry_buf+1,x
sta path+1,y
inx
iny
jmp loop
done: sty path
rts
.endproc
;;; ============================================================
;;; Remove segment from path at src_path_buf
.proc remove_src_path_segment
path := src_path_buf
ldx path ; length
bne :+
rts
: lda path,x
cmp #'/'
beq found
dex
bne :-
stx path
rts
found: dex
stx path
rts
.endproc
;;; ============================================================
;;; Append name at file_entry_buf to path at dst_path_buf
.proc append_to_dst_path
path := dst_path_buf
lda file_entry_buf
bne :+
rts
: ldx #0
ldy path
copy #'/', path+1,y
iny
loop: cpx file_entry_buf
bcs done
lda file_entry_buf+1,x
sta path+1,y
inx
iny
jmp loop
done: sty path
rts
.endproc
;;; ============================================================
;;; Remove segment from path at dst_path_buf
.proc remove_dst_path_segment
path := dst_path_buf
ldx path ; length
bne :+
rts
: lda path,x
cmp #'/'
beq found
dex
bne :-
stx path
rts
found: dex
stx path
rts
.endproc
;;; ============================================================
;;; Copy path_buf3 to src_path_buf, path_buf4 to dst_path_buf
;;; and note last '/' in src.
.proc copy_paths_to_src_and_dst_paths
ldy #0
sty src_path_slash_index
dey
;; Copy path_buf3 to src_path_buf
;; ... but record index of last '/'
loop: iny
lda path_buf3,y
cmp #'/'
bne :+
sty src_path_slash_index
: sta src_path_buf,y
cpy path_buf3
bne loop
;; Copy path_buf4 to dst_path_buf
ldy path_buf4
: lda path_buf4,y
sta dst_path_buf,y
dey
bpl :-
rts
.endproc
;;; ============================================================
;;; Closes dialog, closes all open files, and restores stack.
.proc close_files_cancel_dialog
jsr done_dialog_phase1
jmp :+
DEFINE_CLOSE_PARAMS close_params
: MLI_RELAY_CALL CLOSE, close_params
lda selected_window_index
beq :+
sta getwinport_params2::window_id
yax_call JT_MGTK_RELAY, MGTK::GetWinPort, getwinport_params2
yax_call JT_MGTK_RELAY, MGTK::SetPort, grafport2
: ldx stack_stash ; restore stack, in case recusion was aborted
txs
return #$FF
.endproc
;;; ============================================================
;;; Move or Copy? Compare src/dst paths, same vol = move.
;;; Output: A=high bit set if move, clear if copy
.proc check_move_or_copy
src_ptr := $08
dst_buf := path_buf4
bit BUTN0 ; Open-Apple overrides, forces copy
bmi no_match
ldy #0
lda (src_ptr),y
sta src_len
iny ; skip leading '/'
bne check ; always
;; Chars the same?
loop: lda (src_ptr),y
cmp dst_buf,y
bne no_match
;; Same and a slash?
cmp #'/'
beq match
;; End of src?
check: cpy src_len
bcc :+
cpy dst_buf ; dst also done?
bcs match
lda path_buf4+1,y ; is next char in dst a slash?
bne check_slash ; always
: cpy dst_buf ; src is not done, is dst?
bcc :+
iny
lda (src_ptr),y ; is next char in src a slash?
bne check_slash ; always
: iny ; next char
bne loop ; always
check_slash:
cmp #'/'
beq match ; if so, same vol
;; fall through
no_match:
return #0
match: return #$80
src_len:
.byte 0
.endproc
;;; ============================================================
.proc check_escape_key_down
yax_call JT_MGTK_RELAY, MGTK::GetEvent, event_params
lda event_kind
cmp #MGTK::EventKind::key_down
bne nope
lda event_key
cmp #CHAR_ESCAPE
bne nope
lda #$FF
bne done
nope: lda #$00
done: rts
.endproc
;;; ============================================================
.proc dec_file_count_and_run_delete_dialog_proc
sub16 op_file_count, #1, delete_dialog_params::count
yax_call invoke_dialog_proc, index_delete_dialog, delete_dialog_params
rts
.endproc
.proc dec_file_count_and_run_copy_dialog_proc
sub16 op_file_count, #1, copy_dialog_params::count
yax_call invoke_dialog_proc, index_copy_dialog, copy_dialog_params
rts
.endproc
LA425: .byte 0 ; ??? only written to (with 0)
;;; ============================================================
.proc apply_file_info_and_size
: jsr copy_file_info
copy #ACCESS_DEFAULT, dst_file_info_params::access
jsr set_dst_file_info
lda src_file_info_params::file_type
cmp #FT_DIRECTORY
beq done
;; If a regular file, open/set eof/close
MLI_RELAY_CALL OPEN, open_dst_params
beq :+
jsr show_error_alert_dst
jmp :- ; retry
: lda open_dst_params::ref_num
sta set_eof_params::ref_num
sta close_dst_params::ref_num
@retry: MLI_RELAY_CALL SET_EOF, set_eof_params
beq close
jsr show_error_alert_dst
jmp @retry
close: MLI_RELAY_CALL CLOSE, close_dst_params
done: rts
.endproc
.proc copy_file_info
COPY_BYTES 11, src_file_info_params::access, dst_file_info_params::access
rts
.endproc
.proc set_dst_file_info
: copy #7, dst_file_info_params ; SET_FILE_INFO param_count
MLI_RELAY_CALL SET_FILE_INFO, dst_file_info_params
pha
copy #$A, dst_file_info_params ; GET_FILE_INFO param_count
pla
beq done
jsr show_error_alert_dst
jmp :-
done: rts
.endproc
;;; ============================================================
;;; Show Alert Dialog
;;; A=error. If ERR_VOL_NOT_FOUND or ERR_FILE_NOT_FOUND, will
;;; show "please insert source disk" (or destination, if flag set)
.proc show_error_alert_impl
flag_set:
ldx #$80
bne :+
flag_clear:
ldx #0
: stx flag
cmp #ERR_VOL_NOT_FOUND ; if err is "not found"
beq not_found ; prompt specifically for src/dst disk
cmp #ERR_PATH_NOT_FOUND
beq not_found
jsr JT_SHOW_ALERT0
bne LA4C2 ; cancel???
rts
not_found:
bit flag
bpl :+
lda #ERR_INSERT_DST_DISK
jmp show
: lda #ERR_INSERT_SRC_DISK
show: jsr JT_SHOW_ALERT0
bne LA4C2
jmp do_on_line
LA4C2: jmp close_files_cancel_dialog
flag: .byte 0
do_on_line:
MLI_RELAY_CALL ON_LINE, on_line_params2
rts
.endproc
show_error_alert := show_error_alert_impl::flag_clear
show_error_alert_dst := show_error_alert_impl::flag_set
;;; ============================================================
;;; Reformat /RAM (Slot 3, Drive 2) if present
;;; Assumes ROM is banked in, restores it when complete. Also
;;; assumes hires screen (main and aux) are safe to destroy.
.proc maybe_reformat_ram
ram_unit_number = (1<<7 | 3<<4 | DT_RAM)
;; Search DEVLST to see if S3D2 RAM was restored
ldx DEVCNT
: lda DEVLST,x
cmp #ram_unit_number
beq format
dex
bpl :-
rts
;; NOTE: Assumes driver (in DEVADR) was not modified
;; when detached.
;; /RAM FORMAT call; see ProDOS 8 TRM 5.2.2.4 for details
format: copy #DRIVER_COMMAND_FORMAT, DRIVER_COMMAND
copy #ram_unit_number, DRIVER_UNIT_NUMBER
copy16 #$2000, DRIVER_BUFFER
lda LCBANK1
lda LCBANK1
jsr driver
sta ROMIN2
rts
RAMSLOT := DEVADR + $16 ; Slot 3, Drive 2
driver: jmp (RAMSLOT)
.endproc
;;; ============================================================
;;; Determine if mouse moved (returns w/ carry set if moved)
;;; Used in dialogs to possibly change cursor
.proc check_mouse_moved
ldx #.sizeof(MGTK::Point)-1
: lda event_coords,x
cmp coords,x
bne diff
dex
bpl :-
clc
rts
diff: COPY_STRUCT MGTK::Point, event_coords, coords
sec
rts
coords: DEFINE_POINT 0,0
.endproc
;;; ============================================================
PAD_TO $A500
;;; ============================================================
;;; Dialog Launcher (or just proc handler???)
index_about_dialog = 0
index_copy_dialog = 1
index_delete_dialog = 2
index_new_folder_dialog = 3
index_get_info_dialog = 6
index_lock_dialog = 7
index_unlock_dialog = 8
index_rename_dialog = 9
index_download_dialog = 10
index_get_size_dialog = 11
index_warning_dialog = 12
invoke_dialog_proc:
.assert * = $A500, error, "Entry point used by overlay"
jmp invoke_dialog_proc_impl
dialog_proc_table:
.addr about_dialog_proc
.addr copy_dialog_proc
.addr delete_dialog_proc
.addr new_folder_dialog_proc
.addr rts1
.addr rts1
.addr get_info_dialog_proc
.addr lock_dialog_proc
.addr unlock_dialog_proc
.addr rename_dialog_proc
.addr download_dialog_proc
.addr get_size_dialog_proc
.addr warning_dialog_proc
dialog_param_addr:
.addr 0
.byte 0
.proc invoke_dialog_proc_impl
stax dialog_param_addr
tya
asl a
tax
copy16 dialog_proc_table,x, @jump_addr
lda #0
sta prompt_ip_flag
sta LD8EC
sta LD8F0
sta LD8F1
sta LD8F2
sta has_input_field_flag
sta LD8F5
sta format_erase_overlay_flag
sta cursor_ip_flag
copy DeskTop::Settings::ip_blink_speed, prompt_ip_counter
copy16 #rts1, jump_relay+1
jsr set_cursor_pointer
@jump_addr := *+1
jmp dummy0000 ; self-modified
.endproc
;;; ============================================================
;;; Message handler for OK/Cancel dialog
.proc prompt_input_loop
lda has_input_field_flag
beq :+
;; Blink the insertion point
dec prompt_ip_counter
bne :+
jsr redraw_prompt_insertion_point
copy DeskTop::Settings::ip_blink_speed, prompt_ip_counter
;; Dispatch event types - mouse down, key press
: MGTK_RELAY_CALL MGTK::GetEvent, event_params
lda event_kind
cmp #MGTK::EventKind::button_down
bne :+
jmp prompt_click_handler
: cmp #MGTK::EventKind::key_down
bne :+
jmp prompt_key_handler
;; Does the dialog have an input field?
: lda has_input_field_flag
beq prompt_input_loop
;; Check if mouse is over input field, change cursor appropriately.
jsr check_mouse_moved
bcc prompt_input_loop
MGTK_RELAY_CALL MGTK::FindWindow, event_coords
lda findwindow_which_area
bne :+
jmp prompt_input_loop
: lda findwindow_window_id
cmp winfo_alert_dialog
beq :+
jmp prompt_input_loop
: lda winfo_alert_dialog ; Is over this window... but where?
jsr set_port_from_window_id
copy winfo_alert_dialog, event_params
MGTK_RELAY_CALL MGTK::ScreenToWindow, screentowindow_params
MGTK_RELAY_CALL MGTK::MoveTo, screentowindow_windowx
MGTK_RELAY_CALL MGTK::InRect, name_input_rect
cmp #MGTK::inrect_inside
bne out
jsr set_cursor_insertion_point_with_flag
jmp done
out: jsr set_cursor_pointer_with_flag
done: jsr reset_grafport3a
jmp prompt_input_loop
.endproc
;;; Click handler for prompt dialog
.proc prompt_click_handler
MGTK_RELAY_CALL MGTK::FindWindow, event_coords
lda findwindow_which_area
bne :+
return #$FF
: cmp #MGTK::Area::content
bne :+
jmp content
: return #$FF
content:
lda findwindow_window_id
cmp winfo_alert_dialog
beq :+
return #$FF
: lda winfo_alert_dialog
jsr set_port_from_window_id
copy winfo_alert_dialog, event_params
MGTK_RELAY_CALL MGTK::ScreenToWindow, screentowindow_params
MGTK_RELAY_CALL MGTK::MoveTo, screentowindow_windowx
bit LD8E7
bvc :+
jmp check_button_yes
: MGTK_RELAY_CALL MGTK::InRect, desktop_aux::ok_button_rect
cmp #MGTK::inrect_inside
beq check_button_ok
jmp maybe_check_button_cancel
check_button_ok:
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::ok_button_rect
jsr button_loop_ok
bmi :+
lda #PromptResult::ok
: rts
check_button_yes:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::yes_button_rect
cmp #MGTK::inrect_inside
bne check_button_no
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::yes_button_rect
jsr button_loop_yes
bmi :+
lda #PromptResult::yes
: rts
check_button_no:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::no_button_rect
cmp #MGTK::inrect_inside
bne check_button_all
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::no_button_rect
jsr button_loop_no
bmi :+
lda #PromptResult::no
: rts
check_button_all:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::all_button_rect
cmp #MGTK::inrect_inside
bne maybe_check_button_cancel
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::all_button_rect
jsr button_loop_all
bmi :+
lda #PromptResult::all
: rts
maybe_check_button_cancel:
bit LD8E7
bpl check_button_cancel
return #$FF
check_button_cancel:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::cancel_button_rect
cmp #MGTK::inrect_inside
beq :+
jmp LA6ED
: jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::cancel_button_rect
jsr button_loop_cancel
bmi :+
lda #PromptResult::cancel
: rts
LA6ED: bit has_input_field_flag
bmi LA6F7
lda #$FF
jmp jump_relay
LA6F7: jsr LB9B8
return #$FF
.endproc
;;; Key handler for prompt dialog
.proc prompt_key_handler
lda event_modifiers
cmp #MGTK::event_modifier_solid_apple
bne no_mods
;; Modifier key down.
lda event_key
and #CHAR_MASK
cmp #CHAR_LEFT
bne :+
jmp left_with_mod
: cmp #CHAR_RIGHT
bne done
jmp right_with_mod
done: return #$FF
;; No modifier key down.
no_mods:
lda event_key
and #CHAR_MASK
cmp #CHAR_LEFT
bne LA72E
bit format_erase_overlay_flag
bpl :+
jmp format_erase_overlay_prompt_handle_key_left
: jmp handle_key_left
LA72E: cmp #CHAR_RIGHT
bne LA73D
bit format_erase_overlay_flag
bpl :+
jmp format_erase_overlay_prompt_handle_key_right
: jmp handle_key_right
LA73D: cmp #CHAR_RETURN
bne LA749
bit LD8E7
bvs done
jmp LA851
LA749: cmp #CHAR_ESCAPE
bne LA755
bit LD8E7
bmi done
jmp LA86F
LA755: cmp #CHAR_DELETE
bne LA75C
jmp LA88D
LA75C: cmp #CHAR_UP
bne LA76B
bit format_erase_overlay_flag
bmi :+
jmp done
: jmp format_erase_overlay_prompt_handle_key_up
LA76B: cmp #CHAR_DOWN
bne LA77A
bit format_erase_overlay_flag
bmi :+
jmp done
: jmp format_erase_overlay_prompt_handle_key_down
LA77A: bit LD8E7
bvc LA79B
cmp #'Y'
beq do_yes
cmp #'y'
beq do_yes
cmp #'N'
beq do_no
cmp #'n'
beq do_no
cmp #'A'
beq do_all
cmp #'a'
beq do_all
cmp #CHAR_RETURN
beq do_yes
LA79B: bit LD8F5
bmi LA7C8
cmp #'.'
beq LA7D8
cmp #'0'
bcs LA7AB
jmp done
LA7AB: cmp #'z'+1
bcc LA7B2
jmp done
LA7B2: cmp #'9'+1
bcc LA7D8
cmp #'A'
bcs LA7BD
jmp done
LA7BD: cmp #'Z'+1
bcc LA7DD
cmp #'a'
bcs LA7DD
jmp done
LA7C8: cmp #' '
bcs LA7CF
jmp done
LA7CF: cmp #'~'
beq LA7DD
bcc LA7DD
jmp done
LA7D8: ldx path_buf1
beq LA7E5
LA7DD: ldx has_input_field_flag
beq LA7E5
jsr LBB0B
LA7E5: return #$FF
do_yes: jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::yes_button_rect
return #PromptResult::yes
do_no: jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::no_button_rect
return #PromptResult::no
do_all: jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::all_button_rect
return #PromptResult::all
.proc left_with_mod
lda has_input_field_flag
beq :+
jsr input_field_ip_start
: return #$FF
.endproc
.proc right_with_mod
lda has_input_field_flag
beq :+
jsr input_field_ip_end
: return #$FF
.endproc
.proc handle_key_left
lda has_input_field_flag
beq done
bit format_erase_overlay_flag ; BUG? Should never be set here based on caller test.
bpl :+
jmp format_erase_overlay_prompt_handle_key_right
: jsr input_field_ip_left
done: return #$FF
.endproc
.proc handle_key_right
lda has_input_field_flag
beq done
bit format_erase_overlay_flag ; BUG? Should never be set here based on caller test.
bpl :+
jmp format_erase_overlay_prompt_handle_key_left
: jsr input_field_ip_right
done: return #$FF
.endproc
LA851: lda winfo_alert_dialog
jsr set_port_from_window_id
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::ok_button_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::ok_button_rect
return #0
LA86F: lda winfo_alert_dialog
jsr set_port_from_window_id
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::cancel_button_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::cancel_button_rect
return #1
LA88D: lda has_input_field_flag
beq LA895
jsr LBB63
LA895: return #$FF
.endproc
rts1:
rts
;;; ============================================================
jump_relay:
jmp dummy0000
;;; ============================================================
;;; "About" dialog
.proc about_dialog_proc
MGTK_RELAY_CALL MGTK::OpenWindow, winfo_about_dialog
lda winfo_about_dialog::window_id
jsr set_port_from_window_id
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::about_dialog_outer_rect
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::about_dialog_inner_rect
addr_call draw_dialog_title, desktop_aux::str_about1
yax_call draw_dialog_label, 1 | DDL_CENTER, desktop_aux::str_about2
yax_call draw_dialog_label, 2 | DDL_CENTER, desktop_aux::str_about3
yax_call draw_dialog_label, 3 | DDL_CENTER, desktop_aux::str_about4
yax_call draw_dialog_label, 5, desktop_aux::str_about5
yax_call draw_dialog_label, 6 | DDL_CENTER, desktop_aux::str_about6
yax_call draw_dialog_label, 7, desktop_aux::str_about7
yax_call draw_dialog_label, 9, desktop_aux::str_about8
copy16 #310 - (7 * .strlen(VERSION_SUFFIX)), dialog_label_pos
yax_call draw_dialog_label, 9, desktop_aux::str_about9
copy16 #dialog_label_default_x, dialog_label_pos
: MGTK_RELAY_CALL MGTK::GetEvent, event_params
lda event_kind
cmp #MGTK::EventKind::button_down
beq close
cmp #MGTK::EventKind::key_down
bne :-
lda event_key
and #CHAR_MASK
cmp #CHAR_ESCAPE
beq close
cmp #CHAR_RETURN
bne :-
jmp close
close: MGTK_RELAY_CALL MGTK::CloseWindow, winfo_about_dialog
jsr reset_grafport3a
jsr set_cursor_pointer_with_flag
rts
.endproc
;;; ============================================================
.proc copy_dialog_proc
ptr := $6
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda (ptr),y
cmp #CopyDialogLifecycle::populate
bne :+
jmp do1
: cmp #CopyDialogLifecycle::show
bne :+
jmp do2
: cmp #CopyDialogLifecycle::exists
bne :+
jmp do3
: cmp #CopyDialogLifecycle::too_large
bne :+
jmp do4
: cmp #CopyDialogLifecycle::close
bne :+
jmp do5
;; CopyDialogLifecycle::open
: copy #0, has_input_field_flag
jsr open_dialog_window
yax_call draw_dialog_label, 2, desktop_aux::str_copy_from
yax_call draw_dialog_label, 3, desktop_aux::str_copy_to
bit move_flag
bmi :+
addr_call draw_dialog_title, desktop_aux::str_copy_title
yax_call draw_dialog_label, 1, desktop_aux::str_copy_copying
yax_call draw_dialog_label, 4, desktop_aux::str_copy_remaining
rts
: addr_call draw_dialog_title, desktop_aux::str_move_title
yax_call draw_dialog_label, 1, desktop_aux::str_move_moving
yax_call draw_dialog_label, 4, desktop_aux::str_move_remaining
rts
;; CopyDialogLifecycle::populate
do1: ldy #1
copy16in (ptr),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::copy_file_count_pos
addr_call draw_text1, str_file_count
addr_call draw_text1, str_files
rts
;; CopyDialogLifecycle::exists
do2: ldy #1
copy16in (ptr),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
jsr clear_target_file_rect
jsr clear_dest_file_rect
jsr copy_dialog_param_addr_to_ptr
ldy #$03
lda (ptr),y
tax
iny
lda (ptr),y
sta ptr+1
stx ptr
jsr copy_name_to_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::current_target_file_pos
addr_call draw_text1, path_buf0
jsr copy_dialog_param_addr_to_ptr
ldy #$05
lda (ptr),y
tax
iny
lda (ptr),y
sta ptr+1
stx ptr
jsr copy_name_to_buf1
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::current_dest_file_pos
addr_call draw_text1, path_buf1
yax_call MGTK_RELAY, MGTK::MoveTo, desktop_aux::copy_file_count_pos2
addr_call draw_text1, str_file_count
rts
;; CopyDialogLifecycle::close
do5: jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
rts
;; CopyDialogLifecycle::exists
do3: jsr bell
lda winfo_alert_dialog
jsr set_port_from_window_id
yax_call draw_dialog_label, 6, desktop_aux::str_exists_prompt
jsr draw_yes_no_all_cancel_buttons
LAA7F: jsr prompt_input_loop
bmi LAA7F
pha
jsr erase_yes_no_all_cancel_buttons
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::prompt_rect
pla
rts
;; CopyDialogLifecycle::too_large
do4: jsr bell
lda winfo_alert_dialog
jsr set_port_from_window_id
yax_call draw_dialog_label, 6, desktop_aux::str_large_prompt
jsr draw_ok_cancel_buttons
: jsr prompt_input_loop
bmi :-
pha
jsr erase_ok_cancel_buttons
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::prompt_rect
pla
rts
.endproc
;;; ============================================================
;;; "DownLoad" dialog
.proc download_dialog_proc
ptr := $6
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda (ptr),y
cmp #1
bne :+
jmp do1
: cmp #2
bne :+
jmp do2
: cmp #3
bne :+
jmp do3
: cmp #4
bne else
jmp do4
else: copy #0, has_input_field_flag
jsr open_dialog_window
addr_call draw_dialog_title, desktop_aux::str_download
yax_call draw_dialog_label, 1, desktop_aux::str_copy_copying
yax_call draw_dialog_label, 2, desktop_aux::str_copy_from
yax_call draw_dialog_label, 3, desktop_aux::str_copy_to
yax_call draw_dialog_label, 4, desktop_aux::str_copy_remaining
rts
do1: ldy #1
copy16in (ptr),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::copy_file_count_pos
addr_call draw_text1, str_file_count
addr_call draw_text1, str_files
rts
do2: ldy #1
copy16in (ptr),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
jsr clear_target_file_rect
jsr copy_dialog_param_addr_to_ptr
ldy #3
lda (ptr),y
tax
iny
lda (ptr),y
sta ptr+1
stx ptr
jsr copy_name_to_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::current_target_file_pos
addr_call draw_text1, path_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::copy_file_count_pos2
addr_call draw_text1, str_file_count
rts
do3: jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
rts
do4: jsr bell
lda winfo_alert_dialog
jsr set_port_from_window_id
yax_call draw_dialog_label, 6, desktop_aux::str_ramcard_full
jsr draw_ok_button
: jsr prompt_input_loop
bmi :-
pha
jsr erase_ok_button
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::prompt_rect
pla
rts
.endproc
;;; ============================================================
;;; "Get Size" dialog
.proc get_size_dialog_proc
ptr := $6
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda (ptr),y
cmp #1
bne :+
jmp do1
: cmp #2
bne :+
jmp do2
: cmp #3
bne else
jmp do3
else: jsr open_dialog_window
addr_call draw_dialog_title, desktop_aux::str_size_title
yax_call draw_dialog_label, 1, desktop_aux::str_size_number
ldy #1
jsr draw_colon
yax_call draw_dialog_label, 2, desktop_aux::str_size_blocks
ldy #2
jsr draw_colon
rts
do1: ldy #1
lda (ptr),y
sta file_count
tax
iny
lda (ptr),y
sta ptr+1
stx ptr
ldy #0
copy16in (ptr),y, file_count
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
copy #165, dialog_label_pos
yax_call draw_dialog_label, 1, str_file_count
jsr copy_dialog_param_addr_to_ptr
ldy #3
lda (ptr),y
tax
iny
lda (ptr),y
sta ptr+1
stx ptr
ldy #0
copy16in (ptr),y, file_count
jsr compose_file_count_string
copy #165, dialog_label_pos
yax_call draw_dialog_label, 2, str_file_count
rts
do3: jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
rts
do2: lda winfo_alert_dialog
jsr set_port_from_window_id
jsr draw_ok_button
: jsr prompt_input_loop
bmi :-
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::clear_dialog_labels_rect
jsr erase_ok_button
return #0
.endproc
;;; ============================================================
;;; "Delete File" dialog
.proc delete_dialog_proc
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda ($06),y ; phase
cmp #DeleteDialogLifecycle::populate
bne :+
jmp do1
: cmp #DeleteDialogLifecycle::confirm
bne :+
jmp do2
: cmp #DeleteDialogLifecycle::show
bne :+
jmp do3
: cmp #DeleteDialogLifecycle::locked
bne :+
jmp do4
: cmp #DeleteDialogLifecycle::close
bne :+
jmp do5
;; DeleteDialogLifecycle::open or trash
: sta LAD1F
copy #0, has_input_field_flag
jsr open_dialog_window
addr_call draw_dialog_title, desktop_aux::str_delete_title
lda LAD1F
beq LAD20
yax_call draw_dialog_label, 4, desktop_aux::str_ok_empty
rts
LAD1F: .byte 0
LAD20: yax_call draw_dialog_label, 4, desktop_aux::str_delete_ok
rts
;; DeleteDialogLifecycle::populate
do1: ldy #1
copy16in ($06),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
lda LAD1F
bne LAD54
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::delete_file_count_pos
jmp LAD5D
LAD54: MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::delete_file_count_pos2
LAD5D: addr_call draw_text1, str_file_count
addr_call draw_text1, str_files
rts
;; DeleteDialogLifecycle::show
do3: ldy #1
copy16in ($06),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
jsr clear_target_file_rect
jsr copy_dialog_param_addr_to_ptr
ldy #3
lda ($06),y
tax
iny
lda ($06),y
sta $06+1
stx $06
jsr copy_name_to_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::current_target_file_pos
addr_call draw_text1, path_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::delete_remaining_count_pos
addr_call draw_text1, str_file_count
rts
;; DeleteDialogLifecycle::confirm
do2: lda winfo_alert_dialog
jsr set_port_from_window_id
jsr draw_ok_cancel_buttons
LADC4: jsr prompt_input_loop
bmi LADC4
bne LADF4
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::clear_dialog_labels_rect
jsr erase_ok_cancel_buttons
yax_call draw_dialog_label, 2, desktop_aux::str_file_colon
yax_call draw_dialog_label, 4, desktop_aux::str_delete_remaining
lda #$00
LADF4: rts
;; DeleteDialogLifecycle::close
do5: jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
rts
;; DeleteDialogLifecycle::locked
do4: lda winfo_alert_dialog
jsr set_port_from_window_id
yax_call draw_dialog_label, 6, desktop_aux::str_delete_locked_file
jsr draw_yes_no_all_cancel_buttons
LAE17: jsr prompt_input_loop
bmi LAE17
pha
jsr erase_yes_no_all_cancel_buttons
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy ; white
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::prompt_rect ; erase prompt
pla
rts
.endproc
;;; ============================================================
;;; "New Folder" dialog
.proc new_folder_dialog_proc
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda ($06),y
cmp #$80
bne LAE42
jmp LAE70
LAE42: cmp #$40
bne LAE49
jmp LAF16
LAE49: copy #$80, has_input_field_flag
jsr clear_path_buf2
lda #$00
jsr open_prompt_window
lda winfo_alert_dialog
jsr set_port_from_window_id
addr_call draw_dialog_title, desktop_aux::str_new_folder_title
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::FrameRect, name_input_rect
rts
LAE70: copy #$80, has_input_field_flag
copy #0, LD8E7
jsr clear_path_buf1
jsr copy_dialog_param_addr_to_ptr
ldy #1
copy16in ($06),y, $08
ldy #0
lda ($08),y
tay
LAE90: lda ($08),y
sta path_buf0,y
dey
bpl LAE90
lda winfo_alert_dialog
jsr set_port_from_window_id
yax_call draw_dialog_label, 2, desktop_aux::str_in_colon
copy #55, dialog_label_pos
yax_call draw_dialog_label, 2, path_buf0
copy #dialog_label_default_x, dialog_label_pos
yax_call draw_dialog_label, 4, desktop_aux::str_enter_folder_name
jsr draw_filename_prompt
LAEC6: jsr prompt_input_loop
bmi LAEC6
bne LAF16
jsr merge_path_buf1_path_buf2
lda path_buf1
beq LAEC6
cmp #16 ; max filename length
bcc LAEE1
LAED6: lda #ERR_NAME_TOO_LONG
jsr JT_SHOW_ALERT0
jsr draw_filename_prompt
jmp LAEC6
LAEE1: lda path_buf0
clc
adc path_buf1
clc
adc #$01
cmp #$41
bcs LAED6
inc path_buf0
ldx path_buf0
copy #'/', path_buf0,x
ldx path_buf0
ldy #0
LAEFF: inx
iny
copy path_buf1,y, path_buf0,x
cpy path_buf1
bne LAEFF
stx path_buf0
ldy #<path_buf0
ldx #>path_buf0
return #0
LAF16: jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
return #1
.endproc
;;; ============================================================
;;; "Get Info" dialog
.proc get_info_dialog_proc
ptr := $6
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda (ptr),y
bmi LAF34
jmp LAFB9
LAF34: copy #0, has_input_field_flag
lda (ptr),y
lsr a
lsr a
ror a
eor #$80
jsr open_prompt_window
lda winfo_alert_dialog
jsr set_port_from_window_id
addr_call draw_dialog_title, desktop_aux::str_info_title
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda (ptr),y
and #$7F
lsr a
ror a
sta LB01D
yax_call draw_dialog_label, 1, desktop_aux::str_info_name
bit LB01D
bmi LAF78
yax_call draw_dialog_label, 2, desktop_aux::str_info_locked
jmp LAF81
LAF78: yax_call draw_dialog_label, 2, desktop_aux::str_info_protected
LAF81: bit LB01D
bpl LAF92
yax_call draw_dialog_label, 3, desktop_aux::str_info_blocks
jmp LAF9B
LAF92: yax_call draw_dialog_label, 3, desktop_aux::str_info_size
LAF9B: yax_call draw_dialog_label, 4, desktop_aux::str_info_create
yax_call draw_dialog_label, 5, desktop_aux::str_info_mod
yax_call draw_dialog_label, 6, desktop_aux::str_info_type
jmp reset_grafport3a
LAFB9: lda winfo_alert_dialog
jsr set_port_from_window_id
jsr copy_dialog_param_addr_to_ptr
ldy #0
copy (ptr),y, row
tay
jsr draw_colon
copy #165, dialog_label_pos
jsr copy_dialog_param_addr_to_ptr
lda row
cmp #2
bne LAFF0
ldy #1
lda (ptr),y
beq :+
addr_jump LAFF8, desktop_aux::str_yes_label
: addr_jump LAFF8, desktop_aux::str_no_label
LAFF0: ldy #2
lda (ptr),y
tax
dey
lda (ptr),y
LAFF8: ldy row
jsr draw_dialog_label
lda row
cmp #6
beq :+
rts
: jsr prompt_input_loop
bmi :-
pha
jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer_with_flag
pla
rts
LB01D: .byte 0
row: .byte 0
.endproc
;;; ============================================================
;;; Draw ":" after dialog label
.proc draw_colon
copy #160, dialog_label_pos
addr_call draw_dialog_label, desktop_aux::str_colon
rts
.endproc
;;; ============================================================
;;; "Lock" dialog
.proc lock_dialog_proc
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda ($06),y
cmp #LockDialogLifecycle::populate
bne :+
jmp do1
: cmp #LockDialogLifecycle::loop
bne :+
jmp do2
: cmp #LockDialogLifecycle::operation
bne :+
jmp do3
: cmp #LockDialogLifecycle::close
bne :+
jmp do4
;; LockDialogLifecycle::open
: copy #0, has_input_field_flag
jsr open_dialog_window
addr_call draw_dialog_title, desktop_aux::str_lock_title
yax_call draw_dialog_label, 4, desktop_aux::str_lock_ok
rts
;; LockDialogLifecycle::populate
do1: ldy #1
copy16in ($06),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::lock_remaining_count_pos2
addr_call draw_text1, str_file_count
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::files_pos2
addr_call draw_text1, str_files
rts
;; LockDialogLifecycle::operation
do3: ldy #1
copy16in ($06),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
jsr clear_target_file_rect
jsr copy_dialog_param_addr_to_ptr
ldy #3
lda ($06),y
tax
iny
lda ($06),y
sta $06+1
stx $06
jsr copy_name_to_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::current_target_file_pos
addr_call draw_text1, path_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::lock_remaining_count_pos
addr_call draw_text1, str_file_count
rts
;; LockDialogLifecycle::loop
do2: lda winfo_alert_dialog
jsr set_port_from_window_id
jsr draw_ok_cancel_buttons
LB0FA: jsr prompt_input_loop
bmi LB0FA
bne LB139
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::clear_dialog_labels_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::ok_button_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::cancel_button_rect
yax_call draw_dialog_label, 2, desktop_aux::str_file_colon
yax_call draw_dialog_label, 4, desktop_aux::str_lock_remaining
lda #$00
LB139: rts
;; LockDialogLifecycle::close
do4: jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
rts
.endproc
;;; ============================================================
;;; "Unlock" dialog
.proc unlock_dialog_proc
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda ($06),y
cmp #LockDialogLifecycle::populate
bne :+
jmp do1
: cmp #LockDialogLifecycle::loop
bne :+
jmp do2
: cmp #LockDialogLifecycle::operation
bne :+
jmp do3
: cmp #LockDialogLifecycle::close
bne :+
jmp do4
;; LockDialogLifecycle::open
: copy #0, has_input_field_flag
jsr open_dialog_window
addr_call draw_dialog_title, desktop_aux::str_unlock_title
yax_call draw_dialog_label, 4, desktop_aux::str_unlock_ok
rts
;; LockDialogLifecycle::populate
do1: ldy #1
copy16in ($06),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::unlock_remaining_count_pos2
addr_call draw_text1, str_file_count
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::files_pos
addr_call draw_text1, str_files
rts
;; LockDialogLifecycle::operation
do3: ldy #1
copy16in ($06),y, file_count
jsr adjust_str_files_suffix
jsr compose_file_count_string
lda winfo_alert_dialog
jsr set_port_from_window_id
jsr clear_target_file_rect
jsr copy_dialog_param_addr_to_ptr
ldy #3
lda ($06),y
tax
iny
lda ($06),y
sta $06+1
stx $06
jsr copy_name_to_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::current_target_file_pos
addr_call draw_text1, path_buf0
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::unlock_remaining_count_pos
addr_call draw_text1, str_file_count
rts
;; LockDialogLifecycle::loop
do2: lda winfo_alert_dialog
jsr set_port_from_window_id
jsr draw_ok_cancel_buttons
LB218: jsr prompt_input_loop
bmi LB218
bne LB257
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::clear_dialog_labels_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::ok_button_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::cancel_button_rect
yax_call draw_dialog_label, 2, desktop_aux::str_file_colon
yax_call draw_dialog_label, 4, desktop_aux::str_unlock_remaining
lda #$00
LB257: rts
;; LockDialogLifecycle::close
do4: jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
rts
.endproc
;;; ============================================================
;;; "Rename" dialog
.proc rename_dialog_proc
jsr copy_dialog_param_addr_to_ptr
ldy #0
lda ($06),y
cmp #$80
bne LB276
jmp LB2ED
LB276: cmp #$40
bne LB27D
jmp LB313
LB27D: jsr clear_path_buf1
jsr copy_dialog_param_addr_to_ptr
copy #$80, has_input_field_flag
jsr clear_path_buf2
lda #$00
jsr open_prompt_window
lda winfo_alert_dialog
jsr set_port_from_window_id
addr_call draw_dialog_title, desktop_aux::str_rename_title
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::FrameRect, name_input_rect
yax_call draw_dialog_label, 2, desktop_aux::str_rename_old
copy #85, dialog_label_pos
jsr copy_dialog_param_addr_to_ptr
ldy #1
copy16in ($06),y, $08
ldy #0
lda ($08),y
tay
LB2CA: copy ($08),y, buf_filename,y
dey
bpl LB2CA
yax_call draw_dialog_label, 2, buf_filename
yax_call draw_dialog_label, 4, desktop_aux::str_rename_new
copy #0, path_buf1
jsr draw_filename_prompt
rts
LB2ED: copy16 #$8000, LD8E7
lda winfo_alert_dialog
jsr set_port_from_window_id
LB2FD: jsr prompt_input_loop
bmi LB2FD
bne LB313
lda path_buf1
beq LB2FD
jsr input_field_ip_end
ldy #<path_buf1
ldx #>path_buf1
return #0
LB313: jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
return #1
.endproc
;;; ============================================================
;;; "Warning!" dialog
;;; $6 ptr to message num
.proc warning_dialog_proc
ptr := $6
;; Create window
MGTK_RELAY_CALL MGTK::HideCursor
jsr open_alert_window
lda winfo_alert_dialog
jsr set_port_from_window_id
addr_call draw_dialog_title, desktop_aux::str_warning
MGTK_RELAY_CALL MGTK::ShowCursor
jsr copy_dialog_param_addr_to_ptr
;; Dig up message
ldy #0
lda (ptr),y
pha
bmi only_ok ; high bit set means no cancel
tax
lda warning_cancel_table,x
bne ok_and_cancel
only_ok: ; no cancel button
pla
and #$7F
pha
jsr draw_ok_button
jmp draw_string
ok_and_cancel: ; has cancel button
jsr draw_ok_cancel_buttons
draw_string:
;; First string
pla
pha
asl a ; * 2
asl a ; * 4, since there are two strings each
tay
lda warning_message_table+1,y
tax
lda warning_message_table,y
ldy #3 ; row
jsr draw_dialog_label
;; Second string
pla
asl a
asl a
tay
lda warning_message_table+2+1,y
tax
lda warning_message_table+2,y
ldy #4 ; row
jsr draw_dialog_label
;; Input loop
: jsr prompt_input_loop
bmi :-
pha
jsr reset_grafport3a
MGTK_RELAY_CALL MGTK::CloseWindow, winfo_alert_dialog
jsr set_cursor_pointer
pla
rts
;; high bit set if "cancel" should be an option
warning_cancel_table:
.byte $80,$00,$00,$80,$00,$00,$80
warning_message_table:
.addr desktop_aux::str_insert_system_disk,desktop_aux::str_1_space
.addr desktop_aux::str_selector_list_full,desktop_aux::str_before_new_entries
.addr desktop_aux::str_selector_list_full,desktop_aux::str_before_new_entries
.addr desktop_aux::str_window_must_be_closed,desktop_aux::str_1_space
.addr desktop_aux::str_window_must_be_closed,desktop_aux::str_1_space
.addr desktop_aux::str_too_many_windows,desktop_aux::str_1_space
.addr desktop_aux::str_save_selector_list,desktop_aux::str_on_system_disk
.endproc
warning_msg_insert_system_disk = 0
warning_msg_selector_list_full = 1
warning_msg_selector_list_full2 = 2
warning_msg_window_must_be_closed = 3
warning_msg_window_must_be_closed2 = 4
warning_msg_too_many_windows = 5
warning_msg_save_selector_list = 6
;;; ============================================================
.proc copy_dialog_param_addr_to_ptr
copy16 dialog_param_addr, $06
rts
.endproc
;;; ============================================================
.proc set_cursor_pointer_with_flag
bit cursor_ip_flag
bpl :+
jsr set_cursor_pointer
copy #0, cursor_ip_flag
: rts
.endproc
.proc set_cursor_insertion_point_with_flag
bit cursor_ip_flag
bmi :+
jsr set_cursor_insertion_point
copy #$80, cursor_ip_flag
: rts
.endproc
cursor_ip_flag: ; high bit set if IP, clear if pointer
.byte 0
;;; ============================================================
;;;
;;; Routines beyond this point are used by overlays
;;;
;;; ============================================================
.assert * >= $A000, error, "Routine used by overlays in overlay zone"
.proc bell
sta ALTZPOFF
sta ROMIN2
jsr BELL1
sta ALTZPON
lda LCBANK1
lda LCBANK1
rts
.endproc
.proc set_cursor_watch
MGTK_RELAY_CALL MGTK::HideCursor
MGTK_RELAY_CALL MGTK::SetCursor, watch_cursor
MGTK_RELAY_CALL MGTK::ShowCursor
rts
.endproc
.proc set_cursor_pointer
MGTK_RELAY_CALL MGTK::HideCursor
MGTK_RELAY_CALL MGTK::SetCursor, pointer_cursor
MGTK_RELAY_CALL MGTK::ShowCursor
rts
.endproc
.proc set_cursor_insertion_point
MGTK_RELAY_CALL MGTK::HideCursor
MGTK_RELAY_CALL MGTK::SetCursor, insertion_point_cursor
MGTK_RELAY_CALL MGTK::ShowCursor
rts
.endproc
set_penmode_xor2:
MGTK_RELAY_CALL MGTK::SetPenMode, penXOR
rts
;;; ============================================================
;;; Double Click Detection
;;; Returns with A=0 if double click, A=$FF otherwise.
.proc detect_double_click
double_click_deltax = 5
double_click_deltay = 4
;; Stash initial coords
ldx #3
: copy event_coords,x, coords,x
sta saved_event_coords,x ; for double-click in windows
dex
bpl :-
copy16 DeskTop::Settings::dblclick_speed, counter
;; Decrement counter, bail if time delta exceeded
loop: dec16 counter
lda counter
ora counter+1
beq exit
MGTK_RELAY_CALL MGTK::PeekEvent, event_params
;; Check coords, bail if pixel delta exceeded
jsr check_delta
bmi exit ; moved past delta; no double-click
lda event_kind
cmp #MGTK::EventKind::no_event
beq loop
cmp #MGTK::EventKind::drag
beq loop
cmp #MGTK::EventKind::button_up
bne :+
MGTK_RELAY_CALL MGTK::GetEvent, event_params
jmp loop
: cmp #MGTK::EventKind::button_down
beq :+
cmp #MGTK::EventKind::apple_key ; modified-click
bne exit
: MGTK_RELAY_CALL MGTK::GetEvent, event_params
return #0 ; double-click
exit: return #$FF ; not double-click
;; Is the new coord within range of the old coord?
.proc check_delta
;; compute x delta
lda event_xcoord
sec
sbc xcoord
sta delta
lda event_xcoord+1
sbc xcoord+1
bpl :+
;; is -delta < x < 0 ?
lda delta
cmp #AS_BYTE(-double_click_deltax)
bcs check_y
fail: return #$FF
;; is 0 < x < delta ?
: lda delta
cmp #double_click_deltax
bcs fail
;; compute y delta
check_y:
lda event_ycoord
sec
sbc ycoord
sta delta
lda event_ycoord+1
sbc ycoord+1
bpl :+
;; is -delta < y < 0 ?
lda delta
cmp #AS_BYTE(-double_click_deltay)
bcs ok
;; is 0 < y < delta ?
: lda delta
cmp #double_click_deltay
bcs fail
ok: return #0
.endproc
counter:
.word 0
coords:
xcoord: .word 0
ycoord: .word 0
delta: .byte 0
.endproc
;;; ============================================================
.proc open_prompt_window
sta LD8E7
jsr open_dialog_window
bit LD8E7
bvc :+
jsr draw_yes_no_all_cancel_buttons
jmp no_ok
: MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::ok_button_rect
jsr draw_ok_label
no_ok: bit LD8E7
bmi done
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::cancel_button_rect
jsr draw_cancel_label
done: jmp reset_grafport3a
.endproc
;;; ============================================================
.proc open_dialog_window
MGTK_RELAY_CALL MGTK::OpenWindow, winfo_alert_dialog
lda winfo_alert_dialog
jsr set_port_from_window_id
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::confirm_dialog_outer_rect
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::confirm_dialog_inner_rect
rts
.endproc
;;; ============================================================
.proc open_alert_window
MGTK_RELAY_CALL MGTK::OpenWindow, winfo_alert_dialog
lda winfo_alert_dialog
jsr set_port_from_window_id
jsr set_fill_white
MGTK_RELAY_CALL MGTK::PaintBits, alert_bitmap2_params
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::confirm_dialog_outer_rect
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::confirm_dialog_inner_rect
rts
.endproc
;;; ============================================================
;;; Draw dialog label.
;;; A,X has pointer to DrawText params block
;;; Y has row number (1, 2, ... ) with high bit to center it
DDL_CENTER = $80
.proc draw_dialog_label
textwidth_params := $8
textptr := $8
textlen := $A
result := $B
ptr := $6
stx ptr+1
sta ptr
tya
bmi :+
jmp skip
;; Compute text width and center it
: and #$7F ; strip "center?" flag
pha
add16 ptr, #1, textptr
jsr load_aux_from_ptr
sta textlen
MGTK_RELAY_CALL MGTK::TextWidth, textwidth_params
lsr16 result
sub16 #200, result, dialog_label_pos
pla
;; y = base + desktop_aux::dialog_label_height * line
skip: ldx #0
ldy #desktop_aux::dialog_label_height
jsr Multiply_16_8_16
stax dialog_label_pos::ycoord
add16 dialog_label_pos::ycoord, dialog_label_base_pos::ycoord, dialog_label_pos::ycoord
MGTK_RELAY_CALL MGTK::MoveTo, dialog_label_pos
addr_call_indirect draw_text1, ptr
ldx dialog_label_pos
copy #dialog_label_default_x,dialog_label_pos::xcoord ; restore original x coord
rts
.endproc
;;; ============================================================
draw_ok_label:
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::ok_label_pos
addr_call draw_text1, desktop_aux::str_ok_label
rts
draw_cancel_label:
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::cancel_label_pos
addr_call draw_text1, desktop_aux::str_cancel_label
rts
draw_yes_label:
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::yes_label_pos
addr_call draw_text1, desktop_aux::str_yes_label
rts
draw_no_label:
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::no_label_pos
addr_call draw_text1, desktop_aux::str_no_label
rts
draw_all_label:
MGTK_RELAY_CALL MGTK::MoveTo, desktop_aux::all_label_pos
addr_call draw_text1, desktop_aux::str_all_label
rts
draw_yes_no_all_cancel_buttons:
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::yes_button_rect
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::no_button_rect
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::all_button_rect
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::cancel_button_rect
jsr draw_yes_label
jsr draw_no_label
jsr draw_all_label
jsr draw_cancel_label
copy #$40, LD8E7
rts
erase_yes_no_all_cancel_buttons:
jsr set_fill_white
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::yes_button_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::no_button_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::all_button_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::cancel_button_rect
rts
draw_ok_cancel_buttons:
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::ok_button_rect
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::cancel_button_rect
jsr draw_ok_label
jsr draw_cancel_label
copy #$00, LD8E7
rts
erase_ok_cancel_buttons:
jsr set_fill_white
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::ok_button_rect
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::cancel_button_rect
rts
draw_ok_button:
jsr set_penmode_xor2
MGTK_RELAY_CALL MGTK::FrameRect, desktop_aux::ok_button_rect
jsr draw_ok_label
copy #$80, LD8E7
rts
erase_ok_button:
jsr set_fill_white
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::ok_button_rect
rts
;;; ============================================================
.proc draw_text1
params := $6
textptr := $6
textlen := $8
stax textptr
jsr load_aux_from_ptr
beq done
sta textlen
inc16 textptr
MGTK_RELAY_CALL MGTK::DrawText, params
done: rts
.endproc
;;; ============================================================
.proc draw_dialog_title
str := $6
str_data := $6
str_len := $8
str_width := $9
stax str ; input is length-prefixed string
jsr load_aux_from_ptr
sta str_len
inc str_data ; point past length byte
bne :+
inc str_data+1
: MGTK_RELAY_CALL MGTK::TextWidth, str
lsr16 str_width ; divide by two
lda #>400 ; center within 400px
sta hi
lda #<400
lsr hi ; divide by two
ror a
sec
sbc str_width
sta pos_dialog_title::xcoord
lda hi
sbc str_width+1
sta pos_dialog_title::xcoord+1
MGTK_RELAY_CALL MGTK::MoveTo, pos_dialog_title
MGTK_RELAY_CALL MGTK::DrawText, str
rts
hi: .byte 0
.endproc
;;; ============================================================
;;; Adjust filename case, using GS/OS bits or heuristics
;;; http://www.1000bit.it/support/manuali/apple/technotes/gsos/tn.gsos.08.html
;;; adjust_fileeentry_case:
;;; Input: A,X points at FileEntry structure.
;;;
;;; adjust_volname_case:
;;; Input: A,X points at ON_LINE result (e.g. 'MY.DISK', length + 15 chars)
.proc adjust_case_impl
volpath := $810
volbuf := $820
DEFINE_OPEN_PARAMS volname_open_params, volpath, $1000
DEFINE_READ_PARAMS volname_read_params, volbuf, .sizeof(VolumeDirectoryHeader)
DEFINE_CLOSE_PARAMS volname_close_params
ptr := $A
;;; --------------------------------------------------
;;; Called with volume name. Convert to path, load
;;; VolumeDirectoryHeader, use bytes $1A/$1B
vol_name:
stax ptr
;; Convert volume name to a path
ldy #0
lda (ptr),y
sta volpath
tay
: lda (ptr),y
sta volpath+1,y
dey
bne :-
lda #'/'
sta volpath+1
inc volpath
MLI_RELAY_CALL OPEN, volname_open_params
bne fallback
lda volname_open_params::ref_num
sta volname_read_params::ref_num
sta volname_close_params::ref_num
MLI_RELAY_CALL READ, volname_read_params
bne fallback
MLI_RELAY_CALL CLOSE, volname_close_params
copy16 volbuf + $1A, version_bytes
jmp common
;;; --------------------------------------------------
;;; Called with FileEntry. Copy version bytes directly.
file_entry:
stax ptr
.assert FileEntry::file_name = 1, error, "bad assumptions in structure"
ldy #FileEntry::version
copy16in (ptr),y, version_bytes
;; fall through
common:
asl16 version_bytes
bcs apply_bits ; High bit set = GS/OS case bits present
;;; --------------------------------------------------
;;; GS/OS bits are not present; apply heuristics
fallback:
ldy #0
lda (ptr),y
and #NAME_LENGTH_MASK
beq done
;; Walk backwards through string. At char N, check char N-1
;; to see if it is a '.'. If it isn't, and char N is a letter,
;; lower-case it.
tay
loop: dey
beq done
bpl :+
done: rts
: lda (ptr),y
cmp #'.'
bne check_alpha
dey
bpl loop ; always
check_alpha:
iny
lda (ptr),y
cmp #'A'
bcc :+
ora #AS_BYTE(~CASE_MASK)
sta (ptr),y
: dey
bpl loop ; always
;;; --------------------------------------------------
;;; GS/OS bits are present - apply to recase string.
apply_bits:
ldy #1
bloop: asl16 version_bytes
bcc :+
lda (ptr),y
ora #AS_BYTE(~CASE_MASK)
sta (ptr),y
: iny
cpy #16
bcc bloop
rts
version_bytes:
.word 0
.endproc
adjust_fileentry_case := adjust_case_impl::file_entry
adjust_volname_case := adjust_case_impl::vol_name
;;; ============================================================
.proc set_port_from_window_id
sta getwinport_params2::window_id
MGTK_RELAY_CALL MGTK::GetWinPort, getwinport_params2
MGTK_RELAY_CALL MGTK::SetPort, grafport2
rts
.endproc
;;; ============================================================
;;; Event loop during button press - handle inverting
;;; the text as mouse is dragged in/out, report final
;;; click (A as passed) / cancel (A is negative)
button_loop_ok:
lda #PromptResult::ok
jmp button_event_loop
button_loop_cancel:
lda #PromptResult::cancel
jmp button_event_loop
button_loop_yes:
lda #PromptResult::yes
jmp button_event_loop
button_loop_no:
lda #PromptResult::no
jmp button_event_loop
button_loop_all:
lda #PromptResult::all
jmp button_event_loop
.proc button_event_loop
;; Configure test and fill procs
pha
asl a
asl a
tax
copy16 test_fill_button_proc_table,x, test_button_proc_addr
copy16 test_fill_button_proc_table+2,x, fill_button_proc_addr
pla
jmp event_loop
test_fill_button_proc_table:
.addr test_ok_button,fill_ok_button
.addr test_cancel_button,fill_cancel_button
.addr test_yes_button,fill_yes_button
.addr test_no_button,fill_no_button
.addr test_all_button,fill_all_button
test_ok_button:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::ok_button_rect
rts
test_cancel_button:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::cancel_button_rect
rts
test_yes_button:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::yes_button_rect
rts
test_no_button:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::no_button_rect
rts
test_all_button:
MGTK_RELAY_CALL MGTK::InRect, desktop_aux::all_button_rect
rts
fill_ok_button:
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::ok_button_rect
rts
fill_cancel_button:
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::cancel_button_rect
rts
fill_yes_button:
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::yes_button_rect
rts
fill_no_button:
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::no_button_rect
rts
fill_all_button:
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::all_button_rect
rts
test_proc: jmp (test_button_proc_addr)
fill_proc: jmp (fill_button_proc_addr)
test_button_proc_addr: .addr 0
fill_button_proc_addr: .addr 0
event_loop:
sta click_result
copy #0, down_flag
loop: MGTK_RELAY_CALL MGTK::GetEvent, event_params
lda event_kind
cmp #MGTK::EventKind::button_up
beq exit
lda winfo_alert_dialog
sta event_params
MGTK_RELAY_CALL MGTK::ScreenToWindow, screentowindow_params
MGTK_RELAY_CALL MGTK::MoveTo, screentowindow_windowx
jsr test_proc
cmp #MGTK::inrect_inside
beq inside
lda down_flag ; outside but was inside?
beq invert
jmp loop
inside: lda down_flag ; already depressed?
bne invert
jmp loop
invert: jsr set_penmode_xor2
jsr fill_proc
lda down_flag
clc
adc #$80
sta down_flag
jmp loop
exit: lda down_flag ; was depressed?
beq clicked
return #$FF ; hi bit = cancelled
clicked:
jsr fill_proc ; invert one last time
return click_result ; grab expected result
down_flag:
.byte 0
click_result:
.byte 0
.endproc
.proc noop
rts
.endproc
;;; ============================================================
.proc redraw_prompt_insertion_point
point := $6
xcoord := $6
ycoord := $8
jsr measure_path_buf1
stax xcoord
copy16 name_input_textpos::ycoord, ycoord
MGTK_RELAY_CALL MGTK::MoveTo, point
MGTK_RELAY_CALL MGTK::SetPortBits, name_input_mapinfo
bit prompt_ip_flag
bpl set_flag
clear_flag:
MGTK_RELAY_CALL MGTK::SetTextBG, desktop_aux::textbg_black
copy #0, prompt_ip_flag
beq draw ; always
set_flag:
MGTK_RELAY_CALL MGTK::SetTextBG, desktop_aux::textbg_white
copy #$FF, prompt_ip_flag
drawtext_params := $6
textptr := $6
textlen := $8
draw: copy16 #str_insertion_point+1, textptr
lda str_insertion_point
sta textlen
MGTK_RELAY_CALL MGTK::DrawText, drawtext_params
MGTK_RELAY_CALL MGTK::SetTextBG, desktop_aux::textbg_white
lda winfo_alert_dialog
jsr set_port_from_window_id
rts
.endproc
;;; ============================================================
.proc draw_filename_prompt
lda winfo_alert_dialog
jsr set_port_from_window_id
jsr set_fill_white
MGTK_RELAY_CALL MGTK::PaintRect, name_input_rect
MGTK_RELAY_CALL MGTK::SetPenMode, penXOR
MGTK_RELAY_CALL MGTK::FrameRect, name_input_rect
MGTK_RELAY_CALL MGTK::MoveTo, name_input_textpos
MGTK_RELAY_CALL MGTK::SetPortBits, name_input_mapinfo
addr_call draw_text1, path_buf1
addr_call draw_text1, path_buf2
addr_call draw_text1, str_2_spaces
lda winfo_alert_dialog
jsr set_port_from_window_id
done: rts
.endproc
;;; ============================================================
.proc LB9B8
ptr := $6
textwidth_params := $6
textptr := $6
textlen := $8
result := $9
click_coords := screentowindow_windowx
;; Mouse coords to window coords; is click inside name field?
MGTK_RELAY_CALL MGTK::ScreenToWindow, screentowindow_params
MGTK_RELAY_CALL MGTK::MoveTo, click_coords
MGTK_RELAY_CALL MGTK::InRect, name_input_rect
cmp #MGTK::inrect_inside
beq :+
rts
;; Is it to the right of the text?
: jsr measure_path_buf1
width := $6
stax width
cmp16 click_coords, width
bcs to_right
jmp within_text
;;; --------------------------------------------------
;; Click is to the right of the text
.proc to_right
jsr measure_path_buf1
stax buf1_width
ldx path_buf2
inx
copy #' ', path_buf2,x
inc path_buf2
copy16 #path_buf2, textptr
lda path_buf2
sta ptr+2
LBA10: MGTK_RELAY_CALL MGTK::TextWidth, textwidth_params
add16 result, buf1_width, result
cmp16 result, click_coords
bcc LBA42
dec textlen
lda textlen
cmp #1
bne LBA10
dec path_buf2
jmp draw_text
LBA42:
lda textlen
cmp path_buf2
bcc LBA4F
dec path_buf2
jmp input_field_ip_end
LBA4F: ldx #2
ldy path_buf1
iny
LBA55: lda path_buf2,x
sta path_buf1,y
cpx textlen
beq LBA64
iny
inx
jmp LBA55
LBA64: sty path_buf1
ldy #2
ldx textlen
inx
LBA6C: lda path_buf2,x
sta path_buf2,y
cpx path_buf2
beq LBA7C
iny
inx
jmp LBA6C
LBA7C: dey
sty path_buf2
jmp draw_text
.endproc
;;; --------------------------------------------------
;; Click within text - loop to find where in the
;; name to split the string.
.proc within_text
copy16 #path_buf1, textptr
lda path_buf1
sta textlen
: MGTK_RELAY_CALL MGTK::TextWidth, textwidth_params
add16 result, name_input_textpos::xcoord, result
cmp16 result, click_coords
bcc :+
dec textlen
lda textlen
cmp #1
bcs :-
jmp input_field_ip_start
;; Copy the text to the right of the click to split_buf
: inc textlen
ldy #0
ldx textlen
: cpx path_buf1
beq :+
inx
iny
lda path_buf1,x
sta split_buf+1,y
jmp :-
:
;; Copy it (again) into path_buf2
iny
sty split_buf
ldx #1
ldy split_buf
: cpx path_buf2
beq :+
inx
iny
lda path_buf2,x
sta split_buf,y
jmp :-
:
sty split_buf
lda str_insertion_point+1
sta split_buf+1
LBAF7: lda split_buf,y
sta path_buf2,y
dey
bpl LBAF7
lda textlen
sta path_buf1
;; fall through
.endproc
draw_text:
jsr draw_filename_prompt
rts
buf1_width:
.word 0
.endproc
;;; ============================================================
.proc LBB0B
sta param
lda path_buf1
clc
adc path_buf2
cmp #$10
bcc :+
rts
point := $6
xcoord := $6
ycoord := $8
: lda param
ldx path_buf1
inx
sta path_buf1,x
sta str_1_char+1
jsr measure_path_buf1
inc path_buf1
stax xcoord
copy16 name_input_textpos::ycoord, ycoord
MGTK_RELAY_CALL MGTK::MoveTo, point
MGTK_RELAY_CALL MGTK::SetPortBits, name_input_mapinfo
addr_call draw_text1, str_1_char
addr_call draw_text1, path_buf2
lda winfo_alert_dialog
jsr set_port_from_window_id
rts
param: .byte 0
.endproc
;;; ============================================================
.proc LBB63
lda path_buf1
bne :+
rts
point := $6
xcoord := $6
ycoord := $8
: dec path_buf1
jsr measure_path_buf1
stax xcoord
copy16 name_input_textpos::ycoord, ycoord
MGTK_RELAY_CALL MGTK::MoveTo, point
MGTK_RELAY_CALL MGTK::SetPortBits, name_input_mapinfo
addr_call draw_text1, path_buf2
addr_call draw_text1, str_2_spaces
lda winfo_alert_dialog
jsr set_port_from_window_id
rts
.endproc
;;; ============================================================
;;; Move IP one character left.
.proc input_field_ip_left
;; Any characters to left of IP?
lda path_buf1
bne :+
rts
point := $6
xcoord := $6
ycoord := $8
: ldx path_buf2
cpx #1
beq finish
;; Shift right up by a character.
loop: lda path_buf2,x
sta path_buf2+1,x
dex
cpx #1
bne loop
;; Copy character left to right and adjust lengths.
finish: ldx path_buf1
lda path_buf1,x
sta path_buf2+2
dec path_buf1
inc path_buf2
;; Redraw (just the right part)
jsr measure_path_buf1
stax xcoord
copy16 name_input_textpos::ycoord, ycoord
MGTK_RELAY_CALL MGTK::MoveTo, point
MGTK_RELAY_CALL MGTK::SetPortBits, name_input_mapinfo
addr_call draw_text1, path_buf2
addr_call draw_text1, str_2_spaces
lda winfo_alert_dialog
jsr set_port_from_window_id
rts
.endproc
;;; ============================================================
;;; Move IP one character right.
.proc input_field_ip_right
;; Any characters to right of IP?
lda path_buf2
cmp #2
bcs :+
rts
;; Copy char from right to left and adjust lengths.
: ldx path_buf1
inx
lda path_buf2+2
sta path_buf1,x
inc path_buf1
ldx path_buf2
cpx #3
bcc finish
;; Shift right string down.
ldx #2
loop: lda path_buf2+1,x
sta path_buf2,x
inx
cpx path_buf2
bne loop
;; Redraw (the whole thing)
finish: dec path_buf2
MGTK_RELAY_CALL MGTK::MoveTo, name_input_textpos
MGTK_RELAY_CALL MGTK::SetPortBits, name_input_mapinfo
addr_call draw_text1, path_buf1
addr_call draw_text1, path_buf2
addr_call draw_text1, str_2_spaces
lda winfo_alert_dialog
jsr set_port_from_window_id
rts
.endproc
;;; ============================================================
;;; Move IP to start of input field.
.proc input_field_ip_start
;; Any characters to left of IP?
lda path_buf1
bne :+
rts
;; Any characters to right of IP?
: ldx path_buf2
cpx #1
beq move
;; Preserve right characters up to make room.
;; TODO: Why not just shift them up???
loop1: lda path_buf2,x
sta split_buf-1,x
dex
cpx #1
bne loop1
ldx path_buf2
;; Move characters left to right
move: dex
stx split_buf
ldx path_buf1
loop2: lda path_buf1,x
sta path_buf2+1,x
dex
bne loop2
;; Adjust lengths.
lda str_insertion_point+1
sta path_buf2+1
inc path_buf1
lda path_buf1
sta path_buf2
lda path_buf1
clc
adc split_buf
tay
pha
;; Append right right characters again if needed.
ldx split_buf
beq finish
loop3: lda split_buf,x
sta path_buf2,y
dex
dey
cpy path_buf2
bne loop3
finish: pla
sta path_buf2
copy #0, path_buf1
MGTK_RELAY_CALL MGTK::MoveTo, name_input_textpos ; Seems unnecessary???
jsr draw_filename_prompt
rts
.endproc
;;; ============================================================
.proc merge_path_buf1_path_buf2
lda path_buf2
cmp #2
bcc done
;; Compute new path_buf1 length
ldx path_buf2
dex
txa
clc
adc path_buf1
pha
;; Copy chars from path_buf2 to path_buf1
tay
ldx path_buf2
loop: lda path_buf2,x
sta path_buf1,y
dex
dey
cpy path_buf1
bne loop
;; Finish up, shrinking path_buf2 to just an insertion point
pla
sta path_buf1
copy #1, path_buf2
done: rts
.endproc
;;; ============================================================
;;; Move IP to end of input field.
.proc input_field_ip_end
jsr merge_path_buf1_path_buf2
MGTK_RELAY_CALL MGTK::MoveTo, name_input_textpos ; Seems unnecessary???
jsr draw_filename_prompt
rts
.endproc
;;; ============================================================
;;; Compute width of path_buf1, offset name_input_textpos, return x coord in (A,X)
.proc measure_path_buf1
textwidth_params := $6
textptr := $6
textlen := $8
result := $9
copy16 #path_buf1+1, textptr
lda path_buf1
sta textlen
bne :+
ldax name_input_textpos::xcoord
rts
: MGTK_RELAY_CALL MGTK::TextWidth, textwidth_params
lda result
clc
adc name_input_textpos::xcoord
tay
lda result+1
adc name_input_textpos::xcoord+1
tax
tya
rts
.endproc
;;; ============================================================
.proc clear_path_buf2
copy #1, path_buf2 ; length
copy str_insertion_point+1, path_buf2+1 ; IP character
rts
.endproc
.proc clear_path_buf1
copy #0, path_buf1 ; length
rts
.endproc
;;; ============================================================
.proc load_aux_from_ptr
target := $20
;; Backup copy of $20
COPY_BYTES proc_len+1, target, saved_proc_buf
;; Overwrite with proc
ldx #proc_len
: lda proc,x
sta target,x
dex
bpl :-
;; Call proc
jsr target
pha
;; Restore copy
COPY_BYTES proc_len+1, saved_proc_buf, target
pla
rts
.proc proc
sta RAMRDON
sta RAMWRTON
ldy #0
lda ($06),y
sta RAMRDOFF
sta RAMWRTOFF
rts
.endproc
proc_len = .sizeof(proc)
saved_proc_buf:
.res 20, 0
.endproc
;;; ============================================================
;;; Make str_files singular or plural based on file_count
.proc adjust_str_files_suffix
ldx str_files
lda file_count+1 ; > 255?
bne :+
lda file_count
cmp #2 ; > 2?
bcs :+
copy #' ', str_files,x ; singular
rts
: copy #'s', str_files,x ; plural
rts
.endproc
;;; ============================================================
.proc compose_file_count_string
ldax file_count
jsr int_to_string
ldy #1
copy #' ', str_file_count,y
ldx #0
: cpx str_from_int
beq :+
inx
iny
copy str_from_int,x, str_file_count,y
bne :-
: iny
copy #' ', str_file_count,y
sty str_file_count
rts
.endproc
;;; ============================================================
.proc copy_name_to_buf0
ptr := $6
ldy #0
lda (ptr),y
tay
: lda (ptr),y
sta path_buf0,y
dey
bpl :-
rts
.endproc
.proc copy_name_to_buf1
ptr := $6
ldy #0
lda (ptr),y
tay
: lda (ptr),y
sta path_buf1,y
dey
bpl :-
rts
.endproc
;;; ============================================================
clear_target_file_rect:
jsr set_fill_white
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::current_target_file_rect
rts
clear_dest_file_rect:
jsr set_fill_white
MGTK_RELAY_CALL MGTK::PaintRect, desktop_aux::current_dest_file_rect
rts
set_fill_white:
MGTK_RELAY_CALL MGTK::SetPenMode, pencopy
rts
reset_grafport3a:
MGTK_RELAY_CALL MGTK::InitPort, grafport3
MGTK_RELAY_CALL MGTK::SetPort, grafport3
rts
;;; ============================================================
str_preview_fot:
PASCAL_STRING "Preview/show.image.file"
str_preview_fnt:
PASCAL_STRING "Preview/show.font.file"
str_preview_txt:
PASCAL_STRING "Preview/show.text.file"
;;; ============================================================
PAD_TO $BF00
.endproc ; desktop_main
desktop_main_pop_pointers := desktop_main::pop_pointers
desktop_main_push_pointers := desktop_main::push_pointers
;;; ============================================================
;;; Segment loaded into MAIN $800-$FFF
;;; ============================================================
;;; Init sequence - machine identification, etc
.proc desktop_800
.org $800
start:
;;; ============================================================
;;; Set the reset vector to cold start
.scope hook_reset_vector
;; Main hook
lda #<desktop_main::reset_handler
sta RESETVEC
lda #>desktop_main::reset_handler
sta RESETVEC+1
eor #$A5
sta RESETVEC+2
.endscope
;;; ============================================================
;;; Detect Machine Type
;;; NOTE: Starts with ROM paged in, exits with LCBANK1 paged in.
.scope machine_type
;; See Apple II Miscellaneous #7: Apple II Family Identification
;; First, detect IIgs
sec ; Follow detection protocol
jsr ID_BYTE_FE1F ; RTS on pre-IIgs
bcs :+ ; carry clear = IIgs
copy #$80, is_iigs_flag
:
;; Now stash the bytes we need
copy ID_BYTE_FBB3, id_FBB3 ; $06 = IIe or later
copy ID_BYTE_FBC0, id_FBC0 ; $00 = IIc or later
copy ID_BYTE_FBBF, id_FBBF ; IIc ROM version (IIc+ = $05)
copy ID_BYTE_FB1E, id_FB1E ; $AC = Laser 128
;; ... and page in LCBANK1
sta ALTZPON
lda LCBANK1
lda LCBANK1
sta SET80COL
;; Ensure we're on a IIe or later
lda id_FBB3
cmp #$06 ; Ensure a IIe or later
beq :+
brk ; Otherwise (][, ][+, ///), just crash
;; State needed by MGTK
: copy id_FBB3, startdesktop_params::machine
copy id_FBC0, startdesktop_params::subid
;; Identify machine type (double-click timer, other flags)
lda id_FBC0
beq is_iic ; $FBC0 = $00 -> is IIc or IIc+
bit is_iigs_flag
bmi is_iigs
;; IIe (or IIe Option Card, or Laser 128)
lda id_FB1E ; Is it a Laser 128?
cmp #$AC
bne is_iie
copy #$80, is_laser128_flag
lda #$FD ; Assume accelerated?
ldxy #DeskTop::Settings::kDefaultDblClickSpeed*4
jmp end
;; IIe (or IIe Option Card)
is_iie: lda #$96
ldxy #DeskTop::Settings::kDefaultDblClickSpeed*1
jmp end
;; IIgs
is_iigs:
lda #$FD
ldxy #DeskTop::Settings::kDefaultDblClickSpeed*4
jmp end
;; IIc or IIc+
is_iic: lda id_FBBF ; ROM version
cmp #$05 ; IIc Plus = $05
bne :+
copy #$80, is_iic_plus_flag
: lda #$FA
ldxy #DeskTop::Settings::kDefaultDblClickSpeed*4
jmp end
id_FB1E: .byte 0
id_FBB3: .byte 0
id_FBC0: .byte 0
id_FBBF: .byte 0
end:
sta machine_type
;; Only set if not previously configured
lda DeskTop::Settings::dblclick_speed
ora DeskTop::Settings::dblclick_speed+1
bne :+
stxy DeskTop::Settings::dblclick_speed
:
.endscope
;;; ============================================================
;;; Back up DEVLST
.scope
;; Make a copy of the original device list
ldx DEVCNT
inx
: lda DEVLST-1,x
sta devlst_backup,x
dex
bpl :-
;; fall through
.endscope
;;; ============================================================
;;; Detach aux-memory RAM Disk
.scope
;; Look for /RAM
ldx DEVCNT
: lda DEVLST,x
;; BUG: ProDOS Tech Note #21 says $B3,$B7,$BB or $BF could be /RAM
cmp #(1<<7 | 3<<4 | DT_RAM) ; unit_num for /RAM is Slot 3, Drive 2
beq found_ram
dex
bpl :-
bmi end
found_ram:
jsr remove_device
;; fall through
end:
.endscope
;;; ============================================================
;;; Initialize MGTK
.scope
MGTK_RELAY_CALL MGTK::SetDeskPat, DeskTop::Settings::pattern
MGTK_RELAY_CALL MGTK::StartDeskTop, startdesktop_params
jsr desktop_main::set_mono_mode
MGTK_RELAY_CALL MGTK::SetMenu, splash_menu
MGTK_RELAY_CALL MGTK::SetCursor, watch_cursor
MGTK_RELAY_CALL MGTK::ShowCursor
;; fall through
.endscope
;;; ============================================================
;;; Populate icon_entries table
.scope
ptr := $6
jsr desktop_main::push_pointers
copy16 #icon_entries, ptr
ldx #1
loop: cpx #max_icon_count
bne :+
jsr desktop_main::pop_pointers
jmp end
: txa
pha
asl a
tax
copy16 ptr, icon_entry_address_table,x
pla
pha
ldy #0
sta (ptr),y
iny
copy #0, (ptr),y
lda ptr
clc
adc #.sizeof(IconEntry)
sta ptr
bcc :+
inc ptr+1
: pla
tax
inx
jmp loop
end:
.endscope
;;; ============================================================
;;; Zero the window icon tables
.scope
sta RAMWRTON
lda #$00
tax
loop: sta WINDOW_ICON_TABLES + $400,x ; window 8, icon use map
sta WINDOW_ICON_TABLES + $300,x ; window 6, 7
sta WINDOW_ICON_TABLES + $200,x ; window 4, 5
sta WINDOW_ICON_TABLES + $100,x ; window 2, 3
sta WINDOW_ICON_TABLES + $000,x ; window 0, 1 (0=desktop)
inx
bne loop
sta RAMWRTOFF
jmp create_trash_icon
.endscope
;;; ============================================================
trash_name: PASCAL_STRING " Trash "
.proc create_trash_icon
ptr := $6
copy #0, cached_window_id
lda #1
sta cached_window_icon_count
sta icon_count
jsr AllocateIcon
sta trash_icon_num
sta cached_window_icon_list
jsr desktop_main::icon_entry_lookup
stax ptr
ldy #IconEntry::win_type
copy #icon_entry_type_trash, (ptr),y
ldy #IconEntry::iconx
copy16in #desktop_main::create_volume_icon::trash_iconx, (ptr),y
ldy #IconEntry::icony
copy16in #desktop_main::create_volume_icon::trash_icony, (ptr),y
ldy #IconEntry::iconbits
copy16in #trash_icon, (ptr),y
iny
ldx #0
: lda trash_name,x
sta (ptr),y
iny
inx
cpx trash_name
bne :-
lda trash_name,x
sta (ptr),y
;; fall through
.endproc
;;; ============================================================
;;; This removes particular devices from the device list.
;;; * SmartPort devices
;;; * Mapped to Drive 2
;;; * Removable
;;; * With only one actual device present (per STATUS call)
;;; ... but why???
.proc filter_devices
ptr := $06
lda DEVCNT
sta devcnt
inc devcnt
ldx #0
: lda DEVLST,x
and #%10001111 ; drive, not slot, $CnFE status
cmp #%10001011 ; drive 2 ... ??? $CnFE = $Bx ?
beq :+
inx
cpx devcnt
bne :-
jmp done
: lda DEVLST,x ; unit_num
stx index
sp_addr := $0A
jsr desktop_main::find_smartport_dispatch_address
bne done ; not SmartPort
;; Execute SmartPort call
jsr smartport_call
.byte 0 ; $00 = STATUS
.addr smartport_params
bcs done
lda $1F00 ; number of devices
cmp #2
bcs done
;; Single device - remove from DEVLST - Why ???
ldx index
: copy DEVLST+1,x, DEVLST,x
inx
cpx devcnt
bne :-
dec DEVCNT
done: jmp end
index: .byte 0
smartport_call:
jmp (sp_addr)
smartport_params:
.byte $03 ; parameter count
.byte 0 ; unit number (0 = overall status)
.addr $1F00 ; status list pointer
.byte 0 ; status code (0 = device status)
devcnt: .byte 0
end:
.endproc
;;; ============================================================
.proc load_selector_list
ptr1 := $6
ptr2 := $8
selector_list_io_buf := $1000
selector_list_data_buf := $1400
selector_list_data_len := $400
MGTK_RELAY_CALL MGTK::CheckEvents
copy #0, L0A92
jsr read_selector_list
bne done
lda selector_list_data_buf
clc
adc selector_list_data_buf+1
sta num_selector_list_items
lda #0
sta LD344
lda selector_list_data_buf
sta L0A93
L0A3B: lda L0A92
cmp L0A93
beq done
jsr calc_data_addr
stax ptr1
lda L0A92
jsr calc_entry_addr
stax ptr2
ldy #0
lda (ptr1),y
tay
L0A59: lda (ptr1),y
sta (ptr2),y
dey
bpl L0A59
ldy #15
lda (ptr1),y
sta (ptr2),y
lda L0A92
jsr calc_data_str
stax ptr1
lda L0A92
jsr calc_entry_str
stax ptr2
ldy #0
lda (ptr1),y
tay
L0A7F: lda (ptr1),y
sta (ptr2),y
dey
bpl L0A7F
inc L0A92
inc selector_menu
jmp L0A3B
done: jmp calc_header_item_widths
L0A92: .byte 0
L0A93: .byte 0
.byte 0
;;; --------------------------------------------------
calc_data_addr:
jsr desktop_main::a_times_16
clc
adc #<(selector_list_data_buf+2)
tay
txa
adc #>(selector_list_data_buf+2)
tax
tya
rts
calc_entry_addr:
jsr desktop_main::a_times_16
clc
adc #<run_list_entries
tay
txa
adc #>run_list_entries
tax
tya
rts
calc_entry_str:
jsr desktop_main::a_times_64
clc
adc #<run_list_paths
tay
txa
adc #>run_list_paths
tax
tya
rts
calc_data_str:
jsr desktop_main::a_times_64
clc
adc #<(selector_list_data_buf+2 + $180)
tay
txa
adc #>(selector_list_data_buf+2 + $180)
tax
tya
rts
;;; --------------------------------------------------
DEFINE_OPEN_PARAMS open_params, str_selector_list, selector_list_io_buf
str_selector_list:
PASCAL_STRING "Selector.List"
DEFINE_READ_PARAMS read_params, selector_list_data_buf, selector_list_data_len
DEFINE_CLOSE_PARAMS close_params
.proc read_selector_list
MLI_RELAY_CALL OPEN, open_params
;; bne done
bne write_selector_list
lda open_params::ref_num
sta read_params::ref_num
MLI_RELAY_CALL READ, read_params
MLI_RELAY_CALL CLOSE, close_params
done: rts
.endproc
DEFINE_CREATE_PARAMS create_params, str_selector_list, ACCESS_DEFAULT, $F1
DEFINE_WRITE_PARAMS write_params, selector_list_data_buf, selector_list_data_len
.proc write_selector_list
ptr := $06
;; Clear buffer
copy16 #selector_list_data_buf, ptr
ldx #>selector_list_data_len ; number of pages
lda #0
ploop: ldy #0
: sta (ptr),y
dey
bne :-
dex
bne ploop
;; Write out file
MLI_RELAY_CALL CREATE, create_params
bne done
MLI_RELAY_CALL OPEN, open_params
lda open_params::ref_num
sta write_params::ref_num
sta close_params::ref_num
MLI_RELAY_CALL WRITE, write_params ; two blocks of $400
MLI_RELAY_CALL WRITE, write_params
MLI_RELAY_CALL CLOSE, close_params
done: rts
.endproc
.endproc
;;; ============================================================
.proc calc_header_item_widths
;; Enough space for "123456"
addr_call desktop_main::measure_text1, str_from_int
stax dx
;; Width of "123456 Items"
addr_call desktop_main::measure_text1, str_items
addax dx, width_items_label
;; Width of "123456K in disk"
addr_call desktop_main::measure_text1, str_k_in_disk
addax dx, width_k_in_disk_label
;; Width of "123456K available"
addr_call desktop_main::measure_text1, str_k_available
addax dx, width_k_available_label
add16 width_k_in_disk_label, width_k_available_label, width_right_labels
add16 width_items_label, #5, width_items_label_padded
add16 width_items_label_padded, width_k_in_disk_label, width_left_labels
add16 width_left_labels, #3, width_left_labels
jmp end
dx: .word 0
end:
.endproc
;;; ============================================================
;;; Enumerate Desk Accessories
.scope
MGTK_RELAY_CALL MGTK::CheckEvents
read_dir_buffer := $1400
;; Does the directory exist?
MLI_RELAY_CALL GET_FILE_INFO, get_file_info_params
beq :+
jmp end
: lda get_file_info_type
cmp #FT_DIRECTORY
beq open_dir
jmp end
open_dir:
MLI_RELAY_CALL OPEN, open_params
lda open_ref_num
sta read_ref_num
sta close_ref_num
MLI_RELAY_CALL READ, read_params
lda #0
sta entry_num
sta desk_acc_num
lda #1 ; First block has header instead of entry
sta entry_in_block
lda read_dir_buffer + SubdirectoryHeader::file_count
and #$7F
sta file_count
lda #2
sta apple_menu ; "About..." and separator
lda read_dir_buffer + SubdirectoryHeader::entries_per_block
sta entries_per_block
lda read_dir_buffer + SubdirectoryHeader::entry_length
sta entry_length
dir_ptr := $06
da_ptr := $08
copy16 #read_dir_buffer + .sizeof(SubdirectoryHeader), dir_ptr
process_block:
;; TODO: Adjust case
addr_call_indirect desktop_main::adjust_fileentry_case, dir_ptr
ldy #FileEntry::storage_type_name_length
lda (dir_ptr),y
and #NAME_LENGTH_MASK
bne :+
jmp next_entry
: inc entry_num
ldy #FileEntry::file_type
lda (dir_ptr),y
cmp #DA_FILE_TYPE
bne next_entry
ldy #FileEntry::aux_type+1 ; high bit set = skip
lda (dir_ptr),y
bmi next_entry
;; Compute slot in DA name table
is_da: inc desk_acc_num
copy16 #desk_acc_names, da_ptr
lda #0
sta ptr_calc_hi
lda apple_menu ; num menu items
sec
sbc #2 ; ignore "About..." and separator
asl a
rol ptr_calc_hi
asl a
rol ptr_calc_hi
asl a
rol ptr_calc_hi
asl a
rol ptr_calc_hi
clc
adc da_ptr
sta da_ptr
lda ptr_calc_hi
adc da_ptr+1
sta da_ptr+1
;; Copy name
ldy #FileEntry::storage_type_name_length
lda (dir_ptr),y
and #NAME_LENGTH_MASK
sta (da_ptr),y
tay
: lda (dir_ptr),y
sta (da_ptr),y
dey
bne :-
;; Convert periods to spaces
lda (da_ptr),y
tay
loop: lda (da_ptr),y
cmp #'.'
bne :+
lda #' '
sta (da_ptr),y
: dey
bne loop
inc apple_menu ; number of menu items
next_entry:
;; Room for more DAs?
lda desk_acc_num
cmp #max_desk_acc_count
bcc :+
jmp close_dir
;; Any more entries in dir?
: lda entry_num
cmp file_count
bne :+
jmp close_dir
;; Any more entries in block?
: inc entry_in_block
lda entry_in_block
cmp entries_per_block
bne :+
MLI_RELAY_CALL READ, read_params
copy16 #read_dir_buffer + 4, dir_ptr
lda #0
sta entry_in_block
jmp process_block
: add16_8 dir_ptr, entry_length, dir_ptr
jmp process_block
close_dir:
MLI_RELAY_CALL CLOSE, close_params
jmp end
DEFINE_OPEN_PARAMS open_params, str_desk_acc, $1000
open_ref_num := open_params::ref_num
DEFINE_READ_PARAMS read_params, read_dir_buffer, BLOCK_SIZE
read_ref_num := read_params::ref_num
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params, str_desk_acc
get_file_info_type := get_file_info_params::file_type
.byte 0
DEFINE_CLOSE_PARAMS close_params
close_ref_num := close_params::ref_num
str_desk_acc:
PASCAL_STRING "Desk.acc"
file_count: .byte 0
entry_num: .byte 0
desk_acc_num: .byte 0
entry_length: .byte 0
entries_per_block: .byte 0
entry_in_block: .byte 0
ptr_calc_hi: .byte 0
end:
.endscope
;;; ============================================================
;;; Populate volume icons and device names
;;; TODO: Dedupe with cmd_check_drives
.scope
devname_ptr := $08
ldy #0
sty desktop_main::pending_alert
;; Enumerate DEVLST in reverse order (most important volumes first)
lda DEVCNT
sta device_index
process_volume:
lda device_index
asl a
tay
copy16 device_name_table,y, devname_ptr
ldy device_index
lda DEVLST,y
pha ; save all registers
txa
pha
tya
pha
inc cached_window_icon_count
inc icon_count
lda DEVLST,y
ldx cached_window_icon_count
jsr desktop_main::create_volume_icon ; A = unit number, X = icon index, Y = device number
sta cvi_result
MGTK_RELAY_CALL MGTK::CheckEvents
pla ; restore all registers
tay
pla
tax
pla
pha
lda cvi_result
cmp #ERR_DEVICE_NOT_CONNECTED
bne :+
ldy device_index ; BUG? Is there a missing pla instruction in this path?
lda DEVLST,y
and #$0F
beq select_template
ldx device_index
jsr remove_device
jmp next
: cmp #ERR_DUPLICATE_VOLUME
bne select_template
lda #ERR_DUPLICATE_VOL_NAME
sta desktop_main::pending_alert
;; This section populates device_name_table -
;; it determines which device type string to use, and
;; fills in slot and drive as appropriate.
;;
;; This is for a "Check" menu present in MouseDesk 1.1
;; but which was removed in MouseDesk 2.0, which allowed
;; refreshing individual windows. It is also used in the
;; Format/Erase disk dialog.
.proc select_template
pla ; unit number into A
pha
jsr desktop_main::get_device_type
sta device_type
;; Copy template to device name
asl ; * 2
tax
src := $06
copy16 device_template_table,x, src
ldy #0
lda (src),y
tay
: lda (src),y
sta (devname_ptr),y
dey
bpl :-
;; Insert Slot #
pla ; unit number into A
pha
and #%01110000 ; slot (from DSSSxxxx)
lsr a
lsr a
lsr a
lsr a
ora #'0'
ldx device_type
ldy device_template_slot_offset_table,x
sta (devname_ptr),y
;; Insert Drive #
pla ; unit number into A
pha
rol a ; set carry to drive - 1
lda #0 ; 0 + 1 + carry...
adc #1 ; now 1 or 2
ora #'0' ; convert to '1' or '2'
ldx device_type
ldy device_template_drive_offset_table,x
beq :+ ; 0 = no drive # for this type
sta (devname_ptr),y
:
.endproc
done_drive_num:
pla
next: dec device_index
lda device_index
bpl :+
bmi populate_startup_menu
: jmp process_volume ; next!
device_type:
.byte 0
device_index:
.byte 0
cvi_result:
.byte 0
.endscope
;;; ============================================================
;; Remove device num in X from devices list
.proc remove_device
dex
: inx
copy DEVLST+1,x, DEVLST,x
lda device_to_icon_map+1,x
sta device_to_icon_map,x
cpx DEVCNT
bne :-
dec DEVCNT
rts
.endproc
;;; ============================================================
.proc populate_startup_menu
slot_ptr := $06 ; pointed at $Cn00
table_ptr := $08 ; points into slot_string_table
lda #7
sta slot
lda #0
sta slot_ptr
tax ; X = menu entry
;; Identify ProDOS device in slot by ID bytes
loop: lda slot
ora #$C0 ; hi byte of $Cn00
sta slot_ptr+1
ldy #$01 ; $Cn01 == $20 ?
lda (slot_ptr),y
cmp #$20
bne next
ldy #$03 ; $Cn03 == $00 ?
lda (slot_ptr),y
cmp #$00
bne next
ldy #$05 ; $Cn05 == $03 ?
lda (slot_ptr),y
cmp #$03
bne next
;; It is a ProDOS device - prepare menu item.
txa ; pointer to nth sNN string
pha
asl a
tax
copy16 slot_string_table,x, table_ptr
ldy startup_menu_item_1 ; replace second-from-last char
dey
lda slot
ora #'0'
sta (table_ptr),y
pla
tax
inx
next: dec slot
bne loop
;; Set number of menu items.
stx startup_menu
jmp initialize_disks_in_devices_tables
slot: .byte 0
slot_string_table:
.addr startup_menu_item_1
.addr startup_menu_item_2
.addr startup_menu_item_3
.addr startup_menu_item_4
.addr startup_menu_item_5
.addr startup_menu_item_6
.addr startup_menu_item_7
.endproc
;;; ============================================================
;;; Enumerate DEVLST and find removable devices; build a list of
;;; these, and check to see which have disks in them. The list
;;; will be polled periodically to detect changes and refresh.
;;;
;;; Some hardware (machine/slot) combinations are filtered out
;;; due to known-buggy firmware.
.proc initialize_disks_in_devices_tables
ldx #0
ldy DEVCNT
loop: lda DEVLST,y
and #$0F
cmp #DT_REMOVABLE
beq append ; yes
next: dey
bpl loop
stx desktop_main::removable_device_table
stx desktop_main::disk_in_device_table
jsr desktop_main::check_disks_in_devices
;; Make copy of table
ldx desktop_main::disk_in_device_table
beq done
: copy desktop_main::disk_in_device_table,x, desktop_main::last_disk_in_devices_table,x
dex
bpl :-
done: jmp final_setup
append: lda DEVLST,y ; add it to the list
;; Don't issue STATUS calls to IIc Plus Slot 5 firmware, as it causes
;; the motor to spin. https://github.com/inexorabletash/a2d/issues/25
bit is_iic_plus_flag
bpl :+
and #%01110000 ; mask off slot
cmp #$50 ; is it slot 5?
beq next ; if so, ignore
;; Don't issue STATUS calls to Laser 128 Slot 7 firmware, as it causes
;; hangs in some cases. https://github.com/inexorabletash/a2d/issues/138
: bit is_laser128_flag
bpl :+
and #%01110000 ; mask off slot
cmp #$70 ; is it slot 7?
beq next ; if so, ignore
: lda DEVLST,y
inx
sta desktop_main::removable_device_table,x
bne next ; always
.endproc
;;; ============================================================
.proc final_setup
;; Final MGTK configuration
MGTK_RELAY_CALL MGTK::CheckEvents
MGTK_RELAY_CALL MGTK::SetMenu, desktop_aux::desktop_menu
MGTK_RELAY_CALL MGTK::SetCursor, pointer_cursor
lda #0
sta active_window_id
jsr desktop_main::update_window_menu_items
jsr desktop_main::disable_eject_menu_item
jsr desktop_main::disable_file_menu_items
jmp desktop_main::enter_main_loop
.endproc
;;; ============================================================
;;; High bits set if specific machine type detected.
is_iigs_flag:
.byte 0
is_iic_plus_flag:
.byte 0
is_laser128_flag:
.byte 0
;;; ============================================================
PAD_TO $1000
.endproc ; desktop_800