diff --git a/src/Renderer/DrawBlock/Sheet.fs b/src/Renderer/DrawBlock/Sheet.fs index ed697ce..614dc09 100644 --- a/src/Renderer/DrawBlock/Sheet.fs +++ b/src/Renderer/DrawBlock/Sheet.fs @@ -169,6 +169,10 @@ type Model = { member this.ChangeLabel (dispatch: Dispatch) (compId: ComponentId) (lbl: string) = dispatch <| (Wire (BusWire.Symbol (Symbol.ChangeLabel (compId, lbl) ) ) ) + /// Change the Port Side of Component specified by compId to lbl + member this.ChangePort (dispatch: Dispatch) (compId: ComponentId) (portName: string) (portSide: string) = + dispatch <| (Wire (BusWire.Symbol (Symbol.ChangePort (compId, portName,portSide) ) ) ) + /// Run Bus Width Inference check member this.DoBusWidthInference dispatch = dispatch <| (Wire (BusWire.BusWidths)) diff --git a/src/Renderer/DrawBlock/Symbol.fs b/src/Renderer/DrawBlock/Symbol.fs index 5371804..11b2be9 100644 --- a/src/Renderer/DrawBlock/Symbol.fs +++ b/src/Renderer/DrawBlock/Symbol.fs @@ -1,6 +1,4 @@ -//MAIN TODO: STORE ROTATION TO USE WHEN LOADING THE SYMBOLS// - -//---------------------------------------------------------------------------------// +//---------------------------------------------------------------------------------// //--------------------AP1919 CODE SECTION STARTS-------------------------------------// //---------------------------------------------------------------------------------// @@ -81,6 +79,7 @@ type Msg = | FlipVSymbols of ComponentId list //First Attempt at implementing a way to flip symbol vertically. | SymbolsHaveError of sIds: ComponentId list | ChangeLabel of sId : ComponentId * newLabel : string + | ChangePort of sId : ComponentId * portName: string * portSide:string | PasteSymbols of sIds: ComponentId list | ColorSymbols of compList : ComponentId list * colour : HighLightColor | ErrorSymbols of errorIds: ComponentId list * selectIds: ComponentId list * isDragAndDrop: bool @@ -92,7 +91,7 @@ type Msg = | WriteMemoryLine of ComponentId * int64 * int64 // For Issie Integration | WriteMemoryType of ComponentId * ComponentType -//---------------------------------helper types and functions----------------// +//---------------------------------helper types and fuFnctions----------------// let posDiff (a:XYPos) (b:XYPos) = {X=a.X-b.X; Y=a.Y-b.Y} @@ -436,99 +435,102 @@ let rotatePortMap (map:Map) (symbol:Symbol) = |_ -> rotatePortMap' map symbol + + let flipHPortMap (map:Map) (symbol:Symbol) = - map |> Map.map (fun key port -> - match port.Side with - |Right -> {port with Side=Left} - |Left -> {port with Side=Right} - |_ -> port - ) - + map |> Map.map (fun key port -> + match port.Side with + |Right -> {port with Side=Left} + |Left -> {port with Side=Right} + |_ -> port) +let flipVPortMap (map:Map) (symbol:Symbol) = + failwithf "Not implemented Yet" let changePortSide (map:Map) (portName: string) (newSide:PortOrientation) (symbol:Symbol) = - let rev map: Map = - Map.fold (fun m key value -> m.Add(value,key)) Map.empty map - - let namesInv = rev (portNamesMap symbol.Compo) + let rev map: Map = + Map.fold (fun m key value -> m.Add(value,key)) Map.empty map - let portId = Map.find portName namesInv - - map |> Map.change portId (fun x -> - match x with - | Some s -> Some {Side=newSide;Offset=s.Offset} - | None -> None - ) + let namesInv = rev (portNamesMap symbol.Compo) + + let portId = Map.find portName namesInv + + map |> Map.change portId (fun x -> + match x with + | Some s -> Some {Side=newSide;Offset=s.Offset} + | None -> None + ) let getSides (map:Map) = - let lst = Map.toList map - let sides = lst |> List.map (fun x -> - match x with - |(a,{Side=b;Offset=c}) -> b - ) - sides |> List.map (fun x -> - match x with - |Right->"R" - |Left->"L" - |Top->"T" - |Bottom->"B" - ) + let lst = Map.toList map + let sides = lst |> List.map (fun x -> + match x with + |(a,{Side=b;Offset=c}) -> b + ) + sides |> List.map (fun x -> + match x with + |Right->"R" + |Left->"L" + |Top->"T" + |Bottom->"B" + ) let countsides (map:Map) = - let sides = getSides map - let countmap = List.countBy id sides |> Map.ofList - let counts = [Map.tryFind "R" countmap; Map.tryFind "B" countmap; Map.tryFind "L" countmap; Map.tryFind "T" countmap] - let t = counts |> List.map (fun x -> - match x with - |Some a -> a - |None -> 0 - ) - // t - (t[0],t[1],t[2],t[3]) + let sides = getSides map + let countmap = List.countBy id sides |> Map.ofList + let counts = [Map.tryFind "R" countmap; Map.tryFind "B" countmap; Map.tryFind "L" countmap; Map.tryFind "T" countmap] + let t = counts |> List.map (fun x -> + match x with + |Some a -> a + |None -> 0 + ) + // t + (t[0],t[1],t[2],t[3]) let getMaxPortNameLength (map:Map) = - let labelList = List.map (snd >> String.length) (map |> Map.toList) - if List.isEmpty labelList then 0 //if a component has no inputs or outputs list max will fail - else List.max labelList + let labelList = List.map (snd >> String.length) (map |> Map.toList) + if List.isEmpty labelList then 0 //if a component has no inputs or outputs list max will fail + else List.max labelList -//find max name.length in all ports, not input + output -//height is defined by (max_ton_ports_se_Right_kai_left + 2) => gap gia port names on top/bottom -//width = max_name_size + max_name_size + (max_name_size) * max_ton_ports_se_top_kai_bottom -////////// LEFT RIGTH TOP/BOTTOM -//Rearrange map + //find max name.length in all ports, not input + output + //height is defined by (max_ton_ports_se_Right_kai_left + 2) => gap gia port names on top/bottom + //width = max_name_size + max_name_size + (max_name_size) * max_ton_ports_se_top_kai_bottom + ////////// LEFT RIGTH TOP/BOTTOM + //Rearrange map -//otan allazei ena port thelei -> let symbol' = {symbol with map = changeportside} -> let symbol'' = {redefineCustomHW} -> {symbol'' with map = redefineportmap} + //otan allazei ena port thelei -> let symbol' = {symbol with map = changeportside} -> let symbol'' = {redefineCustomHW} -> {symbol'' with map = redefineportmap} let redefineCustomHW symbol = - // let altercomponent comp nh nw = - // {comp with - // H = nh - // W = nw} - let namesMap = portNamesMap symbol.Compo - let maxname = getMaxPortNameLength namesMap - let r,b,l,t = countsides symbol.APortOffsetsMap - let maxRL = max r l - let maxTB = max t b - let heightNew = GridSize + GridSize * maxRL - let widthNew = maxname*2 + maxname*maxTB - let newcompo = {symbol.Compo with H = heightNew} - let newcompo'= {newcompo with W = widthNew} - {symbol with Compo = newcompo'} + // let altercomponent comp nh nw = + // {comp with + // H = nh + // W = nw} + let namesMap = portNamesMap symbol.Compo + let maxname = getMaxPortNameLength namesMap + let r,b,l,t = countsides symbol.APortOffsetsMap + let maxRL = max r l + let maxTB = max t b + let heightNew = 100 //GridSize + GridSize * maxRL + let widthNew = max (maxname*2 + maxname*maxTB) (GridSize * 4) //maxname*2 + maxname*maxTB + let newcompo = {symbol.Compo with H = heightNew} + let newcompo'= {newcompo with W = widthNew} + {symbol with Compo = newcompo'} let redefineCustomPorts symbol (map:Map) : Map = let customOffsetHelper w h side il ir it ib r l b t : XYPos= let index,all = - match side with - |Right -> ir,r - |Left -> il,l - |Top -> it,t - |Bottom -> ib,b + match side with + |Right -> ir,r + |Left -> il,l + |Top -> it,t + |Bottom -> ib,b let gap = 1.0 let offY = (float(h))* (( float(index) + gap )/( float( all ) + 2.0*gap - 1.0)) // the ports are created so that they are equidistant let offX = (float(w))* (( float(index) + gap )/( float( all ) + 2.0*gap - 1.0)) + // {X=50.0;Y=50.0} match side with |Left -> {X=0.0;Y=offY} |Top -> {X=offX;Y=0.0} @@ -544,15 +546,27 @@ let redefineCustomPorts symbol (map:Map) : Map ignore + valuesNew <- (valuesNew @ [{Side=v.Side;Offset=(customOffsetHelper w h v.Side il ir it ib r l b t)}]) if v.Side = Right then ir <- ir+1 else if v.Side = Left then il <- il+1 else if v.Side = Top then it <- it+1 else ib <- ib+1 + // printf $"IL: %i{il}" + + // printf $"New Y Offset: %f{valuesNew[0].Offset.Y}" + +// for i in valuesNew do + // printf $"New Y Offset: %f{i.Offset.Y}" // valuesNew (keys, valuesNew) ||> List.map2 (fun x y -> (x,y)) |> Map.ofList + // map + + + + + //----------------------------------------ROTATION HELPERS----------------------------------------------- ///Symbol Points rotation function @@ -1306,18 +1320,23 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> = // The selected symbol is rotated by incrementing Stransform rotation and updating new APortOffsetsMap and Symbol Pos List.fold (fun prevSymbols sId -> Map.add sId {model.Symbols[sId] with STransform = stransform_fsm(model.Symbols[sId].STransform); APortOffsetsMap = rotatePortMap model.Symbols[sId].APortOffsetsMap model.Symbols[sId]} prevSymbols) resetSymbols compList - let result = (canvasPortLocation(model.Symbols[compList[0]])) - //Used to print it Dev Tools Terminal list of ports global coordinates starting anticlockwise from inputs - printf "%A" result { model with Symbols = newSymbols }, Cmd.none | FlipHSymbols compList -> // NEW: flip a symbol Horizontally let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols - { model with Symbols = resetSymbols }, Cmd.none + let newSymbols = + // The selected symbol is rotated by incrementing Stransform rotation and updating new APortOffsetsMap and Symbol Pos + List.fold (fun prevSymbols sId -> + Map.add sId {model.Symbols[sId] with STransform = stransform_fsm(stransform_fsm(model.Symbols[sId].STransform)); APortOffsetsMap = flipHPortMap model.Symbols[sId].APortOffsetsMap model.Symbols[sId]} prevSymbols) resetSymbols compList + { model with Symbols = newSymbols }, Cmd.none | FlipVSymbols compList -> let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols - { model with Symbols = resetSymbols }, Cmd.none + let newSymbols = + // The selected symbol is rotated by incrementing Stransform rotation and updating new APortOffsetsMap and Symbol Pos + List.fold (fun prevSymbols sId -> + Map.add sId {model.Symbols[sId] with STransform = stransform_fsm(stransform_fsm(model.Symbols[sId].STransform)); APortOffsetsMap = flipVPortMap model.Symbols[sId].APortOffsetsMap model.Symbols[sId]} prevSymbols) resetSymbols compList + { model with Symbols = newSymbols }, Cmd.none | ErrorSymbols (errorCompList,selectCompList,isDragAndDrop) -> let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols @@ -1339,6 +1358,24 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> = let newcompo = {tempsym.Compo with Label = newLabel} let addsym = {tempsym with Compo = newcompo} { model with Symbols = Map.add sId addsym model.Symbols }, Cmd.none + | ChangePort (sId, portName, portSide) -> + let tempsym = Map.find sId model.Symbols + printf $"Selected Port: %s{portName}" + printf $"Selected Side: %s{portSide}" + let newSide = + match portSide with + | "Top" -> Top + | "Bottom" -> Bottom + | "Left" -> Left + | "Right" -> Right + | _ -> failwithf "Side not implemented" + + let symbol' = {tempsym with APortOffsetsMap = (changePortSide tempsym.APortOffsetsMap portName newSide tempsym)} + //let symbol'' = {redefineCustomHW} -> + let symbol'' = redefineCustomHW symbol' + //{symbol'' with map = redefineportmap} + let symbol''' = {symbol'' with APortOffsetsMap = redefineCustomPorts symbol'' symbol'.APortOffsetsMap} + { model with Symbols = Map.add sId symbol''' model.Symbols }, Cmd.none | PasteSymbols compList -> let newSymbols = @@ -1383,18 +1420,18 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> = comp.H, comp.W ComponentId comp.Id, let s = { Pos = xyPos; - STransform = R0; - ShowInputPorts = false ;//do not show input ports initially - ShowOutputPorts = false ;//do not show output ports initially - Colour = "lightgrey" ;// initial color - Id = ComponentId comp.Id; - Compo = {comp with H=h ; W = w}; - Opacity = 1.0; - Moving = false; - InWidth0 = None; - InWidth1 = None; - APortOffsetsMap = (Map.empty) - } + STransform = R0; + ShowInputPorts = false ;//do not show input ports initially + ShowOutputPorts = false ;//do not show output ports initially + Colour = "lightgrey" ;// initial color + Id = ComponentId comp.Id; + Compo = {comp with H=h ; W = w}; + Opacity = 1.0; + Moving = false; + InWidth0 = None; + InWidth1 = None; + APortOffsetsMap = (Map.empty) + } {s with APortOffsetsMap = (genAPortOffsets s s.Compo.Type)} //to check //need TODO for rotation as well )) let symbolList = diff --git a/src/Renderer/UI/PopupView.fs b/src/Renderer/UI/PopupView.fs index 8b4102f..bb71a8d 100644 --- a/src/Renderer/UI/PopupView.fs +++ b/src/Renderer/UI/PopupView.fs @@ -90,7 +90,10 @@ let setComponentLabel model (sheetDispatch) (comp:Component) (text:string) = model.Sheet.ChangeLabel sheetDispatch (ComponentId comp.Id) label //model.Diagram.EditComponentLabel comp.Id label +let setComponentPortUpdate model sheetDispatch (comp:Component) (portName:string) (portSide:string) = + model.Sheet.ChangePort sheetDispatch (ComponentId comp.Id) portName portSide + //model.Diagram.EditComponentLabel comp.Id label //========// diff --git a/src/Renderer/UI/SelectedComponentView.fs b/src/Renderer/UI/SelectedComponentView.fs index 2ccefc8..fcd4dbb 100644 --- a/src/Renderer/UI/SelectedComponentView.fs +++ b/src/Renderer/UI/SelectedComponentView.fs @@ -6,6 +6,7 @@ module SelectedComponentView +open EEExtensions open Fulma open Fable.React open Fable.React.Props @@ -17,6 +18,7 @@ open MemoryEditorView open PopupView open Notifications + let private readOnlyFormField name body = Field.div [] [ Label.label [] [ str name ] @@ -383,7 +385,7 @@ let private makeExtraInfo model (comp:Component) text dispatch = | _ -> div [] [] -let viewSelectedComponent (model: ModelType.Model) dispatch = +let viewSelectedComponent (model: ModelType.Model) dispatch : ReactElement = let sheetDispatch sMsg = dispatch (Sheet sMsg) @@ -392,107 +394,81 @@ let viewSelectedComponent (model: ModelType.Model) dispatch = |> Seq.filter (function | ch when System.Char.IsLetterOrDigit ch -> true | '.' -> true | '_' -> true | _ -> false) |> Seq.skipWhile (System.Char.IsLetter >> not) |> (fun chars -> match Seq.length chars with | 0 -> None | _ -> Some (String.concat "" (Seq.map string chars))) + + + + + match model.Sheet.SelectedComponents with | [ compId ] -> let comp = Symbol.extractComponent model.Sheet.Wire.Symbol compId // Extract Component : function in Symbol.fs let sym = Symbol.extractSymbol model.Sheet.Wire.Symbol compId // Extract Symbol : function in Symbol.fs - let stransform = string sym.STransform - let ports = - sym.APortOffsetsMap - |> Map.toList - let portName = - ports - |> List.map fst - let portSide = - ports - |> List.map snd - |> List.map (fun i -> i.Side) - |> List.map (fun i -> string i) - let portOffset = - ports - |> List.map snd - |> List.map (fun i -> i.Offset) - |> List.map (fun i -> string i) - + let namesPortRaw = Symbol.portNamesMap comp - div [Key comp.Id] [ + + div [Style [ Margin 0 ];Key comp.Id] [ // let label' = extractLabelBase comp.Label // TODO: normalise labels so they only contain allowed chars all uppercase let label' = Option.defaultValue "L" (formatLabelText comp.Label) // No formatting atm readOnlyFormField "Description" <| makeDescription comp model dispatch makeExtraInfo model comp label' dispatch let required = match comp.Type with | SplitWire _ | MergeWires | BusSelection _ -> false | _ -> true + div [Key comp.Id] [ textFormField required "Component Name" label' (fun text -> - // TODO: removed formatLabel for now - //setComponentLabel model sheetDispatch comp (formatLabel comp text) match formatLabelText text with | Some label -> setComponentLabel model sheetDispatch comp label dispatch <| SetPopupDialogText (Some label) | None -> () - //updateNames model (fun _ _ -> model.WaveSim.Ports) |> StartWaveSim |> dispatch dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) // reload the new component ) - textFormField required "Component STransform" stransform (fun text -> - // TODO: removed formatLabel for now - //setComponentLabel model sheetDispatch comp (formatLabel comp text) - match formatLabelText text with - | Some label -> - setComponentLabel model sheetDispatch comp label //TODO: Fix this part to update STransform - dispatch <| SetPopupDialogText (Some label) - | None -> () - //updateNames model (fun _ _ -> model.WaveSim.Ports) |> StartWaveSim |> dispatch - dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) // reload the new component - ) - textFormField required "Component Port" portName[0] (fun text -> - // TODO: removed formatLabel for now - //setComponentLabel model sheetDispatch comp (formatLabel comp text) - match formatLabelText text with - | Some label -> - setComponentLabel model sheetDispatch comp label - dispatch <| SetPopupDialogText (Some label) - | None -> () - //updateNames model (fun _ _ -> model.WaveSim.Ports) |> StartWaveSim |> dispatch - dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) // reload the new component - ) - textFormField required "Component Port" portSide[0] (fun text -> - // TODO: removed formatLabel for now - //setComponentLabel model sheetDispatch comp (formatLabel comp text) - match formatLabelText text with - | Some label -> - setComponentLabel model sheetDispatch comp label - dispatch <| SetPopupDialogText (Some label) - | None -> () - //updateNames model (fun _ _ -> model.WaveSim.Ports) |> StartWaveSim |> dispatch - dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) // reload the new component - ) - textFormField required "Component Port" portOffset[0] (fun text -> - // TODO: removed formatLabel for now - //setComponentLabel model sheetDispatch comp (formatLabel comp text) - match formatLabelText text with - | Some label -> - setComponentLabel model sheetDispatch comp label - dispatch <| SetPopupDialogText (Some label) - | None -> () - //updateNames model (fun _ _ -> model.WaveSim.Ports) |> StartWaveSim |> dispatch - dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) // reload the new component - ) -// let items = -// List.map (fun i -> -// textFormField required "Component Rent" i (fun text -> -//// TODO: removed formatLabel for now -// //setComponentLabel model sheetDispatch comp (formatLabel comp text) -// match formatLabelText text with -// | Some label -> -// setComponentLabel model sheetDispatch comp label -// dispatch <| SetPopupDialogText (Some label) -// | None -> () -// //updateNames model (fun _ _ -> model.WaveSim.Ports) |> StartWaveSim |> dispatch -// dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) // reload the new component -// )) ports -// match items with -// | [x] -> x -// | _ -> nothing - ] + // Control when the namesPortRaw map can be accessed else return normal name of port + let allowedDescription = match comp.Type with | NbitsAdder _ | Decode4 | Register _ |DFF| RegisterE _ |DFFE| ROM1 _ |AsyncROM1 _ | RAM1 _ | AsyncRAM1 _ | Mux2 | Demux2 | NbitsXor _ | Custom _ -> true | _ -> false + let ports = + sym.APortOffsetsMap + |> Map.toList + let portNameLst = + ports + |> List.map fst + |> List.map (fun key -> if allowedDescription then namesPortRaw[key] else key) + let portSideLst = ["Top";"Left";"Bottom";"Right"] + + //Already done for custom symbols + +// let portDescription (i:string) : ReactElement = +// Label.label [] [ h2 [] [str i ]] +// +// +// Field.div [] [ +// Label.label [] [ str "Component Ports" ] +// g [] (Seq.map portDescription portNameLst) +// ] + let mutable portName = "" + let mutable portSide = "" + + let dropDown (available:bool) (name:string) (lst:string list): ReactElement = + if available then + Field.div [] [ + Label.label [] [ str name ] + Label.label [ ] + [Select.select [] + [ select [(OnChange(fun option -> + match name with + | "Port" -> portName <- option.Value; if (portName <> "" && portSide <> "") then setComponentPortUpdate model sheetDispatch comp portName portSide; dispatch <| SetPopupDialogText (Some portName);dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) else printf "Not yet" + | "Side" -> portSide <- option.Value; if (portName <> "" && portSide <> "") then setComponentPortUpdate model sheetDispatch comp portName portSide; dispatch <| SetPopupDialogText (Some portSide);dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) else printf "Not yet" + | _ -> failwithf "Case not an option" + ))] + + ([option [Value "";Selected true;Disabled true] [str ("Choose " + string name)]] @ List.map(fun value -> option [Value value] [str value]) lst) + ] + ] + ] + else + Field.div [] [] + dropDown allowedDescription "Port" portNameLst + dropDown allowedDescription "Side" portSideLst + + ] + ] | _ -> div [] [ str "Select a component in the diagram to view or change its properties, for example number of bits." ]