Changeset - 9fa3f70d50ba
[Not reviewed]
default
0 2 2
Laman - 8 years ago 2017-02-26 17:54:54

resizing imgview and boardview
4 files changed with 157 insertions and 121 deletions:
0 comments (0 inline, 0 general)
src/gui/boardview.py
Show inline comments
 
import tkinter as tk
 

	
 
from .resizablecanvas import ResizableCanvas
 
from go import BLACK,WHITE
 

	
 

	
 
## Handles and presents the game state as detected by the program.
 
class BoardView(tk.Canvas):
 
class BoardView(ResizableCanvas):
 
	def __init__(self, master=None):
 
		self._master=master
 
		tk.Canvas.__init__(self, master, highlightthickness=0)
 
		super().__init__(master)
 

	
 
		self.configure(width=360,height=360,background="#ffcc00")
 

	
 
		self.width=360
 
		self.height=360
 
		self.padding=18
 
		self.cellWidth=(self.width-2*self.padding)/18
 
		self.cellHeight=(self.height-2*self.padding)/18
 
		self.configure(width=self.width,height=self.height,background="#ffcc00")
 
		self._padding=18
 
		self._cellWidth=(self._width-2*self._padding)/18
 
		self._cellHeight=(self._height-2*self._padding)/18
 

	
 
		self.drawGrid()
 
		master.bind("<Configure>", self._onResize)
 
		self._drawGrid()
 

	
 
	def redrawState(self,gameState):
 
		self.delete("black","white")
 
		for r,row in enumerate(gameState):
 
			for c,point in enumerate(row):
 
				self.drawStone(r,c,point)
 
				self._drawStone(r, c, point)
 

	
 
	def drawGrid(self):
 
		padding=self.padding
 
	def _drawGrid(self):
 
		padding=self._padding
 
		for i in range(19):
 
			self.create_line(padding,18*i+padding,self.width-padding,18*i+padding,tags="row",fill="#000000") # rows
 
			self.create_line(18*i+padding,padding,18*i+padding,self.height-padding,tags="col",fill="#000000") # cols
 
			self.create_line(padding,18*i+padding,self._width-padding,18*i+padding,tags="row",fill="#000000") # rows
 
			self.create_line(18*i+padding,padding,18*i+padding,self._height-padding,tags="col",fill="#000000") # cols
 

	
 
		self.drawStars()
 
		self._drawStars()
 

	
 
	def drawStars(self):
 
	def _drawStars(self):
 
		radius=2
 

	
 
		for r in range(3,19,6):
 
			for c in range(3,19,6):
 
				x=c*self.cellHeight+self.padding
 
				y=r*self.cellWidth+self.padding
 
				x=c*self._cellHeight+self._padding
 
				y=r*self._cellWidth+self._padding
 
				self.create_oval(x-radius,y-radius,x+radius,y+radius,tags="star",fill='#000000')
 

	
 
	## Draws a stone at provided coordinates.
 
@@ -49,7 +45,7 @@ class BoardView(tk.Canvas):
 
	#  @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):
 
	def _drawStone(self, r, c, color):
 
		if color==BLACK:
 
			hexCode='#000000'
 
			tag="black"
 
@@ -58,23 +54,7 @@ class BoardView(tk.Canvas):
 
			tag="white"
 
		else: return False
 

	
 
		x=c*self.cellWidth+self.padding
 
		y=r*self.cellHeight+self.padding
 
		radius=self.cellWidth/2
 
		x=c*self._cellWidth+self._padding
 
		y=r*self._cellHeight+self._padding
 
		radius=self._cellWidth/2
 
		self.create_oval(x-radius,y-radius,x+radius,y+radius,tags=tag,fill=hexCode)
 

	
 
	def _onResize(self, event):
 
		wScale=float(event.width)/self.width
 
		hScale=float(event.height)/self.height
 
		scale=min(wScale,hScale)
 

	
 
		self.width*=scale
 
		self.height*=scale
 
		self.scale("all",0,0,scale,scale) # rescale all the objects tagged with the "all" tag
 

	
 
		x=(event.width-self.width)/2
 
		y=(event.height-self.height)/2
 

	
 
		# place the window, giving it an explicit size
 
		self.place(in_=self._master, x=x, y=y,
 
				width=self.width, height=self.height)
src/gui/imgview.py
Show inline comments
 
new file 100644
 
import logging as log
 

	
 
from PIL import ImageTk
 

	
 
import config
 
from .resizablecanvas import ResizableCanvas
 
from corners import Corners
 
from epoint import EPoint
 
from grid import Grid
 
import imageanalyzer
 

	
 

	
 
