class UserRequestForm(ModelFormWidget): TITLE = 'Access request' MODEL = AccessRequest FIELDSETS = [ 'resource', '_requirements', 'reason' ] CREATE_BTN_LABEL = '<i class="plus icon"></i> Submit request' HAS_CANCEL_BTN_ON_ADD = False HAS_CANCEL_BTN_ON_EDIT = False def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._user_request_app = kwargs.get('user_request_app') self._requirements = ControlLabel('Requirements', visible=False) self.resource.changed_event = self.__resource_changed_evt def __resource_changed_evt(self): if self.resource.value: resource = Resource.objects.get(pk=self.resource.value) self._requirements.value = f'<h3>{resource.name}</h3>{resource.access_req}' self._requirements.show() else: self._requirements.hide() def validate_object(self, obj): obj.requested_by = PyFormsMiddleware.user() return obj def save_object(self, obj, **kwargs): self._user_request_app.populate_list() return super().save_object(obj, **kwargs) def delete_event(self): res = super().delete_event() self._user_request_app.populate_list() return res
class KaryML_Main(BaseWidget): LENGTH_FEATURE = "Chromosome length" AREA_FEATURE = "Chromosome area" CENTROMERIC_INDEX_FEATURE = "Centromeric Index" BANDING_PATTERN_FEATURE = "Banding pattern" FEATURES = [ LENGTH_FEATURE, CENTROMERIC_INDEX_FEATURE, BANDING_PATTERN_FEATURE ] APP_NAME = 'KaryML Framework' def __init__(self): super(KaryML_Main, self).__init__(self.APP_NAME) self._app_title = ControlLabel(self.APP_NAME) self._input_image_path = ControlFile('Input image') self._pairs_path = ControlFile('Expected karyotype (optional)') self._features_label = ControlLabel("Chose features to be extracted") self._f1_check_box = ControlCheckBox(label=self.LENGTH_FEATURE, default=True) self._f1_check_box.changed_event = self._f1_check_box_changed self._f2_check_box = ControlCheckBox(label=self.CENTROMERIC_INDEX_FEATURE, default=True) self._f2_check_box.changed_event = self._f2_check_box_changed self._f3_check_box = ControlCheckBox(label=self.BANDING_PATTERN_FEATURE, default=True) self._f3_check_box.changed_event = self._f3_check_box_changed self._f4_check_box = ControlCheckBox(label=self.AREA_FEATURE, default=True) self._f4_check_box.changed_event = self._f4_check_box_changed self._eu_dist = ControlButton(EUCLIDEAN_DISTANCE) self._we_eu_dist = ControlButton(WEIGHTED_EUCLIDEAN_DISTANCE) self._man_dist = ControlButton(MANHATTAN_DISTANCE) self._dist_label = ControlLabel(label="Distance to use: " + EUCLIDEAN_DISTANCE.upper(), default="Distance to use: " + EUCLIDEAN_DISTANCE) self._f1_w = ControlSlider(label="Chromosome length", default=25, minimum=0, maximum=100, visible=False) self._f2_w = ControlSlider(label=" Centromeric Index", default=25, minimum=0, maximum=100, visible=False) self._f3_w = ControlSlider(label=" Banding pattern", default=25, minimum=0, maximum=100, visible=False) self._f4_w = ControlSlider(label="Chromosome area", default=25, minimum=0, maximum=100, visible=False) self._epochs_no = ControlSlider(label=" Epochs Nr.", default=200000, minimum=50000, maximum=400000) self._rows = ControlSlider(label=" Map rows", default=50, minimum=10, maximum=100) self._cols = ControlSlider(label="Map columns", default=50, minimum=10, maximum=100) self.errors_label_text = ControlLabel(label="Errors:", default="Errors:", visible=True) self.errors_label = ControlLabel(label="Errors", default="", visible=False) self.info_label_text = ControlLabel(label="Info:", default="Info:", visible=True) self.info_label = ControlLabel(label="Info", default="", visible=False) self._button = ControlButton('Start {}'.format(self.APP_NAME)) self._button.value = self._runKarySomAction self._eu_dist.value = self.__dist_changed_eu self._we_eu_dist.value = self.__dist_changed_we_eu self._man_dist.value = self.__dist_changed_man self.t = None @staticmethod def set_message(label, message): label.value = message label.show() def get_number_of_selected_features(self): return len([2 ** j for j in range(4) if [self._f1_check_box, self._f2_check_box, self._f3_check_box, self._f4_check_box][j].value]) def _runKarySomAction(self): """Button action event""" dist_lbl = self.manage_pre_run_gui() self.errors_label.hide() if self.get_number_of_selected_features() < 1: self.set_message(self.errors_label, "At least one feature is required") return cfg = self.__initialize_cfg(dist_lbl) if dist_lbl == WEIGHTED_EUCLIDEAN_DISTANCE and self.get_sum_of_weights() != 100: self.set_message(self.errors_label, "Sum of weights must be 100") return if not os.path.exists(self._input_image_path.value): self.set_message(self.errors_label, "Image path {} doesn't exists".format(self._input_image_path.value)) return print("Start processing using cfg:") pprint.pprint(cfg) self.t = Thread(target=start_process_for_one_image, args=[cfg["input"], cfg["mdist"], "", sum(cfg["features"]), cfg["epochs"], cfg["rows"], cfg["cols"], cfg["weights"], self]) self.t.start() msg = "" if not os.path.isfile(self._pairs_path.value): msg += "Expected karyotype missing or file not exists. PrecKar value won't be calculated." else: msg += "Karyotype file found. Will compute PrecKar value" dir_path = '.'.join(self._input_image_path.value.split('.')[:-1]) if not os.path.isdir(dir_path): os.makedirs(dir_path) shutil.copy2(self._pairs_path.value, os.path.join(dir_path, "pairs.txt")) self.set_message(self.info_label, msg + "\n" + "Start KarySOM for current configuration. Processing...") def manage_pre_run_gui(self): if self.info_label.visible is True: self.info_label.hide() if self._dist_label.value.split()[len(self._dist_label.value.split()) - 2] == "Weighted": dist_lbl = " ".join(self._dist_label.value.split()[len(self._dist_label.value.split()) - 2:]) else: dist_lbl = self._dist_label.value.split()[len(self._dist_label.value.split()) - 1] return dist_lbl def __initialize_cfg(self, dist_lbl): cfg = {"distance": dist_lbl, "feature_names": [self.FEATURES[i] for i in [j for j in range(3) if [self._f1_check_box.value, self._f2_check_box.value, self._f3_check_box.value, self._f4_check_box.value][j]]], "features": [2 ** j for j in range(4) if [self._f1_check_box, self._f2_check_box, self._f3_check_box, self._f4_check_box][j].value], "epochs": self._epochs_no.value, "input": self._input_image_path.value, "pairs": self._pairs_path.value, "rows": self._rows.value, "cols": self._cols.value, "weights": dict()} if self._f1_check_box.value: cfg["weights"][1] = self._f1_w.value / 100 if self._f2_check_box.value: cfg["weights"][2] = self._f2_w.value / 100 if self._f3_check_box.value: cfg["weights"][3] = self._f3_w.value / 100 if self._f4_check_box.value: cfg["weights"][4] = self._f4_w.value / 100 cfg["mdist"] = False if dist_lbl == MANHATTAN_DISTANCE: cfg["mdist"] = True return cfg def __dist_changed_eu(self): self._dist_label.value = "Distance to use: " + EUCLIDEAN_DISTANCE self._dist_label.label = "Distance to use: " + EUCLIDEAN_DISTANCE.upper() self._f1_w.hide() self._f2_w.hide() self._f3_w.hide() self._f4_w.hide() self.info_label.hide() def __dist_changed_we_eu(self): self._dist_label.value = "Distance to use: " + WEIGHTED_EUCLIDEAN_DISTANCE self._dist_label.label = "Distance to use: " + WEIGHTED_EUCLIDEAN_DISTANCE.upper() if self._f1_check_box.value: self._f1_w.show() if self._f2_check_box.value: self._f2_w.show() if self._f3_check_box.value: self._f3_w.show() if self._f4_check_box.value: self._f4_w.show() self.info_label.hide() def __dist_changed_man(self): self._dist_label.value = "Distance to use: " + MANHATTAN_DISTANCE self._dist_label.label = "Distance to use: " + MANHATTAN_DISTANCE.upper() self._f1_w.hide() self._f2_w.hide() self._f3_w.hide() self._f4_w.hide() self.info_label.hide() def get_sum_of_weights(self): weights_sum = 0 if self._f1_check_box.value: weights_sum += self._f1_w.value if self._f2_check_box.value: weights_sum += self._f2_w.value if self._f3_check_box.value: weights_sum += self._f3_w.value if self._f4_check_box.value: weights_sum += self._f4_w.value return weights_sum def _f1_check_box_changed(self): if self._f1_check_box.value and "weighted" in self._dist_label.value.lower(): self._f1_w.show() else: self._f1_w.hide() def _f2_check_box_changed(self): if self._f2_check_box.value and "weighted" in self._dist_label.value.lower(): self._f2_w.show() else: self._f2_w.hide() def _f3_check_box_changed(self): if self._f3_check_box.value and "weighted" in self._dist_label.value.lower(): self._f3_w.show() else: self._f3_w.hide() def _f4_check_box_changed(self): if self._f4_check_box.value and "weighted" in self._dist_label.value.lower(): self._f4_w.show() else: self._f4_w.hide()
class PathGUI(DatasetGUI, Path, BaseWidget): def __init__(self, object2d=None): DatasetGUI.__init__(self) Path.__init__(self, object2d) BaseWidget.__init__(self, '2D Object', parent_win=object2d) self.create_tree_nodes() self._mark_pto_btn = ControlButton('&Mark point', checkable=True, icon=conf.ANNOTATOR_ICON_MARKPLACE ) self._sel_pto_btn = ControlButton('&Select point', default=self.__sel_pto_btn_event, icon=conf.ANNOTATOR_ICON_SELECTPOINT) self._del_path_btn = ControlButton('Delete path', default=self.__del_path_btn_event, icon=conf.ANNOTATOR_ICON_DELETEPATH, visible=False) self._del_point_btn = ControlButton('Delete point', default=self.__del_point_btn_event, icon=conf.ANNOTATOR_ICON_SELECTPOINT, visible=False) self._use_referencial = ControlCheckBox('Apply') self._referencial_pt = ControlText('Referencial', changed_event=self.__referencial_pt_changed_event) self._interpolation_title = ControlLabel('Interpolation', default='INTERPOLATION', visible=False) self._interpolation_mode = ControlCombo('Mode', changed_event=self.__interpolation_mode_changed_event, visible=False) self._interpolate_btn = ControlButton('Apply', default=self.__interpolate_btn_event, icon=conf.ANNOTATOR_ICON_INTERPOLATE, visible=False) self._remove_btn = ControlButton('Remove dataset',default=self.__remove_path_dataset, icon=conf.ANNOTATOR_ICON_REMOVE) self._pickcolor = ControlButton('Pick a color', default=self.__pick_a_color_event) self._show_object_name = ControlCheckBox('Show object name', default=False) self._show_name = ControlCheckBox('Show name', default=False) self._formset = [ '_name', ('_show_name', '_show_object_name'), ('_referencial_pt', '_use_referencial'), '_remove_btn', ' ', '_pickcolor', ' ', ('_mark_pto_btn', '_sel_pto_btn'), '_del_path_btn', '_del_point_btn', '_interpolation_title', ('_interpolation_mode', '_interpolate_btn'), ' ' ] #### set controls ############################################## self._interpolation_mode.add_item("Auto", -1) self._interpolation_mode.add_item("Linear", 'slinear') self._interpolation_mode.add_item("Quadratic", 'quadratic') self._interpolation_mode.add_item("Cubic", 'cubic') ###################################################################### ### FUNCTIONS ######################################################## ###################################################################### def get_velocity(self, index): p1 = self.get_position(index) p2 = self.get_position(index-1) if p1 is None or p2 is None: return None return p2[0]-p1[0], p2[1]-p1[1] def get_acceleration(self, index): v1 = self.get_velocity(index) v2 = self.get_velocity(index-1) if v1 is None or v2 is None: return None return v2[0]-v1[0], v2[1]-v1[1] def get_position_x_value(self, index): v = self.get_position(index) return v[0] if v is not None else None def get_position_y_value(self, index): v = self.get_position(index) return v[1] if v is not None else None def get_velocity_x_value(self, index): v = self.get_velocity(index) return v[0] if v is not None else None def get_velocity_y_value(self, index): v = self.get_velocity(index) return v[1] if v is not None else None def get_velocity_absolute_value(self, index): v = self.get_velocity(index) return math.sqrt(v[1]**2+v[0]**2) if v is not None else None def get_acceleration_x_value(self, index): v = self.get_acceleration(index) return v[0] if v is not None else None def get_acceleration_y_value(self, index): v = self.get_acceleration(index) return v[1] if v is not None else None def get_acceleration_absolute_value(self, index): v = self.get_acceleration(index) return math.sqrt(v[1]**2+v[0]**2) if v is not None else None ###################################################################### ### AUX FUNCTIONS #################################################### ###################################################################### def create_popupmenu_actions(self): self.tree.add_popup_menu_option( label='Duplicate', function_action=self.clone_path, item=self.treenode, icon=conf.ANNOTATOR_ICON_DUPLICATE ) self.tree.add_popup_menu_option( label='Remove', function_action=self.__remove_path_dataset, item=self.treenode, icon=conf.ANNOTATOR_ICON_DELETE ) def create_tree_nodes(self): self.treenode = self.tree.create_child(self.name, icon=conf.ANNOTATOR_ICON_PATH, parent=self.parent_treenode ) self.treenode.win = self self.create_popupmenu_actions() self.create_group_node('position', icon=conf.ANNOTATOR_ICON_POSITION) self.create_data_node('position > x', icon=conf.ANNOTATOR_ICON_X) self.create_data_node('position > y', icon=conf.ANNOTATOR_ICON_Y) self.create_group_node('velocity', icon=conf.ANNOTATOR_ICON_VELOCITY) self.create_data_node('velocity > x', icon=conf.ANNOTATOR_ICON_X) self.create_data_node('velocity > y', icon=conf.ANNOTATOR_ICON_Y) self.create_data_node('velocity > absolute', icon=conf.ANNOTATOR_ICON_INFO) self.create_group_node('acceleration', icon=conf.ANNOTATOR_ICON_ACCELERATION) self.create_data_node('acceleration > x', icon=conf.ANNOTATOR_ICON_X) self.create_data_node('acceleration > y', icon=conf.ANNOTATOR_ICON_Y) self.create_data_node('acceleration > absolute', icon=conf.ANNOTATOR_ICON_INFO) ###################################################################### ### GUI EVENTS ####################################################### ###################################################################### def __del_point_btn_event(self): video_index = self.mainwindow._player.video_index-1 if video_index<0:return self.set_position(video_index, None, None) try: self._sel_pts.remove(video_index) self._interpolate_btn.hide() self._interpolation_mode.hide() self._interpolation_title.hide() self._del_path_btn.hide() self._tmp_points = [] except ValueError: self.calculate_tmp_interpolation() self.mainwindow._player.refresh() if self.visible: if len(self._sel_pts)==2: self._del_path_btn.show() else: self._del_path_btn.hide() def __sel_pto_btn_event(self): video_index = self.mainwindow._player.video_index-1 if video_index<0:return position = self[video_index] if position is None: return if video_index in self._sel_pts: self._sel_pts.remove(video_index) else: self._sel_pts.append(video_index) self._sel_pts = sorted(self._sel_pts) if self.visible: #store a temporary path for interpolation visualization if len(self._sel_pts) >= 2: ######################################################### #In case 2 frames are selected, draw the temporary path## ######################################################### if self.calculate_tmp_interpolation(): self._interpolate_btn.show() self._interpolation_mode.show() self._interpolation_title.show() if len(self._sel_pts)==2: self._del_path_btn.show() else: self._del_path_btn.hide() ######################################################### else: self._interpolate_btn.hide() self._interpolation_mode.hide() self._interpolation_title.hide() self._del_path_btn.hide() self._tmp_points = [] self.mainwindow._player.refresh() def __remove_path_dataset(self): item = self.tree.selected_item if item is not None: self.object2d -= item.win def __referencial_pt_changed_event(self): try: self._referencial = eval(self._referencial_pt.value) except: self._referencial = None def __pick_a_color_event(self): color = QColor(self.color[2], self.color[1], self.color[0]) color = QColorDialog.getColor(color, parent = self, title = 'Pick a color for the path') self.color = color.blue(), color.green(), color.red() self.mainwindow._player.refresh() #################################################################### def __interpolate_btn_event(self): #store a temporary path for interpolation visualization if len(self._sel_pts) >= 2: mode = None if self._interpolation_mode.value=='Auto' else self._interpolation_mode.value #store a temporary path for interpolation visualization self.interpolate_range( self._sel_pts[0], self._sel_pts[-1], interpolation_mode=mode) self.mainwindow._player.refresh() else: QMessageBox.about(self, "Error", "You need to select 2 frames.") def __interpolation_mode_changed_event(self): #store a temporary path for interpolation visualization if len(self._sel_pts) >= 2: if self.calculate_tmp_interpolation(): self.mainwindow._player.refresh() def __del_path_btn_event(self): #store a temporary path for interpolation visualization if len(self._sel_pts) == 2: reply = QMessageBox.question(self, 'Confirmation', "Are you sure you want to delete this path?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: #store a temporary path for interpolation visualization start, end = self._sel_pts[0], self._sel_pts[1] self.delete_range(start, end) self.calculate_tmp_interpolation() self.mainwindow._player.refresh() else: QMessageBox.about(self, "Error", "You need to select 2 frames.") def __lin_dist(self, p1, p2): return np.linalg.norm( (p1[0]-p2[0], p1[1]-p2[1]) ) ###################################################################### ### VIDEO EVENTS ##################################################### ###################################################################### def on_click(self, event, x, y): if event.button== 1: frame_index = self.mainwindow._player.video_index-1 if self._mark_pto_btn.checked: frame_index = frame_index if frame_index>=0 else 0 self.set_position(frame_index, x, y) self._mark_pto_btn.checked = False else: position = self.get_position(frame_index) if position is not None and self.__lin_dist(position, (x,y))<10: modifier = int(event.event.modifiers()) # If the control button is pressed will add the blob to the previous selections if modifier == QtCore.Qt.ControlModifier: if frame_index not in self._sel_pts: #store a temporary path for interpolation visualization self._sel_pts.append(frame_index) else: # Remove the blob in case it was selected before #store a temporary path for interpolation visualization self._sel_pts.remove(frame_index) else: # The control key was not pressed so will select only one #store a temporary path for interpolation visualization self._sel_pts =[frame_index] else: #store a temporary path for interpolation visualization self._sel_pts =[] # No object selected: remove previous selections #store a temporary path for interpolation visualization self._sel_pts = sorted(self._sel_pts) if self.visible: #store a temporary path for interpolation visualization if len(self._sel_pts) >= 2: ######################################################### #In case 2 frames are selected, draw the temporary path## ######################################################### res = self.calculate_tmp_interpolation() if self.visible & res: self._interpolate_btn.show() self._interpolation_mode.show() self._interpolation_title.show() self._del_path_btn.show() #self._sel_pto_btn.hide() ######################################################### else: if self.visible: self._interpolate_btn.hide() self._interpolation_mode.hide() self._interpolation_title.hide() self._del_path_btn.hide() self._tmp_points = [] self.mainwindow._player.refresh() def draw(self, frame, frame_index): if not self.mainwindow.player.is_playing and self.visible: if self[frame_index] is None: self._del_point_btn.hide() else: self._del_point_btn.show() Path.draw(self, frame, frame_index) ###################################################################### ### PROPERTIES ####################################################### ###################################################################### @property def mainwindow(self): return self._object2d.mainwindow @property def tree(self): return self._object2d.tree @property def video_capture(self): return self._object2d.video_capture @property def parent_treenode(self): return self._object2d.treenode @property def interpolation_mode(self): return None if self._interpolation_mode.value==-1 else self._interpolation_mode.value @property def mark_point_button(self): return self._mark_pto_btn @property def referencial(self): return Path.referencial.fget(self) @referencial.setter def referencial(self, value): self._referencial_pt.value = str(value)[1:-1] if value else '' @property def apply_referencial(self): return self._use_referencial.value @apply_referencial.setter def apply_referencial(self, value): self._use_referencial.value = value @property def show_object_name(self): return self._show_object_name.value @show_object_name.setter def show_object_name(self, value): self._show_object_name.value = value @property def show_name(self): return self._show_name.value @show_name.setter def show_name(self, value): self._show_name.value = value
class SettingsWindow(BaseWidget): def __init__(self, *args, **kwargs): global settings_json BaseWidget.__init__(self, "Settings") self._settingslabel = ControlLabel("Settings") self._outputfolder = ControlText("SD Card Path") self._outputfolder.value = settings_json["outputfolder"] self._hmackey = ControlText("Capsrv HMAC Secret") self._hmackey.value = settings_json["hmackey"] self._customgameid = ControlText("Custom Game ID") self._customgameid.value = settings_json["customgameid"] self._typelabel = ControlLabel("Type") self._imagecheckbox = ControlCheckBox("Image") self._imagecheckbox.value = (settings_json["type"] == "image") self._imagecheckbox.changed_event = self.imageCheckbox self._mangacheckbox = ControlCheckBox("Manga") self._mangacheckbox.value = (settings_json["type"] == "manga") self._mangacheckbox.changed_event = self.mangaCheckbox self._comiccheckbox = ControlCheckBox("Comics") self._comiccheckbox.value = (settings_json["type"] == "comics") self._comiccheckbox.changed_event = self.comicCheckbox self._directionlabel = ControlLabel("Direction") self._directionlabel.hide() self._lefttoright = ControlCheckBox("From left to right") self._lefttoright.hide() self._lefttoright.value = (settings_json["direction"] == "ltr") self._lefttoright.changed_event = self.fromLeftToRight self._righttoleft = ControlCheckBox("From right to left") self._righttoleft.hide() self._righttoleft.value = (settings_json["direction"] == "rtl") self._righttoleft.changed_event = self.fromRightToLeft self._savebutton = ControlButton("Save") self._savebutton.value = self.saveButton self.formset = [("_settingslabel"), ("_outputfolder"), ("_hmackey"), ("_customgameid"), ("_typelabel"), ("_imagecheckbox", "_mangacheckbox", "_comiccheckbox"), ("_directionlabel"), ("_lefttoright", "_righttoleft"), (" "), (" ", " ", "_savebutton")] self._typerequested = False self._directionrequested = False #Reimplementing radio buttons sure is fun def imageCheckbox(self): if self._typerequested: return self._typerequested = True self._mangacheckbox.value = False self._comiccheckbox.value = False self._imagecheckbox.value = True self._directionlabel.hide() self._lefttoright.hide() self._righttoleft.hide() self._typerequested = False def comicCheckbox(self): if self._typerequested: return self._typerequested = True self._mangacheckbox.value = False self._comiccheckbox.value = True self._imagecheckbox.value = False self._directionlabel.show() self._lefttoright.show() self._righttoleft.show() self._typerequested = False def mangaCheckbox(self): if self._typerequested: return self._typerequested = True self._mangacheckbox.value = True self._comiccheckbox.value = False self._imagecheckbox.value = False self._directionlabel.show() self._lefttoright.show() self._righttoleft.show() self._typerequested = False def fromLeftToRight(self): if self._directionrequested: return self._directionrequested = True self._lefttoright.value = True self._righttoleft.value = False self._directionrequested = False def fromRightToLeft(self): if self._directionrequested: return self._directionrequested = True self._lefttoright.value = False self._righttoleft.value = True self._directionrequested = False def saveButton(self): global settings_json typ = "" if not self._mangacheckbox.value and not self._comiccheckbox.value: typ = "image" elif self._mangacheckbox.value: typ = "manga" else: typ = "comics" direction = "" if not self._righttoleft.value: direction = "ltr" else: direction = "rtl" try: a = bytes.fromhex(self._hmackey.value) if (len(a) != 0x20 or sha256(a).hexdigest( ) != "e9735dae330300b8bb4b5892c8178f5d57daa32d7b5ef5d15f14491800ce4750" ): raise except: self.alert("Invalid HMAC key!", "Error!") return try: a = bytes.fromhex(self._customgameid.value) if (len(a) != 16) and self._customgameid.value != "": raise ValueError if (self._customgameid.value == ""): raise except ValueError: self.alert("Invalid custom game ID!", "Error!") return except: self._customgameid.value = "57B4628D2267231D57E0FC1078C0596D" if self._outputfolder.value == "": self._outputfolder.value = "." settings_json = { "outputfolder": self._outputfolder.value, "hmackey": self._hmackey.value, "customgameid": self._customgameid.value, "type": typ, "direction": direction } json.dump( settings_json, open( appdirs.AppDirs("NSScreenshotMaker", "").user_data_dir + "/settings.json", "w"))