# Canvas adapter for the 40250 CWindowManager. The window tree remains native; # this Control forwards Godot input and draws the native UI command stream. extends Control const AssetRoot = preload("res://asset_root.gd") const UiAssets = preload("res://ui/ui_assets.gd") const KEY_TO_DIK := { KEY_ESCAPE: 0x01, KEY_1: 0x02, KEY_2: 0x03, KEY_3: 0x04, KEY_4: 0x05, KEY_5: 0x06, KEY_6: 0x07, KEY_7: 0x08, KEY_8: 0x09, KEY_9: 0x0a, KEY_0: 0x0b, KEY_BACKSPACE: 0x0e, KEY_TAB: 0x0f, KEY_Q: 0x10, KEY_W: 0x11, KEY_E: 0x12, KEY_R: 0x13, KEY_T: 0x14, KEY_Y: 0x15, KEY_U: 0x16, KEY_I: 0x17, KEY_O: 0x18, KEY_P: 0x19, KEY_ENTER: 0x1c, KEY_A: 0x1e, KEY_S: 0x1f, KEY_D: 0x20, KEY_F: 0x21, KEY_G: 0x22, KEY_H: 0x23, KEY_J: 0x24, KEY_K: 0x25, KEY_L: 0x26, KEY_Z: 0x2c, KEY_X: 0x2d, KEY_C: 0x2e, KEY_V: 0x2f, KEY_B: 0x30, KEY_N: 0x31, KEY_M: 0x32, KEY_SPACE: 0x39, KEY_UP: 0xc8, KEY_LEFT: 0xcb, KEY_RIGHT: 0xcd, KEY_DOWN: 0xd0, } func _ready() -> void: set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) mouse_filter = Control.MOUSE_FILTER_STOP _sync_size() func _notification(what: int) -> void: if what == NOTIFICATION_RESIZED and is_inside_tree(): _sync_size() func _sync_size() -> void: if ClassDB.class_exists("Metin2PythonHost"): Metin2PythonHost.set_ui_size(int(size.x), int(size.y)) func _process(_delta: float) -> void: if Metin2PythonHost.is_running(): Metin2PythonHost.ui_update() queue_redraw() func _gui_input(event: InputEvent) -> void: if not Metin2PythonHost.is_running(): return if event is InputEventMouseMotion: Metin2PythonHost.ui_mouse_move(int(event.position.x), int(event.position.y)) elif event is InputEventMouseButton: if event.button_index >= MOUSE_BUTTON_LEFT and event.button_index <= MOUSE_BUTTON_MIDDLE: Metin2PythonHost.ui_mouse_button(event.button_index, event.pressed, int(event.position.x), int(event.position.y)) func _unhandled_key_input(event: InputEvent) -> void: if event is InputEventKey and Metin2PythonHost.is_running(): var dik: int = KEY_TO_DIK.get(event.physical_keycode, 0) if dik != 0: Metin2PythonHost.ui_key(dik, event.pressed) func _draw() -> void: if not Metin2PythonHost.is_running(): return for command in Metin2PythonHost.ui_render_commands(): var argb: int = command["argb"] var color := Color8((argb >> 16) & 255, (argb >> 8) & 255, argb & 255, (argb >> 24) & 255) var p1 := Vector2(command["x1"], command["y1"]) var p2 := Vector2(command["x2"], command["y2"]) var clip := Rect2(Vector2(command["clip_x1"], command["clip_y1"]), Vector2(command["clip_x2"] - command["clip_x1"], command["clip_y2"] - command["clip_y1"])) if command["kind"] == "bar": var visible := Rect2(p1, p2 - p1).intersection(clip) if visible.has_area(): draw_rect(visible, color, true) elif command["kind"] == "line": var segment := _clip_line(p1, p2, clip) if segment.size() == 2: draw_line(segment[0], segment[1], color) elif command["kind"] == "text": var font: Font = ThemeDB.fallback_font if font != null: var baseline := p1 + Vector2(0, font.get_ascent(14)) if clip.has_point(p1): draw_string(font, baseline, command["text"], HORIZONTAL_ALIGNMENT_LEFT, clip.end.x - p1.x, 14, color) elif command["kind"] == "image": var texture: Texture2D = UiAssets.load_tex(AssetRoot.path(), command["text"]) if texture != null: var dest := Rect2(p1, p2 - p1) var visible := dest.intersection(clip) if visible.has_area() and dest.has_area(): var scale := texture.get_size() / dest.size var source := Rect2((visible.position - dest.position) * scale, visible.size * scale) draw_texture_rect_region(texture, visible, source, color) func _clip_line(a: Vector2, b: Vector2, clip: Rect2) -> PackedVector2Array: var delta := b - a var p := [-delta.x, delta.x, -delta.y, delta.y] var q := [a.x - clip.position.x, clip.end.x - a.x, a.y - clip.position.y, clip.end.y - a.y] var enter := 0.0 var leave := 1.0 for i in range(4): if is_zero_approx(p[i]): if q[i] < 0.0: return PackedVector2Array() else: var t: float = q[i] / p[i] if p[i] < 0.0: enter = maxf(enter, t) else: leave = minf(leave, t) if enter > leave: return PackedVector2Array() return PackedVector2Array([a + delta * enter, a + delta * leave])