Jump to content

Photo

Programmatic Menu Code

cse oblivion scripting cs obse

  • Please log in to reply
3 replies to this topic

#1
VencGanence

VencGanence

    Enthusiast

  • Supporter
  • PipPip
  • 149 posts

I'm moving onto the last big part of growth armor's coding:  menu code.

 

Like Dusfergon, growth armor will have a form change function and unlike Dusfergon, I stored the data in a proper array this time.  So, I want ideas about how to code menus that create themselves dynamically.

As in, any change I make to the array - re-ordering, adding or subtracting entries - will be reflected in the menu boxes without having to rewrite the code.  I have an idea of how to do the buttons using $Stringify, if not MessageBoxEX, but the dynamic page count...

 

The menu code I wrote for Dusfergon can be found here, here and here.  Full V1.6.1 repository here.



#2
VencGanence

VencGanence

    Enthusiast

  • Supporter
  • PipPip
  • 149 posts

I've got a start.  It's fine for small lists, but I'll need something more to reduce navigation time on large lists.

;Description
;-----------------------------------------------------------------------------
;Menu for changing meshes.
;Takes a name, array of mesh data, last button pressed and current menu page.
;Uses Page to determine which section of Data to list in the menu.
;Makes use of MessageBox inability to handle empty strings to truncate
;unneeded buttons.
;-----------------------------------------------------------------------------

;Parameters
;-----------------------------------------------------------------------------
string_var Name
array_var Data
short Button ;Return value
short Page ;Return value

string_var But0
string_var But1
string_var But2
string_var But3
string_var But4
string_var But5
string_var But6
string_var But7
string_var But8
short Size
short i
short j
array_var Opt
;-----------------------------------------------------------------------------

;-----------------------------------------------------------------------------
begin Function { Name, Data, Button, Page }
;-----------------------------------------------------------------------------

	if ( Button == -2 )

		;Header
		Let Name += " Form (p. " + $(Page+1) + "):"

		if ( Page == 0 )
			Let But0 := "Back"
		else
			Let But0 := "Prev"
		endif

		;Empty strings so MessageBox short circuits
		Let Opt := ar_Map 0::"" 1::"" 2::"" 3::"" 4::"" 5::"" 6::""

		;Until all 7 buttons are filled or reach end of Data
		Let i := Page * 7
		Let j := i + 7
		Let Size := ar_Size Data
		while ( i < j && i < Size )

			Let Opt[i%7] := Data[i][6]

			Let i += 1
		loop

		Let But1 := Opt[0]
		Let But2 := Opt[1]
		Let But3 := Opt[2]
		Let But4 := Opt[3]
		Let But5 := Opt[4]
		Let But6 := Opt[5]
		Let But7 := Opt[6]

		;Truncate next if all 7 buttons are filled but there is no next page
		if ( i == Size )
			Let But8 := ""
		else
			Let But8 := "Next"
		endif


		;Display menu
		MessageBox $Name "Cancel" $But0 $But1 $But2 $But3 $But4 $But5 $But6 $But7 $But8
		Let Button := -1
		
	elseif ( Button < 0 )

		Let Button := GetButtonPressed

	endif

	
	SetFunctionValue ar_Map 0::Button 1::Page
	Return
;-----------------------------------------------------------------------------
end ;Function { Name, Data, Button, Page }
;-----------------------------------------------------------------------------

Edited by VencGanence, 31 May 2020 - 11:04 PM.


#3
VencGanence

VencGanence

    Enthusiast

  • Supporter
  • PipPip
  • 149 posts

Speaking of large lists, the mod's up to 16 pages on some body parts, so... yeah. Gonna need a solution to cut down that navigation time.

Thinking of implementing a table of contents atm



#4
VencGanence

VencGanence

    Enthusiast

  • Supporter
  • PipPip
  • 149 posts

Better menu code

;Description
;-----------------------------------------------------------------------------
;Menu for changing meshes.
;Takes an array containing shorts, whose structure is listed below.
;Displays a Table of Contents when SubMenu = 0 and lists page ranges of PgHi
;size.  If there's only one range on the ToC or PgHi <= 0, skips ToC entirely.
;Uses Page to determine which names to display on the buttons when past ToC.
;Returns to ToC if Page < PageLowerBound or Page > PageLowerBound + PgHi. This
;obviously doesn't happen if ToC is skipped.
;Displays a maximum of 7 names per Page, due to MessageBox's button limit.
;
;Makes use of MessageBox's inability to handle empty strings to truncate
;unneeded buttons.
;
;Called when Menu[0] = 4 || 5.
;
;Menu:
;0::MenuIndex
;1::Button
;2::Page
;3::SubMenu
;4::PageLowerBound
;-----------------------------------------------------------------------------

;Parameters
;-----------------------------------------------------------------------------
string_var Name
array_var Data
array_var Menu ;Return value

string_var But0
string_var But1
string_var But2
string_var But3
string_var But4
string_var But5
string_var But6
string_var But7
string_var But8
short Size
short i
short j
float PgCnt
float Count
short PgHi
short PgLo
array_var Opt
;-----------------------------------------------------------------------------

