This commit is contained in:
Ricky Brent 2021-03-07 21:53:24 -05:00 committed by GitHub
commit 08ffd70097
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 360 additions and 15 deletions

View File

@ -149,9 +149,10 @@ class Buffer(QtCore.QObject):
bufferInput = qt_compat.Signal(str, str) bufferInput = qt_compat.Signal(str, str)
def __init__(self, data={}): def __init__(self, data={}, config=False):
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self)
self.data = data self.data = data
self.config = config
self.nicklist = {} self.nicklist = {}
self.widget = BufferWidget(display_nicklist=self.data.get('nicklist', self.widget = BufferWidget(display_nicklist=self.data.get('nicklist',
0)) 0))
@ -183,6 +184,14 @@ class Buffer(QtCore.QObject):
if self.data: if self.data:
self.bufferInput.emit(self.data['full_name'], text) self.bufferInput.emit(self.data['full_name'], text)
def update_config(self):
"""Match visibility to configuration, faster than a nicklist refresh"""
if (self.config):
nicklist_visible = self.config.get("look", "nicklist") != "off"
topic_visible = self.config.get("look", "topic") != "off"
self.widget.nicklist.setVisible(nicklist_visible)
self.widget.title.setVisible(topic_visible)
def nicklist_add_item(self, parent, group, prefix, name, visible): def nicklist_add_item(self, parent, group, prefix, name, visible):
"""Add a group/nick in nicklist.""" """Add a group/nick in nicklist."""
if group: if group:
@ -245,4 +254,8 @@ class Buffer(QtCore.QObject):
icon = QtGui.QIcon(pixmap) icon = QtGui.QIcon(pixmap)
item = QtGui.QListWidgetItem(icon, nick['name']) item = QtGui.QListWidgetItem(icon, nick['name'])
self.widget.nicklist.addItem(item) self.widget.nicklist.addItem(item)
self.widget.nicklist.setVisible(True) if self.config and self.config.get("look",
"nicklist") == "off":
self.widget.nicklist.setVisible(False)
else:
self.widget.nicklist.setVisible(True)

View File

@ -36,6 +36,12 @@ CONFIG_DEFAULT_OPTIONS = (('relay.server', ''),
('relay.autoconnect', 'off'), ('relay.autoconnect', 'off'),
('relay.lines', str(CONFIG_DEFAULT_RELAY_LINES)), ('relay.lines', str(CONFIG_DEFAULT_RELAY_LINES)),
('look.debug', 'off'), ('look.debug', 'off'),
('look.style', ''),
('look.buffer_list', 'left'),
('look.nicklist', 'on'),
('look.toolbar', 'on'),
('look.menubar', 'on'),
('look.topic', 'on'),
('look.statusbar', 'off')) ('look.statusbar', 'off'))
# Default colors for WeeChat color options (option name, #rgb value) # Default colors for WeeChat color options (option name, #rgb value)

199
qweechat/preferences.py Normal file
View File

