diff --git a/ivette/src/dome/renderer/controls/buttons.tsx b/ivette/src/dome/renderer/controls/buttons.tsx index 85e2b5a79f40f80bd6a2f2ded689b351202cef79..335e9f1640b601d44cf1d2ab81525e58b5891a23 100644 --- a/ivette/src/dome/renderer/controls/buttons.tsx +++ b/ivette/src/dome/renderer/controls/buttons.tsx @@ -32,7 +32,6 @@ import React from 'react'; import { classes } from 'dome/misc/utils'; import { Icon } from './icons'; -import { LabelProps } from './labels'; import './style.css'; interface EVENT { @@ -48,68 +47,6 @@ const TRIGGER = (onClick?: () => void) => (evt?: EVENT) => { if (onClick) onClick(); }; -// -------------------------------------------------------------------------- -// --- LCD -// -------------------------------------------------------------------------- - -/** Button-like label. */ -export function LCD(props: LabelProps) { - const className = classes( - 'dome-xButton dome-xBoxButton dome-text-code dome-xButton-lcd ', - props.className, - ); - return ( - <label - className={className} - title={props.title} - style={props.style} - > - {props.icon && <Icon id={props.icon} />} - {props.label} - {props.children} - </label> - ); -} - -// -------------------------------------------------------------------------- -// --- Led -// -------------------------------------------------------------------------- - -export type LEDstatus = - undefined | 'inactive' | 'active' | 'positive' | 'negative' | 'warning'; - -export interface LEDprops { - /** - Led status: - - `'inactive'`: off (default) - - `'active'`: blue color - - `'positive'`: green color - - `'negative'`: red color - - `'warning'`: orange color - */ - status?: LEDstatus; - /** Blinking Led (default: `false`). */ - blink?: boolean; - /** Tooltip text. */ - title?: string; - /** Additional CSS class. */ - className?: string; - /** Additional CSS style. */ - style?: React.CSSProperties; -} - -export const LED = (props: LEDprops) => { - const className = classes( - 'dome-xButton-led', - `dome-xButton-led-${props.status || 'inactive'}`, - props.blink && 'dome-xButton-blink', - props.className, - ); - return ( - <div className={className} title={props.title} style={props.style} /> - ); -}; - // -------------------------------------------------------------------------- // --- Button // -------------------------------------------------------------------------- diff --git a/ivette/src/dome/renderer/controls/displays.tsx b/ivette/src/dome/renderer/controls/displays.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1a0586bc6db844d6f8d6b0faa22d59e8d7c6cac3 --- /dev/null +++ b/ivette/src/dome/renderer/controls/displays.tsx @@ -0,0 +1,145 @@ +/* ************************************************************************ */ +/* */ +/* This file is part of Frama-C. */ +/* */ +/* Copyright (C) 2007-2021 */ +/* 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). */ +/* */ +/* ************************************************************************ */ + +// -------------------------------------------------------------------------- +// --- LEDs, LCD, meters, etc. +// -------------------------------------------------------------------------- + +/** + @packageDocumentation + @module dome/controls/displays + */ + +import React from 'react'; +import { classes } from 'dome/misc/utils'; +import { Icon } from './icons'; +import { LabelProps } from './labels'; +import './style.css'; + +// -------------------------------------------------------------------------- +// --- LCD +// -------------------------------------------------------------------------- + +/** Button-like label. */ +export function LCD(props: LabelProps) { + const className = classes( + 'dome-xButton dome-xBoxButton dome-text-code dome-xButton-lcd ', + props.className, + ); + return ( + <label + className={className} + title={props.title} + style={props.style} + > + {props.icon && <Icon id={props.icon} />} + {props.label} + {props.children} + </label> + ); +} + +// -------------------------------------------------------------------------- +// --- Led +// -------------------------------------------------------------------------- + +export type LEDstatus = + undefined | 'inactive' | 'active' | 'positive' | 'negative' | 'warning'; + +export interface LEDprops { + /** + Led status: + - `'inactive'`: off (default) + - `'active'`: blue color + - `'positive'`: green color + - `'negative'`: red color + - `'warning'`: orange color + */ + status?: LEDstatus; + /** Blinking Led (default: `false`). */ + blink?: boolean; + /** Tooltip text. */ + title?: string; + /** Additional CSS class. */ + className?: string; + /** Additional CSS style. */ + style?: React.CSSProperties; +} + +export const LED = (props: LEDprops) => { + const className = classes( + 'dome-xButton-led', + `dome-xButton-led-${props.status || 'inactive'}`, + props.blink && 'dome-xButton-blink', + props.className, + ); + return ( + <div className={className} title={props.title} style={props.style} /> + ); +}; + +// -------------------------------------------------------------------------- +// --- Metter +// -------------------------------------------------------------------------- + +export interface MeterProps { + /** Additional CSS class. */ + className?: string; + /** Additional CSS style. */ + style?: React.CSSProperties; + /** Disabled control. */ + /** Meter value. Undefined means disabled. */ + value: number; /** default is undefined */ + min?: number; /** default is 0.0 */ + low?: number; /** default is 0.0 */ + high?: number; /** default is 1.0 */ + max?: number; /** default is 1.0 */ + optimum?: number | 'LOW' | 'MEDIUM' | 'HIGH'; /** default is undefined */ +} + +export const Meter = (props: MeterProps) => { + const { className, style, value, optimum, ...ms } = props; + const min = props.min ?? 0.0; + const max = props.max ?? 1.0; + const low = props.low ?? min; + const hight = props.high ?? max; + const theClass = classes('dome-xMeter', className); + let opt: number | undefined; + if (value !== undefined) + switch (optimum) { + case 'LOW': opt = (min + low) / 2; break; + case 'MEDIUM': opt = (low + hight) / 2; break; + case 'HIGH': opt = (hight + max) / 2; break; + default: opt = optimum; + } + const mv = value === undefined ? min : Math.min(max, Math.max(min, value)); + return ( + <meter + className={theClass} + style={style} + value={mv} + optimum={opt} + {...ms} /> + ); +}; + +// -------------------------------------------------------------------------- diff --git a/ivette/src/dome/renderer/controls/style.css b/ivette/src/dome/renderer/controls/style.css index ffbf1cabcf280cee2b4a4a612cc1b7f35e096128..a7c192a15d462a89ed9982b5c848ea6c5a0a3b0e 100644 --- a/ivette/src/dome/renderer/controls/style.css +++ b/ivette/src/dome/renderer/controls/style.css @@ -248,6 +248,38 @@ background: radial-gradient( circle at center , #ffc749 , #ecd44f ); } +/* -------------------------------------------------------------------------- */ +/* --- Styling Meters --- */ +/* -------------------------------------------------------------------------- */ + + +meter.dome-xMeter { + background: white; + border-radius: 5px; + box-shadow: + 0 0 4px 4px rgba(0,0,0,0.15) inset; + height: 16px; + width: 70px; +} + +meter.dome-xMeter::-webkit-meter-bar { + background: transparent; + border-radius: 5px; + height: 14px; +} + +meter.dome-xMeter::-webkit-meter-optimum-value { + background: linear-gradient(to bottom, #4a0 0%, #8f0 20%, #4a0 100%); +} + +meter.dome-xMeter::-webkit-meter-suboptimum-value { + background: linear-gradient(to bottom, #aa0 0%, #ff0 20%, #aa0 100%); +} + +meter.dome-xMeter::-webkit-meter-even-less-good-value { + background: linear-gradient(to bottom, #a40 0%, #f80 20%, #a40 100%); +} + /* -------------------------------------------------------------------------- */ /* --- Styling Checkbox --- */ /* -------------------------------------------------------------------------- */ diff --git a/ivette/src/frama-c/kernel/Status.tsx b/ivette/src/frama-c/kernel/Status.tsx index 7c0f6ecec41e68267d03bb32e4f3ac580e1afc85..8c4040ca0ca8c9ff3fbbfca1bff35daca648c3f6 100644 --- a/ivette/src/frama-c/kernel/Status.tsx +++ b/ivette/src/frama-c/kernel/Status.tsx @@ -26,7 +26,8 @@ import React from 'react'; import { Code } from 'dome/controls/labels'; -import { LED, IconButton } from 'dome/controls/buttons'; +import { IconButton } from 'dome/controls/buttons'; +import { LED } from 'dome/controls/displays'; import { Icon } from 'dome/controls/icons'; import * as Toolbars from 'dome/frame/toolbars'; import { GlobalState, useGlobalState } from 'dome/data/states'; diff --git a/ivette/src/frama-c/plugins/eva/CoverageMeter.tsx b/ivette/src/frama-c/plugins/eva/CoverageMeter.tsx index b540dc668669eaeabf30532803a5f4e80eb8ac8c..fe709dea8cd16a3dac7fae2ba63998551318fddc 100644 --- a/ivette/src/frama-c/plugins/eva/CoverageMeter.tsx +++ b/ivette/src/frama-c/plugins/eva/CoverageMeter.tsx @@ -21,6 +21,7 @@ /* ************************************************************************ */ import React from 'react'; +import { Meter } from 'dome/controls/displays'; export interface CoverageProps { reachable: number; @@ -37,12 +38,12 @@ export default function(props: { coverage: CoverageProps }) { const total = reachable + dead; return ( - <meter + <Meter min={0} max={total} low={0.50 * total} high={0.85 * total} - optimum={total} + optimum='HIGH' value={reachable} /> ); diff --git a/ivette/src/frama-c/plugins/eva/Summary.tsx b/ivette/src/frama-c/plugins/eva/Summary.tsx index 0a48090a333743f2cb7e381f6ac695e34648d8ef..69e191ea73b54c70c24e2d94d7f9b10a697e4ee8 100644 --- a/ivette/src/frama-c/plugins/eva/Summary.tsx +++ b/ivette/src/frama-c/plugins/eva/Summary.tsx @@ -22,12 +22,11 @@ // React & Dome import React from 'react'; +import { LED } from 'dome/controls/displays'; import * as Ivette from 'ivette'; import * as States from 'frama-c/states'; import * as Eva from 'frama-c/api/plugins/eva/general'; -import { LED } from 'dome/controls/buttons'; - import CoverageMeter, { percent } from './CoverageMeter'; import './summary.css'; @@ -143,10 +142,10 @@ function Alarms(data: Eva.programStatsType, </tbody> </table> {invalid > 0 && ( - <div> - {invalid} of them {invalid === 1 ? 'is a' : 'are'} sure - alarm{plural(invalid)}. - </div> + <div> + {invalid} of them {invalid === 1 ? 'is a' : 'are'} sure + alarm{plural(invalid)}. + </div> )} </> ); diff --git a/ivette/src/renderer/Controller.tsx b/ivette/src/renderer/Controller.tsx index ad77caab74c06c5c50b4d49f4751e33939864a7f..5c98b76014256856cdc287efc7cbf694bda9c835 100644 --- a/ivette/src/renderer/Controller.tsx +++ b/ivette/src/renderer/Controller.tsx @@ -30,7 +30,8 @@ import * as Json from 'dome/data/json'; import * as Settings from 'dome/data/settings'; import * as Toolbars from 'dome/frame/toolbars'; -import { LED, LEDstatus, IconButton } from 'dome/controls/buttons'; +import { IconButton } from 'dome/controls/buttons'; +import { LED, LEDstatus } from 'dome/controls/displays'; import { Label, Code } from 'dome/controls/labels'; import { RichTextBuffer } from 'dome/text/buffers'; import { Text } from 'dome/text/editors'; diff --git a/ivette/src/renderer/style.css b/ivette/src/renderer/style.css index a345a1844183fc546a80e154eedc19e4360b5e04..fa02656e5992d03b039c13ea4f5eb9cd74e8677c 100644 --- a/ivette/src/renderer/style.css +++ b/ivette/src/renderer/style.css @@ -67,32 +67,3 @@ } /* -------------------------------------------------------------------------- */ -/* --- Meters --- */ -/* -------------------------------------------------------------------------- */ - -meter { - background: white; - border-radius: 5px; - box-shadow: - 0 0 4px 4px rgba(0,0,0,0.15) inset; - height: 16px; - width: 70px; -} - -meter::-webkit-meter-bar { - background: transparent; - border-radius: 5px; - height: 14px; -} - -meter::-webkit-meter-optimum-value { - background: linear-gradient(to bottom, #4a0 0%, #8f0 20%, #4a0 100%); -} - -meter::-webkit-meter-suboptimum-value { - background: linear-gradient(to bottom, #aa0 0%, #ff0 20%, #aa0 100%); -} - -meter::-webkit-meter-even-less-good-value { - background: linear-gradient(to bottom, #a40 0%, #f80 20%, #a40 100%); -}