\documentstyle[sli,pceslide,psfig]{article} \renewcommand{\slinote}{Programming in XPCE/Prolog} \psdirectories{figs,../../userguide/figs,../../../TeX/figs} \begin{document} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % INTRO % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Overview} Part 1 \begin{itemize} \item Introduction \item Prolog interface \item Programming Environment \end{itemize} Part 2 \begin{itemize} \item Application control structure \item Using XPCE Executable Objects \item User-Defined Classes \end{itemize} \end{sli} \begin{sli}{Its Authors and History} \begin{itemize} \item{PCE Versions 1 \& 2 By Anjo Anjewierden.} \begin{itemize} \item Basic architecture and interface \item Connected to SunView \item KADS-PowerTools \& internal UvA projects \item Comercialised to ProWindows-2 \end{itemize} \item{PCE Version 3 By Anjo Anjewierden \& Jan Wielemaker} \begin{itemize} \item KADS-Shelley, KEW \item Various internal and external projects \item object-level programming techniques \end{itemize} \item{XPCE Version 4 By Jan Wielemaker} \begin{itemize} \item KADS-II WB, KEW (ported) \item X11 interface \item Integration of menu's and graphics \item Advanced text, process and network management \item Class-level programming \item Comercialised to ProWindows-3/XPCE \end{itemize} \end{itemize} \end{sli} \begin{sli}{Aims of XPCE} \begin{itemize} \item Language independent (GU)I toolkit \begin{itemize} \item Prolog (QP, SICStus, SWI) \item CommonLisp (Lucid, Harlequin) \item C++ (g++) \end{itemize} \item Communication in hybrid systems \item Interactive diagrams \item GUI prototyping environment \item `Kitchen-sink' environment \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % INTERFACE % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Accessing XPCE from Prolog} \begin{itemize} \item new/2: Creating objects \item send/[2-12]: Changing objects \item get/[3-13]: Getting status \item free/1: Removing objects \end{itemize} \end{sli} \begin{sli}{Creating XPCE Objects: new/2} Synopsis: new({\it ?Reference}, {\it +NewTerm}) Examples: \begin{itemize} \item ?- new(X, point(5,6)). \item ?- new(@newline, string('\verb$\n$')). \item ?- new(X, picture('Hello World')). \item ?- new(X, text_item(name, '', \\ message(@pce, write_ln, @arg1))). \item ?- new(X, chain(new(A, bitmap('pce.bm')))). \end{itemize} \end{sli} \begin{sli}{Manipulating objects: send/[2-12]} Synopsis: send({\it +Reference, +Selector, +Arg ...}) Examples: \begin{itemize} \item send(Point, x, 9) \item ?- send(new(P, picture), open). \item send(Picture, display, new(T, text(hello)), point(30,20)) \item ?- send(file(hello), exists). \end{itemize} Optional arguments ('[...]') may be omitted. \end{sli} \begin{sli}{Querying objects: get/[3-13]} Synopsis: get(({\it +Reference, +Selector, +Arg .... -Result}) \begin{itemize} \item get(Point, x, X) \item get(Graphical, size, size(X, Y)) \item get(Sheet, value, name, Name) \item ?- get(file(hello), size, Size). \end{itemize} \end{sli} \begin{sli}{Discarding objects: free/1} \begin{itemize} \item free(+Reference) \begin{itemize} \item If `toplevel' object \end{itemize} \item send(+Rereference, free) \begin{itemize} \item Error if object does not exist \end{itemize} \item send(+Reference, done) \begin{itemize} \item Discarding answers \item Normally leave this to GC \end{itemize} \end{itemize} \end{sli} \begin{sli}{Lazy creation: pce_global/2} Synopsis: :- pce_global(+Ref, +NewTerm$\|$Goal). Examples: \begin{itemize} \item :- pce_global(@newline, new(string('\verb$\n$'))). \item :- pce_global(@mainwindow, make_main_window). \begin{code} make_main_window(W) :- send(new(W, picture('Main Window'), open)). \end{code} \end{itemize} \end{sli} \begin{sli}{Named arguments} Synopsis: ArgumentName := ArgumentValue Applicable to all methods that take many arguments. Examples: \begin{itemize} \item :- pce_global(@bold, new(style(bold := @on))). \item send(Popup, append, menu_item(clear, end_group := @on)). \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % PROGRAM ENVIRONMENT % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Programming Environment (Overview)} \begin{itemize} \item Accessible from Manual (manpce/0; PW3: user_help/0) \item Demo Programs \begin{itemize} \item Graphics (PceDraw) \item Text (PceEmacs, ISpell) \item Resources (Fonts, Images, Cursors) \end{itemize} \item ChangeLog \item Class Hierarchy \item Class Browser \begin{itemize} \item Find Classes, Methods and Variables \end{itemize} \item Group Overview \begin{itemize} \item Access by functional categories \end{itemize} \item Keyword Access \item Inpector \begin{itemize} \item Examine Object Structure \end{itemize} \item Visual Hierarchy \begin{itemize} \item Consists-of hierarchy of interface \end{itemize} \end{itemize} \end{sli} \begin{sli}{Class Browser} \slifig{\textwidth}{classbrowser} \end{sli} \begin{sli}{Class Hierarchy} \slifig{\textwidth}{hierarchy} \end{sli} \begin{sli}{Visual Hierarchy} \slifig{\textwidth}{vishierarchy} \end{sli} \begin{sli}{Inspector Tool} \slifig{\textwidth}{inspector} \end{sli} \begin{sli}{PceEmacs} \slifig{\textwidth}{pceemacs} \begin{itemize} \item Well integrated with the PCE/Prolog environment \item Automatic Prolog Indentation \item Close to accepted GNU-Emacs interface \item Programmable in PCE/Prolog \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % ARCHITECTURE % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{XPCE/Prolog architecture overview} \slifig{\textwidth}{control} \end{sli} \begin{sli}{XPCE as integrating server} \slifig{\textwidth}{multilang} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % STRUCTURE OF APPS % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Event-driven structure} \begin{verbatim} initialise :- initialise_database, create_GUI_components. call_back_when_GUI_xyz_is_operated(Context ...) :- change_application_database(Context ...), update_and_create_GUI_components. \end{verbatim} \end{sli} \begin{sli}{Modal Windows} \begin{verbatim} application :- initialise(Heap), create_GUI_components(Heap), process_events_until_computation_may_proceed, proceed(Heap), ... \end{verbatim} Note: during `process_events_until_computation_may_proceed' the system can handle call-backs on Prolog. \end{sli} \begin{sli}{Which structure to use} Event-driven if: \begin{itemize} \item App data is global state \item Editors \end{itemize} Modal Windows if: \begin{itemize} \item Ongoing task with status on stack \item Problem solvers \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % EXECUTABLE OBJECTS % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Executable Objects (aim)} \begin{itemize} \item Define call-back of GUI component \item `Lambda' function: \begin{itemize} \item send(Chain, sort, ?(@arg1, compare, @arg2)) \item get(Win?graphicals, find, @arg1?pen == 5, Gr) \end{itemize} \item Method implementation \begin{itemize} \item User Defined Classes \item Object-level methods \end{itemize} \end{itemize} \end{sli} \begin{sli}{Executable Objects (procedures)} Returns `success' or `failure' \begin{itemize} \item message(Receiver, Selector, Arg ...) \item assign(Var, Value) \item if(Condition, [Then], [Else]) \item or(Statement ...) \item and(Statement ...) \item not(Statement) \item while(Condition, [Statement]) \item Value1 \verb$==$ Value2 \item Value1 \verb$\==$ Value2 \item Int1 \verb$>, =, =<, >, >=$ Int2 \end{itemize} \end{sli} \begin{sli}{Executable Objects (functions)} Returns a value or `failure' \begin{itemize} \item ?(Receiver, Selector, Arg ...) \item Receiver?Selector \item progn(Statement ..., Function|Value) \item when(Condition, Function1|Value1, Function2|Value2) \item var \item \verb$*, +, -, /$ (Integer arithmetic) \end{itemize} Executed iff \begin{itemize} \item Receiver of send() or get() iff not defined on class of function \item Type-checking \item Appears as argument to other executable object \end{itemize} \end{sli} \begin{sli}{Executable Objects (example 1)} Change the font of all text objects in `Device' to `Font': \begin{verbatim} ... send(Device?graphicals, for_all, if(message(@arg1, instance_of, text), message(@arg1, font, Font))) ... \end{verbatim} \end{sli} \begin{sli}{Executable Objects (example 2)} Find graphicals overlapping `Me' in the same device: \begin{verbatim} ... get(Me?device, find_all, message(Me, overlap, @arg1), ChainOfOverlapping) ... \end{verbatim} Or, excluding myself: \begin{verbatim} ... get(Me?device, find_all, and(message(Me, overlap, @arg1), Me \== @arg1), ChainOfOverlapping) ... \end{verbatim} \end{sli} \begin{sli}{Executable Objects (example 3)} Find all classes implementing the send-method `report': \begin{verbatim} ?- new(Hits, chain), send(@classes, for_all, if(?(@arg2?send_methods, find, @arg1?name == report), message(Hits, append, @arg2))). \end{verbatim} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % TYPES % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Types} \begin{itemize} \item First-class objects \item `type ->validate' and `type <-convert' \item Method argument specification \item instance-variable type \end{itemize} Aims \begin{itemize} \item Documentation \item Early trap of errors \item Compile-time checks (TBD) \item Ensure data-consistency \end{itemize} \end{sli} \begin{sli}{Types | Syntax} \begin{tabular}{ll} \tt Name=Type &Argument named `Name' of type `Type' \\ \tt Type ... &Zero or more of these arguments \\ \verb$Type1|Type2$ &Disjunction (either of the types) \\ \tt Type* &The type or the constant @nil \\ \tt [Type] &The type or @default (optional argument) \\ \tt \{Name1,Name2\} &One of these names \\ \tt object &Any true object, except for functions \\ \tt any &Anything (int|object) \\ \tt int &An integer (the only non-object datum) \\ \tt 3..5 &An integer 3 $\leq$ value $\leq$ 5 \\ \tt 3.2..5.6 &A real (float) in this range \\ \tt 3.. &An integer $\geq$ 3 \\ \tt ClassName &Any instance of this class (or sub-class) \\ \tt alien:char * &Alien (C) data. In this case a char * \end{tabular} \end{sli} \begin{sli}{Types | Examples} \begin{tabular}{ll} \verb$any|function$ &Anything, may be function \\ \verb$[code]*$ &Executable object, @default or @nil \\ \verb$graphical$ &Any graphical object (also dialog item) \\ \verb${none,send,get,both}$ &Any of these names \\ \end{tabular} Method examples: \begin{code} point ->initialise: x=[int], y=[int] menu ->append: menu_item (conversion) \end{code} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % USER-DEFINED-CLASSES % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{User-defined Classes} Classes, methods, variables, etc.\ are normal XPCE objects and thus: \begin{itemize} \item May be created using new() \item Manipulated using send() \item Analysed using get() \item ... but currently {\em not} removed using free() \end{itemize} The Prolog front-end: \begin{itemize} \item Prolog-style declaration of classes \item Full Prolog implemented methods \end{itemize} \end{sli} \begin{sli}{Skeleton} \begin{verbatim} :- pce_begin_class(ClassName[(TermArg...)], SuperClass, [Summary]). variable(Name, Type, Access, [Summary]). ... SendMethod(Self, Arg:Type ...) :-> ["Summary"::] send(Self, send_super, SendMethod, SArg ...), NormalPrologCode. ... GetMethod(Self, Arg:Type ..., String:string) :<- ["Summary"::] NormalPrologCodeBinding(String). :- pce_end_class. \end{verbatim} \end{sli} \begin{sli}{User-defined classes. Example 1a} \begin{verbatim} :- pce_begin_class(matrix(width, height), vector, "Two-dimensional array"). variable(width, int, get, "Width of the matrix"). variable(height, int, get, "Height of the matrix"). initialise(M, Width:int, Height:int) :-> "Create matrix fom width and and height":: send(M, send_super, initialise), send(M, slot, width, Width), send(M, slot, height, Height), Size is Width * Height, send(M, fill, @nil, 1, Size). \end{verbatim} \end{sli} \begin{sli}{User-defined classes. Example 1b} \begin{verbatim} element(M, X:int, Y:int, Value:any) :-> "Set element at X-Y to Value":: get(M, width, W), get(M, height, H), between(1, W, X), between(1, H, Y), Location is X + (Y-1) * W, send(M, send_super, element, Location, Value). :- pce_end_class. \end{verbatim} \end{sli} \begin{sli}{Commonly redefined methods (1)} Object management: \begin{itemize} \item ->initialise (initialise new instance) \item <-lookup (new() to return existing instance) \item ->unlink (detach from environment) \end{itemize} Message passing: \begin{itemize} \item <->slot (access slot without side-effects) \item ->send_super (invoke super-method) \item <-get_super (invoke super-method) \end{itemize} \end{sli} \begin{sli}{Commonly redefined methods (2)} Graphics: \begin{itemize} \item ->event (event-processing) \item ->geometry (resize/move) \item ->device (device I'm displayed on) \item ->displayed (visibility) \end{itemize} \end{sli} \begin{sli}{User Defined Classes: Do I need them?} \begin{itemize} \item Specialise XPCE to your applications needs \item Some things can only be redefined at the class-level \item Exploit XPCE's open structure and tools \item Use classes for the overall control \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % INTRO-2 % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Overview (2)} Part 3 \begin{itemize} \item Tracing and debugging \item Dialog windows in Depth \item Error/status reporting \end{itemize} Part 4 \begin{itemize} \item Graphics \item Data representation \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % TRACING AND DEBUGGING % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Tracing and Debugging XPCE} \begin{itemize} \item All active objects in XPCE are instances of a subclass of class program_object. \item Trace- and Break-points may be set on any program-object. \item On any `port' (enter, exit, fail) \item May be conditional \item @pce ->trace: {never,user,always} \begin{itemize} \item Never: Normal execution mode \item User: Watch user-level objects \item Always: Watch any object executing \end{itemize} \item Class vmi (Virtual Machine Instruction) defines the objects \begin{itemize} \item @vmi_send, @vmi_get, @vmi_new, @vmi_free \end{itemize} \end{itemize} \end{sli} \begin{sli}{Tracing and debugging:\\ example 1} \begin{verbatim} ?- new(@m, message(@prolog, @arg1)). ?- send(@m, forward, true). ===> yes ?- send(@m, trace, @on). %%% Trace @m, switch tracer to user-level if it was off ?- send(@m, forward, true). PCE: 3 enter: message(@prolog/host, @arg1/var) PCE: 3 exit: message(@prolog/host, @arg1/var) \end{verbatim} \end{sli} \begin{sli}{Controlling groups of objects} \begin{itemize} \item `object ->trace: @default' ==> Use class <-trace \item `class ->trace: @default' ==> Use super-class <-trace \end{itemize} Thus: \begin{itemize} \item send(class(program_object), trace, @on). \end{itemize} Switches the tracer fully on (in user mode). \end{sli} \begin{sli}{Tracing methods} Trace-points set to individual program objects are {\em always} honoured if trace-level is \verb$user$ or \verb$system$. Utility predicates for method trace-points: \begin{itemize} \item tracepce((+Class <-Method)). \item tracepce((+Class ->Method)). \item tracepce(+Class -Variable). \end{itemize} \end{sli} \begin{sli}{Conditional Trace-points} `program_object ->trace: [bool], [\{full,enter,exit,fail\}], [code]' Variables for code: \begin{itemize} \item @receiver (receiver of action) \item @selector (referred selector) \item @arg1, @arg2, ... (arguments) \end{itemize} Thus: ?- send(@vmi_send, trace, @on, exit, @selector == event). will print all successful exits from sending ->event to any object. \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % DIALOG WINDOWS % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Dialog Windows} \begin{itemize} \item Layout \item Modal Windows \item Prompting for values \item Editing attributes \item Errors and status information \end{itemize} \end{sli} \begin{sli}{Symbolic Layout} \begin{itemize} \item dialog ->append: Item, [\{right,below,next_row\}] \begin{itemize} \item Relative to last appended item \item Buttons left-to-right, rest top-to-bottom \end{itemize} \item Fine Tuning: \begin{itemize} \item dialog_item ->alignment: {column,center,left,right} \item dialog_item ->auto_label_align: bool \item dialog_item ->auto_value_align: bool \item dialog_item ->reference: point \end{itemize} \end{itemize} \end{sli} \begin{sli}{Symbolic layout (why?)} \begin{itemize} \item Fast specification \item Program-generated dialog windows \item Independent of user font preferences \item Independent of user `look-and-feed' \item Consistent feel over applications \begin{itemize} \item Native XPCE \item OpenLook \item ... MS-Windows, Motif \end{itemize} \end{itemize} \end{sli} \begin{sli}{Modal Windows} \begin{itemize} \item Event-subloop to preserve context on the stack \item Normal user-level: \begin{itemize} \item get(Frame, confirm, Value) \item send(Frame, return, Value) \end{itemize} \end{itemize} \begin{code} ask_name(Name) :- new(D, dialog('Please enter name')), send(D, append, new(N, text_item(name))), send(D, append, button(ok, message(D, return, N?selection))), send(D, append, button(cancel, message(D, return, @nil))), get(D, confirm_centered, RVal), send(D, destroy), RVal \== @nil, RVal = Name. \end{code} \end{sli} \begin{sli}{Editing values (methods)} Relevant methods for dialog_item: \begin{itemize} \item <->default: value|function\hfill\\ Normally initialisation argument \item <->restore\hfill\\ Restore <-selection to <-default \item <->apply: always:[bool]\hfill\\ Execute <-message if <-selection is changed or always: @on. \end{itemize} \end{sli} \begin{sli}{Editing values (example)} %) \begin{code} edit_error(Id) :- get(@pce, convert, Id, error, E), new(D, dialog(string('Error %s', Id))), send(D, append, new(F, text_item(format, E?format, message(E, format, @arg1)))), send(F, length, 50), send(D, append, new(K, menu(kind, choice, message(E, kind, @arg1)))), send_list(K, append, [status,inform,warning, error,fatal,ignored]), send(K, default, E?kind), send(D, append, button(apply)), send(D, append, button(restore)), send(D, append, button(cancel, message(D, destroy))), send(D, default_button, apply), send(D, open). \end{code} \end{sli} \begin{sli}{The result ...} \slifig{\textwidth}{editvalue} \end{sli} \begin{sli}{Error and status reports (reporting)} \slifig{\textwidth}{error} \end{sli} \begin{sli}{Reports (types)} \begin{itemize} \item status\hfill\\ Short message telling what is happening. Only display if there is a place for it. \item inform\hfill\\ Short message that must be displayed somehow. \item progress\hfill\\ Short message to indicate progress of an operation. Displayed as `status', but immediately updates display. \item done\hfill\\ Any sequence of `progress' must be followed by `done' to allow removing the message or writing `done' behind it. \item warning\hfill\\ Short message informing a non-severe problem. If it cannot be displayed, invoke ->alert on the offending visual object (bell or flash). \item error\hfill\\ Short message informing a severe problem. If it cannot be displayed, use a confirmer window. \item fatal\hfill\\ Fatal error. Inform in Prolog window, print the stacks and abort to Prolog toplevel. \end{itemize} \end{sli} \begin{sli}{Error objects} \begin{itemize} \item Id \item Format \item Feedback: \{report,print\} \item Kind: \{warning,error,fatal,ignored\} \end{itemize} User errors are normally ->report'ed, application-programmer errors are printed. Catching: pce_catch_error(+Error, +Goal): ?- pce_catch_error(no_behaviour, send(@pce, hello)). no \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % CUSTOM ITEMS % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Custom Dialog Items} \begin{itemize} \item Subclasses existing dialog items \begin{itemize} \item Alternative for setting attributes \item Reprogramming aspects: event-handling, completion \end{itemize} \item Defining as compoung graphical \begin{itemize} \item using class device \item define standard interaction methods \item see course-notes and library pce_font_item.pl \end{itemize} \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % GRAPHICS % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Graphics: Overview} \begin{itemize} \item Primitives (box, circle, text, bitmap) \item Compound graphicals: devices \item Event-handling (graphical ->event, gestures) \item Relations (connection) \item Attributes (pen, texture, font, ...) \item Resources (interface to ~/.Xdefaults) \item Redraw (animation: ->flush) \end{itemize} \end{sli} \begin{sli}{Compound graphicals: devices} \begin{itemize} \item Defining application-specific graphics \item Generally used with user-defined classes \end{itemize} \end{sli} \begin{sli}{A simple icon class} \begin{code} :- pce_begin_class(icon, device). initialise(I, Image:image, Label:name) :-> "Create from image and label":: send(I, send_super, initialise), send(I, display, bitmap(Image)), send(I, display, text(Label, center)), send(I, reposition). reposition(I) :-> get(I, member, bitmap, Bitmap), get(I, member, text, Text), get(Bitmap, center_x, CX), get(Bitmap, bottom_side, BS), get(Text, width, W), TX is CX - W//2, send(Text, set, TX, BS). label(I, Text:name) :-> "Change the label":: get(I, member, text, Text), send(Text, string, Text). :- pce_end_class. \end{code} \end{sli} \begin{sli}{Event-handling: move and select} \begin{code} :- pce_global(@icon_recogniser, new(handler_group( click_gesture(left, '', single, message(@receiver?device, selection, @receiver)), new(move_gesture)))). event(I, Ev:event) :-> "Process event":: ( send(I, send_super, event, Ev) ; send(@icon_recogniser, event, Ev) ). \end{code} \end{sli} \begin{sli}{Refining gestures} A gesture for just moving objects vertically: \begin{code} :- pce_begin_class(vertical_move_gesture, move_gesture). drag(G, Ev:event) :-> "Only use Y-coordinate":: get(Ev, receiver, Graphical), get(Graphical, device, Dev), get(Ev, y, Dev, Y), get(G?offset, y, OY), GY is Y - OY, send(Graphical, y, GY). terminate(G, Ev:event) :-> "Just call ->drag":: send(G, drag, Ev). :- pce_end_class. \end{code} \end{sli} \begin{sli}{Test} \begin{code} test :- send(new(P, picture), open), send(P, display, new(B, box(50,50))), send(B, recogniser, new(vertical_move_gesture)). \end{code} \end{sli} \begin{sli}{Using Connections} \begin{itemize} \item A connection is a line between two {\em handles} \item Handles are connected to graphical objects \end{itemize} Example: \begin{code} :- pce_global(@in_out_link, make_in_out_link). make_in_out_link(L) :- new(L, link(in, out, line(0,0,0,0,second))). linked_box_demo :- new(P, picture('Linked Box demo')), send(P, open), send(P, display, new(B1, box(50,50)), point(20,20)), send(P, display, new(B2, box(25,25)), point(100,100)), send(B1, handle, handle(w, h/2, in)), send(B2, handle, handle(w/2, 0, out)), send(B1, connect, B2, @in_out_link). \end{code} \end{sli} \begin{sli}{Result ...} \slifig{3in}{link} \end{sli} \begin{sli}{Why Connections?} \begin{itemize} \item Little geometry calculations in your application \item They update if one of the graphicals move \item They are destroyed if one of the graphicals is destroyed \item You can easily {\em read} the diagram in terms of nodes and arcs \item Exploited by `graphical ->layout' \end{itemize} \end{sli} \begin{sli}{Graphics Attributes} Generic attributes (available on many graphical classes): \begin{itemize} \item colour \item pen (thickness of drawing pen) \item texture (dash-pattern) \item shadow (box, ellipse, figure) \item radius (rounded corner: box, figure) \item font (predefined, access to all 8-bit X11 fonts) \end{itemize} \end{sli} \begin{sli}{X11-Resources (user-preferences)} \begin{itemize} \item Specify: \verb$~/.Xdefaults$:\hfill\\ Pce.$<$CapitalisedClassName$>$.$<$resource$>$: $<$value$>$ \item Access: `object <-resource_value: resource ==> Value' \end{itemize} Example: \begin{code} :- pce_begin_class(file_icon, icon). resource(image, image, 'file.bm', "Default image"). variable(file, file, get, "Associated file"). initialise(I, File:file) :-> "Create icon for file":: get(I, resource_value, image, Image), send(I, send_super, initialise, Image, File?base_name), send(I, slot, file, File). :- pce_end_class. \end{code} \end{sli} \begin{sli}{Redraw Strategy} \begin{itemize} \item Change of graphical attribute implies: \begin{itemize} \item If recompute necessary: ->request_compute \item If redraw necessary: notify changed area to window \end{itemize} \item top-level-loop of XPCE: \begin{code} forever { while ( events-in-queue ) process event; redraw(all-displays); } \end{code} \end{itemize} \end{sli} \begin{sli}{Consequences} \begin{itemize} \item Automatic redraw after changes \item Efficient handling of multiple changes \item Only need to force redraw \begin{itemize} \item If redraw is required during ongoing computation \end{itemize} \end{itemize} Methods for explicit redraw: \begin{itemize} \item @display ->flush (redraws the display) \item @display ->synchronise (handle all pending events and redraw) \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % PROCESS % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Interprocess communication} Building blocks: \begin{itemize} \item Class process: inferior processes (c.f.\ GNU-Emacs) \item Sockets: Unix- or ethernet domain sockets. \end{itemize} Communication: \begin{itemize} \item Synchronous (blocks event-handling) \item Asynchronous (Executable object handles input) \item User-definable input records (regex) \end{itemize} \end{sli} \begin{sli}{Calling Simple Unix App} \begin{code} call_unix(Utl, Args, Output) :- NewTerm =.. [process, Utl | Args], new(P, NewTerm), send(P, use_tty, @off), new(OS, string), send(P, record_separator, @nil), send(P, input_message, message(OS, append, @arg1)), send(P, open), send(P, wait), pce_string_to_list(OS, Output), send(P, done), send(OS, done). \end{code} \end{sli} \begin{sli}{Server} \begin{verbatim} pce_server(Addr) :- new(S, socket(Addr)), send(S, input_message, message(@prolog, call_atom, @receiver, @arg1)), send(S, accept_message, message(@arg1, format, '(pce) ')), send(S, listen). call_atom(Socket, Command) :- get(Command, value, Atom), ( CommandAtom == '' -> send(Socket, format, '\n(pce) ') ; ( atom_to_term(Atom, Term, Bindings) -> ( call(Term) -> write_bindings(Bindings, Socket), send(Socket, format, 'yes\n(pce) ') ; send(Socket, format, 'no\n(pce) ') ) ; send(Socket, format, 'Syntax error\n(pce) ') ) ). \end{verbatim} \end{sli} \begin{sli}{Graphical front-end for ftp} \slifig{\textwidth}{ftp} \end{sli} \begin{sli}{Graphical front-end for ftp} Complete sources in the course-notes. Highlights here. \begin{code} :- pce_begin_class(ftp_process, process, "Wrapper around ftp"). variable(state, name, get, "Current command state"). variable(login, name, get, "Login name"). variable(action_message,[code], get, "Message to handle output"). initialise(P, Host:name, Login:[name]) :-> "Create ftp process and connect":: send(P, send_super, initialise, ftp, Host), send(P, record_separator, string('^ftp> \\|^Password:\\|\n')), send(P, input_message, message(P, input, @arg1)), send(P, slot, action_message, @default), send(P, open). \end{code} \end{sli} \begin{sli}{FTP front-end: input (1)} \begin{code} input(P, Input:string) :-> get(P, state, State), pattern(State, Pattern, Action), to_regex(Pattern, Regex), send(Regex, match, Input), !, Action =.. [Selector|Args], maplist(map_pattern_arg(Regex, Input), Args, NArgs), Message =.. [send, P, Selector | NArgs], Message. pattern(_, '^ftp> $', prompt). pattern(pwd, '257[^"]*"\\([^"]+\\)', action(1:name)). ... \end{code} \end{sli} \begin{sli}{FTP front-end: input (2)} \begin{code} wait_for_prompt(P) :-> "Process input till prompt":: send(P, report, progress, 'Waiting for ftp prompt'), repeat, ( get(P, state, prompt) -> !, send(P, report, done) ; send(@display, dispatch), fail ). \end{code} \end{sli} \begin{sli}{FTP front-end: input (3)} \begin{code} action(P, Args:any...) :-> "Perform action":: get(P, action_message, Msg), ( Msg == @default -> send(@pce, send_vector, write_ln, Args) ; send(Msg, forward_vector, Args) ). pwd(P, Msg:[code]) :-> send(P, wait_for_prompt), send(P, slot, state, pwd), send(P, slot, action_message, Msg), send(P, format, 'pwd\n'). \end{code} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % DATA REPRESENTATION % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Data Representation: Alternatives} \begin{itemize} \item Prolog Stacks \begin{itemize} \item Generally `case' data \item Visualisation will often require modal windows \end{itemize} \item Prolog recorded or asserted DB \begin{itemize} \item When a lot of access is needed from Prolog \end{itemize} \item External (relational) DB \begin{itemize} \item When data is available in this format \item Distributed databases \end{itemize} \item XPCE Objects \begin{itemize} \item Manipulation of data closely connected to the interface \end{itemize} \end{itemize} \end{sli} \begin{sli}{XPCE Primitives} Data Organisers: \begin{itemize} \item chain (linked list) \item vector (one-dimensional array, dynamic) \item hash_table (mapping from object to object) \end{itemize} `Frames': \begin{itemize} \item sheet (list of name-value pairs, untyped) \item user-defined class (typed attribute-values) \end{itemize} `Relations': \begin{itemize} \item table (multicolumn; relational database table) \item hyper (2-directional link between two objects) \item user-defined classes \end{itemize} \end{sli} \begin{sli}{Example choices} Workbenches for Knowledge Engineering \begin{itemize} \item Shelley (XPCE-3) \begin{itemize} \item Frames using sheet objects \item Relations using tables \item Program in Prolog-defined OO-layer \end{itemize} \item KADS-II (XPCE-4) \begin{itemize} \item Entirely XPCE user-defined classes \end{itemize} \item KEW (CommonLisp, XPCE-3, ported to XPCE-4) \begin{itemize} \item Frames using sheet objects \item Relations using tables \item Program in CLOS \end{itemize} \item CUE (CommonLisp, XPCE-4) \begin{itemize} \item Integration of existing CLOS packages \item Data and program in CLOS \end{itemize} \end{itemize} \end{sli} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % DEVELOPMENT % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{sli}{Prowindows-3/XPCE Plans} Realised in research version: \begin{itemize} \item C++ interface \begin{itemize} \item Stand-alone XPCE/C++ programs \item Mixed XPCE/Prolog/C++ programs \end{itemize} \item Display windows on windows \item Full integration of graphical and dialog_item \item Full 8-bit character-set support \item Interactive dialog-window editor \end{itemize} \end{sli} \begin{sli}{Prowindows-3/XPCE Plans} Plans (no time-schedule, no warranty): \begin{itemize} \item Motif emulation \item 16-bit character-set support \item MS-Windows/Windows-NT port \item Stand-alone XPCE language \begin{itemize} \item Language-independent XPCE libraries \item Optional interpreted GUI toplevel for compiled environments (C++) \end{itemize} \item Libraries \end{itemize} \end{sli} \end{document}