From beb6d23f8532f5351b4f7b9a398ee4bdf73defd8 Mon Sep 17 00:00:00 2001 From: "Jeison Yehuda Amihud (Blender Dumbass)" Date: Wed, 4 Jan 2023 18:05:16 +0000 Subject: [PATCH] Made analytics more powerfull --- studio/checklist.py | 23 ++- studio/studio_analyticsLayer.py | 299 ++++++++++++++++++++++++++------ studio/studio_gtk.py | 8 +- studio/studio_storyLayer.py | 2 +- 4 files changed, 273 insertions(+), 59 deletions(-) diff --git a/studio/checklist.py b/studio/checklist.py index 50c6711..bb94650 100644 --- a/studio/checklist.py +++ b/studio/checklist.py @@ -387,7 +387,24 @@ def draw(outlayer, win, path, back="story_editor"): UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/checklist.png", 5, 5, 40, 40) - + + # If not in the analytics window. I want to have a button to go to analyitcs. + if win.url != "analytics": + reducing = 60 + def do(): + win.cur = "/set" + win.url = "analytics" + UI_elements.roundrect(layer, win, + width - 55, + 5, + 40, + 40, + 10, + do, + offset=[x,y], + icon="analytics") + else: + reducing = 0 # Fraction fraction = win.checklists[path]["fraction"] @@ -396,7 +413,7 @@ def draw(outlayer, win, path, back="story_editor"): UI_elements.roundrect(layer, win, 50, 17, - width - 60, + width - 60 -reducing, 0, 7) @@ -404,7 +421,7 @@ def draw(outlayer, win, path, back="story_editor"): UI_elements.roundrect(layer, win, 50, 17, - (width - 60 )*fraction, + (width - 60 -reducing)*fraction, 0, 7) diff --git a/studio/studio_analyticsLayer.py b/studio/studio_analyticsLayer.py index 2e79580..8d83de4 100644 --- a/studio/studio_analyticsLayer.py +++ b/studio/studio_analyticsLayer.py @@ -46,8 +46,53 @@ from studio import studio_dialogs from studio import schedule from studio import history -def layer(win): +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. + 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 # Making the layer surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'], @@ -151,7 +196,9 @@ def layer(win): 25, win.current["w"]/2-80, 20, - 10) + 10, + tip=str(round(projectdone*100, 1))+"%") + @@ -180,7 +227,8 @@ def layer(win): 65, win.current["w"]/2-80, 20, - 10) + 10, + tip=str(round(timepassed*100, 1))+"%") # Timepassed UI_color.set(layer, win, "progress_time") @@ -195,22 +243,25 @@ def layer(win): # Icon UI_elements.image(layer, win, "settings/themes/"\ - +win.settings["Theme"]+"/icons/scene.png", + +win.settings["Theme"]+"/icons/shot.png", win.current["w"]/4+10, 95, 40, 40) - UI_color.set(layer, win, "progress_background") + UI_color.set(layer, win, "shot_5") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 105, win.current["w"]/2-80, 20, - 10) + 10, + tip=str(round(rnddone*100, 1))+"%", + fill=False) + layer.stroke() # Scenes - UI_color.set(layer, win, "node_videofile") + UI_color.set(layer, win, "shot_5") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 105, @@ -228,16 +279,19 @@ def layer(win): 40, 40) - UI_color.set(layer, win, "progress_background") + UI_color.set(layer, win, "shot_1") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 145, win.current["w"]/4-80, 20, - 10) + 10, + tip=str(round(chrdone*100, 1))+"%", + fill=False) + layer.stroke() # progress - UI_color.set(layer, win, "node_asset") + UI_color.set(layer, win, "shot_1") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 145, @@ -255,16 +309,19 @@ def layer(win): 40, 40) - UI_color.set(layer, win, "progress_background") + UI_color.set(layer, win, "shot_2") UI_elements.roundrect(layer, win, win.current["w"]/2+60, 145, win.current["w"]/4-80, 20, - 10) + 10, + tip=str(round(vehdone*100, 1))+"%", + fill=False) + layer.stroke() # progress - UI_color.set(layer, win, "node_imagefile") + UI_color.set(layer, win, "shot_2") UI_elements.roundrect(layer, win, win.current["w"]/2+60, 145, @@ -282,16 +339,19 @@ def layer(win): 40, 40) - UI_color.set(layer, win, "progress_background") + UI_color.set(layer, win, "shot_3") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 185, win.current["w"]/4-80, 20, - 10) + 10, + tip=str(round(locdone*100, 1))+"%", + fill=False) + layer.stroke() # progress - UI_color.set(layer, win, "node_blendfile") + UI_color.set(layer, win, "shot_3") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 185, @@ -309,16 +369,19 @@ def layer(win): 40, 40) - UI_color.set(layer, win, "progress_background") + UI_color.set(layer, win, "shot_4") UI_elements.roundrect(layer, win, win.current["w"]/2+60, 185, win.current["w"]/4-80, 20, - 10) + 10, + tip=str(round(objdone*100, 1))+"%", + fill=False) + layer.stroke() # progress - UI_color.set(layer, win, "node_badfile") + UI_color.set(layer, win, "shot_4") UI_elements.roundrect(layer, win, win.current["w"]/2+60, 185, @@ -347,7 +410,7 @@ def layer(win): # Let's make a mode selector. if "analytics_middle_graph_mode" not in win.current: - win.current["analytics_middle_graph_mode"] = "pulse" + win.current["analytics_middle_graph_mode"] = "linear" for num, thing in enumerate(["linear", "analytics", "pulse"]): # By icons @@ -415,12 +478,12 @@ def layer(win): if "analytics_middle_graph_switch" not in win.current: win.current["analytics_middle_graph_switch"] = { "project":[True,"analytics", "progress_active"], - "checklist":[True,"checklist", "darker_parts"], - "rnd":[True,"scene", "node_videofile"], - "chr":[True,"chr", "node_asset"], - "veh":[True,"veh", "node_imagefile"], # Name in data : [ Active, Icon name, color ] - "loc":[True,"loc", "node_blendfile"], - "obj":[True,"obj", "node_badfile"] + "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"] } cat = win.current["analytics_middle_graph_switch"] @@ -434,9 +497,11 @@ def layer(win): UI_elements.roundrect(layer, win, win.current["w"]/4+160+(40*num), 225, + 38, 40, - 40, - 10) + 10, + fill=False) + layer.stroke() def do(): cat[thing][0] = not cat[thing][0] @@ -445,7 +510,7 @@ def layer(win): UI_elements.roundrect(layer, win, win.current["w"]/4+160+(40*num), 225, - 40, + 38, 40, 10, do, @@ -466,6 +531,8 @@ def layer(win): # Now let's make a layer. + # CURRENT DATE + today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format) if "graph_cashe" not in win.current: @@ -483,7 +550,7 @@ def layer(win): #node.fill() # helping line - UI_color.set(node, win, "progress_background") + UI_color.set(node, win, "progress_time") if mode == "analytics": @@ -503,6 +570,7 @@ def layer(win): node.stroke() + todayX = 0 for num, thing in enumerate(reversed(cat)): @@ -518,7 +586,7 @@ def layer(win): pfrac = 0 dates = win.analytics["dates"] - for date in dates: + for date in dates: # Let's calculate the X position of a given part on a graph @@ -529,6 +597,9 @@ def layer(win): dn = int(dn.days) graphX = width / duration * dn + + if date == today: + todayX = graphX # Let's calculate the Y position of a given part on a graph @@ -554,11 +625,61 @@ def layer(win): pfrac = fracs[thing] node.stroke() + + # Today + UI_color.set(node, win, "button_clicked") + node.move_to(todayX, 0) + node.line_to(todayX, height) + node.stroke() win.current["graph_cashe"] = graphsurface + + + # 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() + # Outputting the layer layer.set_source_surface(win.current["graph_cashe"], x, y) - layer.paint() + layer.paint() # Let's force graph to refresh on each click if not win.current["LMB"] and win.previous["LMB"]: @@ -617,8 +738,6 @@ def layer(win): do, button) - # CURRENT DATE - today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format) UI_elements.text(layer, win, "current_date_setting", x+100, @@ -678,7 +797,8 @@ def layer(win): prevyear = [startdate.split("/")[0], win.scroll["days"]] prevmonth = [startdate.split("/")[1], win.scroll["days"]] - + prevday = "1997/07/30" + pfrac = {} for doffset in range(duration+1): # FOR ALL DAYS. NO MATTER IF THEY ARE IN DATA @@ -858,7 +978,8 @@ def layer(win): 10, button=do, offset=[x,y], - fill=False) + fill=False, + tip=datetip(win, theday)) node.stroke() ##################### BOTTOM GRAPH ####################### @@ -873,35 +994,101 @@ def layer(win): # need to be able to navigate with in the bottom graph. # So instead I'm going to redo the graph, but since we - # are re-doing it. I gonna make a slightly different design. - # It will show the same exact data. But drawn with a bit more - # beauty, compared to the top graph. + # 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. + + for num, thing in enumerate(reversed(cat)): if cat[thing][0]: UI_color.set(node, win, cat[thing][2]) try: - fracs = win.analytics["dates"][theday]["fractions"] - gfraction = fracs[thing] - # For now I will implement only Linear mode - # other modes will come later - graphY = ((height-80) - (height-80) * gfraction)+60 - UI_elements.roundrect(node, win, - 8+current_X+win.scroll["days"], - graphY, - 35, - 8, - 5) - except: - pass - + sd = datetime.datetime.strptime(startdate, new_date_format) + nd = datetime.datetime.strptime(theday , new_date_format) + + dn = nd - sd + dn = int(dn.days) + + fracs = win.analytics["dates"][theday]["fractions"] + Pfracs = win.analytics["dates"][prevday]["fractions"] + + gfraction = fracs[thing] + + 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() + + # Now here I want to draw the representations of scheduled - # tasks that are inside + # 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) sch = [] if theday in win.analytics["dates"]: @@ -938,7 +1125,11 @@ def layer(win): 5) + + current_X = current_X + 50 + + prevday = theday UI_color.set(node, win, "dark_overdrop") diff --git a/studio/studio_gtk.py b/studio/studio_gtk.py index c3ff494..6a9fded 100644 --- a/studio/studio_gtk.py +++ b/studio/studio_gtk.py @@ -264,10 +264,16 @@ def pmdrawing(pmdrawing, main_layer, win): win.settings["Blur"] = False win.sFPS = datetime.datetime.now() - + # Current frame (for animations and things like this) win.current["frame"] += 1 + + if win.current["frame"] == 10: + win.cur = "/set" + win.url = "analytics" + + if not "scale" in win.settings: settings.write("scale", 1) # Writing to file win.settings = settings.load_all() diff --git a/studio/studio_storyLayer.py b/studio/studio_storyLayer.py index eed8ab1..b43cc30 100644 --- a/studio/studio_storyLayer.py +++ b/studio/studio_storyLayer.py @@ -151,7 +151,7 @@ def layer(win): slist.append([date, item, schedules[date][item]]) - # Now that we have our list we can start paring it the same way as in the + # Now that we have our list we can start parsing it the same way as in the # scheduling. Only removing some unnesesary stuff. foundtask = False taskname = ""