Exemple #1
0
    def __init__(self):
        QGraphicsPolygonItem.__init__(self, _col_poly)

        self.show_info = False

        self.setBrush(QColor(255, 255, 255, 0))
        self.setPen(no_pen)
        
        self._text = QGraphicsSimpleTextItem('v')
        self._text.setBrush(Color.dark_text)
        update_font(self._text, lambda f: f.setWeight(55))
        fit_inside(self, self._text, 0.86)
Exemple #2
0
    def __init__(self):

        QGraphicsPolygonItem.__init__(self, _cell_outer)

        self._inner = QGraphicsPolygonItem(_cell_inner)
        self._inner.setPen(no_pen)

        pen = QPen(Color.border, 0.03)
        pen.setJoinStyle(qt.MiterJoin)
        self.setPen(pen)

        self._text = QGraphicsSimpleTextItem('{?}')
        self._text.setBrush(Color.light_text)

        self._kind = Cell.unknown
Exemple #3
0
    def __init__(self):
        QGraphicsPolygonItem.__init__(self, _cell_outer)
        
        self._inner = QGraphicsPolygonItem(_cell_inner)
        self._inner.setPen(no_pen)

        pen = QPen(Color.border, 0.03)
        pen.setJoinStyle(qt.MiterJoin)
        self.setPen(pen)

        self._text = QGraphicsSimpleTextItem('{?}')
        self._text.setBrush(Color.light_text)
        update_font(self._text, lambda f: f.setWeight(55))
        
        self._extra_text = QGraphicsSimpleTextItem('')
        
        self.kind = Cell.unknown
        self.show_info = 0
Exemple #4
0
    def __init__(self):
        QGraphicsPolygonItem.__init__(self, _cell_outer)
        
        self._inner = QGraphicsPolygonItem(_cell_inner)
        self._inner.setPen(no_pen)

        pen = QPen(Color.border, 0.03)
        pen.setJoinStyle(qt.MiterJoin)
        self.setPen(pen)

        self._text = QGraphicsSimpleTextItem('{?}')
        self._text.setBrush(Color.light_text)
        update_font(self._text, lambda f: f.setWeight(55))
        
        self._extra_text = QGraphicsSimpleTextItem('')
        
        self.kind = Cell.unknown
        self.show_info = 0
Exemple #5
0
    def __init__(self):
        QGraphicsPolygonItem.__init__(self, _col_poly)

        self.show_info = False

        self.setBrush(QColor(255, 255, 255, 0))
        self.setPen(no_pen)
        
        self._text = QGraphicsSimpleTextItem('v')
        self._text.setBrush(Color.dark_text)
        update_font(self._text, lambda f: f.setWeight(55))
        fit_inside(self, self._text, 0.86)
Exemple #6
0
    def __init__(self):
        # The collision box is rectangular
        poly = QPolygonF()
        poly.append(QPointF(-0.25, 0.48))
        poly.append(QPointF(-0.25, 0.02))
        poly.append(QPointF(0.25, 0.02))
        poly.append(QPointF(0.25, 0.48))
        #l = 0.49/cos30
        #for i in range(6):
        #a = i*tau/6-tau/12
        #poly.append(QPointF(l*math.sin(a), -l*math.cos(a)))

        QGraphicsPolygonItem.__init__(self, poly)

        self.setBrush(QColor(255, 255, 255, 0))
        #self.setPen(QPen(qt.red, 0))
        self.setPen(no_pen)

        self._text = QGraphicsSimpleTextItem('v')
        self._text.setBrush(Color.dark_text)
        fit_inside(self, self._text, 0.8)
Exemple #7
0
    def __init__(self):

        QGraphicsPolygonItem.__init__(self, _cell_outer)

        self._inner = QGraphicsPolygonItem(_cell_inner)
        self._inner.setPen(no_pen)

        pen = QPen(Color.border, 0.03)
        pen.setJoinStyle(qt.MiterJoin)
        self.setPen(pen)

        self._text = QGraphicsSimpleTextItem("{?}")
        self._text.setBrush(Color.light_text)

        self._kind = Cell.unknown
