Application Definition
You should use smallworld_product.register_application() to register your applications to the system. There are various examples in the product(s) that are delivered to you.
NOTE I have seen where the messages aren't loaded when the application is registered into a running image. The way I have fixed this was calling message_handler(:application_name) before registering the application. It doesn't hurt to leave it there for building images either… Below is an example of a register.magik file.
Dangling Application
I call applications that fail to close properly a "Dangling Application." The problem is the application manager thinks it is running, and calling close() on the application doesn't do anything and the application is no longer active, it is "stuck".
To force the application manager to release the old application so you can start a new one you can use the following. Note this is for development use only and you still may have dependency on the old application.
smallworld_product.application_definition(:cu_admin_application).sys!perform(:|stopped()|)
Adding Resizable Plugin to <work_area>
The following section of gui.xml demonstrates how to have a resizable plugins within a tab box. In this example you will see the Editor and OSM are in a "parent" tab box. There are 3 plugins within a child tab box that needed to be resizable. You need a paned_window tag around the tab_box tag in order for the resizing to occur.
Maximized Application
These appear to control the maximation of the application upon start: application.activate() which calls _self.load_application_settings().
smallworld_product.load_and_save_application_settings can be used to remember last position of the application.
Plugins
Creating a "sub" Plugin GUI
Creating an "In Memory" Plugin
An In Memory Plugin allows you to get access to functionality within a plugin without the need of an owning application or framework. You can easily use <plugin_exemplar>.new(:my_plugin) to initiate the plugin, but it doesn't give you the ability to add XML properties easily. Below is some code that allows you to create an XML file with a single <plugin> element with property elements.
Adding Your Own XML Element Definitions
You can create your own unique xml_element tags that helps to define your plugin when simple property values are good enough. To do this you need to create a method on your plugin exemplar called process_initialisation_data_element(xml_element). This will be called when the core plugin definitions do not understand the xml tag. From here you can gather the required data from within the xml_element. These xml elements will be outside <properties> but within <plugin>.
Method Call Order
This is the following method call ordering I have figured out. These were listed in Developing Interactive Applications: API to action, plugin and framework classes 2.8 Initialising a plugin
- init()
- init_actions()
- post_init_plugins()
- post_build_gui()
- pre_activation()
- post_activation()
These methods were listed in help, but not seen during testing
- pre_loading()
- post_loading()
Editor
Editor Specials Pulldown
You will notice that out of the box functionality shows a Specials pulldown in the object editor. You can easily add functionality to this pulldown list.
- Create a plugin inheriting from :editor_plugin.
- Create a method on the object's record exemplar called editor_plugin() that takes editor as the sole argument.
- This method should return a new initialized plugin which has your actions defined in the init_actions() method
- These actions will be listed on the Specials pulldown
Editor (RWO) Specials Plugin Access
You can get to your editor specials plugin thru the following code. The result is a hash table keyed off the actual ds_collection. But I believe you typicallyonly have one so you can use an_elment()
swaf!.plugin(:editor_manager).current_embedded_editor.plugin(:rwo_specials).sys!slot(:plugins)
Editor Exemplars
- Editor
- object_editor - the actual editor GUI
- editor_manager - the plugin interfacing with SWAF
- Join List GUI
- db_join_lister - many join GUI
- simple_join_selector - one join GUI
Getting to the Field Items…
How does editor draw highlights?
Good question, because there is no highlight types being transmitted on the databus…
* The first thing it does is to register with the map manager thru the method editor_manager.post_init_plugins() which uses map_man.add_post_renderer()
* Then editor_manager.map_damage_notify() is called when the view is changed/refreshed
When to Use Plugin, Model, Framework?
There are several ways to build GUIs in Smallworld. You can use the following exemplars to build your GUIs from: model, plugin, and gui_framework. I'm sure there are others too.. But which one is better? As always the answer is not that simple and really depends on your requirements. Below is a brief discussion on each.
- model This by far is the simplest method of creating GUIs. using the panel object, you can quickly build a gui. You can make the appearance look more user friendly and organized using the rowcol object. This methodology does not really expose any functionality outside the exemplar and is not configurable outside magik coding. There is an engine_model exemplar that gives some foundation to running interrupt-able processes.
- plugin This was introduced in 3.3 and further enhanced in the 4.x releases. Plugins can be registered with frameworks (or applications). Plugins themselves register "actions" that are designed to be available to other GUIs. So you can include an action from one plugin in another GUI. Plugins can "build/initiate" other GUIs and themselves can be a GUI. There isn't a "standard" engine_plugin to support interrupt-able processes. The GUI functionality is a little more difficult because "place" the actions on your GUI.
- gui_framework This is the most user customizable GUI. It allows the end user to modify the GUI through config and gui XML files. With flexibility comes complexity. With complexity comes more coding.
Graham Garlick at iFactor has developed Dialog Designer which is a very useful tool and helps with the complexities. Also it is a good tool to learn how to implement GUIs from scratch.
Development Tips
These are some development tips concerning SWAF and the databus.
Adding Producer/Consumer to Databus
Typically the databus producers & consumers are added during application initialization based on the shared constants :databus_consumer_data_types and :databus_producer_data_types. But if you are developing a new plugin and forget to add the the producer or consumer types prior to starting the application, you can add thru the magik prompt using the following.
# appl is the application
# pi is the plugin you are adding as a producer for :post_render_sets
appl.databus.add_producer(pi,:post_render_sets)
Of Models and Plugins
This page goes into more details of plugin relationships with the application
Roles
Roles are used to turn on/off GUI elements during operation. These are typically defined in GUI XML file definitions. These are typically available on the following types of GUI elements:
- 2nd level submenu item. (maybe 3rd + levels also, never saw a 3rd level submenu item)
- tab_box
- plugin (referenced from the GUI XML definition)
- toolbar
You can get access to these gui elements using appl.get_all_gui_elements_with_role().
To turn off the GUI element, use unmanage() to turn them back on, manage().
You can turn on/off 1st level submenu GUI items also, but there isn't a convenient way of accessing them. To get to a button, you can use appl.gui_manager().menus[name][#]. On this button you can use unmanage() and manage().