Skip to content
Snippets Groups Projects
Commit 42d63b98 authored by Loïc Correnson's avatar Loïc Correnson
Browse files

Merge branch 'feature/ivette/visible-functions-filter' into 'master'

[ivette] Visible functions filter

See merge request frama-c/frama-c!3621
parents 8adf0b37 db274ff9
No related branches found
No related tags found
No related merge requests found
...@@ -34,6 +34,8 @@ import { useFlipSettings } from 'dome'; ...@@ -34,6 +34,8 @@ import { useFlipSettings } from 'dome';
import { Badge } from 'dome/controls/icons'; import { Badge } from 'dome/controls/icons';
import { Label } from 'dome/controls/labels'; import { Label } from 'dome/controls/labels';
import { classes } from 'dome/misc/utils'; import { classes } from 'dome/misc/utils';
import { Hbox, Hfill } from 'dome/layout/boxes';
import { IconButton, IconButtonProps } from 'dome/controls/buttons';
import './style.css'; import './style.css';
...@@ -70,12 +72,12 @@ export function SideBar(props: SideBarProps): JSX.Element { ...@@ -70,12 +72,12 @@ export function SideBar(props: SideBarProps): JSX.Element {
export type BadgeElt = undefined | null | string | number | React.ReactNode; export type BadgeElt = undefined | null | string | number | React.ReactNode;
export type Badges = BadgeElt | BadgeElt[]; export type Badges = BadgeElt | BadgeElt[];
const makeBadgeElt = (elt: BadgeElt): React.ReactNode => { const makeBadgeElt = (elt: BadgeElt, index: number): React.ReactNode => {
if (elt === undefined || elt === null) return null; if (elt === undefined || elt === null) return null;
switch (typeof (elt)) { switch (typeof (elt)) {
case 'number': case 'number':
case 'string': case 'string':
return <Badge value={elt} />; return <Badge value={elt} key={`item#${index}`} />;
default: default:
return elt; return elt;
} }
...@@ -84,27 +86,9 @@ const makeBadgeElt = (elt: BadgeElt): React.ReactNode => { ...@@ -84,27 +86,9 @@ const makeBadgeElt = (elt: BadgeElt): React.ReactNode => {
const makeBadge = (elt: Badges): React.ReactNode => { const makeBadge = (elt: Badges): React.ReactNode => {
if (Array.isArray(elt)) if (Array.isArray(elt))
return elt.map(makeBadgeElt); return elt.map(makeBadgeElt);
return makeBadgeElt(elt); return makeBadgeElt(elt, 0);
}; };
// --------------------------------------------------------------------------
// --- SideBar Section Hide/Show Button
// --------------------------------------------------------------------------
interface HideShowProps {
onClick: () => void;
visible: boolean;
}
const HideShow = (props: HideShowProps): JSX.Element => (
<label
className="dome-xSideBarSection-hideshow dome-text-label"
onClick={props.onClick}
>
{props.visible ? 'Hide' : 'Show'}
</label>
);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// --- SideBar Section // --- SideBar Section
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
...@@ -126,10 +110,12 @@ export interface SectionProps { ...@@ -126,10 +110,12 @@ export interface SectionProps {
disabled?: boolean; disabled?: boolean;
/** Badge summary (only visible when folded). */ /** Badge summary (only visible when folded). */
summary?: Badges; summary?: Badges;
/** Right-click callback. */ /** Additional controls, (only visible when unfolded). */
onContextMenu?: () => void; rightButtonProps?: IconButtonProps;
/** Section contents. */ /** Section contents. */
children?: React.ReactNode; children?: React.ReactNode;
/** Additionnal CSS class. */
className?: string;
} }
/** /**
...@@ -143,32 +129,34 @@ export interface SectionProps { ...@@ -143,32 +129,34 @@ export interface SectionProps {
Sections with no items are not displayed. Sections with no items are not displayed.
*/ */
export function Section(props: SectionProps): JSX.Element | null { export function Section(props: SectionProps): JSX.Element | null {
const { settings, defaultUnfold, unfold } = props;
const [state, flipState] = useFlipSettings( const [state, flipState] = useFlipSettings(settings, defaultUnfold);
props.settings, const icon = state ? 'TRIANGLE.DOWN' : 'TRIANGLE.RIGHT';
props.defaultUnfold,
);
const { enabled = true, disabled = false, children } = props; const { enabled = true, disabled = false, children } = props;
if (disabled || !enabled || React.Children.count(children) === 0) if (disabled || !enabled || React.Children.count(children) === 0) return null;
return null;
const { unfold } = props;
const foldable = unfold === undefined;
const visible = unfold ?? state; const visible = unfold ?? state;
const maxHeight = visible ? 'max-content' : 0; const maxHeight = visible ? 'max-content' : 0;
const { rightButtonProps: iconProps } = props;
const className = `dome-xSideBarSection-filterButton ${iconProps?.className}`;
const rightButton =
iconProps ? <IconButton {...iconProps} className={className}/> : undefined;
return ( return (
<div className="dome-xSideBarSection"> <div className={`dome-xSideBarSection ${props.className}`}>
<div <Hbox>
className="dome-xSideBarSection-title dome-color-frame" <Label
title={props.title} className='dome-xSideBarSection-title dome-color-frame'
onContextMenu={props.onContextMenu} title={props.title}
> label={props.label}
<Label label={props.label} /> icon={icon}
{!visible && makeBadge(props.summary)} onClick={flipState}
{foldable && <HideShow visible={visible} onClick={flipState} />} />
</div> <Hfill />
<div className="dome-xSideBarSection-content" style={{ maxHeight }}> {visible ? rightButton : makeBadge(props.summary)}
</Hbox>
<div className='dome-xSideBarSection-content' style={{ maxHeight }}>
{children} {children}
</div> </div>
</div> </div>
......
...@@ -105,12 +105,13 @@ ...@@ -105,12 +105,13 @@
.dome-xSideBarSection { .dome-xSideBarSection {
display: block ; display: block ;
padding: 0px ; padding: 0px ;
padding-top: 3px;
} }
.dome-xSideBarSection-title { .dome-xSideBarSection-title {
position: sticky ; position: sticky ;
top: 0px ; top: 0px ;
padding-top: 3px ; padding-top: 0px;
padding-bottom: 0px ; padding-bottom: 0px ;
padding-left: 3px ; padding-left: 3px ;
padding-right: 2px ; padding-right: 2px ;
...@@ -130,6 +131,11 @@ ...@@ -130,6 +131,11 @@
flex: 0 0 ; flex: 0 0 ;
} }
.dome-xSideBarSection-filterButton {
margin: 0px;
padding: 0px;
}
.dome-xSideBarSection-hideshow { .dome-xSideBarSection-hideshow {
flex: 0 0 ; flex: 0 0 ;
margin: 1px ; margin: 1px ;
...@@ -149,6 +155,23 @@ ...@@ -149,6 +155,23 @@
transition: max-height 250ms ease-in-out ; transition: max-height 250ms ease-in-out ;
} }
.dome-xSideBarSection-content > .dome-xBoxButton {
margin-left: 20px;
margin-right: 10px;
margin-top: 7px;
color: var(--info-text);
fill: var(--info-text);
display: flex;
}
.dome-xSideBarSection-info {
color: var(--info-text-discrete);
font-style: italic;
padding-left: 20px;
padding-right: 10px;
display: block;
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* --- SideBar Items --- */ /* --- SideBar Items --- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
......
...@@ -29,6 +29,7 @@ import * as Dome from 'dome'; ...@@ -29,6 +29,7 @@ import * as Dome from 'dome';
import { classes } from 'dome/misc/utils'; import { classes } from 'dome/misc/utils';
import { alpha } from 'dome/data/compare'; import { alpha } from 'dome/data/compare';
import { Section, Item } from 'dome/frame/sidebars'; import { Section, Item } from 'dome/frame/sidebars';
import { Button } from 'dome/controls/buttons';
import * as Ivette from 'ivette'; import * as Ivette from 'ivette';
import * as States from 'frama-c/states'; import * as States from 'frama-c/states';
...@@ -180,21 +181,48 @@ export default function Globals(): JSX.Element { ...@@ -180,21 +181,48 @@ export default function Globals(): JSX.Element {
const nTotal = fcts.length; const nTotal = fcts.length;
const nFilter = filtered.length; const nFilter = filtered.length;
const title = `Functions ${nFilter} / ${nTotal}`; const title = `Functions ${nFilter} / ${nTotal}`;
const filterButtonProps = {
icon: 'TUNINGS',
title: `Functions filtering options (${nFilter} / ${nTotal})`,
onClick: onContextMenu,
};
const filteredFunctions =
filtered.map((fct) => (
<FctItem
key={fct.name}
fct={fct}
current={current}
onSelection={onSelection}
/>
));
const noFunction =
<div className='dome-xSideBarSection-content'>
<label className='dome-xSideBarSection-info'>
{'There is no function to display.'}
</label>
</div>;
const allFiltered =
<div className='dome-xSideBarSection-content'>
<label className='dome-xSideBarSection-info'>
{'All functions are filtered. Try adjusting function filters.'}
</label>
<Button {...filterButtonProps} label='Functions filters' />
</div>;
return ( return (
<Section <Section
label="Functions" label="Functions"
title={title} title={title}
onContextMenu={onContextMenu}
defaultUnfold defaultUnfold
rightButtonProps={filterButtonProps}
summary={[nFilter]}
className='globals-function-section'
> >
{filtered.map((fct) => ( {nFilter > 0 ? filteredFunctions : nTotal > 0 ? allFiltered : noFunction}
<FctItem
key={fct.name}
fct={fct}
current={current}
onSelection={onSelection}
/>
))}
</Section> </Section>
); );
......
...@@ -49,6 +49,10 @@ ...@@ -49,6 +49,10 @@
color: #aaa; color: #aaa;
} }
.globals-function-section {
padding-right: 3px;
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* --- Globals --- */ /* --- Globals --- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment