; ; dbx.dbx.s ; ; Managing dialogue box control types (MDW) ; ; © 1994 Straylight ; ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis ;----- External dependencies ------------------------------------------------ GET sapphire:dbox GET sapphire:msgs GET sapphire:screen ;----- Main code ------------------------------------------------------------ AREA |Sapphire$$Code|,CODE,READONLY ; --- dbx_declare --- ; ; On entry: R0 == dialogue box handle from dbox ; R1 == pointer to dialogue box definition block ; ; On exit: -- ; ; Use: Declares a dialogue box to be dbx-managed, and declares the ; control types of all its controls. EXPORT dbx_declare dbx_declare ROUT STMFD R13!,{R0-R2,R10,R14} ;Save some registers MOV R10,R0 ;Get dialogue handle ; --- Sort out what needs doing --- LDR R14,[R10,#dbx__defn] ;Is there a dbx definition? CMP R14,#0 ;If so, this isn't zero BEQ %10dbx_declare ;No -- skip onwards ; --- Shut down the existing controls --- MOV R2,R1 ;Keep the control block MOV R0,#dbxEvent_lifeCycle ;Get the lifecycle code LDR R14,[R10,#dbox__flags] ;Load the flags word TST R14,#dbFlag__open ;Is the box open right now? MOVNE R1,#dblc_close ;Tell controls it's closed BLNE dbx__broadcast ;Send the message MOV R1,#dblc_destroy ;Tell controls to shut down BL dbx__broadcast ;Send the message STR R2,[R10,#dbx__defn] ;Save the new control block B %50dbx_declare ;And skip ahead ; --- Set up first dbx controls --- 10dbx_declare STR R1,[R10,#dbx__defn] ;Store the definition pointer ADD R14,R10,#dbox__proc ;Point to the event proc LDMIA R14,{R0-R2} ;Load all the information ADD R14,R10,#dbx__proc ;Point to my bit of data STMIA R14,{R0-R2} ;Save the old handler away ; --- Now set up the dbx handler --- ADR R14,dbx__events ;Point to my event handler STR R14,[R0,#dbox__proc] ;Save this as the new proc STR R10,[R0,#dbox__R10] ;Pass dbox handle in R10 ; --- Send initialise messages --- 50dbx_declare MOV R0,#dbxEvent_lifeCycle ;Get the event code MOV R1,#dblc_create ;Send creation notice BL dbx__broadcast ;Send the message LDR R14,[R10,#dbox__flags] ;Load the flags word TST R14,#dbFlag__open ;Is the dialogue open? MOVNE R1,#dblc_open ;Inform controls it's open BLNE dbx__broadcast ;And send the message ; --- Done (at last) --- LDMFD R13!,{R0-R2,R10,PC}^ ;Return to caller LTORG ; --- dbx_sendEvent --- ; ; On entry: R0 == event code to send ; R1-R7 == depend on the event code ; R10 == dialogue box handle ; ; On exit: C flag as set by event handler ; ; Use: Sends an event to the specified dialogue box. This is ; intended to be used by control handlers, hence the unusual ; placing of the dialogue handle in R10. EXPORT dbx_sendEvent dbx_sendEvent ROUT STMFD R13!,{R8-R10,R12,R14} ;Save some registers MOV R9,R10 ;Pass dialogue handle in R9 LDR R14,[R10,#dbx__defn] ;Is this dialogue box dbx'ed? CMP R14,#0 ;Yes -- then this isn't 0 ADDEQ R14,R10,#dbox__proc ;No -- point to real proc ADDNE R14,R10,#dbx__proc ;Yes -- point to saved proc LDMIA R14,{R8,R10,R12} ;Load the proc bitties ADDS R0,R0,#0 ;Clear the carry flag TEQ R8,#0 ;Is there a handler? MOV R14,PC ;Set up return address MOVNE PC,R8 ;Call the handler then LDMFD R13!,{R8-R10,R12,R14} ;Load the registers I saved ORRCSS PC,R14,#C_flag ;If C set, set C on exit BICCCS PC,R14,#C_flag ;If C clear, clear C on exit LTORG ; --- dbx__events --- ; ; On entry: R0 == event code ; R1-R7 == depend on event type ; R10 == dialogue box handle ; ; On exit: -- ; ; Use: Handles events for a dbx-managed dialogue box. dbx__events ROUT ; --- Make sure it's an interesting event --- CMP R0,#dbEvent_redraw ;Is it a redraw event? BEQ dbx__redraw ;Handle redraws specially CMP R0,#0 ;Is icon handle in R0? BGE %10dbx__events ;Yes -- handle cleverly CMP R0,#dbEvent_help ;Test events with icon in R1 CMPNE R0,#dbEvent_save CMPNE R0,#dbEvent_load CMPNE R0,#dbEvent_menu BEQ %20dbx__events ;If any of them, handle it CMP R0,#dbEvent_drag ;And now ones with icon in R2 CMPNE R0,#dbEvent_key BEQ %30dbx__events CMP R0,#dbEvent_lifeCycle ;Is it a lifecycle broadcast? BEQ %40dbx__events ; --- Don't recognise the event --- ; ; So we'd better pass it to the original dbox handle B dbx_sendEvent ;This handles everything! ; --- Handle mouse click events --- 10dbx__events STMFD R13!,{R0-R2,R14} ;Save some registers away MOV R2,R1 ;Get mouse button state MOV R1,R0 ;Get the icon clicked MOV R0,#dbxEvent_click ;Give control a click event BL dbx__ctrlEvent ;Send it to the control LDMFD R13!,{R0-R2,R14} ;Restore all the registers B %80dbx__events ;Tidy up things with C flag ; --- Handle events with icon handle in R1 --- 20dbx__events STMFD R13!,{R0-R5,R14} ;Save a load of registers CMP R0,#dbEvent_menu ;Is this a menu click event? MOVEQ R0,#dbxEvent_click ;Yes -- then give a click MOVEQ R2,#2 ;And set the `menu' bit MOV R5,#dbxDrop_load ;Assume event is a load CMP R0,#dbEvent_save ;Is this a save event? MOVEQ R5,#dbxDrop_save ;Yes -- it's a save instead CMPNE R0,#dbEvent_load ;Or maybe it's a load event MOVEQ R0,#dbxEvent_drop ;It's a file dropped event CMP R0,#dbEvent_help ;In that case, it's a help? MOVEQ R0,#dbxEvent_help ;Yes -- set up that event BL dbx__ctrlEvent ;Send it to the control LDMFD R13!,{R0-R5,R14} ;Restore a load of registers B %80dbx__events ;And tidy everything up ; --- And now handle the oddities with handles in R2 --- ; ; Both of these work just the same -- swap R2 and R1 over, ; load event code into R0 and dispatch the event 30dbx__events STMFD R13!,{R0-R2,R14} ;Save some registers away EOR R1,R1,R2 ;The standard swap-in-three EOR R2,R1,R2 ;R2 == old_R1 now EOR R1,R1,R2 ;R1 == old_R2 now. Done! CMP R0,#dbEvent_drag ;Was it a drag event? MOVEQ R0,#dbxEvent_click ;Yes -- deliver a click MOVNE R0,#dbxEvent_key ;No -- deliver a keypress BL dbx__ctrlEvent ;Send it to the control LDMFD R13!,{R0-R2,R14} ;Restore the registers B %80dbx__events ;And tidy everything up ; --- Handle lifecycle changes --- 40dbx__events STMFD R13!,{R0,R14} ;Save some registers MOV R0,#dbxEvent_lifeCycle ;Get the event code BL dbx__broadcast ;Send the message out LDMFD R13!,{R0,R14} ;Restore registers B %80dbx__events ;And tidy everything up ; --- Now handle the standard aftermath --- ; ; If the control didn't like it, we pass the whole event on ; to the user dialogue box handler. 80dbx__events BCC dbx_sendEvent ;Send event to user if nec. ORRS PC,R14,#C_flag ;Otherwise, we claim it LTORG ; --- dbx_findData --- ; ; On entry: R0 == icon handle ; R10 == dialogue box handle ; ; On exit: If found, CS and ; R8 == pointer to writable control data ; R9 == pointer to static control data ; else CC and ; R8, R9 corrupted ; ; Use: Allows a control to find its data when called by client ; code. EXPORT dbx_findData dbx_findData ROUT STMFD R13!,{R4-R7,R14} ;Save some registers LDR R9,[R10,#dbx__defn] ;Find the dialogue def block 10dbx_findData LDMIA R9,{R4-R8} ;Load all the information CMP R4,#-1 ;Is the icon handle -1? BEQ %80dbx_findData ;Yes -- icon handle not found CMP R1,R4 ;Is this a match we have? ADDNE R9,R9,R7 ;No -- add in the block size BNE %10dbx_findData ;And loop around again ; --- Find control's workspace if necessary --- ; ; If the user has not supplied control writable data and ; it wants some, an address exception is created. ADD R9,R9,#16 ;Point past this block header TST R6,#dbxFlag_dataR10 :OR: dbxFlag_dataR12 MOVEQ R8,#&80000000 ;Address exception if wanted BEQ %15dbx_findData ;No data -- skip onwards ADD R9,R9,#4 ;Skip past data offset word TST R6,#dbxFlag_dataR10 ;Does he want R10-relative? LDRNE R14,[R10,#dbx__R10] ;Yes -- load user's R10 value LDREQ R14,[R10,#dbx__R12] ;No -- load user's R12 value ADD R8,R14,R8 ;Add in loaded offset nicely 15dbx_findData LDMFD R13!,{R4-R7,R14} ;Unstack registers ORRS PC,R14,#C_flag ;Say we found it OK 80dbx_findData LDMFD R13!,{R4-R7,R14} ;Unstack registers BICS PC,R14,#C_flag ;Say we couldn't find it LTORG ; --- dbx__ctrlEvent --- ; ; On entry: R0 == dbx event code type ; R1 == icon handle to dispatch to ; R2-R7 == depend on the event code ; R10 == dialogue box handle ; ; On exit: Registers preserved, C set if control claimed the event ; ; Use: Sends an event to a control, setting up all the registers ; etc. appropriately. dbx__ctrlEvent ROUT STMFD R13!,{R4-R9,R14} ;Save masses of registers LDR R9,[R10,#dbx__defn] ;Find the dialogue def block MOV R4,R13 ;Point to stacked registers 00 LDMIA R9,{R4-R8} ;Load all the information CMP R4,#-1 ;Is the icon handle -1? BEQ %80dbx__ctrlEvent ;Yes -- icon handle not found CMP R1,R4 ;Is this a match we have? ADDNE R9,R9,R7 ;No -- add in the block size BNE %b00 ;And loop around again BL dbx__deliver ;Deliver the event LDMFD R13!,{R4-R9,R14} ;Unstack registers ORRCSS PC,R14,#C_flag ;And return with C set BICCCS PC,R14,#C_flag ;Or not, appropriately 80 LDMFD R13!,{R4-R9,R14} ;Unstack registers BICS PC,R14,#C_flag ;Event was not claimed LTORG ; --- dbx__deliver --- ; ; On entry: R0 == dbx event code to deliver ; R1-R3 == arguments specific to the event ; R4 == pointer to more arguments for event (R4-R7) ; R5 == (untransformed) pointer to event code ; R6 == dbx control flags ; R7 == size of control block ; R8 == pointer to control writable data ; R9 == address of control information ; R10 == dialogue handle ; ; On exit: Registers preserved, C set if control claimed the event ; ; Use: Delivers an event to a control. dbx__deliver ROUT STMFD R13!,{R4-R9,R12,R14} ;Save some registers ; --- Check that the control is interested --- BL dbx__xform ;Translate R5 nicely LDMIA R5,{R7,R12,R14} ;Load control R12 and flags CMP R7,#0 ;Is there an address? LDRNE R7,[R7,#0] ;Load workspace offset LDRNE R12,[R11,-R12] ;Load workspace base address ADDNE R12,R12,R7 ;And work out workspace MOV R7,#1 ;To shift the bit around TST R14,R7,LSL R0 ;Check event's mask bit BEQ %80dbx__deliver ;Bit is clear -- ignore event ; --- Find control's workspace if necessary --- ; ; If the user has not supplied control writable data and ; it wants some, an address exception is created. ADD R9,R9,#16 ;Point past this block header TST R6,#dbxFlag_dataR10 :OR: dbxFlag_dataR12 MOVEQ R8,#&80000000 ;Address exception if wanted BEQ %15dbx__deliver ;No data -- skip onwards ADD R9,R9,#4 ;Skip past data offset word TST R6,#dbxFlag_dataR10 ;Does he want R10-relative? LDRNE R14,[R10,#dbx__R10] ;Yes -- load user's R10 value LDREQ R14,[R10,#dbx__R12] ;No -- load user's R12 value ADD R8,R14,R8 ;Add in loaded offset nicely ; --- Writable data pointer is set up then --- 15dbx__deliver LDMIA R4,{R4-R7} ;Fetch saved registers MOV R14,PC ;Set up return address nicely ADD PC,R5,#12 ;Call the control's code LDMFD R13!,{R4-R9,R12,R14} ;Restore all the registers ORRCSS PC,R14,#C_flag ;If C set, set C on return BICCCS PC,R14,#C_flag ;Otherwise clear C on return ; --- We couldn't find a suitable control --- 80dbx__deliver LDMFD R13!,{R4-R9,R12,R14} ;Restore all the registers BICS PC,R14,#C_flag ;Clear C -- event ignored LTORG ; --- dbx__broadcast --- ; ; On entry: R0 == dbx event code ; R1-R7 depend on the event code ; R10 == dialogue box handle ; ; On exit: --- ; ; Use: Sends an event to all controls in a dialogue box. dbx__broadcast ROUT STMFD R13!,{R4-R9,R14} ;Save some registers LDR R9,[R10,#dbx__defn] ;Find the control definition MOV R4,R13 ;Point to stacked arguments 00 LDMIA R9,{R4-R8} ;Load information from block CMP R4,#-1 ;Is icon number bogus? LDMEQFD R13!,{R4-R9,PC}^ ;Yes -- then return BL dbx__deliver ;Deliver the event ADD R9,R9,R7 ;Move on to next event B %b00 ;And keep on looping LTORG ; --- dbx__xform --- ; ; On entry: R5 == pointer to a dbx control ; ; On exit: R5 possibly modified ; ; Use: Translates R5 to point to a dbx control block. The problem ; is dynamic linking: R5 might actually point to a branch ; to the real control. So we spot that here and hack around ; the problem. dbx__xform ROUT STMFD R13!,{R14} ;Save a register LDR R14,[R5,#0] ;Load the pointer out CMP R14,#&80000000 ;Is the pointer out of range? BICCS R14,R14,#&FF000000 ;Clear instruction bits ADDCS R14,R14,#2 ;Account for pipeline ADDCS R5,R5,R14,LSL #2 ;And work out the address LDMFD R13!,{PC}^ ;And return to caller LTORG ; --- dbx__redraw --- ; ; On entry: R0 == dbEvent_redraw ; R1 == pointer to redraw rectangle block ; R2 == x coordinate of window origin on screen ; R3 == y coordinate of window origin on screen ; R10 == dialogue box handle ; ; On exit: Registers preserved, C clear on exit unless user claimed ; the redraw event. ; ; Use: Handles a redraw event for a dbx-controlled dialogue box. ; We go through all the controls in the block and test which ; ones want redraw events. For each one, we set the graphics ; rectangle to the intersection of the icon bounding box and ; the redraw rectangle, load the screen position of the icon ; and pass the control handler a redraw event. dbx__redraw ROUT STMFD R13!,{R14} ;Save return address BL dbx_sendEvent ;Let the user do some redraw LDMCSFD R13!,{PC} ;If it was claimed, return STMFD R13!,{R0-R9,R12} ;Save some more registers ; --- Set up some standard registers --- MOV R6,R2 ;Look after the origin coords MOV R7,R3 ;Both x and y -- we need 'em ADD R5,R1,#28 ;Point to redraw rectangle LDR R0,[R10,#dbx__defn] ;Find the control definitions ; --- Now loop through the controls --- 10dbx__redraw LDMIA R0,{R1-R4,R8} ;Load the control information CMP R1,#-1 ;Is this the end of the list? BEQ %90dbx__redraw ;Yes -- return to caller ; --- Check if the control likes redraw events --- LDR R14,[R2,#0] ;Load the value out CMP R14,#&80000000 ;Is it out of range? BICCS R14,R14,#&ff000000 ;Yes -- clear instruction ADDCS R14,R14,#2 ;Compensate for pipeline ADDCS R2,R2,R14,LSL #2 ;And work out real address LDMIA R2,{R9,R12,R14} ;Load control R12 and flags CMP R9,#0 ;Is there an address? LDRNE R9,[R9,#0] ;Load workspace offset LDRNE R12,[R11,-R12] ;Load workspace base ADDNE R12,R12,R9 ;Work out workspace address TST R14,#1<