@ -0,0 +1,199 @@
# -*- coding: utf-8 -*-
#
# preferences.py - preferences dialog box
#
# Copyright (C) 2016 Ricky Brent <ricky@rickybrent.com>
#
# This file is part of QWeeChat, a Qt remote GUI for WeeChat.
#
# QWeeChat is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# QWeeChat is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with QWeeChat. If not, see <http://www.gnu.org/licenses/>.
#
import qt_compat
import config
QtCore = qt_compat.import_module('QtCore')
QtGui = qt_compat.import_module('QtGui')
class PreferencesDialog(QtGui.QDialog):
"""Preferences dialog."""
def __init__(self, name, parent, *args):
QtGui.QDialog.__init__(*(self,) + args)
self.setModal(True)
self.setWindowTitle(name)
self.parent = parent
self.config = parent.config
self.stacked_panes = QtGui.QStackedWidget()
self.list_panes = PreferencesTreeWidget("Settings")
splitter = QtGui.QSplitter()
splitter.addWidget(self.list_panes)
splitter.addWidget(self.stacked_panes)
# Follow same order as defaults:
section_panes = {}
for section in self.config.sections():
item = QtGui.QTreeWidgetItem(section)
item.setText(0, section)
section_panes[section] = PreferencesPaneWidget(section)
self.list_panes.addTopLevelItem(item)
self.stacked_panes.addWidget(section_panes[section])
for setting, default in config.CONFIG_DEFAULT_OPTIONS:
section, key = setting.split(".")
section_panes[section].addItem(key, self.config.get(section, key))
for key, value in self.config.items("color"):
section_panes["color"].addItem(key, value)
self.list_panes.currentItemChanged.connect(self._pane_switch)
self.list_panes.setCurrentItem(self.list_panes.topLevelItem(0))
hbox = QtGui.QHBoxLayout()
self.dialog_buttons = QtGui.QDialogButtonBox()
self.dialog_buttons.setStandardButtons(
QtGui.QDialogButtonBox.Save | QtGui.QDialogButtonBox.Cancel)
self.dialog_buttons.rejected.connect(self.close)
self.dialog_buttons.accepted.connect(self._save_and_close)
hbox.addStretch(1)
hbox.addWidget(self.dialog_buttons)
hbox.addStretch(1)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(splitter)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.show()
def _pane_switch(self, item):
"""Switch the visible preference pane."""
index = self.list_panes.indexOfTopLevelItem(item)
if index >= 0:
self.stacked_panes.setCurrentIndex(index)
def _save_and_close(self):
for widget in (self.stacked_panes.widget(i)
for i in range(self.stacked_panes.count())):
for key, field in widget.fields.items():
if isinstance(field, QtGui.QComboBox):
text = field.itemText(field.currentIndex())
elif isinstance(field, QtGui.QCheckBox):
text = "on" if field.isChecked() else "off"
else:
text = field.text()
self.config.set(widget.section_name, key, str(text))
config.write(self.config)
self.parent.apply_preferences()
self.close()
class PreferencesTreeWidget(QtGui.QTreeWidget):
"""Widget with tree list of preferences."""
def __init__(self, header_label, *args):
QtGui.QTreeWidget.__init__(*(self,) + args)
self.setHeaderLabel(header_label)
self.setRootIsDecorated(False)
self.setMaximumWidth(90)
self.setTextElideMode(QtCore.Qt.ElideNone)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setFocusPolicy(QtCore.Qt.NoFocus)
class PreferencesColorEdit(QtGui.QPushButton):
"""Simple color square that changes based on the color selected."""
def __init__(self, *args):
QtGui.QPushButton.__init__(*(self,) + args)
self.color = "#000000"
self.clicked.connect(self._color_picker)
# Some of the configured colors use a astrisk prefix.
# Toggle this on right click.
self.star = False
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self._color_star)
def insert(self, color):
"""Insert the desired color for the widget."""
if color[:1] == "*":
self.star = True
color = color[1:]
self.setText("*" if self.star else "")
self.color = color
self.setStyleSheet("background-color: " + color)
def text(self):
"""Returns the hex value of the color."""
return ("*" if self.star else "") + self.color
def _color_picker(self):
color = QtGui.QColorDialog.getColor()
self.insert(color.name())
def _color_star(self):
self.star = not self.star
self.insert(self.text())
class PreferencesPaneWidget(QtGui.QWidget):
"""
Widget with (from top to bottom):
title, chat + nicklist (optional) + prompt/input.
"""
def __init__(self, section_name):
QtGui.QWidget.__init__(self)
self.grid = QtGui.QGridLayout()
self.grid.setAlignment(QtCore.Qt.AlignTop)
self.section_name = section_name
self.fields = {}
self.setLayout(self.grid)
self.grid.setColumnStretch(2, 1)
self.grid.setSpacing(10)
self.checkboxes = ("ssl", "autoconnect", "statusbar", "topic",
"menubar", "toolbar", "nicklist", "debug")
self.comboboxes = {"style": QtGui.QStyleFactory.keys(),
"buffer_list": ["left", "right"]}
def addItem(self, key, value):
"""Add a key-value pair."""
line = len(self.fields)
name = key.capitalize().replace("_", " ")
start = 0
if self.section_name == "color":
start = 2 * (line % 2)
line = line // 2
self.grid.addWidget(QtGui.QLabel(name), line, start + 0)
if self.section_name == "color":
edit = PreferencesColorEdit()
edit.setFixedWidth(edit.sizeHint().height())
edit.insert(value)
elif key in self.comboboxes.keys():
edit = QtGui.QComboBox()
edit.addItems(self.comboboxes[key])
edit.setCurrentIndex(edit.findText(value))
edit.setFixedWidth(200)
elif key in self.checkboxes:
edit = QtGui.QCheckBox()
edit.setChecked(value == "on")
else:
edit = QtGui.QLineEdit()
edit.setFixedWidth(200)
edit.insert(value)
if key == 'password':
edit.setEchoMode(QtGui.QLineEdit.Password)
self.grid.addWidget(edit, line, start + 1)
self.fields[key] = edit

View File

@ -29,7 +29,10 @@ except ImportError:
def _pyside_import_module(moduleName): def _pyside_import_module(moduleName):
pyside = __import__('PySide', globals(), locals(), [moduleName], -1) pyside = __import__('PySide', globals(), locals(), [moduleName], -1)
return getattr(pyside, moduleName) mod = getattr(pyside, moduleName)
if moduleName == "QtGui":
mod.QWIDGETSIZE_MAX = ((1 << 24) - 1)
return mod
def _pyqt4_import_module(moduleName): def _pyqt4_import_module(moduleName):

View File

