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

Create BackgroundbuttonWidget and restore ButtonWidget #753

Merged
1 commit merged into from Apr 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion demo/config/targets/INST/screens/commanding.txt
Expand Up @@ -14,6 +14,8 @@ VERTICAL
NAMED_WIDGET COLLECT_TYPE COMBOBOX NORMAL SPECIAL
LABEL " Duration: "
NAMED_WIDGET DURATION TEXTFIELD 12 "10.0"
# Button widgets execute their code directly in the GUI thread
# This allows us to directly ask for the text on the named widget
BUTTON 'Start Collect' 'target_name = get_target_name("INST"); cmd("#{target_name} COLLECT with TYPE #{get_named_widget("COLLECT_TYPE").text}, DURATION #{get_named_widget("DURATION").text.to_f}")'
END
END
Expand All @@ -31,7 +33,10 @@ VERTICAL
VERTICALBOX
SECTIONHEADER "Run Script:"
NAMED_WIDGET SCRIPTNAME COMBOBOX <%= Dir["#{Cosmos::System.paths['PROCEDURES'][0]}/*"].map {|x| File.basename(x) }.join(' ') %>
BUTTON 'Run Script' 'Cosmos.run_process("#{Cosmos::USERPATH}/tools/ScriptRunner -r #{get_named_widget("SCRIPTNAME").text}")'
# Here as an example we're using the BACKGROUNDBUTTON which runs all the code in the background.
# Note we didn't need to use this here but it's an example of wrapping calls to the GUI in Qt.execute_in_main_thread.
# You need to use this button if your code blocks or takes a long time to execute so you don't hang the screen.
BACKGROUNDBUTTON 'Run Script' 'Cosmos.run_process("#{Cosmos::USERPATH}/tools/ScriptRunner -r #{Qt.execute_in_main_thread { get_named_widget("SCRIPTNAME").text }}")'
END
SETTING BACKCOLOR 163 185 163
END
1 change: 1 addition & 0 deletions lib/cosmos/tools/tlm_viewer/widgets.rb
Expand Up @@ -2,6 +2,7 @@
require 'cosmos/tools/tlm_viewer/widgets/array_widget.rb'
require 'cosmos/tools/tlm_viewer/widgets/block_widget.rb'
require 'cosmos/tools/tlm_viewer/widgets/button_widget.rb'
require 'cosmos/tools/tlm_viewer/widgets/backgroundbutton_widget.rb'
require 'cosmos/tools/tlm_viewer/widgets/canvasdot_widget.rb'
require 'cosmos/tools/tlm_viewer/widgets/canvasimagevalue_widget.rb'
require 'cosmos/tools/tlm_viewer/widgets/canvasimage_widget.rb'
Expand Down
54 changes: 54 additions & 0 deletions lib/cosmos/tools/tlm_viewer/widgets/backgroundbutton_widget.rb
@@ -0,0 +1,54 @@
# encoding: ascii-8bit

# Copyright 2014 Ball Aerospace & Technologies Corp.
# All Rights Reserved.
#
# This program is free software; you can modify and/or redistribute it
# under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 3 with
# attribution addendums as found in the LICENSE.txt

# This file contains the implementation of the BackgroundbuttonWidget class.

require 'cosmos'
require 'cosmos/tools/tlm_viewer/widgets/widget'
require 'cosmos/gui/utilities/script_module_gui'

module Cosmos
# Run user defined code in the background. This means that all code which
# interacts with the GUI MUST be wrapped in Qt.execute_in_main_thread.
class BackgroundbuttonWidget < Qt::PushButton
include Widget

def initialize(parent_layout, button_text, string_to_eval)
super()
setText(button_text.to_s)
connect(SIGNAL('clicked()')) { execute(string_to_eval.to_s) }
parent_layout.addWidget(self) if parent_layout
end

def execute(code)
# Disable the button while the code is executed to avoid thrashing
setEnabled(false)
# Spawn a new thread to avoid blocking the GUI.
Thread.new do
begin
@screen.instance_eval(code)
rescue DRb::DRbConnError
Qt.execute_in_main_thread do
Qt::MessageBox.warning(parent.parentWidget, 'Error', "Error Connecting to Command and Telemetry Server")
end
rescue Exception => error
message = error.message
if error.message.include?("Qt methods cannot be called")
message = "Error executing button code:\n#{code}\n\nYou must wrap calls to the GUI in Qt.execute_in_main_thread { <GUI Code> }"
end
Qt.execute_in_main_thread do
Qt::MessageBox.warning(parent.parentWidget, 'Error', "#{error.class} : #{message}")
end
end
Qt.execute_in_main_thread { self.setEnabled(true) }
end
end
end
end
30 changes: 8 additions & 22 deletions lib/cosmos/tools/tlm_viewer/widgets/button_widget.rb
Expand Up @@ -15,39 +15,25 @@
require 'cosmos/gui/utilities/script_module_gui'

module Cosmos
# Run user defined code in the GUI thread context. This means that user
# code should not block or take too long to execute as it will freeze
# the TlmViewer screen.
class ButtonWidget < Qt::PushButton
include Widget

def initialize(parent_layout, button_text, string_to_eval)
super()
setText(button_text.to_s)
connect(SIGNAL('clicked()')) { execute(string_to_eval.to_s) }
parent_layout.addWidget(self) if parent_layout
end

def execute(code)
# Disable the button while the code is executed to avoid thrashing
setEnabled(false)
# Spawn a new thread to avoid blocking the GUI. Users will have to
# wrap any GUI interaction in Qt.execute_in_main_thread.
Thread.new do
connect(SIGNAL('clicked()')) do
begin
@screen.instance_eval(code)
@screen.instance_eval(string_to_eval.to_s)
rescue DRb::DRbConnError
Qt.execute_in_main_thread do
Qt::MessageBox.warning(parent.parentWidget, 'Error', "Error Connecting to Command and Telemetry Server")
end
Qt::MessageBox.warning(parent.parentWidget, 'Error', "Error Connecting to Command and Telemetry Server")
rescue Exception => error
message = error.message
if error.message.include?("Qt methods cannot be called")
message = "Error executing button code:\n#{code}"
end
Qt.execute_in_main_thread do
Qt::MessageBox.warning(parent.parentWidget, 'Error', "#{error.class} : #{message}")
end
Qt::MessageBox.warning(parent.parentWidget, 'Error', "#{error.class} : #{error.message}")
end
Qt.execute_in_main_thread { self.setEnabled(true) }
end
parent_layout.addWidget(self) if parent_layout
end
end
end