Fix redraw of overlapping widgets inside AnchorLayout.
# -*- coding: utf-8 -*-
from tuikit.container import Container
from tuikit.button import Button
from tuikit.layout import AnchorLayout
from tuikit.common import Borders
import logging
class Window(AnchorLayout):
'''Window widget.
It represents part of screen with border, close button and contents.
Window can be moved, resized or closed by user.'''
def __init__(self, inner_layout=AnchorLayout):
'''Create window of requested size.'''
AnchorLayout.__init__(self)
self.sizemin.update(8, 3)
#: Window title.
self.title = ''
#: Allow user to resize window.
self.resizable = True
self._resizing = False
#: Allow user to move window.
self.movable = True
self._moving = False
self.closebtn = Button('x')
self.closebtn.sizereq.w = 3
self.closebtn.add_handler('click', self.on_closebtn_click)
self.closebtn.bg = 'controls'
self.closebtn.bghi = 'controls-active'
Container.add(self, self.closebtn, halign='right', margin=Borders(r=1))
self._closebutton = True
self.colorprefix = 'window:'
self._inner = inner_layout()
self._inner.add_handler('draw', self._on_inner_draw)
Container.add(self, self._inner, halign='fill', valign='fill', margin=Borders(1,1,1,1))
def add(self, widget, **kwargs):
self._inner.add(widget, **kwargs)
@property
def closebutton(self):
'''Show/hide close button.'''
return self._closebutton
@closebutton.setter
def closebutton(self, value):
self._closebutton = value
self.closebtn.hidden = not value
def on_draw(self, ev):
ev.driver.pushcolor('normal')
ev.driver.frame(ev.x, ev.y, self.width, self.height)
if self.resizable:
if self._resizing:
ev.driver.pushcolor('controls-active')
else:
ev.driver.pushcolor('controls')
ev.driver.puts(ev.x + self.width - 2, ev.y + self.height - 1, '─┘') # '━┛'
ev.driver.popcolor()
if self.title:
title = ' ' + self.title + ' '
left = max(1, (self.width - len(title))//2)
right = self.width - len(title) - left
maxlen = self.width - 5
if left > 1 and right < 4:
# move space from left to right to make space for close button
left -= 1
if len(title) > maxlen:
title = title[:maxlen]
title = title[:-1] + ' '
ev.driver.puts(ev.x + left, ev.y, title)
ev.driver.fill(ev.x+1, ev.y+1, self.width-2, self.height-2)
ev.driver.popcolor()
def _on_inner_draw(self, ev):
ev.driver.pushcolor('normal')
ev.driver.fill_clip()
ev.driver.popcolor()
def on_mousedown(self, ev):
self.bring_up()
def after_mousedown(self, ev):
if self.resizable and ev.wx >= self.width - 1 and ev.wy >= self.height - 1:
self._resizing = True
elif self.movable:
self._moving = True
self.redraw()
def after_mouseup(self, ev):
self._resize_or_move(ev)
self._resizing = False
self._moving = False
self.redraw()
def after_mousemove(self, ev):
self._resize_or_move(ev)
self.redraw()
def _resize_or_move(self, ev):
if self._resizing:
self.resize(self.sizereq.w + ev.relx,
self.sizereq.h + ev.rely)
# AnchorLayout, right/bottom align
# also move the window so that it visualy stays in place
if 'halign' in self._hints and self.hint_value('halign') == 'right':
self.move(x = self.x + ev.relx)
if 'valign' in self._hints and self.hint_value('valign') == 'bottom':
self.move(y = self.y + ev.rely)
elif self._moving:
self.move(self.x + ev.relx,
self.y + ev.rely)
def on_closebtn_click(self, ev):
self.hide()