https://github.com/minorua/Qgis2threejs
Revision a7dae9ee88e9a7d13e61bbbe0b5447e2d69e5b9d authored by Minoru Akagi on 17 October 2018, 02:07:40 UTC, committed by Minoru Akagi on 17 October 2018, 04:49:38 UTC
1 parent 22f473b
Tip revision: a7dae9ee88e9a7d13e61bbbe0b5447e2d69e5b9d authored by Minoru Akagi on 17 October 2018, 02:07:40 UTC
update wiki URL
update wiki URL
Tip revision: a7dae9e
stylewidget.py
# -*- coding: utf-8 -*-
"""
/***************************************************************************
Qgis2threejs
A QGIS plugin
export terrain data, map canvas image and vector data to web browser
-------------------
begin : 2014-01-06
copyright : (C) 2014 Minoru Akagi
email : akaginch@gmail.com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
import os
from PyQt5.Qt import QEvent, Qt
from PyQt5.QtCore import QDir, QObject, QVariant
from PyQt5.QtWidgets import QColorDialog, QComboBox, QDialog, QDialogButtonBox, QFileDialog, QVBoxLayout, QWidget
from PyQt5.QtGui import QColor
from qgis.core import QgsFieldProxyModel, QgsProject
from qgis.gui import QgsCompoundColorWidget
from .ui.widgetComboEdit import Ui_ComboEditWidget
from .qgis2threejstools import getDEMLayersInProject, logMessage, shortTextFromSelectedLayerIds
class WidgetFuncBase:
def __init__(self, widget):
self.widget = widget
def setup(self, name, editLabel="", lineEdit="", placeholderText="", toolButton=False, checkBox=False):
# initialize widgets
self.widget.label_1.setText(name)
if editLabel:
self.widget.label_2.setText(editLabel)
self.widget.label_2.setVisible(bool(editLabel))
self.widget.expression.setExpression(lineEdit or "")
self.widget.expression.setLayer(None)
self.widget.expression.setVisible(lineEdit is not None)
if lineEdit is not None:
self.setPlaceholderText(placeholderText)
self.widget.toolButton.setVisible(toolButton)
self.widget.checkBox.setVisible(checkBox)
def resetDefault(self):
pass
def comboBoxSelectionChanged(self, index):
pass
def toolButtonClicked(self):
pass
def setPlaceholderText(self, text):
try:
lineEdit = self.widget.expressionComboBox().lineEdit()
lineEdit.setPlaceholderText(text)
lineEdit.setToolTip(text)
except:
pass
def values(self):
return {"type": self.widget.funcType,
"comboData": self.widget.comboBox.itemData(self.widget.comboBox.currentIndex()),
"comboText": self.widget.comboBox.currentText(),
"editText": self.widget.expression.expression()}
def setValues(self, vals):
index = self.widget.comboBox.findData(vals["comboData"])
if index != -1:
self.widget.comboBox.setCurrentIndex(index)
self.widget.expression.setExpression(vals["editText"])
@classmethod
def numericalFields(cls, layer):
numeric_fields = []
for i, field in enumerate(layer.fields()):
if field.type() in [QVariant.Double, QVariant.Int, QVariant.LongLong, QVariant.UInt, QVariant.ULongLong]:
numeric_fields.append([i, field.name()])
return numeric_fields
class ExpressionWidgetFunc(WidgetFuncBase):
def setup(self, options=None):
""" options: name, label, defaultValue, layer """
options = options or {}
WidgetFuncBase.setup(self, options.get("name", ""), lineEdit=str(options.get("defaultValue", 0)))
self.widget.comboBox.clear()
self.widget.comboBox.addItem("Expression")
layer = options.get("layer")
if layer:
self.widget.expression.setFilters(QgsFieldProxyModel.Numeric)
self.widget.expression.setLayer(layer)
class ColorWidgetFunc(WidgetFuncBase):
FEATURE = 1
RANDOM = 2
EXPRESSION = 3
def setup(self, options=None):
""" options: defaultValue """
WidgetFuncBase.setup(self, "Color", lineEdit=None)
options = options or {}
self.widget.comboBox.clear()
self.widget.comboBox.addItem("Feature style", ColorWidgetFunc.FEATURE)
self.widget.comboBox.addItem("Random", ColorWidgetFunc.RANDOM)
self.widget.comboBox.addItem("Expression", ColorWidgetFunc.EXPRESSION)
self.widget.expression.setExpression(options.get("defaultValue", ""))
self.widget.expression.setFilters(QgsFieldProxyModel.String)
self.setPlaceholderText("e.g. color_rgb(255, 127, 0), '#FF7F00'")
layer = options.get("layer")
if layer:
self.widget.expression.setFilters(QgsFieldProxyModel.String | QgsFieldProxyModel.Int | QgsFieldProxyModel.LongLong)
self.widget.expression.setLayer(layer)
def comboBoxSelectionChanged(self, index):
itemData = self.widget.comboBox.itemData(index)
isRGB = itemData == ColorWidgetFunc.EXPRESSION
self.widget.label_2.setVisible(isRGB)
self.widget.expression.setVisible(isRGB)
self.widget.toolButton.setVisible(isRGB)
def toolButtonClicked(self):
dlg = QDialog()
dlg.setWindowTitle("Select a color")
dlg.setLayout(QVBoxLayout())
widget = QgsCompoundColorWidget()
widget.setAllowOpacity(False)
dlg.layout().addWidget(widget)
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
buttonBox.accepted.connect(dlg.accept)
buttonBox.rejected.connect(dlg.reject)
dlg.layout().addWidget(buttonBox)
if dlg.exec_():
self.widget.expression.setExpression("'" + widget.color().name().replace("#", "0x") + "'")
def setValues(self, vals):
index = self.widget.comboBox.findData(vals["comboData"])
if index != -1:
self.widget.comboBox.setCurrentIndex(index)
self.widget.comboBoxSelectionChanged(index) # make sure to update visibility
self.widget.expression.setExpression(vals["editText"])
class FilePathWidgetFunc(WidgetFuncBase):
FILEPATH = 1
def setup(self, options=None):
""" options: name, label, defaultValue, filterString """
options = options or {}
self.lineEditLabel = options.get("label", "Path")
WidgetFuncBase.setup(self, options.get("name", ""), editLabel=self.lineEditLabel, toolButton=True)
self.widget.expression.setExpression(str(options.get("defaultValue", "")))
self.widget.comboBox.clear()
self.widget.comboBox.addItem("File path", FilePathWidgetFunc.FILEPATH)
layer = options.get("layer")
if layer:
self.widget.expression.setFilters(QgsFieldProxyModel.String)
self.widget.expression.setLayer(layer)
self.filterString = options.get("filterString", "")
def toolButtonClicked(self):
workdir = os.path.split(self.widget.expression.expression())[0]
if not workdir:
workdir = QgsProject.instance().homePath()
if not workdir:
workdir = QDir.homePath()
filepath, _ = QFileDialog.getOpenFileName(None, "Select a file", workdir, self.filterString)
if filepath:
self.widget.expression.setExpression(filepath)
class HeightWidgetFunc(WidgetFuncBase):
def setup(self, options=None):
""" options: name, defaultItem, defaultValue, layer """
options = options or {}
WidgetFuncBase.setup(self, options.get("name", "Mode"))
self.defaultValue = options.get("defaultValue", 0)
# set up combo box
comboBox = self.widget.comboBox
comboBox.clear()
comboBox.addItem("Absolute")
for lyr in getDEMLayersInProject():
comboBox.addItem('Relative to "{0}" layer'.format(lyr.name()), lyr.id())
# z value if layer has
#if layer and layer.wkbType() in [QgsWkbTypes.Point25D, QgsWkbTypes.LineString25D, QgsWkbTypes.MultiPoint25D, QgsWkbTypes.MultiLineString25D]:
# comboBox.addItem("Z value", HeightWidgetFunc.Z_VALUE)
# comboBox.insertSeparator(1)
defaultItem = options.get("defaultItem")
if defaultItem is not None:
index = self.widget.comboBox.findData(defaultItem)
if index != -1:
self.widget.comboBox.setCurrentIndex(index)
def comboBoxSelectionChanged(self, index):
if self.widget.comboBox.itemData(index):
label = "Addend"
defaultValue = 0
else:
label = "Altitude"
defaultValue = self.defaultValue
self.widget.label_2.setText(label)
self.widget.expression.setExpression(str(defaultValue))
def isCurrentItemRelativeHeight(self):
return self.widget.comboBox.itemData(self.widget.comboBox.currentIndex()) is None
class LabelHeightWidgetFunc(WidgetFuncBase):
ABSOLUTE = 0
RELATIVE = 1
def setup(self, options=None):
""" options: defaultValue, layer """
WidgetFuncBase.setup(self, "Label height")
options = options or {}
if hasattr(options, "defaultValue"):
self.defaultValue = options["defaultValue"]
self.widget.expression.setExpression(str(self.defaultValue))
self.widget.comboBox.clear();
self.widget.comboBox.addItem("Absolute", self.ABSOLUTE)
self.widget.comboBox.addItem("Relative", self.RELATIVE)
layer = options.get("layer")
if layer:
self.widget.expression.setFilters(QgsFieldProxyModel.Numeric)
self.widget.expression.setLayer(layer)
class OpacityWidgetFunc(WidgetFuncBase):
FEATURE = 1
EXPRESSION = 2
def setup(self, options=None):
WidgetFuncBase.setup(self, "Opacity", lineEdit=None)
options = options or {}
self.widget.comboBox.clear()
self.widget.comboBox.addItem("Feature style", OpacityWidgetFunc.FEATURE)
self.widget.comboBox.addItem("Expression", OpacityWidgetFunc.EXPRESSION)
layer = options.get("layer")
if layer:
self.widget.expression.setFilters(QgsFieldProxyModel.Numeric)
self.widget.expression.setLayer(layer)
self.setPlaceholderText("numeric (percentage. 0 - 100)")
def comboBoxSelectionChanged(self, index):
itemData = self.widget.comboBox.itemData(index)
isValue = itemData == OpacityWidgetFunc.EXPRESSION
self.widget.label_2.setVisible(isValue)
self.widget.expression.setVisible(isValue)
def setValues(self, vals):
index = self.widget.comboBox.findData(vals["comboData"])
if index != -1:
self.widget.comboBox.setCurrentIndex(index)
self.widget.comboBoxSelectionChanged(index) # make sure to update visibility
self.widget.expression.setExpression(vals["editText"])
class OptionalColorWidgetFunc(ColorWidgetFunc):
NONE = 0
def setup(self, options=None):
""" options: name, itemText, defaultItem """
options = options or {}
ColorWidgetFunc.setup(self, options)
self.widget.label_1.setText(options.get("name", "Color"))
itemText = options.get("itemText", {})
if itemText.get(OptionalColorWidgetFunc.NONE, "") is not None:
self.widget.comboBox.insertItem(0, "None", OptionalColorWidgetFunc.NONE)
for id, text in itemText.items():
index = self.widget.comboBox.findData(id)
if index != -1:
self.widget.comboBox.setItemText(index, text)
index = self.widget.comboBox.findData(options.get("defaultItem", OptionalColorWidgetFunc.NONE))
if index != -1:
self.widget.comboBox.setCurrentIndex(index)
class ColorTextureWidgetFunc(ColorWidgetFunc):
MAP_CANVAS = 10
LAYER = 11
def __init__(self, widget):
ColorWidgetFunc.__init__(self, widget)
self.layerIds = []
self.mapSettings = None
def setup(self, options=None):
""" options: mapSettings """
options = options or {}
self.mapSettings = options.get("mapSettings")
ColorWidgetFunc.setup(self, options)
self.widget.label_1.setText("Color/Texture")
comboBox = self.widget.comboBox
comboBox.insertSeparator(comboBox.count())
comboBox.addItem("Map canvas image", ColorTextureWidgetFunc.MAP_CANVAS)
comboBox.addItem("Layer image", ColorTextureWidgetFunc.LAYER)
self.updateLineEdit()
def comboBoxSelectionChanged(self, index):
itemData = self.widget.comboBox.itemData(index)
isRGB = bool(itemData == ColorWidgetFunc.EXPRESSION)
isLayer = bool(itemData == ColorTextureWidgetFunc.LAYER)
self.widget.label_2.setText("Layers" if isLayer else "Value")
self.widget.label_2.setVisible(isRGB or isLayer)
#self.widget.expression.setPlaceholderText("0xrrggbb" if isRGB else "")
#self.widget.expression.setReadOnly(isLayer)
self.widget.expression.setVisible(isRGB or isLayer)
if isRGB:
self.widget.expression.setExpression("")
elif isLayer:
self.updateLineEdit()
self.widget.toolButton.setVisible(isRGB or isLayer)
def toolButtonClicked(self):
itemData = self.widget.comboBox.itemData(self.widget.comboBox.currentIndex())
if itemData == ColorWidgetFunc.EXPRESSION:
ColorWidgetFunc.toolButtonClicked(self)
return
# ColorTextureWidgetFunc.LAYER
from .layerselectdialog import LayerSelectDialog
dialog = LayerSelectDialog(self.widget)
dialog.initTree(self.layerIds)
dialog.setMapSettings(self.mapSettings)
if not dialog.exec_():
return
layers = dialog.visibleLayers()
self.layerIds = [layer.id() for layer in layers]
self.updateLineEdit()
def updateLineEdit(self):
self.widget.expression.setExpression(shortTextFromSelectedLayerIds(self.layerIds))
def values(self):
v = ColorWidgetFunc.values(self)
if self.layerIds:
v["layerIds"] = self.layerIds
return v
def setValues(self, vals):
self.layerIds = vals.get("layerIds", [])
ColorWidgetFunc.setValues(self, vals)
class CheckBoxWidgetFunc(WidgetFuncBase):
def setup(self, options=None):
""" options: name, defaultValue, connectTo """
options = options or {}
WidgetFuncBase.setup(self, options.get("name", ""), checkBox=True)
self.setLayoutVisible(False)
checked = options.get("defaultValue", False)
# connect with widgets
self.connectedWidgets = []
for w in options.get("connectTo", []):
w.setEnabled(checked)
self.widget.checkBox.toggled.connect(w.setEnabled)
self.connectedWidgets.append(w)
def resetDefault(self):
self.setLayoutVisible(True)
for w in self.connectedWidgets:
self.widget.checkBox.toggled.disconnect(w.setEnabled)
w.setEnabled(True)
def values(self):
return {"type": self.widget.funcType,
"checkBox": self.widget.checkBox.isChecked()}
def setValues(self, vals):
checked = vals["checkBox"]
self.widget.checkBox.setChecked(checked)
for w in self.connectedWidgets:
w.setEnabled(checked)
def setLayoutVisible(self, visible):
self.widget.label_2.setVisible(visible)
self.widget.comboBox.setVisible(visible)
self.widget.expression.setVisible(visible)
self.widget.toolButton.setVisible(visible)
class StyleWidget(QWidget, Ui_ComboEditWidget):
# function types
EXPRESSION = 1
COLOR = 2
FILEPATH = 3
HEIGHT = 4
OPACITY = 5
LABEL_HEIGHT = 6
OPTIONAL_COLOR = 7
COLOR_TEXTURE = 8
CHECKBOX = 9
type2funcClass = {EXPRESSION: ExpressionWidgetFunc,
COLOR: ColorWidgetFunc,
FILEPATH: FilePathWidgetFunc,
HEIGHT: HeightWidgetFunc,
LABEL_HEIGHT: LabelHeightWidgetFunc,
OPACITY: OpacityWidgetFunc,
OPTIONAL_COLOR: OptionalColorWidgetFunc,
COLOR_TEXTURE: ColorTextureWidgetFunc,
CHECKBOX: CheckBoxWidgetFunc}
FIELDTYPE_ALL = 0
FIELDTYPE_NUMBER = 1
FIELDTYPE_STRING = 2
def __init__(self, funcType=None, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
self.comboBox.currentIndexChanged.connect(self.comboBoxSelectionChanged)
self.toolButton.clicked.connect(self.toolButtonClicked)
self.funcType = funcType
self.func = None
self.hasValues = False
# install event filter
self.enterKeyFilter = EnterKeyEventFilter(self)
for w in self.expression.findChildren(QComboBox):
w.installEventFilter(self.enterKeyFilter)
def setup(self, funcType=None, options=None):
if funcType is None:
# use the function type passed to __init__
funcType = self.funcType
if self.func:
self.func.resetDefault()
if self.func is None or self.funcType != funcType:
funcClass = self.type2funcClass.get(funcType)
if funcClass is None:
self.funcType = None
self.func = None
self.setVisible(False)
self.hasValues = False
return
self.func = funcClass(self)
self.funcType = funcType
self.func.setup(options)
self.setVisible(True)
self.hasValues = True
def expressionComboBox(self):
for w in self.expression.findChildren(QComboBox):
return w
def comboBoxSelectionChanged(self, index):
if self.func and index != -1:
self.func.comboBoxSelectionChanged(index)
def toolButtonClicked(self):
if self.func:
self.func.toolButtonClicked()
def hide(self):
self.hasValues = False
QWidget.hide(self)
def values(self):
if self.func and self.hasValues:
return self.func.values()
else:
return {}
def setValues(self, vals):
if self.func:
self.func.setValues(vals)
class EnterKeyEventFilter(QObject):
def eventFilter(self, obj, event):
if event.type() == QEvent.KeyPress and (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter):
event.ignore()
return True
return QObject.eventFilter(self, obj, event)
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...