class ImgView(ResizableCanvas):
 
	def __init__(self,master=None,parent=None):
 
		super().__init__(master)
 

	
 
		self._parent=parent
 
		self._corners=Corners()
 
		self._boardGrid=None
 

	
 
		self._img=None
 
		self._tkImg=None
 
		self._imgSizeCoef=1
 
		self._imgShift=EPoint(0,0)
 

	
 
		self.configure(width=480,height=360)
 
		self.bind('<1>',lambda e: self.addCorner(e.x,e.y))
 

	
 
	## Redraws the current image and its overlay.
 
	def redraw(self):
 
		self.delete("all")
 

	
 
		if self._img:
 
			img=self._img.copy()
 
			img.thumbnail((int(self._width),int(self._height)))
 
			self._tkImg=ImageTk.PhotoImage(img) # just to save the image from the garbage collector
 
			self.create_image(self._width//2, self._height//2, anchor="center", image=self._tkImg)
 

	
 
		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.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.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.create_rectangle(r1,c1,r2,c2,outline="#00ffff")
 

	
 
	def setImg(self,img):
 
		w=int(self._width)
 
		h=int(self._height)
 
		wo,ho=img.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
 

	
 
		self._img=img
 

	
 
	## Stores a grid corner located at x,y coordinates.
 
	def addCorner(self,x,y):
 
		self._corners.add(x,y)
 
		log.debug("click on %d,%d",x,y)
 
		log.debug("sizeCoef: %f, shift: %d,%d",self._imgSizeCoef,self._imgShift.x,self._imgShift.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.redraw()
 

	
 
	## Marks a point at the image with a green cross. Used for corners.
 
	def markPoint(self,x,y):
 
		self.create_line(x-3,y-3,x+4,y+4,fill="#00ff00")
 
		self.create_line(x-3,y+3,x+4,y-4,fill="#00ff00")
 

	
 
	def _onResize(self,event):
 
		super()._onResize(event)
 
		self.redraw()
src/gui/mainwindow.py
Show inline comments
 
import logging as log
 
import tkinter as tk
 
from tkinter import N,S,E,W
 

	
 
from PIL import ImageTk
 

	
 
import config
 
import imageanalyzer
 
from corners import Corners
 
from epoint import EPoint
 
from grid import Grid
 
from .boardview import BoardView
 
from .imgview import ImgView
 

	
 

	
 
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,sticky=(N,S,E,W))
 
		self._createWidgets()
 

	
 
	def setCurrentFrame(self,frame):
 
		self.currentFrame=frame
 

	
 
		w=int(self.imgView['width'])
 
		h=int(self.imgView['height'])
 
		wo,ho=frame.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
 

	
 
		frame.thumbnail((w,h)) # resize
 
		self.img=ImageTk.PhotoImage(frame)
 
		self.imgView.setImg(frame)
 

	
 
	def _createWidgets(self):
 
		# a captured frame with overlay graphics
 
		self.imgView=tk.Canvas(self)
 
		self.imgView.configure(width=480,height=360,background="#ff00ff")
 
		self._imgWrapper=tk.Frame(self,width=480,height=360)
 
		self.imgView=ImgView(self._imgWrapper,self)
 

	
 
		self.imgView.bind('<1>',lambda e: self.addCorner(e.x,e.y))
 

	
 
		self.imgView.grid(column=0,row=0,sticky=(N,S,E,W))
 
		self._imgWrapper.grid(column=0,row=0,sticky=(N,S,E,W))
 

	
 
		# board with detected stones
 
		self._boardWrapper=tk.Frame(self,width=360,height=360)
 
@@ -70,54 +41,14 @@ class MainWindow(tk.Frame):
 
		self.rowconfigure(0,weight=1)
 

	
 
		# render everything
 
		self.redrawImgView()
 

	
 
	## Stores a grid corner located at x,y coordinates.
 
	def addCorner(self,x,y):
 
		self.corners.add(x,y)
 
		log.debug("click on %d,%d",x,y)
 
		log.debug("sizeCoef: %f, shift: %d,%d",self._imgSizeCoef,self._imgShift.x,self._imgShift.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()
 
		self.imgView.redraw()
 

	
 
	## Redraws the current image and its overlay.
 
	def redrawImgView(self):
 
		if self.currentFrame and self.img:
 
			self.imgView.create_image(240,180,anchor="center",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()
 
		self.imgView.redraw()
 

	
 
	def refreshTresholds(self,_):
 
		self.parent.sendMsg("setTresholds",tuple(),{"tresB":self.scaleTresB.get(), "tresW":self.scaleTresW.get()})
 

	
 
	def sendMsg(self,actionName,args=tuple(),kwargs=None):
 
		self.parent.sendMsg(actionName,args,kwargs)
src/gui/resizablecanvas.py
Show inline comments
 
new file 100644
 
import tkinter as tk
 

	
 

	
 
class ResizableCanvas(tk.Canvas):
 
	def __init__(self, master=None):
 
		tk.Canvas.__init__(self, master, highlightthickness=0)
 

	
 
		self._master=master
 
		self._width=0
 
		self._height=0
 

	
 
		master.bind("<Configure>", self._onResize)
 
		
 
	def configure(self,*args,**kwargs):
 
		if "width" in kwargs: self._width=kwargs["width"]
 
		if "height" in kwargs: self._height=kwargs["height"]
 
		
 
		super().configure(*args,**kwargs)
 

	
 
	def _onResize(self, event):
 
		wScale=float(event.width)/self._width
 
		hScale=float(event.height)/self._height
 
		scale=min(wScale,hScale)
 

	
 
		self._width*=scale
 
		self._height*=scale
 
		self.scale("all",0,0,scale,scale) # rescale all the objects tagged with the "all" tag
 

	
 
		x=(event.width-self._width)/2
 
		y=(event.height-self._height)/2
 

	
 
		# place the widget, giving it an explicit size
 
		self.place(in_=self._master, x=x, y=y, width=self._width, height=self._height)
 
		return scale
0 comments (0 inline, 0 general)