예제 #1
0
파일: stylus.py 프로젝트: waebbl/wacom-gui
    def init_eraser(self, dev_id, eraser):
        self.deleteItemsOfLayout(self.eraserToolLeft.layout())
        self.deleteItemsOfLayout(self.eraserToolRight.layout())
        if 'pressurecurve' in eraser.keys():
            self.eraserPressure = WacomPressure(dev_id, eraser['pressurecurve'])
        else:
            self.eraserPressure = WacomPressure(dev_id)
        self.eraserPressure.gauge.installEventFilter(self)
        self.eraserPressure.setToolTip("Set pressure curve for input pressure.\n"
                                       "It is composed of two anchor points (0,0 and 100,100)")
        if 'threshold' in eraser.keys():
            self.eraserThreshold = WacomAttribSlider(dev_id, 'threshold', 26, "Threshold", 0, 2047, 50,
                                                  int(eraser['threshold']))
        else:
            self.eraserThreshold = WacomAttribSlider(dev_id, 'threshold', 26, "Threshold", 0, 2047, 50)
        self.eraserThreshold.setToolTip("Set  the  minimum  pressure  necessary to generate a Button event\n"
                                     "for the stylus tip, eraser, or touch.")
        if 'taptime' in eraser.keys():
            self.eraserTaptime = WacomAttribSlider(dev_id, 'taptime', 250, "Double Tap Time (ms)", 0, 500, 25,
                                                int(eraser['taptime']))
        else:
            self.eraserTaptime = WacomAttribSlider(dev_id, 'taptime', 250, "Threshold", 0, 500, 25)
        self.eraserTaptime.setToolTip("Time between taps in ms that will register as a double time")
        if 'rawsample' in eraser.keys():
            self.eraserRawsample = WacomAttribSlider(dev_id, 'rawsample', 4, "Sample Size", 1, 20, 4,
                                                  int(eraser['rawsample']))
        else:
            self.eraserRawsample = WacomAttribSlider(dev_id, 'rawsample', 4, "Sample Size", 1, 20, 4)
        self.eraserRawsample.setToolTip("Set the sample window size (a sliding average sampling window) for\n"
                                     "incoming input tool raw data points.")
        if 'suppress' in eraser.keys():
            self.eraserSuppress = WacomAttribSlider(dev_id, 'suppress', 2, "Tilt Sensitivity", 0, 100, 10,
                                                  int(eraser['suppress']))
        else:
            self.eraserSuppress = WacomAttribSlider(dev_id, 'suppress', 2, "Tilt Sensitivity", 0, 100, 10)
        self.eraserSuppress.setToolTip("Set the delta (difference) cutoff level for further processing of\n"
                                    "incoming input tool coordinate values.")
        if 'buttons' in eraser.keys():
            if 'Button1' in eraser['buttons']:
                self.button1 = HotkeyWidget(dev_id, 'Button1', 'Button 1', eraser['buttons']['Button1'])
            else:
                self.button1 = HotkeyWidget(dev_id, 'Button1', 'Button 1', 'Default')

        self.eraserToolLeft.addWidget(self.eraserPressure)
        self.eraserToolLeft.addWidget(self.eraserThreshold)
        self.eraserToolLeft.addWidget(self.eraserTaptime)
        self.eraserToolLeft.addWidget(self.eraserRawsample)
        spacer = QSpacerItem(20, 200, QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.eraserToolRight.addWidget(self.button1)
        self.eraserToolRight.addItem(spacer)
        self.eraserToolRight.addWidget(self.eraserSuppress)
예제 #2
0
 def init_keys(self, dev_id, image, buttons, cmds):
     # remove previous stuff
     self.deleteItemsOfLayout(self.keysLayout.layout())
     self.buttons = {'left': [], 'right': [], 'top': [], 'bottom': []}
     # TODO: Bottom, Right
     top = QHBoxLayout()
     top.setAlignment(Qt.AlignHCenter)
     left = QVBoxLayout()
     left.setAlignment(Qt.AlignVCenter)
     right = QVBoxLayout()
     right.setAlignment(Qt.AlignVCenter)
     bottom = QVBoxLayout()
     bottom.setAlignment(Qt.AlignVCenter)
     # add buttons
     but_loc = {}
     for bid in sorted(buttons.keys()):
         but_loc[bid] = buttons[bid].get('pos') or buttons[bid].get("orient")
     for bid, value in sorted(but_loc.items(), key=lambda t: (t[1], t[0])):
         if cmds.__len__() == 0:
             keystroke = "Default"
         else:
             keystroke = cmds[bid]
         if buttons[bid]['orient'] == 'Top':
             self.buttons['top'].append(HotkeyWidget(dev_id, bid, buttons[bid]['bid'], keystroke))
         elif buttons[bid]['orient'] == 'Left':
             self.buttons['left'].append(HotkeyWidget(dev_id, bid, buttons[bid]['bid'], keystroke))
         elif buttons[bid]['orient'] == 'Right':
             self.buttons['right'].append(HotkeyWidget(dev_id, bid, buttons[bid]['bid'], keystroke))
         elif buttons[bid]['orient'] == 'Bottom':
             self.buttons['bottom'].append(HotkeyWidget(dev_id, bid, buttons[bid]['bid'], keystroke))
     svgWidget = None
     svg_hspace = QSpacerItem(800, 80, QSizePolicy.Fixed, QSizePolicy.Fixed)
     svg_vspace = QSpacerItem(80, 300, QSizePolicy.Fixed, QSizePolicy.Fixed)
     hspace = 0
     vspace = 20  # reset button
     row = 0
     col = 0  # need at least 1 column
     if self.buttons['top'].__len__() != 0:
         vspace = vspace + 40
     if self.buttons['bottom'].__len__() != 0:
         vspace = vspace + 40
     if self.buttons['left'].__len__() != 0:
         col = col + 1
         hspace = hspace + 120
     if self.buttons['right'].__len__() != 0:
         col = col + 1
     try:
         bkground = os.path.join("/tmp", image)
         if os.path.exists(bkground):
             svgWidget = QSvgWidget(bkground)
             col = col + 1
     except Exception as e:
         print (e)
     # get spacing for final image
     if svgWidget is not None:
         svg_size = svgWidget.sizeHint()
         img_h = float(540 - vspace)
         img_w = float(860 - hspace)
         scale_w = float(img_w / svg_size.width())
         scale_h = float(img_h / svg_size.height())
         if scale_h < scale_w:
             vspace = round(img_w - (scale_h * svg_size.width()))
             svg_vspace.changeSize(vspace, img_h, QSizePolicy.Fixed, QSizePolicy.Fixed)
             svg_hspace.changeSize(img_w, 0, QSizePolicy.Fixed, QSizePolicy.Fixed)
         else:
             hspace = round(img_h - (scale_w * svg_size.height()))
             svg_vspace.changeSize(0, img_h, QSizePolicy.Fixed, QSizePolicy.Fixed)
             svg_hspace.changeSize(img_w, hspace, QSizePolicy.Fixed, QSizePolicy.Fixed)
     # start to build...
     # add top row
     if self.buttons['top'].__len__() != 0:
         for button in self.buttons['top']:
             top.addWidget(button)
         self.keysLayout.addLayout(top, row, 0, 1, col)
         row = row + 1
     # add left row
     if self.buttons['left'].__len__() != 0:
         for button in self.buttons['left']:
             left.addWidget(button)
         if svgWidget is None:
             self.keysLayout.addLayout(left, row, 0, 1, 1)
         else:
             self.keysLayout.addLayout(left, row, 0, 2, 1)
     if svgWidget is not None:
         if self.buttons['left'].__len__() == 0:
             self.keysLayout.addWidget(svgWidget, row, 0, 1, 1)
         else:
             self.keysLayout.addWidget(svgWidget, row, 1, 1, 1)
             self.keysLayout.addItem(svg_vspace, row, 2, 1, 1)
             self.keysLayout.addItem(svg_hspace, row + 1, 1, 1, 2)
             row = row + 1
     if self.buttons['right'].__len__() != 0:
         for button in self.buttons['right']:
             right.addWidget(button)
         if svgWidget is None:
             self.keysLayout.addLayout(right, row, 2, 1, 1)
         else:
             self.keysLayout.addLayout(right, row - 1, 3, 2, 1)
     if self.buttons['left'].__len__() != 0 or self.buttons['right'].__len__() != 0:
         row = row + 1
     if self.buttons['bottom'].__len__() != 0:
         for button in self.buttons['bottom']:
             top.addWidget(button)
         self.keysLayout.addLayout(top, row, 0, 1, col)
         row = row + 1
     resetLayout = QHBoxLayout()
     resetLayout.setAlignment(Qt.AlignRight)
     resetLayout.addWidget(self.reset)
     self.keysLayout.addLayout(resetLayout, row, col, 1, col)
예제 #3
0
class Stylus(QTabWidget, stylus_ui.Ui_StylusWidget):
    def __init__(self, parent=None):
        super(Stylus, self).__init__(parent)
        self.setupUi(self)
        self.cwd = os.path.dirname(os.path.abspath(__file__))
        self.setFocusPolicy(Qt.NoFocus)
        # put pen images in GUI
        self.penImage.setPixmap(
            QPixmap(os.path.join(self.cwd, "icons/ui/stylus_pen.png")))
        self.penImage.setScaledContents(True)
        self.eraserImage.setPixmap(
            QPixmap(os.path.join(self.cwd, "icons/ui/stylus_eraser.png")))
        self.eraserImage.setScaledContents(True)
        self.button1 = None
        self.button2 = None
        self.button3 = None
        self.pen_id = None
        self.penPressure = None
        self.penThreshold = None
        self.penTaptime = None
        self.penRawsample = None
        self.penSuppress = None
        self.penTabletPC = QCheckBox("TabletPCButton")
        self.penTabletPC.setToolTip(
            "When enabled, pen must touch screen for the stylus to work.")
        self.penTabletPC.stateChanged.connect(self.updateTabletPC)
        self.eraserPressure = None
        self.eraserThreshold = None
        self.eraserTaptime = None
        self.eraserRawsample = None
        self.eraserSuppress = None
        self.mapping = Mapping()
        self.mappingImage.setPixmap(
            QPixmap(os.path.join(self.cwd, "icons/ui/mapping.png")))
        self.penImage.setScaledContents(True)
        self.mappingToolRight.addWidget(self.mapping)
        self.penDefault.clicked.connect(self.resetPen)
        self.eraserDefault.clicked.connect(self.resetEraser)
        self.mappingDefault.clicked.connect(self.mapping.resetMapping)

    def init_pen(self, dev_id, pen):
        self.pen_id = dev_id
        self.deleteItemsOfLayout(self.penToolLeft.layout())
        self.deleteItemsOfLayout(self.penToolRight.layout())
        # TODO: button stuff
        # TODO: mapping stuff
        if 'pressurecurve' in pen.keys():
            self.penPressure = WacomPressure(dev_id, pen['pressurecurve'])
        else:
            self.penPressure = WacomPressure(dev_id)
        self.penPressure.setToolTip(
            "Set pressure curve for input pressure.\n"
            "It is composed of two anchor points (0,0 and 100,100)")
        self.penPressure.gauge.installEventFilter(self)
        if 'threshold' in pen.keys():
            self.penThreshold = WacomAttribSlider(dev_id, 'threshold', 26,
                                                  "Threshold", 0, 2047, 50,
                                                  int(pen['threshold']))
        else:
            self.penThreshold = WacomAttribSlider(dev_id, 'threshold', 26,
                                                  "Threshold", 0, 2047, 50)
        self.penThreshold.setToolTip(
            "Set  the  minimum  pressure  necessary to generate a Button event\n"
            "for the stylus tip, eraser, or touch.")
        if 'taptime' in pen.keys():
            self.penTaptime = WacomAttribSlider(dev_id, 'taptime', 250,
                                                "Double Tap Time (ms)", 0, 500,
                                                25, int(pen['taptime']))
        else:
            self.penTaptime = WacomAttribSlider(dev_id, 'taptime', 250,
                                                "Threshold", 0, 500, 25)
        self.penTaptime.setToolTip(
            "Time between taps in ms that will register as a double time")
        if 'rawsample' in pen.keys():
            self.penRawsample = WacomAttribSlider(dev_id, 'rawsample', 4,
                                                  "Sample Size", 1, 20, 4,
                                                  int(pen['rawsample']))
        else:
            self.penRawsample = WacomAttribSlider(dev_id, 'rawsample', 4,
                                                  "Sample Size", 1, 20, 4)
        self.penRawsample.setToolTip(
            "Set the sample window size (a sliding average sampling window) for\n"
            "incoming input tool raw data points.")
        if 'suppress' in pen.keys():
            self.penSuppress = WacomAttribSlider(dev_id, 'suppress', 2,
                                                 "Tilt Sensitivity", 0, 100,
                                                 10, int(pen['suppress']))
        else:
            self.penSuppress = WacomAttribSlider(dev_id, 'suppress', 2,
                                                 "Tilt Sensitivity", 0, 100,
                                                 10)
        self.penSuppress.setToolTip(
            "Set the delta (difference) cutoff level for further processing of\n"
            "incoming input tool coordinate values.")

        if 'buttons' in pen.keys():
            if 'Button2' in pen['buttons']:
                self.button2 = HotkeyWidget(dev_id, 'Button2', 'Button 2',
                                            pen['buttons']['Button2'])
            else:
                self.button2 = HotkeyWidget(dev_id, 'Button2', 'Button 2',
                                            'Default')
            if 'Button3' in pen['buttons']:
                self.button3 = HotkeyWidget(dev_id, 'Button3', 'Button 3',
                                            pen['buttons']['Button3'])
            else:
                self.button3 = HotkeyWidget(dev_id, 'Button3', 'Button 3',
                                            'Default')

        self.penToolLeft.addWidget(self.penPressure)
        self.penToolLeft.addWidget(self.penThreshold)
        self.penToolLeft.addWidget(self.penTaptime)
        self.penToolLeft.addWidget(self.penRawsample)
        spacer = QSpacerItem(20, 200, QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.penToolRight.addWidget(self.button3)
        self.penToolRight.addWidget(self.button2)
        self.penToolRight.addItem(spacer)
        self.penToolRight.addWidget(self.penSuppress)
        self.penToolRight.addWidget(self.penTabletPC)

    def init_eraser(self, dev_id, eraser):
        self.deleteItemsOfLayout(self.eraserToolLeft.layout())
        self.deleteItemsOfLayout(self.eraserToolRight.layout())
        if 'pressurecurve' in eraser.keys():
            self.eraserPressure = WacomPressure(dev_id,
                                                eraser['pressurecurve'])
        else:
            self.eraserPressure = WacomPressure(dev_id)
        self.eraserPressure.gauge.installEventFilter(self)
        self.eraserPressure.setToolTip(
            "Set pressure curve for input pressure.\n"
            "It is composed of two anchor points (0,0 and 100,100)")
        if 'threshold' in eraser.keys():
            self.eraserThreshold = WacomAttribSlider(dev_id, 'threshold', 26,
                                                     "Threshold", 0, 2047, 50,
                                                     int(eraser['threshold']))
        else:
            self.eraserThreshold = WacomAttribSlider(dev_id, 'threshold', 26,
                                                     "Threshold", 0, 2047, 50)
        self.eraserThreshold.setToolTip(
            "Set  the  minimum  pressure  necessary to generate a Button event\n"
            "for the stylus tip, eraser, or touch.")
        if 'taptime' in eraser.keys():
            self.eraserTaptime = WacomAttribSlider(dev_id, 'taptime', 250,
                                                   "Double Tap Time (ms)", 0,
                                                   500, 25,
                                                   int(eraser['taptime']))
        else:
            self.eraserTaptime = WacomAttribSlider(dev_id, 'taptime', 250,
                                                   "Threshold", 0, 500, 25)
        self.eraserTaptime.setToolTip(
            "Time between taps in ms that will register as a double time")
        if 'rawsample' in eraser.keys():
            self.eraserRawsample = WacomAttribSlider(dev_id, 'rawsample', 4,
                                                     "Sample Size", 1, 20, 4,
                                                     int(eraser['rawsample']))
        else:
            self.eraserRawsample = WacomAttribSlider(dev_id, 'rawsample', 4,
                                                     "Sample Size", 1, 20, 4)
        self.eraserRawsample.setToolTip(
            "Set the sample window size (a sliding average sampling window) for\n"
            "incoming input tool raw data points.")
        if 'suppress' in eraser.keys():
            self.eraserSuppress = WacomAttribSlider(dev_id, 'suppress', 2,
                                                    "Tilt Sensitivity", 0,
                                                    100, 10,
                                                    int(eraser['suppress']))
        else:
            self.eraserSuppress = WacomAttribSlider(dev_id, 'suppress', 2,
                                                    "Tilt Sensitivity", 0, 100,
                                                    10)
        self.eraserSuppress.setToolTip(
            "Set the delta (difference) cutoff level for further processing of\n"
            "incoming input tool coordinate values.")
        if 'buttons' in eraser.keys():
            if 'Button1' in eraser['buttons']:
                self.button1 = HotkeyWidget(dev_id, 'Button1', 'Button 1',
                                            eraser['buttons']['Button1'])
            else:
                self.button1 = HotkeyWidget(dev_id, 'Button1', 'Button 1',
                                            'Default')

        self.eraserToolLeft.addWidget(self.eraserPressure)
        self.eraserToolLeft.addWidget(self.eraserThreshold)
        self.eraserToolLeft.addWidget(self.eraserTaptime)
        self.eraserToolLeft.addWidget(self.eraserRawsample)
        spacer = QSpacerItem(20, 200, QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.eraserToolRight.addWidget(self.button1)
        self.eraserToolRight.addItem(spacer)
        self.eraserToolRight.addWidget(self.eraserSuppress)

    def updateTabletPC(self):
        if self.penTabletPC.isChecked():
            cmd = "xsetwacom --set %s TabletPCButton on" % self.pen_id
            os.popen(cmd)
            return ('tabletpcbutton', 'on')
        else:
            cmd = "xsetwacom --set %s TabletPCButton off" % self.pen_id
            os.popen(cmd)
            return ('tabletpcbutton', 'off')

    def deleteItemsOfLayout(self, layout):
        if layout is not None:
            while layout.count():
                item = layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.setParent(None)
                else:
                    self.deleteItemsOfLayout(item.layout())

    def boxdelete(self, box):
        for i in range(self.keys.count()):
            layout_item = self.keys.itemAt(i)
            if layout_item.layout() == box:
                self.deleteItemsOfLayout(layout_item.layout())
                self.vlayout.removeItem(layout_item)
                break

    def resetPen(self):
        self.button2.reset()
        self.button3.reset()
        self.penPressure.set_defaults()
        self.penThreshold.set_defaults()
        self.penTaptime.set_defaults()
        self.penRawsample.set_defaults()
        self.penSuppress.set_defaults()
        self.penTabletPC.setChecked(False)
        self.updateTabletPC()

    def resetEraser(self):
        self.button1.reset()
        self.eraserPressure.set_defaults()
        self.eraserThreshold.set_defaults()
        self.eraserTaptime.set_defaults()
        self.eraserRawsample.set_defaults()
        self.eraserSuppress.set_defaults()

    def eventFilter(self, source, event):
        if event.type() == QEvent.TabletMove:
            if event.pointerType() == 1:
                self.penPressure.update_gauge(event.pressure())
                return True
            elif event.pointerType() == 3:
                self.eraserPressure.update_gauge(event.pressure())
                return True
        return False

    def get_config(self):
        data = {'stylus': {'buttons': {}}, 'eraser': {'buttons': {}}}
        data['stylus']['pressurecurve'] = self.penPressure.setting
        (attr, value) = self.penSuppress.get_setting()
        data['stylus'][attr] = str(value)
        (attr, value) = self.penSuppress.get_setting()
        data['stylus'][attr] = str(value)
        (attr, value) = self.penRawsample.get_setting()
        data['stylus'][attr] = str(value)
        (attr, value) = self.penThreshold.get_setting()
        data['stylus'][attr] = str(value)
        (attr, value) = self.penTaptime.get_setting()
        data['stylus'][attr] = str(value)
        data['stylus']['mapping'] = self.mapping.settings
        (attr, value) = self.updateTabletPC()
        data['stylus'][attr] = str(value)
        data['eraser']['pressurecurve'] = self.eraserPressure.setting
        (attr, value) = self.eraserSuppress.get_setting()
        data['eraser'][attr] = str(value)
        (attr, value) = self.eraserRawsample.get_setting()
        data['eraser'][attr] = str(value)
        (attr, value) = self.eraserThreshold.get_setting()
        data['eraser'][attr] = str(value)
        (attr, value) = self.eraserTaptime.get_setting()
        data['eraser'][attr] = str(value)
        # buttons
        info = list(self.button1.button.get_button_cmd())
        if info[2] == '1':
            data['eraser']['buttons'][info[0]] = 'Default'
        else:
            data['eraser']['buttons'][info[0]] = info[2]
        info = list(self.button2.button.get_button_cmd())
        if info[2] == '2':
            data['stylus']['buttons'][info[0]] = 'Default'
        else:
            data['stylus']['buttons'][info[0]] = info[2]
        info = list(self.button3.button.get_button_cmd())
        if info[2] == '3':
            data['stylus']['buttons'][info[0]] = 'Default'
        else:
            data['stylus']['buttons'][info[0]] = info[2]
        return data
예제 #4
0
파일: stylus.py 프로젝트: tb2097/wacom-gui
class Stylus(QTabWidget, stylus_ui.Ui_StylusWidget):
    def __init__(self, parent = None):
        super(Stylus, self).__init__(parent)
        self.setupUi(self)
        self.cwd = os.path.dirname(os.path.abspath(__file__))
        self.setFocusPolicy(Qt.NoFocus)
        # put pen images in GUI
        self.penImage.setPixmap(QPixmap(os.path.join(self.cwd, "icons/ui/stylus_pen.png")))
        self.penImage.setScaledContents(True)
        self.eraserImage.setPixmap(QPixmap(os.path.join(self.cwd,"icons/ui/stylus_eraser.png")))
        self.eraserImage.setScaledContents(True)
        self.button1 = None
        self.button2 = None
        self.button3 = None
        self.pen_id = None
        self.penPressure = None
        self.penThreshold = None
        self.penTaptime = None
        self.penRawsample = None
        self.penSuppress = None
        self.penTabletPC = QCheckBox("TabletPCButton")
        self.penTabletPC.setToolTip("When enabled, pen must touch screen for the stylus to work.")
        self.penTabletPC.stateChanged.connect(self.updateTabletPC)
        self.eraserPressure = None
        self.eraserThreshold = None
        self.eraserTaptime = None
        self.eraserRawsample = None
        self.eraserSuppress = None
        self.mapping = Mapping()
        self.mappingImage.setPixmap(QPixmap(os.path.join(self.cwd, "icons/ui/mapping.png")))
        self.penImage.setScaledContents(True)
        self.mappingToolRight.addWidget(self.mapping)
        self.penDefault.clicked.connect(self.resetPen)
        self.eraserDefault.clicked.connect(self.resetEraser)
        self.mappingDefault.clicked.connect(self.mapping.resetMapping)

    def init_pen(self, dev_id, pen):
        self.pen_id = dev_id
        self.deleteItemsOfLayout(self.penToolLeft.layout())
        self.deleteItemsOfLayout(self.penToolRight.layout())
    # TODO: button stuff
    # TODO: mapping stuff
        if 'pressurecurve' in pen.keys():
            self.penPressure = WacomPressure(dev_id, pen['pressurecurve'])
        else:
            self.penPressure = WacomPressure(dev_id)
        self.penPressure.setToolTip("Set pressure curve for input pressure.\n"
                                       "It is composed of two anchor points (0,0 and 100,100)")
        self.penPressure.gauge.installEventFilter(self)
        if 'threshold' in pen.keys():
            self.penThreshold = WacomAttribSlider(dev_id, 'threshold', 26, "Threshold", 0, 2047, 50,
                                                  int(pen['threshold']))
        else:
            self.penThreshold = WacomAttribSlider(dev_id, 'threshold', 26, "Threshold", 0, 2047, 50)
        self.penThreshold.setToolTip("Set  the  minimum  pressure  necessary to generate a Button event\n"
                                     "for the stylus tip, eraser, or touch.")
        if 'taptime' in pen.keys():
            self.penTaptime = WacomAttribSlider(dev_id, 'taptime', 250, "Double Tap Time (ms)", 0, 500, 25,
                                                int(pen['taptime']))
        else:
            self.penTaptime = WacomAttribSlider(dev_id, 'taptime', 250, "Threshold", 0, 500, 25)
        self.penTaptime.setToolTip("Time between taps in ms that will register as a double time")
        if 'rawsample' in pen.keys():
            self.penRawsample = WacomAttribSlider(dev_id, 'rawsample', 4, "Sample Size", 1, 20, 4,
                                                  int(pen['rawsample']))
        else:
            self.penRawsample = WacomAttribSlider(dev_id, 'rawsample', 4, "Sample Size", 1, 20, 4)
        self.penRawsample.setToolTip("Set the sample window size (a sliding average sampling window) for\n"
                                     "incoming input tool raw data points.")
        if 'suppress' in pen.keys():
            self.penSuppress = WacomAttribSlider(dev_id, 'suppress', 2, "Tilt Sensitivity", 0, 100, 10,
                                                  int(pen['suppress']))
        else:
            self.penSuppress = WacomAttribSlider(dev_id, 'suppress', 2, "Tilt Sensitivity", 0, 100, 10)
        self.penSuppress.setToolTip("Set the delta (difference) cutoff level for further processing of\n"
                                    "incoming input tool coordinate values.")

        if 'buttons' in pen.keys():
            if 'Button2' in pen['buttons']:
                self.button2 = HotkeyWidget(dev_id, 'Button2', 'Button 2', pen['buttons']['Button2'])
            else:
                self.button2 = HotkeyWidget(dev_id, 'Button2', 'Button 2', 'Default')
            if 'Button3' in pen['buttons']:
                self.button3 = HotkeyWidget(dev_id, 'Button3', 'Button 3', pen['buttons']['Button3'])
            else:
                self.button3 = HotkeyWidget(dev_id, 'Button3', 'Button 3', 'Default')

        self.penToolLeft.addWidget(self.penPressure)
        self.penToolLeft.addWidget(self.penThreshold)
        self.penToolLeft.addWidget(self.penTaptime)
        self.penToolLeft.addWidget(self.penRawsample)
        spacer = QSpacerItem(20, 200, QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.penToolRight.addWidget(self.button3)
        self.penToolRight.addWidget(self.button2)
        self.penToolRight.addItem(spacer)
        self.penToolRight.addWidget(self.penSuppress)
        self.penToolRight.addWidget(self.penTabletPC)

    def init_eraser(self, dev_id, eraser):
        self.deleteItemsOfLayout(self.eraserToolLeft.layout())
        self.deleteItemsOfLayout(self.eraserToolRight.layout())
        if 'pressurecurve' in eraser.keys():
            self.eraserPressure = WacomPressure(dev_id, eraser['pressurecurve'])
        else:
            self.eraserPressure = WacomPressure(dev_id)
        self.eraserPressure.gauge.installEventFilter(self)
        self.eraserPressure.setToolTip("Set pressure curve for input pressure.\n"
                                       "It is composed of two anchor points (0,0 and 100,100)")
        if 'threshold' in eraser.keys():
            self.eraserThreshold = WacomAttribSlider(dev_id, 'threshold', 26, "Threshold", 0, 2047, 50,
                                                  int(eraser['threshold']))
        else:
            self.eraserThreshold = WacomAttribSlider(dev_id, 'threshold', 26, "Threshold", 0, 2047, 50)
        self.eraserThreshold.setToolTip("Set  the  minimum  pressure  necessary to generate a Button event\n"
                                     "for the stylus tip, eraser, or touch.")
        if 'taptime' in eraser.keys():
            self.eraserTaptime = WacomAttribSlider(dev_id, 'taptime', 250, "Double Tap Time (ms)", 0, 500, 25,
                                                int(eraser['taptime']))
        else:
            self.eraserTaptime = WacomAttribSlider(dev_id, 'taptime', 250, "Threshold", 0, 500, 25)
        self.eraserTaptime.setToolTip("Time between taps in ms that will register as a double time")
        if 'rawsample' in eraser.keys():
            self.eraserRawsample = WacomAttribSlider(dev_id, 'rawsample', 4, "Sample Size", 1, 20, 4,
                                                  int(eraser['rawsample']))
        else:
            self.eraserRawsample = WacomAttribSlider(dev_id, 'rawsample', 4, "Sample Size", 1, 20, 4)
        self.eraserRawsample.setToolTip("Set the sample window size (a sliding average sampling window) for\n"
                                     "incoming input tool raw data points.")
        if 'suppress' in eraser.keys():
            self.eraserSuppress = WacomAttribSlider(dev_id, 'suppress', 2, "Tilt Sensitivity", 0, 100, 10,
                                                  int(eraser['suppress']))
        else:
            self.eraserSuppress = WacomAttribSlider(dev_id, 'suppress', 2, "Tilt Sensitivity", 0, 100, 10)
        self.eraserSuppress.setToolTip("Set the delta (difference) cutoff level for further processing of\n"
                                    "incoming input tool coordinate values.")
        if 'buttons' in eraser.keys():
            if 'Button1' in eraser['buttons']:
                self.button1 = HotkeyWidget(dev_id, 'Button1', 'Button 1', eraser['buttons']['Button1'])
            else:
                self.button1 = HotkeyWidget(dev_id, 'Button1', 'Button 1', 'Default')

        self.eraserToolLeft.addWidget(self.eraserPressure)
        self.eraserToolLeft.addWidget(self.eraserThreshold)
        self.eraserToolLeft.addWidget(self.eraserTaptime)
        self.eraserToolLeft.addWidget(self.eraserRawsample)
        spacer = QSpacerItem(20, 200, QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.eraserToolRight.addWidget(self.button1)
        self.eraserToolRight.addItem(spacer)
        self.eraserToolRight.addWidget(self.eraserSuppress)

    def updateTabletPC(self):
        if self.penTabletPC.isChecked():
            cmd = "xsetwacom --set %s TabletPCButton on" % self.pen_id
            os.popen(cmd)
            return ('tabletpcbutton', 'on')
        else:
            cmd = "xsetwacom --set %s TabletPCButton off" % self.pen_id
            os.popen(cmd)
            return ('tabletpcbutton', 'off')

    def deleteItemsOfLayout(self, layout):
        if layout is not None:
            while layout.count():
                item = layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.setParent(None)
                else:
                    self.deleteItemsOfLayout(item.layout())

    def boxdelete(self, box):
        for i in range(self.keys.count()):
            layout_item = self.keys.itemAt(i)
            if layout_item.layout() == box:
                self.deleteItemsOfLayout(layout_item.layout())
                self.vlayout.removeItem(layout_item)
                break

    def resetPen(self):
        self.button2.reset()
        self.button3.reset()
        self.penPressure.set_defaults()
        self.penThreshold.set_defaults()
        self.penTaptime.set_defaults()
        self.penRawsample.set_defaults()
        self.penSuppress.set_defaults()
        self.penTabletPC.setChecked(False)
        self.updateTabletPC()

    def resetEraser(self):
        self.button1.reset()
        self.eraserPressure.set_defaults()
        self.eraserThreshold.set_defaults()
        self.eraserTaptime.set_defaults()
        self.eraserRawsample.set_defaults()
        self.eraserSuppress.set_defaults()

    def eventFilter(self, source, event):
        if event.type() == QEvent.TabletMove:
            if event.pointerType() == 1:
                self.penPressure.update_gauge(event.pressure())
                return True
            elif event.pointerType() == 3:
                self.eraserPressure.update_gauge(event.pressure())
                return True
        return False

    def get_config(self):
        data = {'stylus': {'buttons': {}}, 'eraser': {'buttons': {}}}
        data['stylus']['pressurecurve'] = self.penPressure.setting
        (attr, value) = self.penSuppress.get_setting()
        data['stylus'][attr] = str(value)
        (attr, value) = self.penSuppress.get_setting()
        data['stylus'][attr] = str(value)
        (attr, value) = self.penRawsample.get_setting()
        data['stylus'][attr] = str(value)
        (attr, value) = self.penThreshold.get_setting()
        data['stylus'][attr] = str(value)
        (attr, value) = self.penTaptime.get_setting()
        data['stylus'][attr] = str(value)
        data['stylus']['mapping'] = self.mapping.settings
        (attr, value) = self.updateTabletPC()
        data['stylus'][attr] = str(value)
        data['eraser']['pressurecurve'] = self.eraserPressure.setting
        (attr, value) = self.eraserSuppress.get_setting()
        data['eraser'][attr] = str(value)
        (attr, value) = self.eraserRawsample.get_setting()
        data['eraser'][attr] = str(value)
        (attr, value) = self.eraserThreshold.get_setting()
        data['eraser'][attr] = str(value)
        (attr, value) = self.eraserTaptime.get_setting()
        data['eraser'][attr] = str(value)
        # buttons
        info = list(self.button1.button.get_button_cmd())
        if info[2] == '1':
            data['eraser']['buttons'][info[0]] = 'Default'
        else:
            data['eraser']['buttons'][info[0]] = info[2]
        info = list(self.button2.button.get_button_cmd())
        if info[2] == '2':
            data['stylus']['buttons'][info[0]] = 'Default'
        else:
            data['stylus']['buttons'][info[0]] = info[2]
        info = list(self.button3.button.get_button_cmd())
        if info[2] == '3':
            data['stylus']['buttons'][info[0]] = 'Default'
        else:
            data['stylus']['buttons'][info[0]] = info[2]
        return data