Current File : //proc/self/root/usr/lib/python3/dist-packages/twisted/conch/insults/window.py
# -*- test-case-name: twisted.conch.test.test_window -*-

"""
Simple insults-based widget library

@author: Jp Calderone
"""

import array

from twisted.conch.insults import helper, insults
from twisted.python import text as tptext


class YieldFocus(Exception):
    """
    Input focus manipulation exception
    """


class BoundedTerminalWrapper:
    def __init__(self, terminal, width, height, xoff, yoff):
        self.width = width
        self.height = height
        self.xoff = xoff
        self.yoff = yoff
        self.terminal = terminal
        self.cursorForward = terminal.cursorForward
        self.selectCharacterSet = terminal.selectCharacterSet
        self.selectGraphicRendition = terminal.selectGraphicRendition
        self.saveCursor = terminal.saveCursor
        self.restoreCursor = terminal.restoreCursor

    def cursorPosition(self, x, y):
        return self.terminal.cursorPosition(
            self.xoff + min(self.width, x), self.yoff + min(self.height, y)
        )

    def cursorHome(self):
        return self.terminal.cursorPosition(self.xoff, self.yoff)

    def write(self, data):
        return self.terminal.write(data)


class Widget:
    focused = False
    parent = None
    dirty = False
    width = height = None

    def repaint(self):
        if not self.dirty:
            self.dirty = True
        if self.parent is not None and not self.parent.dirty:
            self.parent.repaint()

    def filthy(self):
        self.dirty = True

    def redraw(self, width, height, terminal):
        self.filthy()
        self.draw(width, height, terminal)

    def draw(self, width, height, terminal):
        if width != self.width or height != self.height or self.dirty:
            self.width = width
            self.height = height
            self.dirty = False
            self.render(width, height, terminal)

    def render(self, width, height, terminal):
        pass

    def sizeHint(self):
        return None

    def keystrokeReceived(self, keyID, modifier):
        if keyID == b"\t":
            self.tabReceived(modifier)
        elif keyID == b"\x7f":
            self.backspaceReceived()
        elif keyID in insults.FUNCTION_KEYS:
            self.functionKeyReceived(keyID, modifier)
        else:
            self.characterReceived(keyID, modifier)

    def tabReceived(self, modifier):
        # XXX TODO - Handle shift+tab
        raise YieldFocus()

    def focusReceived(self):
        """
        Called when focus is being given to this widget.

        May raise YieldFocus is this widget does not want focus.
        """
        self.focused = True
        self.repaint()

    def focusLost(self):
        self.focused = False
        self.repaint()

    def backspaceReceived(self):
        pass

    def functionKeyReceived(self, keyID, modifier):
        name = keyID
        if not isinstance(keyID, str):
            name = name.decode("utf-8")
        func = getattr(self, "func_" + name, None)
        if func is not None:
            func(modifier)

    def characterReceived(self, keyID, modifier):
        pass


class ContainerWidget(Widget):
    """
    @ivar focusedChild: The contained widget which currently has
    focus, or None.
    """

    focusedChild = None
    focused = False

    def __init__(self):
        Widget.__init__(self)
        self.children = []

    def addChild(self, child):
        assert child.parent is None
        child.parent = self
        self.children.append(child)
        if self.focusedChild is None and self.focused:
            try:
                child.focusReceived()
            except YieldFocus:
                pass
            else:
                self.focusedChild = child
        self.repaint()

    def remChild(self, child):
        assert child.parent is self
        child.parent = None
        self.children.remove(child)
        self.repaint()

    def filthy(self):
        for ch in self.children:
            ch.filthy()
        Widget.filthy(self)

    def render(self, width, height, terminal):
        for ch in self.children:
            ch.draw(width, height, terminal)

    def changeFocus(self):
        self.repaint()

        if self.focusedChild is not None:
            self.focusedChild.focusLost()
            focusedChild = self.focusedChild
            self.focusedChild = None
            try:
                curFocus = self.children.index(focusedChild) + 1
            except ValueError:
                raise YieldFocus()
        else:
            curFocus = 0
        while curFocus < len(self.children):
            try:
                self.children[curFocus].focusReceived()
            except YieldFocus:
                curFocus += 1
            else:
                self.focusedChild = self.children[curFocus]
                return
        # None of our children wanted focus
        raise YieldFocus()

    def focusReceived(self):
        self.changeFocus()
        self.focused = True

    def keystrokeReceived(self, keyID, modifier):
        if self.focusedChild is not None:
            try:
                self.focusedChild.keystrokeReceived(keyID, modifier)
            except YieldFocus:
                self.changeFocus()
                self.repaint()
        else:
            Widget.keystrokeReceived(self, keyID, modifier)


