def _setupGUI(self): self._class_buttons = {} self._class_shortcuts = {} self._label_editor = None # Label class buttons self._classbox = QGroupBox("Labels", self) self._classbox_layout = FloatingLayout() self._classbox.setLayout(self._classbox_layout) # Global widget self._layout = MyVBoxLayout() self.setLayout(self._layout) self._layout.addWidget(self._classbox, 0) self._layout.addStretch(1)
def _setupGUI(self, _groupBoxName): self._widgets_dict = {} self._class_shortcuts = {} # Label class buttons qss = "QGroupBox::title {subcontrol-origin: margin; subcontrol-position: top left; padding: 0 3px; color : red; font-weight:bold; }" self._inserterButtonGroupbox = QGroupBox(_groupBoxName, self) self._inserterButtonGroupbox.setStyleSheet(qss) self._inserterButtonGroup_layout = FloatingLayout() self._inserterButtonGroupbox.setLayout( self._inserterButtonGroup_layout) # Global widget self._layout = MyVBoxLayout() self.setLayout(self._layout) self._layout.addWidget(self._inserterButtonGroupbox, 0) self._layout.addStretch(1)
def __init__(self, annotation_scene, stateChangedSignalSlot=None, buttonWithOptionsProperty=None, displayName=None, parent=None): QWidget.__init__(self, parent) # print "buttonWithOptionsProperty = {}".format(comboPannelProperty) self.buttonWithOptionsProperty = buttonWithOptionsProperty self.name = displayName self.vlayout = QVBoxLayout() self.vlayout.setAlignment(Qt.AlignTop) self.vlayout.setSpacing(4) self.vlayout.setMargin(4) #self.vlayout.setContentsMargins(0, 0, 0, 44) self.vlayout.addWidget(self.propertyEditorWidget) self.vlayout.addWidget(self.attrAreaWidget) self.vlayout.addStretch(1) self.setLayout(self.vlayout) return
class PropertyEditor(QWidget): # Signals insertionModeStarted = pyqtSignal(str) insertionModeEnded = pyqtSignal() insertionPropertiesChanged = pyqtSignal(object) editPropertiesChanged = pyqtSignal(object) def __init__(self, config, parent=None): QWidget.__init__(self, parent) self._class_config = {} self._class_items = {} self._class_prototypes = {} self._attribute_handlers = {} self._handler_factory = AttributeHandlerFactory() self._setupGUI() # Add label classes from config for label in config: self.addLabelClass(label) def onModelChanged(self, new_model): attrs = set([ k for k, v in self._attribute_handlers.items() if v.autoAddEnabled() ]) if len(attrs) > 0: start = time.time() attr2vals = {} for item in new_model.iterator(AnnotationModelItem): for attr in attrs: if attr in item: if attr not in attr2vals: attr2vals[attr] = set((item[attr], )) else: attr2vals[attr] |= set((item[attr], )) diff = time.time() - start LOG.info("Extracted annotation values from model in %.2fs" % diff) for attr, vals in attr2vals.items(): h = self._attribute_handlers[attr] for val in vals: h.addValue(val, True) def addLabelClass(self, label_config): # Check label configuration if 'attributes' not in label_config: raise ImproperlyConfigured("Label with no 'attributes' dict found") attrs = label_config['attributes'] if 'class' not in attrs: raise ImproperlyConfigured("Labels must have an attribute 'class'") label_class = attrs['class'] if label_class in self._class_config: raise ImproperlyConfigured( "Label with class '%s' defined more than once" % label_class) # Store config self._class_config[label_class] = label_config # Parse configuration and create handlers and item self.parseConfiguration(label_class, label_config) # Add label class button button_text = label_config['text'] button = QPushButton(button_text, self) button.setCheckable(True) button.setFlat(True) button.clicked.connect(bind(self.onClassButtonPressed, label_class)) self._class_buttons[label_class] = button self._classbox_layout.addWidget(button) # Add hotkey if 'hotkey' in label_config: hotkey = QShortcut(QKeySequence(label_config['hotkey']), self) hotkey.activated.connect(button.click) self._class_shortcuts[label_class] = hotkey def parseConfiguration(self, label_class, label_config): attrs = label_config['attributes'] # Add prototype item for insertion self._class_items[label_class] = AnnotationModelItem( {'class': label_class}) # Create attribute handler widgets or update their values for attr, vals in attrs.items(): if attr in self._attribute_handlers: self._attribute_handlers[attr].updateValues(vals) else: handler = self._handler_factory.create(attr, vals) if handler is None: self._class_items[label_class][attr] = vals else: self._attribute_handlers[attr] = handler for attr in attrs: if attr in self._attribute_handlers: self._class_items[label_class].update( self._attribute_handlers[attr].defaults()) def getHandler(self, attribute): if attribute in self._attribute_handlers: return self._attribute_handlers[attribute] else: return None def getLabelClassAttributes(self, label_class): return self._class_config[label_class]['attributes'].keys() def onClassButtonPressed(self, label_class): if self._class_buttons[label_class].isChecked(): self.startInsertionMode(label_class) else: self.endInsertionMode() def startInsertionMode(self, label_class): self.endInsertionMode(False) for lc, button in self._class_buttons.items(): button.setChecked(lc == label_class) LOG.debug("Starting insertion mode for %s" % label_class) self._label_editor = LabelEditor([self._class_items[label_class]], self, True) self._layout.insertWidget(1, self._label_editor, 0) self.insertionModeStarted.emit(label_class) def endInsertionMode(self, uncheck_buttons=True): if self._label_editor is not None: LOG.debug("Ending insertion/edit mode") self._label_editor.hide() self._layout.removeWidget(self._label_editor) self._label_editor = None if uncheck_buttons: self.uncheckAllButtons() self.insertionModeEnded.emit() def uncheckAllButtons(self): for lc, button in self._class_buttons.items(): button.setChecked(False) def markEditButtons(self, label_classes): for lc, button in self._class_buttons.items(): button.setFlat(lc not in label_classes) def currentEditorProperties(self): if self._label_editor is None: return None else: return self._label_editor.currentProperties() def startEditMode(self, model_items): # If we're in insertion mode, ignore empty edit requests if self._label_editor is not None and self._label_editor.insertionMode() \ and len(model_items) == 0: return self.endInsertionMode() LOG.debug("Starting edit mode for items: %s" % model_items) self._label_editor = LabelEditor(model_items, self) self.markEditButtons(self._label_editor.labelClasses()) self._layout.insertWidget(1, self._label_editor, 0) def _setupGUI(self): self._class_buttons = {} self._class_shortcuts = {} self._label_editor = None # Label class buttons self._classbox = QGroupBox("Labels", self) self._classbox_layout = FloatingLayout() self._classbox.setLayout(self._classbox_layout) # Global widget self._layout = MyVBoxLayout() self.setLayout(self._layout) self._layout.addWidget(self._classbox, 0) self._layout.addStretch(1)
class PropertyEditor(QWidget): # Signals insertionModeStarted = pyqtSignal(str) insertionModeEnded = pyqtSignal() insertionPropertiesChanged = pyqtSignal(object) editPropertiesChanged = pyqtSignal(object) def __init__(self, config, parent=None): QWidget.__init__(self, parent) self._class_config = {} self._class_items = {} self._class_prototypes = {} self._attribute_handlers = {} self._handler_factory = AttributeHandlerFactory() self._setupGUI() # Add label classes from config for label in config: self.addLabelClass(label) def onModelChanged(self, new_model): attrs = set([k for k, v in self._attribute_handlers.items() if v.autoAddEnabled()]) if len(attrs) > 0: start = time.time() attr2vals = {} for item in new_model.iterator(AnnotationModelItem): for attr in attrs: if attr in item: if attr not in attr2vals: attr2vals[attr] = set((item[attr], )) else: attr2vals[attr] |= set((item[attr], )) diff = time.time() - start LOG.info("Extracted annotation values from model in %.2fs" % diff) for attr, vals in attr2vals.items(): h = self._attribute_handlers[attr] for val in vals: h.addValue(val, True) def addLabelClass(self, label_config): # Check label configuration if 'attributes' not in label_config: raise ImproperlyConfigured("Label with no 'attributes' dict found") attrs = label_config['attributes'] if 'class' not in attrs: raise ImproperlyConfigured("Labels must have an attribute 'class'") label_class = attrs['class'] if label_class in self._class_config: raise ImproperlyConfigured("Label with class '%s' defined more than once" % label_class) # Store config self._class_config[label_class] = label_config # Parse configuration and create handlers and item self.parseConfiguration(label_class, label_config) # Add label class button button = QPushButton(label_class, self) button.setCheckable(True) button.setFlat(True) button.clicked.connect(bind(self.onClassButtonPressed, label_class)) self._class_buttons[label_class] = button self._classbox_layout.addWidget(button) # Add hotkey if 'hotkey' in label_config: hotkey = QShortcut(QKeySequence(label_config['hotkey']), self) hotkey.activated.connect(button.click) self._class_shortcuts[label_class] = hotkey def parseConfiguration(self, label_class, label_config): attrs = label_config['attributes'] # Add prototype item for insertion self._class_items[label_class] = AnnotationModelItem({ 'class': label_class }) # Create attribute handler widgets or update their values for attr, vals in attrs.items(): if attr in self._attribute_handlers: self._attribute_handlers[attr].updateValues(vals) else: handler = self._handler_factory.create(attr, vals) if handler is None: self._class_items[label_class][attr] = vals else: self._attribute_handlers[attr] = handler for attr in attrs: if attr in self._attribute_handlers: self._class_items[label_class].update(self._attribute_handlers[attr].defaults()) def getHandler(self, attribute): if attribute in self._attribute_handlers: return self._attribute_handlers[attribute] else: return None def getLabelClassAttributes(self, label_class): return self._class_config[label_class]['attributes'].keys() def onClassButtonPressed(self, label_class): if self._class_buttons[label_class].isChecked(): self.startInsertionMode(label_class) else: self.endInsertionMode() def startInsertionMode(self, label_class): self.endInsertionMode(False) for lc, button in self._class_buttons.items(): button.setChecked(lc == label_class) LOG.debug("Starting insertion mode for %s" % label_class) self._label_editor = LabelEditor([self._class_items[label_class]], self, True) self._layout.insertWidget(1, self._label_editor, 0) self.insertionModeStarted.emit(label_class) def endInsertionMode(self, uncheck_buttons=True): if self._label_editor is not None: LOG.debug("Ending insertion/edit mode") self._label_editor.hide() self._layout.removeWidget(self._label_editor) self._label_editor = None if uncheck_buttons: self.uncheckAllButtons() self.insertionModeEnded.emit() def uncheckAllButtons(self): for lc, button in self._class_buttons.items(): button.setChecked(False) def markEditButtons(self, label_classes): for lc, button in self._class_buttons.items(): button.setFlat(lc not in label_classes) def currentEditorProperties(self): if self._label_editor is None: return None else: return self._label_editor.currentProperties() def startEditMode(self, model_items): # If we're in insertion mode, ignore empty edit requests if self._label_editor is not None and self._label_editor.insertionMode() \ and len(model_items) == 0: return self.endInsertionMode() LOG.debug("Starting edit mode for items: %s" % model_items) self._label_editor = LabelEditor(model_items, self) self.markEditButtons(self._label_editor.labelClasses()) self._layout.insertWidget(1, self._label_editor, 0) def _setupGUI(self): self._class_buttons = {} self._class_shortcuts = {} self._label_editor = None # Label class buttons self._classbox = QGroupBox("Labels", self) self._classbox_layout = FloatingLayout() self._classbox.setLayout(self._classbox_layout) # Global widget self._layout = MyVBoxLayout() self.setLayout(self._layout) self._layout.addWidget(self._classbox, 0) self._layout.addStretch(1)
def __init__(self, property=None, idName=None, displayName=None, parent=None): QWidget.__init__(self, parent) self.hotkeys = [] self.displayName = displayName self.idName = idName self.vlayout = MyVBoxLayout() #QVBoxLayout() self.vlayout.setAlignment(Qt.AlignTop) self.vlayout.setSpacing(4) self.vlayout.setMargin(4) #self.vlayout.setContentsMargins(0, 0, 0, 44) # LOG.info("AttrAreaWidget constructor : property {} ...".format(property)) self.numGroups = len(property) if property is not None else 0 self.checkboxGroupsDescDict = {} self.checkboxGroupWidgets = {} for i in xrange(self.numGroups): thisGroupProperty = property[i] # thisGroupProperty is a dict thisGroupName = thisGroupProperty.get( 'name') # thisGroupName is a string thisGroupOption = thisGroupProperty.get( 'option' ) # thisGroupOption is a tuple of dicts. each dict describes a checkbox thisGroupText = thisGroupProperty.get('displaytext') isExclusive = False if thisGroupName in config.NON_EXCLUSIVE_ATTRS_TAG_LIST else True if thisGroupName == config.ANNOTATION_PERSONBIKE_TYPE_GROUP_TOKEN: checkboxWidgetMinWidthInPixels = 52 else: checkboxWidgetMinWidthInPixels = 38 if thisGroupName == config.ANNOTATION_UPPER_COLOR_TOKEN: thisGroup_maxCheckedNum = config.MAX_UPPER_COLOR_NUMBER thisGroup_maxSeperateWidgetNum = config.GUI_MAX_SEPERATE_UPPER_COLOR_WIDGET_NUMBER elif thisGroupName == config.ANNOTATION_LOWER_COLOR_TOKEN: thisGroup_maxCheckedNum = config.MAX_LOWER_COLOR_NUMBER thisGroup_maxSeperateWidgetNum = config.GUI_MAX_SEPERATE_LOWER_COLOR_WIDGET_NUMBER elif thisGroupName == config.ANNOTATION_VEHICLE_COLOR_TOKEN: thisGroup_maxCheckedNum = config.MAX_VEHICLE_COLOR_NUMBER thisGroup_maxSeperateWidgetNum = config.GUI_MAX_SEPERATE_VEHICLE_COLOR_WIDGET_NUMBER else: thisGroup_maxCheckedNum = config.MAX_CHECKED_OPTIONS_NUMBER thisGroup_maxSeperateWidgetNum = config.MAX_OPTIONS_NUMBER thisGroupWidget = CheckboxListWidget( thisGroupName, thisGroupText, isExclusive, thisGroupOption, self.checkboxStateChangedSignal, thisGroup_maxCheckedNum, thisGroup_maxSeperateWidgetNum) # add checkbox record to this checkbox group record thisGroupCheckboxs = {} for checkboxOption in thisGroupOption: thisCheckboxName = checkboxOption[ config.METADATA_ATTR_VALUE_TOKEN] thisCheckboxProperty = checkboxOption.copy() thisGroupCheckboxs[thisCheckboxName] = thisCheckboxProperty self.vlayout.addWidget(thisGroupWidget) self.checkboxGroupsDescDict[ thisGroupName] = thisGroupCheckboxs # add this checkbox group record to checkbox groups recrod self.checkboxGroupWidgets[thisGroupName] = thisGroupWidget # LOG.info("checkboxGroupWidgets = {} checkboxGroupsDescDict = {}".format(self.checkboxGroupWidgets, self.checkboxGroupsDescDict) self.vlayout.addStretch(1) self.setLayout(self.vlayout) return
class AttrAreaWidget(QWidget): checkboxStateChangedSignal = pyqtSignal(str, object) def setAnnotationScene(self, annotationScene): self._scene = annotationScene def enableAllGroups(self, enabled=True): for gn, gw in self.checkboxGroupWidgets.items(): gw.setEnabled(enabled) gw.enableAll(enabled) def enableCheckboxGroup(self, checkboxGroupName, enabled=True): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: groupWidget.setEnabled(enabled) groupWidget.enableAll(enabled) def enableCheckbox(self, checkboxGroupName, checkboxName, enabled=True): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: groupWidget.enable(checkboxName, enabled) # return (names_list, texts_list, displaycolors_list) def get_group_config(self, checkboxGroupName): names = [] texts = [] displaycolors = [] groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: names, texts, displaycolors = groupWidget.get_config() return names, texts, displaycolors # return names_list def get_group_names(self): groupNames = [] for groupName in self.checkboxGroupWidgets.keys(): groupNames.append(groupName) return groupNames def setCheckedAllGroups(self, checked=True): for groupName, groupWidget in self.checkboxGroupWidgets.items(): groupWidget.setCheckedAll(checked) def setCheckedGroup(self, checkboxGroupName, checked=True): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: groupWidget.setCheckedAll(checked) def setCheckedCheckbox(self, checkboxGroupName, checkboxName, checked=True): # print "checkboxGroupName {} checkboxName {} checked {} ...".format(checkboxGroupName, checkboxName, checked) groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) # print "checkboxGroupWidgets = {}...".format(self.checkboxGroupWidgets) if groupWidget is not None: # LOG.info("AttrAreaWidget.setCheckedCheckbox for group {} checked {} ..".format(checkboxGroupName, checked)) # print ("AttrAreaWidget.setCheckedCheckbox for group {} checked {} ..".format(checkboxGroupName, checked)) groupWidget.setCheckedCheckbox(checkboxName, checked) def setCheckedCheckboxs(self, checkboxGroupName, checkboxNamesList, checked=True): if checkboxNamesList is None: return groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: # LOG.info(u"{} AttrAreaWidget.setCheckedCheckbox for group {} box {} checked {} ..".format(self.groupName, checkboxGroupName, checkboxNamesList, checked)) groupWidget.setCheckedCheckboxs(checkboxNamesList, checked) def sendCheckedSignal(self, checkboxGroupName): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: groupWidget.sendCheckedSignal() def getCheckedWidgetsOptionInfo(self, checkboxGroupName): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: return groupWidget.getCheckedWidgetsOptionInfo() return None, None def setOptionStateChangedSignalSlot(self, checkboxStateChangedSignalSlot): if checkboxStateChangedSignalSlot is not None: # print u"pannel {}: checkboxStateChangedSignal{} checkboxStateChangedSignalSlot {} is connected...".format(self.idName, self.checkboxStateChangedSignal, checkboxStateChangedSignalSlot) self.checkboxStateChangedSignal.connect( checkboxStateChangedSignalSlot) def hideGroup(self, checkboxGroupName): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: return groupWidget.hide() def __init__(self, property=None, idName=None, displayName=None, parent=None): QWidget.__init__(self, parent) self.hotkeys = [] self.displayName = displayName self.idName = idName self.vlayout = MyVBoxLayout() #QVBoxLayout() self.vlayout.setAlignment(Qt.AlignTop) self.vlayout.setSpacing(4) self.vlayout.setMargin(4) #self.vlayout.setContentsMargins(0, 0, 0, 44) # LOG.info("AttrAreaWidget constructor : property {} ...".format(property)) self.numGroups = len(property) if property is not None else 0 self.checkboxGroupsDescDict = {} self.checkboxGroupWidgets = {} for i in xrange(self.numGroups): thisGroupProperty = property[i] # thisGroupProperty is a dict thisGroupName = thisGroupProperty.get( 'name') # thisGroupName is a string thisGroupOption = thisGroupProperty.get( 'option' ) # thisGroupOption is a tuple of dicts. each dict describes a checkbox thisGroupText = thisGroupProperty.get('displaytext') isExclusive = False if thisGroupName in config.NON_EXCLUSIVE_ATTRS_TAG_LIST else True if thisGroupName == config.ANNOTATION_PERSONBIKE_TYPE_GROUP_TOKEN: checkboxWidgetMinWidthInPixels = 52 else: checkboxWidgetMinWidthInPixels = 38 if thisGroupName == config.ANNOTATION_UPPER_COLOR_TOKEN: thisGroup_maxCheckedNum = config.MAX_UPPER_COLOR_NUMBER thisGroup_maxSeperateWidgetNum = config.GUI_MAX_SEPERATE_UPPER_COLOR_WIDGET_NUMBER elif thisGroupName == config.ANNOTATION_LOWER_COLOR_TOKEN: thisGroup_maxCheckedNum = config.MAX_LOWER_COLOR_NUMBER thisGroup_maxSeperateWidgetNum = config.GUI_MAX_SEPERATE_LOWER_COLOR_WIDGET_NUMBER elif thisGroupName == config.ANNOTATION_VEHICLE_COLOR_TOKEN: thisGroup_maxCheckedNum = config.MAX_VEHICLE_COLOR_NUMBER thisGroup_maxSeperateWidgetNum = config.GUI_MAX_SEPERATE_VEHICLE_COLOR_WIDGET_NUMBER else: thisGroup_maxCheckedNum = config.MAX_CHECKED_OPTIONS_NUMBER thisGroup_maxSeperateWidgetNum = config.MAX_OPTIONS_NUMBER thisGroupWidget = CheckboxListWidget( thisGroupName, thisGroupText, isExclusive, thisGroupOption, self.checkboxStateChangedSignal, thisGroup_maxCheckedNum, thisGroup_maxSeperateWidgetNum) # add checkbox record to this checkbox group record thisGroupCheckboxs = {} for checkboxOption in thisGroupOption: thisCheckboxName = checkboxOption[ config.METADATA_ATTR_VALUE_TOKEN] thisCheckboxProperty = checkboxOption.copy() thisGroupCheckboxs[thisCheckboxName] = thisCheckboxProperty self.vlayout.addWidget(thisGroupWidget) self.checkboxGroupsDescDict[ thisGroupName] = thisGroupCheckboxs # add this checkbox group record to checkbox groups recrod self.checkboxGroupWidgets[thisGroupName] = thisGroupWidget # LOG.info("checkboxGroupWidgets = {} checkboxGroupsDescDict = {}".format(self.checkboxGroupWidgets, self.checkboxGroupsDescDict) self.vlayout.addStretch(1) self.setLayout(self.vlayout) return def stateHasChanged(self, checkedWidgetsAttrDescDict): # LOG.info("call AttrAreaWidget.stateHasChanged({})".format(checkedWidgetsAttrDescDict)) return def get_checked_widgets_name(self, group_name): widget = self.checkboxGroupWidgets.get(str(group_name), None) # LOG.info("AttrAreaWidget.get_checked_widgets_name ... widget = {}".format(widget)) checkedWidgetsNameList = widget.get_checked_widgets_name( ) if widget is not None else None # LOG.info("AttrAreaWidget.get_checked_widgets_name ... checkedWidget = {}".format(checkedWidget)) return checkedWidgetsNameList def add_hotkey(self, choice, name, hotkey): self.hotkeys.append((choice, name, hotkey)) def get_checked_widgets_attrDesc(self): descsDict = {} for widgetName, widgetInfo in self.checkboxWidgetsInfo.items(): if widgetInfo[0].isChecked(): desc = [None, None, None, None, None] desc[ checkedWidgetsAttrDescList_checkedWidget_idx] = widgetInfo[ 0] desc[ checkedWidgetsAttrDescList_checkedWidgetText_idx] = widgetInfo[ 1] desc[ checkedWidgetsAttrDescList_checkedWidgetColor_idx] = widgetInfo[ 2] desc[ checkedWidgetsAttrDescList_checkedWidgetStyleSheet_idx] = widgetInfo[ 3] descsDict[widgetName] = desc for widgetInfo in self.popupWidgetsInfo.values(): for actionWidget in widgetInfo[ popupWidgetsInfo_actionsWidgetList_idx]: if actionWidget.isChecked(): idx = widgetInfo[ popupWidgetsInfo_actionsWidgetList_idx].index( actionWidget) desc = [None, None, None, None, None] desc[ checkedWidgetsAttrDescList_checkedWidget_idx] = actionWidget desc[ checkedWidgetsAttrDescList_checkedWidgetText_idx] = widgetInfo[ popupWidgetsInfo_actionsTextList_idx][idx] desc[ checkedWidgetsAttrDescList_checkedWidgetColor_idx] = widgetInfo[ popupWidgetsInfo_actionsColorList_idx][idx] desc[ checkedWidgetsAttrDescList_checkedWidgetStyleSheet_idx] = widgetInfo[ popupWidgetsInfo_actionsWidgetStyleSheet_idx] desc[ checkedWidgetsAttrDescList_checkedWidgetPopupParentWidget_idx] = widgetInfo[ popupWidgetsInfo_pushButtonWidget_idx] widgetName = widgetInfo[ popupWidgetsInfo_actionsNameList_idx][idx] descsDict[widgetName] = desc return descsDict def startEditMode(self, model_items): return
class PropertyEditor(QWidget): # Signals insertionModeStarted = pyqtSignal(str) insertionModeEnded = pyqtSignal() insertionPropertiesChanged = pyqtSignal(object) editPropertiesChanged = pyqtSignal(object) def __init__(self, config, parent=None): QWidget.__init__(self, parent) self._class_config = {} self._class_items = {} self._class_prototypes = {} self._attribute_handlers = {} self._handler_factory = AttributeHandlerFactory() self._setupGUI() self._parea.setGeometry(0, 0, 200, 0) # (快捷键,button) self.shortcut2button = {} # (button,快捷键) self.label2shortcut = {} # Add label classes from config for label in config: self.addLabelClass(label) self.image_path = None def addLabelClassByPath(self, configs_path): # 读配置文件 with open(configs_path, 'r') as f: configs = json5.load(f) # 写入当前配置文件的路径 direct = os.path.dirname(sys.argv[0]) with open(os.path.join(direct, 'sloth.txt'), 'w') as f: f.write(configs_path) self._parea.setGeometry(0, 0, 200, 0) for temp_json in configs: self.addLabelClass(temp_json) # 注册 self._register('inserter', temp_json['attributes']['class'], temp_json['inserter']) self._register('item', temp_json['attributes']['class'], temp_json['item']) # add_txt的下拉框里也要添加 self.combo_box.addItem(temp_json['attributes']['class']) self.items.append(temp_json['attributes']['class']) cf.LABELS.append(temp_json) def onModelChanged(self, new_model): attrs = set([ k for k, v in self._attribute_handlers.items() if v.autoAddEnabled() ]) if len(attrs) > 0: start = time.time() attr2vals = {} for item in new_model.iterator(AnnotationModelItem): for attr in attrs: if attr in item: if attr not in attr2vals: attr2vals[attr] = set((item[attr], )) else: attr2vals[attr] |= set((item[attr], )) diff = time.time() - start LOG.info("Extracted annotation values from model in %.2fs" % diff) for attr, vals in attr2vals.items(): h = self._attribute_handlers[attr] for val in vals: h.addValue(val, True) # 设置右键菜单所在位置 def showContextMenu(self, label_class): self.label_menu[label_class].exec_(QCursor.pos()) # 删除所有的item def remove_all_item(self): for v in self.shortcut2button.values(): v.setShortcut(QKeySequence()) self.shortcut2button.clear() self.label2shortcut.clear() self.label_menu.clear() self.label_action.clear() self._class_config.clear() self.combo_box.clear() self.items.clear() temp_dict = copy.copy(self._class_buttons) for k, v in temp_dict.items(): self._classbox_layout.removeWidget(v) # 下面这句很重要,不然相当于没删 self._class_buttons[k].deleteLater() self._class_buttons.clear() cf.LABELS.clear() self._parea.setGeometry(0, 0, 200, 60) # 删除标签 def remove_item(self, label_class): """ 删除标签 :param label_class: 删除的标签名字 """ try: # 删除快捷键 self.endInsertionMode() shortcut = self.label2shortcut[label_class] if shortcut in self.shortcut2button and \ self.shortcut2button[shortcut] is not None and \ self.shortcut2button[shortcut] == self._class_buttons[label_class]: self.shortcut2button[shortcut].setShortcut(QKeySequence()) del self.shortcut2button[shortcut] # 删除菜单 del self.label_menu[label_class] # 删除菜单的动作 del self.label_action[label_class] # 删除视图中的按钮 self._classbox_layout.removeWidget( self._class_buttons[label_class]) self._class_buttons[label_class].deleteLater() self._class_buttons[label_class] = None del self._class_config[label_class] # 写回json direct = os.path.dirname(sys.argv[0]) with open(os.path.join(direct, 'sloth.txt'), 'r') as f: label_path = f.read() try: with open(label_path, 'r') as f: temp = json5.load(f) for i, current_json in enumerate(temp): if current_json['attributes']['class'] == label_class: temp.remove(current_json) # 遍历combo box 找到要删的 for i in range(len(self.combo_box)): current_label = self.combo_box.itemText(i) if current_label == label_class: print('removed', label_class) self.combo_box.removeItem(i) self.items.pop(i) break self._class_buttons.pop(label_class) break with open(label_path, 'w') as f: json5.dump(temp, f, quote_keys=True, trailing_commas=False, indent=4, separators=(',', ': '), sort_keys=True, ensure_ascii=False) self._parea.setGeometry( 0, 0, 200, max(self._parea.geometry().height() - 40, 60)) except Exception as e: print(e) except Exception as e: print(e) # 添加标签 def addLabelClass(self, label_config): """ 添加标签 :param label_config: 标签的json """ # Check label configuration if 'attributes' not in label_config: raise ImproperlyConfigured("Label with no 'attributes' dict found") attrs = label_config['attributes'] if 'class' not in attrs: raise ImproperlyConfigured("Labels must have an attribute 'class'") label_class = attrs['class'] if label_class in self._class_config: raise ImproperlyConfigured( "Label with class '%s' defined more than once" % label_class) # Store config self._class_config[label_class] = label_config # Parse configuration and create handlers and item self.parseConfiguration(label_class, label_config) # Add label class button button_text = label_config['text'] button = QPushButton(button_text) button.setCheckable(True) button.setFlat(True) button.clicked.connect(bind(self.onClassButtonPressed, label_class)) self._class_buttons[label_class] = button self._parea.setGeometry(0, 0, 200, self._parea.geometry().height() + 40) self._classbox_layout.addWidget(button) # 添加右键菜单 self.label_menu[label_class] = QtGui.QMenu(self) self.label_action[label_class] = self.label_menu[ label_class].addAction('删除') self.label_action[label_class].triggered.connect( bind(self.remove_item, label_class)) self._class_buttons[label_class].setContextMenuPolicy( QtCore.Qt.CustomContextMenu) self._class_buttons[label_class].customContextMenuRequested.connect( bind(self.showContextMenu, label_class)) # Add hotkey if 'hotkey' in label_config: # 快捷键 hotkey = label_config['hotkey'] # 快捷键已经存在,那就去掉原来的 if hotkey in self.shortcut2button and self.shortcut2button[ hotkey] is not None: self.shortcut2button[hotkey].setShortcut(QKeySequence()) # 设置快捷键 button.setShortcut(QKeySequence(hotkey)) self.shortcut2button[hotkey] = button self.label2shortcut[label_class] = hotkey def parseConfiguration(self, label_class, label_config): attrs = label_config['attributes'] # Add prototype item for insertion self._class_items[label_class] = AnnotationModelItem( {'class': label_class}) # Create attribute handler widgets or update their values for attr, vals in attrs.items(): if attr in self._attribute_handlers: self._attribute_handlers[attr].updateValues(vals) else: handler = self._handler_factory.create(attr, vals) if handler is None: self._class_items[label_class][attr] = vals else: self._attribute_handlers[attr] = handler for attr in attrs: if attr in self._attribute_handlers: self._class_items[label_class].update( self._attribute_handlers[attr].defaults()) def getHandler(self, attribute): if attribute in self._attribute_handlers: return self._attribute_handlers[attribute] else: return None def getLabelClassAttributes(self, label_class): return self._class_config[label_class]['attributes'].keys() def onClassButtonPressed(self, label_class): if self._class_buttons[label_class].isChecked(): self.startInsertionMode(label_class) else: self.endInsertionMode() def startInsertionMode(self, label_class): self.endInsertionMode(False) for lc, button in self._class_buttons.items(): button.setChecked(lc == label_class) LOG.debug("Starting insertion mode for %s" % label_class) self._label_editor = LabelEditor([self._class_items[label_class]], self, True) # self._layout.insertWidget(1, self._label_editor, 0) self.insertionModeStarted.emit(label_class) def endInsertionMode(self, uncheck_buttons=True): if self._label_editor is not None: LOG.debug("Ending insertion/edit mode") self._label_editor.hide() # self._layout.removeWidget(self._label_editor) self._label_editor = None if uncheck_buttons: self.uncheckAllButtons() self.insertionModeEnded.emit() def uncheckAllButtons(self): for lc, button in self._class_buttons.items(): button.setChecked(False) def markEditButtons(self, label_classes): for lc, button in self._class_buttons.items(): button.setFlat(lc not in label_classes) def currentEditorProperties(self): if self._label_editor is None: return None else: return self._label_editor.currentProperties() def startEditMode(self, model_items): # If we're in insertion mode, ignore empty edit requests if self._label_editor is not None and self._label_editor.insertionMode() \ and len(model_items) == 0: return self.endInsertionMode() LOG.debug("Starting edit mode for items: %s" % model_items) self._label_editor = LabelEditor(model_items, self) self.markEditButtons(self._label_editor.labelClasses()) self._layout.insertWidget(1, self._label_editor, 0) # 添加txt def add_txt(self): if not Main.isConfig(Main.get_json()): QMessageBox.warning(self, "Warning", '当前的配置文件错误或者为空,无法添加txt', QMessageBox.Ok) defect = self.combo_box.currentText() if defect is None or defect == '': return dir_path = QFileDialog.getExistingDirectory(self) Main.write_txt(dir_path, {defect}, 'defect') # 选择图片 def select_image(self): image_types = [ '*.jpg', '*.bmp', '*.png', '*.pgm', '*.ppm', '*.tiff', '*.tif', '*.gif' ] format_str = ' '.join(image_types) fname = QFileDialog.getOpenFileName( self, "select training source", '.', "Media files (%s)" % (format_str, )) if fname is None or fname == '': return self.image_path = os.path.abspath(fname) self._image_label.setText(os.path.basename(self.image_path)) # 获得图片路径对应的json路径 def image2json(self, path): temp = path.split('.') return ''.join(temp[:-1]) + '.json' # 获得图片路径转成的训练图片路径 def image2cpimage(self, path, id, length): length = max(length, 5) temp = path.split('.') return ''.join(temp[:-1]) + str(id).zfill(length) + '.' + temp[-1] # 判断是否包含瑕疵 def contains_defect(self, annotations, defect_type): defects = set() for annotation in annotations: if 'class' in annotation: defects.add(annotation['class']) return defect_type.issubset(defects) # 生成训练数据 def generate(self): if not Main.isConfig(Main.get_json()): QMessageBox.warning(self, "Warning", '配置文件错误或者为空,无法生成训练数据', QMessageBox.Ok) return a = TrainDialog(self) a.exec_() # 从labeltool中设置搜索按钮 def setFunction(self, func): self._search_btn.clicked.connect(func) # 获得关键字 def get_key_word(self): key_word = self._key_word.text() if key_word is None or key_word == '': key_word = self._key_word.placeholderText() return key_word # 获得文件类型 def get_extension(self): extension = self._extension.text() # 为空则用默认的,否则用输入的 if extension is None or extension == '': extension = self._extension.placeholderText() return extension # 返回一个含有权限类型的list def get_attributes_type(self): ''' 'Rect':('sloth.items.RectItem','sloth.items.RectItemInserter'), 'Point':('sloth.items.PointItem','sloth.items.PointItemInserter'), 'Polygon':('sloth.items.PolygonItem','sloth.items.PolygonItemInserter') ''' return ['Rect', 'Point', 'Polygon'] # 写回json def rewrite_json(self, temp_json): # json所在的txt direct = os.path.dirname(sys.argv[0]) with open(os.path.join(direct, 'sloth.txt'), 'r') as f: label_path = f.read() try: # 读取旧json with open(label_path, 'r') as f: temp = json5.load(f) # 追加我们要写入的json temp.append(temp_json) # 写入 with open(label_path, 'w') as f: json5.dump(temp, f, quote_keys=True, trailing_commas=False, indent=4, separators=(',', ': '), sort_keys=True, ensure_ascii=False) except Exception as e: print(e) # 添加标签 def add_attributes(self): if not Main.isConfig(Main.get_json()): QMessageBox.warning(self, "Warning", '当前配置文件错误或者为空,不能添加标签', QMessageBox.Ok) return # 转换dict type_dict = { 'Rect': ('sloth.items.RectItem', 'sloth.items.RectItemInserter'), 'Point': ('sloth.items.PointItem', 'sloth.items.PointItemInserter'), 'Polygon': ('sloth.items.PolygonItem', 'sloth.items.PolygonItemInserter') } # 获取添加的标签信息 attributes = {'class': self.attributes_LineEdit.text()} attributes_item, attributes_inserter = type_dict[ self.attributes_type.currentText()] attributes_hotkey = self.hotkey.text() attributes_text = self.text_LineEdit.text() global brush2idx brush_idx = str(brush2idx[self.brush_combo_box.currentText()]) temp_json = { 'attributes': attributes, 'inserter': attributes_inserter, 'item': attributes_item, 'color': ','.join(map(str, self.color_info)), 'brush': brush_idx, 'text': attributes_text } # 快捷键 if attributes_hotkey is not None and attributes_hotkey != '': temp_json['hotkey'] = attributes_hotkey print(temp_json) try: # 加入标签 self.addLabelClass(temp_json) print(self._class_buttons.keys()) # 注册 self._register('inserter', temp_json['attributes']['class'], temp_json['inserter']) self._register('item', temp_json['attributes']['class'], temp_json['item']) # add_txt的下拉框里也要添加 self.combo_box.addItem(temp_json['attributes']['class']) self.items.append(temp_json['attributes']['class']) cf.LABELS.append(temp_json) # 写回json self.rewrite_json(temp_json) except Exception as e: print(e) # 颜色对话框 def color_dialog(self): col = QtGui.QColorDialog.getColor() if col.isValid(): self.color_label.setStyleSheet("QWidget { background-color: %s }" % col.name()) self.color_info = col.getRgb()[:-1] # 设置控件的隐藏状态 def component_visible(self, component_name, state): if component_name == '添加标签': self._group_box_add_label.setVisible(state) elif component_name == 'add_txt': self._group_box_add_txt.setVisible(state) elif component_name == 'add_files': self._group_box_add_files.setVisible(state) def _setupGUI(self): self._class_buttons = {} self.label_menu = {} self.label_action = {} self._label_editor = None # Label class buttons self._parea = QGroupBox("Labels") self._classbox = QScrollArea() self._classbox_layout = FloatingLayout() self._parea.setLayout(self._classbox_layout) self._parea.setGeometry(0, 0, 200, 200) self._classbox.setWidget(self._parea) self._classbox.setGeometry(0, 0, 100, 100) # 添加txt模块 self.combo_box = QComboBox() self._group_box_add_txt = QGroupBox('add_txt', self) self._group_box_add_txt_layout = QVBoxLayout() self._group_box_add_txt.setLayout(self._group_box_add_txt_layout) temp = cf.LABELS self.items = [] # 获取所有的标签 for i in temp: self.items.append(i['attributes']['class']) # 假如下拉框 self.combo_box.addItems(self.items) self.add_txt_btn = QPushButton('add txt') self.add_txt_btn.clicked.connect(self.add_txt) # 加入下拉框和按钮 self._group_box_add_txt_layout.addWidget(self.combo_box, 0) self._group_box_add_txt_layout.addWidget(self.add_txt_btn, 1) # 根据关键字搜索图片模块 self._group_box_add_files = QGroupBox('add files', self) # 文件名包含的 self._key_word = QLineEdit('') self._key_word.setPlaceholderText('Second') # 文件类型 self._extension = QLineEdit('') self._extension.setPlaceholderText('bmp') self._search_btn = QPushButton('search files') self._group_box_add_files_layout = QVBoxLayout() # 加入控件 self._group_box_add_files_layout.addWidget(self._key_word, 0) self._group_box_add_files_layout.addWidget(self._extension, 1) self._group_box_add_files_layout.addWidget(self._search_btn, 2) self._group_box_add_files.setLayout(self._group_box_add_files_layout) # 添加标签模块 self._group_box_add_label = QGroupBox("添加标签", self) self._add_label_group_layout = QVBoxLayout() self._group_box_add_label.setLayout(self._add_label_group_layout) # 标签的class self.attributes_LineEdit = QLineEdit('') self.attributes_LineEdit.setPlaceholderText('attributes') # 标签画出来的类型 self.attributes_type = QComboBox() self.attributes_type.addItems(self.get_attributes_type()) # 快捷键,目前设置了只允许一个键 self.hotkey = QLineEdit('') self.hotkey.setPlaceholderText('hotkey') self.regx = QRegExp("[a-z0-9]$") self.validator = QRegExpValidator(self.regx, self.hotkey) self.hotkey.setValidator(self.validator) # 标签显示 self.text_LineEdit = QLineEdit('') self.text_LineEdit.setPlaceholderText('text') # 颜色 color = QtGui.QColor(0, 0, 0) self.color_label = QtGui.QWidget() self.color_label.setStyleSheet("QWidget { background-color: %s }" % color.name()) self.color_info = [0, 0, 0] self.color_layout = QtGui.QHBoxLayout() self.color_btn = QPushButton('选择颜色') self.color_btn.clicked.connect(self.color_dialog) self.color_layout.addWidget(self.color_label) self.color_layout.addWidget(self.color_btn) # 笔刷 global brush2idx self.brush_combo_box = QComboBox() self.brush_combo_box.addItems(list(brush2idx.keys())) # 按钮 self.attributes_add_btn = QPushButton('添加标签') self.attributes_add_btn.clicked.connect(self.add_attributes) # 加入控件 self._add_label_group_layout.addWidget(self.attributes_LineEdit, 0) self._add_label_group_layout.addWidget(self.attributes_type, 1) self._add_label_group_layout.addWidget(self.hotkey, 2) self._add_label_group_layout.addWidget(self.text_LineEdit, 3) self._label_widget = QWidget() self._label_widget.setLayout(self.color_layout) self._add_label_group_layout.addWidget(self._label_widget, 4) self._add_label_group_layout.addWidget(self.brush_combo_box, 5) self._add_label_group_layout.addWidget(self.attributes_add_btn, 6) # 生成训练数据按钮 self._file_button = QPushButton('生成训练数据') self._file_button.clicked.connect(self.generate) # Global widget self._layout = MyVBoxLayout() self.setLayout(self._layout) self._layout.addWidget(self._classbox, 1) self._layout.insertWidget(-1, self._group_box_add_label, 1) self._layout.insertWidget(-1, self._group_box_add_txt, 1) self._layout.insertWidget(-1, self._group_box_add_files, 1) self._layout.insertWidget(-1, self._file_button, 1)
def _setupGUI(self): self._class_buttons = {} self.label_menu = {} self.label_action = {} self._label_editor = None # Label class buttons self._parea = QGroupBox("Labels") self._classbox = QScrollArea() self._classbox_layout = FloatingLayout() self._parea.setLayout(self._classbox_layout) self._parea.setGeometry(0, 0, 200, 200) self._classbox.setWidget(self._parea) self._classbox.setGeometry(0, 0, 100, 100) # 添加txt模块 self.combo_box = QComboBox() self._group_box_add_txt = QGroupBox('add_txt', self) self._group_box_add_txt_layout = QVBoxLayout() self._group_box_add_txt.setLayout(self._group_box_add_txt_layout) temp = cf.LABELS self.items = [] # 获取所有的标签 for i in temp: self.items.append(i['attributes']['class']) # 假如下拉框 self.combo_box.addItems(self.items) self.add_txt_btn = QPushButton('add txt') self.add_txt_btn.clicked.connect(self.add_txt) # 加入下拉框和按钮 self._group_box_add_txt_layout.addWidget(self.combo_box, 0) self._group_box_add_txt_layout.addWidget(self.add_txt_btn, 1) # 根据关键字搜索图片模块 self._group_box_add_files = QGroupBox('add files', self) # 文件名包含的 self._key_word = QLineEdit('') self._key_word.setPlaceholderText('Second') # 文件类型 self._extension = QLineEdit('') self._extension.setPlaceholderText('bmp') self._search_btn = QPushButton('search files') self._group_box_add_files_layout = QVBoxLayout() # 加入控件 self._group_box_add_files_layout.addWidget(self._key_word, 0) self._group_box_add_files_layout.addWidget(self._extension, 1) self._group_box_add_files_layout.addWidget(self._search_btn, 2) self._group_box_add_files.setLayout(self._group_box_add_files_layout) # 添加标签模块 self._group_box_add_label = QGroupBox("添加标签", self) self._add_label_group_layout = QVBoxLayout() self._group_box_add_label.setLayout(self._add_label_group_layout) # 标签的class self.attributes_LineEdit = QLineEdit('') self.attributes_LineEdit.setPlaceholderText('attributes') # 标签画出来的类型 self.attributes_type = QComboBox() self.attributes_type.addItems(self.get_attributes_type()) # 快捷键,目前设置了只允许一个键 self.hotkey = QLineEdit('') self.hotkey.setPlaceholderText('hotkey') self.regx = QRegExp("[a-z0-9]$") self.validator = QRegExpValidator(self.regx, self.hotkey) self.hotkey.setValidator(self.validator) # 标签显示 self.text_LineEdit = QLineEdit('') self.text_LineEdit.setPlaceholderText('text') # 颜色 color = QtGui.QColor(0, 0, 0) self.color_label = QtGui.QWidget() self.color_label.setStyleSheet("QWidget { background-color: %s }" % color.name()) self.color_info = [0, 0, 0] self.color_layout = QtGui.QHBoxLayout() self.color_btn = QPushButton('选择颜色') self.color_btn.clicked.connect(self.color_dialog) self.color_layout.addWidget(self.color_label) self.color_layout.addWidget(self.color_btn) # 笔刷 global brush2idx self.brush_combo_box = QComboBox() self.brush_combo_box.addItems(list(brush2idx.keys())) # 按钮 self.attributes_add_btn = QPushButton('添加标签') self.attributes_add_btn.clicked.connect(self.add_attributes) # 加入控件 self._add_label_group_layout.addWidget(self.attributes_LineEdit, 0) self._add_label_group_layout.addWidget(self.attributes_type, 1) self._add_label_group_layout.addWidget(self.hotkey, 2) self._add_label_group_layout.addWidget(self.text_LineEdit, 3) self._label_widget = QWidget() self._label_widget.setLayout(self.color_layout) self._add_label_group_layout.addWidget(self._label_widget, 4) self._add_label_group_layout.addWidget(self.brush_combo_box, 5) self._add_label_group_layout.addWidget(self.attributes_add_btn, 6) # 生成训练数据按钮 self._file_button = QPushButton('生成训练数据') self._file_button.clicked.connect(self.generate) # Global widget self._layout = MyVBoxLayout() self.setLayout(self._layout) self._layout.addWidget(self._classbox, 1) self._layout.insertWidget(-1, self._group_box_add_label, 1) self._layout.insertWidget(-1, self._group_box_add_txt, 1) self._layout.insertWidget(-1, self._group_box_add_files, 1) self._layout.insertWidget(-1, self._file_button, 1)
class PropertyEditor(QWidget): # Signals insertionModeStarted = pyqtSignal(str, str, str) insertionModeEnded = pyqtSignal() insertionPropertiesChanged = pyqtSignal(object) editPropertiesChanged = pyqtSignal(object) checkboxStateChangedSignal = pyqtSignal(str, object) _optionsCheckboxStateChangedSignal = pyqtSignal(str, object) def setAnnotationScene(self, annotationScene): self._scene = annotationScene def setOptionStateChangedSignalSlot(self, checkboxStateChangedSignalSlot): if checkboxStateChangedSignalSlot is not None: self.checkboxStateChangedSignal.connect( checkboxStateChangedSignalSlot) self._optionsCheckboxStateChangedSignal.connect( self.onInserterButtonOptionChanged) # set enable status for the checkbox group which is attached to inserterButton def enableCheckboxGroup(self, inserterButtonName, enabled=True): widgetsInfo = self._widgets_dict.get(inserterButtonName, None) if not widgetsInfo: return if widgetsInfo[1]: # this button has an attachedCheckboxGroup attachedCheckboxGroupWidget = widgetsInfo[1] attachedCheckboxGroupWidget.enableAll(enabled) # set check status for one specific checkbox which is attached to inserterButton def setCheckedCheckbox(self, inserterButtonName, checkBoxName, checked=True): widgetsInfo = self._widgets_dict.get(inserterButtonName, None) # print "inserterButtonName {} _widgets_dict {} checkBoxName {} checked {} ...".format(inserterButtonName, self._widgets_dict, checkBoxName, checked) if not widgetsInfo: return if widgetsInfo[1]: # this button has an attachedCheckboxGroup attachedCheckboxGroupWidget = widgetsInfo[1] attachedCheckboxGroupWidget.setCheckedCheckbox( checkBoxName, checked) # set check status for some specific checkboxs which are attached to inserterButton def setCheckedCheckboxs(self, inserterButtonName, checkBoxNamesList, checked=True): widgetsInfo = self._widgets_dict.get(inserterButtonName, None) if not widgetsInfo: return if widgetsInfo[1]: # this button has an attachedCheckboxGroup attachedCheckboxGroupWidget = widgetsInfo[1] attachedCheckboxGroupWidget.setCheckedCheckboxs( checkBoxNamesList, checked) # get names list of all checkboxs in the checkbox group which is attached to inserterButton def getCheckboxsName(self, inserterButtonName, enabled=True): widgetsInfo = self._widgets_dict.get(inserterButtonName, None) if not widgetsInfo: return if widgetsInfo[1]: # this button has an attachedCheckboxGroup attachedCheckboxGroupWidget = widgetsInfo[1] return attachedCheckboxGroupWidget.get_checkboxs_name() return None def __init__(self, config, idName, displayName, groupBoxName, parent=None): QWidget.__init__(self, parent) self._inserters_modelitems = { } # dict. { inserter_class_name : AnnotationModelItem, ...}. Note that, inserter_class_name is not always equal to inserter_button_name, for those buttons with attached options. self._inserters_guiitems = { } # dict. { inserter_class_name : (inserter_creator_method, inserted_item_creator_method) } self._idName = idName self._groupBoxName = groupBoxName self._displayName = displayName self._scene = None self._current_toinsert_inserterClassName = None self._current_is_insert_mode = False self._widgets_dict = { } # dict. { inserter_button_name :[buttonWidget, buttonAttachedOptionsWidget, buttonName], ....} self._setupGUI(self._groupBoxName) # Add label classes from config for buttonConfig in config: self.addButton(buttonConfig) # print "self._inserters_guiitems = {}".format(self._inserters_guiitems) def onModelChanged(self, new_model): pass def addButton(self, buttonConfig): # LOG.info("addLabelClass with buttonConfig {} ...".format(buttonConfig)) # Check label configuration if 'attributes' not in buttonConfig: raise ImproperlyConfigured("Label with no 'attributes' dict found") inserter_creator_method = buttonConfig['inserter'] inserted_item_creator_method = buttonConfig['item'] attrs = buttonConfig['attributes'] # LOG.info("buttonConfig['attributes'] {} type {} ...".format(buttonConfig['attributes'], type(buttonConfig['attributes']))) if config.METADATA_LABELCLASS_TOKEN not in attrs: raise ImproperlyConfigured( "Labels must have an attribute config.METADATA_LABELCLASS_TOKEN" ) label_class = attrs[config.METADATA_LABELCLASS_TOKEN] # LOG.info("buttonConfig['attributes'][config.METADATA_LABELCLASS_TOKEN] {} type {} ...".format(attrs[config.METADATA_LABELCLASS_TOKEN], type(attrs[config.METADATA_LABELCLASS_TOKEN]))) if label_class in self._inserters_modelitems: raise ImproperlyConfigured( "Label with class '%s' defined more than once" % label_class) # Add INSERTER button displaytext = attrs['displaytext'] buttonName = label_class button = QPushButton(displaytext, self) optionInfo = attrs.get('optioninfo', None) # print "button {}: option {}".format(buttonName, optionInfo) buttonOptionsWidget = None buttonDisplayColor = None tmp = [ o.get(default_config.METADATA_DISPLAYCOLOR_TOKEN, None) for o in optionInfo['option'] if o.get(config.METADATA_IS_DEFAULT_TOKEN, False) ][0] if optionInfo else None buttonDisplayColor = tmp if tmp else optionInfo['option'][0].get( default_config.METADATA_DISPLAYCOLOR_TOKEN, None) if optionInfo else attrs.get( default_config.METADATA_DISPLAYCOLOR_TOKEN, None) # LOG.info(u"buttonConfig['attributes'] = {}, displaytext = {}, displayColor = {}".format(attrs, displaytext, buttonDisplayColor)) # ==== zx add @ 20161114 to display button with color configured by user ==== txtColor = None if buttonDisplayColor is not None: qtColor, hexColor = utils.getColorDesc(buttonDisplayColor) rgba = utils.hexColorStrToRGBA(hexColor) distance = math.sqrt((rgba[0] - 255)**2 + (rgba[1] - 255)**2 + (rgba[2] - 255)**2) txtColor = '#000000' if distance > config.GUI_COLOR_TAG_TEXT_BLACKWHITE_TOGGLE_THRESHOLD else '#ffffff' buttonDisplayColor = hexColor[0:8] # LOG.info(u"buttonDisplayColor = {} txtColor = {}, qtColor = {} hexColor = {}".format(buttonDisplayColor, txtColor, qtColor, hexColor )) # print (u"buttonDisplayColor = {} txtColor = {}, qtColor = {} hexColor = {}".format(buttonDisplayColor, txtColor, qtColor, hexColor )) # print "button {} buttonDisplayColor {} ...".format(buttonName, buttonDisplayColor) utils.set_qobj_stylesheet( button, 'QPushButton', widgetBackgroundColor=None, widgetTextColor=None, widgetBackgroundColorWhenChecked=buttonDisplayColor, widgetTextColorWhenChecked=txtColor) # ========================== zx add end ============================ button.clicked.connect(bind(self.onClassButtonPressed, label_class)) # Add hotkey if 'hotkey' in buttonConfig: hotkey = QShortcut(QKeySequence(buttonConfig['hotkey']), self) hotkey.activated.connect(button.click) self._class_shortcuts[label_class] = hotkey # print "{} is set hotkey {} {}".format(label_class, buttonConfig['hotkey'], hotkey) if optionInfo: optionListName = optionInfo['name'] optionListText = optionInfo['displaytext'] option = optionInfo['option'] buttonOptionsWidget = AttachedCheckboxGroupWidget( buttonName, optionListName, optionListText, True, option, self._optionsCheckboxStateChangedSignal, parent=None) isDefaultOption = False for o in option: new_class = o.get('tag', None) if new_class: # Add prototype mdoelItem for insertion mi = {config.METADATA_LABELCLASS_TOKEN: new_class} mi['displaytext'] = o.get('displaytext', new_class) self._inserters_modelitems[ new_class] = AnnotationModelItem(mi) self._inserters_guiitems[new_class] = ( inserter_creator_method, inserted_item_creator_method) # print "addButton.....self._inserters_guiitems[{}] = {}".format(new_class, (inserter_creator_method, inserted_item_creator_method)) for key, val in o.iteritems(): if key != 'tag': self._inserters_modelitems[new_class][key] = val else: attrs = buttonConfig['attributes'] # Add prototype mdoelItem for insertion mi = {config.METADATA_LABELCLASS_TOKEN: label_class} mi['displaytext'] = attrs.get('displaytext', label_class) self._inserters_modelitems[label_class] = AnnotationModelItem(mi) self._inserters_guiitems[label_class] = ( inserter_creator_method, inserted_item_creator_method) # update their values for key, val in attrs.iteritems(): self._inserters_modelitems[label_class][key] = val # LOG.info("self._inserters_modelitems[{}][{}] = {}".format(label_class, key, val)) self._widgets_dict[label_class] = [button, buttonOptionsWidget] # print "self._widgets_dict [ {} ] = {}".format(label_class, button) button.setCheckable(True) utils.set_qobj_stylesheet( self._widgets_dict[label_class][0], 'QPushButton', widgetBackgroundColor=None, widgetTextColor=None, widgetBackgroundColorWhenChecked=buttonDisplayColor, widgetTextColorWhenChecked=txtColor) if buttonOptionsWidget: # self._layout.addWidget(button) self._inserterButtonGroup_layout.addWidget(button) self._layout.addWidget(buttonOptionsWidget) else: self._inserterButtonGroup_layout.addWidget(button) def onClassButtonPressed(self, pressedButtonName): # print "onClassButtonPressed ... button {} isChecked !".format(pressedButtonName) inserterClassName = pressedButtonName if pressedButtonName not in self._widgets_dict.keys(): # check whether passed-in pressedButtonName argument is an checkbox option name for kk, vv in self._widgets_dict.iteritems(): buttonOptionsWidget = vv[1] if vv else None if buttonOptionsWidget: optionsName = buttonOptionsWidget.get_checkboxs_name() if pressedButtonName in optionsName: pressedButtonName = kk # print "pressedButtonName ============ {}".format(kk) if self._widgets_dict[pressedButtonName][0].isChecked(): if not self._scene._image_item: self._widgets_dict[pressedButtonName][0].setChecked(False) return checkedOption = None if self._widgets_dict[pressedButtonName][1]: buttonOptionsWidget = self._widgets_dict[pressedButtonName][1] checkedOptionsNameList = buttonOptionsWidget.get_checked_widgets_name( ) if not checkedOptionsNameList: checkedOptionsNameList = [ buttonOptionsWidget._defaultCheckboxName ] buttonOptionsWidget.setCheckedCheckbox( buttonOptionsWidget._defaultCheckboxName) buttonOptionsWidget.enableAll() checkedOptionName = checkedOptionsNameList[0] orgClsNames = [ i for i in buttonOptionsWidget.get_checkboxs_name() if i in self._inserters_modelitems.keys() ] if (not orgClsNames): raise RuntimeError( "There are no or more than one inserters") inserterClassName = checkedOptionName if ((not self._scene._labeltool._enableAutoConnectLabelMode) and (self._scene._selectedDisplayItemsList is not None) and (len(self._scene._selectedDisplayItemsList) == 1)): parentModelItem = self._scene._selectedDisplayItemsList[0][ annotationscene. SELECTED_DISPLAYED_ITEMS_LIST_MODELITEM_INDEX] clsNameOfChild = inserterClassName if ((clsNameOfChild == config.ANNOTATION_PERSONBIKE_TOKEN) or (clsNameOfChild == config.ANNOTATION_PEDESTRAIN_TOKEN) or (clsNameOfChild == config.ANNOTATION_VEHICLE_TOKEN)): self._scene._selectedDisplayItemsList = [] parentModelItem = None elif (self._scene._sceneViewMode == config.OBJ_VIEW_MODE) and ( self._scene._objViewModeTopModelItem is not None): parentModelItem = self._scene._objViewModeTopModelItem else: parentModelItem = None LOG.info( "onClassButtonPressed ... self._scene._labeltool._enableAutoConnectLabelMode = {} parentModelItem = {}" .format(self._scene._labeltool._enableAutoConnectLabelMode, parentModelItem)) if not self._scene._labeltool._enableAutoConnectLabelMode: clsNameOfChild = inserterClassName isValid, rectBoundary = self._scene.checkModelItemValidity( clsNameOfChild, None, parentModelItem, self._scene._image_item, enablePopupMsgBox=True, enableEmitStatusMsg=False, enableCountingThisModelItem=True) if not isValid: LOG.info("enter hhhhhhhhhhhhhhh....") # -------------------------------------- # added by zx @ 2017-02-08 # to exit all inserters among all pannels # -------------------------------------- for i in self._scene._labeltool.propertyeditors(): if i: i.setCheckedAll(False) # self._scene._labeltool.exitInsertMode() self._scene.deselectAllItems() # -------------------------------------- return LOG.info("onClassButtonPressed ... call startInsertionMode...") self.startInsertionMode(pressedButtonName, inserterClassName) else: LOG.info("onClassButtonPressed ... call endInsertionMode...") self.endInsertionMode() return def startInsertionMode(self, pressedButtonName, inserterClassName): self.endInsertionMode(False) LOG.info( "Starting insertion mode for {} .. self._inserters_modelitems[{}]={} " .format(inserterClassName, inserterClassName, self._inserters_modelitems[inserterClassName])) for lc, buttonAndOption in self._widgets_dict.items(): buttonAndOption[0].setChecked(lc == pressedButtonName) if buttonAndOption[1]: # print ("startInsertionMode .. setchecked for {} option {} enabled = {} ".format(lc, buttonAndOption[1], (lc == pressedButtonName))) buttonAndOption[1].enableAll(lc == pressedButtonName) LOG.info( "startInsertionMode .. setchecked for {} button checked = {} ". format(lc, lc == inserterClassName)) # print ("startInsertionMode .. setchecked for {} button {} checked = {} ".format(lc, buttonAndOption[0], lc == inserterClassName)) self._current_toinsert_inserterClassName = inserterClassName # print "==== startInsertionMode set _current_is_insert_mode False ..." self._current_is_insert_mode = True LOG.info( u"startInsertionMode .. emit insertionModeStarted(pannel = {}, inserter = {})... " .format(self._idName, inserterClassName)) self.insertionModeStarted.emit(self._idName, inserterClassName, inserterClassName) def endInsertionMode(self, uncheck_buttons=True): if uncheck_buttons: self.setCheckedAll(False) LOG.info( u"endInsertionMode... PropertyEditor {} endInsertionMode(uncheck_buttons = {})" .format(self._displayName, uncheck_buttons)) # print (u"endInsertionMode... PropertyEditor {} endInsertionMode(uncheck_buttons = {})".format(self._displayName, uncheck_buttons)) self._current_is_insert_mode = False self.insertionModeEnded.emit() def enableAll(self, enabled=True): for v, buttonAndOption in self._widgets_dict.items(): buttonAndOption[0].setEnabled(enabled) def setCheckedAll(self, checked=True): for v, buttonAndOption in self._widgets_dict.items(): buttonAndOption[0].setChecked(checked) def getChecked(self): buttonname = None for buttonName, buttonWidgets in self._widgets_dict.iteritems(): if buttonWidgets[0].isChecked(): return buttonName return buttonname def setChecked(self, buttonName, checked=True): buttonWidget = self._widgets_dict.get(buttonName, None) if buttonWidget is not None: buttonWidget[0].setChecked(checked) def enable(self, buttonName, enabled=True): buttonWidget = self._widgets_dict.get(buttonName, None) if buttonWidget is not None: buttonWidget[0].setEnabled(enabled) def markEditButtons(self, buttonNamesList): for lc, buttonAndOption in self._widgets_dict.items(): # buttonAndOption[0].setFlat(lc not in buttonNamesList) buttonAndOption[0].setChecked(lc in buttonNamesList) def updateCurrentInserter(self, inserterClassName): self._current_toinsert_inserterClassName = inserterClassName return def isInsertingMode(self): return self._current_is_insert_mode def currentToInsertItemProperty(self): return self._inserters_modelitems.get( self._current_toinsert_inserterClassName, {}) if self._current_toinsert_inserterClassName else {} # return [inserter0ClassName, inserter1ClassName, ...] def getSupportedInserters(self): return self._inserters_modelitems.keys() def startEditMode(self, model_items): # If we're in insertion mode, ignore empty edit requests if self._current_is_insert_mode and len(model_items) == 0: return self.endInsertionMode() LOG.info("Starting edit mode for model_items: {} ".format(model_items)) self._current_toinsert_inserterClassName = None # print "==== startEditMode set _current_is_insert_mode False ..." self._current_is_insert_mode = False labelClasses = set([ item[config.METADATA_LABELCLASS_TOKEN] for item in model_items if config.METADATA_LABELCLASS_TOKEN in item ]) self.markEditButtons(labelClasses) def _setupGUI(self, _groupBoxName): self._widgets_dict = {} self._class_shortcuts = {} # Label class buttons qss = "QGroupBox::title {subcontrol-origin: margin; subcontrol-position: top left; padding: 0 3px; color : red; font-weight:bold; }" self._inserterButtonGroupbox = QGroupBox(_groupBoxName, self) self._inserterButtonGroupbox.setStyleSheet(qss) self._inserterButtonGroup_layout = FloatingLayout() self._inserterButtonGroupbox.setLayout( self._inserterButtonGroup_layout) # Global widget self._layout = MyVBoxLayout() self.setLayout(self._layout) self._layout.addWidget(self._inserterButtonGroupbox, 0) self._layout.addStretch(1) def onInserterButtonOptionChanged(self, _inserterButtonName, checkboxsInfo): # print "onInserterButtonOptionChanged {}: inserterButton {} checkboxinfo {}".format(self._idName, _inserterButtonName, checkboxsInfo) if not checkboxsInfo: return if len(checkboxsInfo) != 2: return inserterButtonName = str(_inserterButtonName) checkedWidgetsAttrDescDict = checkboxsInfo[0] allCheckboxsNameList = checkboxsInfo[1] if len(checkedWidgetsAttrDescDict) != 1: return checkedOptionName = checkedWidgetsAttrDescDict.keys()[0] if (self._current_toinsert_inserterClassName == checkedOptionName): return checkedOptionDisplayText = checkedWidgetsAttrDescDict.values()[0][ attrArea.checkedWidgetsAttrDescList_checkedWidgetText_idx] checkedOptionDisplayColor = checkedWidgetsAttrDescDict.values()[0][ attrArea.checkedWidgetsAttrDescList_checkedWidgetColor_idx] # change inserter button displaycolor # print "--- self._current_is_insert_mode = {} self._widgets_dict[{}][0].is_checked() = {} ...".format(self._current_is_insert_mode, inserterButtonName, self._widgets_dict[inserterButtonName][0].isChecked()) utils.set_qobj_stylesheet( self._widgets_dict[inserterButtonName][0], 'QPushButton', widgetBackgroundColor=None, widgetTextColor=None, widgetBackgroundColorWhenChecked=checkedOptionDisplayColor, widgetTextColorWhenChecked=None) if not self._current_is_insert_mode or self._scene._sceneViewMode == config.OBJ_VIEW_MODE: parentModelItem = None if self._scene._sceneViewMode == config.OBJ_VIEW_MODE: # print "_sceneViewMode = {} _objViewModeTopModelItem = {}".format(self._scene._sceneViewMode, self._scene._objViewModeTopModelItem) parentModelItem = self._scene._objViewModeTopModelItem if not parentModelItem: # get current scene's parent modelitem if len(self._scene._selectedDisplayItemsList) > 0: parentModelItem = self._scene._selectedDisplayItemsList[0][ annotationscene. SELECTED_DISPLAYED_ITEMS_LIST_MODELITEM_INDEX] # print "_selectedDisplayItemsList = {}".format(self._scene._selectedDisplayItemsList) if not parentModelItem: parentModelItem = self._scene._labeltool._current_image # print ("checkedOptionName = {} parentModelItem = {}".format(checkedOptionName, GET_ANNOTATION(parentModelItem))) # print ("allCheckboxsNameList = {}".format((allCheckboxsNameList))) # find all modelItems which has class which in is the option list of changed inserter option but not has not that class of option foundNum = 0 foundListList = [] for a in allCheckboxsNameList: foundList = model.findModelItemsWithSpecificClassNameFromRoot( a, parentModelItem, 5) # print "find {} => {}".format(a, foundList) foundNum += len(foundList) # if a != checkedOptionName else 0 maxNum = 1 if foundNum > maxNum: print "Error: there are {} items of {} in current image! We can only modify at least {} item once!".format( foundNum, allCheckboxsNameList, maxNum) foundListList = [] break if a != checkedOptionName: foundListList += foundList # print ("foundListList = {}".format((foundListList))) # update found modelitems' class field to current selected option if foundListList: for found in foundListList: if not found: continue modelItem = found[0] iterativeLevelNum = found[1] # print "ModelItem is changed from {} => {}!".format(modelItem.get_label_name(), checkedOptionName) modelItem.update({'class': checkedOptionName}, needEmitDatachanged=True) sceneItem = self._scene.modelItem_to_baseItem(modelItem) # print u"checkedOptionDisplayText = {} checkedOptionDisplayColor = {}".format(checkedOptionDisplayText, checkedOptionDisplayColor) sceneItem.updateInfo(checkedOptionDisplayText, checkedOptionDisplayColor) # newModelItem = copy.deepcopy(oldModelItem) # self._scene.deleteItems(self, [oldModelItem], recursiuve=True) else: # switch to new inserter as per current selected inserter button type # print "---------------- _current_is_insert_mode = {} ...".format(self._current_is_insert_mode) # print "call onInsertionModeStarted with {} {}...".format(checkedOptionName, inserterButtonName) self.updateCurrentInserter(checkedOptionName) self._scene.onInsertionModeStarted(self._idName, checkedOptionName, inserterButtonName) return def onInsertionModeStarted(self, _classNameToInsert, _buttonNameOfInserter): buttonNameOfInserter = str(_buttonNameOfInserter) self.setChecked(buttonNameOfInserter, True) self._current_is_insert_mode = True self.updateCurrentInserter(str(_classNameToInsert)) return
def __init__(self, stateChangedSignalSlot=None, property=None, displayName=None, parent=None): QWidget.__init__(self, parent) self.hotkeys = [] self.name = displayName self.vlayout = MyVBoxLayout() #QVBoxLayout() self.vlayout.setAlignment(Qt.AlignTop) self.vlayout.setSpacing(4) self.vlayout.setMargin(4) #self.vlayout.setContentsMargins(0, 0, 0, 44) if stateChangedSignalSlot is not None: self.stateChanged.connect(stateChangedSignalSlot) # LOG.info("AttrAreaWidget constructor : property {} ...".format(property)) self.numGroups = len(property) if property is not None else 0 self.buttonGroupsDescDict = {} self.buttonGroupWidgets = {} for i in xrange(self.numGroups): thisGroupProperty = property[i] # thisGroupProperty is a dict thisGroupName = thisGroupProperty.get( 'name') # thisGroupName is a string thisGroupOption = thisGroupProperty.get( 'option' ) # thisGroupOption is a tuple of dicts. each dict describes a checkbox thisGroupText = thisGroupProperty.get('displaytext') thisGroup isExclusive = False if thisGroupName in config.NON_EXCLUSIVE_ATTRS_TAG_LIST else True if thisGroupName == config.ANNOTATION_PERSONBIKE_TYPE_GROUP_TOKEN: checkboxWidgetMinWidthInPixels = 52 else: checkboxWidgetMinWidthInPixels = 38 thisGroupWidget = checkBoxListWidget(thisGroupName, thisGroupText, isExclusive, thisGroupOption, self.stateChanged) if thisGroupName == config.ANNOTATION_UPPER_COLOR_TOKEN: thisGroupWidget.setMaxCheckedNum(config.MAX_UPPER_COLOR_NUMBER) thisGroupWidget.setMaxSeperateWidgetNum( config.GUI_MAX_SEPERATE_UPPER_COLOR_WIDGET_NUMBER) elif thisGroupName == config.ANNOTATION_LOWER_COLOR_TOKEN: thisGroupWidget.setMaxCheckedNum(config.MAX_LOWER_COLOR_NUMBER) thisGroupWidget.setMaxSeperateWidgetNum( config.GUI_MAX_SEPERATE_LOWER_COLOR_WIDGET_NUMBER) elif thisGroupName == config.ANNOTATION_VEHICLE_COLOR_TOKEN: thisGroupWidget.setMaxCheckedNum( config.MAX_VEHICLE_COLOR_NUMBER) thisGroupWidget.setMaxSeperateWidgetNum( config.GUI_MAX_SEPERATE_VEHICLE_COLOR_WIDGET_NUMBER) else: thisGroupWidget.setMaxCheckedNum( config.MAX_CHECKED_OPTIONS_NUMBER) thisGroupWidget.setMaxSeperateWidgetNum( config.MAX_OPTIONS_NUMBER) thisGroupCheckboxs = {} optCnt = 0 for checkboxOption in thisGroupOption: thisCheckboxName = checkboxOption[ config.METADATA_ATTR_VALUE_TOKEN] thisCheckboxText = checkboxOption[ config.METADATA_DISPLAYTEXT_TOKEN] thisCheckboxProperty = checkboxOption.copy() # get widget display color if thisGroupName == config.ANNOTATION_UPPER_COLOR_TOKEN or thisGroupName == config.ANNOTATION_LOWER_COLOR_TOKEN or thisGroupName == config.ANNOTATION_VEHICLE_COLOR_TOKEN: thisCheckboxBkgColorChecked = thisCheckboxProperty[ config.COLOR_ATTR_RGB_VALUE_TOKEN] thisCheckboxBkgColor = thisCheckboxBkgColorChecked else: thisCheckboxBkgColorChecked = thisCheckboxProperty[ config.METADATA_DISPLAYCOLOR_TOKEN] thisCheckboxBkgColor = None # calc widget text color # thisCheckboxBkgColorChecked string pattern: #123456 txtColorChecked = None if thisCheckboxBkgColorChecked is not None: import math rgba = utils.hexColorStrToRGBA(thisCheckboxBkgColorChecked) distance = math.sqrt((rgba[0] - 255)**2 + (rgba[1] - 255)**2 + (rgba[2] - 255)**2) txtColorChecked = '#ffffff' if distance > config.GUI_COLOR_TAG_TEXT_BLACKWHITE_TOGGLE_THRESHOLD else '#000000' txtColor = txtColorChecked if thisGroupName == config.ANNOTATION_UPPER_COLOR_TOKEN or thisGroupName == config.ANNOTATION_LOWER_COLOR_TOKEN or thisGroupName == config.ANNOTATION_VEHICLE_COLOR_TOKEN else None thisGroupCheckboxs[ thisCheckboxName] = thisCheckboxProperty # add checkbox record to this checkbox group record # add widget to this group if optCnt < thisGroupWidget._maxSeperateWidgetNum: thisGroupWidget.add_checkbox( thisCheckboxName, thisCheckboxText, thisCheckboxBkgColor, txtColor, thisCheckboxBkgColorChecked, txtColorChecked, checkboxWidgetMinWidthInPixels) else: thisGroupWidget.add_popup_button( config.GUI_MORE_WIDGET_DISPLAYTEXT, thisCheckboxName, thisCheckboxText, popupbutton_background_color="#808080", popupbutton_text_color="#ffffff", checkbox_background_color=thisCheckboxBkgColor, checkbox_text_color=txtColor) optCnt += 1 # thisGroupWidget.add_checkbox("Unset", u"Unset") thisGroupWidget.setLayout(thisGroupWidget.flayout) self.vlayout.addWidget(thisGroupWidget) self.checkboxGroupsDescDict[ thisGroupName] = thisGroupCheckboxs # add this checkbox group record to checkbox groups recrod self.checkboxGroupWidgets[thisGroupName] = thisGroupWidget # LOG.info("checkboxGroupWidgets = {} checkboxGroupsDescDict = {}".format(self.checkboxGroupWidgets, self.checkboxGroupsDescDict) self.vlayout.addStretch(1) self.setLayout(self.vlayout) return
class buttonWithOptionsWidget(QWidget): def __init__(self, annotation_scene, stateChangedSignalSlot=None, buttonWithOptionsProperty=None, displayName=None, parent=None): QWidget.__init__(self, parent) # print "buttonWithOptionsProperty = {}".format(comboPannelProperty) self.buttonWithOptionsProperty = buttonWithOptionsProperty self.name = displayName self.vlayout = QVBoxLayout() self.vlayout.setAlignment(Qt.AlignTop) self.vlayout.setSpacing(4) self.vlayout.setMargin(4) #self.vlayout.setContentsMargins(0, 0, 0, 44) self.vlayout.addWidget(self.propertyEditorWidget) self.vlayout.addWidget(self.attrAreaWidget) self.vlayout.addStretch(1) self.setLayout(self.vlayout) return def enableCheckbox(self, checkboxGroupName, checkboxName, enabled=True): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: groupWidget.enable(checkboxName, enabled) def setCheckedCheckbox(self, checkboxName, checked=True): self.checkboxGroupWidget.setCheckedCheckbox(checkboxName, checked) def setCheckedCheckboxs(self, checkboxNamesList, checked=True): if checkboxNamesList is None: return groupWidget = self.checkboxGroupWidget.get(checkboxGroupName, None) if groupWidget is not None: # LOG.info(u"{} AttrAreaWidget.setCheckedCheckbox for group {} box {} checked {} ..".format(self.name, checkboxGroupName, checkboxNamesList, checked)) groupWidget.setCheckedCheckboxs(checkboxNamesList, checked) def sendCheckedSignal(self, checkboxGroupName): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: groupWidget.sendCheckedSignal() def getCheckedWidgetsOptionInfo(self, checkboxGroupName): groupWidget = self.checkboxGroupWidgets.get(checkboxGroupName, None) if groupWidget is not None: return groupWidget.getCheckedWidgetsOptionInfo() return None, None def __init__(self, stateChangedSignalSlot=None, property=None, displayName=None, parent=None): QWidget.__init__(self, parent) self.hotkeys = [] self.name = displayName self.vlayout = MyVBoxLayout() #QVBoxLayout() self.vlayout.setAlignment(Qt.AlignTop) self.vlayout.setSpacing(4) self.vlayout.setMargin(4) #self.vlayout.setContentsMargins(0, 0, 0, 44) if stateChangedSignalSlot is not None: self.stateChanged.connect(stateChangedSignalSlot) # LOG.info("AttrAreaWidget constructor : property {} ...".format(property)) self.numGroups = len(property) if property is not None else 0 self.buttonGroupsDescDict = {} self.buttonGroupWidgets = {} for i in xrange(self.numGroups): thisGroupProperty = property[i] # thisGroupProperty is a dict thisGroupName = thisGroupProperty.get( 'name') # thisGroupName is a string thisGroupOption = thisGroupProperty.get( 'option' ) # thisGroupOption is a tuple of dicts. each dict describes a checkbox thisGroupText = thisGroupProperty.get('displaytext') thisGroup isExclusive = False if thisGroupName in config.NON_EXCLUSIVE_ATTRS_TAG_LIST else True if thisGroupName == config.ANNOTATION_PERSONBIKE_TYPE_GROUP_TOKEN: checkboxWidgetMinWidthInPixels = 52 else: checkboxWidgetMinWidthInPixels = 38 thisGroupWidget = checkBoxListWidget(thisGroupName, thisGroupText, isExclusive, thisGroupOption, self.stateChanged) if thisGroupName == config.ANNOTATION_UPPER_COLOR_TOKEN: thisGroupWidget.setMaxCheckedNum(config.MAX_UPPER_COLOR_NUMBER) thisGroupWidget.setMaxSeperateWidgetNum( config.GUI_MAX_SEPERATE_UPPER_COLOR_WIDGET_NUMBER) elif thisGroupName == config.ANNOTATION_LOWER_COLOR_TOKEN: thisGroupWidget.setMaxCheckedNum(config.MAX_LOWER_COLOR_NUMBER) thisGroupWidget.setMaxSeperateWidgetNum( config.GUI_MAX_SEPERATE_LOWER_COLOR_WIDGET_NUMBER) elif thisGroupName == config.ANNOTATION_VEHICLE_COLOR_TOKEN: thisGroupWidget.setMaxCheckedNum( config.MAX_VEHICLE_COLOR_NUMBER) thisGroupWidget.setMaxSeperateWidgetNum( config.GUI_MAX_SEPERATE_VEHICLE_COLOR_WIDGET_NUMBER) else: thisGroupWidget.setMaxCheckedNum( config.MAX_CHECKED_OPTIONS_NUMBER) thisGroupWidget.setMaxSeperateWidgetNum( config.MAX_OPTIONS_NUMBER) thisGroupCheckboxs = {} optCnt = 0 for checkboxOption in thisGroupOption: thisCheckboxName = checkboxOption[ config.METADATA_ATTR_VALUE_TOKEN] thisCheckboxText = checkboxOption[ config.METADATA_DISPLAYTEXT_TOKEN] thisCheckboxProperty = checkboxOption.copy() # get widget display color if thisGroupName == config.ANNOTATION_UPPER_COLOR_TOKEN or thisGroupName == config.ANNOTATION_LOWER_COLOR_TOKEN or thisGroupName == config.ANNOTATION_VEHICLE_COLOR_TOKEN: thisCheckboxBkgColorChecked = thisCheckboxProperty[ config.COLOR_ATTR_RGB_VALUE_TOKEN] thisCheckboxBkgColor = thisCheckboxBkgColorChecked else: thisCheckboxBkgColorChecked = thisCheckboxProperty[ config.METADATA_DISPLAYCOLOR_TOKEN] thisCheckboxBkgColor = None # calc widget text color # thisCheckboxBkgColorChecked string pattern: #123456 txtColorChecked = None if thisCheckboxBkgColorChecked is not None: import math rgba = utils.hexColorStrToRGBA(thisCheckboxBkgColorChecked) distance = math.sqrt((rgba[0] - 255)**2 + (rgba[1] - 255)**2 + (rgba[2] - 255)**2) txtColorChecked = '#ffffff' if distance > config.GUI_COLOR_TAG_TEXT_BLACKWHITE_TOGGLE_THRESHOLD else '#000000' txtColor = txtColorChecked if thisGroupName == config.ANNOTATION_UPPER_COLOR_TOKEN or thisGroupName == config.ANNOTATION_LOWER_COLOR_TOKEN or thisGroupName == config.ANNOTATION_VEHICLE_COLOR_TOKEN else None thisGroupCheckboxs[ thisCheckboxName] = thisCheckboxProperty # add checkbox record to this checkbox group record # add widget to this group if optCnt < thisGroupWidget._maxSeperateWidgetNum: thisGroupWidget.add_checkbox( thisCheckboxName, thisCheckboxText, thisCheckboxBkgColor, txtColor, thisCheckboxBkgColorChecked, txtColorChecked, checkboxWidgetMinWidthInPixels) else: thisGroupWidget.add_popup_button( config.GUI_MORE_WIDGET_DISPLAYTEXT, thisCheckboxName, thisCheckboxText, popupbutton_background_color="#808080", popupbutton_text_color="#ffffff", checkbox_background_color=thisCheckboxBkgColor, checkbox_text_color=txtColor) optCnt += 1 # thisGroupWidget.add_checkbox("Unset", u"Unset") thisGroupWidget.setLayout(thisGroupWidget.flayout) self.vlayout.addWidget(thisGroupWidget) self.checkboxGroupsDescDict[ thisGroupName] = thisGroupCheckboxs # add this checkbox group record to checkbox groups recrod self.checkboxGroupWidgets[thisGroupName] = thisGroupWidget # LOG.info("checkboxGroupWidgets = {} checkboxGroupsDescDict = {}".format(self.checkboxGroupWidgets, self.checkboxGroupsDescDict) self.vlayout.addStretch(1) self.setLayout(self.vlayout) return def stateHasChanged(self, checkedWidgetsAttrDescDict): # LOG.info("AttrAreaWidget.stateChanged with {}".format(checkedWidgetsAttrDescDict)) return def get_checked_widgets_name(self, group_name): widget = self.checkboxGroupWidgets.get(str(group_name), None) # LOG.info("AttrAreaWidget.get_checked_widgets_name ... widget = {}".format(widget)) checkedWidgetsNameList = widget.get_checked_widgets_name( ) if widget is not None else None # LOG.info("AttrAreaWidget.get_checked_widgets_name ... checkedWidget = {}".format(checkedWidget)) return checkedWidgetsNameList def add_hotkey(self, choice, name, hotkey): self.hotkeys.append((choice, name, hotkey)) def get_checked_widgets_attrDesc(self): descsDict = {} for widgetName, widgetInfo in self.checkboxWidgetsInfo.items(): if widgetInfo[0].isChecked(): desc = [None, None, None, None] desc[ checkedWidgetsAttrDescList_checkedWidget_idx] = widgetInfo[ 0] desc[ checkedWidgetsAttrDescList_checkedWidgetText_idx] = widgetInfo[ 1] desc[ checkedWidgetsAttrDescList_checkedWidgetStyleSheet_idx] = widgetInfo[ 2] descsDict[widgetName] = desc for widgetInfo in self.popupWidgetsInfo.values(): for actionWidget in widgetInfo[ popupWidgetsInfo_actionsWidgetList_idx]: if actionWidget.isChecked(): idx = widgetInfo[ popupWidgetsInfo_actionsWidgetList_idx].index( actionWidget) desc = [None, None, None, None] desc[ checkedWidgetsAttrDescList_checkedWidget_idx] = actionWidget desc[ checkedWidgetsAttrDescList_checkedWidgetText_idx] = widgetInfo[ popupWidgetsInfo_actionsTextList_idx][idx] desc[ checkedWidgetsAttrDescList_checkedWidgetStyleSheet_idx] = widgetInfo[ popupWidgetsInfo_actionsWidgetStyleSheet_idx] desc[ checkedWidgetsAttrDescList_checkedWidgetPopupParentWidget_idx] = widgetInfo[ popupWidgetsInfo_pushButtonWidget_idx] widgetName = widgetInfo[ popupWidgetsInfo_actionsNameList_idx][idx] descsDict[widgetName] = desc return descsDict def startEditMode(self, model_items): return