Exemple #8
0
    def __init__(self):
        # The collision box is rectangular
        poly = QPolygonF()
        poly.append(QPointF(-0.25, 0.48))
        poly.append(QPointF(-0.25, 0.02))
        poly.append(QPointF(0.25, 0.02))
        poly.append(QPointF(0.25, 0.48))
        #l = 0.49/cos30
        #for i in range(6):
            #a = i*tau/6-tau/12
            #poly.append(QPointF(l*math.sin(a), -l*math.cos(a)))
        
        QGraphicsPolygonItem.__init__(self, poly)

        self.setBrush(QColor(255, 255, 255, 0))
        #self.setPen(QPen(qt.red, 0))
        self.setPen(no_pen)
        
        self._text = QGraphicsSimpleTextItem('v')
        self._text.setBrush(Color.dark_text)
        fit_inside(self, self._text, 0.8)
Exemple #9
0
class Column(QGraphicsPolygonItem, Item):
    "Column number marker"
    def __init__(self):
        QGraphicsPolygonItem.__init__(self, _col_poly)

        self.show_info = False

        self.setBrush(QColor(255, 255, 255, 0))
        self.setPen(no_pen)
        
        self._text = QGraphicsSimpleTextItem('v')
        self._text.setBrush(Color.dark_text)
        update_font(self._text, lambda f: f.setWeight(55))
        fit_inside(self, self._text, 0.86)
        #self._text.setY(self._text.y()+0.2)
    
    @setter_property
    def angle(self, value):
        if value not in (-60, 0, 60):
            raise ValueError(value)
        yield value
    
    @property
    def cell(self):
        return self.members[0]

    @cached_property
    def members(self):
        try:
            x, y = self.coord
        except AttributeError:
            return
        result = []
        dx, dy = _col_angle_deltas[self.angle]
        while True:
            x += dx
            y += dy
            it = self.scene().grid.get((x, y))
            if not it and not self.scene().grid_bounds.contains(x, y, False):
                break
            if isinstance(it, Cell):
                result.append(it)
        return result

    @cached_property
    def value(self):
        return sum(1 for it in self.members if it.kind is Cell.full)

    @cached_property
    def together(self):
        if self.show_info:
            groups = itertools.groupby(self.members, key=lambda it: it.kind is Cell.full)
            return sum(1 for full, _ in groups if full) <= 1

    def reset_cache(self):
        for attr in ['members', 'value', 'together']:
            try:
                delattr(self, attr)
            except AttributeError: pass

    def upd(self):
        self.reset_cache()
        
        self.setRotation(self.angle or 1e-3) # not zero so font doesn't look different from rotated variants
        
        if not self.placed:
            return
        
        txt = str(self.value)
        together = self.together
        if together is not None:
            txt = ('{{{}}}' if together else '-{}-').format(txt)
        self._text.setText(txt)
        if txt:
            self._text.setX(-self._text.boundingRect().width()*self._text.scale()/2)
        
        self.update()

    def paint(self, g, option, widget):
        QGraphicsPolygonItem.paint(self, g, option, widget)
        g.setTransform(self._text.sceneTransform(), True)
        self._text.paint(g, option, widget)

    def __repr__(self):
        r = ['Column']
        r.append(self._text.text())
        try:
            r.append('#{}'.format(self.id))
        except AttributeError: pass
        r.append('members:[{}]'.format(' '.join(m.__repr__(False) for m in self.members)))
        return '<{}>'.format(' '.join(str(p) for p in r if str(p)))
