From b8c6631fe21550ca7a40158b6da1473f645abbd3 Mon Sep 17 00:00:00 2001 From: Jonathan Payne Date: Thu, 18 Sep 2014 20:33:35 -0700 Subject: [PATCH] Update OptionsCustomizeProfile --- .../ScreenOptionsCustomizeProfile overlay.lua | 249 ++++++++++++++++-- 1 file changed, 230 insertions(+), 19 deletions(-) diff --git a/Themes/default/BGAnimations/ScreenOptionsCustomizeProfile overlay.lua b/Themes/default/BGAnimations/ScreenOptionsCustomizeProfile overlay.lua index 24d02f4c43..875bb5aa81 100644 --- a/Themes/default/BGAnimations/ScreenOptionsCustomizeProfile overlay.lua +++ b/Themes/default/BGAnimations/ScreenOptionsCustomizeProfile overlay.lua @@ -2,11 +2,28 @@ -- Also, this might be rewritten to us a proper customizable lua menu system -- in the future. +-- Copy this file into your theme, then modify as needed to suit your theme. +-- Each of the things on this list has a comment marking it, so you can +-- quickly find it by searching. +-- Things you will want to change: +-- 1. The Numpad +-- 2. The Cursor +-- 3. The Menu Items +-- 4. The Menu Values +-- 4.1 The L/R indicators +-- 5. The Menu Fader + local profile= GAMESTATE:GetEditLocalProfile() local cursor_width_padding = 16 local cursor_spacing_value = 30 +-- 1. The Numpad +-- This is what sets up how the numpad looks. See Scripts/04 NumPadEntry.lua +-- for a full description of how to customize a NumPad. +-- Note that if you provide a custom prompt actor for the NumPad, it must +-- have a SetCommand because the NumPad is used any time the player needs to +-- enter a number, and the prompt is updated by running its SetCommand. local number_entry= new_numpad_entry{ Name= "number_entry", InitCommand= cmd(diffusealpha, 0; xy, _screen.cx, _screen.cy * 1.5), @@ -74,6 +91,15 @@ local number_entry= new_numpad_entry{ } } +local function calc_list_pos(value, list) + for i, entry in ipairs(list) do + if entry.setting == value then + return i + end + end + return 1 +end + local function item_value_to_text(item, value) if item.item_type == "bool" then if value then @@ -81,10 +107,61 @@ local function item_value_to_text(item, value) else value= THEME:GetString("ScreenOptionsCustomizeProfile", item.false_text) end + elseif item.item_type == "list" then + local pos= calc_list_pos(value, item.list) + return item.list[pos].display_name end return value end +local char_list= {} +do + local all_chars= CHARMAN:GetAllCharacters() + for i, char in ipairs(char_list) do + char_list[#char_list+1]= { + setting= char:GetCharacterID(), display_name= char:GetDisplayName()} + end +end + +-- Uncomment this section if you need to test the behavior of actors in the +-- character list but don't have any duncing characters to test with. + +local fake_profile_mt= {__index= {}} +local val_list= {} +local function get_set_pair(name, default) + fake_profile_mt.__index["Get"..name]= function(self) + return self[name] + end + fake_profile_mt.__index["Set"..name]= function(self, val) + self[name]= val + end + val_list[#val_list+1]= {name, default} +end +get_set_pair("WeightPounds", 0) +get_set_pair("Voomax", 0) +get_set_pair("BirthYear", 0) +get_set_pair("IgnoreStepCountCalories", false) +get_set_pair("IsMale", true) +get_set_pair("Character", "dietlinde") +fake_profile_mt.__index.init= function(self) + for i, vald in ipairs(val_list) do + self[vald[1]]= vald[2] + end +end + +profile= setmetatable({}, fake_profile_mt) +profile:init() + +char_list= { + {setting= "shake", display_name= "soda"}, + {setting= "freem", display_name= "inc"}, + {setting= "midi", display_name= "man"}, + {setting= "kyz", display_name= "zentun"}, + {setting= "mad", display_name= "matt"}, + {setting= "db", display_name= "k2"}, +} + + local menu_items= { {name= "weight", get= "GetWeightPounds", set= "SetWeightPounds", item_type= "number", auto_done= 100}, @@ -97,18 +174,30 @@ local menu_items= { true_text= "use_heart", false_text= "use_steps"}, {name= "gender", get= "GetIsMale", set= "SetIsMale", item_type= "bool", true_text= "male", false_text= "female"}, - {name= "exit", item_type= "exit"} } +if #char_list > 0 then + menu_items[#menu_items+1]= { + name= "character", get= "GetCharacter", set= "SetCharacter", + item_type= "list", list= char_list} +end +menu_items[#menu_items+1]= {name= "exit", item_type= "exit"} local menu_cursor local menu_pos= 1 local menu_start= SCREEN_TOP + 80 +if #menu_items > 6 then + menu_start= SCREEN_TOP + 68 +end local menu_x= SCREEN_CENTER_X * 0.25 local value_x= ( SCREEN_CENTER_X * 0.25 ) + 256 local fader -local cursor_on_menu= true +local cursor_on_menu= "main" local menu_item_actors= {} local menu_values= {} +local list_pos= 0 +local active_list= {} +local left_showing= false +local right_showing= false local function fade_actor_to(actor, alf) actor:stoptweening() @@ -122,30 +211,66 @@ local function update_menu_cursor() menu_cursor:playcommand("Fit", item) end +local function update_list_cursor() + local valactor= menu_values[menu_pos] + valactor:playcommand("Set", {active_list[list_pos].display_name}) + if list_pos > 1 then + if not left_showing then + valactor:playcommand("ShowLeft") + left_showing= true + end + else + if left_showing then + valactor:playcommand("HideLeft") + left_showing= false + end + end + if list_pos < #active_list then + if not right_showing then + valactor:playcommand("ShowRight") + right_showing= true + end + else + if right_showing then + valactor:playcommand("HideRight") + right_showing= false + end + end +end + local function input(event) local pn= event.PlayerNumber if not pn then return false end if event.type == "InputEventType_Release" then return false end local button= event.GameButton - if cursor_on_menu then + if cursor_on_menu == "main" then if button == "Start" then local item= menu_items[menu_pos] if item.item_type == "bool" then - local value= not Profile[item.get](profile) - menu_values[menu_pos]:settext(item_value_to_text(item, value)) - Profile[item.set](profile, value) + local value= not profile[item.get](profile) + menu_values[menu_pos]:playcommand( + "Set", {item_value_to_text(item, value)}) + profile[item.set](profile, value) elseif item.item_type == "number" then --fade_actor_to(fader, .8) fade_actor_to(number_entry.container, 1) - number_entry.value= Profile[item.get](profile) + number_entry.value= profile[item.get](profile) number_entry.value_actor:playcommand("Set", {number_entry.value}) number_entry.auto_done_value= item.auto_done number_entry.max_value= item.max number_entry:update_cursor(number_entry.cursor_start) number_entry.prompt_actor:playcommand( "Set", {THEME:GetString("ScreenOptionsCustomizeProfile", item.name)}) - cursor_on_menu= false + cursor_on_menu= "numpad" + elseif item.item_type == "list" then + cursor_on_menu= "list" + active_list= menu_items[menu_pos].list + list_pos= calc_list_pos( + profile[menu_items[menu_pos].get](profile), active_list) + update_list_cursor() elseif item.item_type == "exit" then + local profile_id= GAMESTATE:GetEditLocalProfileID() + PROFILEMAN:SaveLocalProfile(profile_id) SCREENMAN:GetTopScreen():StartTransitioningScreen("SM_GoToNextScreen") SOUND:PlayOnce(THEME:GetPathS("Common", "Start")) end @@ -158,15 +283,34 @@ local function input(event) update_menu_cursor() end end - else + elseif cursor_on_menu == "numpad" then local done= number_entry:handle_input(button) if done then local item= menu_items[menu_pos] - Profile[item.set](profile, number_entry.value) - menu_values[menu_pos]:settext(item_value_to_text(item, number_entry.value)) + profile[item.set](profile, number_entry.value) + menu_values[menu_pos]:playcommand( + "Set", {item_value_to_text(item, number_entry.value)}) --fade_actor_to(fader, 0) fade_actor_to(number_entry.container, 0) - cursor_on_menu= true + cursor_on_menu= "main" + end + elseif cursor_on_menu == "list" then + if button == "MenuLeft" or button == "MenuUp" then + if list_pos > 1 then list_pos= list_pos - 1 end + update_list_cursor() + menu_values[menu_pos]:playcommand("PressLeft") + elseif button == "MenuRight" or button == "MenuDown" then + if list_pos < #active_list then list_pos= list_pos + 1 end + update_list_cursor() + menu_values[menu_pos]:playcommand("PressRight") + elseif button == "Start" then + profile[menu_items[menu_pos].set](profile, active_list[list_pos].setting) + local valactor= menu_values[menu_pos] + left_showing= false + right_showing= false + valactor:playcommand("HideLeft") + valactor:playcommand("HideRight") + cursor_on_menu= "main" end end end @@ -178,6 +322,10 @@ local args= { SCREENMAN:GetTopScreen():AddInputCallback(input) end }, + -- 2. The Cursor + -- This is the cursor on the main portion of the menu. + -- It needs to have Move and Fit commands for when it's moved to a new + -- item on the list. Def.ActorFrame { Name= "menu_cursor", InitCommand= function(self) menu_cursor= self @@ -216,12 +364,22 @@ local args= { }, } +-- Note that the "character" item in the menu only shows up if there are +-- characters to choose from. You might want to adjust positioning for that. for i, item in ipairs(menu_items) do local item_y= menu_start + ((i-1) * 24) + -- 3. The Menu Items + -- This creates the actor that will be used to show each item on the menu. args[#args+1]= Def.BitmapText{ Name= "menu_" .. item.name, Font= "Common Normal", Text= THEME:GetString("ScreenOptionsCustomizeProfile", item.name), InitCommand= function(self) + -- Note that the item adds itself to the list menu_item_actors. This + -- is so that when the cursor is moved, the appropriate item can be + -- easily fetched for positioning and sizing the cursor. + -- Note the ActorFrames have a width of 1 unless you set it, so when + -- you change this from an BitmapText to a ActorFrame, you will have + -- to make the FitCommand of your cursor look at the children. menu_item_actors[i]= self self:xy(menu_x, item_y) self:diffuse(Color.White) @@ -229,17 +387,70 @@ for i, item in ipairs(menu_items) do end } if item.get then - local value_text= item_value_to_text(item, Profile[item.get](profile)) - args[#args+1]= Def.BitmapText{ - Name= "value_" .. item.name, Font= "Common Normal", - Text= value_text, + local value_text= item_value_to_text(item, profile[item.get](profile)) + -- 4. The Menu Values + -- Each of the values needs to have a SetCommand so it can be updated + -- when the player changes it. + -- And ActorFrame is used because values for list items need to have + -- left/right indicators for when the player is making a choice. + local value_args= { + Name= "value_" .. item.name, InitCommand= function(self) + -- Note that the ActorFrame is being added to the list menu_values + -- so it can be easily fetched and updated when the value changes. menu_values[i]= self self:xy(value_x, menu_start + ((i-1) * 24)) - self:diffuse(Color.White) - self:horizalign(left) - end + end, + Def.BitmapText{ + Name= "val", Font= "Common Normal", Text= value_text, + InitCommand= function(self) + self:diffuse(Color.White) + self:horizalign(left) + end, + SetCommand= function(self, param) + self:settext(param[1]) + end, + } } + if item.item_type == "list" then + -- 4.1 The L/R indicators + -- The L/R indicators are there to tell the player when there is a + -- choice to the left or right of the choice they are on. + -- Note that they are placed inside the ActorFrame for the value, so + -- when commands are played on the ActorFrame, they are played for the + -- indicators too. + -- The commands are ShowLeft, HideLeft, PressLeft, and the same for + -- Right. + -- Note that the right indicator has a SetCommand so it sees when the + -- value changes and checks the new width to position itself. + -- Show/Hide is only played when the indicator changes state. + -- Command execution order: Set, Show/Hide (if change occurred), Press + value_args[#value_args+1]= LoadActor(THEME:GetPathG("_StepsDisplayListRow","arrow")) .. { + InitCommand= function(self) + self:rotationy(-180) + self:x(-8) + self:visible(false) + self:playcommand("Set", {value_text}) + end, + ShowLeftCommand= cmd(visible, true), + HideLeftCommand= cmd(visible, false), + PressLeftCommand= cmd(finishtweening;zoom,1.5;smooth,0.25;zoom,1), + } + value_args[#value_args+1]= LoadActor(THEME:GetPathG("_StepsDisplayListRow","arrow")) .. { + InitCommand= function(self) + self:visible(false) + self:playcommand("Set", {value_text}) + end, + SetCommand= function(self) + local valw= self:GetParent():GetChild("val"):GetWidth() + self:x(valw+8) + end, + ShowRightCommand= cmd(visible, true), + HideRightCommand= cmd(visible, false), + PressRightCommand= cmd(finishtweening;zoom,1.5;smooth,0.25;zoom,1), + } + end + args[#args+1]= Def.ActorFrame(value_args) end end