def onInit(self): # white background avg.RectNode(parent=self, size=self.size, fillopacity=1.0) # foreground image self._fg = avg.ImageNode(parent=self, href='rgb24-64x64.png', size=self.size, masksize=self.size) # mask drawing canvas self._maskCanvas = player.createCanvas(id='mask', size=self.size, handleevents=False, autorender=False) # image to put the canvas on-screen (invisible) self._maskImage = avg.ImageNode(parent=self, href='canvas:mask', opacity=0.0) # black mask on start (full transparency) avg.RectNode(parent=self._maskCanvas.getRootNode(), size=self.size, color='000000', fillcolor='000000', fillopacity=1.0) # poly line to draw white on black mask (adding opacity) self._drawLine = None self._updateMask() self._maskImage.subscribe(self._maskImage.CURSOR_DOWN, self._onDown) self._maskImage.subscribe(self._maskImage.CURSOR_MOTION, self._onMotion) self._maskImage.subscribe(self._maskImage.CURSOR_UP, self._onUp)
def initFeld(self, startX, endX, oben): #linker Rahmen avg.RectNode( parent=self.divNodeGameMenue, sensitive=False, pos=(startX - self.rahmenbreite, oben), fillcolor="000000", fillopacity=1, color="000000", size=avg.Point2D( self.rahmenbreite, self.tetrishoehe) #self.divNodeGameMenue.size[1]* 0.87 ) #rechter Rahmen avg.RectNode(parent=self.divNodeGameMenue, pos=(endX, oben), sensitive=False, fillcolor="000000", fillopacity=1, color="000000", size=avg.Point2D(self.rahmenbreite, self.tetrishoehe)) #Boden avg.RectNode( parent=self.divNodeGameMenue, sensitive=False, pos=(startX - self.rahmenbreite, self.tetrishoehe + oben), fillcolor="000000", fillopacity=1, color="000000", size=avg.Point2D( endX - startX + 2 * int(self.divNodeGameMenue.size[0] * 0.025), self.rahmenbreite))
def __init__(self, GameMenue, Field): self.Field = Field self.gameMenue = GameMenue self.part1 = avg.RectNode(parent = GameMenue.divNodeGameMenue, pos = (Field.xWertLinksOben+ (6 * GameMenue.blocksize), Field.yWertOben), fillcolor = "FFFF00", fillopacity = 1, color = "000000", size = avg.Point2D(GameMenue.blocksize ,GameMenue.blocksize) ) self.part2 = avg.RectNode(parent = GameMenue.divNodeGameMenue, pos = (Field.xWertLinksOben+ (7 * GameMenue.blocksize), Field.yWertOben), fillcolor = "FFFF00", fillopacity = 1, color = "000000", size = avg.Point2D(GameMenue.blocksize ,GameMenue.blocksize) ) self.part3 = avg.RectNode(parent = GameMenue.divNodeGameMenue, pos = (Field.xWertLinksOben+ (8 * GameMenue.blocksize), Field.yWertOben), fillcolor = "FFFF00", fillopacity = 1, color = "000000", size = avg.Point2D(GameMenue.blocksize ,GameMenue.blocksize) ) self.part4 = avg.RectNode(parent = GameMenue.divNodeGameMenue, pos = (Field.xWertLinksOben+ (9 * GameMenue.blocksize), Field.yWertOben), fillcolor = "FFFF00", fillopacity = 1, color = "000000", size = avg.Point2D(GameMenue.blocksize ,GameMenue.blocksize) ) self.currPos1 = (6,0) self.currPos2 = (7,0) self.currPos3 = (8,0) self.currPos4 = (9,0) self.blockType = "I" self.rotatingPosition = 0
def __init__(self, parent=None, **kwargs): super(CrossCursor, self).__init__(**kwargs) self.registerInstance(self, parent) color = self.colors['Healthy'] if 'Bumpy' in self._device.rui_proxy_name: color = self.colors['Bumpy'] if 'Bumpy' not in self._device.rui_proxy_name: avg.CircleNode(parent=self, r=self.circle_size, strokewidth=self.circle_bg_width, fillopacity=0, color=color['bg'], opacity=self.bg_opacity) avg.CircleNode(parent=self, r=self.circle_size, strokewidth=self.circle_width, fillopacity=0, color=self.circle_color) else: w = self.circle_size * 1.75 hW = w * .5 avg.RectNode(parent=self, size=(w, w), pos=(-hW, -hW), strokewidth=self.circle_bg_width, fillopacity=0, color=color['bg'], opacity=self.bg_opacity) avg.RectNode(parent=self, size=(w, w), pos=(-hW, -hW), strokewidth=self.circle_width, fillopacity=0, color=self.circle_color) # draw cross diff = (self.cross_bg_width - self.cross_width) * .5 avg.LineNode(parent=self, pos1=(-self.cross_half_length + diff, 0), pos2=(-self.cross_center_offset - diff, 0), strokewidth=self.cross_width, color=color['fc']) avg.LineNode(parent=self, pos1=(self.cross_half_length - diff, 0), pos2=(self.cross_center_offset + diff, 0), strokewidth=self.cross_width, color=color['fc']) avg.LineNode(parent=self, pos1=(0, -self.cross_half_length + diff), pos2=(0, -self.cross_center_offset - diff), strokewidth=self.cross_width, color=color['fc']) avg.LineNode(parent=self, pos1=(0, self.cross_half_length - diff), pos2=(0, self.cross_center_offset + diff), strokewidth=self.cross_width, color=color['fc'])
def __init__(self, vis_params, session, parent, **kwargs): super(OptionsPanel, self).__init__(**kwargs) self.registerInstance(self, parent) self.__vis_params = vis_params self.parent_div = parent # parent node self.__duration = session.duration self.__time_interval = [None, None] # rect for coloured border and background self.background_rect = avg.RectNode( pos=(0, 0), size=self.size, parent=self, strokewidth=1, fillopacity=1, color=global_values.COLOR_BACKGROUND, fillcolor=global_values.COLOR_BACKGROUND) """play/pause button""" icon_size = (15, 15) button_size = (30, 30) # rect for play button border self.play_rect = avg.RectNode(pos=(6, 22), size=button_size, parent=self, strokewidth=1, fillopacity=0, color=global_values.COLOR_FOREGROUND, sensitive=False) # play button icon_h_size = (icon_size[0] / 2, icon_size[1] / 2) self.play_button = widget.ToggleButton( uncheckedUpNode=avg.ImageNode(href="images/play.png", pos=icon_h_size, size=icon_size), uncheckedDownNode=avg.ImageNode(href="images/play.png", pos=icon_h_size, size=icon_size), checkedUpNode=avg.ImageNode(href="images/pause.png", pos=icon_h_size, size=icon_size), checkedDownNode=avg.ImageNode(href="images/pause.png", pos=icon_h_size, size=icon_size), pos=self.play_rect.pos, size=button_size, parent=self) self.play_button.subscribe(widget.CheckBox.TOGGLED, lambda checked: self.__play_pause(checked)) self.__init_time_bar(self.__duration, vis_params.get_time_interval()) self.__phase_lines = {} self.__create_phase_lines(session) # self.__init_smoothness_slider() self.__vis_params.subscribe(self.__vis_params.CHANGED, self.__update_time) self.__vis_params.subscribe(self.__vis_params.IS_PLAYING, self.__on_play_pause)
def __init__(self, label, vis_params, axis_size, show_grid, aspect=None, parent=None, **kwargs): super(VisPanel, self).__init__(**kwargs) self.registerInstance(self, parent) self.crop = True self.__axis_size = avg.Point2D(axis_size) data_div_size = self.size - self.__axis_size if aspect is not None: data_div_size.y = data_div_size.x * aspect self.size = data_div_size + self.__axis_size # rect for background avg.RectNode(pos=(self.__axis_size.x, 0), size=data_div_size, strokewidth=0, fillopacity=1, fillcolor=global_values.VIS_PANEL_BACKGROUND, parent=self) self._grid_div = avg.DivNode(pos=(self.__axis_size.x, 0), size=data_div_size, parent=self) # rect for border avg.RectNode(pos=(self.__axis_size.x, 0), size=data_div_size, strokewidth=1, color=global_values.COLOR_FOREGROUND, parent=self) self._data_div = avg.DivNode(pos=(self.__axis_size.x, 0), size=data_div_size, crop=True) avg.WordsNode(pos=(6, 6), color=global_values.COLOR_FOREGROUND, text=label, variant="bold", sensitive=False, fontsize=global_values.FONT_SIZE_SMALLER, parent=self._data_div) vis_params.subscribe(vis_params.CHANGED, self._update_time) self._vis_params = vis_params self.__show_grid = show_grid self._x_grid = [] self._y_grid = [] self._x_axis = None self._y_axis = None
def testOpacity(self): root = self.loadEmptyScene() avg.ImageNode(pos=(0,0), href="rgb24-65x65.png", opacity=0.5, parent=root) avg.RectNode(pos=(0,64), size=(64,64), opacity=0.5, fillopacity=0.5, fillcolor="FF0000", strokewidth=2, parent=root) div = avg.DivNode(pos=(80,0), opacity=0.5, parent=root) avg.ImageNode(pos=(0,0), href="rgb24-65x65.png", parent=div) avg.RectNode(pos=(0,64), size=(64,64), opacity=1, fillopacity=1, fillcolor="FF0000", strokewidth=2, parent=div) self.start(False, (lambda: self.compareImage("testOpacity"), ))
def onInit(self): avg.RectNode(size=(1024, 768), fillopacity=1, fillcolor="FFFFFF", parent=self) hScrollBar = widget.ScrollBar(pos=(10, 10), width=150, parent=self) self.__addValueDisplay(hScrollBar, (175, 12)) vScrollBar = widget.ScrollBar(pos=(15, 60), height=150, orientation=widget.Orientation.VERTICAL, parent=self) vScrollBar.thumbExtent = 5 vScrollBar.range = (10, 0) self.__addValueDisplay(vScrollBar, (10, 220)) hSlider = widget.Slider(pos=(10, 35), width=150, parent=self) self.__addValueDisplay(hSlider, (175, 33)) vSlider = widget.Slider(pos=(60.5, 60), height=150, orientation=widget.Orientation.VERTICAL, parent=self) vSlider.range = (1, 0) self.__addValueDisplay(vSlider, (55, 220)) self.controls = [hScrollBar, vScrollBar, hSlider, vSlider] self.createScrollArea(avg.Point2D(220, 10)) checkBox = widget.CheckBox(pos=(10, 270), text="Disable everything", parent=self) checkBox.subscribe(widget.CheckBox.TOGGLED, self.onCheck)
def addRect(): rect = avg.RectNode(pos=(2, 2), size=(50, 30), fillopacity=1, strokewidth=0) canvas.appendChild(rect) return rect
def setup(self, widgetCls): self.__background = avg.RectNode(parent=self, opacity=0.8, fillcolor='000000', fillopacity=0.8) self.__widget = widgetCls(parent=self, size=(max(0, self.width - self.BORDER * 2), 0), pos=(self.BORDER, self.BORDER)) self.__selectHighlight = avg.RectNode(parent=self, color="35C0CD", strokewidth=self.BORDER, opacity=0.8, pos=(self.BORDER / 2, self.BORDER / 2), active=False, sensitive=False) self.__boundary = avg.RectNode(parent=self, sensitive=False) self.publish(DebugWidgetFrame.FRAME_HEIGHT_CHANGED) self.__widget.subscribe(self.__widget.WIDGET_HEIGHT_CHANGED, self.adjustWidgetHeight) self.__widget.update()
def testCheckBox(self): root = self.loadEmptyScene() avg.RectNode(size=(160, 120), fillcolor="FFFFFF", fillopacity=1, parent=root) checkBox = widget.CheckBox(text="checkboxtext", pos=(10, 10), parent=root) self.start( True, ( lambda: self.compareImage("testUICheckBoxUnchecked_Up"), lambda: self._sendMouseEvent(avg.Event.CURSOR_DOWN, 15, 15), lambda: self.compareImage("testUICheckBoxUnchecked_Down"), lambda: self._sendMouseEvent(avg.Event.CURSOR_UP, 15, 15), lambda: self.compareImage("testUICheckBoxChecked_Up"), lambda: self._sendMouseEvent(avg.Event.CURSOR_DOWN, 15, 15), lambda: self.compareImage("testUICheckBoxChecked_Down"), lambda: self._sendMouseEvent(avg.Event.CURSOR_UP, 15, 15), lambda: self.compareImage("testUICheckBoxUnchecked_Up"), lambda: checkBox.setEnabled(False), lambda: self.compareImage("testUICheckBoxUnchecked_Disabled"), lambda: checkBox.setEnabled(True), lambda: self.compareImage("testUICheckBoxUnchecked_Up"), # Test click on text. lambda: self._sendMouseEvent(avg.Event.CURSOR_DOWN, 50, 15), lambda: self.compareImage("testUICheckBoxUnchecked_Down"), ))
def _initRow(self): self.columnBackground = avg.RectNode(parent=self, fillcolor="222222", fillopacity=0.6, opacity=0) self.columnContainer = avg.DivNode(parent=self) if TableRow.ROW_ID % 2 != 0: self.columnBackground.fillopacity = 0 self.cols = [0] * NUM_COLS self.liveColumn = avg.WordsNode(parent=self.columnContainer, fontsize=g_fontsize, text="N/A - SPECIAL", size=(COL_WIDTH, ROW_HEIGHT), variant="bold") for i in xrange(0, NUM_COLS): self.cols[i] = (avg.WordsNode(parent=self.columnContainer, fontsize=g_fontsize, text="0", size=(COL_WIDTH / 2.0, ROW_HEIGHT), pos=((i + 1) * COL_WIDTH, 0)), avg.WordsNode(parent=self.columnContainer, fontsize=g_fontsize, text="(0)", size=(COL_WIDTH / 2.0, ROW_HEIGHT), pos=((i + 1) * COL_WIDTH + COL_WIDTH / 2, 0), color="000000")) self.rowData = deque([(0, 0)] * (NUM_COLS + 1), maxlen=NUM_COLS + 1) self.label = avg.WordsNode(parent=self, fontsize=g_fontsize, variant="bold") self.setLabel("NONE")
def testInputDeviceEventReceiverNode(self): root = self.loadEmptyScene() divNode = avg.DivNode(id="div", size=(50, 50), parent=root) rectNode = avg.RectNode(id="rect", size=(50, 50), parent=root) self.customInputDevice = CustomInputDevice(divNode) player.addInputDevice(self.customInputDevice) handlerTester = NodeHandlerTester(self, divNode) self.start(False, ( lambda: self.customInputDevice.feedEvent( avg.MouseEvent(avg.Event.CURSOR_DOWN, True, False, False, (10, 10), 1)), lambda: handlerTester.assertState( (avg.Node.CURSOR_DOWN, avg.Node.CURSOR_OVER)), lambda: self.customInputDevice.feedEvent( avg.MouseEvent(avg.Event.CURSOR_MOTION, True, False, False, (12, 12), 1)), lambda: handlerTester.assertState((avg.Node.CURSOR_MOTION, )), lambda: self.customInputDevice.feedEvent( avg.MouseEvent(avg.Event.CURSOR_MOTION, True, False, False, (100, 100), 1)), lambda: handlerTester.assertState((avg.Node.CURSOR_OUT, )), lambda: self.customInputDevice.feedEvent( avg.MouseEvent(avg.Event.CURSOR_MOTION, True, False, False, (12, 12), 1)), lambda: handlerTester.assertState( (avg.Node.CURSOR_OVER, avg.Node.CURSOR_MOTION)), lambda: self.customInputDevice.feedEvent( avg.MouseEvent(avg.Event.CURSOR_UP, False, False, False, (12, 12), 1)), lambda: handlerTester.assertState((avg.Node.CURSOR_UP, )), ))
def onInit(self): # avg.VideoWriter requires a canvas as source # (can be the main canvas returned by player.getMainCanvas()) canvas = player.createCanvas(id='source_canvas', size=self.size) root = canvas.getRootNode() # some nodes in source canvas self._text = avg.WordsNode(parent=root, text='000000', fontsize=42) self._text.pos = (self.size - self._text.size) / 2 self._rect = avg.RectNode(parent=root, size=(200, 200)) self._rect.pos = (self.size - self._rect.size) / 2 # show source canvas on screen (not required for video recording) avg.ImageNode(parent=self, href='canvas:source_canvas') # start writing source canvas to video file fps = int(player.getFramerate()) self._video_writer = avg.VideoWriter(canvas, 'video_writer.avi', fps) self._writing = True # these nodes are not included in the video (outside source canvas) avg.WordsNode(parent=self, text='writing to "%s"' % self._video_writer.filename) self._btn = widget.TextButton(parent=self, pos=(0, 20), size=(100, 25), text='PAUSE') self._btn.subscribe(widget.Button.CLICKED, self._onButton)
def change_configuration(self, device_pointer_config): """ Changes the device pointer configuration and draws the view anew. :param device_pointer_config: The new configuration. :type device_pointer_config: DevicePointerConfigurations """ internal_div_nodes = [ self.__internal_div.getChild(i) for i in range(self.__internal_div.getNumChildren()) ] for node in internal_div_nodes: node.unlink(True) self.__device_pointer_config = device_pointer_config self.__internal_div = avg.DivNode(parent=self) avg.RectNode( parent=self.__internal_div, strokewidth=0, fillcolor=self.__device_pointer_config.device_canvas_color, fillopacity=1, size=self.__device.size) avg.WordsNode( parent=self.__internal_div, text=self.__device_pointer_config.device_canvas_text, alignment="center", fontsize=self.__device_pointer_config.text_configuration.font_size, color=self.__device_pointer_config.text_configuration.color, pos=(self.__device.size[0] / 2, self.__device.size[1] / 2))
def addRect2(): rect = avg.RectNode(pos=(60, 2), size=(50, 30), fillopacity=1, strokewidth=2) rect.color = "FFFF00" canvas.insertChild(rect, 0)
def __create_reload_overlay(self): if not self.__use_reload_overlay: return self.__reload_overlay = avg.DivNode(parent=self._data_div, size=self._data_div.size, active=False) avg.RectNode(parent=self.__reload_overlay, size=self._data_div.size, strokewidth=0, fillopacity=0.75, fillcolor=global_values.COLOR_DARK_GREY) text = avg.WordsNode(parent=self.__reload_overlay, text="Click to\nreload", fontsize=global_values.FONT_SIZE * 2, color=global_values.COLOR_FOREGROUND, alignment="center", rawtextmode=True, pos=(self._data_div.size[0] / 2, self._data_div.size[1] / 2)) text.pos = text.pos[ 0], text.pos[1] - 2 * global_values.FONT_SIZE + text.linespacing self.__reload_tap_recognizer = gesture.TapRecognizer( node=self.__reload_overlay, detectedHandler=self.__on_reload_overlay_tapped, maxDist=5, maxTime=500)
def __init__(self, title='', getValue=None, parent=None, **kwargs): super(Graph, self).__init__(**kwargs) self.registerInstance(self, parent) self._getValue = getValue self._xSkip = 2 self._curUsage = 0 self.sensitive = False avg.RectNode(parent=self, strokewidth=0, fillopacity=0.6, fillcolor="FFFFFF", size=self.size) self._textNode0 = avg.WordsNode(parent=self, x=10, y=self.size.y - 22, color="000080") self._textNode1 = avg.WordsNode(parent=self, x=10, y=self.size.y - 39, color="000080") self._maxLineNode = avg.PolyLineNode(parent=self, color="880000") self._lineNode = avg.PolyLineNode(parent=self, color="008000") self.__graphText = avg.WordsNode(parent=self, x=10, y=0, color="000080") self.__graphText.text = title self._setup()
def addBgNode(): node = avg.RectNode(pos=(0, 0), size=(64, 96), fillopacity=1, opacity=0, fillcolor="FFFFFF") root.insertChild(node, 0)
def testCanvasBlendModes(self): def createBaseCanvas(): canvas = player.createCanvas(id="testcanvas", size=(64, 64), mediadir="media") avg.ImageNode(href="rgb24alpha-64x64.png", parent=canvas.getRootNode()) return canvas root = self.loadEmptyScene() createBaseCanvas() avg.RectNode(parent=root, pos=(48, 0), size=(32, 120), strokewidth=2, fillopacity=1, fillcolor="808080") avg.ImageNode(parent=root, href="canvas:testcanvas") avg.ImageNode(parent=root, pos=(0, 64), href="canvas:testcanvas", opacity=0.6) avg.ImageNode(parent=root, pos=(64, 0), href="canvas:testcanvas", blendmode="add") avg.ImageNode(parent=root, pos=(64, 64), href="canvas:testcanvas", opacity=0.6, blendmode="add") self.start(False, (lambda: self.compareImage("testCanvasBlendModes"), ))
def setMask(): try: node.maskhref = "mask4.png" self.rect = avg.RectNode(pos=(0.5, 0.5), size=(64, 64), parent=root) except avg.Exception: self.skip("no shader support") player.stop()
def addRect(): rect = avg.RectNode(pos=(2, 2), size=(50, 30), fillopacity=1, strokewidth=0) canvas.appendChild(rect) rect.subscribe(avg.Node.CURSOR_DOWN, onMouseDown) return rect
def testImageMaskCanvas(self): root = self.loadEmptyScene() canvas = player.createCanvas(id="testcanvas", size=(64,64), mediadir="media") avg.ImageNode(href="rgb24-64x64.png", parent=canvas.getRootNode()) avg.RectNode(size=(160,120), fillcolor="FFFFFF", fillopacity=1, parent=root) avg.ImageNode(href="canvas:testcanvas", maskhref="mask4.png", parent=root) self.start(False, (lambda: self.compareImage("testImgMaskCanvas"),))
def __makeAlphaBackground(self): SQUARESIZE = 40 size = self.node.getMediaSize() avg.RectNode(parent=self, size=self.node.getMediaSize(), strokewidth=0, fillcolor="FFFFFF", fillopacity=1) for y in xrange(0, int(size.y) / SQUARESIZE): for x in xrange(0, int(size.x) / (SQUARESIZE * 2)): pos = avg.Point2D(x * SQUARESIZE * 2, y * SQUARESIZE) if y % 2 == 1: pos += (SQUARESIZE, 0) avg.RectNode(parent=self, pos=pos, size=(SQUARESIZE, SQUARESIZE), strokewidth=0, fillcolor="C0C0C0", fillopacity=1)
def __create_wall_rect(self): x_min = self._x_axis.value_to_pixel(0) x_max = self._x_axis.value_to_pixel(pat_model.wall_width) y_max = self._y_axis.value_to_pixel(0) avg.RectNode(pos=(x_min, y_max-16), size=(x_max - x_min, 16), fillcolor=global_values.COLOR_DARK_GREY, fillopacity=1, parent=self._data_div) label_pos = (x_min + (x_max-x_min)/2, y_max-18) avg.WordsNode(pos=label_pos, text="WALL", fontsize=14, alignment="center", parent=self._data_div)
def testCanvasAlpha(self): root = self.loadEmptyScene() canvas = player.createCanvas(id="testcanvas", size=(80,120), mediadir="media") avg.ImageNode(id="test1", href="rgb24alpha-64x64.png", parent=canvas.getRootNode()) avg.RectNode(parent=root, fillcolor="FFFFFF", pos=(0.5, 0.5), size=(160, 48), fillopacity=1) avg.ImageNode(parent=root, href="canvas:testcanvas") avg.ImageNode(parent=root, x=64, href="rgb24alpha-64x64.png") self.start(False, (lambda: self.compareImage("testCanvasAlpha"),))
def testRectSizeChanged(self): def onResize(newSize): self.messageReceived = True self.messageReceived = False root = self.loadEmptyScene() self.rect = avg.RectNode(size=(10, 10), parent=root) self.rect.subscribe(self.rect.SIZE_CHANGED, onResize) self.rect.size = (100, 100) self.assert_(self.messageReceived)
def redAlphaScene(): self.redRect = avg.RectNode(parent=self.root, pos=(5, 5), fillcolor='FF0000', fillopacity=1, opacity=0, size=(72, 72)) self.node = avg.ImageNode(parent=self.root, pos=(10, 10), href="rgb24alpha-64x64.png") resetFX()
def __init__(self, binsThresholds, parent=None, **kwargs): super(BinsGraph, self).__init__(**kwargs) self.registerInstance(self, parent) avg.RectNode(size=self.size, parent=self) colWidth = self.size.x / len(binsThresholds) self._binBars = [BinBar(str(int(thr)), pos=(idx * colWidth, 0), size=(colWidth, self.size.y), parent=self) for idx, thr in enumerate(binsThresholds)]
def addRect(): self.rect = avg.RectNode(pos=(20, 20), size=(50, 40), fillopacity=1, filltexcoord1=(1, 1), filltexcoord2=(0, 0), strokewidth=20, texcoords=(1, 0.75, 0.5, 0.25, 0), texhref="rgb24-64x64.png") canvas.appendChild(self.rect) return self.rect