Commit 968d84a3 authored by Mart Lubbers's avatar Mart Lubbers

Merge branch '202-malfunctioning-dropdowns' into 'master'

Resolve "Malfunctioning dropdowns"

Closes #202 and #200

See merge request !156
parents 8217d1d9 645a410e
......@@ -719,7 +719,6 @@ callProcessExample =
enterInformation "Enter the path to the external process. To for instance open a shell run '/bin/bash' or 'c:\\Windows\\System32\\cmd.exe'." []
>>= \path->'P'.callProcess () [] path [] Nothing Nothing
>>- viewInformation "Process terminated" []
//* Customizing interaction with views
......
......@@ -139,7 +139,7 @@ where
browse workflows Nothing
= workAs (AuthenticatedUser "guest" ["manager"] (Just "Guest user")) (manageWorklist workflows)
layout = sequenceLayouts (layoutSubUIs (SelectByType UIAction) (setActionIcon ('DM'.fromList [("Login","login")]))) frameCompact
layout = sequenceLayouts [layoutSubUIs (SelectByType UIAction) (setActionIcon ('DM'.fromList [("Login","login")])) ,frameCompact]
manageWorkInSession:: Task ()
manageWorkInSession
......@@ -148,22 +148,22 @@ manageWorkInSession
)
>>* [OnValue (ifStable (const (return ())))]) <<@ ApplyLayout layout
where
layout = foldl1 sequenceLayouts
layout = sequenceLayouts
[unwrapUI //Get rid of the step
,arrangeWithSideBar 0 TopSide 50 True
,arrangeWithSideBar 0 TopSide 50 False
,layoutSubUIs (SelectByPath [0]) layoutManageSession
,layoutSubUIs (SelectByPath [1]) (sequenceLayouts unwrapUI layoutWhatToDo)
,layoutSubUIs (SelectByPath [1]) (sequenceLayouts [unwrapUI,layoutWhatToDo])
//Use maximal screen space
,setUIAttributes (sizeAttr FlexSize FlexSize)
]
layoutManageSession = foldl1 sequenceLayouts
layoutManageSession = sequenceLayouts
[layoutSubUIs SelectChildren actionToButton
,layoutSubUIs (SelectByPath [0]) (setUIType UIContainer)
,setUIType UIContainer
,setUIAttributes ('DM'.unions [heightAttr WrapSize,directionAttr Horizontal,paddingAttr 2 2 2 10])
]
layoutWhatToDo = sequenceLayouts (arrangeWithSideBar 0 LeftSide 150 True) (layoutSubUIs (SelectByPath [1]) unwrapUI)
layoutWhatToDo = sequenceLayouts [arrangeWithSideBar 0 LeftSide 150 True, layoutSubUIs (SelectByPath [1]) unwrapUI]
manageSession :: Task ()
manageSession =
......@@ -200,7 +200,7 @@ where
userRoles (AuthenticatedUser _ roles _) = roles
userRoles _ = []
layoutManageWork = foldl1 sequenceLayouts
layoutManageWork = sequenceLayouts
//Split the screen space
[ arrangeWithSideBar 0 TopSide 200 True
//Layout all dynamically added tasks as tabs
......
......@@ -12,6 +12,7 @@ import iTasks.WF.Definition
import iTasks.WF.Tasks.IO
from iTasks.WF.Combinators.Core import :: AttachmentStatus
import iTasks.UI.Editor, iTasks.UI.Editor.Common
from iTasks.UI.Layout import :: LUI, :: LUIMoves, :: LUIMoveID, :: LUIEffectStage, :: LUINo
from iTasks.Internal.TaskState import :: TaskTree(..), :: DeferredJSON(..), :: TIMeta(..)
from iTasks.Internal.TaskEval import :: TaskEvalInfo(..)
......
......@@ -7,6 +7,7 @@ from iTasks.WF.Definition import :: InstanceNo, :: InstanceKey, :: InstanceProgr
from iTasks.WF.Combinators.Core import :: AttachmentStatus
from iTasks.UI.Definition import :: UIChange
from iTasks.UI.Editor import :: EditMask
from iTasks.UI.Layout import :: LUI, :: LUIMoves, :: LUIMoveID, :: LUINo, :: LUIEffectStage
from Text.GenJSON import generic JSONEncode, generic JSONDecode, :: JSONNode
from Data.Map import :: Map
from Data.Maybe import :: Maybe
......@@ -67,7 +68,8 @@ derive JSONDecode TIMeta, TIReduct, TaskTree
| TCAttach !TaskId !TaskTime !AttachmentStatus !String !String
| TCExposedShared !TaskId !TaskTime !String !TaskTree // +URL //TODO: Remove
| TCStable !TaskId !TaskTime !DeferredJSON
| TCLayout !DeferredJSON !TaskTree
//| TCLayout !DeferredJSON !TaskTree
| TCLayout !(!LUI,!LUIMoves) !TaskTree
| TCNop
| TCDestroy !TaskTree //Marks a task state as garbage that must be destroyed (TODO: replace by explicit event
......
implementation module iTasks.Internal.TaskState
import Text.GenJSON, StdString, Data.Func, Data.GenEq, Data.Maybe, Data.Functor
import iTasks.UI.Definition
import iTasks.UI.Definition, iTasks.UI.Layout
import iTasks.WF.Definition
from iTasks.WF.Combinators.Core import :: AttachmentStatus
......@@ -15,6 +15,10 @@ import Data.Error, Data.Either
derive JSONEncode TIMeta, TIValue, TIReduct, TaskTree, ParallelTaskState, ParallelTaskChange, TaskResult, TaskEvalInfo, TonicOpts, CircularStack
derive JSONDecode TIMeta, TIValue, TIReduct, TaskTree, ParallelTaskState, ParallelTaskChange, TaskResult, TaskEvalInfo, TonicOpts, CircularStack
derive JSONEncode LUI, LUIChanges, LUIEffects, LUIEffectStage, LUINo, Set
derive JSONDecode LUI, LUIChanges, LUIEffects, LUIEffectStage, LUINo, Set
instance toString DeferredJSON where
toString (DeferredJSON x) = toString $ toJSON x
toString (DeferredJSONNode json) = toString json
......
......@@ -143,7 +143,7 @@ createClientTaskInstance task sessionId instanceNo iworld=:{options={appVersion}
createTaskInstance :: !(Task a) !*IWorld -> (!MaybeError TaskException (!InstanceNo,InstanceKey),!*IWorld) | iTask a
createTaskInstance task iworld=:{options={appVersion,autoLayout},current={taskTime},clock}
# task = if autoLayout (tune (ApplyLayout defaultSessionLayout) task) task
# task = if autoLayout (applyLayout defaultSessionLayout task) task
# (mbInstanceNo,iworld) = newInstanceNo iworld
# instanceNo = fromOk mbInstanceNo
# (instanceKey,iworld) = newInstanceKey iworld
......@@ -160,7 +160,7 @@ createTaskInstance task iworld=:{options={appVersion,autoLayout},current={taskTi
createDetachedTaskInstance :: !(Task a) !Bool !TaskEvalOpts !InstanceNo !TaskAttributes !TaskId !Bool !*IWorld -> (!MaybeError TaskException TaskId, !*IWorld) | iTask a
createDetachedTaskInstance task isTopLevel evalOpts instanceNo attributes listId refreshImmediate iworld=:{options={appVersion,autoLayout},current={taskTime},clock}
# task = if autoLayout (tune (ApplyLayout defaultSessionLayout) task) task
# task = if autoLayout (applyLayout defaultSessionLayout task) task
# (instanceKey,iworld) = newInstanceKey iworld
# progress = {InstanceProgress|value=Unstable,instanceKey=instanceKey,attachedTo=[],firstEvent=Nothing,lastEvent=Nothing}
# constants = {InstanceConstants|session=False,listId=listId,build=appVersion,issuedAt=clock}
......
......@@ -199,6 +199,7 @@ runUnitTestsCLI :: [TestSuite] *World -> *World
runUnitTestsCLI suites world
# (console,world) = stdio world
# (report,(console,world)) = foldl runSuite ([],(console,world)) suites
# console = showStats report console
# (_,world) = fclose console world
# world = setReturnCode (if (noneFailed report) 0 1) world
= world
......@@ -226,6 +227,15 @@ where
= (console,world)
= ([(name,result):results],(console,world))
showStats report console
# console = fwrites ("Tests executed: "+++ toString (countTests (const True)) +++ ", ") console
# console = fwrites ("Passed: "+++ green (toString (countTests (\r -> r =: Passed))) +++ ", ") console
# console = fwrites ("Skipped: "+++ yellow (toString (countTests (\r -> r =: Skipped))) +++ ", ") console
# console = fwrites ("Failed: " +++ red (toString (countTests (\r -> r =: (Failed _)))) +++ "\n") console
= console
where
countTests condition = sum (map (\{testResults} -> length (filter (condition o snd) testResults)) report)
//ANSI COLOR CODES -> TODO: Create a library in clean-platform for ANSI colored output
red s = toString [toChar 27,'[','3','1','m'] +++ s +++ toString [toChar 27,'[','0','m']
green s = toString [toChar 27,'[','3','2','m'] +++ s +++ toString [toChar 27,'[','0','m']
......
......@@ -42,6 +42,7 @@ derive class iTask UITreeNode
| RemoveChild //Remove the child at the given index (next children 'move down')
| InsertChild !UI //Insert a new child at the given index (next children 'move up')
| MoveChild !Int //Move an existing child a given index to a new index
//(i,MoveChild j) == [(i,RemoveChild),(j,InsertChild _)]
derive class iTask UIChange, UIAttributeChange, UIChildChange
......@@ -108,6 +109,8 @@ derive class iTask UIChange, UIAttributeChange, UIChildChange
| UIData
:: UIAttributes :== Map String JSONNode
:: UIAttribute :== (!String,!JSONNode)
:: UIAttributeKey :== String
// Floating window
:: UIWindowType
......@@ -172,6 +175,7 @@ LABEL_ATTRIBUTE :== "label"
PREFIX_ATTRIBUTE :== "prefix"
POSTFIX_ATTRIBUTE :== "postfix"
ICON_ATTRIBUTE :== "icon"
STEPPED_ATTRIBUTE :== "stepped"
//Construction functions
......@@ -236,7 +240,8 @@ resizableAttr :: ![UISide] -> UIAttributes
maxlengthAttr :: !Int -> UIAttributes
minlengthAttr :: !Int -> UIAttributes
boundedlengthAttr :: !Int !Int -> UIAttributes
eventTimeoutAttr :: !(Maybe Int) -> UIAttributes
eventTimeoutAttr :: !(Maybe Int) -> UIAttributes
steppedAttr :: !Bool -> UIAttributes
editAttrs :: !String !String !(Maybe JSONNode) -> UIAttributes
choiceAttrs :: !String !String ![Int] ![JSONNode] -> UIAttributes
......
......@@ -209,9 +209,12 @@ minlengthAttr l = 'DM'.fromList [("minlength", JSONInt l)]
boundedlengthAttr :: !Int !Int -> UIAttributes
boundedlengthAttr min max = 'DM'.unions [minlengthAttr min, maxlengthAttr max]
eventTimeoutAttr :: !(Maybe Int) -> UIAttributes
eventTimeoutAttr :: !(Maybe Int) -> UIAttributes
eventTimeoutAttr to = 'DM'.fromList [("eventTimeout", maybe JSONNull JSONInt to)]
steppedAttr :: !Bool -> UIAttributes
steppedAttr stepped = 'DM'.fromList [(STEPPED_ATTRIBUTE, JSONBool stepped)]
editAttrs :: !String !String !(Maybe JSONNode) -> UIAttributes
editAttrs taskId editorId mbValue
= 'DM'.fromList [("taskId",JSONString taskId),("editorId",JSONString editorId):maybe [] (\value -> [("value",value)]) mbValue]
......
......@@ -6,61 +6,15 @@ definition module iTasks.UI.Layout
* updates that are later applied accordingly.
*/
from iTasks.UI.Definition import :: UI, :: UIType, :: UIAttributes, :: UIChange
from iTasks.UI.Definition import :: UI, :: UIType, :: UIAttribute, :: UIAttributes, :: UIAttributeKey, :: UIChange, :: UIChildChange
from Data.Maybe import :: Maybe
from Data.Map import :: Map
from Data.Set import :: Set
from Data.Either import :: Either
from Text.GenJSON import :: JSONNode
// When a layout changes the stucture of the UI, changes to the UI have to be
// changed too to route the changes to the correct place in the structure
:: Layout =
{ apply :: UI -> (UIChange,LayoutState) // Modify the UI layout to the existing UI
, adjust :: (UIChange,LayoutState) -> (UIChange,LayoutState) // Rewrite changes to the UI to accomodate for the changes caused by the layout
, restore :: LayoutState -> UIChange // Modify the UI to a state as if the layout had never been applied
}
:: LayoutState
= LSNone //No state is tracked for a layout
| LSType !UI //State for layouts that change the type
| LSAttributes !UIAttributes //State for layouts that modify attributes
| LSModifyAttributes !UIAttributes !UIAttributes //A more extended state for layouts that modify attributes
| LSCopyAttributes !UI //A more extended state for layouts that copy attributes
| LSWrap !UI //State for unwrap layouts
| LSUnwrap !UI //State for unwrap layouts
| LSInsert !Int //State for inserting layouts
| LSSequence !LayoutState !LayoutState //Combined state of two sequenced layouts
| LSLayoutSubUIs !UI (LayoutTree LayoutState ()) //States of layouts applied to sub-ui's
| LSRemoveSubUIs !MvUI //UI's that were removed by the layout
| LSReference !UI
:: LayoutTree a b
= UIModified !a
| SubUIsModified !b ![(Int,LayoutTree a b)]
// This is an extended version of UI that annotates UI's with additional information about nodes that were removed, moved or restored.
:: MvUI = { type :: UIType //From UI
, attr :: UIAttributes //From UI
, matched :: Bool //Does this node match the selection upstream? (we hide this node downstream)
, moved :: Bool //Have we moved this node to another node?
//They were inserted somewhere, so we should know that we have to remove them there
, deleted :: Bool //When an upstream change replaces, or removes a UI, we only mark it, and remove it after we have adjusted the destination
, dstChange :: UIChange //If we have moved an item, we need to store local changes such that they can be applied in the target location
, children :: [MvUIChild] //Either items original nodes, or additional marks
}
:: MvUIChild
= MvUIItem MvUI //Upstream UI nodes with their annotations
| MvUIMoveDestination Int //A marker for the segment in the upstream ui where the moved nodes have been inserted (n should equal the amount of moved nodes)
// | MvUINoLongerMoved Int //A marker that indicates that at this location in the UI there were previously 'moved' nodes.
// //A RemoveChild or ReplaceUI change has removed them.
// In specifications of layouts, sub-parts of UI's are commonly addressed as
// a path of child selections in the UI tree.
:: UIPath :== [Int]
from StdOverloaded import class <
// This type is a mini query language to describe a selection
// of nodes in a UI (use for removing, moving, hiding or layouting)
......@@ -108,82 +62,142 @@ SelectChildren :== SelectByDepth 1
= SelectAll
| SelectKeys ![String]
// Basic DSL for creating layouts
// In specifications of layouts, sub-parts of UI's are commonly addressed as
// a path of child selections in the UI tree.
:: UIPath :== [Int]
// == Do nothing ==
idLayout :: Layout
// Basic DSL for creating layouts
// == Changing node types ==
setUIType :: UIType -> Layout
setUIType:: UIType -> LayoutRule
// == Changing attributes ==
setUIAttributes :: UIAttributes -> Layout
delUIAttributes :: UIAttributeSelection -> Layout
modifyUIAttributes :: UIAttributeSelection (UIAttributes -> UIAttributes) -> Layout
copySubUIAttributes :: UIAttributeSelection UIPath UIPath -> Layout
setUIAttributes :: UIAttributes -> LayoutRule
delUIAttributes :: UIAttributeSelection -> LayoutRule
modifyUIAttributes :: UIAttributeSelection (UIAttributes -> UIAttributes) -> LayoutRule
copySubUIAttributes :: UIAttributeSelection UIPath UIPath -> LayoutRule
// == Changing the structure of a UI ==
wrapUI :: UIType -> LayoutRule
unwrapUI :: LayoutRule
//* Create a new UI node which has the original UI as its only child.
wrapUI :: UIType -> Layout
//* Replace the UI by its first child.
unwrapUI :: Layout
/*
* Hide a (piece of a) UI
*/
hideUI :: LayoutRule
removeSubUIs selection :== layoutSubUIs selection hideUI
/*
* Insert a (static) element into a UI
*/
insertChildUI :: Int UI -> Layout
/**
* Remove all elements that match the predicate, but keep the removed elements in the state.
* Further changes to these elements are processed in the background. When the predicate no longer holds, the elements are inserted back into the UI.
* When new elements are added dynamically they are also tested against the predicate
*/
removeSubUIs :: UISelection -> Layout
insertChildUI :: Int UI -> LayoutRule
/**
* Move all elements that match the predicate to a particular location in the tree.
* Further changes to these elements are rewritten to target the new location.
* When new elements are added dynamically they are also tested against the predicate
*/
moveSubUIs :: UISelection UIPath Int -> Layout
moveSubUIs :: UISelection UIPath Int -> LayoutRule
// == Composition of layouts ==
/**
* Apply a layout locally to parts of a UI
* Applying a rule locally to matching parts of a UI
* When the predicate no longer holds, the elements are inserted back into the UI.
* When new elements are added dynamically they are also tested against the predicate.
*/
layoutSubUIs :: UISelection Layout -> Layout
/**
* Apply multiple layouts sequentially. The UI changes that have been transformed by one layout are further transformed by the next layout
*/
sequenceLayouts :: Layout Layout -> Layout
layoutSubUIs :: UISelection LayoutRule -> LayoutRule
/**
* This layout can apply any transformation on UI's, but it replaces everything on each change.
* Use this only as a debugging tool, because it will effectively remove the minimal data exchange of editors with UIChanges
* Applying multiple rules one after another.
*/
referenceLayout :: (UI -> UI) -> Layout
applyLayout :: Layout UI -> UI
//Reference layouts of all core layouts for testing
setUITypeRef_ :: UIType -> Layout
setUIAttributesRef_ :: UIAttributes -> Layout
delUIAttributesRef_ :: UIAttributeSelection -> Layout
modifyUIAttributesRef_ :: UIAttributeSelection (UIAttributes -> UIAttributes) -> Layout
copySubUIAttributesRef_ :: UIAttributeSelection UIPath UIPath -> Layout
wrapUIRef_ :: UIType -> Layout
unwrapUIRef_ :: Layout
insertChildUIRef_ :: Int UI -> Layout
removeSubUIsRef_ :: UISelection -> Layout
moveSubUIsRef_ :: UISelection UIPath Int -> Layout
layoutSubUIsRef_ :: UISelection Layout -> Layout
sequenceLayoutsRef_ :: Layout Layout -> Layout
//This type records the states of layouts applied somewhere in a ui tree
:: NodeLayoutStates :== [(Int,NodeLayoutState)]
:: NodeLayoutState
= BranchLayout LayoutState
| ChildBranchLayout NodeLayoutStates
:: TaskHost a = InTaskHost | NoTaskHost
sequenceLayouts :: [LayoutRule] -> LayoutRule
// ### Implementation: ####
//Experimental type that encodes all changes that are in effect by layouts
//From this data structure both the UI with, and without the layout effects, can be deduced
:: LUI
//UI nodes (with upstream changes)
= LUINode UIType UIAttributes [LUI] LUIChanges LUIEffects
//Placeholder nodes
| LUIShiftDestination LUIShiftID
| LUIMoveSource LUIMoveID
| LUIMoveDestination LUIMoveID LUINo
//Upstream UI changes
:: LUIChanges =
{ toBeInserted :: !Bool
, toBeRemoved :: !Bool
, toBeReplaced :: !Maybe LUI
, toBeShifted :: !Maybe LUIShiftID
, setAttributes :: UIAttributes
, delAttributes :: Set UIAttributeKey
}
:: LUIEffects =
{ overwrittenType :: LUIEffectStage (LUINo,UIType)
, overwrittenAttributes :: Map UIAttributeKey (LUIEffectStage (LUINo,JSONNode))
, hiddenAttributes :: Map UIAttributeKey (LUIEffectStage LUINo)
, additional :: LUIEffectStage LUINo
, hidden :: LUIEffectStage LUINo
, wrapper :: LUIEffectStage LUINo
, unwrapped :: LUIEffectStage LUINo
}
//Layout rules determine that an effect should according to that rule be applied or restored.
//This desired state change can be undone by a later rule
//Only when the downstream changes have been collected is an effect marked as 'applied'
:: LUIEffectStage a
//In between events effects can only be either applied or not
= ESNotApplied
| ESApplied a
//While the layout rules are applied the effects can be in intermediate state
| ESToBeApplied a
| ESToBeUpdated a a
| ESToBeRemoved a
//Nodes that are moved by a moveSubUIs rule need to be accesible both in their source location (to apply changes)
//and in their destination location (to apply further effects).
//To make this possible, we put those nodes in a separate table and put references in the tree
:: LUIMoves :== Map LUIMoveID (LUIEffectStage LUINo, LUI)
noChanges :: LUIChanges
noEffects :: LUIEffects
//When layout rules make changes, it must be tracable which layout rule caused the change
:: LUINo = LUINo [Int]
instance < LUINo
instance == LUINo
instance toString LUINo
//When shifting children, it must be tracable which source connects to which destination
:: LUIShiftID :== Int
:: LUIMoveID :== Int
//A layout rule is simply a function that applies (or undoes) an effect to a LUI tree
:: LayoutRule :== LUINo (LUI,LUIMoves) -> (LUI, LUIMoves)
initLUI :: UI -> LUI
initLUIMoves :: LUIMoves
extractResetChange :: (LUI,LUIMoves) -> (UIChange,(LUI,LUIMoves))
applyUpstreamChange :: UIChange (LUI,LUIMoves) -> (LUI,LUIMoves)
extractDownstreamChange :: (LUI,LUIMoves) -> (!UIChange,!(LUI,LUIMoves))
//Helper functions (exported for unit testing)
scanToPosition_ :: LUINo Int [LUI] LUIMoves -> (Int,Bool,Maybe LUI)
nodeExists_ :: !LUINo !LUI LUIMoves -> Bool
selectChildNodes_ :: LUINo ([LUI],LUIMoves) -> [LUI]
updateChildNodes_ :: LUINo (Int (LUI,LUIMoves) -> (LUI,LUIMoves)) ([LUI],LUIMoves) -> ([LUI],LUIMoves)
selectSubNode_ :: LUINo UIPath (LUI,LUIMoves) -> Maybe LUI
updateSubNode_ :: LUINo UIPath ((LUI,LUIMoves) -> (LUI,LUIMoves)) (LUI,LUIMoves) -> (LUI,LUIMoves)
selectAttributes_ :: UIAttributeSelection UIAttributes -> UIAttributes
overwriteAttribute_ :: LUINo UIAttribute (Map UIAttributeKey (LUIEffectStage (LUINo,JSONNode))) -> (Map UIAttributeKey (LUIEffectStage (LUINo,JSONNode)))
hideAttribute_ :: LUINo (UIAttributeKey -> Bool) UIAttributeKey (Map UIAttributeKey (LUIEffectStage LUINo)) -> (Map UIAttributeKey (LUIEffectStage LUINo))
matchAttributeKey_ :: UIAttributeSelection UIAttributeKey -> Bool
extractUIWithEffects_ :: (LUI,LUIMoves) -> Maybe UI
isPartOf_ :: LUINo LUINo -> Bool
This diff is collapsed.
definition module iTasks.UI.Layout.BasicForms
/**
* This module provides a layout rule that converts all intermediate UI nodes to basic forms
* It does what the minimal layout does, but also adds labels and hint icons to form elements
*/
import iTasks.UI.Layout
basicFormsSessionLayout :: LayoutRule
implementation module iTasks.UI.Layout.BasicForms
import iTasks.UI.Definition
import iTasks.UI.Layout
import iTasks.UI.Layout.Common
import StdBool, StdString, StdArray, Data.List, Data.Maybe, Text.GenJSON
import qualified Data.Map as DM
basicFormsSessionLayout :: LayoutRule
basicFormsSessionLayout = layoutCombinatorContainers
layoutCombinatorContainers = sequenceLayouts
[layoutSubUIs (SelectByType UIInteract) layoutInteract
,layoutSubUIs (SelectByType UIStep) layoutStep
,layoutSubUIs (SelectByType UIParallel) layoutParallel
,layoutSubUIs (SelectByType UIAction) layoutAsButton
,removeSubUIs (SelectByType UIEmpty)
]
layoutStep = sequenceLayouts
[setUIType UIContainer
,addButtonBar
,layoutSubUIs (SelectAND SelectDescendents (SelectByType UIStep)) layoutStep
]
where
addButtonBar = sequenceLayouts
[insertChildUI 1 (ui UIButtonBar) //Create a buttonbar
,moveSubUIs (SelectAND SelectChildren (SelectByType UIAction)) [1] 0 //Move all actions to the buttonbar
,layoutSubUIs (SelectByPath [1]) (layoutSubUIs SelectChildren layoutAsButton) //Transform actions to buttons
]
layoutParallel = sequenceLayouts
[setUIType UIContainer
,layoutSubUIs (SelectAND SelectDescendents (SelectByType UIParallel)) layoutParallel
]
layoutInteract = sequenceLayouts
[setUIType UIPanel
,layoutSubUIs (SelectAND SelectDescendents SelectFormElement) toFormItem
,layoutSubUIs (SelectAND SelectDescendents SelectEditorContainers) layoutEditorContainer
]
SelectFormElement = SelectByHasAttribute LABEL_ATTRIBUTE
SelectEditorContainers = foldr1 SelectOR
(map SelectByType [UIPair,UIRecord,UICons,UIVarCons])
layoutEditorContainer = sequenceLayouts
[setUIType UIContainer
,layoutSubUIs (SelectAND SelectDescendents SelectEditorContainers) layoutEditorContainer
]
layoutAsButton = sequenceLayouts
[setUIType UIButton
,modifyUIAttributes (SelectKeys ["actionId"]) toButtonAttributes
]
where
toButtonAttributes attr
= maybe attr (\(JSONString a) -> 'DM'.unions [valueAttr (JSONString a),textAttr a]) ('DM'.get "actionId" attr)
......@@ -15,7 +15,7 @@ from iTasks.WF.Definition import :: Task
* Create a tabset with all child items as separate tabs
* The flag denotes whether close buttons should be lifted to the tabs
*/
arrangeWithTabs :: Bool -> Layout
arrangeWithTabs :: Bool -> LayoutRule
/**
* Extract one child item and put it in a separate panel at the side of the screen
......@@ -25,13 +25,13 @@ arrangeWithTabs :: Bool -> Layout
* @param Initial size of the sidebar
* @param Enable resize?
*/
arrangeWithSideBar :: !Int !UISide !Int !Bool -> Layout
arrangeWithSideBar :: !Int !UISide !Int !Bool -> LayoutRule
/**
* Lift actions starting with / to the menu
* @param The list of paths to menu separators
*/
arrangeAsMenu :: [[Int]] -> Layout
arrangeAsMenu :: [[Int]] -> LayoutRule
/**
* Divide the available screen space
......@@ -39,35 +39,35 @@ arrangeAsMenu :: [[Int]] -> Layout
* @param Direction to split the available space in
* @param Enable resize?
*/
arrangeSplit :: !UIDirection !Bool -> Layout
arrangeSplit :: !UIDirection !Bool -> LayoutRule
/**
* Turn current UI into a panel and set direction to vertical.
*/
arrangeVertical :: Layout
arrangeVertical :: LayoutRule
/**
* Turn current UI into a panel and set direction to vertical.
*/
arrangeHorizontal :: Layout
arrangeHorizontal :: LayoutRule
/**
* Turn the UI into a wrapping framed container inside a general container
*
* Use this is if you don't want to use the entire viewport
*/
frameCompact :: Layout
frameCompact :: LayoutRule
/**
* Apply a layout only before a step has been made
*/
beforeStep :: Layout -> Layout
beforeStep :: LayoutRule -> LayoutRule