Skip to content

Commit

Permalink
added scrolling, and fixed loading bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
cbteeple committed Mar 28, 2022
1 parent e6726cc commit 018c8e0
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 21 deletions.
16 changes: 16 additions & 0 deletions armstron/config/test_profiles/simple_pull_test2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
params:
preload:
- {balance: pose}
- jog:
angular: [0.0, 0.0, 0.0]
linear: [0.0, 0.0, -0.003]
stop_conditions: {min_force_z: -60.0}
- pose:
orientation: [0.0, 0.0, 0.0]
position: [0.0, 0.0, 0.0]
test:
- jog:
angular: [0.0, 0.0, 0.0]
linear: [0.0, 0.0, 0.001]
stop_conditions: {max_position_z: 0.02}
type: sequence
1 change: 1 addition & 0 deletions armstron/scripts/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ def init_profile_handler(self, parent):
)
self.profile_handler.set_callback('open_after',self.update_config)
self.profile_handler.set_callback('saveas_before',self.get_config_from_gui)
self.profile_handler.set_callback('saveas_after',lambda : self.profile_handler.open_file(direct=True))


self.save_handler = ProfileHandler(
Expand Down
29 changes: 23 additions & 6 deletions armstron/src/armstron/gui/profile_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from ttkthemes import ThemedTk

from armstron.gui.utils import Spinbox, OptionSwitcher
from armstron.gui.utils import Spinbox, OptionSwitcher, ScrollbarLabelFrame


class ProfileEditor:
Expand Down Expand Up @@ -347,6 +347,13 @@ def _make_input_group(self, parent, config, vars, index):
condition['signal'],
sorted(self.stop_values.keys()))

def cb (*args):
cond.update_options(self.stop_values[var['signal'].get()])
fr_stop_inner.configure(bg=self.colors[var['signal'].get()][1])

var['signal'].trace("w", cb)
# cond.update_options(self.stop_values[value])

box = Spinbox(fr_stop_inner, textvariable=var['value'])
box.set(condition['value'])
cond.pack(expand=False, fill="y", side='left')
Expand Down Expand Up @@ -491,7 +498,11 @@ def _init_inputs(self, parent, profile, var_tree):
preload_vars = var_tree['params'].get('preload')
test_vars = var_tree['params'].get('test')

fr_preload = tk.LabelFrame(self.fr_buttons, text="Preload", font=('Arial', 12, 'bold'), bd=2)
sbf = ScrollbarLabelFrame(self.fr_buttons, text="Preload", font=('Arial', 12, 'bold'), bd=2)
sbf.pack(expand=True, fill="both", padx=5, pady=5, side='left')
#canvas = Scrollable(self.fr_buttons)

fr_preload = sbf.scrolled_frame #tk.LabelFrame(sbf.scrolled_frame, text="Preload", font=('Arial', 12, 'bold'), bd=2)
for idx,seg in enumerate(preload):
fr_step=tk.Frame(fr_preload)
fr_step.pack(expand=False, fill='both', side='top')
Expand All @@ -509,9 +520,15 @@ def _init_inputs(self, parent, profile, var_tree):
fr_ctrl.pack(expand=False, fill="both", padx=5, pady=5, side='left')
fr.pack(expand=False, fill="both", padx=5, pady=5, side='left')

fr_preload.pack(expand=False, fill="both", padx=5, pady=5, side='left')
#fr_preload.pack(expand=False, fill="both", padx=5, pady=5, side='left')

sbf2 = ScrollbarLabelFrame(self.fr_buttons, text="Preload", font=('Arial', 12, 'bold'), bd=2)
sbf2.pack(expand=True, fill="both", padx=5, pady=5, side='left')
#canvas = Scrollable(self.fr_buttons)

fr_test = sbf2.scrolled_frame

fr_test = tk.LabelFrame(self.fr_buttons ,text="Main Test", font=('Arial', 12, 'bold'), bd=2)
#fr_test = tk.LabelFrame(self.fr_buttons ,text="Main Test", font=('Arial', 12, 'bold'), bd=2)
for idx,seg in enumerate(test):
fr_step=tk.Frame(fr_test)
fr_step.pack(expand=False, fill='both', side='top')
Expand All @@ -529,9 +546,9 @@ def _init_inputs(self, parent, profile, var_tree):
fr_ctrl.pack(expand=False, fill="both", padx=5, pady=5, side='left')
fr.pack(expand=False, fill="both", padx=5, pady=5, side='left')

fr_test.pack(expand=False, fill="both", padx=5, pady=5, side='left')
#fr_test.pack(expand=False, fill="both", padx=5, pady=5, side='left')

self.fr_buttons.pack(expand=False, fill="x", side='top')
self.fr_buttons.pack(expand=True, fill="both", side='top')


def __del__(self):
Expand Down
22 changes: 12 additions & 10 deletions armstron/src/armstron/gui/profile_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,21 @@ def _check_enable_buttons(self):
self.buttons['saveas'].configure(state='disabled')


def open_file(self):
def open_file(self, direct=False):

self.callbacks['open_before']()

filepath = fdialog.askopenfilename(
filetypes=self.file_types,
initialdir=self.curr_config_file['dirname'],
initialfile=self.curr_config_file['basename']
)
if not filepath:
return None
self.curr_config_file['basename'] = os.path.basename(filepath)
self.curr_config_file['dirname'] = os.path.dirname(filepath)
if not direct:
filepath = fdialog.askopenfilename(
filetypes=self.file_types,
initialdir=self.curr_config_file['dirname'],
initialfile=self.curr_config_file['basename']
)
if not filepath:
return None
self.curr_config_file['basename'] = os.path.basename(filepath)
self.curr_config_file['dirname'] = os.path.dirname(filepath)

self.load_file()
self._check_enable_buttons()