class TopWindow(ContainerWidget):
    """
    A top-level container object which provides focus wrap-around and paint
    scheduling.

    @ivar painter: A no-argument callable which will be invoked when this
    widget needs to be redrawn.

    @ivar scheduler: A one-argument callable which will be invoked with a
    no-argument callable and should arrange for it to invoked at some point in
    the near future.  The no-argument callable will cause this widget and all
    its children to be redrawn.  It is typically beneficial for the no-argument
    callable to be invoked at the end of handling for whatever event is
    currently active; for example, it might make sense to call it at the end of
    L{twisted.conch.insults.insults.ITerminalProtocol.keystrokeReceived}.
    Note, however, that since calls to this may also be made in response to no
    apparent event, arrangements should be made for the function to be called
    even if an event handler such as C{keystrokeReceived} is not on the call
    stack (eg, using
    L{reactor.callLater<twisted.internet.interfaces.IReactorTime.callLater>}
    with a short timeout).
    """

    focused = True

    def __init__(self, painter, scheduler):
        ContainerWidget.__init__(self)
        self.painter = painter
        self.scheduler = scheduler

    _paintCall = None

    def repaint(self):
        if self._paintCall is None:
            self._paintCall = object()
            self.scheduler(self._paint)
        ContainerWidget.repaint(self)

    def _paint(self):
        self._paintCall = None
        self.painter()

    def changeFocus(self):
        try:
            ContainerWidget.changeFocus(self)
        except YieldFocus:
            try:
                ContainerWidget.changeFocus(self)
            except YieldFocus:
                pass

    def keystrokeReceived(self, keyID, modifier):
        try:
            ContainerWidget.keystrokeReceived(self, keyID, modifier)
        except YieldFocus:
            self.changeFocus()


class AbsoluteBox(ContainerWidget):
    def moveChild(self, child, x, y):
        for n in range(len(self.children)):
            if self.children[n][0] is child:
                self.children[n] = (child, x, y)
                break
        else:
            raise ValueError("No such child", child)

    def render(self, width, height, terminal):
        for ch, x, y in self.children:
            wrap = BoundedTerminalWrapper(terminal, width - x, height - y, x, y)
            ch.draw(width, height, wrap)


class _Box(ContainerWidget):
    TOP, CENTER, BOTTOM = range(3)

    def __init__(self, gravity=CENTER):
        ContainerWidget.__init__(self)
        self.gravity = gravity

    def sizeHint(self):
        height = 0
        width = 0
        for ch in self.children:
            hint = ch.sizeHint()
            if hint is None:
                hint = (None, None)

            if self.variableDimension == 0:
                if hint[0] is None:
                    width = None
                elif width is not None:
                    width += hint[0]
                if hint[1] is None:
                    height = None
                elif height is not None:
                    height = max(height, hint[1])
            else:
                if hint[0] is None:
                    width = None
                elif width is not None:
                    width = max(width, hint[0])
                if hint[1] is None:
                    height = None
                elif height is not None:
                    height += hint[1]

        return width, height

    def render(self, width, height, terminal):
        if not self.children:
            return

        greedy = 0
        wants = []
        for ch in self.children:
            hint = ch.sizeHint()
            if hint is None:
                hint = (None, None)
            if hint[self.variableDimension] is None:
                greedy += 1
            wants.append(hint[self.variableDimension])

        length = (width, height)[self.variableDimension]
        totalWant = sum(w for w in wants if w is not None)
        if greedy:
            leftForGreedy = int((length - totalWant) / greedy)

        widthOffset = heightOffset = 0

        for want, ch in zip(wants, self.children):
            if want is None:
                want = leftForGreedy

            subWidth, subHeight = width, height
            if self.variableDimension == 0:
                subWidth = want
            else:
                subHeight = want

            wrap = BoundedTerminalWrapper(
                terminal,
                subWidth,
                subHeight,
                widthOffset,
                heightOffset,
            )
            ch.draw(subWidth, subHeight, wrap)
            if self.variableDimension == 0:
                widthOffset += want
            else:
                heightOffset += want


