diff --git a/entry/src/main/ets/components/Menubar.ets b/entry/src/main/ets/components/Menubar.ets new file mode 100644 index 0000000..0dd100d --- /dev/null +++ b/entry/src/main/ets/components/Menubar.ets @@ -0,0 +1,86 @@ +import { UIComponent, analysisXML } from "../utils/XMLHandler"; +import { common } from '@kit.AbilityKit'; +import { util } from '@kit.ArkTS'; +import { BusinessError } from '@kit.BasicServicesKit'; + + + +@ComponentV2 + + +export struct Menubar { + private content: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext; + @Local ui_components: UIComponent[] = []; + + aboutToAppear() { + const xml_string = this.getXML(); + this.ui_components = analysisXML(xml_string); + } + + getXML(): string { + try { + let data: Uint8Array = this.content.resourceManager.getRawFileContentSync("mainmenubar.xml"); + let text_decoder: util.TextDecoder = util.TextDecoder.create("utf-8", { ignoreBOM: true }); + let xml_string: string = text_decoder.decodeToString(data, { stream: false }); + return xml_string; + } catch (err) { + let code: number = (err as BusinessError).code; + let message: string = (err as BusinessError).message; + console.log(`[Error](${code}): ${message}`); + return ""; + } + } + + @Builder + buildMenu(items: UIComponent[]) { + Menu() { + ForEach(items, (item: UIComponent) => { + if (item.isSection === true) { + MenuItemGroup() { + ForEach(item.children || [], (sub: UIComponent) => { + this.buildMenuItem(sub); + }, (sub: UIComponent, idx) => idx.toString()) + } + } else { + this.buildMenuItem(item); + } + }, (item: UIComponent, idx) => idx.toString()); + } + } + + @Builder + buildMenuItem(item: UIComponent) { + if (item.children && item.children?.length > 0) { + MenuItem({ content: item.label, labelInfo: item.accel }) { + this.buildSubMenu(item.children || []); + } + } else { + MenuItem({ content: item.label, labelInfo: item.accel }); + } + } + + @Builder + buildSubMenu(items: UIComponent[]) { + Menu() { + ForEach(items, (sub: UIComponent) => { + if (sub.children && sub.children?.length > 0) { + MenuItem({ content: sub.label, labelInfo: sub.accel }) { + this.buildSubMenu(sub.children || []); + } + } else { + MenuItem({ content: sub.label, labelInfo: sub.accel }); + } + }, (sub: UIComponent, idx) => idx.toString()) + } + } + + build() { + Row() { + ForEach(this.ui_components, (menu: UIComponent) => { + Text(menu.label) + .bindMenu(this.buildMenu(menu.children || [])) + .padding('10vp') + }, (menu: UIComponent, idx) => idx.toString()) + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 0b6eb93..131d6b2 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -1,23 +1,15 @@ -@Entry -@Component -struct Index { - @State message: string = 'Hello World'; +import { Menubar } from "../components/Menubar"; - build() { - RelativeContainer() { - Text(this.message) - .id('HelloWorld') - .fontSize($r('app.float.page_text_font_size')) - .fontWeight(FontWeight.Bold) - .alignRules({ - center: { anchor: '__container__', align: VerticalAlign.Center }, - middle: { anchor: '__container__', align: HorizontalAlign.Center } - }) - .onClick(() => { - this.message = 'Welcome'; - }) + + +@Entry +@ComponentV2 + + +struct Index { + build() { + Column() { + Menubar(); + } } - .height('100%') - .width('100%') - } -} +} \ No newline at end of file diff --git a/entry/src/main/ets/utils/XMLHandler.ets b/entry/src/main/ets/utils/XMLHandler.ets new file mode 100644 index 0000000..73dfa3e --- /dev/null +++ b/entry/src/main/ets/utils/XMLHandler.ets @@ -0,0 +1,120 @@ +import { convertxml } from '@kit.ArkTS'; + +interface XMLNode { + _name: string; + _attributes?: Record; + _text?: string; + _cdata?: string; + elements?: XMLNode[]; +} + +export interface UIComponent { + label: string; + action?: string; + accel?: string; + target?: string | number | boolean; + isSection?: boolean; + children?: UIComponent[]; +} + +export function analysisXML(xml_string: string): UIComponent[] { + const conv = new convertxml.ConvertXML(); + const options: convertxml.ConvertOptions = { + trim: true, + declarationKey: "_declaration", + instructionKey: "_instruction", + attributesKey: "_attributes", + textKey: "_text", + cdataKey: "_cdata", + doctypeKey: "_doctype", + commentKey: "_comment", + parentKey: "_parent", + typeKey: "_type", + nameKey: "_name", + elementsKey: "elements" + }; + + const result = conv.fastConvertToJSObject(xml_string, options) as XMLNode; + const interface_obj = result.elements?.[0]; + const menu = interface_obj?.elements?.find( + (elem: XMLNode) => elem._name === "menu" && elem._attributes?.id === "menubar" + ); + if (!menu) { + return []; + } + return getMenuItem(menu.elements || []); +} + +function getMenuItem(elements: XMLNode[]): UIComponent[] { + const items: UIComponent[] = []; + for (const elem of elements) { + if (elem._name === "submenu") { + const label = getAttribute(elem, "label") || ""; + const children = getMenuItem(elem.elements || []); + items.push({ + label: cleanLabel(label), + children: children.length > 0 ? children : undefined + }); + } else if (elem._name === "item") { + const label = getAttribute(elem, "label") || ""; + const action = getAttribute(elem, "action") || ""; + const accel = getAttribute(elem, "accel") || ""; + let target: string | number | boolean | undefined; + const target_attr = elem.elements?.find( + (e: XMLNode) => e._name === "attribute" && e._attributes?.name === "target" + ); + if (target_attr) { + const text_node = target_attr.elements?.[0]; + const raw = text_node?._text || text_node?._cdata || ""; + const type = target_attr._attributes?.type || "s"; + if (raw !== "") { + switch (type) { + case "i": + target = parseInt(raw, 10); + break; + case "b": + target = raw === "true" || raw === "1"; + break; + default: + target = raw; + break; + } + } + } + items.push({ + label: cleanLabel(label), + action: action, + accel: accel, + target: target + }); + } else if (elem._name === "section") { + const section_items = getMenuItem(elem.elements || []); + if (section_items.length > 0) { + items.push({ + label: "", + isSection: true, + children: section_items + }); + } + } + } + return items; +} + +function getAttribute(element: XMLNode, att_name: string): string | undefined { + const att_elem = element.elements?.find( + (elem: XMLNode) => elem._name === "attribute" && elem._attributes?.name === att_name + ); + if (att_elem) { + const text_node = att_elem.elements?.[0]; + if (text_node) { + return text_node._text || text_node._cdata; + } + return undefined; + } + return undefined; +} + +function cleanLabel(label: string): string { + return label.replace(/_/g, ""); +} \ No newline at end of file diff --git a/entry/src/main/resources/rawfile/mainmenubar.xml b/entry/src/main/resources/rawfile/mainmenubar.xml new file mode 100644 index 0000000..2c4e53d --- /dev/null +++ b/entry/src/main/resources/rawfile/mainmenubar.xml @@ -0,0 +1,874 @@ + + + + + _File + +
+ + _Export as PDF + win.export-as-pdf + + + Export as... + win.export-as + <Ctrl>e + +
+
+ + Print + win.print + <Ctrl>p + + + Quit + app.quit + macos-menubar + +
+
+ + _Edit +
+ + Undo + win.undo + + + + Redo + win.redo + + +
+
+ + Cut + win.cut + + + + Copy + win.copy + + + + Paste + win.paste + + +
+
+ + Select All + win.select-all + <Ctrl>a + +
+
+ + Find + win.search + <Ctrl>f + +
+
+ + Delete + win.delete + Delete + +
+
+ + Arrange Selection +
+ + Bring to Front + win.arrange-selection-order + 0 + + + Bring Forward + win.arrange-selection-order + 1 + + + Send Backward + win.arrange-selection-order + 2 + + + Send to Back + win.arrange-selection-order + 3 + +
+
+
+
+ + Move Selection Layer Up + win.move-selection-layer-up + + + Move Selection Layer Down + win.move-selection-layer-down + +
+
+ + Rotation Snapping + win.rotation-snapping + + + Grid Snapping + win.grid-snapping + +
+
+ + Preferences + app.preferences + macos-menubar + + + T_oolbars +
+ + _Manage + win.manage-toolbar + + + _Customize + win.customize-toolbar + +
+
+
+
+ + _View + +
+ + Show Toolbars + win.show-toolbar + F9 + + + Show Menubar + win.show-menubar + F10 + + + Show Sidebar + win.show-sidebar + F12 + +
+
+ + Layout +
+ + _Horizontal + win.set-layout-vertical + false + + + _Vertical + win.set-layout-vertical + true + +
+
+ + _Left to Right + win.set-layout-right-to-left + false + + + _Right to Left + win.set-layout-right-to-left + true + +
+
+ + _Top to Bottom + win.set-layout-bottom-to-top + false + + + _Bottom to Top + win.set-layout-bottom-to-top + true + +
+
+ + _Cols/Rows +
+ + Set Columns +
+ + + _1 Column + win.set-columns-or-rows + 1 + + + _2 Columns + win.set-columns-or-rows + 2 + + + _3 Columns + win.set-columns-or-rows + 3 + + + _4 Columns + win.set-columns-or-rows + 4 + + + _5 Columns + win.set-columns-or-rows + 5 + + + _6 Columns + win.set-columns-or-rows + 6 + + + _7 Columns + win.set-columns-or-rows + 7 + + + _8 Columns + win.set-columns-or-rows + 8 + +
+
+ + Set Rows +
+ + + _1 Row + win.set-columns-or-rows + -1 + + + _2 Rows + win.set-columns-or-rows + -2 + + + _3 Rows + win.set-columns-or-rows + -3 + + + _4 Rows + win.set-columns-or-rows + -4 + + + _5 Rows + win.set-columns-or-rows + -5 + + + _6 Rows + win.set-columns-or-rows + -6 + + + _7 Rows + win.set-columns-or-rows + -7 + + + _8 Rows + win.set-columns-or-rows + -8 + +
+
+
+
+
+
+ + Zoom In + win.zoom-in + + + + Zoom Out + win.zoom-out + + + + Normal Size + win.zoom-100 + + + Zoom to Fit + win.zoom-fit + +
+
+ + _Navigation + +
+ + _Previous Layer + win.layer-goto-previous + <Shift>Page_Down + + + _Next Layer + win.layer-goto-next + <Shift>Page_Up + + + _Top Layer + win.layer-goto-top + +
+
+ + N_ext Annotated Page + win.goto-next-annotated-page + <Ctrl><Shift>Page_Down + + + P_revious Annotated Page + win.goto-previous-annotated-page + <Ctrl><Shift>Page_Up + +
+
+ + _Journal + +
+ + Add a _Layer above the active layer + win.layer-new-above-current + <Ctrl>l + + + Add a layer below the active layer + win.layer-new-below-current + + + Delete Layer + win.layer-delete + <Ctrl><Shift>l + + + Merge Layer Down + win.layer-merge-down + <Ctrl>m + + + Rename Layer + win.layer-rename + <Ctrl>r + +
+
+ + Paper _Format + win.paper-format + + + Paper _Color + win.paper-background-color + + + Paper B_ackground + +
+
+ + _Tools + +
+ + Drawing Type + + _Shape Recognizer + win.tool-draw-shape-recognizer + <Ctrl>1 + + + Draw Rectangle + win.tool-draw-rectangle + <Ctrl>2 + + + Draw Ellipse + win.tool-draw-ellipse + <Ctrl>3 + + + Draw Arrow + win.tool-draw-arrow + <Ctrl>4 + + + Draw Double Arrow + win.tool-draw-double-arrow + <Ctrl>5 + + + Draw Coordinate System + win.tool-draw-coordinate-system + <Ctrl>6 + + + Draw _Line + win.tool-draw-line + <Ctrl>7 + + + Draw Spline + win.tool-draw-spline + <Ctrl>8 + + +
+
+ + Select Rectangle + win.select-tool + 6 + <Ctrl><Shift>r + + + Select Region + win.select-tool + 7 + <Ctrl><Shift>g + + + Select Multi-Layer Rectangle + win.select-tool + 8 + + + Select Multi-Layer Region + win.select-tool + 9 + + + Select Object + win.select-tool + 10 + <Ctrl><Shift>o + + + _Vertical Space + win.select-tool + 12 + <Ctrl><Shift>v + + + Play Object + win.select-tool + 11 + audio + + + H_and Tool + win.select-tool + 13 + <Ctrl><Shift>a + + + Setsquare + win.setsquare + + + Compass + win.compass + +
+
+ + Pen _Options + +
+ + standard + win.tool-pen-line-style + plain + + + dashed + win.tool-pen-line-style + dash + + + dash-/ dotted + win.tool-pen-line-style + dashdot + + + dotted + win.tool-pen-line-style + dot + +
+
+ + Fi_ll + win.tool-pen-fill + + + Fill opacity + win.tool-pen-fill-opacity + +
+
+ + Eraser Optio_ns + +
+ + _standard + win.tool-eraser-type + 1 + + + _whiteout + win.tool-eraser-type + 2 + + + _delete strokes + win.tool-eraser-type + 3 + +
+
+ + Highlighter Opti_ons + +
+ + Fi_ll + win.tool-highlighter-fill + + + Fill opacity + win.tool-highlighter-fill-opacity + +
+
+ + Select PDF Text Options +
+ + Marker Opacity + win.tool-select-pdf-text-marker-opacity + +
+
+ + Text Font... + win.select-font + <Ctrl><Shift>f + + + Record / Stop + win.audio-record + audio + + + Pause + win.audio-pause-playback + audio + + + Stop + win.audio-stop-playback + audio + + + Forward + win.audio-seek-forwards + audio + + + Back + win.audio-seek-backwards + audio + + + Add/Edit TeX + win.tex + <Ctrl><Shift>x + +
+
+ + _Help + <Ctrl>h + + +
+