Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Controls test suite

examples/gui/controls_test_suite.livemd

Controls test suite

Mix.install([
  {:zexray, github: "jn-jairo/zexray", depth: 1}
])

Code example

Example complexity rating: [★★★★] 4/4

defmodule ExampleState do
  require Record
  require Zexray.Enum.Color
  require Zexray.Type.Vector2

  Record.defrecord(:example_state,
    exit_window: false,
    show_message_box: false,
    dropdown_box_000_active: 0,
    dropdown_000_edit_mode: false,
    dropdown_box_001_active: 0,
    dropdown_001_edit_mode: false,
    force_squared_checked: false,
    spinner_001_value: 0,
    spinner_edit_mode: false,
    value_box_002_value: 0,
    value_box_edit_mode: false,
    text_box_text: "",
    text_box_edit_mode: false,
    text_input: "foo bar",
    show_text_input_box: false,
    visual_style_active: 0,
    prev_visual_style_active: 0,
    list_view_scroll_index: 0,
    list_view_active: -1,
    list_view_ex_scroll_index: 0,
    list_view_ex_active: 2,
    list_view_ex_focus: -1,
    toggle_group_active: 0,
    toggle_slider_active: 0,
    color_picker_value: Zexray.Enum.Color.enum(:red),
    slider_value: 50,
    slider_bar_value: 60,
    progress_value: 0.1,
    view_scroll: Zexray.Type.Vector2.t(x: 0, y: 0),
    alpha_value: 0.5,
    text_box_multi_text:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\nThisisastringlongerthanexpectedwithoutspacestotestcharbreaksforthosecases,checkingifworkingasexpected.\n\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
    text_box_multi_edit_mode: false
  )

  @type example_state ::
          record(:example_state,
            exit_window: boolean,
            show_message_box: boolean,
            dropdown_box_000_active: integer,
            dropdown_000_edit_mode: boolean,
            dropdown_box_001_active: integer,
            dropdown_001_edit_mode: boolean,
            force_squared_checked: boolean,
            spinner_001_value: integer,
            spinner_edit_mode: boolean,
            value_box_002_value: integer,
            value_box_edit_mode: boolean,
            text_box_text: binary,
            text_box_edit_mode: boolean,
            text_input: binary,
            show_text_input_box: boolean,
            visual_style_active: integer,
            prev_visual_style_active: integer,
            list_view_scroll_index: integer,
            list_view_active: integer,
            list_view_ex_scroll_index: integer,
            list_view_ex_active: integer,
            list_view_ex_focus: integer,
            toggle_group_active: integer,
            toggle_slider_active: integer,
            color_picker_value: Zexray.Type.Color.t_all(),
            slider_value: number,
            slider_bar_value: number,
            progress_value: number,
            view_scroll: Zexray.Type.Vector2.t_all(),
            alpha_value: number,
            text_box_multi_text: binary,
            text_box_multi_edit_mode: boolean
          )
end

