diff --git a/ivette/src/frama-c/index.tsx b/ivette/src/frama-c/index.tsx index 22e06943d7667cf2ee7e4d977e1163bb4396596d..67192985b75380ba638c1d7e3c8ee8c8b5abb756 100644 --- a/ivette/src/frama-c/index.tsx +++ b/ivette/src/frama-c/index.tsx @@ -20,9 +20,9 @@ /* */ /* ************************************************************************ */ -/* --------------------------------------------------------------------------*/ -/* --- Frama-C Registry ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Frama-C Registry --- */ +/* -------------------------------------------------------------------------- */ import React from 'react'; import * as Ivette from 'ivette'; @@ -37,9 +37,6 @@ import PivotTable from 'frama-c/kernel/PivotTable'; import Locations from 'frama-c/kernel/Locations'; import Properties from 'frama-c/kernel/Properties'; import Messages from 'frama-c/kernel/Messages'; -import * as SideBar from '../sandbox/sidebar'; - -import funcIco from '../sandbox/icons/function.png'; import 'frama-c/kernel/style.css'; @@ -47,20 +44,27 @@ import * as Menu from 'frama-c/menu'; Menu.init(); -/* --------------------------------------------------------------------------*/ -/* --- Frama-C Kernel Groups ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Frama-C Tools --- */ +/* -------------------------------------------------------------------------- */ + +Ivette.registerSidebar({ + id: 'frama-c.globals', + label: 'AST', + children: <Globals /> +}); + +Ivette.registerToolbar({ id: 'frama-c.history', children: <History /> }); +Ivette.registerStatusbar({ id: 'frama-c.message', children: <Status /> }); + +/* -------------------------------------------------------------------------- */ +/* --- Frama-C Kernel Groups --- */ +/* -------------------------------------------------------------------------- */ Ivette.registerGroup({ id: 'frama-c.kernel', label: 'Frama-C Kernel', }, () => { - Ivette.registerSidebar({ - id: 'frama-c.sidebar', - children: <SideBar.SideBar /> - }); - Ivette.registerToolbar({ id: 'frama-c.history', children: <History /> }); - Ivette.registerStatusbar({ id: 'frama-c.message', children: <Status /> }); Ivette.registerComponent({ id: 'frama-c.astinfo', label: 'Inspector', @@ -105,18 +109,18 @@ Ivette.registerGroup({ }); }); -/* --------------------------------------------------------------------------*/ -/* --- Frama-C Plug-ins Group ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Frama-C Plug-ins Group --- */ +/* -------------------------------------------------------------------------- */ Ivette.registerGroup({ id: 'frama-c.plugins', label: 'Frama-C Plug-ins', }); -/* --------------------------------------------------------------------------*/ -/* --- Frama-C Views ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Frama-C Views --- */ +/* -------------------------------------------------------------------------- */ Ivette.registerView({ id: 'source', @@ -148,16 +152,4 @@ Ivette.registerView({ ], }); -/* --------------------------------------------------------------------------*/ -/* --- Frama-C Categories ---*/ -/* --------------------------------------------------------------------------*/ - -Ivette.registerCategory({ - id: "functions", - label: "Functions", - iconPath: funcIco, - children: <Globals /> -}); - - -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ diff --git a/ivette/src/ivette/index.tsx b/ivette/src/ivette/index.tsx index 1bc90a1e9ab298e1ce7fbb5544df4248396b7ad0..f3169e20e94753f83e1944f991493416a16b6d94 100644 --- a/ivette/src/ivette/index.tsx +++ b/ivette/src/ivette/index.tsx @@ -20,9 +20,9 @@ /* */ /* ************************************************************************ */ -/* --------------------------------------------------------------------------*/ -/* --- Lab View Component ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Lab View Component --- */ +/* -------------------------------------------------------------------------- */ /** @packageDocumentation @@ -36,11 +36,10 @@ import { DefineElement } from 'dome/layout/dispatch'; import { GridItem, GridHbox, GridVbox } from 'dome/layout/grids'; import * as Lab from 'ivette@lab'; import * as Ext from 'ivette@ext'; -import * as Doublebar from '../sandbox/sidebar'; -/* --------------------------------------------------------------------------*/ -/* --- Items ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Items --- */ +/* -------------------------------------------------------------------------- */ export interface ItemProps { /** Identifier. */ @@ -58,9 +57,9 @@ export interface ContentProps extends ItemProps { children?: React.ReactNode; } -/* --------------------------------------------------------------------------*/ -/* --- Groups ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Groups --- */ +/* -------------------------------------------------------------------------- */ let GROUP: string | undefined; @@ -85,9 +84,9 @@ export function registerGroup(group: ItemProps, job?: () => void): void { } } -/* --------------------------------------------------------------------------*/ -/* --- View Layout ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- View Layout --- */ +/* -------------------------------------------------------------------------- */ /** Alternating V-split and H-split layouts. @@ -128,9 +127,9 @@ export function registerView(view: ViewLayoutProps): void { }); } -/* --------------------------------------------------------------------------*/ -/* --- Components ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Components --- */ +/* -------------------------------------------------------------------------- */ export interface ComponentProps extends ContentProps { /** Group attachment. */ @@ -178,9 +177,9 @@ export function TitleBar(props: TitleBarProps): JSX.Element | null { ); } -/* --------------------------------------------------------------------------*/ -/* --- Sidebar Panels ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Sidebar Panels --- */ +/* -------------------------------------------------------------------------- */ export interface ToolProps { id: string; @@ -188,34 +187,38 @@ export interface ToolProps { children?: React.ReactNode; } +/** @ignore */ +export const TOOLBAR = new Ext.ElementRack<ToolProps>(); + +/** @ignore */ +export const STATUSBAR = new Ext.ElementRack<ToolProps>(); + export function registerToolbar(tools: ToolProps): void { - Ext.TOOLBAR.register(tools); + TOOLBAR.register(tools); } export function registerStatusbar(status: ToolProps): void { - Ext.STATUSBAR.register(status); + STATUSBAR.register(status); } -/* --------------------------------------------------------------------------*/ -/* --- Sidebar ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Sidebar --- */ +/* -------------------------------------------------------------------------- */ -export interface SideBarCategoryProps extends ContentProps{ - label: string; +export interface SidebarProps extends ContentProps { iconPath?: string; } -export function registerSidebar(panel: ToolProps): void { - Ext.SIDEBAR.register(panel); -} +/** @ignore */ +export const SIDEBAR = new Ext.ElementRack<SidebarProps>(); -export function registerCategory(props: SideBarCategoryProps): void { - Doublebar.registerCategory(props); +export function registerSidebar(sidebar: SidebarProps): void { + SIDEBAR.register(sidebar); } -/* --------------------------------------------------------------------------*/ -/* --- Sandbox ---*/ -/* --------------------------------------------------------------------------*/ +/* -------------------------------------------------------------------------- */ +/* --- Sandbox --- */ +/* -------------------------------------------------------------------------- */ if (DEVEL) { registerGroup({ @@ -236,4 +239,4 @@ export function registerSandbox(props: ComponentProps): void { if (DEVEL) registerComponent({ ...props, group: 'sandbox' }); } -// -------------------------------------------------------------------------- +/* -------------------------------------------------------------------------- */ diff --git a/ivette/src/renderer/Application.tsx b/ivette/src/renderer/Application.tsx index c6a1f7276e0ced47a5254696419f6ab9623e29ce..e1b8817d674a33c6962b8a8b9403b5bd7b27e1ea 100644 --- a/ivette/src/renderer/Application.tsx +++ b/ivette/src/renderer/Application.tsx @@ -31,10 +31,11 @@ import * as Dome from 'dome'; import { Vfill } from 'dome/layout/boxes'; import { LSplit } from 'dome/layout/splitters'; import * as Toolbar from 'dome/frame/toolbars'; -import * as Sidebar from 'dome/frame/sidebars'; +import * as Sidebar from './Sidebar'; import * as Controller from './Controller'; -import * as Extensions from './Extensions'; import * as Laboratory from './Laboratory'; +import * as Ext from './Extensions'; +import { TOOLBAR, STATUSBAR } from 'ivette'; import * as IvettePrefs from 'ivette/prefs'; import * as Studia from 'frama-c/plugins/studia/studia'; import './loader'; @@ -51,6 +52,8 @@ export default function Application(): JSX.Element { Dome.useFlipSettings('frama-c.viewbar.unfold', true); Studia.useStudiaMode(); + const tools = Ext.useChildren(TOOLBAR); + const status = Ext.useChildren(STATUSBAR); return ( <Vfill> @@ -62,7 +65,7 @@ export default function Application(): JSX.Element { onClick={flipSidebar} /> <Controller.Control /> - <Extensions.Toolbar /> + <>{tools}</> <Toolbar.Filler /> <IvettePrefs.ThemeSwitchTool /> <IvettePrefs.FontTools /> @@ -75,10 +78,7 @@ export default function Application(): JSX.Element { /> </Toolbar.ToolBar> <LSplit settings="frama-c.sidebar.split" unfold={sidebar}> - <Sidebar.SideBar> - <div className="sidebar-ruler" /> - <Extensions.Sidebar /> - </Sidebar.SideBar> + <Sidebar.Panel /> <Laboratory.LabView customize={viewbar} settings="frama-c.labview" @@ -86,7 +86,7 @@ export default function Application(): JSX.Element { </LSplit> <Toolbar.ToolBar> <Controller.Status /> - <Extensions.Statusbar /> + <>{status}</> <Toolbar.Filler /> <Controller.Stats /> </Toolbar.ToolBar> diff --git a/ivette/src/renderer/Extensions.tsx b/ivette/src/renderer/Extensions.tsx index 4b8ec17ea0a59be97d2c5004b6c02102f2199569..3f4a16e55e2b68ddd64f3de494fbff748d4bf830 100644 --- a/ivette/src/renderer/Extensions.tsx +++ b/ivette/src/renderer/Extensions.tsx @@ -39,7 +39,7 @@ export interface ElementProps { children?: React.ReactNode; } -function byPanel(p: ElementProps, q: ElementProps): number { +function byRank(p: ElementProps, q: ElementProps): number { const rp = p.rank ?? 0; const rq = q.rank ?? 0; if (rp < rq) return -1; @@ -51,38 +51,38 @@ function byPanel(p: ElementProps, q: ElementProps): number { return 0; } -export class ElementRack { +export class ElementRack<A extends ElementProps> { private rank = 1; - private readonly items = new Map<string, ElementProps>(); + private readonly items = new Map<string, A>(); - register(elt: ElementProps): void { + register(elt: A): void { if (elt.rank === undefined) elt.rank = this.rank; this.rank++; this.items.set(elt.id, elt); UPDATED.emit(); } - render(): JSX.Element { - const panels: ElementProps[] = []; - this.items.forEach((p) => { if (p.children) { panels.push(p); } }); - const contents = panels.sort(byPanel).map((p) => p.children); - return <>{React.Children.toArray(contents)}</>; + getElements(): A[] { + const buffer: A[] = []; + this.items.forEach((p) => { if (p.children) { buffer.push(p); } }); + return buffer.sort(byRank); } } -export function useRack(E: ElementRack): JSX.Element { +export function useElements<A extends ElementProps>( + E: ElementRack<A> +): A[] { Dome.useUpdate(UPDATED); - return E.render(); + return E.getElements(); } -export const SIDEBAR = new ElementRack(); -export const TOOLBAR = new ElementRack(); -export const STATUSBAR = new ElementRack(); - -export function Sidebar(): JSX.Element { return useRack(SIDEBAR); } -export function Toolbar(): JSX.Element { return useRack(TOOLBAR); } -export function Statusbar(): JSX.Element { return useRack(STATUSBAR); } +export function useChildren<A extends ElementProps>( + E: ElementRack<A> +): React.ReactNode { + const elements = useElements(E); + return React.Children.toArray(elements.map((e) => e.children)); +} /* --------------------------------------------------------------------------*/ diff --git a/ivette/src/renderer/Sidebar.tsx b/ivette/src/renderer/Sidebar.tsx new file mode 100644 index 0000000000000000000000000000000000000000..61d2ac6af260983d3ca0205bd1dd89892e65086f --- /dev/null +++ b/ivette/src/renderer/Sidebar.tsx @@ -0,0 +1,124 @@ +/* ************************************************************************ */ +/* */ +/* This file is part of Frama-C. */ +/* */ +/* Copyright (C) 2007-2023 */ +/* CEA (Commissariat à l'énergie atomique et aux énergies */ +/* alternatives) */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 2.1. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 2.1 */ +/* for more details (enclosed in the file licenses/LGPLv2.1). */ +/* */ +/* ************************************************************************ */ + +// -------------------------------------------------------------------------- +// --- Sidebar Selector +// -------------------------------------------------------------------------- + +import React from 'react'; +import { SIDEBAR } from 'ivette'; +import * as Ext from './Extensions'; + +/* + export function SideBar(): JSX.Element { + const classNameGlobal = classes( + 'dome-xSideBar-double', + ); + + const classNamePrime = classes( + 'dome-xSideBar-double-primary', + 'dome-color-frame', + ); + + const classNamePrimeIcon = classes( + 'dome-xSideBar-double-primary-icon' + ); + + const classNamePrimeLabel = classes( + 'dome-xSideBar-double-primary-label' + ); + + const classNameSecondary = classes( + 'dome-xSideBar-double-secondary', + 'dome-color-frame', + ); + + const [selectedCategory, setSelectedCategory] = useState(0); + + function updateSelected(key: number): void { + setSelectedCategory(key); + categories[key].display = true; + } + + return ( + <Catch label={"dome-xSideBar-double-catch"}> + <div className={classNameGlobal}> + <div className={classNamePrime}> + <> + {categories.map((item, key) => ( + <div key={key}> + {item.iconPath ? + <img + className={classNamePrimeIcon} + id={item.id} + src={item.iconPath} + alt={item.label} + title={item.label} + onClick={ + () => updateSelected(key) + } + /> + : + <label + className={classNamePrimeLabel} + id={item.id} + onClick={ + () => updateSelected(key) + } + > + {item.label.slice(0, 4).toLocaleUpperCase()} + </label> + } + <br/> + </div> + ))} + </> + </div> + <sb.SideBar className={classNameSecondary + + (categories[selectedCategory].display === false ? 'dome-erased' : '')}> + {categories[selectedCategory].children} + </sb.SideBar> + </div> + </Catch> + ); + } + */ + +export function Panel(): JSX.Element { + const sidebars = Ext.useElements(SIDEBAR); + const items = sidebars.map((sb) => ( + <ul key={sb.id}> + {sb.label} + </ul> + )); + return ( + <div> + <div className='sidebar-ruler' /> + Side Bar Selector + <ul> + {items} + </ul> + </div> + ); +} + +// -------------------------------------------------------------------------- diff --git a/ivette/src/sandbox/sidebar.tsx b/ivette/src/sandbox/sidebar.tsx index 41bcd992848478d6840e93ce1df77ef4aae96ada..dc9b9a5dd318d5ad60bd6db972c865ef48feff6d 100644 --- a/ivette/src/sandbox/sidebar.tsx +++ b/ivette/src/sandbox/sidebar.tsx @@ -21,193 +21,52 @@ /* ************************************************************************ */ -import React, { useState } from 'react'; -import { classes } from 'dome/misc/utils'; +import React from 'react'; import { Item, Section } from "dome/frame/sidebars"; -import { Catch } from 'dome/errors'; -import { SideBarCategoryProps, registerSandbox } from 'ivette'; -import * as sb from '../../src/dome/renderer/frame/sidebars'; -import './style.css'; +import * as Ivette from 'ivette'; /* -------------------------------------------------------------------------- */ /* --- Mocking --- */ /* -------------------------------------------------------------------------- */ -interface Category extends SideBarCategoryProps{ - display: boolean; -} - -const itemsSection1 = ( - <div> - <Item - className="class1.1" - label="item 1.1-l" - title="item 1.1-t" - selected={false} - /> - <Item - className="class1.2" - label="item 1.2-l" - title="item 1.2-t" - selected={false} - /> - <Item - className="class1.3" - label="item 1.3-l" - title="item 1.3-t" - selected={false} - /> - </div> -); - -const itemsSection2 = ( - <div> - <Item - className="class2.1" - label="item 2.1-l" - title="item 2.1-t" - selected={false} - /> - <Item - className="class2.2" - label="item 2.2-l" - title="item 2.2-t" - selected={false} - /> - <Item - className="class2.3" - label="item 2.3-l" - title="item 2.3-t" - selected={false} - /> - </div> -); - -export const secondaryMenu1 = ( - <> - <Section - label="label section1" - title="title section1" - defaultUnfold - settings="frama-c.sidebar.updated" - className='globals-function-section' - > - {itemsSection1} - </Section> - <Section - label="label section2" - title="title section2" - defaultUnfold={false} - settings="frama-c.sidebar.updated2" - className='globals-function-section' - > - {itemsSection2} - </Section> -</> -); - -export const secondaryMenu2 = ( - <> - <Section - label="label section1" - title="title section1" - defaultUnfold={false} - settings="frama-c.sidebar.updated2" - className='globals-function-section' - > - {itemsSection2} - </Section> - </> -); - -const categories: Category[] = []; - -export function registerCategory(item: SideBarCategoryProps): void { - categories.push({ ...item, display: false }); -} - -export function SideBar(): JSX.Element { - const classNameGlobal = classes( - 'dome-xSideBar-double', - ); - - const classNamePrime = classes( - 'dome-xSideBar-double-primary', - 'dome-color-frame', - ); - - const classNamePrimeIcon = classes( - 'dome-xSideBar-double-primary-icon' - ); - - const classNamePrimeLabel = classes( - 'dome-xSideBar-double-primary-label' - ); - - const classNameSecondary = classes( - 'dome-xSideBar-double-secondary', - 'dome-color-frame', - ); - - const [selectedCategory, setSelectedCategory] = useState(0); - - function updateSelected(key: number): void { - setSelectedCategory(key); - categories[key].display = true; - } - - return ( - <Catch label={"dome-xSideBar-double-catch"}> - <div className={classNameGlobal}> - <div className={classNamePrime}> - <> - {categories.map((item, key) => ( - <div key={key}> - {item.iconPath ? - <img - className={classNamePrimeIcon} - id={item.id} - src={item.iconPath} - alt={item.label} - title={item.label} - onClick={ - () => updateSelected(key) - } - /> - : - <label - className={classNamePrimeLabel} - id={item.id} - onClick={ - () => updateSelected(key) - } - > - {item.label.slice(0, 4).toLocaleUpperCase()} - </label> - } - <br/> - </div> - ))} - </> - </div> - <sb.SideBar className={classNameSecondary + - (categories[selectedCategory].display === false ? 'dome-erased' : '')}> - {categories[selectedCategory].children} - </sb.SideBar> - </div> - </Catch> - ); -} - - -/* -------------------------------------------------------------------------- */ -/* --- Sandbox --- */ -/* -------------------------------------------------------------------------- */ +Ivette.registerSidebar({ + id: 'sandbox.sidebar.a', + label: 'SandA', + children: + <> + <Section label='Section A.1'> + <Item label='Item A.1.1' /> + <Item label='Item A.1.2' /> + <Item label='Item A.1.3' /> + <Item label='Item A.1.4' /> + </Section> + <Section label='Section A.2'> + <Item label='Item A.2.1' /> + <Item label='Item A.2.2' /> + <Item label='Item A.2.3' /> + <Item label='Item A.2.4' /> + </Section> + </> +}); -registerSandbox({ - id: 'sandbox.sidebar', - label: 'Sidebar', - children: <SideBar />, +Ivette.registerSidebar({ + id: 'sandbox.sidebar.b', + label: 'SandB', + children: + <> + <Section label='Section B.1'> + <Item label='Item B.1.1' /> + <Item label='Item B.1.2' /> + <Item label='Item B.1.3' /> + <Item label='Item B.1.4' /> + </Section> + <Section label='Section B.2'> + <Item label='Item B.2.1' /> + <Item label='Item B.2.2' /> + <Item label='Item B.2.3' /> + <Item label='Item B.2.4' /> + </Section> + </> }); /* -------------------------------------------------------------------------- */ diff --git a/ivette/src/sandbox/sidebarMocking.tsx b/ivette/src/sandbox/sidebarMocking.tsx deleted file mode 100644 index 5b678f03a68f113a963801196490cbe860c1326d..0000000000000000000000000000000000000000 --- a/ivette/src/sandbox/sidebarMocking.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* ************************************************************************ */ -/* */ -/* This file is part of Frama-C. */ -/* */ -/* Copyright (C) 2007-2023 */ -/* CEA (Commissariat à l'énergie atomique et aux énergies */ -/* alternatives) */ -/* */ -/* you can redistribute it and/or modify it under the terms of the GNU */ -/* Lesser General Public License as published by the Free Software */ -/* Foundation, version 2.1. */ -/* */ -/* It is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Lesser General Public License for more details. */ -/* */ -/* See the GNU Lesser General Public License version 2.1 */ -/* for more details (enclosed in the file licenses/LGPLv2.1). */ -/* */ -/* ************************************************************************ */ - - -import React from 'react'; -import * as Ivette from 'ivette'; -import { registerSandbox } from 'ivette'; -import * as SideBar from './sidebar'; -import fileIco from './icons/file.png'; -import folderIco from './icons/folder.png'; - -/* -------------------------------------------------------------------------- */ -/* --- Mocking --- */ -/* -------------------------------------------------------------------------- */ - -export function SideBarMocking(): JSX.Element { - Ivette.registerCategory({ - id: "file", - label: "File", - iconPath: fileIco, - children: SideBar.secondaryMenu1 - }); - Ivette.registerCategory({ - id: "folder", - label: "Folder", - iconPath: folderIco, - children: SideBar.secondaryMenu2 - }); - Ivette.registerCategory({ - id: "lorem", - label: "lorem", - children: SideBar.secondaryMenu1 - }); - Ivette.registerCategory({ - id: "ipsum", - label: "ipsum", - children: SideBar.secondaryMenu2 - }); - - return ( - <SideBar.SideBar></SideBar.SideBar> - ); -} - -/* -------------------------------------------------------------------------- */ -/* --- Sandbox --- */ -/* -------------------------------------------------------------------------- */ - - -registerSandbox({ - id: 'sandbox.sidebar-mocking', - label: 'Sidebar Mocking', - children: <SideBarMocking />, - }); - -/* -------------------------------------------------------------------------- */