Skip to content
Snippets Groups Projects
ui_panels.py 84.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Vilém Duha's avatar
    Vilém Duha committed
                split.scale_y = 1.6
    
                # split = row
                # split = layout.row()
            else:
                split = split.column()
    
            split.prop(ui_props, 'asset_type', expand=True, icon_only=ui_props.asset_type_fold)
    
    Vilém Duha's avatar
    Vilém Duha committed
            # row = layout.column(align = False)
    
            # layout.prop(ui_props, 'asset_type', expand=False, text='')
    
    Vilem Duha's avatar
    Vilem Duha committed
    
            w = context.region.width
    
            if len(user_preferences.api_key) < 20 and user_preferences.asset_counter > 20:
    
                    draw_login_buttons(layout)
    
                else:
                    op = layout.operator("wm.url_open", text="Get your API Key",
                                         icon='QUESTION')
                    op.url = paths.BLENDERKIT_SIGNUP_URL
                    layout.label(text='Paste your API Key:')
                    layout.prop(user_preferences, 'api_key', text='')
    
    Vilem Duha's avatar
    Vilem Duha committed
                layout.separator()
    
    Vilém Duha's avatar
    Vilém Duha committed
            # if bpy.data.filepath == '':
            #     layout.alert = True
    
            #    utils.label_multiline(layout, text="It's better to save your file first.", width=w)
    
    Vilém Duha's avatar
    Vilém Duha committed
            #     layout.alert = False
            #     layout.separator()
    
            if ui_props.down_up == 'SEARCH':
    
                if utils.profile_is_validator():
                    search_props = utils.get_search_props()
                    layout.prop(search_props, 'search_verification_status')
    
                    layout.prop(search_props, "unrated_only")
    
    
    Vilem Duha's avatar
    Vilem Duha committed
                if ui_props.asset_type == 'MODEL':
                    # noinspection PyCallByClass
                    draw_panel_model_search(self, context)
                if ui_props.asset_type == 'SCENE':
                    # noinspection PyCallByClass
                    draw_panel_scene_search(self, context)
    
                if ui_props.asset_type == 'HDR':
                    # noinspection PyCallByClass
                    draw_panel_hdr_search(self, context)
    
    Vilem Duha's avatar
    Vilem Duha committed
                elif ui_props.asset_type == 'MATERIAL':
                    draw_panel_material_search(self, context)
                elif ui_props.asset_type == 'BRUSH':
                    if context.sculpt_object or context.image_paint_object:
                        # noinspection PyCallByClass
                        draw_panel_brush_search(self, context)
                    else:
    
                        utils.label_multiline(layout, text='Switch to paint or sculpt mode.', width=context.region.width)
    
    Vilem Duha's avatar
    Vilem Duha committed
            elif ui_props.down_up == 'UPLOAD':
                if not ui_props.assetbar_on:
                    text = 'Show asset preview - ;'
                else:
                    text = 'Hide asset preview - ;'
                op = layout.operator('view3d.blenderkit_asset_bar', text=text, icon='EXPORT')
                op.keep_running = False
                op.do_search = False
    
                op.tooltip = 'Show/Hide asset preview'
    
    
    Vilem Duha's avatar
    Vilem Duha committed
                e = s.render.engine
                if e not in ('CYCLES', 'BLENDER_EEVEE'):
                    rtext = 'Only Cycles and EEVEE render engines are currently supported. ' \
                            'Please use Cycles for all assets you upload to BlenderKit.'
    
                    utils.label_multiline(layout, rtext, icon='ERROR', width=w)
    
    Vilem Duha's avatar
    Vilem Duha committed
                    return;
    
                if ui_props.asset_type == 'MODEL':
    
                    # utils.label_multiline(layout, "Uploaded models won't be available in b2.79", icon='ERROR')
    
                    if bpy.context.view_layer.objects.active is not None:
    
    Vilem Duha's avatar
    Vilem Duha committed
                        draw_panel_model_upload(self, context)
                    else:
                        layout.label(text='selet object to upload')
                elif ui_props.asset_type == 'SCENE':
                    draw_panel_scene_upload(self, context)
    
                elif ui_props.asset_type == 'HDR':
                    draw_panel_hdr_upload(self, context)
    
    Vilem Duha's avatar
    Vilem Duha committed
    
                elif ui_props.asset_type == 'MATERIAL':
    
                    # utils.label_multiline(layout, "Uploaded materials won't be available in b2.79", icon='ERROR')
    
                    if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None:
    
    Vilem Duha's avatar
    Vilem Duha committed
                        draw_panel_material_upload(self, context)
                    else:
    
                        utils.label_multiline(layout, text='select object with material to upload materials', width=w)
    
    Vilem Duha's avatar
    Vilem Duha committed
    
                elif ui_props.asset_type == 'BRUSH':
                    if context.sculpt_object or context.image_paint_object:
                        draw_panel_brush_upload(self, context)
                    else:
    
                        layout.label(text='Switch to paint or sculpt mode.')
    
    class BlenderKitWelcomeOperator(bpy.types.Operator):
        """Login online on BlenderKit webpage"""
    
        bl_idname = "wm.blenderkit_welcome"
        bl_label = "Welcome to BlenderKit!"
        bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
    
        step: IntProperty(
            name="step",
            description="Tutorial Step",
            default=0,
            options={'SKIP_SAVE'}
        )
    
        @classmethod
        def poll(cls, context):
            return True
    
        def draw(self, context):
            layout = self.layout
            if self.step == 0:
    
                user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
    
    
                # message = "BlenderKit connects from Blender to an online, " \
                #           "community built shared library of models, " \
                #           "materials, and brushes. " \
                #           "Use addon preferences to set up where files will be saved in the Global directory setting."
                #
                # utils.label_multiline(layout, text=message, width=300)
    
                layout.template_icon(icon_value=self.img.preview.icon_id, scale=18)
    
                # utils.label_multiline(layout, text="\n Let's start by searching for some cool materials?", width=300)
                op = layout.operator("wm.url_open", text='Watch Video Tutorial', icon='QUESTION')
                op.url = paths.BLENDERKIT_MANUAL
    
                message = "Operator Tutorial called with invalid step"
    
    
        def execute(self, context):
            if self.step == 0:
    
                # move mouse:
                # bpy.context.window_manager.windows[0].cursor_warp(1000, 1000)
                # show n-key sidebar (spaces[index] has to be found for view3d too:
    
                # bpy.context.window_manager.windows[0].screen.areas[5].spaces[0].show_region_ui = False
                print('running search no')
                ui_props = bpy.context.scene.blenderkitUI
    
                random_searches = [
                    ('MATERIAL','ice'),
                    ('MODEL','car'),
                    ('MODEL','vase'),
                    ('MODEL','grass'),
                    ('MODEL','plant'),
                    ('MODEL','man'),
                    ('MATERIAL','metal'),
                    ('MATERIAL','wood'),
                    ('MATERIAL','floor'),
                    ('MATERIAL','bricks'),
                ]
                random_search = random.choice(random_searches)
                ui_props.asset_type = random_search[0]
    
                bpy.context.scene.blenderkit_mat.search_keywords = ''#random_search[1]
                bpy.context.scene.blenderkit_mat.search_keywords = '+is_free:true+score_gte:1000+order:-created'#random_search[1]
    
                # search.search()
    
            return {'FINISHED'}
    
        def invoke(self, context, event):
            wm = bpy.context.window_manager
    
            img = utils.get_thumbnail('intro.jpg')
            utils.img_to_preview(img, copy_original = True)
            self.img = img
            w, a, r = utils.get_largest_area(area_type='VIEW_3D')
            if a is not None:
                a.spaces.active.show_region_ui = True
    
            return wm.invoke_props_dialog(self, width = 500)
    
    def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
    
    Vilém Duha's avatar
    Vilém Duha committed
        author_id = str(asset_data['author'].get('id'))
    
    
        layout.operator_context = 'INVOKE_DEFAULT'
    
    
        if from_panel:
            op = layout.operator('wm.blenderkit_menu_rating_upload', text='Rate')
            op.asset_name = asset_data['name']
            op.asset_id = asset_data['id']
            op.asset_type = asset_data['assetType']
    
        if from_panel and wm.get('bkit authors') is not None and author_id is not None:
    
            a = bpy.context.window_manager['bkit authors'].get(author_id)
            if a is not None:
                # utils.p('author:', a)
    
                op = layout.operator('wm.url_open', text="Open Author's Website")
    
                if a.get('aboutMeUrl') is not None:
                    op.url = a['aboutMeUrl']
    
                else:
                    op.url = paths.get_author_gallery_url(a['id'])
    
                op = layout.operator('view3d.blenderkit_search', text="Show Assets By Author")
                op.keywords = ''
                op.author_id = author_id
    
        op = layout.operator('view3d.blenderkit_search', text='Search Similar')
    
        op.tooltip = 'Search for similar assets in the library'
    
    Vilém Duha's avatar
    Vilém Duha committed
        # build search string from description and tags:
    
        op.keywords = asset_data['name']
        if asset_data.get('description'):
    
    Vilém Duha's avatar
    Vilém Duha committed
            op.keywords += ' ' + asset_data.get('description') + ' '
    
        op.keywords += ' '.join(asset_data.get('tags'))
    
    
        if asset_data.get('canDownload') != 0:
            if len(bpy.context.selected_objects) > 0 and ui_props.asset_type == 'MODEL':
                aob = bpy.context.active_object
                if aob is None:
                    aob = bpy.context.selected_objects[0]
                op = layout.operator('scene.blenderkit_download', text='Replace Active Models')
    
    Vilém Duha's avatar
    Vilém Duha committed
                # this checks if the menu got called from right-click in assetbar(then index is 0 - x) or
    
                # from a panel(then replacement happens from the active model)
    
    Vilém Duha's avatar
    Vilém Duha committed
                if from_panel:
    
    Vilém Duha's avatar
    Vilém Duha committed
                    # called from addon panel
    
    Vilém Duha's avatar
    Vilém Duha committed
                    op.asset_base_id = asset_data['assetBaseId']
    
                else:
                    op.asset_index = ui_props.active_index
    
    
    Vilém Duha's avatar
    Vilém Duha committed
                # op.asset_type = ui_props.asset_type
    
                op.model_location = aob.location
                op.model_rotation = aob.rotation_euler
                op.target_object = aob.name
                op.material_target_slot = aob.active_material_index
                op.replace = True
    
    Vilém Duha's avatar
    Vilém Duha committed
                op.replace_resolution = False
    
            # resolution replacement operator
            # if asset_data['downloaded'] == 100: # only show for downloaded/used assets
            # if ui_props.asset_type in ('MODEL', 'MATERIAL'):
            #     layout.menu(OBJECT_MT_blenderkit_resolution_menu.bl_idname)
    
            if ui_props.asset_type in ('MODEL', 'MATERIAL', 'HDR') and \
    
    Vilém Duha's avatar
    Vilém Duha committed
                    utils.get_param(asset_data, 'textureResolutionMax') is not None and \
                    utils.get_param(asset_data, 'textureResolutionMax') > 512:
    
                s = bpy.context.scene
    
                col = layout.column()
                col.operator_context = 'INVOKE_DEFAULT'
    
                if from_panel:
                    # Called from addon panel
    
                    if asset_data.get('resolution'):
                        op = col.operator('scene.blenderkit_download', text='Replace asset resolution')
                        op.asset_base_id = asset_data['assetBaseId']
                        if asset_data['assetType'] == 'MODEL':
                            o = utils.get_active_model()
                            op.model_location = o.location
                            op.model_rotation = o.rotation_euler
                            op.target_object = o.name
                            op.material_target_slot = o.active_material_index
    
    Vilém Duha's avatar
    Vilém Duha committed
                        elif asset_data['assetType'] == 'MATERIAL':
                            aob = bpy.context.active_object
                            op.model_location = aob.location
                            op.model_rotation = aob.rotation_euler
                            op.target_object = aob.name
    
                            op.material_target_slot = aob.active_material_index
    
    Vilém Duha's avatar
    Vilém Duha committed
                        op.replace_resolution = True
    
                        op.replace = False
    
    
    Vilém Duha's avatar
    Vilém Duha committed
                        op.invoke_resolution = True
                        op.max_resolution = asset_data.get('max_resolution',
                                                           0)  # str(utils.get_param(asset_data, 'textureResolutionMax'))
    
    
                elif asset_data['assetBaseId'] in s['assets used'].keys() and asset_data['assetType'] != 'hdr':
    
    Vilém Duha's avatar
    Vilém Duha committed
                    # HDRs are excluded from replacement, since they are always replaced.
    
    Vilém Duha's avatar
    Vilém Duha committed
                    # called from asset bar:
                    op = col.operator('scene.blenderkit_download', text='Replace asset resolution')
    
                    op.asset_index = ui_props.active_index
                    # op.asset_type = ui_props.asset_type
                    op.replace_resolution = True
    
                    op.replace = False
    
    Vilém Duha's avatar
    Vilém Duha committed
                    op.invoke_resolution = True
                    o = utils.get_active_model()
                    if o and o.get('asset_data'):
    
                        if o['asset_data']['assetBaseId'] == bpy.context.window_manager['search results'][
                            ui_props.active_index]:
    
    Vilém Duha's avatar
    Vilém Duha committed
                            op.model_location = o.location
                            op.model_rotation = o.rotation_euler
    
                            op.model_location = (0, 0, 0)
                            op.model_rotation = (0, 0, 0)
    
    Vilém Duha's avatar
    Vilém Duha committed
                    op.max_resolution = asset_data.get('max_resolution',
                                                       0)  # str(utils.get_param(asset_data, 'textureResolutionMax'))
                # print('operator res ', resolution)
                # op.resolution = resolution
    
    
        wm = bpy.context.window_manager
        profile = wm.get('bkit profile')
        if profile is not None:
            # validation
    
            if author_id == str(profile['user']['id']) or utils.profile_is_validator():
    
                layout.label(text='Management tools:')
    
    
                row = layout.row()
                row.operator_context = 'INVOKE_DEFAULT'
    
                op = layout.operator('wm.blenderkit_fast_metadata', text='Edit Metadata')
    
                op.asset_id = asset_data['id']
    
                op.asset_type = asset_data['assetType']
    
    Vilém Duha's avatar
    Vilém Duha committed
                if asset_data['assetType'] == 'model':
                    op = layout.operator('object.blenderkit_regenerate_thumbnail', text='Regenerate thumbnail')
                    op.asset_index = ui_props.active_index
    
                if asset_data['assetType'] == 'material':
                    op = layout.operator('object.blenderkit_regenerate_material_thumbnail', text='Regenerate thumbnail')
                    op.asset_index = ui_props.active_index
                    # op.asset_id = asset_data['id']
                    # op.asset_type = asset_data['assetType']
    
    
            if author_id == str(profile['user']['id']):
    
                row = layout.row()
                row.operator_context = 'INVOKE_DEFAULT'
                op = row.operator('object.blenderkit_change_status', text='Delete')
                op.asset_id = asset_data['id']
                op.state = 'deleted'
    
    
            if utils.profile_is_validator():
    
                layout.label(text='Dev Tools:')
    
    Vilém Duha's avatar
    Vilém Duha committed
                op = layout.operator('object.blenderkit_print_asset_debug', text='Print asset debug')
                op.asset_id = asset_data['id']
    
    
    # def draw_asset_resolution_replace(self, context, resolution):
    #     layout = self.layout
    #     ui_props = bpy.context.scene.blenderkitUI
    #
    #     op = layout.operator('scene.blenderkit_download', text=resolution)
    #     if ui_props.active_index == -3:
    #         # This happens if the command is called from addon panel
    #         o = utils.get_active_model()
    #         op.asset_base_id = o['asset_data']['assetBaseId']
    #
    #     else:
    #         op.asset_index = ui_props.active_index
    #
    #         op.asset_type = ui_props.asset_type
    #     if len(bpy.context.selected_objects) > 0:  # and ui_props.asset_type == 'MODEL':
    #         aob = bpy.context.active_object
    #         op.model_location = aob.location
    #         op.model_rotation = aob.rotation_euler
    #         op.target_object = aob.name
    #         op.material_target_slot = aob.active_material_index
    #     op.replace_resolution = True
    #     print('operator res ', resolution)
    #     op.resolution = resolution
    
    
    # class OBJECT_MT_blenderkit_resolution_menu(bpy.types.Menu):
    #     bl_label = "Replace Asset Resolution"
    #     bl_idname = "OBJECT_MT_blenderkit_resolution_menu"
    #
    #     def draw(self, context):
    #         ui_props = context.scene.blenderkitUI
    #
    
    #         # sr = bpy.context.window_manager['search results']
    
    #         # sr = bpy.context.window_manager['search results']
    
    Vilém Duha's avatar
    Vilém Duha committed
    #         # asset_data = sr[ui_props.active_index]
    #
    #         for k in resolutions.resolution_props_to_server.keys():
    #             draw_asset_resolution_replace(self, context, k)
    
    
    class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu):
        bl_label = "Asset options:"
        bl_idname = "OBJECT_MT_blenderkit_asset_menu"
    
        def draw(self, context):
            ui_props = context.scene.blenderkitUI
    
    
            sr = bpy.context.window_manager['search results']
    
            asset_data = sr[ui_props.active_index]
            draw_asset_context_menu(self.layout, context, asset_data, from_panel=False)
    
    
    def numeric_to_str(s):
        if s:
            s = str(round(s))
        else:
            s = '-'
        return s
    
    def push_op_left(layout, strength =5):
        for a in range(0, strength):
    
    Vilem Duha's avatar
    Vilem Duha committed
            layout.label(text='')
    
    
    
    def label_or_url(layout, text='', tooltip='', url='', icon_value=None, icon=None):
        '''automatically switch between different layout options for linking or tooltips'''
        layout.emboss = 'NONE'
        if url != '':
            if icon:
                op = layout.operator('wm.blenderkit_url', text=text, icon=icon)
            elif icon_value:
                op = layout.operator('wm.blenderkit_url', text=text, icon_value=icon_value)
            else:
                op = layout.operator('wm.blenderkit_url', text=text)
            op.url = url
            op.tooltip = tooltip
    
    Vilem Duha's avatar
    Vilem Duha committed
            push_op_left(layout)
    
    
            return
        if tooltip != '':
            if icon:
                op = layout.operator('wm.blenderkit_tooltip', text=text, icon=icon)
            elif icon_value:
                op = layout.operator('wm.blenderkit_tooltip', text=text, icon_value=icon_value)
            else:
                op = layout.operator('wm.blenderkit_tooltip', text=text)
            op.tooltip = tooltip
    
    Vilém Duha's avatar
    Vilém Duha committed
            # these are here to move the text to left, since operators can only center text by default
    
    Vilem Duha's avatar
    Vilem Duha committed
            push_op_left(layout)
    
            return
        if icon:
            layout.label(text=text, icon=icon)
        elif icon_value:
            layout.label(text=text, icon_value=icon_value)
        else:
            layout.label(text=text)
    
    
    class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
    
        """Generate Cycles thumbnail for model assets"""
        bl_idname = "wm.blenderkit_asset_popup"
        bl_label = "BlenderKit asset popup"
    
    Vilem Duha's avatar
    Vilem Duha committed
        width = 800
    
        @classmethod
        def poll(cls, context):
            return True
    
    
        def draw_menu(self, context, layout):
    
    Vilem Duha's avatar
    Vilem Duha committed
            # layout = layout.column()
            draw_asset_context_menu(layout, context, self.asset_data, from_panel=False)
    
        def draw_property(self, layout, left, right, icon=None, icon_value=None, url='', tooltip=''):
    
            right = str(right)
            row = layout.row()
    
    Vilem Duha's avatar
    Vilem Duha committed
            split = row.split(factor=0.35)
    
            split.alignment = 'RIGHT'
            split.label(text=left)
            split = split.split()
    
            split.alignment = 'LEFT'
    
            # split for questionmark:
            if url != '':
    
    Vilem Duha's avatar
    Vilem Duha committed
                split = split.split(factor=0.6)
    
            label_or_url(split, text=right, tooltip=tooltip, url=url, icon_value=icon_value, icon=icon)
            # additional questionmark icon where it's important?
            if url != '':
    
                split = split.split()
                op = split.operator('wm.blenderkit_url', text='', icon='QUESTION')
                op.url = url
                op.tooltip = tooltip
    
        def draw_asset_parameter(self, layout, key='', pretext=''):
            parameter = utils.get_param(self.asset_data, key)
            if parameter == None:
                return
    
            if type(parameter) == int:
                parameter = f"{parameter:,d}"
            elif type(parameter) == float:
                parameter = f"{parameter:,.1f}"
    
            self.draw_property(layout, pretext, parameter)
    
    
    Vilem Duha's avatar
    Vilem Duha committed
        def draw_description(self, layout, width=250):
    
    Vilem Duha's avatar
    Vilem Duha committed
            if len(self.asset_data['description']) > 0:
                box = layout.box()
    
    Vilem Duha's avatar
    Vilem Duha committed
                box.scale_y = 0.4
    
    Vilem Duha's avatar
    Vilem Duha committed
                box.label(text='Description')
    
    Vilem Duha's avatar
    Vilem Duha committed
                box.separator()
    
                link_more = utils.label_multiline(box, self.asset_data['description'], width=width, max_lines = 10)
                if link_more:
                    row = box.row()
                    row.scale_y = 2
                    op = row.operator('wm.blenderkit_url', text='See full description', icon='URL')
                    op.url = paths.get_asset_gallery_url(self.asset_data['assetBaseId'])
                    op.tooltip = 'Read full description on website'
    
    Vilem Duha's avatar
    Vilem Duha committed
                box.separator()
    
        def draw_properties(self, layout, width=250):
    
            if type(self.asset_data['parameters']) == list:
                mparams = utils.params_to_dict(self.asset_data['parameters'])
            else:
                mparams = self.asset_data['parameters']
    
            pcoll = icons.icon_collections["main"]
    
            box = layout.box()
    
    Vilem Duha's avatar
    Vilem Duha committed
            box.scale_y = 0.4
    
            box.label(text='Properties')
    
    Vilem Duha's avatar
    Vilem Duha committed
            box.separator()
    
            if self.asset_data.get('license') == 'cc_zero':
    
    Vilém Duha's avatar
    Vilém Duha committed
                t = 'CC Zero          '
    
                icon = pcoll['cc0']
    
            else:
                t = 'Royalty free'
                icon = pcoll['royalty_free']
    
            self.draw_property(box,
    
    Vilem Duha's avatar
    Vilem Duha committed
                               'License', t,
    
                               # icon_value=icon.icon_id,
    
                               url="https://www.blenderkit.com/docs/licenses/",
    
                               tooltip='All BlenderKit assets are available for commercial use. \n' \
    
                                       'Click to read more about BlenderKit licenses on the website'
    
                               )
    
            if upload.can_edit_asset(asset_data=self.asset_data):
                icon = pcoll[self.asset_data['verificationStatus']]
                verification_status_tooltips = {
                    'uploading': "Your asset got stuck during upload. Probably, your file was too large "
                                 "or your connection too slow or interrupting. If you have repeated issues, "
                                 "please contact us and let us know, it might be a bug",
                    'uploaded': "Your asset uploaded successfully. Yay! If it's public, "
                                "it's awaiting validation. If it's private, use it",
                    'on_hold': "Your asset needs some (usually smaller) fixes, "
                               "so we can make it public for everybody."
                               " Please check your email to see the feedback "
                               "that we send to every creator personally",
                    'rejected': "The asset has serious quality issues, " \
                                "and it's probable that it might be good to start " \
                                "all over again or try with something simpler. " \
                                "You also get personal feedback into your e-mail, " \
                                "since we believe that together, we can all learn " \
                                "to become awesome 3D artists",
                    'deleted': "You deleted this asset",
                    'validated': "Your asset passed our validation process, "
                                 "and is now available to BlenderKit users"
    
                }
                self.draw_property(box,
    
    Vilem Duha's avatar
    Vilem Duha committed
                                   'Verification',
    
                                   self.asset_data['verificationStatus'],
                                   icon_value=icon.icon_id,
                                   url="https://www.blenderkit.com/docs/validation-status/",
                                   tooltip=verification_status_tooltips[self.asset_data['verificationStatus']]
    
                                   )
    
            resolution = utils.get_param(self.asset_data, 'textureResolutionMax')
    
            if resolution is not None:
    
    Vilém Duha's avatar
    Vilém Duha committed
                fs = self.asset_data['files']
    
    
                ress = f"{int(round(resolution / 1024, 0))}K"
    
                self.draw_property(box, 'Resolution', ress,
    
                                   tooltip='Maximal resolution of textures in this asset.\n' \
                                           'Most texture asset have also lower resolutions generated.\n' \
                                           'Go to BlenderKit add-on import settings to set default resolution')
    
    Vilém Duha's avatar
    Vilém Duha committed
                if fs and len(fs) > 2 and utils.profile_is_validator():
                    resolutions = ''
                    list.sort(fs, key=lambda f: f['fileType'])
                    for f in fs:
                        if f['fileType'].find('resolution') > -1:
                            resolutions += f['fileType'][11:] + ' '
                    resolutions = resolutions.replace('_', '.')
    
    Vilem Duha's avatar
    Vilem Duha committed
                    self.draw_property(box, 'Generated', resolutions)
    
            self.draw_asset_parameter(box, key='designer', pretext='Designer')
    
            self.draw_asset_parameter(box, key='manufacturer', pretext='Manufacturer')  # TODO make them clickable!
    
            self.draw_asset_parameter(box, key='designCollection', pretext='Collection')
            self.draw_asset_parameter(box, key='designVariant', pretext='Variant')
            self.draw_asset_parameter(box, key='designYear', pretext='Design year')
    
            self.draw_asset_parameter(box, key='faceCount', pretext='Face count')
            # self.draw_asset_parameter(box, key='thumbnailScale', pretext='Preview scale')
            # self.draw_asset_parameter(box, key='purePbr', pretext='Pure PBR')
            # self.draw_asset_parameter(box, key='productionLevel', pretext='Readiness')
            # self.draw_asset_parameter(box, key='condition', pretext='Condition')
            self.draw_asset_parameter(box, key='material_style', pretext='Style')
            self.draw_asset_parameter(box, key='model_style', pretext='Style')
    
    
            if utils.get_param(self.asset_data, 'dimensionX'):
    
                t = '%s×%s×%s m' % (utils.fmt_length(mparams['dimensionX']),
    
                                    utils.fmt_length(mparams['dimensionY']),
                                    utils.fmt_length(mparams['dimensionZ']))
    
    Vilem Duha's avatar
    Vilem Duha committed
                self.draw_property(box, 'Size', t)
    
            if self.asset_data.get('filesSize'):
                fs = self.asset_data['filesSize']
                fsmb = fs // (1024 * 1024)
                fskb = fs % 1024
                if fsmb == 0:
    
    Vilem Duha's avatar
    Vilem Duha committed
                    self.draw_property(box, 'Original size', f'{fskb} KB')
    
    Vilem Duha's avatar
    Vilem Duha committed
                    self.draw_property(box, 'Original size', f'{fsmb} MB')
    
            # Tags section
            # row = box.row()
            # letters_on_row = 0
            # max_on_row = width / 10
            # for tag in self.asset_data['tags']:
            #     if tag in ('manifold', 'uv', 'non-manifold'):
            #         # these are sometimes accidentally stored in the lib
            #         continue
            #
            #     # row.emboss='NONE'
            #     # we need to split wisely
            #     remaining_row = (max_on_row - letters_on_row) / max_on_row
            #     split_factor = (len(tag) / max_on_row) / remaining_row
            #     row = row.split(factor=split_factor)
            #     letters_on_row += len(tag)
            #     if letters_on_row > max_on_row:
            #         letters_on_row = len(tag)
            #         row = box.row()
            #         remaining_row = (max_on_row - letters_on_row) / max_on_row
            #         split_factor = (len(tag) / max_on_row) / remaining_row
            #         row = row.split(factor=split_factor)
            #
            #     op = row.operator('wm')
            #     op = row.operator('view3d.blenderkit_search', text=tag)
            #     op.tooltip = f'Search items with tag {tag}'
            #     # build search string from description and tags:
            #     op.keywords = f'+tags:{tag}'
    
            # self.draw_property(box, 'Tags', self.asset_data['tags']) #TODO make them clickable!
    
            # Free/Full plan or private Access
    
            plans_tooltip = 'BlenderKit has 2 plans:\n' \
                            '  *  Free plan - more than 50% of all assets\n' \
                            '  *  Full plan - unlimited access to everything\n' \
                            'Click to go to subscriptions page'
    
            plans_link = 'https://www.blenderkit.com/plans/pricing/'
    
            if self.asset_data['isPrivate']:
                t = 'Private'
    
    Vilem Duha's avatar
    Vilem Duha committed
                self.draw_property(box, 'Access', t, icon='LOCKED')
    
            elif self.asset_data['isFree']:
                t = 'Free plan'
                icon = pcoll['free']
    
    Vilem Duha's avatar
    Vilem Duha committed
                self.draw_property(box, 'Access', t,
    
                                   icon_value=icon.icon_id,
    
                                   tooltip=plans_tooltip,
                                   url=plans_link)
    
            else:
                t = 'Full plan'
                icon = pcoll['full']
    
    Vilem Duha's avatar
    Vilem Duha committed
                self.draw_property(box, 'Access', t,
    
                                   icon_value=icon.icon_id,
                                   tooltip=plans_tooltip,
                                   url=plans_link)
    
            if utils.profile_is_validator():
                date = self.asset_data['created'][:10]
                date = f"{date[8:10]}. {date[5:7]}. {date[:4]}"
    
    Vilem Duha's avatar
    Vilem Duha committed
                self.draw_property(box, 'Created', date)
            box.separator()
    
        def draw_author_area(self, context, layout, width=330):
    
            self.draw_author(context, layout, width=width)
    
    
        def draw_author(self, context, layout, width=330):
    
            image_split = 0.25
            text_width = width
            authors = bpy.context.window_manager['bkit authors']
            a = authors.get(self.asset_data['author']['id'])
            if a is not None:  # or a is '' or (a.get('gravatarHash') is not None and a.get('gravatarImg') is None):
    
                row = layout.row()
                author_box = row.box()
                author_box.scale_y = 0.6  # get text lines closer to each other
    
                author_box.label(text='Author')  # just one extra line to give spacing
    
                if hasattr(self, 'gimg'):
    
    
    Vilem Duha's avatar
    Vilem Duha committed
                    author_left = author_box.split(factor=image_split)
    
                    author_left.template_icon(icon_value=self.gimg.preview.icon_id, scale=7)
    
                    text_area = author_left.split()
                    text_width = int(text_width * (1 - image_split))
                else:
                    text_area = author_box
    
                author_right = text_area.column()
                row = author_right.row()
                col = row.column()
    
                utils.label_multiline(col, text=a['tooltip'], width=text_width)
    
                # check if author didn't fill any data about himself and prompt him if that's the case
    
    Vilem Duha's avatar
    Vilem Duha committed
                if utils.user_is_owner(asset_data=self.asset_data) and a.get('aboutMe') is not None and len(
    
                        a.get('aboutMe', '')) == 0:
    
                    row = col.row()
                    row.enabled = False
                    row.label(text='Please introduce yourself to the community!')
    
    
                    op = col.operator('wm.blenderkit_url', text='Edit your profile')
                    op.url = 'https://www.blenderkit.com/profile'
                    op.tooltip = 'Edit your profile on BlenderKit webpage'
    
                button_row = author_box.row()
                button_row.scale_y = 2.0
    
                if a.get('aboutMeUrl') is not None:
                    url = a['aboutMeUrl']
                    text = url
                    if len(url) > 25:
                        text = url[:25] + '...'
                else:
                    url = paths.get_author_gallery_url(a['id'])
                    text = "Open Author's Profile"
    
                op = button_row.operator('wm.url_open', text=text)
                op.url = url
    
    
                op = button_row.operator('view3d.blenderkit_search', text="Find Assets By Author")
    
                op.keywords = ''
                op.author_id = self.asset_data['author']['id']
    
    
    Vilem Duha's avatar
    Vilem Duha committed
        def draw_thumbnail_box(self, layout, width=250):
    
            layout.emboss = 'NORMAL'
    
            box_thumbnail = layout.box()
    
    
            box_thumbnail.scale_y = .4
    
    Vilem Duha's avatar
    Vilem Duha committed
            box_thumbnail.template_icon(icon_value=self.img.preview.icon_id, scale=width * .12)
    
            # op = row.operator('view3d.asset_drag_drop', text='Drag & Drop from here', depress=True)
    
            # From here on, only ratings are drawn, which won't be displayed for private assets from now on.
    
            if not self.asset_data['isPrivate']:
                row = box_thumbnail.row()
                row.alignment = 'EXPAND'
    
                # display_ratings = can_display_ratings(self.asset_data)
                rc = self.asset_data.get('ratingsCount')
                show_rating_threshold = 0
                show_rating_prompt_threshold = 5
    
                if rc:
                    rcount = min(rc['quality'], rc['workingHours'])
                else:
                    rcount = 0
                if rcount >= show_rating_threshold or upload.can_edit_asset(asset_data=self.asset_data):
                    s = numeric_to_str(self.asset_data['score'])
                    q = numeric_to_str(self.asset_data['ratingsAverage'].get('quality'))
                    c = numeric_to_str(self.asset_data['ratingsAverage'].get('workingHours'))
                else:
                    s = '-'
                    q = '-'
                    c = '-'
    
                pcoll = icons.icon_collections["main"]
    
                row.emboss = 'NONE'
                op = row.operator('wm.blenderkit_tooltip', text=str(s), icon_value=pcoll['trophy'].icon_id)
                op.tooltip = 'Asset score calculated from averaged user ratings. \n\n' \
                             'Score = quality × complexity × 10*\n\n *Happiness multiplier'
                row.label(text='   ')
    
                tooltip_extension = f'.\n\nRatings results are shown for assets with more than {show_rating_threshold} ratings'
                op = row.operator('wm.blenderkit_tooltip', text=str(q), icon='SOLO_ON')
                op.tooltip = f"Quality, average from {rc['quality']} ratings" \
                             f"{tooltip_extension if rcount <= show_rating_threshold else ''}"
                row.label(text='   ')
    
                op = row.operator('wm.blenderkit_tooltip', text=str(c), icon_value=pcoll['dumbbell'].icon_id)
                op.tooltip = f"Complexity, average from {rc['workingHours']} ratings" \
                             f"{tooltip_extension if rcount <= show_rating_threshold else ''}"
    
                if rcount <= show_rating_prompt_threshold:
                    box_thumbnail.alert = True
                    box_thumbnail.label(text=f"")
                    box_thumbnail.label(text=f"This asset has only {rcount} rating{'' if rcount == 1 else 's'}, please rate.")
                    # box_thumbnail.label(text=f"Please rate this asset.")
    
            row = box_thumbnail.row()
            row.alert = False
    
            row.scale_y = 3
            ui_props = bpy.context.scene.blenderkitUI
            row.prop(ui_props, 'drag_init_button', icon='MOUSE_LMB_DRAG', text='Click / Drag from here', emboss=True)
    
        def draw_menu_desc_author(self, context, layout, width=330):
    
            box = layout.column()
    
            box.emboss = 'NORMAL'
            # left - tooltip & params
            row = box.row()
    
            split_factor = 0.7
    
    Vilem Duha's avatar
    Vilem Duha committed
            split_left = row.split(factor=split_factor)
            col = split_left.column()
            width_left = int(width * split_factor)
            self.draw_description(col, width=width_left)
    
            self.draw_properties(col, width=width_left)
    
    Vilem Duha's avatar
    Vilem Duha committed
            split_right = split_left.split()
            col = split_right.column()
            self.draw_menu(context, col)
    
            self.draw_author_area(context, box, width=width)
    
    Vilem Duha's avatar
    Vilem Duha committed
            # self.draw_author_area(context, box, width=width)
            #
            # col = box.column_flow(columns=2)
            # self.draw_menu(context, col)
            #
            #
            # # self.draw_description(box, width=int(width))
            # self.draw_properties(box, width=int(width))
    
    
        def draw(self, context):
            ui_props = context.scene.blenderkitUI
    
    
            sr = bpy.context.window_manager['search results']
    
            asset_data = sr[ui_props.active_index]
    
            self.asset_data = asset_data
    
            layout = self.layout
    
            # top draggabe bar with name of the asset
            top_row = layout.row()
            top_drag_bar = top_row.box()
    
            bcats  = bpy.context.window_manager['bkit_categories']
    
            cat_path = categories.get_category_path(bcats,
    
                                                    self.asset_data['category'])[1:]
    
    
    
            cat_path_names = categories.get_category_name_path(bcats,
                                            self.asset_data['category'])[1:]
    
            aname = asset_data['displayName']
    
    Vilém Duha's avatar
    Vilém Duha committed
            aname = aname[0].upper() + aname[1:]
    
            if 1:
                name_row = top_drag_bar.row()
                # name_row = name_row.split(factor=0.5)
                # name_row = name_row.column()
                # name_row = name_row.row()
                for i, c in enumerate(cat_path):
                    cat_name = cat_path_names[i]
    
                    op = name_row.operator('view3d.blenderkit_asset_bar', text=cat_name + '     >', emboss=False)
    
                    op.do_search = True
                    op.keep_running = True
                    op.tooltip = f"Browse {cat_name} category"
                    op.category = c
                    # name_row.label(text='>')
    
                name_row.label(text=aname)
                push_op_left(name_row, strength = 3)
    
                op = name_row.operator('view3d.close_popup_button', text='', icon = 'CANCEL')
    
    
            # for i,c in enumerate(cat_path_names):
            #     cat_path_names[i] = c.capitalize()
            # cat_path_names_string = ' > '.join(cat_path_names)
            # # box.label(text=cat_path)
            #
            #
            #
            #
            # # name_row.label(text='                                           ')
            # top_drag_bar.label(text=f'{cat_path_names_string} > {aname}')
    
            # left side
            row = layout.row(align=True)
    
    Vilem Duha's avatar
    Vilem Duha committed
            split_ratio = 0.45
            split_left = row.split(factor=split_ratio)
            left_column = split_left.column()
    
    Vilem Duha's avatar
    Vilem Duha committed
            self.draw_thumbnail_box(left_column, width=int(self.width * split_ratio))
    
    Vilem Duha's avatar
    Vilem Duha committed
            # self.draw_description(left_column, width = int(self.width*split_ratio))
    
            # right split
            split_right = split_left.split()
    
    Vilem Duha's avatar
    Vilem Duha committed
            self.draw_menu_desc_author(context, split_right, width=int(self.width * (1 - split_ratio)))
    
    Vilem Duha's avatar
    Vilem Duha committed
            if not utils.user_is_owner(asset_data=asset_data):
    
    Vilem Duha's avatar
    Vilem Duha committed
                # Draw ratings, but not for owners of assets - doesn't make sense.
    
    Vilem Duha's avatar
    Vilem Duha committed
                ratings_box = layout.box()
                ratings.draw_ratings_menu(self, context, ratings_box)
            # else:
            #     ratings_box.label('Here you should find ratings, but you can not rate your own assets ;)')
    
            tip_box = layout.box()
            tip_box.label(text=self.tip)
    
        def execute(self, context):
    
            wm = context.window_manager
            ui_props = context.scene.blenderkitUI
            ui_props.draw_tooltip = False
    
            sr = bpy.context.window_manager['search results']
    
            asset_data = sr[ui_props.active_index]
            self.img = ui.get_large_thumbnail_image(asset_data)
    
            utils.img_to_preview(self.img, copy_original = True)
    
    
            self.asset_type = asset_data['assetType']
    
            self.asset_id = asset_data['id']
    
            # self.tex = utils.get_hidden_texture(self.img)
            # self.tex.update_tag()
    
            authors = bpy.context.window_manager['bkit authors']
            a = authors.get(asset_data['author']['id'])
    
    
            if a is not None and a.get('gravatarImg') is not None:
    
                self.gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash'])
    
    
            bl_label = asset_data['name']
    
            self.tip = search.get_random_tip()
            self.tip = self.tip.replace('\n', '')
    
    Vilém Duha's avatar
    Vilém Duha committed
    
            # pre-fill ratings
            self.prefill_ratings()
    
    
            return wm.invoke_popup(self, width=self.width)
    
    class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu):
        bl_label = "BlenderKit login/signup:"
        bl_idname = "OBJECT_MT_blenderkit_login_menu"
    
        def draw(self, context):
            layout = self.layout
    
            # utils.label_multiline(layout, text=message)
            draw_login_buttons(layout)
    
    
    Vilem Duha's avatar
    Vilem Duha committed
    class SetCategoryOperator(bpy.types.Operator):
        """Visit subcategory"""
        bl_idname = "view3d.blenderkit_set_category"
        bl_label = "BlenderKit Set Active Category"
    
    Vilém Duha's avatar
    Vilém Duha committed
        bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
    
    Vilem Duha's avatar
    Vilem Duha committed
    
        category: bpy.props.StringProperty(
            name="Category",
            description="set this category active",
            default="")
    
        asset_type: bpy.props.StringProperty(
            name="Asset Type",
            description="asset type",
            default="")
    
        @classmethod
        def poll(cls, context):
            return True
    
        def execute(self, context):
            acat = bpy.context.window_manager['active_category'][self.asset_type]
            if self.category == '':
                acat.remove(acat[-1])
            else:
                acat.append(self.category)
            # we have to write back to wm. Thought this should happen with original list.
            bpy.context.window_manager['active_category'][self.asset_type] = acat
            return {'FINISHED'}
    
    
    class ClosePopupButton(bpy.types.Operator):
        """Visit subcategory"""
        bl_idname = "view3d.close_popup_button"
        bl_label = "BlenderKit close popup"
        bl_options = {'REGISTER', 'INTERNAL'}
    
        @classmethod
        def poll(cls, context):
            return True
    
        def win_close(self):
            VK_ESCAPE = 0x1B
            ctypes.windll.user32.keybd_event(VK_ESCAPE)
            print('hit escape')
            return True
    
        def mouse_trick(self,context,x,y):
            # import time
            context.area.tag_redraw()
            w = context.window
            w.cursor_warp(w.x+15,w.y+w.height-15);
            # time.sleep(.12)
            w.cursor_warp(x,y);
            context.area.tag_redraw()
    
    
        def invoke(self, context, event):