431 lines
18 KiB
Python
431 lines
18 KiB
Python
# This is a component of LinuxCNC
|
|
# Copyright 2013 Chris Morley <chrisinnanaimo@hotmail.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
|
|
import gi
|
|
from gi.repository import Gtk as gtk
|
|
from gi.repository import Gdk
|
|
from gi.repository import Pango as pango
|
|
|
|
import hal
|
|
import gladevcp.makepins # needed for the dialog's calulator widget
|
|
|
|
_MAN = 0;_MDI = 1;_AUTO = 2;_LOCKTOGGLE = 1
|
|
|
|
# This is a handler file for using Gscreen's infrastructure
|
|
# to load a completely custom glade screen
|
|
# The only things that really matters is that it's saved as a GTK builder project,
|
|
# the toplevel window is caller window1 (The default name) and you connect a destroy
|
|
# window signal else you can't close down linuxcnc
|
|
class HandlerClass:
|
|
|
|
# This will be pretty standard to gain access to everything
|
|
# emc is for control and status of linuxcnc
|
|
# data is important data from gscreen and linuxcnc
|
|
# widgets is all the widgets from the glade files
|
|
# gscreen is for access to gscreens methods
|
|
def __init__(self, halcomp,builder,useropts,gscreen):
|
|
self.emc = gscreen.emc
|
|
self.data = gscreen.data
|
|
self.widgets = gscreen.widgets
|
|
self.gscreen = gscreen
|
|
|
|
# This is a new method that calls a gscreen method to toggle the DRO units
|
|
# Gscreen's regular unit button saves the state
|
|
# for startup, This one just changes it for the session
|
|
def on_metric_select_clicked(self,widget):
|
|
data = (self.data.dro_units -1) * -1
|
|
self.gscreen.set_dro_units(data,False)
|
|
for i in ("1","2","3"):
|
|
for letter in self.data.axis_list:
|
|
axis = "dro_%s%s"% (letter,i)
|
|
try:
|
|
self.widgets[axis].set_property("display_units_mm",data)
|
|
except:
|
|
pass
|
|
|
|
def on_diameter_mode_pressed(self, widget):
|
|
data = widget.get_active()
|
|
print("switch diam mode",data)
|
|
self.gscreen.set_diameter_mode(data)
|
|
for i in ("1","2","3"):
|
|
axis = "dro_x%s"% (i)
|
|
if data:
|
|
self.widgets[axis].set_to_diameter()
|
|
else:
|
|
self.widgets[axis].set_to_radius()
|
|
|
|
# This is a new method for our button
|
|
# we selected this method name in the glade file as a signal callback
|
|
def on_estop_clicked(self,*args):
|
|
print("estop")
|
|
if self.data.estopped:
|
|
self.emc.estop_reset(1)
|
|
self.gscreen.add_alarm_entry("Machine Estop Reset")
|
|
else:
|
|
self.emc.machine_off(1)
|
|
self.emc.estop(1)
|
|
self.widgets.on_label.set_text("Machine Off")
|
|
self.gscreen.add_alarm_entry("Machine Estopped and Powered Off")
|
|
return True
|
|
|
|
# This is a new method for our new button
|
|
# we selected this method name in the glade file as a signal callback
|
|
def on_machine_state_clicked(self,widget):
|
|
if self.data.estopped:
|
|
return
|
|
elif not self.data.machine_on:
|
|
self.emc.machine_on(1)
|
|
self.widgets.on_label.set_text("Machine On")
|
|
self.gscreen.add_alarm_entry("Machine powered on")
|
|
else:
|
|
self.emc.machine_off(1)
|
|
self.widgets.on_label.set_text("Machine Off")
|
|
self.gscreen.add_alarm_entry("Machine powered off")
|
|
|
|
# display the main tab and set the mode to setup
|
|
def on_setup_button_clicked(self,widget):
|
|
self.widgets.notebook_main.set_current_page(0)
|
|
self.data.mode_order = _MAN,_MDI,_AUTO
|
|
label = self.data.mode_labels
|
|
self.widgets.button_mode.set_label(label[self.data.mode_order[0]])
|
|
self.gscreen.mode_changed(self.data.mode_order[0])
|
|
self.toggle_modes(widget)
|
|
|
|
# display the main tab and set the mode to run
|
|
def on_run_button_clicked(self,widget):
|
|
self.widgets.notebook_main.set_current_page(0)
|
|
self.data.mode_order = _AUTO,_MAN,_MDI
|
|
label = self.data.mode_labels
|
|
self.widgets.button_mode.set_label(label[self.data.mode_order[0]])
|
|
self.gscreen.mode_changed(self.data.mode_order[0])
|
|
self.toggle_modes(widget)
|
|
|
|
# display the main tab and set the mode to MDI
|
|
def on_mdi_button_clicked(self,widget):
|
|
self.widgets.notebook_main.set_current_page(0)
|
|
self.data.mode_order = _MDI,_MAN,_AUTO
|
|
label = self.data.mode_labels
|
|
self.widgets.button_mode.set_label(label[self.data.mode_order[0]])
|
|
self.gscreen.mode_changed(self.data.mode_order[0])
|
|
self.toggle_modes(widget)
|
|
|
|
# This is called when the system button is toggled
|
|
# If the page is not showing it displays a unlock code dialog
|
|
# unless you have already unlocked the page.
|
|
# if that returns true then the page is shown
|
|
# otherwise the button is untoggled and the page is not shown
|
|
# if you press the system buttonn when the system page is already showing
|
|
# it will relock the page
|
|
def on_system_button_clicked(self,widget):
|
|
if self.widgets.notebook_main.get_current_page() == 4:
|
|
self.gscreen.block("system_button")
|
|
widget.set_active(True)
|
|
self.gscreen.unblock("system_button")
|
|
global _LOCKTOGGLE
|
|
_LOCKTOGGLE=1
|
|
self.widgets.system_button.set_label(" System\n(Locked)")
|
|
self.gscreen.add_alarm_entry("System page re-locked")
|
|
self.on_setup_button_clicked(self.widgets.setup_button)
|
|
return
|
|
if not self.system_dialog():
|
|
self.gscreen.block("system_button")
|
|
widget.set_active(False)
|
|
self.gscreen.unblock("system_button")
|
|
return
|
|
self.widgets.notebook_main.set_current_page(4)
|
|
self.toggle_modes(widget)
|
|
self.widgets.system_button.set_label(" System\n ")
|
|
|
|
# Display the tooledit tab
|
|
def on_tooledit_button_clicked(self,widget):
|
|
self.widgets.notebook_main.set_current_page(3)
|
|
self.toggle_modes(widget)
|
|
|
|
# Display the offsetpage tab
|
|
def on_offsetpage_button_clicked(self,widget):
|
|
self.widgets.notebook_main.set_current_page(2)
|
|
self.toggle_modes(widget)
|
|
|
|
# This toggles the buttons so only one is presses at any one time
|
|
def toggle_modes(self,widget):
|
|
temp = "setup_button","mdi_button","run_button","tooledit_button","system_button","offsetpage_button"
|
|
for i in temp:
|
|
state = False
|
|
if self.widgets[i] == widget: state = True
|
|
self.gscreen.block(i)
|
|
self.widgets[i].set_active(state)
|
|
self.gscreen.unblock(i)
|
|
|
|
def on_button_edit_clicked(self,widget):
|
|
state = widget.get_active()
|
|
if not state:
|
|
self.gscreen.edited_gcode_check()
|
|
self.widgets.notebook_main.set_current_page(0)
|
|
self.widgets.notebook_main.set_show_tabs(not (state))
|
|
self.gscreen.edit_mode(state)
|
|
if not state and self.widgets.button_full_view.get_active():
|
|
self.gscreen.set_full_graphics_view(True)
|
|
if self.data.edit_mode:
|
|
self.widgets.mode_select_box.hide()
|
|
self.widgets.search_box.show()
|
|
self.widgets.button_edit.set_label("Exit\nEdit")
|
|
else:
|
|
self.widgets.mode_select_box.show()
|
|
self.widgets.search_box.hide()
|
|
self.widgets.button_edit.set_label("Edit")
|
|
self.widgets.notebook_main.set_show_tabs(False)
|
|
|
|
# This dialog is for unlocking the system tab
|
|
# The unlock code number is defined at the top of the page
|
|
def system_dialog(self):
|
|
global _LOCKTOGGLE
|
|
if _LOCKTOGGLE == 0: return True
|
|
dialog = gtk.Dialog("Enter System Unlock Code",
|
|
self.widgets.window1,
|
|
gtk.DialogFlags.DESTROY_WITH_PARENT)
|
|
label = gtk.Label("Enter System Unlock Code")
|
|
label.modify_font(pango.FontDescription("sans 20"))
|
|
calc = gladevcp.Calculator()
|
|
dialog.vbox.pack_start(label,True,True,0)
|
|
dialog.vbox.add(calc)
|
|
calc.set_value("")
|
|
calc.set_property("font","sans 20")
|
|
calc.set_editable(True)
|
|
calc.entry.connect("activate", lambda w : dialog.emit('response',gtk.ResponseType.ACCEPT))
|
|
calc.integer_entry_only(True)
|
|
calc.num_pad_only(True)
|
|
dialog.parse_geometry("360x400")
|
|
dialog.set_decorated(False)
|
|
dialog.show_all()
|
|
response = dialog.run()
|
|
code = calc.get_value()
|
|
dialog.destroy()
|
|
if response == gtk.ResponseType.ACCEPT:
|
|
if code == int(self.data.unlock_code):
|
|
self.gscreen.add_alarm_entry("System page unlocked")
|
|
_LOCKTOGGLE = 0
|
|
return True
|
|
_LOCKTOGGLE = 1
|
|
return False
|
|
|
|
def _get_RGBA_color(self, color_raw):
|
|
def convert_color(color):
|
|
colortuple = ((int(color.red * 255.0), int(color.green * 255.0), int(color.blue * 255.0)))
|
|
return ('#' + ''.join(f'{i:02X}' for i in colortuple))
|
|
|
|
# convert string RGB to 8bit RGBA
|
|
if type(color_raw) == str:
|
|
color = Gdk.RGBA()
|
|
color.parse(color_raw)
|
|
return convert_color(Gdk.RGBA(color.red, color.green, color.blue, color.alpha))
|
|
|
|
# convert old 16bit RGB to 8bit RGBA
|
|
elif type(color_raw) == tuple:
|
|
b = Gdk.RGBA(color_raw[0], color_raw[1], color_raw[2], 0)
|
|
color = Gdk.RGBA()
|
|
color.parse(b.to_string())
|
|
return convert_color(Gdk.RGBA(color.red, color.green, color.blue, color.alpha))
|
|
|
|
def on_abs_colorbutton_color_set(self,widget):
|
|
self.gscreen.set_abs_color()
|
|
for i in self.data.axis_list:
|
|
axis = "dro_%s1"% i
|
|
color = self._get_RGBA_color(self.data.abs_color)
|
|
self.widgets[axis].set_style("labelcolor", color )
|
|
|
|
def on_rel_colorbutton_color_set(self,widget):
|
|
self.gscreen.set_rel_color()
|
|
color = self._get_RGBA_color(self.data.rel_color)
|
|
for i in self.data.axis_list:
|
|
axis = "dro_%s2"% i
|
|
self.widgets[axis].set_style("labelcolor", color )
|
|
|
|
def on_dtg_colorbutton_color_set(self,widget):
|
|
self.gscreen.set_dtg_color()
|
|
color = self._get_RGBA_color(self.data.dtg_color)
|
|
for i in self.data.axis_list:
|
|
axis = "dro_%s3"% i
|
|
self.widgets[axis].set_style("labelcolor", color )
|
|
|
|
def on_hal_status_not_all_homed(self,widget,data):
|
|
temp =[]
|
|
for letter in self.data.axis_list:
|
|
axnum = "xyzabcuvws".index(letter)
|
|
if str(axnum) in data:
|
|
self.widgets["home_%s"%letter].set_text(" ")
|
|
temp.append(" %s"%letter.upper())
|
|
self.gscreen.add_alarm_entry(_("There are unhomed axes: %s"%temp))
|
|
|
|
def on_hal_status_axis_homed(self,widget,data):
|
|
for letter in self.data.axis_list:
|
|
axnum = "xyzabcuvws".index(letter)
|
|
if str(axnum) in data:
|
|
self.widgets["home_%s"%letter].set_text("*")
|
|
else:
|
|
self.widgets["home_%s"%letter].set_text(" ")
|
|
|
|
def on_show_dtg_pressed(self, widget):
|
|
data = widget.get_active()
|
|
self.widgets.dtg_vbox.set_visible(data)
|
|
self.gscreen.set_show_dtg(data)
|
|
|
|
# Connect to gscreens regular signals and add a couple more
|
|
def connect_signals(self,handlers):
|
|
self.gscreen.connect_signals(handlers)
|
|
# connect to handler file callbacks:
|
|
self.gscreen.widgets.metric_select.connect("clicked", self.on_metric_select_clicked)
|
|
self.gscreen.widgets.diameter_mode.connect("clicked", self.on_diameter_mode_pressed)
|
|
temp = "setup_button","mdi_button","run_button","tooledit_button","system_button","offsetpage_button"
|
|
for cb in temp:
|
|
i = "_sighandler_%s"% (cb)
|
|
self.data[i] = int(self.widgets[cb].connect("toggled", self["on_%s_clicked"%cb]))
|
|
self.widgets.hal_status.connect("not-all-homed",self.on_hal_status_not_all_homed)
|
|
self.widgets.hal_status.connect("homed",self.on_hal_status_axis_homed)
|
|
self.widgets.abs_colorbutton.connect("color-set", self.on_abs_colorbutton_color_set)
|
|
self.widgets.rel_colorbutton.connect("color-set", self.on_rel_colorbutton_color_set)
|
|
self.widgets.dtg_colorbutton.connect("color-set", self.on_dtg_colorbutton_color_set)
|
|
self.widgets.unlock_number.connect("value-changed",self.gscreen.on_unlock_number_value_changed)
|
|
self.widgets.show_dtg.connect("clicked", self.on_show_dtg_pressed)
|
|
|
|
# We don't want Gscreen to initialize ALL it's regular widgets because this custom
|
|
# screen doesn't have them all -just most of them. So we call the ones we want
|
|
def initialize_widgets(self):
|
|
self.gscreen.init_show_windows()
|
|
self.gscreen.init_dynamic_tabs()
|
|
#self.gscreen.init_axis_frames()
|
|
#self.gscreen.init_dro_colors()
|
|
self.gscreen.init_screen2()
|
|
self.gscreen.init_fullscreen1()
|
|
self.gscreen.init_gremlin()
|
|
self.gscreen.init_manual_spindle_controls()
|
|
self.gscreen.init_dro_colors()
|
|
self.init_dro() # local function
|
|
self.gscreen.init_audio()
|
|
self.gscreen.init_desktop_notify()
|
|
self.gscreen.init_statusbar()
|
|
self.gscreen.init_entry()
|
|
self.gscreen.init_tooleditor()
|
|
self.gscreen.init_offsetpage()
|
|
self.gscreen.init_embeded_terminal()
|
|
self.gscreen.init_themes()
|
|
self.gscreen.init_screen1_geometry()
|
|
self.gscreen.init_running_options()
|
|
self.gscreen.init_hide_cursor()
|
|
#self.gscreen.init_mode()
|
|
self.gscreen.mode_changed(self.data.mode_order[0])
|
|
self.gscreen.init_sensitive_on_off()
|
|
self.gscreen.init_sensitive_run_idle()
|
|
self.gscreen.init_sensitive_all_homed()
|
|
self.gscreen.init_sensitive_override_mode()
|
|
self.gscreen.init_sensitive_graphics_mode()
|
|
self.gscreen.init_sensitive_origin_mode()
|
|
self.init_sensitive_edit_mode() # local function
|
|
for i in ("setup_button","mdi_button","run_button","tooledit_button","offsetpage_button","button_index_tool"):
|
|
self.data.sensitive_override_mode.append(i)
|
|
self.data.sensitive_graphics_mode.append(i)
|
|
self.data.sensitive_origin_mode.append(i)
|
|
self.widgets["spindle-at-speed"].set_property("on_color","black")
|
|
self.gscreen.init_unlock_code()
|
|
self.gscreen.init_state()
|
|
for i in ('x','y','z','a','b','c','u','v','w'):
|
|
if i in self.data.axis_list:
|
|
self.widgets["dro_%s1"%i].show()
|
|
self.widgets["dro_%s2"%i].show()
|
|
self.widgets["dro_%s3"%i].show()
|
|
self.widgets["axis_%s"%i].show()
|
|
self.widgets["home_%s"%i].show()
|
|
else:
|
|
self.widgets["dro_%s1"%i].hide()
|
|
self.widgets["dro_%s2"%i].hide()
|
|
self.widgets["dro_%s3"%i].hide()
|
|
self.widgets["axis_%s"%i].hide()
|
|
self.widgets["home_%s"%i].hide()
|
|
|
|
#self.widgets.offsetpage1.set_highlight_color("lightblue")
|
|
self.widgets.offsetpage1.set_font("sans 18")
|
|
self.widgets.offsetpage1.set_row_visible("1",False)
|
|
self.widgets.tooledit1.set_font("sans 18")
|
|
|
|
if self.data.embedded_keyboard:
|
|
self.gscreen.launch_keyboard()
|
|
|
|
def init_sensitive_edit_mode(self):
|
|
self.data.sensitive_edit_mode = ["button_graphics","button_override","button_restart","button_cycle_start","button_single_step",
|
|
"run_button","setup_button","mdi_button","system_button","tooledit_button","ignore_limits",
|
|
"offsetpage_button"]
|
|
|
|
def init_dro(self):
|
|
self.on_abs_colorbutton_color_set(None)
|
|
self.on_rel_colorbutton_color_set(None)
|
|
self.on_dtg_colorbutton_color_set(None)
|
|
self.widgets.show_dtg.set_active(self.data.show_dtg)
|
|
self.on_show_dtg_pressed(self.widgets.show_dtg)
|
|
self.gscreen.init_dro()
|
|
data = self.data.dro_units
|
|
for i in ("1","2","3"):
|
|
for letter in self.data.axis_list:
|
|
axis = "dro_%s%s"% (letter,i)
|
|
try:
|
|
self.widgets[axis].set_property("display_units_mm",data)
|
|
except:
|
|
pass
|
|
|
|
# every 100 milli seconds this gets called
|
|
# we add calls to the regular functions for the widgets we are using.
|
|
# and add any extra calls/code
|
|
def periodic(self):
|
|
self.update_mdi_spindle_button() # local method
|
|
self.gscreen.update_spindle_bar()
|
|
#self.gscreen.update_dro()
|
|
self.gscreen.update_active_gcodes()
|
|
self.gscreen.update_active_mcodes()
|
|
self.gscreen.update_aux_coolant_pins()
|
|
self.gscreen.update_feed_speed_label()
|
|
self.gscreen.update_tool_label()
|
|
self.gscreen.update_coolant_leds()
|
|
self.gscreen.update_estop_led()
|
|
self.gscreen.update_machine_on_led()
|
|
self.gscreen.update_limit_override()
|
|
self.gscreen.update_override_label()
|
|
self.gscreen.update_jog_rate_label()
|
|
self.gscreen.update_mode_label()
|
|
self.gscreen.update_units_button_label()
|
|
|
|
# spindle controls
|
|
def update_mdi_spindle_button(self):
|
|
self.widgets.at_speed_label.set_label(_("%d RPM"%abs(self.data.spindle_speed)))
|
|
label = self.widgets.spindle_control.get_label()
|
|
speed = self.data.spindle_speed
|
|
if speed == 0 and not label == _("Start"):
|
|
temp = _("Start")
|
|
self.widgets["spindle-at-speed"].set_property("on_color","black")
|
|
elif speed and not label == _("Stop"):
|
|
temp = _("Stop")
|
|
self.widgets["spindle-at-speed"].set_property("on_color","green")
|
|
else: return
|
|
self.widgets.spindle_control.set_label(temp)
|
|
|
|
def __getitem__(self, item):
|
|
return getattr(self, item)
|
|
def __setitem__(self, item, value):
|
|
return setattr(self, item, value)
|
|
|
|
# standard handler call
|
|
def get_handlers(halcomp,builder,useropts,gscreen):
|
|
return [HandlerClass(halcomp,builder,useropts,gscreen)]
|