# Layer effect > Stroke
# (fr) Effet de calque > Trait
from lazpaint import dialog

try:
    from tkinter import Tk, Frame, Label, Scale, HORIZONTAL, Button, RIGHT, W, E
except ImportError:
    dialog.show_message("Please install tkinter. On Debian distributions, use the command: apt install python3-tk")
    exit()
        
from lazpaint import colors, image, layer, filters, tools, selection

translation = dialog.translate_dict(["Layer is empty", "Radius", "Color", 
    "Opacity", "Ok", "Cancel", "Run this script again to update effect"])

if layer.is_empty():
    dialog.show_message(translation["Layer is empty"])
    exit()

############ image processing

FRIENDLY_NAME = dialog.get_script_name()
MAX_RADIUS = 100
MAX_OPACITY = 255

source_layer_id = layer.get_id()
source_layer_name = layer.get_name()

chosen_radius = layer.get_registry("stroke-radius")
if chosen_radius == None: 
    chosen_radius = image.get_registry("stroke-radius")
if chosen_radius == None:
    chosen_radius = 10

stroke_layer_id = layer.get_registry("stroke-layer-id")
if image.get_layer_index(stroke_layer_id) == None:
    stroke_layer_id = None

if stroke_layer_id is not None:
    layer.select_id(stroke_layer_id)
    chosen_opacity = layer.get_opacity()
    overlay_color = colors.str_to_RGBA(layer.get_registry("overlay-color"))
    layer.select_id(source_layer_id)
else:
    chosen_opacity = layer.get_opacity() 
    overlay_color = None

if overlay_color is None:
  overlay_color = colors.BLACK

def create_stroke_layer():
    global stroke_layer_id
    image.do_begin()
    if stroke_layer_id != None:
        layer.select_id(stroke_layer_id)
        stroke_index = image.get_layer_index()
        selection.select_all()
        selection.delete()
        layer.select_id(source_layer_id)
        layer.duplicate()
        image.move_layer_index(image.get_layer_index(), stroke_index+1)
        layer.merge_over()        
    else:
        layer.select_id(source_layer_id)
        layer.duplicate()
        layer.set_name(FRIENDLY_NAME + " - " + source_layer_name)
        layer.set_registry("stroke-source-layer-id", source_layer_id)
        stroke_layer_id = layer.get_id()
        stroke_index = image.get_layer_index()
        image.move_layer_index(stroke_index, stroke_index-1)
    image.do_end()

stroke_done = False
opacity_done = False
stroke_initial_color = None

def apply_stroke():
    global stroke_done, opacity_done, stroke_initial_color
    if opacity_done:
        image.undo()
        opacity_done = False
    if stroke_done:
        image.undo()
        stroke_done = False
    image.do_begin() 
    if chosen_radius > 0.5:
        layer.duplicate()
        disk_id = layer.get_id()
        filters.blur(name=filters.BLUR_DISK, radius=chosen_radius-0.5)
        filters.filter_function(red=overlay_color.red/255, green=overlay_color.green/255, blue=overlay_color.blue/255, alpha="min(alpha*"+str(chosen_radius*5)+",(1-alpha)*"+str(chosen_radius*5)+")", gamma_correction=False)
        layer.select_id(stroke_layer_id) 
    else:
        disk_id = None   
    filters.blur(name=filters.BLUR_CORONA, radius=chosen_radius+0.5)
    filters.filter_function(red=overlay_color.red/255, green=overlay_color.green/255, blue=overlay_color.blue/255, alpha="min(alpha*"+str(chosen_radius)+",(1-alpha)*"+str(chosen_radius)+")", gamma_correction=False)
    if disk_id is not None:
        layer.select_id(disk_id)
        layer.merge_over()
    layer.set_registry("overlay-color", overlay_color)
    stroke_initial_color = overlay_color
    stroke_done = image.do_end()
    apply_opacity()

def apply_opacity():
    global opacity_done, chosen_opacity, overlay_color
    if opacity_done:
        image.undo()
        opacity_done = False
    image.do_begin()
    layer.set_opacity(chosen_opacity)
    if overlay_color != stroke_initial_color:
        filters.filter_function(red=overlay_color.red/255, green=overlay_color.green/255, blue=overlay_color.blue/255, gamma_correction=False)
        layer.set_registry("overlay-color", overlay_color)
    opacity_done = image.do_end()

