220 lines
7.0 KiB
Python
220 lines
7.0 KiB
Python
################################################################
|
|
#
|
|
# Albow - Tab Panel
|
|
#
|
|
################################################################
|
|
|
|
from OpenGL.GL import *
|
|
from OpenGL.GLU import *
|
|
from OpenGL.GLUT import *
|
|
from albow import *
|
|
from pygame import Rect, Surface, draw, image
|
|
from pygame.locals import SRCALPHA
|
|
from widget import Widget
|
|
from theme import ThemeProperty, FontProperty
|
|
from utils import brighten
|
|
from numpy import fromstring
|
|
|
|
|
|
class TabPanel(Widget):
|
|
# pages [Widget]
|
|
# current_page Widget
|
|
|
|
tab_font = FontProperty('tab_font')
|
|
tab_height = ThemeProperty('tab_height')
|
|
tab_border_width = ThemeProperty('tab_border_width')
|
|
tab_spacing = ThemeProperty('tab_spacing')
|
|
tab_margin = ThemeProperty('tab_margin')
|
|
tab_fg_color = ThemeProperty('tab_fg_color')
|
|
default_tab_bg_color = ThemeProperty('default_tab_bg_color')
|
|
tab_area_bg_color = ThemeProperty('tab_area_bg_color')
|
|
tab_dimming = ThemeProperty('tab_dimming')
|
|
tab_titles = None
|
|
#use_page_bg_color_for_tabs = ThemeProperty('use_page_bg_color_for_tabs')
|
|
|
|
def __init__(self, pages=None, **kwds):
|
|
Widget.__init__(self, **kwds)
|
|
self.pages = []
|
|
self.current_page = None
|
|
if pages:
|
|
w = h = 0
|
|
for title, page in pages:
|
|
w = max(w, page.width)
|
|
h = max(h, page.height)
|
|
self._add_page(title, page)
|
|
self.size = (w, h)
|
|
self.show_page(pages[0][1])
|
|
|
|
def content_size(self):
|
|
return self.width, self.height - self.tab_height
|
|
|
|
def content_rect(self):
|
|
return Rect((0, self.tab_height), self.content_size())
|
|
|
|
def page_height(self):
|
|
return self.height - self.tab_height
|
|
|
|
def add_page(self, title, page):
|
|
self._add_page(title, page)
|
|
if not self.current_page:
|
|
self.show_page(page)
|
|
|
|
def _add_page(self, title, page):
|
|
page.tab_title = title
|
|
page.anchor = 'ltrb'
|
|
self.pages.append(page)
|
|
|
|
def remove_page(self, page):
|
|
try:
|
|
i = self.pages.index(page)
|
|
del self.pages[i]
|
|
except IndexError:
|
|
pass
|
|
if page is self.current_page:
|
|
self.show_page(None)
|
|
|
|
def show_page(self, page):
|
|
if self.current_page:
|
|
self.remove(self.current_page)
|
|
self.current_page = page
|
|
if page:
|
|
th = self.tab_height
|
|
page.rect = Rect(0, th, self.width, self.height - th)
|
|
self.add(page)
|
|
page.focus()
|
|
|
|
def draw(self, surf):
|
|
self.draw_tab_area_bg(surf)
|
|
self.draw_tabs(surf)
|
|
|
|
def draw_tab_area_bg(self, surf):
|
|
bg = self.tab_area_bg_color
|
|
if bg:
|
|
surf.fill(bg, (0, 0, self.width, self.tab_height))
|
|
|
|
def draw_tabs(self, surf):
|
|
font = self.tab_font
|
|
fg = self.tab_fg_color
|
|
b = self.tab_border_width
|
|
if b:
|
|
surf.fill(fg, (0, self.tab_height - b, self.width, b))
|
|
for i, title, page, selected, rect in self.iter_tabs():
|
|
x0 = rect.left
|
|
w = rect.width
|
|
h = rect.height
|
|
r = rect
|
|
if not selected:
|
|
r = Rect(r)
|
|
r.bottom -= b
|
|
self.draw_tab_bg(surf, page, selected, r)
|
|
if b:
|
|
surf.fill(fg, (x0, 0, b, h))
|
|
surf.fill(fg, (x0 + b, 0, w - 2 * b, b))
|
|
surf.fill(fg, (x0 + w - b, 0, b, h))
|
|
buf = font.render(title, True, page.fg_color or fg)
|
|
r = buf.get_rect()
|
|
r.center = (x0 + w // 2, h // 2)
|
|
surf.blit(buf, r)
|
|
|
|
def iter_tabs(self):
|
|
pages = self.pages
|
|
current_page = self.current_page
|
|
n = len(pages)
|
|
b = self.tab_border_width
|
|
s = self.tab_spacing
|
|
h = self.tab_height
|
|
m = self.tab_margin
|
|
width = self.width - 2 * m + s - b
|
|
x0 = m
|
|
for i, page in enumerate(pages):
|
|
x1 = m + (i + 1) * width // n # self.tab_boundary(i + 1)
|
|
selected = page is current_page
|
|
yield i, page.tab_title, page, selected, Rect(x0, 0, x1 - x0 - s + b, h)
|
|
x0 = x1
|
|
|
|
def draw_tab_bg(self, surf, page, selected, rect):
|
|
bg = self.tab_bg_color_for_page(page)
|
|
if not selected:
|
|
bg = brighten(bg, self.tab_dimming)
|
|
surf.fill(bg, rect)
|
|
|
|
def tab_bg_color_for_page(self, page):
|
|
return getattr(page, 'tab_bg_color', None) \
|
|
or page.bg_color \
|
|
or self.default_tab_bg_color
|
|
|
|
def mouse_down(self, e):
|
|
x, y = e.local
|
|
if y < self.tab_height:
|
|
i = self.tab_number_containing_x(x)
|
|
if i is not None:
|
|
self.show_page(self.pages[i])
|
|
|
|
def tab_number_containing_x(self, x):
|
|
n = len(self.pages)
|
|
m = self.tab_margin
|
|
width = self.width - 2 * m + self.tab_spacing - self.tab_border_width
|
|
i = (x - m) * n // width
|
|
if 0 <= i < n:
|
|
return i
|
|
|
|
def gl_draw_self(self, root, offset):
|
|
self.gl_draw(root, offset)
|
|
|
|
def gl_draw(self, root, offset):
|
|
pages = self.pages
|
|
|
|
if len(pages) > 1:
|
|
tlcorner = (offset[0] + self.bottomleft[0], offset[1] + self.bottomleft[1])
|
|
pageTabContents = []
|
|
current_page = self.current_page
|
|
n = len(pages)
|
|
b = self.tab_border_width
|
|
s = self.tab_spacing
|
|
h = self.tab_height
|
|
m = self.tab_margin
|
|
tabWidth = (self.size[0]-(s*n)-(2*m))/n
|
|
width = self.width - 2 * m + s - b
|
|
x0 = m + tlcorner[0]
|
|
|
|
font = self.tab_font
|
|
fg = self.tab_fg_color
|
|
surface = Surface(self.size, SRCALPHA)
|
|
|
|
glEnable(GL_BLEND)
|
|
|
|
for i, page in enumerate(pages):
|
|
x1 = x0+tabWidth
|
|
selected = page is current_page
|
|
if selected:
|
|
glColor(1.0, 1.0, 1.0, 0.5)
|
|
else:
|
|
glColor(0.5, 0.5, 0.5, 0.5)
|
|
glRectf(x0, tlcorner[1]-(m+b), x1, tlcorner[1]-(h))
|
|
buf = font.render(self.pages[i].tab_title, True, self.fg_color or fg)
|
|
r = buf.get_rect()
|
|
|
|
offs = ((tabWidth - r.size[0])/2) + m +((s+tabWidth)*i)
|
|
|
|
surface.blit(buf, (offs, m))
|
|
x0 = x1 + s
|
|
|
|
data = image.tostring(surface, 'RGBA', 1)
|
|
rect = self.rect.move(offset)
|
|
w, h = root.size
|
|
glViewport(0, 0, w, h)
|
|
glMatrixMode(GL_PROJECTION)
|
|
glLoadIdentity()
|
|
gluOrtho2D(0, w, 0, h)
|
|
glMatrixMode(GL_MODELVIEW)
|
|
glLoadIdentity()
|
|
glRasterPos2i(rect.left, h - rect.bottom)
|
|
glPushAttrib(GL_COLOR_BUFFER_BIT)
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
glDrawPixels(self.width, self.height,
|
|
GL_RGBA, GL_UNSIGNED_BYTE, fromstring(data, dtype='uint8'))
|
|
glPopAttrib()
|
|
glFlush()
|
|
|
|
glDisable(GL_BLEND)
|