@ -44,6 +44,7 @@ from connection import ConnectionDialog
from buffer import BufferListWidget, Buffer from buffer import BufferListWidget, Buffer
from debug import DebugDialog from debug import DebugDialog
from about import AboutDialog from about import AboutDialog
from preferences import PreferencesDialog
from version import qweechat_version from version import qweechat_version
QtCore = qt_compat.import_module('QtCore') QtCore = qt_compat.import_module('QtCore')
@ -91,14 +92,11 @@ class MainWindow(QtGui.QMainWindow):
self.stacked_buffers.addWidget(self.buffers[0].widget) self.stacked_buffers.addWidget(self.buffers[0].widget)
# splitter with buffers + chat/input # splitter with buffers + chat/input
splitter = QtGui.QSplitter() self.splitter = QtGui.QSplitter()
splitter.addWidget(self.list_buffers) self.splitter.addWidget(self.list_buffers)
splitter.addWidget(self.stacked_buffers) self.splitter.addWidget(self.stacked_buffers)
self.setCentralWidget(splitter) self.setCentralWidget(self.splitter)
if self.config.getboolean('look', 'statusbar'):
self.statusBar().visible = True
# actions for menu and toolbar # actions for menu and toolbar
actions_def = { actions_def = {
@ -124,6 +122,27 @@ class MainWindow(QtGui.QMainWindow):
'application-exit.png', 'Quit application', 'application-exit.png', 'Quit application',
'Ctrl+Q', self.close], 'Ctrl+Q', self.close],
} }
# toggleable actions
self.toggles_def = {
'show menubar': [
'look.menubar', 'Show Menubar',
'Ctrl+M', self.toggle_menubar],
'show toolbar': [
'look.toolbar', 'Show Toolbar',
False, self.toggle_toolbar],
'show status bar': [
'look.statusbar', 'Show Status Bar',
False, self.toggle_statusbar],
'show topic': [
'look.topic', 'Show Topic',
False, self.toggle_topic],
'show nick list': [
'look.nicklist', 'Show Nick List',
'Ctrl+F7', self.toggle_nicklist],
'fullscreen': [
False, 'Fullscreen',
'F11', self.toggle_fullscreen],
}
self.actions = {} self.actions = {}
for name, action in list(actions_def.items()): for name, action in list(actions_def.items()):
self.actions[name] = QtGui.QAction( self.actions[name] = QtGui.QAction(
@ -133,6 +152,13 @@ class MainWindow(QtGui.QMainWindow):
self.actions[name].setStatusTip(action[1]) self.actions[name].setStatusTip(action[1])
self.actions[name].setShortcut(action[2]) self.actions[name].setShortcut(action[2])
self.actions[name].triggered.connect(action[3]) self.actions[name].triggered.connect(action[3])
for name, action in list(self.toggles_def.items()):
self.actions[name] = QtGui.QAction(name.capitalize(), self)
self.actions[name].setStatusTip(action[1])
self.actions[name].setCheckable(True)
if action[2]:
self.actions[name].setShortcut(action[2])
self.actions[name].triggered.connect(action[3])
# menu # menu
self.menu = self.menuBar() self.menu = self.menuBar()
@ -142,6 +168,15 @@ class MainWindow(QtGui.QMainWindow):
self.actions['preferences'], self.actions['preferences'],
self.actions['save connection'], self.actions['save connection'],
self.actions['quit']]) self.actions['quit']])
menu_view = self.menu.addMenu('&View')
menu_view.addActions([self.actions['show menubar'],
self.actions['show toolbar'],
self.actions['show status bar'],
self._actions_separator(),
self.actions['show topic'],
self.actions['show nick list'],
self._actions_separator(),
self.actions['fullscreen']])
menu_window = self.menu.addMenu('&Window') menu_window = self.menu.addMenu('&Window')
menu_window.addAction(self.actions['debug']) menu_window.addAction(self.actions['debug'])
menu_help = self.menu.addMenu('&Help') menu_help = self.menu.addMenu('&Help')
@ -159,12 +194,20 @@ class MainWindow(QtGui.QMainWindow):
# toolbar # toolbar
toolbar = self.addToolBar('toolBar') toolbar = self.addToolBar('toolBar')
toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
toolbar.setMovable(False)
toolbar.addActions([self.actions['connect'], toolbar.addActions([self.actions['connect'],
self.actions['disconnect'], self.actions['disconnect'],
self.actions['debug'], self.actions['debug'],
self.actions['preferences'], self.actions['preferences'],
self.actions['about'], self.actions['about'],
self.actions['quit']]) self.actions['quit']])
self.toolbar = toolbar
# Override context menu for both -- default is a simple menubar toggle.
self.menu.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.toolbar.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.menu.customContextMenuRequested.connect(self._menu_context)
self.toolbar.customContextMenuRequested.connect(self._menu_context)
self.buffers[0].widget.input.setFocus() self.buffers[0].widget.input.setFocus()
@ -180,9 +223,60 @@ class MainWindow(QtGui.QMainWindow):
'ssl'), 'ssl'),
self.config.get('relay', 'password'), self.config.get('relay', 'password'),
self.config.get('relay', 'lines')) self.config.get('relay', 'lines'))
self.apply_preferences()
self.show() self.show()
def _actions_separator(self):
"""Create a new QAction separator."""
sep = QtGui.QAction("", self)
sep.setSeparator(True)
return sep
def apply_preferences(self):
"""Apply non-server options from preferences."""
app = QtCore.QCoreApplication.instance()
if self.config.getboolean('look', 'toolbar'):
self.toolbar.show()
else:
self.toolbar.hide()
# Change the height to avoid losing all hotkeys:
if self.config.getboolean('look', 'menubar'):
self.menu.setMaximumHeight(QtGui.QWIDGETSIZE_MAX)
else:
self.menu.setFixedHeight(1)
# Apply the selected qt style here so it will update without a restart
if self.config.get('look', 'style'):
app.setStyle(QtGui.QStyleFactory.create(
self.config.get('look', 'style')))
# Statusbar:
if self.config.getboolean('look', 'statusbar'):
self.statusBar().show()
else:
self.statusBar().hide()
# Move the buffer list / main buffer view:
if self.config.get('look', 'buffer_list') == 'right':
self.splitter.insertWidget(1, self.list_buffers)
else:
self.splitter.insertWidget(1, self.stacked_buffers)
# Update visibility of all nicklists/topics:
for buffer in self.buffers:
buffer.update_config()
# Update toggle state for menubar:
for name, action in list(self.toggles_def.items()):
if action[0]:
ac = action[0].split(".")
toggle = self.config.get(ac[0], ac[1])
self.actions[name].setChecked(toggle == "on")
def _menu_context(self, event):
"""Show a slightly nicer context menu for the menu/toolbar."""
menu = QtGui.QMenu()
menu.addActions([self.actions['show menubar'],
self.actions['show toolbar'],
self.actions['show status bar']])
menu.exec_(self.mapToGlobal(event))
def _buffer_switch(self, index): def _buffer_switch(self, index):
"""Switch to a buffer.""" """Switch to a buffer."""
if index >= 0: if index >= 0:
@ -198,10 +292,7 @@ class MainWindow(QtGui.QMainWindow):
def open_preferences_dialog(self): def open_preferences_dialog(self):
"""Open a dialog with preferences.""" """Open a dialog with preferences."""
# TODO: implement the preferences dialog box self.preferences_dialog = PreferencesDialog('Preferences', self)
messages = ['Not yet implemented!',
'']
self.preferences_dialog = AboutDialog('Preferences', messages, self)
def save_connection(self): def save_connection(self):
"""Save connection configuration.""" """Save connection configuration."""
@ -266,6 +357,39 @@ class MainWindow(QtGui.QMainWindow):
self.connection_dialog.dialog_buttons.accepted.connect( self.connection_dialog.dialog_buttons.accepted.connect(
self.connect_weechat) self.connect_weechat)
def toggle_setting(self, section, option):
"""Toggles any boolean setting."""
val = self.config.getboolean(section, option)
self.config.set(section, option, "off" if val else "on")
self.apply_preferences()
def toggle_menubar(self):
"""Toggle menubar."""
self.toggle_setting('look', 'menubar')
def toggle_toolbar(self):
"""Toggle toolbar."""
self.toggle_setting('look', 'toolbar')
def toggle_statusbar(self):
"""Toggle statusbar."""
self.toggle_setting('look', 'statusbar')
def toggle_topic(self):
"""Toggle topic."""
self.toggle_setting('look', 'topic')
def toggle_nicklist(self):
"""Toggle nicklist."""
self.toggle_setting('look', 'nicklist')
def toggle_fullscreen(self):
"""Toggle fullscreen."""
if self.isFullScreen():
self.showNormal()
else:
self.showFullScreen()
def connect_weechat(self): def connect_weechat(self):
"""Connect to WeeChat.""" """Connect to WeeChat."""
self.network.connect_weechat( self.network.connect_weechat(
@ -498,7 +622,7 @@ class MainWindow(QtGui.QMainWindow):
def create_buffer(self, item): def create_buffer(self, item):
"""Create a new buffer.""" """Create a new buffer."""
buf = Buffer(item) buf = Buffer(item, self.config)
buf.bufferInput.connect(self.buffer_input) buf.bufferInput.connect(self.buffer_input)
buf.widget.input.bufferSwitchPrev.connect( buf.widget.input.bufferSwitchPrev.connect(
self.list_buffers.switch_prev_buffer) self.list_buffers.switch_prev_buffer)