Expand Down
164 changes: 159 additions & 5 deletions armstron/src/armstron/gui/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import os
import sys
import copy
import time
import numpy as np
if sys.version_info[0] == 3:
import tkinter as tk
import tkinter.ttk as ttk
Expand Down Expand Up @@ -35,10 +37,162 @@ def set(self, value):

class OptionSwitcher(ttk.OptionMenu):
def __init__(self, container, variable, default=None, *values, **kwargs):
fill_option = "< Choose >"
values_cp = copy.deepcopy(*values)
values_cp.insert(0, fill_option)
self.container=container
self.variable=variable
self.default=default
self.fill_option = "< Choose >"
self.values=self._add_fill_option(*values)

if default is None:
default = values_cp[0]
default = self.values[0]

ttk.OptionMenu.__init__(self,container,variable, default, *self.values, **kwargs)


def _add_fill_option(self,options):
values_cp = copy.deepcopy(options)
values_cp.insert(0, self.fill_option)
return values_cp


def update_options(self, options):
self.values=self._add_fill_option(options)

self['menu'].delete(0, "end")
for string in self.values:
self['menu'].add_command(label=string,
command=lambda value=string: self.variable.set(value))

self.variable.set(self.fill_option)

def get_options(self):
return self.values[1:]


class Scrollable(tk.Frame):
"""
Make a frame scrollable with scrollbar on the right.
After adding or removing widgets to the scrollable frame,
call the update() method to refresh the scrollable area.
"""

def __init__(self, frame, width=16):

scrollbar = tk.Scrollbar(frame, width=width)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y, expand=False)

self.canvas = tk.Canvas(frame, yscrollcommand=scrollbar.set)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

scrollbar.config(command=self.canvas.yview)

self.canvas.bind('<Configure>', self.__fill_canvas)

# base class initialization
tk.Frame.__init__(self, frame)

# assign this obj (the inner frame) to the windows item of the canvas
self.windows_item = self.canvas.create_window(0,0, window=self, anchor=tk.NW)


def __fill_canvas(self, event):
"Enlarge the windows item to the canvas width"

canvas_width = event.width
self.canvas.itemconfig(self.windows_item, width = canvas_width)

def update(self):
"Update the canvas and the scrollregion"

self.update_idletasks()


class ScrollbarFrame(tk.Frame):
"""
Extends class tk.Frame to support a scrollable Frame
This class is independent from the widgets to be scrolled and
can be used to replace a standard tk.Frame
"""
def __init__(self, parent, **kwargs):
tk.Frame.__init__(self, parent, **kwargs)

# The Scrollbar, layout to the right
vsb = tk.Scrollbar(self, orient="vertical")
vsb.pack(side="right", fill="y")

# The Canvas which supports the Scrollbar Interface, layout to the left
self.canvas = tk.Canvas(self, borderwidth=0)
self.canvas.pack(side="left", fill="both", expand=True)

# Bind the Scrollbar to the self.canvas Scrollbar Interface
def cb(*args):
print(args)
val=float(list(args)[1])
for i in range(20):
self.canvas.yview(args[0],np.ceil(val/20.0), args[2])
time.sleep(0.05)

#self.canvas.configure(yscrollcommand=cb)
self.canvas.configure(yscrollcommand=vsb.set)
#self.canvas.configure(scrollregion=self.canvas.bbox("all"))
vsb.configure(command=self.canvas.yview)

# The Frame to be scrolled, layout into the canvas
# All widgets to be scrolled have to use this Frame as parent
self.scrolled_frame = tk.Frame(self.canvas, background=self.canvas.cget('bg'))
self.canvas.create_window((4, 4), window=self.scrolled_frame, anchor="nw")

# Configures the scrollregion of the Canvas dynamically
self.scrolled_frame.bind("<Configure>", self.on_configure)

def on_configure(self, event):
"""Set the scroll region to encompass the scrolled frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))


class ScrollbarLabelFrame(tk.LabelFrame):
"""
Extends class tk.Frame to support a scrollable Frame
This class is independent from the widgets to be scrolled and
can be used to replace a standard tk.Frame
"""
def __init__(self, parent, **kwargs):
tk.LabelFrame.__init__(self, parent, **kwargs)

# The Scrollbar, layout to the right
vsb = tk.Scrollbar(self, orient="vertical")
vsb.pack(side="right", fill="y")

# The Canvas which supports the Scrollbar Interface, layout to the left
self.canvas = tk.Canvas(self, borderwidth=0)
self.canvas.pack(side="left", fill="both", expand=True)

# Bind the Scrollbar to the self.canvas Scrollbar Interface
def cb(*args):
if args[0] =='moveto':
self.canvas.yview(*args)

else:
val=float(args[1])
args = list(args)
args[1] = int(np.sign(val)*np.ceil(abs(val)/5.0))
self.canvas.yview(*tuple(args))


#self.canvas.configure(yscrollcommand=cb)
self.canvas.configure(yscrollcommand=vsb.set)
#self.canvas.configure(scrollregion=self.canvas.bbox("all"))
vsb.configure(command=cb)
#vsb.configure(command=self.canvas.yview)

# The Frame to be scrolled, layout into the canvas
# All widgets to be scrolled have to use this Frame as parent
self.scrolled_frame = tk.Frame(self.canvas, background=self.canvas.cget('bg'))
self.canvas.create_window((4, 4), window=self.scrolled_frame, anchor="nw")

# Configures the scrollregion of the Canvas dynamically
self.scrolled_frame.bind("<Configure>", self.on_configure)

ttk.OptionMenu.__init__(self, container,variable, default, *values_cp, **kwargs)
def on_configure(self, event):
"""Set the scroll region to encompass the scrolled frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))

0 comments on commit 018c8e0

Please sign in to comment.