Exemple #10
0
class Cell(QGraphicsPolygonItem, Item):
    "Hexagonal cell"
    unknown = Entity('Cell.unknown')
    empty = Entity('Cell.empty')
    full = Entity('Cell.full')
    
    def __init__(self):
        QGraphicsPolygonItem.__init__(self, _cell_outer)
        
        self._inner = QGraphicsPolygonItem(_cell_inner)
        self._inner.setPen(no_pen)

        pen = QPen(Color.border, 0.03)
        pen.setJoinStyle(qt.MiterJoin)
        self.setPen(pen)

        self._text = QGraphicsSimpleTextItem('{?}')
        self._text.setBrush(Color.light_text)
        update_font(self._text, lambda f: f.setWeight(55))
        
        self._extra_text = QGraphicsSimpleTextItem('')
        
        self.kind = Cell.unknown
        self.show_info = 0

    @property
    def display(self):
        return self.kind
    
    @cached_property
    def neighbors(self):
        return list(self._find_neighbors(_neighbors_deltas, Cell))
    @cached_property
    def flower_neighbors(self):
        return list(self._find_neighbors(_flower_deltas, Cell))
    @cached_property
    def columns(self):
        result = []
        for col in self._find_neighbors(_columns_deltas, Column):
            sgn = col.angle//60
            if sgn == col.coord.x-self.coord.x:
                result.append(col)
        return result
    
    @cached_property
    def members(self):
        if self.show_info:
            if self.kind is Cell.empty:
                return self.neighbors
            if self.kind is Cell.full:
                return self.flower_neighbors

    def is_neighbor(self, other):
        return other in self.neighbors

    @cached_property
    def value(self):
        if self.show_info:
            return sum(1 for it in self.members if it.kind is Cell.full)
    
    @cached_property
    def together(self):
        if self.show_info == 2:
            full_items = {it for it in self.members if it.kind is Cell.full}
            return all_grouped(full_items, key=Cell.is_neighbor)

    def reset_cache(self):
        for attr in ['neighbors', 'flower_neighbors', 'columns', 'members', 'value', 'together']:
            try:
                delattr(self, attr)
            except AttributeError: pass
    
    @property
    def extra_text(self):
        return self._extra_text.text().replace('\n', '')
    @extra_text.setter
    def extra_text(self, value):
        value = value[:3]
        self._extra_text.setText(value)
        self.upd()
    
    def keyPressEvent(self, e):
        for c in e.text():
            c = c.upper()
            if c.isdigit() or e.modifiers() & (qt.ShiftModifier):
                if c not in ['Q', 'W']:
                    self.extra_text += c
        if e.key() in [qt.Key_Backspace, qt.Key_QuoteLeft, qt.Key_AsciiTilde] or\
          e.text() in [u'`', u'~', u'^', u'\\', u'\N{SECTION SIGN}']:
            if not (e.modifiers() & qt.ShiftModifier):
                self.guess = None
                self.extra_text = ''
    
    def upd(self, first=False):
        self.reset_cache()
        
        if self.display is Cell.unknown:
            self.setBrush(Color.yellow_border)
            self._inner.setBrush(Color.yellow)
            self._text.setText('')
        elif self.display is Cell.empty:
            self.setBrush(Color.black_border)
            self._inner.setBrush(Color.black)
        elif self.display is Cell.full:
            self.setBrush(Color.blue_border)
            self._inner.setBrush(Color.blue)
        
        if not self.placed:
            return
        
        if self.display is not Cell.unknown and self.value is not None:
            txt = str(self.value)
            if self.together is not None:
                txt = ('{{{}}}' if self.together else '-{}-').format(txt)
        else:
            txt = '?' if self.display is Cell.empty else ''
        
        self._text.setText(txt)
        if txt:
            fit_inside(self, self._text, 0.48)
        
        if self.extra_text:
            unknown = self.display is Cell.unknown
            fit_inside(self, self._extra_text, 0.31)
            self._extra_text.setPos(self._extra_text.pos() + QPointF(0, -0.2))
            self._extra_text.setBrush(Color.dark_text if unknown else Color.light_text)
        
        if txt and self.extra_text:
            self._text.setPos(self._text.pos() + QPointF(0, 0.1))

        self.update()
        
        if first:
            with self.upd_neighbors():
                pass
    
    @contextlib.contextmanager
    def upd_neighbors(self):
        neighbors = list(self.flower_neighbors)
        scene = self.scene()
        yield
        for it in neighbors:
            it.upd()
        for it in scene.all(Column):
            it.upd()
    
    def paint(self, g, option, widget):
        QGraphicsPolygonItem.paint(self, g, option, widget)
        self._inner.paint(g, option, widget)
        transform = g.transform()
        g.setTransform(self._extra_text.sceneTransform(), True)
        self._extra_text.paint(g, option, widget)
        g.setTransform(transform)
        g.setTransform(self._text.sceneTransform(), True)
        g.setOpacity(self._text.opacity())
        self._text.paint(g, option, widget)
    
    def __repr__(self, first=True):
        r = [self.display]
        if self.display!=self.kind:
            r.append('({})'.format(repr(self.kind).split('.')[1]))
        r.append(self._text.text())
        try:
            r.append('#{}'.format(self.id))
        except AttributeError: pass
        if first:
            r.append('neighbors:[{}]'.format(' '.join(m.__repr__(False) for m in self.neighbors)))
            if self.members:
                r.append('members:[{}]'.format(' '.join(m.__repr__(False) for m in self.members)))
        return '<{}>'.format(' '.join(str(p) for p in r if str(p)))
