Skip to content

Commit

Permalink
Add buttons and modal dialog boxes. (facebookresearch#1956)
Browse files Browse the repository at this point in the history
  • Loading branch information
0mdc authored and dannymcy committed Jun 26, 2024
1 parent c6c82bf commit b523e5e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
42 changes: 42 additions & 0 deletions habitat-hitl/habitat_hitl/core/client_message_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

from dataclasses import dataclass
from typing import Final, List, Optional, Union

import magnum as mn
Expand All @@ -14,6 +15,19 @@
DEFAULT_NORMAL: Final[List[float]] = [0.0, 1.0, 0.0]


# TODO: Move to another file.
@dataclass
class UIButton:
"""
Networked UI button. Use RemoteClientState.ui_button_pressed() to retrieve state.
"""

def __init__(self, button_id: str, text: str, enabled: bool):
self.button_id = button_id
self.text = text
self.enabled = enabled


class ClientMessageManager:
r"""
Extends gfx-replay keyframes to include server messages to be interpreted by the clients.
Expand Down Expand Up @@ -144,6 +158,34 @@ def add_text(
{"text": text, "position": [pos[0], pos[1]]}
)

def show_modal_dialogue_box(
self,
title: str,
text: str,
buttons: List[UIButton],
destination_mask: Mask = Mask.ALL,
):
r"""
Show a modal dialog box with buttons.
There can only be one modal dialog box at a time.
"""
for user_index in self._users.indices(destination_mask):
message = self._messages[user_index]

message["dialog"] = {
"title": title,
"text": text,
"buttons": [],
}
for button in buttons:
message["dialog"]["buttons"].append(
{
"id": button.button_id,
"text": button.text,
"enabled": button.enabled,
}
)

def change_humanoid_position(
self, pos: List[float], destination_mask: Mask = Mask.ALL
) -> None:
Expand Down
19 changes: 17 additions & 2 deletions habitat-hitl/habitat_hitl/core/remote_client_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# LICENSE file in the root directory of this source tree.

import math
from typing import Any, List, Optional, Tuple
from typing import Any, List, Optional, Set, Tuple

import magnum as mn

Expand Down Expand Up @@ -49,13 +49,17 @@ def __init__(
self._on_client_connected = Event()
self._on_client_disconnected = Event()

# TODO: Handle UI in a different class.
self._pressed_ui_buttons: List[Set[str]] = []

self._gui_inputs: List[GuiInput] = []
self._client_state_history: List[List[ClientState]] = []
self._receive_rate_trackers: List[AverageRateTracker] = []
for _ in users.indices(Mask.ALL):
self._gui_inputs.append(GuiInput())
self._client_state_history.append([])
self._receive_rate_trackers.append(AverageRateTracker(2.0))
self._pressed_ui_buttons.append(set())

self._client_loading: List[bool] = [False] * users.max_user_count

Expand Down Expand Up @@ -95,6 +99,9 @@ def bind_gui_input(self, gui_input: GuiInput, user_index: int) -> None:
assert user_index < len(self._gui_inputs)
self._gui_inputs[user_index] = gui_input

def ui_button_pressed(self, user_index: int, button_id: str) -> bool:
return button_id in self._pressed_ui_buttons[user_index]

def get_history_length(self) -> int:
"""Length of client state history preserved. Anything beyond this horizon is discarded."""
return 4
Expand Down Expand Up @@ -217,13 +224,19 @@ def _update_input_state(
if len(all_client_states) == 0 or len(self._gui_inputs) == 0:
return

# Gather all recent keyDown and keyUp events
# Gather all input events.
for user_index in range(len(all_client_states)):
client_states = all_client_states[user_index]
if len(client_states) == 0:
continue
gui_input = self._gui_inputs[user_index]
for client_state in client_states:
# UI element events.
ui = client_state.get("ui", None)
if ui is not None:
for button in ui.get("buttonsPressed", []):
self._pressed_ui_buttons[user_index].add(button)

input_json = (
client_state["input"] if "input" in client_state else None
)
Expand Down Expand Up @@ -458,11 +471,13 @@ def get_new_connection_records(self) -> List[ConnectionRecord]:
def on_frame_end(self) -> None:
for user_index in self._users.indices(Mask.ALL):
self._gui_inputs[user_index].on_frame_end()
self._pressed_ui_buttons[user_index].clear()
self._new_connection_records = None

def clear_history(self, user_mask=Mask.ALL) -> None:
for user_index in self._users.indices(user_mask):
self._client_state_history[user_index].clear()
self._pressed_ui_buttons[user_index].clear()

def kick(self, user_mask: Mask) -> None:
"""
Expand Down

0 comments on commit b523e5e

Please sign in to comment.