diff --git a/lib/dialogs/confirm_dialog.rb b/lib/dialogs/confirm_dialog.rb index 8d8a4a4..f95fbc4 100644 --- a/lib/dialogs/confirm_dialog.rb +++ b/lib/dialogs/confirm_dialog.rb @@ -12,7 +12,7 @@ module TAC button "Cancel", width: 0.475 do close end - button "Okay", width: 0.475, **TAC::THEME_DANGER_BUTTON do + button "Proceed", width: 0.475, **TAC::THEME_DANGER_BUTTON do close @options[:callback_method].call diff --git a/lib/page.rb b/lib/page.rb new file mode 100644 index 0000000..eefc765 --- /dev/null +++ b/lib/page.rb @@ -0,0 +1,45 @@ +module TAC + class Page + include CyberarmEngine::DSL + include CyberarmEngine::Common + + attr_reader :menu_bar, :status_bar, :body + + def initialize(host:, header_bar_label:, menu_bar:, status_bar:, body:) + @host = host + @header_bar_label = header_bar_label + @menu_bar = menu_bar + @status_bar = status_bar + @body = body + end + + def page(klass) + @host.page(klass) + end + + def header_bar(text) + @header_bar_label.value = text + end + + def setup + end + + def focus + end + + def blur + end + + def draw + end + + def update + end + + def button_down(id) + end + + def button_up(id) + end + end +end \ No newline at end of file diff --git a/lib/pages/configurations.rb b/lib/pages/configurations.rb new file mode 100644 index 0000000..2c3ff5b --- /dev/null +++ b/lib/pages/configurations.rb @@ -0,0 +1,92 @@ +module TAC + class Pages + class Configurations < Page + def setup + header_bar("Manage Configurations") + + menu_bar.clear do + button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_height: 1.0, tip: "Add configuration" do + push_state(Dialog::NamePromptDialog, title: "Config Name", callback_method: proc { |name| + window.backend.write_new_config(name) + + change_config(name) + populate_configs + }) + end + + # label "Manage Configurations", text_size: 36 + end + + status_bar.clear do + label "Current Configuration: " + @config_label = label window.backend.settings.config + end + + body.clear do + @configs_list = stack width: 1.0 do + end + end + + populate_configs + end + + def populate_configs + @config_files = Dir.glob("#{TAC::CONFIGS_PATH}/*.json") + @config_files_list = @config_files.map { |file| Dialog::NamePromptDialog::NameStub.new(File.basename(file, ".json")) } + + @configs_list.clear do + @config_files.each_with_index do |config_file, i| + flow width: 1.0, **THEME_ITEM_CONTAINER_PADDING do + background i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR + + name = File.basename(config_file, ".json") + + button "#{name}", width: 0.94 do + change_config(name) + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/gear.png"), image_width: THEME_ICON_SIZE, tip: "Rename configuration" do + push_state(Dialog::NamePromptDialog, title: "Rename Config", renaming: @config_files_list.find { |c| c.name == name }, list: @config_files_list, accept_label: "Update", callback_method: proc { |old_name, new_name| + if not File.exist?("#{TAC::CONFIGS_PATH}/#{new_name}.json") + FileUtils.mv( + "#{TAC::CONFIGS_PATH}/#{name}.json", + "#{TAC::CONFIGS_PATH}/#{new_name}.json" + ) + + if window.backend.settings.config == name + change_config(new_name) + end + + populate_configs + else + push_state(Dialog::AlertDialog, title: "Config Rename Failed", message: "File already exists at\n#{TAC::CONFIGS_PATH}/#{new_name}.json}") + end + }) + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/trashcan.png"), image_width: THEME_ICON_SIZE, **THEME_DANGER_BUTTON, tip: "Delete configuration" do + push_state(Dialog::ConfirmDialog, title: "Delete Config?", callback_method: proc { + File.delete("#{TAC::CONFIGS_PATH}/#{name}.json") + + if window.backend.settings.config == name + change_config(nil) + end + + populate_configs + }) + end + end + end + end + end + + def change_config(name) + window.backend.settings.config = name + window.backend.save_settings + window.backend.load_config(name) + + @config_label.value = name.to_s + end + end + end +end \ No newline at end of file diff --git a/lib/pages/editor.rb b/lib/pages/editor.rb new file mode 100644 index 0000000..71ba6a4 --- /dev/null +++ b/lib/pages/editor.rb @@ -0,0 +1,23 @@ +module TAC + class Pages + class Editor < Page + def setup + header_bar("Editor") + + body.clear do + flow(width: 1.0, height: 1.0) do + stack(width: 0.3333, height: 1.0) do + background 0xff_550055 + end + stack(width: 0.3333, height: 1.0) do + background 0xff_555555 + end + stack(width: 0.3333, height: 1.0) do + background 0xff_55ff55 + end + end + end + end + end + end +end \ No newline at end of file diff --git a/lib/pages/home.rb b/lib/pages/home.rb new file mode 100644 index 0000000..6540766 --- /dev/null +++ b/lib/pages/home.rb @@ -0,0 +1,42 @@ +module TAC + class Pages + class Home < Page + def setup + header_bar(TAC::NAME) + + body.clear do + stack(width: 1.0, height: 1.0) do + label TAC::NAME, width: 1.0, text_size: 48, text_align: :center + + stack(width: 1.0, height: 8) do + background 0xff_006000 + end + + if window.backend.settings.config.empty? + label "TODO: Introduction" + label "Get Started", text_size: 28 + button "1. Create a configuration" do + page(TAC::Pages::Configurations) + end + label "2. Add a group" + label "3. Add an action" + label "4. Add a variable" + label "5. Profit?" + else + label "Display config stats or something?" + + config = window.backend.config + groups = config.groups + actions = config.groups.map { |g| g.actions }.flatten + variables = actions.map { |a| a.variables }.flatten + + label "Total groups: #{groups.size}" + label "Total actions: #{actions.size}" + label "Total variables: #{variables.size}" + end + end + end + end + end + end +end \ No newline at end of file diff --git a/lib/pages/presets.rb b/lib/pages/presets.rb new file mode 100644 index 0000000..da76e17 --- /dev/null +++ b/lib/pages/presets.rb @@ -0,0 +1,13 @@ +module TAC + class Pages + class Presets < Page + def setup + header_bar("Manage Presets") + + body.clear do + label "Not Yet Implemented" + end + end + end + end +end \ No newline at end of file diff --git a/lib/pages/search.rb b/lib/pages/search.rb new file mode 100644 index 0000000..ff93faf --- /dev/null +++ b/lib/pages/search.rb @@ -0,0 +1,20 @@ +module TAC + class Pages + class Search < Page + def setup + header_bar("Search") + + menu_bar.clear do + search = edit_line "", width: 0.9, height: 1.0 + button get_image("#{TAC::ROOT_PATH}/media/icons/zoom.png"), image_height: 1.0 do + # do search + body.clear do + label "Search results for: #{search.value.strip}" + label "TODO: Search Results." + end + end + end + end + end + end +end \ No newline at end of file diff --git a/lib/pages/simulator.rb b/lib/pages/simulator.rb new file mode 100644 index 0000000..f5c0370 --- /dev/null +++ b/lib/pages/simulator.rb @@ -0,0 +1,79 @@ +module TAC + class Pages + class Simulator < Page + SOURCE_FILE_PATH = "#{TAC::ROOT_PATH}/data/simulator.rb" + def setup + header_bar("Simulator") + + menu_bar.clear do + button get_image("#{TAC::ROOT_PATH}/media/icons/right.png"), tip: "Run Simulation", image_height: 1.0 do + begin + @simulation_start_time = Gosu.milliseconds + @simulation = TAC::Simulator::Simulation.new(source_code: @source_code.value, field_container: @field_container) + @simulation.start + rescue SyntaxError, NameError, NoMethodError, TypeError, ArgumentError => e + puts e.backtrace.reverse.join("\n") + puts e + push_state(Dialog::AlertDialog, title: "#{e.class}", message: e) + end + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/stop.png"), tip: "Stop Simulation", image_height: 1.0 do + @simulation.robots.each { |robot| robot.queue.clear } if @simulation + 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}" + end + end + + status_bar.clear do + @simulation_status = label "" + end + + body.clear do + flow(width: 1.0, height: 1.0) do + @field_container = stack width: 0.4, height: 1.0 do + background 0xff_111111 + end + + stack(width: 0.6, height: 1.0) do + source_code = +"robot = create_robot(alliance: :blue, width: 18, depth: 18) +robot.backward 100 +robot.turn 90 +robot.forward 100 +robot.turn -90 +robot.forward 100 +robot.turn -90 +robot.forward 100" + + source_code = File.read(SOURCE_FILE_PATH) if File.exists?(SOURCE_FILE_PATH) + + @source_code = edit_box source_code, width: 1.0, height: 1.0 + end + end + end + end + + def blur + @simulation.robots.each { |robot| robot.queue.clear } if @simulation + end + + def draw + @simulation.draw if @simulation + end + + def update + return unless @simulation + + @simulation.update + + unless @simulation.robots.all? { |robot| robot.queue.empty? } # Only update clock if simulation is running + @simulation_status.value = "Time: #{((Gosu.milliseconds - @simulation_start_time) / 1000.0).round(1)} seconds" if @simulation_start_time + end + end + end + end +end \ No newline at end of file diff --git a/lib/pages/tacnet.rb b/lib/pages/tacnet.rb new file mode 100644 index 0000000..34853fe --- /dev/null +++ b/lib/pages/tacnet.rb @@ -0,0 +1,26 @@ +module TAC + class Pages + class TACNET < Page + def setup + header_bar("TimeCrafters Auxiliary Configuration Network") + + menu_bar.clear do + label "Hostname" + hostname = edit_line "192.168.49.1", width: 0.33, height: 1.0 + label "Port" + port = edit_line "192.168.49.1", width: 0.33, height: 1.0 + button "Connect", height: 1.0 do + status_bar.clear do + label "Connecting to #{hostname.value}:#{port.value}" + end + end + end + + status_bar.clear do + image "#{TAC::ROOT_PATH}/media/icons/signal3.png", height: 1.0 + label "TACNET: Connected Pkt Sent: 00314 Pkt Received: 00313", text_size: 26 + end + end + end + end +end \ No newline at end of file diff --git a/lib/simulator/field.rb b/lib/simulator/field.rb index d1043eb..bf300a4 100644 --- a/lib/simulator/field.rb +++ b/lib/simulator/field.rb @@ -16,6 +16,8 @@ module TAC end def draw + Gosu.flush + Gosu.clip_to(@position.x, @position.y, @size, @size) do Gosu.translate(@position.x, @position.y) do draw_field diff --git a/lib/states/boot.rb b/lib/states/boot.rb index e188bfb..0630579 100644 --- a/lib/states/boot.rb +++ b/lib/states/boot.rb @@ -11,6 +11,8 @@ module TAC @animator = CyberarmEngine::Animator.new(start_time: 0, duration: 3_000, from: 0, to: 255) @transition_color = Gosu::Color.new(0x00_000000) + + @next_state = ARGV.include?("--redesign") ? NewEditor : Editor end def draw @@ -29,13 +31,13 @@ module TAC @transition_color.alpha = @animator.transition(0, 255, :sine) - push_state(Editor) if @transition_color.alpha >= 255 + push_state(@next_state) if @transition_color.alpha >= 255 end def button_up(id) super - push_state(Editor) + push_state(@next_state) end end end diff --git a/lib/states/new_editor.rb b/lib/states/new_editor.rb new file mode 100644 index 0000000..b64529a --- /dev/null +++ b/lib/states/new_editor.rb @@ -0,0 +1,155 @@ +class NewEditor < CyberarmEngine::GuiState + include CyberarmEngine::Theme # get access to deep_merge method + + def setup + @window_width = 0 + @window_height = 0 + + @pages = {} + @page = nil + + # TODO: Use these colors for buttons + _theme = { + Button: { + background: 0xff_006000, + border_color: 0x88_111111, + hover: { + color: 0xff_ffffff, + background: 0xff_00d000, + border_color: 0x88_111111 + }, + active: { + color: 0xff_ffffff, + background: 0xff_004000, + border_color: 0x88_111111 + } + } + } + + theme(deep_merge(TAC::THEME, _theme)) + + @header_bar = flow(width: 1.0, height: 36) do + background 0xff_006000 + + @header_bar_label = label TAC::NAME, width: 1.0, text_align: :center, text_size: 32 + + @window_controls = flow(x: window.width - 36 * 2, y: 0, height: 1.0) do + button get_image("#{TAC::ROOT_PATH}/media/icons/minus.png"), tip: "Minimize", image_height: 1.0 do + # window.minimize + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/cross.png"), tip: "Exit", image_height: 1.0, **TAC::THEME_DANGER_BUTTON do + window.close + end + end + end + + @container = flow(width: 1.0, height: 1.0) do + @navigation = stack(width: 64, height: 1.0) do + background 0xff_333333 + + button get_image("#{TAC::ROOT_PATH}/media/icons/home.png"), margin: 4, tip: "Home", image_width: 1.0 do + page(TAC::Pages::Home) + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/menuList.png"), margin: 4, tip: "Editor", image_width: 1.0 do + page(TAC::Pages::Editor) + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/signal3.png"), margin: 4, tip: "TACNET", image_width: 1.0 do + page(TAC::Pages::TACNET) + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/right.png"), margin: 4, tip: "Simulator", image_width: 1.0 do + page(TAC::Pages::Simulator) + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/gear.png"), margin: 4, tip: "Configurations", image_width: 1.0 do + page(TAC::Pages::Configurations) + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/menuGrid.png"), margin: 4, tip: "Presets", image_width: 1.0 do + page(TAC::Pages::Presets) + end + + button get_image("#{TAC::ROOT_PATH}/media/icons/zoom.png"), margin: 4, tip: "Search", image_width: 1.0 do + page(TAC::Pages::Search) + end + end + + @content = stack(width: window.width - @navigation.style.width, height: 1.0) do + @chrome = stack(width: 1.0, height: 96) do + @menu_bar = flow(width: 1.0, height: 48, padding: 8) do + background 0xff_008000 + end + + @status_bar = flow(width: 1.0, height: 96 - 48, padding: 2) do + background 0xff_006000 + end + end + + @body = stack(width: 1.0, height: 1.0) do + background 0xff_707070 + end + end + end + + page(TAC::Pages::Home) + end + + def draw + super + + @page.draw if @page + end + + def update + super + + @page.update if @page + + window.width = Gosu.available_width / 2 if window.width < Gosu.available_width / 2 + window.height = Gosu.available_height / 2 if window.height < Gosu.available_height / 2 + + if window.width != @window_width || window.height != @window_height + @window_width = window.width + @window_height = window.height + + recalc + end + end + + def recalc + @window_controls.style.x = window.width - @window_controls.width + @container.style.height = window.height - @header_bar.height + @content.style.width = window.width - @navigation.width + @body.style.height = window.height - (@chrome.height + @header_bar.height) + + + request_recalculate + end + + def page(klass) + @menu_bar.clear + @status_bar.clear + @body.clear + + if window.backend.settings.config.empty? + if [TAC::Pages::Home, TAC::Pages::TACNET, TAC::Pages::Simulator, TAC::Pages::Configurations].include?(klass) + else + push_state(TAC::Dialog::AlertDialog, title: "No Config Loaded", message: "A config must be loaded.") + page(TAC::Pages::Configurations) + + return + end + end + + @page.blur if @page + + @pages[klass] = klass.new(host: self, header_bar_label: @header_bar_label, menu_bar: @menu_bar, status_bar: @status_bar, body: @body) unless @pages[klass] + @page = @pages[klass] + + @page.setup + @page.focus + end +end \ No newline at end of file diff --git a/media/fonts/LICENSE b/media/fonts/DejaVuSans-LICENSE.txt similarity index 100% rename from media/fonts/LICENSE rename to media/fonts/DejaVuSans-LICENSE.txt diff --git a/timecrafters_configuration_tool.rb b/timecrafters_configuration_tool.rb index e0e58bf..afe6841 100644 --- a/timecrafters_configuration_tool.rb +++ b/timecrafters_configuration_tool.rb @@ -13,9 +13,18 @@ require_relative "lib/config" require_relative "lib/settings" require_relative "lib/states/boot" require_relative "lib/states/editor" +require_relative "lib/states/new_editor" require_relative "lib/states/simulator" require_relative "lib/states/manage_presets" require_relative "lib/states/manage_configurations" +require_relative "lib/page" +require_relative "lib/pages/home" +require_relative "lib/pages/editor" +require_relative "lib/pages/tacnet" +require_relative "lib/pages/simulator" +require_relative "lib/pages/configurations" +require_relative "lib/pages/presets" +require_relative "lib/pages/search" require_relative "lib/simulator/robot" require_relative "lib/simulator/field" require_relative "lib/simulator/simulation"