class HBox(_Box):
    variableDimension = 0


class VBox(_Box):
    variableDimension = 1


class Packer(ContainerWidget):
    def render(self, width, height, terminal):
        if not self.children:
            return

        root = int(len(self.children) ** 0.5 + 0.5)
        boxes = [VBox() for n in range(root)]
        for n, ch in enumerate(self.children):
            boxes[n % len(boxes)].addChild(ch)
        h = HBox()
        map(h.addChild, boxes)
        h.render(width, height, terminal)


class Canvas(Widget):
    focused = False

    contents = None

    def __init__(self):
        Widget.__init__(self)
        self.resize(1, 1)

    def resize(self, width, height):
        contents = array.array("B", b" " * width * height)
        if self.contents is not None:
            for x in range(min(width, self._width)):
                for y in range(min(height, self._height)):
                    contents[width * y + x] = self[x, y]
        self.contents = contents
        self._width = width
        self._height = height
        if self.x >= width:
            self.x = width - 1
        if self.y >= height:
            self.y = height - 1

    def __getitem__(self, index):
        (x, y) = index
        return self.contents[(self._width * y) + x]

    def __setitem__(self, index, value):
        (x, y) = index
        self.contents[(self._width * y) + x] = value

    def clear(self):
        self.contents = array.array("B", b" " * len(self.contents))

    def render(self, width, height, terminal):
        if not width or not height:
            return

        if width != self._width or height != self._height:
            self.resize(width, height)
        for i in range(height):
            terminal.cursorPosition(0, i)
            text = self.contents[
                self._width * i : self._width * i + self._width
            ].tobytes()
            text = text[:width]
            terminal.write(text)


def horizontalLine(terminal, y, left, right):
    terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0)
    terminal.cursorPosition(left, y)
    terminal.write(b"\161" * (right - left))
    terminal.selectCharacterSet(insults.CS_US, insults.G0)


def verticalLine(terminal, x, top, bottom):
    terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0)
    for n in range(top, bottom):
        terminal.cursorPosition(x, n)
        terminal.write(b"\170")
    terminal.selectCharacterSet(insults.CS_US, insults.G0)


def rectangle(terminal, position, dimension):
    """
    Draw a rectangle

    @type position: L{tuple}
    @param position: A tuple of the (top, left) coordinates of the rectangle.
    @type dimension: L{tuple}
    @param dimension: A tuple of the (width, height) size of the rectangle.
    """
    (top, left) = position
    (width, height) = dimension
    terminal.selectCharacterSet(insults.CS_DRAWING, insults.G0)

    terminal.cursorPosition(top, left)
    terminal.write(b"\154")
    terminal.write(b"\161" * (width - 2))
    terminal.write(b"\153")
    for n in range(height - 2):
        terminal.cursorPosition(left, top + n + 1)
        terminal.write(b"\170")
        terminal.cursorForward(width - 2)
        terminal.write(b"\170")
    terminal.cursorPosition(0, top + height - 1)
    terminal.write(b"\155")
    terminal.write(b"\161" * (width - 2))
    terminal.write(b"\152")

    terminal.selectCharacterSet(insults.CS_US, insults.G0)


class Border(Widget):
    def __init__(self, containee):
        Widget.__init__(self)
        self.containee = containee
        self.containee.parent = self

    def focusReceived(self):
        return self.containee.focusReceived()

    def focusLost(self):
        return self.containee.focusLost()

    def keystrokeReceived(self, keyID, modifier):
        return self.containee.keystrokeReceived(keyID, modifier)

    def sizeHint(self):
        hint = self.containee.sizeHint()
        if hint is None:
            hint = (None, None)
        if hint[0] is None:
            x = None
        else:
            x = hint[0] + 2
        if hint[1] is None:
            y = None
        else:
            y = hint[1] + 2
        return x, y

    def filthy(self):
        self.containee.filthy()
        Widget.filthy(self)

    def render(self, width, height, terminal):
        if self.containee.focused:
            terminal.write(b"\x1b[31m")
        rectangle(terminal, (0, 0), (width, height))
        terminal.write(b"\x1b[0m")
        wrap = BoundedTerminalWrapper(terminal, width - 2, height - 2, 1, 1)
        self.containee.draw(width - 2, height - 2, wrap)