;-----------------------------------------------------------------------------
begin Function { PgHi, Name, Data, Menu }
;-----------------------------------------------------------------------------

	if eval( Menu[1] == -2 )

		Let Size := ar_Size Data
		DebugPrint "Size: %.0f" Size

		Let But0 := "[<Back]"

		;Empty strings so MessageBox short circuits
		Let Opt := ar_Map 0::"" 1::"" 2::"" 3::"" 4::"" 5::"" 6::"" 7::""

		;-----------------------------------------------------------------------------
		;Table of contents
		;-----------------------------------------------------------------------------
		if eval( Menu[3] == 0 )

			;Header
			Let Name += " Form Table of Contents:"
			
			Let PgCnt := Size / 7
			Let PgCnt := Ceil PgCnt

			if ( PgHi > 0 )
				Let Count := PgCnt / PgHi
				Let Count := Ceil Count
			else
				Let Count := 1
			endif
			

			;If only 1 button, skip this submenu
			if ( Count == 1 )

				;Page is negative if we are going [<Back]
				if eval( Menu[2] < 0 )
					Let Menu[0] := 1
				;Else we are going forward
				else
					Let Menu[3] := 1
					Let Menu[4] := Menu[5] := 0
				endif

				;Button is already -2
				SetFunctionValue Menu
				Return
				
			;Adjust PgHi if going over 8 buttons
			elseif ( Count > 8 )

				Let Count := PgCnt / 8
				Let PgHi := Ceil Count

				;Recalc Count
				Let Count := PgCnt / PgHi
				Let Count := Ceil Count
	
			endif

			;Store PgHi incase it was modified
			;Menu[5] will be wiped once Menu[0] = 0
			Let Menu[5] := PgHi
			

			;Populate Opt with page ranges
			Let i := 0
			while ( i < Count )

				Let PgLo := 1 + ( i * PgHi )
				
				Let Opt[i] := "Page " + $(PgLo)

				;Get the end of the buttons range
				Let j := PgLo + PgHi - 1
				if ( j > PgCnt )
					Let j := PgCnt
				endif

				;Only show a range if there is a range
				if ( j > PgLo )
					Let Opt[i] += " - " + $(j)
				endif
				
				Let i += 1
			loop

		;-----------------------------------------------------------------------------
		;Individual pages
		;-----------------------------------------------------------------------------
		elseif eval( Menu[3] == 1 )

			;Header
			Let Name += " Form (p. " + $(Menu[2]+1) + "):"

			;Change Back to Prev if hitting it will return to another individual page
			if eval( Menu[2] != Menu[4] )
				Let But0 := "[<Prev]"
			endif

			;Until all 7 buttons are filled or reach end of Data
			Let i := Menu[2] * 7
			Let j := i + 7
			while ( i < j && i < Size )

				Let Opt[i%7] := Data[i][6]

				Let i += 1
			loop

			;Truncate [Next>] if all 7 buttons are filled but there is no next page
			if ( i < Size )
				if eval( Menu[5] > 0 && Menu[2] >= Menu[4] + Menu[5] - 1 )
					Let Opt[7] := "[Back>]"
				else
					Let Opt[7] := "[Next>]"
				endif
			endif

		endif


		Let But1 := Opt[0]
		Let But2 := Opt[1]
		Let But3 := Opt[2]
		Let But4 := Opt[3]
		Let But5 := Opt[4]
		Let But6 := Opt[5]
		Let But7 := Opt[6]
		Let But8 := Opt[7]

		;Display menu
		MessageBox $Name "[Cancel]" $But0 $But1 $But2 $But3 $But4 $But5 $But6 $But7 $But8
		Let Menu[1] := -1
		
	elseif eval( Menu[1] < 0 )
	
		Let Menu[1] := GetButtonPressed
	
	elseif eval( Menu[1] == 0 )
	
		;Cancel
		DebugPrint "Cancelling MeshMenu."
		Let Menu[0] := 0
	
	elseif eval( Menu[1] == 1 )

		Let Menu[1] := -2

		if eval( Menu[3] == 0 )

			;Back
			DebugPrint "Returning to FormMenu."
			Let Menu[0] := 1
			
		elseif eval( Menu[3] == 1 )

			;Prev
			Let Menu[2] -= 1

			if eval( Menu[2] < Menu[4] )

				;Back
				DebugPrint "Returning to MeshMenu ToC."
				Let Menu[3] -= 1
		
			endif

		endif

	elseif eval( Menu[3] == 1 && Menu[1] == 9 )

		;Next
		Let Menu[2] += 1
		Let Menu[1] := -2

		if eval( Menu[5] > 0 && Menu[2] >= Menu[4] + Menu[5] )

			;Back
			DebugPrint "Returning to MeshMenu ToC."
			Let Menu[3] -= 1
			
		endif

	else

		;if ToC, adjust Page based on button chosen
		if eval( Menu[3] == 0 )

			;Menu[4] will be wiped once Menu[0] = 0
			Let Menu[2] := Menu[4] := Menu[5] * ( Menu[1] - 2 )
			Let Menu[1] := -2
			
		endif

		Let Menu[3] += 1
	
	endif

	
	SetFunctionValue Menu
	Return
;-----------------------------------------------------------------------------
end ;Function { PgHi, Name, Data, Menu }
;-----------------------------------------------------------------------------

Edited by VencGanence, 09 June 2020 - 05:42 PM.






Also tagged with one or more of these keywords: cse, oblivion, scripting, cs, obse

Page loaded in: 1.032 seconds