# HG changeset patch # User Laman # Date 2017-01-07 21:50:10 # Node ID 4b4cae6939e8e81e81e72c98bccf383be33df488 # Parent 79f823432bb4cf9dae94779e1a2fc176b2e28547 gui split into more files diff --git a/src/core.py b/src/core.py --- a/src/core.py +++ b/src/core.py @@ -3,7 +3,7 @@ import logging as log import PIL from util import MsgQueue from gui import gui -from image_analyzer import ImageAnalyzer +from imageanalyzer import ImageAnalyzer from go import Go diff --git a/src/gui/__init__.py b/src/gui/__init__.py --- a/src/gui/__init__.py +++ b/src/gui/__init__.py @@ -1,164 +1,9 @@ import threading -import logging as log import tkinter as tk -from PIL import ImageTk -import PIL import config -from epoint import EPoint -from corners import Corners -import image_analyzer -import go -from grid import Grid - - -class MainWindow(tk.Frame): - def __init__(self,parent,master=None): - self.parent=parent - self.corners=Corners() - - self.currentFrame=None - self._boardGrid=None - - self.img=None - self._imgSizeCoef=1 - self._imgShift=EPoint(0,0) - - tk.Frame.__init__(self, master) - self.grid(column=0,row=0) - self._createWidgets() - - def setCurrentFrame(self,frame): - self.currentFrame=frame - - w=int(self.imgView['width']) - h=int(self.imgView['height']) - self.img=ImageTk.PhotoImage(frame.resize((w,h),resample=PIL.Image.BILINEAR)) - - wo,ho=self.currentFrame.size # o for original - widthRatio=wo/w - heightRatio=ho/h - self._imgSizeCoef=max(widthRatio,heightRatio) - # shift compensates possible horizontal or vertical empty margins from unmatching aspect ratios - self._imgShift=EPoint(wo-w*self._imgSizeCoef,ho-h*self._imgSizeCoef)/2 - - def _createWidgets(self): - # a captured frame with overlay graphics - self.imgView=tk.Canvas(self) - self.imgView.configure(width=480,height=360) - - self.imgView.bind('<1>',lambda e: self.addCorner(e.x,e.y)) - - self.imgView.grid(column=0,row=0) - - # board with detected stones - self.boardView=BoardView(self) - self.boardView.grid(column=1,row=0) - - # more controls below the board - self.scaleTresB=tk.Scale(self, orient=tk.HORIZONTAL, length=200, from_=0.0, to=100.0, command=self.refreshTresholds) - self.scaleTresW=tk.Scale(self, orient=tk.HORIZONTAL, length=200, from_=0.0, to=100.0, command=self.refreshTresholds) - self.scaleTresB.set(30.0) # !! proper defaults - self.scaleTresW.set(60.0) - self.scaleTresB.grid(column=0,row=1,columnspan=2) - self.scaleTresW.grid(column=0,row=2,columnspan=2) - - # render everything - self.redrawImgView() - - ## Stores a grid corner located at x,y coordinates. - def addCorner(self,x,y): - self.corners.add(x,y) - if self.corners.canonizeOrder(): - # transform corners from show coordinates to real coordinates - log.debug(self.corners.corners) - self._boardGrid=Grid(self.corners.corners) - corners=[(c*self._imgSizeCoef+self._imgShift) for c in self.corners.corners] - self.parent.sendMsg("setCorners",(corners,)) - - self.redrawImgView() - - ## Redraws the current image and its overlay. - def redrawImgView(self): - if self.currentFrame and self.img: - self.imgView.create_image(2,2,anchor="nw",image=self.img) - - for corner in self.corners.corners: - self.markPoint(corner.x,corner.y) - - if self._boardGrid!=None and config.gui.showGrid: - for r in range(19): - a=self._boardGrid.intersections[r][0] - b=self._boardGrid.intersections[r][-1] - self.imgView.create_line(a.x,a.y,b.x,b.y,fill='#00ff00') - for c in range(19): - a=self._boardGrid.intersections[0][c] - b=self._boardGrid.intersections[-1][c] - self.imgView.create_line(a.x,a.y,b.x,b.y,fill='#00ff00') - - if self._boardGrid!=None and config.gui.showBigPoints: - for r in range(19): - for c in range(19): - ((r1,c1),(r2,c2))=image_analyzer.relevantRect(self._boardGrid.intersections[r][c], *(self._boardGrid.stoneSizeAt(r, c))) - self.imgView.create_rectangle(r1,c1,r2,c2,outline="#00ffff") - - self.imgView.grid() - - ## Marks a point at the image with a green cross. Used for corners. - def markPoint(self,x,y): - self.imgView.create_line(x-3,y-3,x+4,y+4,fill="#00ff00") - self.imgView.create_line(x-3,y+3,x+4,y-4,fill="#00ff00") - - self.imgView.grid() - - def refreshTresholds(self,_): - self.parent.sendMsg("setTresholds",tuple(),{"tresB":self.scaleTresB.get(), "tresW":self.scaleTresW.get()}) - - -## Handles and presents the game state as detected by the program. -class BoardView(tk.Canvas): - def __init__(self, master=None): - tk.Canvas.__init__(self, master) - self.configure(width=360,height=360,background="#ffcc00") - - self.drawGrid() - - self.grid() - - def redrawState(self,gameState): - # !! will need to remove old stones or redraw the element completely - for r,row in enumerate(gameState): - for c,point in enumerate(row): - self.drawStone(r,c,point) - - self.grid() - - def drawGrid(self): - for i in range(19): - self.create_line(18,18*(i+1),360-18,18*(i+1),fill="#000000") # rows - self.create_line(18*(i+1),18,18*(i+1),360-18,fill="#000000") # cols - - self.drawStars() - - def drawStars(self): - for r in range(4,19,6): - for c in range(4,19,6): - self.create_oval(r*18-2,c*18-2,r*18+2,c*18+2,fill='#000000') - - ## Draws a stone at provided coordinates. - # - # For an unknown color draws nothing and returns False. - # - # @param r row coordinate, [0-18], counted from top - # @param c column coordinate, [0-18], counted from left - # @param color color indicator, go.BLACK or go.WHITE - def drawStone(self,r,c,color): - if color==go.BLACK: hexCode='#000000' - elif color==go.WHITE: hexCode='#ffffff' - else: return False - r+=1 - c+=1 - self.create_oval(c*18-9,r*18-9,c*18+9,r*18+9,fill=hexCode) +from .mainwindow import MainWindow +from .boardview import BoardView class GUI: @@ -168,7 +13,7 @@ class GUI: self._coreMessages=None - self.mainWindow = MainWindow(self,master=self.root) + self.mainWindow = MainWindow(self, master=self.root) self.root.bind("<>", lambda e: self.mainWindow.redrawImgView()) self.root.bind("<>", lambda e: print("fired receiveState")) diff --git a/src/gui/boardview.py b/src/gui/boardview.py new file mode 100644 --- /dev/null +++ b/src/gui/boardview.py @@ -0,0 +1,49 @@ +import tkinter as tk + +import go + + +## Handles and presents the game state as detected by the program. +class BoardView(tk.Canvas): + def __init__(self, master=None): + tk.Canvas.__init__(self, master) + self.configure(width=360,height=360,background="#ffcc00") + + self.drawGrid() + + self.grid() + + def redrawState(self,gameState): + # !! will need to remove old stones or redraw the widget completely + for r,row in enumerate(gameState): + for c,point in enumerate(row): + self.drawStone(r,c,point) + + self.grid() + + def drawGrid(self): + for i in range(19): + self.create_line(18,18*(i+1),360-18,18*(i+1),fill="#000000") # rows + self.create_line(18*(i+1),18,18*(i+1),360-18,fill="#000000") # cols + + self.drawStars() + + def drawStars(self): + for r in range(4,19,6): + for c in range(4,19,6): + self.create_oval(r*18-2,c*18-2,r*18+2,c*18+2,fill='#000000') + + ## Draws a stone at provided coordinates. + # + # For an unknown color draws nothing and returns False. + # + # @param r row coordinate, [0-18], counted from top + # @param c column coordinate, [0-18], counted from left + # @param color color indicator, go.BLACK or go.WHITE + def drawStone(self,r,c,color): + if color==go.BLACK: hexCode='#000000' + elif color==go.WHITE: hexCode='#ffffff' + else: return False + r+=1 + c+=1 + self.create_oval(c*18-9,r*18-9,c*18+9,r*18+9,fill=hexCode) diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py new file mode 100644 --- /dev/null +++ b/src/gui/mainwindow.py @@ -0,0 +1,115 @@ +import logging as log +import tkinter as tk + +import PIL +from PIL import ImageTk + +import config +import imageanalyzer +from corners import Corners +from epoint import EPoint +from grid import Grid +from .boardview import BoardView + + +class MainWindow(tk.Frame): + def __init__(self,parent,master=None): + self.parent=parent + self.corners=Corners() + + self.currentFrame=None + self._boardGrid=None + + self.img=None + self._imgSizeCoef=1 + self._imgShift=EPoint(0,0) + + tk.Frame.__init__(self, master) + self.grid(column=0,row=0) + self._createWidgets() + + def setCurrentFrame(self,frame): + self.currentFrame=frame + + w=int(self.imgView['width']) + h=int(self.imgView['height']) + self.img=ImageTk.PhotoImage(frame.resize((w,h),resample=PIL.Image.BILINEAR)) + + wo,ho=self.currentFrame.size # o for original + widthRatio=wo/w + heightRatio=ho/h + self._imgSizeCoef=max(widthRatio,heightRatio) + # shift compensates possible horizontal or vertical empty margins from unmatching aspect ratios + self._imgShift=EPoint(wo-w*self._imgSizeCoef,ho-h*self._imgSizeCoef)/2 + + def _createWidgets(self): + # a captured frame with overlay graphics + self.imgView=tk.Canvas(self) + self.imgView.configure(width=480,height=360) + + self.imgView.bind('<1>',lambda e: self.addCorner(e.x,e.y)) + + self.imgView.grid(column=0,row=0) + + # board with detected stones + self.boardView= BoardView(self) + self.boardView.grid(column=1,row=0) + + # more controls below the board + self.scaleTresB=tk.Scale(self, orient=tk.HORIZONTAL, length=200, from_=0.0, to=100.0, command=self.refreshTresholds) + self.scaleTresW=tk.Scale(self, orient=tk.HORIZONTAL, length=200, from_=0.0, to=100.0, command=self.refreshTresholds) + self.scaleTresB.set(30.0) # !! proper defaults + self.scaleTresW.set(60.0) + self.scaleTresB.grid(column=0,row=1,columnspan=2) + self.scaleTresW.grid(column=0,row=2,columnspan=2) + + # render everything + self.redrawImgView() + + ## Stores a grid corner located at x,y coordinates. + def addCorner(self,x,y): + self.corners.add(x,y) + if self.corners.canonizeOrder(): + # transform corners from show coordinates to real coordinates + log.debug(self.corners.corners) + self._boardGrid=Grid(self.corners.corners) + corners=[(c*self._imgSizeCoef+self._imgShift) for c in self.corners.corners] + self.parent.sendMsg("setCorners",(corners,)) + + self.redrawImgView() + + ## Redraws the current image and its overlay. + def redrawImgView(self): + if self.currentFrame and self.img: + self.imgView.create_image(2,2,anchor="nw",image=self.img) + + for corner in self.corners.corners: + self.markPoint(corner.x,corner.y) + + if self._boardGrid!=None and config.gui.showGrid: + for r in range(19): + a=self._boardGrid.intersections[r][0] + b=self._boardGrid.intersections[r][-1] + self.imgView.create_line(a.x,a.y,b.x,b.y,fill='#00ff00') + for c in range(19): + a=self._boardGrid.intersections[0][c] + b=self._boardGrid.intersections[-1][c] + self.imgView.create_line(a.x,a.y,b.x,b.y,fill='#00ff00') + + if self._boardGrid!=None and config.gui.showBigPoints: + for r in range(19): + for c in range(19): + ((r1,c1),(r2,c2))=imageanalyzer.relevantRect(self._boardGrid.intersections[r][c], *(self._boardGrid.stoneSizeAt(r, c))) + self.imgView.create_rectangle(r1,c1,r2,c2,outline="#00ffff") + + self.imgView.grid() + + ## Marks a point at the image with a green cross. Used for corners. + def markPoint(self,x,y): + self.imgView.create_line(x-3,y-3,x+4,y+4,fill="#00ff00") + self.imgView.create_line(x-3,y+3,x+4,y-4,fill="#00ff00") + + self.imgView.grid() + + def refreshTresholds(self,_): + self.parent.sendMsg("setTresholds",tuple(),{"tresB":self.scaleTresB.get(), "tresW":self.scaleTresW.get()}) diff --git a/src/image_analyzer.py b/src/imageanalyzer.py rename from src/image_analyzer.py rename to src/imageanalyzer.py