Blender-Pipeline/studio/studio_analyticsLayer.py

1357 lines
43 KiB
Python
Raw Normal View History

2021-12-19 19:14:53 +01:00
####################################
# #
# COPYRIGHT NOTICE #
# #
# This file is a part of Victori- #
# ous Children Studio Organizer. #
# Or simply VCStudio. Copyright #
# of J.Y.Amihud. But don't be sad #
# because I released the entire #
# project under a GNU GPL license. #
# You may use Version 3 or later. #
# See www.gnu.org/licenses if your #
# copy has no License file. Please #
# note. Ones I used the GPL v2 for #
# it. It's no longer the case. #
# #
####################################
2020-12-13 04:06:44 +01:00
import os
import datetime
# GTK module ( Graphical interface
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import Gdk
import cairo
# Own modules
from settings import settings
from settings import talk
from settings import fileformats
from settings import oscalls
from project_manager import pm_project
#UI modules
from UI import UI_elements
from UI import UI_color
# story
from studio import story
from studio import checklist
from studio import analytics
from studio import studio_dialogs
from studio import schedule
2020-12-14 04:21:25 +01:00
from studio import history
2020-12-13 04:06:44 +01:00
2023-01-04 19:05:16 +01:00
def datetip(win, date):
# Function that outputs basic analytics about a given date
# in text form
# TODO: This function is in a prototype stage. Meaning it's
# not translated to multiple languages. This should be fixed.
# See settings/talk.py file.
2020-12-13 04:06:44 +01:00
2023-01-04 19:05:16 +01:00
text = date
try:
data = win.analytics["dates"][date]
# Expected
startdate = win.analytics["startdate"]
deadline = win.analytics["deadline"]
duration = win.analytics["duration"]
new_date_format = "%Y/%m/%d"
sd = datetime.datetime.strptime(startdate, new_date_format)
nd = datetime.datetime.strptime(date , new_date_format)
dn = nd - sd
daysin = int(dn.days)
expected = round(100 / duration * daysin, 2)
text = text +"\n\nExpected: "+str(expected)+"%"
# Actual
frac = round(data.get("fractions", {}).get("project")*100, 2)
text = text +"\nActual: "+str(frac)+"%"
# Productivity
productivity = int(round(frac - expected+100))
text = text +"\n\nProductivity: "+str(productivity)+"%"
except Exception as e:
pass
return text
def layer(win):
# This is very important. I makes live easier. LOL.
win.current["shot_left_side_scroll_please_work_omg_wtf"] = True
2020-12-13 04:06:44 +01:00
# Making the layer
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'],
win.current['h'])
layer = cairo.Context(surface)
#text setting
layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
UI_color.set(layer, win, "dark_overdrop")
layer.rectangle(
0,
0,
win.current["w"],
win.current["h"],
)
layer.fill()
UI_color.set(layer, win, "node_background")
UI_elements.roundrect(layer, win,
win.current["w"]/4,
10,
win.current["w"]/2,
win.current["h"]-20,
10)
############################################################################
# This is the Analitycs window. This time I want to do something crazy.
# There will be 5 sections on the screen.
############################################################################
# # # #
# # # #
# # PROGRESS BARS # #
# # # #
# # # #
# # ####################################### # #
# # # #
# SCHEDULING # ANALYTICS GRAPH # MAIN #
# # # CHECKLIS #
# # # #
# # ####################################### # #
# # # #
# # CALENDAR / DAY SELECTOR # #
# # # #
# # X # #
############################################################################
# The idea is that you could be in Assets or Script Editor and drag the
# tasks from the checklist down to Calendar and leave it there. So when you
# move the task and mouse comes into the center part, you automatically
# transferred to the analytics layer for untill you leave the task somewhere
# or return it back to the checklist.
# I want to do the same with the SCHEDULING. So you could simple drag it to
# the Calendar to change it's date. Let's see how terribly hard will it be
# to implement. Because I'm already fighting with the Scedules all day.
############################################################################
############## PROGRESS BARS #############
timepassed = 0.0
projectdone = 0.0
chrdone = 0.0
vehdone = 0.0
locdone = 0.0
objdone = 0.0
rnddone = 0.0
try:
timepassed = win.analytics["timepassed"]
projectdone = win.analytics["fraction"]
chrdone = win.analytics["chr"]
vehdone = win.analytics["veh"]
locdone = win.analytics["loc"]
objdone = win.analytics["obj"]
rnddone = win.analytics["rnd"]
except:
pass
# MAIN PROGRESS
2023-02-04 18:52:33 +01:00
2020-12-13 04:06:44 +01:00
UI_elements.image(layer, win, "settings/themes/"\
2023-02-04 18:52:33 +01:00
+win.settings["Theme"]+"/icons/star.png",
2020-12-13 04:06:44 +01:00
win.current["w"]/4+10,
15,
40,
40)
# Progressbar
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
25,
win.current["w"]/2-80,
20,
2023-01-04 19:05:16 +01:00
10,
2023-02-04 18:52:33 +01:00
tip="Today's requirement is: "+str(round(win.analytics.get("needed", 0)*100, 1))+"% ( "+str(round(win.analytics.get("star", 0)*100, 1))+"% of which is done )")
2023-01-04 19:05:16 +01:00
2023-02-04 18:52:33 +01:00
UI_color.set(layer, win, "text_link")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
25,
2023-02-04 18:52:33 +01:00
(win.current["w"]/2-80)*min(win.analytics.get("star", 0), 1),
2020-12-13 04:06:44 +01:00
20,
10)
2023-02-04 18:52:33 +01:00
# # Icon
# UI_elements.image(layer, win, "settings/themes/"\
# +win.settings["Theme"]+"/icons/analytics.png",
# win.current["w"]/4+10,
# 15,
# 40,
# 40)
# # Progressbar
# UI_color.set(layer, win, "progress_background")
# UI_elements.roundrect(layer, win,
# win.current["w"]/4+60,
# 25,
# win.current["w"]/2-80,
# 20,
# 10,
# tip=str(round(projectdone*100, 1))+"%")
# # Project Done
# UI_color.set(layer, win, "progress_active")
# UI_elements.roundrect(layer, win,
# win.current["w"]/4+60,
# 25,
# (win.current["w"]/2-80)*projectdone,
# 20,
# 10)
2020-12-13 04:06:44 +01:00
# TIME PASSED
# Icon
UI_elements.image(layer, win, "settings/themes/"\
+win.settings["Theme"]+"/icons/schedule.png",
win.current["w"]/4+10,
55,
40,
40)
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
65,
win.current["w"]/2-80,
20,
2023-01-04 19:05:16 +01:00
10,
2023-02-04 18:52:33 +01:00
tip="Time: "+str(round(timepassed*100, 1))+"% Project: "+str(round(projectdone*100, 1))+"%")
2020-12-13 04:06:44 +01:00
# Timepassed
UI_color.set(layer, win, "progress_time")
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
65,
(win.current["w"]/2-80)*timepassed,
20,
10)
2023-02-04 18:52:33 +01:00
# Project Done
UI_color.set(layer, win, "progress_active")
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
65,
(win.current["w"]/2-80)*projectdone,
20,
10)
2020-12-13 04:06:44 +01:00
# SCENES DONE ( RND )
# Icon
UI_elements.image(layer, win, "settings/themes/"\
2023-01-04 19:05:16 +01:00
+win.settings["Theme"]+"/icons/shot.png",
2020-12-13 04:06:44 +01:00
win.current["w"]/4+10,
95,
40,
40)
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_5")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
105,
win.current["w"]/2-80,
20,
2023-01-04 19:05:16 +01:00
10,
tip=str(round(rnddone*100, 1))+"%",
fill=False)
layer.stroke()
2020-12-13 04:06:44 +01:00
# Scenes
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_5")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
105,
(win.current["w"]/2-80)*rnddone,
20,
10)
# CHR DONE
# Icon
UI_elements.image(layer, win, "settings/themes/"\
+win.settings["Theme"]+"/icons/chr.png",
win.current["w"]/4+10,
135,
40,
40)
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_1")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
145,
win.current["w"]/4-80,
20,
2023-01-04 19:05:16 +01:00
10,
tip=str(round(chrdone*100, 1))+"%",
fill=False)
layer.stroke()
2020-12-13 04:06:44 +01:00
# progress
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_1")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
145,
(win.current["w"]/4-80)*chrdone,
20,
10)
# VEH DONE
# Icon
UI_elements.image(layer, win, "settings/themes/"\
+win.settings["Theme"]+"/icons/veh.png",
win.current["w"]/2,
135,
40,
40)
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_2")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/2+60,
145,
win.current["w"]/4-80,
20,
2023-01-04 19:05:16 +01:00
10,
tip=str(round(vehdone*100, 1))+"%",
fill=False)
layer.stroke()
2020-12-13 04:06:44 +01:00
# progress
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_2")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/2+60,
145,
(win.current["w"]/4-80)*vehdone,
20,
10)
# LOC DONE
# Icon
UI_elements.image(layer, win, "settings/themes/"\
+win.settings["Theme"]+"/icons/loc.png",
win.current["w"]/4+10,
175,
40,
40)
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_3")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
185,
win.current["w"]/4-80,
20,
2023-01-04 19:05:16 +01:00
10,
tip=str(round(locdone*100, 1))+"%",
fill=False)
layer.stroke()
2020-12-13 04:06:44 +01:00
# progress
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_3")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/4+60,
185,
(win.current["w"]/4-80)*locdone,
20,
10)
# OBJ DONE
# Icon
UI_elements.image(layer, win, "settings/themes/"\
+win.settings["Theme"]+"/icons/obj.png",
win.current["w"]/2,
175,
40,
40)
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_4")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/2+60,
185,
win.current["w"]/4-80,
20,
2023-01-04 19:05:16 +01:00
10,
tip=str(round(objdone*100, 1))+"%",
fill=False)
layer.stroke()
2020-12-13 04:06:44 +01:00
# progress
2023-01-04 19:05:16 +01:00
UI_color.set(layer, win, "shot_4")
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
win.current["w"]/2+60,
185,
(win.current["w"]/4-80)*objdone,
20,
10)
############### THE GRAPH ##################
# This graph going to show the entire time of the whole project from
# StartDate till Deadline. It will fill up with data overtime.
# We are going to have a couple of modes.
# Regular mode: Showing actuall values represented on the graph
# it's going to be a diagonal line if the work was done
# linearly.
# Normalized : This this a graph of true values compared to time. So let's
# say at a second day you had to be only at 3%. Being at 3% will
# make graph show 100%. The expected value is linear from 0%
# to 100% over the whole project.
# Pulse mode : This mode will give a graph compared to the previous day.
# if on a given day there was a gib jump in percentage there
# will be a big spike on the graph.
# Let's make a mode selector.
if "analytics_middle_graph_mode" not in win.current:
2023-01-04 19:05:16 +01:00
win.current["analytics_middle_graph_mode"] = "linear"
2020-12-13 04:06:44 +01:00
for num, thing in enumerate(["linear", "analytics", "pulse"]): # By icons
if win.current["analytics_middle_graph_mode"] == thing:
UI_color.set(layer, win, "progress_time")
UI_elements.roundrect(layer, win,
win.current["w"]/4+10+(40*num),
225,
40,
40,
10)
def do():
win.current["analytics_middle_graph_mode"] = thing
del win.current["graph_cashe"]
UI_elements.roundrect(layer, win,
win.current["w"]/4+10+(40*num),
225,
40,
40,
10,
do,
thing)
# And before we start a little settings icon.
2020-12-25 15:20:34 +01:00
# Documentation entry
def do():
def after(win, var):
pass
studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_analytics"))
UI_elements.roundrect(layer, win,
win.current["w"]/4*3-110,
225,
40,
40,
10,
do,
"question")
2020-12-13 04:06:44 +01:00
# Settings
def do():
win.url = "settings_layer"
UI_elements.roundrect(layer, win,
win.current["w"]/4*3-60,
225,
40,
40,
10,
do,
"settings",
talk.text("Settings"))
# Now let's make a filter by type. As you maybe already know appart from
# the main progress I'm reading all the other things too. Every progress
# bar on the screen should have a corrisponding graph. But sometimes if
# paths go too far appart, this aint helpfull. So a filter is required to
# switch a category on and off.
if "analytics_middle_graph_switch" not in win.current:
win.current["analytics_middle_graph_switch"] = {
"project":[True,"analytics", "progress_active"],
2023-01-04 19:05:16 +01:00
"checklist":[True,"checklist", "node_videofile"],
"rnd":[True,"shot", "shot_5"],
"chr":[True,"chr", "shot_1"],
"veh":[True,"veh", "shot_2"], # Name in data : [ Active, Icon name, color ]
"loc":[True,"loc", "shot_3"],
"obj":[True,"obj", "shot_4"]
2020-12-13 04:06:44 +01:00
}
cat = win.current["analytics_middle_graph_switch"]
mode = win.current["analytics_middle_graph_mode"]
for num, thing in enumerate(cat):
if cat[thing][0]:
UI_color.set(layer, win, cat[thing][2])
UI_elements.roundrect(layer, win,
win.current["w"]/4+160+(40*num),
225,
2023-01-04 19:05:16 +01:00
38,
2020-12-13 04:06:44 +01:00
40,
2023-01-04 19:05:16 +01:00
10,
fill=False)
layer.stroke()
2020-12-13 04:06:44 +01:00
def do():
cat[thing][0] = not cat[thing][0]
del win.current["graph_cashe"]
UI_elements.roundrect(layer, win,
win.current["w"]/4+160+(40*num),
225,
2023-01-04 19:05:16 +01:00
38,
2020-12-13 04:06:44 +01:00
40,
10,
do,
cat[thing][1])
# Let's set up some very handy values
new_date_format = "%Y/%m/%d"
startdate = win.analytics["startdate"]
deadline = win.analytics["deadline"]
duration = win.analytics["duration"]
# Let's setup the little graph layer. So nothing come out of the frame.
x = win.current["w"]/4
y = 280
width = win.current["w"] / 2
2021-12-19 19:14:53 +01:00
height = 100
2020-12-13 04:06:44 +01:00
# Now let's make a layer.
2023-01-04 19:05:16 +01:00
# CURRENT DATE
today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
2020-12-14 04:21:25 +01:00
2020-12-13 04:06:44 +01:00
if "graph_cashe" not in win.current:
# Making the layer
graphsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
node = cairo.Context(graphsurface)
node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
# Background
#UI_color.set(node, win, "dark_overdrop")
#node.rectangle(0,0,width, height)
#node.fill()
# helping line
2023-01-04 19:05:16 +01:00
UI_color.set(node, win, "progress_time")
2020-12-13 04:06:44 +01:00
if mode == "analytics":
node.move_to(0, height/2)
node.line_to(width, height/2)
elif mode == "pulse":
ty = height / duration
node.move_to(0, height/2-ty)
node.line_to(width, height/2-ty)
else:
node.move_to(0, height)
node.line_to(width, 0)
node.stroke()
2023-01-04 19:05:16 +01:00
todayX = 0
2020-12-13 04:06:44 +01:00
for num, thing in enumerate(reversed(cat)):
if cat[thing][0]:
UI_color.set(node, win, cat[thing][2])
if mode == "linear":
node.move_to(0, height)
else:
node.move_to(0, height/2)
pfrac = 0
dates = win.analytics["dates"]
2023-01-04 19:05:16 +01:00
for date in dates:
2020-12-13 04:06:44 +01:00
# Let's calculate the X position of a given part on a graph
sd = datetime.datetime.strptime(startdate, new_date_format)
nd = datetime.datetime.strptime(date , new_date_format)
dn = nd - sd
dn = int(dn.days)
graphX = width / duration * dn
2023-01-04 19:05:16 +01:00
if date == today:
todayX = graphX
2020-12-13 04:06:44 +01:00
# Let's calculate the Y position of a given part on a graph
if "fractions" in dates[date]:
fracs = dates[date]["fractions"]
if mode == "linear":
gfraction = fracs[thing]
graphY = height - height * gfraction
node.line_to(graphX, graphY)
elif mode == "analytics":
gfraction = fracs[thing]
tfraction = dn / duration
gfraction = gfraction / tfraction / 2
graphY = height - height * gfraction
node.line_to(graphX, graphY)
else:
gfraction = fracs[thing]
gfraction = gfraction - pfrac
graphY = height - height * gfraction - height / 2
node.line_to(graphX, graphY)
pfrac = fracs[thing]
node.stroke()
2023-01-04 19:05:16 +01:00
# Today
UI_color.set(node, win, "button_clicked")
node.move_to(todayX, 0)
node.line_to(todayX, height)
node.stroke()
2020-12-13 04:06:44 +01:00
win.current["graph_cashe"] = graphsurface
2023-01-04 19:05:16 +01:00
# Dynamic elements of the graph!
# I sense a possible bug here, since I will draw these on top
# of a prebaked image. And something sometimes might not align
# properly. I don't know how to deal with it quite yet, perhaps
# you can try fixing the issue. LOL.
# Bottom Graph position on the top graph.
try:
posX = width / (duration*50) * win.scroll["days"]
posX2 = (width / (duration*50) * (win.scroll["days"]+width))-posX
except:
posX = 0
posX2 = 20
UI_color.set(layer, win, "dark_overdrop")
UI_elements.roundrect(layer, win,
x-posX,
y,
posX2,
height,
5,
fill=True)
layer.stroke()
# Mouse drag thingy
if x < win.current["mx"] < x+width\
and y < win.current["my"] < y+height:
if win.current["LMB"]:
win.scroll["days"] = 0- (( win.current["mx"] - x ) / width * (duration*50)) + (width/2)
sd = datetime.datetime.strptime(startdate, new_date_format)
daysin = int(round( duration / width * (x-win.current["mx"])))*-1
td = datetime.timedelta(days=daysin)
hoverdate = sd + td
hoverdate = hoverdate.strftime(new_date_format)
UI_elements.tooltip(win, datetip(win, hoverdate))
UI_color.set(layer, win, "progress_background")
layer.move_to(win.current["mx"], y)
layer.line_to(win.current["mx"], y+height)
layer.stroke()
2020-12-13 04:06:44 +01:00
# Outputting the layer
layer.set_source_surface(win.current["graph_cashe"], x, y)
2023-01-04 19:05:16 +01:00
layer.paint()
2020-12-14 04:21:25 +01:00
# Let's force graph to refresh on each click
if not win.current["LMB"] and win.previous["LMB"]:
try:
del win.current["graph_cashe"]
except:
pass
2020-12-13 04:06:44 +01:00
############### SCHEDULING / DATE SELECTION ################
# So here I want to put a dialog that in the Blender-Organizer legacy was
# in the center of the frame. I thought here it makes a bit more sense. Tho
# I will remove the graph from it. I have a very good graph on the top from
# it. And in my opinion this is enough. In you think otherwise let me know.
# or fork VCStudio and implement it yourself. See what I can do with free-
# software. I can just tell you to do everything yourself. Imaging doing this
# when developing proprietery software.
# Anyway back to the thing. I do want to draw schedules inside the days cells.
# and by their colors. RED or GREY or PURPLE or GREEN you will have an idea of
# how much stuff is done and how much stuff is not yet done. A kind of second
# graph, so to speak. But representing differnt kind of data.
2021-12-19 19:14:53 +01:00
2020-12-13 04:06:44 +01:00
# OKAY. SETTINGS.
if "schedule_analytics_settings" not in win.current:
win.current["schedule_analytics_settings"] = {
"checked":False,
"multiuser":False
}
for num, button in enumerate(win.current["schedule_analytics_settings"]):
if win.current["schedule_analytics_settings"][button]:
UI_color.set(layer, win, "progress_time")
UI_elements.roundrect(layer, win,
x+10+(40*num),
y+height+10,
40,
40,
10)
def do():
win.current["schedule_analytics_settings"][button] = not win.current["schedule_analytics_settings"][button]
UI_elements.roundrect(layer, win,
x+10+(40*num),
y+height+10,
40,
40,
10,
do,
button)
UI_elements.text(layer, win, "current_date_setting",
x+100,
y+height+10,
200,
40,
set_text=win.current["date"])
if win.text["current_date_setting"]["text"] != win.current["date"]\
and analytics.ifdate(win.text["current_date_setting"]["text"]):
def do():
win.current["date"] = win.text["current_date_setting"]["text"]
2020-12-14 04:21:25 +01:00
win.textactive = ""
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
x+260,
y+height+10,
40,
40,
10,
button=do,
icon="ok",
tip=talk.text("checked"))
elif win.current["date"] != today:
def do():
win.current["date"] = today
win.text["current_date_setting"]["text"] = today
2020-12-14 04:21:25 +01:00
win.textactive = ""
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(layer, win,
x+260,
y+height+10,
40,
40,
10,
button=do,
icon="cancel",
tip=talk.text("cancel"))
y = y + height + 60
2021-12-19 19:14:53 +01:00
height = win.current["h"]-500
2020-12-13 04:06:44 +01:00
# Making the layer
graphsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
node = cairo.Context(graphsurface)
node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
if "days" not in win.scroll:
win.scroll["days"] = 0 - win.analytics["dayspassed"]*50 + width / 2 - 25
current_X = 0
prevyear = [startdate.split("/")[0], win.scroll["days"]]
prevmonth = [startdate.split("/")[1], win.scroll["days"]]
2023-01-04 19:05:16 +01:00
prevday = "1997/07/30"
pfrac = {}
2020-12-13 04:06:44 +01:00
for doffset in range(duration+1): # FOR ALL DAYS. NO MATTER IF THEY ARE IN DATA
sd = datetime.datetime.strptime(startdate, new_date_format)
theday = datetime.datetime.strftime(sd+datetime.timedelta(days=doffset), new_date_format)
nowyear = [theday.split("/")[0], current_X+win.scroll["days"]]
nowmonth = [theday.split("/")[1], current_X+win.scroll["days"]]
# Focusing if selected
if win.current["date"] != win.previous["date"] and win.current["date"] == theday:
win.scroll["days"] = 0 - current_X + width / 2 - 25
# YEARS
if nowyear[0] != prevyear[0]:
UI_color.set(node, win, "dark_overdrop")
UI_elements.roundrect(node, win,
5+prevyear[1]+2,
0,
nowyear[1] - prevyear[1]-7,
20,
10)
UI_color.set(node, win, "text_normal")
node.set_font_size(15)
node.move_to(
max(prevyear[1] + 200, min(width/2-23, nowyear[1]- 200)),
15,
)
node.show_text(prevyear[0])
prevyear = nowyear
# MONTHS
if nowmonth[0] != prevmonth[0]:
UI_color.set(node, win, "dark_overdrop")
UI_elements.roundrect(node, win,
5+prevmonth[1]+2,
22,
nowmonth[1]-prevmonth[1]-7,
20,
10)
UI_color.set(node, win, "text_normal")
node.set_font_size(15)
node.move_to(
max(prevmonth[1] + 12, min(width/2-12, nowmonth[1]- 35)),
38,
)
node.show_text(prevmonth[0])
prevmonth = nowmonth
# DAYS
if -50 < current_X+win.scroll["days"] < width:
UI_color.set(node, win, "dark_overdrop")
UI_elements.roundrect(node, win,
5+current_X+win.scroll["days"],
44,
40,
20,
10)
UI_color.set(node, win, "text_normal")
node.set_font_size(15)
node.move_to(
15+current_X+win.scroll["days"],
59,
)
node.show_text(theday.split("/")[2])
UI_color.set(node, win, "dark_overdrop")
2021-12-19 19:14:53 +01:00
if theday >= today:
if theday == today:
UI_color.set(node, win, "button_clicked")
UI_elements.roundrect(node, win,
5+current_X+win.scroll["days"],
67,
40,
height-67,
10)
2020-12-13 04:06:44 +01:00
if win.current["date"] == theday:
UI_color.set(node, win, "progress_background")
UI_elements.roundrect(node, win,
5+current_X+win.scroll["days"],
67,
40,
height-67,
10,
fill=False)
node.stroke()
2020-12-14 04:21:25 +01:00
# STARTDATE & DEADLINE
elif theday in [startdate, deadline]:
UI_color.set(node, win, "node_badfile")
UI_elements.roundrect(node, win,
5+current_X+win.scroll["days"],
67,
40,
height-67,
10,
fill=False)
node.stroke()
2020-12-13 04:06:44 +01:00
# SELECTION BUTTON
def do():
2020-12-14 04:21:25 +01:00
if win.current["tool"] == "schedule":
# If it's a scheduling.
path, back, cur, schedulepath, username = win.current["grab_data"].copy()
path = path.replace(win.project, "")
path = path[path.find(cur)+len(cur):]
if theday not in win.analytics["dates"]:
win.analytics["dates"][theday] = {}
name = cur[cur.rfind("/")+1:]
acur = cur.replace(name, "").replace("/", "")
if acur in ["chr", "veh", "loc","obj"]:
itemtype = "assets"
elif not acur:
itemtype = "files"
else:
itemtype = "scenes"
if itemtype not in win.analytics["dates"][theday]:
win.analytics["dates"][theday][itemtype] = {}
if cur not in win.analytics["dates"][theday][itemtype]:
win.analytics["dates"][theday][itemtype][cur] = []
2020-12-15 21:38:04 +01:00
#print("test 1")
2020-12-14 04:21:25 +01:00
win.analytics["dates"][theday][itemtype][cur].append(
["00:00:00",
"schedule",
path,
"[Un-Checked]",
schedulepath,
username]
)
2020-12-15 21:38:04 +01:00
#print("test 2")
2020-12-14 04:21:25 +01:00
# RETURNING BACK TO NORMAL
win.url = back
win.current["tool"] = "selection"
analytics.save(win.project, win.analytics)
win.analytics = analytics.load(win.project)
win.checklists = {}
# Multiuser sycning
win.multiuser["request"] = "analytics"
2020-12-15 21:38:04 +01:00
#print("test 3")
2020-12-14 04:21:25 +01:00
else:
win.current["date"] = theday
win.text["current_date_setting"]["text"] = theday
2020-12-13 04:06:44 +01:00
UI_elements.roundrect(node, win,
5+current_X+win.scroll["days"],
67,
40,
height-67,
10,
button=do,
offset=[x,y],
2023-01-04 19:05:16 +01:00
fill=False,
tip=datetip(win, theday))
2020-12-13 04:06:44 +01:00
node.stroke()
2021-12-19 19:14:53 +01:00
##################### BOTTOM GRAPH #######################
# Blender-Organizer legacy had two graphs. One smaller
# that shows all the project from start to finish
# ( Implemented above ) and one bigger. That shows a
# Zoomed in version of the graph. Back then I made it
# executing the same code twice. Which was fine. Since
# I had to make a change only ones. Now it's a bit of a
# problem to do so. Since the graph above is baked. And
# need to be able to navigate with in the bottom graph.
# So instead I'm going to redo the graph, but since we
2023-01-04 19:05:16 +01:00
# are re-doing it. I orignally wanted to do a different
# design. But it ended up looking confusing. It needs lines!
# Roundrects will not do.
2021-12-19 19:14:53 +01:00
2023-02-04 18:52:33 +01:00
2023-01-04 19:05:16 +01:00
2021-12-19 19:14:53 +01:00
for num, thing in enumerate(reversed(cat)):
if cat[thing][0]:
UI_color.set(node, win, cat[thing][2])
try:
2023-01-04 19:05:16 +01:00
sd = datetime.datetime.strptime(startdate, new_date_format)
nd = datetime.datetime.strptime(theday , new_date_format)
dn = nd - sd
dn = int(dn.days)
2021-12-19 19:14:53 +01:00
fracs = win.analytics["dates"][theday]["fractions"]
2023-01-04 19:05:16 +01:00
Pfracs = win.analytics["dates"][prevday]["fractions"]
2021-12-19 19:14:53 +01:00
gfraction = fracs[thing]
2023-01-04 19:05:16 +01:00
if mode == "linear":
graphY = ((height-80) - (height-80) * gfraction)+60
elif mode == "analytics":
tfraction = dn / duration
gfraction = gfraction / tfraction / 2
graphY = ((height-80) - (height-80) * gfraction)+60
else:
try:
gfraction = fracs[thing]
gfraction = gfraction - Pfracs[thing]
except:
gfraction = 0
graphY = ((height-80) - (height-80) * gfraction - (height-80) / 2)+60
PgraphY = pfrac.get(thing, graphY)
pfrac[thing] = graphY
node.move_to(current_X+win.scroll["days"]-25,
PgraphY)
node.line_to(current_X+win.scroll["days"]+25,
graphY)
node.stroke()
except Exception as e:
if theday < today and theday not in win.analytics["dates"]:
UI_color.set(node, win, "node_badfile")
UI_elements.roundrect(node, win,
5+current_X+win.scroll["days"],
67,
40,
height-67,
10,
fill=False)
node.stroke()
2021-12-19 19:14:53 +01:00
2023-01-04 19:05:16 +01:00
2021-12-19 19:14:53 +01:00
2020-12-13 04:06:44 +01:00
# Now here I want to draw the representations of scheduled
2023-01-04 19:05:16 +01:00
# tasks that are inside
# Icons of what was done at the day
icons_stuff = {"assets":"obj",
"scenes":"shot",
"files":"checklist"}
icons = []
for t in icons_stuff:
if t in win.analytics["dates"].get(theday, {}) and t != "assets":
icons.append(icons_stuff[t])
elif t in win.analytics["dates"].get(theday, {}):
for at in ["chr", "obj", "loc", "veh"]:
for stuff in win.analytics["dates"].get(theday, {})[t]:
if at in stuff and at not in icons:
icons.append(at)
for nicon, icon in enumerate(icons):
UI_elements.image(node, win, "settings/themes/"\
+win.settings["Theme"]+"/icons/"+icon+".png",
6+current_X+win.scroll["days"],
height-(50*nicon)-50,
40,
40)
2023-02-04 18:52:33 +01:00
# Stars! If the day was exceptional.
try:
if win.analytics["needed"] <= fracs.get("project", 0) - Pfracs.get("project", 0) and theday <= today:
stars = (fracs.get("project", 0) - Pfracs.get("project", 0)) / win.analytics["needed"]
for star in range(int(round(stars))):
UI_elements.image(node, win, "settings/themes/"\
+win.settings["Theme"]+"/icons/star.png",
6+current_X+win.scroll["days"],
height-(50*(nicon+star-1))-150,
40,
40)
2023-02-04 18:52:33 +01:00
except:
pass
2020-12-13 04:06:44 +01:00
2023-02-04 18:52:33 +01:00
# Schedules
2020-12-13 04:06:44 +01:00
sch = []
if theday in win.analytics["dates"]:
date = win.analytics["dates"][theday]
2020-12-15 21:38:04 +01:00
2020-12-13 04:06:44 +01:00
for i in ["files", "assets", "scenes"]:
if i in date:
for item in date[i]:
for stuff in date[i][item]:
if stuff[1] == "schedule":
2020-12-15 21:38:04 +01:00
2020-12-13 04:06:44 +01:00
if not win.current["schedule_analytics_settings"]["multiuser"]:
if win.settings["Username"] != stuff[-1]:
continue
if "[Checked]" in stuff:
if win.current["schedule_analytics_settings"]["checked"]:
sch.append(True)
else:
sch.append(False)
for n, s in enumerate(sch):
UI_color.set(node, win, "node_background")
if theday < today:
UI_color.set(node, win, "node_badfile")
elif theday > today:
UI_color.set(node, win, "node_asset")
if s:
UI_color.set(node, win, "node_blendfile")
UI_elements.roundrect(node, win,
8+current_X+win.scroll["days"],
70+13*n,
35,
8,
5)
2023-01-04 19:05:16 +01:00
2020-12-13 04:06:44 +01:00
current_X = current_X + 50
2023-01-04 19:05:16 +01:00
prevday = theday
2020-12-13 04:06:44 +01:00
2021-12-19 19:14:53 +01:00
2020-12-13 04:06:44 +01:00
UI_color.set(node, win, "dark_overdrop")
UI_elements.roundrect(node, win,
5+prevyear[1]+2,
0,
nowyear[1] - prevyear[1]-4 + 50,
20,
10)
UI_color.set(node, win, "text_normal")
node.set_font_size(15)
node.move_to(
max(prevyear[1] + 200, min(width/2-23, nowyear[1]- 200)),
15,
)
node.show_text(prevyear[0])
UI_color.set(node, win, "dark_overdrop")
UI_elements.roundrect(node, win,
5+prevmonth[1]+2,
22,
nowmonth[1]-prevmonth[1]-4 + 50,
20,
10)
UI_color.set(node, win, "text_normal")
node.set_font_size(15)
node.move_to(
max(prevmonth[1] + 12, min(width/2-12, nowmonth[1]- 35)),
38,
)
node.show_text(prevmonth[0])
# Outputting the layer
layer.set_source_surface(graphsurface, x, y)
layer.paint()
# Scroll
UI_elements.scroll_area(layer, win, "days",
x,
y,
width,
height+30,
current_X,
bar=True,
mmb=True,
sideways=True)
############## CHECKLIST ################
if win.current["tool"] == "schedule":
2020-12-14 04:21:25 +01:00
# If the tool is scheduling I want to make sure that the user sees where
# he needs to place the task. A higlight.
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
x,
y+67,
width,
height-67,
10,
fill=False)
layer.stroke()
2020-12-13 04:06:44 +01:00
2020-12-14 04:21:25 +01:00
path, back, cur, schedulepath, username = win.current["grab_data"].copy()
2020-12-13 04:06:44 +01:00
2020-12-15 21:38:04 +01:00
2020-12-13 04:06:44 +01:00
checklist.draw(layer, win, path, back)
UI_color.set(layer, win, "node_background")
UI_elements.roundrect(layer, win,
win.current["mx"],
win.current["my"],
40,
40,
10)
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/schedule.png",
win.current["mx"],
win.current["my"],
40,
40)
elif os.path.exists(win.project+"/set/project.progress"):
checklist.draw(layer, win, win.project+"/set/project.progress", back=win.url)
elif os.path.exists(win.project+"/project.progress"):
checklist.draw(layer, win, win.project+"/project.progress", back=win.url)
2020-12-14 04:21:25 +01:00
# In the analytics window there will a choise of whether to see schedules. Or to
# see history.
if "analytics_left_panel" not in win.current:
win.current["analytics_left_panel"] = "schedule"
2020-12-13 04:06:44 +01:00
UI_color.set(layer, win, "node_background")
UI_elements.roundrect(layer, win,
10,
10,
win.current["w"]/4-20,
50,
10)
2020-12-14 04:21:25 +01:00
for num, thing in enumerate(["schedule", "history"]):
if win.current["analytics_left_panel"] == thing:
UI_color.set(layer, win, "progress_time")
UI_elements.roundrect(layer, win,
20+(40*num),
15,
40,
40,
10)
def do():
win.current["analytics_left_panel"] = thing
2020-12-13 04:06:44 +01:00
2020-12-14 04:21:25 +01:00
UI_elements.roundrect(layer, win,
20+(40*num),
15,
40,
40,
10,
do,
thing)
##### SCHEDULE ######
if win.current["analytics_left_panel"] == "schedule":
schedule.draw(layer, win)
##### HISTORY #######
else:
history.draw(layer, win)
2020-12-13 04:06:44 +01:00
# CANCEl
def do():
win.url = "story_editor"
win.assets = {}
win.current["asset_file_selected"] = ""
UI_elements.roundrect(layer, win,
win.current["w"]-40-win.current["w"]/4,
win.current["h"]-50,
40,
40,
10,
button=do,
icon="cancel",
tip=talk.text("cancel"))
# Short cut ESC
if 65307 in win.current["keys"] and not win.textactive:
do()
return surface