-- calculator.lua -- ---------------------------------------------------------------- local function get_gui_root(player) return player.gui.screen end -- ---------------------------------------------------------------- function show_think(player, enabled) local root = get_gui_root(player) if enabled then root.calcui.calcui_table.calcui_table_col2.calcui_rant.sprite = "sprite_calcui_think" root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.style.height = 196 else root.calcui.calcui_table.calcui_table_col2.calcui_rant.sprite = nil root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.style.height = 252 end end -- ---------------------------------------------------------------- function show_rant(player, enabled) local root = get_gui_root(player) if enabled then root.calcui.calcui_table.calcui_table_col2.calcui_rant.sprite = "sprite_calcui_rant" root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.style.height = 196 else root.calcui.calcui_table.calcui_table_col2.calcui_rant.sprite = nil root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.style.height = 252 end end -- ---------------------------------------------------------------- local function destroy_calculator(player) local root = get_gui_root(player) if root.calcui then root.calcui.destroy() end end -- ---------------------------------------------------------------- function show_calculator(player) local root = get_gui_root(player) if not root.calcui then local calcui = root.add({ type = "frame", name = "calcui", style = "dialog_frame", direction = "vertical" }) local flow = calcui.add({ type = "flow", name = "calcui_flow" }) flow.style.horizontally_stretchable = "on" flow.add({ type = "label", caption = {"calculator-ui.title"}, style = "frame_title" }).drag_target = calcui local widget = flow.add({ type = "empty-widget", style = "draggable_space_header", name = "calcui_drag" }) widget.drag_target = calcui widget.style.horizontally_stretchable = "on" widget.style.minimal_width = 24 widget.style.natural_height = 24 flow.add({ type = "sprite-button", sprite = "utility/close_white", style = "frame_action_button", name = "calcui_close" }) local table = calcui.add({ type = "table", name = "calcui_table", column_count = "2", vertical_centering = "false" }) local col1 = table.add({ type = "flow", name = "calcui_table_col1", direction = "vertical" }) local display = col1.add({ type = "textfield", caption = "", name = "calcui_display" }) display.style.width = 212 local row1 = col1.add({type="flow", name="calcui_col1_row1", direction="horizontal"}) row1.add({type="sprite-button", style="calcui_button_style_light", caption="CE", name="calcui_button_CE"}).sprite = "sprite_calcui_light" -- CE = Clear Entry (just this line) row1.add({type="sprite-button", style="calcui_button_style_light", caption="C", name="calcui_button_C"}).sprite = "sprite_calcui_light" -- C = Clear (all, past results as well) row1.add({type="sprite-button", style="calcui_button_style_light", caption="BS", name="calcui_button_BS"}).sprite = "sprite_calcui_light" row1.add({type="sprite-button", style="calcui_button_style_light", caption="/", name="calcui_button_DIV"}).sprite = "sprite_calcui_light" local row2 = col1.add({type="flow", name="calcui_col1_row2", direction="horizontal"}) row2.add({type="sprite-button", style="calcui_button_style_dark", caption="7", name="calcui_button_7"}).sprite = "sprite_calcui_dark" row2.add({type="sprite-button", style="calcui_button_style_dark", caption="8", name="calcui_button_8"}).sprite = "sprite_calcui_dark" row2.add({type="sprite-button", style="calcui_button_style_dark", caption="9", name="calcui_button_9"}).sprite = "sprite_calcui_dark" row2.add({type="sprite-button", style="calcui_button_style_light", caption="*", name="calcui_button_MUL"}).sprite = "sprite_calcui_light" local row3 = col1.add({type="flow", name="calcui_col1_row3", direction="horizontal"}) row3.add({type="sprite-button", style="calcui_button_style_dark", caption="4", name="calcui_button_4"}).sprite = "sprite_calcui_dark" row3.add({type="sprite-button", style="calcui_button_style_dark", caption="5", name="calcui_button_5"}).sprite = "sprite_calcui_dark" row3.add({type="sprite-button", style="calcui_button_style_dark", caption="6", name="calcui_button_6"}).sprite = "sprite_calcui_dark" row3.add({type="sprite-button", style="calcui_button_style_light", caption="-", name="calcui_button_SUB"}).sprite = "sprite_calcui_light" local row4 = col1.add({type="flow", name="calcui_col1_row4", direction="horizontal"}) row4.add({type="sprite-button", style="calcui_button_style_dark", caption="1", name="calcui_button_1"}).sprite = "sprite_calcui_dark" row4.add({type="sprite-button", style="calcui_button_style_dark", caption="2", name="calcui_button_2"}).sprite = "sprite_calcui_dark" row4.add({type="sprite-button", style="calcui_button_style_dark", caption="3", name="calcui_button_3"}).sprite = "sprite_calcui_dark" row4.add({type="sprite-button", style="calcui_button_style_light", caption="+", name="calcui_button_ADD"}).sprite = "sprite_calcui_light" local row5 = col1.add({type="flow", name="calcui_col1_row5", direction="horizontal"}) row5.add({type="sprite-button", style="calcui_button_style_light", caption="%", name="calcui_button_PERC"}).sprite = "sprite_calcui_light" row5.add({type="sprite-button", style="calcui_button_style_dark", caption="0", name="calcui_button_0"}).sprite = "sprite_calcui_dark" row5.add({type="sprite-button", style="calcui_button_style_dark", caption=".", name="calcui_button_DOT"}).sprite = "sprite_calcui_dark" row5.add({type="sprite-button", style="calcui_button_style_red", caption="=", name="calcui_button_EQU"}).sprite = "sprite_calcui_red" --.sprite = "sprite_calcui_dark" local col2 = table.add({ type = "flow", name = "calcui_table_col2", direction = "vertical" }) local result = col2.add({ type = "label", caption = "= ", name = "calcui_display_result" }) result.style.font = "default-large" local rant = col2.add({ type = "sprite", name = "calcui_rant" }) col2.add({ type = "line", direction = "horizontal" }) local scroll = col2.add({ type = "scroll-pane", name = "calcui_scroll_pane" }) scroll.style.height = 252 local recents = scroll.add({ type = "table", caption = "", name = "calcui_result_table", column_count = "2" }) recents.style.column_alignments[1] = "right" -- center the gui calcui.force_auto_center() end end -- ---------------------------------------------------------------- function hide_calculator(player) destroy_calculator(player) end -- ---------------------------------------------------------------- function toggle_calculator(player) local root = get_gui_root(player) if root and root.calcui then hide_calculator(player) else show_calculator(player) end end -- ---------------------------------------------------------------- function focus_on_input(player) local root = get_gui_root(player) root.calcui.calcui_table.calcui_table_col1.calcui_display.focus() end -- ---------------------------------------------------------------- function clear_equation(player) local root = get_gui_root(player) root.calcui.calcui_table.calcui_table_col1.calcui_display.text = "" end -- ---------------------------------------------------------------- function process_ce_key(player, button) local root = get_gui_root(player) clear_equation(player) root.calcui.calcui_table.calcui_table_col2.calcui_display_result.caption = "=" root.calcui.calcui_table.calcui_table_col2.calcui_display_result.tooltip = "" end -- ---------------------------------------------------------------- function process_c_key(player, button) local root = get_gui_root(player) process_ce_key(player, button) root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.calcui_result_table.clear() end -- ---------------------------------------------------------------- function process_backspace_key(player, button) local root = get_gui_root(player) root.calcui.calcui_table.calcui_table_col1.calcui_display.text = string.sub(root.calcui.calcui_table.calcui_table_col1.calcui_display.text, 1, -2) end -- ---------------------------------------------------------------- function fix_equation(equation, root) local result = equation local prev_result = root.calcui.calcui_table.calcui_table_col2.calcui_display_result.tooltip -- 1. visible part -- if equation does not start with a number or char, use the previous result (if available) and put it in front if not (string.match(result:sub(1, 1), "[^%w%(%)]") == nil) and prev_result then result = prev_result .. result end -- remove "math." result = result:gsub("math.", "") local new_equation = result -- 2. invisible part -- fix math library shortcuts local math_lib = { ["abs"] = "math.abs", ["acos"] = "math.acos", ["asin"] = "math.asin", ["atan"] = "math.atan", ["atan2"] = "math.atan2", ["ceil"] = "math.ceil", ["floor"] = "math.floor", ["cos"] = "math.cos", ["cosh"] = "math.cosh", ["sin"] = "math.sin", ["sinh"] = "math.sinh", ["tan"] = "math.tan", ["tanh"] = "math.tanh", ["deg"] = "math.deg", ["rad"] = "math.rad", ["exp"] = "math.exp", ["log"] = "math.log", ["log10"] = "math.log10", ["min"] = "math.min", ["max"] = "math.max", ["modf"] = "math.modf", ["fmod"] = "math.fmod", ["frexp"] = "math.frexp", ["ldexp"] = "math.ldexp", ["sqrt"] = "math.sqrt", ["huge"] = "math.huge", ["pi"] = "math.pi", ["pow"] = "math.pow" } for key, val in pairs(math_lib) do result = result:gsub(key, val) end -- fix percentage result = result:gsub("(%%)", "/100") -- fix danish keyboard result = result:gsub(",", ".") result = result:gsub(";", ",") return result, new_equation end -- ---------------------------------------------------------------- function process_equal_key(player, button) local root = get_gui_root(player) local original_equation = root.calcui.calcui_table.calcui_table_col1.calcui_display.text; equation, original_equation = fix_equation(original_equation, root) -- just testing --root.calcui.calcui_table.calcui_table_col1.calcui_display.text = equation if not (equation == nil or equation == "") then local status, retval = pcall(function() return load("return " .. equation)() end) root.calcui.calcui_table.calcui_table_col2.calcui_display_result.tooltip = retval if not (retval == math.huge or retval ~= retval) then status, retval_show = pcall(function() local result = string.format("%0." .. settings.get_player_settings(player)["calcui-decimal-places"].value .. "f", retval) if result:len() > tostring(retval):len() then result = retval end return result end) else status = false end if retval_show == nil or retval_show == "" then status = false end if not status then retval_show = "NaN" show_rant(player, true) else if retval <= 0 then show_think(player, true) else show_rant(player, false) end end root.calcui.calcui_table.calcui_table_col2.calcui_display_result.caption = "= " .. retval_show -- only write in recent table if actually a result if status then -- check last equation and only insert if not the same local item_size = #root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.calcui_result_table.children if item_size == 0 or root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.calcui_result_table.children[item_size-1].caption ~= original_equation then local recent_equation = root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.calcui_result_table.add({ type = "label", name = "calcui_recent_equation_" .. item_size, caption = original_equation, tooltip = {"calculator-ui.recent_tooltip"} }) local recent_result = root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.calcui_result_table.add({ type = "label", name = "calcui_recent_result_" .. item_size, caption = root.calcui.calcui_table.calcui_table_col2.calcui_display_result.caption }) root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.scroll_to_bottom() end end end if settings.get_player_settings(player)["calcui-clear-on-calc"].value then clear_equation(player) end end -- ---------------------------------------------------------------- function display_addchar(player, char) local root = get_gui_root(player) root.calcui.calcui_table.calcui_table_col1.calcui_display.text = root.calcui.calcui_table.calcui_table_col1.calcui_display.text .. char show_rant(player, false) end -- ---------------------------------------------------------------- local button_dispatch = { ["CE"] = process_ce_key, ["C"] = process_c_key, ["BS"] = process_backspace_key, -- ["EQU"] = process_equal_key } local button_addchar = { ["DIV"] = "/", -- ["7"] = "7", ["8"] = "8", ["9"] = "9", ["MUL"] = "*", -- ["4"] = "4", ["5"] = "5", ["6"] = "6", ["SUB"] = "-", -- ["1"] = "1", ["2"] = "2", ["3"] = "3", ["ADD"] = "+", -- ["PERC"] = "%", ["0"] = "0", ["DOT"] = "." } function handle_calcui_click(event, player) debug_print("handle_calcui_click()") local event_name = event.element.name local button_prefix = "calcui_button_" local button_prefix_len = string.len(button_prefix) local recent_prefix = "calcui_recent_" local recent_prefix_len = string.len(recent_prefix); -- calculator buttons if string.sub(event_name, 1, button_prefix_len) == button_prefix then show_rant(player, false) button = string.sub(event_name, button_prefix_len + 1 ) debug_print("handle_calcui_click button " .. button) local dispatch_func = button_dispatch[button] if dispatch_func then dispatch_func(player, button) end local addchar = button_addchar[button] if addchar then display_addchar(player, addchar) end -- close button elseif event_name == "calcui_close" then hide_calculator(player) -- recent results elseif string.sub(event_name, 1, recent_prefix_len) == recent_prefix then if event.button == defines.mouse_button_type.left and event.shift == true then -- copy equation to display local root = get_gui_root(player) root.calcui.calcui_table.calcui_table_col1.calcui_display.text = root.calcui.calcui_table.calcui_table_col2.calcui_scroll_pane.calcui_result_table[event_name].caption focus_on_input(player) end end end -- ---------------------------------------------------------------- function calcui_on_gui_text_changed(event) if event.element.name == "calcui_display" then local player = game.players[event.player_index] local root = get_gui_root(player) if string.find(root.calcui.calcui_table.calcui_table_col1.calcui_display.text, "=") then root.calcui.calcui_table.calcui_table_col1.calcui_display.text = root.calcui.calcui_table.calcui_table_col1.calcui_display.text:gsub("=", "") process_equal_key(player) end end end -- ---------------------------------------------------------------- function calcui_on_gui_location_changed(event) if event.element.name == "calcui" then local player = game.players[event.player_index] local root = get_gui_root(player) root.calcui.location = event.element.location end end