Skip to content

Commit

Permalink
Merge pull request #813 from YoheiKakiuchi/add_tabbed_button_pullreq
Browse files Browse the repository at this point in the history
  • Loading branch information
k-okada authored Jun 29, 2021
2 parents b216ad9 + bfee9da commit a5893a5
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 9 deletions.
13 changes: 13 additions & 0 deletions jsk_rqt_plugins/bin/rqt_tabbed_buttons
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python
import sys

from rqt_gui.main import Main
try:
from jsk_rqt_plugins.tabbed_button import ServiceTabbedButtons
except:
import roslib; roslib.load_manifest('jsk_rqt_plugins')
from jsk_rqt_plugins.tabbed_button import ServiceTabbedButtons

plugin = 'ServiceTabbedButtons'
main = Main(filename=plugin)
sys.exit(main.main(standalone=plugin))
13 changes: 13 additions & 0 deletions jsk_rqt_plugins/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,17 @@
<statustip>A plugin to wait for user input.</statustip>
</qtgui>
</class>
<class name="ServiceTabbedButtons"
type="jsk_rqt_plugins.tabbed_button.ServiceTabbedButtons"
base_class_type="rqt_gui_py::Plugin">
<qtgui>
<group>
<label>Visualization</label>
<icon type="theme">folder</icon>
<statustip>Plugins related to visualization.</statustip>
</group>
<label>ServiceTabbedButton</label>
<icon type="theme">utilities-system-monitor</icon>
</qtgui>
</class>
</library>
23 changes: 23 additions & 0 deletions jsk_rqt_plugins/sample/sample_tabbed_buttons.launch
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<launch>
<node name="$(anon sample_buttons)"
pkg="jsk_rqt_plugins" type="rqt_tabbed_buttons" output="screen" clear_params="true">
<rosparam>
tabbed_layout:
tab_list: ['push', 'radio']
push:
name: 'push button'
namespace: push
type: push
yaml_file: 'package://jsk_rqt_plugins/resource/service_button_layout.yaml'
radio:
name: 'radio button'
namespace: radio
type: radio
yaml_file: 'package://jsk_rqt_plugins/resource/service_radio_button_layout.yaml'
</rosparam>
</node>
<node name="push_sample_service_buttons" pkg="jsk_rqt_plugins" type="sample_service_buttons.py"
ns='push' output="screen"/>
<node name="sample_service_buttons" pkg="jsk_rqt_plugins" type="sample_service_radio_buttons.py"
ns='radio' output="screen"/>
</launch>
7 changes: 4 additions & 3 deletions jsk_rqt_plugins/sample_scripts/sample_service_buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ def __init__(self):
rospy.Service('dummy/buttonE', Empty, self._empty_cb),
rospy.Service('dummy/buttonF', Empty, self._empty_cb),
]
self._name = rospy.get_name()

def _set_bool_cb(self, req):
rospy.loginfo('SetBool service called: req.data={}'.format(req.data))
rospy.loginfo('{} | SetBool service called: req.data={}'.format(self._name,req.data))
return SetBoolResponse(success=True)

def _trigger_cb(self, req):
rospy.loginfo('Trigger service called')
rospy.loginfo('{} | Trigger service called'.format(self._name))
return TriggerResponse(success=True)

def _empty_cb(self, req):
rospy.loginfo('Empty service called')
rospy.loginfo('{} | Empty service called'.format(self._name))
return EmptyResponse()


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ def __init__(self):
rospy.Service('dummy/buttonE', Empty, self._empty_cb),
rospy.Service('dummy/buttonF', Empty, self._empty_cb),
]
self._name = rospy.get_name()

def _empty_cb(self, req):
rospy.loginfo('Empty service called')
rospy.loginfo('{} | Empty service called'.format(self._name))
return EmptyResponse()


Expand Down
26 changes: 21 additions & 5 deletions jsk_rqt_plugins/src/jsk_rqt_plugins/button_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,23 @@ def loadLayoutYaml(self, layout_param):

def setupButtons(self, yaml_file):
"""
Parse yaml file and setup Buttons. Format of the yaml file should be:
Parse yaml file and setup Buttons.
"""
with open(yaml_file) as f:
yaml_data = yaml.load(f)
self.setupButtons_with_yaml_data(yaml_data)

