From lechner@cs.uml.edu  Tue Sep 20 02:30:28 2005

Subject: Thoughts on a bde browser project, and the Fox gui

To: 05f523

Subject: Thoughts on a bde browser project

RJLRef: $PH/COOL-BDE/bdeBrowserAlternatives.htm [.txt]

                    [There are no other hyperlinks below -- RJL]

  I. Introduction

 

 II. Diagram browsing alternatives

          1. Fix bde2java

          2. Use bde(Linux/Unix)

          3. Upgrade bde2ht

          4. Enhance bde

          5. Port bde to FOX API

 

III. BDE's display code organizaion

          updatedisplaylist()

          ReDraw()

          GUI-hiding functions

 

 IV. A sample of FOX code

 

I. Introduction:

----------------

 

Bde is so large that refactoring might be

easier if we extract a display-only capability.

That's consistent with my goal of removing

pr_init functionaliity from chgen

and separating the input editing from the output

rendering side of bde's GUI.

 

Fox is a PI GUI (PIM not PSM in UML terms).

I invite you if you have OpenGL experience to

try porting a display-output-only subset of bde

to Fox as a 05f523 project. This involves he

contracting the bde user inerface and rendering

bde diagram content, currently done in bde/src/

files display.cc and draw.cc.

 

You might first try out the game of Set at setgame.com.

This shows that a nice addition to bde would be

a 2Dim OpenGL colored shape capability.

(Bde bendpt objects already reserve a byte for

color in the HP attribute string hsegpattern.)

 

R Almonte did a nice project in 04f522 on communication

protocols for the distributed multi-client setGame.

[RJLRef: $PH/04f522/04fdsg_raReportR1.{doc,htm}.]

(I added a few footnotes to his original 04fdsg_raReport.doc.)

 

At the end I append a sample of FOX code from  a question

to the FOX User Group and reply from FOX 'guru' Jerouen:

It is enclosed  for inspection by those who might

want to consider a bde2FOX project.

 

Before that, let's consider other bde browser

alternatives that are much further along.

 

===============================

 

II. Diagram browsing alternatives:

 

1. One way to browse bde diagrams is using bde2java.

This requires removing current bugs and enabling it

to display any diagram in a multi-diagram file.

Right now it is limited to one diagram per file.

bde2java is much farther along than other alternatives

to bdeUnix, and could possibly replace it entirely.

 

------------------------------

 

2. Another way is to upgrade bde2ht*; this project has

multiple versions and converts a bde.dat file to a set

of file pairs <HG#.htm,HG#.gif>, one pair per diagram.

This has the advantage that it already creates hyperlinks

from diagram nodes to other diagrams, or to text files

which follow a consistent labeling standard.

 

Bd2htm expands multiple hotspots in a node to either

another diagram or to a text-file#anchor point.

There is a (big but primitive) demo of this at

$PH/COOL-LCP/JP2html.

 

----------------------------------------

 

3. Another way is to use bde (bdeUnix) whose GraphSelect

OOMenu option gives random access to any diagram after

displaying the HG table of titles. However bde is buggy

and crashes frequently and does not render a diagram

properly. [Focusing on a display-only subset of bde

might fix display-side bugs and help to get rid of

the pr_init process which is built into fileio.cc

and pr_util/pr_load.c but deprecated.]

 

--------------------------------

 

4. Another way is to enhance the display-side of bde:

 

Here is a suggested refactoring process:

(a) Declare that a particular subdiagram is the

optional expansion of one node (or more than one).

 

(b) Enable browsing down and back up in a LIFO

stack of sub-diagrams and/or text files like bde2htm.

 

(c) A placeholder already exists in 94subdeschema.sch

for node to diagram expansion: an unused FSid field.

Replace FSid by HGid2 with is_key = 1 in table HN.

 

(d) Implement Node-Expand as Graph-Select

Graph Select currently responds to a click anywhere

in the canvas widget by displaying the HG-table

and promping the user to select a row.  It should

be easy to make a mouse click inside a node use

the HGid2 field of this HN instead for Graph Selection.

 

A new user-callable InsertLink method is required.

Irs callback should follow the usual *ops.cc

state model user interface protocol. After

InsertLink works for Nodes, Caption and Link

should also be enhanced with this method.

 

But where to put the 'InsertLink' selection box?

 

The generic approach would be to make InsertLink

a Text class method  or more generally, emulate

MSword's Insert/Edit/Open/Delete Hyperlink actions.

The challenge is to open a html browser from inside bde

rather than off-line convert a bde.dat file to html

as in bde2htm.

 

------------------------------------------

 

(5) Another way is to convert part of bde to the FOX API.

This is valuable only if it begins an effort to convert

ALL of bde to FOX.

 

I hesitate to do this because I am more interested

in applying the COOL Framework to its own components

and to other applicaionsa than to learning another GUI.

 

==========================================

 

III.  BDE's display code organizaion:

 

What would it take to  extract a browser

from bdeUnix and possibly port it to FOX?

 

A survey of bde code organization shows that function

updatedisplaylist in fileio.cc converts one diagram

