Пример #1
0
class GameWidget(QGraphicsView):
    def __init__(self, parent=None):
        super(GameWidget, self).__init__(parent)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.m = 150
        self.n = 150

        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)
        self.scene.setSceneRect(0, 0, self.width(), self.height())
        self.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.universe = engine.Universe(self.n, self.m)

        print(Qt.red)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.step)

    def load(self, item):
        self.universe.file_input(item)

    def drawUniverse(self):
        width = self.width()
        height = self.height()

        cellWidth = width / self.universe.n
        cellHeight = height / self.universe.m

        x = 0
        y = 0
        for this_list in self.universe.map:
            y = 0
            for elem in this_list:
                color = Qt.gray
                if elem == 1:
                    color = Qt.green
                self.scene.addRect(x, y, cellWidth, cellHeight, brush=color)
                y += cellHeight
            x += cellWidth

    def step(self):
        self.scene.clear()
        self.universe.step()
        self.drawUniverse()
        self.scene.update()

    def run(self):
        self.timer.start()

    def stop(self):
        self.timer.stop()
Пример #2
0
    def create_ui(self):
        button = QPushButton("Rotate - ", self)
        button.setGeometry(200, 450, 100, 50)
        button.clicked.connect(self.rotateMinus)

        button2 = QPushButton("Rotate + ", self)
        button2.setGeometry(320, 450, 100, 50)
        button2.clicked.connect(self.rotatePlus)

        scene = QGraphicsScene(self)

        greenBrush = QBrush(Qt.green)
        blueBrush = QBrush(Qt.blue)

        blackPen = QPen(Qt.black)
        blackPen.setWidth(5)

        ellipse = scene.addEllipse(10, 10, 200, 200, blackPen, greenBrush)
        rect = scene.addRect(-100, -100, 200, 200, blackPen, blueBrush)

        scene.addText("antoine-libert.com", QFont("Sanserif", 15))

        ellipse.setFlag(QGraphicsItem.ItemIsMovable)
        rect.setFlag(QGraphicsItem.ItemIsMovable)

        self.view = QGraphicsView(scene, self)
        self.view.setGeometry(0, 0, 640, 440)
 def _create_obj_group_renderer(self, object_class_name):
     display_icon = self.display_icons.get(object_class_name, -1)
     icon_code, color_code = interpret_icon_id(display_icon)
     font = QFont('Font Awesome 5 Free Solid')
     scene = QGraphicsScene()
     x = 0
     for _ in range(2):
         y = 0
         for _ in range(2):
             text_item = scene.addText(chr(icon_code), font)
             text_item.setDefaultTextColor(color_code)
             text_item.setPos(x, y)
             y += 0.875 * text_item.boundingRect().height()
         x += 0.875 * text_item.boundingRect().width()
     scene.addRect(scene.itemsBoundingRect())
     self.obj_group_renderers[
         object_class_name] = _SceneSvgRenderer.from_scene(scene)
Пример #4
0
    def waferPainter(self):
        blackPen = QPen(Qt.black)
        blackPen.setWidth(1)
        blueBrush = QBrush(Qt.blue)
        scene = QGraphicsScene()
        chipNumX = 100
        chipNumY = 100
        canvasWidth = self.ui.mapView.width()
        canvasHeight = self.ui.mapView.height()
        chipWidthX = (canvasWidth - 5) / chipNumX
        chipHeightY = (canvasHeight - 5) / chipNumY
        waferEllipse = QGraphicsEllipseItem()
        scene.addEllipse(0, 0, canvasWidth - 5, canvasHeight - 5, blackPen)
        for numx in range(0, chipNumX):
            for numy in range(0, chipNumY):
                scene.addRect(numx * chipWidthX, numy * chipHeightY, chipWidthX, chipHeightY, blackPen, blueBrush)


        # --》隐藏graphicsView的滚动条
        self.ui.mapView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.ui.mapView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.ui.mapView.setScene(scene)
Пример #5
0
class ReferenceCount(UsesQApplication):

    def setUp(self):
        super(ReferenceCount, self).setUp()
        self.scene = QGraphicsScene()

    def tearDown(self):
        super(ReferenceCount, self).tearDown()

    def beforeTest(self):
        points = [QPointF(0, 0), QPointF(100, 100), QPointF(0, 100)]
        pol = self.scene.addPolygon(QPolygonF(points))
        self.assert_(isinstance(pol, QGraphicsPolygonItem))
        self.wrp = weakref.ref(pol, pol_del)

        #refcount need be 3 because one ref for QGraphicsScene, and one to rect obj
        self.assertEqual(sys.getrefcount(pol), 3)

    def testReferenceCount(self):
        global destroyedRect
        global destroyedPol

        self.beforeTest()
        
        rect = self.scene.addRect(10.0, 10.0, 10.0, 10.0)
        self.assert_(isinstance(rect, QGraphicsRectItem))

        self.wrr = weakref.ref(rect, rect_del)

        #refcount need be 3 because one ref for QGraphicsScene, and one to rect obj
        self.assertEqual(sys.getrefcount(rect), 3)

        del rect
        #not destroyed because one ref continue in QGraphicsScene
        self.assertEqual(destroyedRect, False)
        self.assertEqual(destroyedPol, False)

        del self.scene

        #QGraphicsScene was destroyed and this destroy internal ref to rect
        self.assertEqual(destroyedRect, True)
        self.assertEqual(destroyedPol, True)
Пример #6
0
class ReferenceCount(UsesQApplication):
    def setUp(self):
        super(ReferenceCount, self).setUp()
        self.scene = QGraphicsScene()

    def tearDown(self):
        super(ReferenceCount, self).tearDown()

    def beforeTest(self):
        points = [QPointF(0, 0), QPointF(100, 100), QPointF(0, 100)]
        pol = self.scene.addPolygon(QPolygonF(points))
        self.assert_(isinstance(pol, QGraphicsPolygonItem))
        self.wrp = weakref.ref(pol, pol_del)

        #refcount need be 3 because one ref for QGraphicsScene, and one to rect obj
        self.assertEqual(sys.getrefcount(pol), 3)

    def testReferenceCount(self):
        global destroyedRect
        global destroyedPol

        self.beforeTest()

        rect = self.scene.addRect(10.0, 10.0, 10.0, 10.0)
        self.assert_(isinstance(rect, QGraphicsRectItem))

        self.wrr = weakref.ref(rect, rect_del)

        #refcount need be 3 because one ref for QGraphicsScene, and one to rect obj
        self.assertEqual(sys.getrefcount(rect), 3)

        del rect
        #not destroyed because one ref continue in QGraphicsScene
        self.assertEqual(destroyedRect, False)
        self.assertEqual(destroyedPol, False)

        del self.scene

        #QGraphicsScene was destroyed and this destroy internal ref to rect
        self.assertEqual(destroyedRect, True)
        self.assertEqual(destroyedPol, True)
Пример #7
0
    def __init__(self):
        super(Window, self).__init__()

        self.setWindowTitle("Pyside2 Simple Application")
        self.setGeometry(300, 300, 300, 300)
        scene = QGraphicsScene(self)

        greenBrush = QBrush(Qt.green)
        blueBrush = QBrush(Qt.blue)

        blackPen = QPen(Qt.black)
        blackPen.setWidth(5)

        ellipse = scene.addEllipse(10, 10, 200, 200, blackPen, greenBrush)

        rect = scene.addRect(-100, -100, 200, 200, blackPen, blueBrush)

        ellipse.setFlag(QGraphicsItem.ItemIsMovable)
        rect.setFlag(QGraphicsItem.ItemIsMovable)

        self.view = QGraphicsView(scene, self)
        self.setCentralWidget(self.view)
        self.view.rotate(30)