Exemple #11
0
class Column(QGraphicsPolygonItem):
    "Column number marker"

    def __init__(self):
        # The collision box is rectangular
        poly = QPolygonF()
        poly.append(QPointF(-0.25, 0.48))
        poly.append(QPointF(-0.25, 0.02))
        poly.append(QPointF(0.25, 0.02))
        poly.append(QPointF(0.25, 0.48))
        #l = 0.49/cos30
        #for i in range(6):
        #a = i*tau/6-tau/12
        #poly.append(QPointF(l*math.sin(a), -l*math.cos(a)))

        QGraphicsPolygonItem.__init__(self, poly)

        self.setBrush(QColor(255, 255, 255, 0))
        #self.setPen(QPen(qt.red, 0))
        self.setPen(no_pen)

        self._text = QGraphicsSimpleTextItem('v')
        self._text.setBrush(Color.dark_text)
        fit_inside(self, self._text, 0.8)
        #self._text.setY(self.text._y()+0.2)

    @property
    def text(self):
        return self._text.text()

    @text.setter
    def text(self, value):
        self._text.setText(value)
        if value:
            self._text.setX(-self._text.boundingRect().width() *
                            self._text.scale() / 2)

    def upd(self):
        txt = str(self.value)
        together = self.together
        if together is not None:
            txt = ('{{{}}}' if together else '-{}-').format(txt)
        self.text = txt
        self.update()

    def paint(self, g, option, widget):
        QGraphicsPolygonItem.paint(self, g, option, widget)
        g.setTransform(self._text.sceneTransform(), True)
        self._text.paint(g, option, widget)
Exemple #12
0
class Cell(QGraphicsPolygonItem):
    "Hexagonal cell"
    unknown = None
    empty = False
    full = True

    def __init__(self):

        QGraphicsPolygonItem.__init__(self, _cell_outer)

        self._inner = QGraphicsPolygonItem(_cell_inner)
        self._inner.setPen(no_pen)

        pen = QPen(Color.border, 0.03)
        pen.setJoinStyle(qt.MiterJoin)
        self.setPen(pen)

        self._text = QGraphicsSimpleTextItem('{?}')
        self._text.setBrush(Color.light_text)

        self._kind = Cell.unknown

    @event_property
    def kind(self):
        self.upd()

    @property
    def text(self):
        return self._text.text()

    @text.setter
    def text(self, value):
        self._text.setText(value)
        if value:
            fit_inside(self, self._text, 0.5)
        self.update()

    def is_neighbor(self, other):
        return other in self.neighbors

    def upd(self, first=True):
        if self.kind is Cell.unknown:
            self.setBrush(Color.yellow_border)
            self._inner.setBrush(Color.yellow)
            self.text = ''
        elif self.kind is Cell.empty:
            self.setBrush(Color.black_border)
            self._inner.setBrush(Color.black)
        elif self.kind is Cell.full:
            self.setBrush(Color.blue_border)
            self._inner.setBrush(Color.blue)

        if self.kind is not Cell.unknown and self.value is not None:
            txt = str(self.value)
            together = self.together
            if together is not None:
                txt = ('{{{}}}' if together else '-{}-').format(txt)
        else:
            txt = '?' if self.kind is Cell.empty else ''

        self.text = txt

        self.update()

    def paint(self, g, option, widget):
        QGraphicsPolygonItem.paint(self, g, option, widget)
        self._inner.paint(g, option, widget)
        g.setTransform(self._text.sceneTransform(), True)
        g.setOpacity(self._text.opacity())
        self._text.paint(g, option, widget)
