.. _rework:

Rework
======

Rework
~~~~~~

I have tried to facilitate rework in PAGE.  That is, how do you use
PAGE to tweak the GUI without loosing the supporting code that you
have written? At the same time I want to allow one to view the changes
with the run command button in the Python console.

Here is the situation.  You design a GUI and generate the Python code
using PAGE, which creates an executable skeleton Python program.  You fleshed out
the skeleton program to support the GUI and then decided to modify
the GUI.  If then you again generate the Python code for the GUI, you
do not want to loose the application code which you have written to
realize the application.  This is the rework problem: How to keep your
hard fought code when reworking the GUI?

My approach is to create the generated GUI code in one Python module,
called the GUI module and the supporting code in a separate Python
support module.  That is, PAGE generates two Python modules, one for
the GUI and one for the supporting code complete with the necessary
linkage.

PAGE implements this schema as follows.  PAGE works with three
files:

+ "<name>.tcl" which is the design description of the GUI suitable for
  input to PAGE. It can either be created in PAGE, passed to PAGE as a
  parameter, or opened from the File submenu of the main menu.

+ "<name>.py" which is the main python module generated by PAGE which
  contains the automatically code to create the GUI on the screen. It
  is meant to be completely generated by PAGE. This will be referred
  to as the GUI module.

+ "<name>_support.py" which contains the code supporting the GUI
  module. PAGE creates a skeleton of this module that contains all of
  the necessary boiler plate code for linkage to the GUI module as
  well as the definitions of the Tkinter variables and skeleton
  versions of callback routines.  I refer to this as the support
  module.

In the above, "<name>" is the application name (it was called the
project name in the original Visual Tcl program) selected by the user
when the system saves the ".tcl" or extracted from the file name which
may be supplied as a parameter when invoking PAGE.

It is expected that the user will generate a new version of the GUI
module whenever he modifies the GUI but will need PAGE to modify the
support module only when new toplevel windows or callback functions
are defined. The first will be much more frequent than the
latter. PAGE includes a mechanism for automatically updating the
support module. This mechanism will be discussed in the next section.

In earlier versions of PAGE, it was only necessary to add new skeletal
callback functions and new Tkinter variables. I adopted the rule that
the update will never remove code from the support module. PAGE
version 7 with the support of multiple toplevel windows, updating is
more complicated. First, the Tkinter variables are no longer defined
or created in the support module. Further, changes to the GUI may add
or delete toplevel windows. These cases are discussed below.

Let me emphasize two points:

+ You should never modify the GUI module because modifying the GUI
  design and regenerating the GUI code will loose the modifications.
+ Let me repeat: You should only generate the support module once for
  an application; otherwise any code which you manually added will be
  lost.

.. _auto_update:

Automatically Updating the Support Module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This facility was introduced in version 4.3.  The basic
idea is that reworking the GUI design may introduce new callback
functions, Tkinter variables, or custom widgets which need to
incorporated into the support module. PAGE can now add those entities
to the support module.  That is, new skeletal functions are added and
new entries are added to the set_Tk_var function, if necessary the
set_Tk_var function is added. Similarly, new rename statements for
added custom widgets are added. All this while leaving the rest of the
existing support module unchanged. It was the case that only additions
were required and so updating never involved removing code from the
support module.

If Control-U was selected to generate the support module, then the
user will be given the options of:

+ generating the support module anew, 

+ using an existing support module, thereby utilizing the existing handwritten code; the old support module will be displayed.

+ updating an existing support module to preserve the existing code and adding new Tk Variables or skeleton callback functions.  

To rephrase the above, when the user selects Gen_Python->Generate
Support Module from the main menu or selects Control-U, PAGE will
analyze an existing support module and compare the callback functions
and Tkinter variables in it with those utilized in the reworked
design.  If new entities are required the user will be given the
option of automatically adding them.  Existing code is not removed or
modified.  It is up to the user to remove or otherwise deal with code
no longer needed.

The first step in this process is to analyze the existing support
module to determine the required new code.  Next,the new code is added
to the existing support module.  Following inspection in the Python
console, the user may elect to save the updated module.

There can be an issue with tab
characters. In step 2, tab characters are not expanded while the added
code will use spaces for indentation and that could cause syntax
errors through misalignment. You should remove any tabs in support
modules before attempting updates.

With version 7, the automatic update feature has been expanded to
handle the adding of toplevel windows, and the changing of toplevel
class names which are aliases of the toplevel widget. If a toplevel is
added then create statements are added to the function "main". If a
toplevel is deleted, then the automatic update feature will comment
out the create statements. Finally, changing the alias of a toplevel
window will cause one create statement to be commented out and
replaced by another.

If the user adds a toplevel window with the alias "Login" then the
following code will be added to the function "main" in the support
module.

.. sourcecode:: python
  
    # Creates a toplevel widget.
    global _top2, _w2
    _top2 = tk.Toplevel(root)
    _w2 = unknown.Login(_top2)			


If the user changes the alias of a
toplevel window from "Toplevel2" to "Second", them the following
create statements.