(one HG-row + components) to equivalent display list content.

It constructs a polymorphic list of node hlink and caption

objects without drawing this content to the canvas window.

 

Function ReDraw displays the diagram, by calling <subclass>::Draw

for each object in the list. ::Draw calls GUI-hiding functions

drawtext, draw<shape>, drawline.  Currently these are implemented

in bde/src/draw.cc and they hide calls to the X11 API.

 

DO NOT UNDER-ESTIMATE THIS PROJECT:

 

One major complication is setting up bde's menus

and converting their X11 callbacks in bde/src/init.cc

from X11 to the FOX API.

[over 1400 refs counted at $RBGB/src/findX11refs.csh;

 setenv RBGB ~lechner/bde2alpha_rl/sandbox/bdeNT050526/bdegen13/bde]

 

Another complication is loading a bde.dat file of diagrams

via FILE/OPEN via fileio.cc calls to pr_load.

 

Retaining the top-line FILE menu is desirable,

so its conversion options can be added to the browser.

The left menu Graph Select command is needed for diagram selection.

One possible option is to add it (and remove EDIT) on the top menu.

 

All other left-OO-menu commands can be disabled for browsing.

To avoid double maintenance, these would be conditionally

compiled out of bde/src if X11 were the only GUI.

 

 

Here is sample code from bde/src:

------------------------------------

void updatedisplaylist(struct HG *cHG)  /* updates HGcurr - RJL*/

/* moved from bdeReplay to fileio.cc

 * because DisplayGraph below calls it regardless of BDELOG flag

 * Updatedisplaylist regenerates the graph object list

 * of new HN/outgoing-HL/CG  struct ptrs

 * after a database update or HG-row selection;

 * This list supplies input data for ReDraw.

 * The caller is responsible for updating cHG - RJL 020427

 * The client also must call ReDraw - RJL 031013

 */

//Pre-condition: Client must do clearObjects() first.

{EP;

    node *lastnode;

    hlink *lastlink;

    caption *lastcaption; // last caption Added by 94FBDE

 

    HGcurr = cHG ;// 020427

    (void) new graph(HGcurr);

 

    child_loop(HG,HN,HNid,HGid) // depends on HGcurr!

    {   //create node and link ptrs on display list

        lastnode = new node(HNcurr);

        child_loop(HN,HL,HLid1,HNid1)  

                 //pre-cond: source of link must be in this HN

        {

             lastlink = new hlink(HLcurr);

        }

    }

 

    child_loop(HG,CG,CGid,HGid)   //      Added by 94FBDE

    {   //create Caption ptrs on display list

        lastcaption = new caption(CGcurr);

#if 0

// Added by 96f523 BDECODE Group for XB text class- N/A now - RJL050909

// I'm not so sure - check again - RJL050919

        child_loop(CG, GX, GXid, CGid) {

                if (GXcurr != NULL) (void) new captiontext(GXcurr);

        }

#endif

    }

    DP;topobject->Ggroup::doDump();

LP;}  // end updatedisplaylist

 

----------------------------------------------

 

'grep ReDraw *.cc|wc'  says that ReDraw() in display.cc

is referenced from about 100 places in bde/src/*.cc.

 

During list traversal the generic draw method is over-ridden

based on an object's subclass (node, hlink or caption).

All the object's properties are accessible from  HN, CG or HL

but the object has only an fkey but not a pointer as a

result of [over-]encapsulation (too much info-hiding:-)

 

This enhancement really needs modeling in bde.sch:

Add tables ListNode LN, ListLink LL and ListCaption LC

with 1:1 or 1:0 associations from HN, HL and CG

respectively, and remove the hand-written code that

manages the List graphobjectlist.

 

BDE's data model would show a 1..1 HN-parent

to optional 0..1 singleton LN-child associaton

and similar associations from CG to LC and HL to LL.

Only the diagram selected for display would have

this LH, LL or LC singleton chld.

 

Another (OOP) way is to create a LH subclass of HN,

(and LL for HL and LC for CG.  These subclasses 

would automatically get the 0..1 multiplicity.

LN, LL and LC can inherit database update methods

from HN, HL and CG resp. It might be easier

to ensure that no other diagram is updated from

the local canvas edit operations.

 

In either case, whenever an LN, LL or LC object

is created by Graph Select via updatedisplaylist,

or by local edits, pr_add or its gencpcp constructor

automatically generates an HNid_pp parent pointer

in LN from its HNid fkey, and similarly

for HLid_pp in LL and CGid_pp in LC.

 

---------------------------

 

/******************************************************************

 * Description:  ReDraw() in display.cc:

 *      calls XClearArea and topobject->doDraw()==>subobject::Draw

 * Error handling:

 *      NONE.

 * Side effects:

 *      NONE.

 **********************************************************************/

void ReDraw()

{EP;

    static int callCount = 0;

    Display *display;

 

    display = XtDisplay(toplevel);

    XClearArea(display, XtWindow(canvas), 0, 0, 0, 0, False);

    DP;dprintd("\tcall %d to topobject->doDraw()\n",++callCount);

    topobject->doDraw(); // ReDraw ---> topobj->doDraw ---> subobject::Draw.

LP;} // end ReDraw

 

