@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))