diff --git a/main.py b/main.py index f93fc5a..b29e324 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,6 @@ import math +from copy import copy + import pygame as pg from pygame.locals import * from sys import exit @@ -7,6 +9,8 @@ import numpy as np import src.render as render import src.menu as menu import src.pathEditor as pathEditor +import src.buttonEditor as buttonEditor +import src.export as export doubleClickDuration = 200 @@ -14,50 +18,48 @@ pg.init() pg.font.init() topBarHeight = 40 -bottomBarHeight = 40 +bottomBarHeight = 60 screen_width = 1200 screen_height = (screen_width * (643/1286)) + topBarHeight + bottomBarHeight -screen = pg.display.set_mode((screen_width, screen_height)) +screen = pg.display.set_mode((screen_width, screen_height))#, pg.RESIZABLE) pg.display.set_caption("Auto Planner") -pathR = render.render(pg, screen, topBarHeight) - -tabIndex = 1 +render = render.render(pg, screen, topBarHeight, bottomBarHeight) +tabIndex = 0 tabs = [ - menu.menu(pg, pathR), - pathEditor.pathEditor(pg, pathR) + menu.menu(pg, render), + pathEditor.pathEditor(render), + buttonEditor.buttonEditor(render, pathEditor), + export.export(pg, render) ] -def isInRect(pos, rect): - return pos[0] >= rect[0] and \ - pos[0] <= rect[2] and \ - pos[1] >= rect[1] and \ - pos[1] <= rect[3] +tabs[tabIndex].load() -def refreshTabs(pos): - for i in range(len(tabs)): - - # color = i * (255/(len(tabs)-1)) - # color = (color, color, color) - - x1 = i * (screen_width/(len(tabs))) - x2 = (i+1) * (screen_width/(len(tabs))) - rect = (x1, 0, x2, topBarHeight) - - if i == tabIndex: - color = (255, 255, 255) - elif isInRect(pos, rect): - color = (127,127,127) - else: - color = (63,63,63) - - pg.draw.rect(screen, color, rect) - pg.display.update() - -refreshTabs((screen_width/2, screen_height/2)) +def addTab(i): + x1 = i * (screen_width/(len(tabs))) + x2 = (screen_width/(len(tabs))) + rect = (x1, 0, x2, topBarHeight) + + def getIsSelected(): + global tabIndex + return tabIndex == i + + def onClick(pos): + global tabIndex + tabIndex = i + tabs[tabIndex].load() + render.renderElements(pos) + pg.display.update() + + render.addButton(rect, tabs[i].name, getIsSelected, onClick) + +for i in range(len(tabs)): + addTab(i) + +render.renderElements((screen_width/2, screen_height/2)) running = True last_click = -1 @@ -68,8 +70,16 @@ def offsetPos(pos): while running: for event in pg.event.get(): - if event.type == pg.MOUSEBUTTONDOWN: + if event.type == pg.MOUSEMOTION: pos = pg.mouse.get_pos() + render.renderElements(pos) + if pos[1] > topBarHeight: + tabs[tabIndex].mouseMove(offsetPos(pos)) + # refreshTabs(pos) + + elif event.type == pg.MOUSEBUTTONDOWN: + pos = pg.mouse.get_pos() + render.clickElement(pos) if pos[1] > topBarHeight: now = pg.time.get_ticks() if now - last_click <= doubleClickDuration: @@ -77,19 +87,18 @@ while running: else: tabs[tabIndex].mouseDown(offsetPos(pos)) last_click = pg.time.get_ticks() - - if event.type == pg.MOUSEMOTION: - pos = pg.mouse.get_pos() - if pos[1] > topBarHeight: - tabs[tabIndex].mouseMove(offsetPos(pos)) - refreshTabs(pos) + # else: + # clickTab(pos) - if event.type == pg.MOUSEBUTTONUP: + elif event.type == pg.MOUSEBUTTONUP: pos = pg.mouse.get_pos() if pos[1] > topBarHeight: tabs[tabIndex].mouseUp(offsetPos(pos)) - if event.type == pg.QUIT: + elif event.type == pg.KEYDOWN: + tabs[tabIndex].keyDown(event.key) + + elif event.type == pg.QUIT: running = False pg.quit() diff --git a/src/buttonEditor.py b/src/buttonEditor.py new file mode 100644 index 0000000..22265d2 --- /dev/null +++ b/src/buttonEditor.py @@ -0,0 +1,148 @@ +render = None +pathEditor = None +bottomBarRect = None + +ogNodes = [] +ogCtrlNodes = [] + +events = [] + +matchLength = 15 +matchTicks = 15 * 50 +displayTickResolution = 5 +displayTicks = round(matchTicks / displayTickResolution) + +indicatorBarRect = None + +selFrame = -1 + +# def addTab(i): +# x1 = i * (render.width/(displayTicks)) +# x2 = (render.width/(displayTicks)) +# rect = (x1, bottomBarRect[1], x2, bottomBarRect[3]) + +# def getIsSelected(): +# return False + +# def onClick(pos): +# pass + +# render.addButton(rect, "", getIsSelected, onClick) + +def getTimeBarColor(index): + for event in events: + if event["timeIndex"] == index: + if event['type'] == 'position': + return (127,127,0) + elif event['type'] == 'controller': + return (0,127,0) + + return (16,16,32) + +def renderSelectIndicator(i): + x1 = i * (render.width/(displayTicks)) + x2 = (render.width/(displayTicks)) + rect = (x1, indicatorBarRect[1], x2, indicatorBarRect[3]) + + if i == selFrame: + render.drawrect((255,0,0), rect) + + + + + +def reloadBar(pos): + toggle = False + for i in range(displayTicks): + x1 = i * (render.width/(displayTicks)) + x2 = (render.width/(displayTicks)) + rect = (x1, bottomBarRect[1], x2, bottomBarRect[3]) + + color = getTimeBarColor(i) + + if i == selFrame: + color = (color[0]+64,color[1]+64,color[2]+64) + + if render.isInRect(pos, rect): + color = (color[0]+64,color[1]+64,color[2]+64) + else: + color = (color[0]+16+(toggle*16),color[1]+16+(toggle*16),color[2]+32+(toggle*16)) + + toggle = not toggle + + render.drawrect(color, rect) + renderSelectIndicator(i) + render.update() + +def clickBar(pos): + for i in range(displayTicks): + x1 = i * (render.width/(displayTicks)) + x2 = (render.width/(displayTicks)) + rect = (x1, bottomBarRect[1], x2, bottomBarRect[3]) + + if render.isInRect(pos, rect): + global selFrame + selFrame = i + reloadBar(pos) + return + +class buttonEditor: + name = "Button Editor" + + def __init__(self, tmprender, tmppathEditor): + global render + render = tmprender + global pathEditor + pathEditor = tmppathEditor + + global indicatorBarRect + indicatorBarHeight = round(render.screen.get_width()/displayTicks) + indicatorBarRect = (0, render.screen.get_height()-indicatorBarHeight, render.screen.get_width(), indicatorBarHeight) + + global bottomBarRect + bottomBarRect = (0, (render.screen.get_height()-render.bottomBarHeight), render.screen.get_width(), render.screen.get_height()) + + def refresh(self): + render.clear() + render.drawField() + render.renderBezier(pathEditor.nodes, pathEditor.curveEditPoints) + reloadBar((0,0)) + render.update() + + def mouseDown(self, pos): + if pos[1] > bottomBarRect[1]: + clickBar(pos) + pass + + def mouseUp(self, pos): + pass + + def mouseMove(self, pos): + reloadBar(pos) + + def doubleClick(self, pos): + pass + + def keyDown(self, key): + pass + + def load(self): + + global ogNodes + global ogCtrlNodes + global selFrame + selFrame = -1 + + # for i in range(displayTicks): + # addTab(i) + + if ogNodes != pathEditor.nodes or \ + ogCtrlNodes != pathEditor.curveEditPoints: + + ogNodes = pathEditor.nodes + ogCtrlNodes = pathEditor.curveEditPoints + + # for i in range(len(ogNodes)): + # events + + self.refresh() \ No newline at end of file diff --git a/src/export.py b/src/export.py new file mode 100644 index 0000000..3e86928 --- /dev/null +++ b/src/export.py @@ -0,0 +1,31 @@ +pg = None +render = None +bottomBarHeight = 0 + +class export: + name = "Export" + + def __init__(self, tmppg, tmprender): + global pg + pg = tmppg + global render + render = tmprender + + def mouseDown(self, pos): + pass + + def mouseUp(self, pos): + pass + + def mouseMove(self, pos): + pass + + def doubleClick(self, pos): + pass + + def keyDown(self, key): + pass + + def load(self): + render.clear() + pg.display.update() \ No newline at end of file diff --git a/src/menu.py b/src/menu.py index 5f62c95..ea21017 100644 --- a/src/menu.py +++ b/src/menu.py @@ -22,6 +22,9 @@ class menu: def doubleClick(self, pos): pass + def keyDown(self, key): + pass + def load(self): render.clear() pg.display.update() \ No newline at end of file diff --git a/src/pathEditor.py b/src/pathEditor.py index 59563d8..a892974 100644 --- a/src/pathEditor.py +++ b/src/pathEditor.py @@ -2,11 +2,11 @@ import math from pygame.locals import * nodeColor = (255, 255, 255) -nodeRadius = 15 +nodeRadius = 12 rotNodeDist = 35 rotNodeColor = (255, 0, 255) -rotNodeRadius = 10 +rotNodeRadius = 8 nodeSquareRadius = 35 nodeSquareColor = (127, 127, 127, 0.5) @@ -16,7 +16,7 @@ lineApproximationLineColor = (127, 127, 127, 0.5) lineApproximationLineWidth = 3 curveEditPointColor = (0, 255, 255) -curveEditPointRadius = 5 +curveEditPointRadius = 8 nodes = [] curveEditPoints = [] @@ -25,12 +25,13 @@ nodeRotations = [] clickType = -1 clickIndex = -1 -pg = None render = None def refresh(): - render.render(nodes, curveEditPoints) + render.clear() + render.drawField() + render.renderBezier(nodes, curveEditPoints) for i in range(0,len(curveEditPoints)): render.line(lineApproximationLineColor, nodes[i], curveEditPoints[i], lineApproximationLineWidth) @@ -58,20 +59,20 @@ def refresh(): for pos in nodes: render.circle(nodeColor, pos, nodeRadius) - pg.display.update() + render.update() def getElemAt(pos): - for i in range(0,len(curveEditPoints)): - if getDist(pos, curveEditPoints[i], curveEditPointRadius): - return 1, i + for i in range(0,len(nodes)): + if getDist(pos, nodes[i], nodeRadius): + return 0, i for i in range(0,len(nodeRotations)): posX = (math.sin(nodeRotations[i])*rotNodeDist) + nodes[i][0] posY = (math.cos(nodeRotations[i])*rotNodeDist) + nodes[i][1] if getDist(pos, (posX, posY), nodeRadius): return 2, i - for i in range(0,len(nodes)): - if getDist(pos, nodes[i], nodeRadius): - return 0, i + for i in range(0,len(curveEditPoints)): + if getDist(pos, curveEditPoints[i], curveEditPointRadius): + return 1, i return -1, -1 def getDist(pos1, pos2, dist): @@ -79,12 +80,14 @@ def getDist(pos1, pos2, dist): def addNode(pos): nodes.append(pos) - nodeRotations.append(math.pi/2) if len(nodes) > 1: index = len(nodes)-1 # Middle point between current point and previous point editPos = (nodes[index-1][0]+pos[0])/2,(nodes[index-1][1]+pos[1])/2 curveEditPoints.append(editPos) + nodeRotations.append(nodeRotations[index-1]) + else: + nodeRotations.append(math.pi/2) refresh() def nearestCirclePoint(center, pos, R): @@ -102,9 +105,7 @@ def points2rad(center, pos): class pathEditor: name = "Path Editor" - def __init__(self, tmppg, tmprender): - global pg - pg = tmppg + def __init__(self, tmprender): # global screen # screen = tmpscreen global render @@ -137,7 +138,7 @@ class pathEditor: refresh() def doubleClick(self, pos): - clickType, clickIndex = getElemAt(pg.mouse.get_pos()) + clickType, clickIndex = getElemAt(pos) if clickType == -1: pass if clickType == 0: @@ -151,4 +152,9 @@ class pathEditor: nodes.pop(clickIndex) nodeRotations.pop(clickIndex) refresh() - \ No newline at end of file + + def keyDown(self, key): + pass + + def load(self): + refresh() \ No newline at end of file diff --git a/src/render.py b/src/render.py index 1a62190..979c7d8 100644 --- a/src/render.py +++ b/src/render.py @@ -6,28 +6,45 @@ curvePointCount = 300 curvePointColor = (255, 255, 0) curvePointRadius = 2 +selTabBorderSize = 2 +selTabBorderIndent = 3 + class render(): - def __init__(self, pg, screen, offsetY): + def __init__(self, pg, screen, topBarHeight, bottomBarHeight): self.pg = pg self.screen = screen - self.offsetY = offsetY + self.topBarHeight = topBarHeight + self.bottomBarHeight = bottomBarHeight + self.width = self.screen.get_width() self.height = self.screen.get_width() * (643/1286) - self.rect = (0, self.offsetY, self.width, self.height) + self.rect = (0, self.topBarHeight, self.width, self.height+bottomBarHeight) + + self.font = self.pg.font.Font(None, 25) self.fieldImg = pg.image.load("frc2024.png").convert_alpha() - self.offsetSize = self.fieldImg.get_width() / self.width - self.fieldImg = pg.transform.scale(self.fieldImg, (self.width, self.height)) - + + self.elements = [] + def line(self, color, pos1, pos2, width): self.pg.draw.line(self.screen, color, pos1, pos2, round(width/self.offsetSize)) def circle(self, color, pos, radius): self.pg.draw.circle(self.screen, color, pos, radius/self.offsetSize) + def drawrect(self, color, rect): + self.pg.draw.rect(self.screen, color, rect) + + def isInRect(self, pos, rect): + return pos[0] >= rect[0] and \ + pos[0] <= rect[0]+rect[2] and \ + pos[1] >= rect[1] and \ + pos[1] <= rect[1]+rect[3] + + def bezier(self, p0, p1, p2): #for p in [p0, p1, p2]: # pg.draw.circle(self.screen, (255, 255, 255), p, 5) @@ -39,13 +56,61 @@ class render(): def clear(self): self.pg.draw.rect(self.screen, (0, 0, 0), self.rect) - def render(self, nodes, curveEditPoints): - self.pg.draw.rect(self.screen, (0, 0, 0), self.rect) + def drawField(self): self.screen.blit(self.fieldImg, self.rect) + + def renderElements(self, pos): + for elem in self.elements: + if elem['type'] == 'button': + # print(elem['getIsSelected']()) + self.renderButton(elem['rect'], elem['text'], elem['getIsSelected'](), pos) + + def clickElement(self, pos): + for elem in self.elements: + if elem['type'] == 'button' and self.isInRect(pos, elem['rect']): + elem['onClick'](pos) + + def renderBezier(self, nodes, curveEditPoints): for i in range(0,len(curveEditPoints)): - # self.pg.draw.line(self.screen, lineApproximationLineColor, nodes[i], curveEditPoints[i], lineApproximationLineWidth) - # self.pg.draw.line(self.screen, lineApproximationLineColor, curveEditPoints[i], nodes[i+1], lineApproximationLineWidth) self.bezier(nodes[i], curveEditPoints[i], nodes[i+1]) - # self.pg.draw.circle(self.screen, curveEditPointColor, curveEditPoints[i], curveEditPointRadius) + + def update(self): self.pg.display.update() - \ No newline at end of file + + def addButton(self, rect, text, getIsSelected, onClick): + self.elements.append({ + "type": "button", + "text": text, + "getIsSelected": getIsSelected, + "onClick": onClick, + "rect": rect + }) + + def renderButton(self, rect, text, selected, mousePos): + + # print(isInRect(mousePos, rect)) + + if self.isInRect(mousePos, rect): + color = (16,64,32) + else: + color = (16,16,32) + + if selected: + borderColor = (0,255,0) + else: + borderColor = (64,127,127) + + text = self.font.render(text, True, (255,255,255)) + text_rect = text.get_rect(center=(rect[0]+(rect[2]/2), rect[1]+(rect[3]/2))) + + self.pg.draw.rect(self.screen, color, rect) + rect = (rect[0]+selTabBorderIndent,rect[1]+selTabBorderIndent, + rect[2]-selTabBorderIndent*2,rect[3]-selTabBorderIndent*2) + self.pg.draw.rect(self.screen, borderColor, rect) + rect = (rect[0]+selTabBorderSize,rect[1]+selTabBorderSize, + rect[2]-selTabBorderSize*2,rect[3]-selTabBorderSize*2) + self.pg.draw.rect(self.screen, color, rect) + + self.screen.blit(text, text_rect) + + self.update() \ No newline at end of file