--------------------------------

 

Also in display.cc:

 

/******************* node::Draw: display.cc: 231-308 ****************

 * Description: Draw the node shape border at HN* cHN.

 * Then draw the HA-children text lines.

 * Preconditions: Requires DC in HN and HA;

 * Requires valid HNrow at HN* cHN;

 * Error handling:

 *      NONE.

 * Side effects:

 *      Alters HNcurr = cHN, alters HAcurr. ???-RJL040717

 *********************************************************************

...

 

and

/********************* hlink::Draw, display.cc:409-581 ******************

 

These call GUI-hiding functions drawtext, draw<shape>, drawline

in display.cc

--------------------------------

 

=========================================

 

IV. A sample of FOX code:

 

Forwarded message:

> From foxgui-users-admin@lists.sourceforge.net  Mon Sep 19 21:16:30 2005

> Organization: FOX Toolkit

> To: foxgui-users@lists.sourceforge.net, jamesravan@comcast.net

> Subject: Re: [Foxgui-users]Silent Canvas...?

>

> On Monday 19 September 2005 19:52, James Ravan wrote:

> > Here is a short program that creates a window, and I think should beep

> > when the mouse is left-clicked inside it. It does nothing. Can anyone

> > please tell me what I did wrong?

> >

> > grateful for *any* help,

> > -jim

> >

> > =============================================

> > #include "fx.h"

> >

> > // my application window

> > class myMainWindow : public FXMainWindow

> > {

> >   FXDECLARE( myMainWindow )

> >

> > private:

> >   myMainWindow( void ) {}

> >

> > protected:

> >

> > public:

> >   // Message enum

> >   enum

> >   {

> >            ID_QUIT = FXMainWindow::ID_LAST,

> >            ID_LBP,

> >            ID_LAST

> >      };

> >

> >   // Constructor/Destructor

> >   myMainWindow( FXApp *a );

> >   virtual ~myMainWindow( void );

> >

> >   void create( void );

> >

> >   // Messages

> >   long onCmdQuit( FXObject*, FXSelector, void* );

> >   long onLeftButtonPress( FXObject*, FXSelector, void* );

> > };

> >

> > // FOX message map

> > FXDEFMAP( myMainWindow ) myMainWindowMap[] =

> > {

> >   FXMAPFUNC( SEL_LEFTBUTTONPRESS, myMainWindow::ID_LBP,

> > myMainWindow::onLeftButtonPress ),

> >   FXMAPFUNC( SEL_CLOSE,           0,

> > myMainWindow::onCmdQuit         ),

> > };

> >

> > // FOX standard object implementation

> > FXIMPLEMENT ( myMainWindow, FXMainWindow, myMainWindowMap,

> > ARRAYNUMBER(myMainWindowMap) )

> >

> > // Create the main window.

> > myMainWindow::myMainWindow( FXApp* a ) : FXMainWindow( a, "mytest",

> > NULL, NULL, DECOR_ALL )

> > {

> >   setWidth( 300 );

> >   setHeight( 250 );

> > }

> >

> > // Create and initialize

> > void myMainWindow::create( void )

> > {

> >   // Create the window

> >   FXMainWindow::create();

> >

> >   // Make the main window appear

> >   show(PLACEMENT_SCREEN);

> > }

> >

> > // Clean up

> > myMainWindow::~myMainWindow( void )

> > {

> > }

> >

> > long myMainWindow::onLeftButtonPress( FXObject*, FXSelector, void* )

> > {

> >   getApp()->beep();

> >   return 1;

> > }

> >

> > // Quit

> > long myMainWindow::onCmdQuit( FXObject*, FXSelector, void* )

> > {

> >   getApp()->exit(0);

> >   return 1;

> > }

> >

> > int main( int argc, char** argv )

> > {

> >   // Construct and initialize the application.

> >   FXApp application( "mytest", "mytest" );

> >   application.init( argc, argv );

> >

> >   // Create the main window and the application.

> >   new myMainWindow( &application );

> >   application.create();

> >

> >   // Run the application.

> >   return application.run();

> > }

>

> There's several things that are needed:

>

> 1) Most "container" widgets are normally not mouse-sensitive; however after

>    a call to enable() they are  receiving mouse messages from the system.

>

> 2) The "raw" mouse messages are received by the widget as ID=0.  Thus, map as

>     follows:

>

>      FXMAPFUNC( SEL_LEFTBUTTONPRESS, 0, myMainWindow::onLeftButtonPress),

>

>    The idea with those message ID's is that they're unique for the *receiver*,

>    when receiving messages from a control.  However, in this case you're

>    effectively writing a "custom control", a main window with mouse-handling.

>

> Hope this helps,

>

>               Jeroen

> +----------------------------------------------------------------------------+

> | Copyright (C) 21:40 09/19/2005 Jeroen van der Zijp.   All Rights Reserved. |

> +----------------------------------------------------------------------------+