export struct BitInfo { value: bool, index: int, } export global UiStyle { in-out property size: 2; in-out property theme: 0; in-out property bg: #202020; in-out property surface: #2a2a2a; in-out property btn: #323232; in-out property btn-hover: #464646; in-out property digit: #3b3b3b; in-out property digit-hover: #505050; in-out property accent: #60cdff; in-out property accent-hover: #78d7ff; in-out property text: #ffffff; in-out property text-muted: #c8c8c8; in-out property text-dim: #9a9a9a; in-out property menu-active: #2f3a42; in-out property eq-text: #141414; in-out property border: #404040; in-out property btn-h: UiStyle.size == 1 ? 34px : (UiStyle.size == 3 ? 52px : 42px); in-out property btn-h-sm: UiStyle.size == 1 ? 28px : (UiStyle.size == 3 ? 40px : 32px); in-out property mem-h: UiStyle.size == 1 ? 26px : (UiStyle.size == 3 ? 38px : 32px); in-out property tab-h: UiStyle.size == 1 ? 26px : (UiStyle.size == 3 ? 34px : 30px); in-out property font-sm: UiStyle.size == 1 ? 12px : (UiStyle.size == 3 ? 15px : 13px); in-out property font-md: UiStyle.size == 1 ? 13px : (UiStyle.size == 3 ? 16px : 14px); in-out property font-digit: UiStyle.size == 1 ? 14px : (UiStyle.size == 3 ? 18px : 16px); in-out property font-eq: UiStyle.size == 1 ? 16px : (UiStyle.size == 3 ? 20px : 18px); } component BitCell inherits Rectangle { callback toggled(); in property on; width: 14px; height: 16px; border-radius: 2px; background: touch.has-hover ? UiStyle.menu-active : transparent; Text { text: root.on ? "1" : "0"; color: root.on ? UiStyle.accent : UiStyle.text-dim; font-size: 10px; font-weight: 700; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; horizontal-alignment: center; vertical-alignment: center; } touch := TouchArea { clicked => { root.toggled(); } } } component BitLine inherits Rectangle { callback toggle-bit(int); in property <[BitInfo]> cells; height: 28px; background: transparent; VerticalLayout { spacing: 0px; HorizontalLayout { padding-left: 2px; padding-right: 2px; height: 10px; Text { text: root.cells.length > 0 ? "\{root.cells[0].index}" : ""; color: #808080; font-size: 9px; horizontal-alignment: left; vertical-alignment: center; } Text { text: root.cells.length > 0 ? "\{root.cells[root.cells.length - 1].index}" : ""; color: #808080; font-size: 9px; horizontal-alignment: right; vertical-alignment: center; } } HorizontalLayout { spacing: 0px; padding-left: 2px; alignment: start; for c[i] in root.cells: HorizontalLayout { spacing: 0px; if i > 0 && mod(i, 4) == 0: Rectangle { width: 6px; height: 1px; } BitCell { on: c.value; toggled => { root.toggle-bit(c.index); } } } } } } component MemBtn inherits Rectangle { callback clicked(); in property label; height: UiStyle.mem-h; background: touch.has-hover ? UiStyle.btn : transparent; border-radius: 4px; Text { text: root.label; color: UiStyle.text-muted; font-size: UiStyle.font-sm; horizontal-alignment: center; vertical-alignment: center; } touch := TouchArea { clicked => { root.clicked(); } } } component FuncBtn inherits Rectangle { callback clicked(); in property label; in property enabled: true; in property min-h: UiStyle.btn-h; background: !root.enabled ? UiStyle.surface : (touch.has-hover ? UiStyle.btn-hover : UiStyle.btn); border-radius: 4px; min-height: root.min-h; opacity: root.enabled ? 1.0 : 0.45; Text { text: root.label; color: UiStyle.text; font-size: UiStyle.font-md; horizontal-alignment: center; vertical-alignment: center; } touch := TouchArea { enabled: root.enabled; clicked => { root.clicked(); } } } component DigitBtn inherits Rectangle { callback clicked(); in property label; in property enabled: true; in property min-h: UiStyle.btn-h; background: !root.enabled ? UiStyle.surface : (touch.has-hover ? UiStyle.digit-hover : UiStyle.digit); border-radius: 4px; min-height: root.min-h; opacity: root.enabled ? 1.0 : 0.4; Text { text: root.label; color: UiStyle.text; font-size: UiStyle.font-digit; font-weight: 600; horizontal-alignment: center; vertical-alignment: center; } touch := TouchArea { enabled: root.enabled; clicked => { root.clicked(); } } } component EqBtn inherits Rectangle { callback clicked(); in property min-h: UiStyle.btn-h; background: touch.has-hover ? UiStyle.accent-hover : UiStyle.accent; border-radius: 4px; min-height: root.min-h; Text { text: "="; color: UiStyle.eq-text; font-size: UiStyle.font-eq; font-weight: 700; horizontal-alignment: center; vertical-alignment: center; } touch := TouchArea { clicked => { root.clicked(); } } } component MenuRow inherits Rectangle { callback clicked(); in property label; in property active; height: 36px; background: root.active ? UiStyle.menu-active : (touch.has-hover ? UiStyle.btn : transparent); Text { text: root.label; color: root.active ? UiStyle.accent : UiStyle.text; font-size: 14px; font-weight: root.active ? 700 : 500; vertical-alignment: center; horizontal-alignment: left; x: 14px; width: parent.width - 28px; height: 100%; } touch := TouchArea { clicked => { root.clicked(); } } } component ModeTab inherits Rectangle { callback clicked(); in property label; in property active; height: UiStyle.tab-h; border-radius: 4px; background: root.active ? UiStyle.btn : (touch.has-hover ? UiStyle.surface : transparent); Text { text: root.label; color: root.active ? UiStyle.accent : UiStyle.text-muted; font-size: UiStyle.font-sm; font-weight: root.active ? 700 : 500; horizontal-alignment: center; vertical-alignment: center; } touch := TouchArea { clicked => { root.clicked(); } } } component BaseRow inherits Rectangle { callback clicked(); in property label; in property value; in property active; height: 24px; border-radius: 4px; background: root.active ? #2f3a42 : (touch.has-hover ? #2a2a2a : transparent); HorizontalLayout { padding-left: 8px; padding-right: 8px; spacing: 12px; Text { text: root.label; color: root.active ? #60cdff : #9a9a9a; font-size: 12px; font-weight: 700; width: 36px; vertical-alignment: center; } Text { text: root.value; color: white; font-size: 13px; font-family: "Cascadia Mono, Consolas, monospace"; horizontal-alignment: left; vertical-alignment: center; overflow: elide; } } touch := TouchArea { clicked => { root.clicked(); } } } component FieldRow inherits Rectangle { callback clicked(); in property label; in property value; in property active; height: 40px; border-radius: 4px; background: root.active ? #2f3a42 : (touch.has-hover ? #2a2a2a : #262626); border-width: root.active ? 1px : 0; border-color: #60cdff; HorizontalLayout { padding-left: 10px; padding-right: 10px; spacing: 12px; Text { text: root.label; color: root.active ? #60cdff : #9a9a9a; font-size: 12px; font-weight: 700; width: 64px; vertical-alignment: center; } Text { text: root.value; color: white; font-size: 20px; font-weight: 600; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; horizontal-alignment: right; vertical-alignment: center; overflow: elide; } } touch := TouchArea { clicked => { root.clicked(); } } } component EndianChip inherits Rectangle { callback clicked(); in property label; in property active; height: 30px; border-radius: 4px; background: root.active ? #3b3b3b : (touch.has-hover ? #2c2c2c : #262626); border-width: root.active ? 1px : 0; border-color: #60cdff; Text { text: root.label; color: root.active ? #60cdff : #c8c8c8; font-size: 12px; font-weight: root.active ? 700 : 500; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; horizontal-alignment: center; vertical-alignment: center; } touch := TouchArea { clicked => { root.clicked(); } } } export component AppWindow inherits Window { in-out property app-title: "Rcalc"; title: root.app-title; icon: @image-url("../assets/icon-256.png"); preferred-width: 420px; preferred-height: 640px; min-width: 380px; min-height: 520px; background: UiStyle.bg; // 0=standard 1=engineering 2=programmer 3=convert 4=crc 5=settings in-out property mode: 0; in-out property menu-open: false; in property mode-title: "Standard"; in property cfg-button-size: 2; in property cfg-theme: 0; in property display-text: "0"; in property expression-text: ""; in property has-memory: false; // 0 = classic standard, 1 = formula in property std-panel: 0; // Engineering in property eng-angle-label: "DEG"; in property eng-second: false; in property hex-text: "0"; in property dec-text: "0"; in property oct-text: "0"; in property bin-text: "0"; // 0=hex 1=dec 2=oct 3=bin in property active-base: 1; in property word-size-label: "QWORD"; in property show-bits: true; in property bit-row-count: 0; in property <[BitInfo]> bit-row0; in property <[BitInfo]> bit-row1; in property <[BitInfo]> bit-row2; in property <[BitInfo]> bit-row3; // Convert tab // 0=words 1=ratio in property conv-panel: 0; in property conv-endian: 0; // 0=AB CD 1=CD AB 2=BA DC 3=DC BA in property conv-active: 0; // 0=float 1=word0 2=word1 in property conv-float: "0"; in property conv-word0: "0000"; in property conv-word1: "0000"; in property conv-bytes: "00 00 00 00"; in property conv-ieee: "0x00000000"; in property conv-error: ""; in property ratio-width: 1; // 0=byte 1=word in property ratio-precision: "1e-6"; in property ratio-num: "1"; in property ratio-den: "1"; in property ratio-frac: "1 / 1"; in property ratio-approx: "1"; in property ratio-error: "exact"; in property ascii-char: "A"; in property ascii-hex: "41"; in property ascii-dec: "65"; in property ascii-name: "'A'"; // CRC tab in-out property crc-input: "01 03 00 00 00 0A"; in property crc-parsed: ""; in property crc-count: "0"; in property crc-rtu-bytes: "—"; in property crc-rtu-word: "—"; in property crc-rtu-frame: "—"; in property crc-ascii-lrc: "—"; in property crc-ascii-frame: "—"; in property crc-error: ""; callback key-pressed(string); callback crc-edited(string); function press(id: string) { root.key-pressed(id); } property hex-digits: root.mode == 2 && root.active-base == 0; property allow-2: root.mode == 0 || root.mode == 1 || root.active-base <= 2; property allow-8: root.mode == 0 || root.mode == 1 || root.active-base <= 1; property allow-a: root.mode == 2 && root.active-base == 0; VerticalLayout { padding: 12px; spacing: 6px; HorizontalLayout { spacing: 10px; height: 34px; Rectangle { width: 34px; height: 34px; border-radius: 4px; background: menu-touch.has-hover || root.menu-open ? UiStyle.btn : transparent; // Drawn icon — Unicode ☰ is missing in many Windows fonts. VerticalLayout { padding-top: 9px; padding-bottom: 9px; padding-left: 8px; padding-right: 8px; spacing: 4px; Rectangle { height: 2px; background: UiStyle.text; border-radius: 1px; } Rectangle { height: 2px; background: UiStyle.text; border-radius: 1px; } Rectangle { height: 2px; background: UiStyle.text; border-radius: 1px; } } menu-touch := TouchArea { clicked => { root.menu-open = !root.menu-open; if (root.menu-open) { mode-menu.show(); } else { mode-menu.close(); } } } mode-menu := PopupWindow { x: 0; y: 38px; width: 210px; height: 260px; close-on-click: true; Rectangle { background: UiStyle.surface; border-radius: 6px; border-width: 1px; border-color: UiStyle.border; VerticalLayout { padding: 6px; spacing: 2px; MenuRow { label: "Standard"; active: root.mode == 0; clicked => { root.press("mode:std"); root.menu-open = false; mode-menu.close(); } } MenuRow { label: "Engineering"; active: root.mode == 1; clicked => { root.press("mode:eng"); root.menu-open = false; mode-menu.close(); } } MenuRow { label: "Programmer"; active: root.mode == 2; clicked => { root.press("mode:prog"); root.menu-open = false; mode-menu.close(); } } MenuRow { label: "Convert"; active: root.mode == 3; clicked => { root.press("mode:conv"); root.menu-open = false; mode-menu.close(); } } MenuRow { label: "CRC"; active: root.mode == 4; clicked => { root.press("mode:crc"); root.menu-open = false; mode-menu.close(); } } MenuRow { label: "Settings"; active: root.mode == 5; clicked => { root.press("mode:settings"); root.menu-open = false; mode-menu.close(); } } } } } } Text { text: root.mode-title; color: UiStyle.text; font-size: 18px; font-weight: 700; vertical-alignment: center; horizontal-stretch: 1; } } if root.mode == 0 || root.mode == 1 || root.mode == 2: HorizontalLayout { height: 18px; Text { text: root.has-memory && (root.mode == 0 || root.mode == 1) ? "M" : ""; color: UiStyle.text-muted; font-size: 12px; horizontal-alignment: left; vertical-alignment: center; width: 16px; } Text { text: root.mode == 2 ? root.word-size-label : ""; color: UiStyle.accent; font-size: 11px; vertical-alignment: center; } Text { text: root.expression-text; color: UiStyle.text-dim; font-size: 13px; horizontal-alignment: right; vertical-alignment: center; } } if root.mode == 0 || root.mode == 1 || root.mode == 2: Text { text: root.display-text; color: UiStyle.text; font-size: root.mode == 2 ? 28px : 34px; font-weight: 700; horizontal-alignment: right; vertical-alignment: center; height: root.mode == 2 ? 40px : 48px; overflow: elide; } if root.mode == 4: VerticalLayout { spacing: 10px; Text { text: "Hex bytes (space-separated)"; color: #9a9a9a; font-size: 12px; } Rectangle { height: 44px; border-radius: 4px; background: #2a2a2a; border-width: 1px; border-color: crc-input.has-focus ? #60cdff : #3a3a3a; crc-input := TextInput { x: 10px; width: parent.width - 20px; height: 100%; color: white; font-size: 15px; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; single-line: true; text <=> root.crc-input; edited => { root.crc-edited(self.text); } } } Text { text: "example: 01 03 00 00 00 0A"; color: #666666; font-size: 11px; } if root.crc-error != "": Text { text: root.crc-error; color: #ff8a80; font-size: 12px; } HorizontalLayout { height: 18px; Text { text: "Parsed"; color: #9a9a9a; font-size: 11px; width: 70px; } Text { text: root.crc-parsed; color: #c8c8c8; font-size: 12px; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; overflow: elide; } } HorizontalLayout { height: 18px; Text { text: "Length"; color: #9a9a9a; font-size: 11px; width: 70px; } Text { text: root.crc-count + " bytes"; color: #c8c8c8; font-size: 12px; } } Rectangle { height: 1px; background: #333333; } Text { text: "Modbus RTU (CRC-16)"; color: #60cdff; font-size: 13px; font-weight: 700; } HorizontalLayout { height: 22px; Text { text: "CRC"; color: #9a9a9a; font-size: 12px; width: 70px; vertical-alignment: center; } Text { text: root.crc-rtu-bytes + " (" + root.crc-rtu-word + ")"; color: white; font-size: 16px; font-weight: 700; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; vertical-alignment: center; } } Text { text: "lo hi — append after PDU"; color: #666666; font-size: 11px; } HorizontalLayout { height: 18px; Text { text: "Frame"; color: #9a9a9a; font-size: 11px; width: 70px; } Text { text: root.crc-rtu-frame; color: #c8c8c8; font-size: 12px; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; overflow: elide; } } Rectangle { height: 1px; background: #333333; } Text { text: "Modbus ASCII (LRC)"; color: #60cdff; font-size: 13px; font-weight: 700; } HorizontalLayout { height: 22px; Text { text: "LRC"; color: #9a9a9a; font-size: 12px; width: 70px; vertical-alignment: center; } Text { text: root.crc-ascii-lrc; color: white; font-size: 16px; font-weight: 700; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; vertical-alignment: center; } } HorizontalLayout { height: 18px; Text { text: "Frame"; color: #9a9a9a; font-size: 11px; width: 70px; } Text { text: root.crc-ascii-frame; color: #c8c8c8; font-size: 12px; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; overflow: elide; } } Rectangle { height: 8px; background: transparent; } HorizontalLayout { spacing: 6px; height: 36px; FuncBtn { min-h: 36px; label: "Clear"; clicked => { root.crc-input = ""; root.crc-edited(""); } } FuncBtn { min-h: 36px; label: "Example"; clicked => { root.crc-input = "01 03 00 00 00 0A"; root.crc-edited(root.crc-input); } } } } if root.mode == 3: VerticalLayout { spacing: 8px; HorizontalLayout { spacing: 6px; height: 30px; ModeTab { label: "Words"; active: root.conv-panel == 0; clicked => { root.press("panel:words"); } } ModeTab { label: "Ratio"; active: root.conv-panel == 1; clicked => { root.press("panel:ratio"); } } ModeTab { label: "ASCII"; active: root.conv-panel == 2; clicked => { root.press("panel:ascii"); } } } if root.conv-panel == 0: VerticalLayout { spacing: 8px; Text { text: "Endian (byte / word order)"; color: #9a9a9a; font-size: 12px; } HorizontalLayout { spacing: 6px; height: 30px; EndianChip { label: "AB CD"; active: root.conv-endian == 0; clicked => { root.press("endian:0"); } } EndianChip { label: "CD AB"; active: root.conv-endian == 1; clicked => { root.press("endian:1"); } } EndianChip { label: "BA DC"; active: root.conv-endian == 2; clicked => { root.press("endian:2"); } } EndianChip { label: "DC BA"; active: root.conv-endian == 3; clicked => { root.press("endian:3"); } } } FieldRow { label: "Float32"; value: root.conv-float; active: root.conv-active == 0; clicked => { root.press("conv:float"); } } FieldRow { label: "Word 0"; value: root.conv-word0; active: root.conv-active == 1; clicked => { root.press("conv:w0"); } } FieldRow { label: "Word 1"; value: root.conv-word1; active: root.conv-active == 2; clicked => { root.press("conv:w1"); } } HorizontalLayout { height: 18px; Text { text: "Wire"; color: #9a9a9a; font-size: 11px; width: 40px; } Text { text: root.conv-bytes; color: #c8c8c8; font-size: 12px; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; } } HorizontalLayout { height: 18px; Text { text: "IEEE"; color: #9a9a9a; font-size: 11px; width: 40px; } Text { text: root.conv-ieee; color: #c8c8c8; font-size: 12px; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; } } } if root.conv-panel == 1: VerticalLayout { spacing: 8px; Text { text: "Electronic gear: float → num / den"; color: #9a9a9a; font-size: 12px; } HorizontalLayout { spacing: 6px; height: 30px; EndianChip { label: "Byte (≤255)"; active: root.ratio-width == 0; clicked => { root.press("rwidth:byte"); } } EndianChip { label: "Word (≤65535)"; active: root.ratio-width == 1; clicked => { root.press("rwidth:word"); } } } HorizontalLayout { spacing: 6px; height: 30px; Text { text: "Precision"; color: #9a9a9a; font-size: 12px; vertical-alignment: center; width: 70px; } EndianChip { label: root.ratio-precision; active: true; clicked => { root.press("rprec"); } } Text { text: "rel. error (tap to cycle)"; color: #666666; font-size: 11px; vertical-alignment: center; } } FieldRow { label: "Float32"; value: root.conv-float; active: true; clicked => { root.press("conv:float"); } } FieldRow { label: "Num"; value: root.ratio-num; active: false; clicked => { } } FieldRow { label: "Den"; value: root.ratio-den; active: false; clicked => { } } HorizontalLayout { height: 18px; Text { text: "Frac"; color: #9a9a9a; font-size: 11px; width: 40px; } Text { text: root.ratio-frac; color: #60cdff; font-size: 13px; font-weight: 700; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; } } HorizontalLayout { height: 18px; Text { text: "≈"; color: #9a9a9a; font-size: 11px; width: 40px; } Text { text: root.ratio-approx; color: #c8c8c8; font-size: 12px; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; } } HorizontalLayout { height: 18px; Text { text: "Err"; color: #9a9a9a; font-size: 11px; width: 40px; } Text { text: root.ratio-error; color: #c8c8c8; font-size: 12px; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; } } } if root.conv-panel == 2: VerticalLayout { spacing: 8px; Text { text: "ASCII / Latin-1 · Char ↔ Hex ↔ Dec"; color: #9a9a9a; font-size: 12px; } FieldRow { label: "Char"; value: root.ascii-char; active: root.conv-active == 0; clicked => { root.press("ascii:char"); } } FieldRow { label: "Hex"; value: root.ascii-hex; active: root.conv-active == 1; clicked => { root.press("ascii:hex"); } } FieldRow { label: "Dec"; value: root.ascii-dec; active: root.conv-active == 2; clicked => { root.press("ascii:dec"); } } HorizontalLayout { height: 20px; Text { text: "Name"; color: #9a9a9a; font-size: 11px; width: 40px; } Text { text: root.ascii-name; color: #60cdff; font-size: 13px; font-weight: 700; font-family: "Cascadia Mono, Consolas, DejaVu Sans Mono, monospace"; } } Text { text: "Char: type on keyboard · Hex/Dec: keypad"; color: #666666; font-size: 11px; } } if root.conv-error != "": Text { text: root.conv-error; color: #ff8a80; font-size: 12px; } GridLayout { spacing: 5px; Row { FuncBtn { label: "CE"; clicked => { root.press("CE"); } } FuncBtn { label: "C"; clicked => { root.press("clear"); } } FuncBtn { label: "⌫"; clicked => { root.press("BS"); } } FuncBtn { label: "±"; enabled: root.conv-panel == 1 || (root.conv-panel == 0 && root.conv-active == 0); clicked => { root.press("neg"); } } } Row { DigitBtn { label: "A"; enabled: (root.conv-panel == 0 && root.conv-active != 0) || (root.conv-panel == 2 && root.conv-active != 2); clicked => { root.press("A"); } } DigitBtn { label: "B"; enabled: (root.conv-panel == 0 && root.conv-active != 0) || (root.conv-panel == 2 && root.conv-active != 2); clicked => { root.press("B"); } } DigitBtn { label: "C"; enabled: (root.conv-panel == 0 && root.conv-active != 0) || (root.conv-panel == 2 && root.conv-active != 2); clicked => { root.press("C"); } } DigitBtn { label: "D"; enabled: (root.conv-panel == 0 && root.conv-active != 0) || (root.conv-panel == 2 && root.conv-active != 2); clicked => { root.press("D"); } } } Row { DigitBtn { label: "E"; enabled: (root.conv-panel == 0 && root.conv-active != 0) || (root.conv-panel == 2 && root.conv-active != 2); clicked => { root.press("E"); } } DigitBtn { label: "F"; enabled: (root.conv-panel == 0 && root.conv-active != 0) || (root.conv-panel == 2 && root.conv-active != 2); clicked => { root.press("F"); } } DigitBtn { label: "."; enabled: root.conv-panel == 1 || (root.conv-panel == 0 && root.conv-active == 0); clicked => { root.press("."); } } FuncBtn { label: "e"; enabled: root.conv-panel == 1 || (root.conv-panel == 0 && root.conv-active == 0); clicked => { root.press("e"); } } } Row { DigitBtn { label: "7"; clicked => { root.press("7"); } } DigitBtn { label: "8"; clicked => { root.press("8"); } } DigitBtn { label: "9"; clicked => { root.press("9"); } } DigitBtn { label: "4"; clicked => { root.press("4"); } } } Row { DigitBtn { label: "5"; clicked => { root.press("5"); } } DigitBtn { label: "6"; clicked => { root.press("6"); } } DigitBtn { label: "1"; clicked => { root.press("1"); } } DigitBtn { label: "2"; clicked => { root.press("2"); } } } Row { DigitBtn { label: "3"; clicked => { root.press("3"); } } DigitBtn { label: "0"; clicked => { root.press("0"); } } FuncBtn { label: "Spc"; enabled: root.conv-panel == 2 && root.conv-active == 0; clicked => { root.press(" "); } } Rectangle { background: transparent; } } } } if root.mode == 2: VerticalLayout { spacing: 2px; BaseRow { label: "HEX"; value: root.hex-text; active: root.active-base == 0; clicked => { root.press("base:hex"); } } BaseRow { label: "DEC"; value: root.dec-text; active: root.active-base == 1; clicked => { root.press("base:dec"); } } BaseRow { label: "OCT"; value: root.oct-text; active: root.active-base == 2; clicked => { root.press("base:oct"); } } BaseRow { label: "BIN"; value: root.bin-text; active: root.active-base == 3; clicked => { root.press("base:bin"); } } } if root.mode == 2 && root.show-bits: VerticalLayout { spacing: 2px; padding-top: 4px; padding-bottom: 4px; if root.bit-row-count > 0: BitLine { cells: root.bit-row0; toggle-bit(idx) => { root.press("bit:\{idx}"); } } if root.bit-row-count > 1: BitLine { cells: root.bit-row1; toggle-bit(idx) => { root.press("bit:\{idx}"); } } if root.bit-row-count > 2: BitLine { cells: root.bit-row2; toggle-bit(idx) => { root.press("bit:\{idx}"); } } if root.bit-row-count > 3: BitLine { cells: root.bit-row3; toggle-bit(idx) => { root.press("bit:\{idx}"); } } } if root.mode == 1: HorizontalLayout { spacing: 6px; height: 32px; FuncBtn { label: root.eng-angle-label; clicked => { root.press("eng:angle"); } } MemBtn { label: "MC"; clicked => { root.press("MC"); } } MemBtn { label: "MR"; clicked => { root.press("MR"); } } MemBtn { label: "M+"; clicked => { root.press("M+"); } } MemBtn { label: "M-"; clicked => { root.press("M-"); } } MemBtn { label: "MS"; clicked => { root.press("MS"); } } } if root.mode == 1: GridLayout { spacing: 4px; Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: root.eng-second ? "2nd●" : "2nd"; clicked => { root.press("eng:2nd"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "π"; clicked => { root.press("eng:pi"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "e"; clicked => { root.press("eng:e"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "C"; clicked => { root.press("C"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "⌫"; clicked => { root.press("BS"); } } } Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: root.eng-second ? "sin⁻¹" : "sin"; clicked => { root.press(root.eng-second ? "eng:asin" : "eng:sin"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: root.eng-second ? "cos⁻¹" : "cos"; clicked => { root.press(root.eng-second ? "eng:acos" : "eng:cos"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: root.eng-second ? "tan⁻¹" : "tan"; clicked => { root.press(root.eng-second ? "eng:atan" : "eng:tan"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: root.eng-second ? "³√x" : "√x"; clicked => { root.press(root.eng-second ? "eng:cbrt" : "eng:sqrt"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "÷"; clicked => { root.press("/"); } } } Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: root.eng-second ? "x³" : "x²"; clicked => { root.press(root.eng-second ? "eng:cube" : "eng:sq"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "1/x"; clicked => { root.press("eng:inv"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "|x|"; clicked => { root.press("eng:abs"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "n!"; clicked => { root.press("eng:fact"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "×"; clicked => { root.press("*"); } } } Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: "x^y"; clicked => { root.press("^"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "("; clicked => { root.press("("); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: ")"; clicked => { root.press(")"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "CE"; clicked => { root.press("CE"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "−"; clicked => { root.press("-"); } } } Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: root.eng-second ? "eˣ" : "10ˣ"; clicked => { root.press(root.eng-second ? "eng:exp" : "eng:tenpow"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "7"; clicked => { root.press("7"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "8"; clicked => { root.press("8"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "9"; clicked => { root.press("9"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "+"; clicked => { root.press("+"); } } } Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: "log"; clicked => { root.press("eng:log"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "4"; clicked => { root.press("4"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "5"; clicked => { root.press("5"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "6"; clicked => { root.press("6"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "±"; clicked => { root.press("neg"); } } } Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: "ln"; clicked => { root.press("eng:ln"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "1"; clicked => { root.press("1"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "2"; clicked => { root.press("2"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "3"; clicked => { root.press("3"); } } EqBtn { min-h: UiStyle.btn-h-sm; clicked => { root.press("="); } } } Row { DigitBtn { min-h: UiStyle.btn-h-sm; label: "0"; clicked => { root.press("0"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "."; clicked => { root.press("."); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "exp"; clicked => { root.press("eng:exp"); } } Rectangle { min-height: 32px; background: transparent; } Rectangle { min-height: 32px; background: transparent; } } } if root.mode == 0: HorizontalLayout { spacing: 6px; height: 30px; ModeTab { label: "Ordinary"; active: root.std-panel == 0; clicked => { root.press("panel:std"); } } ModeTab { label: "Formula"; active: root.std-panel == 1; clicked => { root.press("panel:formula"); } } } if root.mode == 0: HorizontalLayout { spacing: 6px; height: 32px; MemBtn { label: "MC"; clicked => { root.press("MC"); } } MemBtn { label: "MR"; clicked => { root.press("MR"); } } MemBtn { label: "M+"; clicked => { root.press("M+"); } } MemBtn { label: "M-"; clicked => { root.press("M-"); } } MemBtn { label: "MS"; clicked => { root.press("MS"); } } } if root.mode == 0: GridLayout { spacing: 6px; Row { if root.std-panel == 0: FuncBtn { label: "%"; clicked => { root.press("%"); } } if root.std-panel == 1: FuncBtn { label: "("; clicked => { root.press("("); } } if root.std-panel == 0: FuncBtn { label: "CE"; clicked => { root.press("CE"); } } if root.std-panel == 1: FuncBtn { label: ")"; clicked => { root.press(")"); } } FuncBtn { label: "C"; clicked => { root.press("C"); } } FuncBtn { label: "⌫"; clicked => { root.press("BS"); } } } Row { FuncBtn { label: "1/x"; enabled: root.std-panel == 0; clicked => { root.press("1/x"); } } FuncBtn { label: "x²"; enabled: root.std-panel == 0; clicked => { root.press("x2"); } } FuncBtn { label: "√x"; enabled: root.std-panel == 0; clicked => { root.press("sqrt"); } } FuncBtn { label: "÷"; clicked => { root.press("/"); } } } Row { DigitBtn { label: "7"; clicked => { root.press("7"); } } DigitBtn { label: "8"; clicked => { root.press("8"); } } DigitBtn { label: "9"; clicked => { root.press("9"); } } FuncBtn { label: "×"; clicked => { root.press("*"); } } } Row { DigitBtn { label: "4"; clicked => { root.press("4"); } } DigitBtn { label: "5"; clicked => { root.press("5"); } } DigitBtn { label: "6"; clicked => { root.press("6"); } } FuncBtn { label: "−"; clicked => { root.press("-"); } } } Row { DigitBtn { label: "1"; clicked => { root.press("1"); } } DigitBtn { label: "2"; clicked => { root.press("2"); } } DigitBtn { label: "3"; clicked => { root.press("3"); } } FuncBtn { label: "+"; clicked => { root.press("+"); } } } Row { DigitBtn { label: "±"; clicked => { root.press("neg"); } } DigitBtn { label: "0"; clicked => { root.press("0"); } } DigitBtn { label: "."; clicked => { root.press("."); } } EqBtn { clicked => { root.press("="); } } } } if root.mode == 2: GridLayout { spacing: 4px; Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: root.word-size-label; clicked => { root.press("word"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "CE"; clicked => { root.press("CE"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "C"; clicked => { root.press("clear"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "⌫"; clicked => { root.press("BS"); } } } Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: "AND"; clicked => { root.press("AND"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "OR"; clicked => { root.press("OR"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "NOT"; clicked => { root.press("NOT"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "NAND"; clicked => { root.press("NAND"); } } } Row { FuncBtn { min-h: UiStyle.btn-h-sm; label: "NOR"; clicked => { root.press("NOR"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "XOR"; clicked => { root.press("XOR"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "Lsh"; clicked => { root.press("Lsh"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "Rsh"; clicked => { root.press("Rsh"); } } } Row { DigitBtn { min-h: UiStyle.btn-h-sm; label: "A"; enabled: root.allow-a; clicked => { root.press("A"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "B"; enabled: root.allow-a; clicked => { root.press("B"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "C"; enabled: root.allow-a; clicked => { root.press("C"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "÷"; clicked => { root.press("/"); } } } Row { DigitBtn { min-h: UiStyle.btn-h-sm; label: "D"; enabled: root.allow-a; clicked => { root.press("D"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "E"; enabled: root.allow-a; clicked => { root.press("E"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "F"; enabled: root.allow-a; clicked => { root.press("F"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "×"; clicked => { root.press("*"); } } } Row { DigitBtn { min-h: UiStyle.btn-h-sm; label: "7"; enabled: root.allow-2; clicked => { root.press("7"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "8"; enabled: root.allow-8; clicked => { root.press("8"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "9"; enabled: root.allow-8; clicked => { root.press("9"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "−"; clicked => { root.press("-"); } } } Row { DigitBtn { min-h: UiStyle.btn-h-sm; label: "4"; enabled: root.allow-2; clicked => { root.press("4"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "5"; enabled: root.allow-2; clicked => { root.press("5"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "6"; enabled: root.allow-2; clicked => { root.press("6"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "+"; clicked => { root.press("+"); } } } Row { DigitBtn { min-h: UiStyle.btn-h-sm; label: "1"; clicked => { root.press("1"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "2"; enabled: root.active-base != 3; clicked => { root.press("2"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "3"; enabled: root.allow-2; clicked => { root.press("3"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: "%"; clicked => { root.press("%"); } } } Row { DigitBtn { min-h: UiStyle.btn-h-sm; label: "±"; clicked => { root.press("neg"); } } DigitBtn { min-h: UiStyle.btn-h-sm; label: "0"; clicked => { root.press("0"); } } FuncBtn { min-h: UiStyle.btn-h-sm; label: root.show-bits ? "Bits●" : "Bits"; clicked => { root.press("bits"); } } EqBtn { min-h: UiStyle.btn-h-sm; clicked => { root.press("="); } } } } if root.mode == 5: VerticalLayout { spacing: 14px; padding-top: 8px; Text { text: "Appearance"; color: UiStyle.accent; font-size: 16px; font-weight: 700; } Text { text: "Button size"; color: UiStyle.text-dim; font-size: 12px; } HorizontalLayout { spacing: 6px; ModeTab { label: "1 Compact"; active: root.cfg-button-size == 1; clicked => { root.press("cfg:size:1"); } } ModeTab { label: "2 Normal"; active: root.cfg-button-size == 2; clicked => { root.press("cfg:size:2"); } } ModeTab { label: "3 Large"; active: root.cfg-button-size == 3; clicked => { root.press("cfg:size:3"); } } } Text { text: "Theme"; color: UiStyle.text-dim; font-size: 12px; } HorizontalLayout { spacing: 6px; ModeTab { label: "Dark"; active: root.cfg-theme == 0; clicked => { root.press("cfg:theme:0"); } } ModeTab { label: "Light"; active: root.cfg-theme == 1; clicked => { root.press("cfg:theme:1"); } } ModeTab { label: "Blue"; active: root.cfg-theme == 2; clicked => { root.press("cfg:theme:2"); } } } Text { text: "Settings are saved automatically."; color: UiStyle.text-dim; font-size: 12px; } HorizontalLayout { spacing: 6px; FuncBtn { label: "Back"; clicked => { root.press("mode:std"); } } } } } forward-focus: key-handler; key-handler := FocusScope { key-pressed(event) => { if (root.mode == 4) { return reject; } if (event.text == Key.Return) { root.press("="); return accept; } if (event.text == Key.Backspace) { root.press("BS"); return accept; } if (event.text == Key.Escape) { root.press(root.mode == 0 || root.mode == 1 ? "C" : "clear"); return accept; } if (event.text == Key.Delete) { root.press("CE"); return accept; } if (event.text != "") { root.press(event.text); return accept; } reject } } }