class AlphaButton(QtWidgets.QWidget): alphaClick = QtCore.Signal() ''' custom QLbael the can send clicked signal, only from the pixmap are that has 100% alpha used for the thumbnail transperent icon button ''' def __init__(self, parent, alpha): QtWidgets.QWidget.__init__(self, parent) self.pixmap = alpha self.button = QLabelButton(self) # self.solid = QtGui.QPixmap(96,96) # self.solid.fill(QtGui.QColor(cfg.colors.LIGHT_PURPLE)) self.button.setPixmap(self.pixmap) # self.button.setStyleSheet('''QLabel { # color: ''' + cfg.colors.LIGHT_PURPLE + '''; # }''') self.button.setScaledContents(True) self.button.setMask(self.pixmap.mask()) self.button.clicked.connect(self.onClick) # self.connect(self.button, QtCore.SIGNAL('clicked()'), self.onClick) def onClick(self): self.alphaClick.emit() # self.emit(QtCore.SIGNAL('clicked()')) def set_pixmap(self, pixmap): self.button.setPixmap(pixmap) self.button.setScaledContents(True) self.button.setMask(pixmap.mask())
class Click_label(QtWidgets.QLabel): clicked = QtCore.Signal() def __init__(self): super(Click_label, self).__init__() def mouseReleaseEvent(self, e): logger.info(e) self.clicked.emit() e.accept()
class QLabelButton(QtWidgets.QLabel): clicked = QtCore.Signal() ''' custom QLbael the can send clicked signal ''' def __init__(self, parent): QtWidgets.QLabel.__init__(self, parent) # color = cfg.colors.LIGHT_GRAY # "#ccc" # # # self.setStyleSheet('''QLabel{ # # color: #ccc; # # background-color: ''' + color + '''; # # border-radius: 12px; # # padding: 4px; # # } # # ''') def mouseReleaseEvent(self, ev): click = ev.pos() if self.mask().contains(click): self.clicked.emit()
class FilterComboWidget(comboBox.ComboWidget): changed = QtCore.Signal(str) def __init__(self, items=None, path=None, parent_layout=None, parent=None): super(FilterComboWidget, self).__init__(parent_layout, parent) self.setMaximumHeight(30) self.setMinimumHeight(30) self.setMaximumWidth(150) self.setMinimumWidth(150) self.label.setParent(None) self.label.deleteLater() self.parent = parent self.setHidden(False) # self.comboBox.currentIndexChanged.connect(self.update) # logger.info("connecting to {}".format(self.parent)) # self.changed.connect(self.parent.set_view_root) def update(self): return # logger.info("updating with {}".format(self.comboBox.currentText())) # path = os.path.join(self._path,self.comboBox.currentText()) if self._path else self.comboBox.currentText() # self.changed.emit(path) # self.parent.address_label.setText(self.comboBox.currentText()) def set_branch(self, string): return if comboBox.setComboValue(self.comboBox, string): # logger.info("branch set to {}".format(string)) self.update() def set_root(self, path): return if path: self._path = path self.listDirectory() self.createModel() # self.update() else: self.comboBox.clear() def createModel(self): return self.comboBox.clear() # dt.CatagoryNode(name, path=path, project = self.parent.parent.project) li = [] # p = self._parent_box.folderView.selectionModel() if self._subdirectories: # p = self._parent_box.selected_node if self._parent_box else None for dir in sorted(self._subdirectories): n = os.path.split(dir)[1] path = os.path.join(self._path, dir) if misc.branch_dir(path): li.append( pipeline.libs.nodes.stages.BranchNode( n, path=path, project=self.project)) if li: self.comboBox.setModel(models.List_Model(li)) return True return False
class Scan_masters_thread(QtCore.QObject, threading.Thread): update = QtCore.Signal(object) percent = QtCore.Signal(int) def __init__(self, path_to_dir='.', project=None): QtCore.QObject.__init__(self) threading.Thread.__init__(self) self._path = path_to_dir self.project = project self.daemon = True self.killed = False def run(self): li = [] try: li = self.createModel() except SystemExit: pass # print 'system exit at in {}.thread.run():'.format(self.__class__.__name__) except: print 'exceptions in {}.thread.run():'.format( self.__class__.__name__) print traceback.print_exc() finally: self.update.emit(li) return def calculate_total(self): total = 0 for root, subFolders, _files in os.walk(self._path): for s in subFolders: total += 1 return total def createModel(self): li = list() index = 0 max = self.calculate_total() if not self.project: return li for root, subFolders, _files in os.walk(self._path): for s in subFolders: index += 1 folder = os.path.join(root, s) comp = folder if misc.component_dir(folder) else None if comp: node = stages.ComponentNode(os.path.split(comp)[1], path=comp, project=self.project) if node.public: li.append({ "name": os.path.split(comp)[1], "path": comp }) del node val = remap(index, 0, max, 0, 100) self.percent.emit(val) return li def start(self): """Start the thread.""" self.__run_backup = self.run self.run = self.__run # Force the Thread to threading.Thread.start(self) def __run(self): """Hacked run function, which installs the trace.""" sys.settrace(self.globaltrace) self.__run_backup() self.run = self.__run_backup def globaltrace(self, frame, why, arg): if why == 'call': return self.localtrace else: return None def localtrace(self, frame, why, arg): if self.killed: if why == 'line': raise SystemExit() return self.localtrace def kill(self): try: self.update.disconnect() self.percent.disconnect() except: pass self.killed = True
class Library(QtWidgets.QWidget): component_changed = QtCore.Signal() def __init__(self, parent=None, settings=None): super(Library, self).__init__(parent) self.setMinimumHeight(100) self.parent = parent self.layout = QtWidgets.QVBoxLayout(self) self.layout.setContentsMargins(0, 5, 0, 0) self.library_view = views.Library_View(self, settings=settings) self.layout.addWidget(self.library_view) self.progressBar = QtWidgets.QProgressBar(self) self.progressBar.setMaximum(100) self.progressBar.setMinimum(0) self.progressBar.setValue(0) self.progressBar.setMaximumHeight(5) self.progressBar.setTextVisible(False) self.progressBar.setStyleSheet(''' QProgressBar { border: 1px solid ''' + cfg.colors.DARK_GRAY_MINUS + '''; } QProgressBar::chunk { background-color: ''' + cfg.colors.DARK_PURPLE + '''; }''') self.layout.addWidget(self.progressBar) self.address_widget = QtWidgets.QWidget(self) self.address_widget_layout = QtWidgets.QHBoxLayout(self.address_widget) self.address_widget_layout.setAlignment(QtCore.Qt.AlignLeft) self.address_widget_layout.setContentsMargins(0, 3, 0, 0) self.layout.addWidget(self.address_widget) self.search_line = inputs.SuggestionSearchBar( self, label="Search public components...") self.search_line.setMinimumHeight(30) self.address_widget_layout.addWidget(self.search_line) # self.comps = list() self.comp_hints = list() self.comps_model = None self.project = None self.scan = None # # self.search_line.set_suggestions_model(None) # self.library_view.setModel_(None) # self.populate() self.search_line.textChanged.connect(self.search_changed) def set_project(self, project): # logger.info(self.parent) self.project = None if project: self.project = project # self.root_path = os.path.join(self.project.path, "assets") # self.populate() def set_root(self, path): if self.scan: try: self.scan.kill() except: print traceback.print_exc() self.search_line.set_suggestions_model(None) self.library_view.setModel_(None) if path: if os.path.exists(path): self.root_path = path self.scan = Scan_masters_thread(path_to_dir=self.root_path, project=self.project) self.scan.update.connect(self.populate) self.scan.percent.connect(self.progressBar.setValue) self.scan.start() self.show_loader() # self.populate() def populate(self, items=None): # root = self.parent.project.path self.comps = list() self.comp_hints = list() self.comps_model = None self.search_line.set_suggestions_model(None) self.library_view.setModel_(None) if not items: self.hide_loader() if self.scan: self.scan.kill() self.scan = None return for item in items: node = stages.ComponentNode(item['name'], path=item['path'], project=self.project) self.comps.append(node) # self.comp_hints.append(node.name) self.comp_hints.extend(node.full_path_elements) comp_hints_no_duplicates = sorted(list(set(self.comp_hints))) self.search_line.set_suggestions_model( QtCore.QStringListModel(comp_hints_no_duplicates)) self.comps_model = models.Library_Model(self.comps) self.library_view.setModel_(self.comps_model) self.hide_loader() if self.scan: self.scan.kill() return True def search_changed(self, str): if (self.search_line.text() != "") and (self.search_line.text() != self.search_line.label): self.filter(str) # logger.info("searching...") return else: self.library_view.setModel_(self.comps_model) # if self.rootFolder and (self.search_line.text() == ""): # if isinstance(self.results_folder, FolderStaticWidget): # self.results_folder.remove() # self.results_folder = None # # if isinstance(self.rootFolder, FolderDynamicWidget): # self.rootFolder.hide(False) # logger.info("Not searching") # return def filter(self, string): filterd_comps = list() for comp in self.comps: f = None try: f = re.search(string, comp.nice_full_name) # os.path.split(folder)[1]) except: logger.info("This search pattern {} is invalid".format(string)) # logger.info(search_in) if f: filterd_comps.append(comp) self.library_view.setModel_(models.Library_Model(filterd_comps)) def hide_loader(self): # self.folder_view.setHidden(False) self.progressBar.setHidden(True) def show_loader(self): # self.folder_view.setHidden(False) self.progressBar.setHidden(False) self.progressBar.setValue(0)
class ProjectNode(RootNode): loaded = QtCore.Signal(dict) def __init__(self, name, parent=None, **kwargs): super(ProjectNode, self).__init__(name, parent, **kwargs) self.project_file = None if self.data_file: self.project_file = self.data_file.read() self.pipelineUI = None for key in kwargs: if key == "pipelineUI": self.pipelineUI = kwargs[key] self.loaded.connect(self.pipelineUI.updateCurrentProject) def create(self, nice_name=None, path=None, padding=3, fps=25, file_type="ma", users={"0": ["Admin", "1234", "admin"]}, branches=["scenes", "assets"], playblasts_root=cfg.playblast_save_options.PROJECT_ROOT, prefix=None): file_type = "ma" project_key = serializer.id_generator() project_data = {} project_data["nice_name"] = nice_name if nice_name else self.name project_data["project_name"] = self.name project_data["project_key"] = project_key project_data["padding"] = padding project_data["fps"] = fps project_data["defult_file_type"] = file_type project_data["users"] = users project_data["playblasts_root"] = playblasts_root # project_data["prefix"] = prefix # project_data["playblast_outside"] = playblast_outside folders = [ "scenes", "assets", "images", "sourceimages", "data", "autosave", "movies", "scripts", "sound", "clips", "renderData", "cache" ] for folder in folders: # project_data[folder] = folder files.create_directory(os.path.join(path, folder)) # render folders: r_folders = ["renderData", "depth", "iprimages", "shaders"] for r_folder in r_folders[1:]: files.create_directory(os.path.join(path, r_folders[0], r_folder)) fur_folders = [ "renderData", "fur", "furFiles", "furImages", "furEqualMap", "furAttrMap", "furShadowMap" ] for f_folder in fur_folders[2:]: files.create_directory( os.path.join(path, fur_folders[0], fur_folders[1], f_folder)) # cache folders: c_folders = ["cache", "particles", "nCache", "bifrost"] for c_folder in c_folders[1:]: files.create_directory(os.path.join(path, c_folders[0], c_folder)) fl_folders = ["cache", "nCache", "fluid"] for fl_folder in fl_folders[2:]: files.create_directory( os.path.join(path, fl_folders[0], fl_folders[1], fl_folder)) self.path = path data_path = os.path.join(path, "%s.%s" % (self.name, "json")) self.data_file_path = data_path self.data_file = serializer.JSONSerializer().create( self.data_file_path, project_data) self.project_file = self.data_file.read() for branch in branches: elements.BranchNode( branch, path=os.path.join(path, branch), project=self).create(path=os.path.join(path, branch)) # elements.BranchNode("assets", path=os.path.join(path, "assets"), project = self).create(path=os.path.join(path, "assets")) if playblasts_root == cfg.playblast_save_options.PROJECT_ROOT: files.create_directory(os.path.join(path, "playblasts")) if playblasts_root == cfg.playblast_save_options.PROJECT_SISTER: try: files.create_directory( os.path.join(os.path.dirname(path), "{}_playblasts".format(self.name))) except: logger.info("Could not create Playblasts folder at: {}".format( os.path.dirname(path))) return self def online(self): if os.path.isdir(self.path): if os.path.isfile(self.data_file_path): return True return False def edit(self): logger.info(self.edit.__name__) # _users = True if self.project_users else False user = self.pipelineUI.settings.user[0] password = self.pipelineUI.settings.user[1] projectDlg = project_editor.Project_edit_Dialog( project=self, user_data=[user, password]) result = projectDlg.exec_() res = projectDlg.result() if result == QtWidgets.QDialog.Accepted: # logger.info(res) self.nice_name = res["nice_name"] if res["users_mode"]: self.users = res["users"] else: self.users = None if res["playblasts_root"] != self.project_playblasts_root: self.set_playblasts_root(res["playblasts_root"]) self.set(user=[user, password]) self.pipelineUI.navigate_to_current_file() def validate_user(self, username=None, password=None): for key in self.users: if self.users[key][0] == username and self.users[key][ 1] == password: role = self.users[key][2] if role == 'admin': role = 'administrator' return role return '' def link(self): path = QtWidgets.QFileDialog.getOpenFileName( None, "Select Pipeline project file", filter="*.*") if path[0]: project_path = os.path.dirname(path[0]) self.path = project_path self.data_file_path = path[0] self.set_data_file(self.data_file_path) self.project_file = self.data_file.read() self.pipelineUI.link_project(self) def set(self, **kwargs): user = '' password = '' role = '' if 'user' in kwargs: user = kwargs['user'][0] password = kwargs['user'][1] if self.data_file: _users = True if self.project_users else False if self.project_users: # the project is permission based if user == '': # no user was called with the function, need to prompt for credentials login = users.LoginWindow() result = login.exec_() user, password = login.result() if result == QtWidgets.QDialog.Accepted: # user entered credentials role = self.validate_user(user, password) # from user+password, return the role if role == '': # if no role was return there is no such user logger.info("invalid username or password") return False else: # recived valid role, set the user as current in the settings self.pipelineUI.settings.user = [user, password] else: # user aborted, exit return False else: # the function was called with a user+password, let's get their role role = self.validate_user(user, password) self.pipelineUI.settings.user = [user, password] if role == '': # if no role was return there is no such user logger.info("invalid username or password") return False import pymel.core as pm import maya.mel as mel pm.workspace.open(self.path) pm.workspace.chdir(self.path) raw_project_path = self.path.replace("\\", "\\\\") melCmd = "setProject \"" + raw_project_path + "\";" try: mel.eval(melCmd) except: pass logger.info("Project changed to: {} ({})".format( self.nice_name, self.name)) self.loaded.emit({'users': _users, 'user': user, 'role': role}) return True def project_file_key(self, key=None): if self.project_file: return self.project_file[key] else: return None def set_playblasts_root(self, new_root): project_root = cfg.playblast_save_options.PROJECT_ROOT project_sister = cfg.playblast_save_options.PROJECT_SISTER component_root = cfg.playblast_save_options.COMPONENT def get_fullpath_if_is_component(dir): if os.path.exists(dir): if os.path.isfile( os.path.join(dir, "%s.%s" % (os.path.split(dir)[1], "json"))): j = serializer.Metadata_file(path=os.path.join( dir, "%s.%s" % (os.path.split(dir)[1], "json"))) info = j.data_file.read() if info: if info["typeInfo"] == cfg._component_: return "_".join(info["fullpath"]) return False def move_playblasts_into_components(move_from): # logger.info("move_playblasts_into_components from {}, to {}".format(move_from, "components")) for branch in self.branches: for root, subFolders, _files in os.walk(branch): for s in subFolders: p = os.path.join(root, s) fullpath = get_fullpath_if_is_component(p) if fullpath: b = os.path.split(branch)[1] master_avi = os.path.join( move_from, b, "{}_MASTER.avi".format(fullpath)) master_mov = os.path.join( move_from, b, "{}_MASTER.mov".format(fullpath)) versions_dir = os.path.join( move_from, b, "versions", fullpath) if os.path.isfile(master_avi): logger.info( "*.avi master from: {}".format(master_avi)) target_master_avi = os.path.join( p, "{}_MASTER.avi".format(fullpath)) logger.info("will move to: {}".format( target_master_avi)) files.dir_move(master_avi, target_master_avi) if os.path.isfile(master_mov): logger.info( "*.mov master from: {}".format(master_mov)) target_master_mov = os.path.join( p, "{}_MASTER.mov".format(fullpath)) logger.info("will move to: {}".format( target_master_mov)) files.dir_move(master_mov, target_master_mov) if os.path.isdir(versions_dir): logger.info( "playblasts versions folder from: {}". format(versions_dir)) target_dir = os.path.join(p, "playblasts") logger.info( "will move to: {}".format(target_dir)) files.dir_move(versions_dir, target_dir) logger.info("<>") logger.info(os.listdir(os.path.join(move_from, b, "versions"))) if not os.listdir(os.path.join(move_from, b, "versions")): files.delete(os.path.join(move_from, b, "versions")) if not os.listdir(os.path.join(move_from, b)): files.delete(os.path.join(move_from, b)) if not os.listdir(move_from): files.delete(move_from) def move_playblasts_to_single_folder(move_to): # logger.info("move_playblasts_to_single_folde from {}, to {}".format(current_root, move_to)) for branch in self.branches: b = os.path.split(branch)[1] for root, subFolders, _files in os.walk(branch): for s in subFolders: p = os.path.join(root, s) fullpath = get_fullpath_if_is_component(p) if fullpath: master_avi = os.path.join( p, "{}_MASTER.avi".format(fullpath)) master_mov = os.path.join( p, "{}_MASTER.mov".format(fullpath)) versions_dir = os.path.join(p, "playblasts") if os.path.isfile(master_mov): target_master_mov = os.path.join( move_to, b, "{}_MASTER.mov".format(fullpath)) files.assure_folder_exists( os.path.join(move_to, b)) files.dir_move(master_mov, target_master_mov) if os.path.isfile(master_avi): target_master_avi = os.path.join( move_to, b, "{}_MASTER.avi".format(fullpath)) files.assure_folder_exists( os.path.join(move_to, b)) files.dir_move(master_avi, target_master_avi) if os.path.isdir(versions_dir): target_dir = os.path.join( move_to, b, "versions", fullpath) files.assure_folder_exists( os.path.join(move_to, b, "versions")) files.dir_move(versions_dir, target_dir) current_root = self.project_playblasts_root msg = "You are about to move your playblasts folder from {0}, to {1}.\n" \ "This may take a few minutes.".format(current_root, new_root) prompt = massage.PromptUser(self.pipelineUI, prompt=msg, override_yes_text="Proceed", override_no_label="Don't move", cancel_button=False) result = prompt.exec_() if result == 0: if (current_root == project_root) or (current_root == project_sister): if (new_root == project_root) or (new_root == project_sister): current_playblasts_folder = self.playblasts_path self.project_playblasts_root = new_root files.dir_move(current_playblasts_folder, self.playblasts_path) return else: move_playblasts_into_components(self.playblasts_path) self.project_playblasts_root = new_root return else: if (new_root == project_root) or (new_root == project_sister): self.project_playblasts_root = new_root move_playblasts_to_single_folder(self.playblasts_path) return def explore(self): files.explore(self.path) @property def branches(self): branches = list() for dir in files.list_dir_folders(self.path): if misc.branch_dir(os.path.join(self.path, dir)): branches.append(os.path.join(self.path, dir)) return branches @property def nice_name(self): if self.project_file: try: return self.project_file["nice_name"] except: return self.name else: return self.name @nice_name.setter def nice_name(self, nice_name): if self.data_file: data = {} data["nice_name"] = nice_name self.data_file.edit(data) self.project_file = self.data_file.read() @property def project_name(self): if self.project_file: return self.project_file["project_name"] else: return None @property def project_fps(self): if self.project_file: if "fps" in self.project_file.keys(): return self.project_file["fps"] else: return None else: return None @project_fps.setter def project_fps(self, fps): if self.data_file: data = {} data["fps"] = fps self.data_file.edit(data) self.project_file = self.data_file.read() @property def project_key(self): if self.project_file: return self.project_file["project_key"] else: return None @property def project_padding(self): if self.project_file: return self.project_file["padding"] else: return None @property def project_file_type(self): if self.project_file: return self.project_file["defult_file_type"] else: return None @project_file_type.setter def project_file_type(self, type): if self.data_file: data = {} data["defult_file_type"] = type self.data_file.edit(data) self.project_file = self.data_file.read() @property def project_playblasts_root(self): if self.project_file: if "playblasts_root" in self.project_file: return self.project_file["playblasts_root"] return cfg.playblast_save_options.PROJECT_ROOT @project_playblasts_root.setter def project_playblasts_root(self, root_type): if self.data_file: data = {} data["playblasts_root"] = root_type self.data_file.edit(data) self.project_file = self.data_file.read() # # @property # def movie_file_type(self): # if self.project_file: # return "mov" # else: # return None @property def project_users(self): if self.project_file: if "users" in self.project_file.keys(): return self.project_file["users"] else: return None else: return None @project_users.setter def project_users(self, users): if self.data_file: data = {} data["users"] = users self.data_file.edit(data) self.project_file = self.data_file.read() # @property # def playblast_outside(self): # if self.project_file: # if "playblast_outside" in self.project_file.keys(): # return self.project_file["playblast_outside"] # else: # return False # else: # return None # # @playblast_outside.setter # def playblast_outside(self, playblast_outside): # # old_path = self.playblasts_path # # if self.data_file: # data = {} # data["playblast_outside"] = playblast_outside # self.data_file.edit(data) # self.project_file = self.data_file.read() # # files.dir_move(old_path, self.playblasts_path) @property def playblasts_path(self): if self.project_file: if self.project_playblasts_root == cfg.playblast_save_options.PROJECT_ROOT: return os.path.join(self.path, "playblasts") if self.project_playblasts_root == cfg.playblast_save_options.PROJECT_SISTER: return os.path.join(os.path.dirname(self.path), "{}_playblasts".format(self.name)) return "" @property def users(self): if self.project_file: return self.project_file["users"] else: return None @users.setter def users(self, dict): if self.data_file: data = {} data["users"] = dict self.data_file.edit(data) self.project_file = self.data_file.read()
class Branch_list_view(QtWidgets.QListView): edited = QtCore.Signal() def __init__(self, parent): super(Branch_list_view, self).__init__(parent) self.dummy = True self.project = None def setModel_(self, model): if model: self.setModel(model) else: pass # self.setModel(None) def contextMenuEvent(self, event): handled = True index = self.indexAt(event.pos()) menu = QtWidgets.QMenu() node = None if index.isValid(): node = self.model().getNode(index) # top_actions = list() def_actions = list() if node: def_actions.append(QtWidgets.QAction("Remove branch...", menu, triggered=functools.partial(self.remove, node, index))) else: def_actions.append(QtWidgets.QAction("Add branch...", menu, triggered=functools.partial(self.add, node))) menu.addActions(def_actions) menu.exec_(event.globalPos()) event.accept() return def add(self, node): branch = outliner.New_branch_dialog(self) result = branch.exec_() res = branch.result() if result == QtWidgets.QDialog.Accepted: name = res["name"] branches = [b.name for b in self.model().items] if not name in branches: if self.dummy: new_branch = dt.Node(name) if not self.dummy and self.project: new_branch = elements.BranchNode(name, path=os.path.join(self.project.path, name), project = self).create(path=os.path.join(self.project.path, name)) self.model().insertRows(0, 1, parent=QtCore.QModelIndex(), node=new_branch) self.edited.emit() else: logger.info("A branch called {} exsists.".format(name)) # logger.info("add branch...") def remove(self, node, index): if node.typeInfo() == cfg._node_: self.model().removeRows(0,1,QtCore.QModelIndex(),node) self.edited.emit() else: if not self.dummy: string = "Caution: This is not undoable,\nBranch {} and all of its contants will be deleted!".format(node.name) alert = massage.Prompt_alert(alert_string=string) result = alert.exec_() if result == QtWidgets.QDialog.Accepted: node.delete_me() self.model().removeRows(0, 1, QtCore.QModelIndex(), node) self.edited.emit()
class TextBox(QtWidgets.QPlainTextEdit): #(QtWidgets.QTextEdit): text_saved = QtCore.Signal(str) def __init__(self, parent, text=""): super(TextBox, self).__init__(parent) self.setStyleSheet(cfg.stylesheet) # self.layout = QtWidgets.QHBoxLayout(self) # self.layout.setContentsMargins(0,0,0,0) # # self.text_box = QtWidgets.QPlainTextEdit() # self.layout.addWidget(self.text_box) self.setStyleSheet(cfg.stylesheet) self._original_text = text # self.setPadding(5) self._changed = False # self.setText(self._original_text) font = QtGui.QFont() font.setItalic(True) font.setBold(True) self.setFont(font) self.commit_button = inputs.NiceQPushButton( parent=self) #QtWidgets.QPushButton(self, "Save") # self.commit_button.setPixmap(cfg.yes_icon) self.commit_button.setIconSize(QtCore.QSize(12, 12)) self.commit_button.setIcon(QtGui.QIcon(cfg.yes_icon)) # self.commit_button.setText("Save") # self.commit_button.setMinimumHeight(20) self.discard_button = inputs.NiceQPushButton( parent=self) #QtWidgets.QPushButton(self, "Save") # self.discard_button.setText("Discard") # self.discard_button.setMinimumHeight(20) self.discard_button.setIconSize(QtCore.QSize(12, 12)) self.discard_button.setIcon(QtGui.QIcon(cfg.no_icon)) self.viewport_VLayout = QtWidgets.QVBoxLayout(self) self.viewport().setLayout(self.viewport_VLayout) self.viewport_VLayout.setContentsMargins(0, 0, 0, 0) self.viewport_VLayout.setAlignment(QtCore.Qt.AlignBottom) self.input_panel = QtWidgets.QWidget(self) self.input_panel_layout = QtWidgets.QHBoxLayout(self.input_panel) self.input_panel_layout.setContentsMargins(2, 2, 2, 2) self.input_panel_layout.setSpacing(5) self.input_panel_layout.setAlignment(QtCore.Qt.AlignRight) self.input_panel_layout.addWidget(self.commit_button) self.input_panel_layout.addWidget(self.discard_button) self.commit_button.clicked.connect(self.save_text) self.discard_button.clicked.connect(self.restore_text) self.icon_widget = QtWidgets.QWidget() self.icon_widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.icon_widget_layout = QtWidgets.QVBoxLayout(self.icon_widget) self.icon_widget_layout.setContentsMargins(0, 0, 0, 0) self.icon_widget_layout.setAlignment(QtCore.Qt.AlignTop) self.icon_label_widget = QtWidgets.QLabel() self.icon_label_widget.setPixmap(cfg.add_comment_icon) self.icon_widget_layout.addWidget(self.icon_label_widget) self.viewport_VLayout.addWidget(self.icon_widget) self.viewport_VLayout.addWidget(self.input_panel) self.textChanged.connect(self.text_edit) self.setText(self._original_text) self.panel_hide(True) # color = cfg.colors.DARK_GRAY # self.setStyleSheet('''QTextEdit{ # color: #ccc; # border: 0px none; # background-color: ''' + color + '''; # } # ''') def setText(self, text): super(TextBox, self).setPlainText(text) # logger.info("set text") self.icon_visiblity() def icon_visiblity(self): text = self.toPlainText() # logger.info("icon") # logger.info(text) if text == "": # logger.info("unhide") self.icon_widget.setHidden(False) else: # logger.info("hide") self.icon_widget.setHidden(True) def focusInEvent(self, e): self.icon_widget.setHidden(True) QtWidgets.QPlainTextEdit.focusOutEvent(self, e) # super(TextBox, self).focusInEvent(e) def focusOutEvent(self, e): self.icon_visiblity() QtWidgets.QPlainTextEdit.focusOutEvent(self, e) # super(TextBox, self).focusOutEvent(e) def set_orig_text(self, str): self._original_text = str self.restore_text() def text_edit(self): self._changed = True self.panel_hide(False) def save_text(self): self.panel_hide(True) text = self.toPlainText() self._original_text = text self.text_saved.emit(text) self.clearFocus() def restore_text(self): self.setPlainText(self._original_text) self.panel_hide(True) self.clearFocus() self.icon_visiblity() def panel_hide(self, bool): self.input_panel.setHidden(bool)