def setupButtons_with_yaml_data(self, yaml_data, namespace=None):
"""
Setup Buttons with yaml_data which is loaded in setupButtons. Format of the yaml file should be:
- name: 'button name' (required)
image: 'path to image for icon' (optional)
image_size: 'width and height of icon' (optional)
service: 'service' (required)
column: 'column index' (optional, defaults to 0)
"""
self.buttons = []
with open(yaml_file) as f:
yaml_data = yaml.load(f)
if True:
# lookup colum direction
direction = 'vertical'
for d in yaml_data:
Expand Down Expand Up @@ -206,8 +213,17 @@ def setupButtons(self, yaml_file):
service_type = Empty
if service_type == SetBool:
button.setCheckable(True)
button.clicked.connect(
self.buttonCallback(button_data['service'], service_type, button))
if namespace:
sname = button_data['service']
if sname[0] == '/' or sname[0] == '~':
sname = sname
else:
sname = namespace + '/' + sname
button.clicked.connect(
self.buttonCallback(sname, service_type, button))
else:
button.clicked.connect(
self.buttonCallback(button_data['service'], service_type, button))
if self.button_type == "push":
button.setToolButtonStyle(
QtCore.Qt.ToolButtonTextUnderIcon)
Expand Down
25 changes: 25 additions & 0 deletions jsk_rqt_plugins/src/jsk_rqt_plugins/tabbed_button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from rqt_gui_py.plugin import Plugin
from jsk_rqt_plugins.tabbed_button_general import ServiceTabbedButtonGeneralWidget

class ServiceTabbedButtons(Plugin):
"""
rqt class to provide multiple buttons
"""
def __init__(self, context):
super(ServiceTabbedButtons, self).__init__(context)
self.setObjectName("ServiceTabbedButtons")
self._widget = ServiceTabbedButtonWidget()
context.add_widget(self._widget)
def save_settings(self, plugin_settings, instance_settings):
self._widget.save_settings(plugin_settings, instance_settings)
def restore_settings(self, plugin_settings, instance_settings):
self._widget.restore_settings(plugin_settings, instance_settings)
def trigger_configuration(self):
self._widget.trigger_configuration()

class ServiceTabbedButtonWidget(ServiceTabbedButtonGeneralWidget):
"""
Qt widget to visualize multiple buttons
"""
def __init__(self):
super(ServiceTabbedButtonWidget, self).__init__()
167 changes: 167 additions & 0 deletions jsk_rqt_plugins/src/jsk_rqt_plugins/tabbed_button_general.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
from distutils.version import LooseVersion
import math
import os
import sys

import python_qt_binding
import python_qt_binding.QtCore as QtCore
from python_qt_binding.QtCore import QEvent
from python_qt_binding.QtCore import QSize
from python_qt_binding.QtCore import Qt
from python_qt_binding.QtCore import QTimer
from python_qt_binding.QtCore import qWarning
from python_qt_binding.QtCore import Slot
import python_qt_binding.QtGui as QtGui
from python_qt_binding.QtGui import QBrush
from python_qt_binding.QtGui import QColor
from python_qt_binding.QtGui import QFont
from python_qt_binding.QtGui import QIcon
from python_qt_binding.QtGui import QPainter
from python_qt_binding.QtGui import QPen
import yaml

from resource_retriever import get_filename
import rospy
from rqt_gui_py.plugin import Plugin
from std_msgs.msg import Bool
from std_msgs.msg import Time
from std_srvs.srv import Empty
from std_srvs.srv import SetBool
from std_srvs.srv import Trigger

