Use bootstrap styles.
Better than anything I can do in a short period of time!
This commit is contained in:
parent
5710f10999
commit
6a06a99529
|
@ -1,6 +1,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script src="/static/js/elm.js"></script>
|
<script src="/static/js/elm.js"></script>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||||
<link rel="stylesheet" href="/static/css/style.css">
|
<link rel="stylesheet" href="/static/css/style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -4,30 +4,68 @@ import CacheSim.Model exposing (..)
|
||||||
import CacheSim.Cache exposing (..)
|
import CacheSim.Cache exposing (..)
|
||||||
import CacheSim.AccessView exposing (..)
|
import CacheSim.AccessView exposing (..)
|
||||||
import CacheSim.Hierarchy exposing (..)
|
import CacheSim.Hierarchy exposing (..)
|
||||||
import Html exposing (Html, input, text, div, label, span, h2, h3, table, tr, td)
|
import Html exposing (Html, Attribute, input, text, div, label, span, h2, h3, table, tr, td, th)
|
||||||
import Html.Attributes exposing (type_, class, value, for, classList, disabled, colspan)
|
import Html.Attributes exposing (type_, class, value, for, classList, disabled, colspan, hidden)
|
||||||
import Html.Events exposing (onInput, onClick)
|
import Html.Events exposing (onInput, onClick)
|
||||||
|
|
||||||
optionalButton : Bool -> String -> Msg -> Html Msg
|
-- Button components, powered by Bootstrap
|
||||||
optionalButton e s m =
|
basicButton : List (Attribute Msg) -> String -> Html Msg
|
||||||
let
|
basicButton attrs s = input ([ type_ "button", value s, class "btn", class "btn-info" ] ++ attrs) []
|
||||||
events = if e then [ onClick m ] else [ disabled (not e) ]
|
|
||||||
in
|
disabledButton : String -> Html Msg
|
||||||
input ([ type_ "button", value s ] ++ events) []
|
disabledButton = basicButton [ disabled True ]
|
||||||
|
|
||||||
|
advancedButton : List (Attribute Msg) -> String -> Msg -> Html Msg
|
||||||
|
advancedButton attrs s m = basicButton (attrs ++ [ onClick m ]) s
|
||||||
|
|
||||||
button : String -> Msg -> Html Msg
|
button : String -> Msg -> Html Msg
|
||||||
button s m = input [ type_ "button", onClick m, value s] []
|
button s m = basicButton [ onClick m ] s
|
||||||
|
|
||||||
|
dangerButton : String -> Msg -> Html Msg
|
||||||
|
dangerButton = advancedButton [ class "btn-danger" ]
|
||||||
|
|
||||||
|
primaryButton : String -> Msg -> Html Msg
|
||||||
|
primaryButton = advancedButton [ class "btn-primary" ]
|
||||||
|
|
||||||
|
secondaryButton : String -> Msg -> Html Msg
|
||||||
|
secondaryButton = advancedButton [ class "btn-secondary" ]
|
||||||
|
|
||||||
|
maybeButton : Maybe a -> String -> (a -> Msg) -> Html Msg
|
||||||
|
maybeButton m s f =
|
||||||
|
case m of
|
||||||
|
Just v -> button s (f v)
|
||||||
|
_ -> disabledButton s
|
||||||
|
|
||||||
|
resultButton : Result e a -> String -> (a -> Msg) -> Html Msg
|
||||||
|
resultButton = maybeButton << Result.toMaybe
|
||||||
|
|
||||||
|
-- Button wrapper (button group)
|
||||||
buttonWrapper : List (Html Msg) -> Html Msg
|
buttonWrapper : List (Html Msg) -> Html Msg
|
||||||
buttonWrapper = div [ class "button-wrapper" ]
|
buttonWrapper = div [ classList [("btn-group", True), ("mb-3", True) ] ]
|
||||||
|
|
||||||
|
-- Input with a label
|
||||||
labeledInput : String -> String -> (String -> Msg) -> Html Msg
|
labeledInput : String -> String -> (String -> Msg) -> Html Msg
|
||||||
labeledInput s val f =
|
labeledInput s val f =
|
||||||
div [ class "input-group" ]
|
div [ class "input-group mb-3" ]
|
||||||
[ span [] [ text s ]
|
[ div [ class "input-group-prepend" ]
|
||||||
, input [ value val, type_ "text", onInput f ] []
|
[ span [ class "input-group-text" ] [ text s ]
|
||||||
|
]
|
||||||
|
, input [ value val, type_ "text", class "form-control", onInput f ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
-- Error view
|
||||||
|
viewError : Bool -> String -> Html Msg
|
||||||
|
viewError hide e = div
|
||||||
|
[ classList
|
||||||
|
[ ("alert", True)
|
||||||
|
, ("alert-danger", True)
|
||||||
|
]
|
||||||
|
, hidden hide
|
||||||
|
] [ text e ]
|
||||||
|
|
||||||
|
panel : List (Html Msg) -> Html Msg
|
||||||
|
panel = div [ classList [("card", True), ("p-3", True), ("mb-3", True) ] ]
|
||||||
|
|
||||||
viewRawCacheModel : Int -> RawCacheModel -> Html Msg
|
viewRawCacheModel : Int -> RawCacheModel -> Html Msg
|
||||||
viewRawCacheModel level rcm =
|
viewRawCacheModel level rcm =
|
||||||
let
|
let
|
||||||
|
@ -36,15 +74,15 @@ viewRawCacheModel level rcm =
|
||||||
updateSetSize s cm = { cm | setSize = s}
|
updateSetSize s cm = { cm | setSize = s}
|
||||||
wrapUpdate f s = ChangeRawModel level (f s)
|
wrapUpdate f s = ChangeRawModel level (f s)
|
||||||
|
|
||||||
deleteButton = button "Delete" (DeleteRawModel level)
|
deleteButton = dangerButton "Delete" (DeleteRawModel level)
|
||||||
|
|
||||||
params = div [ class "cache-model-params" ]
|
params = div []
|
||||||
[ labeledInput "Block size" rcm.blockSize (wrapUpdate updateBlockSize)
|
[ labeledInput "Block size" rcm.blockSize (wrapUpdate updateBlockSize)
|
||||||
, labeledInput "Set count" rcm.setCount (wrapUpdate updateSetCount)
|
, labeledInput "Set count" rcm.setCount (wrapUpdate updateSetCount)
|
||||||
, labeledInput "Set size" rcm.setSize (wrapUpdate updateSetSize)
|
, labeledInput "Set size" rcm.setSize (wrapUpdate updateSetSize)
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
div [ class "cache-model" ]
|
panel
|
||||||
[ h3 [] [ text <| "L" ++ String.fromInt (level + 1) ++ " Cache" ]
|
[ h3 [] [ text <| "L" ++ String.fromInt (level + 1) ++ " Cache" ]
|
||||||
, buttonWrapper [ deleteButton ]
|
, buttonWrapper [ deleteButton ]
|
||||||
, params
|
, params
|
||||||
|
@ -57,21 +95,15 @@ viewRawCacheModelHierarchy rcmh =
|
||||||
<| List.indexedMap viewRawCacheModel rcmh
|
<| List.indexedMap viewRawCacheModel rcmh
|
||||||
translationResult = Result.andThen validateCacheModelHierarchy
|
translationResult = Result.andThen validateCacheModelHierarchy
|
||||||
<| translateRawCacheModelHierarchy rcmh
|
<| translateRawCacheModelHierarchy rcmh
|
||||||
isValid =
|
|
||||||
case translationResult of
|
|
||||||
Ok _ -> True
|
|
||||||
Err _ -> False
|
|
||||||
errorHtml =
|
errorHtml =
|
||||||
case translationResult of
|
case translationResult of
|
||||||
Ok _ -> viewError True ""
|
Ok _ -> viewError True ""
|
||||||
Err e -> viewError False e
|
Err e -> viewError False e
|
||||||
|
|
||||||
newButton = button "Add level" CreateRawModel
|
newButton = button "Add level" CreateRawModel
|
||||||
useButton = case translationResult of
|
useButton = resultButton translationResult "Use hierarchy" (UseHierarchy << Just)
|
||||||
Ok cmh -> optionalButton True "Use hierarchy" (UseHierarchy <| Just cmh)
|
|
||||||
Err _ -> optionalButton False "Use hierarchy" (UseHierarchy Nothing)
|
|
||||||
in
|
in
|
||||||
div [ class "cache-model-hierarchy" ]
|
div []
|
||||||
[ h2 [] [ text "Cache hierarchy" ]
|
[ h2 [] [ text "Cache hierarchy" ]
|
||||||
, errorHtml
|
, errorHtml
|
||||||
, buttonWrapper [ newButton, useButton ]
|
, buttonWrapper [ newButton, useButton ]
|
||||||
|
@ -84,14 +116,14 @@ viewCache level (cm, cs) =
|
||||||
slotLabels =
|
slotLabels =
|
||||||
List.indexedMap (\i _ -> td [] [ text <| String.fromInt i ])
|
List.indexedMap (\i _ -> td [] [ text <| String.fromInt i ])
|
||||||
<| List.repeat cm.setSize ()
|
<| List.repeat cm.setSize ()
|
||||||
slotLabel = td [ colspan cm.setSize ] [ text "Slot" ]
|
slotLabel = th [ colspan cm.setSize ] [ text "Slot" ]
|
||||||
allSlotLabels = List.concat <| List.repeat cm.setCount slotLabels
|
allSlotLabels = List.concat <| List.repeat cm.setCount slotLabels
|
||||||
allSlotsLabel = List.repeat cm.setCount slotLabel
|
allSlotsLabel = List.repeat cm.setCount slotLabel
|
||||||
|
|
||||||
setLabels =
|
setLabels =
|
||||||
List.indexedMap (\i _ -> td [ colspan cm.setSize ] [ text <| String.fromInt i ])
|
List.indexedMap (\i _ -> td [ colspan cm.setSize ] [ text <| String.fromInt i ])
|
||||||
<| List.repeat cm.setCount ()
|
<| List.repeat cm.setCount ()
|
||||||
setLabel = [ td [ colspan <| cm.setSize * cm.setCount ] [ text "Set" ] ]
|
setLabel = [ th [ colspan <| cm.setSize * cm.setCount ] [ text "Set" ] ]
|
||||||
setRow set =
|
setRow set =
|
||||||
let
|
let
|
||||||
slotHtml s =
|
slotHtml s =
|
||||||
|
@ -102,17 +134,17 @@ viewCache level (cm, cs) =
|
||||||
List.map slotHtml set
|
List.map slotHtml set
|
||||||
cacheRow = List.concat <| List.map setRow cs
|
cacheRow = List.concat <| List.map setRow cs
|
||||||
cacheTable =
|
cacheTable =
|
||||||
table []
|
table [ class "table" ]
|
||||||
[ tr [ classList [("hidden", cm.setCount == 1)] ] setLabel
|
[ tr [ hidden (cm.setCount == 1), class "table-info" ] setLabel
|
||||||
, tr [ classList [("hidden", cm.setCount == 1)] ] setLabels
|
, tr [ hidden (cm.setCount == 1) ] setLabels
|
||||||
, tr [ classList [("hidden", cm.setSize == 1)] ] allSlotsLabel
|
, tr [ hidden (cm.setSize == 1), class "table-info" ] allSlotsLabel
|
||||||
, tr [ classList [("hidden", cm.setSize == 1)] ] allSlotLabels
|
, tr [ hidden (cm.setSize == 1) ] allSlotLabels
|
||||||
, tr [] cacheRow
|
, tr [] cacheRow
|
||||||
]
|
]
|
||||||
|
|
||||||
in
|
in
|
||||||
div [ class "cache" ]
|
panel
|
||||||
[ h3 [] [ text <| "L" ++ String.fromInt level ++ " Cache" ]
|
[ h3 [] [ text <| "L" ++ String.fromInt (level + 1) ++ " Cache" ]
|
||||||
, cacheTable
|
, cacheTable
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -122,7 +154,7 @@ viewCacheHierarchy ch =
|
||||||
levels = div [ class "cache-levels" ]
|
levels = div [ class "cache-levels" ]
|
||||||
<| List.indexedMap viewCache ch
|
<| List.indexedMap viewCache ch
|
||||||
in
|
in
|
||||||
div [ class "cache-hierarchy" ] <|
|
div [] <|
|
||||||
[ h2 [] [ text <| "Cache State" ]
|
[ h2 [] [ text <| "Cache State" ]
|
||||||
, levels
|
, levels
|
||||||
]
|
]
|
||||||
|
@ -132,11 +164,11 @@ viewAccessView m av =
|
||||||
let
|
let
|
||||||
currentCache = Maybe.withDefault [] m.hierarchy
|
currentCache = Maybe.withDefault [] m.hierarchy
|
||||||
in
|
in
|
||||||
div [ class "access-view" ]
|
div []
|
||||||
[ h2 [] [ text "Access Simulation" ]
|
[ h2 [] [ text "Access Simulation" ]
|
||||||
, buttonWrapper
|
, buttonWrapper
|
||||||
[ button "Forward" AccessViewForward
|
[ primaryButton "Back" AccessViewBack
|
||||||
, button "Back" AccessViewBack
|
, primaryButton "Forward" AccessViewForward
|
||||||
]
|
]
|
||||||
, viewAccessLog av
|
, viewAccessLog av
|
||||||
, viewCacheHierarchy <| effectiveCacheHierarchy currentCache av
|
, viewCacheHierarchy <| effectiveCacheHierarchy currentCache av
|
||||||
|
@ -145,12 +177,11 @@ viewAccessView m av =
|
||||||
viewAccessLog : AccessView -> Html Msg
|
viewAccessLog : AccessView -> Html Msg
|
||||||
viewAccessLog (aes, ap) =
|
viewAccessLog (aes, ap) =
|
||||||
let
|
let
|
||||||
resultSpan r =
|
resultSpan r =
|
||||||
case r of
|
span [ classList [ ("badge", True), ("badge-danger", True), ("badge-success", r == Hit) ] ]
|
||||||
Hit -> span [ class "success" ] [ text "HIT" ]
|
[ text <| if r == Hit then "Hit" else "Miss" ]
|
||||||
Miss -> span [ class "failure" ] [ text "MISS" ]
|
|
||||||
downEvent n ae = div [ class "event" ]
|
downEvent n ae = div [ class "event" ]
|
||||||
[ text <| "L" ++ String.fromInt (n + 1)
|
[ text <| "L" ++ String.fromInt (n + 1) ++ " "
|
||||||
, resultSpan ae.result
|
, resultSpan ae.result
|
||||||
]
|
]
|
||||||
upEvent n ae = div [ class "event" ]
|
upEvent n ae = div [ class "event" ]
|
||||||
|
@ -163,35 +194,32 @@ viewAccessLog (aes, ap) =
|
||||||
Up n -> List.indexedMap downEvent aes ++
|
Up n -> List.indexedMap downEvent aes ++
|
||||||
(List.indexedMap upEvent <| List.drop n aes)
|
(List.indexedMap upEvent <| List.drop n aes)
|
||||||
in
|
in
|
||||||
div [ class "access-log" ]
|
div [ ]
|
||||||
[ h3 [] [ text "Simulation events" ]
|
[ h3 [] [ text "Simulation events" ]
|
||||||
, div [ class "access-log-events" ] events
|
, div [] events
|
||||||
]
|
]
|
||||||
|
|
||||||
viewAccessInput : Model -> Html Msg
|
viewAccessInput : Model -> Html Msg
|
||||||
viewAccessInput m =
|
viewAccessInput m =
|
||||||
let
|
let
|
||||||
accessButton =
|
accessButton = maybeButton (String.toInt m.accessInput) "Access address" Access
|
||||||
case String.toInt m.accessInput of
|
|
||||||
Just i -> optionalButton True "Access address" (Access i)
|
|
||||||
Nothing -> optionalButton False "Access address" (Access -1)
|
|
||||||
in
|
in
|
||||||
div [ class "access-input" ]
|
div []
|
||||||
[ h2 [] [ text "Run access simulation" ]
|
[ h2 [] [ text "Run access simulation" ]
|
||||||
, div [ class "note" ]
|
, div [ classList [("alert", True), ("alert-primary", True)] ]
|
||||||
[ text "Please make sure to click \"Use Hierarchy\" to load a hierarchy to simulate."
|
[ text "Please make sure to click \"Use Hierarchy\" to load a hierarchy to simulate."
|
||||||
]
|
]
|
||||||
, labeledInput "Access address" m.accessInput ChangeAccessInput
|
, labeledInput "Access address" m.accessInput ChangeAccessInput
|
||||||
, accessButton
|
, accessButton
|
||||||
]
|
]
|
||||||
|
|
||||||
viewError : Bool -> String -> Html Msg
|
|
||||||
viewError hide e = div [ classList [ ("hidden", hide), ("error", True) ] ] [ text e ]
|
|
||||||
|
|
||||||
viewBase : Model -> Html Msg
|
viewBase : Model -> Html Msg
|
||||||
viewBase m =
|
viewBase m =
|
||||||
let
|
let
|
||||||
rawView = viewRawCacheModelHierarchy m.rawHierarchy
|
rawView =
|
||||||
|
case m.accessView of
|
||||||
|
Nothing -> [ viewRawCacheModelHierarchy m.rawHierarchy ]
|
||||||
|
Just _ -> []
|
||||||
cacheView =
|
cacheView =
|
||||||
case m.accessView of
|
case m.accessView of
|
||||||
Nothing ->
|
Nothing ->
|
||||||
|
@ -201,4 +229,5 @@ viewBase m =
|
||||||
accessView = Maybe.withDefault [] <| Maybe.map (List.singleton << viewAccessView m) <| m.accessView
|
accessView = Maybe.withDefault [] <| Maybe.map (List.singleton << viewAccessView m) <| m.accessView
|
||||||
accessInputView = [ viewAccessInput m ]
|
accessInputView = [ viewAccessInput m ]
|
||||||
in
|
in
|
||||||
div [] <| [ rawView ] ++ cacheView ++ accessView ++ accessInputView
|
div [ class "container" ]
|
||||||
|
<| rawView ++ cacheView ++ accessView ++ accessInputView
|
||||||
|
|
|
@ -1,128 +1,3 @@
|
||||||
@import url('https://fonts.googleapis.com/css?family=Raleway&display=swap');
|
.btn-group {
|
||||||
$primary-color: lighten(#26c176, 30%);
|
width: min-content;
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: Raleway, serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"] {
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
background-color: #efefef;
|
|
||||||
|
|
||||||
&:active, &:focus {
|
|
||||||
background-color: $primary-color;
|
|
||||||
transition: .25s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
border: 2px solid tomato;
|
|
||||||
color: tomato;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.success {
|
|
||||||
margin-left: 10px;
|
|
||||||
color: green;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.failure {
|
|
||||||
margin-left: 10px;
|
|
||||||
color: tomato;
|
|
||||||
}
|
|
||||||
|
|
||||||
button, input[type="button"] {
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: none;
|
|
||||||
margin-right: 5px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
&:hover, &:focus {
|
|
||||||
background-color: $primary-color;
|
|
||||||
transition: .25s;
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
background-color: lightgrey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.cache-model-levels {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cache-model {
|
|
||||||
max-width: 600px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 2px solid lightgrey;
|
|
||||||
margin: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cache, .cache-model {
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 2px solid lightgrey;
|
|
||||||
margin: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cache-model-hierarchy, .cache-hierarchy, .access-input {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
&:nth-child(1), &:nth-child(3) {
|
|
||||||
background-color: $primary-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
text-align: center;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user