def _splitFreeNode(self, freeNode, usedNode): if usedNode.x >= freeNode.x + freeNode.width or usedNode.x + usedNode.width <= freeNode.x or usedNode.y >= freeNode.y + freeNode.height or usedNode.y + usedNode.height <= freeNode.y: return False if usedNode.x < freeNode.x + freeNode.width and usedNode.x + usedNode.width > freeNode.x: if usedNode.y > freeNode.y and usedNode.y < freeNode.y + freeNode.height: newNode = core.Rect(freeNode) newNode.height = usedNode.y - newNode.y self._freeRectangles.append(newNode) if usedNode.y + usedNode.height < freeNode.y + freeNode.height: newNode = core.Rect(freeNode) newNode.y = usedNode.y + usedNode.height newNode.height = freeNode.y + freeNode.height - ( usedNode.y + usedNode.height) self._freeRectangles.append(newNode) if usedNode.y < freeNode.y + freeNode.height and usedNode.y + usedNode.height > freeNode.y: if usedNode.x > freeNode.x and usedNode.x < freeNode.x + freeNode.width: newNode = core.Rect(freeNode) newNode.width = usedNode.x - newNode.x self._freeRectangles.append(newNode) if usedNode.x + usedNode.width < freeNode.x + freeNode.width: newNode = core.Rect(freeNode) newNode.x = usedNode.x + usedNode.width newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width) self._freeRectangles.append(newNode) return True
def _updateBounds(self, indent, offset, visibleItems): visibleItems.add(self) style = self.style layoutFont = style.font.textFont labelTextWidth = (layoutFont.lineWidth(self.labelText) + layoutFont.outline * 2) / style.scaleFactor labelTextHeight = (layoutFont.lineHeight() + layoutFont.baseline) / style.scaleFactor if self.labelImage: labelIconWidth = self.labelImage.width / style.scaleFactor labelIconHeight = self.labelImage.height / style.scaleFactor else: labelIconWidth = 0 labelIconHeight = 0 contentHeight = max(style.expandIconSize, labelIconHeight, labelTextHeight) contentHeight = math.ceil(contentHeight) rowHeight = contentHeight + style.topMargin + style.bottomMargin x = offset.x + indent * style.indentationLevelWidth + style.leftMargin y = offset.y - (contentHeight + style.topMargin) self._expandIconRect = core.Rect( x, y + (contentHeight - style.expandIconSize) * 0.5, style.expandIconSize, style.expandIconSize) x += style.expandIconSize + style.padding self._labelIconRect = core.Rect( x, y + (contentHeight - labelIconHeight) * 0.5, labelIconWidth, labelIconHeight) x += labelIconWidth + style.padding self._labelTextRect = core.Rect( x, y + (contentHeight - labelTextHeight) * 0.5, labelTextWidth, labelTextHeight) self._rowRect = core.Rect(offset.x, offset.y - rowHeight, x + labelTextWidth + style.rightMargin, rowHeight) maxHeight = rowHeight maxWidth = self._rowRect.width offset.y -= rowHeight if self.expanded: for item in self.children: w, h = item._updateBounds(indent + 1, offset, visibleItems) maxHeight += h maxWidth = max(maxWidth, w) self._groupRect = core.Rect(offset.x, offset.y, maxWidth, maxHeight) return maxWidth, maxHeight
def show(self, screen, callback): if callback: assert callable(callback) if len(self.buttons) == 0: self.buttons.append('Dismiss') numButtons = len(self.buttons) totalButtonsWidth = (self.minimumButtonWidth + self.buttonPadding ) * numButtons + self.buttonPadding width = max(totalButtonsWidth, self.minimumViewWidth) buttonWidth = floor((width - self.buttonPadding) / numButtons - self.buttonPadding) alertView = titled.TitledView() alertView.caption = self.title alertView.frame = alertView.frameForContentFrame( core.Rect(0, 0, width, self.viewHeight)) bounds = alertView.contentBounds() rect = core.Rect(bounds) rect.y += self.buttonHeight + self.buttonPadding rect.height -= self.buttonHeight + self.buttonPadding textView = label.Label(self.text, frame=rect) textView.fontAttributes = font.attributes(18) textView.align = label.ALIGN_CENTER textView.textColor = core.Color(0, 0, 0) textView.backgroundColor = core.Color(1, 1, 1) rect.origin = bounds.x, bounds.y rect.size = buttonWidth, self.buttonHeight rect.x += self.buttonPadding rect.y += self.buttonPadding print('bounds', bounds) print('rect', rect) tag = 0 for txt in self.buttons: btn = button.Button(txt, frame=rect) btn.tag = tag tag += 1 btn.addTarget(self, self._onButtonClick) alertView.addChild(btn) rect.x += self.buttonPadding + buttonWidth alertView.addChild(textView) self._modal = modal.Modal(alertView) self._modal.present(screen.frame, self._onModalCallback) self.callback = callback
def onRender(self, renderer): border = round(self.borderWidth) border2 = border * 2 bounds = self.bounds() rc = core.Rect(bounds.x + border, bounds.y + border, bounds.width - border2, bounds.height - border2) prog = self._progress / (self.maximumValue - self.minimumValue) if prog < 0.0: prog = 0.0 if prog > 1.0: prog = 1.0 rc.width = rc.width * prog if border > 0: renderer.clear(self.borderColor) with renderer.contextForSolidRects( self.progressColor, blend=blendstate.defaultOpaque) as r: r.add(rc) rc.x += rc.width rc.width = (bounds.width - border2) - rc.width with renderer.contextForSolidRects( self.backgroundColor, blend=blendstate.defaultOpaque) as r: r.add(rc) else: renderer.clear(self.backgroundColor) with renderer.contextForSolidRects( self.progressColor, blend=blendstate.defaultOpaque) as r: r.add(rc)
def addItems(view, items, rect, columns=1, selectedItemIndex=0, group=None): if group is None: group = object() buttons = [] numItems = len(items) columns = max(columns, 1) rows = math.ceil(numItems / columns) width = rect.width / columns height = rect.height / rows count = 0 for v in items: col = count % columns row = int(count / columns) rc = core.Rect(rect.x + width * col, rect.y + height * row, width, height) item = RadioButton(v, group, frame=rc) buttons.append(item) count += 1 try: button = buttons[selectedItemIndex] button.setSelected() except IndexError: pass if view is not None: for item in buttons: view.addChild(item) return buttons
def _findPositionForNewNodeContactPoint(self, width, height, bestContactScore, reverse=False): bestContactScore = -1 bestNode = core.Rect() for rectItem in self._freeRectangles: if rectItem.width >= width and rectItem.height >= height: score = self._contactPointScoreNode(rectItem.x, rectItem.y, width, height) if score > bestContactScore: bestNode.x = rectItem.x bestNode.y = rectItem.y bestNode.width = width bestNode.height = height bestContactScore = score if rectItem.width >= height and rectItem.height >= width: score = self._contactPointScoreNode(rectItem.x, rectItem.y, height, width) if score > bestContactScore: bestNode.x = rectItem.x bestNode.y = rectItem.y bestNode.width = height bestNode.height = width bestContactScore = score if reverse: bestContactScore = -bestContactScore return bestNode
def _findPositionForNewNodeBestAreaFit(self, width, height, bestAreaFit, bestShortSideFit): bestAreaFit = sys.maxsize bestNode = core.Rect() for rectItem in self._freeRectangles: areaFit = rectItem.width * rectItem.height - width * height if rectItem.width >= width and rectItem.height >= height: leftoverHoriz = abs(rectItem.width - width) leftoverVert = abs(rectItem.height - height) shortSideFit = min(leftoverHoriz, leftoverVert) if areaFit < bestAreaFit or (areaFit == bestAreaFit and shortSideFit < bestShortSideFit): bestNode.x = rectItem.x bestNode.y = rectItem.y bestNode.width = width bestNode.height = height bestShortSideFit = shortSideFit bestAreaFit = areaFit if rectItem.width >= height and rectItem.height >= width: leftoverHoriz = abs(rectItem.width - height) leftoverVert = abs(rectItem.height - width) shortSideFit = min(leftoverHoriz, leftoverVert) if areaFit < bestAreaFit or (areaFit == bestAreaFit and shortSideFit < bestShortSideFit): bestNode.x = rectItem.x bestNode.y = rectItem.y bestNode.width = height bestNode.height = width bestShortSideFit = shortSideFit bestAreaFit = areaFit return bestNode
def _findPositionForNewNodeBottomLeft(self, width, height, bestY, bestX): bestY = sys.maxsize bestNode = core.Rect() for rectItem in self._freeRectangles: if rectItem.width >= width and rectItem.height >= height: topSideY = rectItem.y + height if topSideY < bestY or (topSideY == bestY and rectItem.x < bestX): bestNode.x = rectItem.x bestNode.y = rectItem.y bestNode.width = width bestNode.height = height bestY = topSideY bestX = rectItem.x if rectItem.width >= height and rectItem.height >= width: topSideY = rectItem.y + width if topSideY < bestY or (topSideY == bestY and rectItem.x < bestX): bestNode.x = rectItem.x bestNode.y = rectItem.y bestNode.width = height bestNode.height = width bestY = topSideY bestX = rectItem.x return bestNode
def onRender(self, renderer): c = self.backgroundColor if self.enabled: if self.__mouseTrackInfo: self.backgroundColor = self.outerBoundColorActivated textColor = self.titleTextColorActivated outlineColor = self.titleOutlineColorActivated elif self.__mouseHover: self.backgroundColor = self.outerBoundColorHighlighted textColor = self.titleTextColorHighlighted outlineColor = self.titleOutlineColorHighlighted else: self.backgroundColor = self.outerBoundColor textColor = self.titleTextColor outlineColor = self.titleOutlineColor else: self.backgroundColor = self.outerBoundColorDisabled textColor = self.titleTextColorDisabled outlineColor = self.titleOutlineColorDisabled super().onRender(renderer) self.backgroundColor = c _tm = renderer.transform renderer.transform = core.Matrix3() titleRect = self.titleFrame() titleRect.x += self.captionLeftMargin titleRect.width -= self.captionLeftMargin + self.captionRightMargin titleRect.y += self.captionBottomMargin titleRect.height -= self.captionTopMargin + self.captionBottomMargin font.drawText(renderer, titleRect, self.caption, self.font, textColor, outlineColor, align=font.ALIGN_BOTTOM) bounds = TitledView.contentBounds(self) border = round(self.contentBorder) if border > 0: rc = core.Rect(bounds) rc.x -= border rc.width += border * 2 rc.y -= border rc.height += border * 2 with renderer.contextForSolidRects( self.borderColor, blend=blendstate.defaultOpaque) as r: r.add(rc) with renderer.contextForSolidRects( self.backgroundColor, blend=blendstate.defaultOpaque) as r: r.add(bounds) pixelBounds = self.convertLocalToPixel(self.unprojectLocalRect(bounds)) renderer.viewport = pixelBounds.tuple renderer.bounds = bounds.tuple renderer.transform = _tm
def _updateScrollSliderRect(self): self.__verticalScrollSliderRect = None self.__horizontalScrollSliderRect = None if self.showVerticalScrollBar or self.showHorizontalScrollBar: # print('_updateScrollSliderRect ({})'.format(core.Timer.tick())) bounds = self.contentBounds() if self.showVerticalScrollBar: scale = bounds.height / self.__zoomScale scrollMax = self.__contentSize.height - scale if scrollMax > 0 and self.__verticalScrollTrackRect.height > 2: rc = core.Rect(self.__verticalScrollTrackRect) pos = self.__contentOffset.y / scrollMax height = rc.height sliderMinLength = self.scrollSliderMinimumLength if sliderMinLength >= rc.height: sliderMinLength = rc.height * 0.5 rc.height = ( rc.height - sliderMinLength ) * scale / self.__contentSize.height + sliderMinLength rc.y += (height - rc.height) * pos self.__verticalScrollSliderRect = rc if self.showHorizontalScrollBar: scale = bounds.width / self.__zoomScale scrollMax = self.__contentSize.width - scale if scrollMax > 0 and self.__horizontalScrollTrackRect.height > 2: rc = core.Rect(self.__horizontalScrollTrackRect) pos = self.__contentOffset.x / scrollMax width = rc.width sliderMinLength = self.scrollSliderMinimumLength if sliderMinLength >= rc.width: sliderMinLength = rc.width * 0.5 rc.width = ( rc.width - sliderMinLength ) * scale / self.__contentSize.width + sliderMinLength rc.x += (width - rc.width) * pos self.__horizontalScrollSliderRect = rc
def onRender(self, renderer): super().onRender(renderer) bounds = self.contentBounds() itemPadding = self.itemPadding offsetX = bounds.x + self.margin width = bounds.width - self.margin * 2 height = bounds.height - self.margin * 2 scale = 1.0 / self.scaleFactor state = _ITEM_STATE_NORMAL if self.enabled else _ITEM_STATE_DISABLED if self.__popup or self.verticalLayout: offsetY = bounds.y + bounds.height - self.margin for item in self.__items: w, h = item.calculateFrameSize(_LAYOUT_VERTICAL, scale) offsetY -= h rc = core.Rect(offsetX, offsetY, max(w, width), h) itemState = state if self.__highlightedItem == item and item.selectable( ) and itemState == _ITEM_STATE_NORMAL: itemState = _ITEM_STATE_HIGHLIGHTED with renderer.contextForSolidRects( self.backgroundColorHighlighted) as r: r.add(rc) item.drawRect(renderer, rc, itemState, _LAYOUT_VERTICAL) offsetY -= itemPadding else: offsetY = bounds.y + self.margin for item in self.__items: w, h = item.calculateFrameSize(_LAYOUT_HORIZONTAL, scale) rc = core.Rect(offsetX, offsetY, w, max(h, height)) itemState = state if self.__highlightedItem == item and item.selectable( ) and itemState == _ITEM_STATE_NORMAL: itemState = _ITEM_STATE_HIGHLIGHTED with renderer.contextForSolidRects( self.backgroundColorHighlighted) as r: r.add(rc) item.drawRect(renderer, rc, itemState, _LAYOUT_HORIZONTAL) offsetX = offsetX + w + itemPadding
def contentBounds(self): border = round(self.contentBorder) margin = round(self.contentMargin) bounds = super().contentBounds() y1 = bounds.y + margin + border y2 = bounds.y + bounds.height - self.captionHeight - margin - border x1 = bounds.x + margin + border x2 = bounds.x + bounds.width - margin - border return core.Rect(x1, y1, x2 - x1, y2 - y1)
def frameForContentFrame(self, frame): frameBorder = round(self.borderWidth) contentBorder = round(self.contentBorder) margin = round(self.contentMargin) x1 = frame.x - (margin + contentBorder + frameBorder) x2 = frame.x + frame.width + (margin + contentBorder + frameBorder) y1 = frame.y - (margin + contentBorder + frameBorder) y2 = frame.y + frame.height + (margin + contentBorder + frameBorder + self.captionHeight) return core.Rect(x1, y1, x2 - x1, y2 - y1)
def __init__(self, frame=core.Rect(0, 0, 1, 1), *args, **kwargs): super().__init__(*args, **kwargs) self.scaleFactor = DEFAULT_UI_SCALE assert self.scaleFactor > 0 assert isinstance(frame, core.Rect) self.layouter = None self.gestureRecognizers = [] self.setFrame(frame) self.setBlendState(blendstate.defaultOpaque) self.font = None
def _splitFreeRectAlongAxis(self, freeRect, placedRect, splitHorizontal): bottom = core.Rect() bottom.x = freeRect.x bottom.y = freeRect.y + placedRect.height bottom.height = freeRect.height - placedRect.height right = core.Rect() right.x = freeRect.x + placedRect.width right.y = freeRect.y right.width = freeRect.width - placedRect.width if splitHorizontal: bottom.width = freeRect.width right.height = placedRect.height else: bottom.width = placedRect.width right.height = freeRect.height if bottom.width > 0 and bottom.height > 0: self._freeRectangles.append(bottom) if right.width > 0 and right.height > 0: self._freeRectangles.append(right)
def onRender(self, renderer): super().onRender(renderer) adjustFactor = core.Point((self.frame.width / self.binWidth), (self.frame.height / self.binHeight)) ##################################################################### for index in range(len(self.packedBounds)): renderBound = core.Rect(self.packedBounds[index]) renderBound.x = adjustFactor.x * renderBound.x renderBound.y = adjustFactor.y * renderBound.y renderBound.width = adjustFactor.x * renderBound.width renderBound.height = adjustFactor.y * renderBound.height with renderer.contextForSolidRects(self.packedColors[index]) as r: r.add(renderBound)
def drawRect(self, renderer, rect, state, layout): super().drawRect(renderer, rect, state, layout) style = self.style if layout == _LAYOUT_VERTICAL: w = rect.width - style.separatorMargin * 2 h = style.separatorWidth else: w = style.separatorWidth h = rect.height - style.separatorMargin * 2 x = (rect.width - w) * 0.5 y = (rect.height - h) * 0.5 rc = core.Rect(rect.x + x, rect.y + y, w, h) with renderer.contextForSolidRects(style.separatorColor) as r: r.add(rc)
def _findPositionForNewNodeBestShortSideFit(self, width, height, bestShortSideFit, bestLongSideFit): bestShortSideFit = sys.maxsize bestNode = core.Rect() for rectItem in self._freeRectangles: if rectItem.width >= width and rectItem.height >= height: leftoverHoriz = abs(rectItem.width - width) leftoverVert = abs(rectItem.height - height) shortSideFit = min(leftoverHoriz, leftoverVert) longSideFit = max(leftoverHoriz, leftoverVert) if shortSideFit < bestShortSideFit or ( shortSideFit == bestShortSideFit and longSideFit < bestLongSideFit): bestNode.x = rectItem.x bestNode.y = rectItem.y bestNode.width = width bestNode.height = height bestShortSideFit = shortSideFit bestLongSideFit = longSideFit if rectItem.width >= height and rectItem.height >= width: flippedLeftoverHoriz = abs(rectItem.width - height) flippedLeftoverVert = abs(rectItem.height - width) flippedShortSideFit = min(flippedLeftoverHoriz, flippedLeftoverVert) flippedLongSideFit = max(flippedLeftoverHoriz, flippedLeftoverVert) if flippedShortSideFit < bestShortSideFit or ( flippedShortSideFit == bestShortSideFit and flippedLongSideFit < bestLongSideFit): bestNode.x = rectItem.x bestNode.y = rectItem.y bestNode.width = height bestNode.height = width bestShortSideFit = flippedShortSideFit bestLongSideFit = flippedLongSideFit return bestNode
def _findPositionForNewNode(self, width, height, rectChoice): nodeIndex = 0 bestNode = core.Rect() bestScore = sys.maxsize for itemIndex in range(len(self._freeRectangles)): if width == self._freeRectangles[itemIndex].width and height == self._freeRectangles[itemIndex].height: bestNode.x = self._freeRectangles[itemIndex].x bestNode.y = self._freeRectangles[itemIndex].y bestNode.width = width bestNode.height = height bestScore = sys.maxsize nodeIndex = itemIndex break elif height == self._freeRectangles[itemIndex].width and width == self._freeRectangles[itemIndex].height: bestNode.x = self._freeRectangles[itemIndex].x bestNode.y = self._freeRectangles[itemIndex].y bestNode.width = height bestNode.height = width bestScore = sys.maxsize nodeIndex = itemIndex break elif width <= self._freeRectangles[itemIndex].width and height <= self._freeRectangles[itemIndex].height: score = GuillotineBinPack._scoreByHeuristic(width, height, self._freeRectangles[itemIndex], rectChoice) if score < bestScore: bestNode.x = self._freeRectangles[itemIndex].x bestNode.y = self._freeRectangles[itemIndex].y bestNode.width = width bestNode.height = height bestScore = score nodeIndex = itemIndex elif height <= self._freeRectangles[itemIndex].width and width <= self._freeRectangles[itemIndex].height: score = GuillotineBinPack._scoreByHeuristic(height, width, self._freeRectangles[itemIndex], rectChoice) if score < bestScore: bestNode.x = self._freeRectangles[itemIndex].x bestNode.y = self._freeRectangles[itemIndex].y bestNode.width = height bestNode.height = width bestScore = score nodeIndex = itemIndex return bestNode, nodeIndex
def popupOnScreen(self, screen, origin, parentMenu=None): if self.parent() is None: self.unload() self.__popup = True self.__autoExpand = True self.verticalLayout = True root = screen.frame root.addChild(self) self.load(screen) # load font to calculate frame size = self.calculateFrameSize() sizeInPixel = self.convertLocalToPixel(size) sizeInRoot = root.convertPixelToLocal(sizeInPixel) origin.y -= sizeInRoot.height originInPixel = root.convertLocalToPixel(origin) originInPixel.x = math.floor(originInPixel.x + 0.5) originInPixel.y = math.floor(originInPixel.y + 0.5) originInRoot = root.convertPixelToLocal(originInPixel) frame = core.Rect(originInRoot, sizeInRoot) bounds = root.contentDisplayBounds() if frame.x < bounds.x: frame.x = bounds.x if frame.y < bounds.y: frame.y = bounds.y if frame.x + frame.width > bounds.x + bounds.width: frame.x = bounds.x + bounds.width - frame.width if frame.y + frame.height > bounds.y + bounds.height: frame.y = bounds.y + bounds.height - frame.height self.frame = frame self.redraw() if not isinstance(parentMenu, Menu): screen.postOperation(self._popupMouseSetup, ()) return self
def insert(self, width, height, method): if width <= 0 or height <= 0: print("MaxRectsBinPack::_binWidth and _binHeight must not be 0") return None score1, score2 = 0, 0 newNode = core.Rect() if method == FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = self._findPositionForNewNodeBestShortSideFit( width, height, score1, score2) elif method == FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = self._findPositionForNewNodeBestLongSideFit( width, height, score2, score1) elif method == FreeRectChoiceHeuristic.RectBestAreaFit: newNode = self._findPositionForNewNodeBestAreaFit( width, height, score1, score2) elif method == FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = self._findPositionForNewNodeBottomLeft( width, height, score1, score2) elif method == FreeRectChoiceHeuristic.RectContactPointRule: newNode = self._findPositionForNewNodeContactPoint( width, height, score1) if newNode.height == 0: return newNode index = 0 numRectanglesToProcess = len(self._freeRectangles) while index < numRectanglesToProcess: if self._splitFreeNode(self._freeRectangles[index], newNode): self._freeRectangles.pop(index) index = index - 1 numRectanglesToProcess = numRectanglesToProcess - 1 index = index + 1 self._pruneFreeList() self._usedRectangles.append(newNode) return newNode
def _render(self, rc, transform, color): if self.hidden: return cc = core.Color(self.diffuse[0] * color.r, self.diffuse[1] * color.g, self.diffuse[2] * color.b, self.alpha[0] * color.a) if cc.a > 0.0: transform = self.transform * transform # get texture ids if self.texturePack: texIds = self._textureIdsForState[self.state] if len(texIds): texIndex = round(self.textureIndex[0]) % len(texIds) texKey = texIds[texIndex] frame = self.texturePack.frames.get(texKey) else: frame = self.texturePack.frames.get(self.name) if frame: # draw other Sprites if rc.texture != self.texturePack.texture or rc.color.argb32Value( ) != cc.argb32Value(): if rc.texture: with rc: pass rc.texture = self.texturePack.texture rc.color = cc # calculate texture frame. rect = core.Rect(self.size[0] * frame.offset.x, self.size[1] * frame.offset.y, self.size[0] * frame.scale.width, self.size[1] * frame.scale.height) rc.add(rect, transform, self.TEXTURE_RECT, frame.transform) for c in self.children: c._render(rc, transform, cc)
def __frameClippedByParentBounds(self, frame): parent = self.parent() if parent: try: bounds = parent.contentBounds() except AttributeError: bounds = parent.bounds() # make a copy of frame frame = core.Rect(frame) if frame.width > bounds.width: frame.x = bounds.x elif frame.x + frame.width > bounds.x + bounds.width: frame.x = bounds.x + bounds.width - frame.width elif frame.x < bounds.x: frame.x = bounds.x if frame.height > bounds.height: frame.y = bounds.y + bounds.height - frame.height elif frame.y + frame.height > bounds.y + bounds.height: frame.y = bounds.y + bounds.height - frame.height elif frame.y < bounds.y: frame.y = bounds.y return frame
def unprojectLocalRect(self, rect): """ convert visible(projected) local rect to actual(un-projected) local rect. :param rect: value to convert :type rect: Rect :return: value converted :rtype: Rect """ v0 = core.Vector2(rect.origin) v1 = core.Vector2(rect.x, rect.y + rect.height) v2 = core.Vector2(rect.x + rect.width, rect.y) v3 = core.Vector2(rect.x + rect.width, rect.y + rect.height) mat = self.contentTransformInverseMatrix() for v in (v0, v1, v2, v3): v.transform(mat) x1 = min(v0.x, v1.x, v2.x, v3.x) x2 = max(v0.x, v1.x, v2.x, v3.x) y1 = min(v0.y, v1.y, v2.y, v3.y) y2 = max(v0.y, v1.y, v2.y, v3.y) return core.Rect(x1, y1, x2-x1, y2-y1)
def setFrame(self, frame): assert isinstance(frame, core.Rect) #assert frame.width > 0 #assert frame.height > 0 assert self.minimumViewWidth > 0 assert self.minimumViewHeight > 0 width = max(frame.width, self.minimumViewWidth) height = max(frame.height, self.minimumViewHeight) frame = core.Rect(frame.origin + (width, height)) try: f = self.__frame if f == frame: return except AttributeError: pass self.__frame = frame self.contentScale = width, height linear = core.LinearTransform2() linear.scale(width, height) self.transform = core.AffineTransform2(linear, frame.origin).matrix3()
def bounds(self): ''' :return: projected local bounds rect (include border) ''' w, h = self.contentScale return core.Rect(0, 0, w, h)
def frame(self): return core.Rect(self.__frame)
def drawText(renderer, frame, text, font, textColor=core.Color(1.0, 1.0, 1.0, 1.0), outlineColor=core.Color(0, 0, 0, 0.5), scaleToFit=False, align=ALIGN_CENTER, alignToPixel=True, linebreak=LINE_BREAK_TRUNCATING_TAIL, blend=blendstate.defaultAlpha): textFont = None outlineFont = None if font: if isinstance(font, UIFont): textFont = font.textFont outlineFont = font.outlineFont elif isinstance(font, core.Font): textFont = font elif isinstance(font, (tuple, list)): c = len(font) if c > 0: textFont = font[0] if c > 1: outlineFont = font[1] else: raise TypeError( 'font argument must be Font or two Font objects tuple.') layoutFont = textFont if textFont else outlineFont if len(text) > 0 and frame.width > 0 and frame.height > 0 and layoutFont: viewport = renderer.viewport[2:] scale = renderer.bounds[2:] scaleFactor = (viewport[0] / scale[0], viewport[1] / scale[1]) localToPixel = lambda x, y: (x * scaleFactor[0], y * scaleFactor[1]) pixelToLocal = lambda x, y: (x / scaleFactor[0], y / scaleFactor[1]) pixelFrame = core.Rect(frame) pixelFrame.origin = localToPixel(*frame.origin) pixelFrame.size = localToPixel(*frame.size) text = linebreak(pixelFrame, layoutFont, text) width = layoutFont.lineWidth(text) height = layoutFont.lineHeight() baseline = layoutFont.baseline if scaleToFit: scaleX = pixelFrame.width / width scaleY = pixelFrame.height / height scale = min(scaleX, scaleY) width = width * scale height = height * scale baseline = baseline * scale begin = align(pixelFrame, width, height, baseline) if alignToPixel: x = floor(begin[0] + 0.5) y = floor(begin[1] + 0.5) begin = (x, y) end = (begin[0] + width, begin[1]) begin = core.Point(pixelToLocal(*begin)) end = core.Point(pixelToLocal(*end)) if outlineFont and outlineColor: renderer.renderTextBaseline(begin, end, text, outlineFont, outlineColor, blend) if textFont and textColor: renderer.renderTextBaseline(begin, end, text, textFont, textColor, blend)
def onRender(self, renderer): super().onRender(renderer) border = round(self.scrollBarBorderWidth) / self.__zoomScale border2 = border * 2 trackPos = self.__mouseTrackInfo.type if self.__mouseTrackInfo else 0 hoverPos = self.__mouseHoverPos if self.__verticalScrollTrackRect: rc = self.unprojectLocalRect(self.__verticalScrollTrackRect) if border > 0: with renderer.contextForSolidRects( self.borderColor, blend=blendstate.defaultOpaque) as r: r.add( core.Rect(rc.x - border, rc.y - border, rc.width + border2, rc.height + border2)) color = self.scrollTrackColorHighlighted if hoverPos == _POS_VERTICAL_SCROLL_TRACK \ else self.scrollTrackColor if self.__verticalScrollSliderRect \ else self.scrollTrackColorDisabled with renderer.contextForSolidRects( color, blend=blendstate.defaultOpaque) as r: r.add(rc) if self.__verticalScrollSliderRect: rc = self.unprojectLocalRect(self.__verticalScrollSliderRect) color = self.scrollSliderColorActivated if trackPos == _POS_VERTICAL_SCROLL_SLIDER \ else self.scrollSliderColorHighlighted if hoverPos == _POS_VERTICAL_SCROLL_SLIDER \ else self.scrollSliderColor with renderer.contextForSolidRects( color, blend=blendstate.defaultOpaque) as r: r.add(rc) if self.__horizontalScrollTrackRect: rc = self.unprojectLocalRect(self.__horizontalScrollTrackRect) if border > 0: with renderer.contextForSolidRects( self.borderColor, blend=blendstate.defaultOpaque) as r: r.add( core.Rect(rc.x - border, rc.y - border, rc.width + border2, rc.height + border2)) color = self.scrollTrackColorHighlighted if hoverPos == _POS_HORIZONTAL_SCROLL_TRACK \ else self.scrollTrackColor if self.__horizontalScrollSliderRect \ else self.scrollTrackColorDisabled with renderer.contextForSolidRects( color, blend=blendstate.defaultOpaque) as r: r.add(rc) if self.__horizontalScrollSliderRect: rc = self.unprojectLocalRect(self.__horizontalScrollSliderRect) color = self.scrollSliderColorActivated if trackPos == _POS_HORIZONTAL_SCROLL_SLIDER \ else self.scrollSliderColorHighlighted if hoverPos == _POS_HORIZONTAL_SCROLL_SLIDER \ else self.scrollSliderColor with renderer.contextForSolidRects( color, blend=blendstate.defaultOpaque) as r: r.add(rc) if self.__zoomButtonRect: rc = self.unprojectLocalRect(self.__zoomButtonRect) if border > 0: with renderer.contextForSolidRects( self.borderColor, blend=blendstate.defaultOpaque) as r: r.add( core.Rect(rc.x - border, rc.y - border, rc.width + border2, rc.height + border2)) activated = trackPos == _POS_ZOOM_BUTTON if activated: pos = self.__mouseTrackInfo.offset + self.__zoomButtonRect.origin activated = self.__zoomButtonRect.isInside(pos) color = self.zoomButtonColorDisabled if not self.showZoomButton \ else self.zoomButtonColorActivated if activated \ else self.zoomButtonColorHighlighted if hoverPos == _POS_ZOOM_BUTTON \ else self.zoomButtonColor with renderer.contextForSolidRects( color, blend=blendstate.defaultOpaque) as r: r.add(rc) x, y = self.contentScale w, h = self.contentResolution scaleX = w / x scaleY = h / y bounds = self.contentBounds() renderer.viewport = bounds.x * scaleX, bounds.y * scaleY, bounds.width * scaleX, bounds.height * scaleY renderer.bounds = bounds
def _updateScrollTrackRect(self): self.__verticalScrollTrackRect = None self.__horizontalScrollTrackRect = None self.__zoomButtonRect = None if self.showVerticalScrollBar or self.showHorizontalScrollBar: # print('_updateScrollTrackRect') border = round(self.scrollBarBorderWidth) bounds = self.contentBounds() scrollBarSize = self.scrollBarSize if self.showVerticalScrollBar: rc = core.Rect() rc.width = scrollBarSize if self.leftScrollBar: rc.x = bounds.x - scrollBarSize - border else: rc.x = bounds.x + bounds.width + border if not self.showHorizontalScrollBar and self.showZoomButton: rc.y = bounds.y + scrollBarSize + border rc.height = bounds.height - scrollBarSize else: rc.y = bounds.y rc.height = bounds.height self.__verticalScrollTrackRect = rc if self.showHorizontalScrollBar: rc = core.Rect() rc.x = bounds.x rc.y = bounds.y - scrollBarSize - border rc.height = scrollBarSize if not self.showVerticalScrollBar and self.showZoomButton: rc.width = bounds.width - scrollBarSize + border if self.leftScrollBar: rc.x = bounds.x + scrollBarSize + border else: rc.width = bounds.width self.__horizontalScrollTrackRect = rc zoomRectShouldVisible = self.showVerticalScrollBar and self.showHorizontalScrollBar if zoomRectShouldVisible or self.showZoomButton: rc = core.Rect() rc.width = scrollBarSize rc.height = scrollBarSize if self.showVerticalScrollBar: if self.leftScrollBar: rc.x = bounds.x - scrollBarSize - border else: rc.x = bounds.x + bounds.width + border else: if self.leftScrollBar: rc.x = bounds.x else: rc.x = bounds.x + bounds.width - scrollBarSize if self.showHorizontalScrollBar: rc.y = bounds.y - scrollBarSize - border else: rc.y = bounds.y self.__zoomButtonRect = rc self._updateScrollSliderRect()