4
0
Fork 0
WolfBox/addons/qr_code/qr_code_rect.gd

357 lines
11 KiB
GDScript

@tool
@icon("res://addons/qr_code/qr_code.svg")
extends TextureRect
class_name QRCodeRect
const QRCode := preload("res://addons/qr_code/qr_code.gd")
const ShiftJIS := preload("res://addons/qr_code/shift_jis.gd")
var _qr: QRCode = QRCode.new()
var mode: QRCode.Mode:
set = set_mode,
get = get_mode
var error_correction: QRCode.ErrorCorrection:
set = set_error_correction,
get = get_error_correction
## Use Extended Channel Interpretation (ECI).
var use_eci: bool:
set = set_use_eci,
get = get_use_eci
## Extended Channel Interpretation (ECI) Value.
var eci_value: int:
set = set_eci_value,
get = get_eci_value
var data: Variant = "":
set = set_data,
get = get_data
## Use automatically the smallest version possible.
var auto_version: bool = true:
set = set_auto_version,
get = get_auto_version
var version: int = 1:
set = set_version,
get = get_version
## Use automatically the best mask pattern.
var auto_mask_pattern: bool = true:
set = set_auto_mask_pattern,
get = get_auto_mask_pattern
## Used mask pattern.
var mask_pattern = 0:
set = set_mask_pattern,
get = get_mask_pattern
var light_module_color: Color = Color.WHITE:
set = set_light_module_color
var dark_module_color: Color = Color.BLACK:
set = set_dark_module_color
## Automatically set the module pixel size based on the size.
## Do not use expand mode KEEP_SIZE when using it.
## Turn this off when the QR Code changes or is resized often, as it impacts the performance quite heavily.
var auto_module_px_size: bool = true:
set = set_auto_module_px_size
## Use that many pixel for one module.
var module_px_size: int = 1:
set = set_module_px_size
## Use that many modules for the quiet zone. A value of 4 is recommended.
var quiet_zone_size: int = 4:
set = set_quiet_zone_size
func set_mode(new_mode: QRCode.Mode) -> void:
self._qr.mode = new_mode
self.notify_property_list_changed()
self._update_qr()
func get_mode() -> QRCode.Mode:
return self._qr.mode
func set_error_correction(new_error_correction: QRCode.ErrorCorrection) -> void:
self._qr.error_correction = new_error_correction
self._update_qr()
func get_error_correction() -> QRCode.ErrorCorrection:
return self._qr.error_correction
func set_use_eci(new_use_eci: bool) -> void:
self._qr.use_eci = new_use_eci
self.notify_property_list_changed()
self._update_qr()
func get_use_eci() -> bool:
return self._qr.use_eci
func set_eci_value(new_eci_value: int) -> void:
self._qr.eci_value = new_eci_value
self.notify_property_list_changed()
self._update_qr()
func get_eci_value() -> int:
return self._qr.eci_value
func set_data(new_data: Variant) -> void:
match self._qr.mode:
QRCode.Mode.NUMERIC:
self._qr.put_numeric(new_data)
QRCode.Mode.ALPHANUMERIC:
self._qr.put_alphanumeric(new_data)
QRCode.Mode.BYTE:
if typeof(new_data) == TYPE_PACKED_BYTE_ARRAY || !self.use_eci:
self._qr.put_byte(new_data)
return
match self.eci_value:
QRCode.ECI.ISO_8859_1:
self._qr.put_byte(new_data.to_ascii_buffer())
QRCode.ECI.SHIFT_JIS:
self._qr.put_byte(ShiftJIS.to_shift_jis_2004_buffer(new_data))
QRCode.ECI.UTF_8:
self._qr.put_byte(new_data.to_utf8_buffer())
QRCode.ECI.UTF_16:
self._qr.put_byte(new_data.to_utf16_buffer())
QRCode.ECI.US_ASCII:
self._qr.put_byte(new_data.to_ascii_buffer())
_:
self._qr.put_byte(new_data)
QRCode.Mode.KANJI:
self._qr.put_kanji(new_data)
self._update_qr()
func get_data() -> Variant:
var input_data: Variant = self._qr.get_input_data()
if self.mode == QRCode.Mode.BYTE && self.use_eci:
match self.eci_value:
QRCode.ECI.ISO_8859_1:
return input_data.get_string_from_ascii()
QRCode.ECI.SHIFT_JIS:
return ShiftJIS.get_string_from_shift_jis_2004(input_data)
QRCode.ECI.UTF_8:
return input_data.get_string_from_utf8()
QRCode.ECI.UTF_16:
return input_data.get_string_from_utf16()
QRCode.ECI.US_ASCII:
return input_data.get_string_from_ascii()
return self._qr.get_input_data()
func set_auto_version(new_auto_version: bool) -> void:
self._qr.auto_version = new_auto_version
self.notify_property_list_changed()
self._update_qr()
func get_auto_version() -> bool:
return self._qr.auto_version
func set_version(new_version: int) -> void:
self._qr.version = new_version
self._update_qr()
func get_version() -> int:
return self._qr.version
func set_auto_mask_pattern(new_auto_mask_pattern: bool) -> void:
self._qr.auto_mask_pattern = new_auto_mask_pattern
self.notify_property_list_changed()
self._update_qr()
func get_auto_mask_pattern() -> bool:
return self._qr.auto_mask_pattern
func set_mask_pattern(new_mask_pattern: int) -> void:
self._qr.mask_pattern = new_mask_pattern
self._update_qr()
func get_mask_pattern() -> int:
return self._qr.mask_pattern
func set_light_module_color(new_light_module_color: Color) -> void:
light_module_color = new_light_module_color
self._update_qr()
func set_dark_module_color(new_dark_module_color: Color) -> void:
dark_module_color = new_dark_module_color
self._update_qr()
func set_auto_module_px_size(new_auto_module_px_size: bool) -> void:
auto_module_px_size = new_auto_module_px_size
self.notify_property_list_changed()
self.update_configuration_warnings()
self._update_qr()
func set_module_px_size(new_module_px_size: int) -> void:
module_px_size = new_module_px_size
if !self.auto_module_px_size:
self._update_qr()
func set_quiet_zone_size(new_quiet_zone_size: int) -> void:
quiet_zone_size = maxi(0, new_quiet_zone_size)
self._update_qr()
func _init() -> void:
if self.texture != null:
self._update_qr()
func _set(property: StringName, value: Variant) -> bool:
if property == "expand_mode":
self.update_configuration_warnings()
return false
func _get_property_list() -> Array[Dictionary]:
var eci_value_prop: Dictionary = {
"name": "eci_value",
"type": TYPE_INT,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "Code Page 437:2,ISO 8859-1:3,ISO 8859-2:4,ISO 8859-3:5,ISO 8859-4:6,ISO 8859-5:7,ISO 8859-6:8,ISO 8859-7:9,ISO 8859-8:10,ISO 8859-9:11,ISO 8859-10:12,ISO 8859-11:13,ISO 8859-12:14,ISO 8859-13:15,ISO 8859-14:16,ISO 8859-15:17,ISO 8859-16:18,Shift JIS:20,Windows 1250:21,Windows 1251:22,Windows 1252:23,Windows 1256:24,UTF-16:25,UTF-8:26,US ASCII:27,BIG 5:28,GB 18030:29,EUC KR:30"
}
if !self.use_eci:
eci_value_prop["usage"] = (eci_value_prop["usage"] | PROPERTY_USAGE_READ_ONLY) & ~PROPERTY_USAGE_STORAGE
var data_prop: Dictionary = {
"name": "data",
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
}
match self.mode:
QRCode.Mode.NUMERIC:
data_prop["type"] = TYPE_STRING
QRCode.Mode.ALPHANUMERIC, QRCode.Mode.KANJI:
data_prop["type"] = TYPE_STRING
data_prop["hint"] = PROPERTY_HINT_MULTILINE_TEXT
QRCode.Mode.BYTE:
# these encoding is nativeley supported
if self.use_eci && self.eci_value in [QRCode.ECI.ISO_8859_1, QRCode.ECI.SHIFT_JIS, QRCode.ECI.UTF_8, QRCode.ECI.UTF_16, QRCode.ECI.US_ASCII]:
data_prop["type"] = TYPE_STRING
data_prop["hint"] = PROPERTY_HINT_MULTILINE_TEXT
else:
data_prop["type"] = TYPE_PACKED_BYTE_ARRAY
var version_prop: Dictionary = {
"name": "version",
"type": TYPE_INT,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "1,40"
}
if self.auto_version:
version_prop["usage"] = (version_prop["usage"] | PROPERTY_USAGE_READ_ONLY) & ~PROPERTY_USAGE_STORAGE
var mask_prop: Dictionary = {
"name": "mask_pattern",
"type": TYPE_INT,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,7"
}
if self.auto_mask_pattern:
mask_prop["usage"] = (mask_prop["usage"] | PROPERTY_USAGE_READ_ONLY) & ~PROPERTY_USAGE_STORAGE
var module_px_size_prop: Dictionary = {
"name": "module_px_size",
"type": TYPE_INT,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "1,1,or_greater"
}
if self.auto_module_px_size:
module_px_size_prop["usage"] = (module_px_size_prop["usage"] | PROPERTY_USAGE_READ_ONLY) & ~PROPERTY_USAGE_STORAGE
return [
{
"name": "mode",
"type": TYPE_INT,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "Numeric:1,Alphanumeric:2,Byte:4,Kanji:8"
},
{
"name": "error_correction",
"type": TYPE_INT,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "Low:1,Medium:0,Quartile:3,High:2"
},
{
"name": "use_eci",
"type": TYPE_BOOL,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
},
eci_value_prop,
data_prop,
{
"name": "auto_version",
"type": TYPE_BOOL,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
},
version_prop,
{
"name": "auto_mask_pattern",
"type": TYPE_BOOL,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
},
mask_prop,
{
"name": "Appearance",
"type": TYPE_NIL,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_GROUP,
},
{
"name": "light_module_color",
"type": TYPE_COLOR,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE ,
},
{
"name": "dark_module_color",
"type": TYPE_COLOR,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE ,
},
{
"name": "auto_module_px_size",
"type": TYPE_BOOL,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
},
module_px_size_prop,
{
"name": "quiet_zone_size",
"type": TYPE_INT,
"usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
"hint_string": "0,1,or_greater",
},
]
func _property_can_revert(property: StringName) -> bool:
return property in ["eci_value", "auto_version", "auto_mask_pattern", "light_module_color", "dark_module_color", "auto_module_px_size", "quiet_zone_size"]
func _property_get_revert(property: StringName) -> Variant:
match property:
"eci_value":
return QRCode.ECI.ISO_8859_1
"auto_version":
return true
"auto_mask_pattern":
return true
"light_module_color":
return Color.WHITE
"dark_module_color":
return Color.BLACK
"auto_module_px_size":
return true
"quiet_zone_size":
return 4
_:
return null
func _get_configuration_warnings() -> PackedStringArray:
if self.auto_module_px_size && self.expand_mode == EXPAND_KEEP_SIZE:
return ["Do not use auto module px size AND keep size expand mode."]
return []
func _notification(what: int) -> void:
match what:
NOTIFICATION_RESIZED:
if self.auto_module_px_size:
self._update_qr()
func _update_qr() -> void:
if self.auto_module_px_size:
self.module_px_size = mini(self.size.x, self.size.y) / (self._qr.get_module_count() + 2 * self.quiet_zone_size)
self.texture = ImageTexture.create_from_image(self._qr.generate_image(self.module_px_size, self.light_module_color, self.dark_module_color, self.quiet_zone_size))