Download presentation
Presentation is loading. Please wait.
Published bySuzanna McKinney Modified over 6 years ago
1
Generic Graphical User Interfaces ___________
Peter Achten - Marko van Eekelen - Rinus Plasmeijer University of Nijmegen
2
Problem Description How to define Graphical User Interfaces ?
Visual editor : + Look: simply draw or use predefined components - Feel: connecting visual objects to handling code - Gui’s which look and feel depend on run-time data Program API: + Any functionality offered by the OS can be used - Steep learning curve Object I/O: Clean’s platform independent GUI library, (Peter Achten) partly available for Haskell programmers subset ported to Haskell by Karsimir Angelor combine Haskell and Clean programs using Peter Diviansky & Hajnalka Hegedus front end Properties of Object I/O: simple GUI’s are relatively easy to define complicated GUI’s require much more expertise and complicated code
3
Object I/O : Clean IDE (diederik van arkel)
4
Object I/O : Sparkle Theorem Prover (maarten de mol)
5
Problem Description For defining GUI’s we need better tools !
New feature in Clean: kind-indexed Generic Functions small examples : generic equality, map, foldr, : parser, pretty-printer serious stuff : parser generators, e.g. XML-parser : automatic marshalling for calling Web services : GAST automatic testing tool (Pieter Koopman) Can Generic Programming Techniques be used to generate GUI’s ?
6
Overview of the talk Architecture and use of generic Graphical Editor Components Implementation of these GECs using generic programming techniques Conclusions and Future Work
7
Generic GUI Components
Wanted: high-level, flexible, powerful, and reusable GUI components Use generics to generate a Graphical Editor Component that can display any value of any type can be used to edit and change any value of that type takes care of all communication with any (related) visual component use generic specialisation such that it can be customised in an easy way
8
Architecture of a Graphical Editor Component
:: Tree a = Node (Tree a) a (Tree a) | Leaf Location :: Location Initial Value :: t Call-back function :: t (PSt ps) (PSt ps) GEC Handle :: GEC_Handle t (PSt ps)
9
Architecture of a Graphical Editor Component
:: Tree a = Node (Tree a) a (Tree a) | Leaf Location :: Location Initial Value :: t Call-back function :: t (PSt ps) (PSt ps) GEC Handle :: GEC_Handle t (PSt ps) Demo
10
Architecture of a Graphical Editor Component
generic gGEC t :: Location t (t *(PSt ps) * (PSt ps)) *(PSt ps) *(GEC_Handle t *(PSt ps),*(PSt ps)) :: GEC_Handle t pSt = { .... , gecGetValue :: *pSt *(t, *pSt) , gecSetValue :: t *pSt *pSt }
11
Architecture of a Graphical Editor Component
generic gGEC t :: Location t (t *(PSt ps) * (PSt ps)) *(PSt ps) *(GEC_Handle t *(PSt ps),*(PSt ps)) :: GEC_Handle t pSt = { .... , gecGetValue :: *pSt *(t, *pSt) , gecSetValue :: t *pSt *pSt } gGEC location (Node Leaf 1 Leaf) pst
12
Examples of GEC’s apply_Two_GECs toBalancedTree [1,5,2,8,3,9] pst
where apply_Two_GECs f a pst # (fGecHndl, pst) = gGEC loc1 (f a) not_used pst # (_, pst) = gGEC loc2 a (set fGecHndl f) pst = pst set handle f na pst = handle .gecSetValue (f na) pst
13
Examples of GEC’s apply_Two_GECs toBalancedTree [1,5,2,8,3,9] pst
where apply_Two_GECs f a pst # (fGecHndl, pst) = gGEC loc1 (f a) not_used pst # (_, pst) = gGEC loc2 a (set fGecHndl f) pst = pst set handle f na pst = handle .gecSetValue (f na) pst
14
Examples of GEC’s apply_Self_GEC balanceTree (Node Leaf 1 Leaf) pst
where apply_Self_GEC f a pst = new_pst (selfGecHndl, new_pst) = gGEC loc (f a) (set selfGecHndlf) pst
15
Examples of GEC’s apply_Self_GEC balanceTree (Node Leaf 1 Leaf) pst
where apply_Self_GEC f a pst = new_pst (selfGecHndl, new_pst) = gGEC loc (f a) (set selfGecHndlf) pst
16
GEC Combinators In this way all kinds of GEC's connections can be made: e.g. application, split, join, mutual recursive, etcetera. GEC-combinators (like parser combinators): collection of high-order operators to making arbitrary circuit of editors, displays, and functions (Arjen van Weelden)
17
Costomizing the look of GEC’s
:: UpDown = UpPressed | DownPressed | Neutral :: Counter a :== (a,UpDown) updateCounter:: (Counter a) (Counter a) | IncDec a updateCounter (n,UpPressed) = (n+one,Neutral) updateCounter (n,DownPressed) = (n-one,Neutral) updateCounter any = any apply_Self_GEC updateCounter (0,Neutral)
18
Costomizing the look of GEC’s
:: UpDown = UpPressed | DownPressed | Neutral :: Counter a :== (a,UpDown) updateCounter:: (Counter a) (Counter a) | IncDec a updateCounter (n,UpPressed) = (n+one,Neutral) updateCounter (n,DownPressed) = (n-one,Neutral) updateCounter any = any apply_Self_GEC updateCounter (0,Neutral) gGEC {| (,) |} = …. // just redefine graphical representation for tuples gGEC {| UpDown |} = …. // just redefine graphical representation for UpDown
19
Costomizing the look of GEC’s
:: UpDown = UpPressed | DownPressed | Neutral :: Counter a :== (a,UpDown) updateCounter:: (Counter a) (Counter a) | IncDec a updateCounter (n,UpPressed) = (n+one,Neutral) updateCounter (n,DownPressed) = (n-one,Neutral) updateCounter any = any apply_Self_GEC updateCounter (0,Neutral) gGEC {| (,) |} = …. // just redefine graphical representation for tuples gGEC {| UpDown |} = …. // just redefine graphical representation for UpDown
20
Composing GEC’s - part 1 Solution: create a “b”-editor that is used as an “a”-value ! :: BimapGEC a b = { toGEC :: a b , updGEC :: b b , fromGEC :: b a , value :: a }
21
Composing GEC’s - part 1 Solution: create a “b”-editor that is used as an “a”-value ! :: BimapGEC a b = { toGEC :: a b , updGEC :: b b , fromGEC :: b a , value :: a } gGEC {| BimapGEC |} = … // convert initial “a”-value to “b”-domain // apply updGEC to any change in “b”-domain // and convert result back to “a”-domain // and store it in value field
22
Composing GEC’s - part 1 :: BimapGEC a b = { toGEC :: a b
Solution: create a “b”-editor that is used as an “a”-value ! :: BimapGEC a b = { toGEC :: a b , updGEC :: b b , fromGEC :: b a , value :: a } gGEC {| BimapGEC |} = … // convert initial “a”-value to “b”-domain // apply updGEC to any change in “b”-domain // and convert result back to “a”-domain // and store it in value field cntrGEC :: a BimapGEC a (Counter a) | IncDec a cntrGEC i = { toGEC = \i (i,Neutral) , updGEC = updateCounter , fromGEC = fst , value = i }
23
Composing GEC’s - part 2 Abstract: Hide the "b"-editor type in an abstract type AGEC But: type needed to generate an editor => hide the editor in type :: AGEC a = E. b : Hidden (BimapGEC a b) (A. ps: GEC_Handle (BimapGEC a b) (PSt ps)) gGEC {| AGEC |} = … // same as BimapGEC, but with hidden editor included
24
Composing GEC’s - part 2 Solution: Hide the "b"-editor type in an abstract type AGEC But: type needed to generate an editor => hide the editor in type :: AGEC a = E. b : Hidden (BimapGEC a b) (A. ps: GEC_Handle (BimapGEC a b) (PSt ps)) gGEC {| AGEC |} = … // same as BimapGEC, but store the editor inside mkAGEC :: (BimapGEC a b) AGEC a | gGEC{|*|} a & gGEC{|*|} b ^^ :: (AGEC a) a (^=) infixl :: (AGEC a) a (AGEC a)
25
Composing GEC’s - part 2 Solution: Hide the "b"-editor type an abstract type AGEC But: type needed to generate an editor => hide the editor in type :: AGEC a = E. b : Hidden (BimapGEC a b) (A. ps: GEC_Handle (BimapGEC a b) (PSt ps)) gGEC {| AGEC |} = … // same as BimapGEC, but store the editor inside mkAGEC :: (BimapGEC a b) AGEC a | gGEC{|*|} a & gGEC{|*|} b ^^ :: (AGEC a) a (^=) infixl :: (AGEC a) a (AGEC a) counterGEC :: a AGEC a | gGEC{|*|} a & IncDec a calcGEC :: a [[(Button,a a)]] AGEC a | gGEC{|*|} a idGEC :: a AGEC a | gGEC{|*|} a hidGEC :: a AGEC a | gGEC{|*|} a horlistGEC :: [a] AGEC [a] | gGEC{|*|} a vertlistGEC :: [a] AGEC [a] | gGEC{|*|} a tableGEC :: [[a]] AGEC [[a]] | gGEC{|*|} a
26
Composing GEC’s - part 3 :: DoubleCounter a = { cntr1 :: AGEC a, cntr2 :: AGEC a, sum :: AGEC a } doubleCntr:: (DoubleCounter a) DoubleCounter a | + a doubleCntr cntr = { cntr & sum = cntr.sum ^= ^^ cntr.cntr1 + ^^ cntr.cntr2 } apply_Self_GEC doubleCntr { cntr1 = idGEC 0 , cntr2 = idGEC 0, sum = idGEC 0 }
27
Composing GEC’s - part 5 :: DoubleCounter a = { cntr1 :: AGEC a, cntr2 :: AGEC a, sum :: AGEC a } doubleCntr:: (DoubleCounter a) DoubleCounter a | + a doubleCntr cntr = { cntr & sum = cntr.sum ^= ^^ cntr.cnt1 + ^^ cntr.cnt2 } apply_Self_GEC doubleCntr { cntr1 = idGEC 0 , cntr2 = idGEC 0, sum = idGEC 0 } apply_Self_GEC doubleCntr { cntr1 = cntrGEC 0, cntr2 = cntrGEC 0, sum = idGEC 0 }
28
Composing GEC’s - part 5 :: DoubleCounter a = { cntr1 :: AGEC a, cntr2 :: AGEC a, sum :: AGEC a } doubleCntr:: (DoubleCounter a) DoubleCounter a | + a doubleCntr cntr = { cntr & sum = cntr.sum ^= ^^ cntr.cnt1 + ^^ cntr.cnt2 } apply_Self_GEC doubleCntr { cntr1 = idGEC 0 , cntr2 = idGEC 0, sum = idGEC 0 } apply_Self_GEC doubleCntr { cntr1 = cntrGEC 0, cntr2 = cntrGEC 0, sum = idGEC 0 } apply_Self_GEC doubleCntr { cntr1 = cntrGEC 0, cntr2 = calcGEC 0, sum = idGEC 0 }
29
Generic function definitions (Hinze, Jeuring, Alimarine)
One function definition for all thinkable (future) data structures: List a gGEC :: … (List a) … Handle (List a) from List to List Generic Type generic gGEC :: … t … Handle (Generic Type) from Tree to Tree Tree a gGEC :: … (Tree a) … Handle (Tree a)
30
Bimaps between User Type Generic Types
:: List a = Cons a (List a) | Nil Family of Generic types :: UNIT = UNIT :: EITHER a b = LEFT a | RIGHT b :: PAIR a b = PAIR a b :: Type a = Type InfoT a :: Cons a = Constr InfoC a Unit Left Right Pair :: List Cons :: Nil ::
31
Converting User Data Generic Representation
:: List a = Cons a (List a) | Nil Cons 1 Nil Left 1 Unit Pair Right :: List Cons :: Nil ::
32
Converting User Data Generic Representation
:: List a = Cons a (List a) | Nil Cons 1 (Cons 2 Nil) :: List Left Cons :: Pair 1 :: List Left Cons :: Pair 2 :: List Right Nil :: Unit
33
Implementation issues
Problems There is no “type of types” that we can use to represent any type Generic types are actually a family of types A user defined type is converted to a generic type in a lazy way We want to be able to change any data interactively in any order New implementation technique required for interactive applications: For each generic element an Object I/O object (a receiver) is created Objects communicate in Object I/O via message passing primitives All objects offer methods like: GetValue, SetValue t, OpenGUI, CloseGUI, Switch. Communication infrastructure separated from graphical representation
34
Objects that Represent a Generic Value
:: List a = Cons a (List a) | Nil Cons 1 Nil Objects Infrastructure Graphical Representation :: List Left Cons :: Nil :: Pair 1 :: List Right Cons :: Nil :: Unit
35
Objects that Represent a Generic Value
:: List a = Cons a (List a) | Nil Nil Objects Infrastructure Graphical Representation :: List Right Left Cons :: Nil :: Pair Unit 1 :: List Right Cons :: Nil :: Unit
36
Objects that Represent a Generic Value
:: List a = Cons a (List a) | Nil Cons 1 Nil Objects Infrastructure Graphical Representation Graphical Representation :: List Left Cons :: Nil :: Pair Unit 1 :: List Right Cons :: Nil :: Unit
37
Objects that Represent a Generic Value
:: List a = Cons a (List a) | Nil Cons 1 (Cons 2 Nil) Objects Infrastructure Graphical Representation :: List Left Cons :: Nil :: Pair Unit 1 :: List Right Cons :: Nil :: Pair Unit 2 :: List Right Cons :: Nil :: Unit
38
Conclusions & Future Work
Generic functions are very suited for generating interactive applications GEC’s are easy to use building blocks: rapid prototyping, education, debugging Composition of GEC's possible to display/edit any type in a customized way GEC Combinators are available to create any thinkable circuit of editors Circuits can be used as (abstract) editor Future work Include functions in editors using Arjen van Weelden’s OS Shell Use editors in shell to visualize values, directories (browser), anything
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.