GPencil Tools: Canvas rotate improvement
[blender-addons.git] / blenderkit / ratings_utils.py
blobfe2643e1746905e8f34f7ef493703c6b0147b3a0
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # mainly update functions and callbacks for ratings properties, here to avoid circular imports.
20 import bpy
21 from blenderkit import utils, paths, tasks_queue, rerequests
23 from bpy.props import (
24 IntProperty,
25 FloatProperty,
26 FloatVectorProperty,
27 StringProperty,
28 EnumProperty,
29 BoolProperty,
30 PointerProperty,
33 import threading
34 import requests
35 import logging
37 bk_logger = logging.getLogger('blenderkit')
40 def upload_rating_thread(url, ratings, headers):
41 ''' Upload rating thread function / disconnected from blender data.'''
42 bk_logger.debug('upload rating ' + url + str(ratings))
43 for rating_name, score in ratings:
44 if (score != -1 and score != 0):
45 rating_url = url + rating_name + '/'
46 data = {
47 "score": score, # todo this kind of mixing is too much. Should have 2 bkit structures, upload, use
50 try:
51 r = rerequests.put(rating_url, data=data, verify=True, headers=headers)
53 except requests.exceptions.RequestException as e:
54 print('ratings upload failed: %s' % str(e))
57 def send_rating_to_thread_quality(url, ratings, headers):
58 '''Sens rating into thread rating, main purpose is for tasks_queue.
59 One function per property to avoid lost data due to stashing.'''
60 thread = threading.Thread(target=upload_rating_thread, args=(url, ratings, headers))
61 thread.start()
64 def send_rating_to_thread_work_hours(url, ratings, headers):
65 '''Sens rating into thread rating, main purpose is for tasks_queue.
66 One function per property to avoid lost data due to stashing.'''
67 thread = threading.Thread(target=upload_rating_thread, args=(url, ratings, headers))
68 thread.start()
71 def store_rating_local_empty(asset_id):
72 context = bpy.context
73 context.window_manager['asset ratings'] = context.window_manager.get('asset ratings', {})
74 context.window_manager['asset ratings'][asset_id] = context.window_manager['asset ratings'].get(asset_id, {})
77 def store_rating_local(asset_id, type='quality', value=0):
78 context = bpy.context
79 context.window_manager['asset ratings'] = context.window_manager.get('asset ratings', {})
80 context.window_manager['asset ratings'][asset_id] = context.window_manager['asset ratings'].get(asset_id, {})
81 context.window_manager['asset ratings'][asset_id][type] = value
84 def get_rating(asset_id, headers):
85 '''
86 Retrieve ratings from BlenderKit server. Can be run from a thread
87 Parameters
88 ----------
89 asset_id
90 headers
92 Returns
93 -------
94 ratings - dict of type:value ratings
95 '''
96 url = paths.get_api_url() + 'assets/' + asset_id + '/rating/'
97 params = {}
98 r = rerequests.get(url, params=params, verify=True, headers=headers)
99 print(r.text)
100 rj = r.json()
101 ratings = {}
102 # store ratings - send them to task queue
103 for r in rj['results']:
104 ratings[r['ratingType']] = r['score']
105 tasks_queue.add_task((store_rating_local,(asset_id, r['ratingType'], r['score'])))
106 # store_rating_local(asset_id, type = r['ratingType'], value = r['score'])
108 if len(rj['results'])==0:
109 # store empty ratings too, so that server isn't checked repeatedly
110 tasks_queue.add_task((store_rating_local_empty,(asset_id,)))
111 return ratings
114 def get_rating_local(asset_id):
115 context = bpy.context
116 context.window_manager['asset ratings'] = context.window_manager.get('asset ratings', {})
117 rating = context.window_manager['asset ratings'].get(asset_id)
118 if rating:
119 return rating.to_dict()
120 return None
123 def update_ratings_quality(self, context):
124 user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
125 api_key = user_preferences.api_key
127 headers = utils.get_headers(api_key)
129 if not (hasattr(self, 'rating_quality')):
130 # first option is for rating of assets that are from scene
131 asset = self.id_data
132 bkit_ratings = asset.bkit_ratings
133 asset_id = asset['asset_data']['id']
134 else:
135 # this part is for operator rating:
136 bkit_ratings = self
137 asset_id = self.asset_id
139 if bkit_ratings.rating_quality > 0.1:
140 url = paths.get_api_url() + f'assets/{asset_id}/rating/'
142 store_rating_local(asset_id, type='quality', value=bkit_ratings.rating_quality)
144 ratings = [('quality', bkit_ratings.rating_quality)]
145 tasks_queue.add_task((send_rating_to_thread_quality, (url, ratings, headers)), wait=2.5, only_last=True)
148 def update_ratings_work_hours(self, context):
149 user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
150 api_key = user_preferences.api_key
151 headers = utils.get_headers(api_key)
152 if not (hasattr(self, 'rating_work_hours')):
153 # first option is for rating of assets that are from scene
154 asset = self.id_data
155 bkit_ratings = asset.bkit_ratings
156 asset_id = asset['asset_data']['id']
157 else:
158 # this part is for operator rating:
159 bkit_ratings = self
160 asset_id = self.asset_id
162 if bkit_ratings.rating_work_hours > 0.45:
163 url = paths.get_api_url() + f'assets/{asset_id}/rating/'
165 store_rating_local(asset_id, type='working_hours', value=bkit_ratings.rating_work_hours)
167 ratings = [('working_hours', round(bkit_ratings.rating_work_hours, 1))]
168 tasks_queue.add_task((send_rating_to_thread_work_hours, (url, ratings, headers)), wait=2.5, only_last=True)
171 def update_quality_ui(self, context):
172 '''Converts the _ui the enum into actual quality number.'''
173 user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
174 if user_preferences.api_key == '':
175 # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
176 # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
177 # return
178 bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
179 message='Please login/signup to rate assets. Clicking OK takes you to web login.')
180 # self.rating_quality_ui = '0'
181 self.rating_quality = int(self.rating_quality_ui)
184 def update_ratings_work_hours_ui(self, context):
185 user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
186 if user_preferences.api_key == '':
187 # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
188 # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
189 # return
190 bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
191 message='Please login/signup to rate assets. Clicking OK takes you to web login.')
192 # self.rating_work_hours_ui = '0'
193 self.rating_work_hours = float(self.rating_work_hours_ui)
196 def update_ratings_work_hours_ui_1_5(self, context):
197 user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
198 if user_preferences.api_key == '':
199 # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
200 # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
201 # return
202 bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
203 message='Please login/signup to rate assets. Clicking OK takes you to web login.')
204 # self.rating_work_hours_ui_1_5 = '0'
205 self.rating_work_hours = float(self.rating_work_hours_ui_1_5)
208 def update_ratings_work_hours_ui_1_10(self, context):
209 user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
210 if user_preferences.api_key == '':
211 # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
212 # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
213 # return
214 bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
215 message='Please login/signup to rate assets. Clicking OK takes you to web login.')
216 # self.rating_work_hours_ui_1_5 = '0'
217 # print('updating 1-5')
218 # print(float(self.rating_work_hours_ui_1_5))
219 self.rating_work_hours = float(self.rating_work_hours_ui_1_10)
222 def stars_enum_callback(self, context):
223 '''regenerates the enum property used to display rating stars, so that there are filled/empty stars correctly.'''
224 items = []
225 for a in range(0, 10):
226 if self.rating_quality < a + 1:
227 icon = 'SOLO_OFF'
228 else:
229 icon = 'SOLO_ON'
230 # has to have something before the number in the value, otherwise fails on registration.
231 items.append((f'{a + 1}', f'{a + 1}', '', icon, a + 1))
232 return items
235 class RatingsProperties():
236 message: StringProperty(
237 name="message",
238 description="message",
239 default="Rating asset",
240 options={'SKIP_SAVE'})
242 asset_id: StringProperty(
243 name="Asset Base Id",
244 description="Unique id of the asset (hidden)",
245 default="",
246 options={'SKIP_SAVE'})
248 asset_name: StringProperty(
249 name="Asset Name",
250 description="Name of the asset (hidden)",
251 default="",
252 options={'SKIP_SAVE'})
254 asset_type: StringProperty(
255 name="Asset type",
256 description="asset type",
257 default="",
258 options={'SKIP_SAVE'})
260 rating_quality: IntProperty(name="Quality",
261 description="quality of the material",
262 default=0,
263 min=-1, max=10,
264 update=update_ratings_quality,
265 options={'SKIP_SAVE'})
267 # the following enum is only to ease interaction - enums support 'drag over' and enable to draw the stars easily.
268 rating_quality_ui: EnumProperty(name='rating_quality_ui',
269 items=stars_enum_callback,
270 description='Rating stars 0 - 10',
271 default=0,
272 update=update_quality_ui,
273 options={'SKIP_SAVE'})
275 rating_work_hours: FloatProperty(name="Work Hours",
276 description="How many hours did this work take?",
277 default=0.00,
278 min=0.0, max=300,
279 update=update_ratings_work_hours,
280 options={'SKIP_SAVE'}
283 high_rating_warning = "This is a high rating, please be sure to give such rating only to amazing assets"
285 possible_wh_values = [0,.5,1,2,3,4,5,6,8,10,15,20,30,50,100,150,200,250]
286 items_models = [('0', '0', ''),
287 ('.5', '0.5', ''),
288 ('1', '1', ''),
289 ('2', '2', ''),
290 ('3', '3', ''),
291 ('4', '4', ''),
292 ('5', '5', ''),
293 ('6', '6', ''),
294 ('8', '8', ''),
295 ('10', '10', ''),
296 ('15', '15', ''),
297 ('20', '20', ''),
298 ('30', '30', high_rating_warning),
299 ('50', '50', high_rating_warning),
300 ('100', '100', high_rating_warning),
301 ('150', '150', high_rating_warning),
302 ('200', '200', high_rating_warning),
303 ('250', '250', high_rating_warning),
305 rating_work_hours_ui: EnumProperty(name="Work Hours",
306 description="How many hours did this work take?",
307 items=items_models,
308 default='0', update=update_ratings_work_hours_ui,
309 options={'SKIP_SAVE'}
311 possible_wh_values_1_5 = [0,.2, .5,1,2,3,4,5]
313 items_1_5 = [('0', '0', ''),
314 ('.2', '0.2', ''),
315 ('.5', '0.5', ''),
316 ('1', '1', ''),
317 ('2', '2', ''),
318 ('3', '3', ''),
319 ('4', '4', ''),
320 ('5', '5', '')
322 rating_work_hours_ui_1_5: EnumProperty(name="Work Hours",
323 description="How many hours did this work take?",
324 items=items_1_5,
325 default='0',
326 update=update_ratings_work_hours_ui_1_5,
327 options={'SKIP_SAVE'}
329 possible_wh_values_1_10 = [0,1,2,3,4,5,6,7,8,9,10]
331 items_1_10= [('0', '0', ''),
332 ('1', '1', ''),
333 ('2', '2', ''),
334 ('3', '3', ''),
335 ('4', '4', ''),
336 ('5', '5', ''),
337 ('6', '6', ''),
338 ('7', '7', ''),
339 ('8', '8', ''),
340 ('9', '9', ''),
341 ('10', '10', '')
343 rating_work_hours_ui_1_10: EnumProperty(name="Work Hours",
344 description="How many hours did this work take?",
345 items= items_1_10,
346 default='0',
347 update=update_ratings_work_hours_ui_1_10,
348 options={'SKIP_SAVE'}
351 def prefill_ratings(self):
352 # pre-fill ratings
353 ratings = get_rating_local(self.asset_id)
354 if ratings and ratings.get('quality'):
355 self.rating_quality = ratings['quality']
356 if ratings and ratings.get('working_hours'):
357 wh = int(ratings['working_hours'])
358 whs = str(wh)
359 if wh in self.possible_wh_values:
360 self.rating_work_hours_ui = whs
361 if wh < 6 and wh in self.possible_wh_values_1_5:
362 self.rating_work_hours_ui_1_5 = whs
363 if wh < 11 and wh in self.possible_wh_values_1_10:
364 self.rating_work_hours_ui_1_10 = whs