Пример #8
0
class QPOIViewer(QWidget):
    """
    POI Viewer QWidget
    """

    TAG_SPACING = 50
    LEGEND_X = -50
    LEGEND_Y = 0
    LEGEND_WIDTH = 10

    TRACE_FUNC_X = 0
    TRACE_FUNC_Y = 0
    TRACE_FUNC_WIDTH = 50
    TRACE_FUNC_MINHEIGHT = 1000

    TAB_HEADER_SIZE = 40
    MAX_WINDOW_SIZE = 500

    MARK_X = LEGEND_X
    MARK_WIDTH = TRACE_FUNC_X - LEGEND_X + TRACE_FUNC_WIDTH
    MARK_HEIGHT = 1

    POIID_COLUMN = 0
    CRASH_COLUMN = 1
    CATEGORY_COLUMN = 2
    DIAGNOSE_COLUMN = 3
    COLUMN_FIELD = ['id', 'bbl', 'category', 'diagnose']


    def __init__(self, workspace, parent=None, diagnose_handler=None):
        super().__init__(parent=parent)
        self.workspace = workspace
        self._diagnose_handler = diagnose_handler

        self.mark = None
        self.legend = None
        self.legend_height = 0
        self.legend_img = None
        self.trace_func_unit_height = 0

        self.trace_func = None
        self.trace_id = None

        self.tabView = None
        self.traceView = None
        self.traceScene = None
        self.POITraceTab = None
        self.multiPOITab : QWidget = None
        self.multiPOIList : QTableWidget = None

        self.mark = None
        self.curr_position = 0
        self._use_precise_position = False
        self._selected_traces = []
        self._selected_poi = None

        self._init_widgets()

        self.selected_ins.am_subscribe(self._subscribe_select_ins)
        self.poi_trace.am_subscribe(self._subscribe_set_trace)
        self.multi_poi.am_subscribe(self._subscribe_add_poi)

        self.multiPOIList.cellDoubleClicked.connect(self._on_cell_double_click)
        self.multiPOIList.itemChanged.connect(self._on_diagnose_change)

    #
    # Forwarding properties
    #

    @property
    def disasm_view(self):
        """
        Get the current disassembly view (if there is one), or create a new one as needed.
        """
        view = self.workspace.view_manager.current_view_in_category("disassembly")
        if view is None:
            view = self.workspace._get_or_create_disassembly_view()
        return view

    @property
    def poi_trace(self):
        return self.workspace.instance.poi_trace

    @property
    def multi_poi(self):
        return self.workspace.instance.multi_poi

    @property
    def selected_ins(self):
        return self.disasm_view.infodock.selected_insns

    def _init_widgets(self):
        _l.debug("QPOI Viewer Initiating")
        self.tabView = QTabWidget() # QGraphicsView()
        self.tabView.setContentsMargins(0, 0, 0, 0)

        #
        # POI trace Tab
        #
        self.POITraceTab = QWidget()
        self.POITraceTab.setContentsMargins(0, 0, 0, 0)
        singleLayout = QVBoxLayout()
        singleLayout.setSpacing(0)
        singleLayout.setContentsMargins(0, 0, 0, 0)

        self.traceView = QGraphicsView()
        self.traceScene = QGraphicsScene()
        self.traceView.setScene(self.traceScene)

        singleLayout.addWidget(self.traceView)
        self.POITraceTab.setLayout(singleLayout)

        #
        # multiPOI Tab
        #
        self.multiPOITab = QMultiPOITab(self)
        # self.multiPOITab = QWidget()
        multiLayout = QVBoxLayout()
        multiLayout.setSpacing(0)
        multiLayout.setContentsMargins(0, 0, 0, 0)

        self.multiPOIList = QTableWidget(0, 4) # row, col
        self.multiPOIList.setHorizontalHeaderItem(0, QTableWidgetItem("ID"))
        self.multiPOIList.setHorizontalHeaderItem(1, QTableWidgetItem("Crash Point"))
        self.multiPOIList.setHorizontalHeaderItem(2, QTableWidgetItem("Tag"))
        self.multiPOIList.setHorizontalHeaderItem(3, QTableWidgetItem("Diagnose"))
        self.multiPOIList.horizontalHeader().setStretchLastSection(True)
        self.multiPOIList.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.multiPOIList.setSelectionBehavior(QAbstractItemView.SelectRows)
        multiLayout.addWidget(self.multiPOIList)
        self.multiPOITab.setLayout(multiLayout)

        self.tabView.addTab(self.multiPOITab, "POI List")
        self.tabView.addTab(self.POITraceTab, "POI Trace")

        self.POI_TRACE = 1
        self.MULTI_POI = 0

        layout = QVBoxLayout()
        layout.addWidget(self.tabView)
        layout.setContentsMargins(0, 0, 0, 0)

        self.setLayout(layout)
        self.show()

    def _reset(self):
        self.traceScene.clear() #clear items
        self.mark = None

        self.legend = None
        self.legend_height = 0

        self.trace_func = QGraphicsItemGroup()
        self.trace_id = QGraphicsItemGroup()
        self.traceScene.addItem(self.trace_func)
        self.hide()

    #
    # Event
    #

    def _on_cell_double_click(self, row, _):
        _l.debug("row %d is double clicked", row)
        first_cell = self.multiPOIList.item(row, 0)
        if first_cell is None:
            return
        poi_id = first_cell.text()
        poi = self.multi_poi.am_obj.get_poi_by_id(poi_id)
        if poi is None:
            return
        # sanity checks
        if not isinstance(poi, dict):
            return
        if 'output' not in poi or not isinstance(poi['output'], dict):
            return
        if 'bbl_history' not in poi['output']:
            return

        trace = poi['output']['bbl_history']
        if self._selected_poi != poi_id and trace is not None:
            # render the trace
            self.poi_trace.am_obj = TraceStatistics(self.workspace, trace, trace_id=poi_id)

            # show the trace statistic in POI trace
            self.poi_trace.am_event()

            # show covered basic blocks and functions
            self.multi_poi.am_obj.reload_heatmap(poi_id)

            # redraw function view
            view = self.workspace.view_manager.first_view_in_category('functions')
            if view is not None:
                view.refresh()

            # redraw disassembly view
            view = self.workspace.view_manager.first_view_in_category('disassembly')
            if view is not None:
                view.redraw_current_graph()

        if trace is not None:
            # switch to POI trace tab
            self.tabView.setCurrentIndex(self.POI_TRACE)
        self._selected_poi = poi_id

        second_cell = self.multiPOIList.item(row, 1)
        crash_addr = None
        if second_cell is not None:
            try:
                crash_addr = int(second_cell.text(), 16)
            except ValueError:
                pass
        if crash_addr is not None:
            # show the crashing address
            view = self.workspace.view_manager.first_view_in_category('disassembly')
            if view is not None:
                crash_func = self._get_func_from_addr(crash_addr)
                if crash_func is not None:
                    self.workspace.on_function_selected(crash_func)
                    self.selected_ins.clear()
                    self.selected_ins.update([crash_addr])
                    self.selected_ins.am_event()
                    view.current_graph.show_instruction(crash_addr)

    def _on_diagnose_change(self, item: QTableWidgetItem):
        column = item.column()
        row = item.row()

        poi_id = self.multiPOIList.item(row, self.POIID_COLUMN).text()
        content = item.text()
        original_content = self.multi_poi.am_obj.get_content_by_id_column(poi_id, column)
        _l.debug('updaing %s, content: %s, original: %s', poi_id, content, original_content)
        if not self._is_identical(content, original_content):
            updated_poi = self.multi_poi.update_poi(poi_id, column, content)
            self._diagnose_handler.submit_updated_poi(poi_id, updated_poi)

    def _subscribe_add_poi(self):
        _l.debug('add a poi to multi poi list')
        if self.multi_poi.am_none:
            self.multi_poi.am_obj = MultiPOI(self.workspace)
        poi_ids = self.multi_poi.am_obj.get_all_poi_ids()

        self.multiPOIList.clearContents()
        self._populate_poi_table(self.multiPOIList, poi_ids)
        self.show()

    def _subscribe_set_trace(self):
        _l.debug('on set trace in poi trace viewer')
        self._reset()
        if self.poi_trace.am_none:
            return
        _l.debug('minheight: %d, count: %d', self.TRACE_FUNC_MINHEIGHT,
                self.poi_trace.count)
        if self.poi_trace.count <= 0:
            _l.warning("No valid addresses found in trace to show. Check base address offsets?")
            self.poi_trace.am_obj = None
            self.poi_trace.am_event()
            return
        if self.TRACE_FUNC_MINHEIGHT < self.poi_trace.count * 15:
            self.trace_func_unit_height = 15
            show_func_tag = True
        else:
            self.trace_func_unit_height = self.TRACE_FUNC_MINHEIGHT / self.poi_trace.count
            show_func_tag = True

        self.legend_height = int(self.poi_trace.count * self.trace_func_unit_height)

        self._show_trace_func(show_func_tag)
        self._show_legend()
        self._set_mark_color()
        self._refresh_multi_list()

        # boundingSize = self.traceScene.itemsBoundingRect().width()
        # windowSize = boundingSize
        # if boundingSize > self.MAX_WINDOW_SIZE:
        #     windowSize = self.MAX_WINDOW_SIZE
        # self.traceScene.setSceneRect(self.traceScene.itemsBoundingRect()) #resize
        # if windowSize > self.width():
        #     self.setMinimumWidth(windowSize)

        self.show()

    def _subscribe_select_ins(self, **kwargs): # pylint: disable=unused-argument
        if self.poi_trace.am_none:
            return

        if self.mark is not None:
            for i in self.mark.childItems():
                self.mark.removeFromGroup(i)
                self.traceScene.removeItem(i)
            self.traceScene.removeItem(self.mark)

        self.mark = QGraphicsItemGroup()
        self.traceScene.addItem(self.mark)

        if self.selected_ins:
            addr = next(iter(self.selected_ins))
            positions = self.poi_trace.get_positions(addr)
            if positions: #if addr is in list of positions
                # handle case where insn was selected from disas view
                if not self._use_precise_position:
                    self.curr_position = positions[0] - self.poi_trace.count
                for p in positions:
                    color = self._get_mark_color(p, self.poi_trace.count)
                    y = self._get_mark_y(p)

                    if p == self.poi_trace.count + self.curr_position: #add thicker line for 'current' mark
                        self.mark.addToGroup(self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH,
                                                                     self.MARK_HEIGHT*4,
                                                                     QPen(QColor('black')), QBrush(color)))
                    else:
                        self.mark.addToGroup(self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH,
                                                                     self.MARK_HEIGHT, QPen(color), QBrush(color)))

                self.traceScene.update() #force redraw of the traceScene
                self.scroll_to_position(self.curr_position)

    def _get_func_from_addr(self, addr):
        if self.workspace.instance.cfg.am_none:
            return None
        bbl = self.workspace.instance.cfg.get_any_node(addr, anyaddr=True)
        function_addr = bbl.function_address
        return self.workspace.instance.project.kb.functions.get(function_addr)

    def _populate_poi_table(self, view, poi_ids):
        view.clearContents()
        view.setRowCount(len(poi_ids))
        row = 0 #start after label row
        for poi_id in poi_ids:
            poi = self.multi_poi.am_obj.get_poi_by_id(poi_id)
            _l.debug('populating poi: %s', poi)
            category = poi['category']
            output = poi['output']
            crash_addr = output['bbl']
            if crash_addr is not None:
                crash = hex(crash_addr)
            else:
                crash = None
            diagnose = output.get('diagnose')
            _l.debug('poi_ids: %s', poi_ids)
            _l.debug('current poi id: %s', poi_id)
            self._set_item(view, row, self.POIID_COLUMN, poi_id, editable=False)
            self._set_item(view, row, self.CRASH_COLUMN, crash, editable=True)
            self._set_item(view, row, self.CATEGORY_COLUMN, category, editable=True)
            self._set_item(view, row, self.DIAGNOSE_COLUMN, diagnose, editable=True)
            row += 1
            _l.debug('poi_ids: %s', poi_ids)

    @staticmethod
    def _set_item(view, row, column, text, editable=True):
        if not text:
            text = ""
        item = QTableWidgetItem(text)
        if not editable:
            item.setFlags(item.flags() ^ Qt.ItemIsEditable)
        view.setItem(row, column, item)

    def _refresh_multi_list(self):
        multiPOI = self.multi_poi.am_obj
        trace_ids = multiPOI.get_all_poi_ids()

        self.multiPOIList.clearContents()
        self._populate_poi_table(self.multiPOIList, trace_ids)
        if self._selected_traces and self.multiPOIList.rowCount() > 0:
            self.multiPOIList.item(0, 0).setSelected(True)
            self.multiPOIList.item(0, 1).setSelected(True)
        else:
            for row in range(self.multiPOIList.rowCount()):
                item = self.multiPOIList.item(row, 0)
                inputItem = self.multiPOIList.item(row, 1)
                if item.text() in self._selected_traces:
                    item.setSelected(True)
                    inputItem.setSelected(True)
        self.multi_poi.am_event()

    def _on_tab_change(self):
        multiPOI = self.multi_poi.am_obj
        if self.tabView.currentIndex() == self.MULTI_POI:
            multiPOI.is_active_tab = True
            self._refresh_multi_list()
        elif self.tabView.currentIndex() == self.POI_TRACE:
            multiPOI = self.multi_poi.am_obj
            multiPOI.is_active_tab = False
            # self._show_trace_ids()

    def scroll_to_position(self, position):
        relative_pos = self.poi_trace.count + position
        y_offset = self._get_mark_y(relative_pos)

        scrollValue = 0
        if y_offset > 0.5 * self.traceView.size().height():
            scrollValue = y_offset - 0.5 * self.traceView.size().height()
        scrollValue = min(scrollValue, self.traceView.verticalScrollBar().maximum())
        self.traceView.verticalScrollBar().setValue(scrollValue)
        self._use_precise_position = False

    def jump_next_insn(self):
        # for some reason indexing is done backwards
        if self.curr_position + self.poi_trace.count < self.poi_trace.count - 1:
            self.curr_position += 1
            self._use_precise_position = True
            bbl_addr = self.poi_trace.get_bbl_from_position(self.curr_position)
            func = self.poi_trace.get_func_from_position(self.curr_position)
            self._jump_bbl(func, bbl_addr)

    def jump_prev_insn(self):
        if self.curr_position + self.poi_trace.count > 0:
            self.curr_position -= 1
            self._use_precise_position = True
            bbl_addr = self.poi_trace.get_bbl_from_position(self.curr_position)
            func = self.poi_trace.get_func_from_position(self.curr_position)
            self._jump_bbl(func, bbl_addr)

    def mousePressEvent(self, event):
        button = event.button()
        pos = self._to_logical_pos(event.pos())
        if button == Qt.LeftButton and self.tabView.currentIndex() == self.POI_TRACE and self._at_legend(pos):
            func = self._get_func_from_y(pos.y())
            bbl_addr = self._get_bbl_from_y(pos.y())
            self._use_precise_position = True
            self.curr_position = self._get_position(pos.y())
            self._jump_bbl(func, bbl_addr)

    def _jump_bbl(self, func, bbl_addr):
        disasm_view = self.disasm_view
        if disasm_view is not None:
            all_insn_addrs = self.workspace.instance.project.factory.block(bbl_addr).instruction_addrs
            # TODO: replace this with am_events perhaps?
            self.workspace.on_function_selected(func)
            self.selected_ins.clear()
            self.selected_ins.update(all_insn_addrs)
            self.selected_ins.am_event()
            # TODO: this ought to happen automatically as a result of the am_event
            disasm_view.current_graph.show_instruction(bbl_addr)

    def _get_mark_color(self, i, total):
        relative_gradient_pos = i * 1000 // total
        return self.legend_img.pixelColor(self.LEGEND_WIDTH // 2,
                                          relative_gradient_pos)

    def _get_mark_y(self, i):
        return self.TRACE_FUNC_Y + self.trace_func_unit_height * i

    def _show_trace_func(self, show_func_tag=True):
        x = self.TRACE_FUNC_X
        y = self.TRACE_FUNC_Y
        prev_name = None
        for position in self.poi_trace.trace_func:
            func_name = position.func_name
            color = self.poi_trace.get_func_color(func_name)
            self.trace_func.addToGroup(self.traceScene.addRect(x, y,
                                                          self.TRACE_FUNC_WIDTH, self.trace_func_unit_height,
                                                          QPen(color), QBrush(color)))
            if show_func_tag is True and func_name != prev_name:
                tag = self.traceScene.addText(func_name, QFont("Source Code Pro", 7))
                tag.setPos(x + self.TRACE_FUNC_WIDTH +
                           self.TAG_SPACING, y -
                           tag.boundingRect().height() // 2)
                self.trace_func.addToGroup(tag)
                anchor = self.traceScene.addLine(
                    self.TRACE_FUNC_X + self.TRACE_FUNC_WIDTH, y,
                    x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y)
                self.trace_func.addToGroup(anchor)
                prev_name = func_name
            y += self.trace_func_unit_height

    @staticmethod
    def _make_legend_gradient(x1, y1, x2, y2):
        gradient = QLinearGradient(x1, y1, x2, y2)
        gradient.setColorAt(0.0, Qt.red)
        gradient.setColorAt(0.4, Qt.yellow)
        gradient.setColorAt(0.6, Qt.green)
        gradient.setColorAt(0.8, Qt.blue)
        gradient.setColorAt(1.0, Qt.darkBlue)
        return gradient

    def _show_legend(self):
        pen = QPen(Qt.transparent)

        gradient = self._make_legend_gradient(self.LEGEND_X, self.LEGEND_Y,
                                   self.LEGEND_X, self.LEGEND_Y + self.legend_height)
        brush = QBrush(gradient)
        self.legend = self.traceScene.addRect(self.LEGEND_X, self.LEGEND_Y,
                                         self.LEGEND_WIDTH, self.legend_height, pen, brush)

        reference_gradient = self._make_legend_gradient(0, 0, self.LEGEND_WIDTH, 1000)
        base_img = QImage(self.LEGEND_WIDTH, 1000, QImage.Format.Format_ARGB32)
        p = QPainter(base_img)
        p.fillRect(base_img.rect(),reference_gradient)
        self.legend_img = base_img #reference shade

    def _set_mark_color(self):
        _l.debug('trace count: %d', self.poi_trace.count)
        for p in range(self.poi_trace.count):
            color = self._get_mark_color(p, self.poi_trace.count)
            self.poi_trace.set_mark_color(p, color)

    def _at_legend(self, pos):
        x = pos.x()
        y = pos.y()
        return self.TRACE_FUNC_X + self.LEGEND_X < x < self.traceView.width() and \
           self.TRACE_FUNC_Y < y < self.TRACE_FUNC_Y + self.legend_height

    def _to_logical_pos(self, pos):
        x_offset = self.traceView.horizontalScrollBar().value()
        y_offset = self.traceView.verticalScrollBar().value()
        return QPoint(pos.x() + x_offset, pos.y() + y_offset)

    def _get_position(self, y):
        y_relative = y - self.legend_height - self.TAB_HEADER_SIZE

        return int(y_relative // self.trace_func_unit_height)

    def _get_bbl_from_y(self, y):
        position = self._get_position(y)
        return self.poi_trace.get_bbl_from_position(position)

    def _get_func_from_y(self, y):
        position = self._get_position(y)
        func = self.poi_trace.get_func_from_position(position)
        return func

    #
    # Context Menu
    #

    def menu_add_empty_poi(self):
        _l.debug('adding a new empty poi item')

        if self._diagnose_handler.get_image_id() is None:
            QMessageBox.warning(self.workspace.main_window,
                                "No CHESS target available",
                                "No angr project is loaded, or you did not associate the current project with a CHESS "
                                "target. Please load a binary and associate it with a CHESS target before creating "
                                "POIs.")
            return

        poi_id = str(uuid4())
        if self.multi_poi.am_none:
            self.multi_poi.am_obj = MultiPOI(self.workspace)
        empty_poi = deepcopy(EMPTY_POI)
        self.multi_poi.add_poi(poi_id, empty_poi)
        self.multi_poi.am_event()
        self._diagnose_handler.submit_updated_poi(poi_id, empty_poi)

    def menu_remove_poi(self):
        items = self.multiPOIList.selectedItems()
        row = items.pop().row()
        poi_id = self.multiPOIList.item(row, 0).text()
        _l.debug('removing ID %s', poi_id)
        self.multi_poi.remove_poi(poi_id)
        self.multi_poi.am_event()

    @staticmethod
    def _is_identical(content, original_content):
        if content == original_content:
            return True
        if content == '' and original_content is None:
            return True
        try:
            if int(content, 16) == int(original_content):
                return True
        except (TypeError, ValueError):
            return False
        return False
Пример #9
0
class AddItem(UsesQApplication):
    '''Tests for QGraphicsScene.add*'''

    qapplication = True

    def setUp(self):
        #Acquire resources
        super(AddItem, self).setUp()
        self.scene = QGraphicsScene()
        # While the scene does not inherits from QWidget, requires
        # an application to make the internals work.

    def tearDown(self):
        #Release resources
        del self.scene
        super(AddItem, self).tearDown()

    def testEllipse(self):
        #QGraphicsScene.addEllipse
        item = self.scene.addEllipse(100, 100, 100, 100)
        self.assertTrue(isinstance(item, QGraphicsEllipseItem))

    def testLine(self):
        #QGraphicsScene.addLine
        item = self.scene.addLine(100, 100, 200, 200)
        self.assertTrue(isinstance(item, QGraphicsLineItem))

    def testPath(self):
        #QGraphicsScene.addPath
        item = self.scene.addPath(QPainterPath())
        self.assertTrue(isinstance(item, QGraphicsPathItem))

    def testPixmap(self):
        #QGraphicsScene.addPixmap
        item = self.scene.addPixmap(QPixmap())
        self.assertTrue(isinstance(item, QGraphicsPixmapItem))

    def testPolygon(self):
        #QGraphicsScene.addPolygon
        points = [QPointF(0, 0), QPointF(100, 100), QPointF(0, 100)]
        item = self.scene.addPolygon(QPolygonF(points))
        self.assertTrue(isinstance(item, QGraphicsPolygonItem))

    def testRect(self):
        #QGraphicsScene.addRect
        item = self.scene.addRect(100, 100, 100, 100)
        self.assertTrue(isinstance(item, QGraphicsRectItem))

    def testSimpleText(self):
        #QGraphicsScene.addSimpleText
        item = self.scene.addSimpleText('Monty Python 42')
        self.assertTrue(isinstance(item, QGraphicsSimpleTextItem))

    def testText(self):
        #QGraphicsScene.addText
        item = self.scene.addText('Monty Python 42')
        self.assertTrue(isinstance(item, QGraphicsTextItem))

    def testWidget(self):
        #QGraphicsScene.addWidget
        # XXX: printing some X11 error when using under PyQt4
        item = self.scene.addWidget(QPushButton())
        self.assertTrue(isinstance(item, QGraphicsProxyWidget))
Пример #10
0
class MainWindow(QMainWindow):
    def __init__(self):

        # load setting json file
        with open('setting.json') as f:
            self.app_setting = json.load(f)

        # Status of window
        super().__init__()
        self.title = 'Image Editor'
        self.left = 70
        self.top = 70
        self.width = 800
        self.height = 700

        # Status of view image
        self.org_qimg = None
        self.org_img_width = 0
        self.org_img_height = 0

        self.layer_pixmap = None
        self.layer_width = 0
        self.layer_height = 0
        self.layer_alpha = 50.0

        # Prepare color bar data
        self.colormap_gain = self.app_setting["SoftwareSetting"]["process"][
            "colormap"]["gain"]
        self.colormap_offset_x = self.app_setting["SoftwareSetting"][
            "process"]["colormap"]["offset_x"]
        self.colormap_offset_green = self.app_setting["SoftwareSetting"][
            "process"]["colormap"]["offset_green"]

        self.colormap_data = [
            colormap.colorBarRGB(x * 0.001, self.colormap_offset_x,
                                 self.colormap_offset_green,
                                 self.colormap_gain) for x in range(1000)
        ]

        self.img_edit_mode = 'cursor'

        self.draw_color = QColor(255, 0, 0)
        self.draw_tool_size = 5
        self.eraser_color = QColor(0, 0, 0, 0)

        # setup user interface components
        self.setup_ui()

    # Setup user interface components
    def setup_ui(self):
        # Set main window title
        self.setWindowTitle(self.title)
        # Set main wiodow initial position
        self.setGeometry(self.left, self.top, self.width, self.height)

        # Set up mainWindow's layout
        self.mainWidget = QWidget(self)  # Note not to forget this code.
        self.main_layout = QVBoxLayout()

        # Set menu for main window
        self.main_menu = self.menuBar()
        self.file_menu = self.main_menu.addMenu('File')
        self.edit_menu = self.main_menu.addMenu('Edit')
        self.help_menu = self.main_menu.addMenu('Help')

        self.main_layout.addWidget(self.main_menu)

        # Set "Original Image Open" menu
        self.org_img_open_button = QAction(
            self.style().standardIcon(getattr(QStyle, 'SP_FileDialogStart')),
            'Open Orginal Image', self)
        self.org_img_open_button.setShortcut('Ctrl+O')
        self.org_img_open_button.triggered.connect(self.open_org_img_dialog)
        self.file_menu.addAction(self.org_img_open_button)

        # Set "Save layer image" menu
        self.layer_img_save_button = QAction(
            self.style().standardIcon(getattr(QStyle, 'SP_FileDialogEnd')),
            'Save Layer Image', self)
        self.layer_img_save_button.setShortcut('Ctrl+S')
        self.layer_img_save_button.triggered.connect(self.save_layer_image)
        self.file_menu.addAction(self.layer_img_save_button)

        # Set "Save compose image(original + layer image)" menu
        self.compose_img_save_button = QAction(
            self.style().standardIcon(getattr(QStyle, 'SP_FileDialogEnd')),
            'Save Compose Image', self)
        self.compose_img_save_button.setShortcut('Ctrl+D')
        self.compose_img_save_button.triggered.connect(self.save_compose_image)
        self.file_menu.addAction(self.compose_img_save_button)

        # Set "exit software" menu
        self.exit_button = QAction(
            self.style().standardIcon(getattr(QStyle, 'SP_DialogCloseButton')),
            'Exit', self)
        self.exit_button.setShortcut('Ctrl-Q')
        self.exit_button.setStatusTip('Exit software')
        self.exit_button.triggered.connect(self.close)
        self.file_menu.addAction(self.exit_button)

        self.upper_layout = QHBoxLayout()
        self.main_layout.addLayout(self.upper_layout)

        # Set image display area
        self.gview_default_size = 500
        self.graphics_view = QGraphicsView()
        self.graphics_view.setFixedSize(self.gview_default_size,
                                        self.gview_default_size)
        self.graphics_view.setObjectName("imageDisplayArea")
        self.upper_layout.addWidget(self.graphics_view)

        # image display area's contents
        self.scene = GraphicsSceneForMainView(self.graphics_view, self)
        self.imgs_pixmap = []
        self.imgs = []

        self.img_status_layout = QVBoxLayout()
        self.upper_layout.addLayout(self.img_status_layout)

        # Set tranparency value of layer image
        self.transparency_title_label = QLabel('layer transparency value')
        self.img_status_layout.addWidget(self.transparency_title_label)

        transparency = round((1.0 - self.layer_alpha / 255.0) * 100)
        self.img_transparency_edit = QLineEdit(str(transparency))

        self.img_transparency_sld = QSlider(Qt.Horizontal)
        self.img_transparency_sld.setFocusPolicy(Qt.NoFocus)
        self.img_transparency_sld.setRange(0, 100)
        self.img_transparency_sld.setValue(transparency)

        self.transparency_layout = QFormLayout()
        self.transparency_layout.addRow(self.img_transparency_sld,
                                        self.img_transparency_edit)
        self.img_status_layout.addLayout(self.transparency_layout)

        # Signal of transparency value changed
        self.img_transparency_sld.valueChanged.connect(
            self.transparency_change_sld)
        self.img_transparency_edit.textChanged.connect(
            self.transparency_change_edit)

        self.img_editor_layout = QVBoxLayout()
        self.img_status_layout.addLayout(self.img_editor_layout)

        # Set layer image editor tool
        self.img_editor_tool1_layout = QHBoxLayout()
        self.img_editor_layout.addLayout(self.img_editor_tool1_layout)
        self.tool_button_size = 64

        # Set Mouse cursor
        self.mouse_cursor_button = QPushButton()
        self.mouse_cursor_button.setIcon(QIcon('icon/cursor.png'))
        self.mouse_cursor_button.setCheckable(True)
        self.mouse_cursor_button.setIconSize(
            QSize(self.tool_button_size, self.tool_button_size))
        self.img_editor_tool1_layout.addWidget(self.mouse_cursor_button)

        # Set Pen
        self.pen_button = QPushButton()
        self.pen_button.setIcon(QIcon('icon/pen.png'))
        self.pen_button.setCheckable(True)
        self.pen_button.setIconSize(
            QSize(self.tool_button_size, self.tool_button_size))
        self.img_editor_tool1_layout.addWidget(self.pen_button)

        # Set Eraser
        self.eraser_button = QPushButton()
        self.eraser_button.setIcon(QIcon('icon/eraser.png'))
        self.eraser_button.setCheckable(True)
        self.eraser_button.setIconSize(
            QSize(self.tool_button_size, self.tool_button_size))
        self.img_editor_tool1_layout.addWidget(self.eraser_button)

        # Group button of mouse cursor, pen, eraser
        self.img_editor_tool1_group1 = QButtonGroup()
        self.img_editor_tool1_group1.addButton(self.mouse_cursor_button, 1)
        self.img_editor_tool1_group1.addButton(self.pen_button, 2)
        self.img_editor_tool1_group1.addButton(self.eraser_button, 3)

        # Set signal-slot of image editor button
        self.mouse_cursor_button.toggled.connect(
            self.mouse_cursor_button_toggled)
        self.pen_button.toggled.connect(self.pen_button_toggled)
        self.eraser_button.toggled.connect(self.eraser_button_toggled)

        # Set color bar
        self.color_bar_width = 64
        self.color_bar_height = 256
        self.color_bar_view = QGraphicsView()
        self.color_bar_view.setFixedSize(self.color_bar_width + 3,
                                         self.color_bar_height + 3)
        self.color_bar_scene = GraphicsSceneForTools()

        self.color_bar_img = QImage(self.color_bar_width,
                                    self.color_bar_height,
                                    QImage.Format_RGB888)

        for i in range(self.color_bar_height):
            # Set drawing pen for colormap
            ii = round(i * (1000 / 256))
            color = QColor(self.colormap_data[ii][0],
                           self.colormap_data[ii][1],
                           self.colormap_data[ii][2])
            pen = QPen(color, 1, Qt.SolidLine, \
                Qt.SquareCap, Qt.RoundJoin)
            self.color_bar_scene.addLine(0,
                                         self.color_bar_height - i - 1,
                                         self.color_bar_width,
                                         self.color_bar_height - i - 1,
                                         pen=pen)
            for j in range(self.color_bar_width):
                self.color_bar_img.setPixelColor(j,
                                                 self.color_bar_height - i - 1,
                                                 color)

        self.color_bar_scene.set_img_content(self.color_bar_img)

        self.color_bar_view.setScene(self.color_bar_scene)

        # Connect signal to slot of color_bar_scene
        self.color_bar_scene.img_info.connect(self.set_selected_color)

        self.img_editor_tool1_layout.addWidget(self.color_bar_view)

        # Set thickness of Pen or Eraser
        self.draw_status_layout = QVBoxLayout()
        self.draw_thick_title_label = QLabel('thickness of pen or eraser')
        self.draw_status_layout.addWidget(self.draw_thick_title_label)

        self.draw_thick_edit = QLineEdit(str(self.draw_tool_size))

        self.draw_thick_sld = QSlider(Qt.Horizontal)
        self.draw_thick_sld.setFocusPolicy(Qt.NoFocus)
        self.draw_thick_sld.setRange(1, 30)
        self.draw_thick_sld.setValue(self.draw_tool_size)

        self.draw_thick_layout = QFormLayout()
        self.draw_thick_layout.addRow(self.draw_thick_sld,
                                      self.draw_thick_edit)
        self.draw_status_layout.addLayout(self.draw_thick_layout)

        self.img_editor_layout.addLayout(self.draw_status_layout)

        # Signal of draw thickness value changed
        self.draw_thick_sld.valueChanged.connect(self.draw_thick_change_sld)
        self.draw_thick_edit.textChanged.connect(self.draw_thick_change_edit)

        # Set view area of selected color
        self.select_color_view_size = 64
        self.select_color_view = QGraphicsView()
        self.select_color_view.setFixedSize(self.select_color_view_size + 3,
                                            self.select_color_view_size + 3)
        self.select_color_scene = QGraphicsScene()
        brush = QBrush(self.draw_color)

        self.select_color_rect = self.select_color_scene.addRect(QRect(0, 0, self.select_color_view_size, self.select_color_view_size), \
            brush=brush)

        self.select_color_view.setScene(self.select_color_scene)

        self.select_color_title_label = QLabel('Selected color')
        self.selected_color_layout = QFormLayout()
        self.selected_color_layout.addRow(self.select_color_title_label,
                                          self.select_color_view)
        self.img_editor_layout.addLayout(self.selected_color_layout)

        # Set save button
        self.save_button_layout = QHBoxLayout()
        self.img_status_layout.addLayout(self.save_button_layout)
        self.layer_save_button = QPushButton('Save layer image')
        self.layer_save_button.setIcon(QIcon('icon/layer_save.png'))
        self.layer_save_button.setIconSize(
            QSize(self.tool_button_size, self.tool_button_size))

        self.compose_save_button = QPushButton(
            'Save composed original and layer image')
        self.compose_save_button.setIcon(QIcon('icon/compose_save.png'))
        self.compose_save_button.setIconSize(
            QSize(self.tool_button_size, self.tool_button_size))

        self.save_button_layout.addWidget(self.layer_save_button)
        self.save_button_layout.addWidget(self.compose_save_button)

        self.layer_save_button.clicked.connect(self.save_layer_image)
        self.compose_save_button.clicked.connect(self.save_compose_image)

        # Set display area of selected file path
        self.org_img_path_title_label = QLabel('original image file: ')
        self.org_img_path_label = QLabel('')

        self.file_path_layout = QFormLayout()
        self.file_path_layout.addRow(self.org_img_path_title_label,
                                     self.org_img_path_label)

        self.bottom_layout = QVBoxLayout()
        self.bottom_layout.addLayout(self.file_path_layout)
        self.main_layout.addLayout(self.bottom_layout)

        self.mainWidget.setLayout(self.main_layout)
        self.setCentralWidget(self.mainWidget)

    # Original image select Function
    def open_org_img_dialog(self):
        options = QFileDialog.Options()
        org_img_default_path = self.app_setting["SoftwareSetting"][
            "file_path"]["org_img_dir"]
        self.org_img_file_path, selected_filter = QFileDialog.getOpenFileName(self, 'Select original image', org_img_default_path, \
            'Image files(*.jpg *jpeg *.png)', options=options)

        org_img_dir_path, org_img_file = os.path.split(self.org_img_file_path)
        org_img_bare_name, org_img_ext = os.path.splitext(org_img_file)

        self.org_img_path_label.setText(self.org_img_file_path)

        self.set_image_on_viewer()

    def set_image_on_viewer(self):
        # Delete existing image item
        if len(self.imgs_pixmap) != 0:
            for item in self.imgs_pixmap:
                self.scene.removeItem(item)

        self.scene.clear_contents()
        self.imgs_pixmap.clear()
        self.imgs.clear()

        # load original image
        self.org_qimg = QImage(self.org_img_file_path)
        self.org_pixmap = QPixmap.fromImage(self.org_qimg)
        org_img_size = self.org_qimg.size()
        self.org_img_width = org_img_size.width()
        self.org_img_height = org_img_size.height()

        # Set layer image
        self.layer_qimg = QImage(self.org_img_width, self.org_img_height,
                                 QImage.Format_RGBA8888)
        self.layer_qimg.fill(QColor(0, 0, 0, self.layer_alpha))
        self.layer_pixmap = QPixmap.fromImage(self.layer_qimg)

        self.imgs.append(self.org_qimg)
        self.imgs.append(self.layer_qimg)
        # Set image to scene
        self.imgs_pixmap.append(QGraphicsPixmapItem(self.org_pixmap))
        self.scene.addItem(self.imgs_pixmap[-1])
        self.imgs_pixmap.append(QGraphicsPixmapItem(self.layer_pixmap))
        self.scene.addItem(self.imgs_pixmap[-1])

        self.scene.set_img_contents(self.imgs)

        # Set scene to graphics view
        self.graphics_view.setScene(self.scene)
        self.graphics_view.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)

        self.show()

    # Slot function of transparency slider changed
    def transparency_change_sld(self, value):
        self.img_transparency_edit.setText(str(value))
        self.layer_alpha = int(255 * (1.0 - (value / 100)))

        # Change layer image's transparency(alpha value)
        for y in range(self.org_img_height):
            for x in range(self.org_img_width):
                self.layer_qimg.setPixelColor(
                    QPoint(x, y), QColor(0, 0, 0, self.layer_alpha))

        self.layer_pixmap = QPixmap.fromImage(self.layer_qimg)

        # remove previous layer image
        self.scene.removeItem(self.imgs_pixmap[-1])
        self.imgs_pixmap.pop(-1)

        # add new layer image to scene
        self.imgs_pixmap.append(QGraphicsPixmapItem(self.layer_pixmap))
        self.scene.addItem(self.imgs_pixmap[-1])

        self.show()

    # Slot function of transparency text edit changed
    def transparency_change_edit(self, value):
        if int(value) < 0 or int(value) > 100:
            return

        self.img_transparency_sld.setValue(int(value))
        self.layer_alpha = int(255 * (1.0 - (int(value) / 100.0)))

        # Change layer image's transparency(alpha value)
        for y in range(self.org_img_height):
            for x in range(self.org_img_width):
                self.layer_qimg.setPixelColor(
                    QPoint(x, y), QColor(0, 0, 0, self.layer_alpha))

        self.layer_pixmap = QPixmap.fromImage(self.layer_qimg)

        # remove previous layer image
        self.scene.removeItem(self.imgs_pixmap[-1])
        self.imgs_pixmap.pop(-1)

        # add new layer image to scene
        self.imgs_pixmap.append(QGraphicsPixmapItem(self.layer_pixmap))
        self.scene.addItem(self.imgs_pixmap[-1])

        self.show()

    # slot(receiver of signal) of mouse_cursor_button toggled
    def mouse_cursor_button_toggled(self, checked):
        if checked:
            self.img_edit_mode = 'cursor'
            self.scene.set_mode(self.img_edit_mode)
            self.color_bar_scene.set_mode(self.img_edit_mode)

    # slot(receiver of signal) of pen_button toggled
    def pen_button_toggled(self, checked):
        if checked:
            self.img_edit_mode = 'pen'
            self.scene.set_mode(self.img_edit_mode)
            self.color_bar_scene.set_mode(self.img_edit_mode)

    # slot(receiver of signal) of eraser_button toggled
    def eraser_button_toggled(self, checked):
        if checked:
            self.img_edit_mode = 'eraser'
            self.scene.set_mode(self.img_edit_mode)
            self.color_bar_scene.set_mode(self.img_edit_mode)
            self.draw_color = self.eraser_color

            self.select_color_scene.removeItem(self.select_color_rect)
            brush = QBrush(self.draw_color)
            self.select_color_rect = self.select_color_scene.addRect(QRect(0, 0, self.select_color_view_size, self.select_color_view_size), \
                brush=brush)
            self.select_color_view.setScene(self.select_color_scene)

    # Slot of color bar clicked for selection color
    def set_selected_color(self, color):
        # Delete existng image item
        self.select_color_scene.removeItem(self.select_color_rect)
        self.draw_color = color
        brush = QBrush(self.draw_color)
        self.select_color_rect = self.select_color_scene.addRect(QRect(0, 0, self.select_color_view_size, self.select_color_view_size), \
            brush=brush)
        self.select_color_view.setScene(self.select_color_scene)

    # Slot function of draw thicikeness slider changed
    def draw_thick_change_sld(self, value):
        self.draw_thickness_edit.setText(str(value))
        self.draw_tool_size = value

    # Slot function of draw thicikeness text editor changed
    def draw_thick_change_edit(self, value):
        if int(value) < 1 or int(value) > 30:
            return
        self.draw_thickness_sld.setValue(int(value))

    def make_layer_image(self):
        for i, line in enumerate(self.scene.lines):
            pen = self.scene.pens[i]

            pen_size = int(pen.width())
            pen_color = pen.color()

            # start pixel of line
            x1 = int(line.x1())
            y1 = int(line.y1())

            # end pixel of line
            x2 = int(line.x2())
            y2 = int(line.y2())

            dx = int(line.dx())
            dy = int(line.dy())

            # When only 1pixl line
            if dx <= 1 and dy <= 1:
                draw_pix_x1_s = max(x1 - int(pen_size / 2), 0)
                draw_pix_x1_e = min(x1 + int(pen_size / 2),
                                    self.org_img_width - 1)
                draw_pix_y1_s = max(y1 - int(pen_size / 2), 0)
                draw_pix_y1_e = min(y1 + int(pen_size / 2),
                                    self.org_img_height - 1)

                # for Pen's size
                for y in range(draw_pix_y1_s, draw_pix_y1_e):
                    for x in range(draw_pix_x1_s, draw_pix_x1_e):
                        self.layer_qimg.setPixelColor(x, y, pen_color)

                draw_pix_x2_s = max(x2 - int(pen_size / 2), 0)
                draw_pix_x2_e = min(x2 + int(pen_size / 2),
                                    self.org_img_width - 1)
                draw_pix_y2_s = max(y2 - int(pen_size / 2), 0)
                draw_pix_y2_e = min(y2 + int(pen_size / 2),
                                    self.org_img_height - 1)

                # for Pen's size
                for y in range(draw_pix_y2_s, draw_pix_y2_e):
                    for x in range(draw_pix_x2_s, draw_pix_x2_e):
                        self.layer_qimg.setPixelColor(x, y, pen_color)

            else:
                # For avoid devide by 0
                if dx == 0:
                    for y in range(y1, y2 + 1):
                        draw_pix_y_s = y - int(pen_size / 2)
                        draw_pix_y_e = y + int(pen_size / 2)
                        # for Pen's size
                        for yy in range(draw_pix_y_s, draw_pix_y_e):
                            self.layer_qimg.setPixelColor(x1, yy, pen_color)

                else:
                    grad = dy / dx

                    # Choose coordinates with small slope not to skip pixels
                    if grad >= 1.0:
                        for x in range(dx):
                            y = y1 + int(grad * x + 0.5)
                            draw_pix_x_s = max(x1 + x - int(pen_size / 2), 0)
                            draw_pix_x_e = min(x1 + x + int(pen_size / 2),
                                               self.org_img_width - 1)
                            draw_pix_y_s = max(y - int(pen_size / 2), 0)
                            draw_pix_y_e = min(y + int(pen_size / 2),
                                               self.org_img_height - 1)
                            # for Pen's size
                            for yy in range(draw_pix_y_s, draw_pix_y_e + 1):
                                for xx in range(draw_pix_x_s,
                                                draw_pix_x_e + 1):
                                    self.layer_qimg.setPixelColor(
                                        xx, yy, pen_color)

                    else:
                        for y in range(dy):
                            x = x1 + int(1 / grad * y + 0.5)
                            draw_pix_y_s = max(y1 + y - int(pen_size / 2), 0)
                            draw_pix_y_e = min(y1 + y + int(pen_size / 2),
                                               self.org_img_height - 1)
                            draw_pix_x_s = max(x - int(pen_size / 2), 0)
                            draw_pix_x_e = min(x + int(pen_size / 2),
                                               self.org_img_width - 1)
                            # for Pen's size
                            for yy in range(draw_pix_y_s, draw_pix_y_e + 1):
                                for xx in range(draw_pix_x_s,
                                                draw_pix_x_e + 1):
                                    self.layer_qimg.setPixelColor(
                                        xx, yy, pen_color)

    # Slot function of save layer image button clicked
    def save_layer_image(self):

        self.make_layer_image()

        layer_img_default_path = self.app_setting["SoftwareSetting"][
            "file_path"]["layer_img_dir"]
        options = QFileDialog.Options()
        file_name, selected_filete = QFileDialog.getSaveFileName(self, 'Save layer image', layer_img_default_path, \
            'image files(*.png, *jpg)', options=options)

        #print('layer image save name:{file}'.format(file=file_name))
        self.layer_qimg.save(file_name)
        ret = QMessageBox(self, 'Success', 'layer image is saved successfully',
                          QMessageBox.Ok)

    # Make composed orignal and layered image
    def make_compose_image(self):
        self.make_layer_image()

        self.compose_qimg = QImage(self.org_img_width, self.org_img_height,
                                   QImage.Format_RGBA8888)
        painter = QPainter(self.compose_qimg)

        painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
        painter.drawImage(0, 0, self.org_qimg)

        painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
        painter.drawImage(0, 0, self.layer_qimg)

        painter.end()

    # Slot function of save composer original and layer image button clicked
    def save_compose_image(self):
        self.make_compose_image()

        compose_img_default_path = self.app_setting["SoftwareSetting"][
            "file_path"]["compose_img_dir"]
        options = QFileDialog.Options()
        file_name, selected_fileter = QFileDialog.getSaveFileName(self, 'Save composed image', compose_img_default_path, \
            'image files(*.png, *jpg)', options=options)

        #print('compose image save name:{file}'.format(file=file_name))
        self.compose_qimg.save(file_name)
        ret = QMessageBox(self, 'Success',
                          'compose image is saved successfully',
                          QMessageBox.Ok)
Пример #11
0
class Apartment2D(object):
    def __init__(self, ui):
        #self.ui = ui
        #self.ui.guiDlg.resize(QDesktopWidget().availableGeometry(self).size() * 0.6)
        self.scene = QGraphicsScene()
        self.dim = {
            "HMIN": -3000,
            "VMIN": -4000,
            "WIDTH": 6000,
            "HEIGHT": 8000
        }
        self.scene.setSceneRect(self.dim['HMIN'], self.dim['VMIN'],
                                self.dim['WIDTH'], self.dim['HEIGHT'])
        ui.graphicsView.setScene(self.scene)
        self.boxes = []
        #self.ui.graphicsView.setViewport(QGLWidget())
        ui.graphicsView.scale(1, -1)
        ui.graphicsView.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
        ui.graphicsView.setTransformationAnchor(QGraphicsView.NoAnchor)
        ui.graphicsView.setResizeAnchor(QGraphicsView.NoAnchor)

        self.persons = {}
        self.pixmapSize = (0, 0)
        self.initializeWorld()

    def addPerson(self, pos, angle=0, color=-1, size=100):
        colors = QColor.colorNames()
        color = colors[random.randint(0,
                                      len(colors) -
                                      1)] if color == -1 else color
        pos = [pos[0], pos[2]] if len(pos) > 2 else pos
        p = self.scene.addEllipse(pos[0] - size // 2,
                                  pos[1] - size // 2,
                                  size,
                                  size,
                                  pen=QPen(QColor(color), 20),
                                  brush=QBrush(color=QColor(color)))

        # pixmap
        pixmap = QPixmap("person.png").scaled(600, 300)
        self.pixmapSize = (pixmap.width() / 2, pixmap.height() / 2)
        pixItem = QGraphicsPixmapItem(pixmap)
        pixItem.setTransformOriginPoint(pixItem.boundingRect().center())
        pixItem.setZValue(20)
        self.scene.addItem(pixItem)

        self.persons[p] = pixItem

        return p

    def movePerson(self, elipse, pos, size=100):
        #elipse.setPos(pos[0], pos[1])
        pos = [pos[0], pos[2]] if len(pos) > 2 else pos
        color = elipse.pen().color()
        self.scene.addEllipse(pos[0] - size // 2,
                              pos[1] - size // 2,
                              size,
                              size,
                              pen=QPen(QColor(color), 20),
                              brush=QBrush(color=QColor(color)))
        # pixmap
        self.persons[elipse].setPos(pos[0] - self.pixmapSize[0],
                                    pos[1] - self.pixmapSize[1])

        # change rotation value when provided
        self.persons[elipse].setRotation(180)

    def wheelEvent(self, event):
        zoomInFactor = 1.15
        zoomOutFactor = 1 / zoomInFactor
        # Zoom
        if event.delta() > 0:
            zoomFactor = zoomInFactor
        else:
            zoomFactor = zoomOutFactor
        self.graphicsView.scale(zoomFactor, zoomFactor)

    def initializeWorld(self):
        with open('autonomy.json', 'r') as f:
            world = json.load(f)

        #load dimensions
        dim = world["dimensions"]
        x_offset = -3200
        y_offset = 1850

        # load roundtables
        # for k,v in world["roundTables"].items():
        #     print(v)
        #     box = self.scene.addEllipse(QRectF(-v[2]// 2, -v[3]// 2, v[2], v[3]), QPen(QColor("Khaki")), QBrush(QColor("Khaki")));
        #     box.setPos(v[4]+x_offset, v[5]+x_offset);
        #     self.boxes.append(box)

        # load tables
        for k, v in world["tables"].items():
            box = self.scene.addRect(
                QRectF(-v[2] // 2, -v[3] // 2, v[2], v[3]),
                QPen(QColor("SandyBrown")), QBrush(QColor("SandyBrown")))
            box.setPos(v[4] + x_offset, v[5] + y_offset)
            box.setTransformOriginPoint(box.mapFromScene(QPointF(0, 0)))
            box.setRotation(v[6])
            self.boxes.append(box)

        # load walls
        for k, v in world['walls'].items():
            box = self.scene.addRect(
                QRectF(-v[2] // 2, -v[3] // 2, v[2], v[3]),
                QPen(QColor("Brown")), QBrush(QColor("Brown")))
            box.setPos(v[4] + x_offset, v[5] + y_offset)
            box.setTransformOriginPoint(box.mapFromScene(QPointF(0, 0)))
            box.setRotation(v[6])
            self.boxes.append(box)
        # }

        # //load points
        # QVariantMap points = mainMap[QString("points")].toMap();
        # for (auto &t : points)
        # {
        #     QVariantList object = t.toList();
        #     auto box = scene.addRect(QRectF(-object[2].toFloat() / 2, -object[3].toFloat() / 2, object[2].toFloat(), object[3].toFloat()), QPen(QColor("Brown")), QBrush(QColor("Brown")));
        #     box->setPos(object[4].toFloat()+x_offset, object[5].toFloat()+y_offset);
        #     boxes.push_back(box);
        # }
        # //load boxes
        # QVariantMap cajas = mainMap[QString("boxes")].toMap();
        # for (auto &t : cajas)
        # {
        #     QVariantList object = t.toList();
        #     auto box = scene.addRect(QRectF(-object[2].toFloat() / 2, -object[3].toFloat() / 2, object[2].toFloat(), object[3].toFloat()), QPen(QColor("Brown")), QBrush(QColor("Orange")));
        #     box->setPos(object[4].toFloat()+x_offset, object[5].toFloat()+y_offset);
        #     //box->setPos(object[4].toFloat(), object[5].toFloat());
        #     //box->setRotation(object[6].toFloat()*180/M_PI2);
        #     box->setFlag(QGraphicsItem::ItemIsMovable);
        #     boxes.push_back(box);
        # }
        # QTransform t;
        # //t.translate(3200, -1850);
        # t.rotate(-90);
        # //t.translate(-3200, 1850);
        # for(auto &item : boxes)
        # {
        #     item->setPos(t.map(item->pos()));
        #     item->setRotation(item->rotation() + 90);
        #     item->setPos(item->pos() + QPointF(1850,3200));
        # }
        # /////////////
        # //AXIS
        self.scene.addLine(0, 0, 400, 0, QPen(QBrush(QColor("red")), 20))
        self.scene.addLine(0, 0, 0, 400, QPen(QBrush(QColor("blue")), 20))
class HumanVisualizationWidget(QGraphicsView):
    def __init__(self, parent=None):
        super(HumanVisualizationWidget, self).__init__(parent)
        self._scene = QGraphicsScene(self)
        self.setScene(self._scene)
        # circle = QGraphicsEllipseItem( 10, 10, 10 ,10)
        # self._scene.addItem(circle)
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self._boxes = []
        self._humans = {}

    def load_inner_model(self, file):
        import xml.etree.cElementTree as ET
        tree = ET.ElementTree(file=file)
        root = tree.getroot()
        transforms = tree.findall(".//transform[plane]")
        walls = {}
        for trans in transforms:
            if 'id' in trans.attrib and 'pared' in trans.attrib['id']:
                print("Pared:", trans.attrib['id'])
                current_wall = [0] * 7
                # "wall5": [x, y, width, height, posx, posy, 0]
                if 'tx' in trans.attrib:
                    # print trans.attrib['tx']
                    current_wall[4] = int(float(trans.attrib['tx']))
                if 'ty' in trans.attrib:
                    # print trans.attrib['ty']
                    current_wall[5] = int(float(trans.attrib['tz']))
                # current_wall =
                planes = trans.findall('plane')
                for plane in planes:
                    if 'id' in plane.attrib and 'muro' in plane.attrib['id']:
                        # if 'nx' in plane.attrib:
                        # 	print plane.attrib['nx']
                        # if 'nz' in plane.attrib:
                        # 	print plane.attrib['nz']
                        if 'size' in plane.attrib:
                            # print int(float(plane.attrib['size'].split(',')[0])
                            current_wall[2] = int(
                                float(plane.attrib['size'].split(',')[0])) / 2.
                            # print int(float(plane.attrib['size'].split(',')[1])
                            current_wall[3] = int(
                                float(plane.attrib['size'].split(',')[1])) / 2.
                            if current_wall[2] < current_wall[3]:
                                current_wall[2] = 200
                            else:
                                current_wall[3] = 200
                walls[trans.attrib['id']] = current_wall
        for id in sorted(walls.keys()):
            object = walls[id]
            # rect = QRectF(-float(object[2]) / 2, -float(object[3]) / 2, float(object[2]), float(object[3]))
            rect = QRectF(0, 0, float(object[2]), float(object[3]))

            border = QPen(QColor("black"))
            fill = QBrush(QColor("black"))
            box = self._scene.addRect(rect, border, fill)

            self._scene.addEllipse(
                QRectF(float(object[4]), float(object[5]), 10, 10),
                QPen(QColor("green")), QBrush(QColor("green")))
            box.setPos(float(object[4]), float(object[5]))
            box.setRotation(float(object[6]))
            self._boxes.append(box)
            self._scene.update()
            QApplication.processEvents()
            sleep(1)

    def load_custom_json_world(self, file):

        if not os.path.isfile(file):
            print("Error reading world file, check config params:", file)
            return False

        with open(file, "r") as read_file:
            json_data = json.load(read_file)

        types_colors = {
            "tables": "SandyBrown",
            "roundTables": "Khaki",
            "walls": "Brown",
            "points": "Blue"
        }
        self.clear()
        for type, color in types_colors.items():
            if type in json_data:
                tables = json_data[type]
                for object in tables.values():
                    rect = QRectF(-float(object[2]) / 2, -float(object[3]) / 2,
                                  float(object[2]), float(object[3]))
                    border = QPen(QColor(color))
                    fill = QBrush(QColor(color))
                    if type == "roundTables":
                        box = self._scene.addEllipse(rect, border, fill)
                    else:
                        box = self._scene.addRect(rect, border, fill)

                    box.setPos(float(object[4]), float(object[5]))
                    box.setRotation(float(object[6]))
                    self._boxes.append(box)

    def load_json_world(self, file):

        if not os.path.isfile(file):
            print("Error reading world file, check config params:", file)
            return False

        with open(file, "r") as read_file:
            json_data = json.load(read_file)

            polygon_points = []
        paths_count = 0
        for item in json_data:
            if 'json_geometry' in item:
                geometry = item['json_geometry']
                if geometry['type'] == 'Polygon':
                    for coord in geometry['coordinates'][0]:

                        if isinstance(coord, list) and (
                            (isinstance(coord, list) and len(coord) == 2) or
                            (len(coord) == 3 and coord[3] == 0)):
                            current_point = QPointF(coord[0], coord[1])
                            polygon_points.append(current_point)
                        else:
                            print("Unknown coord", geometry["coordinates"][0])
                    polygon = QPolygonF(polygon_points)
                    path = QPainterPath()
                    path.addPolygon(polygon)
                    contour = QGraphicsPathItem(path)
                    # r = lambda: random.randint(0, 255)
                    # next_color = '#%02X%02X%02X' % (r(), r(), r())
                    contour.setPen(QPen(QColor("red"), 0.1))

                    contour.setBrush(QBrush(Qt.transparent))
                    # if paths_count == 4:
                    print(item['json_featuretype'])
                    self._scene.addItem(contour)
                    paths_count += 1
        self.update()

    def clear(self):
        for human in self._humans.values():
            self._scene.removeItem(human)
        self._humans = {}
        # self._scene.setSceneRect(QRectF(0,0,400,400))

    def resizeEvent(self, event):
        # skip initial entry
        self.own_resize()
        super(HumanVisualizationWidget, self).resizeEvent(event)

    def own_resize(self):
        self.fitInView(self._scene.itemsBoundingRect(), Qt.KeepAspectRatio)
        self._scene.setSceneRect(self._scene.itemsBoundingRect())

    def add_human_by_pos(self, id, pos):
        x, y = pos
        human = QGraphicsEllipseItem(0, 0, 200, 200)
        self._scene.addItem(human)
        human.setBrush(QBrush(Qt.black, style=Qt.SolidPattern))
        human_text = QGraphicsTextItem(str(pos))
        font = QFont("Helvetica [Cronyx]", 40, QFont.Bold)
        human_text.setFont(font)
        human_text.setParentItem(human)
        human.setPos(pos[0], pos[1])
        self._humans[id] = human
        human.setZValue(30)

    def move_human(self, id, pos):
        x, y = pos
        human = self._humans[id]
        human.setPos(x, y)

    def set_human_color(self, id, color):
        if id in self._humans:
            self._humans[id].setBrush(color)
Пример #13
0
class Screenshot(QGraphicsView):
    """ Main Class """

    screen_shot_grabed = Signal(QImage)
    screen_shot_pos_grabed = Signal(QRect)
    widget_closed = Signal()

    def __init__(self, flags=constant.DEFAULT, parent=None):
        """
        flags: binary flags. see the flags in the constant.py
        """
        super().__init__(parent)

        # Init
        self.penColorNow = QColor(PENCOLOR)
        self.penSizeNow = PENSIZE
        self.fontNow = QFont('Sans')
        self.clipboard = QApplication.clipboard()

        self.drawListResult = [
        ]  # draw list that sure to be drew, [action, coord]
        self.drawListProcess = None  # the process to the result
        self.selected_area = QRect(
        )  # a QRect instance which stands for the selected area
        self.selectedAreaRaw = QRect()
        self.mousePosition = MousePosition.OUTSIDE_AREA  # mouse position
        self.screenPixel = None
        self.textRect = None

        self.mousePressed = False
        self.action = ACTION_SELECT
        self.mousePoint = self.cursor().pos()

        self.startX, self.startY = 0, 0  # the point where you start
        self.endX, self.endY = 0, 0  # the point where you end
        self.pointPath = QPainterPath(
        )  # the point mouse passes, used by draw free line
        self.items_to_remove = [
        ]  # the items that should not draw on screenshot picture
        self.textPosition = None

        # result
        self.target_img = None
        self.target_img_pos = None

        # Init window
        self.getscreenshot()
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)

        self.setMouseTracking(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setContentsMargins(0, 0, 0, 0)
        self.setStyleSheet("QGraphicsView { border-style: none; }")

        self.tooBar = MyToolBar(flags, self)
        self.tooBar.trigger.connect(self.changeAction)

        self.penSetBar = None
        if flags & constant.RECT or flags & constant.ELLIPSE or flags & constant.LINE or flags & constant.FREEPEN \
                or flags & constant.ARROW or flags & constant.TEXT:
            self.penSetBar = PenSetWidget(self)
            self.penSetBar.penSizeTrigger.connect(self.changePenSize)
            self.penSetBar.penColorTrigger.connect(self.changePenColor)
            self.penSetBar.fontChangeTrigger.connect(self.changeFont)

        self.textInput = TextInput(self)
        self.textInput.inputChanged.connect(self.textChange)
        self.textInput.cancelPressed.connect(self.cancelInput)
        self.textInput.okPressed.connect(self.okInput)

        self.graphics_scene = QGraphicsScene(0, 0, self.screenPixel.width(),
                                             self.screenPixel.height())

        self.show()
        self.setScene(self.graphics_scene)
        self.windowHandle().setScreen(QGuiApplication.screenAt(QCursor.pos()))
        self.scale = self.get_scale()
        # self.setFixedSize(self.screenPixel.width(), self.screenPixel.height())
        self.setGeometry(QGuiApplication.screenAt(QCursor.pos()).geometry())
        self.showFullScreen()
        self.redraw()

        QShortcut(QKeySequence('ctrl+s'),
                  self).activated.connect(self.saveScreenshot)
        QShortcut(QKeySequence('esc'), self).activated.connect(self.close)

    @staticmethod
    def take_screenshot(flags):
        loop = QEventLoop()
        screen_shot = Screenshot(flags)
        screen_shot.show()
        screen_shot.widget_closed.connect(loop.quit)

        loop.exec_()
        img = screen_shot.target_img
        return img

    @staticmethod
    def take_screenshot_pos(flags):
        loop = QEventLoop()
        screen_shot = Screenshot(flags)
        screen_shot.show()
        screen_shot.widget_closed.connect(loop.quit)

        loop.exec_()
        pos = screen_shot.target_img_pos
        return pos

    def getscreenshot(self):
        screen = QGuiApplication.screenAt(QCursor.pos())
        self.screenPixel = screen.grabWindow(0)

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() != Qt.LeftButton:
            return

        if self.action is None:
            self.action = ACTION_SELECT

        self.startX, self.startY = event.x(), event.y()

        if self.action == ACTION_SELECT:
            if self.mousePosition == MousePosition.OUTSIDE_AREA:
                self.mousePressed = True
                self.selected_area = QRect()
                self.selected_area.setTopLeft(QPoint(event.x(), event.y()))
                self.selected_area.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            elif self.mousePosition == MousePosition.INSIDE_AREA:
                self.mousePressed = True
            else:
                pass
        elif self.action == ACTION_MOVE_SELECTED:
            if self.mousePosition == MousePosition.OUTSIDE_AREA:
                self.action = ACTION_SELECT
                self.selected_area = QRect()
                self.selected_area.setTopLeft(QPoint(event.x(), event.y()))
                self.selected_area.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            self.mousePressed = True
        elif self.action in DRAW_ACTION:
            self.mousePressed = True
            if self.action == ACTION_FREEPEN:
                self.pointPath = QPainterPath()
                self.pointPath.moveTo(QPoint(event.x(), event.y()))
            elif self.action == ACTION_TEXT:
                if self.textPosition is None:
                    self.textPosition = QPoint(event.x(), event.y())
                    self.textRect = None
                    self.redraw()

    def mouseMoveEvent(self, event: QMouseEvent):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.mousePoint = QPoint(event.globalPos().x(), event.globalPos().y())

        if self.action is None:
            self.action = ACTION_SELECT

        if not self.mousePressed:
            point = QPoint(event.x(), event.y())
            self.detect_mouse_position(point)
            self.setCursorStyle()
            self.redraw()
        else:
            self.endX, self.endY = event.x(), event.y()

            # if self.mousePosition != OUTSIDE_AREA:
            #    self.action = ACTION_MOVE_SELECTED

            if self.action == ACTION_SELECT:
                self.selected_area.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            elif self.action == ACTION_MOVE_SELECTED:
                self.selected_area = QRect(self.selectedAreaRaw)

                if self.mousePosition == MousePosition.INSIDE_AREA:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.left()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.top()
                    if 0 <= move_to_x <= self.screenPixel.width(
                    ) - 1 - self.selected_area.width():
                        self.selected_area.moveLeft(move_to_x)
                    if 0 <= move_to_y <= self.screenPixel.height(
                    ) - 1 - self.selected_area.height():
                        self.selected_area.moveTop(move_to_y)
                    self.selected_area = self.selected_area.normalized()
                    self.selectedAreaRaw = QRect(self.selected_area)
                    self.startX, self.startY = event.x(), event.y()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_LEFT_SIDE:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.left()
                    if move_to_x <= self.selected_area.right():
                        self.selected_area.setLeft(move_to_x)
                        self.selected_area = self.selected_area.normalized()
                        self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.right()
                    self.selected_area.setRight(move_to_x)
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_UP_SIDE:
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.top()
                    self.selected_area.setTop(move_to_y)
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_DOWN_SIDE:
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.bottom()
                    self.selected_area.setBottom(move_to_y)
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.left()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.top()
                    self.selected_area.setTopLeft(QPoint(move_to_x, move_to_y))
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.right()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.bottom()
                    self.selected_area.setBottomRight(
                        QPoint(move_to_x, move_to_y))
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.right()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.top()
                    self.selected_area.setTopRight(QPoint(
                        move_to_x, move_to_y))
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.left()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.bottom()
                    self.selected_area.setBottomLeft(
                        QPoint(move_to_x, move_to_y))
                    self.redraw()
                else:
                    pass
            elif self.action == ACTION_RECT:
                self.drawRect(self.startX, self.startY, event.x(), event.y(),
                              False)
                self.redraw()
                pass
            elif self.action == ACTION_ELLIPSE:
                self.drawEllipse(self.startX, self.startY, event.x(),
                                 event.y(), False)
                self.redraw()
            elif self.action == ACTION_ARROW:
                self.drawArrow(self.startX, self.startY, event.x(), event.y(),
                               False)
                self.redraw()
            elif self.action == ACTION_LINE:
                self.drawLine(self.startX, self.startY, event.x(), event.y(),
                              False)
                self.redraw()
            elif self.action == ACTION_FREEPEN:
                y1, y2 = event.x(), event.y()
                rect = self.selected_area.normalized()
                if y1 <= rect.left():
                    y1 = rect.left()
                elif y1 >= rect.right():
                    y1 = rect.right()

                if y2 <= rect.top():
                    y2 = rect.top()
                elif y2 >= rect.bottom():
                    y2 = rect.bottom()

                self.pointPath.lineTo(y1, y2)
                self.drawFreeLine(self.pointPath, False)
                self.redraw()

    def mouseReleaseEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() != Qt.LeftButton:
            return

        if self.mousePressed:
            self.mousePressed = False
            self.endX, self.endY = event.x(), event.y()

            if self.action == ACTION_SELECT:
                self.selected_area.setBottomRight(QPoint(event.x(), event.y()))
                self.selectedAreaRaw = QRect(self.selected_area)
                self.action = ACTION_MOVE_SELECTED
                self.redraw()
            elif self.action == ACTION_MOVE_SELECTED:
                self.selectedAreaRaw = QRect(self.selected_area)
                self.redraw()
                # self.action = None
            elif self.action == ACTION_RECT:
                self.drawRect(self.startX, self.startY, event.x(), event.y(),
                              True)
                self.redraw()
            elif self.action == ACTION_ELLIPSE:
                self.drawEllipse(self.startX, self.startY, event.x(),
                                 event.y(), True)
                self.redraw()
            elif self.action == ACTION_ARROW:
                self.drawArrow(self.startX, self.startY, event.x(), event.y(),
                               True)
                self.redraw()
            elif self.action == ACTION_LINE:
                self.drawLine(self.startX, self.startY, event.x(), event.y(),
                              True)
                self.redraw()
            elif self.action == ACTION_FREEPEN:
                self.drawFreeLine(self.pointPath, True)
                self.redraw()

    def detect_mouse_position(self, point):
        """
        :type point: QPoint
        :param point: the mouse position you want to check
        :return:
        """
        if self.selected_area == QRect():
            self.mousePosition = MousePosition.OUTSIDE_AREA
            return

        if self.selected_area.left() - ERRORRANGE <= point.x(
        ) <= self.selected_area.left() and (
                self.selected_area.top() - ERRORRANGE <= point.y() <=
                self.selected_area.top()):
            self.mousePosition = MousePosition.ON_THE_TOP_LEFT_CORNER
        elif self.selected_area.right() <= point.x(
        ) <= self.selected_area.right() + ERRORRANGE and (
                self.selected_area.top() - ERRORRANGE <= point.y() <=
                self.selected_area.top()):
            self.mousePosition = MousePosition.ON_THE_TOP_RIGHT_CORNER
        elif self.selected_area.left() - ERRORRANGE <= point.x(
        ) <= self.selected_area.left() and (
                self.selected_area.bottom() <= point.y() <=
                self.selected_area.bottom() + ERRORRANGE):
            self.mousePosition = MousePosition.ON_THE_BOTTOM_LEFT_CORNER
        elif self.selected_area.right() <= point.x(
        ) <= self.selected_area.right() + ERRORRANGE and (
                self.selected_area.bottom() <= point.y() <=
                self.selected_area.bottom() + ERRORRANGE):
            self.mousePosition = MousePosition.ON_THE_BOTTOM_RIGHT_CORNER
        elif -ERRORRANGE <= point.x() - self.selected_area.left() <= 0 and (
                self.selected_area.topLeft().y() < point.y() <
                self.selected_area.bottomLeft().y()):
            self.mousePosition = MousePosition.ON_THE_LEFT_SIDE
        elif 0 <= point.x() - self.selected_area.right() <= ERRORRANGE and (
                self.selected_area.topRight().y() < point.y() <
                self.selected_area.bottomRight().y()):
            self.mousePosition = MousePosition.ON_THE_RIGHT_SIDE
        elif -ERRORRANGE <= point.y() - self.selected_area.top() <= 0 and (
                self.selected_area.topLeft().x() < point.x() <
                self.selected_area.topRight().x()):
            self.mousePosition = MousePosition.ON_THE_UP_SIDE
        elif 0 <= point.y() - self.selected_area.bottom() <= ERRORRANGE and (
                self.selected_area.bottomLeft().x() < point.x() <
                self.selected_area.bottomRight().x()):
            self.mousePosition = MousePosition.ON_THE_DOWN_SIDE
        elif not self.selected_area.contains(point):
            self.mousePosition = MousePosition.OUTSIDE_AREA
        else:
            self.mousePosition = MousePosition.INSIDE_AREA

    def setCursorStyle(self):
        if self.action in DRAW_ACTION:
            self.setCursor(Qt.CrossCursor)
            return

        if self.mousePosition == MousePosition.ON_THE_LEFT_SIDE or \
                self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE:

            self.setCursor(Qt.SizeHorCursor)
        elif self.mousePosition == MousePosition.ON_THE_UP_SIDE or \
                self.mousePosition == MousePosition.ON_THE_DOWN_SIDE:

            self.setCursor(Qt.SizeVerCursor)
        elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER or \
                self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER:

            self.setCursor(Qt.SizeFDiagCursor)
        elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER or \
                self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER:

            self.setCursor(Qt.SizeBDiagCursor)
        elif self.mousePosition == MousePosition.OUTSIDE_AREA:
            self.setCursor(Qt.ArrowCursor)
        elif self.mousePosition == MousePosition.INSIDE_AREA:
            self.setCursor(Qt.OpenHandCursor)
        else:
            self.setCursor(Qt.ArrowCursor)
            pass

    def drawMagnifier(self):
        # First, calculate the magnifier position due to the mouse position
        watch_area_width = 16
        watch_area_height = 16

        cursor_pos = self.mousePoint

        watch_area = QRect(
            QPoint(cursor_pos.x() - watch_area_width / 2,
                   cursor_pos.y() - watch_area_height / 2),
            QPoint(cursor_pos.x() + watch_area_width / 2,
                   cursor_pos.y() + watch_area_height / 2))
        if watch_area.left() < 0:
            watch_area.moveLeft(0)
            watch_area.moveRight(watch_area_width)
        if self.mousePoint.x(
        ) + watch_area_width / 2 >= self.screenPixel.width():
            watch_area.moveRight(self.screenPixel.width() - 1)
            watch_area.moveLeft(watch_area.right() - watch_area_width)
        if self.mousePoint.y() - watch_area_height / 2 < 0:
            watch_area.moveTop(0)
            watch_area.moveBottom(watch_area_height)
        if self.mousePoint.y(
        ) + watch_area_height / 2 >= self.screenPixel.height():
            watch_area.moveBottom(self.screenPixel.height() - 1)
            watch_area.moveTop(watch_area.bottom() - watch_area_height)

        # tricks to solve the hidpi impact on QCursor.pos()
        watch_area.setTopLeft(
            QPoint(watch_area.topLeft().x() * self.scale,
                   watch_area.topLeft().y() * self.scale))
        watch_area.setBottomRight(
            QPoint(watch_area.bottomRight().x() * self.scale,
                   watch_area.bottomRight().y() * self.scale))
        watch_area_pixmap = self.screenPixel.copy(watch_area)

        # second, calculate the magnifier area
        magnifier_area_width = watch_area_width * 10
        magnifier_area_height = watch_area_height * 10
        font_area_height = 40

        cursor_size = 24
        magnifier_area = QRectF(
            QPoint(QCursor.pos().x() + cursor_size,
                   QCursor.pos().y() + cursor_size),
            QPoint(QCursor.pos().x() + cursor_size + magnifier_area_width,
                   QCursor.pos().y() + cursor_size + magnifier_area_height))
        if magnifier_area.right() >= self.screenPixel.width():
            magnifier_area.moveLeft(QCursor.pos().x() - magnifier_area_width -
                                    cursor_size / 2)
        if magnifier_area.bottom(
        ) + font_area_height >= self.screenPixel.height():
            magnifier_area.moveTop(QCursor.pos().y() - magnifier_area_height -
                                   cursor_size / 2 - font_area_height)

        # third, draw the watch area to magnifier area
        watch_area_scaled = watch_area_pixmap.scaled(
            QSize(magnifier_area_width * self.scale,
                  magnifier_area_height * self.scale))
        magnifier_pixmap = self.graphics_scene.addPixmap(watch_area_scaled)
        magnifier_pixmap.setOffset(magnifier_area.topLeft())

        # then draw lines and text
        self.graphics_scene.addRect(QRectF(magnifier_area),
                                    QPen(QColor(255, 255, 255), 2))
        self.graphics_scene.addLine(
            QLineF(
                QPointF(magnifier_area.center().x(), magnifier_area.top()),
                QPointF(magnifier_area.center().x(), magnifier_area.bottom())),
            QPen(QColor(0, 255, 255), 2))
        self.graphics_scene.addLine(
            QLineF(
                QPointF(magnifier_area.left(),
                        magnifier_area.center().y()),
                QPointF(magnifier_area.right(),
                        magnifier_area.center().y())),
            QPen(QColor(0, 255, 255), 2))

        # get the rgb of mouse point
        point_rgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint))

        # draw information
        self.graphics_scene.addRect(
            QRectF(
                magnifier_area.bottomLeft(),
                magnifier_area.bottomRight() +
                QPoint(0, font_area_height + 30)), QPen(Qt.black),
            QBrush(Qt.black))
        rgb_info = self.graphics_scene.addSimpleText(
            ' Rgb: ({0}, {1}, {2})'.format(point_rgb.red(), point_rgb.green(),
                                           point_rgb.blue()))
        rgb_info.setPos(magnifier_area.bottomLeft() + QPoint(0, 5))
        rgb_info.setPen(QPen(QColor(255, 255, 255), 2))

        rect = self.selected_area.normalized()
        size_info = self.graphics_scene.addSimpleText(
            ' Size: {0} x {1}'.format(rect.width() * self.scale,
                                      rect.height() * self.scale))
        size_info.setPos(magnifier_area.bottomLeft() + QPoint(0, 15) +
                         QPoint(0, font_area_height / 2))
        size_info.setPen(QPen(QColor(255, 255, 255), 2))

    def get_scale(self):
        return self.devicePixelRatio()

    def saveScreenshot(self,
                       clipboard=False,
                       fileName='screenshot.png',
                       picType='png'):
        fullWindow = QRect(0, 0, self.width() - 1, self.height() - 1)
        selected = QRect(self.selected_area)
        if selected.left() < 0:
            selected.setLeft(0)
        if selected.right() >= self.width():
            selected.setRight(self.width() - 1)
        if selected.top() < 0:
            selected.setTop(0)
        if selected.bottom() >= self.height():
            selected.setBottom(self.height() - 1)

        source = (fullWindow & selected)
        source.setTopLeft(
            QPoint(source.topLeft().x() * self.scale,
                   source.topLeft().y() * self.scale))
        source.setBottomRight(
            QPoint(source.bottomRight().x() * self.scale,
                   source.bottomRight().y() * self.scale))
        image = self.screenPixel.copy(source)

        if clipboard:
            QGuiApplication.clipboard().setImage(image.toImage(),
                                                 QClipboard.Clipboard)
        else:
            image.save(fileName, picType, 10)
        self.target_img = image
        self.target_img_pos = source
        self.screen_shot_grabed.emit(image.toImage())
        self.screen_shot_pos_grabed.emit(source)

    def redraw(self):
        self.graphics_scene.clear()

        # draw screenshot
        self.graphics_scene.addPixmap(self.screenPixel)

        # prepare for drawing selected area
        rect = QRectF(self.selected_area)
        rect = rect.normalized()

        top_left_point = rect.topLeft()
        top_right_point = rect.topRight()
        bottom_left_point = rect.bottomLeft()
        bottom_right_point = rect.bottomRight()
        top_middle_point = (top_left_point + top_right_point) / 2
        left_middle_point = (top_left_point + bottom_left_point) / 2
        bottom_middle_point = (bottom_left_point + bottom_right_point) / 2
        right_middle_point = (top_right_point + bottom_right_point) / 2

        # draw the picture mask
        mask = QColor(0, 0, 0, 155)

        if self.selected_area == QRect():
            self.graphics_scene.addRect(0, 0, self.screenPixel.width(),
                                        self.screenPixel.height(),
                                        QPen(Qt.NoPen), mask)
        else:
            self.graphics_scene.addRect(0, 0, self.screenPixel.width(),
                                        top_right_point.y(), QPen(Qt.NoPen),
                                        mask)
            self.graphics_scene.addRect(0, top_left_point.y(),
                                        top_left_point.x(), rect.height(),
                                        QPen(Qt.NoPen), mask)
            self.graphics_scene.addRect(
                top_right_point.x(), top_right_point.y(),
                self.screenPixel.width() - top_right_point.x(), rect.height(),
                QPen(Qt.NoPen), mask)
            self.graphics_scene.addRect(
                0, bottom_left_point.y(), self.screenPixel.width(),
                self.screenPixel.height() - bottom_left_point.y(),
                QPen(Qt.NoPen), mask)

        # draw the toolBar
        if self.action != ACTION_SELECT:
            spacing = 5
            # show the toolbar first, then move it to the correct position
            # because the width of it may be wrong if this is the first time it shows
            self.tooBar.show()

            dest = QPointF(rect.bottomRight() -
                           QPointF(self.tooBar.width(), 0) -
                           QPointF(spacing, -spacing))
            if dest.x() < spacing:
                dest.setX(spacing)
            pen_set_bar_height = self.penSetBar.height(
            ) if self.penSetBar is not None else 0
            if dest.y() + self.tooBar.height(
            ) + pen_set_bar_height >= self.height():
                if rect.top() - self.tooBar.height(
                ) - pen_set_bar_height < spacing:
                    dest.setY(rect.top() + spacing)
                else:
                    dest.setY(rect.top() - self.tooBar.height() -
                              pen_set_bar_height - spacing)

            self.tooBar.move(dest.toPoint())

            if self.penSetBar is not None:
                self.penSetBar.show()
                self.penSetBar.move(dest.toPoint() +
                                    QPoint(0,
                                           self.tooBar.height() + spacing))

                if self.action == ACTION_TEXT:
                    self.penSetBar.showFontWidget()
                else:
                    self.penSetBar.showPenWidget()
        else:
            self.tooBar.hide()

            if self.penSetBar is not None:
                self.penSetBar.hide()

        # draw the list
        for step in self.drawListResult:
            self.drawOneStep(step)

        if self.drawListProcess is not None:
            self.drawOneStep(self.drawListProcess)
            if self.action != ACTION_TEXT:
                self.drawListProcess = None

        if self.selected_area != QRect():
            self.items_to_remove = []

            # draw the selected rectangle
            pen = QPen(QColor(0, 255, 255), 2)
            self.items_to_remove.append(self.graphics_scene.addRect(rect, pen))

            # draw the drag point
            radius = QPoint(3, 3)
            brush = QBrush(QColor(0, 255, 255))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(top_left_point - radius, top_left_point + radius),
                    pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(top_middle_point - radius,
                           top_middle_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(top_right_point - radius, top_right_point + radius),
                    pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(left_middle_point - radius,
                           left_middle_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(right_middle_point - radius,
                           right_middle_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(bottom_left_point - radius,
                           bottom_left_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(bottom_middle_point - radius,
                           bottom_middle_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(bottom_right_point - radius,
                           bottom_right_point + radius), pen, brush))

        # draw the textedit
        if self.textPosition is not None:
            textSpacing = 50
            position = QPoint()
            if self.textPosition.x() + self.textInput.width(
            ) >= self.screenPixel.width():
                position.setX(self.textPosition.x() - self.textInput.width())
            else:
                position.setX(self.textPosition.x())

            if self.textRect is not None:
                if self.textPosition.y() + self.textInput.height(
                ) + self.textRect.height() >= self.screenPixel.height():
                    position.setY(self.textPosition.y() -
                                  self.textInput.height() -
                                  self.textRect.height())
                else:
                    position.setY(self.textPosition.y() +
                                  self.textRect.height())
            else:
                if self.textPosition.y() + self.textInput.height(
                ) >= self.screenPixel.height():
                    position.setY(self.textPosition.y() -
                                  self.textInput.height())
                else:
                    position.setY(self.textPosition.y())

            self.textInput.move(position)
            self.textInput.show()
            # self.textInput.getFocus()

        # draw the magnifier
        if self.action == ACTION_SELECT:
            self.drawMagnifier()
            if self.mousePressed:
                self.drawSizeInfo()

        if self.action == ACTION_MOVE_SELECTED:
            self.drawSizeInfo()

    # deal with every step in drawList
    def drawOneStep(self, step):
        """
        :type step: tuple
        """
        if step[0] == ACTION_RECT:
            self.graphics_scene.addRect(
                QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_ELLIPSE:
            self.graphics_scene.addEllipse(
                QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_ARROW:
            arrow = QPolygonF()

            linex = float(step[1] - step[3])
            liney = float(step[2] - step[4])
            line = sqrt(pow(linex, 2) + pow(liney, 2))

            # in case to divided by 0
            if line == 0:
                return

            sinAngel = liney / line
            cosAngel = linex / line

            # sideLength is the length of bottom side of the body of an arrow
            # arrowSize is the size of the head of an arrow, left and right
            # sides' size is arrowSize, and the bottom side's size is arrowSize / 2
            sideLength = step[5].width()
            arrowSize = 8
            bottomSize = arrowSize / 2

            tmpPoint = QPointF(step[3] + arrowSize * sideLength * cosAngel,
                               step[4] + arrowSize * sideLength * sinAngel)

            point1 = QPointF(step[1] + sideLength * sinAngel,
                             step[2] - sideLength * cosAngel)
            point2 = QPointF(step[1] - sideLength * sinAngel,
                             step[2] + sideLength * cosAngel)
            point3 = QPointF(tmpPoint.x() - sideLength * sinAngel,
                             tmpPoint.y() + sideLength * cosAngel)
            point4 = QPointF(tmpPoint.x() - bottomSize * sideLength * sinAngel,
                             tmpPoint.y() + bottomSize * sideLength * cosAngel)
            point5 = QPointF(step[3], step[4])
            point6 = QPointF(tmpPoint.x() + bottomSize * sideLength * sinAngel,
                             tmpPoint.y() - bottomSize * sideLength * cosAngel)
            point7 = QPointF(tmpPoint.x() + sideLength * sinAngel,
                             tmpPoint.y() - sideLength * cosAngel)

            arrow.append(point1)
            arrow.append(point2)
            arrow.append(point3)
            arrow.append(point4)
            arrow.append(point5)
            arrow.append(point6)
            arrow.append(point7)
            arrow.append(point1)

            self.graphics_scene.addPolygon(arrow, step[5], step[6])
        elif step[0] == ACTION_LINE:
            self.graphics_scene.addLine(
                QLineF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_FREEPEN:
            self.graphics_scene.addPath(step[1], step[2])
        elif step[0] == ACTION_TEXT:
            textAdd = self.graphics_scene.addSimpleText(step[1], step[2])
            textAdd.setPos(step[3])
            textAdd.setBrush(QBrush(step[4]))
            self.textRect = textAdd.boundingRect()

    # draw the size information on the top left corner
    def drawSizeInfo(self):
        sizeInfoAreaWidth = 200
        sizeInfoAreaHeight = 30
        spacing = 5
        rect = self.selected_area.normalized()
        sizeInfoArea = QRect(rect.left(),
                             rect.top() - spacing - sizeInfoAreaHeight,
                             sizeInfoAreaWidth, sizeInfoAreaHeight)

        if sizeInfoArea.top() < 0:
            sizeInfoArea.moveTopLeft(rect.topLeft() + QPoint(spacing, spacing))
        if sizeInfoArea.right() >= self.screenPixel.width():
            sizeInfoArea.moveTopLeft(rect.topLeft() -
                                     QPoint(spacing, spacing) -
                                     QPoint(sizeInfoAreaWidth, 0))
        if sizeInfoArea.left() < spacing:
            sizeInfoArea.moveLeft(spacing)
        if sizeInfoArea.top() < spacing:
            sizeInfoArea.moveTop(spacing)

        self.items_to_remove.append(
            self.graphics_scene.addRect(QRectF(sizeInfoArea), QPen(Qt.white),
                                        QBrush(Qt.black)))

        sizeInfo = self.graphics_scene.addSimpleText('  {0} x {1}'.format(
            rect.width() * self.scale,
            rect.height() * self.scale))
        sizeInfo.setPos(sizeInfoArea.topLeft() + QPoint(0, 2))
        sizeInfo.setPen(QPen(QColor(255, 255, 255), 2))
        self.items_to_remove.append(sizeInfo)

    def drawRect(self, x1, x2, y1, y2, result):
        rect = self.selected_area.normalized()
        tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized()
        resultRect = rect & tmpRect
        tmp = [
            ACTION_RECT,
            resultRect.topLeft().x(),
            resultRect.topLeft().y(),
            resultRect.bottomRight().x(),
            resultRect.bottomRight().y(),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawEllipse(self, x1, x2, y1, y2, result):
        rect = self.selected_area.normalized()
        tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized()
        resultRect = rect & tmpRect
        tmp = [
            ACTION_ELLIPSE,
            resultRect.topLeft().x(),
            resultRect.topLeft().y(),
            resultRect.bottomRight().x(),
            resultRect.bottomRight().y(),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawArrow(self, x1, x2, y1, y2, result):
        rect = self.selected_area.normalized()
        if y1 <= rect.left():
            y1 = rect.left()
        elif y1 >= rect.right():
            y1 = rect.right()

        if y2 <= rect.top():
            y2 = rect.top()
        elif y2 >= rect.bottom():
            y2 = rect.bottom()

        tmp = [
            ACTION_ARROW, x1, x2, y1, y2,
            QPen(QColor(self.penColorNow), int(self.penSizeNow)),
            QBrush(QColor(self.penColorNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawLine(self, x1, x2, y1, y2, result):
        rect = self.selected_area.normalized()
        if y1 <= rect.left():
            y1 = rect.left()
        elif y1 >= rect.right():
            y1 = rect.right()

        if y2 <= rect.top():
            y2 = rect.top()
        elif y2 >= rect.bottom():
            y2 = rect.bottom()

        tmp = [
            ACTION_LINE, x1, x2, y1, y2,
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawFreeLine(self, pointPath, result):
        tmp = [
            ACTION_FREEPEN,
            QPainterPath(pointPath),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def textChange(self):
        if self.textPosition is None:
            return
        self.text = self.textInput.getText()
        self.drawListProcess = [
            ACTION_TEXT,
            str(self.text),
            QFont(self.fontNow),
            QPoint(self.textPosition),
            QColor(self.penColorNow)
        ]
        self.redraw()

    def undoOperation(self):
        if len(self.drawListResult) == 0:
            self.action = ACTION_SELECT
            self.selected_area = QRect()
            self.selectedAreaRaw = QRect()
            self.tooBar.hide()
            if self.penSetBar is not None:
                self.penSetBar.hide()
        else:
            self.drawListResult.pop()
        self.redraw()

    def saveOperation(self):
        filename = QFileDialog.getSaveFileName(self, 'Save file',
                                               './screenshot.png',
                                               '*.png;;*.jpg')
        if len(filename[0]) == 0:
            return
        else:
            self.saveScreenshot(False, filename[0], filename[1][2:])
            self.close()

    def close(self):
        self.widget_closed.emit()
        super().close()
        self.tooBar.close()
        if self.penSetBar is not None:
            self.penSetBar.close()

    def saveToClipboard(self):
        QApplication.clipboard().setText('Test in save function')

        self.saveScreenshot(True)
        self.close()

    # slots
    def changeAction(self, nextAction):
        QApplication.clipboard().setText('Test in changeAction function')

        if nextAction == ACTION_UNDO:
            self.undoOperation()
        elif nextAction == ACTION_SAVE:
            self.saveOperation()
        elif nextAction == ACTION_CANCEL:
            self.close()
        elif nextAction == ACTION_SURE:
            self.saveToClipboard()

        else:
            self.action = nextAction

        self.setFocus()

    def changePenSize(self, nextPenSize):
        self.penSizeNow = nextPenSize

    def changePenColor(self, nextPenColor):
        self.penColorNow = nextPenColor

    def cancelInput(self):
        self.drawListProcess = None
        self.textPosition = None
        self.textRect = None
        self.textInput.hide()
        self.textInput.clearText()
        self.redraw()

    def okInput(self):
        self.text = self.textInput.getText()
        self.drawListResult.append([
            ACTION_TEXT,
            str(self.text),
            QFont(self.fontNow),
            QPoint(self.textPosition),
            QColor(self.penColorNow)
        ])
        self.textPosition = None
        self.textRect = None
        self.textInput.hide()
        self.textInput.clearText()
        self.redraw()

    def changeFont(self, font):
        self.fontNow = font
Пример #14
0
class MyImageViewer(QMainWindow):
    def __init__(self, filename):
        super(MyImageViewer, self).__init__()

        self.filename = filename
        self.goTo = 0
        self.frameIdx = 0
        self.doZoom = False
        self.showOverlay = True

        self.imageFile = ImageFile(self.filename)
        self.initUI()
        self.updateUI()

    def prevFrame(self):
        if self.frameIdx > 0:
            self.frameIdx -= 1
            self.updateUI()

    def nextFrame(self):
        if self.frameIdx < self.imageFile.frameMax:
            self.frameIdx += 1
            self.updateUI()

    def firstFrame(self):
        self.frameIdx = 0
        self.updateUI()

    def lastFrame(self):
        self.frameIdx = self.imageFile.frameMax
        self.updateUI()

    def toggleZoom(self):
        self.doZoom = not self.doZoom
        self.updateUI()

    def toggleOverlay(self):
        self.showOverlay = not self.showOverlay
        # don't recenter since we're not changing the frame
        self.updateUI(updateCenter=False)

    def keyPressEvent(self, e):
        # tab key toggles overlay
        if e.key() == 16777217:
            self.toggleOverlay()
        # enter key goes to number entered
        elif e.key() == 16777220:
            if self.goTo >= 0 and self.goTo <= self.imageFile.frameMax:
                self.frameIdx = self.goTo
                self.updateUI()
            self.goTo = 0
        # ascii characters
        elif e.key() < 128:
            # number keys: store digits to build number of goto frame
            if chr(e.key()).isnumeric():
                self.goTo = 10 * self.goTo + int(chr(e.key()))
            # z toggles zoom
            elif chr(e.key()) == 'Z':
                self.toggleZoom()
            else:
                #print("key:",e.key())
                pass

    def updateUI(self, updateCenter=True):
        self.pixmap.setPixmap(self.getFramePixmap(self.frameIdx))
        outlineBox = self.imageFile.box(
            self.imageFile.findCenterOfMass(self.frameIdx))
        if self.boxRect: self.boxRect.setRect(*outlineBox)
        if self.doZoom:
            self.view.resetTransform()
            self.view.scale(2, 2)
            if updateCenter:
                self.view.centerOn(
                    *self.imageFile.findCenterOfMass(self.frameIdx))
        else:
            self.view.resetTransform()
        self.setWindowTitle(
            "%s... [%d/%d]" %
            (self.filename[:20], self.frameIdx, self.imageFile.frameMax))

    def getFramePixmap(self, i):
        image = QtGui.QImage(self.imageFile.getFrame(i, self.showOverlay),
                             self.imageFile.imgH, self.imageFile.imgW,
                             QtGui.QImage.Format_ARGB32)
        return QtGui.QPixmap.fromImage(image)

    def initUI(self):
        self.scene = QGraphicsScene()
        self.pixmap = QGraphicsPixmapItem()
        self.scene.addItem(self.pixmap)

        self.boxRect = None
        # option to draw box around overlay spots
        if False:
            outlineBox = self.imageFile.box(
                self.imageFile.findCenterOfMass(self.frameIdx))
            self.scene.addRect(QRect(*outlineBox),
                               pen=QtGui.QPen(QtCore.Qt.blue, 1))
            self.boxRect = self.scene.items()[
                0]  # not the best way to get rect

        self.view = MyGraphicsView(self)
        self.view.setDragMode(QGraphicsView.ScrollHandDrag)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setScene(self.scene)

        self.setCentralWidget(self.view)

        controlDock = QDockWidget()
        controlDock.setFeatures(QDockWidget.NoDockWidgetFeatures)
        self.addDockWidget(Qt.TopDockWidgetArea, controlDock)

        main_layout = QHBoxLayout()
        main_layout.setContentsMargins(0, 0, 0, 0)
        # first frame button
        firstButton = QPushButton('<<', self)
        firstButton.clicked.connect(self.firstFrame)
        main_layout.addWidget(firstButton)
        # previous frame button
        prevButton = QPushButton('<', self)
        prevButton.clicked.connect(self.prevFrame)
        main_layout.addWidget(prevButton)
        # next frame button
        nextButton = QPushButton('>', self)
        nextButton.clicked.connect(self.nextFrame)
        main_layout.addWidget(nextButton)
        # last frame button
        lastButton = QPushButton('>>', self)
        lastButton.clicked.connect(self.lastFrame)
        main_layout.addWidget(lastButton)
        # zoom button
        zoomButton = QPushButton('zoom', self)
        zoomButton.clicked.connect(self.toggleZoom)
        main_layout.addWidget(zoomButton)
        # zoom button
        overlayButton = QPushButton('color', self)
        overlayButton.clicked.connect(self.toggleOverlay)
        main_layout.addWidget(overlayButton)
        # add dock widget
        dockContainerWidget = QWidget(controlDock)
        dockContainerWidget.setLayout(main_layout)
        dockContainerWidget.setGeometry(0, 0, self.imageFile.imgW, 20)

        self.setFixedSize(self.imageFile.imgW,
                          self.imageFile.imgH + dockContainerWidget.height())
        self.show()
Пример #15
0
class QTraceViewer(QWidget):
    """
    Load a basic block trace through json and visualize it in the disassembly
    Ref: https://github.com/angr/angr-management/pull/122
    """

    TAG_SPACING = 50
    LEGEND_X = -50
    LEGEND_Y = 0
    LEGEND_WIDTH = 10

    TRACE_FUNC_X = 0
    TRACE_FUNC_Y = 0
    TRACE_FUNC_WIDTH = 50
    TRACE_FUNC_MINHEIGHT = 1000

    TAB_HEADER_SIZE = 40
    MAX_WINDOW_SIZE = 500

    MARK_X = LEGEND_X
    MARK_WIDTH = TRACE_FUNC_X - LEGEND_X + TRACE_FUNC_WIDTH
    MARK_HEIGHT = 1

    def __init__(self, workspace, disasm_view, parent=None):
        super().__init__(parent=parent)
        self.workspace = workspace
        self.disasm_view = disasm_view

        self.mark = None
        self.legend = None
        self.legend_height = 0
        self.legend_img = None
        self.trace_func_unit_height = 0

        self.trace_func = None
        self.trace_id = None

        self.view = None
        self.traceView = None
        self.traceTab = None
        self.traceScene = None
        self.multiView = None
        self.listView = None
        self.mark = None
        self.curr_position = 0
        self._use_precise_position = False
        self._selected_traces = []

        self._init_widgets()

        self.trace.am_subscribe(self._on_set_trace)
        self.selected_ins.am_subscribe(self._on_select_ins)
        self.traceTab.installEventFilter(self)

    #
    # Forwarding properties
    #

    @property
    def trace(self):
        return self.workspace.instance.trace

    @property
    def multi_trace(self):
        return self.workspace.instance.multi_trace

    @property
    def selected_ins(self):
        return self.disasm_view.infodock.selected_insns

    def _init_widgets(self):
        self.view = QTabWidget()  # QGraphicsView()

        self.traceTab = QWidget()
        tracelayout = QVBoxLayout()

        self.traceView = QGraphicsView()
        self.traceScene = QGraphicsScene()
        self.traceView.setScene(self.traceScene)

        self.listView = QTableWidget(0, 2)  # row, col
        self.listView.setHorizontalHeaderItem(0, QTableWidgetItem("Trace ID"))
        self.listView.setHorizontalHeaderItem(1, QTableWidgetItem("Input ID"))
        self.listView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.listView.setSelectionBehavior(QAbstractItemView.SelectRows)
        # self.listView.horizontalHeader().setStretchLastSection(True)
        # self.listView.horizontalHeader().setSectionResizeModel(0, QHeaderView.Stretch)
        self.listView.cellClicked.connect(self._switch_current_trace)

        self.traceSeedButton = QPushButton("View Input Seed")
        self.traceSeedButton.clicked.connect(self._view_input_seed)

        tracelayout.addWidget(self.traceView)
        tracelayout.addWidget(self.listView)
        tracelayout.addWidget(self.traceSeedButton)
        self.traceTab.setLayout(tracelayout)

        self.multiView = QWidget()
        multiLayout = QVBoxLayout()
        self.multiTraceList = QTableWidget(0, 2)  # row, col
        self.multiTraceList.setSelectionMode(QAbstractItemView.MultiSelection)
        self.multiTraceList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.multiTraceList.setHorizontalScrollMode(
            self.multiTraceList.ScrollPerPixel)
        self.multiTraceList.setHorizontalHeaderItem(
            0, QTableWidgetItem("Trace ID"))
        self.multiTraceList.setHorizontalHeaderItem(
            1, QTableWidgetItem("Input ID"))
        self.selectMultiTrace = QPushButton("Refresh Heatmap")
        self.selectMultiTrace.clicked.connect(self._refresh_heatmap)
        multiLayout.addWidget(self.multiTraceList)
        multiLayout.addWidget(self.selectMultiTrace)
        self.multiView.setLayout(multiLayout)

        self.view.addTab(self.traceTab, "SingleTrace")
        self.view.addTab(self.multiView, "MultiTrace HeatMap")
        self.SINGLE_TRACE = 0
        self.MULTI_TRACE = 1

        self.view.currentChanged.connect(self._on_tab_change)

        self._reset()

        layout = QVBoxLayout()
        layout.addWidget(self.view)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setAlignment(self.view, Qt.AlignLeft)

        self.setLayout(layout)

    def _reset(self):
        self.traceScene.clear()  #clear items
        self.listView.clearContents()
        self.multiTraceList.clearContents()
        self.mark = None

        self.legend = None
        self.legend_height = 0

        self.trace_func = QGraphicsItemGroup()
        self.trace_id = QGraphicsItemGroup()
        self.traceScene.addItem(self.trace_func)
        self.hide()

    def _view_input_seed(self):
        current_trace_stats = self.trace.am_obj
        input_id = current_trace_stats.input_id

        inputSeed = self.multi_trace.am_obj.get_input_seed_for_id(input_id)
        msgText = "%s" % inputSeed
        msgDetails = "Input for [%s]" % current_trace_stats.id
        msgbox = QMessageBox()
        msgbox.setWindowTitle("Seed Input")
        msgbox.setDetailedText(msgDetails)
        msgbox.setText(msgText)
        msgbox.setStandardButtons(QMessageBox.Ok)
        msgbox.exec()

    def _switch_current_trace(self, row):
        if self.listView.rowCount() <= 0:
            return

        current_trace = self.trace.am_obj.id
        new_trace = self.multiTraceList.item(row, 0).text()
        if current_trace == new_trace:
            return

        trace_stats = self.multi_trace.am_obj.get_trace_with_id(new_trace)
        if trace_stats:
            self.trace.am_obj = trace_stats
            self._on_set_trace()

    def _on_set_trace(self):
        self._reset()
        if self.trace.am_none or self.trace.count is None:
            return

        l.debug('minheight: %d, count: %d', self.TRACE_FUNC_MINHEIGHT,
                self.trace.count)
        if self.trace.count <= 0:
            l.warning(
                "No valid addresses found in trace to show. Check base address offsets?"
            )
            self.trace.am_obj = None
            self.trace.am_event()
            return
        if self.TRACE_FUNC_MINHEIGHT < self.trace.count * 15:
            self.trace_func_unit_height = 15
            show_func_tag = True
        else:
            self.trace_func_unit_height = self.TRACE_FUNC_MINHEIGHT / self.trace.count
            show_func_tag = True

        self.legend_height = int(self.trace.count *
                                 self.trace_func_unit_height)

        self._show_trace_func(show_func_tag)
        self._show_legend()
        self._show_trace_ids()
        self._set_mark_color()
        self._refresh_multi_list()

        boundingSize = self.traceScene.itemsBoundingRect().width()
        windowSize = boundingSize
        if boundingSize > self.MAX_WINDOW_SIZE:
            windowSize = self.MAX_WINDOW_SIZE
        self.traceScene.setSceneRect(
            self.traceScene.itemsBoundingRect())  #resize
        self.setFixedWidth(windowSize)

        # self.listScene.setSceneRect(self.listScene.itemsBoundingRect()) #resize
        self.multiView.setFixedWidth(windowSize)
        cellWidth = windowSize // 2
        self.listView.setColumnWidth(0, cellWidth)
        self.listView.setColumnWidth(1, cellWidth)
        self.listView.setFixedHeight(self.multiView.height() // 4)
        self.multiTraceList.setColumnWidth(0, cellWidth)
        self.multiTraceList.setColumnWidth(1, cellWidth)
        self.view.setFixedWidth(windowSize)

        self.show()

    def _populate_trace_table(self, view, trace_ids):
        numIDs = len(trace_ids)
        view.clearContents()
        view.setRowCount(numIDs)
        row = 0  #start after label row
        for traceID in trace_ids:
            inputID = self.multi_trace.am_obj.get_input_id_for_trace_id(
                traceID)
            if inputID is None:
                self.workspace.log("No inputID found for trace %s" % traceID)
            view.setItem(row, 0, QTableWidgetItem(traceID))
            view.setItem(row, 1, QTableWidgetItem(inputID))
            row += 1

    def _refresh_heatmap(self):
        multiTrace = self.multi_trace.am_obj
        multiTrace.clear_heatmap()
        multiTrace.is_active_tab = True

        selected_items = self.multiTraceList.selectedItems()
        self._selected_traces.clear()
        for row in range(self.multiTraceList.rowCount()):
            item = self.multiTraceList.item(row, 0)
            if item in selected_items:
                self._selected_traces.append(item.text())
        multiTrace.reload_heatmap(self._selected_traces)
        self.multi_trace.am_event()

    def _refresh_multi_list(self):
        multiTrace = self.multi_trace.am_obj
        trace_ids = multiTrace.get_all_trace_ids()

        self.multiTraceList.clearContents()
        self._populate_trace_table(self.multiTraceList, trace_ids)
        if self._selected_traces and self.multiTraceList.rowCount() > 0:
            self.multiTraceList.item(0, 0).setSelected(True)
            self.multiTraceList.item(0, 1).setSelected(True)
        else:
            for row in range(self.multiTraceList.rowCount()):
                item = self.multiTraceList.item(row, 0)
                inputItem = self.multiTraceList.item(row, 1)
                if item.text() in self._selected_traces:
                    item.setSelected(True)
                    inputItem.setSelected(True)
        self.multi_trace.am_event()

    def _on_tab_change(self):
        # self._reset()
        multiTrace = self.multi_trace.am_obj
        if self.view.currentIndex() == self.MULTI_TRACE:
            multiTrace.is_active_tab = True
            self._refresh_multi_list()
        elif self.view.currentIndex() == self.SINGLE_TRACE:
            multiTrace = self.multi_trace.am_obj
            multiTrace.is_active_tab = False
            self._show_trace_ids()

    def _on_select_ins(self, **kwargs):  # pylint: disable=unused-argument
        if self.trace.am_none:
            return

        if self.mark is not None:
            for i in self.mark.childItems():
                self.mark.removeFromGroup(i)
                self.traceScene.removeItem(i)
            self.traceScene.removeItem(self.mark)

        self.mark = QGraphicsItemGroup()
        self.traceScene.addItem(self.mark)

        if self.selected_ins:
            addr = next(iter(self.selected_ins))
            positions = self.trace.get_positions(addr)
            if positions:  #if addr is in list of positions
                if not self._use_precise_position:  #handle case where insn was selected from disas view
                    self.curr_position = positions[0] - self.trace.count
                for p in positions:
                    color = self._get_mark_color(p, self.trace.count)
                    y = self._get_mark_y(p)

                    if p == self.trace.count + self.curr_position:  #add thicker line for 'current' mark
                        self.mark.addToGroup(
                            self.traceScene.addRect(self.MARK_X, y,
                                                    self.MARK_WIDTH,
                                                    self.MARK_HEIGHT * 4,
                                                    QPen(QColor('black')),
                                                    QBrush(color)))
                    else:
                        self.mark.addToGroup(
                            self.traceScene.addRect(self.MARK_X, y,
                                                    self.MARK_WIDTH,
                                                    self.MARK_HEIGHT,
                                                    QPen(color),
                                                    QBrush(color)))

                self.traceScene.update()  #force redraw of the traceScene
                self.scroll_to_position(self.curr_position)

    def scroll_to_position(self, position):
        relative_pos = self.trace.count + position
        y_offset = self._get_mark_y(relative_pos)

        scrollValue = 0
        if y_offset > 0.5 * self.traceView.size().height():
            scrollValue = y_offset - 0.5 * self.traceView.size().height()
        scrollValue = min(scrollValue,
                          self.traceView.verticalScrollBar().maximum())
        self.traceView.verticalScrollBar().setValue(scrollValue)
        self._use_precise_position = False

    def jump_next_insn(self):
        if self.curr_position + self.trace.count < self.trace.count - 1:  #for some reason indexing is done backwards
            self.curr_position += 1
            self._use_precise_position = True
            bbl_addr = self.trace.get_bbl_from_position(self.curr_position)
            func = self.trace.get_func_from_position(self.curr_position)
            self._jump_bbl(func, bbl_addr)

    def jump_prev_insn(self):
        if self.curr_position + self.trace.count > 0:
            self.curr_position -= 1
            self._use_precise_position = True
            bbl_addr = self.trace.get_bbl_from_position(self.curr_position)
            func = self.trace.get_func_from_position(self.curr_position)
            self._jump_bbl(func, bbl_addr)

    def eventFilter(self, obj, event):  #specifically to catch arrow keys #pylint: disable=unused-argument
        # more elegant solution to link w/ self.view's scroll bar keypressevent?
        if event.type() == QEvent.Type.KeyPress:
            if not event.modifiers() & Qt.ShiftModifier:  #shift + arrowkeys
                return False
            key = event.key()
            if key in [Qt.Key_Up, Qt.Key_Left]:
                self.jump_prev_insn()
            elif key in [Qt.Key_Down, Qt.Key_Right]:
                self.jump_next_insn()
            return True

        return False  # pass through all other events

    def mousePressEvent(self, event):
        button = event.button()
        pos = self._to_logical_pos(event.pos())
        if button == Qt.LeftButton and self.view.currentIndex(
        ) == self.SINGLE_TRACE and self._at_legend(pos):
            func = self._get_func_from_y(pos.y())
            bbl_addr = self._get_bbl_from_y(pos.y())
            self._use_precise_position = True
            self.curr_position = self._get_position(pos.y())
            self._jump_bbl(func, bbl_addr)

    def _jump_bbl(self, func, bbl_addr):
        all_insn_addrs = self.workspace.instance.project.factory.block(
            bbl_addr).instruction_addrs
        # TODO: replace this with am_events perhaps?
        if func is None:
            return
        self.workspace.on_function_selected(func)
        self.selected_ins.clear()
        self.selected_ins.update(all_insn_addrs)
        self.selected_ins.am_event()
        # TODO: this ought to happen automatically as a result of the am_event
        self.disasm_view.current_graph.show_instruction(bbl_addr)

    def _get_mark_color(self, i, total):
        relative_gradient_pos = i * 1000 // total
        return self.legend_img.pixelColor(self.LEGEND_WIDTH // 2,
                                          relative_gradient_pos)

    def _get_mark_y(self, i):
        return self.TRACE_FUNC_Y + self.trace_func_unit_height * i

    def _show_trace_ids(self):
        trace_ids = self.multi_trace.get_all_trace_ids()
        # traceID = self.listScene.addText(id_txt, QFont("Source Code Pro", 7))
        # traceID.setPos(5,5)
        self.listView.clearContents()
        self._populate_trace_table(self.listView, trace_ids)
        if len(self.listView.selectedItems()) <= 0 and not self.trace.am_none:
            for row in range(self.listView.rowCount()):
                item = self.listView.item(row, 0)
                inputItem = self.listView.item(row, 1)
                if self.trace.id in item.text():
                    item.setSelected(True)
                    inputItem.setSelected(True)
                    break

    def _show_trace_func(self, show_func_tag):
        x = self.TRACE_FUNC_X
        y = self.TRACE_FUNC_Y
        prev_name = None
        for position in self.trace.trace_func:
            bbl_addr = position.bbl_addr
            func_name = position.func_name
            l.debug('Draw function %x, %s', bbl_addr, func_name)
            color = self.trace.get_func_color(func_name)
            self.trace_func.addToGroup(
                self.traceScene.addRect(x, y, self.TRACE_FUNC_WIDTH,
                                        self.trace_func_unit_height,
                                        QPen(color), QBrush(color)))
            if show_func_tag is True and func_name != prev_name:
                tag = self.traceScene.addText(func_name,
                                              QFont("Source Code Pro", 7))
                tag.setPos(x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING,
                           y - tag.boundingRect().height() // 2)
                self.trace_func.addToGroup(tag)
                anchor = self.traceScene.addLine(
                    self.TRACE_FUNC_X + self.TRACE_FUNC_WIDTH, y,
                    x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y)
                self.trace_func.addToGroup(anchor)
                prev_name = func_name
            y += self.trace_func_unit_height

    @staticmethod
    def _make_legend_gradient(x1, y1, x2, y2):
        gradient = QLinearGradient(x1, y1, x2, y2)
        gradient.setColorAt(0.0, Qt.red)
        gradient.setColorAt(0.4, Qt.yellow)
        gradient.setColorAt(0.6, Qt.green)
        gradient.setColorAt(0.8, Qt.blue)
        gradient.setColorAt(1.0, Qt.darkBlue)
        return gradient

    def _show_legend(self):
        pen = QPen(Qt.transparent)

        gradient = self._make_legend_gradient(
            self.LEGEND_X, self.LEGEND_Y, self.LEGEND_X,
            self.LEGEND_Y + self.legend_height)
        brush = QBrush(gradient)
        self.legend = self.traceScene.addRect(self.LEGEND_X, self.LEGEND_Y,
                                              self.LEGEND_WIDTH,
                                              self.legend_height, pen, brush)

        reference_gradient = self._make_legend_gradient(
            0, 0, self.LEGEND_WIDTH, 1000)
        base_img = QImage(self.LEGEND_WIDTH, 1000, QImage.Format.Format_ARGB32)
        p = QPainter(base_img)
        p.fillRect(base_img.rect(), reference_gradient)
        self.legend_img = base_img  #reference shade

    def _set_mark_color(self):
        for p in range(self.trace.count):
            color = self._get_mark_color(p, self.trace.count)
            self.trace.set_mark_color(p, color)

    def _at_legend(self, pos):
        x = pos.x()
        y = pos.y()
        return self.TRACE_FUNC_X + self.LEGEND_X < x < self.traceView.width() and \
           self.TRACE_FUNC_Y < y < self.TRACE_FUNC_Y + self.legend_height

    def _to_logical_pos(self, pos):
        x_offset = self.traceView.horizontalScrollBar().value()
        y_offset = self.traceView.verticalScrollBar().value()
        return QPoint(pos.x() + x_offset, pos.y() + y_offset)

    def _get_position(self, y):
        y_relative = y - self.legend_height - self.TAB_HEADER_SIZE

        return int(y_relative // self.trace_func_unit_height)

    def _get_bbl_from_y(self, y):
        position = self._get_position(y)
        return self.trace.get_bbl_from_position(position)

    def _get_func_from_y(self, y):
        position = self._get_position(y)
        func = self.trace.get_func_from_position(position)
        return func
Пример #16
0
class LabelingWidget(QGraphicsView):
    def __init__(self):
        super().__init__()

        self._tag_brushes = []
        self._tag_brushes.append(QBrush(QColor(0, 0, 0, 0)))
        self._tag_brushes.append(QBrush(QColor(255, 0, 0, 90)))

        self._image_item = QGraphicsPixmapItem()
        self._create_default_scene()

        self.setScene(self._scene)

    def _create_default_scene(self):
        self._scene = QGraphicsScene()

        self._scene.addItem(self._image_item)

        line_pen = QPen(Qt.black, 2)
        for i in range(LABELING_TAG_WIDTH + 1):
            self._scene.addLine(i * LABELING_STEP, 0, i * LABELING_STEP,
                                LABELING_HEIGHT, line_pen)

        for i in range(LABELING_TAG_HEIGHT + 1):
            self._scene.addLine(0, i * LABELING_STEP, LABELING_WIDTH,
                                i * LABELING_STEP, line_pen)

        self._tags = np.zeros((LABELING_TAG_HEIGHT, LABELING_TAG_WIDTH),
                              dtype=int)
        self._tags_items = []

        tag_pen = QPen(Qt.black, 0)
        for i in range(LABELING_TAG_HEIGHT):
            tags = []
            for j in range(LABELING_TAG_WIDTH):
                item = self._scene.addRect(j * LABELING_STEP,
                                           i * LABELING_STEP, LABELING_STEP,
                                           LABELING_STEP, tag_pen,
                                           self._tag_brushes[0])
                tags.append(item)

            self._tags_items.append(tags)

    def _update_tags(self):
        for i in range(LABELING_TAG_HEIGHT):
            for j in range(LABELING_TAG_WIDTH):
                self._tags_items[i][j].setBrush(
                    self._tag_brushes[self._tags[i, j]])

    def set_image(self, path):
        self._image_item.setPixmap(QPixmap(path))

    def clear(self):
        self._tags[:, :] = 0
        self._update_tags()

    def get_tags(self):
        return self._tags.copy()

    def set_tags(self, tags):
        if tags.shape[0] != LABELING_TAG_HEIGHT or tags.shape[
                1] != LABELING_TAG_WIDTH:
            raise ValueError('Wrong tags shape')

        self._tags = tags.copy()
        self._update_tags()

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.fitInView(self._scene.sceneRect(), Qt.KeepAspectRatio)

    def mousePressEvent(self, event):
        point = self.mapToScene(event.pos())
        index_x = int(point.x() / LABELING_STEP)
        index_y = int(point.y() / LABELING_STEP)

        if event.buttons() & Qt.LeftButton != 0:
            self._tags[index_y, index_x] = 1
        elif event.buttons() & Qt.RightButton != 0:
            self._tags[index_y, index_x] = 0

        self._update_tags()

    def mouseMoveEvent(self, event):
        point = self.mapToScene(event.pos())
        index_x = int(point.x() / LABELING_STEP)
        index_y = int(point.y() / LABELING_STEP)

        if event.buttons() & Qt.LeftButton != 0:
            self._tags[index_y, index_x] = 1
        elif event.buttons() & Qt.RightButton != 0:
            self._tags[index_y, index_x] = 0

        self._update_tags()
Пример #17
0
            self.mapToParent(-(self.boundingRect().width()),
                             -(self.boundingRect().width() + 2)))

        if not self.scene().sceneRect().contains((newPoint)):
            print('move to 0, 0')
            newPoint = self.mapToParent(0, 0)
        else:
            self.setPos(newPoint)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    scene = QGraphicsScene(QRectF(-200, -200, 300, 300))

    view = QGraphicsView()
    view.setRenderHint(QPainter.Antialiasing)
    boundaryPen = QPen(Qt.red)
    scene.addRect(scene.sceneRect())

    itemCount = 20
    for i in range(0, itemCount):
        item = MyItem()
        scene.addItem(item)

    timer = QTimer()
    timer.setInterval(500)
    timer.timeout.connect(scene.advance)

    view.setScene(scene)
    view.show()
    sys.exit(app.exec_())
Пример #18
0
class AddItem(UsesQApplication):
    '''Tests for QGraphicsScene.add*'''

    qapplication = True

    def setUp(self):
        #Acquire resources
        super(AddItem, self).setUp()
        self.scene = QGraphicsScene()
        # While the scene does not inherits from QWidget, requires
        # an application to make the internals work.

    def tearDown(self):
        #Release resources
        del self.scene
        super(AddItem, self).tearDown()

    def testEllipse(self):
        #QGraphicsScene.addEllipse
        item = self.scene.addEllipse(100, 100, 100, 100)
        self.assertTrue(isinstance(item, QGraphicsEllipseItem))

    def testLine(self):
        #QGraphicsScene.addLine
        item = self.scene.addLine(100, 100, 200, 200)
        self.assertTrue(isinstance(item, QGraphicsLineItem))

    def testPath(self):
        #QGraphicsScene.addPath
        item = self.scene.addPath(QPainterPath())
        self.assertTrue(isinstance(item, QGraphicsPathItem))

    def testPixmap(self):
        #QGraphicsScene.addPixmap
        item = self.scene.addPixmap(QPixmap())
        self.assertTrue(isinstance(item, QGraphicsPixmapItem))

    def testPolygon(self):
        #QGraphicsScene.addPolygon
        points = [QPointF(0, 0), QPointF(100, 100), QPointF(0, 100)]
        item = self.scene.addPolygon(QPolygonF(points))
        self.assertTrue(isinstance(item, QGraphicsPolygonItem))

    def testRect(self):
        #QGraphicsScene.addRect
        item = self.scene.addRect(100, 100, 100, 100)
        self.assertTrue(isinstance(item, QGraphicsRectItem))

    def testSimpleText(self):
        #QGraphicsScene.addSimpleText
        item = self.scene.addSimpleText('Monty Python 42')
        self.assertTrue(isinstance(item, QGraphicsSimpleTextItem))

    def testText(self):
        #QGraphicsScene.addText
        item = self.scene.addText('Monty Python 42')
        self.assertTrue(isinstance(item, QGraphicsTextItem))

    def testWidget(self):
        #QGraphicsScene.addWidget
        # XXX: printing some X11 error when using under PyQt4
        item = self.scene.addWidget(QPushButton())
        self.assertTrue(isinstance(item, QGraphicsProxyWidget))
Пример #19
0
class BarrenLandsWindow(QMainWindow):
    """User interface to interact with the barren lands library."""
    def __init__(self, width=400, height=600, zones=None):
        """Initialization of BarrenLands GUI

        Args:
            width (int): The width of the canvas/field.
            height (int): The height of the canvas/field.
            zones (str): Text data to add to raw input if provided.
        """
        QMainWindow.__init__(self)
        self.app = QApplication.instance()
        self.resources = pathlib.Path(__file__).parent
        self.results = set()
        self.canvas_width = width
        self.canvas_height = height
        self.user_input = zones
        # Colors for drawing onto the QGraphicsScene
        self.brush_barren = QBrush(QColor(120, 120, 75), Qt.Dense2Pattern)
        self.brush_overlay = QBrush(QColor(20, 20, 20, 35), Qt.SolidPattern)
        self.brush_innerlay = QBrush(QColor(32, 37, 44), Qt.SolidPattern)
        self.brush_fertile = QBrush(QColor(90, 220, 90, 150), Qt.Dense5Pattern)
        self.brush_fertile_no_go = QBrush(QColor(90, 220, 90, 150),
                                          Qt.BDiagPattern)

        # Setup the filed class that will handle our calculations.
        self.field = land.Field(width=self.canvas_width,
                                height=self.canvas_height)
        self.barren_zones = list()
        self.fertile_zones = list()

        self.setup_window()
        self.build_core_ui()
        self.build_controls()

    def setup_window(self):
        """Setup all the window related settings/flags."""
        self.setWindowTitle("Barren Lands")
        self.setMinimumHeight(600)
        self.setMinimumWidth(700)
        self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
        self.setWindowIcon(QIcon(utils.get_icon()))
        self.setStyleSheet(utils.get_css())

    def build_core_ui(self):
        """Sets up the core elements of this window.

        Notes:
            Setting up QGraphicsScene:
                https://stackoverflow.com/questions/23174481/pyside-qt-layout-not-working
        """
        self.base_widget = QWidget(self)
        self.layout_base = QHBoxLayout(self.base_widget)
        self.layout_canvas = QVBoxLayout()
        self.setContentsMargins(0, 0, 0, 0)
        # Setup the QGraphics items to display out zones as active elements.
        scene_zone = QRect(0, 0, self.canvas_width, self.canvas_height)
        self.scene = QGraphicsScene(scene_zone, self)
        self.canvas = QGraphicsView(self.scene, self)
        self.canvas.setFixedSize(self.canvas_width + 1, self.canvas_height + 1)
        # Draw faint bullseye for target.
        self.scene.addEllipse(self.get_center_rect(300), Qt.NoPen,
                              self.brush_overlay)
        self.scene.addEllipse(self.get_center_rect(200), Qt.NoPen,
                              self.brush_innerlay)
        self.scene.addEllipse(self.get_center_rect(100), Qt.NoPen,
                              self.brush_overlay)
        self.layout_canvas.addWidget(self.canvas)
        self.lbl_island = QLabel("Island Areas:")
        self.layout_canvas.addWidget(self.lbl_island)
        self.layout_base.addLayout(self.layout_canvas)
        # Set the core widget to the window.
        self.setCentralWidget(self.base_widget)

    def get_center_rect(self, size):
        """Generates a QRect that is at the center of the canvas and it's width/height set to size.

        Args:
            size (int): The size to set the bounds to.

        Returns:
            (QRectF): A rectangle coordinate that is center on the canvas with a given size.
        """
        return QRectF(self.canvas_width * 0.5 - (size * 0.5),
                      self.canvas_height * 0.5 - (size * 0.5), size, size)

    def build_controls(self):
        """Build the control panel that contains all the inputs."""
        self.controls = QWidget(self)
        self.layout_controls = QVBoxLayout(self.controls)
        self.layout_controls.setContentsMargins(0, 0, 0, 0)
        # Initialize the text box for user input
        self.input = self.build_coord_input()
        # Create the buttons
        self.btn_add_bzone = BarrenButton(label="Add",
                                          parent=self,
                                          cmd=self.ctl_add_input)
        self.btn_run = BarrenButton(label="Analyze",
                                    parent=self,
                                    cmd=self.ctl_run)
        # Build the utility buttons
        self.layout_btm_btn = QHBoxLayout()
        self.layout_btm_btn.setContentsMargins(0, 0, 0, 0)
        self.btn_reset = BarrenButton(label="Reset All",
                                      parent=self,
                                      cmd=self.ctl_clear_zones)
        self.btn_debug = BarrenButton(label="Debug",
                                      parent=self,
                                      cmd=self.ctr_debug)
        self.layout_btm_btn.addWidget(self.btn_debug)
        self.layout_btm_btn.addWidget(self.btn_reset)
        self.results_grp = self.build_results_group()
        self.lbl_area = QLabel("Total Area: 0")
        self.lbl_area.setAlignment(Qt.AlignCenter)
        # Add everything to the controls layout
        self.layout_controls.addLayout(self.input)
        self.layout_controls.addWidget(self.btn_add_bzone)
        self.layout_controls.addWidget(self.btn_run)
        self.layout_controls.addWidget(self.results_grp)
        self.layout_controls.addWidget(self.lbl_area)
        self.layout_controls.addLayout(self.layout_btm_btn)
        # Add to the windows base layout.
        self.layout_base.addWidget(self.controls)

    def build_results_group(self):
        """Build the results group to contain the results of analysis.

        Returns:
            results_grp (QGroupBox): The group box that contains the results layout.
        """
        grp_results = QGroupBox("Results: Largest island zone.")
        grp_results.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        # Add a layout to hold all the results from the Analysis.
        self.layout_results = QVBoxLayout()
        self.layout_results.setContentsMargins(0, 0, 0, 0)
        grp_results.setLayout(self.layout_results)
        return grp_results

    def build_coord_input(self):
        """Build the necessary elements for the user input text box.

        Returns:
            (QVBoxLayout): The base layout of the coord input.
        """
        layout_base = QVBoxLayout()
        layout_base.setContentsMargins(0, 0, 0, 0)
        self.raw_input = QPlainTextEdit()
        self.raw_input.setMaximumHeight(75)
        self.raw_input.setPlaceholderText('example: "0 292 399 307"')
        if self.user_input:
            self.raw_input.setPlainText(self.user_input)
        self.layout_input = QVBoxLayout()
        self.layout_input.setContentsMargins(0, 0, 0, 0)
        layout_base.addWidget(self.raw_input)
        layout_base.addLayout(self.layout_input)
        return layout_base

    def ctr_debug(self):
        """CONTROL: Called by the 'debug' button to randomly assign colors to the zones."""
        for result in self.results:
            rand_color = [random.randint(0, 255) for i in range(3)]
            rand_color = QColor(*rand_color)
            brush = QBrush(rand_color, Qt.Dense5Pattern)
            result.rectangle.setBrush(brush)
            result.base = brush

    def ctl_add_input(self):
        """CONTROL: Called by the 'Add' button to handle parsing the raw input."""
        raw_data = self.raw_input.toPlainText()
        if raw_data:
            parsed_input = utils.format_raw_input(raw_data)
            for user_input in parsed_input:
                start_coord = land.Coord(user_input[0], user_input[1])
                end_coord = land.Coord(user_input[2], user_input[3])
                zone = land.Zone(start_coord, end_coord)
                self.field.add_zone(zone, barren=True)
                self.draw_zone(zone, barren=True)

    def ctl_run(self):
        """CONTROL: Called by the 'Run' button to initialize the final analysis."""
        # Make sure some values are cleared ahead of the analysis.
        self.clear_results()
        for rectangle in self.fertile_zones:
            self.scene.removeItem(rectangle)
        self.field.fertile_zones = set()

        # Run the analysis
        self.field.check_zones()
        total_area = 0
        # Format and draw the results in the QGraphicsScene.
        for i, island in enumerate(self.field.islands):
            for zone in island:
                rectangle = self.draw_zone(zone)
                size = zone.get_size()
                if i == 0:  # Only add (largest) island to results. Always at 0.
                    total_area += size
                    self.results.add(
                        ResultLabel(label=str(size),
                                    rectangle=rectangle,
                                    zone=zone))
                else:
                    # This zone is fertile, but Inaccessible.
                    rectangle.setBrush(self.brush_fertile_no_go)
                self.canvas.update()
                # Pain the update for the user to see the new zone.
                self.app.processEvents()
                # Dont show all at the same time. (For more pleasing visual)
                time.sleep(.015)

        # Print islands, smallest to largest.
        print("Islands", self.field.islands_as_area())
        island_areas = " ".join(str(i) for i in self.field.islands_as_area())
        self.lbl_island.setText(f"Island Areas: {island_areas}")
        # Set the label as the total area as the largest island.
        self.lbl_area.setText(f"Total Area: {total_area}")

        # Sort the results by their zones area.
        for result in sorted(self.results, key=lambda x: x.zone.get_size()):
            # Add the result to the results layout in the UI
            self.layout_results.addWidget(result)

    def ctl_clear_zones(self):
        """CONTROL: Called by the 'Reset' button to handle resetting the data and graphics."""
        for rectangle in self.barren_zones + self.fertile_zones:
            self.scene.removeItem(rectangle)
        self.field.fertile_zones = set()
        self.fertile_zones = list()
        self.field.barren_zones = set()
        self.barren_zones = list()
        self.clear_results()

    def clear_results(self):
        """Clears the results set in preparation for incoming new results."""
        for result in self.results:
            result.deleteLater()
        self.results = set()
        self.lbl_area.setText("Total Area:")
        self.lbl_island.setText("Island Areas:")

    def draw_zone(self, zone, barren=False):
        """Creates a QGraphicsRecItem from a Zone and adds it to the scene.

        Args:
            zone (Zone): The zone to generate the rectangle from.
            barren (bool): barren colors if True else fertile color.

        Returns:
            (QGraphicsRecItem): The drown rectangle that is added to the canvas.
        """
        # Build the QGraphicsRecItem from the zone data.
        rectangle = self.scene.addRect(zone.start.x, zone.start.y,
                                       zone.end.x - zone.start.x + 1,
                                       zone.end.y - zone.start.y + 1)
        if barren:
            self.barren_zones.append(rectangle)
            brush = self.brush_barren
        else:
            self.fertile_zones.append(rectangle)
            brush = self.brush_fertile
        # Apply the color to the rectangle item.
        rectangle.setBrush(brush)
        # Remove the default border
        rectangle.setPen(Qt.NoPen)
        return rectangle
Пример #20
0
class TestGUI(QMainWindow):
    def __init__(self):
        self.app = QApplication(sys.argv)
        ui_file = QFile("testgui.ui")
        ui_file.open(QFile.ReadOnly)

        loader = QUiLoader()
        self.window = loader.load(ui_file)
        ui_file.close()
        self.scene_gt = QGraphicsScene()
        self.scene_gt.setSceneRect(-2000, -3000, 4000, 6000)

        self.view_gt = QGraphicsView(self.scene_gt, self.window.scene_gt)
        self.view_gt.scale(-0.1, 0.1)

        self.view_gt.resize(self.window.scene_gt.geometry().width(),
                            self.window.scene_gt.geometry().height())

        self.personPos_gt = self.scene_gt.addEllipse(
            QRectF(-200, -200, 400, 400), QPen(QColor("LightGreen")),
            QBrush(QColor("LightGreen")))
        self.personPos_gt.setFlag(QGraphicsItem.ItemIsMovable)
        self.personPos_gt.setPos(0, 0)
        self.personAng_gt = self.scene_gt.addRect(QRectF(-10, 0, 20, 300),
                                                  QPen(QColor("Green")),
                                                  QBrush(QColor("Green")))
        self.personAng_gt.setFlag(QGraphicsItem.ItemIsMovable)
        self.personAng_gt.setPos(0, 0)

        self.scene_cc = QGraphicsScene()
        self.scene_cc.setSceneRect(-2000, -3000, 4000, 6000)

        self.view_cc = QGraphicsView(self.scene_cc, self.window.scene_cc)
        self.view_cc.scale(-0.1, 0.1)

        self.view_cc.resize(self.window.scene_cc.geometry().width(),
                            self.window.scene_cc.geometry().height())

        self.personPos_cc = self.scene_cc.addEllipse(
            QRectF(-200, -200, 400, 400), QPen(QColor("Red")),
            QBrush(QColor("Red")))
        self.personPos_cc.setFlag(QGraphicsItem.ItemIsMovable)
        self.personPos_cc.setPos(0, 0)
        self.personAng_cc = self.scene_cc.addRect(QRectF(-10, 0, 20, 300),
                                                  QPen(QColor("Black")),
                                                  QBrush(QColor("Black")))
        self.personAng_cc.setFlag(QGraphicsItem.ItemIsMovable)
        self.personAng_cc.setPos(0, 0)

        self.scene_nn = QGraphicsScene()
        self.scene_nn.setSceneRect(-2000, -3000, 4000, 6000)

        self.view_nn = QGraphicsView(self.scene_nn, self.window.scene_nn)
        self.view_nn.scale(-0.1, 0.1)

        self.view_nn.resize(self.window.scene_nn.geometry().width(),
                            self.window.scene_nn.geometry().height())

        self.personPos_nn = self.scene_nn.addEllipse(
            QRectF(-200, -200, 400, 400), QPen(QColor("LightBlue")),
            QBrush(QColor("LightBlue")))
        self.personPos_nn.setFlag(QGraphicsItem.ItemIsMovable)
        self.personPos_nn.setPos(0, 0)
        self.personAng_nn = self.scene_nn.addRect(QRectF(-10, 0, 20, 300),
                                                  QPen(QColor("Blue")),
                                                  QBrush(QColor("Blue")))
        self.personAng_nn.setFlag(QGraphicsItem.ItemIsMovable)
        self.personAng_nn.setPos(0, 0)

        self.loadData(sys.argv[1])

        self.window.instantScrollBar.valueChanged.connect(self.changeInstant)

        self.it = 0
        self.timer = QTimer()
        self.timer.timeout.connect(self.compute)
        self.timer.start(150)

        self.window.show()

        r = self.app.exec_()
        sys.exit(r)

    def loadData(self, filename):
        test_dataset = graph_generator.CalibrationDataset(filename, 'run', '1')
        with open(sys.argv[1], 'r') as f:
            raw = f.read()
        raw = list(raw)

        raws = ''.join(raw)
        data = json.loads(raws)['data_set']

        model = trackerapi.TrackerAPI('.', test_dataset)

        self.x_gt = []
        self.x_cc = []
        self.x_nn = []
        self.z_gt = []
        self.z_cc = []
        self.z_nn = []
        self.a_gt = []
        self.a_cc = []
        self.a_nn = []

        try:
            with open('kk', 'rb') as f:
                results = pickle.load(f)
        except:
            results = [x for x in model.predict()]
            with open('kk', 'wb') as f:
                pickle.dump(results, f, pickle.HIGHEST_PROTOCOL)

        eX_cc = []
        eZ_cc = []
        eA_cc = []
        eX_nn = []
        eZ_nn = []
        eA_nn = []

        self.trajectory = []

        s = 0
        ang_prev = 0
        for i in range(int(len(results))):

            n_joints = 0
            for cam in range(len(data[i]['superbody'])):
                n_joints += len(data[i]['superbody'][cam]['joints'])

            if n_joints < 3:
                continue

            s += 1
            if s < 2 or s % 1 != 0:
                continue

            self.x_gt.append(data[i]['superbody'][0]['ground_truth'][0])
            self.z_gt.append(data[i]['superbody'][0]['ground_truth'][2])
            self.a_gt.append(data[i]['superbody'][0]['ground_truth'][3] *
                             180. / math.pi)

            self.trajectory.append(QPointF(self.x_gt[-1], self.z_gt[-1]))

            x_cc = 0
            z_cc = 0
            ncams = 0
            for cam in range(0, len(data[i]['superbody'])):
                x_cc += data[i]['superbody'][cam]['world'][0]
                z_cc += data[i]['superbody'][cam]['world'][2]
                ncams += 1

            self.x_cc.append(x_cc / ncams)
            self.z_cc.append(z_cc / ncams)

            s_cc = 0
            c_cc = 0
            ncams = 0
            for cam in range(0, len(data[i]['superbody'])):
                joints = data[i]['superbody'][cam]["joints"]
                if ("right_shoulder" in joints and "left_shoulder"
                        in joints) or ("right_hip" in joints
                                       and "left_hip" in joints):
                    s_cc = math.sin(data[i]['superbody'][cam]['world'][3])
                    c_cc = math.cos(data[i]['superbody'][cam]['world'][3])
                    ncams += 1

            if ncams > 0:
                a_cc = math.atan2(s_cc / ncams, c_cc / ncams)
                ang_prev = a_cc
            else:
                a_cc = ang_prev

            self.a_cc.append(a_cc * 180. / math.pi)

            self.x_nn.append(results[i][0] * 4000)
            self.z_nn.append(results[i][2] * 4000)
            self.a_nn.append(
                math.atan2(results[i][3] / 0.7, results[i][4] / 0.7) * 180. /
                math.pi)
            eX_cc.append(abs(self.x_gt[-1] - self.x_cc[-1]))
            eZ_cc.append(abs(self.z_gt[-1] - self.z_cc[-1]))
            eAng = 180 - abs(abs(self.a_gt[-1] - self.a_cc[-1]) - 180)
            if eAng < 0:
                eAng = 360 + eAng
            eA_cc.append(eAng)

            eX_nn.append(abs(self.x_gt[-1] - self.x_nn[-1].item()))
            eZ_nn.append(abs(self.z_gt[-1] - self.z_nn[-1].item()))
            eAng = 180 - abs(abs(self.a_gt[-1] - self.a_nn[-1]) - 180)
            if eAng < 0:
                eAng = 360 + eAng
            eA_nn.append(eAng)

        array_err_z = np.array(eZ_nn)
        print("len array error", len(array_err_z))

        #        self.window.eX_cc.display(np.array(eX_cc).mean())
        #        self.window.eZ_cc.display(np.array(eZ_cc).mean())
        #        self.window.eA_cc.display(np.array(eA_cc).mean())

        #        self.window.eX_nn.display(np.array(eX_nn).mean())
        #        self.window.eZ_nn.display(np.array(eZ_nn).mean())
        #        self.window.eA_nn.display(np.array(eA_nn).mean())

        self.scene_gt.addPolygon(self.trajectory, QPen(QColor("Black")))
        self.scene_cc.addPolygon(self.trajectory, QPen(QColor("Black")))
        self.scene_nn.addPolygon(self.trajectory, QPen(QColor("Black")))

        self.window.instantScrollBar.setMaximum(len(self.a_gt) - 1)

    def compute(self):
        if self.window.playButton.isChecked():
            if self.it >= len(self.x_gt):
                self.it = 0
            self.movePerson()
            self.it += 1
            self.window.instantScrollBar.setValue(self.it)

    def changeInstant(self, instant):
        self.it = instant
        self.movePerson()

    def movePerson(self):

        self.personPos_gt.setPos(self.x_gt[self.it], self.z_gt[self.it])
        self.personAng_gt.setPos(self.x_gt[self.it], self.z_gt[self.it])
        self.personAng_gt.setRotation(self.a_gt[self.it])

        self.personPos_cc.setPos(self.x_cc[self.it], self.z_cc[self.it])
        self.personAng_cc.setPos(self.x_cc[self.it], self.z_cc[self.it])
        self.personAng_cc.setRotation(self.a_cc[self.it])

        self.personPos_nn.setPos(self.x_nn[self.it], self.z_nn[self.it])
        self.personAng_nn.setPos(self.x_nn[self.it], self.z_nn[self.it])
        self.personAng_nn.setRotation(self.a_nn[self.it])
Пример #21
0
class QTraceViewer(QWidget):
    TAG_SPACING = 50
    LEGEND_X = -50
    LEGEND_Y = 0
    LEGEND_WIDTH = 10

    TRACE_FUNC_X = 0
    TRACE_FUNC_Y = 0
    TRACE_FUNC_WIDTH = 50
    TRACE_FUNC_MINHEIGHT = 1000

    MARK_X = LEGEND_X
    MARK_WIDTH = TRACE_FUNC_X - LEGEND_X + TRACE_FUNC_WIDTH
    MARK_HEIGHT = 1

    def __init__(self, workspace, disasm_view, parent=None):
        super().__init__(parent=parent)
        self.workspace = workspace
        self.disasm_view = disasm_view

        self.view = None
        self.scene = None
        self.mark = None
        self.curr_position = 0
        self._use_precise_position = False

        self._init_widgets()

        self.trace.am_subscribe(self._on_set_trace)
        self.selected_ins.am_subscribe(self._on_select_ins)
        self.view.installEventFilter(self)

    #
    # Forwarding properties
    #

    @property
    def trace(self):
        return self.workspace.instance.trace

    @property
    def selected_ins(self):
        return self.disasm_view.infodock.selected_insns

    def _init_widgets(self):
        self.view = QGraphicsView()
        self.scene = QGraphicsScene()
        self.view.setScene(self.scene)

        self._reset()

        layout = QHBoxLayout()
        layout.addWidget(self.view)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setAlignment(self.view, Qt.AlignLeft)

        self.setLayout(layout)

    def _reset(self):
        self.scene.clear()  #clear items
        self.mark = None

        self.legend = None
        self.legend_height = 0

        self.trace_func = QGraphicsItemGroup()
        self.scene.addItem(self.trace_func)
        self.hide()

    def _on_set_trace(self, **kwargs):
        self._reset()

        if self.trace.am_obj is not None:
            l.debug('minheight: %d, count: %d', self.TRACE_FUNC_MINHEIGHT,
                    self.trace.count)
            if self.trace.count <= 0:
                l.warning(
                    "No valid addresses found in trace to show. Check base address offsets?"
                )
                self.trace.am_obj = None
                self.trace.am_event()
                return
            if self.TRACE_FUNC_MINHEIGHT < self.trace.count * 15:
                self.trace_func_unit_height = 15
                show_func_tag = True
            else:
                self.trace_func_unit_height = self.TRACE_FUNC_MINHEIGHT / self.trace.count
                show_func_tag = True

            self.legend_height = int(self.trace.count *
                                     self.trace_func_unit_height)

            self._show_trace_func(show_func_tag)
            self._show_legend()
            self._set_mark_color()

            self.scene.setSceneRect(self.scene.itemsBoundingRect())  #resize
            self.setFixedWidth(self.scene.itemsBoundingRect().width())
            self.view.setFixedWidth(self.scene.itemsBoundingRect().width())

            self.show()

    def _on_select_ins(self, **kwargs):
        if self.trace == None:
            return

        if self.mark is not None:
            for i in self.mark.childItems():
                self.mark.removeFromGroup(i)
                self.scene.removeItem(i)
            self.scene.removeItem(self.mark)

        self.mark = QGraphicsItemGroup()
        self.scene.addItem(self.mark)

        if self.selected_ins:
            addr = next(iter(self.selected_ins))
            positions = self.trace.get_positions(addr)
            if positions:  #if addr is in list of positions
                if not self._use_precise_position:  #handle case where insn was selected from disas view
                    self.curr_position = positions[0] - self.trace.count
                for p in positions:
                    color = self._get_mark_color(p, self.trace.count)
                    y = self._get_mark_y(p, self.trace.count)

                    if p == self.trace.count + self.curr_position:  #add thicker line for 'current' mark
                        self.mark.addToGroup(
                            self.scene.addRect(self.MARK_X, y, self.MARK_WIDTH,
                                               self.MARK_HEIGHT * 4,
                                               QPen(QColor('black')),
                                               QBrush(color)))
                    else:
                        self.mark.addToGroup(
                            self.scene.addRect(self.MARK_X, y, self.MARK_WIDTH,
                                               self.MARK_HEIGHT, QPen(color),
                                               QBrush(color)))
                #y = self._get_mark_y(positions[0], self.trace.count)
                #self.view.verticalScrollBar().setValue(y - 0.5 * self.view.size().height())

                self.scene.update()  #force redraw of the scene
                self.scroll_to_position(self.curr_position)

    def scroll_to_position(self, position):
        relative_pos = self.trace.count + position
        y_offset = self._get_mark_y(relative_pos, self.trace.count)

        scrollValue = 0
        if y_offset > 0.5 * self.view.size().height():
            scrollValue = y_offset - 0.5 * self.view.size().height()
        scrollValue = min(scrollValue, self.view.verticalScrollBar().maximum())
        self.view.verticalScrollBar().setValue(scrollValue)
        self._use_precise_position = False

    def jump_next_insn(self):
        if self.curr_position + self.trace.count < self.trace.count - 1:  #for some reason indexing is done backwards
            self.curr_position += 1
            self._use_precise_position = True
            func_name = self.trace.trace_func[self.curr_position].func_name
            func = self._get_func_from_func_name(func_name)
            bbl_addr = self.trace.trace_func[self.curr_position].bbl_addr
            self._jump_bbl(func, bbl_addr)

    def jump_prev_insn(self):
        if self.curr_position + self.trace.count > 0:
            self.curr_position -= 1
            self._use_precise_position = True
            func_name = self.trace.trace_func[self.curr_position].func_name
            func = self._get_func_from_func_name(func_name)
            bbl_addr = self.trace.trace_func[self.curr_position].bbl_addr
            self._jump_bbl(func, bbl_addr)

    def eventFilter(self, object, event):  #specifically to catch arrow keys
        # more elegant solution to link w/ self.view's scroll bar keypressevent?
        if event.type() == QEvent.Type.KeyPress:
            if not (event.modifiers() & Qt.ShiftModifier):  #shift + arrowkeys
                return False
            key = event.key()
            if key == Qt.Key_Up or key == Qt.Key_Left:
                self.jump_prev_insn()
            elif key == Qt.Key_Down or key == Qt.Key_Right:
                self.jump_next_insn()
            return True

        return False  # pass through all other events

    def mousePressEvent(self, event):
        button = event.button()
        pos = self._to_logical_pos(event.pos())
        if button == Qt.LeftButton and self._at_legend(pos):
            func = self._get_func_from_y(pos.y())
            bbl_addr = self._get_bbl_from_y(pos.y())
            self._use_precise_position = True
            self.curr_position = self._get_position(pos.y())
            self._jump_bbl(func, bbl_addr)

    def _jump_bbl(self, func, bbl_addr):
        all_insn_addrs = self.workspace.instance.project.factory.block(
            bbl_addr).instruction_addrs
        # TODO: replace this with am_events perhaps?
        self.workspace.on_function_selected(func)
        self.selected_ins.clear()
        self.selected_ins.update(all_insn_addrs)
        self.selected_ins.am_event()
        # TODO: this ought to happen automatically as a result of the am_event
        self.disasm_view.current_graph.show_instruction(bbl_addr)

    def _get_mark_color(self, i, total):
        relative_gradient_pos = i * 1000 // total
        return self.legend_img.pixelColor(self.LEGEND_WIDTH // 2,
                                          relative_gradient_pos)

    def _get_mark_y(self, i, total):
        return self.TRACE_FUNC_Y + self.trace_func_unit_height * i

    def _show_trace_func(self, show_func_tag):
        x = self.TRACE_FUNC_X
        y = self.TRACE_FUNC_Y
        prev_name = None
        for position in self.trace.trace_func:
            bbl_addr = position.bbl_addr
            func_name = position.func_name
            l.debug('Draw function %x, %s', bbl_addr, func_name)
            color = self.trace.get_func_color(func_name)
            self.trace_func.addToGroup(
                self.scene.addRect(x, y, self.TRACE_FUNC_WIDTH,
                                   self.trace_func_unit_height, QPen(color),
                                   QBrush(color)))
            if show_func_tag is True and func_name != prev_name:
                tag = self.scene.addText(func_name,
                                         QFont("Source Code Pro", 7))
                tag.setPos(x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING,
                           y - tag.boundingRect().height() // 2)
                self.trace_func.addToGroup(tag)
                anchor = self.scene.addLine(
                    self.TRACE_FUNC_X + self.TRACE_FUNC_WIDTH, y,
                    x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y)
                self.trace_func.addToGroup(anchor)
                prev_name = func_name
            y += self.trace_func_unit_height

    def _make_legend_gradient(self, x1, y1, x2, y2):
        gradient = QLinearGradient(x1, y1, x2, y2)
        gradient.setColorAt(0.0, Qt.red)
        gradient.setColorAt(0.4, Qt.yellow)
        gradient.setColorAt(0.6, Qt.green)
        gradient.setColorAt(0.8, Qt.blue)
        gradient.setColorAt(1.0, Qt.darkBlue)
        return gradient

    def _show_legend(self):
        pen = QPen(Qt.transparent)

        gradient = self._make_legend_gradient(
            self.LEGEND_X, self.LEGEND_Y, self.LEGEND_X,
            self.LEGEND_Y + self.legend_height)
        brush = QBrush(gradient)
        self.legend = self.scene.addRect(self.LEGEND_X, self.LEGEND_Y,
                                         self.LEGEND_WIDTH, self.legend_height,
                                         pen, brush)

        reference_gradient = self._make_legend_gradient(
            0, 0, self.LEGEND_WIDTH, 1000)
        base_img = QImage(self.LEGEND_WIDTH, 1000, QImage.Format.Format_ARGB32)
        p = QPainter(base_img)
        p.fillRect(base_img.rect(), reference_gradient)
        self.legend_img = base_img  #reference shade

    def _set_mark_color(self):
        for p in range(self.trace.count):
            color = self._get_mark_color(p, self.trace.count)
            self.trace.set_mark_color(p, color)

    def _at_legend(self, pos):
        x = pos.x()
        y = pos.y()
        if self.TRACE_FUNC_X + self.LEGEND_X < x < self.view.width() and \
           self.TRACE_FUNC_Y < y < self.TRACE_FUNC_Y + self.legend_height:
            return True
        else:
            return False

    def _to_logical_pos(self, pos):
        x_offset = self.view.horizontalScrollBar().value()
        y_offset = self.view.verticalScrollBar().value()
        return QPoint(pos.x() + x_offset, pos.y() + y_offset)

    def _get_position(self, y):
        y_relative = y - self.legend_height

        return int(y_relative // self.trace_func_unit_height)

    def _get_bbl_from_y(self, y):
        position = self._get_position(y)
        return self.trace.get_bbl_from_position(position)

    def _get_func_from_func_name(self, func_name):
        return self.workspace.instance.kb.functions.function(name=func_name)

    def _get_func_from_y(self, y):
        position = self._get_position(y)
        func_name = self.trace.get_func_name_from_position(position)
        return self._get_func_from_func_name(func_name)