Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bookmark system & Integrate toast message into thunderscope #3418

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d915a43
add stubs and new proto
Lmh-java Nov 16, 2024
21cfb2e
investigate missing logs
Lmh-java Nov 17, 2024
adb16da
add listener to bookmark
Lmh-java Nov 17, 2024
fbbe763
work?
Lmh-java Nov 23, 2024
0fb7db1
refactor proto_player.py
Lmh-java Nov 30, 2024
341d2fc
finish refactoring for proto_player.py
Lmh-java Nov 30, 2024
c787ebf
refactor bookmark visual
Lmh-java Jan 6, 2025
baa2d5d
display bookmark visual
Lmh-java Jan 6, 2025
ca7a32c
fix time stamp calculation
Lmh-java Jan 6, 2025
6b6608d
fix bookmark visual
Lmh-java Jan 6, 2025
2dc347a
update documentations
Lmh-java Jan 7, 2025
eead58e
use kwargs as argument list
Lmh-java Jan 7, 2025
a422813
optimize bookmark button
Lmh-java Jan 7, 2025
724eba2
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jan 7, 2025
2f17f24
add documentation
Lmh-java Jan 11, 2025
24fa058
add shortcut doc
Lmh-java Jan 11, 2025
47944fc
add toast msg dependency
Lmh-java Jan 11, 2025
4b47951
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jan 11, 2025
fe2aec0
build toast helper and apply
Lmh-java Jan 12, 2025
c0c4b3e
Merge branch 'master' into minghao/bookmark
Lmh-java Jan 12, 2025
de3d238
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jan 12, 2025
2c8bfa1
upgrade pyqt6-qt
Lmh-java Jan 12, 2025
d45bee1
fix index test
Lmh-java Jan 12, 2025
9a4a686
add _ms suffix
Lmh-java Jan 14, 2025
091ea83
adjust offset
Lmh-java Jan 14, 2025
5929f09
add None as return type
Lmh-java Jan 19, 2025
4ea5031
remove magic number
Lmh-java Jan 26, 2025
d504694
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jan 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions environment_setup/ubuntu20_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ python-Levenshtein==0.25.1
psutil==5.9.0
PyOpenGL==3.1.6
ruff==0.5.5
pyqt-toast-notification==1.3.2
1 change: 1 addition & 0 deletions environment_setup/ubuntu22_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ psutil==5.9.0
PyOpenGL==3.1.6
numpy==1.26.4
ruff==0.5.5
pyqt-toast-notification==1.3.2
1 change: 1 addition & 0 deletions environment_setup/ubuntu24_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ python-Levenshtein==0.25.1
psutil==5.9.0
PyOpenGL==3.1.6
ruff==0.5.5
pyqt-toast-notification==1.3.2
2 changes: 2 additions & 0 deletions src/proto/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ proto_library(
"play.proto",
"power_frame_msg.proto",
"primitive.proto",
"replay_bookmark.proto",
"robot_crash_msg.proto",
"robot_log_msg.proto",
"robot_statistic.proto",
Expand Down Expand Up @@ -53,6 +54,7 @@ py_proto_library(
"parameters.proto",
"play.proto",
"primitive.proto",
"replay_bookmark.proto",
"robot_statistic.proto",
"robot_status_msg.proto",
"tactic.proto",
Expand Down
10 changes: 10 additions & 0 deletions src/proto/replay_bookmark.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto3";

package TbotsProto;

import "proto/tbots_timestamp_msg.proto";

message ReplayBookmark
{
Timestamp timestamp = 1;
}
5 changes: 5 additions & 0 deletions src/software/backend/unix_simulator_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ UnixSimulatorBackend::UnixSimulatorBackend(
robot_crash_listener.reset(new ThreadedProtoUnixListener<TbotsProto::RobotCrash>(
runtime_dir + ROBOT_CRASH_PATH, [](TbotsProto::RobotCrash& v) {}, proto_logger));

replay_bookmark_listener.reset(
new ThreadedProtoUnixListener<TbotsProto::ReplayBookmark>(
runtime_dir + REPLAY_BOOKMARK_PATH, [](TbotsProto::ReplayBookmark& v) {},
proto_logger));

// Protobuf Outputs
world_output.reset(new ThreadedProtoUnixSender<TbotsProto::World>(
runtime_dir + WORLD_PATH, proto_logger));
Expand Down
4 changes: 4 additions & 0 deletions src/software/backend/unix_simulator_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
#include <mutex>

#include "proto/parameters.pb.h"
#include "proto/replay_bookmark.pb.h"
#include "proto/robot_crash_msg.pb.h"
#include "proto/robot_log_msg.pb.h"
#include "proto/robot_status_msg.pb.h"
#include "proto/sensor_msg.pb.h"
#include "proto/tbots_software_msgs.pb.h"
#include "proto/validation.pb.h"
#include "proto/world.pb.h"
#include "software/backend/backend.h"
#include "software/logger/proto_logger.h"
#include "software/networking/unix/threaded_proto_unix_listener.hpp"
Expand Down Expand Up @@ -50,6 +52,8 @@ class UnixSimulatorBackend : public Backend, public Subject<TbotsProto::Thunderb
std::unique_ptr<ThreadedProtoUnixListener<TbotsProto::RobotLog>> robot_log_listener;
std::unique_ptr<ThreadedProtoUnixListener<TbotsProto::RobotCrash>>
robot_crash_listener;
std::unique_ptr<ThreadedProtoUnixListener<TbotsProto::ReplayBookmark>>
replay_bookmark_listener;

// Outputs
std::unique_ptr<ThreadedProtoUnixSender<TbotsProto::World>> world_output;
Expand Down
1 change: 1 addition & 0 deletions src/software/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const std::string SIMULATOR_STATE_PATH = "/simulator_state";
const std::string VALIDATION_PROTO_SET_PATH = "/validation_proto_set";
const std::string ROBOT_LOG_PATH = "/robot_log";
const std::string ROBOT_CRASH_PATH = "/robot_crash";
const std::string REPLAY_BOOKMARK_PATH = "/replay_bookmark";
const std::string DYNAMIC_PARAMETER_UPDATE_REQUEST_PATH = "/dynamic_parameter_request";
const std::string DYNAMIC_PARAMETER_UPDATE_RESPONSE_PATH = "/dynamic_parameter_response";
const std::string WORLD_STATE_RECEIVED_TRIGGER_PATH = "/world_state_received_trigger";
Expand Down
1 change: 1 addition & 0 deletions src/software/py_constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ PYBIND11_MODULE(py_constants, m)
m.attr("VALIDATION_PROTO_SET_PATH") = VALIDATION_PROTO_SET_PATH;
m.attr("ROBOT_LOG_PATH") = ROBOT_LOG_PATH;
m.attr("ROBOT_CRASH_PATH") = ROBOT_CRASH_PATH;
m.attr("REPLAY_BOOKMARK_PATH") = REPLAY_BOOKMARK_PATH;
m.attr("UNIX_BUFFER_SIZE") = UNIX_BUFFER_SIZE;
m.attr("DYNAMIC_PARAMETER_UPDATE_REQUEST_PATH") =
DYNAMIC_PARAMETER_UPDATE_REQUEST_PATH;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,6 @@ def setup_proto_unix_io(self, proto_unix_io: ProtoUnixIO) -> None:
(VALIDATION_PROTO_SET_PATH, ValidationProtoSet),
(ROBOT_LOG_PATH, RobotLog),
(ROBOT_CRASH_PATH, RobotCrash),
(REPLAY_BOOKMARK_PATH, ReplayBookmark),
]:
proto_unix_io.attach_unix_sender(self.full_system_runtime_dir, *arg)
10 changes: 10 additions & 0 deletions src/software/thunderscope/common/BUILD
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package(default_visibility = ["//visibility:public"])

load("@thunderscope_deps//:requirements.bzl", "requirement")

py_library(
name = "proto_configuration_widget",
srcs = ["proto_configuration_widget.py"],
Expand Down Expand Up @@ -41,3 +43,11 @@ py_library(
":frametime_counter",
],
)

py_library(
name = "toast_msg_helper",
srcs = ["toast_msg_helper.py"],
deps = [
requirement("pyqt-toast-notification"),
],
)
59 changes: 59 additions & 0 deletions src/software/thunderscope/common/toast_msg_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from PyQt6.QtWidgets import QWidget
from pyqttoast import Toast, ToastPreset


def show_toast(
parent: QWidget, title: str, text: str, timeout_ms: int, preset: ToastPreset
) -> None:
"""Display a toast message with the given properties
:param parent: parent widget to inject toast message component
:param title: title of toast message
:param text: text of toast message
:param timeout_ms: duration of the message (in ms)
:param preset: preset of the message box
"""
toast = Toast(parent)
toast.setDuration(timeout_ms)
toast.setTitle(title)
toast.setText(text)
toast.applyPreset(preset)
toast.setShowCloseButton(False)
toast.setBorderRadius(10)
toast.setShowDurationBar(False)
toast.show()


def success_toast(parent: QWidget, text: str, timeout_ms: int = 1000) -> None:
"""Display a success toast message
:param parent: parent widget to inject toast message component
:param text: text of toast message
:param timeout_ms: duration of the message (in ms)
"""
show_toast(parent, "", text, timeout_ms, ToastPreset.SUCCESS_DARK)


def failure_toast(parent: QWidget, text: str, timeout_ms: int = 1000) -> None:
"""Display a failure toast message
:param parent: parent widget to inject toast message component
:param text: text of toast message
:param timeout_ms: duration of the message (in ms)
"""
show_toast(parent, "", text, timeout_ms, ToastPreset.ERROR_DARK)


def info_toast(parent: QWidget, text: str, timeout_ms: int = 1000) -> None:
"""Display an information toast message
:param parent: parent widget to inject toast message component
:param text: text of toast message
:param timeout_ms: duration of the message (in ms)
"""
show_toast(parent, "", text, timeout_ms, ToastPreset.INFORMATION_DARK)


def warning_toast(parent: QWidget, text: str, timeout_ms: int = 1000) -> None:
"""Display a warning toast message
:param parent: parent widget to inject toast message component
:param text: text of toast message
:param timeout_ms: duration of the message (in ms)
"""
show_toast(parent, "", text, timeout_ms, ToastPreset.WARNING_DARK)
1 change: 1 addition & 0 deletions src/software/thunderscope/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class EstopMode(IntEnum):
<b><code>O:</code></b> Identify robots, toggle robot name visibility<br>
<b><code>M:</code></b> Toggle measure mode<br>
<b><code>S:</code></b> Toggle visibility of robot/ball speed visualization<br>
<b><code>B:</code></b> Add a bookmark<br>
<b><code>Ctrl + Space:</code></b> Stop AI vs AI simulation<br>
<b><code>Ctrl + Up:</code></b> Increment simulation speed<br>
<b><code>Ctrl + Down:</code></b> Decrement simulation speed<br>
Expand Down
1 change: 1 addition & 0 deletions src/software/thunderscope/gl/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ py_library(
srcs = ["gl_widget.py"],
deps = [
"//software/thunderscope:proto_unix_io",
"//software/thunderscope/common:toast_msg_helper",
"//software/thunderscope/gl/helpers:extended_gl_view_widget",
"//software/thunderscope/gl/layers:gl_layer",
"//software/thunderscope/gl/layers:gl_measure_layer",
Expand Down
18 changes: 18 additions & 0 deletions src/software/thunderscope/gl/gl_widget.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import time

import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.Qt.QtCore import Qt
Expand All @@ -22,6 +24,10 @@
)
from software.thunderscope.thread_safe_buffer import ThreadSafeBuffer
from proto.world_pb2 import SimulationState
from proto.replay_bookmark_pb2 import ReplayBookmark
from proto.tbots_timestamp_msg_pb2 import Timestamp

from software.thunderscope.common.toast_msg_helper import success_toast


class GLWidget(QWidget):
Expand Down Expand Up @@ -95,6 +101,8 @@ def __init__(
layers_menu=self.layers_menu,
toolbars_menu=self.toolbars_menu,
sandbox_mode=sandbox_mode,
replay_mode=player is not None,
on_add_bookmark=self.add_bookmark,
)

# Setup gamecontroller toolbar
Expand All @@ -121,6 +129,7 @@ def __init__(
self.layers = []

self.set_camera_view(CameraView.LANDSCAPE_HIGH_ANGLE)
self.proto_unix_io = proto_unix_io

def get_sim_control_toolbar(self):
"""Returns the simulation control toolbar"""
Expand Down Expand Up @@ -367,3 +376,12 @@ def __calc_orthographic_distance(self) -> float:
distance *= half_x_length_with_buffer

return distance

def add_bookmark(self):
"""Handler for clicking 'add bookmark' button"""
timestamp = time.time()
bookmark = ReplayBookmark(
timestamp=Timestamp(epoch_timestamp_seconds=timestamp)
)
self.proto_unix_io.send_proto(ReplayBookmark, bookmark)
success_toast(self.parentWidget(), "Added bookmark!")
18 changes: 18 additions & 0 deletions src/software/thunderscope/gl/widgets/gl_field_toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ def __init__(
layers_menu: QMenu,
toolbars_menu: QMenu,
sandbox_mode: bool = False,
replay_mode: bool = False,
on_add_bookmark=Callable[[], None],
):
"""Set up the toolbar with these buttons:

Expand All @@ -38,13 +40,16 @@ def __init__(
- Help
- Measure Mode Toggle
- Camera View Select menu
- Add bookmark

:param parent: the parent to overlay this toolbar over
:param on_camera_view_change: the callback function for when the camera view is changed
:param on_measure_mode: the callback function for when measure mode is toggled
:param layers_menu: the QMenu for the layers menu selection
:param toolbars_menu: the QMenu for the toolbars menu selection
:param sandbox_mode: if sandbox mode should be enabled
:param replay_mode: if replay mode is enabled
:param on_add_bookmark: the callback function when adding a bookmark
"""
super(GLFieldToolbar, self).__init__(parent=parent)

Expand Down Expand Up @@ -114,6 +119,15 @@ def __init__(
self.toolbars_button.setMenu(toolbars_menu)
self.toolbars_button.setStyleSheet(self.get_button_style())

if not replay_mode:
self.bookmark_button = QPushButton()
self.bookmark_button.setIcon(
icons.get_bookmark_icon(self.BUTTON_ICON_COLOR)
)
self.bookmark_button.setShortcut("b")
itsarune marked this conversation as resolved.
Show resolved Hide resolved
self.bookmark_button.setStyleSheet(self.get_button_style())
self.bookmark_button.clicked.connect(on_add_bookmark)

# Setup simulation speed button and menu
self.sim_speed_menu = QMenu()
self.sim_speed_button = QPushButton()
Expand Down Expand Up @@ -161,10 +175,14 @@ def __init__(
self.layout().addWidget(self.undo_button)
self.layout().addWidget(self.pause_button)
self.layout().addWidget(self.redo_button)

self.layout().addWidget(self.help_button)
self.layout().addWidget(self.measure_button)
self.layout().addWidget(self.camera_view_button)

if not replay_mode:
self.layout().addWidget(self.bookmark_button)

def refresh(self) -> None:
"""Refreshes the UI for all the toolbar icons and updates toolbar position"""
# update the pause button state
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ py_library(
name = "icon_loader",
srcs = ["icon_loader.py"],
data = [
":bookmark.svg",
":help.svg",
":measure.svg",
":pause.svg",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class GLFieldToolbarIconLoader:
RESET_ICON = None
VIEW_ICON = None
MEASURE_ICON = None
BOOKMARK_ICON = None


def get_undo_icon(color: str) -> QtGui.QPixmap:
Expand Down Expand Up @@ -138,3 +139,18 @@ def get_measure_icon(color: str) -> QtGui.QPixmap:
)

return GLFieldToolbarIconLoader.MEASURE_ICON


def get_bookmark_icon(color: str) -> QtGui.QPixmap:
"""Loads the Bookmark icon pixmap as a GLFieldToolbarIconLoader attribute

:param color: the color the icon should be initialized with if not already created
:return: the icon pixmap
"""
if not GLFieldToolbarIconLoader.BOOKMARK_ICON:
GLFieldToolbarIconLoader.BOOKMARK_ICON = get_icon(
"software/thunderscope/gl/widgets/toolbar_icons/sandbox_mode/bookmark.svg",
color,
)

return GLFieldToolbarIconLoader.BOOKMARK_ICON
8 changes: 8 additions & 0 deletions src/software/thunderscope/replay/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,18 @@ py_library(
],
deps = [
requirement("pyqtgraph"),
"bookmark_marker",
":proto_player",
],
)

py_library(
name = "bookmark_marker",
srcs = [
"bookmark_marker.py",
],
)

py_binary(
name = "replay_file_debugging_script",
srcs = [
Expand Down
Loading