add InputWidget

This commit is contained in:
Johannes 'josch' Schauer 2019-07-04 07:59:19 +02:00
parent 21bf0c30d6
commit a26876fb1b
Signed by: josch
GPG key ID: F2CBA5C78FBD83E1

View file

@ -50,7 +50,7 @@ class LayoutNotComputedException(PlakativException):
class Plakativ: class Plakativ:
def __init__(self, infile, pagenr=1): def __init__(self, infile, pagenr=0):
self.doc = fitz.open(infile) self.doc = fitz.open(infile)
self.pagenr = pagenr self.pagenr = pagenr
@ -59,23 +59,27 @@ class Plakativ:
self.border_top = 20 self.border_top = 20
self.border_bottom = 20 self.border_bottom = 20
# set page number -- first page is 0
def set_input_pagenr(self, pagenr): def set_input_pagenr(self, pagenr):
if pagenr < 1 or pagenr >= len(self.doc): if pagenr < 0 or pagenr >= len(self.doc):
raise PageNrOutOfRangeException() raise PageNrOutOfRangeException(
"%d is not between 0 and %d (inclusive)" % (pagenr, len(self.doc))
)
self.pagenr = pagenr self.pagenr = pagenr
def get_input_pagenums(self):
return len(self.doc)
def get_input_page_size(self): def get_input_page_size(self):
width = self.doc[self.pagenr - 1].getDisplayList().rect.width width = self.doc[self.pagenr].getDisplayList().rect.width
height = self.doc[self.pagenr - 1].getDisplayList().rect.height height = self.doc[self.pagenr].getDisplayList().rect.height
return (width, height) return (width, height)
def get_image(self, zoom): def get_image(self, zoom):
mat_0 = fitz.Matrix(zoom, zoom) mat_0 = fitz.Matrix(zoom, zoom)
pix = ( pix = (
self.doc[self.pagenr - 1] self.doc[self.pagenr].getDisplayList().getPixmap(matrix=mat_0, alpha=False)
.getDisplayList()
.getPixmap(matrix=mat_0, alpha=False)
) )
return pix.getImageData("ppm") return pix.getImageData("ppm")
@ -104,8 +108,8 @@ class Plakativ:
printable_height = self.layout["output_pagesize"][1] - ( printable_height = self.layout["output_pagesize"][1] - (
border_top + border_bottom border_top + border_bottom
) )
inpage_width = pt_to_mm(self.doc[self.pagenr - 1].getDisplayList().rect.width) inpage_width = pt_to_mm(self.doc[self.pagenr].getDisplayList().rect.width)
inpage_height = pt_to_mm(self.doc[self.pagenr - 1].getDisplayList().rect.height) inpage_height = pt_to_mm(self.doc[self.pagenr].getDisplayList().rect.height)
if mode in ["size", "mult"]: if mode in ["size", "mult"]:
if mode == "size": if mode == "size":
@ -241,7 +245,7 @@ class Plakativ:
if not hasattr(self, "layout"): if not hasattr(self, "layout"):
raise LayoutNotComputedException() raise LayoutNotComputedException()
inpage_width = pt_to_mm(self.doc[self.pagenr - 1].getDisplayList().rect.width) inpage_width = pt_to_mm(self.doc[self.pagenr].getDisplayList().rect.width)
outdoc = fitz.open() outdoc = fitz.open()
@ -297,7 +301,7 @@ class Plakativ:
page.showPDFpage( page.showPDFpage(
targetrect, # fill the whole page targetrect, # fill the whole page
self.doc, # input document self.doc, # input document
self.pagenr - 1, # input page number self.pagenr, # input page number
clip=sourcerect, # part of the input page to use clip=sourcerect, # part of the input page to use
) )
@ -363,6 +367,7 @@ class VerticalScrolledFrame(tkinter.Frame):
# Python License # Python License
# #
# add support for 'state' and 'name' kwargs # add support for 'state' and 'name' kwargs
# add support for updating list of options
class OptionMenu(tkinter.Menubutton): class OptionMenu(tkinter.Menubutton):
"""OptionMenu which allows the user to select a value from a menu.""" """OptionMenu which allows the user to select a value from a menu."""
@ -387,24 +392,28 @@ class OptionMenu(tkinter.Menubutton):
del kwargs["name"] del kwargs["name"]
tkinter.Widget.__init__(self, master, "menubutton", kw) tkinter.Widget.__init__(self, master, "menubutton", kw)
self.widgetName = "tk_optionMenu" self.widgetName = "tk_optionMenu"
menu = self.__menu = tkinter.Menu(self, name="menu", tearoff=0) self.callback = kwargs.get("command")
self.menuname = menu._w self.variable = variable
# 'command' is the only supported keyword
callback = kwargs.get("command")
if "command" in kwargs: if "command" in kwargs:
del kwargs["command"] del kwargs["command"]
if kwargs: if kwargs:
raise tkinter.TclError("unknown option -" + list(kwargs.keys())[0]) raise tkinter.TclError("unknown option -" + list(kwargs.keys())[0])
menu.add_command(label=value, command=tkinter._setit(variable, value, callback)) self.set_values([value] + list(values))
for v in values:
menu.add_command(label=v, command=tkinter._setit(variable, v, callback))
self["menu"] = menu
def __getitem__(self, name): def __getitem__(self, name):
if name == "menu": if name == "menu":
return self.__menu return self.__menu
return tkinter.Widget.__getitem__(self, name) return tkinter.Widget.__getitem__(self, name)
def set_values(self, values):
menu = self.__menu = tkinter.Menu(self, name="menu", tearoff=0)
self.menuname = menu._w
for v in values:
menu.add_command(
label=v, command=tkinter._setit(self.variable, v, self.callback)
)
self["menu"] = menu
def destroy(self): def destroy(self):
"""Destroy this widget and the associated menu.""" """Destroy this widget and the associated menu."""
tkinter.Menubutton.destroy(self) tkinter.Menubutton.destroy(self)
@ -427,11 +436,10 @@ class Application(tkinter.Frame):
self.canvas_size = self.canvas.winfo_width(), self.canvas.winfo_height() self.canvas_size = self.canvas.winfo_width(), self.canvas.winfo_height()
self.canvas.bind("<Configure>", self.on_resize) self.canvas.bind("<Configure>", self.on_resize)
# tkinter does not allow scrollbars for frames frame_right = tkinter.Frame(self)
frame1 = VerticalScrolledFrame(self) frame_right.pack(side=tkinter.TOP, expand=tkinter.TRUE, fill=tkinter.Y)
frame1.pack(side=tkinter.TOP, expand=tkinter.TRUE, fill=tkinter.Y)
top_frame = tkinter.Frame(frame1.interior) top_frame = tkinter.Frame(frame_right)
top_frame.pack(fill=tkinter.X) top_frame.pack(fill=tkinter.X)
open_button = tkinter.Button( open_button = tkinter.Button(
@ -441,23 +449,14 @@ class Application(tkinter.Frame):
help_button = tkinter.Button(top_frame, text="Help", state=tkinter.DISABLED) help_button = tkinter.Button(top_frame, text="Help", state=tkinter.DISABLED)
help_button.pack(side=tkinter.RIGHT, expand=tkinter.TRUE, fill=tkinter.X) help_button.pack(side=tkinter.RIGHT, expand=tkinter.TRUE, fill=tkinter.X)
input_group = tkinter.LabelFrame(frame1.interior, text="Input properties") frame1 = VerticalScrolledFrame(frame_right)
input_group.pack(fill=tkinter.X) frame1.pack(side=tkinter.TOP, expand=tkinter.TRUE, fill=tkinter.Y)
label_input_width = tkinter.Label(input_group, text="Width:") self.input = InputWidget(frame1.interior)
label_input_width.grid(row=0, column=0, sticky=tkinter.W) self.input.pack(fill=tkinter.X)
label_input_height = tkinter.Label(input_group, text="Height:") self.input.set(1, (0, 0))
label_input_height.grid(row=1, column=0, sticky=tkinter.W) if hasattr(self, "plakativ"):
label_input_npages = tkinter.Label(input_group, text="# of pages:") self.input.callback = self.on_input
label_input_npages.grid(row=2, column=0, sticky=tkinter.W)
label_input_range = tkinter.Label(input_group, text="Page range:")
label_input_range.grid(row=3, column=0, sticky=tkinter.W)
self.input_range = tkinter.StringVar()
self.input_range.set("1")
input_range_entry = tkinter.Entry(
input_group, textvariable=self.input_range, width=6, state=tkinter.DISABLED
)
input_range_entry.grid(row=3, column=1, sticky=tkinter.W)
self.pagesize = PageSizeWidget(frame1.interior) self.pagesize = PageSizeWidget(frame1.interior)
self.pagesize.pack(fill=tkinter.X) self.pagesize.pack(fill=tkinter.X)
@ -513,7 +512,28 @@ class Application(tkinter.Frame):
output_group, text="Print poster border", state=tkinter.DISABLED output_group, text="Print poster border", state=tkinter.DISABLED
).pack(anchor=tkinter.W) ).pack(anchor=tkinter.W)
bottom_frame = tkinter.Frame(frame1.interior) option_group = tkinter.LabelFrame(frame1.interior, text="Program options")
option_group.pack(fill=tkinter.X)
tkinter.Label(option_group, text="Unit:", state=tkinter.DISABLED).grid(
row=0, column=0, sticky=tkinter.W
)
unit = tkinter.StringVar()
unit.set("mm")
OptionMenu(option_group, unit, ["mm"], state=tkinter.DISABLED).grid(
row=0, column=1, sticky=tkinter.W
)
tkinter.Label(option_group, text="Language:", state=tkinter.DISABLED).grid(
row=1, column=0, sticky=tkinter.W
)
language = tkinter.StringVar()
language.set("English")
OptionMenu(option_group, language, ["English"], state=tkinter.DISABLED).grid(
row=1, column=1, sticky=tkinter.W
)
bottom_frame = tkinter.Frame(frame_right)
bottom_frame.pack(fill=tkinter.X) bottom_frame.pack(fill=tkinter.X)
self.save_button = tkinter.Button( self.save_button = tkinter.Button(
@ -529,10 +549,26 @@ class Application(tkinter.Frame):
) )
quit_button.pack(side=tkinter.RIGHT, expand=tkinter.TRUE, fill=tkinter.X) quit_button.pack(side=tkinter.RIGHT, expand=tkinter.TRUE, fill=tkinter.X)
def on_pagesize(self, value): def on_input(self, value):
_, pagesize = value _, pagesize = self.pagesize.value
pagenum, _ = value
mode, (custom_size, size), mult, npages = self.postersize.value mode, (custom_size, size), mult, npages = self.postersize.value
bordersize = self.bordersize.value bordersize = self.bordersize.value
self.plakativ.set_input_pagenr(pagenum - 1)
size, mult, npages = self.plakativ.compute_layout(
mode, size, mult, npages, pagesize, bordersize
)
self.postersize.set(mode, (custom_size, size), mult, npages)
self.draw()
width, height = self.plakativ.get_input_page_size()
return "%.02f" % pt_to_mm(width), "%.02f" % pt_to_mm(height)
def on_pagesize(self, value):
_, pagesize = value
pagenum, _ = self.input.value
mode, (custom_size, size), mult, npages = self.postersize.value
bordersize = self.bordersize.value
self.plakativ.set_input_pagenr(pagenum - 1)
size, mult, npages = self.plakativ.compute_layout( size, mult, npages = self.plakativ.compute_layout(
mode, size, mult, npages, pagesize, bordersize mode, size, mult, npages, pagesize, bordersize
) )
@ -541,7 +577,9 @@ class Application(tkinter.Frame):
def on_bordersize(self, value): def on_bordersize(self, value):
_, pagesize = self.pagesize.value _, pagesize = self.pagesize.value
pagenum, _ = self.input.value
mode, (custom_size, size), mult, npages = self.postersize.value mode, (custom_size, size), mult, npages = self.postersize.value
self.plakativ.set_input_pagenr(pagenum - 1)
size, mult, npages = self.plakativ.compute_layout( size, mult, npages = self.plakativ.compute_layout(
mode, size, mult, npages, pagesize, value mode, size, mult, npages, pagesize, value
) )
@ -550,8 +588,10 @@ class Application(tkinter.Frame):
def on_postersize(self, value): def on_postersize(self, value):
mode, (custom_size, size), mult, npages = value mode, (custom_size, size), mult, npages = value
pagenum, _ = self.input.value
_, pagesize = self.pagesize.value _, pagesize = self.pagesize.value
border = self.bordersize.value border = self.bordersize.value
self.plakativ.set_input_pagenr(pagenum - 1)
size, mult, npages = self.plakativ.compute_layout( size, mult, npages = self.plakativ.compute_layout(
mode, size, mult, npages, pagesize, border mode, size, mult, npages, pagesize, border
) )
@ -570,7 +610,7 @@ class Application(tkinter.Frame):
self.canvas.create_text( self.canvas.create_text(
self.canvas_size[0] / 2, self.canvas_size[0] / 2,
self.canvas_size[1] / 2, self.canvas_size[1] / 2,
text="Click on the \"Open PDF\" button in the upper right.", text='Click on the "Open PDF" button in the upper right.',
fill="white", fill="white",
) )
return return
@ -677,6 +717,15 @@ class Application(tkinter.Frame):
size, mult, npages = self.plakativ.compute_layout( size, mult, npages = self.plakativ.compute_layout(
mode, size, mult, npages, pagesize, border mode, size, mult, npages, pagesize, border
) )
# update input widget
width, height = self.plakativ.get_input_page_size()
self.input.set(1, ("%.02f" % pt_to_mm(width), "%.02f" % pt_to_mm(height)))
self.input.nametowidget("spinbox_pagenum").configure(
to=self.plakativ.get_input_pagenums()
)
self.input.nametowidget("label_of_pagenum").configure(
text="of %d" % self.plakativ.get_input_pagenums()
)
# update postersize widget # update postersize widget
self.postersize.set(mode, (custom_size, size), mult, npages) self.postersize.set(mode, (custom_size, size), mult, npages)
# draw preview in canvas # draw preview in canvas
@ -684,6 +733,7 @@ class Application(tkinter.Frame):
# enable save button # enable save button
self.save_button.configure(state=tkinter.NORMAL) self.save_button.configure(state=tkinter.NORMAL)
# set callback function # set callback function
self.input.callback = self.on_input
self.pagesize.callback = self.on_pagesize self.pagesize.callback = self.on_pagesize
self.bordersize.callback = self.on_bordersize self.bordersize.callback = self.on_bordersize
self.postersize.callback = self.on_postersize self.postersize.callback = self.on_postersize
@ -703,6 +753,78 @@ class Application(tkinter.Frame):
self.plakativ.render(filename) self.plakativ.render(filename)
class InputWidget(tkinter.LabelFrame):
def __init__(self, parent, *args, **kw):
tkinter.LabelFrame.__init__(self, parent, text="Input properties", *args, **kw)
self.callback = None
self.variables = {
"pagenum": tkinter.IntVar(),
"width": tkinter.StringVar(),
"height": tkinter.StringVar(),
}
def callback(varname, idx, op):
assert op == "w"
self.on_pagenum(self.variables["pagenum"].get())
self.variables["pagenum"].trace("w", callback)
tkinter.Label(self, text="Use page").grid(row=0, column=0, sticky=tkinter.W)
tkinter.Spinbox(
self,
increment=1,
from_=1,
to=100,
width=3,
name="spinbox_pagenum",
textvariable=self.variables["pagenum"],
).grid(row=0, column=1, sticky=tkinter.W)
tkinter.Label(self, text="of 1", name="label_of_pagenum").grid(
row=0, column=2, sticky=tkinter.W
)
tkinter.Label(self, text="Width:").grid(row=1, column=0, sticky=tkinter.W)
tkinter.Label(self, textvariable=self.variables["width"]).grid(
row=1, column=1, sticky=tkinter.W
)
tkinter.Label(self, text="mm", name="size_label_width_mm").grid(
row=1, column=2, sticky=tkinter.W
)
tkinter.Label(self, text="Height:").grid(row=2, column=0, sticky=tkinter.W)
tkinter.Label(self, textvariable=self.variables["height"]).grid(
row=2, column=1, sticky=tkinter.W
)
tkinter.Label(self, text="mm", name="size_label_height_mm").grid(
row=2, column=2, sticky=tkinter.W
)
def on_pagenum(self, value):
if getattr(self, "value", None) is None:
return
_, size = self.value
self.set(value, size)
def set(self, pagenum, pagesize):
# before setting self.value, check if the effective value is different
# from before or otherwise we do not need to execute the callback in
# the end
state_changed = True
if getattr(self, "value", None) is not None:
state_changed = self.value != (pagenum, pagesize)
# execute callback if necessary
if state_changed and self.callback is not None:
pagesize = self.callback((pagenum, pagesize))
self.value = (pagenum, pagesize)
width, height = pagesize
if self.variables["pagenum"].get() != pagenum:
self.variables["pagenum"].set(pagenum)
if self.variables["width"].get() != width:
self.variables["width"].set(width)
if self.variables["height"].get() != height:
self.variables["height"].set(height)
class PageSizeWidget(tkinter.LabelFrame): class PageSizeWidget(tkinter.LabelFrame):
def __init__(self, parent, *args, **kw): def __init__(self, parent, *args, **kw):
tkinter.LabelFrame.__init__( tkinter.LabelFrame.__init__(
@ -1138,10 +1260,11 @@ def compute_layout(
size=None, size=None,
mult=None, mult=None,
npages=None, npages=None,
pagenr=0,
pagesize=(210, 297), pagesize=(210, 297),
border=(0, 0, 0, 0), border=(0, 0, 0, 0),
): ):
plakativ = Plakativ(infile) plakativ = Plakativ(infile, pagenr)
plakativ.compute_layout(mode, size, mult, npages, pagesize, border) plakativ.compute_layout(mode, size, mult, npages, pagesize, border)
plakativ.render(outfile) plakativ.render(outfile)