Exemple #13
0
class Column(QGraphicsPolygonItem):
    "Column number marker"
    def __init__(self):
        # The collision box is rectangular
        poly = QPolygonF()
        poly.append(QPointF(-0.25, 0.48))
        poly.append(QPointF(-0.25, 0.02))
        poly.append(QPointF(0.25, 0.02))
        poly.append(QPointF(0.25, 0.48))
        #l = 0.49/cos30
        #for i in range(6):
            #a = i*tau/6-tau/12
            #poly.append(QPointF(l*math.sin(a), -l*math.cos(a)))
        
        QGraphicsPolygonItem.__init__(self, poly)

        self.setBrush(QColor(255, 255, 255, 0))
        #self.setPen(QPen(qt.red, 0))
        self.setPen(no_pen)
        
        self._text = QGraphicsSimpleTextItem('v')
        self._text.setBrush(Color.dark_text)
        fit_inside(self, self._text, 0.8)
        #self._text.setY(self.text._y()+0.2)

    @property
    def text(self):
        return self._text.text()
    @text.setter
    def text(self, value):
        self._text.setText(value)
        if value:
            self._text.setX(-self._text.boundingRect().width()*self._text.scale()/2)

    def upd(self):
        txt = str(self.value)
        together = self.together
        if together is not None:
            txt = ('{{{}}}' if together else '-{}-').format(txt)
        self.text = txt
        self.update()

    def paint(self, g, option, widget):
        QGraphicsPolygonItem.paint(self, g, option, widget)
        g.setTransform(self._text.sceneTransform(), True)
        self._text.paint(g, option, widget)
Exemple #14
0
class Cell(QGraphicsPolygonItem):
    "Hexagonal cell"
    unknown = None
    empty = False
    full = True
    
    def __init__(self):
        
        
        QGraphicsPolygonItem.__init__(self, _cell_outer)

        self._inner = QGraphicsPolygonItem(_cell_inner)
        self._inner.setPen(no_pen)

        pen = QPen(Color.border, 0.03)
        pen.setJoinStyle(qt.MiterJoin)
        self.setPen(pen)

        self._text = QGraphicsSimpleTextItem('{?}')
        self._text.setBrush(Color.light_text)
        
        self._kind = Cell.unknown
    
    @event_property
    def kind(self):
        self.upd()
    
    @property
    def text(self):
        return self._text.text()
    @text.setter
    def text(self, value):
        self._text.setText(value)
        if value:
            fit_inside(self, self._text, 0.5)
        self.update()
    
    def is_neighbor(self, other):
        return other in self.neighbors
    
    def upd(self, first=True):
        if self.kind is Cell.unknown:
            self.setBrush(Color.yellow_border)
            self._inner.setBrush(Color.yellow)
            self.text = ''
        elif self.kind is Cell.empty:
            self.setBrush(Color.black_border)
            self._inner.setBrush(Color.black)
        elif self.kind is Cell.full:
            self.setBrush(Color.blue_border)
            self._inner.setBrush(Color.blue)
        
        if self.kind is not Cell.unknown and self.value is not None:
            txt = str(self.value)
            together = self.together
            if together is not None:
                txt = ('{{{}}}' if together else '-{}-').format(txt)
        else:
            txt = '?' if self.kind is Cell.empty else ''
        
        self.text = txt
        
        self.update()
    
    def paint(self, g, option, widget):
        QGraphicsPolygonItem.paint(self, g, option, widget)
        self._inner.paint(g, option, widget)
        g.setTransform(self._text.sceneTransform(), True)
        g.setOpacity(self._text.opacity())
        self._text.paint(g, option, widget)
