# encoding: utf-8
import os, re
from collections import OrderedDict
from ..lib.cocoa import *
from math import floor, ceil
import objc
## classes instantiated by PlotDeviceDocument.xib & PlotDeviceScript.xib
class StatusView(NSView):
spinner = IBOutlet()
counter = IBOutlet()
cancel = IBOutlet()
def awakeFromNib(self):
self.cancel.setHidden_(True)
self._state = 'idle'
self._finishing = False
opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp);
trackingArea = NSTrackingArea.alloc().initWithRect_options_owner_userInfo_(self.bounds(), opts, self, None)
self.addTrackingArea_(trackingArea)
self.cancel.cell().setHighlightsBy_(NSContentsCellMask)
self.cancel.cell().setShowsStateBy_(NSContentsCellMask)
self.counter.setHidden_(True)
def beginExport(self):
self._state = 'run'
self.spinner.stopAnimation_(None)
self.cancel.setHidden_(True)
self.spinner.setIndeterminate_(False)
self.spinner.setDoubleValue_(0)
self.spinner.startAnimation_(None)
self.counter.setHidden_(False)
self.counter.setStringValue_("")
def updateExport_total_(self, written, total):
self.spinner.setMaxValue_(total)
self.spinner.setDoubleValue_(written)
msg = "Frame {:,}/{:,}".format(written, total) if written 0:
pOrigin = (win.origin.x - pw, win.origin.y + win.size.height - ph - 38)
else:
pOrigin = (win.origin.x + win.size.width - pw - 15, win.origin.y + 15)
self.panel.setFrame_display_animate_( (pOrigin, (pw,ph)), True, True )
self.positioned = True
elif needs_resize:
pOrigin.y -= ph-pSize.height
self.panel.setFrame_display_animate_( (pOrigin, (pw,ph)), True, True )
# reposition the elements of each row to fit the new panel size and row contents
for idx, v in enumerate(self.rows.values()):
v.updateLayout(col, pw - 10 - num_w, pw, idx*30)
self.panel.orderFront_(None)
from ..context import RGB, CMYK
class ExportSheet(NSObject):
# the script whose doExportAsImage and doExportAsMovie methods will be called
script = IBOutlet()
# Image export settings
imageAccessory = IBOutlet()
imageFormat = IBOutlet()
imageZoom = IBOutlet()
imagePageCount = IBOutlet()
imagePagination = IBOutlet()
imageCMYK = IBOutlet()
# Movie export settings
movieAccessory = IBOutlet()
movieFormat = IBOutlet()
movieFrames = IBOutlet()
movieFps = IBOutlet()
movieLoop = IBOutlet()
movieBitrate = IBOutlet()
def awakeFromNib(self):
self.formats = dict(image=(0, 'pdf', 0,0, 'png', 'jpg', 'heic', 'tiff', 'gif', 0,0, 'pdf', 'eps'), movie=('mov', 'mov', 'gif'))
self.movie = dict(format='mov', first=1, last=150, fps=30, bitrate=1, loop=0, codec=0)
self.image = dict(format='pdf', zoom=1.0, first=1, last=1, cmyk=False, single=True)
self.last = None
@objc.python_method
def beginExport(self, kind):
# configure the accessory controls
if kind=='image':
format = self.image['format']
accessory = self.imageAccessory
if self.image['single']:
self.imageFormat.selectItemAtIndex_(1)
else:
format_idx = 2 + self.formats['image'][2:].index(self.image['format'])
self.imageFormat.selectItemAtIndex_(format_idx)
self.imagePageCount.setIntValue_(self.image['last'])
self.updatePagination()
self.updateColorMode()
elif kind=='movie':
format = self.movie['format']
accessory = self.movieAccessory
format_idx = self.formats['movie'].index(self.movie['format'])
should_loop = self.movie['format']=='gif' and self.movie['loop']==-1
self.movieFrames.setIntValue_(self.movie['last'])
self.movieFps.setIntValue_(self.movie['fps'])
self.movieFormat.selectItemAtIndex_(format_idx)
self.movieLoop.setState_(NSOnState if should_loop else NSOffState)
self.movieLoop.setEnabled_(format=='gif')
self.movieBitrate.setEnabled_(format!='gif')
self.movieBitrate.selectItemWithTag_(self.movie['bitrate'])
# set the default filename and save dir
# path = self.script.fileName()
path = self.script.path
if path:
dirName, fileName = os.path.split(path)
fileName, ext = os.path.splitext(fileName)
fileName += "." + format
else:
dirName, fileName = None, "Untitled.%s"%format
# If a file was already exported, use that folder/filename as the default.
if self.last is not None:
dirName, fileName = self.last
fileName, ext = os.path.splitext(fileName)
# create the sheet
exportPanel = NSSavePanel.savePanel()
exportPanel.setNameFieldLabel_("Export To:")
exportPanel.setPrompt_("Export")
exportPanel.setCanSelectHiddenExtension_(True)
exportPanel.setShowsTagField_(False)
exportPanel.setAllowedFileTypes_([format])
exportPanel.setAccessoryView_(accessory)
self.exportPanel = exportPanel
# present the dialog
callback = "exportPanelDidEnd:returnCode:contextInfo:"
context = 0 if kind=='image' else 1
exportPanel.beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo_(
dirName, fileName, NSApp().mainWindow(), self, callback, context
)
def exportPanelDidEnd_returnCode_contextInfo_(self, panel, returnCode, context):
fname = panel.filename()
panel.close()
panel.setAccessoryView_(None)
# if the user clicked Save:
if returnCode:
if context:
kind, opts = 'movie', self.movieState()
else:
kind, opts = 'image', self.imageState()
setattr(self, kind, dict(opts)) # save the options for next time
self.last = os.path.split(fname) # save the path we exported to
self.script.exportInit(kind, fname, opts)
def movieState(self, key=None):
fmts = self.formats['movie']
fmt_idx = self.movieFormat.indexOfSelectedItem()
state = dict(format = fmts[fmt_idx],
first=1,
last=self.movieFrames.intValue(),
fps=self.movieFps.floatValue(),
loop=-1 if self.movieLoop.state()==NSOnState else 0,
bitrate=self.movieBitrate.selectedItem().tag(),
codec=fmt_idx ) # 0=h265 1=h264
if key:
return state[key]
return state
def imageState(self, key=None):
fmts = self.formats['image']
fmt_idx = self.imageFormat.indexOfSelectedItem()
state = dict(format=fmts[fmt_idx],
zoom=self.image['zoom'],
first=1,
cmyk=self.imageCMYK.state()==NSOnState,
single=fmt_idx==1,
last=self.imagePageCount.intValue())
if key:
return state[key]
return state
def updatePagination(self):
label = 'Pages:' if self.imageState('single') else 'Files:'
self.imagePagination.setStringValue_(label)
def updateColorMode(self):
format = self.imageState('format')
can_cmyk = format in ('pdf','eps','tiff','jpg')
self.imageCMYK.setEnabled_(can_cmyk)
if not can_cmyk:
self.imageCMYK.setState_(NSOffState)
@IBAction
def imageFormatChanged_(self, sender):
format = self.formats['image'][sender.indexOfSelectedItem()]
self.exportPanel.setAllowedFileTypes_([format])
self.updateColorMode()
self.updatePagination()
@IBAction
def imageZoomStepped_(self, sender):
step = sender.intValue()
sender.setIntValue_(0)
self.imageZoomChanged_(None) # reflect any editing in text field
pct = self.image['zoom'] * 100
if step > 0:
pct = 100 * ceil((pct + 1) / 100)
elif step < 0:
pct = 100 * floor((pct - 1) / 100)
if 0 < pct < 10000:
self.image['zoom'] = pct / 100
self.imageZoom.setStringValue_("%i%%" % pct)
@IBAction
def imageZoomChanged_(self, sender):
pct = self.imageZoom.intValue()
if pct > 0:
self.image['zoom'] = pct / 100
else:
pct = self.image['zoom'] * 100
self.imageZoom.setStringValue_("%i%%" % pct)
@IBAction
def movieFormatChanged_(self, sender):
format = self.formats['movie'][sender.indexOfSelectedItem()]
self.exportPanel.setAllowedFileTypes_([format])
is_gif = format=='gif'
self.movieLoop.setState_(NSOnState if is_gif else NSOffState)
self.movieLoop.setEnabled_(is_gif)
self.movieBitrate.setEnabled_(not is_gif)