defmodule Example do
  use Zexray.Enum
  use Zexray.Type

  import ExampleState

  @screen_width 960
  @screen_height 560
  @title "zexray [gui] example - controls test suite"

  def init do
    # Initialize window
    Zexray.Window.with_window(@screen_width, @screen_height, @title, fn ->
      # Set our game to run at 60 frames-per-second
      Zexray.Timing.set_target_fps(60)

      Zexray.Keyboard.set_exit(enum_keyboard_key(:null))

      Zexray.Gui.load_style_default()

      # Manage resources loading/unloading
      Zexray.Resource.with_resource(
        fn ->
          example_state()
        end,
        &loop/1
      )
    end)
  end

  defp format_number(value) do
    :erlang.float_to_binary(value * 1.0, decimals: 2)
  end

  defp loop(state) do
    example_state(exit_window: exit_window) = state

    # Detect window close button or ESC key
    if exit_window do
      :ok
    else
      # Update

      example_state(
        show_message_box: show_message_box,
        dropdown_box_000_active: dropdown_box_000_active,
        dropdown_000_edit_mode: dropdown_000_edit_mode,
        dropdown_box_001_active: dropdown_box_001_active,
        dropdown_001_edit_mode: dropdown_001_edit_mode,
        force_squared_checked: force_squared_checked,
        spinner_001_value: spinner_001_value,
        spinner_edit_mode: spinner_edit_mode,
        value_box_002_value: value_box_002_value,
        value_box_edit_mode: value_box_edit_mode,
        text_box_text: text_box_text,
        text_box_edit_mode: text_box_edit_mode,
        text_input: text_input,
        show_text_input_box: show_text_input_box,
        visual_style_active: visual_style_active,
        prev_visual_style_active: prev_visual_style_active,
        list_view_scroll_index: list_view_scroll_index,
        list_view_active: list_view_active,
        list_view_ex_scroll_index: list_view_ex_scroll_index,
        list_view_ex_active: list_view_ex_active,
        list_view_ex_focus: list_view_ex_focus,
        toggle_group_active: toggle_group_active,
        toggle_slider_active: toggle_slider_active,
        color_picker_value: color_picker_value,
        slider_value: slider_value,
        slider_bar_value: slider_bar_value,
        progress_value: progress_value,
        view_scroll: view_scroll,
        alpha_value: alpha_value,
        text_box_multi_text: text_box_multi_text,
        text_box_multi_edit_mode: text_box_multi_edit_mode
      ) = state

      exit_window = Zexray.Window.should_close?()

      show_message_box =
        if Zexray.Keyboard.pressed?(enum_keyboard_key(:escape)),
          do: not show_message_box,
          else: show_message_box

      show_text_input_box =
        if Zexray.Keyboard.down?(enum_keyboard_key(:left_control)) and
             Zexray.Keyboard.pressed?(enum_keyboard_key(:s)),
           do: true,
           else: show_text_input_box

      if Zexray.FileSystem.file_dropped?() do
        Zexray.FileSystem.get_dropped_files()
        |> Enum.each(fn file ->
          if Path.extname(file) == ".rgs" do
            Zexray.Gui.load_style(file)
          end
        end)
      end

      prev_visual_style_active =
        if visual_style_active != prev_visual_style_active do
          case visual_style_active do
            0 -> Zexray.Gui.load_style_default(:light)
            1 -> Zexray.Gui.load_style_default(:dark)
          end

          Zexray.Gui.set_style(
            enum_gui_control(:label),
            enum_gui_property_control(:text_alignment),
            enum_gui_text_alignment(:left)
          )

          visual_style_active
        else
          prev_visual_style_active
        end

      progress_value =
        cond do
          Zexray.Keyboard.pressed?(enum_keyboard_key(:left)) -> progress_value - 0.1
          Zexray.Keyboard.pressed?(enum_keyboard_key(:right)) -> progress_value + 0.1
          true -> progress_value
        end

      progress_value =
        cond do
          progress_value > 1 -> 1
          progress_value < 0 -> 0
          true -> progress_value
        end

      # Draw

      Zexray.Drawing.with_drawing(fn ->
        Zexray.Gui.get_style_color(
          enum_gui_control(:default),
          enum_gui_property_default(:background_color)
        )
        |> Zexray.Drawing.clear_background()

        # Controls drawing

        # Check all possible events that require GuiLock
        if dropdown_000_edit_mode or dropdown_001_edit_mode, do: Zexray.Gui.lock()

        # First GUI column

        {_, force_squared_checked} =
          Zexray.Gui.check_box(
            type_rectangle(x: 25, y: 108, width: 15, height: 15),
            "FORCE CHECK!",
            force_squared_checked
          )

        Zexray.Gui.set_style(
          enum_gui_control(:textbox),
          enum_gui_property_control(:text_alignment),
          enum_gui_text_alignment(:center)
        )

        {spinner_001_changed, spinner_001_value} =
          Zexray.Gui.spinner(
            type_rectangle(x: 25, y: 135, width: 125, height: 30),
            "",
            spinner_001_value,
            0,
            100,
            spinner_edit_mode
          )

        spinner_edit_mode =
          if spinner_001_changed, do: not spinner_edit_mode, else: spinner_edit_mode

        {value_box_002_changed, value_box_002_value} =
          Zexray.Gui.value_box(
            type_rectangle(x: 25, y: 175, width: 125, height: 30),
            "",
            value_box_002_value,
            0,
            100,
            value_box_edit_mode
          )

        value_box_edit_mode =
          if value_box_002_changed, do: not value_box_edit_mode, else: value_box_edit_mode

        Zexray.Gui.set_style(
          enum_gui_control(:textbox),
          enum_gui_property_control(:text_alignment),
          enum_gui_text_alignment(:left)
        )

        {text_box_changed, text_box_text} =
          Zexray.Gui.text_box(
            type_rectangle(x: 25, y: 215, width: 125, height: 30),
            text_box_text,
            64,
            text_box_edit_mode
          )

        text_box_edit_mode =
          if text_box_changed, do: not text_box_edit_mode, else: text_box_edit_mode

        Zexray.Gui.set_style(
          enum_gui_control(:button),
          enum_gui_property_control(:text_alignment),
          enum_gui_text_alignment(:center)
        )

        show_text_input_box =
          Zexray.Gui.button(
            type_rectangle(x: 25, y: 255, width: 125, height: 30),
            Zexray.Gui.icon_text(enum_gui_icon(:file_save), "Save File")
          ) or show_text_input_box

        Zexray.Gui.group_box(
          type_rectangle(x: 25, y: 310, width: 125, height: 150),
          "STATES"
        )

        # Zexray.Gui.lock()

        Zexray.Gui.set_state(enum_gui_state(:normal))

        _ =
          Zexray.Gui.button(
            type_rectangle(x: 30, y: 320, width: 115, height: 30),
            "NORMAL"
          )

        Zexray.Gui.set_state(enum_gui_state(:focused))

        _ =
          Zexray.Gui.button(
            type_rectangle(x: 30, y: 355, width: 115, height: 30),
            "FOCUSED"
          )

        Zexray.Gui.set_state(enum_gui_state(:pressed))

        _ =
          Zexray.Gui.button(
            type_rectangle(x: 30, y: 390, width: 115, height: 30),
            "PRESSED"
          )

        Zexray.Gui.set_state(enum_gui_state(:disabled))

        _ =
          Zexray.Gui.button(
            type_rectangle(x: 30, y: 425, width: 115, height: 30),
            "DISABLED"
          )

        Zexray.Gui.set_state(enum_gui_state(:normal))

        # Zexray.Gui.unlock()

        visual_style_active =
          Zexray.Gui.combo_box(
            type_rectangle(x: 25, y: 480, width: 125, height: 30),
            "default;dark",
            visual_style_active
          )

        # NOTE: gui_dropdown_box must draw after any other control that can be covered on unfolding
        Zexray.Gui.unlock()

        if dropdown_000_edit_mode, do: Zexray.Gui.lock()

        Zexray.Gui.set_style(
          enum_gui_control(:dropdownbox),
          enum_gui_property_control(:text_padding),
          4
        )

        Zexray.Gui.set_style(
          enum_gui_control(:dropdownbox),
          enum_gui_property_control(:text_alignment),
          enum_gui_text_alignment(:left)
        )

        {dropdown_box_001_pressed, dropdown_box_001_active} =
          Zexray.Gui.dropdown_box(
            type_rectangle(x: 25, y: 65, width: 125, height: 30),
            "#01#ONE;#02#TWO;#03#THREE;#04#FOUR",
            dropdown_box_001_active,
            dropdown_001_edit_mode
          )

        dropdown_001_edit_mode =
          if dropdown_box_001_pressed,
            do: not dropdown_001_edit_mode,
            else: dropdown_001_edit_mode

        Zexray.Gui.set_style(
          enum_gui_control(:dropdownbox),
          enum_gui_property_control(:text_padding),
          0
        )

        Zexray.Gui.set_style(
          enum_gui_control(:dropdownbox),
          enum_gui_property_control(:text_alignment),
          enum_gui_text_alignment(:center)
        )

        Zexray.Gui.unlock()

        {dropdown_box_000_pressed, dropdown_box_000_active} =
          Zexray.Gui.dropdown_box(
            type_rectangle(x: 25, y: 25, width: 125, height: 30),
            "ONE;TWO;THREE",
            dropdown_box_000_active,
            dropdown_000_edit_mode
          )

        dropdown_000_edit_mode =
          if dropdown_box_000_pressed,
            do: not dropdown_000_edit_mode,
            else: dropdown_000_edit_mode

        # Second GUI column

        # Zexray.Gui.set_style(
        #   enum_gui_control(:listview),
        #   enum_gui_property_list_view(:list_items_border_normal),
        #   1
        # )

        {list_view_scroll_index, list_view_active} =
          Zexray.Gui.list_view(
            type_rectangle(x: 165, y: 25, width: 140, height: 124),
            "Charmander;Bulbasaur;#18#Squirtel;Pikachu;Eevee;Pidgey",
            list_view_scroll_index,
            list_view_active
          )

        {list_view_ex_scroll_index, list_view_ex_active, list_view_ex_focus} =
          Zexray.Gui.list_view_ex(
            type_rectangle(x: 165, y: 162, width: 140, height: 184),
            ["This", "is", "a", "list view", "with", "disable", "elements", "amazing!"],
            list_view_ex_scroll_index,
            list_view_ex_active,
            list_view_ex_focus
          )

        Zexray.Gui.set_style(
          enum_gui_control(:listview),
          enum_gui_property_list_view(:list_items_border_normal),
          0
        )

        toggle_group_active =
          Zexray.Gui.toggle_group(
            type_rectangle(x: 165, y: 360, width: 140, height: 24),
            "#1#ONE\n#3#TWO\n#8#THREE\n#23#",
            toggle_group_active
          )

        # Zexray.Gui.disable()

        Zexray.Gui.set_style(
          enum_gui_control(:slider),
          enum_gui_property_slider(:slider_padding),
          2
        )

        toggle_slider_active =
          Zexray.Gui.toggle_slider(
            type_rectangle(x: 165, y: 480, width: 140, height: 30),
            "ON;OFF",
            toggle_slider_active
          )

        Zexray.Gui.set_style(
          enum_gui_control(:slider),
          enum_gui_property_slider(:slider_padding),
          0
        )

        # Third GUI column

        Zexray.Gui.panel(
          type_rectangle(x: 320, y: 25, width: 225, height: 140),
          "Panel Info"
        )

        color_picker_value =
          Zexray.Gui.color_picker(
            type_rectangle(x: 320, y: 185, width: 196, height: 192),
            "",
            color_picker_value
          )

        # Zexray.Gui.disable()

        {_, slider_value} =
          Zexray.Gui.slider(
            type_rectangle(x: 355, y: 400, width: 165, height: 20),
            "TEST",
            "#{format_number(slider_value)}",
            slider_value,
            -50,
            100
          )

        {_, slider_bar_value} =
          Zexray.Gui.slider_bar(
            type_rectangle(x: 320, y: 430, width: 200, height: 20),
            "",
            "#{trunc(slider_bar_value)}",
            slider_bar_value,
            0,
            100
          )

        progress_value =
          Zexray.Gui.progress_bar(
            type_rectangle(x: 320, y: 460, width: 200, height: 20),
            "",
            "#{trunc(progress_value * 100)}%",
            progress_value,
            0,
            1
          )

        Zexray.Gui.enable()

        # NOTE: View rectangle could be used to perform some scissor test
        view = type_rectangle(x: 0, y: 0, width: 0, height: 0)

        {view_scroll, _view} =
          Zexray.Gui.scroll_panel(
            type_rectangle(x: 560, y: 25, width: 102, height: 354),
            "",
            type_rectangle(x: 560, y: 25, width: 300, height: 1200),
            view_scroll,
            view
          )

        mouse_cell = type_vector2(x: 0, y: 0)

        _mouse_cell =
          Zexray.Gui.grid(
            type_rectangle(x: 560, y: 25 + 180 + 195, width: 100, height: 120),
            "",
            20,
            3,
            mouse_cell
          )

        alpha_value =
          Zexray.Gui.color_bar_alpha(
            type_rectangle(x: 320, y: 490, width: 200, height: 30),
            "",
            alpha_value
          )

        # WARNING: Word-wrap does not work as expected in case of no-top alignment
        Zexray.Gui.set_style(
          enum_gui_control(:default),
          enum_gui_property_default(:text_alignment_vertical),
          enum_gui_text_alignment_vertical(:top)
        )

        # WARNING: Word-wrap does not work as expected in case of no-top alignment
        Zexray.Gui.set_style(
          enum_gui_control(:default),
          enum_gui_property_default(:text_wrap_mode),
          enum_gui_text_wrap_mode(:word)
        )

        {text_box_multi_changed, text_box_multi_text} =
          Zexray.Gui.text_box(
            type_rectangle(x: 678, y: 25, width: 258, height: 492),
            text_box_multi_text,
            1024,
            text_box_multi_edit_mode
          )

        text_box_multi_edit_mode =
          if text_box_multi_changed,
            do: not text_box_multi_edit_mode,
            else: text_box_multi_edit_mode

        Zexray.Gui.set_style(
          enum_gui_control(:default),
          enum_gui_property_default(:text_alignment_vertical),
          enum_gui_text_alignment_vertical(:middle)
        )

        Zexray.Gui.set_style(
          enum_gui_control(:default),
          enum_gui_property_default(:text_wrap_mode),
          enum_gui_text_wrap_mode(:none)
        )

        Zexray.Gui.status_bar(
          type_rectangle(
            x: 0,
            y: @screen_height - 20,
            width: @screen_width,
            height: 20
          ),
          "This is a status bar"
        )

        {show_message_box, exit_window} = message_box(show_message_box, exit_window)

        {show_text_input_box, text_input} = text_input_box(show_text_input_box, text_input)

        state
        |> example_state(
          exit_window: exit_window,
          show_message_box: show_message_box,
          dropdown_box_000_active: dropdown_box_000_active,
          dropdown_000_edit_mode: dropdown_000_edit_mode,
          dropdown_box_001_active: dropdown_box_001_active,
          dropdown_001_edit_mode: dropdown_001_edit_mode,
          force_squared_checked: force_squared_checked,
          spinner_001_value: spinner_001_value,
          spinner_edit_mode: spinner_edit_mode,
          value_box_002_value: value_box_002_value,
          value_box_edit_mode: value_box_edit_mode,
          text_box_text: text_box_text,
          text_box_edit_mode: text_box_edit_mode,
          text_input: text_input,
          show_text_input_box: show_text_input_box,
          visual_style_active: visual_style_active,
          prev_visual_style_active: prev_visual_style_active,
          list_view_scroll_index: list_view_scroll_index,
          list_view_active: list_view_active,
          list_view_ex_scroll_index: list_view_ex_scroll_index,
          list_view_ex_active: list_view_ex_active,
          list_view_ex_focus: list_view_ex_focus,
          toggle_group_active: toggle_group_active,
          toggle_slider_active: toggle_slider_active,
          color_picker_value: color_picker_value,
          slider_value: slider_value,
          slider_bar_value: slider_bar_value,
          progress_value: progress_value,
          view_scroll: view_scroll,
          alpha_value: alpha_value,
          text_box_multi_text: text_box_multi_text,
          text_box_multi_edit_mode: text_box_multi_edit_mode
        )
      end)
      |> loop()
    end
  end

  defp overlay() do
    Zexray.Shape.draw_rectangle(
      0,
      0,
      @screen_width,
      @screen_height,
      Zexray.Color.fade(enum_color(:raywhite), 0.8)
    )
  end

  defp text_input_box(false, text_input), do: {false, text_input}

  defp text_input_box(true, text_input) do
    overlay()

    Zexray.Gui.unlock()

    Zexray.Gui.set_style(
      enum_gui_control(:default),
      enum_gui_property_default(:text_wrap_mode),
      enum_gui_text_wrap_mode(:none)
    )

    {should_close, button_pressed, text_input, _secret_view_active} =
      Zexray.Gui.text_input_box(
        type_rectangle(
          x: @screen_width / 2 - 120,
          y: @screen_height / 2 - 60,
          width: 240,
          height: 140
        ),
        Zexray.Gui.icon_text(enum_gui_icon(:file_save), "Save file as ..."),
        "Introduce output file name:",
        "Ok;Cancel",
        text_input,
        255,
        nil
      )

    show_text_input_box =
      if should_close or button_pressed == 1 or button_pressed == 2, do: false, else: true

    {show_text_input_box, text_input}
  end

  defp message_box(false, exit_window), do: {false, exit_window}

  defp message_box(true, exit_window) do
    overlay()

    {should_close, button_pressed} =
      Zexray.Gui.message_box(
        type_rectangle(
          x: @screen_width / 2 - 125,
          y: @screen_height / 2 - 50,
          width: 250,
          height: 100
        ),
        Zexray.Gui.icon_text(enum_gui_icon(:exit), "Close Window"),
        "Do you really want to exit?",
        "Yes;No"
      )

    show_message_box = if should_close or button_pressed == 2, do: false, else: true

    exit_window = if button_pressed == 1, do: true, else: exit_window

    {show_message_box, exit_window}
  end
end
Example.init()

Press CTRL+S to open the save window

Press LEFT or RIGHT to change the progress bar

Drag and drop a .rgs file to load a custom style, you can create the style file using the rGuiStyler