class Button(Widget):
    def __init__(self, label, onPress):
        Widget.__init__(self)
        self.label = label
        self.onPress = onPress

    def sizeHint(self):
        return len(self.label), 1

    def characterReceived(self, keyID, modifier):
        if keyID == b"\r":
            self.onPress()

    def render(self, width, height, terminal):
        terminal.cursorPosition(0, 0)
        if self.focused:
            terminal.write(b"\x1b[1m" + self.label + b"\x1b[0m")
        else:
            terminal.write(self.label)


class TextInput(Widget):
    def __init__(self, maxwidth, onSubmit):
        Widget.__init__(self)
        self.onSubmit = onSubmit
        self.maxwidth = maxwidth
        self.buffer = b""
        self.cursor = 0

    def setText(self, text):
        self.buffer = text[: self.maxwidth]
        self.cursor = len(self.buffer)
        self.repaint()

    def func_LEFT_ARROW(self, modifier):
        if self.cursor > 0:
            self.cursor -= 1
            self.repaint()

    def func_RIGHT_ARROW(self, modifier):
        if self.cursor < len(self.buffer):
            self.cursor += 1
            self.repaint()

    def backspaceReceived(self):
        if self.cursor > 0:
            self.buffer = self.buffer[: self.cursor - 1] + self.buffer[self.cursor :]
            self.cursor -= 1
            self.repaint()

    def characterReceived(self, keyID, modifier):
        if keyID == b"\r":
            self.onSubmit(self.buffer)
        else:
            if len(self.buffer) < self.maxwidth:
                self.buffer = (
                    self.buffer[: self.cursor] + keyID + self.buffer[self.cursor :]
                )
                self.cursor += 1
                self.repaint()

    def sizeHint(self):
        return self.maxwidth + 1, 1

    def render(self, width, height, terminal):
        currentText = self._renderText()
        terminal.cursorPosition(0, 0)
        if self.focused:
            terminal.write(currentText[: self.cursor])
            cursor(terminal, currentText[self.cursor : self.cursor + 1] or b" ")
            terminal.write(currentText[self.cursor + 1 :])
            terminal.write(b" " * (self.maxwidth - len(currentText) + 1))
        else:
            more = self.maxwidth - len(currentText)
            terminal.write(currentText + b"_" * more)

    def _renderText(self):
        return self.buffer


class PasswordInput(TextInput):
    def _renderText(self):
        return "*" * len(self.buffer)


class TextOutput(Widget):
    text = b""

    def __init__(self, size=None):
        Widget.__init__(self)
        self.size = size

    def sizeHint(self):
        return self.size

    def render(self, width, height, terminal):
        terminal.cursorPosition(0, 0)
        text = self.text[:width]
        terminal.write(text + b" " * (width - len(text)))

    def setText(self, text):
        self.text = text
        self.repaint()

    def focusReceived(self):
        raise YieldFocus()


class TextOutputArea(TextOutput):
    WRAP, TRUNCATE = range(2)

    def __init__(self, size=None, longLines=WRAP):
        TextOutput.__init__(self, size)
        self.longLines = longLines

    def render(self, width, height, terminal):
        n = 0
        inputLines = self.text.splitlines()
        outputLines = []
        while inputLines:
            if self.longLines == self.WRAP:
                line = inputLines.pop(0)
                if not isinstance(line, str):
                    line = line.decode("utf-8")
                wrappedLines = []
                for wrappedLine in tptext.greedyWrap(line, width):
                    if not isinstance(wrappedLine, bytes):
                        wrappedLine = wrappedLine.encode("utf-8")
                    wrappedLines.append(wrappedLine)
                outputLines.extend(wrappedLines or [b""])
            else:
                outputLines.append(inputLines.pop(0)[:width])
            if len(outputLines) >= height:
                break
        for n, L in enumerate(outputLines[:height]):
            terminal.cursorPosition(0, n)
            terminal.write(L)


