Простой модальный диалог в плагине gimp python-fu может быть реализован через интерфейс Dialog gtk, в частности, gtk.MessageDialog.Общий диалог может быть создан с помощью
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT \
gtk.MESSAGE_QUESTION, \
gtk.BUTTONS_OK_CANCEL, "")
. Как только диалоговое окно было показано, из него можно получить синхронный ответ
queryDialogue.show()
response = queryDialogue.run()
queryDialogue.hide()
Выше предполагается, что диалоговое окно не создается, а затем уничтожается после каждого использования.
В случае использования (упомянутом в вопросе) модального диалогового окна для управления одним пошаговым переходом через pspScript в gimp через пакет эмулятора приложения содержимое диалогового сообщения необходимо настраивать для каждого использования.[Следовательно, "" для аргумента сообщения в конструкторе.[подробнее ниже]]
Кроме того, эмулятор должен быть в состоянии принять [отменить] ответ «выйти из Dodge» - то есть выйти из всего плагина (изящно).Я не смог найти интерфейс gimpfu для последнего (и не хочу полностью убивать приложение через gimp.exit ()).Следовательно, это достигается путем поднятия пользовательского класса Exception [appTerminate] внутри pkg приложения и перехвата исключения в самой внешней области действия плагина.После этого подключаемый модуль возвращает (завершает работу). [App.Do () не может возвращать значение для указания продолжения / выхода / и т. Д., Потому что pspScripts должен быть включен дословно.]
ниже приведен сокращенный каркас решения -
- плагин, включающий (частично) pspScript
- pkg App.py, обеспечивающий среду, и App.Do () для поддержки pspScript
- pkg Map.py, поддерживающий, как pspScripts использует точечную нотацию для параметров
App.py демонстрирует создание, настройку и использование модального диалога - App.doContinue () отображает диалог, иллюстрирующий, как это может бытьнастроены на каждое использование.App._parse () анализирует pspScript (фрагмент, показывающий, как он определяет запуск / остановку одного шага с помощью диалога). App._exec () реализует команды pspScript (фрагмент, показывающий, как он создает диалог, идентифицирует виджет сообщения для последующей настройкии запускает / останавливает его использование)
# App.py (abbreviated)
#
import gimp
import gtk
import Map # see /1874765/kak-ispolzovat-tochku-poluchit-dostup-k-chlenam-slovarya use-a-dot-to-access-members-of-dictionary
from Map import *
pdb = gimp.pdb
isDialogueAvailable = False
queryDialogue = None
queryMessage = None
Environment = Map({'executionMode' : 1 })
_AutoActionMode = Map({'Match' : 0})
_ExecutionMode = Map({'Default' : 0}, Silent=1, Interactive=2)
Constants = Map({'AutoActionMode' : _AutoActionMode}, ExecutionMode=_ExecutionMode ) # etc...
class appTerminate(Exception): pass
def Do(eNvironment, procedureName, options = {}):
global appTerminate
img = gimp.image_list()[0]
lyr = pdb.gimp_image_get_active_layer(img)
parsed = _parse(img, lyr, procedureName, options)
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
resp = doContinue(procedureName, parsed.detail)
if resp == -5: # OK
print procedureName # log to stdout
if parsed.valid:
if parsed.isvalid:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
else:
print "invalid args"
else:
print "invalid procedure"
elif resp == -6: # CANCEL
raise appTerminate, "script cancelled"
pass # terminate plugin
else:
print procedureName + " skipped"
pass # skip execution, continue
else:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
return
def doContinue(procedureName, details):
global queryMessage, querySkip, queryDialogue
# - customize the dialog -
if details == "":
msg = "About to execute procedure \n "+procedureName+ "\n\nContinue?"
else:
msg = "About to execute procedure \n "+procedureName+ "\n\nDetails - \n" + details +"\n\nContinue?"
queryMessage.set_text(msg)
queryDialogue.show()
resp = queryDialogue.run() # get modal response
queryDialogue.hide()
return resp
def _parse(img, lyr, procedureName, options):
# validate and interpret App.Do options' semantics vz gimp
if procedureName == "Selection":
isValid=True
# ...
# parsed = Map({'valid' : True}, isvalid=True, start=Start, width=Width, height=Height, channelOP=ChannelOP ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
newMode = generalOptions['ExecutionMode']
if newMode == Constants.ExecutionMode.Interactive:
msg = "set mode interactive/single-step"
else:
msg = "set mode silent/run"
parsed = Map({'valid' : True}, isvalid=True, detail=msg, mode=newMode)
# /SetExecutionMode
else:
parsed = Map({'valid' : False})
return parsed
def _exec(img, lyr, procedureName, options, o, eNvironment):
global isDialogueAvailable, queryMessage, queryDialogue
#
try:
# -------------------------------------------------------------------------------------------------------------------
if procedureName == "Selection":
# pdb.gimp_rect_select(img, o.start[0], o.start[1], o.width, o.height, o.channelOP, ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
eNvironment.executionMode = generalOptions['ExecutionMode']
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
if isDialogueAvailable:
queryDialogue.destroy() # then clean-up and refresh
isDialogueAvailable = True
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, "")
queryDialogue.set_title("psp/APP.Do Emulator")
queryDialogue.set_size_request(450, 180)
aqdContent = queryDialogue.children()[0]
aqdHeader = aqdContent.children()[0]
aqdMsgBox = aqdHeader.children()[1]
aqdMessage = aqdMsgBox.children()[0]
queryMessage = aqdMessage
else:
if isDialogueAvailable:
queryDialogue.destroy()
isDialogueAvailable = False
# /SetExecutionMode
else: # should not get here (should have been screened by parse)
raise AssertionError, "unimplemented PSP procedure: " + procedureName
except:
raise AssertionError, "App.Do("+procedureName+") generated an exception:\n" + sys.exc_info()
return
Скелет самого плагина.Это иллюстрирует включение pspScript, который включает в себя запрос для одношагового / интерактивного режима выполнения, и, таким образом, диалогов.Он перехватывает исключение завершения, вызванное диалогом, а затем завершается.
def generateWebImageSet(dasImage, dasLayer, title, mode):
try:
img = dasImage.duplicate()
# ...
bkg = img.layers[-1]
frameWidth = 52
start = bkg.offsets
end = (start[0]+bkg.width, start[1]+frameWidth)
# pspScript: (snippet included verbatim)
# SetExecutionMode / begin interactive single-step through pspScript
App.Do( Environment, 'SetExecutionMode', {
'GeneralSettings': {
'ExecutionMode': App.Constants.ExecutionMode.Interactive
}
})
# Selection
App.Do( Environment, 'Selection', {
'General' : {
'Mode' : 'Replace',
'Antialias' : False,
'Feather' : 0
},
'Start': start,
'End': end
})
# Promote
App.Do( Environment, 'SelectPromote' )
# und_so_weiter ...
except App.appTerminate:
raise AssertionError, "script cancelled"
# /generateWebImageSet
# _generateFloatingCanvasSetWeb.register -----------------------------------------
#
def generateFloatingCanvasSetWeb(dasImage, dasLayer, title):
mode="FCSW"
generateWebImageSet(dasImage, dasLayer, title, mode)
register(
"generateFloatingCanvasSetWeb",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"C G",
"C G",
"2019",
"<Image>/Image/Generate Web Imagesets/Floating-Frame Gallery-Wrapped Canvas Imageset...",
"*",
[
( PF_STRING, "title", "title", "")
],
[],
generateFloatingCanvasSetWeb)
main()
Я понимаю, что это может показаться большой работой, просто чтобы включить некоторые pspScripts в плагин gimp, ичтобы можно было пошагово пройти эмуляцию.Но мы говорим о, возможно, 10K строк сценариев (и нескольких сценариев).Однако, если что-то из этого поможет кому-либо еще с диалогами внутри плагинов и т. Д., Тем лучше.