Blender-Pipeline/studio/checklist.py
Jeison Yehuda Amihud (Blender Dumbass) 162d3f8038 Multiuser Bug Fixes
Implemented missing features that could be
seen as bugs for the casual users.

Such as sync of the main checklist. And other
minor changes.
2021-01-04 15:52:29 +00:00

1141 lines
40 KiB
Python

# THIS FILE IS A PART OF VCStudio
# PYTHON 3
import os
import cairo
#UI modules
from UI import UI_elements
from UI import UI_color
#settings
from settings import talk
#studio
from studio import analytics
from studio import history
def get_list(filepath):
# This fucntion converts text documents. (.progress) into a more machine
# friendly recursive dict.
# In the original organizer evaluation of the checklist was done separatelly
# in a different function. Which made it very messy for recursive stuff.
# I will attemp to combine it. And make it more clean as a result.
checklist = {
"fraction":0.0, # The percentage of a checklist. From 0.0 to 1.0
"string":filepath,
"editing":False,# Whether the string is during editing. UI.
"selected":False,# Whether the current task is selected.
"open":True, # Whether to draw the suptasks. UI.
"subtasks":[] # List of subtastks. (In the same format as the checklist)
}
data = open(filepath)
data = data.read()
data = data.split("\n")
# Let's filter out all the comments. Lines starting with #. For some reason
# in the old organizer. I just thought it wasn't important. LOL. And just
# started reading from the 10th line.
# Here is an example of the first 9 lines.
# 1 #### Blender orgainizer checklist format
# 2 #### INDINTATION (4 SPACES LONG)
# 3 #### STR means Start date of the ASSET
# 4 #### FIN means Finish deadline of the asset
# 5 #### [ ] means that task is on list
# 6 #### [V] means that tast is finished
# 7 #### DO NOT USE EMPTY LINES
# 8 STR 24/02/2020
# 9 FIN 01/05/2021
# You can see a trace from a very long time ago. From the first versions
# of the blender organizer. The STR and FIN values. Which are start and
# deadline of the project.
# I guess we need to filter it out a bit differently. Checking whether a
# given line starts with a [ or with a number of spaces and [. This will
# make the file a little more open to editing by hand. Without too much
# worrying that something will break.
cleandata = []
for line in data:
# So not to mangle the line.
tmp = line
while tmp.startswith(" "):
tmp = tmp[1:]
# Checking
if tmp.startswith("[ ]") or tmp.startswith("[V]"):
cleandata.append(line)
# Now since we have the cleandata. We can try to parse it somehow into a
# checklist thing. For this we need a reqursion. I gonna use a method from
# the blender-organizer. By running the function with in itself. It's not
# very wise. I know. In python3 it will give you no more then 996 recursions
# untill it will declare an error. BUT. It's 996 layers of a subtaks.
# For now I don't see a need in so many subtasks. Let's think of layers of
# subtasks as of memory. This laptop has only 8 GB of RAM. I can't put more
# data into it even if I wanted.
def convert(part, indent=0):
# If a thing have subtasks it should not even be a checkbox. So trying
# To evaluate it's fraction by whether it's a [ ] or [V] shoun't be
# done.
subtask = []
for num, line in enumerate(part):
# Let's get the NEXT line. I'm not kidding. We gonna work with the
# next line to see whether to count this lines [V]
if line[indent:].startswith("["):
thisline = {
"fraction":0.0,
"string":line[line.find("]")+2:],
"editing":False,
"selected":False,
"open":False,
"subtasks":[]
}
try:
nextline = part[num+1]
except:
nextline = ""
if not line[line.find("]")+1] == ".":
thisline["open"] = True
if nextline.find("[")-1 <= indent:
if line[indent:].startswith("[V]"):
thisline["fraction"] = 1.0
else:
subpart = []
subdent = indent
for n, l in enumerate(part[num+1:]):
if n == 0:
subdent = l.find("[")
if l.find("[")-1 <= indent:
break
else:
subpart.append(l)
#print(subpart)
thisline["subtasks"] = convert(subpart, subdent)
fracs = []
for task in thisline["subtasks"]:
if not task["string"].startswith("#"):
fracs.append(task["fraction"])
try:
thisline["fraction"] = sum(fracs) / len(fracs)
except:
thisline["fraction"] = 0.0
# Sometime it was showing 99% when infect it's 100%
if thisline["fraction"] == 0.9999:
thisline["fraction"] = 1.0
subtask.append(thisline)
return subtask
checklist["subtasks"] = convert(cleandata)
fracs = []
for task in checklist["subtasks"]:
if not task["string"].startswith("#"):
fracs.append(task["fraction"])
try:
checklist["fraction"] = sum(fracs) / len(fracs)
except:
checklist["fraction"] = 0.0
# Sometime it was showing 99% when infect it's 100%
if checklist["fraction"] == 0.9999:
checklist["fraction"] = 1.0
return checklist
def get_fraction(win, path):
############################################################################
# This function will return a fraction of a given checklist. It will ignore
# complitelly what is the asset / shot / project the checklist is from.
# For sake of making this function actually somewhat useful, aka not bloated
# I will use it to cashe the whole checklist data objects. So they could be
# easily accesable later on.
# This is usefull so I would not need to create 2 cash data structures. One
# for fractions and for the checklists them selves.
############################################################################
if path not in win.checklists:
# Let's check if path exists in the project first.
if os.path.exists(win.project+"/"+path):
win.checklists[path] = get_list(win.project+"/"+path)
else:
win.checklists[path] = get_list(path)
# Let's now return back the fraction
return win.checklists[path]["fraction"]
def get_task_by_path(tasks, path, p=[]):
############################################################################
# This function will give the information about a given task from a non
# recursive URL such as ["Task", "Sub-task", "Sub-task2"]. This will look
# the recursive list and output the given task. In this case "Sub-task2"
# with all the information inside it.
############################################################################
for task in tasks:
pa = p.copy()
pa.append(" "+task["string"])
if pa == path:
return task
if task["subtasks"]:
t = get_task_by_path(task["subtasks"], path, pa)
if t:
return t
return False
def filter_tasks(data):
############################################################################
# This function going to remove all selections and all edits from a given
# checklist. This is nessesary for being able to select one task without
# manually deselcting the other. And since the checklist is recursive it's
# not a trivial task.
############################################################################
data["selected"] = False
data["editing"] = False
if data["subtasks"]:
for i in data["subtasks"]:
filter_tasks(i)
def save(path, data):
############################################################################
# This funtion will save the checklist into a .progress file. Formatted
# similarly as in the old Blender-Organizer. But as easy to understand.
#
# NOTE: I will remove some stuff from the file. Mainly the comments in the
# beginning and the STR and END data. Which are no longer needed in a
# VCStudio project.
#
# But since some part of Legacy Organizer relies on those, it's not adviced
# to open the projects that you are planning to work on with Blender-Organizer
# in VCStudio.
############################################################################
indent = [0]
lines = []
def writetasks(tasks):
for task in tasks:
if task["fraction"] and not task["subtasks"]:
v = "[V]"
else:
v = "[ ]"
if task["open"]:
o = " "
else:
o = "."
lines.append(" "*indent[0]+v+o+task["string"])
if task["subtasks"]:
indent[0] = indent[0] + 4
writetasks(task["subtasks"])
indent[0] = indent[0] - 4
writetasks(data["subtasks"])
# Writting to file
w = open(path, "w")
for i in lines:
w.write(i+"\n")
w.close()
def draw(outlayer, win, path, back="story_editor"):
############################################################################
# This function will draw the checklists to the screen.
# You probably noticed that there is no x, y, width or height values that
# you can input. This due to one idea that I have in mind.
# I'm planning to make scheduling a kind of interactive process rather then
# a boring date selection. Something that's going to be somewhat fun to do.
# The idea is to grab the task and to drug it outside the checklist. Which
# will call for an analytics window to show up, where you can put the
# schedules into a given date.
# For this reason the checklist should always be in the same spot on the
# screen. Which is a (window width) / 4 at the right side.
############################################################################
if path not in win.checklists:
# Let's check if path exists in the project first.
if os.path.exists(win.project+"/"+path):
win.checklists[path] = get_list(win.project+"/"+path)
elif os.path.exists(win.project+"/rnd"+path):
win.checklists[path] = get_list(win.project+"/rnd"+path)
else:
win.checklists[path] = get_list(path)
x = win.current["w"] / 4 * 3 + 10
y = 10
width = win.current["w"] / 4 - 20
height = win.current["h"] - 20
# Now let's make a layer.
# Making the layer
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
layer = cairo.Context(surface)
layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
# Clip
UI_elements.roundrect(layer, win,
0,
0,
width,
height,
10,
fill=False)
layer.clip()
# Checklist icon.
UI_color.set(layer, win, "node_background")
UI_elements.roundrect(layer, win,
0,
0,
width,
50,
10)
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/checklist.png",
5, 5, 40, 40)
# Fraction
fraction = win.checklists[path]["fraction"]
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
50,
17,
width - 60,
0,
7)
UI_color.set(layer, win, "progress_active")
UI_elements.roundrect(layer, win,
50,
17,
(width - 60 )*fraction,
0,
7)
# Clip
UI_elements.roundrect(layer, win,
0,
60,
width,
height,
10,
fill=False)
layer.clip()
###########################################################################
# NOW THIS IS THE HARD RECURSION PART! THERE IS GOING TO BE SOME REDIC!
###########################################################################
tileX = 0
current_Y = 70
# There is some bullshit regarding the Global variables. I gonna do a bit
# trickier. Since lists are only links to lists. Let's do this.
cXY = [tileX, current_Y]
if "checklist" not in win.scroll:
win.scroll["checklist"] = 0
if "moving_task_now" not in win.current:
win.current["moving_task_now"] = False
def draw_tasks(tasks, cXY, schedulep):
#########################################
# #
# THIS IS THE RECURSIVE FUNCTION #
# #
#########################################
# I will try to explain what is going on here. But it will require me
# understanding the code myself. And it's a bit redic. There was a hell
# of a lot of copy-paste, edit value, continue.
for num , task in enumerate(tasks):
# This is the code that will be done for each task in the list. Or
# subtask if a task have them.
# Let's get a schedule path. A folder like structure.
# Exacmple:
# Instead of:
# Task
# Sub-Task
# Sub-Task 2
# We get:
# [" Task", " Sub-Task", " Sub-Task 2"]
schedulepath = schedulep.copy()
schedulepath.append(" "+task["string"])
###### SCHEDULING STUFF BACKWARD ######
# This is a set of stuff to make schedules work with checklists.
if "schedule_task_selected" not in win.current:
win.current["schedule_task_selected"] = False
if win.current["schedule_task_selected"] and win.cur == win.current["schedule_task_selected"][-1]\
or win.current["schedule_task_selected"] and win.cur == "/set" and win.current["schedule_task_selected"][-1] == "":
csl = win.current["schedule_task_selected"][0][0][4]
if " "+task["string"] in csl and not task["open"]:
task["open"] = True
if schedulepath == csl and not task["selected"]:
filter_tasks(win.checklists[path])
task["selected"] = True
win.scroll["checklist"] = 0 - cXY[1] + height/2
#### DELETE SHORT KEY ####
# There is probably a reason to put it here. Probably something
# breaks if you put it anywhere else. IDK actually. Test it. I
# don't remember
if 65535 in win.current["keys"] and task["selected"] and not win.current["schedule_task_selected"]:
del tasks[num]
win.current["keys"] = []
# Saving
save(path, win.checklists[path])
win.checklists = {}
win.assets = {}
win.analytics = analytics.load(win.project)
win.multiuser["last_request"] = ""
#### THE GRABBING FUNCTION ####
# This is the activation of the grab tool. It uses the same
# win.current["tool"] = "grab" as the story editor. Because it makes
# sense to reuse it if it already exists. For sake of conviniense.
# It doesn't mean that it uses the same code. It's a bit different.
# due to the nature of lists vs free positioning items.
# Now let's set up a few positional variables. So I could move the tasks
# while moving the currently selected task. And in the same time will not
# screw the data.
# So I copy the X and the Y locations like this.
sx = cXY[0]
sy = win.scroll["checklist"] + cXY[1]
grabY = 40
if task["subtasks"]:
grabY = 60
# Grab
if win.current["LMB"]\
and int(win.current["LMB"][0]) in range(int(x+sx), int(x+sx+width))\
and int(win.current["LMB"][1]) in range(int(y+sy), int(y+sy+grabY))\
and win.current["tool"] == "selection"\
and int(win.current["LMB"][0]) not in range(int(win.current["mx"]-2), int(win.current["mx"]+2))\
and int(win.current["LMB"][1]) not in range(int(win.current["my"]-2), int(win.current["my"]+2)):
# So here we set up the grab tool and creating a little variable.
# This variable (moving_task_now) will consist of 2 parts on release.
# 1. The entire task ( with subtasks ) using pop. Which is not simply
# a copy. But also removing the task from the checklist's list.
# 2. The current frame of poping. So to offset insertion for 1 frame.
# This insures that you insert the task in the correct spot.
filter_tasks(win.checklists[path])
task["selected"] = True
win.current["schedule_task_selected"] = False
win.current["tool"] = "grab"
win.current["moving_task_now"] = False
# Now let's actually setup the pop. So when the mouse is now pressed, but
# was on a previous framae, and our current tool is grab.
if not win.current["LMB"] and win.previous["LMB"] and win.current["tool"] == "grab"\
and task["selected"]:
# We remove the task from the list. And write it to the variable. With
# the current frame.
win.current["moving_task_now"] = [tasks.pop(num), win.current["frame"]]
# Now I can touch the sx and sy without screwing up the cXY or scroll.
thismoving = False # This is going to be True is this is the task that's
# moving currently
somemoving = False # This is going to be True if any task is moving
someXY = [0,0] # And this is the mouse position translated to location
# of the checklist. (x, y coordinates of the whole
# widget). Or in other words position of the task.
# Then comes some logic to determen those 3 values.
if win.current["tool"] == "grab":
# Okay so here. If grab first we assume that it's some other
# task. And now currently selected one.
somemoving = True
someXY = [
win.current["mx"]-x,
win.current["my"]-y
]
# Now this is the editing of the sx and sy values. To be at
# the position of the mouse.
if task["selected"]:
# Calculating so the mouse will end up about in the centre
# of the task while the task is at motion.
sx = win.current["mx"] - x - (width - cXY[0])/2
sy = win.current["my"] - y - 10
task["open"] = False
thismoving = True
somemoving = False
# Now if the mouse is outside the frame of the checklist
# it will activate the scheduling.
############################################################
# SCHEDULING PART #
############################################################
if win.current["mx"] < x:
win.url = "analytics"
win.current["grab_data"] = [path, back, win.cur, schedulepath, win.settings["Username"]]
win.current["tool"] = "schedule"
#
#
#
# SEE studio/studio_analyticsLayer.py
# for more details about scheduling
#
# And if back into frame it will return to normal grab mode.
elif win.current["tool"] == "schedule" and win.current["mx"] > x:
win.url = back
win.current["tool"] = "grab"
####################################################################
# SCHEDULING PART END #
####################################################################
inside = False
between = False
if sy-10 < someXY[1] < sy+10 and somemoving and not task["selected"]:
if win.current["moving_task_now"] and win.current["moving_task_now"][1] != win.current["frame"]:
tasks.insert(num, win.current["moving_task_now"][0])
win.current["tool"] = "selection"
win.current["LMB"] = False
win.previous["LMB"] = False
# Saving
save(path, win.checklists[path])
win.checklists = {}
win.assets = {}
win.analytics = analytics.load(win.project)
win.multiuser["last_request"] = ""
elif win.current["LMB"]:
for line in range(int(cXY[0]/20)):
line = line * 20 + 10
UI_color.set(layer, win, "node_background")
layer.move_to(line, win.scroll["checklist"] + cXY[1]-10)
layer.line_to(line, win.scroll["checklist"] + cXY[1]+40)
layer.stroke()
cXY[1] = cXY[1] + 50
sx = cXY[0]
sy = win.scroll["checklist"] + cXY[1]
between = True
somemoving = False
elif sy < someXY[1] < sy + 40 and somemoving and not task["selected"]:
if win.current["moving_task_now"] and win.current["moving_task_now"][1] != win.current["frame"]:
task["subtasks"].append(win.current["moving_task_now"][0])
win.current["tool"] = "selection"
win.current["LMB"] = False
win.previous["LMB"] = False
# Saving
save(path, win.checklists[path])
win.checklists = {}
win.assets = {}
win.analytics = analytics.load(win.project)
win.multiuser["last_request"] = ""
elif win.current["LMB"]:
inside = True
# Selection
if win.textactive != "editing_task" and win.current["tool"] == "selection":
def do():
ed = task["selected"] and not task["editing"]
filter_tasks(win.checklists[path])
win.current["schedule_task_selected"] = False
task["selected"] = True
if ed:
task["editing"] = True
UI_elements.roundrect(layer, win,
sx+40,
sy,
width - cXY[0]-40,
grabY,
10,
button=do,
offset=[x,y],
fill=False)
layer.stroke()
# Background
if not task["subtasks"]:
UI_color.set(layer, win, "node_background")
if task["string"].startswith("#"):
UI_color.set(layer, win, "dark_overdrop")
UI_elements.roundrect(layer, win,
sx,
sy,
width - cXY[0],
40,
10)
if inside:
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
sx,
sy,
width - cXY[0],
40,
10,
fill=False)
layer.stroke()
if task["selected"]:
UI_color.set(layer, win, "text_normal")
UI_elements.roundrect(layer, win,
sx,
sy,
width - cXY[0],
40,
10,
fill=False)
layer.stroke()
# Line to see how deep you are in
for line in range(int(cXY[0]/20)):
line = line * 20 + 10
UI_color.set(layer, win, "node_background")
layer.move_to(line, win.scroll["checklist"] + cXY[1]-10)
layer.line_to(line, win.scroll["checklist"] + cXY[1]+40)
layer.stroke()
if not task["string"].startswith("#"):
if task["fraction"]:
im = "checked"
else:
im = "unchecked"
# CHECK BUTTON
def do():
if task["fraction"]:
task["fraction"] = 0.0
history.record(win, path, "[Un-Checked]", schedulepath)
else:
task["fraction"] = 1.0
history.record(win, path, "[Checked]", schedulepath)
# Saving
save(path, win.checklists[path])
win.checklists = {}
win.assets = {}
win.multiuser["last_request"] = ""
win.analytics = analytics.load(win.project)
UI_elements.roundrect(layer, win,
sx,
sy,
40,
40,
10,
button=do,
icon=im,
offset=[x,y])
else:
UI_color.set(layer, win, "node_background")
if task["string"].startswith("#"):
UI_color.set(layer, win, "dark_overdrop")
UI_elements.roundrect(layer, win,
sx,
sy,
width - cXY[0],
60,
10)
if inside:
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
sx,
sy,
width - cXY[0],
60,
10,
fill=False)
layer.stroke()
if task["selected"]:
UI_color.set(layer, win, "text_normal")
UI_elements.roundrect(layer, win,
sx,
sy,
width - cXY[0],
60,
10,
fill=False)
layer.stroke()
# Line to see how deep you are in
for line in range(int(cXY[0]/20)):
line = line * 20 + 10
UI_color.set(layer, win, "node_background")
layer.move_to(line, win.scroll["checklist"] + cXY[1]-10)
layer.line_to(line, win.scroll["checklist"] + cXY[1]+60)
layer.stroke()
# Fraction
if not task["string"].startswith("#"):
fraction = task["fraction"]
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
sx+10,
sy+45,
width-20 - cXY[0],
0,
5)
UI_color.set(layer, win, "progress_active")
UI_elements.roundrect(layer, win,
sx+10,
sy+45,
(width -20 - cXY[0])*fraction,
0,
5)
if task["open"]:
im = "open"
else:
im = "closed"
def do():
task["open"] = not task["open"]
win.current["schedule_task_selected"] = False
# Saving
save(path, win.checklists[path])
win.multiuser["last_request"] = ""
UI_elements.roundrect(layer, win,
sx,
sy,
40,
60,
10,
button=do,
icon=im,
offset=[x,y])
# TEXT
# ECS
if 65307 in win.current["keys"] and task["editing"]:
# It's here because Text entry has it's own ESC
win.textactive = ""
task["editing"] = False
del win.text["editing_task"]
win.current["keys"] = []
# Saving
save(path, win.checklists[path])
win.checklists = {}
win.assets = {}
win.analytics = analytics.load(win.project)
win.multiuser["last_request"] = ""
if not task["editing"]:
layer.set_font_size(20)
layer.move_to(
sx+50,
sy+25
)
if task["string"].startswith("#"):
UI_color.set(layer, win, "progress_background")
if not task["subtasks"]:
layer.move_to(
sx+10,
sy+25
)
layer.show_text(task["string"][1:])
else:
UI_color.set(layer, win, "text_normal")
layer.show_text(task["string"])
else:
UI_elements.text(layer, win, "editing_task",
sx+39,
sy,
width - cXY[0] - 40,
40,
set_text=task["string"],
offset=[x,y])
win.textactive = "editing_task"
# Assigning the text
def do():
task["string"] = win.text["editing_task"]["text"]
win.textactive = ""
filter_tasks(win.checklists[path])
del win.text["editing_task"]
# Saving
save(path, win.checklists[path])
win.multiuser["last_request"] = ""
def button():
do()
win.checklists = {}
win.assets = {}
UI_elements.roundrect(layer, win,
sx+39 + width - cXY[0] - 80,
sy,
40,
40,
10,
button=button,
icon="ok",
tip=talk.text("checked"),
offset=[x,y])
# Enter
if 65293 in win.current["keys"]:
button()
win.current["keys"] = []
# Tab
if 65289 in win.current["keys"]:
do()
tasks.append(
{
"fraction":0.0,
"string":"",
"editing":True,
"selected":True,
"open":False,
"subtasks":[]
}
)
win.current["keys"] = []
# RECURSION
if not thismoving:
if not task["subtasks"]:
cXY[1] = cXY[1] + 50
else:
cXY[1] = cXY[1] + 70
cXY[0] = cXY[0] + 20
# THERE IS YOUR RECURSION
if task["open"]:
draw_tasks(task["subtasks"], cXY, schedulepath)
cXY[0] = cXY[0] - 20
# Adding subtasks
if ((task["subtasks"] and task["open"] and task["selected"])\
or (task["selected"] and not task["subtasks"]))\
and win.textactive != "editing_task"\
and win.current["tool"] == "selection":
cXY[0] = cXY[0] + 20
def do():
task["open"] = True
filter_tasks(win.checklists[path])
task["subtasks"].append(
{
"fraction":0.0,
"string":"",
"editing":True,
"selected":True,
"open":False,
"subtasks":[]
}
)
UI_elements.roundrect(layer, win,
cXY[0],
win.scroll["checklist"] + cXY[1],
width - cXY[0],
40,
10,
button=do,
icon="new",
offset=[x,y])
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
cXY[0],
win.scroll["checklist"] + cXY[1],
width - cXY[0],
40,
10,
fill=False)
layer.stroke()
layer.set_font_size(20)
layer.move_to(
cXY[0]+50,
win.scroll["checklist"] + cXY[1]+25
)
layer.show_text(talk.text("add_new_subtask"))
for line in range(int(cXY[0]/20)):
line = line * 20 + 10
UI_color.set(layer, win, "node_background")
layer.move_to(line, win.scroll["checklist"] + cXY[1]-10)
layer.line_to(line, win.scroll["checklist"] + cXY[1]+40)
layer.stroke()
cXY[0] = cXY[0] - 20
cXY[1] = cXY[1] + 50
schedulepath = []
draw_tasks(win.checklists[path]["subtasks"], cXY, schedulepath)
# Go to the bottom.
if win.current["tool"] == "grab"\
and win.current["my"] - y > win.scroll["checklist"] + cXY[1]:
if win.current["moving_task_now"] and win.current["moving_task_now"][1] != win.current["frame"]:
win.checklists[path]["subtasks"].append(win.current["moving_task_now"][0])
win.current["tool"] = "selection"
win.current["LMB"] = False
win.previous["LMB"] = False
# Saving
save(path, win.checklists[path])
win.checklists = {}
win.assets = {}
win.analytics = analytics.load(win.project)
win.multiuser["last_request"] = ""
# Adding a task.
if win.textactive != "editing_task"\
and win.current["tool"] == "selection":
def do():
filter_tasks(win.checklists[path])
win.checklists[path]["subtasks"].append(
{
"fraction":0.0,
"string":"",
"editing":True,
"selected":True,
"open":False,
"subtasks":[]
}
)
UI_elements.roundrect(layer, win,
cXY[0],
win.scroll["checklist"] + cXY[1],
width - cXY[0],
40,
10,
button=do,
icon="new",
offset=[x,y])
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
cXY[0],
win.scroll["checklist"] + cXY[1],
width - cXY[0],
40,
10,
fill=False)
layer.stroke()
layer.set_font_size(20)
layer.move_to(
cXY[0]+50,
win.scroll["checklist"] + cXY[1]+25
)
layer.show_text(talk.text("add_new_task"))
tileX, current_Y = cXY
# So there would not be jumps of stuff. Let's add heigh to the scroll while
# in grab.
if win.current["tool"] == "grab":
current_Y = current_Y + height
# Outputting the layer
outlayer.set_source_surface(surface, x, y)
outlayer.paint()
# Scroll
UI_elements.scroll_area(outlayer, win, "checklist",
x+0,
y+50,
width,
height-50,
current_Y,
bar=True,
mmb=True)