.. sourcecode:: python

			global _top2, _w2
			_top2 = tk.Toplevel(root)
			_w2 = unknown.Toplevel2(_top2)

might be replaced with

.. sourcecode:: python

		global _top2, _w2
		_top2 = tk.Toplevel(root)
		#_w2 = unknown.Toplevel2(_top2)
		_w2 = unknown.Second(_top2)				

In the case where the user deletes a toplevel window the update
process does nothing. This is because the analysis of the support
module cannot determine all references to a toplevel widget. It is
left to the user to remove them. Hopefully deleting a toplevel window
is a are occurrence.
		
To mitigate cases where the update process damages an existing support
module, PAGE keeps several backups.


.. _reuse:

Reuse
=====

By reuse, I mean the using of widget definitions used and defined in
previous PAGE projects.  The two aspects of reuse are:

+ Using existing projects as templates.

+ Borrowing widget definitions from existing projects.

Templates
~~~~~~~~~

Basically, one can use an existing project as a template for a new
project. The file submenu of the main menu has two variations for
loading existing projects - Open as Project, and Open as Template. The
first, Open as Project, is the one to use when you wish to continue
work on an existing project because the opening reestablishes the
default color scheme and default fonts as they existed when the project
was last stored. That means that if the project will look the same as
when last viewed. It also means that if someone gives you a project
files and you open it will appear to you as it appeared to him. Of
course, you must have the same fonts as he used in the project to
preserve the appearance.

Opening a project file as a template abandons the default colors and
fonts in favor of the preferences in the profile or rc file.

Very simple then, just load the project you want to use as a template and
do a "Save As..." from the main menu providing the name of the new
project. Of course, you will have to copy any images used in the
template to the directory of the new project.

.. _borrow:

Borrowing Widgets from Existing Projects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

With borrowing one retrieves and opens an existing project, which I
will refer as the Lender GUI or Brorrowee, at the same time as the
current project is open and then may copy-and-paste elements from that
preexisting GUI onto the current GUI. For instance one might have a
frame with and array of buttons in one GUI and would like to replicate
it in another project.

Since PAGE version 7 supports multiple toplevel widgets, one can also
copy-and-paste entire toplevel widgets from the Lender GUI to the
current GUI. For instance, one can borrow a toplevel window designed
for logging in from a Lender GUI. Another example would be borrowing a
toplevel widget containing a progress bar.

The Lender GUI is opened via File->Borrow menu entry in the Main
menu. When it is opened, the background for each toplevel widget is
set to Plum so that the user will recognize it as a Lender GUI.  I
chose Plum because I doubt that many users will choose Plum as a
toplevel background color. Also its position is offset from the source
for visibility. It is possible even likely that a toplevel window of
the Lender GUI will overlap or obscure the current GUI under
construction; in that case just move it to the side to expose the
current GUI.

The Lender GUI is read only in the sense that the save functions will
ignore it, leaving it unchanged on disk.  So don't worry about changes
you might make to the Lender GUI such as moving a toplevel window.  By
the same token you cannot make changes to the Lender GUI that you
would like to save.

This feature required a minor change in the format of the project tcl
file. That means that a project file created before version 4.10 will
need to be opened and saved before it can be a lender. Remember to use
"Save as" instead of "Save" which only saves if the main GUI has been
changed.

A peculiar side effect of borrowing is that if the Lender GUI happens
to have context (popup) menus, they will be incorporated in the main
GUI. That is because every bit of documentation that I could find on
context menus used root as the parent rather than a Toplevel window;
so I did too. This may not be too bad because if you don't bind to
them they will never be invoked. Further, if you borrow a widget which
is bound to a popup you will likely want to pull over the menu as well
as the widget. If not wanted context widgets are easily deleted from
the Widget Tree.  Comments solicited.

The Menu Bar from the Lender GUI may be copied and
pasted into the current GUI. To do that 

*  Select the Menu Bar entry in the Widget Tree with Button-3 and 
   then the Copy entry of the popupmenu, select the toplevel window 
   with Button-3. 

*  Select the Copy entry in the popup window.

*  Select the Toplevel GUI window with Button-3.

*  Select the Paste entry in the popup window.

*  Press Button-1 anywhere in the destination toplevel GUI window.

If any of the borrowed widgets have images, then the image files must
be copied to the new project directory **before** the paste operation
and they must be in the same relative position in the new project
directory. That is, if the image path was, for instance
"./images/image.png" then the image path in the new directory should
also be "./images/image.png". If the image files are not in place
before the paste operation, the past operation will fail. In many
cases PAGE will volunteer to do that for you.
   
When finished with a Lender GUI, one may close the Lender GUI with the
Close Borrowed button in the Widget Tree. If one does a save while a
Lender GUI is open, the Lender GUI is ignored; it is not saved.

Care must be exercised in borrowing widgets with images. After the
borrow is completed, any image reference must be updated to refer to
images in the destination project directory.
   
Borrowing is an unusual function, so please report any problems encountered.