Exemple #15
0
class Column(QGraphicsPolygonItem, Item):
    "Column number marker"
    def __init__(self):
        QGraphicsPolygonItem.__init__(self, _col_poly)

        self.show_info = False

        self.setBrush(QColor(255, 255, 255, 0))
        self.setPen(no_pen)
        
        self._text = QGraphicsSimpleTextItem('v')
        self._text.setBrush(Color.dark_text)
        update_font(self._text, lambda f: f.setWeight(55))
        fit_inside(self, self._text, 0.86)
        #self._text.setY(self._text.y()+0.2)
    
    @setter_property
    def angle(self, value):
        if value not in (-60, 0, 60):
            raise ValueError(value)
        yield value
    
    @property
    def cell(self):
        return self.members[0]

    @cached_property
    def members(self):
        try:
            x, y = self.coord
        except AttributeError:
            return
        result = []
        dx, dy = _col_angle_deltas[self.angle]
        while True:
            x += dx
            y += dy
            it = self.scene().grid.get((x, y))
            if not it and not self.scene().grid_bounds.contains(x, y, False):
                break
            if isinstance(it, Cell):
                result.append(it)
        return result

    @cached_property
    def value(self):
        return sum(1 for it in self.members if it.kind is Cell.full)

    @cached_property
    def together(self):
        if self.show_info:
            groups = itertools.groupby(self.members, key=lambda it: it.kind is Cell.full)
            return sum(1 for full, _ in groups if full) <= 1

    def reset_cache(self):
        for attr in ['members', 'value', 'together']:
            try:
                delattr(self, attr)
            except AttributeError: pass

    def upd(self):
        self.reset_cache()
        
        self.setRotation(self.angle or 1e-3) # not zero so font doesn't look different from rotated variants
        
        if not self.placed:
            return
        
        txt = str(self.value)
        together = self.together
        if together is not None:
            txt = ('{{{}}}' if together else '-{}-').format(txt)
        self._text.setText(txt)
        if txt:
            self._text.setX(-self._text.boundingRect().width()*self._text.scale()/2)
        
        self.update()

    def paint(self, g, option, widget):
        QGraphicsPolygonItem.paint(self, g, option, widget)
        g.setTransform(self._text.sceneTransform(), True)
        self._text.paint(g, option, widget)

    def __repr__(self):
        r = ['Column']
        r.append(self._text.text())
        try:
            r.append('#{}'.format(self.id))
        except AttributeError: pass
        r.append('members:[{}]'.format(' '.join(m.__repr__(False) for m in self.members)))
        return '<{}>'.format(' '.join(str(p) for p in r if str(p)))
