diff --git a/res/Sketchfab_Logo_exporter.png b/res/Sketchfab_Logo_exporter.png index 0af5d36..4d49795 100644 Binary files a/res/Sketchfab_Logo_exporter.png and b/res/Sketchfab_Logo_exporter.png differ diff --git a/res/Sketchfab_Logo_importer.png b/res/Sketchfab_Logo_importer.png index 7bdae94..6f35e99 100644 Binary files a/res/Sketchfab_Logo_importer.png and b/res/Sketchfab_Logo_importer.png differ diff --git a/res/icon.png b/res/icon.png index 1c15442..8f53913 100644 Binary files a/res/icon.png and b/res/icon.png differ diff --git a/res/modelPlaceholder.png b/res/modelPlaceholder.png index f9be203..172738a 100644 Binary files a/res/modelPlaceholder.png and b/res/modelPlaceholder.png differ diff --git a/sketchfab/api.py b/sketchfab/api.py index 9869d9a..adbd993 100644 --- a/sketchfab/api.py +++ b/sketchfab/api.py @@ -536,4 +536,4 @@ def get_square_crop_resolution(im): self.skfb_api.search_results['current'][uid].preview_path = preview_path self.skfb_api.search_results['current'][uid].thumbnail_path = thumbnail_path if self.skfb_api.request_callback: - self.skfb_api.request_callback() + self.skfb_api.request_callback() diff --git a/sketchfab/config.py b/sketchfab/config.py index 3414116..24ce79e 100644 --- a/sketchfab/config.py +++ b/sketchfab/config.py @@ -107,5 +107,3 @@ def get_temp_path(): ('LIKES', "Likes", ""), ('VIEWS', "Views", ""), ('RECENT', "Recent", "")) - - diff --git a/sketchfab/import_gltf.py b/sketchfab/import_gltf.py index d78d9be..056c326 100644 --- a/sketchfab/import_gltf.py +++ b/sketchfab/import_gltf.py @@ -98,7 +98,7 @@ def run(self, filepath, uid=None): gui.MessageDialog(text=msg, type=c4d.GEMB_OK) self.is_done = True self.progress_callback('Done', 1, 1) - return + return # Import self.import_gltf_textures(gltf) @@ -165,7 +165,7 @@ def switch_handedness_v3(self, v3): return v3 def quat_to_eulerxyz(self, quat): - + x, y, z, w = quat X = math.atan2(2*(w*x+y*z), 1-2*(x*x+y*y)) @@ -221,7 +221,7 @@ def create_c4d_nodes(self, gltf, skins, materials): gltf_node = gltf.data.nodes[i] c4d_object, name = None, None - + if i not in joints: if gltf_node.mesh is not None: c4d_object = self.convert_mesh(gltf, gltf_node.mesh, materials) @@ -237,7 +237,7 @@ def create_c4d_nodes(self, gltf, skins, materials): nodes[i] = c4d_object c4d_object.SetName(name) - # Transforms + # Transforms c4d_object.SetRotationOrder(5) # Local XYZ c4d_object.SetQuaternionRotationMode(1, 0) ignoreTransforms = gltf_node.mesh is not None and gltf_node.skin is not None @@ -291,7 +291,7 @@ def apply_transforms(self, obj, gltf_node): if gltf_node.translation: tr = gltf_node.translation obj.SetRelPos(c4d.Vector(tr[0], tr[1], -tr[2])) - + def convert_primitive(self, prim, gltf, materials): # Helper functions def float2bytes(f): @@ -437,7 +437,7 @@ def parse_tangents(): parse_texcoords(texcoord_index, c4d_mesh) if prim.material is not None: - + mat = materials[prim.material] # Only parse COLORS_0 @@ -478,7 +478,7 @@ def create_c4d_hierarchy(self, gltf, nodes, skins): # Add GlTF root objects to document for node in gltf.data.scenes[0].nodes: c4d.documents.GetActiveDocument().InsertObject(nodes[node]) - + # Do the parenting for n in nodes: if nodes[n] is not None: @@ -520,7 +520,7 @@ def create_c4d_weights(self, gltf, nodes, skins): for i in skins: skin = skins[i] - + for iNode, iMesh in zip(skin.node_idx, skin.mesh_idx): c4d_obj = nodes[iNode] @@ -535,12 +535,12 @@ def create_c4d_weights(self, gltf, nodes, skins): # Create the C4D tag tag = CAWeightTag() - c4d_obj.InsertTag(tag) + c4d_obj.InsertTag(tag) # Accessor data weights = BinaryData.get_data_from_accessor(gltf, prim.attributes["WEIGHTS_0"]) if "WEIGHTS_0" in prim.attributes else [] joints = BinaryData.get_data_from_accessor(gltf, prim.attributes["JOINTS_0"]) if "JOINTS_0" in prim.attributes else [] - + # Unique list of joints used for the skinning local_joints = list(set([j for sub in joints for j in sub])) @@ -554,7 +554,7 @@ def create_c4d_weights(self, gltf, nodes, skins): ind = skin.joints[idx] joint = nodes[ind] gltf_to_c4d[ind] = tag.AddJoint(joint) - + c4d_ibms.append(ibm) c4d_joints.append(joint) @@ -564,8 +564,8 @@ def create_c4d_weights(self, gltf, nodes, skins): weight = weights[vert_idx][influence_idx] if weight > 0: tag.SetWeight( - gltf_to_c4d[ skin.joints[joints[vert_idx][influence_idx] ]], - vert_idx, + gltf_to_c4d[ skin.joints[joints[vert_idx][influence_idx] ]], + vert_idx, weight ) @@ -574,7 +574,7 @@ def create_c4d_weights(self, gltf, nodes, skins): if joint.GetName() not in initial_transforms: initial_transforms[joint.GetName()] = joint.GetMl() - + # Read the IBM if M is not None: c4d_mat = self.gltf_matrix_to_c4d(M) @@ -584,7 +584,7 @@ def create_c4d_weights(self, gltf, nodes, skins): doc = c4d.documents.GetActiveDocument() doc.SetActiveTag(tag, mode=c4d.SELECTION_NEW) c4d.CallButton(tag, c4d.ID_CA_WEIGHT_TAG_SET) - + # Restore the inital position for jt in skin.joints: joint = nodes[jt] @@ -670,12 +670,12 @@ def import_animations(self, gltf, nodes): ranges[i]["start"] += animationStart ranges[i]["end"] += animationStart animationStart += margin + ranges[i]["end"] - ranges[i]["start"] - + # Remember the static positions of the nodes concerned by the keyframed channels for ID in CHANNELS: node_idx = CHANNELS[ID]["node"] path = CHANNELS[ID]["path"] - + c4d_object = nodes[node_idx] CHANNELS[ID]["rest_data"] = None if path == "translation": @@ -692,7 +692,7 @@ def import_animations(self, gltf, nodes): if not len(c["time"][i]): # Empty channel -> we fix it to the rest position pass c["time"][i] = [ranges[i]["start"] + eps, ranges[i]["end"] - eps] - c["data"][i] = [c["rest_data"], c["rest_data"]] + c["data"][i] = [c["rest_data"], c["rest_data"]] c["fixed"][i] = 1 else: @@ -741,7 +741,7 @@ def import_animations(self, gltf, nodes): for axis in [c4d.VECTOR_X, c4d.VECTOR_Y, c4d.VECTOR_Z]: descid = c4d.DescID( - c4d.DescLevel(trackType, c4d.DTYPE_VECTOR,0), + c4d.DescLevel(trackType, c4d.DTYPE_VECTOR,0), c4d.DescLevel(axis, c4d.DTYPE_REAL,0) ) descid = [trackType, axis] @@ -759,7 +759,7 @@ def import_animations(self, gltf, nodes): # Create the keyframes for i,o in zip(in_data, out_data): - + data = None if channel["fixed"][ani]: # Animation data for "fixed" keyframes @@ -786,7 +786,7 @@ def import_animations(self, gltf, nodes): curves[j].InsertKey(key) key.SetInterpolation(curves[j], c4d.CINTERPOLATION_LINEAR) key.SetQuatInterpolation(curves[j], c4d.ROTATIONINTERPOLATION_QUATERNION_SLERP) - + # Update c4d_object.Message(c4d.MSG_UPDATE) @@ -841,7 +841,7 @@ def make_vertex_colors_layer(self, mat, colortag): mat.SetParameter(c4d.MATERIAL_COLOR_SHADER, vtxcolorshader, c4d.DESCFLAGS_SET_NONE) # check if vertex color already enabled: - if not colortag or mat.GetReflectionLayerIndex(0).GetName() == 'Vertex Colors': + if not colortag or (mat.GetReflectionLayerIndex(0) and (mat.GetReflectionLayerIndex(0).GetName() == 'Vertex Colors')): return vtx_color_diffuse = mat.AddReflectionLayer() diff --git a/sketchfab/ui_exporter.py b/sketchfab/ui_exporter.py index bfc3a81..2a4e834 100644 --- a/sketchfab/ui_exporter.py +++ b/sketchfab/ui_exporter.py @@ -63,29 +63,29 @@ FBX20142 = 1026370 export_options = { - c4d.FBXEXPORT_LIGHTS: 0, - c4d.FBXEXPORT_CAMERAS: 0, - c4d.FBXEXPORT_SPLINES: 1, - # Geometry and Materials - c4d.FBXEXPORT_SAVE_NORMALS: 1, - c4d.FBXEXPORT_EMBED_TEXTURES: 1, - c4d.FBXEXPORT_FBX_VERSION: c4d.FBX_EXPORTVERSION_NATIVE, - # cancel all these one - c4d.FBXEXPORT_PLA_TO_VERTEXCACHE: 0, - c4d.FBXEXPORT_SAVE_VERTEX_MAPS_AS_COLORS: 0, - c4d.FBXEXPORT_TRIANGULATE: 0, - c4d.FBXEXPORT_SDS_SUBDIVISION: 1, - c4d.FBXEXPORT_ASCII: 0 + c4d.FBXEXPORT_LIGHTS: 0, + c4d.FBXEXPORT_CAMERAS: 0, + c4d.FBXEXPORT_SPLINES: 1, + # Geometry and Materials + c4d.FBXEXPORT_SAVE_NORMALS: 1, + c4d.FBXEXPORT_EMBED_TEXTURES: 1, + c4d.FBXEXPORT_FBX_VERSION: c4d.FBX_EXPORTVERSION_NATIVE, + # cancel all these one + c4d.FBXEXPORT_PLA_TO_VERTEXCACHE: 0, + c4d.FBXEXPORT_SAVE_VERTEX_MAPS_AS_COLORS: 0, + c4d.FBXEXPORT_TRIANGULATE: 0, + c4d.FBXEXPORT_SDS_SUBDIVISION: 1, + c4d.FBXEXPORT_ASCII: 0 } # Take API changes from R22 into account # https://developers.maxon.net/docs/Cinema4DPythonSDK/html/misc/changelog/changelog_s22.html if c4d.GetC4DVersion() >= 22000: - export_options[c4d.FBXEXPORT_BAKE_MATERIALS] = 0 - export_options[c4d.FBXEXPORT_MATERIALS] = c4d.FBXEXPORT_MATERIALS_PHONGLAMBERT + export_options[c4d.FBXEXPORT_BAKE_MATERIALS] = 0 + export_options[c4d.FBXEXPORT_MATERIALS] = c4d.FBXEXPORT_MATERIALS_PHONGLAMBERT else: - # In S22+, this becomes enforced by FBXEXPORT_EMBED_TEXTURES - export_options[c4d.FBXEXPORT_TEXTURES] = 1 + # In S22+, this becomes enforced by FBXEXPORT_EMBED_TEXTURES + export_options[c4d.FBXEXPORT_TEXTURES] = 1 # Globals g_uploaded = False @@ -95,312 +95,312 @@ class PublishModelThread(c4d.threading.C4DThread): - """Class that publishes 3D model to Sketchfab.com.""" - - def __init__(self, api, data, title, activeDoc, activeDocPath, enable_animation): - c4d.threading.C4DThread.__init__(self) - self.skfb_api = api - self.data = data - self.title = title - self.activeDoc = activeDoc - self.activeDocPath = activeDocPath - self.enable_animation = enable_animation - - def Main(self): - global g_uploaded - global g_error - global model_id - - # Create a temporary directory to export everything in - exportDirectory = tempfile.mkdtemp() - zipName = os.path.join(self.activeDocPath, self.title) - - # Save the current FBX export options - options = self.get_fbxexport_options() - export_options[c4d.FBXEXPORT_TRACKS] = self.enable_animation - export_options[c4d.FBXEXPORT_BAKE_ALL_FRAMES] = self.enable_animation - backup_options = {} - for key in export_options: - if options[key] != export_options[key]: - backup_options[key] = options[key] - options[key] = export_options[key] - - # Export the FBX file - exportFBX = os.path.join(exportDirectory, self.title + '.fbx') - c4d.documents.SaveDocument(self.activeDoc, exportFBX, - c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, FBX20142) - if not os.path.exists(exportFBX): - g_uploaded = False - g_error = "FBX export failed." - c4d.SpecialEventAdd(__exporter_id__) - return False - print("FBX export successful.") - - # Restore the old FBX export options - for key in backup_options: - options[key] = backup_options[key] - - # Zip the temporary directory content - shutil.make_archive(zipName, 'zip', exportDirectory) - - # Do the request - _headers = self.skfb_api.headers - try: - r = requests.post( - Config.SKETCHFAB_MODEL, - data = self.data, - files = {"modelFile": open(zipName + ".zip", 'rb')}, - headers = _headers - ) - except requests.exceptions.RequestException as e: - g_uploaded = False - g_error = e - return - - result = r.json() - - if r.status_code != requests.codes.created: - g_error = "Invalid response from server: %d." % r.status_code - # Was the file too big ? - if "size" in r.text: - print("request:") - print(r.text) - else: - # We'll open the messagebox in CoreMessage - g_uploaded = True - model_id = result["uid"] - - # Clean up - self.cleanup_files([zipName + ".zip", exportDirectory]) - c4d.SpecialEventAdd(__exporter_id__) - - return - - def get_fbxexport_options(self): - ''' Set the good options for fbx export to Sketchfab ''' - # Get the fbx export plugin - fbxplugin = c4d.plugins.FindPlugin(1026370, c4d.PLUGINTYPE_SCENESAVER) - if not fbxplugin: - return - # Access the plugin options - reply = {} - if fbxplugin.Message(c4d.MSG_RETRIEVEPRIVATEDATA, reply): - return reply.get('imexporter') - - def cleanup_files(self, files): - for f in files: - if os.path.exists(f): - try: - if os.path.isdir(f): - shutil.rmtree(f) - else: - os.remove(f) - except Exception: - print("Unable to remove file {0}".format(f)) - + """Class that publishes 3D model to Sketchfab.com.""" + + def __init__(self, api, data, title, activeDoc, activeDocPath, enable_animation): + c4d.threading.C4DThread.__init__(self) + self.skfb_api = api + self.data = data + self.title = title + self.activeDoc = activeDoc + self.activeDocPath = activeDocPath + self.enable_animation = enable_animation + + def Main(self): + global g_uploaded + global g_error + global model_id + + # Create a temporary directory to export everything in + exportDirectory = tempfile.mkdtemp() + zipName = os.path.join(self.activeDocPath, self.title) + + # Save the current FBX export options + options = self.get_fbxexport_options() + export_options[c4d.FBXEXPORT_TRACKS] = self.enable_animation + export_options[c4d.FBXEXPORT_BAKE_ALL_FRAMES] = self.enable_animation + backup_options = {} + for key in export_options: + if options[key] != export_options[key]: + backup_options[key] = options[key] + options[key] = export_options[key] + + # Export the FBX file + exportFBX = os.path.join(exportDirectory, self.title + '.fbx') + c4d.documents.SaveDocument(self.activeDoc, exportFBX, + c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, FBX20142) + if not os.path.exists(exportFBX): + g_uploaded = False + g_error = "FBX export failed." + c4d.SpecialEventAdd(__exporter_id__) + return False + print("FBX export successful.") + + # Restore the old FBX export options + for key in backup_options: + options[key] = backup_options[key] + + # Zip the temporary directory content + shutil.make_archive(zipName, 'zip', exportDirectory) + + # Do the request + _headers = self.skfb_api.headers + try: + r = requests.post( + Config.SKETCHFAB_MODEL, + data = self.data, + files = {"modelFile": open(zipName + ".zip", 'rb')}, + headers = _headers + ) + except requests.exceptions.RequestException as e: + g_uploaded = False + g_error = e + return + + result = r.json() + + if r.status_code != requests.codes.created: + g_error = "Invalid response from server: %d." % r.status_code + # Was the file too big ? + if "size" in r.text: + print("request:") + print(r.text) + else: + # We'll open the messagebox in CoreMessage + g_uploaded = True + model_id = result["uid"] + + # Clean up + self.cleanup_files([zipName + ".zip", exportDirectory]) + c4d.SpecialEventAdd(__exporter_id__) + + return + + def get_fbxexport_options(self): + ''' Set the good options for fbx export to Sketchfab ''' + # Get the fbx export plugin + fbxplugin = c4d.plugins.FindPlugin(1026370, c4d.PLUGINTYPE_SCENESAVER) + if not fbxplugin: + return + # Access the plugin options + reply = {} + if fbxplugin.Message(c4d.MSG_RETRIEVEPRIVATEDATA, reply): + return reply.get('imexporter') + + def cleanup_files(self, files): + for f in files: + if os.path.exists(f): + try: + if os.path.isdir(f): + shutil.rmtree(f) + else: + os.remove(f) + except Exception: + print("Unable to remove file {0}".format(f)) + class MainDialog(ui_login.SketchfabDialogWithLogin): - """Main Dialog Class""" - - def InitValues(self): - super(MainDialog, self).InitValues() - self.userarea_paths_header.set_img(os.path.join(Config.PLUGIN_DIRECTORY, 'res', 'Sketchfab_Logo_exporter.png')) - return True - - def refresh(self): - self.draw_login_ui() - self.draw_upload_button() - - def draw_model_properties(self): - docname = c4d.documents.GetActiveDocument().GetDocumentName() - - self.AddStaticText(id=TXT_MODEL_NAME, flags=c4d.BFH_LEFT, initw=0, inith=0, name="Model name:") - self.AddEditText(id=EDITXT_MODEL_TITLE, flags=c4d.BFH_SCALEFIT, initw=0, inith=0) - self.SetString(EDITXT_MODEL_TITLE, docname) - - self.AddStaticText(id=TXT_DESCRIPTION, flags=c4d.BFH_LEFT | c4d.BFV_TOP, - initw=0, inith=0, name="Description:") - self.AddMultiLineEditText(id=EDITXT_DESCRIPTION, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, - initw=0, inith=100, style=c4d.DR_MULTILINE_WORDWRAP) - - self.AddStaticText(id=TXT_TAGS, flags=c4d.BFH_LEFT, initw=0, inith=0, name="Tags: cinema4d ") - self.AddEditText(id=EDITXT_TAGS, flags= c4d.BFH_RIGHT | c4d.BFH_SCALEFIT, initw=0, inith=0) - - self.AddCheckbox(id=CHK_ANIMATION, flags=c4d.BFH_LEFT, - initw=0, inith=0, name="Enable animation") - - def draw_private_options(self): - self.LayoutFlushGroup(GROUP_FIVE) - self.AddCheckbox(id=CHK_PRIVATE, flags=c4d.BFH_SCALEFIT | c4d.BFH_LEFT, - initw=0, inith=0, name="Private Model (Pro User Only)") - self.AddStaticText(id=0, flags=c4d.BFH_LEFT, - initw=0, inith=0, name="Password (optional): ") - self.AddEditText(id=EDITXT_PASSWORD, flags=c4d.BFH_SCALEFIT, - initw=0, inith=0, editflags=c4d.EDITTEXT_PASSWORD) - self.AddCheckbox(id=CHK_PUBLISHDRAFT, flags=c4d.BFH_LEFT, - initw=0, inith=0, name="Publish as a draft (not visible to public immediately)") - self.LayoutChanged(GROUP_FIVE) - - def draw_upload_button(self): - self.LayoutFlushGroup(GROUP_SIX) - self.AddStaticText(id=0, flags=c4d.BFH_LEFT | c4d.BFH_SCALEFIT, initw=0, inith=0, name=g_upload_message) - self.AddButton(id=BTN_PUBLISH, flags=c4d.BFH_CENTER | c4d.BFV_CENTER, initw=200, inith=38, name="Upload") - self.Enable(BTN_PUBLISH, self.skfb_api.is_user_logged()) - self.LayoutChanged(GROUP_SIX) - - def CreateLayout(self): - - # Title - self.SetTitle(__exporter_title__) - - # Header and inheritance - super(MainDialog, self).CreateLayout() - - self.skfb_api.login_callback = self.refresh - - # Model properties - self.GroupBegin(id=GROUP_TWO, - flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, - cols=2, - rows=1) - self.GroupSpace(40, 10) - self.GroupBorderSpace(6, 6, 6, 6) - self.draw_model_properties() - self.GroupEnd() - - self.AddSeparatorH(inith=0, flags=c4d.BFH_FIT) - - # Private options - self.GroupBegin(id=GROUP_FIVE, - flags=c4d.BFH_SCALEFIT | c4d.BFV_BOTTOM, - cols=3, - rows=1) - self.GroupSpace(4, 4) - self.GroupBorderSpace(6, 6, 6, 2) - self.draw_private_options() - self.GroupEnd() - - # Upload button - self.GroupBegin(id=GROUP_SIX, - flags=c4d.BFH_SCALEFIT | c4d.BFV_CENTER | c4d.BFH_CENTER, - cols=1, - rows=1) - self.GroupSpace(4, 4) - self.GroupBorderSpace(6, 2, 6, 6) - self.draw_upload_button() - self.GroupEnd() - - #self.GroupEnd() - - self.draw_footer() - - return True - - def CoreMessage(self, id, msg): - """Override this function if you want to react - to C4D core messages. The original message is stored in msg. - """ - if id == __exporter_id__: - c4d.StatusSetBar(100) - - if g_uploaded: - result = gui.MessageDialog("Your model was uploaded to Sketchfab.com.\nClick OK to open it in your browser.", c4d.GEMB_OKCANCEL) - if result == c4d.GEMB_R_OK: - webbrowser.open(Config.SKETCHFAB_URL + '/models/' + model_id) - else: - print("Unable to upload model to Sketchfab.com. Reason: {0}".format(g_error)) - gui.MessageDialog("Unable to upload model to Sketchfab.com. Reason: {0}".format(g_error), c4d.GEMB_OK) - - self.draw_upload_button() - self.Enable(BTN_PUBLISH, True) - self.SetTitle("Upload status") - c4d.StatusClear() - - return True - - def Command(self, id, msg): - - self.common_commands(id, msg) - - if id == BTN_THUMB_SRC_PATH: - selected = c4d.storage.LoadDialog(type=c4d.FILESELECTTYPE_ANYTHING) - if not selected: - return False - else: - self.SetString(EDITXT_THUMB_SRC_PATH, selected) - - if id == CHK_PRIVATE: - if self.GetBool(CHK_PRIVATE): - self.Enable(EDITXT_PASSWORD, True) - else: - self.draw_private_options() - self.Enable(EDITXT_PASSWORD, False) - - if id == BTN_PUBLISH: - c4d.StatusSetBar(50) - g_upload_message = "Uploading..." - self.draw_upload_button() - - activeDoc = c4d.documents.GetActiveDocument() - activeDocPath = activeDoc.GetDocumentPath() - if not os.path.exists(activeDocPath): - path = c4d.storage.SaveDialog(type=c4d.FILESELECTTYPE_ANYTHING, title="Please save your .c4d scene", force_suffix="c4d") - result = c4d.documents.SaveDocument(activeDoc, path, c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_C4DEXPORT) - c4d.documents.LoadFile(path) - if not result: - gui.MessageDialog("Please save your .c4d scene first.", c4d.GEMB_OK) - c4d.StatusClear() - return False - - # Set document data with newly saved document - activeDoc = c4d.documents.GetActiveDocument() - activeDocPath = activeDoc.GetDocumentPath() - - self.Enable(BTN_PUBLISH, False) - self.SetTitle("{0} uploading model...".format(__exporter_title__)) - - title = self.GetString(EDITXT_MODEL_TITLE) - description = self.GetString(EDITXT_DESCRIPTION) - tags = self.GetString(EDITXT_TAGS) - private = self.GetBool(CHK_PRIVATE) - password = self.GetString(EDITXT_PASSWORD) - enable_animation = self.GetBool(CHK_ANIMATION) - auto_publish = not(self.GetBool(CHK_PUBLISHDRAFT)) - - # Error messages - if len(title) == 0 or len(title) > 48 or len(description) > 1024: - error_message = "" - if len(title) == 0: - error_message = "Please enter a title for your model" - if len(title) > 48: - error_message = "The model title must be less than 48 characters long" - if len(description) > 1024: - error_message = "The description must be less than 1024 characters long" - gui.MessageDialog(error_message, c4d.GEMB_OK) - self.Enable(BTN_PUBLISH, True) - self.SetTitle(__exporter_title__) - c4d.StatusClear() - return False - - # populate data - data = { - "source": "cinema4d", - "tags": "cinema4d ", - "title": title - } - data['isPublished'] = auto_publish - if len(description) != 0: - data['description'] = description - if len(tags) != 0: - data['tags'] += " ".join(tags.split(" ")[:41]).strip() - if private: - data['private'] = private - if private and len(password) != 0: - data['password'] = password - - # Start Multithread operations - self.publish = PublishModelThread(self.skfb_api, data, title, activeDoc, activeDocPath, enable_animation) - self.publish.Start() - self.publish.Wait(True) - - return True \ No newline at end of file + """Main Dialog Class""" + + def InitValues(self): + super(MainDialog, self).InitValues() + self.userarea_paths_header.set_img(os.path.join(Config.PLUGIN_DIRECTORY, 'res', 'Sketchfab_Logo_exporter.png')) + return True + + def refresh(self): + self.draw_login_ui() + self.draw_upload_button() + + def draw_model_properties(self): + docname = c4d.documents.GetActiveDocument().GetDocumentName() + + self.AddStaticText(id=TXT_MODEL_NAME, flags=c4d.BFH_LEFT, initw=0, inith=0, name="Model name:") + self.AddEditText(id=EDITXT_MODEL_TITLE, flags=c4d.BFH_SCALEFIT, initw=0, inith=0) + self.SetString(EDITXT_MODEL_TITLE, docname) + + self.AddStaticText(id=TXT_DESCRIPTION, flags=c4d.BFH_LEFT | c4d.BFV_TOP, + initw=0, inith=0, name="Description:") + self.AddMultiLineEditText(id=EDITXT_DESCRIPTION, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, + initw=0, inith=100, style=c4d.DR_MULTILINE_WORDWRAP) + + self.AddStaticText(id=TXT_TAGS, flags=c4d.BFH_LEFT, initw=0, inith=0, name="Tags: cinema4d ") + self.AddEditText(id=EDITXT_TAGS, flags= c4d.BFH_RIGHT | c4d.BFH_SCALEFIT, initw=0, inith=0) + + self.AddCheckbox(id=CHK_ANIMATION, flags=c4d.BFH_LEFT, + initw=0, inith=0, name="Enable animation") + + def draw_private_options(self): + self.LayoutFlushGroup(GROUP_FIVE) + self.AddCheckbox(id=CHK_PRIVATE, flags=c4d.BFH_SCALEFIT | c4d.BFH_LEFT, + initw=0, inith=0, name="Private Model (Pro Only)") + self.AddStaticText(id=0, flags=c4d.BFH_LEFT, + initw=0, inith=0, name="Password (optional): ") + self.AddEditText(id=EDITXT_PASSWORD, flags=c4d.BFH_SCALEFIT, + initw=0, inith=0, editflags=c4d.EDITTEXT_PASSWORD) + self.AddCheckbox(id=CHK_PUBLISHDRAFT, flags=c4d.BFH_LEFT, + initw=0, inith=0, name="Upload as a draft (not visible to public immediately)") + self.LayoutChanged(GROUP_FIVE) + + def draw_upload_button(self): + self.LayoutFlushGroup(GROUP_SIX) + self.AddStaticText(id=0, flags=c4d.BFH_LEFT | c4d.BFH_SCALEFIT, initw=0, inith=0, name=g_upload_message) + self.AddButton(id=BTN_PUBLISH, flags=c4d.BFH_CENTER | c4d.BFV_CENTER, initw=200, inith=38, name="Upload") + self.Enable(BTN_PUBLISH, self.skfb_api.is_user_logged()) + self.LayoutChanged(GROUP_SIX) + + def CreateLayout(self): + + # Title + self.SetTitle(__exporter_title__) + + # Header and inheritance + super(MainDialog, self).CreateLayout() + + self.skfb_api.login_callback = self.refresh + + # Model properties + self.GroupBegin(id=GROUP_TWO, + flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, + cols=2, + rows=1) + self.GroupSpace(40, 10) + self.GroupBorderSpace(6, 6, 6, 6) + self.draw_model_properties() + self.GroupEnd() + + self.AddSeparatorH(initw=0, flags=c4d.BFH_FIT) + + # Private options + self.GroupBegin(id=GROUP_FIVE, + flags=c4d.BFH_SCALEFIT | c4d.BFV_BOTTOM, + cols=3, + rows=1) + self.GroupSpace(4, 4) + self.GroupBorderSpace(6, 6, 6, 2) + self.draw_private_options() + self.GroupEnd() + + # Upload button + self.GroupBegin(id=GROUP_SIX, + flags=c4d.BFH_SCALEFIT | c4d.BFV_CENTER | c4d.BFH_CENTER, + cols=1, + rows=1) + self.GroupSpace(4, 4) + self.GroupBorderSpace(6, 2, 6, 6) + self.draw_upload_button() + self.GroupEnd() + + #self.GroupEnd() + + self.draw_footer() + + return True + + def CoreMessage(self, id, msg): + """Override this function if you want to react + to C4D core messages. The original message is stored in msg. + """ + if id == __exporter_id__: + c4d.StatusSetBar(100) + + if g_uploaded: + result = gui.MessageDialog("Your model was uploaded to Sketchfab.com.\nClick OK to open it in your browser.", c4d.GEMB_OKCANCEL) + if result == c4d.GEMB_R_OK: + webbrowser.open(Config.SKETCHFAB_URL + '/models/' + model_id) + else: + print("Unable to upload model to Sketchfab.com. Reason: {0}".format(g_error)) + gui.MessageDialog("Unable to upload model to Sketchfab.com. Reason: {0}".format(g_error), c4d.GEMB_OK) + + self.draw_upload_button() + self.Enable(BTN_PUBLISH, True) + self.SetTitle("Upload status") + c4d.StatusClear() + + return True + + def Command(self, id, msg): + + self.common_commands(id, msg) + + if id == BTN_THUMB_SRC_PATH: + selected = c4d.storage.LoadDialog(type=c4d.FILESELECTTYPE_ANYTHING) + if not selected: + return False + else: + self.SetString(EDITXT_THUMB_SRC_PATH, selected) + + if id == CHK_PRIVATE: + if self.GetBool(CHK_PRIVATE): + self.Enable(EDITXT_PASSWORD, True) + else: + self.draw_private_options() + self.Enable(EDITXT_PASSWORD, False) + + if id == BTN_PUBLISH: + c4d.StatusSetBar(50) + g_upload_message = "Uploading..." + self.draw_upload_button() + + activeDoc = c4d.documents.GetActiveDocument() + activeDocPath = activeDoc.GetDocumentPath() + if not os.path.exists(activeDocPath): + path = c4d.storage.SaveDialog(type=c4d.FILESELECTTYPE_ANYTHING, title="Please save your .c4d scene", force_suffix="c4d") + result = c4d.documents.SaveDocument(activeDoc, path, c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_C4DEXPORT) + c4d.documents.LoadFile(path) + if not result: + gui.MessageDialog("Please save your .c4d scene first.", c4d.GEMB_OK) + c4d.StatusClear() + return False + + # Set document data with newly saved document + activeDoc = c4d.documents.GetActiveDocument() + activeDocPath = activeDoc.GetDocumentPath() + + self.Enable(BTN_PUBLISH, False) + self.SetTitle("{0} uploading model...".format(__exporter_title__)) + + title = self.GetString(EDITXT_MODEL_TITLE) + description = self.GetString(EDITXT_DESCRIPTION) + tags = self.GetString(EDITXT_TAGS) + private = self.GetBool(CHK_PRIVATE) + password = self.GetString(EDITXT_PASSWORD) + enable_animation = self.GetBool(CHK_ANIMATION) + auto_publish = not(self.GetBool(CHK_PUBLISHDRAFT)) + + # Error messages + if len(title) == 0 or len(title) > 48 or len(description) > 1024: + error_message = "" + if len(title) == 0: + error_message = "Please enter a title for your model" + if len(title) > 48: + error_message = "The model title must be less than 48 characters long" + if len(description) > 1024: + error_message = "The description must be less than 1024 characters long" + gui.MessageDialog(error_message, c4d.GEMB_OK) + self.Enable(BTN_PUBLISH, True) + self.SetTitle(__exporter_title__) + c4d.StatusClear() + return False + + # populate data + data = { + "source": "cinema4d", + "tags": "cinema4d ", + "title": title + } + data['isPublished'] = auto_publish + if len(description) != 0: + data['description'] = description + if len(tags) != 0: + data['tags'] += " ".join(tags.split(" ")[:41]).strip() + if private: + data['private'] = private + if private and len(password) != 0: + data['password'] = password + + # Start Multithread operations + self.publish = PublishModelThread(self.skfb_api, data, title, activeDoc, activeDocPath, enable_animation) + self.publish.Start() + self.publish.Wait(True) + + return True \ No newline at end of file diff --git a/sketchfab/ui_importer.py b/sketchfab/ui_importer.py index 56c8576..ce1f299 100644 --- a/sketchfab/ui_importer.py +++ b/sketchfab/ui_importer.py @@ -59,7 +59,7 @@ LB_SEARCH_QUERY = 2200 LB_FACE_COUNT = 2202 LB_SORT_BY = 2203 -LB_RESULT_NAME_START = 2209 +LB_RESULT_NAME_START = 2209 # Model Window LB_MODEL_NAME = 2210 LB_MODEL_AUTHOR = 2211 @@ -100,532 +100,532 @@ class SkfbPluginDialog(ui_login.SketchfabDialogWithLogin): - redraw_results = False - - def InitValues(self): - super(SkfbPluginDialog, self).InitValues() - self.model_dialog = None - self.SetBool(CHK_IS_STAFFPICK, True) - self.userarea_paths_header.set_img(os.path.join(Config.PLUGIN_DIRECTORY, 'res', 'Sketchfab_Logo_importer.png')) - return True - - def refresh(self): - self.redraw_login = True - self.redraw_results = True - - def refresh_login_ui(self): - self.draw_login_ui() - self.draw_search_ui() - #if self.model_dialog: - # self.model_dialog.refresh_window() - - def Timer(self, msg): - if self.redraw_results: - self.resultGroupWillRedraw() - - if self.redraw_login: - self.draw_login_ui() - self.redraw_login = False - - def CreateLayout(self): - - # Title - self.SetTitle(__importer_title__) - - # Main UI - super(SkfbPluginDialog, self).CreateLayout() - self.skfb_api.request_callback = self.refresh - self.skfb_api.login_callback = self.refresh_login_ui - - # Toggle CHK_My8models - if self.is_initialized: - self.Enable(CHK_MY_MODELS, self.skfb_api.is_user_logged()) - - self.GroupBegin(id=GROUP_QUERY, - flags=c4d.BFH_CENTER | c4d.BFV_FIT, - cols=4, - rows=1, - title="Search", - groupflags=c4d.BORDER_NONE) - - self.draw_search_ui() - - self.GroupEnd() - - self.GroupBegin(id=GROUP_FILTERS, - flags=c4d.BFH_SCALEFIT | c4d.BFV_FIT, - cols=9, - rows=1, - title="Search", - groupflags=c4d.BORDER_NONE | c4d.BFV_BORDERGROUP_FOLD_OPEN) - - self.GroupBorderSpace(6, 6, 6, 6) - - self.draw_filters_ui() - - self.GroupEnd() - - self.AddSeparatorH(inith=0, flags=c4d.BFH_FIT) - - self.GroupBegin(GROUP_PREVNEXT, c4d.BFH_FIT | c4d.BFV_CENTER, 3, 1, "Prevnext") - self.GroupBorderSpace(4, 2, 4, 2) - self.draw_prev_next() - self.GroupEnd() - - - warning = self.needs_warning() - if self.is_initialized and warning: - self.draw_warning_ui(warning) - else: - self.ScrollGroupBegin(GROUP_RESULTS_SCROLL, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_VERT | c4d.SCROLLGROUP_HORIZ | c4d.SCROLLGROUP_AUTOHORIZ | c4d.SCROLLGROUP_AUTOVERT, 200, 200) - self.GroupBegin(GROUP_RESULTS, c4d.BFH_SCALEFIT | c4d.BFV_TOP, 6, 4, "Results", c4d.BFV_GRIDGROUP_EQUALCOLS | c4d.BFV_GRIDGROUP_EQUALROWS) - self.GroupBorderSpace(6, 2, 6, 2) - self.draw_results_ui() - self.GroupEnd() - self.GroupEnd() - - self.draw_footer() - - self.trigger_default_search() - - return True - - def draw_search_ui(self): - self.LayoutFlushGroup(GROUP_QUERY) - - self.AddStaticText(id=LB_SEARCH_QUERY, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=90, inith=TEXT_WIDGET_HEIGHT, name=" Search: ") - self.AddComboBox(id=CBOX_SEARCH_DOMAIN, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=150, inith=TEXT_WIDGET_HEIGHT) - for index, category in enumerate(Config.SKETCHFAB_SEARCH_DOMAINS): - self.AddChild(id=CBOX_SEARCH_DOMAIN, subid=CBOX_SEARCH_DOMAIN_ELT + index, child=category[2]) - self.SetInt32(CBOX_SEARCH_DOMAIN, CBOX_SEARCH_DOMAIN_ELT) - self.AddEditText(id=EDITXT_SEARCH_QUERY, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=500, inith=TEXT_WIDGET_HEIGHT) - self.AddButton(id=BTN_SEARCH, flags=c4d.BFH_RIGHT | c4d.BFV_BOTTOM, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Search") - self.Enable(CBOX_SEARCH_DOMAIN, int(self.skfb_api.is_user_logged())) - - self.LayoutChanged(GROUP_QUERY) - - def refresh_search_ui(self): - self.draw_search_ui() - - def draw_filters_ui(self): - self.LayoutFlushGroup(GROUP_FILTERS) - - # Categories - self.AddComboBox(id=CBOX_CATEGORY, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=250, inith=TEXT_WIDGET_HEIGHT) - for index, category in enumerate(Config.SKETCHFAB_CATEGORIES): - self.AddChild(id=CBOX_CATEGORY, subid=CBOX_CATEGORY_ELT + index, child=category[2]) - self.SetInt32(CBOX_CATEGORY, CBOX_CATEGORY_ELT) - - self.AddCheckbox(id=CHK_IS_PBR, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=80, inith=TEXT_WIDGET_HEIGHT, name='PBR') - self.SetBool(CHK_IS_PBR, False) - self.AddCheckbox(id=CHK_IS_STAFFPICK, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=120, inith=TEXT_WIDGET_HEIGHT, name='Staffpick') - self.SetBool(CHK_IS_STAFFPICK, False) - self.AddCheckbox(id=CHK_IS_ANIMATED, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=150, inith=TEXT_WIDGET_HEIGHT, name='Animated') - self.SetBool(CHK_IS_ANIMATED, False) - - self.AddStaticText(id=LB_FACE_COUNT, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=90, inith=TEXT_WIDGET_HEIGHT, name="Face count: ") - self.AddComboBox(id=CBOX_FACE_COUNT, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=120, inith=TEXT_WIDGET_HEIGHT) - for index, face_count in enumerate(Config.SKETCHFAB_FACECOUNT): - self.AddChild(id=CBOX_FACE_COUNT, subid=CBOX_FACE_COUNT_ELT + index, child=face_count[1]) - self.SetInt32(CBOX_FACE_COUNT, CBOX_FACE_COUNT_ELT) - - self.AddSeparatorV(50.0, flags=c4d.BFH_SCALE) - self.AddStaticText(id=LB_FACE_COUNT, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=60, inith=TEXT_WIDGET_HEIGHT, name="Sort by: ") - self.AddComboBox(id=CBOX_SORT_BY, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=90, inith=TEXT_WIDGET_HEIGHT) - for index, sort_by in enumerate(Config.SKETCHFAB_SORT_BY): - self.AddChild(id=CBOX_SORT_BY, subid=CBOX_SORT_BY_ELT + index, child=sort_by[1]) - self.SetInt32(CBOX_SORT_BY, CBOX_SORT_BY_ELT + 3) - - self.LayoutChanged(GROUP_FILTERS) - - def refresh_filters_ui(self): - self.draw_filters_ui() - - def result_valid(self): - if 'current' not in self.skfb_api.search_results: - return False - - return True - - def needs_warning(self): - """ - returns 0 if no warning is needed, the warning code otherwise: - 1 - Normal search, no results - 2 - Own models but not pro - 3 - No Store purchases - """ - - if not self.result_valid(): - return 0 - - search_domain = self.GetInt32(CBOX_SEARCH_DOMAIN) - CBOX_SEARCH_DOMAIN_ELT - if search_domain == 1 and not self.skfb_api.is_user_pro: - return 2 - - n_results = len(self.skfb_api.search_results['current']) - if n_results == 0: - if search_domain in [0,1]: - return 1 - else: - return 3 - else: - return 0 - - def resultGroupWillRedraw(self): - self.draw_prev_next() - self.draw_results_ui() - - def draw_results_ui(self): - self.LayoutFlushGroup(GROUP_RESULTS) - if not self.result_valid(): - return - - # Warning message - warning = self.needs_warning() - if warning: - self.draw_warning_ui(warning) - - for index, skfb_model in enumerate(self.skfb_api.search_results['current'].values()): - image_container = c4d.BaseContainer() # Create a new container to store the image we will load for the button later on - self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFH_SCALEFIT, 1, 2, "Bitmap Example", 0) - filenameid = resultContainerIDStart + index - image_container.SetBool(c4d.BITMAPBUTTON_BUTTON, True) - image_container.SetBool(c4d.BITMAPBUTTON_NOBORDERDRAW, True) - image_container.SetFilename(filenameid, str(skfb_model.thumbnail_path)) - - self.mybutton = self.AddCustomGui(filenameid, c4d.CUSTOMGUI_BITMAPBUTTON, "Sketchfab model button", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 10, 10, image_container) - self.mybutton.SetLayoutMode(c4d.LAYOUTMODE_MINIMIZED) - self.mybutton.SetImage(str(skfb_model.thumbnail_path), False) - self.mybutton.SetToggleState(True) - - nameid = LB_RESULT_NAME_START + index - modelname = textwrap.wrap(skfb_model.title, 18)[0] # dumbly truncate names for the UI - - self.AddStaticText(id=nameid, - flags=c4d.BFV_BOTTOM | c4d.BFH_CENTER, - initw=192, - inith=16, - name=u'{}'.format(modelname), - borderstyle=c4d.BORDER_WITH_TITLE) - - self.GroupEnd() - - self.LayoutChanged(GROUP_RESULTS) - - self.Enable(BTN_PREV_PAGE, self.skfb_api.has_prev()) - self.Enable(BTN_NEXT_PAGE, self.skfb_api.has_next()) - - self.redraw_results = False - - def draw_prev_next(self): - self.LayoutFlushGroup(GROUP_PREVNEXT) - - if self.result_valid() and len(self.skfb_api.search_results['current']) > 0: - self.AddButton(id=BTN_PREV_PAGE, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Previous") - self.AddSeparatorV(0.0, flags=c4d.BFH_SCALE) - self.AddButton(id=BTN_NEXT_PAGE, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Next") - self.Enable(BTN_PREV_PAGE, self.skfb_api.has_prev()) - self.Enable(BTN_NEXT_PAGE, self.skfb_api.has_next()) - - self.LayoutChanged(GROUP_PREVNEXT) - - def trigger_default_search(self): - self.skfb_api.search(Config.DEFAULT_SEARCH) - - def trigger_search(self): - search_domain_str = Config.SKETCHFAB_SEARCH_DOMAINS[self.GetInt32(CBOX_SEARCH_DOMAIN) - CBOX_SEARCH_DOMAIN_ELT][0] - final_query = Config.SKETCHFAB_API + '/v3' + search_domain_str - - if self.GetString(EDITXT_SEARCH_QUERY): - final_query = final_query + '&q={}'.format(self.GetString(EDITXT_SEARCH_QUERY)) - - if self.GetBool(CHK_IS_ANIMATED): - final_query = final_query + '&animated=true' - - if self.GetBool(CHK_IS_STAFFPICK): - final_query = final_query + '&staffpicked=true' - - if self.GetInt32(CBOX_SORT_BY) == CBOX_SORT_BY_ELT + 1: - final_query = final_query + '&sort_by=-likeCount' - elif self.GetInt32(CBOX_SORT_BY) == CBOX_SORT_BY_ELT + 2: - final_query = final_query + '&sort_by=-viewCount' - elif self.GetInt32(CBOX_SORT_BY) == CBOX_SORT_BY_ELT + 3: - final_query = final_query + '&sort_by=-publishedAt' - - if self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 1: - final_query = final_query + '&min_face_count=1&max_face_count=10000' - elif self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 2: - final_query = final_query + '&min_face_count=10000&max_face_count=50000' - elif self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 3: - final_query = final_query + '&min_face_count=50000&max_face_count=100000' - elif self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 4: - final_query = final_query + "&min_face_count=100000&max_face_count=250000" - elif self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 5: - final_query = final_query + "&min_face_count=250000" - else: - final_query = final_query + "&min_face_count=1" - - if self.GetInt32(CBOX_CATEGORY) != CBOX_CATEGORY_ELT: - final_query = final_query + '&categories={}'.format(Config.SKETCHFAB_CATEGORIES[self.GetInt32(CBOX_CATEGORY) - CBOX_CATEGORY_ELT][0]) - - if self.GetBool(CHK_IS_PBR): - final_query = final_query + '&pbr_type=true' - - self.skfb_api.search(final_query) - - def reset_filters(self, is_own_model): - self.SetBool(CHK_IS_STAFFPICK, not is_own_model) - self.SetBool(CHK_IS_ANIMATED, False) - self.SetBool(CHK_IS_PBR, False) - self.SetInt32(CBOX_CATEGORY, CBOX_CATEGORY_ELT) - self.SetInt32(CBOX_FACE_COUNT, CBOX_FACE_COUNT_ELT) - self.SetInt32(CBOX_SORT_BY, CBOX_SORT_BY_ELT + 1) - - def Command(self, id, msg): - trigger_search = False - - self.common_commands(id, msg) - - if id == BTN_PREV_PAGE: - self.skfb_api.search_prev() - - if id == BTN_NEXT_PAGE: - self.skfb_api.search_next() + redraw_results = False - bc = c4d.BaseContainer() - if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.KEY_ENTER, bc): - if bc[c4d.BFM_INPUT_VALUE] == 1: - if self.IsActive(EDITXT_SEARCH_QUERY): - trigger_search = True + def InitValues(self): + super(SkfbPluginDialog, self).InitValues() + self.model_dialog = None + self.SetBool(CHK_IS_STAFFPICK, True) + self.userarea_paths_header.set_img(os.path.join(Config.PLUGIN_DIRECTORY, 'res', 'Sketchfab_Logo_importer.png')) + return True - if id in [ - BTN_SEARCH, - CBOX_SEARCH_DOMAIN, - CBOX_CATEGORY, - CBOX_SORT_BY, - CBOX_FACE_COUNT, - CHK_IS_PBR, - CHK_IS_ANIMATED, - CHK_IS_STAFFPICK]: - trigger_search = True + def refresh(self): + self.redraw_login = True + self.redraw_results = True - if id == CBOX_SEARCH_DOMAIN: - self.Enable(GROUP_FILTERS, (self.GetInt32(CBOX_SEARCH_DOMAIN) - CBOX_SEARCH_DOMAIN_ELT) != 2) - self.refresh_filters_ui() - - if trigger_search: - self.trigger_search() - - for i in range(24): - if id == resultContainerIDStart + i: - if self.model_dialog: - self.model_dialog.Close() - - model = list(self.skfb_api.search_results['current'].values())[i] - self.skfb_api.request_model_info(model.uid) - self.model_dialog = SkfbModelDialog() - self.model_dialog.SetModelInfo(model, self.skfb_api) - self.model_dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, defaultw=450, defaulth=300, xpos=-1, ypos=-1) - - return True + def refresh_login_ui(self): + self.draw_login_ui() + self.draw_search_ui() + #if self.model_dialog: + # self.model_dialog.refresh_window() + + def Timer(self, msg): + if self.redraw_results: + self.resultGroupWillRedraw() + + if self.redraw_login: + self.draw_login_ui() + self.redraw_login = False + + def CreateLayout(self): + + # Title + self.SetTitle(__importer_title__) + + # Main UI + super(SkfbPluginDialog, self).CreateLayout() + self.skfb_api.request_callback = self.refresh + self.skfb_api.login_callback = self.refresh_login_ui + + # Toggle CHK_My8models + if self.is_initialized: + self.Enable(CHK_MY_MODELS, self.skfb_api.is_user_logged()) + + self.GroupBegin(id=GROUP_QUERY, + flags=c4d.BFH_CENTER | c4d.BFV_FIT, + cols=4, + rows=1, + title="Search", + groupflags=c4d.BORDER_NONE) + + self.draw_search_ui() + + self.GroupEnd() + + self.GroupBegin(id=GROUP_FILTERS, + flags=c4d.BFH_SCALEFIT | c4d.BFV_FIT, + cols=9, + rows=1, + title="Search", + groupflags=c4d.BORDER_NONE | c4d.BFV_BORDERGROUP_FOLD_OPEN) + + self.GroupBorderSpace(6, 6, 6, 6) + + self.draw_filters_ui() + + self.GroupEnd() + + self.AddSeparatorH(initw=0, flags=c4d.BFH_FIT) + + self.GroupBegin(GROUP_PREVNEXT, c4d.BFH_FIT | c4d.BFV_CENTER, 3, 1, "Prevnext") + self.GroupBorderSpace(4, 2, 4, 2) + self.draw_prev_next() + self.GroupEnd() + + + warning = self.needs_warning() + if self.is_initialized and warning: + self.draw_warning_ui(warning) + else: + self.ScrollGroupBegin(GROUP_RESULTS_SCROLL, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_VERT | c4d.SCROLLGROUP_HORIZ | c4d.SCROLLGROUP_AUTOHORIZ | c4d.SCROLLGROUP_AUTOVERT, 200, 200) + self.GroupBegin(GROUP_RESULTS, c4d.BFH_SCALEFIT | c4d.BFV_TOP, 6, 4, "Results", c4d.BFV_GRIDGROUP_EQUALCOLS | c4d.BFV_GRIDGROUP_EQUALROWS) + self.GroupBorderSpace(6, 2, 6, 2) + self.draw_results_ui() + self.GroupEnd() + self.GroupEnd() + + self.draw_footer() + + self.trigger_default_search() + + return True + + def draw_search_ui(self): + self.LayoutFlushGroup(GROUP_QUERY) + + self.AddStaticText(id=LB_SEARCH_QUERY, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=90, inith=TEXT_WIDGET_HEIGHT, name=" Search: ") + self.AddComboBox(id=CBOX_SEARCH_DOMAIN, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=150, inith=TEXT_WIDGET_HEIGHT) + for index, category in enumerate(Config.SKETCHFAB_SEARCH_DOMAINS): + self.AddChild(id=CBOX_SEARCH_DOMAIN, subid=CBOX_SEARCH_DOMAIN_ELT + index, child=category[2]) + self.SetInt32(CBOX_SEARCH_DOMAIN, CBOX_SEARCH_DOMAIN_ELT) + self.AddEditText(id=EDITXT_SEARCH_QUERY, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=500, inith=TEXT_WIDGET_HEIGHT) + self.AddButton(id=BTN_SEARCH, flags=c4d.BFH_RIGHT | c4d.BFV_BOTTOM, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Search") + self.Enable(CBOX_SEARCH_DOMAIN, int(self.skfb_api.is_user_logged())) + + self.LayoutChanged(GROUP_QUERY) + + def refresh_search_ui(self): + self.draw_search_ui() + + def draw_filters_ui(self): + self.LayoutFlushGroup(GROUP_FILTERS) + + # Categories + self.AddComboBox(id=CBOX_CATEGORY, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=250, inith=TEXT_WIDGET_HEIGHT) + for index, category in enumerate(Config.SKETCHFAB_CATEGORIES): + self.AddChild(id=CBOX_CATEGORY, subid=CBOX_CATEGORY_ELT + index, child=category[2]) + self.SetInt32(CBOX_CATEGORY, CBOX_CATEGORY_ELT) + + self.AddCheckbox(id=CHK_IS_PBR, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=80, inith=TEXT_WIDGET_HEIGHT, name='PBR') + self.SetBool(CHK_IS_PBR, False) + self.AddCheckbox(id=CHK_IS_STAFFPICK, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=120, inith=TEXT_WIDGET_HEIGHT, name='Staffpick') + self.SetBool(CHK_IS_STAFFPICK, False) + self.AddCheckbox(id=CHK_IS_ANIMATED, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=150, inith=TEXT_WIDGET_HEIGHT, name='Animated') + self.SetBool(CHK_IS_ANIMATED, False) + + self.AddStaticText(id=LB_FACE_COUNT, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=90, inith=TEXT_WIDGET_HEIGHT, name="Face count: ") + self.AddComboBox(id=CBOX_FACE_COUNT, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=120, inith=TEXT_WIDGET_HEIGHT) + for index, face_count in enumerate(Config.SKETCHFAB_FACECOUNT): + self.AddChild(id=CBOX_FACE_COUNT, subid=CBOX_FACE_COUNT_ELT + index, child=face_count[1]) + self.SetInt32(CBOX_FACE_COUNT, CBOX_FACE_COUNT_ELT) + + self.AddSeparatorV(50.0, flags=c4d.BFH_SCALE) + self.AddStaticText(id=LB_FACE_COUNT, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=60, inith=TEXT_WIDGET_HEIGHT, name="Sort by: ") + self.AddComboBox(id=CBOX_SORT_BY, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=90, inith=TEXT_WIDGET_HEIGHT) + for index, sort_by in enumerate(Config.SKETCHFAB_SORT_BY): + self.AddChild(id=CBOX_SORT_BY, subid=CBOX_SORT_BY_ELT + index, child=sort_by[1]) + self.SetInt32(CBOX_SORT_BY, CBOX_SORT_BY_ELT + 3) + + self.LayoutChanged(GROUP_FILTERS) + + def refresh_filters_ui(self): + self.draw_filters_ui() + + def result_valid(self): + if 'current' not in self.skfb_api.search_results: + return False + + return True + + def needs_warning(self): + """ + returns 0 if no warning is needed, the warning code otherwise: + 1 - Normal search, no results + 2 - Own models but not pro + 3 - No Store purchases + """ + + if not self.result_valid(): + return 0 + + search_domain = self.GetInt32(CBOX_SEARCH_DOMAIN) - CBOX_SEARCH_DOMAIN_ELT + if search_domain == 1 and not self.skfb_api.is_user_pro: + return 2 + + n_results = len(self.skfb_api.search_results['current']) + if n_results == 0: + if search_domain in [0,1]: + return 1 + else: + return 3 + else: + return 0 + + def resultGroupWillRedraw(self): + self.draw_prev_next() + self.draw_results_ui() + + def draw_results_ui(self): + self.LayoutFlushGroup(GROUP_RESULTS) + if not self.result_valid(): + return + + # Warning message + warning = self.needs_warning() + if warning: + self.draw_warning_ui(warning) + + for index, skfb_model in enumerate(self.skfb_api.search_results['current'].values()): + image_container = c4d.BaseContainer() # Create a new container to store the image we will load for the button later on + self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFH_SCALEFIT, 1, 2, "Bitmap Example", 0) + filenameid = resultContainerIDStart + index + image_container.SetBool(c4d.BITMAPBUTTON_BUTTON, True) + image_container.SetBool(c4d.BITMAPBUTTON_NOBORDERDRAW, True) + image_container.SetFilename(filenameid, str(skfb_model.thumbnail_path)) + + self.mybutton = self.AddCustomGui(filenameid, c4d.CUSTOMGUI_BITMAPBUTTON, "Sketchfab model button", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 10, 10, image_container) + self.mybutton.SetLayoutMode(c4d.LAYOUTMODE_MINIMIZED) + self.mybutton.SetImage(str(skfb_model.thumbnail_path), False) + self.mybutton.SetToggleState(True) + + nameid = LB_RESULT_NAME_START + index + modelname = textwrap.wrap(skfb_model.title, 18)[0] # dumbly truncate names for the UI + + self.AddStaticText(id=nameid, + flags=c4d.BFV_BOTTOM | c4d.BFH_CENTER, + initw=192, + inith=16, + name=u'{}'.format(modelname), + borderstyle=c4d.BORDER_WITH_TITLE) + + self.GroupEnd() + + self.LayoutChanged(GROUP_RESULTS) + + self.Enable(BTN_PREV_PAGE, self.skfb_api.has_prev()) + self.Enable(BTN_NEXT_PAGE, self.skfb_api.has_next()) + + self.redraw_results = False + + def draw_prev_next(self): + self.LayoutFlushGroup(GROUP_PREVNEXT) + + if self.result_valid() and len(self.skfb_api.search_results['current']) > 0: + self.AddButton(id=BTN_PREV_PAGE, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Previous") + self.AddSeparatorV(0.0, flags=c4d.BFH_SCALE) + self.AddButton(id=BTN_NEXT_PAGE, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Next") + self.Enable(BTN_PREV_PAGE, self.skfb_api.has_prev()) + self.Enable(BTN_NEXT_PAGE, self.skfb_api.has_next()) + + self.LayoutChanged(GROUP_PREVNEXT) + + def trigger_default_search(self): + self.skfb_api.search(Config.DEFAULT_SEARCH) + + def trigger_search(self): + search_domain_str = Config.SKETCHFAB_SEARCH_DOMAINS[self.GetInt32(CBOX_SEARCH_DOMAIN) - CBOX_SEARCH_DOMAIN_ELT][0] + final_query = Config.SKETCHFAB_API + '/v3' + search_domain_str + + if self.GetString(EDITXT_SEARCH_QUERY): + final_query = final_query + '&q={}'.format(self.GetString(EDITXT_SEARCH_QUERY)) + + if self.GetBool(CHK_IS_ANIMATED): + final_query = final_query + '&animated=true' + + if self.GetBool(CHK_IS_STAFFPICK): + final_query = final_query + '&staffpicked=true' + + if self.GetInt32(CBOX_SORT_BY) == CBOX_SORT_BY_ELT + 1: + final_query = final_query + '&sort_by=-likeCount' + elif self.GetInt32(CBOX_SORT_BY) == CBOX_SORT_BY_ELT + 2: + final_query = final_query + '&sort_by=-viewCount' + elif self.GetInt32(CBOX_SORT_BY) == CBOX_SORT_BY_ELT + 3: + final_query = final_query + '&sort_by=-publishedAt' + + if self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 1: + final_query = final_query + '&min_face_count=1&max_face_count=10000' + elif self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 2: + final_query = final_query + '&min_face_count=10000&max_face_count=50000' + elif self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 3: + final_query = final_query + '&min_face_count=50000&max_face_count=100000' + elif self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 4: + final_query = final_query + "&min_face_count=100000&max_face_count=250000" + elif self.GetInt32(CBOX_FACE_COUNT) == CBOX_FACE_COUNT_ELT + 5: + final_query = final_query + "&min_face_count=250000" + else: + final_query = final_query + "&min_face_count=1" + + if self.GetInt32(CBOX_CATEGORY) != CBOX_CATEGORY_ELT: + final_query = final_query + '&categories={}'.format(Config.SKETCHFAB_CATEGORIES[self.GetInt32(CBOX_CATEGORY) - CBOX_CATEGORY_ELT][0]) + + if self.GetBool(CHK_IS_PBR): + final_query = final_query + '&pbr_type=true' + + self.skfb_api.search(final_query) + + def reset_filters(self, is_own_model): + self.SetBool(CHK_IS_STAFFPICK, not is_own_model) + self.SetBool(CHK_IS_ANIMATED, False) + self.SetBool(CHK_IS_PBR, False) + self.SetInt32(CBOX_CATEGORY, CBOX_CATEGORY_ELT) + self.SetInt32(CBOX_FACE_COUNT, CBOX_FACE_COUNT_ELT) + self.SetInt32(CBOX_SORT_BY, CBOX_SORT_BY_ELT + 1) + + def Command(self, id, msg): + trigger_search = False + + self.common_commands(id, msg) + + if id == BTN_PREV_PAGE: + self.skfb_api.search_prev() + + if id == BTN_NEXT_PAGE: + self.skfb_api.search_next() + + bc = c4d.BaseContainer() + if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.KEY_ENTER, bc): + if bc[c4d.BFM_INPUT_VALUE] == 1: + if self.IsActive(EDITXT_SEARCH_QUERY): + trigger_search = True + + if id in [ + BTN_SEARCH, + CBOX_SEARCH_DOMAIN, + CBOX_CATEGORY, + CBOX_SORT_BY, + CBOX_FACE_COUNT, + CHK_IS_PBR, + CHK_IS_ANIMATED, + CHK_IS_STAFFPICK]: + trigger_search = True + + if id == CBOX_SEARCH_DOMAIN: + self.Enable(GROUP_FILTERS, (self.GetInt32(CBOX_SEARCH_DOMAIN) - CBOX_SEARCH_DOMAIN_ELT) != 2) + self.refresh_filters_ui() + + if trigger_search: + self.trigger_search() + + for i in range(24): + if id == resultContainerIDStart + i: + if self.model_dialog: + self.model_dialog.Close() + + model = list(self.skfb_api.search_results['current'].values())[i] + self.skfb_api.request_model_info(model.uid) + self.model_dialog = SkfbModelDialog() + self.model_dialog.SetModelInfo(model, self.skfb_api) + self.model_dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, defaultw=450, defaulth=300, xpos=-1, ypos=-1) + + return True class SkfbModelDialog(gui.GeDialog): - skfb_model = None - - def __init__(self): - self.progress = 0 - self.step = '' - self.status = '' - self.importer = None - - def SetModelInfo(self, skfb_model, api): - self.skfb_model = skfb_model - self.skfb_api = api - self.skfb_api.import_callback = self.progress_callback - - self.Enable(BTN_IMPORT, self.skfb_api.is_user_logged()) - - def CreateLayout(self): - # Create the menu - self.MenuFlushAll() - - self.GroupBegin(GROUP_MODEL_WINDOW, c4d.BFH_CENTER | c4d.BFV_TOP, 1, 1, "Model Window") - self.draw_model_window() - self.GroupEnd() - - self.GroupBegin(GROUP_MODEL_INFO, c4d.BFH_CENTER | c4d.BFV_TOP, 3, 3, "Results", 0) - self.draw_model_details() - self.GroupEnd() - - self.GroupBegin(GROUP_MODEL_IMPORT, c4d.BFH_CENTER | c4d.BFV_CENTER, 1, 3) - self.draw_model_import() - self.GroupEnd() - - self.GroupBegin(GROUP_MODEL_PROGRESS, c4d.BFH_SCALEFIT | c4d.BFV_CENTER, 1, 3) - self.draw_model_progress() - self.GroupEnd() - - self.Enable(BTN_IMPORT, self.skfb_api.is_user_logged()) - return True - - def draw_model_window(self): - self.LayoutFlushGroup(GROUP_MODEL_WINDOW) - - # BIG Thumbnail - use_thumbnail = True - if use_thumbnail: - image_container = c4d.BaseContainer() # Create a new container to store the image we will load for the button later on - image_container.SetBool(c4d.BITMAPBUTTON_BUTTON, True) - image_container.SetBool(c4d.BITMAPBUTTON_NOBORDERDRAW, True) - image_container.SetFilename(resultContainerIDStart, self.skfb_model.thumbnail_path) - - self.mybutton = self.AddCustomGui(2, c4d.CUSTOMGUI_BITMAPBUTTON, "Sketchfab thumbnail Button", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 10, 10, image_container) - self.mybutton.SetLayoutMode(c4d.LAYOUTMODE_MINIMIZED) - self.mybutton.SetImage(str(self.skfb_model.preview_path), False) - self.mybutton.SetToggleState(False) - - self.AddButton(id=BTN_VIEW_SKFB, flags=c4d.BFH_CENTER | c4d.BFV_TOP, initw=150, inith=16, name="View on Sketchfab") - else: - self.html = self.AddCustomGui(1000, c4d.CUSTOMGUI_HTMLVIEWER, "html", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 405, 720) - self.html.SetUrl("https://sketchfab.com/models/{}/embed?autostart=1".format(self.skfb_model.uid), c4d.URL_ENCODING_UTF16) - self.html.DoAction(c4d.WEBPAGE_REFRESH) - - self.LayoutChanged(GROUP_MODEL_WINDOW) - - def draw_model_details(self): - self.LayoutFlushGroup(GROUP_MODEL_INFO) - - self.AddStaticText(id=LB_MODEL_NAME, flags=c4d.BFH_LEFT, - initw=500, - name=u'Title: {}'.format(self.skfb_model.title)) - - self.AddSeparatorV(50.0, flags=c4d.BFH_SCALE) - self.AddStaticText(id=LB_MODEL_VERTEX_COUNT, - flags=c4d.BFH_RIGHT, - initw=500, - name=u' Vertex Count: {}'.format(Utils.humanify_number(self.skfb_model.vertex_count))) - - self.AddStaticText(id=LB_MODEL_AUTHOR, flags=c4d.BFH_LEFT, - initw=500, - name=u'Author: {}'.format(self.skfb_model.author)) - - self.AddSeparatorV(50.0, flags=c4d.BFH_SCALE) - self.AddStaticText(id=LB_MODEL_FACE_COUNT, flags=c4d.BFH_RIGHT, - initw=500, - name=u' Face Count: {}'.format(Utils.humanify_number(self.skfb_model.face_count))) - - self.AddStaticText(id=LB_MODEL_LICENCE, flags=c4d.BFH_LEFT, - initw=500, - name=u'License: {}'.format(self.skfb_model.license)) - self.AddSeparatorV(50.0, flags=c4d.BFH_SCALE) - self.AddStaticText(id=LB_MODEL_ANIMATION_COUNT, flags=c4d.BFH_RIGHT, - initw=500, - name=u' Animated: {}'.format(self.skfb_model.animated)) - - self.LayoutChanged(GROUP_MODEL_INFO) - - def draw_model_import(self): - self.LayoutFlushGroup(GROUP_MODEL_IMPORT) - - self.Enable(BTN_IMPORT, self.skfb_api.is_user_logged()) - self.AddStaticText(id=LB_MODEL_STEP, flags=c4d.BFH_SCALEFIT, initw=250, inith=TEXT_WIDGET_HEIGHT) - caption = self.GetString(BTN_IMPORT) - caption = self.status - - if not caption: - caption = "IMPORT MODEL" if self.skfb_api.is_user_logged() else "You need to be logged in" - if self.skfb_model is not None and self.skfb_model.download_size: - caption += " (" + self.skfb_model.download_size + ")" - - self.AddButton(id=BTN_IMPORT, flags=c4d.BFH_CENTER | c4d.BFV_CENTER, initw=200, inith=38, name=caption) - self.LayoutChanged(GROUP_MODEL_IMPORT) - - def draw_model_progress(self): - self.LayoutFlushGroup(GROUP_MODEL_PROGRESS) - self.AddCustomGui(UI_PROGRESSBAR, c4d.CUSTOMGUI_PROGRESSBAR, "", c4d.BFH_SCALEFIT, 0, 0) - self.LayoutChanged(GROUP_MODEL_PROGRESS) - - def set_status(self, status): - self.step = status - self.SetString(BTN_IMPORT, status) - - def refresh_window(self): - self.draw_model_import() - - def Command(self, id, msg): - if id == BTN_VIEW_SKFB: - url = Config.SKETCHFAB_URL + '/models/' + self.skfb_model.uid - webbrowser.open(url) - - if id == BTN_IMPORT: - self.EnableStatusBar() - self.set_status('Downloading') - self.download_model() - - return True - - def download_model(self): - model_url = self.skfb_api.request_model_url(self.skfb_model.uid) - if not model_url: - return - - filepath = self.skfb_api.get_archive(model_url, self.progress_callback) - if os.path.exists(filepath): - self.import_model(filepath, self.skfb_model.uid) - - def import_model(self, filepath, uid): - self.set_status('Importing model..') - self.importer = ImportGLTF(self.progress_callback) - self.importer.run(filepath, uid) - - def EnableStatusBar(self): - progressMsg = c4d.BaseContainer(c4d.BFM_SETSTATUSBAR) - progressMsg[c4d.BFM_STATUSBAR_PROGRESSON] = True - progressMsg[c4d.BFM_STATUSBAR_PROGRESS] = 0.2 - - def progress_callback(self, step, current, total): - real_current = 100 / total * current / 100.0 - self.progress = real_current - - progressMsg = c4d.BaseContainer(c4d.BFM_SETSTATUSBAR) - progressMsg[c4d.BFM_STATUSBAR_PROGRESSON] = True - progressMsg[c4d.BFM_STATUSBAR_PROGRESS] = self.progress - self.SendMessage(UI_PROGRESSBAR, progressMsg) - - if step != self.step: - self.step = step - self.status = step - - if self.importer and self.importer.is_done: - self.StopProgress() - - def StopProgress(self): - self.set_status('IMPORT MODEL') - progressMsg = c4d.BaseContainer(c4d.BFM_SETSTATUSBAR) - progressMsg.SetBool(c4d.BFM_STATUSBAR_PROGRESSON, False) - self.SendMessage(UI_PROGRESSBAR, progressMsg) - - def Timer(self, msg): - progressMsg = c4d.BaseContainer(c4d.BFM_SETSTATUSBAR) - progressMsg[c4d.BFM_STATUSBAR_PROGRESSON] = True - progressMsg[c4d.BFM_STATUSBAR_PROGRESS] = self.progress - self.SendMessage(UI_PROGRESSBAR, progressMsg) - self.refresh_window() - - def Message(self, msg, result): - if msg.GetId() == c4d.BFM_TIMER_MESSAGE: - if self.step == 'FINISHED': - self.StopProgress() - return True - - return gui.GeDialog.Message(self, msg, result) - - def AskClose(self): - if self.importer and not self.importer.is_done: - answer = gui.MessageDialog(text='Are you sure you want to abort the import ?', type=c4d.GEMB_YESNO) - if answer == c4d.GEMB_R_YES: - self.importer.AbortImport() - else: - return - return False + skfb_model = None + + def __init__(self): + self.progress = 0 + self.step = '' + self.status = '' + self.importer = None + + def SetModelInfo(self, skfb_model, api): + self.skfb_model = skfb_model + self.skfb_api = api + self.skfb_api.import_callback = self.progress_callback + + self.Enable(BTN_IMPORT, self.skfb_api.is_user_logged()) + + def CreateLayout(self): + # Create the menu + self.MenuFlushAll() + + self.GroupBegin(GROUP_MODEL_WINDOW, c4d.BFH_CENTER | c4d.BFV_TOP, 1, 1, "Model Window") + self.draw_model_window() + self.GroupEnd() + + self.GroupBegin(GROUP_MODEL_INFO, c4d.BFH_CENTER | c4d.BFV_TOP, 3, 3, "Results", 0) + self.draw_model_details() + self.GroupEnd() + + self.GroupBegin(GROUP_MODEL_IMPORT, c4d.BFH_CENTER | c4d.BFV_CENTER, 1, 3) + self.draw_model_import() + self.GroupEnd() + + self.GroupBegin(GROUP_MODEL_PROGRESS, c4d.BFH_SCALEFIT | c4d.BFV_CENTER, 1, 3) + self.draw_model_progress() + self.GroupEnd() + + self.Enable(BTN_IMPORT, self.skfb_api.is_user_logged()) + return True + + def draw_model_window(self): + self.LayoutFlushGroup(GROUP_MODEL_WINDOW) + + # BIG Thumbnail + use_thumbnail = True + if use_thumbnail: + image_container = c4d.BaseContainer() # Create a new container to store the image we will load for the button later on + image_container.SetBool(c4d.BITMAPBUTTON_BUTTON, True) + image_container.SetBool(c4d.BITMAPBUTTON_NOBORDERDRAW, True) + image_container.SetFilename(resultContainerIDStart, self.skfb_model.thumbnail_path) + + self.mybutton = self.AddCustomGui(2, c4d.CUSTOMGUI_BITMAPBUTTON, "Sketchfab thumbnail Button", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 10, 10, image_container) + self.mybutton.SetLayoutMode(c4d.LAYOUTMODE_MINIMIZED) + self.mybutton.SetImage(str(self.skfb_model.preview_path), False) + self.mybutton.SetToggleState(False) + + self.AddButton(id=BTN_VIEW_SKFB, flags=c4d.BFH_CENTER | c4d.BFV_TOP, initw=150, inith=16, name="View on Sketchfab") + else: + self.html = self.AddCustomGui(1000, c4d.CUSTOMGUI_HTMLVIEWER, "html", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 405, 720) + self.html.SetUrl("https://sketchfab.com/models/{}/embed?autostart=1".format(self.skfb_model.uid), c4d.URL_ENCODING_UTF16) + self.html.DoAction(c4d.WEBPAGE_REFRESH) + + self.LayoutChanged(GROUP_MODEL_WINDOW) + + def draw_model_details(self): + self.LayoutFlushGroup(GROUP_MODEL_INFO) + + self.AddStaticText(id=LB_MODEL_NAME, flags=c4d.BFH_LEFT, + initw=500, + name=u'Title: {}'.format(self.skfb_model.title)) + + self.AddSeparatorV(50.0, flags=c4d.BFH_SCALE) + self.AddStaticText(id=LB_MODEL_VERTEX_COUNT, + flags=c4d.BFH_RIGHT, + initw=500, + name=u' Vertex Count: {}'.format(Utils.humanify_number(self.skfb_model.vertex_count))) + + self.AddStaticText(id=LB_MODEL_AUTHOR, flags=c4d.BFH_LEFT, + initw=500, + name=u'Author: {}'.format(self.skfb_model.author)) + + self.AddSeparatorV(50.0, flags=c4d.BFH_SCALE) + self.AddStaticText(id=LB_MODEL_FACE_COUNT, flags=c4d.BFH_RIGHT, + initw=500, + name=u' Face Count: {}'.format(Utils.humanify_number(self.skfb_model.face_count))) + + self.AddStaticText(id=LB_MODEL_LICENCE, flags=c4d.BFH_LEFT, + initw=500, + name=u'License: {}'.format(self.skfb_model.license)) + self.AddSeparatorV(50.0, flags=c4d.BFH_SCALE) + self.AddStaticText(id=LB_MODEL_ANIMATION_COUNT, flags=c4d.BFH_RIGHT, + initw=500, + name=u' Animated: {}'.format(self.skfb_model.animated)) + + self.LayoutChanged(GROUP_MODEL_INFO) + + def draw_model_import(self): + self.LayoutFlushGroup(GROUP_MODEL_IMPORT) + + self.Enable(BTN_IMPORT, self.skfb_api.is_user_logged()) + self.AddStaticText(id=LB_MODEL_STEP, flags=c4d.BFH_SCALEFIT, initw=250, inith=TEXT_WIDGET_HEIGHT) + caption = self.GetString(BTN_IMPORT) + caption = self.status + + if not caption: + caption = "IMPORT MODEL" if self.skfb_api.is_user_logged() else "You need to be logged in" + if self.skfb_model is not None and self.skfb_model.download_size: + caption += " (" + self.skfb_model.download_size + ")" + + self.AddButton(id=BTN_IMPORT, flags=c4d.BFH_CENTER | c4d.BFV_CENTER, initw=200, inith=38, name=caption) + self.LayoutChanged(GROUP_MODEL_IMPORT) + + def draw_model_progress(self): + self.LayoutFlushGroup(GROUP_MODEL_PROGRESS) + self.AddCustomGui(UI_PROGRESSBAR, c4d.CUSTOMGUI_PROGRESSBAR, "", c4d.BFH_SCALEFIT, 0, 0) + self.LayoutChanged(GROUP_MODEL_PROGRESS) + + def set_status(self, status): + self.step = status + self.SetString(BTN_IMPORT, status) + + def refresh_window(self): + self.draw_model_import() + + def Command(self, id, msg): + if id == BTN_VIEW_SKFB: + url = Config.SKETCHFAB_URL + '/models/' + self.skfb_model.uid + webbrowser.open(url) + + if id == BTN_IMPORT: + self.EnableStatusBar() + self.set_status('Downloading') + self.download_model() + + return True + + def download_model(self): + model_url = self.skfb_api.request_model_url(self.skfb_model.uid) + if not model_url: + return + + filepath = self.skfb_api.get_archive(model_url, self.progress_callback) + if os.path.exists(filepath): + self.import_model(filepath, self.skfb_model.uid) + + def import_model(self, filepath, uid): + self.set_status('Importing model..') + self.importer = ImportGLTF(self.progress_callback) + self.importer.run(filepath, uid) + + def EnableStatusBar(self): + progressMsg = c4d.BaseContainer(c4d.BFM_SETSTATUSBAR) + progressMsg[c4d.BFM_STATUSBAR_PROGRESSON] = True + progressMsg[c4d.BFM_STATUSBAR_PROGRESS] = 0.2 + + def progress_callback(self, step, current, total): + real_current = 100 / total * current / 100.0 + self.progress = real_current + + progressMsg = c4d.BaseContainer(c4d.BFM_SETSTATUSBAR) + progressMsg[c4d.BFM_STATUSBAR_PROGRESSON] = True + progressMsg[c4d.BFM_STATUSBAR_PROGRESS] = self.progress + self.SendMessage(UI_PROGRESSBAR, progressMsg) + + if step != self.step: + self.step = step + self.status = step + + if self.importer and self.importer.is_done: + self.StopProgress() + + def StopProgress(self): + self.set_status('IMPORT MODEL') + progressMsg = c4d.BaseContainer(c4d.BFM_SETSTATUSBAR) + progressMsg.SetBool(c4d.BFM_STATUSBAR_PROGRESSON, False) + self.SendMessage(UI_PROGRESSBAR, progressMsg) + + def Timer(self, msg): + progressMsg = c4d.BaseContainer(c4d.BFM_SETSTATUSBAR) + progressMsg[c4d.BFM_STATUSBAR_PROGRESSON] = True + progressMsg[c4d.BFM_STATUSBAR_PROGRESS] = self.progress + self.SendMessage(UI_PROGRESSBAR, progressMsg) + self.refresh_window() + + def Message(self, msg, result): + if msg.GetId() == c4d.BFM_TIMER_MESSAGE: + if self.step == 'FINISHED': + self.StopProgress() + return True + + return gui.GeDialog.Message(self, msg, result) + + def AskClose(self): + if self.importer and not self.importer.is_done: + answer = gui.MessageDialog(text='Are you sure you want to abort the import ?', type=c4d.GEMB_YESNO) + if answer == c4d.GEMB_R_YES: + self.importer.AbortImport() + else: + return + return False diff --git a/sketchfab/ui_login.py b/sketchfab/ui_login.py index 60195c0..30f0b50 100644 --- a/sketchfab/ui_login.py +++ b/sketchfab/ui_login.py @@ -45,224 +45,224 @@ TEXT_WIDGET_HEIGHT = 10 class UserAreaPathsHeader(c4d.gui.GeUserArea): - """Sketchfab header image.""" - img_path = "" - bmp = c4d.bitmaps.BaseBitmap() - - def set_img(self, path): - self.img_path = path - - def GetMinSize(self): - self.width = 448 - self.height = 75 - return (self.width, self.height) - - def DrawMsg(self, x1, y1, x2, y2, msg): - logo, _ = self.bmp.InitWith(self.img_path) - if logo == c4d.IMAGERESULT_OK: - self.DrawBitmap(self.bmp, 0, 0, 448, 75, - 0, 0, self.bmp.GetBw(), self.bmp.GetBh(), - c4d.BMP_NORMALSCALED | c4d.BMP_ALLOWALPHA) - - def Redraw(self): - logo, _ = self.bmp.InitWith(self.img_path) - if logo == c4d.IMAGERESULT_OK: - self.DrawBitmap(self.bmp, 0, 0, 448, 75, - 0, 0, self.bmp.GetBw(), self.bmp.GetBh(), - c4d.BMP_NORMALSCALED | c4d.BMP_ALLOWALPHA) + """Sketchfab header image.""" + img_path = "" + bmp = c4d.bitmaps.BaseBitmap() + + def set_img(self, path): + self.img_path = path + + def GetMinSize(self): + self.width = 448 + self.height = 75 + return (self.width, self.height) + + def DrawMsg(self, x1, y1, x2, y2, msg): + logo, _ = self.bmp.InitWith(self.img_path) + if logo == c4d.IMAGERESULT_OK: + self.DrawBitmap(self.bmp, 0, 0, 448, 75, + 0, 0, self.bmp.GetBw(), self.bmp.GetBh(), + c4d.BMP_NORMALSCALED | c4d.BMP_ALLOWALPHA) + + def Redraw(self): + logo, _ = self.bmp.InitWith(self.img_path) + if logo == c4d.IMAGERESULT_OK: + self.DrawBitmap(self.bmp, 0, 0, 448, 75, + 0, 0, self.bmp.GetBw(), self.bmp.GetBh(), + c4d.BMP_NORMALSCALED | c4d.BMP_ALLOWALPHA) class SketchfabDialogWithLogin(c4d.gui.GeDialog): - userarea_paths_header = UserAreaPathsHeader() - - redraw_login = False - status_widget = None - is_initialized = False - cta_link = None - - def initialize(self): - self.is_initialized = True - self.skfb_api.connect_to_sketchfab() - - def draw_header(self): - self.LayoutFlushGroup(GROUP_HEADER) - - self.AddUserArea(UA_HEADER, c4d.BFH_CENTER) - self.AttachUserArea(self.userarea_paths_header, UA_HEADER) - self.userarea_paths_header.LayoutChanged() - - self.LayoutChanged(GROUP_HEADER) - - def draw_login_ui(self): - - self.LayoutFlushGroup(GROUP_LOGIN) - - if not self.is_initialized: - self.AddButton(id=BTN_CONNECT_SKETCHFAB, flags=c4d.BFH_CENTER | c4d.BFV_BOTTOM, initw=350, inith=TEXT_WIDGET_HEIGHT, name="Connect to Sketchfab") - else: - if self.skfb_api.is_user_logged(): - self.AddStaticText(id=LB_CONNECT_STATUS, flags=c4d.BFH_LEFT, initw=0, inith=0, name=u"Connected as {}".format(self.skfb_api.display_name)) - self.AddButton(id=BTN_CONNECT_SKETCHFAB, flags=c4d.BFH_RIGHT | c4d.BFV_BOTTOM, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Logout") - else: - self.AddStaticText(id=LB_LOGIN_EMAIL, flags=c4d.BFH_LEFT, initw=0, inith=0, name="Email:") - self.AddEditText(id=EDITXT_LOGIN_EMAIL, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=350, inith=TEXT_WIDGET_HEIGHT) - self.AddStaticText(id=LB_LOGIN_PASSWORD, flags=c4d.BFH_LEFT, initw=0, inith=0, name="Password:") - self.AddEditText(id=EDITXT_LOGIN_PASSWORD, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=350, inith=TEXT_WIDGET_HEIGHT, editflags=c4d.EDITTEXT_PASSWORD) - self.AddButton(id=BTN_LOGIN, flags=c4d.BFH_RIGHT | c4d.BFV_BOTTOM, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Login") - - # Little hack to get username set in UI - self.SetString(LB_CONNECT_STATUS, u"Connected as {}".format(self.skfb_api.display_name)) - self.LayoutChanged(GROUP_LOGIN) - - def refresh_version_ui(self): - self.draw_version_ui() - - def msgbox_message(self, text): - c4d.gui.MessageDialog(text, type=c4d.GEMB_OK) - - def draw_version_ui(self): - self.LayoutFlushGroup(GROUP_FOOTER_VERSION) - - version_state = 'connect to check version' - is_latest_version = True - if self.skfb_api.latest_release_version: - if self.skfb_api.latest_release_version != Config.PLUGIN_VERSION: - version_state = 'outdated' - is_latest_version = False - else: - version_state = 'up to date' - - self.AddStaticText(id=LB_PLUGIN_VERSION, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=0, inith=0, name="Plugin version: {} ({})".format(Config.PLUGIN_VERSION, version_state)) - if not is_latest_version: - self.AddButton(id=BTN_UPGRADE_PLUGIN, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=75, inith=TEXT_WIDGET_HEIGHT, name='Upgrade') - - self.LayoutChanged(GROUP_FOOTER_VERSION) - - def draw_warning_ui(self, _type): - """ - 1 - Normal search, no results - 2 - Own models but not pro - 3 - No Store purchases - """ - msg, btn = u'No results found', None - if _type == 2: - msg = u'Access your personal library of 3D models' - btn = 'Upgrade to PRO' - self.cta_link = Config.SKETCHFAB_PLANS - elif _type == 3: - msg = u'You did not purchase any model yet' - btn = 'Visit the Store' - self.cta_link = Config.SKETCHFAB_STORE - - self.GroupBegin(GROUP_WARNING, c4d.BFH_CENTER | c4d.BFV_CENTER, 6, 4, "Warning") - self.LayoutFlushGroup(GROUP_WARNING) - self.GroupBorderSpace(6, 2, 6, 2) - self.AddStaticText(id=LB_WARNING, flags=c4d.BFH_CENTER | c4d.BFV_CENTER, initw=500, name=msg) - if btn: - self.AddButton(id=BTN_WARNING, flags=c4d.BFH_CENTER | c4d.BFV_CENTER, initw=150, inith=TEXT_WIDGET_HEIGHT * 2, name=btn) - self.LayoutChanged(GROUP_WARNING) - self.GroupEnd() - - def draw_footer(self): - self.AddSeparatorH(inith=0, flags=c4d.BFH_FIT) - self.GroupBegin(GROUP_FOOTER, c4d.BFH_FIT | c4d.BFV_CENTER, 3, 1, "Footer") - - self.LayoutFlushGroup(GROUP_FOOTER) - self.GroupBorderSpace(6, 2, 6, 6) - self.AddSeparatorV(0.0, flags=c4d.BFH_SCALE) - - self.GroupBegin(GROUP_FOOTER_VERSION, c4d.BFH_RIGHT | c4d.BFV_CENTER, 5, 1, "Footer_version") - self.draw_version_ui() - self.GroupEnd() - - self.LayoutChanged(GROUP_FOOTER) - - self.GroupEnd() - - def draw_contact_ui(self): - self.AddButton(id=BTN_UPGRADE_PLUGIN, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=120, inith=TEXT_WIDGET_HEIGHT, name='Documentation') - self.AddButton(id=BTN_REPORT, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=120, inith=TEXT_WIDGET_HEIGHT, name='Report an issue') - - def setup_api(self): - self.skfb_api = SketchfabApi() - self.skfb_api.version_callback = self.refresh_version_ui - self.skfb_api.request_callback = self.draw_login_ui # self.refresh - self.skfb_api.login_callback = self.draw_login_ui - self.skfb_api.msgbox_callback = self.msgbox_message - - def InitValues(self): - self.SetTimer(20) - self.SetString(EDITXT_LOGIN_EMAIL, Cache.get_key('username')) - return True - - def CreateLayout(self): - # Initialization - self.setup_api() - - # Menu - self.MenuFlushAll() - self.MenuSubBegin("File") - self.MenuAddCommand(c4d.IDM_CM_CLOSEWINDOW) - self.MenuSubEnd() - self.MenuSubBegin("Help") - self.MenuAddString(BTN_CREATE_ACCOUNT, "Create an account") - self.MenuAddString(BTN_REPORT, "Report an issue") - self.MenuAddString(BTN_DOCUMENTATION, "Documentation") - self.MenuAddString(BTN_OPEN_CACHE, "Open cache directory") - self.MenuSubEnd() - self.MenuFinished() - - # Header - self.GroupBegin(GROUP_HEADER, c4d.BFH_LEFT | c4d.BFV_TOP, 1, 1, "Header") - self.draw_header() - self.GroupEnd() - self.AddSeparatorH(inith=0, flags=c4d.BFH_FIT) - - # Login - self.GroupBegin(id=GROUP_LOGIN, - flags=c4d.BFH_CENTER, - cols=7, - rows=1, - title="Login", - groupflags=c4d.BORDER_NONE | c4d.BFV_GRIDGROUP_EQUALCOLS | c4d.BFV_GRIDGROUP_EQUALROWS) - self.draw_login_ui() - self.GroupEnd() - - self.AddSeparatorH(inith=0, flags=c4d.BFH_FIT) - - def AskClose(self): - self.is_initialized = False - return False - - def common_commands(self, id, msg): - if id == BTN_CONNECT_SKETCHFAB: - if not self.is_initialized: - self.initialize() - else: - self.skfb_api.logout() - self.SetString(EDITXT_LOGIN_EMAIL, Cache.get_key('username')) - self.skfb_api.login_callback() - - if id == BTN_LOGIN: - self.skfb_api.login(self.GetString(EDITXT_LOGIN_EMAIL), self.GetString(EDITXT_LOGIN_PASSWORD)) - - #if id == BTN_WEB: - # Utilities.ESOpen_website(Config.SKETCHFAB_URL) - - if id == BTN_DOCUMENTATION: - webbrowser.open(Config.PLUGIN_LATEST_RELEASE) - - if id == BTN_UPGRADE_PLUGIN: - webbrowser.open(Config.PLUGIN_LATEST_RELEASE) - - if id == BTN_CREATE_ACCOUNT: - webbrowser.open(Config.SKETCHFAB_SIGNUP) - - if id == BTN_OPEN_CACHE: - Utils.open_directory('{}'.format(Config.SKETCHFAB_TEMP_DIR)) - - if id == BTN_WARNING: - webbrowser.open(self.cta_link) - - if id == BTN_REPORT: - webbrowser.open(Config.SKETCHFAB_REPORT_URL) + userarea_paths_header = UserAreaPathsHeader() + + redraw_login = False + status_widget = None + is_initialized = False + cta_link = None + + def initialize(self): + self.is_initialized = True + self.skfb_api.connect_to_sketchfab() + + def draw_header(self): + self.LayoutFlushGroup(GROUP_HEADER) + + self.AddUserArea(UA_HEADER, c4d.BFH_CENTER) + self.AttachUserArea(self.userarea_paths_header, UA_HEADER) + self.userarea_paths_header.LayoutChanged() + + self.LayoutChanged(GROUP_HEADER) + + def draw_login_ui(self): + + self.LayoutFlushGroup(GROUP_LOGIN) + + if not self.is_initialized: + self.AddButton(id=BTN_CONNECT_SKETCHFAB, flags=c4d.BFH_CENTER | c4d.BFV_BOTTOM, initw=350, inith=TEXT_WIDGET_HEIGHT, name="Connect to Sketchfab") + else: + if self.skfb_api.is_user_logged(): + self.AddStaticText(id=LB_CONNECT_STATUS, flags=c4d.BFH_LEFT, initw=0, inith=0, name=u"Connected as {}".format(self.skfb_api.display_name)) + self.AddButton(id=BTN_CONNECT_SKETCHFAB, flags=c4d.BFH_RIGHT | c4d.BFV_BOTTOM, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Logout") + else: + self.AddStaticText(id=LB_LOGIN_EMAIL, flags=c4d.BFH_LEFT, initw=0, inith=0, name="Email:") + self.AddEditText(id=EDITXT_LOGIN_EMAIL, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=350, inith=TEXT_WIDGET_HEIGHT) + self.AddStaticText(id=LB_LOGIN_PASSWORD, flags=c4d.BFH_LEFT, initw=0, inith=0, name="Password:") + self.AddEditText(id=EDITXT_LOGIN_PASSWORD, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=350, inith=TEXT_WIDGET_HEIGHT, editflags=c4d.EDITTEXT_PASSWORD) + self.AddButton(id=BTN_LOGIN, flags=c4d.BFH_RIGHT | c4d.BFV_BOTTOM, initw=75, inith=TEXT_WIDGET_HEIGHT, name="Login") + + # Little hack to get username set in UI + self.SetString(LB_CONNECT_STATUS, u"Connected as {}".format(self.skfb_api.display_name)) + self.LayoutChanged(GROUP_LOGIN) + + def refresh_version_ui(self): + self.draw_version_ui() + + def msgbox_message(self, text): + c4d.gui.MessageDialog(text, type=c4d.GEMB_OK) + + def draw_version_ui(self): + self.LayoutFlushGroup(GROUP_FOOTER_VERSION) + + version_state = 'connect to check version' + is_latest_version = True + if self.skfb_api.latest_release_version: + if self.skfb_api.latest_release_version != Config.PLUGIN_VERSION: + version_state = 'outdated' + is_latest_version = False + else: + version_state = 'up to date' + + self.AddStaticText(id=LB_PLUGIN_VERSION, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=0, inith=0, name="Plugin version: {} ({})".format(Config.PLUGIN_VERSION, version_state)) + if not is_latest_version: + self.AddButton(id=BTN_UPGRADE_PLUGIN, flags=c4d.BFH_LEFT | c4d.BFV_CENTER, initw=75, inith=TEXT_WIDGET_HEIGHT, name='Upgrade') + + self.LayoutChanged(GROUP_FOOTER_VERSION) + + def draw_warning_ui(self, _type): + """ + 1 - Normal search, no results + 2 - Own models but not pro + 3 - No Store purchases + """ + msg, btn = u'No results found', None + if _type == 2: + msg = u'Access your personal library of 3D models' + btn = 'Upgrade to PRO' + self.cta_link = Config.SKETCHFAB_PLANS + elif _type == 3: + msg = u'You did not purchase any model yet' + btn = 'Visit the Store' + self.cta_link = Config.SKETCHFAB_STORE + + self.GroupBegin(GROUP_WARNING, c4d.BFH_CENTER | c4d.BFV_CENTER, 6, 4, "Warning") + self.LayoutFlushGroup(GROUP_WARNING) + self.GroupBorderSpace(6, 2, 6, 2) + self.AddStaticText(id=LB_WARNING, flags=c4d.BFH_CENTER | c4d.BFV_CENTER, initw=500, name=msg) + if btn: + self.AddButton(id=BTN_WARNING, flags=c4d.BFH_CENTER | c4d.BFV_CENTER, initw=150, inith=TEXT_WIDGET_HEIGHT * 2, name=btn) + self.LayoutChanged(GROUP_WARNING) + self.GroupEnd() + + def draw_footer(self): + self.AddSeparatorH(initw=0, flags=c4d.BFH_FIT) + self.GroupBegin(GROUP_FOOTER, c4d.BFH_FIT | c4d.BFV_CENTER, 3, 1, "Footer") + + self.LayoutFlushGroup(GROUP_FOOTER) + self.GroupBorderSpace(6, 2, 6, 6) + self.AddSeparatorV(0.0, flags=c4d.BFH_SCALE) + + self.GroupBegin(GROUP_FOOTER_VERSION, c4d.BFH_RIGHT | c4d.BFV_CENTER, 5, 1, "Footer_version") + self.draw_version_ui() + self.GroupEnd() + + self.LayoutChanged(GROUP_FOOTER) + + self.GroupEnd() + + def draw_contact_ui(self): + self.AddButton(id=BTN_UPGRADE_PLUGIN, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=120, inith=TEXT_WIDGET_HEIGHT, name='Documentation') + self.AddButton(id=BTN_REPORT, flags=c4d.BFH_RIGHT | c4d.BFV_CENTER, initw=120, inith=TEXT_WIDGET_HEIGHT, name='Report an issue') + + def setup_api(self): + self.skfb_api = SketchfabApi() + self.skfb_api.version_callback = self.refresh_version_ui + self.skfb_api.request_callback = self.draw_login_ui # self.refresh + self.skfb_api.login_callback = self.draw_login_ui + self.skfb_api.msgbox_callback = self.msgbox_message + + def InitValues(self): + self.SetTimer(20) + self.SetString(EDITXT_LOGIN_EMAIL, Cache.get_key('username')) + return True + + def CreateLayout(self): + # Initialization + self.setup_api() + + # Menu + self.MenuFlushAll() + self.MenuSubBegin("File") + self.MenuAddCommand(c4d.IDM_CM_CLOSEWINDOW) + self.MenuSubEnd() + self.MenuSubBegin("Help") + self.MenuAddString(BTN_CREATE_ACCOUNT, "Create an account") + self.MenuAddString(BTN_REPORT, "Report an issue") + self.MenuAddString(BTN_DOCUMENTATION, "Documentation") + self.MenuAddString(BTN_OPEN_CACHE, "Open cache directory") + self.MenuSubEnd() + self.MenuFinished() + + # Header + self.GroupBegin(GROUP_HEADER, c4d.BFH_LEFT | c4d.BFV_TOP, 1, 1, "Header") + self.draw_header() + self.GroupEnd() + self.AddSeparatorH(initw=0, flags=c4d.BFH_FIT) + + # Login + self.GroupBegin(id=GROUP_LOGIN, + flags=c4d.BFH_CENTER, + cols=7, + rows=1, + title="Login", + groupflags=c4d.BORDER_NONE | c4d.BFV_GRIDGROUP_EQUALCOLS | c4d.BFV_GRIDGROUP_EQUALROWS) + self.draw_login_ui() + self.GroupEnd() + + self.AddSeparatorH(initw=0, flags=c4d.BFH_FIT) + + def AskClose(self): + self.is_initialized = False + return False + + def common_commands(self, id, msg): + if id == BTN_CONNECT_SKETCHFAB: + if not self.is_initialized: + self.initialize() + else: + self.skfb_api.logout() + self.SetString(EDITXT_LOGIN_EMAIL, Cache.get_key('username')) + self.skfb_api.login_callback() + + if id == BTN_LOGIN: + self.skfb_api.login(self.GetString(EDITXT_LOGIN_EMAIL), self.GetString(EDITXT_LOGIN_PASSWORD)) + + #if id == BTN_WEB: + # Utilities.ESOpen_website(Config.SKETCHFAB_URL) + + if id == BTN_DOCUMENTATION: + webbrowser.open(Config.PLUGIN_LATEST_RELEASE) + + if id == BTN_UPGRADE_PLUGIN: + webbrowser.open(Config.PLUGIN_LATEST_RELEASE) + + if id == BTN_CREATE_ACCOUNT: + webbrowser.open(Config.SKETCHFAB_SIGNUP) + + if id == BTN_OPEN_CACHE: + Utils.open_directory('{}'.format(Config.SKETCHFAB_TEMP_DIR)) + + if id == BTN_WARNING: + webbrowser.open(self.cta_link) + + if id == BTN_REPORT: + webbrowser.open(Config.SKETCHFAB_REPORT_URL)