class Viewport(Widget):
    _xOffset = 0
    _yOffset = 0

    @property
    def xOffset(self):
        return self._xOffset

    @xOffset.setter
    def xOffset(self, value):
        if self._xOffset != value:
            self._xOffset = value
            self.repaint()

    @property
    def yOffset(self):
        return self._yOffset

    @yOffset.setter
    def yOffset(self, value):
        if self._yOffset != value:
            self._yOffset = value
            self.repaint()

    _width = 160
    _height = 24

    def __init__(self, containee):
        Widget.__init__(self)
        self.containee = containee
        self.containee.parent = self

        self._buf = helper.TerminalBuffer()
        self._buf.width = self._width
        self._buf.height = self._height
        self._buf.connectionMade()

    def filthy(self):
        self.containee.filthy()
        Widget.filthy(self)

    def render(self, width, height, terminal):
        self.containee.draw(self._width, self._height, self._buf)

        # XXX /Lame/
        for y, line in enumerate(
            self._buf.lines[self._yOffset : self._yOffset + height]
        ):
            terminal.cursorPosition(0, y)
            n = 0
            for n, (ch, attr) in enumerate(line[self._xOffset : self._xOffset + width]):
                if ch is self._buf.void:
                    ch = b" "
                terminal.write(ch)
            if n < width:
                terminal.write(b" " * (width - n - 1))


class _Scrollbar(Widget):
    def __init__(self, onScroll):
        Widget.__init__(self)
        self.onScroll = onScroll
        self.percent = 0.0

    def smaller(self):
        self.percent = min(1.0, max(0.0, self.onScroll(-1)))
        self.repaint()

    def bigger(self):
        self.percent = min(1.0, max(0.0, self.onScroll(+1)))
        self.repaint()


class HorizontalScrollbar(_Scrollbar):
    def sizeHint(self):
        return (None, 1)

    def func_LEFT_ARROW(self, modifier):
        self.smaller()

    def func_RIGHT_ARROW(self, modifier):
        self.bigger()

    _left = "\N{BLACK LEFT-POINTING TRIANGLE}"
    _right = "\N{BLACK RIGHT-POINTING TRIANGLE}"
    _bar = "\N{LIGHT SHADE}"
    _slider = "\N{DARK SHADE}"

    def render(self, width, height, terminal):
        terminal.cursorPosition(0, 0)
        n = width - 3
        before = int(n * self.percent)
        after = n - before
        me = (
            self._left
            + (self._bar * before)
            + self._slider
            + (self._bar * after)
            + self._right
        )
        terminal.write(me.encode("utf-8"))


class VerticalScrollbar(_Scrollbar):
    def sizeHint(self):
        return (1, None)

    def func_UP_ARROW(self, modifier):
        self.smaller()

    def func_DOWN_ARROW(self, modifier):
        self.bigger()

    _up = "\N{BLACK UP-POINTING TRIANGLE}"
    _down = "\N{BLACK DOWN-POINTING TRIANGLE}"
    _bar = "\N{LIGHT SHADE}"
    _slider = "\N{DARK SHADE}"

    def render(self, width, height, terminal):
        terminal.cursorPosition(0, 0)
        knob = int(self.percent * (height - 2))
        terminal.write(self._up.encode("utf-8"))
        for i in range(1, height - 1):
            terminal.cursorPosition(0, i)
            if i != (knob + 1):
                terminal.write(self._bar.encode("utf-8"))
            else:
                terminal.write(self._slider.encode("utf-8"))
        terminal.cursorPosition(0, height - 1)
        terminal.write(self._down.encode("utf-8"))