Exemple #16
0
class Cell(QGraphicsPolygonItem, Item):
    "Hexagonal cell"
    unknown = Entity('Cell.unknown')
    empty = Entity('Cell.empty')
    full = Entity('Cell.full')
    
    def __init__(self):
        QGraphicsPolygonItem.__init__(self, _cell_outer)
        
        self._inner = QGraphicsPolygonItem(_cell_inner)
        self._inner.setPen(no_pen)

        pen = QPen(Color.border, 0.03)
        pen.setJoinStyle(qt.MiterJoin)
        self.setPen(pen)

        self._text = QGraphicsSimpleTextItem('{?}')
        self._text.setBrush(Color.light_text)
        update_font(self._text, lambda f: f.setWeight(55))
        
        self._extra_text = QGraphicsSimpleTextItem('')
        
        self.kind = Cell.unknown
        self.show_info = 0

    @property
    def display(self):
        return self.kind
    
    @cached_property
    def neighbors(self):
        return list(self._find_neighbors(_neighbors_deltas, Cell))
    @cached_property
    def flower_neighbors(self):
        return list(self._find_neighbors(_flower_deltas, Cell))
    @cached_property
    def columns(self):
        result = []
        for col in self._find_neighbors(_columns_deltas, Column):
            sgn = col.angle//60
            if sgn == col.coord.x-self.coord.x:
                result.append(col)
        return result
    
    @cached_property
    def members(self):
        if self.show_info:
            if self.kind is Cell.empty:
                return self.neighbors
            if self.kind is Cell.full:
                return self.flower_neighbors

    def is_neighbor(self, other):
        return other in self.neighbors

    @cached_property
    def value(self):
        if self.show_info:
            return sum(1 for it in self.members if it.kind is Cell.full)
    
    @cached_property
    def together(self):
        if self.show_info == 2:
            full_items = {it for it in self.members if it.kind is Cell.full}
            return all_grouped(full_items, key=Cell.is_neighbor)

    def reset_cache(self):
        for attr in ['neighbors', 'flower_neighbors', 'columns', 'members', 'value', 'together']:
            try:
                delattr(self, attr)
            except AttributeError: pass
    
    @property
    def extra_text(self):
        return self._extra_text.text().replace('\n', '')
    @extra_text.setter
    def extra_text(self, value):
        value = value[:3]
        self._extra_text.setText(value)
        self.upd()
    
    def keyPressEvent(self, e):
        for c in e.text():
            c = c.upper()
            if c.isdigit() or e.modifiers() & (qt.ShiftModifier):
                if c not in ['Q', 'W']:
                    self.extra_text += c
        if e.key() in [qt.Key_Backspace, qt.Key_QuoteLeft, qt.Key_AsciiTilde] or\
          e.text() in [u'`', u'~', u'^', u'\\', u'\N{SECTION SIGN}']:
            if not (e.modifiers() & qt.ShiftModifier):
                self.guess = None
                self.extra_text = ''
    
    def upd(self, first=False):
        self.reset_cache()
        
        if self.display is Cell.unknown:
            self.setBrush(Color.yellow_border)
            self._inner.setBrush(Color.yellow)
            self._text.setText('')
        elif self.display is Cell.empty:
            self.setBrush(Color.black_border)
            self._inner.setBrush(Color.black)
        elif self.display is Cell.full:
            self.setBrush(Color.blue_border)
            self._inner.setBrush(Color.blue)
        
        if not self.placed:
            return
        
        if self.display is not Cell.unknown and self.value is not None:
            txt = str(self.value)
            if self.together is not None:
                txt = ('{{{}}}' if self.together else '-{}-').format(txt)
        else:
            txt = '?' if self.display is Cell.empty else ''
        
        self._text.setText(txt)
        if txt:
            fit_inside(self, self._text, 0.48)
        
        if self.extra_text:
            unknown = self.display is Cell.unknown
            fit_inside(self, self._extra_text, 0.31)
            self._extra_text.setPos(self._extra_text.pos() + QPointF(0, -0.2))
            self._extra_text.setBrush(Color.dark_text if unknown else Color.light_text)
        
        if txt and self.extra_text:
            self._text.setPos(self._text.pos() + QPointF(0, 0.1))

        self.update()
        
        if first:
            with self.upd_neighbors():
                pass
    
    @contextlib.contextmanager
    def upd_neighbors(self):
        neighbors = list(self.flower_neighbors)
        scene = self.scene()
        yield
        for it in neighbors:
            it.upd()
        for it in scene.all(Column):
            it.upd()
    
    def paint(self, g, option, widget):
        QGraphicsPolygonItem.paint(self, g, option, widget)
        self._inner.paint(g, option, widget)
        transform = g.transform()
        g.setTransform(self._extra_text.sceneTransform(), True)
        self._extra_text.paint(g, option, widget)
        g.setTransform(transform)
        g.setTransform(self._text.sceneTransform(), True)
        g.setOpacity(self._text.opacity())
        self._text.paint(g, option, widget)
    
    def __repr__(self, first=True):
        r = [self.display]
        if self.display!=self.kind:
            r.append('({})'.format(repr(self.kind).split('.')[1]))
        r.append(self._text.text())
        try:
            r.append('#{}'.format(self.id))
        except AttributeError: pass
        if first:
            r.append('neighbors:[{}]'.format(' '.join(m.__repr__(False) for m in self.neighbors)))
            if self.members:
                r.append('members:[{}]'.format(' '.join(m.__repr__(False) for m in self.members)))
        return '<{}>'.format(' '.join(str(p) for p in r if str(p)))