diff --git a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py index bce21e7b78..2b3b66fa3e 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/__init__.py @@ -66,6 +66,9 @@ classes = ( operator.SelectTaskRelatedProducts, operator.VisualiseWorkScheduleDate, operator.VisualiseWorkScheduleDateRange, + operator.BlenderBIM_DatePicker, + operator.BlenderBIM_DatePickerSetDate, + operator.BlenderBIM_RedrawDatePicker, prop.WorkPlan, prop.BIMWorkPlanProperties, prop.Task, @@ -74,6 +77,7 @@ classes = ( prop.WorkCalendar, prop.RecurrenceComponent, prop.BIMWorkCalendarProperties, + prop.DatePickerProperties, ui.BIM_PT_work_plans, ui.BIM_PT_work_schedules, ui.BIM_PT_work_calendars, @@ -91,6 +95,7 @@ def register(): bpy.types.Scene.BIMWorkScheduleProperties = bpy.props.PointerProperty(type=prop.BIMWorkScheduleProperties) bpy.types.Scene.BIMTaskTreeProperties = bpy.props.PointerProperty(type=prop.BIMTaskTreeProperties) bpy.types.Scene.BIMWorkCalendarProperties = bpy.props.PointerProperty(type=prop.BIMWorkCalendarProperties) + bpy.types.Scene.DatePickerProperties = bpy.props.PointerProperty(type=prop.DatePickerProperties) bpy.types.TOPBAR_MT_file_import.append(menu_func_import) @@ -99,4 +104,5 @@ def unregister(): del bpy.types.Scene.BIMWorkScheduleProperties del bpy.types.Scene.BIMTaskTreeProperties del bpy.types.Scene.BIMWorkCalendarProperties + del bpy.types.Scene.DatePickerProperties bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/helper.py b/src/blenderbim/blenderbim/bim/module/sequence/helper.py index b0fed75c6f..3c6aec4199 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/helper.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/helper.py @@ -1,3 +1,4 @@ +import bpy import math import isodate import datetime @@ -5,8 +6,6 @@ from dateutil import parser from ifcopenshell.api.sequence.data import Data - - def derive_date(ifc_definition_id, attribute_name, date=None, is_earliest=False, is_latest=False): task = Data.tasks[ifc_definition_id] if task["TaskTime"]: @@ -56,3 +55,23 @@ def parse_duration(value): return isodate.parse_duration(value) except: return None + + +def canonicalise_time(time): + if not time: + return "-" + return time.strftime("%d/%m/%y") + + +def get_scene_prop(prop_path): + prop = bpy.context.scene.get(prop_path.split(".")[0]) + for part in prop_path.split(".")[1:]: + if part: + prop = prop.get(part) + return prop + + +def set_scene_prop(prop_path, value): + parent = get_scene_prop(prop_path[: prop_path.rfind(".")]) + prop = prop_path.split(".")[-1] + parent[prop] = value \ No newline at end of file diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 48649199ae..b5aea85e7b 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -3,6 +3,7 @@ import os import bpy import json import time +import calendar import isodate import pystache import webbrowser @@ -13,7 +14,7 @@ import blenderbim.bim.helper import blenderbim.bim.module.sequence.helper as helper from datetime import datetime from datetime import timedelta -from dateutil import parser +from dateutil import parser, relativedelta from blenderbim.bim.ifc import IfcStore from bpy_extras.io_utils import ImportHelper from ifcopenshell.api.sequence.data import Data @@ -1424,3 +1425,89 @@ class VisualiseWorkScheduleDateRange(bpy.types.Operator): "STARTED": round(self.start_frame + (((start - self.start) / self.duration) * self.total_frames)), "COMPLETED": round(self.start_frame + (((finish - self.start) / self.duration) * self.total_frames)), } + + +class BlenderBIM_DatePicker(bpy.types.Operator): + bl_label = "Date Picker" + bl_idname = "bim.datepicker" + display_date: bpy.props.StringProperty(name="Display Date") + selected_date: bpy.props.StringProperty(name="Selected Date") + target_prop: bpy.props.StringProperty(name="Target date prop to set") + + def execute(self, context): + helper.set_scene_prop(self.target_prop, self.selected_date) + return {"FINISHED"} + + def draw(self, context): + self.selected_date = helper.get_scene_prop("DatePickerProperties.selected_date") or helper.canonicalise_time(datetime.now()) + current_date = parser.parse(context.scene.DatePickerProperties.display_date, dayfirst=True, fuzzy=True) + current_month = (current_date.year, current_date.month) + lines = calendar.monthcalendar(*current_month) + month_title, week_titles = calendar.month(*current_month).splitlines()[:2] + + layout = self.layout + row = layout.row() + row.prop(self, "selected_date") + + split = layout.split() + col = split.row() + op = col.operator("bim.redraw_datepicker", icon="TRIA_LEFT", text="") + op.action = "previous" + col = split.row() + col.label(text=month_title.strip()) + col = split.row() + col.alignment = "RIGHT" + op = col.operator("bim.redraw_datepicker", icon="TRIA_RIGHT", text="") + op.action = "next" + + row = layout.row(align=True) + for title in week_titles.split(): + col = row.column(align=True) + col.alignment = "CENTER" + col.label(text=title.strip()) + + for line in lines: + row = layout.row(align=True) + for i in line: + col = row.column(align=True) + if i == 0: + col.label(text=" ") + else: + op = col.operator("bim.datepicker_setdate", text="{:2d}".format(i)) + selected_date = "{}/{}/{}".format(i, current_date.month, current_date.year) + selected_date = parser.parse(selected_date, dayfirst=True, fuzzy=True) + op.selected_date = helper.canonicalise_time(selected_date) + + def invoke(self, context, event): + self.display_date = helper.get_scene_prop(self.target_prop) or helper.canonicalise_time(datetime.now()) + context.scene.DatePickerProperties.display_date = self.display_date + context.scene.DatePickerProperties.selected_date = self.display_date + return context.window_manager.invoke_props_dialog(self) + + +class BlenderBIM_DatePickerSetDate(bpy.types.Operator): + bl_label = "set date" + bl_idname = "bim.datepicker_setdate" + selected_date: bpy.props.StringProperty() + + def invoke(self, context, event): + context.scene.DatePickerProperties.selected_date = self.selected_date + return {"FINISHED"} + + +class BlenderBIM_RedrawDatePicker(bpy.types.Operator): + bl_label = "redraw datepicker window" + bl_idname = "bim.redraw_datepicker" + action: bpy.props.StringProperty() + + def invoke(self, context, event): + current_date = parser.parse(context.scene.DatePickerProperties.display_date, dayfirst=True, fuzzy=True) + + if self.action == "previous": + date_to_set = current_date - relativedelta.relativedelta(months=1) + elif self.action == "next": + date_to_set = current_date + relativedelta.relativedelta(months=1) + + context.scene.DatePickerProperties.display_date = helper.canonicalise_time(date_to_set) + + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index 392c7bcfc2..7d21dc1d04 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -121,7 +121,7 @@ def updateTaskduration(self, context): ifcopenshell.api.run( "sequence.edit_task_time", self.file, - **{"task_time":task_time, "attributes": {"ScheduleDuration": self.duration}}, + **{"task_time": task_time, "attributes": {"ScheduleDuration": self.duration}}, ) Data.load(IfcStore.get_file()) if props.active_task_id == self.ifc_definition_id: @@ -283,3 +283,8 @@ class BIMWorkCalendarProperties(PropertyGroup): ) start_time: StringProperty(name="Start Time") end_time: StringProperty(name="End Time") + + +class DatePickerProperties(PropertyGroup): + display_date: StringProperty() + selected_date: StringProperty() diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index 6cf9a948de..6b0e12bf99 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -2,6 +2,8 @@ import isodate from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.sequence.data import Data +import blenderbim.bim.module.sequence.helper as helper +from datetime import datetime class BIM_PT_work_plans(Panel): @@ -133,8 +135,12 @@ class BIM_PT_work_schedules(Panel): def draw_visualisation_ui(self): row = self.layout.row(align=True) - row.prop(self.props, "visualisation_start", text="", icon="REW") - row.prop(self.props, "visualisation_finish", text="", icon="FF") + target_prop = "BIMWorkScheduleProperties.visualisation_start" + op = row.operator("bim.datepicker", text=helper.get_scene_prop(target_prop), icon="REW") + op.target_prop = target_prop + target_prop = "BIMWorkScheduleProperties.visualisation_finish" + op = row.operator("bim.datepicker", text=helper.get_scene_prop(target_prop), icon="FF") + op.target_prop = target_prop op = row.operator("bim.visualise_work_schedule_date", text="", icon="RESTRICT_RENDER_OFF") op.work_schedule = self.props.active_work_schedule_id op = row.operator("bim.visualise_work_schedule_date_range", text="", icon="OUTLINER_OB_CAMERA")