######## interface

def button_ok_click():
    global source_layer_id, chosen_radius, chosen_offset
    layer.select_id(source_layer_id)
    layer.set_registry("stroke-radius", chosen_radius)
    layer.set_registry("stroke-layer-id", stroke_layer_id)
    image.set_registry("stroke-radius", chosen_radius)
    image.do_end()
    exit()

def button_cancel_click():    
    if image.do_end():
        image.undo()
    layer.select_id(source_layer_id)
    exit()

scale_radius_update_job = None

def scale_radius_update_do():
    global scale_radius_update_job, chosen_radius, scale_radius
    new_radius = scale_radius.get() 
    if new_radius != chosen_radius:
        chosen_radius = new_radius
        apply_stroke()
    scale_radius_update_job = None    

def scale_radius_update(event):
    global window, scale_radius_update_job
    if scale_radius_update_job:
        window.after_cancel(scale_radius_update_job)
    scale_radius_update_job = window.after(500, scale_radius_update_do)

scale_opacity_update_job = None

def scale_opacity_update_do():
    global chosen_opacity 
    new_opacity = scale_opacity.get()
    if new_opacity != chosen_opacity:
        chosen_opacity = new_opacity
        apply_opacity()
    scale_opacity_update_job = None

def scale_opacity_update(event):   
    global window, scale_opacity_update_job
    if scale_opacity_update_job:
        window.after_cancel(scale_opacity_update_job)
    scale_opacity_update_job = window.after(100, scale_opacity_update_do)

def button_color_click():
    global overlay_color, window
    new_color = colors.show_dialog(overlay_color)
    window.attributes('-topmost', True)
    window.attributes('-topmost', False)
    if new_color is not None and new_color != overlay_color:
        overlay_color = new_color
        apply_opacity()

window = Tk()
window.title(FRIENDLY_NAME)
window.resizable(False, False)

frame = Frame(window)
frame.pack()

label_radius = Label(frame, text=translation["Radius"])
label_radius.grid(column=0, row=0)
scale_radius = Scale(frame, from_=0, to=MAX_RADIUS, orient=HORIZONTAL, command=scale_radius_update)
scale_radius.grid(column=1, row=0, sticky=W+E, padx=10)
scale_radius.set(chosen_radius)

label_opacity = Label(frame, text=translation["Opacity"])
label_opacity.grid(column=0, row=1)
scale_opacity = Scale(frame, from_=0, to=MAX_OPACITY, orient=HORIZONTAL, command=scale_opacity_update)
scale_opacity.grid(column=1, row=1, sticky=W+E, padx=10)
scale_opacity.set(chosen_opacity)

label_color = Label(frame, text=translation["Color"])
label_color.grid(column=0, row=2)
button_color = Button(frame, text=translation["Color"] + "...", command=button_color_click)
button_color.grid(column=1, row=2)

label_info = Label(frame, text=translation["Run this script again to update effect"],
    background="lemon chiffon", foreground="black", borderwidth=1, relief="solid")
label_info.grid(column=0, rows=3, columnspan=2)

frame.columnconfigure(0, pad=20)
frame.columnconfigure(1, minsize=250)
frame.rowconfigure(0, pad=20)
frame.rowconfigure(1, pad=20)
frame.rowconfigure(2, pad=20)

button_ok = Button(window, text=translation["Ok"], command=button_ok_click)
button_ok.pack(side=RIGHT, padx=10, pady=10)
button_cancel = Button(window, text=translation["Cancel"], command=button_cancel_click)
button_cancel.pack(side=RIGHT, pady=10)

image.do_begin()
selection.deselect()
create_stroke_layer()
apply_stroke()

window.update()
window_width = window.winfo_width()
screen_width = window.winfo_screenwidth()
window.geometry('+%d+0' % (int((screen_width - window_width) / 2)))

window.lift()
window.attributes('-topmost',True)
window.after_idle(window.attributes,'-topmost',False)

window.mainloop()
button_cancel_click()
