class ListItem(Item): def __init__(self, scene, x, y, w, data, item_selected_cb=None, parent=None): self.w = 100 self.h = 100 self.sp = 0 self.item_selected_cb = item_selected_cb super(ListItem, self).__init__(scene, x, y, parent) self.w = self.m2pix(w) self.h = self.m2pix(0.2) self.sp = self.m2pix(0.005) self.items = [] self.middle_item_idx = 0 self.selected_item_idx = None for d in data: self.items.append(ButtonItem(self.scene(), 0, 0, d, self, self.item_clicked_cb, width=w, push_button=True)) rospack = rospkg.RosPack() icons_path = rospack.get_path('art_projected_gui') + '/icons/' self.up_btn = ButtonItem(self.scene(), 0, 0, translate( "ProgramItem", "Up"), self, self.up_btn_cb, width=w, image_path=icons_path + "arrow-up.svg") self.down_btn = ButtonItem(self.scene(), 0, 0, translate( "ProgramItem", "Down"), self, self.down_btn_cb, width=w, image_path=icons_path + "arrow-down.svg") self.up_btn.setPos(0, 0) self.down_btn.setPos(0, self.h - self.down_btn.boundingRect().height()) self.set_current_idx(min(1, len(self.items) - 1)) self.update() def item_clicked_cb(self, btn): if not self.isEnabled(): return if not btn.pressed: self.selected_item_idx = None else: self.selected_item_idx = self.items.index(btn) for i in range(0, len(self.items)): if i != self.selected_item_idx: self.items[i].set_pressed(False) self.set_current_idx(self.selected_item_idx) if self.item_selected_cb is not None: self.item_selected_cb() def get_current_idx(self): return self.middle_item_idx def set_current_idx(self, idx, select=False): if select: self.selected_item_idx = idx self.middle_item_idx = max(idx, min(1, len(self.items) - 1)) if self.isEnabled(): if self.middle_item_idx == min(1, len(self.items) - 1): self.up_btn.set_enabled(False) else: self.up_btn.set_enabled(True) if (idx < len(self.items) - 2): self.down_btn.set_enabled(True) else: self.down_btn.set_enabled(False) for it in self.items: it.setVisible(False) if select: it.set_pressed(False) # selected item is always vertically centered self.items[self.middle_item_idx].setPos( 0, (self.h - self.items[self.middle_item_idx].boundingRect().height()) / 2) self.items[self.middle_item_idx].setVisible(True) if select: self.items[self.middle_item_idx].set_pressed(True) # how much vert. space is used vspace = self.items[self.middle_item_idx].boundingRect().height() # fill space above selected item for idx in range(self.middle_item_idx - 1, -1, -1): h = self.items[idx].boundingRect().height() y = self.items[idx + 1].y() - self.sp - h if y < self.up_btn.y() + self.up_btn.boundingRect().height(): break self.items[idx].setPos(0, y) self.items[idx].setVisible(True) vspace += self.sp + h # fill space below selected item for idx in range(self.middle_item_idx + 1, len(self.items)): h = self.items[idx].boundingRect().height() y = self.items[idx - 1].y() + self.items[idx - 1].boundingRect().height() + self.sp if y + h > self.down_btn.y(): break self.items[idx].setPos(0, y) self.items[idx].setVisible(True) vspace += self.sp + h def up_btn_cb(self, btn): if self.middle_item_idx > 0: self.set_current_idx(self.middle_item_idx - 1) def down_btn_cb(self, btn): if self.middle_item_idx < len(self.items) - 1: self.set_current_idx(self.middle_item_idx + 1) def boundingRect(self): return QtCore.QRectF(0, 0, self.w, self.h) def paint(self, painter, option, widget): pass
class ListItem(Item): def __init__(self, scene, x, y, w, data, item_selected_cb=None, parent=None): self.w = 100 self.h = 100 self.sp = 0 self.item_selected_cb = item_selected_cb super(ListItem, self).__init__(scene, x, y, parent=parent) self.w = self.m2pix(w) self.h = self.m2pix(0.2) self.sp = self.m2pix(0.005) self.items = [] self.middle_item_idx = 0 self.selected_item_idx = None for d in data: self.items.append(ButtonItem(self.scene(), 0, 0, d, self, self.item_clicked_cb, width=w, push_button=True)) # TODO down_btn is not properly aligned self.up_btn = ButtonItem(self.scene(), 0, 0, "", self, self.up_btn_cb, width=w / 2 - 0.005 / 2, image_path=icons_path + "arrow-up.svg") self.down_btn = ButtonItem(self.scene(), 0, 0, "", self, self.down_btn_cb, width=w / 2 - 0.005 / 2, image_path=icons_path + "arrow-down.svg") self.up_btn.setPos(0, self.h - self.down_btn.boundingRect().height()) self.down_btn.setPos(self.up_btn.boundingRect().width() + self.sp, self.h - self.down_btn.boundingRect().height()) self.set_current_idx(min(1, len(self.items) - 1)) self.update() def item_clicked_cb(self, btn): if not self.isEnabled(): return if not btn.pressed: self.selected_item_idx = None else: self.selected_item_idx = self.items.index(btn) for i in range(0, len(self.items)): if i != self.selected_item_idx: self.items[i].set_pressed(False) self.set_current_idx(self.selected_item_idx) if self.item_selected_cb is not None: self.item_selected_cb() def get_current_idx(self): return self.middle_item_idx def set_current_idx(self, idx, select=False): if select: self.selected_item_idx = idx self.middle_item_idx = max(idx, min(1, len(self.items) - 1)) for it in self.items: it.setVisible(False) if select: it.set_pressed(False) displayed = [self.middle_item_idx] # selected item is always vertically centered self.items[self.middle_item_idx].setPos( 0, (self.h - self.items[self.middle_item_idx].boundingRect().height()) / 2) self.items[self.middle_item_idx].setVisible(True) if select: self.items[self.selected_item_idx].set_pressed(True) # how much vert. space is used vspace = self.items[self.middle_item_idx].boundingRect().height() # fill space above middle item for idx in range(self.middle_item_idx - 1, -1, -1): h = self.items[idx].boundingRect().height() y = self.items[idx + 1].y() - self.sp - h if y < 0: break self.items[idx].setPos(0, y) self.items[idx].setVisible(True) displayed.append(idx) vspace += self.sp + h displayed.append(idx) # fill space below middle item for idx in range(self.middle_item_idx + 1, len(self.items)): h = self.items[idx].boundingRect().height() y = self.items[idx - 1].y() + self.items[idx - 1].boundingRect().height() + self.sp if y + h > self.down_btn.y(): break self.items[idx].setPos(0, y) self.items[idx].setVisible(True) vspace += self.sp + h displayed.append(idx) if self.isEnabled(): self.up_btn.set_enabled(min(displayed) > 0) self.down_btn.set_enabled(max(displayed) < len(self.items) - 1) def up_btn_cb(self, btn): if self.middle_item_idx > 0: self.set_current_idx(self.middle_item_idx - 1) def down_btn_cb(self, btn): if self.middle_item_idx < len(self.items) - 1: self.set_current_idx(self.middle_item_idx + 1) def boundingRect(self): return QtCore.QRectF(0, 0, self.w, self.h) def paint(self, painter, option, widget): pass
class ProgramItem(Item): def __init__(self, scene, rpm, x, y, active_item_switched=None, program_state_changed=None): self.states = ['LEARNING', 'RUNNING', 'PAUSED', 'STOPPED'] self.state = 'LEARNING' self.w = 180 # TODO spocitat podle rpm self.h = 20 super(ProgramItem, self).__init__(scene, rpm, x, y) self.prog = None self.template = None self.items = [] self.active_item = None self.active_item_switched = active_item_switched self.program_state_changed = program_state_changed self.fixed = False self.setZValue(100) def set_running(self): self.state = 'RUNNING' def has_prog(self): return self.prog is None def set_active(self, it=None, inst_id=None): if it is None and inst_id is not None: it = self.get_item_by_id(inst_id) if it is None: return if self.active_item is not None: self.active_item.setPos(30, self.active_item.y()) self.active_item.active_item = False it.active_item = True self.active_item = it self.active_item.update() self.active_item.setPos(10, self.active_item.y()) def is_prog_learned(self): for it in self.items: if not it.item_learned(): return False return True def get_prog(self): # TODO deal with more blocks del self.prog.blocks[0].items[:] for it in self.items: self.prog.blocks[0].items.append(it.item) return self.prog def set_prog(self, prog, template): self.prog = prog self.template = template self.items = [] self.active_item = None cnt = 0 max_w = 0 # TODO Handle program groups - create ProgramGroupItem class and allow switching between groups. For now, let's assume that there will always be just one group for pitem in self.prog.blocks[0].items: if self.template: # to make sure that template is 'clear' pitem.object = "" del pitem.pick_polygon.polygon.points[:] pitem.place_pose.pose.position.x = 0 pitem.place_pose.pose.position.y = 0 pitem.place_pose.pose.position.z = 0 # TODO how to place items easily? using some layout?? self.items.append(ProgramItemItem(self.scene(), self.rpm, 0, 0, pitem, self, self.item_selected_cb)) if len(self.items) < 2: self.items[-1].setPos(30, 20) else: self.items[-1].setPos(30, 10 + self.items[-2].y() + self.items[-2].h) if self.items[-1].w > max_w: max_w = self.items[-1].w cnt += 1 # set first item as active if (self.active_item is None) and self.items[-1].item_req_learning(): self.set_active(self.items[-1]) # if pitem.type in self.items_req_learning: # if self.active_item is None: self.active_item = pitem self.btn = ButtonItem(self.scene(), self.rpm, 0, 0, translate("ProgramItem", "Start"), self, self.btn_clicked) self.btn.setPos(10, 5 + cnt * 50) self.btn.set_enabled(False) # TODO najit max. sirku itemu a tomu prizpusobit sirku programu self.h = 20 + cnt * 50 + 30 self.w = max_w + 40 self.update() def btn_clicked(self): if self.state == 'LEARNING': self.state = 'RUNNING' self.btn.set_caption(translate("ProgramItem", "Pause")) elif self.state == 'RUNNING': self.state = 'PAUSED' self.btn.set_caption(translate("ProgramItem", "Resume")) # TODO second button for STOP if self.program_state_changed is not None: self.program_state_changed(self.state) def item_selected_cb(self, it): if self.state == 'RUNNING': print "program running - ignoring item selection" return self.set_active(it) if self.active_item_switched is not None: self.active_item_switched() def update_size(self): self.active_item.update_size() max_w = 0 for it in self.items: if self.active_item.w + 40 > max_w: max_w = self.active_item.w + 40 self.w = max_w self.update() def program_updated(self): # TODO consides state if self.is_prog_learned(): print "enabling start button" self.btn.set_enabled(True) def set_object(self, obj): self.active_item.item.object = obj self.program_updated() self.update_size() def set_place_pose(self, x, y): self.active_item.item.place_pose.pose.position.x = x self.active_item.item.place_pose.pose.position.y = y self.active_item.item.place_pose.pose.orientation.w = 1.0 self.program_updated() self.update_size() def set_polygon(self, pts): del self.active_item.item.pick_polygon.polygon.points[:] for pt in pts: self.active_item.item.pick_polygon.polygon.points.append(Point32(pt[0], pt[1], 0)) self.program_updated() self.update_size() def boundingRect(self): return QtCore.QRectF(0, -30, self.w, self.h + 30) def get_item_by_id(self, id): for it in self.items: if it.item.id == id: return it return None def paint(self, painter, option, widget): if self.prog is None: return painter.setClipRect(option.exposedRect) painter.setRenderHint(QtGui.QPainter.Antialiasing) font = QtGui.QFont('Arial', 14) painter.setFont(font) painter.setPen(QtCore.Qt.white) painter.drawText(0, -10, translate("ProgramItem", "Program") + " ID=" + str(self.prog.id)) pen = QtGui.QPen() pen.setStyle(QtCore.Qt.NoPen) painter.setPen(pen) painter.setBrush(QtCore.Qt.gray) painter.setOpacity(0.5) # TODO projit itemy a zjistit skutecnou velikost (muze byt ruzna) painter.drawRect(0, 0, self.w, self.h)