Window Painter is intended to be a fairly simple but important time saver, not the heart of where software development occurs. Typically a programmer should not spend more than a few minutes at a time using it, though perhaps longer when experimenting with different approaches. Despite being an optional and technically stand-alone component, it is fully and seamlessly integrated into Edita.
Generally speaking, complex dynamic windows are outside the scope of this program, for example the main window of Edita, which has seven optional components (toolbar, tabs, treeview, message view, horizontal and vertical scrollbars, and status bar), and five (main editor pane, treeview, the message area, and both scrollbars) that are dynamically sized. If you try it, the window will be shown, but it won't look very familiar. Besides, in the case of the Edita main window, if you move or resize any of the controls shown, it will make little or no difference because they are automatically resized and repositioned when the program is run.
Instead, Window Painter is intended for use with the much larger number of simpler windows, typically those found on Tools and Options menus, and of course the main window on simpler applications.
Window Painter is not really intended to compete, for example, with the much more extensive Judith's IDE which many users, especially beginners, may prefer (not that I belive that product handles complex dynamic windows any better). Instead as the name suggests it only addresses the window painting aspect.
Personally, I find an IDE too restrictive, but without a simple Window Painter even a trivial dialogue with only three or four fields can sometimes take several edit/test cycles to get right. A good example, and perhaps the main impetus for writing Window Painter, is the Colour Selection dialogue in Edita. That deceptively simple window is in fact the fourth or fifth significant redesign; the swatches have been on the right of the radio buttons, the standard colours on the left, the edit text now at the top right has been a combo on the left hand side, and probably a few others I have forgotten. A relatively simple window like that can prove unusable if the controls are placed in the wrong order, for example if you have to select something on the right before something on the left is enabled. Window Painter makes such redesign a snip.
There is extensive checking, however in many cases failure simply terminates with a (deliberate) divide by zero. These will be replaced by more meaningful messages in the next few releases.
Window Painter is complete, and works far better than I ever hoped.
constant EDIT2 = create(EditText,"",0,DEMO,140,30,200,20,{ES_CENTER,WS_EX_CLIENTEDGE})with
constant wStyle = {ES_CENTER,WS_EX_CLIENTEDGE} constant EDIT2 = create(EditText,"",0,DEMO,140,30,200,20,wStyle)Then although Window Painter should resolve the reference to wStyle successfully, it will be replaced with {ES_CENTER,WS_EX_CLIENTEDGE} every time it is subsequently run. [Actually, see notes below, it is replaced with ES_CENTER.] Window Painter will never modify the wStyle constant, it only ever modifies create calls.
Attempting to run Window Painter on demo_menus.ew, which contains:
constant CHECKSUBMENU = {"Check SubMenu", "Uncheck SubMenu"} constant CHECK4 = create(MenuItem, CHECKSUBMENU[1], 0, CHECK,0,0,0,0,0)aborts with the message "Unrecognised: subscript on line 45". Window Painter could (and in a previous version did) resolve the reference yielding "Check SubMenu", but there isn't (yet) the right code to replace it. There may be other complex expressions Window Painter will not handle. At the moment, this probably includes unary plus, unary minus, not, *, /, &, and, or, xor, as well as subscripts. Support for these (inside the create statements Window Painter is to modify, that is) will be added as and when needed, if they ever really are needed. There is some very incomplete handling of and_bits and or_all, which may cause a problem if encountered. I will state that all the above can be supported; it is more a matter of testing than any serious technical difficulty.
Instead of trying to imagine, let alone deal with, all possible bizzare constructs a deranged programmer might concoct (joke), the initial focus is firmly on Window Painter dealing correctly with its previous output, while at the same time treading cautiously and ensuring Window Painter does no untoward damage to a program source (although any and all changes made can always be undone using Ctrl Z).
There is no problem creating an initial draft window using Window Painter, and then modifying it with no regard to ever running it through Window Painter again. Much of Window Painter itself was created in this fashion.
Another slight confusion is that PushButton is replaced with Button, which is not really a problem since line 80 of classes.ew (part of arwen) reads:
Button = newClass(), PushButton = Button,Lastly, note that use of setClassDefaults() is not actively supported by Window Painter, though it is fairly unlikely ever to be a problem.
Also, running Window Painter on demo_memo.exw replaces ES_RIGHT (=2) with SS_RIGHT (=2), which I think is correct, but more by luck than judgement.
The extended control styles WS_EX_CLIENTEDGE, WS_EX_DLGMODALFRAME, and WS_EX_STATICEDGE rarely appear correctly in the design window unless the program is closed and restarted. Equally the left and right alignment in edit text controls, and capitalisation, appears to be buffered in some way by the windows API. I am sure you will notice when changing style settings that I am using the most aggressive method I can think of to force Windows to repaint completely, but in some cases it is simply not enough, in which case you may need to run a test.
create(Label,xl("label"),0,0,30,40,100,200,0) create(Window,sprintf("%s settings for %s",{text,moretext}),0,main,0,0,600,350,0)is treated as:
create(Label,"label",0,0,30,40,100,200,0) create(Window,"%s settings for %s",0,main,0,0,600,350,0)However, Window Painter replaces the individual parameters ("segments") rather than the entire create statement, hence the "xl(" and "sprintf(" etc are always left unmodified.
constant Button56=create(Button,"Button",0,Group57,20,20,75,30,0) . . . . . . . . . . . ^ Error: Group57 has not been defined constant Group57=create(Group,"Group",0,main,20,50,100,200,0)An information message is displayed when Window Painter has updated the controls:
The following controls must be reordered manually: Move Button56 after Group57.It is the programmer's responsibility to cut and paste the controls as instructed after Window Painter has finished to overcome this. The message box may safely be left on-screen while this is performed.
Although it may look otherwise, an automated solution to this is far from trivial. Referring to the previous point, some of the controls may have "xl(" and "sprintf(" parts we want to leave undamaged, so we would need a line-based cut/paste operation unlike the "segment"-based one we have used until the eleventh hour. Another complication is that some existing constants may have been defined separated by commas, or the word "constant" may not be on the same line as "create".
This is not likely to happen very often anyway.
Example:
constant main=create(Window,"Title",0,0,410,0,400,399,0) constant Button96=create(Button,"Button96",0,main,13,31,75,30,0) constant Group97=create(Group,"Group97",0,main,27,90,200,255,0) constant Group98=create(Group,"Group98",0,Group97,39,66,156,184,0)Drag Group98 off Group97, resize it to be larger than Group 97, drag Group97 onto Group98, drag Button96 onto Group97, and close the design window. The following message appears:
The following controls must be reordered manually: Move Group97 after Group98. Move Button96 after Group97.
create(Label,"label",0,mainX+30,mainY+40,100,200,0)may generate the error "Unrecognised: mainX". Even if mainX and mainY are defined as constants, say with the value of 100, the above will be replaced with:
create(Label,"label",0,130,140,100,200,0)
It is possible to create simple one-level menus, however the creation of submenus, checkboxes, separators, moving or deleting menu entries, and Popup menus are not supported. Clicking on a MenuItem will set the focus to the Window Painter window with the MenuItem selected, however this does not happen with Menus. (If you must change a Menu, select the first MenuItem and then use the ComboDropDown to find it.)
Coding something like eamenus.ew is a better idea anyway, since it allows things like foreign language support and other customisation.
Likewise, ToolBars and StatusBars may be created, mainly because they affect the overall geometry, but adding buttons and fields to them is largely considered to be outside the scope of this program.
While Window Painter does recognise type definitions which occur in the current file, if you have, for example a global type fred in include1.e and run Window Painter on include2.e, which contains "fred thing", then because it has not parsed include1.e, Window Painter will not recognise fred as a type, and issue the error "assignment operator expected". You can probably comment out the line causing the error temporarily, to get round this.
The current source is scanned and organised into windows. A selection dialogue is shown to allow one of the existing windows to be selected or a new one created. If the program contains no recognisable windows then the selection dialogue only permits a new window to be created, otherwise the initial focus is on the selection list, allowing up and down arrow to be used to choose the window to be amended. If any of the rules above are broken by the existing create statements, either an error message will be displayed when the window is selected, or in more severe cases the window will not be recognised as such, and will simply not appear in the list.
Two windows appear. The Window Painter window is initially show on the left. The design window is initially (when created anew) shown to the right, but in its final position during amendment, which in some cases may completely obscure the other window. Both windows can be resized, overlapped, minimised or maximised. For windows which should appear on the left hand side of the screen in the final application, the recommendation is to drag them over to the right while working on them in Window Painter, and drag them back to the left just before exiting.
The design (right hand) window is shown with the title as expected in the application; bear this in mind when the term "design window" is used below.
Right click on an empty area of the design window, or an existing Group, Tab, or ToolBar to insert a new control. Right clicking on other existing controls sets the focus to Window Painter to allow the properties to be updated.
Click on the titlebar of the design window if required to set Focus, and move the mouse over the design window to select, resize, or drag an existing control. Right click on a control or press F4 to set the focus to the Window Painter, with the text field (if visible) selected for amendment. Failing to right click and attempting to move the mouse over to the Window Painter (a natural thing to attempt) will usually select a different control as the mouse is moved.
Note the behaviour of the mouse cursor depends on whether the design window has focus or not.
The design window itself can be moved by dragging the title bar, or resized in the usual manner.
At the top of the Window Painter is a ComboDropDownList containing all the currently defined controls.
Name. The variable name. You should always change this to something more meaningful. This field always recieves focus first when a new control is created.
Type. The control type (non amendable).
Parent. The control's parent. This changes automatically as the control is dragged onto or off a Group or TabItem.
Text. Only shown for selected control types. Changes here are immediately reflected in the other window.
Bitmap. Only shown for selected control types. (Currently this is completely unsupported).
Style and StyleEx. Shows a selection of windows constants. When one of the constants shown is a combination of other constants, for example WS_CAPTION = WS_BORDER + WS_DLGFRAME, changing the setting of one may also change the setting of the others. Some entries may be disabled to indicate they are part of the class defaults, which Arwen always expects and therefore should not be altered. Note that some may be inappropriate or incorrectly applied when checked. (work in progress).
While it is possible to switch back to Edita and modify the current file while Window Painter is running, this should be considered highly dangerous, in that it may become impossible for Window Painter to safely apply the modifications made to the source file. If this happens, Window Painter will issue an error, and discard the amendments just made. This will also happen if you switch to a different source in Edita or close the file being amended by Window Painter. You should at the very least avoid modifying any create statements, which includes using cut/paste to change their order, or inserting or deleting any lines above the last relevant create statement. Amendments to lines below that point should not cause a problem. If possible, exit Window Painter, make whatever changes are needed in Edita, and re-invoke Window Painter.
Changes are automatically saved when Window Painter is exited. You can reverse any changes made to the program source using the standard undo facility (Ctrl Z).
Edita does not require Window Painter to be installed; Window Painter merely simplifies a common task which can be performed manually.
Window Painter does not store any required proprietory information about the layouts created or otherwise lock a developer into continued use. The result of using Window Painter is the complete source code (well, create statements) for your application. You are perfectly free to develop an application using Window Painter and then maintain it "by hand". Equally you can often take an application previously developed "by hand" and modify it using Window Painter. A licencing scheme is planned, but at the moment Window Painter is free.
The complete source code is not freely available. Few users would understand it, even fewer would contribute to its development, and no-one would gain since it would prevent Edita from (ever) being self-financing.
Selected parts of the source code may be released into the public domain. Please state any requirements in functional terms, for example if you would like the list of manual reorders to be passed to a routine rather than appear in a message box, or access to the list of currently defined controls, the location of the "insertion point", which will indicate what part of the source code an external program can safely modify, pre- and post-processing of modified create statements, external options for menu, toolbar, status bar or setHandler processing, etc. Simple curiosity is not, however, a functional requirement.
There is no absolute bar on open source advocates developing an equivalent program. However the closed source version must also be supplied so that users continue to have a choice. It is entirely my responsibility to ensure that the closed source version remains better than any open source alternative.