class ScrolledArea(Widget):
    """
    A L{ScrolledArea} contains another widget wrapped in a viewport and
    vertical and horizontal scrollbars for moving the viewport around.
    """

    def __init__(self, containee):
        Widget.__init__(self)
        self._viewport = Viewport(containee)
        self._horiz = HorizontalScrollbar(self._horizScroll)
        self._vert = VerticalScrollbar(self._vertScroll)

        for w in self._viewport, self._horiz, self._vert:
            w.parent = self

    def _horizScroll(self, n):
        self._viewport.xOffset += n
        self._viewport.xOffset = max(0, self._viewport.xOffset)
        return self._viewport.xOffset / 25.0

    def _vertScroll(self, n):
        self._viewport.yOffset += n
        self._viewport.yOffset = max(0, self._viewport.yOffset)
        return self._viewport.yOffset / 25.0

    def func_UP_ARROW(self, modifier):
        self._vert.smaller()

    def func_DOWN_ARROW(self, modifier):
        self._vert.bigger()

    def func_LEFT_ARROW(self, modifier):
        self._horiz.smaller()

    def func_RIGHT_ARROW(self, modifier):
        self._horiz.bigger()

    def filthy(self):
        self._viewport.filthy()
        self._horiz.filthy()
        self._vert.filthy()
        Widget.filthy(self)

    def render(self, width, height, terminal):
        wrapper = BoundedTerminalWrapper(terminal, width - 2, height - 2, 1, 1)
        self._viewport.draw(width - 2, height - 2, wrapper)
        if self.focused:
            terminal.write(b"\x1b[31m")
        horizontalLine(terminal, 0, 1, width - 1)
        verticalLine(terminal, 0, 1, height - 1)
        self._vert.draw(
            1, height - 1, BoundedTerminalWrapper(terminal, 1, height - 1, width - 1, 0)
        )
        self._horiz.draw(
            width, 1, BoundedTerminalWrapper(terminal, width, 1, 0, height - 1)
        )
        terminal.write(b"\x1b[0m")


def cursor(terminal, ch):
    terminal.saveCursor()
    terminal.selectGraphicRendition(str(insults.REVERSE_VIDEO))
    terminal.write(ch)
    terminal.restoreCursor()
    terminal.cursorForward()


class Selection(Widget):
    # Index into the sequence
    focusedIndex = 0

    # Offset into the displayed subset of the sequence
    renderOffset = 0

    def __init__(self, sequence, onSelect, minVisible=None):
        Widget.__init__(self)
        self.sequence = sequence
        self.onSelect = onSelect
        self.minVisible = minVisible
        if minVisible is not None:
            self._width = max(map(len, self.sequence))

    def sizeHint(self):
        if self.minVisible is not None:
            return self._width, self.minVisible

    def func_UP_ARROW(self, modifier):
        if self.focusedIndex > 0:
            self.focusedIndex -= 1
            if self.renderOffset > 0:
                self.renderOffset -= 1
            self.repaint()

    def func_PGUP(self, modifier):
        if self.renderOffset != 0:
            self.focusedIndex -= self.renderOffset
            self.renderOffset = 0
        else:
            self.focusedIndex = max(0, self.focusedIndex - self.height)
        self.repaint()

    def func_DOWN_ARROW(self, modifier):
        if self.focusedIndex < len(self.sequence) - 1:
            self.focusedIndex += 1
            if self.renderOffset < self.height - 1:
                self.renderOffset += 1
            self.repaint()

    def func_PGDN(self, modifier):
        if self.renderOffset != self.height - 1:
            change = self.height - self.renderOffset - 1
            if change + self.focusedIndex >= len(self.sequence):
                change = len(self.sequence) - self.focusedIndex - 1
            self.focusedIndex += change
            self.renderOffset = self.height - 1
        else:
            self.focusedIndex = min(
                len(self.sequence) - 1, self.focusedIndex + self.height
            )
        self.repaint()

    def characterReceived(self, keyID, modifier):
        if keyID == b"\r":
            self.onSelect(self.sequence[self.focusedIndex])

    def render(self, width, height, terminal):
        self.height = height
        start = self.focusedIndex - self.renderOffset
        if start > len(self.sequence) - height:
            start = max(0, len(self.sequence) - height)

        elements = self.sequence[start : start + height]

        for n, ele in enumerate(elements):
            terminal.cursorPosition(0, n)
            if n == self.renderOffset:
                terminal.saveCursor()
                if self.focused:
                    modes = str(insults.REVERSE_VIDEO), str(insults.BOLD)
                else:
                    modes = (str(insults.REVERSE_VIDEO),)
                terminal.selectGraphicRendition(*modes)
            text = ele[:width]
            terminal.write(text + (b" " * (width - len(text))))
            if n == self.renderOffset:
                terminal.restoreCursor()
¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!