Source code for gui.toolbar
#
##
## This file is part of pyFormex 2.0 (Mon Sep 14 12:29:05 CEST 2020)
## pyFormex is a tool for generating, manipulating and transforming 3D
## geometrical models by sequences of mathematical operations.
## Home page: http://pyformex.org
## Project page: http://savannah.nongnu.org/projects/pyformex/
## Copyright 2004-2020 (C) Benedict Verhegghe (benedict.verhegghe@ugent.be)
## Distributed under the GNU General Public License version 3 or later.
##
## 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 3 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, see http://www.gnu.org/licenses/.
##
"""Toolbars for the pyFormex GUI.
This module defines the functions for creating the pyFormex window toolbars.
"""
import pyformex as pf
from pyformex import utils
from pyformex.gui import QtGui, QPixmap
from pyformex.gui import widgets
################### General Button Functions ###########
[docs]def addButton(toolbar, tooltip, icon, func, repeat=False, toggle=False, checked=False, icon0=None, enabled=True):
"""Add a button to a toolbar.
- `toolbar`: the toolbar where the button will be added
- `tooltip`: the text to appear as tooltip
- `icon`: name of the icon to be displayed on the button,
- `func`: function to be called when the button is pressed,
- `repeat`: if True, the `func` will repeatedly be called if button is
held down.
- `toggle`: if True, the button is a toggle and stays in depressed state
until pressed again.
- `checked`: initial state for a toggle buton.
- `icon1`: for a toggle button, icon to display when button is not checked.
"""
iconset = QtGui.QIcon()
icon_on = QPixmap(utils.findIcon(icon))
iconset.addPixmap(icon_on, QtGui.QIcon.Normal, QtGui.QIcon.On)
if toggle and icon0:
icon_off = QPixmap(utils.findIcon(icon0))
iconset.addPixmap(icon_off, QtGui.QIcon.Normal, QtGui.QIcon.Off)
a = toolbar.addAction(iconset, tooltip, func)
a.setEnabled(enabled)
b = toolbar.widgetForAction(a)
if repeat:
b.setAutoRepeat(True)
b.setAutoRepeatDelay(500)
b.clicked.connect(a.trigger)
if toggle:
b.setCheckable(True)
b.clicked.connect(b.toggle)
b.setChecked(checked)
b.setToolTip(tooltip)
return b
[docs]def removeButton(toolbar, button):
"""Remove a button from a toolbar."""
toolbar.removeAction(button)
################### Script action toolbar ###########
[docs]def addActionButtons(toolbar):
"""Add the script action buttons to the toolbar."""
from pyformex.gui import draw
from pyformex.gui.menus import File
action = {}
avail_buttons = [
("Play", "next", draw.play, False),
("ReRun", "rerun", draw.replay, False),
## ( "Step", "nextstop", draw.step, False ),
("Continue", "ff", draw.fforward, False),
("Stop", "stop", draw.raiseExit, False),
("Edit", "pencil", File.editApp, False),
("Info", "info", draw.showDoc, False),
]
# Filter configured buttons
show_buttons = pf.cfg['gui/actionbuttons']
show_buttons = [b for b in avail_buttons if b[0].lower() in show_buttons]
for name, icon, func, enabled in show_buttons:
action[name] = addButton(toolbar, '', icon, func, enabled=enabled)
return action
################# Camera action toolbar ###############
[docs]def addCameraButtons(toolbar):
"""Add the camera buttons to a toolbar."""
# The buttons have the following fields:
# 0 : tooltip
# 1 : icon
# 2 : function
# optional:
# 3 : REPEAT (default True)
from pyformex.gui.menus import Camera
buttons = [["Rotate left", "rotleft", Camera.rotLeft],
["Rotate right", "rotright", Camera.rotRight],
["Rotate up", "rotup", Camera.rotUp],
["Rotate down", "rotdown", Camera.rotDown],
["Twist left", "twistleft", Camera.twistLeft],
["Twist right", "twistright", Camera.twistRight],
["Translate left", "left", Camera.panLeft],
["Translate right", "right", Camera.panRight],
["Translate down", "down", Camera.panDown],
["Translate up", "up", Camera.panUp],
["Zoom Out", "zoomout", Camera.dollyOut],
["Zoom In", "zoomin", Camera.dollyIn],
["Zoom All", "zoomall", Camera.zoomAll, False],
["Zoom Rectangle", "zoomrect", Camera.zoomRectangle, False],
]
for but in buttons:
icon = widgets.pyformexIcon(but[1])
a = toolbar.addAction(icon, but[0], but[2])
b = toolbar.children()[-1] # Get the QToolButton for the last action
if len(but) < 4 or but[3]:
b.setAutoRepeat(True)
b.setAutoRepeatDelay(500)
# This causes a double action on the button click
# only use it if we can detach the button press from trigger
#b.released.connect(a.trigger)
if len(but) >= 5:
# This is currently not used
b.setCheckable(but[4])
b.released.connect(a.toggle)
b.setToolTip(but[0])
#######################################################################
# Viewport Toggle buttons #
###########################
class Toggle(object):
def __init__(self, state=False):
self.state = state
def toggle(self, onoff=None):
if onoff is None:
onoff = not self.state
self.state = onoff
class ViewportToggleButton(object):
def __init__(self, toolbar, tooltip, icon, func, attr, checked=False, icon0=None):
self.button = addButton(toolbar, tooltip, icon, func, toggle=True, icon0=icon0)
self.attr = attr
def updateButton(self):
"""Update the button to current viewport state."""
#print "UPDATE TOGGLE %s" % attr
vp = pf.GUI.viewports.current
if vp == pf.canvas:
self.setChecked(vp.settings[self.attr])
pf.GUI.processEvents()
def toggle(self, attr, state=None):
"""Update the corresponding viewport attribute.
This does not update the button state.
"""
vp = pf.GUI.viewports.current
vp.setToggle(attr, state)
vp.update()
pf.GUI.processEvents()
[docs]def toggleButton(attr, state=None):
"""Update the corresponding viewport attribute.
This does not update the button state.
"""
vp = pf.GUI.viewports.current
vp.setToggle(attr, state)
vp.update()
pf.GUI.processEvents()
[docs]def updateButton(button, attr):
"""Update the button to correct state."""
if button:
vp = pf.GUI.viewports.current
button.setChecked(vp.settings[attr])
pf.GUI.processEvents()
def updateViewportButtons(vp):
## if vp != pf.GUI.viewports.current:
## print "viewport %s is not current" % pf.GUI.viewports.viewIndex(vp)
if vp.focus:
#print "viewport %s has focus" % pf.GUI.viewports.viewIndex(vp)
updateWireButton()
updateTransparencyButton()
updateLightButton()
updateNormalsButton()
#
# BEWARE: The toggle functions are currently not passed the state!
# It should be got from
#
################# Wire Button ###############
wire_button = None # the toggle wire button
def addWireButton(toolbar):
global wire_button
wire_button = addButton(toolbar, 'Toggle Wire Mode',
'wireall', toggleWire, icon0='wirenone',
toggle=True)
def toggleWire(state=None):
vp = pf.GUI.viewports.current
state = wire_button.isChecked()
# TODO:
# WELL, it looks like we get here BEFORE the button is updated,
# so we need to change the state.
# WE should really connect this to a signal that is raised
# AFTER the button state is update
state = not state
vp.setWireMode(state)
vp.update()
pf.GUI.processEvents()
[docs]def updateWireButton():
"""Update the wire button to correct state."""
if wire_button:
vp = pf.GUI.viewports.current
wire_button.setChecked(vp.settings['wiremode'] > 0)
pf.GUI.processEvents()
################# Transparency Button ###############
transparency_button = None # the toggle transparency button
def addTransparencyButton(toolbar):
global transparency_button
transparency_button = addButton(toolbar, 'Toggle Transparent Mode',
'transparent', toggleTransparency,
toggle=True)
def toggleTransparency(state=None):
toggleButton('alphablend', state)
[docs]def updateTransparencyButton():
"""Update the transparency button to correct state."""
updateButton(transparency_button, 'alphablend')
################# Lights Button ###############
light_button = None
def addLightButton(toolbar):
global light_button
light_button = addButton(toolbar, 'Toggle Lights',
'lamp-on', toggleLight, icon0='lamp',
toggle=True, checked=False)
def toggleLight(state=None):
toggleButton('lighting', state)
[docs]def updateLightButton():
"""Update the light button to correct state."""
updateButton(light_button, 'lighting')
################# Normals Button ###############
normals_button = None
def addNormalsButton(toolbar):
global normals_button
normals_button = addButton(toolbar, 'Toggle Normals',
'normals-avg', toggleNormals, icon0='normals-ind',
toggle=True, checked=False)
def toggleNormals(state=None):
toggleButton('avgnormals', state)
[docs]def updateNormalsButton(state=True):
"""Update the normals button to correct state."""
updateButton(normals_button, 'avgnormals')
################# Perspective Button ###############
perspective_button = None # the toggle perspective button
def togglePerspective(mode=None): # Called by the button, not by user
vp = pf.GUI.viewports.current
if mode is None:
mode = not vp.camera.perspective
vp.camera.setPerspective(mode)
vp.display()
vp.update()
pf.GUI.processEvents()
def addPerspectiveButton(toolbar):
global perspective_button
perspective_button = addButton(toolbar, 'Toggle Perspective/Projective Mode',
'perspect', togglePerspective,
toggle=True, icon0='project', checked=True)
[docs]def updatePerspectiveButton():
"""Update the normals button to correct state."""
#updateButton(perspective_button,'avgnormals')
vp = pf.GUI.viewports.current
if vp == pf.canvas:
perspective_button.setChecked(vp.camera.perspective)
pf.GUI.processEvents()
def setPerspective():
togglePerspective(True)
updatePerspectiveButton()
def setProjection():
togglePerspective(False)
updatePerspectiveButton()
################# Shrink Button ###############
#
# The shrink button currently does not redraw, it only sets the default
# shrink factor and clears the viewport
#
shrink_button = None # the toggle shrink button
def toggleShrink(): # Called by the button
from pyformex.gui import draw
mode = draw.DrawOptions.get('shrink', None)
if mode is None:
mode = 0.8
else:
mode = None
draw.shrink(mode)
def addShrinkButton(toolbar):
global shrink_button
shrink_button = addButton(toolbar, 'Toggle Shrink Mode',
'shrink', toggleShrink,
toggle=True)
def setShrink(mode):
from pyformex.gui import draw
draw.shrink(mode)
if shrink_button:
shrink_button.setChecked(mode != None)
################# Timeout Button ###############
timeout_button = None # the timeout toggle button
def toggleTimeout(onoff=None):
if onoff is None:
onoff = widgets.input_timeout < 0
if onoff:
timeout = pf.cfg['gui/timeoutvalue']
else:
timeout = -1
widgets.setInputTimeout(timeout)
onoff = widgets.input_timeout > 0
if onoff:
# THIS SUSPENDS ALL WAITING! WE SHOULD IMPLEMENT A TIMEOUT!
# BY FORCING ALL INDEFINITE PAUSES TO A WAIT TIME EQUAL TO
# WIDGET INPUT TIMEOUT
pf.debug("FREEING the draw lock")
pf.GUI.drawlock.free()
else:
pf.debug("ALLOWING the draw lock")
pf.GUI.drawlock.allow()
return onoff
[docs]def addTimeoutButton(toolbar):
"""Add or remove the timeout button,depending on cfg."""
global timeout_button
if pf.cfg['gui/timeoutbutton']:
if timeout_button is None:
timeout_button = addButton(toolbar, 'Toggle Timeout', 'clock', toggleTimeout, toggle=True, checked=False)
else:
if timeout_button is not None:
removeButton(toolbar, timeout_button)
timeout_button = None
[docs]def timeout(onoff=None):
"""Programmatically toggle the timeout button"""
if timeout_button is not None:
timeout_button.setChecked(toggleTimeout(onoff))
# End