def testQGraphicsProxyWidget(self): scene = QGraphicsScene() proxy = QGraphicsProxyWidget(None, Qt.Window) widget = QLabel('Widget') proxy.setWidget(widget) proxy.setCacheMode(QGraphicsItem.DeviceCoordinateCache) scene.addItem(proxy) scene.setSceneRect(scene.itemsBoundingRect()) view = QGraphicsView(scene) view.setRenderHints(QPainter.Antialiasing|QPainter.SmoothPixmapTransform) view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) view.show() timer = QTimer.singleShot(100, self.app.quit) self.app.exec_()
def __init__(self): super(Window, self).__init__() aliasedLabel = self.createLabel("Aliased") antialiasedLabel = self.createLabel("Antialiased") intLabel = self.createLabel("Int") floatLabel = self.createLabel("Float") layout = QGridLayout() layout.addWidget(aliasedLabel, 0, 1) layout.addWidget(antialiasedLabel, 0, 2) layout.addWidget(intLabel, 1, 0) layout.addWidget(floatLabel, 2, 0) timer = QTimer(self) for i in range(2): for j in range(2): w = CircleWidget() w.setAntialiased(j != 0) w.setFloatBased(i != 0) timer.timeout.connect(w.nextAnimationFrame) layout.addWidget(w, i + 1, j + 1) timer.start(100) self.setLayout(layout) self.setWindowTitle("Concentric Circles")
class TestTimeoutSignal(UsesQCoreApplication): '''Test case to check if the signals are really being caught''' def setUp(self): #Acquire resources UsesQCoreApplication.setUp(self) self.watchdog = WatchDog(self) self.timer = QTimer() self.called = False def tearDown(self): #Release resources del self.watchdog del self.timer del self.called UsesQCoreApplication.tearDown(self) def callback(self, *args): #Default callback self.called = True def testTimeoutSignal(self): #Test the QTimer timeout() signal refCount = sys.getrefcount(self.timer) QObject.connect(self.timer, SIGNAL('timeout()'), self.callback) self.timer.start(4) self.watchdog.startTimer(10) self.app.exec_() self.assert_(self.called) self.assertEqual(sys.getrefcount(self.timer), refCount)
class CpuLoadModel(QAbstractListModel): def __init__(self): QAbstractListModel.__init__(self) self.__cpu_count = psutil.cpu_count() self.__cpu_load = [0] * self.__cpu_count self.__update_timer = QTimer(self) self.__update_timer.setInterval(1000) self.__update_timer.timeout.connect(self.__update) self.__update_timer.start() # The first call returns invalid data psutil.cpu_percent(percpu=True) def __update(self): self.__cpu_load = psutil.cpu_percent(percpu=True) self.dataChanged.emit(self.index(0,0), self.index(self.__cpu_count-1, 0)) def rowCount(self, parent): return self.__cpu_count def data(self, index, role): if (role == Qt.DisplayRole and index.row() >= 0 and index.row() < len(self.__cpu_load) and index.column() == 0): return self.__cpu_load[index.row()] else: return None
def testFontInfo(self): w = MyWidget() w._app = self.app w._info = None QTimer.singleShot(300, w.show) self.app.exec_() self.assert_(w._info)
def testPythonSlot(self): self._sucess = False view = View() view.called.connect(self.done) view.show() QTimer.singleShot(300, QCoreApplication.instance().quit) self.app.exec_() self.assertTrue(self._sucess)
def testSetPenWithPenStyleEnum(self): '''Calls QPainter.setPen with both enum and integer. Bug #511.''' w = Painting() w.show() QTimer.singleShot(1000, self.app.quit) self.app.exec_() self.assertEqual(w.penFromEnum.style(), Qt.NoPen) self.assertEqual(w.penFromInteger.style(), Qt.SolidLine)
def testIt(self): app = QGuiApplication([]) qmlRegisterType(MyClass,'Example',1,0,'MyClass') view = QQuickView() view.setSource(QUrl.fromLocalFile(adjust_filename('bug_926.qml', __file__))) self.assertEqual(len(view.errors()), 0) view.show() QTimer.singleShot(0, app.quit) app.exec_()
def setUp(self, timeout=100): '''Setups this Application. timeout - timeout in milisseconds''' global _timed_instance if _timed_instance is None: _timed_instance = QApplication([]) self.app = _timed_instance QTimer.singleShot(timeout, self.app.quit)
def testIt(self): app = QApplication([]) self.box = MySpinBox() self.box.show() QTimer.singleShot(0, self.sendKbdEvent) QTimer.singleShot(100, app.quit) app.exec_() self.assertEqual(self.box.text(), '0')
def createNextWebView(): global functionID nListCount = len(FUNCTIONS_LIST) - 1 functionID = functionID + 1 print functionID if functionID < nListCount: createWebView( functionID ) else: QTimer.singleShot(300, QApplication.instance().quit)
def generateEvent(self): o = QTest.touchEvent(self) o.press(0, QPoint(10, 10)) o.commit() del o QTest.touchEvent(self).press(0, QPoint(10, 10)) QTest.touchEvent(self).stationary(0).press(1, QPoint(40, 10)) QTest.touchEvent(self).move(0, QPoint(12, 12)).move(1, QPoint(45, 5)) QTest.touchEvent(self).release(0, QPoint(12, 12)).release(1, QPoint(45, 5)) QTimer.singleShot(200, self.deleteLater)
def testSignalStarted(self): #QThread.started() (signal) obj = Dummy() QObject.connect(obj, SIGNAL('started()'), self.cb) obj.start() self._thread = obj QTimer.singleShot(1000, self.abort_application) self.app.exec_() self.assertEqual(obj.qobj.thread(), obj) # test QObject.thread() method self.assert_(self.called)
def testIt(self): self.textEdit = QTextEdit() self.textEdit.show() interface = Foo() self.textEdit.document().documentLayout().registerHandler(QAbstractTextDocumentLayoutTest.objectType, interface) QTimer.singleShot(0, self.foo) self.app.exec_() self.assertTrue(Foo.called)
def test_setParentItem(self): global qgraphics_item_painted scene = QGraphicsScene() scene.addText("test") view = QGraphicsView(scene) rect = self.createRoundRect(scene) view.show() QTimer.singleShot(1000, self.quit_app) self.app.exec_() self.assert_(qgraphics_item_painted)
def testIt(self): app = QGuiApplication([]) qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart'); qmlRegisterType(PieSlice, "Charts", 1, 0, "PieSlice"); view = QQuickView() view.setSource(QUrl.fromLocalFile(helper.adjust_filename('registertype.qml', __file__))) view.show() QTimer.singleShot(250, view.close) app.exec_() self.assertTrue(appendCalled) self.assertTrue(paintCalled)
def testSignalFinished(self): #QThread.finished() (signal) obj = Dummy() QObject.connect(obj, SIGNAL('finished()'), self.cb) mutex.lock() obj.start() mutex.unlock() self._thread = obj QTimer.singleShot(1000, self.abort_application) self.app.exec_() self.assert_(self.called)
def animate(animation: QPropertyAnimation, start: Union[QPointF, int, float], end: Union[QPointF, int, float], curve: QEasingCurve=QEasingCurve.Linear, speed: float=1 / 50, delay: int=-1): animation.setStartValue(start) animation.setEndValue(end) animation.setEasingCurve(curve) if type(start) == type(end) == QPointF: distance = (end - start).manhattanLength() else: distance = abs(end - start) animation.setDuration(round(distance / speed)) if delay == 0: animation.start() if delay > 0: QTimer.singleShot(delay, animation.start)
def testPlugin(self): view = QWebView() fac = PluginFactory() view.page().setPluginFactory(fac) QWebSettings.globalSettings().setAttribute(QWebSettings.PluginsEnabled, True) view.load(QUrl(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'qmlplugin', 'index.html'))) view.resize(840, 600) view.show() QTimer.singleShot(500, self.app.quit) self.app.exec_()
def testBasic(self): '''QStateMachine.configuration converting QSet to python set''' machine = QStateMachine() s1 = QState() machine.addState(s1) machine.setInitialState(s1) machine.start() QTimer.singleShot(100, self.app.quit) self.app.exec_() configuration = machine.configuration() self.assert_(isinstance(configuration, set)) self.assert_(s1 in configuration)
def __init__(self): QWidget.__init__(self) self.setMinimumSize(800, 600) self.donuts = [] self.chart_view = QtCharts.QChartView() self.chart_view.setRenderHint(QPainter.Antialiasing) self.chart = self.chart_view.chart() self.chart.legend().setVisible(False) self.chart.setTitle("Nested donuts demo") self.chart.setAnimationOptions(QtCharts.QChart.AllAnimations) self.min_size = 0.1 self.max_size = 0.9 self.donut_count = 5 self.setup_donuts() # create main layout self.main_layout = QGridLayout(self) self.main_layout.addWidget(self.chart_view, 1, 1) self.setLayout(self.main_layout) self.update_timer = QTimer(self) self.update_timer.timeout.connect(self.update_rotation) self.update_timer.start(1250)
def exposeEvent(self, event): if self.isExposed(): self.render() if self.timer is None: self.timer = QTimer(self) self.timer.timeout.connect(self.slotTimer) self.timer.start(10)
def initUI(self): self.setWindowTitle(self.tr("Game of Life")) self.setLayout(QVBoxLayout()) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self.comboBox = QComboBox() self.comboBox.addItems([*QGameOfLife.Games.keys()]) self.comboBox.currentTextChanged.connect(self.select) self.layout().addWidget(self.comboBox) self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)) self.view.setFrameShape(QFrame.NoFrame) self.layout().addWidget(self.view) self.item = None self.timer = QTimer() self.timer.setInterval(10) self.timer.timeout.connect(self.tick) initialGame = random.choice([*QGameOfLife.Games.keys()]) self.select(initialGame) self.view.fitInView(self.item, Qt.KeepAspectRatioByExpanding) self.comboBox.setCurrentText(initialGame)
def testBasic(self): self.machine = QStateMachine() s1 = QState() s2 = QState() s3 = QFinalState() QObject.connect(self.machine, SIGNAL("started()"), self.cb) self.anim = QParallelAnimationGroup() self.machine.addState(s1) self.machine.addState(s2) self.machine.addState(s3) self.machine.setInitialState(s1) self.machine.addDefaultAnimation(self.anim) self.machine.start() QTimer.singleShot(100, self.app.quit) self.app.exec_()
def testFromData(self): picture = QPicture() painter = QPainter() painter.begin(picture) painter.drawEllipse(10, 20, 80, 70) painter.end() data = picture.data() picture2 = QPicture() picture2.setData(data) self.assertEqual(picture2.data(), picture.data()) w = MyWidget() w._picture = picture2 w._app = self.app QTimer.singleShot(300, w.show) self.app.exec_()
def __init__(self): QAbstractListModel.__init__(self) self.__cpu_count = psutil.cpu_count() self.__cpu_load = [0] * self.__cpu_count self.__update_timer = QTimer(self) self.__update_timer.setInterval(1000) self.__update_timer.timeout.connect(self.__update) self.__update_timer.start() # The first call returns invalid data psutil.cpu_percent(percpu=True)
def initializeAudio(self): self.m_pullTimer = QTimer(self) self.m_pullTimer.timeout.connect(self.pullTimerExpired) self.m_pullMode = True self.m_format = QAudioFormat() self.m_format.setSampleRate(self.DataSampleRateHz) self.m_format.setChannelCount(1) self.m_format.setSampleSize(16) self.m_format.setCodec('audio/pcm') self.m_format.setByteOrder(QAudioFormat.LittleEndian) self.m_format.setSampleType(QAudioFormat.SignedInt) info = QAudioDeviceInfo(QAudioDeviceInfo.defaultOutputDevice()) if not info.isFormatSupported(self.m_format): qWarning("Default format not supported - trying to use nearest") self.m_format = info.nearestFormat(self.m_format) self.m_generator = Generator(self.m_format, self.DurationSeconds * 1000000, self.ToneSampleRateHz, self) self.createAudioOutput()
class DownloadTask(QObject): download_ready = Signal(QObject) download_not_ready = Signal(QObject) download_complete = Signal(QObject) download_failed = Signal(QObject) download_error = Signal(str) download_ok = Signal() download_finishing = Signal() copy_added = Signal(str) chunk_downloaded = Signal( str, # obj_id str, # str(offset) to fix offset >= 2**31 int) # length chunk_aborted = Signal() request_data = Signal( str, # node_id str, # obj_id str, # str(offset) to fix offset >= 2**31 int) # length abort_data = Signal( str, # node_id str, # obj_id str) # str(offset) to fix offset >= 2**31 possibly_sync_folder_is_removed = Signal() no_disk_space = Signal( QObject, # task str, # display_name bool) # is error wrong_hash = Signal(QObject) # task) signal_info_rx = Signal(tuple) default_part_size = DOWNLOAD_PART_SIZE receive_timeout = 20 # seconds retry_limit = 2 timeouts_limit = 2 max_node_chunk_requests = 128 end_race_timeout = 5. # seconds def __init__(self, tracker, connectivity_service, priority, obj_id, obj_size, file_path, display_name, file_hash=None, parent=None, files_info=None): QObject.__init__(self, parent=parent) self._tracker = tracker self._connectivity_service = connectivity_service self.priority = priority self.size = obj_size self.id = obj_id self.file_path = file_path self.file_hash = file_hash self.download_path = file_path + '.download' self._info_path = file_path + '.info' self.display_name = display_name self.received = 0 self.files_info = files_info self.hash_is_wrong = False self._ready = False self._started = False self._paused = False self._finished = False self._no_disk_space_error = False self._wanted_chunks = SortedDict() self._downloaded_chunks = SortedDict() self._nodes_available_chunks = dict() self._nodes_requested_chunks = dict() self._nodes_last_receive_time = dict() self._nodes_downloaded_chunks_count = dict() self._nodes_timeouts_count = dict() self._total_chunks_count = 0 self._file = None self._info_file = None self._started_time = time() self._took_from_turn = 0 self._received_via_turn = 0 self._received_via_p2p = 0 self._retry = 0 self._limiter = None self._init_wanted_chunks() self._on_downloaded_cb = None self._on_failed_cb = None self.download_complete.connect(self._on_downloaded) self.download_failed.connect(self._on_failed) self._timeout_timer = QTimer(self) self._timeout_timer.setInterval(15 * 1000) self._timeout_timer.setSingleShot(False) self._timeout_timer.timeout.connect(self._on_check_timeouts) self._leaky_timer = QTimer(self) self._leaky_timer.setInterval(1000) self._leaky_timer.setSingleShot(True) self._leaky_timer.timeout.connect(self._download_chunks) self._network_limited_error_set = False def __lt__(self, other): if not isinstance(other, DownloadTask): return object.__lt__(self, other) if self == other: return False if self.priority == other.priority: if self.size - self.received == other.size - other.received: return self.id < other.id return self.size - self.received < other.size - other.received return self.priority > other.priority def __le__(self, other): if not isinstance(other, DownloadTask): return object.__le__(self, other) if self == other: return True if self.priority == other.priority: if self.size - self.received == other.size - other.received: return self.id < other.id return self.size - self.received < other.size - other.received return self.priority >= other.priority def __gt__(self, other): if not isinstance(other, DownloadTask): return object.__gt__(self, other) if self == other: return False if self.priority == other.priority: if self.size - self.received == other.size - other.received: return self.id > other.id return self.size - self.received > other.size - other.received return self.priority <= other.priority def __ge__(self, other): if not isinstance(other, DownloadTask): return object.__ge__(self, other) if self == other: return True if self.priority == other.priority: if self.size - self.received == other.size - other.received: return self.id > other.id return self.size - self.received > other.size - other.received return self.priority <= other.priority def __eq__(self, other): if not isinstance(other, DownloadTask): return object.__eq__(self, other) return self.id == other.id def on_availability_info_received(self, node_id, obj_id, info): if obj_id != self.id or self._finished or not info: return logger.info( "availability info received, " "node_id: %s, obj_id: %s, info: %s", node_id, obj_id, info) new_chunks_stored = self._store_availability_info(node_id, info) if not self._ready and new_chunks_stored: if self._check_can_receive(node_id): self._ready = True self.download_ready.emit(self) else: self.download_error.emit('Turn limit reached') if self._started and not self._paused \ and not self._nodes_requested_chunks.get(node_id, None): logger.debug("Downloading next chunk") self._download_next_chunks(node_id) self._clean_nodes_last_receive_time() self._check_download_not_ready(self._nodes_requested_chunks) def on_availability_info_failure(self, node_id, obj_id, error): if obj_id != self.id or self._finished: return logger.info( "availability info failure, " "node_id: %s, obj_id: %s, error: %s", node_id, obj_id, error) try: if error["err_code"] == "FILE_CHANGED": self.download_failed.emit(self) except Exception as e: logger.warning("Can't parse error message. Reson: %s", e) def start(self, limiter): if exists(self.file_path): logger.info("download task file already downloaded %s", self.file_path) self.received = self.size self.download_finishing.emit() self.download_complete.emit(self) return self._limiter = limiter if self._started: # if we swapped task earlier self.resume() return self._no_disk_space_error = False if not self.check_disk_space(): return logger.info("starting download task, obj_id: %s", self.id) self._started = True self._paused = False self.hash_is_wrong = False self._started_time = time() self._send_start_statistic() if not self._open_file(): return self._read_info_file() for downloaded_chunk in self._downloaded_chunks.items(): self._remove_from_chunks(downloaded_chunk[0], downloaded_chunk[1], self._wanted_chunks) self.received = sum(self._downloaded_chunks.values()) if self._complete_download(): return self._download_chunks() if not self._timeout_timer.isActive(): self._timeout_timer.start() def check_disk_space(self): if self.size * 2 + get_signature_file_size(self.size) > \ get_free_space_by_filepath(self.file_path): self._emit_no_disk_space() return False return True def pause(self, disconnect_cb=True): self._paused = True if disconnect_cb: self.disconnect_callbacks() self.stop_download_chunks() def resume(self, start_download=True): self._started_time = time() self._paused = False self.hash_is_wrong = False if start_download: self._started = True self._download_chunks() if not self._timeout_timer.isActive(): self._timeout_timer.start() def cancel(self): self._close_file() self._close_info_file() self.stop_download_chunks() self._finished = True def clean(self): logger.debug("Cleaning download files %s", self.download_path) try: remove_file(self.download_path) except: pass try: remove_file(self._info_path) except: pass def connect_callbacks(self, on_downloaded, on_failed): self._on_downloaded_cb = on_downloaded self._on_failed_cb = on_failed def disconnect_callbacks(self): self._on_downloaded_cb = None self._on_failed_cb = None @property def ready(self): return self._ready @property def paused(self): return self._paused @property def no_disk_space_error(self): return self._no_disk_space_error def _init_wanted_chunks(self): self._total_chunks_count = math.ceil( float(self.size) / float(DOWNLOAD_CHUNK_SIZE)) self._wanted_chunks[0] = self.size def _on_downloaded(self, task): if callable(self._on_downloaded_cb): self._on_downloaded_cb(task) self._on_downloaded_cb = None def _on_failed(self, task): if callable(self._on_failed_cb): self._on_failed_cb(task) self._on_failed_cb = None def on_data_received(self, node_id, obj_id, offset, length, data): if obj_id != self.id or self._finished: return logger.debug( "on_data_received for objId: %s, offset: %s, from node_id: %s", self.id, offset, node_id) now = time() last_received_time = self._nodes_last_receive_time.get(node_id, 0.) if node_id in self._nodes_last_receive_time: self._nodes_last_receive_time[node_id] = now self._nodes_timeouts_count.pop(node_id, 0) downloaded_count = \ self._nodes_downloaded_chunks_count.get(node_id, 0) + 1 self._nodes_downloaded_chunks_count[node_id] = downloaded_count # to collect traffic info node_type = self._connectivity_service.get_self_node_type() is_share = node_type == "webshare" # tuple -> (obj_id, rx_wd, rx_wr, is_share) if self._connectivity_service.is_relayed(node_id): # relayed traffic info_rx = (obj_id, 0, length, is_share) else: # p2p traffic info_rx = (obj_id, length, 0, is_share) self.signal_info_rx.emit(info_rx) if not self._is_chunk_already_downloaded(offset): if not self._on_new_chunk_downloaded(node_id, offset, length, data): return else: logger.debug("chunk %s already downloaded", offset) requested_chunks = self._nodes_requested_chunks.get( node_id, SortedDict()) if not requested_chunks: return self._remove_from_chunks(offset, length, requested_chunks) if not requested_chunks: self._nodes_requested_chunks.pop(node_id, None) requested_count = sum(requested_chunks.values()) // DOWNLOAD_CHUNK_SIZE if downloaded_count * 4 >= requested_count \ and requested_count < self.max_node_chunk_requests: self._download_next_chunks(node_id, now - last_received_time) self._clean_nodes_last_receive_time() self._check_download_not_ready(self._nodes_requested_chunks) def _is_chunk_already_downloaded(self, offset): if self._downloaded_chunks: chunk_index = self._downloaded_chunks.bisect_right(offset) if chunk_index > 0: chunk_index -= 1 chunk = self._downloaded_chunks.peekitem(chunk_index) if offset < chunk[0] + chunk[1]: return True return False def _on_new_chunk_downloaded(self, node_id, offset, length, data): if not self._write_to_file(offset, data): return False self.received += length if self._connectivity_service.is_relayed(node_id): self._received_via_turn += length else: self._received_via_p2p += length new_offset = offset new_length = length left_index = self._downloaded_chunks.bisect_right(new_offset) if left_index > 0: left_chunk = self._downloaded_chunks.peekitem(left_index - 1) if left_chunk[0] + left_chunk[1] == new_offset: new_offset = left_chunk[0] new_length += left_chunk[1] self._downloaded_chunks.popitem(left_index - 1) right_index = self._downloaded_chunks.bisect_right(new_offset + new_length) if right_index > 0: right_chunk = self._downloaded_chunks.peekitem(right_index - 1) if right_chunk[0] == new_offset + new_length: new_length += right_chunk[1] self._downloaded_chunks.popitem(right_index - 1) self._downloaded_chunks[new_offset] = new_length assert self._remove_from_chunks(offset, length, self._wanted_chunks) logger.debug("new chunk downloaded from node: %s, wanted size: %s", node_id, sum(self._wanted_chunks.values())) part_offset = (offset / DOWNLOAD_PART_SIZE) * DOWNLOAD_PART_SIZE part_size = min([DOWNLOAD_PART_SIZE, self.size - part_offset]) if new_offset <= part_offset \ and new_offset + new_length >= part_offset + part_size: if self._file: self._file.flush() self._write_info_file() self.chunk_downloaded.emit(self.id, str(part_offset), part_size) if self._complete_download(): return False return True def _remove_from_chunks(self, offset, length, chunks): if not chunks: return False chunk_left_index = chunks.bisect_right(offset) if chunk_left_index > 0: left_chunk = chunks.peekitem(chunk_left_index - 1) if offset >= left_chunk[0] + left_chunk[1] \ and len(chunks) > chunk_left_index: left_chunk = chunks.peekitem(chunk_left_index) else: chunk_left_index -= 1 else: left_chunk = chunks.peekitem(chunk_left_index) if offset >= left_chunk[0] + left_chunk[1] or \ offset + length <= left_chunk[0]: return False chunk_right_index = chunks.bisect_right(offset + length) right_chunk = chunks.peekitem(chunk_right_index - 1) if chunk_right_index == chunk_left_index: to_del = [right_chunk[0]] else: to_del = list(chunks.islice(chunk_left_index, chunk_right_index)) for chunk in to_del: chunks.pop(chunk) if left_chunk[0] < offset: if left_chunk[0] + left_chunk[1] >= offset: chunks[left_chunk[0]] = offset - left_chunk[0] if right_chunk[0] + right_chunk[1] > offset + length: chunks[offset + length] = \ right_chunk[0] + right_chunk[1] - offset - length return True def on_data_failed(self, node_id, obj_id, offset, error): if obj_id != self.id or self._finished: return logger.info( "data request failure, " "node_id: %s, obj_id: %s, offset: %s, error: %s", node_id, obj_id, offset, error) self.on_node_disconnected(node_id) def get_downloaded_chunks(self): if not self._downloaded_chunks: return None return self._downloaded_chunks def on_node_disconnected(self, node_id, connection_alive=False, timeout_limit_exceed=True): requested_chunks = self._nodes_requested_chunks.pop(node_id, None) logger.info("node disconnected %s, chunks removed from requested: %s", node_id, requested_chunks) if timeout_limit_exceed: self._nodes_available_chunks.pop(node_id, None) self._nodes_timeouts_count.pop(node_id, None) if connection_alive: self._connectivity_service.reconnect(node_id) self._nodes_last_receive_time.pop(node_id, None) self._nodes_downloaded_chunks_count.pop(node_id, None) if connection_alive: self.abort_data.emit(node_id, self.id, None) if self._nodes_available_chunks: self._download_chunks(check_node_busy=True) else: chunks_to_test = self._nodes_requested_chunks \ if self._started and not self._paused \ else self._nodes_available_chunks self._check_download_not_ready(chunks_to_test) def complete(self): if self._started and not self._finished: self._complete_download(force_complete=True) elif not self._finished: self._finished = True self.clean() self.download_complete.emit(self) def _download_chunks(self, check_node_busy=False): if not self._started or self._paused or self._finished: return logger.debug("download_chunks for %s", self.id) node_ids = list(self._nodes_available_chunks.keys()) random.shuffle(node_ids) for node_id in node_ids: node_free = not check_node_busy or \ not self._nodes_requested_chunks.get(node_id, None) if node_free: self._download_next_chunks(node_id) self._clean_nodes_last_receive_time() self._check_download_not_ready(self._nodes_requested_chunks) def _check_can_receive(self, node_id): return True def _write_to_file(self, offset, data): self._file.seek(offset) try: self._file.write(data) except EnvironmentError as e: logger.error("Download task %s can't write to file. Reason: %s", self.id, e) self._send_error_statistic() if e.errno == errno.ENOSPC: self._emit_no_disk_space(error=True) else: self.download_failed.emit(self) self.possibly_sync_folder_is_removed.emit() return False return True def _open_file(self, clean=False): if not self._file or self._file.closed: try: if clean: self._file = open(self.download_path, 'wb') else: self._file = open(self.download_path, 'r+b') except IOError: try: self._file = open(self.download_path, 'wb') except IOError as e: logger.error( "Can't open file for download for task %s. " "Reason: %s", self.id, e) self.download_failed.emit(self) return False return True def _close_file(self): if not self._file: return True try: self._file.close() except EnvironmentError as e: logger.error("Download task %s can't close file. Reason: %s", self.id, e) self._send_error_statistic() if e.errno == errno.ENOSPC: self._emit_no_disk_space(error=True) else: self.download_failed.emit(self) self.possibly_sync_folder_is_removed.emit() self._file = None return False self._file = None return True def _write_info_file(self): try: self._info_file.seek(0) self._info_file.truncate() pickle.dump(self._downloaded_chunks, self._info_file, pickle.HIGHEST_PROTOCOL) self._info_file.flush() except EnvironmentError as e: logger.debug("Can't write to info file for task id %s. Reason: %s", self.id, e) def _read_info_file(self): try: if not self._info_file or self._info_file.closed: self._info_file = open(self._info_path, 'a+b') self._info_file.seek(0) try: self._downloaded_chunks = pickle.load(self._info_file) except: pass except EnvironmentError as e: logger.debug("Can't open info file for task id %s. Reason: %s", self.id, e) def _close_info_file(self, to_remove=False): if not self._info_file: return try: self._info_file.close() if to_remove: remove_file(self._info_path) except Exception as e: logger.debug( "Can't close or remove info file " "for task id %s. Reason: %s", self.id, e) self._info_file = None def _complete_download(self, force_complete=False): if (not self._wanted_chunks or force_complete) and \ not self._finished: logger.debug("download %s completed", self.id) self._nodes_requested_chunks.clear() for node_id in self._nodes_last_receive_time.keys(): self.abort_data.emit(node_id, self.id, None) if not force_complete: self.download_finishing.emit() if not force_complete and self.file_hash: hash_check_result = self._check_file_hash() if hash_check_result is not None: return hash_check_result self._started = False self._finished = True self.stop_download_chunks() self._close_info_file(to_remove=True) if not self._close_file(): return False try: if force_complete: remove_file(self.download_path) self.download_complete.emit(self) else: shutil.move(self.download_path, self.file_path) self._send_end_statistic() self.download_complete.emit(self) if self.file_hash: self.copy_added.emit(self.file_hash) except EnvironmentError as e: logger.error( "Download task %s can't (re)move file. " "Reason: %s", self.id, e) self._send_error_statistic() self.download_failed.emit(self) self.possibly_sync_folder_is_removed.emit() return False result = True else: result = not self._wanted_chunks return result def _check_file_hash(self): self._file.flush() try: hash = Rsync.hash_from_block_checksum( Rsync.block_checksum(self.download_path)) except IOError as e: logger.error("download %s error: %s", self.id, e) hash = None if hash != self.file_hash: logger.error( "download hash check failed objId: %s, " "expected hash: %s, actual hash: %s", self.id, self.file_hash, hash) if not self._close_file() or not self._open_file(clean=True): return False self._downloaded_chunks.clear() self._nodes_downloaded_chunks_count.clear() self._nodes_last_receive_time.clear() self._nodes_timeouts_count.clear() self._write_info_file() self._init_wanted_chunks() self.received = 0 if self._retry < self.retry_limit: self._retry += 1 self.resume() else: self._retry = 0 self._nodes_available_chunks.clear() self.hash_is_wrong = True self.wrong_hash.emit(self) return True return None def _download_next_chunks(self, node_id, time_from_last_received_chunk=0.): if (self._paused or not self._started or not self._ready or self._finished or not self._wanted_chunks or self._leaky_timer.isActive()): return total_requested = sum( map(lambda x: sum(x.values()), self._nodes_requested_chunks.values())) if total_requested + self.received >= self.size: if self._nodes_requested_chunks.get(node_id, None) and \ time_from_last_received_chunk <= self.end_race_timeout: return available_chunks = \ self._get_end_race_chunks_to_download_from_node(node_id) else: available_chunks = \ self._get_available_chunks_to_download_from_node(node_id) if not available_chunks: logger.debug("no chunks available for download %s", self.id) logger.debug("downloading from: %s nodes, length: %s, wanted: %s", len(self._nodes_requested_chunks), total_requested, self.size - self.received) return available_offset = random.sample(available_chunks.keys(), 1)[0] available_length = available_chunks[available_offset] logger.debug("selected random offset: %s", available_offset) parts_count = math.ceil( float(available_length) / float(DOWNLOAD_PART_SIZE)) - 1 logger.debug("parts count: %s", parts_count) part_to_download_number = random.randint(0, parts_count) offset = available_offset + \ part_to_download_number * DOWNLOAD_PART_SIZE length = min(DOWNLOAD_PART_SIZE, available_offset + available_length - offset) logger.debug("selected random part: %s, offset: %s, length: %s", part_to_download_number, offset, length) self._request_data(node_id, offset, length) def _get_end_race_chunks_to_download_from_node(self, node_id): available_chunks = self._nodes_available_chunks.get(node_id, None) if not available_chunks: return [] available_chunks = available_chunks.copy() logger.debug("end race downloaded_chunks: %s", self._downloaded_chunks) logger.debug("end race requested_chunks: %s", self._nodes_requested_chunks) logger.debug("end race available_chunks before excludes: %s", available_chunks) if self._downloaded_chunks: for downloaded_chunk in self._downloaded_chunks.items(): self._remove_from_chunks(downloaded_chunk[0], downloaded_chunk[1], available_chunks) if not available_chunks: return [] available_from_other_nodes = available_chunks.copy() for requested_offset, requested_length in \ self._nodes_requested_chunks.get(node_id, dict()).items(): self._remove_from_chunks(requested_offset, requested_length, available_from_other_nodes) result = available_from_other_nodes if available_from_other_nodes \ else available_chunks if result: logger.debug("end race available_chunks after excludes: %s", available_chunks) return result def _get_available_chunks_to_download_from_node(self, node_id): available_chunks = self._nodes_available_chunks.get(node_id, None) if not available_chunks: return [] available_chunks = available_chunks.copy() logger.debug("downloaded_chunks: %s", self._downloaded_chunks) logger.debug("requested_chunks: %s", self._nodes_requested_chunks) logger.debug("available_chunks before excludes: %s", available_chunks) for _, requested_chunks in self._nodes_requested_chunks.items(): for requested_offset, requested_length in requested_chunks.items(): self._remove_from_chunks(requested_offset, requested_length, available_chunks) if not available_chunks: return [] for downloaded_chunk in self._downloaded_chunks.items(): self._remove_from_chunks(downloaded_chunk[0], downloaded_chunk[1], available_chunks) logger.debug("available_chunks after excludes: %s", available_chunks) return available_chunks def _request_data(self, node_id, offset, length): logger.debug("Requesting date from node %s, request_chunk (%s, %s)", node_id, offset, length) if self._limiter: try: self._limiter.leak(length) except LeakyBucketException: if node_id not in self._nodes_requested_chunks: self._nodes_last_receive_time.pop(node_id, None) if not self._network_limited_error_set: self.download_error.emit('Network limited.') self._network_limited_error_set = True if not self._leaky_timer.isActive(): self._leaky_timer.start() return if self._network_limited_error_set: self._network_limited_error_set = False self.download_ok.emit() requested_chunks = self._nodes_requested_chunks.get(node_id, None) if not requested_chunks: requested_chunks = SortedDict() self._nodes_requested_chunks[node_id] = requested_chunks requested_chunks[offset] = length logger.debug("Requested chunks %s", requested_chunks) self._nodes_last_receive_time[node_id] = time() self.request_data.emit(node_id, self.id, str(offset), length) def _clean_nodes_last_receive_time(self): for node_id in list(self._nodes_last_receive_time.keys()): if node_id not in self._nodes_requested_chunks: self._nodes_last_receive_time.pop(node_id, None) def _on_check_timeouts(self): if self._paused or not self._started \ or self._finished or self._leaky_timer.isActive(): return timed_out_nodes = set() cur_time = time() logger.debug("Chunk requests check %s", len(self._nodes_requested_chunks)) if self._check_download_not_ready(self._nodes_requested_chunks): return for node_id in self._nodes_last_receive_time: last_receive_time = self._nodes_last_receive_time.get(node_id) if cur_time - last_receive_time > self.receive_timeout: timed_out_nodes.add(node_id) logger.debug("Timed out nodes %s, nodes last receive time %s", timed_out_nodes, self._nodes_last_receive_time) for node_id in timed_out_nodes: timeout_count = self._nodes_timeouts_count.pop(node_id, 0) timeout_count += 1 if timeout_count >= self.timeouts_limit: retry = False else: retry = True self._nodes_timeouts_count[node_id] = timeout_count logger.debug("Node if %s, timeout_count %s, retry %s", node_id, timeout_count, retry) self.on_node_disconnected(node_id, connection_alive=True, timeout_limit_exceed=not retry) def _get_chunks_from_info(self, chunks, info): new_added = False for part_info in info: logger.debug("get_chunks_from_info part_info %s", part_info) if part_info.length == 0: continue if not chunks: chunks[part_info.offset] = part_info.length new_added = True continue result_offset = part_info.offset result_length = part_info.length left_index = chunks.bisect_right(part_info.offset) if left_index > 0: left_chunk = chunks.peekitem(left_index - 1) if (left_chunk[0] <= part_info.offset and left_chunk[0] + left_chunk[1] >= part_info.offset + part_info.length): continue if part_info.offset <= left_chunk[0] + left_chunk[1]: result_offset = left_chunk[0] result_length = part_info.offset + \ part_info.length - result_offset left_index -= 1 right_index = chunks.bisect_right(part_info.offset + part_info.length) if right_index > 0: right_chunk = chunks.peekitem(right_index - 1) if part_info.offset + part_info.length <= \ right_chunk[0] + right_chunk[1]: result_length = right_chunk[0] + \ right_chunk[1] - result_offset to_delete = list(chunks.islice(left_index, right_index)) for to_del in to_delete: chunks.pop(to_del) new_added = True chunks[result_offset] = result_length return new_added def _store_availability_info(self, node_id, info): known_chunks = self._nodes_available_chunks.get(node_id, None) if not known_chunks: known_chunks = SortedDict() self._nodes_available_chunks[node_id] = known_chunks return self._get_chunks_from_info(known_chunks, info) def _check_download_not_ready(self, checkable): if not self._wanted_chunks and self._started: self._complete_download(force_complete=False) return False if self._leaky_timer.isActive(): if not self._nodes_available_chunks: self._make_not_ready() return True elif not checkable: self._make_not_ready() return True return False def _make_not_ready(self): if not self._ready: return logger.info("download %s not ready now", self.id) self._ready = False self._started = False if self._timeout_timer.isActive(): self._timeout_timer.stop() if self._leaky_timer.isActive(): self._leaky_timer.stop() self.download_not_ready.emit(self) def _clear_globals(self): self._wanted_chunks.clear() self._downloaded_chunks.clear() self._nodes_available_chunks.clear() self._nodes_requested_chunks.clear() self._nodes_last_receive_time.clear() self._nodes_downloaded_chunks_count.clear() self._nodes_timeouts_count.clear() self._total_chunks_count = 0 def stop_download_chunks(self): if self._leaky_timer.isActive(): self._leaky_timer.stop() if self._timeout_timer.isActive(): self._timeout_timer.stop() for node_id in self._nodes_requested_chunks: self.abort_data.emit(node_id, self.id, None) self._nodes_requested_chunks.clear() self._nodes_last_receive_time.clear() def _emit_no_disk_space(self, error=False): self._no_disk_space_error = True self._nodes_available_chunks.clear() self._clear_globals() self._make_not_ready() file_name = self.display_name.split()[-1] \ if self.display_name else "" self.no_disk_space.emit(self, file_name, error) def _send_start_statistic(self): if self._tracker: self._tracker.download_start(self.id, self.size) def _send_end_statistic(self): if self._tracker: time_diff = time() - self._started_time if time_diff < 1e-3: time_diff = 1e-3 self._tracker.download_end( self.id, time_diff, websockets_bytes=0, webrtc_direct_bytes=self._received_via_p2p, webrtc_relay_bytes=self._received_via_turn, chunks=len(self._downloaded_chunks), chunks_reloaded=0, nodes=len(self._nodes_available_chunks)) def _send_error_statistic(self): if self._tracker: time_diff = time() - self._started_time if time_diff < 1e-3: time_diff = 1e-3 self._tracker.download_error( self.id, time_diff, websockets_bytes=0, webrtc_direct_bytes=self._received_via_p2p, webrtc_relay_bytes=self._received_via_turn, chunks=len(self._downloaded_chunks), chunks_reloaded=0, nodes=len(self._nodes_available_chunks))
def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.popup = QMessageBox() self.inputPopup = QInputDialog() self.tasks = [] self.timer = False self.study_time = 0 self.break_time = 0 self.second_count = 60 self.status = "Work" self.timer_status = "Play" #Setting up the Table self.ui.tasksTable.setColumnCount(5) self.ui.tasksTable.setHorizontalHeaderLabels([ "Task Name", "Subject", "Estimated Duration", "Actual Time Taken", "Completed" ]) self.ui.tasksTable.resizeColumnsToContents() if not os.path.exists("tasks.npy"): tasks_to_save = np.array(self.tasks) np.save("tasks", tasks_to_save) else: self.tasks = list(np.load("tasks.npy")) self.loadTasks() study_methods = [ "Traditional Pomodoro", "Extended Pomodoro", "Animedoro" ] self.study_intervals = ["25 minutes", "50 minutes", "40-60 minutes"] self.break_intervals = [ "5 minutes", "10 minutes", "approx. 20 minutes - one anime (or other with a similar duration) episode" ] self.cycles = [ "4, then take 15-30 minutes as a break", "2, then take 15-30 minutes as a break", "2, then take an extra 10 minutes" ] self.ui.productivityChoose.addItems(study_methods) self.updateMethods() self.ui.productivityChoose.currentIndexChanged.connect( self.updateMethods) self.ui.chooseButton.clicked.connect(self.selectTask) self.ui.addTaskButton.clicked.connect(self.addTask) self.ui.completeButton.clicked.connect(self.completeTask) self.ui.deleteButton.clicked.connect(self.deleteTask) self.ui.actionNewDay.triggered.connect(self.clear) self.ui.timerButton.clicked.connect(self.startCycle) self.ui.endButton.clicked.connect(self.endEarly) self.ui.resetButton.clicked.connect(self.newCycle) self.ui.playPauseButton.clicked.connect(self.playPause) timer = QTimer(self) timer.timeout.connect(self.cycleTimer) timer.start(1000) #change back to 1000
class SkeletonEditorDialog(QDialog, Ui_Dialog): def __init__(self, name, skeleton, share_widget, parent=None, enable_line_edit=False, skeleton_model=None): self.initialized = False QDialog.__init__(self, parent) Ui_Dialog.setupUi(self, self) self.view = SceneViewerWidget(parent, share_widget, size=(400, 400)) self.view.setObjectName("left") self.view.setMinimumSize(400, 400) self.view.initializeGL() self.nameLineEdit.setText(name) self.nameLineEdit.setEnabled(enable_line_edit) self.name = name self.view.enable_mouse_interaction = True self.view.mouse_click.connect(self.on_mouse_click) self.viewerLayout.addWidget(self.view) self.radius = 1.0 self.fps = 60 self.dt = 1 / 60 self.timer = QTimer() self.timer.timeout.connect(self.draw) self.timer.start(0) self.timer.setInterval(1000.0 / self.fps) self.skeleton = skeleton self.view.makeCurrent() self.scene = EditorScene(True) self.scene.enable_scene_edit_widget = True if skeleton_model is not None: self.skeleton_model = skeleton_model elif skeleton.skeleton_model is not None: self.skeleton_model = skeleton.skeleton_model else: self.skeleton_model = dict() print("create new skeleton model") if "cos_map" not in self.skeleton_model: self.skeleton_model["cos_map"] = dict() if "joints" not in self.skeleton_model: self.skeleton_model["joints"] = dict() if "joint_constraints" not in self.skeleton_model: self.skeleton_model["joint_constraints"] = dict() motion_vector = MotionVector() self.reference_frame = skeleton.reference_frame print(self.reference_frame[:3]) motion_vector.frames = [skeleton.reference_frame] motion_vector.n_frames = 1 o = self.scene.object_builder.create_object("animation_controller", "skeleton", skeleton, motion_vector, skeleton.frame_time) self.controller = o._components["animation_controller"] self.skeleton = self.controller.get_skeleton() self.skeleton_vis = o._components["skeleton_vis"] self.init_joints(self.controller) self.fill_joint_map() self.selectButton.clicked.connect(self.slot_accept) self.cancelButton.clicked.connect(self.slot_reject) self.applyTwistRotationButton.clicked.connect(self.slot_set_twist) self.applySwingRotationButton.clicked.connect(self.slot_set_swing) self.setOrthogonalTwistButton.clicked.connect( self.slot_set_orthogonal_twist) self.setOrthogonalSwingButton.clicked.connect( self.slot_set_orthogonal_swing) self.rotateTwistButton.clicked.connect(self.slot_rotate_twist) self.rotateSwingButton.clicked.connect(self.slot_rotate_swing) self.flipTwistButton.clicked.connect(self.slot_flip_twist) self.flipSwingButton.clicked.connect(self.slot_flip_swing) self.flipZAxisButton.clicked.connect(self.slot_flip_z_axis) self.alignToUpAxisButton.clicked.connect(self.slot_align_to_up_axis) self.alignToForwardAxisButton.clicked.connect( self.slot_align_to_forward_axis) self.guessSelectedButton.clicked.connect( self.slot_guess_selected_cos_map) self.resetSelectedCosButton.clicked.connect( self.slot_reset_selected_cos_map) self.guessAllCosButton.clicked.connect(self.slot_guess_cos_map) self.resetAllCosButton.clicked.connect(self.slot_reset_cos_map) self.loadDefaultPoseButton.clicked.connect(self.slot_load_default_pose) self.applyScaleButton.clicked.connect(self.slot_apply_scale) self.jointMapComboBox.currentIndexChanged.connect( self.slot_update_joint_map) self.aligningRootComboBox.currentIndexChanged.connect( self.slot_update_aligning_root_joint) self.mirrorLeftButton.clicked.connect(self.slot_mirror_left_to_right) self.mirrorRightButton.clicked.connect(self.slot_mirror_right_to_left) self.is_updating_joint_info = False self.success = False self.initialized = False self.skeleton_data = None self.precision = 3 self.aligning_root_node = self.skeleton.aligning_root_node self.fill_root_combobox() self.init_aligning_root_node() def init_aligning_root_node(self): print("init", self.skeleton.root, self.skeleton.aligning_root_node) if self.aligning_root_node is None: self.aligning_root_node = self.skeleton.root if self.aligning_root_node is not None: index = self.aligningRootComboBox.findText(self.aligning_root_node, Qt.MatchFixedString) print("found index", index, self.aligning_root_node) if index >= 0: self.aligningRootComboBox.setCurrentIndex(index) def closeEvent(self, e): self.timer.stop() self.view.makeCurrent() del self.view def on_mouse_click(self, event, ray_start, ray_dir, pos, node_id): if event.button() == Qt.LeftButton: self.scene.select_object(node_id) joint_knob = self.get_selected_joint() self.update_joint_info(joint_knob) def update_joint_info(self, joint_knob): self.is_updating_joint_info = True self.scene.scene_edit_widget.reset_rotation() self.jointMapComboBox.setCurrentIndex(0) label = "Selected Joint: " if joint_knob is None: label += "None" self.jointLabel.setText(label) self.is_updating_joint_info = False return label += joint_knob.joint_name joint_name = joint_knob.joint_name if "joints" in self.skeleton_model: key = find_key(self.skeleton_model["joints"], joint_name) print("key", joint_name, key) if key is not None: index = self.jointMapComboBox.findText(key, Qt.MatchFixedString) if index >= 0: self.jointMapComboBox.setCurrentIndex(index) if "cos_map" in self.skeleton_model and joint_name in self.skeleton_model[ "cos_map"]: x_vector = self.skeleton_model["cos_map"][joint_name]["x"] if x_vector is None: x_vector = [1, 0, 0] self.skeleton_model["cos_map"][joint_name]["x"] = x_vector y_vector = self.skeleton_model["cos_map"][joint_name]["y"] if y_vector is None: y_vector = [0, 1, 0] self.skeleton_model["cos_map"][joint_name]["y"] = y_vector swing = np.round(x_vector, self.precision) twist = np.round(y_vector, self.precision) self.set_swing_text(swing) self.set_twist_text(twist) m = self.skeleton.nodes[joint_name].get_global_matrix( self.reference_frame)[:3, :3] g_swing = np.dot(m, swing) g_swing = normalize(g_swing) g_twist = np.dot(m, twist) g_twist = normalize(g_twist) q = axes_to_q(g_twist, g_swing) m = quaternion_matrix(q) #print("g_twist", g_twist, twist) #print("g_swing", g_swing, swing) self.scene.scene_edit_widget.rotation = m[:3, :3].T else: print("no cos map", self.skeleton_model.keys()) self.jointLabel.setText(label) self.is_updating_joint_info = False def set_swing_text(self, swing): self.swingXLineEdit.setText(str(swing[0])) self.swingYLineEdit.setText(str(swing[1])) self.swingZLineEdit.setText(str(swing[2])) def set_twist_text(self, twist): self.twistXLineEdit.setText(str(twist[0])) self.twistYLineEdit.setText(str(twist[1])) self.twistZLineEdit.setText(str(twist[2])) def fill_joint_map(self): self.jointMapComboBox.clear() for idx, joint in enumerate(STANDARD_JOINTS): print("add", joint) self.jointMapComboBox.addItem(joint, idx) def fill_root_combobox(self): self.aligningRootComboBox.clear() for idx, joint in enumerate(self.controller.get_animated_joints()): self.aligningRootComboBox.addItem(joint, idx) def init_joints(self, controller): for joint_name in controller.get_animated_joints(): if len(self.skeleton.nodes[joint_name].children ) > 0: # filter out end site joints node = self.skeleton.nodes[joint_name] if joint_name == self.skeleton.root or np.linalg.norm( node.offset) > 0: self.scene.object_builder.create_object( "joint_control_knob", controller, joint_name, self.radius * self.skeleton_vis.box_scale) def draw(self): """ draw current scene on the given view (note before calling this function the context of the view has to be set as current using makeCurrent() and afterwards the doubble buffer has to swapped to display the current frame swapBuffers()) """ if not self.initialized: if self.view.graphics_context is not None: self.view.resize(400, 400) self.initialized = True self.scene.update(self.dt) self.view.makeCurrent() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.view.graphics_context.render(self.scene) self.view.swapBuffers() def left_display_changed(self, frame_idx): if self.controller is not None: self.controller.setCurrentFrameNumber(frame_idx) self.leftDisplayFrameSpinBox.setValue(frame_idx) def left_spinbox_frame_changed(self, frame): self.leftStartFrameSlider.setValue(self.leftStartFrameSpinBox.value()) self.leftEndFrameSlider.setValue(self.leftEndFrameSpinBox.value()) def left_slider_frame_changed(self, frame): self.leftStartFrameSpinBox.setValue(self.leftStartFrameSlider.value()) self.leftEndFrameSpinBox.setValue(self.leftEndFrameSlider.value()) def slot_accept(self): self.name = str(self.nameLineEdit.text()) if self.name != "": print("accept") self.success = True self.skeleton = self.controller.get_skeleton() self.skeleton.set_reference_frame(self.reference_frame) if self.aligning_root_node is not None: self.skeleton.aligning_root_node = self.aligning_root_node self.skeleton_data = self.skeleton.to_unity_format() if "cos_map" in self.skeleton_model: for k in self.skeleton_model["cos_map"]: for l in self.skeleton_model["cos_map"][k]: if type(self.skeleton_model["cos_map"][k] [l]) == np.ndarray: self.skeleton_model["cos_map"][k][ l] = self.skeleton_model["cos_map"][k][ l].tolist() else: self.skeleton_model["cos_map"][k][ l] = self.skeleton_model["cos_map"][k][l] self.close() else: print("Please provide a name") def slot_reject(self): self.close() def get_selected_joint(self): joint_knob = None o = self.scene.selected_scene_object if o is not None and "joint_control_knob" in o._components: joint_knob = o._components["joint_control_knob"] return joint_knob def set_twist(self, joint_name): x = round(float(self.twistXLineEdit.text()), self.precision) y = round(float(self.twistYLineEdit.text()), self.precision) z = round(float(self.twistZLineEdit.text()), self.precision) #set twist axis twist = np.array([x, y, z]) magnitude = np.linalg.norm(twist) if magnitude > 0: twist /= magnitude self.skeleton_model["cos_map"][joint_name]["y"] = twist def set_swing(self, joint_name): x = round(float(self.swingXLineEdit.text()), self.precision) y = round(float(self.swingYLineEdit.text()), self.precision) z = round(float(self.swingZLineEdit.text()), self.precision) #set swing axis swing = np.array([x, y, z]) magnitude = np.linalg.norm(swing) if magnitude > 0: swing /= magnitude self.skeleton_model["cos_map"][joint_name]["x"] = swing.tolist() def slot_set_twist(self): plot = False joint_knob = self.get_selected_joint() if joint_knob is None: return self.set_swing(joint_knob.joint_name) self.set_twist(joint_knob.joint_name) self.update_joint_info(joint_knob) def slot_set_swing(self): joint_knob = self.get_selected_joint() if joint_knob is None: return self.set_swing(joint_knob.joint_name) self.set_twist(joint_knob.joint_name) self.update_joint_info(joint_knob) def slot_set_orthogonal_twist(self): """ https://stackoverflow.com/questions/33658620/generating-two-orthogonal-vectors-that-are-orthogonal-to-a-particular-direction """ joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name #get swing axis swing = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) # find orthogonal vector y = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) #y = np.random.randn(3) # take a random vector y -= y.dot(swing) * swing # make it orthogonal to twist y /= np.linalg.norm(y) # normalize it #replace twist axis self.set_twist_text(y) self.skeleton_model["cos_map"][joint_name]["y"] = y self.update_joint_info(joint_knob) def slot_set_orthogonal_swing(self): """ https://stackoverflow.com/questions/33658620/generating-two-orthogonal-vectors-that-are-orthogonal-to-a-particular-direction """ joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name #get twist axis twist = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) x = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) x -= x.dot(twist) * twist # make it orthogonal to twist x /= np.linalg.norm(x) # normalize it #replace twist axis self.set_swing_text(x) self.skeleton_model["cos_map"][joint_name]["x"] = x self.update_joint_info(joint_knob) def slot_flip_twist(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name #get twist axis twist = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) twist *= -1 self.skeleton_model["cos_map"][joint_name]["y"] = twist self.set_twist_text(twist) self.update_joint_info(joint_knob) def slot_flip_swing(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name swing = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) swing *= -1 self.skeleton_model["cos_map"][joint_name]["x"] = swing self.set_swing_text(swing) self.update_joint_info(joint_knob) def slot_rotate_twist(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name #get twist axis angle = round(float(self.twistRotationLineEdit.text()), self.precision) rotation_axis = np.array( self.skeleton_model["cos_map"][joint_name]["x"]) q = quaternion_about_axis(np.deg2rad(angle), rotation_axis) q = normalize(q) twist = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) twist = rotate_vector(q, twist) twist = normalize(twist) self.skeleton_model["cos_map"][joint_name]["y"] = twist self.set_twist_text(twist) self.update_joint_info(joint_knob) def slot_rotate_swing(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name angle = round(float(self.swingRotationLineEdit.text()), self.precision) rotation_axis = np.array( self.skeleton_model["cos_map"][joint_name]["y"]) q = quaternion_about_axis(np.deg2rad(angle), rotation_axis) q = normalize(q) swing = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) swing = rotate_vector(q, swing) swing = normalize(swing) self.skeleton_model["cos_map"][joint_name]["x"] = swing self.set_swing_text(swing) self.update_joint_info(joint_knob) def slot_flip_z_axis(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name twist = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) swing = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) new_swing = twist new_twist = swing #print("new swing", new_swing, swing) self.skeleton_model["cos_map"][joint_name]["y"] = new_twist self.skeleton_model["cos_map"][joint_name]["x"] = new_swing self.set_swing_text(new_swing) self.set_twist_text(new_twist) self.update_joint_info(joint_knob) def slot_guess_cos_map(self): """ creates a guess for the coordinate system for all joints""" temp_skeleton = copy(self.skeleton) temp_skeleton.skeleton_model = self.skeleton_model cos_map = create_local_cos_map_from_skeleton_axes_with_map( temp_skeleton) self.skeleton_model["cos_map"] = cos_map joint_knob = self.get_selected_joint() if joint_knob is not None: self.update_joint_info(joint_knob) def slot_reset_cos_map(self): """ resets the coordinate systems for all joints""" for joint_name in self.skeleton_model["cos_map"]: up_vector = self.skeleton_model["cos_map"][joint_name]["y"] x_vector = self.skeleton_model["cos_map"][joint_name]["x"] if up_vector is not None and x_vector is not None: new_up_vector, new_x_vector = self.reset_joint_cos( joint_name, up_vector, x_vector) self.skeleton_model["cos_map"][joint_name]["y"] = new_up_vector self.skeleton_model["cos_map"][joint_name]["x"] = new_x_vector joint_knob = self.get_selected_joint() if joint_knob is not None: self.update_joint_info(joint_knob) def slot_guess_selected_cos_map(self): """ creates a guess for the for the selected joint""" joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name temp_skeleton = copy(self.skeleton) temp_skeleton.skeleton_model = self.skeleton_model cos_map = create_local_cos_map_from_skeleton_axes_with_map( temp_skeleton) self.skeleton_model["cos_map"][joint_name] = cos_map[joint_name] self.update_joint_info(joint_knob) def slot_reset_selected_cos_map(self): """ creates resetrs the coordinate system for the selected joint""" joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name if joint_name in self.skeleton_model["cos_map"]: up_vector = self.skeleton_model["cos_map"][joint_name]["y"] x_vector = self.skeleton_model["cos_map"][joint_name]["x"] new_up_vector, new_x_vector = self.reset_joint_cos( joint_name, up_vector, x_vector) self.skeleton_model["cos_map"][joint_name]["y"] = new_up_vector self.skeleton_model["cos_map"][joint_name]["x"] = new_x_vector self.update_joint_info(joint_knob) def slot_update_joint_map(self): if not self.is_updating_joint_info and "joints" in self.skeleton_model: joint_knob = self.get_selected_joint() if joint_knob is not None: new_joint_key = str(self.jointMapComboBox.currentText()) old_joint_key = find_key(self.skeleton_model["joints"], joint_knob.joint_name) if old_joint_key in self.skeleton_model["joints"]: self.skeleton_model["joints"][old_joint_key] = None self.skeleton_model["joints"][ new_joint_key] = joint_knob.joint_name print("update joint mapping", joint_knob.joint_name, new_joint_key) else: print("is updating joint info") def reset_joint_cos(self, joint_name, up_vector, x_vector, target_up_vector=DEFAULT_TARGET_CS_UP): """ rotates the up_vector to look towards target_up_vector and rotates the x_vector with the same rotation """ m = self.skeleton.nodes[joint_name].get_global_matrix( self.skeleton.reference_frame)[:3, :3] m_inv = np.linalg.inv(m) target_up_vector = normalize(target_up_vector) local_target = np.dot(m_inv, target_up_vector) local_target = normalize(local_target) q = quaternion_from_vector_to_vector(up_vector, local_target) x_vector = rotate_vector(q, x_vector) x_vector -= x_vector.dot( local_target) * local_target # make it orthogonal to twist x_vector /= np.linalg.norm(x_vector) # normalize it x_vector = normalize(x_vector) return local_target, x_vector def slot_update_aligning_root_joint(self): if not self.is_updating_joint_info and "joints" in self.skeleton_model: self.aligning_root_node = str( self.aligningRootComboBox.currentText()) def slot_load_default_pose(self): filename = QFileDialog.getOpenFileName(self, 'Load From File', '.')[0] filename = str(filename) if os.path.isfile(filename): motion = load_motion_from_bvh(filename) if len(motion.frames): self.reference_frame = motion.frames[0] frames = [self.reference_frame] self.controller.replace_frames(frames) self.controller.set_reference_frame(0) self.controller.updateTransformation() print("replaced frames") def slot_apply_scale(self): scale = float(self.scaleLineEdit.text()) if scale > 0: self.controller.set_scale(scale) frames = [self.reference_frame] self.controller.replace_frames(frames) self.controller.currentFrameNumber = 0 self.controller.updateTransformation() def slot_align_to_up_axis(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name if joint_name in self.skeleton_model["cos_map"]: up_vector = self.skeleton_model["cos_map"][joint_name]["y"] x_vector = self.skeleton_model["cos_map"][joint_name]["x"] q_offset = get_axis_correction(self.skeleton, joint_name, up_vector, OPENGL_UP_AXIS) up_vector = rotate_vector(q_offset, up_vector) x_vector = rotate_vector(q_offset, x_vector) self.skeleton_model["cos_map"][joint_name]["x"] = normalize( x_vector) self.skeleton_model["cos_map"][joint_name]["y"] = normalize( up_vector) self.update_joint_info(joint_knob) def slot_align_to_forward_axis(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name if joint_name in self.skeleton_model["cos_map"]: up_vector = self.skeleton_model["cos_map"][joint_name]["y"] m = self.skeleton.nodes[joint_name].get_global_matrix( self.skeleton.reference_frame)[:3, :3] m_inv = np.linalg.inv(m) target_vector = np.dot(m, up_vector) target_vector[1] = 0 target_vector = normalize(target_vector) local_up = np.dot(m_inv, target_vector) local_up = normalize(local_up) self.skeleton_model["cos_map"][joint_name]["y"] = local_up x_vector = self.skeleton_model["cos_map"][joint_name]["x"] q = quaternion_from_vector_to_vector(up_vector, local_up) x_vector = rotate_vector(q, x_vector) x_vector -= x_vector.dot( local_up) * local_up # make it orthogonal to twist x_vector /= np.linalg.norm(x_vector) # normalize it self.skeleton_model["cos_map"][joint_name]["x"] = normalize( x_vector) self.update_joint_info(joint_knob) def slot_mirror_left_to_right(self): self.skeleton_model = mirror_join_map(self.skeleton, self.skeleton_model, STANDARD_MIRROR_MAP_LEFT) print("mirrored left to right") print(self.skeleton_model["joints"]) def slot_mirror_right_to_left(self): self.skeleton_model = mirror_join_map(self.skeleton, self.skeleton_model, STANDARD_MIRROR_MAP_RIGHT) print("mirrored right to left")
class SessionTracker: """Class containing the necessary data to track a stations sessions Paramaters: station(Station): Station to track the times on """ def __init__(self, station: Station, tracked_sessions: List[Session] = []): self.station = station self.windows = self.station.windows self.stationID = self.station.stationID self.tracked_sessions = tracked_sessions # -Setup- self._initialize_timers() self._initialize_binds() self.refresh() # -Initialize methods- def _initialize_timers(self): """ Set up timers here """ # Refresh timer self.timer = QTimer() self.timer.timeout.connect(self.refresh) self.timer.start(2500) def _initialize_binds(self): """ Bind the buttons of this station to """ reconnect(self.windows['main'].findChild(QPushButton, f"pushButton_statistics_showSessions_{self.stationID}").clicked, self.clicked_showSessions) # nopep8 def refresh(self): """ Refresh this statistics tracker: - Sort tracked sessions - Update visibility - Update texts - Update table """ self.tracked_sessions = sorted(self.tracked_sessions, key=lambda s: s.start_date) self._update_visibility() self._update_texts(sessions=self.tracked_sessions) if self.windows['history'].property('stationID') == self.stationID: self._historyWindow_updateTable(sessions=self.tracked_sessions) def update(self, tracked_sessions: list, override: bool): """Update the data of this sessionTracker""" new_tracked_sessions = tracked_sessions if not override: # Do not override existing data new_tracked_sessions.append(self.tracked_sessions) self.tracked_sessions = new_tracked_sessions self.refresh() def extract_data(self) -> Union[dict, None]: """ Extract the data of this tracker Returns(dict or None): Full data of the session history or None if the parent station does not have a registered device """ if self.station.device is None: # No device registered for this station return None data = { 'deviceID': self.station.device.deviceID, 'tracked_sessions': self.tracked_sessions } return data # -Session tracking- def add_session_to_history(self, session: Session): """ Add a session to the session history of this station """ # Search for conflicting sessions for tracked_session in self.tracked_sessions: if tracked_session.range_conflicts(start_date=session.start_date, end_date=session.end_date): # Two tracked sessions might conflict if the user # finished one session and then set up a session that # happened during that previous sessions time range # Action: Override old session self.tracked_sessions.remove(tracked_session) self.tracked_sessions.append(session) self.refresh() def calculate_stats(self, sessions: list) -> dict: """ Return the stats displayed on the application """ if not len(sessions): # No tracked sessions session_history = { 'total_time': dt.time(hour=0, minute=0), 'average_time': dt.time(hour=0, minute=0), 'total_sessions': 0, 'average_sessions': 0, } return session_history session_history = {} total_minutes = 0 # -Total time- for session in sessions: total_minutes += session.duration.hour * 60 total_minutes += session.duration.minute hours, minutes = divmod(total_minutes, 60) session_history['total_time'] = dt.time(hour=hours, minute=minutes) # -Average session time- average_minutes = int(total_minutes / len(sessions)) hours, minutes = divmod(average_minutes, 60) session_history['average_time'] = dt.time(hour=hours, minute=minutes) # -Total sessions- session_history['total_sessions'] = len(sessions) # -Average sessions/day- dates = [] for session in sessions: start_date = session.start_date.date() if start_date in dates: continue else: dates.append(start_date) average_sessions = round(len(sessions) / len(dates), 1) if average_sessions.is_integer(): average_sessions = int(average_sessions) session_history['average_sessions'] = average_sessions return session_history # -Button clicks- def clicked_showSessions(self): """ Show a table of the sessions history """ # -Window Setup- # Set variable if self.station.device is not None: # Device is registered self.windows['history'].label.setText(f'{self.station.device.deviceName} Session History') else: self.windows['history'].label.setText(f'N/A Session History') # Set stationID self.windows['history'].setProperty('stationID', self.stationID) # Reshow window self.windows['history'].setWindowFlag(Qt.WindowStaysOnTopHint) self.windows['history'].show() # Focus window self.windows['history'].activateWindow() self.windows['history'].raise_() # -Fill List- self.refresh() def _historyWindow_updateTable(self, sessions: list): """ Update the history table """ headers = ['Date', 'Customer Name', 'Start Time', 'End Time'] headerTranslator = { 'Date': 'date', 'Customer Name': 'customerName', 'Start Time': 'start_date', 'End Time': 'end_date', 'Total Time': 'duration', } tableWidget = self.windows['history'].tableWidget_history tableWidget.setRowCount(0) # Base widget settings tableWidget.setRowCount(len(sessions)) tableWidget.setColumnCount(len(headers)) tableWidget.setHorizontalHeaderLabels(headers) # -Set column widths- column_width = 90 tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) tableWidget.setColumnWidth(0, column_width + 20) tableWidget.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) tableWidget.setColumnWidth(2, column_width) tableWidget.setColumnWidth(3, column_width) # -Fill table- for row in range(tableWidget.rowCount()): session = sessions[row] session_data = session.extract_data() session_data['end_date'] = session.end_date for col, header_key in enumerate(headers): key = headerTranslator[header_key] if key == 'date': data = session_data['start_date'].strftime(r'%d.%m.%Y') else: data = session_data[key] if type(data) in (dt, dt.date, dt.datetime, dt.time): data = data.strftime('%H:%M') item = QTableWidgetItem(str(data)) item.setTextAlignment(Qt.AlignCenter) tableWidget.setItem(row, col, item) def _update_visibility(self): """ Check whether to hide or show this station """ station_frame = self.windows['main'].findChild(QWidget, f"frame_station_{self.stationID}") statistic_frame = self.windows['main'].findChild(QWidget, f"frame_statistics_{self.stationID}") if station_frame.isHidden(): # Parent station is hidden # Hide the tracker as well statistic_frame.setHidden(True) else: statistic_frame.setHidden(False) def _update_texts(self, sessions: list): """ Update the text elements of the statistics """ # -Get Values- session_history = self.calculate_stats(sessions) total_time = session_history['total_time'].strftime('%H:%M') average_time = session_history['average_time'].strftime('%H:%M') total_sessions = str(session_history['total_sessions']) average_sessions = str(session_history['average_sessions']) # -Update texts- self.windows['main'].findChild(QLabel, f"label_statistics_totalTimeValue_{self.stationID}").setText(total_time) self.windows['main'].findChild(QLabel, f"label_statistics_avgSessionTimeValue_{self.stationID}").setText(average_time) # nopep8 self.windows['main'].findChild(QLabel, f"label_statistics_totalSessionsValue_{self.stationID}").setText(total_sessions) # nopep8 self.windows['main'].findChild(QLabel, f"label_statistics_avgSessionDayValue_{self.stationID}").setText(average_sessions) # nopep8 if self.station.device is not None: # Device is registered self.windows['main'].findChild(QLabel, f"label_statistics_deviceName_{self.stationID}").setText(self.station.device.deviceName) # nopep8 else: self.windows['main'].findChild(QLabel, f"label_statistics_deviceName_{self.stationID}").setText('N/A')
def __init__(self, ui): """ Dialog to import Datapool items :param modules.gui.main_ui.KnechtWindow ui: Main Window """ super(DatapoolDialog, self).__init__(ui) SetupWidget.from_ui_file(self, Resource.ui_paths['knecht_datapool']) self.setWindowTitle('Datapool Import') self._asked_for_close = False self._current_project_name = '' self.ui = ui # Avoid db/thread polling within timeout self.action_timeout = QTimer() self.action_timeout.setSingleShot(True) self.action_timeout.setInterval(300) # --- Translations n Style --- self.project_icon: QLabel self.project_icon.setPixmap(IconRsc.get_pixmap('storage')) self.project_title: QLabel self.project_title.setText(_('Datapool Projekte')) self.image_icon: QLabel self.image_icon.setPixmap(IconRsc.get_pixmap('img')) self.image_title: QLabel self.image_title.setText(_('Bildeinträge')) self.details_btn: QPushButton self.details_btn.setText(_('Detailspalten anzeigen')) self.details_btn.toggled.connect(self.toggle_view_columns) self.filter_box: QLineEdit self.filter_box.setPlaceholderText( _('Im Baum tippen um zu filtern...')) # -- Trigger filter update for all views --- self.update_filter_timer = QTimer() self.update_filter_timer.setInterval(5) self.update_filter_timer.setSingleShot(True) self.update_filter_timer.timeout.connect(self.update_filter_all_views) self.filter_box: QLineEdit self.filter_box.textChanged.connect(self.update_filter_timer.start) # --- Init Tree Views --- self.project_view = KnechtTreeViewCheckable( self, None, filter_widget=self.filter_box, replace=self.project_view) self.image_view = KnechtTreeViewCheckable( self, None, filter_widget=self.filter_box, replace=self.image_view) # --- Database Connector --- self.dp = DatapoolController(self) self.dp.add_projects.connect(self.update_project_view) self.dp.add_images.connect(self.update_image_view) self.dp.error.connect(self.error) # Connection timeout self.connection_timeout = QTimer() self.connection_timeout.setInterval(self.timeout) self.connection_timeout.setSingleShot(True) self.connection_timeout.timeout.connect(self.connection_timed_out) # Make sure to end thread on App close self.ui.is_about_to_quit.connect(self.close) # Intercept mouse press events from project view self.org_view_mouse_press_event = self.project_view.mousePressEvent self.project_view.mousePressEvent = self.view_mouse_press_event # Start thread QTimer.singleShot(100, self.start_datapool_connection)
class MainController: PING_RATE_MS = 3000 def __init__(self): self.window = MainWindow() self.network_access_manager = QNetworkAccessManager(self.window) self.window.controllers_mdi.tileSubWindows() self.ping_timer = QTimer(self.window) self.detected_devices = {} self.open_devices = {} self.ssdp_interface = SSDPInterface(parent=self.window) self.ssdp_interface.new_device.connect(self.device_info_received) self.window.refresh_button.clicked.connect(self.refresh_clicked) self.ping_timer.timeout.connect(self.ssdp_interface.ping_devices) self.window.auto_ping.stateChanged.connect(self.auto_ping_changed) self.window.camera_list.itemDoubleClicked.connect( self.item_double_clicked) if self.window.auto_ping.isChecked(): print("Starting auto ping") self.ping_timer.start(MainController.PING_RATE_MS) def refresh_clicked(self): self.window.camera_list.clear() self.detected_devices.clear() self.ssdp_interface.ping_devices() def auto_ping_changed(self, state): if state == Qt.Checked: if not self.ping_timer.isActive(): print("Starting auto ping") self.ping_timer.start(MainController.PING_RATE_MS) else: print("Stopping auto ping") self.ping_timer.stop() def show(self): self.window.show() def device_info_received(self, cam_desc: CamDesc): add_string = cam_desc.host.toString() if add_string not in self.detected_devices: self.detected_devices[add_string] = cam_desc self.window.camera_list.addItem(add_string) if self.window.open_automatically.isChecked(): self.open_controller(add_string) def item_double_clicked(self, item: QtWidgets.QListWidgetItem): self.open_controller(item.text()) def open_controller(self, add_string): if add_string in self.open_devices: return print(f"Opening controller for {add_string}") cam_controller = CameraController(self, self.detected_devices[add_string], self.window.controllers_mdi) self.open_devices[add_string] = cam_controller def controller_closed(self, add_string): self.open_devices.pop(add_string)
class MainWindow(QObject): def __init__(self): QObject.__init__(self) # Creating a timer self.timer = QTimer() self.timer.timeout.connect(lambda: self.setTime()) self.timer.start(1000) # Signal Set name setName = Signal(str) # print time printTime = Signal(str) # Recieve switch status signal isVisible = Signal(bool) # Signal for read text readTextSignal = Signal(str) # Text string textField = "" # Set time slot def setTime(self): now = datetime.datetime.now() formattedTime = now.strftime("The time is %I:%M:%S %p in %Y-%m-%d") # print(formattedTime) self.printTime.emit(formattedTime) # set the slot @Slot(str) def welcomeText(self, name): self.setName.emit("Welcome, " + name) # Act on the switch status signal @Slot(bool) def showHideRectangle(self, isChecked): print("Rectangle visible ", isChecked) self.isVisible.emit(isChecked) # function to open file @Slot(str) def openFile(self, filePath): file = open(QUrl(filePath).toLocalFile(), encoding="utf-8") textRead = file.read() file.close() print(textRead) self.readTextSignal.emit(str(textRead)) # function to receive text file that has been modified @Slot(str) def getTextFile(self, text): self.textField = text @Slot(str) def writeFile(self, filePath): file = open(QUrl(filePath).toLocalFile(), "w") file.write(self.textField) file.close() print(self.textField)
## $QT_END_LICENSE$ ## ############################################################################# from __future__ import print_function import os import sys from PySide2.QtCore import QTimer, QUrl from PySide2.QtGui import QGuiApplication from PySide2.QtQuick import QQuickView if __name__ == '__main__': app = QGuiApplication(sys.argv) timer = QTimer() timer.start(2000) view = QQuickView() qmlFile = os.path.join(os.path.dirname(__file__), 'view.qml') view.setSource(QUrl.fromLocalFile(os.path.abspath(qmlFile))) if view.status() == QQuickView.Error: sys.exit(-1) root = view.rootObject() timer.timeout.connect(root.updateRotater) view.show() res = app.exec_() # Deleting the view before it goes out of scope is required to make sure all child QML instances # are destroyed in the correct order.
def __init__(self): super(BoidsApp, self).__init__() self.setWindowTitle('Boids') self._boids_environment = BoidsEnvironment() layout = QHBoxLayout() self._boids_widget = BoidsWidget() self._boids_widget.set_boids_environment(self._boids_environment) self._boids_widget.setMinimumWidth(550) self._form_layout = QFormLayout() self._is_running_checkbox = QCheckBox() self._is_running_checkbox.setChecked(True) self._is_running_checkbox.stateChanged.connect( self.__is_running_changed) self._tick_button = QPushButton() self._tick_button.setText('Tick') self._tick_button.clicked.connect(self.__do_tick) self._total_spinbox = _make_spinbox(TOTAL_BOIDS, 0, 9999) self._total_spinbox.valueChanged.connect(self.__total_changed) self._max_speed_spinbox = _make_double_spinbox(DEFAULT_MAX_SPEED, 0.0, 9999.0, 0.1) self._max_speed_spinbox.valueChanged.connect(self.__max_speed_changed) self._eyesight_radius_spinbox = _make_double_spinbox( DEFAULT_MAX_DISTANCE, 0.0, 9999.0, 0.5) self._eyesight_radius_spinbox.valueChanged.connect( self.__eyesight_radius_changed) self._eyesight_angle_spinbox = _make_double_spinbox( DEFAULT_EYE_SIGHT_ANGLE, 0.0, 360.0, 1.0) self._eyesight_angle_spinbox.valueChanged.connect( self.__eyesight_angle_changed) self._separation_distance_spinbox = _make_double_spinbox( SEPARATION_DISTANCE, 0.0, 9999.0, 1.0) self._separation_distance_spinbox.valueChanged.connect( self.__separation_distance_changed) self._separation_value_spinbox = _make_double_spinbox( SEPARATION_VALUE, 0.0, 1.0, 0.1) self._separation_value_spinbox.valueChanged.connect( self.__separation_value_changed) self._cohesion_value_spinbox = _make_double_spinbox( COHESION_VALUE, 0.0, 1.0, 0.1) self._cohesion_value_spinbox.valueChanged.connect( self.__cohesion_value_changed) self._alignment_value_spinbox = _make_double_spinbox( ALIGNMENT_VALUE, 0.0, 1.0, 0.1) self._alignment_value_spinbox.valueChanged.connect( self.__alignment_value_changed) self._generate_button = QPushButton() self._generate_button.setText('Generate') self._generate_button.clicked.connect(self._generate_environment) self._form_layout.addRow('Total Boids', self._total_spinbox) self._form_layout.addRow('Separation', self._separation_value_spinbox) self._form_layout.addRow('Cohesion', self._cohesion_value_spinbox) self._form_layout.addRow('Alignment', self._alignment_value_spinbox) self._form_layout.addRow('Max Speed', self._max_speed_spinbox) self._form_layout.addRow('Eyesight Radius', self._eyesight_radius_spinbox) self._form_layout.addRow('Eyesight Angle (degrees)', self._eyesight_angle_spinbox) self._form_layout.addRow('Separation Distance', self._separation_distance_spinbox) self._form_layout.addRow('Running', self._is_running_checkbox) self._form_layout.addWidget(self._generate_button) self._form_layout.addWidget(self._tick_button) layout.addWidget(self._boids_widget) layout.addLayout(self._form_layout) self.setLayout(layout) self.tick_timer = QTimer() self.tick_timer.setInterval(int(1000 / 24)) self.tick_timer.timeout.connect(self._tick) self.tick_timer.start()
def _single_shot(self, timeout_ms: int, func: Callable[[], Any]): timer = QTimer(parent=self.test_qobj) timer.setSingleShot(True) timer.setInterval(timeout_ms) timer.timeout.connect(func) timer.start()
def start(_exit: bool = False) -> None: app = QApplication(sys.argv) first_start = False if not os.path.isfile(STATE_FILE): first_start = True logo = QIcon(LOGO) main_window = MainWindow() ui = main_window.ui main_window.setWindowIcon(logo) tray = QSystemTrayIcon(logo, app) tray.activated.connect(main_window.systray_clicked) menu = QMenu() action_show = QAction("Show") action_show.triggered.connect(main_window.show) action_exit = QAction("Exit") action_exit.triggered.connect(app.exit) menu.addAction(action_show) menu.addAction(action_exit) tray.setContextMenu(menu) ui.text.textChanged.connect(partial(queue_text_change, ui)) ui.command.textChanged.connect(partial(update_button_command, ui)) ui.keys.textChanged.connect(partial(update_button_keys, ui)) ui.write.textChanged.connect(partial(update_button_write, ui)) ui.change_brightness.valueChanged.connect(partial(update_change_brightness, ui)) ui.switch_page.valueChanged.connect(partial(update_switch_page, ui)) ui.imageButton.clicked.connect(partial(select_image, main_window)) ui.brightness.valueChanged.connect(partial(set_brightness, ui)) items = api.open_decks().items() print("wait for device(s)") while len(items) == 0: time.sleep(3) items = api.open_decks().items() print("found " + str(len(items))) for deck_id, deck in items: ui.information.currentIndexChanged.connect(partial(set_information, ui)) for deck_id, deck in api.open_decks().items(): ui.device_list.addItem(f"{deck['type']} - {deck_id}", userData=deck_id) build_device(ui) ui.device_list.currentIndexChanged.connect(partial(build_device, ui)) ui.pages.currentChanged.connect(partial(change_page, ui)) ui.actionExport.triggered.connect(partial(export_config, main_window)) ui.actionImport.triggered.connect(partial(import_config, main_window)) ui.actionExit.triggered.connect(app.exit) timer = QTimer() timer.timeout.connect(partial(sync, ui)) timer.start(1000) api.init_http_images() api.render() tray.show() if first_start: main_window.show() if _exit: return else: sys.exit(app.exec_()) if __name__ == "__main__": start()
class TaskForm(QFrame): def __init__(self, parent): super().__init__() self.parent = parent self.setupUi() self.timer = QTimer() self.timer.timeout.connect(self.progress_flash) def setupUi(self): self.setWindowTitle('设置任务详情') self.flayout = QFormLayout(self) form_dict = dict(关键词=QLineEdit(), 休息数量=QLineEdit(), 休息间隔=QLineEdit(), 持续时间=QLineEdit()) form_data_dict = dict() for i in form_dict: if i == '休息数量': form_data_dict[i] = '20' form_dict[i].setPlaceholderText('单位:个;默认20个') elif i == '休息间隔': form_data_dict[i] = '10' form_dict[i].setPlaceholderText('单位:秒;默认10秒') elif i == '持续时间': form_data_dict[i] = '45' form_dict[i].setPlaceholderText('单位:分钟;默认45分钟') else: form_data_dict[i] = '' form_dict[i].setPlaceholderText('关键词') form_dict[i].textChanged.connect(self.on_text_changed(i)) self.flayout.addRow(i, form_dict[i]) start_btn = QPushButton('开始任务') start_btn.clicked.connect(self.on_start_task) self.flayout.addRow(start_btn) self.form_data_dict = form_data_dict self.resize(260, 180) self.show() def on_text_changed(self, which): def handle_text_changed(value): self.form_data_dict[which] = value return handle_text_changed def on_start_task(self): if not self.form_data_dict['关键词']: return QMessageBox.warning(self, '错误提示', '请输入关键词', QMessageBox.Ok) self.hide() self.working = True self.run_task() def run_task(self): self.parent.hub.run(form_data_dict=self.form_data_dict, serial=self.parent.serial) self.task = self.parent.hub.task_pool[self.parent.serial] self.parent.total_time_left.setRange( 0, int(self.task.form_data_dict['持续时间']) * 60) self.parent.qty_left.setRange(0, int(self.task.form_data_dict['休息数量'])) self.timer.start(1000) # self.pthread = PThread(self) # self.pthread.start() def progress_flash(self): self.task = self.parent.hub.task_pool[self.parent.serial] self.parent.total_time_left.setValue( int(time.time() - self.task.start_at)) self.parent.qty_left.setValue(int(self.task.qty)) print(time.time() - self.task.start_at)
def __init__(self, name, skeleton, share_widget, parent=None, enable_line_edit=False, skeleton_model=None): self.initialized = False QDialog.__init__(self, parent) Ui_Dialog.setupUi(self, self) self.view = SceneViewerWidget(parent, share_widget, size=(400, 400)) self.view.setObjectName("left") self.view.setMinimumSize(400, 400) self.view.initializeGL() self.nameLineEdit.setText(name) self.nameLineEdit.setEnabled(enable_line_edit) self.name = name self.view.enable_mouse_interaction = True self.view.mouse_click.connect(self.on_mouse_click) self.viewerLayout.addWidget(self.view) self.radius = 1.0 self.fps = 60 self.dt = 1 / 60 self.timer = QTimer() self.timer.timeout.connect(self.draw) self.timer.start(0) self.timer.setInterval(1000.0 / self.fps) self.skeleton = skeleton self.view.makeCurrent() self.scene = EditorScene(True) self.scene.enable_scene_edit_widget = True if skeleton_model is not None: self.skeleton_model = skeleton_model elif skeleton.skeleton_model is not None: self.skeleton_model = skeleton.skeleton_model else: self.skeleton_model = dict() print("create new skeleton model") if "cos_map" not in self.skeleton_model: self.skeleton_model["cos_map"] = dict() if "joints" not in self.skeleton_model: self.skeleton_model["joints"] = dict() if "joint_constraints" not in self.skeleton_model: self.skeleton_model["joint_constraints"] = dict() motion_vector = MotionVector() self.reference_frame = skeleton.reference_frame print(self.reference_frame[:3]) motion_vector.frames = [skeleton.reference_frame] motion_vector.n_frames = 1 o = self.scene.object_builder.create_object("animation_controller", "skeleton", skeleton, motion_vector, skeleton.frame_time) self.controller = o._components["animation_controller"] self.skeleton = self.controller.get_skeleton() self.skeleton_vis = o._components["skeleton_vis"] self.init_joints(self.controller) self.fill_joint_map() self.selectButton.clicked.connect(self.slot_accept) self.cancelButton.clicked.connect(self.slot_reject) self.applyTwistRotationButton.clicked.connect(self.slot_set_twist) self.applySwingRotationButton.clicked.connect(self.slot_set_swing) self.setOrthogonalTwistButton.clicked.connect( self.slot_set_orthogonal_twist) self.setOrthogonalSwingButton.clicked.connect( self.slot_set_orthogonal_swing) self.rotateTwistButton.clicked.connect(self.slot_rotate_twist) self.rotateSwingButton.clicked.connect(self.slot_rotate_swing) self.flipTwistButton.clicked.connect(self.slot_flip_twist) self.flipSwingButton.clicked.connect(self.slot_flip_swing) self.flipZAxisButton.clicked.connect(self.slot_flip_z_axis) self.alignToUpAxisButton.clicked.connect(self.slot_align_to_up_axis) self.alignToForwardAxisButton.clicked.connect( self.slot_align_to_forward_axis) self.guessSelectedButton.clicked.connect( self.slot_guess_selected_cos_map) self.resetSelectedCosButton.clicked.connect( self.slot_reset_selected_cos_map) self.guessAllCosButton.clicked.connect(self.slot_guess_cos_map) self.resetAllCosButton.clicked.connect(self.slot_reset_cos_map) self.loadDefaultPoseButton.clicked.connect(self.slot_load_default_pose) self.applyScaleButton.clicked.connect(self.slot_apply_scale) self.jointMapComboBox.currentIndexChanged.connect( self.slot_update_joint_map) self.aligningRootComboBox.currentIndexChanged.connect( self.slot_update_aligning_root_joint) self.mirrorLeftButton.clicked.connect(self.slot_mirror_left_to_right) self.mirrorRightButton.clicked.connect(self.slot_mirror_right_to_left) self.is_updating_joint_info = False self.success = False self.initialized = False self.skeleton_data = None self.precision = 3 self.aligning_root_node = self.skeleton.aligning_root_node self.fill_root_combobox() self.init_aligning_root_node()
def __init__(self, tracker, connectivity_service, priority, obj_id, obj_size, file_path, display_name, file_hash=None, parent=None, files_info=None): QObject.__init__(self, parent=parent) self._tracker = tracker self._connectivity_service = connectivity_service self.priority = priority self.size = obj_size self.id = obj_id self.file_path = file_path self.file_hash = file_hash self.download_path = file_path + '.download' self._info_path = file_path + '.info' self.display_name = display_name self.received = 0 self.files_info = files_info self.hash_is_wrong = False self._ready = False self._started = False self._paused = False self._finished = False self._no_disk_space_error = False self._wanted_chunks = SortedDict() self._downloaded_chunks = SortedDict() self._nodes_available_chunks = dict() self._nodes_requested_chunks = dict() self._nodes_last_receive_time = dict() self._nodes_downloaded_chunks_count = dict() self._nodes_timeouts_count = dict() self._total_chunks_count = 0 self._file = None self._info_file = None self._started_time = time() self._took_from_turn = 0 self._received_via_turn = 0 self._received_via_p2p = 0 self._retry = 0 self._limiter = None self._init_wanted_chunks() self._on_downloaded_cb = None self._on_failed_cb = None self.download_complete.connect(self._on_downloaded) self.download_failed.connect(self._on_failed) self._timeout_timer = QTimer(self) self._timeout_timer.setInterval(15 * 1000) self._timeout_timer.setSingleShot(False) self._timeout_timer.timeout.connect(self._on_check_timeouts) self._leaky_timer = QTimer(self) self._leaky_timer.setInterval(1000) self._leaky_timer.setSingleShot(True) self._leaky_timer.timeout.connect(self._download_chunks) self._network_limited_error_set = False
def __init__(self): super().__init__() self.imit_peop = threading.Thread(target=imitation_people, args=()) self._timer = QTimer() self.loadFinished.connect(self.startTimer) self._timer.timeout.connect(self.start_thread_imitation)
class DatapoolDialog(QDialog): finished = Signal(KnechtModel, Path) check_column = Kg.NAME # Close connection after 10 minutes of user inactivity timeout = 600000 def __init__(self, ui): """ Dialog to import Datapool items :param modules.gui.main_ui.KnechtWindow ui: Main Window """ super(DatapoolDialog, self).__init__(ui) SetupWidget.from_ui_file(self, Resource.ui_paths['knecht_datapool']) self.setWindowTitle('Datapool Import') self._asked_for_close = False self._current_project_name = '' self.ui = ui # Avoid db/thread polling within timeout self.action_timeout = QTimer() self.action_timeout.setSingleShot(True) self.action_timeout.setInterval(300) # --- Translations n Style --- self.project_icon: QLabel self.project_icon.setPixmap(IconRsc.get_pixmap('storage')) self.project_title: QLabel self.project_title.setText(_('Datapool Projekte')) self.image_icon: QLabel self.image_icon.setPixmap(IconRsc.get_pixmap('img')) self.image_title: QLabel self.image_title.setText(_('Bildeinträge')) self.details_btn: QPushButton self.details_btn.setText(_('Detailspalten anzeigen')) self.details_btn.toggled.connect(self.toggle_view_columns) self.filter_box: QLineEdit self.filter_box.setPlaceholderText( _('Im Baum tippen um zu filtern...')) # -- Trigger filter update for all views --- self.update_filter_timer = QTimer() self.update_filter_timer.setInterval(5) self.update_filter_timer.setSingleShot(True) self.update_filter_timer.timeout.connect(self.update_filter_all_views) self.filter_box: QLineEdit self.filter_box.textChanged.connect(self.update_filter_timer.start) # --- Init Tree Views --- self.project_view = KnechtTreeViewCheckable( self, None, filter_widget=self.filter_box, replace=self.project_view) self.image_view = KnechtTreeViewCheckable( self, None, filter_widget=self.filter_box, replace=self.image_view) # --- Database Connector --- self.dp = DatapoolController(self) self.dp.add_projects.connect(self.update_project_view) self.dp.add_images.connect(self.update_image_view) self.dp.error.connect(self.error) # Connection timeout self.connection_timeout = QTimer() self.connection_timeout.setInterval(self.timeout) self.connection_timeout.setSingleShot(True) self.connection_timeout.timeout.connect(self.connection_timed_out) # Make sure to end thread on App close self.ui.is_about_to_quit.connect(self.close) # Intercept mouse press events from project view self.org_view_mouse_press_event = self.project_view.mousePressEvent self.project_view.mousePressEvent = self.view_mouse_press_event # Start thread QTimer.singleShot(100, self.start_datapool_connection) def view_mouse_press_event(self, event: QMouseEvent): if event.buttons( ) == Qt.LeftButton and not self.action_timeout.isActive(): idx = self.project_view.indexAt(event.pos()) name = idx.siblingAtColumn(Kg.NAME).data(Qt.DisplayRole) self._current_project_name = name _id = idx.siblingAtColumn(Kg.ID).data(Qt.DisplayRole) LOGGER.debug('Project %s Id %s selected', name, _id) self.action_timeout.start() if _id: self.request_project(_id) self.org_view_mouse_press_event(event) def update_filter_all_views(self): # Do not filter project view self.project_view.filter_timer.stop() # Update image view filter if not self.filter_box.text(): self.image_view.clear_filter() else: self.image_view.filter_timer.start() def start_datapool_connection(self): self.show_progress(_('Verbinde mit Datenbank')) self.dp.start() self.connection_timeout.start() @Slot(dict) def update_project_view(self, projects: dict): """ (Name, ModelYear, 'JobNo) """ if not projects: return root_item = KnechtItem( None, ('', _('Bezeichnung'), _('Modelljahr'), _('Job'), '', _('Id'))) for num_idx, (_id, project_data) in enumerate(projects.items()): data = (f'{num_idx:03d}', *project_data, '', str(_id)) p_item = KnechtItem(root_item, data) KnechtItemStyle.style_column(p_item, 'render_preset', column=Kg.NAME) root_item.append_item_child(p_item) update_model = UpdateModel(self.project_view) update_model.update(KnechtModel(root_item)) self.toggle_view_columns(self.details_btn.isChecked()) self.project_view.setHeaderHidden(False) def request_project(self, _id: str): self.image_view.clear_filter() self.image_view.progress_msg.msg(_('Daten werden angefordert')) self.image_view.progress_msg.show_progress() self.dp.request_project(_id) self.connection_timeout.start() @Slot(dict) def update_image_view(self, images: dict): if not images: return root_item = KnechtItem(None, ('', _('Name'), _('Priorität'), _('Erstellt'), '', _('wagenbauteil Id'))) for num_idx, (img_id, image_data) in enumerate(images.items()): """ (name, priority, created, pr_string, opt_id, produced_image_id) """ name, priority, created, pr_string, opt_id, produced_image_id = image_data img_item = KnechtItem( root_item, (f'{num_idx:03d}', name, priority, created, '', str(opt_id))) KnechtItemStyle.style_column(img_item, 'preset', Kg.NAME) root_item.append_item_child(img_item) update_model = UpdateModel(self.image_view) update_model.update( KnechtModel(root_item, checkable_columns=[self.check_column])) self.toggle_view_columns(self.details_btn.isChecked()) self.image_view.setHeaderHidden(False) self.image_view.check_items([], Kg.NAME, check_all=True) def create_presets(self): root_item = KnechtItem() for (src_index, item) in self.image_view.editor.iterator.iterate_view(): if item.data(self.check_column, Qt.CheckStateRole) == Qt.Unchecked: continue name = item.data(Kg.NAME) data = (f'{root_item.childCount():03d}', name, '', 'preset', '', Kid.convert_id(f'{root_item.childCount()}')) root_item.insertChildren(root_item.childCount(), 1, data) date = datetime.datetime.now().strftime('%Y%m%d') project = self._current_project_name.replace(' ', '_') self.finished.emit(KnechtModel(root_item), Path(f'{date}_{project}.xml')) def toggle_view_columns(self, checked: bool): columns = { Kg.ORDER, Kg.NAME, Kg.VALUE, Kg.TYPE, Kg.REF, Kg.ID, Kg.DESC } if checked: show_columns = {Kg.NAME, Kg.VALUE, Kg.TYPE, Kg.ID} else: show_columns = {Kg.NAME} for col in columns: self.project_view.setColumnHidden(col, col not in show_columns) self.image_view.setColumnHidden(col, col not in show_columns) self._setup_view_headers() def _setup_view_headers(self): setup_header_layout(self.project_view) setup_header_layout(self.image_view) @Slot(str) def error(self, error_msg): self.project_view.progress_msg.hide_progress() self.image_view.progress_msg.hide_progress() self.ui.msg(error_msg, 9000) @Slot(str) def show_progress(self, msg: str): self.project_view.progress_msg.msg(msg) self.project_view.progress_msg.show_progress() self.image_view.progress_msg.msg(_('Projekt auswählen')) self.image_view.progress_msg.show_progress() self.image_view.progress_msg.progressBar.setValue(0) def connection_timed_out(self): self.show_progress(_('Zeitüberschreitung')) self.ui.msg( _('Zeitüberschreitung bei Datenbankverbindung. Die Verbindung wurde automatisch getrennt.' ), 12000) self.dp.close() def reject(self): self.close() def accept(self): self.create_presets() self._asked_for_close = True self.close() def closeEvent(self, close_event): LOGGER.debug('Datapool close event called. %s', close_event.type()) if self._ask_abort_close(): close_event.ignore() return False LOGGER.info( 'Datapool window close event triggered. Aborting database connection' ) # End thread if not self._finalize_dialog(): close_event.ignore() return False close_event.accept() return True def _ask_abort_close(self): if self._asked_for_close: return False msg_box = AskToContinue(self) if not msg_box.ask( title=_('Importvorgang'), txt=_('Soll der Vorgang wirklich abgebrochen werden?'), ok_btn_txt=_('Ja'), abort_btn_txt=_('Nein'), ): # Cancel close return True # Close confirmed return False def _finalize_dialog(self, self_destruct: bool = True) -> bool: LOGGER.debug('Datapool dialog is finishing tasks.') if not self.dp.close(): return False if self_destruct: self.deleteLater() return True
def run(self): self.timer = QTimer() self.timer.timeout.connect(self.frame) self.timer.start(1000 / config.FPS)
def execute_1(): """ after 3 seconds, deactivate and re-activate the app after 3 seconds, re-open and re-activate the app after 3 more seconds, quit :return: """ logger.info("execute_1:begin") cfg = Services.getService("Configuration") rc = Services.getService("RecordingControl") logger.info("app activated") app = cfg.configuration().applicationByName("myApp") t = QTimer() t.setSingleShot(True) t.setInterval(3000) t.start() waitForSignal(t.timeout) execute_1.i = MethodInvoker(cfg.deactivate, Qt.QueuedConnection) waitForSignal(app.activeApplication.stateChanged, lambda s: s == FilterState.CONSTRUCTED) logger.info("app deactivated") execute_1.i = MethodInvoker(cfg.activate, Qt.QueuedConnection) waitForSignal(cfg.configuration().appActivated) if app.activeApplication.getState() != FilterState.ACTIVE: waitForSignal(app.activeApplication.stateChanged, lambda s: s == FilterState.ACTIVE) execute_1.i = MethodInvoker(rc.startRecording, Qt.QueuedConnection, ".") logger.info("app activated") t = QTimer() t.setSingleShot(True) t.setInterval(3000) t.start() waitForSignal(t.timeout) execute_1.i = MethodInvoker(cfg.deactivate, Qt.QueuedConnection) waitForSignal(app.activeApplication.stateChanged, lambda s: s == FilterState.CONSTRUCTED) logger.info("app deactivated") # re-open this application execute_1.i = MethodInvoker(cfg.loadConfig, Qt.QueuedConnection, "basicworkflow.json") waitForSignal(cfg.configuration().configNameChanged) logger.info("config loaded") # activate execute_1.i = MethodInvoker(cfg.changeActiveApp, Qt.QueuedConnection, "myApp") waitForSignal(cfg.configuration().appActivated) execute_1.i = MethodInvoker(cfg.activate, Qt.QueuedConnection) waitForSignal(cfg.configuration().appActivated) if app.activeApplication.getState() != FilterState.ACTIVE: waitForSignal(app.activeApplication.stateChanged, lambda s: s == FilterState.ACTIVE) logger.info("app activated") t = QTimer() t.setSingleShot(True) t.setInterval(3000) t.start() waitForSignal(t.timeout) execute_1.i = MethodInvoker(QCoreApplication.quit, Qt.QueuedConnection) logger.info("execute_1:end")
def testSingleShotSignal(self): emitter = SigEmitter() emitter.sig1.connect(self.callback) QTimer.singleShot(100, emitter.sig1) self.app.exec_() self.assert_(self.called)
def recording(self, gesture): self.core_controller.write_to_file(self.current_path, gesture) self.tips_label.setText('Recording...') QTimer.singleShot(RECORDING_DURATION * 1000, self.stop_recording)
global sec item2.setTransformOriginPoint(300, 100) item2.setRotation(sec) sec += 1 if __name__ == '__main__': app = QApplication(sys.argv) scene = QGraphicsScene(QRectF(0, 0, 1000, 200)) scene.addItem(QGraphicsRectItem(scene.sceneRect())) item1 = createItem(0, scene) sec = 0 item2 = createItem(200, scene) timer = QTimer() timer.setInterval(1000) timer.timeout.connect(timerHandler) # item2.mapToScene(300, 100) # # item2.translate(300, 100) item2.setTransformOriginPoint(300, 100) item2.setRotation(30) # # item2.translate(-300, -100) # item2.mapToScene(-300, -100) item3 = createItem(400, scene) # item3.translate(500, 100) item3.setTransformOriginPoint(500, 100) item3.setScale(0.5) # item3.translate(-500, -100)
class Station: """Station class containing the necessary data to control a single station Paramaters: stationID(int): ID identifier for the station and suffix for all widget names """ DEFAULT_DEVICE = None DEFAULT_CUSTOMERNAME = '' DEFAULT_ACTIVATION = False DEFAULT_SESSIONS = [] def __init__(self, windows, stationID: int, tracked_sessions: List[Session] = []): self.windows = windows # -Main Variables- # Static Paramaters self.stationID = stationID self.device: Union[Device, None] = self.DEFAULT_DEVICE self.sessionTracker = SessionTracker(self, tracked_sessions) # Dynamic Paramaters self._customerName: str = self.DEFAULT_CUSTOMERNAME self._is_activated: bool = self.DEFAULT_ACTIVATION self.sessions: List[Session] = self.DEFAULT_SESSIONS # Helper Variables self._editWindow_shownSessions: List[Session] = [] self.rowTranslator: Dict[int, int] = {} # Connect edit row to sessionID # -Setup- self._initialize_timers() self._initialize_binds() self.hide() self.refresh() @property def is_activated(self): return self._is_activated @is_activated.setter def is_activated(self, value: bool): assert isinstance(value, bool), "is_activated has to be bool" self._is_activated = value if not self.is_activated: # Deactivate station if self.device is not None: # Device is registered self.device.turn_off() self.refresh() @property def customerName(self): return self._customerName @customerName.setter def customerName(self, value: str): assert isinstance(value, str), "customerName has to be str" self._customerName = value self._update_texts() # -Initialize methods- def _initialize_timers(self): """ Set up timers here """ # Refresh timer self.timer = QTimer() self.timer.timeout.connect(self.refresh) self.timer.start(2500) def _initialize_binds(self): """ Bind the buttons of this station to """ reconnect(self.windows['main'].findChild(QPushButton, f"pushButton_newSession_{self.stationID}").clicked, self.clicked_newSession) # nopep8 reconnect(self.windows['main'].findChild(QPushButton, f"pushButton_edit_{self.stationID}").clicked, self.clicked_editSession) # nopep8 reconnect(self.windows['main'].findChild(QPushButton, f"pushButton_toggleState_{self.stationID}").clicked, self.clicked_onOff) # nopep8 # -Station methods- def refresh(self): """ Refresh this station: - Update sessions - Update texts - Update colors - Update Edit Window - Update Statistics Tracker """ self._update_sessions() self._update_texts() self._update_colors() self._editWindow_refresh() self.sessionTracker.refresh() def update(self, **kwargs): """Update the data of this station Paramaters: **kwargs: Data to update the station on """ if 'device' in kwargs: assert (isinstance(kwargs['device'], Device) or kwargs['device'] is None) self.device = kwargs['device'] if 'customerName' in kwargs: assert isinstance(kwargs['customerName'], str) self._customerName = kwargs['customerName'] if 'is_activated' in kwargs: assert isinstance(kwargs['is_activated'], bool) self._is_activated = kwargs['is_activated'] if 'sessions' in kwargs: assert isinstance(kwargs['sessions'], list) self.sessions = kwargs['sessions'].copy() self.refresh() def extract_data(self) -> dict: """ Extract the data of this station Returns(dict): Full data of the station """ data = { 'device': self.device, 'customerName': self.customerName, 'is_activated': self.is_activated, 'sessions': self.sessions, } return data def show(self, **kwargs): """Display the station Paramaters: **kwargs: Data to update the station on """ self.windows['main'].findChild(QWidget, f"frame_station_{self.stationID}").setHidden(False) if kwargs: self.update(**kwargs) self.refresh() def hide(self): """Hide the station""" self.windows['main'].findChild(QWidget, f"frame_station_{self.stationID}").setHidden(True) def reset(self, hide: bool = False): """Reset the data of this station Paramaters: hide(bool): Hide the station """ if hide: self.hide() self.update(**{ 'device': self.DEFAULT_DEVICE, 'customerName': self.DEFAULT_CUSTOMERNAME, 'is_activated': self.DEFAULT_ACTIVATION, 'sessions': self.DEFAULT_SESSIONS, }) # -Session methods- def add_session(self, customerName: str, start_date: Union[dt.datetime, None], duration: dt.time, sessionID: Union[int, None] = None) -> bool: """ Add a new session Paramaters: customerName(str): Name of customer for this session start_date(dt.datetime or None): If None, the end_date of the last queue item will be taken duration(dt.time): Time length of the session sessionID(int or None): ID of session, if None a new session is created, otherwise it may replace a session if a session already has that sessionID (no warning) Returns(bool): Succesfully added session """ # -Determine session paramaters- if start_date is None: if self.sessions: start_date = self.sessions[-1].end_date else: start_date = dt.datetime.now() new_session = Session(customerName=customerName, start_date=start_date, duration=duration, sessionID=sessionID) # -Check for conflicting sessions- conflicting_sessions = [] for queued_session in self.sessions: if new_session.range_conflicts(queued_session.start_date, queued_session.end_date): # Ranges conflict if queued_session.sessionID == new_session.sessionID: # Ignore the session as it is the one being replaced continue conflicting_sessions.append(queued_session) # Ask for confirmation on deletion of overlapping sessions if conflicting_sessions: # Create messagebox msg = QMessageBox() msg.setWindowTitle("Conflicting Sessions") msg.setIcon(QMessageBox.Warning) msg.setText(f"Your session is conflicting with {len(conflicting_sessions)} already registered session(s).\nDo you wish to delete the overlapping sessions?") # nopep8 detailedText = f"Your sessions start: {new_session.start_date.strftime('%H:%M')}\nYour sessions end: {new_session.end_date.strftime('%H:%M')}" detailedText += '\n\nConflicting session(s):\n\n' for conflicting_data in conflicting_sessions: conflicting_session = conflicting_data detailedText += f"{conflicting_session.customerName}´s session start: {conflicting_session.start_date.strftime('%H:%M')}" detailedText += f"\n{conflicting_session.customerName}´s session end: {conflicting_session.end_date.strftime('%H:%M')}" detailedText += '\n\n' msg.setDetailedText(detailedText) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setWindowFlag(Qt.WindowStaysOnTopHint) val = msg.exec_() # User pressed continue if val == QMessageBox.Yes: # Remove all conflicting sessions for conflicting_session in conflicting_sessions: self.delete_session(session=conflicting_session, track=None) # Add the session again session_data = new_session.extract_data() del session_data['sessionID'] return self.add_session(**session_data) else: # User pressed cancel -> unsuccessful return False if sessionID is not None: # Delete old session self.delete_session(session=sessionID, track=False) self.sessions.append(new_session) self.refresh() return True def delete_session(self, session: Union[int, Session] = None, track: Union[bool, None] = None): """ Delete the session Paramaters: session(int or Session): ID of the session to delete OR Session class to delete track(bool): Whether to track the session If track is None, the session is only tracked if its range is in the current date. If that condition is true, the session is tracked up until the current date """ deleted_session: Session if isinstance(session, int): deleted_session = self._find_session(session) elif isinstance(session, Session): deleted_session = session if track is None: datetime_now = dt.datetime.now() if deleted_session.range_contains(datetime_now): deleted_session.end_date = datetime_now track = True else: track = False if track: self.sessionTracker.add_session_to_history(deleted_session) self.sessions.remove(deleted_session) def replace_session(self, sessionID: int, new_customerName: str = None, new_start_date: dt.datetime = None, new_end_date: dt.datetime = None, new_duration: dt.time = None): """ Update the session with the given session id with the newly given session data Paramaters: sessionID(int): ID of the session to delete new_customerName(str): The new customer name new_start_date(dt.datetime): New start date (end date will change) new_end_date(dt.datetime): New end date (duration will change) new_duration(dt.time): New duration (end date will change) """ session = self._find_session(sessionID).copy() if new_customerName is not None: session.customerName = new_customerName if new_start_date is not None: session.start_date = new_start_date if new_end_date is not None: session.end_date = new_end_date if new_duration is not None: session.duration = new_duration self.add_session(**session.extract_data()) def running_session(self) -> bool: """ Check if a session is currently running Returns(bool): Currently running a session """ if (not self.sessions or not self.is_activated): return False # Sort session by start date self.sessions = sorted(self.sessions, key=lambda s: s.start_date) first_session = self.sessions[0] datetime_now = dt.datetime.now() # Current time inside the sessions range return first_session.range_contains(datetime_now) def _update_sessions(self): """ Update the session queue """ datetime_now = dt.datetime.now() # Sort session by start date self.sessions = sorted(self.sessions, key=lambda s: s.start_date) # Clear out expired sessions (already past sessions; includes the most recent active session) for queue_session in self.sessions: if queue_session.end_date <= datetime_now: # Session is done self.delete_session(session=queue_session, track=True) # -Determine Text shown and states- if not self.running_session(): # No session running self.customerName = self.DEFAULT_CUSTOMERNAME # Check for an upcoming session if self.sessions: upcoming_session = self.sessions[0] if upcoming_session.start_date > datetime_now: customerName = f"{upcoming_session.customerName}" self.customerName = customerName + f" <span style=\" font-size:8pt; font-style:italic; color:#333;\" >starts at {upcoming_session.start_date.strftime('%H:%M')}</span>" # nopep8 if self.is_activated: # Station is activated if self.device is not None: # Device is registered self.device.turn_off() else: # Session running self.customerName = self.sessions[0].customerName if self.device is not None: # Device is registered self.device.turn_on() def _find_session(self, sessionID: int) -> Session: """ Find a session by its id Paramaters: sessionID(int): ID of the session to delete Returns(Session): Session instance with that id """ for session in self.sessions: if session.sessionID == sessionID: return session else: raise KeyError('No session found with id', sessionID) # -Button clicks- def clicked_onOff(self): """ Toggle between activated and deactivated """ if self.is_activated: if self.sessions: msg = QMessageBox() msg.setWindowTitle("Confirmation") msg.setIcon(QMessageBox.Warning) msg.setText("Deactivating this station will close the current customer session and all sessions queued.\nDo you wish to proceed?") # nopep8 msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setWindowFlag(Qt.WindowStaysOnTopHint) val = msg.exec_() if val != QMessageBox.Yes: # Not Continue return for session in self.sessions: self.delete_session(session=session, track=None) self.is_activated = False else: self.is_activated = True def clicked_newSession(self): """ Open the session window """ # -Window Setup- if self.sessions: time = self.sessions[-1].end_date else: time = dt.datetime.now() time = self.ceil_dt(time, dt.timedelta(minutes=30)) # Time is over the current day if time.day > dt.date.today().day: time = dt.time(23, 59) else: time = time.time() # Reset variable self.windows['session'].lineEdit_customerName.setText('') self.windows['session'].timeEdit_startAt.setTime(time) # Set dynamic properties self.windows['session'].setProperty('stationID', self.stationID) # Reshow window self.windows['session'].setWindowFlag(Qt.WindowStaysOnTopHint) self.windows['session'].show() # Focus window self.windows['session'].activateWindow() self.windows['session'].raise_() def clicked_editSession(self): """ Open the edit sessions window """ # -Window Setup- # Reset variable # Set stationID self.windows['edit'].setProperty('stationID', self.stationID) # Reshow window self.windows['edit'].setWindowFlag(Qt.WindowStaysOnTopHint) self.windows['edit'].show() # Focus window self.windows['edit'].activateWindow() self.windows['edit'].raise_() # -Fill List- self._editWindow_updateTable() self.refresh() # -Edit Window- def delete_selection(self): """ Delete all session selected """ assert self.windows['edit'].property('stationID') == self.stationID, "stationID in edit window does not equal stationID deletion is being performed on" # nopep8 # Get selection widget = self.windows['edit'].tableWidget_queue selection = widget.selectionModel().selectedRows() # Perform deletion datetime_now = dt.datetime.now() for item in selection: session = self._find_session(self.rowTranslator[item.row()]) if session.range_contains(datetime_now): # Current time inside the sessions range msg = QMessageBox() msg.setWindowTitle('Confirmation') msg.setIcon(QMessageBox.Icon.Information) msg.setText('You are deleting a session that is currently active. Do you wish to proceed?') msg.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel) msg.setWindowFlag(Qt.WindowStaysOnTopHint) val = msg.exec_() if val == QMessageBox.Cancel: # Skip this session deletion continue self.delete_session(session=session, track=None) self.refresh() @staticmethod def ceil_dt(date, delta) -> dt.datetime: """ Round up datetime """ return date + (dt.datetime.min - date) % delta def _editWindow_refresh(self): """ Check if the table in the edit window needs an update Is being checked as a refill of the table results in an unselection """ if self.windows['edit'].property('stationID') == self.stationID: if self.sessions != self._editWindow_shownSessions: self._editWindow_updateTable() def _editWindow_updateTable(self): """ Fill the table in the edit sessions window """ headers = ['Customer Name', 'Start Time', 'End Time', 'Total Time'] headerTranslator = { 'Customer Name': 'customerName', 'Start Time': 'start_date', 'End Time': 'end_date', 'Total Time': 'duration', } self.rowTranslator = {} tableWidget = self.windows['edit'].tableWidget_queue tableWidget.setRowCount(0) # Base widget settings tableWidget.setRowCount(len(self.sessions)) tableWidget.setColumnCount(len(headers)) tableWidget.setHorizontalHeaderLabels(headers) # -Set column widths- tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) column_width = max(tableWidget.columnWidth(1), tableWidget.columnWidth(2), tableWidget.columnWidth(3)) tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) tableWidget.setColumnWidth(1, column_width) tableWidget.setColumnWidth(2, column_width) tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) # -Fill table- for row in range(tableWidget.rowCount()): self.rowTranslator[row] = self.sessions[row].sessionID datas = self.sessions[row].extract_data() datas['end_date'] = self.sessions[row].end_date for col, header_key in enumerate(headers): data = datas[headerTranslator[header_key]] if type(data) in (dt, dt.date, dt.datetime, dt.time): data = data.strftime('%H:%M') item = QTableWidgetItem(str(data)) item.setTextAlignment(Qt.AlignCenter) tableWidget.setItem(row, col, item) tableWidget.setItemDelegate(QWidgetDelegate(self.windows['edit'], station=self)) self._editWindow_shownSessions = self.sessions.copy() def _update_texts(self): """ Update the text elements of the station """ def strfdelta(tdelta, fmt): """ Stringify timedelta """ class DeltaTemplate(Template): delimiter = "%" d = {"D": tdelta.days} d["H"], rem = divmod(tdelta.seconds, 3600) d["M"], d["S"] = divmod(rem, 60) for key in d.keys(): d[key] = str(d[key]).zfill(2) t = DeltaTemplate(fmt) return t.substitute(**d) # -Update start date, end date and time left- if not self.running_session(): # Station is either deactivated, or has no session running start_date = '' end_date = '' time_left = '' else: # Stringify the time formats datetime_now = dt.datetime.now() start_date = self.sessions[0].start_date.strftime('%H:%M') end_date = self.sessions[0].end_date.strftime('%H:%M') time_left = strfdelta(self.sessions[0].end_date - datetime_now, '%H:%M') # -Push Buttons- if not self.is_activated: toggleState_text = 'Take Control' newSession_enabled = False edit_enabled = False else: toggleState_text = 'Release Control' newSession_enabled = True edit_enabled = True # -Update texts- self.windows['main'].findChild(QLabel, f"label_customerName_{self.stationID}").setText(self.customerName) self.windows['main'].findChild(QLabel, f"label_startTimeValue_{self.stationID}").setText(start_date) self.windows['main'].findChild(QLabel, f"label_endTimeValue_{self.stationID}").setText(end_date) self.windows['main'].findChild(QLabel, f"label_timeLeftValue_{self.stationID}").setText(time_left) self.windows['main'].findChild(QPushButton, f"pushButton_toggleState_{self.stationID}").setText(toggleState_text) # nopep8 self.windows['main'].findChild(QPushButton, f"pushButton_newSession_{self.stationID}").setEnabled(newSession_enabled) # nopep8 self.windows['main'].findChild(QPushButton, f"pushButton_edit_{self.stationID}").setEnabled(edit_enabled) if self.device is not None: # Device is registered self.windows['main'].findChild(QLabel, f"label_deviceName_{self.stationID}").setText(self.device.deviceName) else: self.windows['main'].findChild(QLabel, f"label_deviceName_{self.stationID}").setText('N/A') def _update_colors(self): """ Update the indicator colors of the station """ if self.running_session(): frame_labels_color = const.NOT_AVAILABLE_COLOR elif self.is_activated: frame_labels_color = const.AVAILABLE_COLOR else: frame_labels_color = const.DEACTIVATED_COLOR frame_labels_stylesheet = """QFrame { background-color: rgb(%d, %d, %d);}""" % (frame_labels_color[0], frame_labels_color[1], frame_labels_color[2]) # -Update color- self.windows['main'].findChild(QFrame, f"frame_labels_{self.stationID}").setStyleSheet(frame_labels_stylesheet)
class DSRViewer(QObject): save_graph_signal = Signal() close_window_signal = Signal() reset_viewer = Signal(QWidget) def __init__(self, window, G, options, main=None): super().__init__() self.timer = QTimer() self.alive_timer = QElapsedTimer() self.g = G self.window = window self.view_menu = QMenu() self.file_menu = QMenu() self.forces_menu = QMenu() self.main_widget = window self.docks = {} self.widgets = {} self.widgets_by_type = {} available_geometry = QApplication.desktop().availableGeometry() window.move((available_geometry.width() - window.width()) / 2, (available_geometry.height() - window.height()) / 2) self.__initialize_file_menu() viewMenu = window.menuBar().addMenu(window.tr("&View")) forcesMenu = window.menuBar().addMenu(window.tr("&Forces")) actionsMenu = window.menuBar().addMenu(window.tr("&Actions")) restart_action = actionsMenu.addAction("Restart") self.__initialize_views(options, main) self.alive_timer.start() self.timer.start(500) # self.init() #intialize processor number # connect(timer, SIGNAL(timeout()), self, SLOT(compute())) def __del__(self): settings = QSettings("RoboComp", "DSR") settings.beginGroup("MainWindow") settings.setValue("size", self.window.size()) settings.setValue("pos", self.window.pos()) settings.endGroup() def get_widget_by_type(self, widget_type) -> QWidget: if widget_type in self.widgets_by_type: return self.widgets_by_type[widget_type].widget return None def get_widget_by_name(self, name) -> QWidget: if name in self.widgets: return self.widgets[name].widget return None def add_custom_widget_to_dock(self, name, custom_view): widget_c = WidgetContainer() widget_c.name = name widget_c.type = View.none widget_c.widget = custom_view self.widgets[name] = widget_c self.__create_dock_and_menu(name, custom_view) # Tabification of current docks previous = None for dock_name, dock in self.docks.items(): if previous and previous != dock: self.window.tabifyDockWidget(previous, self.docks[name]) break previous = dock self.docks[name].raise_() def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.close_window_signal.emit() # SLOTS def save_graph_slot(self, state): self.save_graph_signal.emit() def restart_app(self, state): pass def switch_view(self, state, container): widget = container.widget dock = container.dock if state: widget.blockSignals(True) dock.hide() else: widget.blockSignals(False) self.reset_viewer.emit(widget) dock.show() dock.raise_() def compute(self): pass def __create_dock_and_menu(self, name, view): # TODO: Check if name exists in docks if name in self.docks: dock_widget = self.docks[name] self.window.removeDockWidget(dock_widget) else: dock_widget = QDockWidget(name) new_action = QAction(name, self) new_action.setStatusTip("Create a new file") new_action.setCheckable(True) new_action.setChecked(True) new_action.triggered.connect( lambda state: self.switch_view(state, self.widgets[name])) self.view_menu.addAction(new_action) self.docks[name] = dock_widget self.widgets[name].dock = dock_widget dock_widget.setWidget(view) dock_widget.setAllowedAreas(Qt.AllDockWidgetAreas) self.window.addDockWidget(Qt.RightDockWidgetArea, dock_widget) dock_widget.raise_() def __initialize_views(self, options, central): # Create docks view and main widget valid_options = [(View.graph, "Graph"), (View.tree, "Tree"), (View.osg, "3D"), (View.scene, "2D")] # Creation of docks and mainwidget for widget_type, widget_name in valid_options: if widget_type == central and central != View.none: viewer = self.__create_widget(widget_type) self.window.setCentralWidget(viewer) widget_c = WidgetContainer() widget_c.widget = viewer widget_c.name = widget_name widget_c.type = widget_type self.widgets[widget_name] = widget_c self.widgets_by_type[widget_type] = widget_c self.main_widget = viewer elif options & widget_type: viewer = self.__create_widget(widget_type) widget_c = WidgetContainer() widget_c.widget = viewer widget_c.name = widget_name widget_c.type = widget_type self.widgets[widget_name] = widget_c self.widgets_by_type[widget_type] = widget_c self.__create_dock_and_menu(widget_name, viewer) if View.graph in self.widgets_by_type: new_action = QAction("Animation", self) new_action.setStatusTip("Toggle animation") new_action.setCheckable(True) new_action.setChecked(False) self.forces_menu.addAction(new_action) new_action.triggered.connect(lambda: self.widgets_by_type[ View.graph].widget.toggle_animation(True)) # Tabification of current docks previous = None for dock_name, dock_widget in self.docks.items(): if previous: self.window.tabifyDockWidget(previous, dock_widget) previous = dock_widget # Connection of tree to graph signals if "Tree" in self.docks: if self.main_widget: graph_widget = self.main_widget if graph_widget: tree_widget = self.docks["Tree"].widget() tree_widget.node_check_state_changed_signal.connect( lambda node_id: graph_widget.hide_show_node_SLOT( node_id, 2)) if len(self.docks) > 0 or central != None: self.window.show() else: self.window.showMinimized() def __initialize_file_menu(self): file_menu = self.window.menuBar().addMenu(self.window.tr("&File")) file_submenu = file_menu.addMenu("Save") save_action = QAction("Save", self) file_submenu.addAction(save_action) rgbd = QAction("RGBD", self) rgbd.setCheckable(True) rgbd.setChecked(False) file_submenu.addAction(rgbd) laser = QAction("Laser", self) laser.setCheckable(True) laser.setChecked(False) file_submenu.addAction(laser) # save_action save_action.triggered.connect( lambda: self.__save_json_file(rgbd, laser)) def __save_json_file(self, rgbd, laser): file_name = QFileDialog.getSaveFileName( None, "Save file", "/home/robocomp/robocomp/components/dsr-graph/etc", "JSON Files (*.json)", None, QFileDialog.Option.DontUseNativeDialog) skip_content = [] if not rgbd.isChecked(): skip_content.push_back("rgbd") if not laser.isChecked(): skip_content.push_back("laser") self.g.write_to_json_file(file_name.toStdString(), skip_content) print("File saved") def __create_widget(self, widget_type): widget_view = None if widget_type == View.graph: widget_view = GraphViewer(self.g) elif widget_type == View.osg: widget_view = OSG3dViewer(self.g, 1, 1) elif widget_type == View.tree: widget_view = TreeViewer(self.g) elif widget_type == View.scene: widget_view = QScene2dViewer(self.g) elif widget_type == View.none: widget_view = None # self.reset_viewer.connect(self.reload) return widget_view
class DebugView(QWidget, View): class DebugViewHistoryEntry(HistoryEntry): def __init__(self, memory_addr, address, is_raw): HistoryEntry.__init__(self) self.memory_addr = memory_addr self.address = address self.is_raw = is_raw def __repr__(self): if self.is_raw: return "<raw history: {}+{:0x} (memory: {:0x})>".format( self.address['module'], self.address['offset'], self.memory_addr) return "<code history: {:0x} (memory: {:0x})>".format( self.address, self.memory_addr) def __init__(self, parent, data): if not type(data) == BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data self.debug_state = binjaplug.get_state(data) memory_view = self.debug_state.memory_view self.debug_state.ui.debug_view = self QWidget.__init__(self, parent) self.controls = ControlsWidget.DebugControlsWidget( self, "Controls", data, self.debug_state) View.__init__(self) self.setupView(self) self.current_offset = 0 self.splitter = QSplitter(Qt.Orientation.Horizontal, self) frame = ViewFrame.viewFrameForWidget(self) self.memory_editor = LinearView(memory_view, frame) self.binary_editor = DisassemblyContainer(frame, data, frame) self.binary_text = TokenizedTextView(self, memory_view) self.is_raw_disassembly = False self.raw_address = 0 self.is_navigating_history = False self.memory_history_addr = 0 # TODO: Handle these and change views accordingly # Currently they are just disabled as the DisassemblyContainer gets confused # about where to go and just shows a bad view self.binary_editor.getDisassembly().actionHandler().bindAction( "View in Hex Editor", UIAction()) self.binary_editor.getDisassembly().actionHandler().bindAction( "View in Linear Disassembly", UIAction()) self.binary_editor.getDisassembly().actionHandler().bindAction( "View in Types View", UIAction()) self.memory_editor.actionHandler().bindAction("View in Hex Editor", UIAction()) self.memory_editor.actionHandler().bindAction( "View in Disassembly Graph", UIAction()) self.memory_editor.actionHandler().bindAction("View in Types View", UIAction()) small_font = QApplication.font() small_font.setPointSize(11) bv_layout = QVBoxLayout() bv_layout.setSpacing(0) bv_layout.setContentsMargins(0, 0, 0, 0) bv_label = QLabel("Loaded File") bv_label.setFont(small_font) bv_layout.addWidget(bv_label) bv_layout.addWidget(self.binary_editor) self.bv_widget = QWidget() self.bv_widget.setLayout(bv_layout) disasm_layout = QVBoxLayout() disasm_layout.setSpacing(0) disasm_layout.setContentsMargins(0, 0, 0, 0) disasm_label = QLabel("Raw Disassembly at PC") disasm_label.setFont(small_font) disasm_layout.addWidget(disasm_label) disasm_layout.addWidget(self.binary_text) self.disasm_widget = QWidget() self.disasm_widget.setLayout(disasm_layout) memory_layout = QVBoxLayout() memory_layout.setSpacing(0) memory_layout.setContentsMargins(0, 0, 0, 0) memory_label = QLabel("Debugged Process") memory_label.setFont(small_font) memory_layout.addWidget(memory_label) memory_layout.addWidget(self.memory_editor) self.memory_widget = QWidget() self.memory_widget.setLayout(memory_layout) self.splitter.addWidget(self.bv_widget) self.splitter.addWidget(self.memory_widget) # Equally sized self.splitter.setSizes([0x7fffffff, 0x7fffffff]) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.controls) layout.addWidget(self.splitter, 100) self.setLayout(layout) self.needs_update = True self.update_timer = QTimer(self) self.update_timer.setInterval(200) self.update_timer.setSingleShot(False) self.update_timer.timeout.connect(lambda: self.updateTimerEvent()) self.add_scripting_ref() def add_scripting_ref(self): # Hack: The interpreter is just a thread, so look through all threads # and assign our state to the interpreter's locals for thread in threading.enumerate(): if type(thread) == PythonScriptingInstance.InterpreterThread: thread.locals["dbg"] = self.debug_state def getData(self): return self.bv def getFont(self): return binaryninjaui.getMonospaceFont(self) def getCurrentOffset(self): if not self.is_raw_disassembly: return self.binary_editor.getDisassembly().getCurrentOffset() return self.raw_address def getSelectionOffsets(self): if not self.is_raw_disassembly: return self.binary_editor.getDisassembly().getSelectionOffsets() return (self.raw_address, self.raw_address) def getCurrentFunction(self): if not self.is_raw_disassembly: return self.binary_editor.getDisassembly().getCurrentFunction() return None def getCurrentBasicBlock(self): if not self.is_raw_disassembly: return self.binary_editor.getDisassembly().getCurrentBasicBlock() return None def getCurrentArchitecture(self): if not self.is_raw_disassembly: return self.binary_editor.getDisassembly().getCurrentArchitecture() return None def getCurrentLowLevelILFunction(self): if not self.is_raw_disassembly: return self.binary_editor.getDisassembly( ).getCurrentLowLevelILFunction() return None def getCurrentMediumLevelILFunction(self): if not self.is_raw_disassembly: return self.binary_editor.getDisassembly( ).getCurrentMediumLevelILFunction() return None def getHistoryEntry(self): if self.is_navigating_history: return None memory_addr = self.memory_editor.getCurrentOffset() if memory_addr != self.memory_history_addr: self.memory_history_addr = memory_addr if self.is_raw_disassembly and self.debug_state.connected: rel_addr = self.debug_state.modules.absolute_addr_to_relative( self.raw_address) return DebugView.DebugViewHistoryEntry(memory_addr, rel_addr, True) else: address = self.binary_editor.getDisassembly().getCurrentOffset() return DebugView.DebugViewHistoryEntry(memory_addr, address, False) def navigateToHistoryEntry(self, entry): self.is_navigating_history = True if hasattr(entry, 'is_raw'): self.memory_editor.navigate(entry.memory_addr) if entry.is_raw: if self.debug_state.connected: address = self.debug_state.modules.relative_addr_to_absolute( entry.address) self.navigate_raw(address) else: self.navigate_live(entry.address) View.navigateToHistoryEntry(self, entry) self.is_navigating_history = False def navigate(self, addr): if self.debug_state.memory_view.is_local_addr(addr): local_addr = self.debug_state.memory_view.remote_addr_to_local( addr) if self.debug_state.bv.read(local_addr, 1) and len( self.debug_state.bv.get_functions_containing( local_addr)) > 0: return self.navigate_live(local_addr) # This runs into conflicts if some other address space is mapped over # where the local BV is currently loaded, but this is was less likely # than the user navigating to a function from the UI if self.debug_state.bv.read(addr, 1) and len( self.debug_state.bv.get_functions_containing(addr)) > 0: return self.navigate_live(addr) return self.navigate_raw(addr) def navigate_live(self, addr): self.show_raw_disassembly(False) return self.binary_editor.getDisassembly().navigate(addr) def navigate_raw(self, addr): if not self.debug_state.connected: # Can't navigate to remote addr when disconnected return False self.raw_address = addr self.show_raw_disassembly(True) self.load_raw_disassembly(addr) return True def notifyMemoryChanged(self): self.needs_update = True def updateTimerEvent(self): if self.needs_update: self.needs_update = False # Refresh the editor if not self.debug_state.connected: self.memory_editor.navigate(0) return # self.memory_editor.navigate(self.debug_state.stack_pointer) def showEvent(self, event): if not event.spontaneous(): self.update_timer.start() self.add_scripting_ref() def hideEvent(self, event): if not event.spontaneous(): self.update_timer.stop() def shouldBeVisible(self, view_frame): if view_frame is None: return False else: return True def load_raw_disassembly(self, start_ip): # Read a few instructions from rip and disassemble them inst_count = 50 arch_dis = self.debug_state.remote_arch rip = self.debug_state.ip # Assume the worst, just in case read_length = arch_dis.max_instr_length * inst_count data = self.debug_state.memory_view.read(start_ip, read_length) lines = [] # Append header line tokens = [ InstructionTextToken( InstructionTextTokenType.TextToken, "(Code not backed by loaded file, showing only raw disassembly)" ) ] contents = DisassemblyTextLine(tokens, start_ip) line = LinearDisassemblyLine(LinearDisassemblyLineType.BasicLineType, None, None, 0, contents) lines.append(line) total_read = 0 for i in range(inst_count): line_addr = start_ip + total_read (insn_tokens, length) = arch_dis.get_instruction_text(data[total_read:], line_addr) if insn_tokens is None: insn_tokens = [ InstructionTextToken(InstructionTextTokenType.TextToken, "??") ] length = arch_dis.instr_alignment if length == 0: length = 1 tokens = [] color = HighlightStandardColor.NoHighlightColor if line_addr == rip: if self.debug_state.breakpoints.contains_absolute(start_ip + total_read): # Breakpoint & pc tokens.append( InstructionTextToken( InstructionTextTokenType.TagToken, self.debug_state.ui.get_breakpoint_tag_type().icon + ">", width=5)) color = HighlightStandardColor.RedHighlightColor else: # PC tokens.append( InstructionTextToken( InstructionTextTokenType.TextToken, " ==> ")) color = HighlightStandardColor.BlueHighlightColor else: if self.debug_state.breakpoints.contains_absolute(start_ip + total_read): # Breakpoint tokens.append( InstructionTextToken( InstructionTextTokenType.TagToken, self.debug_state.ui.get_breakpoint_tag_type().icon, width=5)) color = HighlightStandardColor.RedHighlightColor else: # Regular line tokens.append( InstructionTextToken( InstructionTextTokenType.TextToken, " ")) # Address tokens.append( InstructionTextToken( InstructionTextTokenType.AddressDisplayToken, hex(line_addr)[2:], line_addr)) tokens.append( InstructionTextToken(InstructionTextTokenType.TextToken, " ")) tokens.extend(insn_tokens) # Convert to linear disassembly line contents = DisassemblyTextLine(tokens, line_addr, color=color) line = LinearDisassemblyLine( LinearDisassemblyLineType.CodeDisassemblyLineType, None, None, 0, contents) lines.append(line) total_read += length # terrible workaround for libshiboken conversion issue for line in lines: # line is LinearDisassemblyLine last_tok = line.contents.tokens[-1] #if last_tok.type != InstructionTextTokenType.PossibleAddressToken: continue #if last_tok.width != 18: continue # strlen("0xFFFFFFFFFFFFFFF0") if last_tok.size != 8: continue #print('fixing: %s' % line) last_tok.value &= 0x7FFFFFFFFFFFFFFF self.binary_text.setLines(lines) def show_raw_disassembly(self, raw): if raw != self.is_raw_disassembly: self.splitter.replaceWidget( 0, self.disasm_widget if raw else self.bv_widget) self.is_raw_disassembly = raw def refresh_raw_disassembly(self): if not self.debug_state.connected: # Can't navigate to remote addr when disconnected return if self.is_raw_disassembly: self.load_raw_disassembly(self.getCurrentOffset())
class TreeWidgetFilter(QObject): change_item = Signal(QModelIndex, bool, int) scroll_to_signal = Signal(QModelIndex) def __init__(self, ui, widget: QWidget, line_edit: QWidget, columns: Tuple = (0, 1, 2)): super(TreeWidgetFilter, self).__init__(widget) self.ui = ui self.widget = widget self.columns = columns self.clean = True self.filter_timer = QTimer() self.filter_timer.setSingleShot(True) self.filter_timer.setInterval(1500) self.filter_timer.timeout.connect(self.search) self.restore_timer = QTimer() self.restore_timer.setSingleShot(True) self.restore_timer.setInterval(500) self.restore_timer.timeout.connect(self.restore) self.busy_timer = QTimer() self.busy_timer.setSingleShot(True) self.busy_timer.setInterval(100) self.busy_timer.timeout.connect(self.filtering_finished) self.line_edit: QLineEdit = line_edit self.line_edit.textChanged.connect(self._line_edit_text_changed) self.bgr_animation = BgrAnimation(self.line_edit, (255, 255, 255, 255)) self.change_item.connect(self.apply_item_change) self.scroll_to_signal.connect(self.scroll_to_item) self.widget.installEventFilter(self) def eventFilter(self, watched: QObject, event: QEvent) -> bool: if self.ui.widget_with_focus() is not watched: return False if not event.type() == QEvent.KeyPress: return False if event.key() in (Qt.Key_Backspace, Qt.Key_Escape): self.line_edit.clear() self.restore() self.widget.info_overlay.display(f'Clearing filter.', 1500, True) return True # Send alphanumeric keys to LineEdit filter widget filter_keys = [Qt.Key_Space, Qt.Key_Underscore, Qt.Key_Minus] if event.text().isalnum() or event.key() in filter_keys: filter_txt = self.line_edit.text() filter_txt += event.text() if filter_txt: self.widget.info_overlay.display(f'Filtering: {filter_txt}', 1500, True) self.line_edit.setText(filter_txt) return True return False def start(self): if self.line_edit.text(): self.filter_timer.start() else: if not self.clean: self.restore_timer.start() def _line_edit_text_changed(self, txt): if self.ui.widget_with_focus() is not self.widget: return self.start() def _prepare_filtering(self): LOGGER.debug('Running filter on: %s', self.widget.objectName()) # Display actual filter t = '' for word in self.line_edit.text().split(' '): t += f'{word} AND ' if self.line_edit.text(): self.widget.info_overlay.display(f'Filtering: {t[:-5]}', 4500, True) else: self.widget.info_overlay.display(f'Filter Reset', 3000, True) self.bgr_animation.blink() self.widget.hide() self.busy_timer.start() def filtering_finished(self): LOGGER.debug('Filter operation finished on: %s', self.widget.objectName()) self.widget.show() if self.line_edit.text(): self.clean = False else: self.clean = True def search(self): self._prepare_filtering() for item in iterate_widget_items_flat(self.widget): txt = '' for c in self.columns: # Match any column text with OR '|' txt += f'{item.text(c)}|' if txt: txt = txt[:-1] # Show everything and collapse parents index = self.widget.indexFromItem(item) parent_index = self.widget.indexFromItem(item.parent()) results = list() # Match space separated filter strings with AND for word in self.line_edit.text().split(' '): results.append(True if re.search( word, txt, flags=re.IGNORECASE) else False) if not all(results): # Hide all non-matching items self.change_item.emit(index, True, 0) continue # Un-hide self.change_item.emit(index, False, 0) if parent_index: # Show and expand parent self.change_item.emit(parent_index, False, 1) # Scroll to selection if item.isSelected(): self.scroll_to_signal.emit(index) def restore(self): self._prepare_filtering() for item in iterate_widget_items_flat(self.widget): # Show everything and collapse parents index = self.widget.indexFromItem(item) parent_index = self.widget.indexFromItem(item.parent()) if not parent_index.isValid(): # Show and collapse top level items self.change_item.emit(index, False, 2) else: # Un-hide all self.change_item.emit(index, False, 0) # Scroll to selection if item.isSelected(): self.widget.horizontalScrollBar().setSliderPosition(0) self.widget.scrollToItem(item) def scroll_to_item(self, index: QModelIndex): item = self.widget.itemFromIndex(index) self.widget.horizontalScrollBar().setSliderPosition(0) self.widget.scrollToItem(item) def apply_item_change(self, index, hide=False, expand: int = 0): """ Receives signal to hide/unhide or expand/collapse items """ item = self.widget.itemFromIndex(index) if not item: return self.busy_timer.start() if hide: item.setHidden(True) else: item.setHidden(False) if expand == 1: item.setExpanded(True) elif expand == 2: item.setExpanded(False)
def __init__(self, parent, data): if not type(data) == BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data self.debug_state = binjaplug.get_state(data) memory_view = self.debug_state.memory_view self.debug_state.ui.debug_view = self QWidget.__init__(self, parent) self.controls = ControlsWidget.DebugControlsWidget( self, "Controls", data, self.debug_state) View.__init__(self) self.setupView(self) self.current_offset = 0 self.splitter = QSplitter(Qt.Orientation.Horizontal, self) frame = ViewFrame.viewFrameForWidget(self) self.memory_editor = LinearView(memory_view, frame) self.binary_editor = DisassemblyContainer(frame, data, frame) self.binary_text = TokenizedTextView(self, memory_view) self.is_raw_disassembly = False self.raw_address = 0 self.is_navigating_history = False self.memory_history_addr = 0 # TODO: Handle these and change views accordingly # Currently they are just disabled as the DisassemblyContainer gets confused # about where to go and just shows a bad view self.binary_editor.getDisassembly().actionHandler().bindAction( "View in Hex Editor", UIAction()) self.binary_editor.getDisassembly().actionHandler().bindAction( "View in Linear Disassembly", UIAction()) self.binary_editor.getDisassembly().actionHandler().bindAction( "View in Types View", UIAction()) self.memory_editor.actionHandler().bindAction("View in Hex Editor", UIAction()) self.memory_editor.actionHandler().bindAction( "View in Disassembly Graph", UIAction()) self.memory_editor.actionHandler().bindAction("View in Types View", UIAction()) small_font = QApplication.font() small_font.setPointSize(11) bv_layout = QVBoxLayout() bv_layout.setSpacing(0) bv_layout.setContentsMargins(0, 0, 0, 0) bv_label = QLabel("Loaded File") bv_label.setFont(small_font) bv_layout.addWidget(bv_label) bv_layout.addWidget(self.binary_editor) self.bv_widget = QWidget() self.bv_widget.setLayout(bv_layout) disasm_layout = QVBoxLayout() disasm_layout.setSpacing(0) disasm_layout.setContentsMargins(0, 0, 0, 0) disasm_label = QLabel("Raw Disassembly at PC") disasm_label.setFont(small_font) disasm_layout.addWidget(disasm_label) disasm_layout.addWidget(self.binary_text) self.disasm_widget = QWidget() self.disasm_widget.setLayout(disasm_layout) memory_layout = QVBoxLayout() memory_layout.setSpacing(0) memory_layout.setContentsMargins(0, 0, 0, 0) memory_label = QLabel("Debugged Process") memory_label.setFont(small_font) memory_layout.addWidget(memory_label) memory_layout.addWidget(self.memory_editor) self.memory_widget = QWidget() self.memory_widget.setLayout(memory_layout) self.splitter.addWidget(self.bv_widget) self.splitter.addWidget(self.memory_widget) # Equally sized self.splitter.setSizes([0x7fffffff, 0x7fffffff]) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.controls) layout.addWidget(self.splitter, 100) self.setLayout(layout) self.needs_update = True self.update_timer = QTimer(self) self.update_timer.setInterval(200) self.update_timer.setSingleShot(False) self.update_timer.timeout.connect(lambda: self.updateTimerEvent()) self.add_scripting_ref()
try: logger.setLevel(conf['log_level'].upper()) except KeyError: logger.setLevel('INFO') conf['interval'] = conf['interval'] if 'interval' in conf else 30 if getenv('GITHUB_TOKEN'): conf['token'] = getenv('GITHUB_TOKEN') elif 'token' not in conf: raise ValueError('Gihub token has to be provided') except (IOError, yaml.YAMLError, ValueError) as e: logger.error(e) print(e) sys.exit(1) app = QtWidgets.QApplication() widget = QtWidgets.QWidget() tray_app = GPRMon.TrayIcon(widget, conf=conf) tray_app.show() timer = QTimer(widget) timer.setInterval(conf['interval'] * 1000) timer.timeout.connect(tray_app.update_prs) timer.start() logger.info('Starting gprmon...') sys.exit(app.exec_())
def testDestructor(self): w = Test() w.show() QTimer.singleShot(0, w.close)
class Bot(QQuickPaintedItem): def __init__(self, parent=None): super(Bot, self).__init__(parent) self._map = None self.image = QImage(300, 300, QImage.Format_RGBA8888) self.image.fill('#000000ff') self.timer = QTimer() self.position = QPoint() self.around = None self.angle = 0 self.last_front = False self.timer.timeout.connect(lambda: self.drawCircle(self.position)) def paint(self, painter): painter.drawImage(QRect(0, 0, self.width(), self.height()), self.image) def setMap(self, map: Map): if not map: return print('Map', map) self._map = map self._map.clicked.connect(self.handleClick) self.image = QImage(self.map.image.width(), self.map.image.height(), QImage.Format_RGBA8888) self.image.fill('#000000ff') def getMap(self) -> Map: return self._map map = Property(Map, getMap, setMap) @Slot(QPoint) def handleClick(self, point: QPoint): self.position = point self.around = False self.drawCircle(point) self.timer.start(100) def mousePressEvent(self, event): a, b = event.pos().x() * self.image.width() / self.width(), event.pos( ).y() * self.image.height() / self.height() def mouseMoveEvent(self, event): a, b = event.pos().x() * self.image.width() / self.width(), event.pos( ).y() * self.image.height() / self.height() @Slot(QPoint) def drawCircle(self, point: QPoint): a = point.x() b = point.y() angle_step_size = 64 radius = 90 initPoint = QPoint(-1, -1) finalPoint = initPoint firstPoint = finalPoint self.image.fill('#000000ff') painter = QPainter(self.image) lidarPoints = [] painter.setPen('#00ff00') painter.drawRect(point.x() - 1, point.y() - 1, 2, 2) front = QPoint(math.cos(self.angle), math.sin(self.angle)) self.image.setPixelColor(point + front, QColor('#0000ff')) painter.setPen('#ff0000') for step in range(0, angle_step_size - 1): angle = 2 * math.pi * step / angle_step_size + self.angle initPoint = finalPoint for r in range(1, radius): x = point.x() + r * math.cos(angle) y = point.y() + r * math.sin(angle) finalPoint = QPoint(x, y) if not self.map.pixel(x, y): break if initPoint != QPoint(-1, -1): painter.drawLine(initPoint, finalPoint) else: firstPoint = finalPoint lidarPoints.append(finalPoint - point) painter.drawLine(finalPoint, firstPoint) painter.end() self.update() self.runObstacleAvoidance(point, lidarPoints) def runObstacleAvoidance(self, point, lidarPoints): # Calculate distance # Target 287, 293 destiny = QPoint(287, 293) ao = destiny - point rcoli = 2 # Get only the front, right, back and left values lpoints = [ lidarPoints[int(i * (len(lidarPoints) + 1) / 4)] for i in range(4) ] dist = lambda d: (d.x()**2 + d.y()**2)**0.5 dist2 = lambda d, d2: ((d.x() - d2.x())**2 + (d.y() - d2.y())**2)**0.5 dists = [dist(p) for p in lpoints] # Calculate next point nextPoint = point if dists[0] < rcoli and not self.around: self.around_point = copy.copy(point) self.around = dists[0] < rcoli or self.around # Bug algorithm if not self.around: if abs(ao.x()) > abs(ao.y()): if ao.x() > 0: nextPoint += QPoint(1, 0) self.angle = 0 else: nextPoint += QPoint(-1, 0) self.angle = math.pi else: if ao.y() > 0: nextPoint += QPoint(0, 1) self.angle = math.pi / 2 else: nextPoint += QPoint(0, -1) self.angle = 3 * math.pi / 2 else: if dist2(self.around_point, point) + dist2(destiny, point) - dist2( destiny, self.around_point) < 3 and dist2( self.around_point, point) > 3: self.around = False elif dists[3] < rcoli: if dists[0] > rcoli: self.position += QPoint(math.cos(self.angle), math.sin(self.angle)) else: self.angle += math.pi / 2 elif dists[0] < rcoli: self.position += QPoint(math.cos(self.angle), math.sin(self.angle)) self.angle += math.pi / 2 elif dists[1] < rcoli: self.angle += math.pi else: self.position += QPoint(math.cos(self.angle - math.pi / 2), math.sin(self.angle - math.pi / 2)) self.angle -= math.pi / 2
def startup_check(self): QTimer.singleShot(200, QApplication.instance().quit)
def __init__(self, parent): super().__init__() self.parent = parent self.setupUi() self.timer = QTimer() self.timer.timeout.connect(self.progress_flash)
def setUp(self): #Acquire resources UsesQCoreApplication.setUp(self) self.watchdog = WatchDog(self) self.timer = QTimer() self.called = False
class BoidsApp(QWidget): def __init__(self): super(BoidsApp, self).__init__() self.setWindowTitle('Boids') self._boids_environment = BoidsEnvironment() layout = QHBoxLayout() self._boids_widget = BoidsWidget() self._boids_widget.set_boids_environment(self._boids_environment) self._boids_widget.setMinimumWidth(550) self._form_layout = QFormLayout() self._is_running_checkbox = QCheckBox() self._is_running_checkbox.setChecked(True) self._is_running_checkbox.stateChanged.connect( self.__is_running_changed) self._tick_button = QPushButton() self._tick_button.setText('Tick') self._tick_button.clicked.connect(self.__do_tick) self._total_spinbox = _make_spinbox(TOTAL_BOIDS, 0, 9999) self._total_spinbox.valueChanged.connect(self.__total_changed) self._max_speed_spinbox = _make_double_spinbox(DEFAULT_MAX_SPEED, 0.0, 9999.0, 0.1) self._max_speed_spinbox.valueChanged.connect(self.__max_speed_changed) self._eyesight_radius_spinbox = _make_double_spinbox( DEFAULT_MAX_DISTANCE, 0.0, 9999.0, 0.5) self._eyesight_radius_spinbox.valueChanged.connect( self.__eyesight_radius_changed) self._eyesight_angle_spinbox = _make_double_spinbox( DEFAULT_EYE_SIGHT_ANGLE, 0.0, 360.0, 1.0) self._eyesight_angle_spinbox.valueChanged.connect( self.__eyesight_angle_changed) self._separation_distance_spinbox = _make_double_spinbox( SEPARATION_DISTANCE, 0.0, 9999.0, 1.0) self._separation_distance_spinbox.valueChanged.connect( self.__separation_distance_changed) self._separation_value_spinbox = _make_double_spinbox( SEPARATION_VALUE, 0.0, 1.0, 0.1) self._separation_value_spinbox.valueChanged.connect( self.__separation_value_changed) self._cohesion_value_spinbox = _make_double_spinbox( COHESION_VALUE, 0.0, 1.0, 0.1) self._cohesion_value_spinbox.valueChanged.connect( self.__cohesion_value_changed) self._alignment_value_spinbox = _make_double_spinbox( ALIGNMENT_VALUE, 0.0, 1.0, 0.1) self._alignment_value_spinbox.valueChanged.connect( self.__alignment_value_changed) self._generate_button = QPushButton() self._generate_button.setText('Generate') self._generate_button.clicked.connect(self._generate_environment) self._form_layout.addRow('Total Boids', self._total_spinbox) self._form_layout.addRow('Separation', self._separation_value_spinbox) self._form_layout.addRow('Cohesion', self._cohesion_value_spinbox) self._form_layout.addRow('Alignment', self._alignment_value_spinbox) self._form_layout.addRow('Max Speed', self._max_speed_spinbox) self._form_layout.addRow('Eyesight Radius', self._eyesight_radius_spinbox) self._form_layout.addRow('Eyesight Angle (degrees)', self._eyesight_angle_spinbox) self._form_layout.addRow('Separation Distance', self._separation_distance_spinbox) self._form_layout.addRow('Running', self._is_running_checkbox) self._form_layout.addWidget(self._generate_button) self._form_layout.addWidget(self._tick_button) layout.addWidget(self._boids_widget) layout.addLayout(self._form_layout) self.setLayout(layout) self.tick_timer = QTimer() self.tick_timer.setInterval(int(1000 / 24)) self.tick_timer.timeout.connect(self._tick) self.tick_timer.start() def showEvent(self, event): self._generate_environment() def _tick(self): tick_environment(self._boids_environment) self._boids_widget.update() def __do_tick(self): is_running = self._boids_environment.is_running self._boids_environment.is_running = True tick_environment(self._boids_environment) self._boids_widget.update() self._boids_environment.is_running = is_running def __total_changed(self): total = self._total_spinbox.value() _change_total(self._boids_environment, total) def __cohesion_value_changed(self): value = self._cohesion_value_spinbox.value() for boid in self._boids_environment.boids: boid.cohesion = value def __alignment_value_changed(self): value = self._alignment_value_spinbox.value() for boid in self._boids_environment.boids: boid.alignment = value def __max_speed_changed(self): self._boids_environment.max_speed = self._max_speed_spinbox.value() def __eyesight_radius_changed(self): value = self._eyesight_radius_spinbox.value() self._boids_environment.neighbour_max_distance = value self._boids_environment.neighbour_max_distance2 = value * value def __is_running_changed(self): self._boids_environment.is_running = self._is_running_checkbox.isChecked( ) def __separation_distance_changed(self): value = self._separation_distance_spinbox.value() for boid in self._boids_environment.boids: boid.separation_distance = value boid.separation_distance2 = value * value def __separation_value_changed(self): value = self._separation_value_spinbox.value() for boid in self._boids_environment.boids: boid.separation = value def __eyesight_angle_changed(self): for boid in self._boids_environment.boids: boid.eyesight = math.radians(self._eyesight_angle_spinbox.value()) def _generate_environment(self): max_speed = self._max_speed_spinbox.value() separation = self._separation_value_spinbox.value() environment = _make_environment(self._total_spinbox.value(), Rect(0.0, 0.0, 500.0, 500.0), max_speed, separation) environment.is_running = self._is_running_checkbox.isChecked() environment.max_speed = max_speed self._boids_environment = environment self._boids_widget.set_boids_environment(self._boids_environment) def sizeHint(self): return QSize(800, 550)