666 lines
25 KiB
Python
666 lines
25 KiB
Python
# This file is part of ssiv.
|
|
#
|
|
# ssiv is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# ssiv is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with ssiv. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
from math import ceil
|
|
from operator import mul
|
|
|
|
from .modules import *
|
|
from ..co import AttrDict
|
|
|
|
__all__=['draw_canvas','draw_tiling','draw_status','draw_empty']
|
|
|
|
def draw_canvas(self):
|
|
if self.double_canvas:
|
|
return draw_dual_canvas(self)
|
|
else:
|
|
return draw_solo_canvas(self)
|
|
|
|
def draw_status(self):
|
|
draw_statusbar(self)
|
|
draw_motion_indicator(self)
|
|
return
|
|
|
|
def draw_empty(self):
|
|
area_x,area_y,area_w,area_h=self.get_renderer_area_for_canvas()
|
|
renderer=self.renderer
|
|
with renderer.viewporter((area_x,area_y,area_w,area_h)),\
|
|
renderer.drawer(self.fgcolor):
|
|
runsdl(SDL_RenderFillRect,renderer,None)
|
|
if min(area_w,area_h)>20:
|
|
with renderer.viewporter((area_x+10,area_y+10,area_w-20,area_h-20)):
|
|
runsdl(SDL_RenderFillRect,renderer,None)
|
|
return
|
|
|
|
def draw_solo_canvas(self):
|
|
# always set renderer size equal to output size
|
|
# no viewport
|
|
container,filename=self.containers.current_page
|
|
path=(container,filename)
|
|
self.add_to_scene(path)
|
|
self.window.title=f'Loading... {prettypath(*path)}'
|
|
if (canvas:=self.getcanvas(path)) is None:return
|
|
if not canvas.ready:return # at leas one frame required
|
|
self.window.title=f'{prettypath(*path)}'
|
|
area_x,area_y,area_w,area_h=self.get_renderer_area_for_canvas()
|
|
if min(area_w,area_h)<=0:return
|
|
self.set_anti_alias(canvas)
|
|
self.anime_starter()
|
|
cvs_w,cvs_h=canvas.get_canvas_size(use_page=self.use_page)
|
|
cvs_x,cvs_y=canvas.offset if self.use_page else (0,0)
|
|
src_w,src_h=canvas.size
|
|
if self.scale_ratio:
|
|
# ignore page size and page offset
|
|
# force to center if scaled canvas is smaller than area
|
|
# prevent downscale if both side is smaller than area
|
|
if self.scale_ratio<0:
|
|
limit=max(src_w/area_w,src_h/area_h,1)
|
|
scale_ratio=-self.scale_ratio
|
|
scale_ratio=min(limit,scale_ratio)
|
|
self._scale_ratio=-int(scale_ratio)
|
|
if self._scale_ratio==-1:
|
|
self._scale_ratio=1
|
|
scale_ratio=1/scale_ratio
|
|
else:
|
|
limit=min(area_w/src_w,area_h/src_h,1)
|
|
scale_ratio=self.scale_ratio
|
|
if limit==scale_ratio==1:
|
|
scale_ratio+=1
|
|
# at least one pixel to draw
|
|
scale_ratio=min(max(limit,scale_ratio),src_w,src_h)
|
|
self._scale_ratio=int(scale_ratio)
|
|
|
|
off_x,off_y=self._canvas_offset
|
|
|
|
off_x=max(0,min(src_w-area_w/scale_ratio,off_x))
|
|
if src_w*scale_ratio>area_w:
|
|
src_x=off_x
|
|
src_w=area_w/scale_ratio
|
|
dst_x=0
|
|
dst_w=area_w
|
|
else:
|
|
src_x=0
|
|
dst_x=(area_w-src_w*scale_ratio)/2
|
|
dst_w=src_w*scale_ratio
|
|
|
|
off_y=max(0,min(src_h-area_h/scale_ratio,off_y))
|
|
if src_h*scale_ratio>area_h:
|
|
src_y=off_y
|
|
src_h=area_h/scale_ratio
|
|
dst_y=0
|
|
dst_h=area_h
|
|
else:
|
|
src_y=0
|
|
dst_y=(area_h-src_h*scale_ratio)/2
|
|
dst_h=src_h*scale_ratio
|
|
|
|
srcrect=(*map(int,(src_x,src_y,src_w,src_h)),)
|
|
dstrect=(*map(int,(dst_x+area_x,dst_y+area_y,dst_w,dst_h)),)
|
|
pgerect=None
|
|
self._canvas_offset=(*map(int,(off_x,off_y)),)
|
|
|
|
else:
|
|
# autofit, downscale only if canvas is larger than output size.
|
|
# always show in center, ignore canvas_offset
|
|
srcrect=None # entire texture
|
|
scale=min(area_w/cvs_w,area_h/cvs_h,1)
|
|
pge_w=cvs_w*scale
|
|
pge_h=cvs_h*scale
|
|
pge_x=(area_w-pge_w)/2
|
|
pge_y=(area_h-pge_h)/2
|
|
dst_x=pge_x+cvs_x*scale
|
|
dst_y=pge_y+cvs_y*scale
|
|
dst_w=src_w*scale
|
|
dst_h=src_h*scale
|
|
# apply area offset
|
|
pgerect=(*map(int,(pge_x+area_x,pge_y+area_y,pge_w,pge_h)),)
|
|
dstrect=(*map(int,(dst_x+area_x,dst_y+area_y,dst_w,dst_h)),)
|
|
|
|
if self.checker:
|
|
if pgerect is None or pgerect==dstrect:
|
|
if canvas.has_alpha:
|
|
draw_alpha_checker(self.renderer,dstrect)
|
|
else:
|
|
draw_canvas_checker(self.renderer,pgerect)
|
|
if canvas.has_alpha:
|
|
draw_alpha_on_checker(self.renderer,dstrect)
|
|
canvas.draw(srcrect=srcrect,dstrect=dstrect)
|
|
return preload_canvas(self)
|
|
|
|
def draw_dual_canvas(self):
|
|
if not self.containers.flip(1):
|
|
# last page, fallback to solo canvas
|
|
return draw_solo_canvas(self)
|
|
container2,filename2=self.containers.current_page
|
|
self.containers.flip(-1)
|
|
container1,filename1=self.containers.current_page
|
|
path1=(container1,filename1)
|
|
path2=(container2,filename2)
|
|
# always set renderer size equal to output size
|
|
# no viewport
|
|
self.add_to_scene(path1,path2)
|
|
# 1st page is required
|
|
# show 2nd page only if first page available
|
|
self.window.title=f'Loading... {prettypath(*path1)} {prettypath(*path2)}'
|
|
canvas1=self.getcanvas(path1)
|
|
canvas2=self.getcanvas(path2)
|
|
if canvas1 is None or not canvas1.ready:
|
|
# at leas one frame required
|
|
return preload_canvas(self)
|
|
if canvas2 is None or not canvas2.ready:
|
|
# 2nd page is not ready, fallback to solo canvas
|
|
return draw_solo_canvas(self)
|
|
if canvas1.is_horizontal(self.use_page) or canvas2.is_horizontal(self.use_page):
|
|
# either page is horizontal, only draw 1st page and remove 2nd page from scene
|
|
self.remove_from_scene(path2)
|
|
return draw_solo_canvas(self)
|
|
if self.double_right:
|
|
self.window.title=f'{prettypath(*path2)} {prettypath(*path1)}'
|
|
canvasl,canvasr=canvas2,canvas1
|
|
else:
|
|
self.window.title=f'{prettypath(*path1)} {prettypath(*path2)}'
|
|
canvasl,canvasr=canvas1,canvas2
|
|
area_x,area_y,area_w,area_h=self.get_renderer_area_for_canvas()
|
|
if min(area_w,area_h)<=0:return
|
|
self.set_anti_alias(canvasl)
|
|
self.set_anti_alias(canvasr)
|
|
self.anime_starter()
|
|
cvsl_w,cvsl_h=canvasl.get_canvas_size(use_page=self.use_page)
|
|
cvsl_x,cvsl_y=canvasl.offset if self.use_page else (0,0)
|
|
srcl_w,srcl_h=canvasl.size
|
|
cvsr_w,cvsr_h=canvasr.get_canvas_size(use_page=self.use_page)
|
|
cvsr_x,cvsr_y=canvasr.offset if self.use_page else (0,0)
|
|
srcr_w,srcr_h=canvasr.size
|
|
|
|
#
|
|
# dp_x (dpl_x)
|
|
# |
|
|
# dp_y + |<------------------inn_w------------------->|
|
|
# \ \ |<-------inl_w------->|<-------inr_w-------->|
|
|
# \ \ | | |
|
|
# \ +---+---------------------+----------------------+---+-----
|
|
# +------|xxx|xxxxxxxxxxxxxxxxxxxxx|xxxxxxxxxxxxxxxxxxxxxx|xxx| ^
|
|
# -----+---+---------------------+---------+------------+---+ |
|
|
# ^ |xxx| ^ | | |xxx| |
|
|
# | |xxx| | |<-dpr_x->|<--sul_w--->|xxx| |
|
|
# | |xxx| dpl_y | | sur_w |xxx| |
|
|
# | |xxx| dpr_y | | |xxx| |
|
|
# | |xxx| | | | |xxx| |
|
|
# | |xxx| v | | |xxx| |
|
|
# | |xxx+-----------+ | | |xxx| |
|
|
# inn_h |xxx| ^ | | +------------+xxx| |
|
|
# | |xxx| | | | |xxx| dp_h
|
|
# | |xxx| | | | |xxx| |
|
|
# | |xxx| sul_h | | |xxx| |
|
|
# | |xxx| sur_h | | |xxx| |
|
|
# | |xxx| | | | |xxx| |
|
|
# | |xxx| | | | |xxx| |
|
|
# v |xxx| v | | |xxx| |
|
|
# -----+---+-----------+---------+----------------------+---+ |
|
|
# |xxx|xxxxxxxxxxxxxxxxxxxxx|xxxxxxxxxxxxxxxxxxxxxx|xxx| v
|
|
# +---+---------------------+----------------------+---+-----
|
|
# | | |
|
|
# |<---------dpl_w--------->|<---------dpr_w---------->|
|
|
# |<----------------------dp_w------------------------>|
|
|
|
|
dp_h=min(cvsl_h,cvsr_h)
|
|
scale_l=dp_h/cvsl_h
|
|
scale_r=dp_h/cvsr_h
|
|
sul_w=srcl_w*scale_l
|
|
sur_w=srcr_w*scale_r
|
|
sul_h=srcl_h*scale_l
|
|
sur_h=srcr_h*scale_r
|
|
dpl_w=cvsl_w*scale_l
|
|
dpr_w=cvsr_w*scale_r
|
|
dpl_x=cvsl_x*scale_l
|
|
dpl_y=cvsl_y*scale_l
|
|
dpr_x=cvsr_x*scale_r
|
|
dpr_y=cvsr_y*scale_r
|
|
dp_x=dpl_x
|
|
dp_y=min(dpl_y,dpr_y)
|
|
dpl_y-=dp_y
|
|
dpr_y-=dp_y
|
|
dp_w=dpl_w+dpr_w
|
|
inl_w=dpl_w-dp_x
|
|
inr_w=dpr_x+sur_w
|
|
inn_w=inl_w+inr_w
|
|
inn_h=max(dpl_y+sul_h,dpr_y+sur_h)
|
|
|
|
if self.scale_ratio:
|
|
if self.scale_ratio<0:
|
|
limit=max(inn_w/area_w,inn_h/area_h,1)
|
|
scale_ratio=-self.scale_ratio
|
|
scale_ratio=min(limit,scale_ratio)
|
|
self._scale_ratio=-int(scale_ratio)
|
|
if self._scale_ratio==-1:
|
|
self._scale_ratio=1
|
|
scale_ratio=1/scale_ratio
|
|
else:
|
|
limit=min(area_w/inn_w,area_h/inn_h,1)
|
|
scale_ratio=self.scale_ratio
|
|
if limit==scale_ratio==1:
|
|
scale_ratio+=1
|
|
# at least one pixel to draw
|
|
scale_ratio=min(max(limit,scale_ratio),inn_w,inn_h)
|
|
self._scale_ratio=int(scale_ratio)
|
|
|
|
off_x,off_y=self._canvas_offset
|
|
|
|
draw_l=draw_r=True
|
|
on_page=False
|
|
|
|
off_x=max(0,min(inn_w-area_w/scale_ratio,off_x))
|
|
if inn_w*scale_ratio>area_w:
|
|
pge_x=0
|
|
pge_w=area_w
|
|
draw_l=draw_l and (sul_w-off_x>0)
|
|
draw_r=draw_r and (area_w>(inl_w+dpr_x-off_x)*scale_ratio)
|
|
else:
|
|
pge_w=inn_w*scale_ratio
|
|
pge_x=(area_w-pge_w)/2
|
|
|
|
off_y=max(0,min(inn_h-area_h/scale_ratio,off_y))
|
|
if inn_h*scale_ratio>area_h:
|
|
pge_y=0
|
|
pge_h=area_h
|
|
#draw_l=draw_l and (area_h/scale_ratio>dpl_y-off_y and dpl_y-off_y+sul_h>0)
|
|
#draw_r=draw_r and (area_h/scale_ratio>dpr_y-off_y and dpr_y-off_y+sur_h>0)
|
|
draw_l=draw_l and (area_h/scale_ratio>dpl_y-off_y>-sul_h)
|
|
draw_r=draw_r and (area_h/scale_ratio>dpr_y-off_y>-sur_h)
|
|
else:
|
|
pge_h=inn_h*scale_ratio
|
|
pge_y=(area_h-pge_h)/2
|
|
|
|
pgerect=(*map(int,(pge_x+area_x,pge_y+area_y,pge_w,pge_h)),)
|
|
self._canvas_offset=(*map(int,(off_x,off_y)),)
|
|
if self.checker and self.use_page and (canvasl.has_page or canvasr.has_page):
|
|
on_page=True
|
|
draw_canvas_checker(self.renderer,pgerect)
|
|
|
|
dst_x=max(0,(area_w-inn_w*scale_ratio)/2)
|
|
dst_y=max(0,(area_h-inn_h*scale_ratio)/2)
|
|
if draw_l:
|
|
srcl_x=off_x/scale_l
|
|
dstl_x=dst_x
|
|
if (srcl_w-srcl_x)*scale_l*scale_ratio>area_w:
|
|
srcl_w=area_w/scale_ratio/scale_l
|
|
dstl_w=area_w
|
|
else:
|
|
srcl_w-=srcl_x
|
|
dstl_w=(sul_w-off_x)*scale_ratio
|
|
|
|
srcl_y=(dpl_y+off_y)/scale_l
|
|
dstl_y=max(0,dpl_y-off_y)*scale_ratio+dst_y
|
|
if (srcl_h-srcl_y)*scale_l*scale_ratio>area_h:
|
|
srcl_h=area_h/scale_ratio/scale_l
|
|
dstl_h=area_h
|
|
else:
|
|
srcl_h-=srcl_y
|
|
dstl_h=(sul_h-off_y)*scale_ratio
|
|
|
|
srcrectl=(*map(int,(srcl_x,srcl_y,srcl_w,srcl_h)),)
|
|
dstrectl=(*map(int,(dstl_x+area_x,dstl_y+area_y,dstl_w,dstl_h)),)
|
|
if self.checker and canvasl.has_alpha:
|
|
if on_page:
|
|
draw_alpha_on_checker(self.renderer,dstrectl)
|
|
else:
|
|
draw_alpha_checker(self.renderer,dstrectl)
|
|
canvasl.draw(srcrect=srcrectl,dstrect=dstrectl)
|
|
|
|
if draw_r:
|
|
srcr_x=max(0,off_x/scale_r-(inl_w+dpr_x))
|
|
dstr_x=max(0,(inl_w+dpr_x)*scale_ratio-off_x*scale_ratio+dst_x)
|
|
dstr_w=min(area_w-dstr_x,sur_w*scale_ratio)
|
|
if (srcr_w-srcr_x)*scale_r*scale_ratio>dstr_w:
|
|
srcr_w=dstr_w/scale_ratio/scale_r
|
|
else:
|
|
srcr_w-=srcr_x
|
|
|
|
srcr_y=(dpr_y+off_y)/scale_r
|
|
dstr_y=max(0,dpr_y-off_y)*scale_ratio+dst_y
|
|
if (srcr_h-srcr_y)*scale_r*scale_ratio>area_h:
|
|
srcr_h=area_h/scale_ratio/scale_r
|
|
dstr_h=area_h
|
|
else:
|
|
srcr_h-=srcr_y
|
|
dstr_h=(sur_h-off_y)*scale_ratio
|
|
|
|
srcrectr=(*map(int,(srcr_x,srcr_y,srcr_w,srcr_h)),)
|
|
dstrectr=(*map(int,(dstr_x+area_x,dstr_y+area_y,dstr_w,dstr_h)),)
|
|
if self.checker and canvasr.has_alpha:
|
|
if on_page:
|
|
draw_alpha_on_checker(self.renderer,dstrectr)
|
|
else:
|
|
draw_alpha_checker(self.renderer,dstrectr)
|
|
canvasr.draw(srcrect=srcrectr,dstrect=dstrectr)
|
|
return preload_canvas(self)
|
|
|
|
else:
|
|
# autofit, downscale only if canvas is larger than output size.
|
|
# always show in left/rigt center, ignore canvas_offset
|
|
# place split gap in middle of window
|
|
srcrectl=srcrectr=None # entire texture
|
|
outer_width=max(dpl_w,dpr_w)*2
|
|
scale=min(area_w/outer_width,area_h/dp_h,1)
|
|
pge_x=area_w/2-dpl_w*scale
|
|
pge_y=(area_h-dp_h*scale)/2
|
|
pge_w=dp_w*scale
|
|
pge_h=dp_h*scale
|
|
dstl_x=dpl_x*scale+pge_x
|
|
dstr_x=dpr_x*scale+area_w/2
|
|
dstl_y=dpl_y*scale+pge_y
|
|
dstr_y=dpr_y*scale+pge_y
|
|
dstl_w=srcl_w*scale*scale_l
|
|
dstl_h=srcl_h*scale*scale_l
|
|
dstr_w=srcr_w*scale*scale_r
|
|
dstr_h=srcr_h*scale*scale_r
|
|
# apply area offset
|
|
pgerect=(*map(int,(pge_x+area_x,pge_y+area_y,pge_w,pge_h)),)
|
|
dstrectl=(*map(int,(dstl_x+area_x,dstl_y+area_y,dstl_w,dstl_h)),)
|
|
dstrectr=(*map(int,(dstr_x+area_x,dstr_y+area_y,dstr_w,dstr_h)),)
|
|
|
|
if self.checker:
|
|
if self.use_page and (canvasl.has_page or canvasr.has_page):
|
|
draw_canvas_checker(self.renderer,pgerect)
|
|
if canvasl.has_alpha:
|
|
draw_alpha_on_checker(self.renderer,dstrectl)
|
|
if canvasr.has_alpha:
|
|
draw_alpha_on_checker(self.renderer,dstrectr)
|
|
else:
|
|
if canvasl.has_alpha:
|
|
draw_alpha_checker(self.renderer,dstrectl)
|
|
if canvasr.has_alpha:
|
|
draw_alpha_checker(self.renderer,dstrectr)
|
|
|
|
canvasl.draw(srcrect=srcrectl,dstrect=dstrectl)
|
|
canvasr.draw(srcrect=srcrectr,dstrect=dstrectr)
|
|
return preload_canvas(self)
|
|
|
|
def draw_tiling(self):
|
|
area_x,area_y,area_w,area_h=self.get_renderer_area_for_canvas()
|
|
if min(area_w,area_h)<self.thumbsize+self.thumbgap*2:
|
|
# screen too small, draw nothing
|
|
return
|
|
|
|
#
|
|
# +----------------------------------------------------+
|
|
# | ^ |
|
|
# | y |
|
|
# | v |
|
|
# | +--------------------------------------------+ |
|
|
# | | ^ | |
|
|
# |<x>| gap |<x>|
|
|
# | | v | |
|
|
# | | +------+ +------+ +------+ | |
|
|
# | |<gap>|<size>|<gap>|<size>|<gap>|<size>|<gap>| |
|
|
# | | +------+ +------+ +------+ | |
|
|
# | | ^ | |
|
|
# | | gap | |
|
|
# | | v | |
|
|
# | | +------+ | |
|
|
# | |<gap>|<size>| | |
|
|
# | | +------+ | |
|
|
# | | ^ | |
|
|
# | | gap | |
|
|
# | | v | |
|
|
# | +--------------------------------------------+ |
|
|
# | ^ |
|
|
# | y |
|
|
# | v |
|
|
# +----------------------------------------------------+
|
|
#
|
|
|
|
container,filename=self.containers.current_page
|
|
pathcount=len(self.containers[container])
|
|
self.window.title=f'{container}({pathcount})'
|
|
gap=self.thumbgap
|
|
size=self.thumbsize
|
|
if self.double_right:
|
|
height=min(pathcount,(area_h-gap)//(size+gap))
|
|
width=min(ceil(pathcount/height),(area_w-gap)//(size+gap))
|
|
self.tiling_width=height
|
|
else:
|
|
width=min(pathcount,(area_w-gap)//(size+gap))
|
|
height=min(ceil(pathcount/width),(area_h-gap)//(size+gap))
|
|
self.tiling_width=width
|
|
x=(area_w-((size+gap)*width+gap))//2
|
|
y=(area_h-((size+gap)*height+gap))//2
|
|
if self.double_right:
|
|
slots=[(x+gap+row*(size+gap)+area_x,y+gap+col*(size+gap)+area_y)
|
|
for row in reversed(range(width)) for col in range(height)]
|
|
else:
|
|
slots=[(x+gap+col*(size+gap)+area_x,y+gap+row*(size+gap)+area_y)
|
|
for row in range(height) for col in range(width)]
|
|
|
|
index=self.containers[container].index(filename)
|
|
row,col=divmod(index,self.tiling_width)
|
|
rows=len(slots)//self.tiling_width
|
|
start=min(max(0,row-(rows-1)//2),ceil(pathcount/self.tiling_width)-rows)
|
|
|
|
for slot,fn in zip(slots,self.containers[container][start*self.tiling_width:]):
|
|
path=(container,fn)
|
|
self.add_to_scene(path)
|
|
if (thumbnail:=self.getthumbnail(path,cutin=(fn==filename))) is None or \
|
|
not thumbnail.ready:
|
|
if fn==filename:
|
|
draw_selected(self.renderer,(*slot,size,size),self.fgcolor)
|
|
continue
|
|
x,y=slot
|
|
w,h=thumbnail.size
|
|
scale=min(1,size/max(w,h))
|
|
w*=scale
|
|
h*=scale
|
|
x+=(size-w)/2
|
|
y+=(size-h)/2
|
|
dstrect=(*map(int,(x,y,w,h)),)
|
|
if fn==filename:
|
|
draw_selected(self.renderer,dstrect,self.fgcolor)
|
|
if self.checker and thumbnail.has_alpha:
|
|
draw_alpha_checker(self.renderer,dstrect)
|
|
thumbnail.draw(dstrect=dstrect)
|
|
# preload
|
|
for fn in self.containers[container]:
|
|
if not self.is_in_scene((container,fn)):
|
|
self.getthumbnail((container,fn))
|
|
return
|
|
|
|
def preload_canvas(self):
|
|
container,filename=self.containers.current_page
|
|
fl=self.containers[container]
|
|
pos=fl.index(filename)
|
|
slen=2 if self.scene_len>1 else 1
|
|
clen=self.cachesize+slen
|
|
start=max(0,min(len(fl)-clen,pos-self.cachesize//2))
|
|
for fn in *fl[pos+slen:start+clen],*reversed(fl[start:pos]):
|
|
self.getcanvas((container,fn))
|
|
|
|
def draw_checker(renderer,rect,color1,color2):
|
|
blen=8
|
|
*_,w,h=rect
|
|
points=[(px,py,blen,blen)
|
|
for col,px in enumerate(range(0,w,blen))
|
|
for row,py in enumerate(range(0,h,blen))
|
|
if (col+row)%2]
|
|
amount=len(points)
|
|
rects=(SDL_Rect*amount)(*points)
|
|
points.clear()
|
|
with renderer.viewporter(rect),renderer.drawer():
|
|
renderer.set_draw_color(*color1)
|
|
runsdl(SDL_RenderFillRect,renderer,SDL_Rect(0,0,w,h))
|
|
renderer.set_draw_color(*color2)
|
|
runsdl(SDL_RenderFillRects,renderer,rects,amount)
|
|
return
|
|
|
|
def draw_canvas_checker(renderer,rect):
|
|
return draw_checker(renderer,rect,(0,0,0),(0x22,0x22,0x22))
|
|
|
|
def draw_alpha_checker(renderer,rect):
|
|
return draw_checker(renderer,rect,(0x77,0x77,0x77),(0x99,0x99,0x99))
|
|
|
|
def draw_alpha_on_checker(renderer,rect):
|
|
with renderer.blender(SDL_BLENDMODE_BLEND),\
|
|
renderer.drawer((0xff,0xff,0xff,0x80)):
|
|
runsdl(SDL_RenderFillRect,renderer,SDL_Rect(*rect))
|
|
return
|
|
|
|
def draw_selected(renderer,rect,color):
|
|
border=2
|
|
gap=1
|
|
x,y,w,h=rect
|
|
gap2=gap*2
|
|
border+=gap
|
|
border2=border*2
|
|
length=max(8,max(w,h)//4)
|
|
length2=length*2
|
|
with renderer.viewporter((x-border,y-border,w+border2,h+border2)),\
|
|
renderer.drawer(color):
|
|
runsdl(SDL_RenderFillRect,renderer,None)
|
|
if w>length2:
|
|
with renderer.viewporter((x+length,y-border,w-length2,h+border2)):
|
|
runsdl(SDL_RenderFillRect,renderer,None)
|
|
if h>length2:
|
|
with renderer.viewporter((x-border,y+length,w+border2,h-length2)):
|
|
runsdl(SDL_RenderFillRect,renderer,None)
|
|
return runsdl(SDL_RenderFillRect,renderer,SDL_Rect(x-gap,y-gap,w+gap2,h+gap2))
|
|
|
|
def draw_statusbar(self):
|
|
# draw statusbar
|
|
if not (barsize:=self.statusbar_size):return
|
|
x,y,w,h,island=self.get_renderer_area_for_statusbar()
|
|
if min(x,y)<0:return
|
|
if not max(x,y,w,h):return
|
|
csize=6
|
|
fsize=10
|
|
clen=len(self.containers)
|
|
flen=self.containers.container_length
|
|
cpos,fpos=self.containers.current_position
|
|
cblocks=create_blocks(cpos,clen,limit=self.blklmt,color=self.fgcolor)
|
|
fblocks=create_blocks(fpos,flen,limit=self.blklmt,color=self.fgcolor)
|
|
total=len(cblocks)*csize+fsize+len(fblocks)*fsize
|
|
if island:
|
|
if self.double_right:
|
|
# from right to left
|
|
p=q=0
|
|
for block in reversed(fblocks):
|
|
block.rect=(p,q,fsize,fsize)
|
|
p+=fsize
|
|
p+=fsize
|
|
q+=(fsize-csize)//2
|
|
for block in reversed(cblocks):
|
|
block.rect=(p,q,csize,csize)
|
|
p+=csize
|
|
else:
|
|
# from left to right
|
|
p=0
|
|
q=(fsize-csize)//2
|
|
for block in cblocks:
|
|
block.rect=(p,q,csize,csize)
|
|
p+=csize
|
|
p+=fsize
|
|
q=0
|
|
for block in fblocks:
|
|
block.rect=(p,q,fsize,fsize)
|
|
p+=fsize
|
|
box=(w-total)//2+x,(h-fsize)//2+y,total,fsize
|
|
else:
|
|
# from top to bottom
|
|
p=0
|
|
q=(fsize-csize)//2
|
|
for block in cblocks:
|
|
block.rect=(q,p,csize,csize)
|
|
p+=csize
|
|
p+=fsize
|
|
q=0
|
|
for block in fblocks:
|
|
block.rect=(q,p,fsize,fsize)
|
|
p+=fsize
|
|
box=(w-fsize)//2+x,(h-total)//2+y,fsize,total
|
|
blockmap={} # {color:(x,y,w,h), ...}
|
|
for block in *cblocks,*fblocks:
|
|
blockmap.setdefault(block.color,[]).append(block.rect)
|
|
with self.renderer.viewporter(box):
|
|
while blockmap:
|
|
color,blocks=blockmap.popitem()
|
|
amount=len(blocks)
|
|
rects=(SDL_Rect*amount)(*blocks)
|
|
blocks.clear()
|
|
with self.renderer.drawer(color):
|
|
runsdl(SDL_RenderFillRects,self.renderer,rects,amount)
|
|
return
|
|
|
|
def create_blocks(position,length,limit=5,color=(0xff,0xff,0xff)):
|
|
limit=(limit//2)*2+1
|
|
color_cur=color
|
|
color_sid=tuple(int(c*.67) for c in color)
|
|
color_out=tuple(int(c*.33) for c in color)
|
|
blocks=tuple(AttrDict(color=None) for _ in range(min(length,limit)))
|
|
harf=(len(blocks)+1)//2
|
|
rpos=length-position
|
|
if position<harf:
|
|
blocks[position].color=color_cur
|
|
pos=position
|
|
elif rpos<harf:
|
|
blocks[-rpos].color=color_cur
|
|
pos=len(blocks)-rpos
|
|
else:
|
|
blocks[-harf].color=color_cur
|
|
pos=len(blocks)-harf
|
|
if blocks[0].color is None and position>pos:
|
|
blocks[0].color=color_out
|
|
if blocks[-1].color is None and rpos>len(blocks)-pos:
|
|
blocks[-1].color=color_out
|
|
for block in blocks:
|
|
if block.color is None:
|
|
block.color=color_sid
|
|
return blocks
|
|
|
|
def draw_motion_indicator(self):
|
|
# draw motion indicator
|
|
if self.canvas_offset==self.canvas_offset_old:return
|
|
if self.motion_status is None:return
|
|
area_x,area_y,area_w,area_h=self.get_renderer_area_for_canvas()
|
|
xstat,ystat=self.motion_status
|
|
size,xaxis,yaxis=self.motion_indicator
|
|
points=[]
|
|
if xstat and xaxis is not None:
|
|
off=(area_h-size) if xaxis else size
|
|
pos=area_h if xaxis else 0
|
|
mid=area_w//2
|
|
points.extend((
|
|
(mid+xstat*5,pos),(mid,pos),(mid,off)
|
|
))
|
|
if ystat and yaxis is not None:
|
|
off=(area_w-size) if yaxis else size
|
|
pos=area_w if yaxis else 0
|
|
mid=area_h//2
|
|
points.extend((
|
|
(pos,mid+ystat*5),(pos,mid),(off,mid)
|
|
))
|
|
amount=len(points)
|
|
with self.renderer.viewporter((area_x,area_y,area_w,area_h)):
|
|
vertices=(SDL_Vertex*amount)(*(
|
|
(point,self.fgcolor) for point in points
|
|
))
|
|
points.clear()
|
|
runsdl(SDL_RenderGeometry,self.renderer,None,vertices,amount,None,0)
|
|
return
|
|
|
|
|
|
# Local Variables:
|
|
# coding: utf-8
|
|
# mode: python
|
|
# python-indent-offset: 4
|
|
# indent-tabs-mode: nil
|
|
# End:
|