From 75d6de0b0065bde6db940bd3ac64f2f967daa27e Mon Sep 17 00:00:00 2001 From: cyberarm Date: Thu, 11 Feb 2021 09:28:04 -0600 Subject: [PATCH] Added autofocus to edit dialogs first editline, added tab support for selecting next focusable element in edit dialogs, made valid? method be called in edit dialogs when fields change, simulator robot can now strafe side to side --- lib/dialog.rb | 34 +++++++++++++++++++ lib/dialogs/action_dialog.rb | 5 ++- lib/dialogs/name_prompt_dialog.rb | 2 +- lib/dialogs/variable_dialog.rb | 11 ++++++- lib/pages/simulator.rb | 11 +++++-- lib/simulator/robot.rb | 54 +++++++++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 5 deletions(-) diff --git a/lib/dialog.rb b/lib/dialog.rb index cc74ad0..875d8e2 100644 --- a/lib/dialog.rb +++ b/lib/dialog.rb @@ -57,6 +57,38 @@ module TAC def try_commit end + def focus_next_element + elements = [] + + _deep_dive_interactive_elements(@dialog_content, elements) + + element_index = elements.find_index(self.focused) + + if element_index && elements.size.positive? + element = elements[element_index + 1] + element ||= elements.first + + if element + request_focus(element) + end + end + end + + def _deep_dive_interactive_elements(element, list) + element.children.each do |child| + if child.visible? && child.is_a?(CyberarmEngine::Element::EditLine) || + child.is_a?(CyberarmEngine::Element::EditBox) || + child.is_a?(CyberarmEngine::Element::CheckBox) || + child.is_a?(CyberarmEngine::Element::ToggleButton) || + child.is_a?(CyberarmEngine::Element::ListBox) + + list << child + elsif child.visible? && child.is_a?(CyberarmEngine::Element::Container) + _deep_dive_interactive_elements(child, list) + end + end + end + def draw @previous_state.draw Gosu.flush @@ -84,6 +116,8 @@ module TAC try_commit when Gosu::KB_ESCAPE close + when Gosu::KB_TAB + focus_next_element end end diff --git a/lib/dialogs/action_dialog.rb b/lib/dialogs/action_dialog.rb index 3290a3c..cbada40 100644 --- a/lib/dialogs/action_dialog.rb +++ b/lib/dialogs/action_dialog.rb @@ -7,7 +7,10 @@ module TAC label "Name", width: 1.0, text_align: :center @name_error = label "Error", color: TAC::Palette::TACNET_CONNECTION_ERROR @name_error.hide - @name = edit_line @options[:action] ? @options[:action].name : "", filter: method(:name_filter), width: 1.0 + @name = edit_line @options[:action] ? @options[:action].name : "", filter: method(:name_filter), width: 1.0, autofocus: true + @name.subscribe(:changed) do |sender, value| + valid? + end label "Comment", width: 1.0, text_align: :center @comment = edit_line @options[:action] ? @options[:action].comment : "", width: 1.0 diff --git a/lib/dialogs/name_prompt_dialog.rb b/lib/dialogs/name_prompt_dialog.rb index 3ebcdc7..4129134 100644 --- a/lib/dialogs/name_prompt_dialog.rb +++ b/lib/dialogs/name_prompt_dialog.rb @@ -8,7 +8,7 @@ module TAC label "Name", width: 1.0, text_align: :center @name_error = label "", color: TAC::Palette::TACNET_CONNECTION_ERROR @name_error.hide - @name = edit_line @options[:renaming] ? @options[:renaming].name : "", filter: method(:name_filter), width: 1.0 + @name = edit_line @options[:renaming] ? @options[:renaming].name : "", filter: method(:name_filter), width: 1.0, autofocus: true @name.subscribe(:changed) do |sender, value| valid? diff --git a/lib/dialogs/variable_dialog.rb b/lib/dialogs/variable_dialog.rb index 0a12d25..640def1 100644 --- a/lib/dialogs/variable_dialog.rb +++ b/lib/dialogs/variable_dialog.rb @@ -9,7 +9,10 @@ module TAC label "Name", width: 1.0, text_align: :center @name_error = label "Error", color: TAC::Palette::TACNET_CONNECTION_ERROR @name_error.hide - @name = edit_line @options[:variable] ? @options[:variable].name : "", filter: method(:name_filter), width: 1.0 + @name = edit_line @options[:variable] ? @options[:variable].name : "", filter: method(:name_filter), width: 1.0, autofocus: true + @name.subscribe(:changed) do |sender, value| + valid? + end label "Type", width: 1.0, text_align: :center @type_error = label "Error", color: TAC::Palette::TACNET_CONNECTION_ERROR @@ -24,6 +27,8 @@ module TAC @value.show @value_boolean.hide end + + valid? end @type ||= @var_type.value.to_sym @@ -35,6 +40,10 @@ module TAC @value = edit_line @options[:variable] ? @options[:variable].value : "", width: 1.0 @value_boolean = check_box "Boolean", checked: @options[:variable] ? @options[:variable].value == "true" : false + @value.subscribe(:changed) do |sender, value| + valid? + end + unless @options[:variable] && @options[:variable].type == :boolean @value_boolean.hide else diff --git a/lib/pages/simulator.rb b/lib/pages/simulator.rb index f5c0370..db5d74e 100644 --- a/lib/pages/simulator.rb +++ b/lib/pages/simulator.rb @@ -7,6 +7,8 @@ module TAC menu_bar.clear do button get_image("#{TAC::ROOT_PATH}/media/icons/right.png"), tip: "Run Simulation", image_height: 1.0 do + save_source + begin @simulation_start_time = Gosu.milliseconds @simulation = TAC::Simulator::Simulation.new(source_code: @source_code.value, field_container: @field_container) @@ -23,8 +25,7 @@ module TAC end button get_image("#{TAC::ROOT_PATH}/media/icons/save.png"), tip: "Save", image_height: 1.0 do - File.open(SOURCE_FILE_PATH, "w") { |f| f.write @source_code.value } - @simulation_status.value = "Saved source to #{SOURCE_FILE_PATH}" + save_source end end @@ -57,8 +58,14 @@ robot.forward 100" end end + def save_source + File.open(SOURCE_FILE_PATH, "w") { |f| f.write @source_code.value } + @simulation_status.value = "Saved source to #{SOURCE_FILE_PATH}" + end + def blur @simulation.robots.each { |robot| robot.queue.clear } if @simulation + save_source end def draw diff --git a/lib/simulator/robot.rb b/lib/simulator/robot.rb index a362482..1c787dd 100644 --- a/lib/simulator/robot.rb +++ b/lib/simulator/robot.rb @@ -75,6 +75,14 @@ module TAC @queue << Move.new(robot: self, distance: -distance, power: power) end + def strafe_right(distance, power = 1.0) + @queue << Strafe.new(robot: self, distance: distance, power: power) + end + + def strafe_left(distance, power = 1.0) + @queue << Strafe.new(robot: self, distance: -distance, power: power) + end + def turn(relative_angle, power = 1.0) @queue << Turn.new(robot: self, relative_angle: relative_angle, power: power) end @@ -143,6 +151,52 @@ class State end end + class Strafe < State + def initialize(robot:, distance:, power:) + @robot = robot + @distance = distance + @power = power.clamp(-1.0, 1.0) + end + + def start + @starting_position = @robot.position.clone + @goal = @starting_position.clone + if @distance.positive? + @goal.x += Math.cos((@robot.angle + 90).gosu_to_radians) * @distance + @goal.y += Math.sin((@robot.angle + 90).gosu_to_radians) * @distance + else + @goal.x += Math.cos((@robot.angle - 90).gosu_to_radians) * @distance + @goal.y += Math.sin((@robot.angle - 90).gosu_to_radians) * @distance + end + + @complete = false + @allowable_error = 1.0 + end + + def draw + Gosu.draw_line( + @robot.position.x + @robot.width / 2, @robot.position.y + @robot.depth / 2, TAC::Palette::TIMECRAFTERS_TERTIARY, + @goal.x + @robot.width / 2, @goal.y + @robot.depth / 2, TAC::Palette::TIMECRAFTERS_TERTIARY + ) + Gosu.draw_rect(@goal.x + (@robot.width / 2 - 1), @goal.y + (@robot.depth / 2 - 1), 2, 2, Gosu::Color::RED) + end + + def update(dt) + speed = (@distance > 0 ? @power * dt : -@power * dt) * @robot.speed + + if @robot.position.distance(@goal) <= @allowable_error + @complete = true + @robot.position = @goal + else + if speed > 0 + @robot.position -= (@robot.position - @goal).normalized * speed + else + @robot.position += (@robot.position - @goal).normalized * speed + end + end + end + end + class Turn < State def initialize(robot:, relative_angle:, power:) @robot = robot