if LooseVersion(python_qt_binding.QT_BINDING_VERSION).version[0] >= 5:
from python_qt_binding.QtWidgets import QAction
from python_qt_binding.QtWidgets import QComboBox
from python_qt_binding.QtWidgets import QCompleter
from python_qt_binding.QtWidgets import QDialog
from python_qt_binding.QtWidgets import QGroupBox
from python_qt_binding.QtWidgets import QHBoxLayout
from python_qt_binding.QtWidgets import QLineEdit
from python_qt_binding.QtWidgets import QMenu
from python_qt_binding.QtWidgets import QMessageBox
from python_qt_binding.QtWidgets import QPushButton
from python_qt_binding.QtWidgets import QRadioButton
from python_qt_binding.QtWidgets import QSizePolicy
from python_qt_binding.QtWidgets import QToolButton
from python_qt_binding.QtWidgets import QVBoxLayout
from python_qt_binding.QtWidgets import QWidget
from python_qt_binding.QtWidgets import QTabWidget
else:
from python_qt_binding.QtGui import QAction
from python_qt_binding.QtGui import QComboBox
from python_qt_binding.QtGui import QCompleter
from python_qt_binding.QtGui import QDialog
from python_qt_binding.QtGui import QGroupBox
from python_qt_binding.QtGui import QHBoxLayout
from python_qt_binding.QtGui import QLineEdit
from python_qt_binding.QtGui import QMenu
from python_qt_binding.QtGui import QMessageBox
from python_qt_binding.QtGui import QPushButton
from python_qt_binding.QtGui import QRadioButton
from python_qt_binding.QtGui import QSizePolicy
from python_qt_binding.QtGui import QToolButton
from python_qt_binding.QtGui import QVBoxLayout
from python_qt_binding.QtGui import QWidget
from python_qt_binding.QtGui import QTabWidget

from jsk_rqt_plugins.button_general import ServiceButtonGeneralWidget
from jsk_rqt_plugins.button_general import LineEditDialog

class ServiceTabbedButtonGeneralWidget(QWidget):
def __init__(self):
super(ServiceTabbedButtonGeneralWidget, self).__init__()
self._tab_settings = None

if rospy.has_param("~tabbed_layout"):
tabbed_layout = rospy.get_param("~tabbed_layout")
self._tab_list = []
if not 'tab_list' in tabbed_layout:
self.showError("Cannot find tab_list in %s"%(tabbed_layout))
return
tab_list = tabbed_layout['tab_list']
for tb in tab_list:
if tb in tabbed_layout:
param_settings = tabbed_layout[tb]
settings = {}
##
if 'type' in param_settings:
settings['type'] = param_settings['type']
##
if not 'name' in param_settings:
settings['name'] = tb
else:
settings['name'] = param_settings['name']
##
if 'yaml_file' in param_settings:
settings['yaml_file'] = param_settings['yaml_file']
else:
self.showError("Cannot find yaml_file in %s"%(tb))
settings = None
##
if 'namespace' in param_settings:
settings['namespace'] = param_settings['namespace']

if settings:
self._tab_list.append(settings)
else:
self.showError("Cannot find key %s in %s"%(tb, tabbed_layout))
else:
self.showError("Cannot find rosparam ~tabbed_layout")
return

if len(self._tab_list) == 0:
self.showError("there is no valid param in ~tabbed_layout")
return

qtab = QTabWidget()
for tb in self._tab_list:
wg = ServiceButtonGeneralWidget_in_tab(tb)
qtab.addTab(wg, tb['name'] )

#self.setWindowTitle('Tab Layout')
hbox = QHBoxLayout()
hbox.addWidget(qtab)
self.setLayout(hbox)
self.show()

def showError(self, message):
QMessageBox.about(self, "ERROR", message)

def save_settings(self, plugin_settings, instance_settings):
## ignore settings
pass
def restore_settings(self, plugin_settings, instance_settings):
## ignore settings
pass
def trigger_configuration(self):
## ignore settings
pass

class ServiceButtonGeneralWidget_in_tab(ServiceButtonGeneralWidget):
"""
Qt widget to visualize multiple buttons
"""
def __init__(self, settings):
super(ServiceButtonGeneralWidget, self).__init__()
yaml_file = settings['yaml_file']
namespace = None
if 'type' in settings:
self.button_type = settings['type']
else:
self.button_type = 'push'

if 'namespace' in settings:
namespace = settings['namespace']

self._layout_param = None
self._dialog = LineEditDialog()

resolved_yaml = get_filename(yaml_file)
if "file://" == resolved_yaml[0:7]:
resolved_yaml = resolved_yaml[len("file://"):]

with open(resolved_yaml) as f:
yaml_data = yaml.load(f)
self.setupButtons_with_yaml_data(yaml_data=yaml_data, namespace=namespace)

self.show()

0 comments on commit a5893a5

Please sign in to comment.