As suggested by Roudoudou, although AYAY Kaeppttn would be the primary beneficent, a generic GUI engine should be an independent project.
So, here it is! I've updated the draft, with a complete use example, which would only require NumericWidget to be coded: UiSpecifications - ORGAMS (http://orgams.wikidot.com/uispecifications)
Four ways to contribute:
* propose a better architecture.
* complete specification, from the eye of the GUI designer who would like to use the widgets.
* code one particular widget.
Each of these could take from several minutes to a couple of hours.
NB: I've taken a look at Symbios's way to define GUI, but I haven't found the way to bind user inputs with specific actions (i.e. the 'controller' part of MVC).
Anyway, it doesn't cover same requirements. For maximal efficiency, this new GUI should be text based. By that I mean: no proportional font or arbitrary location for editable fields, but it might support sprites.
As we may change set_cursor,write_char,write_text during gui_init, i think we need to set a font bitmap (char width, char height, 1bit pixels for the 96 first characters, excluding 0-31 ascii char?).
I propose to not use the system font cause there will be ASCII differences between differents officials system ROM
In addition to that, with a another font, disregarding the screen offset and dimensions, we are able to change the text resolution (because people want more lines, more characters with the same screen resolution)
Another problem may be the need of graphical characters -> how many, which?
You're right ! I was mentioning firmware's own BB5D to make it concrete and give required interface.
Yep for custom resolution, that's the power of genericity! Actually it could be a good idea to be able to override
set_cursor and
write_char on a widget basis (for sub-window with custom resolution).
In that case we must think
set_cursor's interface again. For instance it should be passed the offset, since it's engine's responsibility to know where the window would begin.
As said in AYAY's thread, Orgams already provide custom font and fast display routines. Nonetheless we may use firmware for WIP version.
Actually, for code and testing purpose, I would recommend to plug mock routines, allowing automatized unit tests.
Oh by the way, for Orgams I intend to use 01-1f for internationalization (merging french and german charmap, mostly) and some special chars (e.g. ellipsis).
Also agree on the need of graphical characters. Semi-graphics interface is what I have in mind, i.e. we should be able to almost reproduce Soundtrakker/Starkos GUI. At least two solutions for displaying these characters :
- Using chars >= #80
- Using dedicated widget (i.e. non TextWidget), with settable sprites bank.
I prefer the second idea, since:
- Separate concerns keep isolated (we may have several fonts, but sharing the same graphical elements).
- Even for screen refresh, we typically display text and graphical elements (e.g. table separators) separatly.
Quote from: madram on 10:18, 03 July 16
Actually, for code and testing purpose, I would recommend to plug mock routines, allowing automatized unit tests.
Yes ! :)
For handling UI we can have:
- callback functions
Each widget would need it's own data for registering a function to be called when an action is done (e.g. button pressed).
- messages
Each widget sends a message (with it's id) to a function. I think less data is needed for this.
I use wxwidgets and it's xrc. I define the gui using wxformbuilder and this writes out an xml file with the description of the gui. Parts of the gui may be loaded and created at runtime. There are message handlers (so wxwidgets is message based). I define functions that respond to the messages. This is nice because I don't need to write code to describe the ui. I would say this is a nice idea to consider. wxwidgets is similar to windows resources but it is better.
Another really great thing of wxwidgets is the layout and I really think this should be considered. wxwidgets have containers (row, column, grid). I define my gui using this, I don't use pixel positions. The gui can resize *automatically* and it handles any size fonts. I think this should be considered for this gui.
I also use a games development kit which uses callbacks. This also has a "language" for describing ui but it is really c++ templates so it is short-hand for writing C++ code. The callbacks are executed when the user performs an interaction. The callback method is ok because any class can register a callback for the same "button press" but I find it a bit more messy.
So consider a tool that can make the gui and please don't use pixel positions.
Thanks for your comments!
Quote from: arnoldemu on 10:45, 03 July 16
For handling UI we can have:
- callback functions
- messages
The callback functions would be simple Z80 routines, and the 'messages' the parameters passed to these routines (and the simple fact of calling the routine!). See complete usage example: http://orgams.wikidot.com/uispecifications#toc9 (http://orgams.wikidot.com/uispecifications#toc9)
I'm not sure why would we need any scheme more complex than that. But I keep the good idea of passing ID of emittor widget. And maybe some meta-information about the passed value (its type?).
Quote from: arnoldemu on 10:45, 03 July 16
wxwidgets have containers (row, column, grid).
The gui can resize *automatically* and it handles any size fonts. I think this should be considered for this gui.
[...]
please don't use pixel positions
Yes sure for containers (cf table example in draft UI) and stacking operators instead of absolution positionning.
Automatic resize and arbitrary fonts would be going some bits too far, not meeting the requirements (http://orgams.wikidot.com/uispecifications#toc0 (http://orgams.wikidot.com/uispecifications#toc0)) anymore.
On CPC, resolution is known and fixed, so I'm not willing to sacrifice render speed for too much flexiblity which would give questionnable look anyway.
In other words, I think gedeihen requirements gives best of both world :
* no need to compute positions.
* ability to tweak the interface pixel-wise via sprites. No cluncky layout.
Quote from: arnoldemu on 10:45, 03 July 16
So consider a tool that can make the gui.
The goal is to make the design so neat that a tool would be both unneeded and easy to code!
Table widget interface proposal.
In the draft, horizontal separator are defined between each column.
I think that's a bad idea! All separators should be defined as optionnal parameters of the TableWidget itself.
Here is what it would look like:
++ TableWidget
All the following parameters allow to define separators.
Names are formed from the type of 4 cells surrounding the separator, in this order:
up-left, up-right, down-left, down-right.
The type can be :
* o (outside table)
* h (header cell)
* c (normal cell)
* _ (when no separation between up/down or down/left)
E.g. hh__ is a vertical separator between 2 header cells.
c_c_ is an horizontal separator between 2 normal cells.
By default, header and normal cells aren't descriminated. I.e., if you only define cc__, c_c_ and the likes, the separators between headers would be the same.
All these parameters takes a widget as value. If this is NoneWidget, the cells are concatenated.
The separators are localised in figure 1 below.
* oooh (a) Default=oohh
* oohh (=) Default=oocc
* oocc Default=NoneWidget
* ooho (b) Default=oohh
* oh__ (U) Default=oc__
* oc__ Default=NoneWidget
* ohhc (c) Default=occc
* occc Default=NoneWidget
* h_c_ (~) Default=c_c_
* h_cc (d) Default=c_cc
* hoco (e) Default=coco
* hc__ (V) Default=cc__
* cc__ (|) Default=Nonewidget
* c_cc Default=c_c_
* c_c_ (-) Default=NoneWidget
* coco (h) Default=NoneWidget
* ohoo (i) Default=ocoo
* ocoo Default=NoneWidget
* h_oo (_) Default=c_oo
* hcoo (j) Default=ccoo
* c_oo (.) Default=NoneWidget
* ccoo (k) Default=c_oo
* cooo (l) Default=c_oo
a====================b
U header1 U
a=============c~~~~~~~~~d~~~~~~~~~~e
U header3 V | |
f=============g---------+----------h
U header4 V | |
f=============g---------+----------h
U header5 V | |
i_____________j.........k..........l
Figure 1. Separators labels.
Introducing InputManager
Just as well writing byte on screen is delegated to external routines, scanning keyboard/mouse would be taken care of by a so called InputManager. gedeihen musn't have to deal with things such as dead-keys or auto-repetition delay.
Now, requiring 'read_key' isn't enough; sometimes we want the char (e.g. 'a' when entering text), and other times the key position (e.g. A/Q in the keyboard to play C note). Anyway we can do better at isolating responsibility: let the InputManager do all key mapping, and convert to an event number.
So, gedeihen would simply have to call a non blocking 'get_event' routine.
This should return either the absence of event, or an event id along with a parameter (since we don't want a distinct event by char for e.g. text input).
On another side, keymaps are associated to widget, since certains event only makes sense when a widget has focus. We must be able to set a particular keymap in widget definition. gedeihen would call set_keymap when entering the widget, and reset_keymap when exiting.
To summarize, InputManager would come with 3 routines :
set_keymap
----------
Enrich/override current keymap.
in: hl= map table.
out: N/A
reset_keymap
------------
Remove last added keymap.
in: N/A
out: N/A
get_event
---------
Query event.
in: N/A
out: Carry if event occured. Then,
A= event ID
C= event parameter.
NC otherwise.
Refining DisplayManager
Instead of introducing "graphical characters", I think it is more flexible to allow arbitrary sprite, via a SpriteWidget. I find it more convenient to directly provide the address of sprite, instead of the address of a sprite bank and then the index in the bank.
So, in addition to write_char, DisplayManager should expose draw_sprite, with the following interface:
draw_sprite
-----------
In:
hl = sprite address
bc = size to draw (in grid-unit)
nb: size might be greater than actual sprite's size (auto-repetition) or less (croping).
Also, the following routines might come handy:
fill
----
Fill a window from current cursor position
In:
bc = size of window to fill (in grid-unit)
a = paper
scroll_up
scroll_down
scroll_left
scroll_right
------------
Scroll window from current cursor postion, by 'a' grid-units.
In:
bc = size of window to scroll (in grid-unit)
a = scroll amplitude (in grid-unit)
To summarize, the DisplayManager would come with the following routines:
set_cursor
get_offset (needed for sub-windows with different DisplayManager)
write_char
write_text
draw_sprite
fill
scroll_up
scroll_down
scroll_left
scroll_right
Yet another way to contribute!
- Make a working version of the pattern example (UI case study http://orgams.wikidot.com/uispecifications#toc3 (http://orgams.wikidot.com/uispecifications#toc3)), or a subset of it (e.g. notes and instrument) in the declarative GUI framework of your liking. No code should we written, except to query/update a dummy model.
Thus we can gather best designs and check whether we're missing something.
Can I ask what this is for? Dont we have Symbos and FutureOs doing this already
Quote from: Trebmint on 18:29, 05 July 16
Can I ask what this is for? Dont we have Symbos and FutureOs doing this already
SymbOS's GUI is very comprehensive, and btw. it's source is available. Why start from scratch? Why to invent the wheel again? Just my thoughts. :)
Quote from: Trebmint on 18:29, 05 July 16
Can I ask what this is for? Dont we have Symbos and FutureOs doing this already
SymbOS and FutureOS are... OS !
I think madram want to do something doing only UI and not in a WIMP paradigm...
Hmm..... good point, so he want's it more light-weight. Biggest problem is always what's really needed and what to implement (or better what not to save space if needed). :)
Quote from: CloudStrife on 18:39, 05 July 16
SymbOS and FutureOS are... OS !
I think madram want to do something doing only UI and not in a WIMP paradigm...
Okay, Im all for anything development wise on the CPC, just as long as we're not reinventing the wheel
Hi MadRam, that's another interesting project!
I have a few questions:
- at the end will it be pixel or fixed textchar (like 8x8) based? Or will it support two different modi? So if it's a library, you can choose what you want for your single tasking app? (in a multitasking GUI it's probably impossible to mix it, when you want to display different apps/forms)
- what is a "sprite"? is it a bitmap control/widget ("picture box" etc.) or can it move like a sprite in games?
- is it desgined to support (overlapping) forms ("windows")? as you were already talking about controls which have focus and send messages, it sounds like a form-based environment or is it just based on controls/widgets within a non-window area like a classic sound tracker?
- will it be combined with your dynamic memory management project you talked about some time ago?
Non technical question: Why does a French person give their software a German name? And a strange one at that. (gedeihen is the German word verb "to thrive", "fleurir" in French).
Bryce.
Hello Trebmint!
SymbOS's crossplatform GUI is quite impressive, but I don't think it makes it possible to reproduce a soundtrakker-like interface with the following requirements:
* No code needed to encode UI logic (except some thin wrappers to query/update the model). Having to write code means reinventing the wheel for *each* tool.
* maximum speed possible, for reactive pattern scrolling.
* split-screen allowed.
* full-screen allowed.
Also, I might be wrong, but it doesn't seems easy to code for SymbOS natively on CPC.
Last thing: by delegating input handling and raw display, gedeihen is actually cross-OS by design!
Hi Prodatron! Glad you came by!
* It will be grid-based. Grid size (typically 1 byte * 8 lines) can be customized for each application, or even for a particular window. So we get best of both worlds, text-like for full speed, higher resolution if needed. See "grid based layout" http://orgams.wikidot.com/uispecifications#toc1 (http://orgams.wikidot.com/uispecifications#toc1) for more precisions.
* Multitasking access isn't in requirements, but I see no incompatibility.
* What I called sprite is an arbritrary bitmap to fill a round number of cells. No move planned.
* I'm not fully aware on forms/windows distinctions, maybe we should set a nomenclature everybody could agree on.
* It's primarly thought for static tiling windows rather than resizeable floating ones.
* But overlapping windows could be added in a second version via a dedicated operator. The design is open for new widgets and operators, so we don't have to code them all at once.
* Yeah ideally it should use a memory manager. It's not strictly needed, but then client and engine will have to figure out how to reconnect their respective work bank/page.
Bonjour Bryce !
I think it's a beautiful word, and can mean GEneric DEclarative Interface Horse ENgine.
Plus, too much English already!
Hey Madram
That sounds like a cool aim, and I would admit thats not what Symbos is at present. Its an interesting time with new frameworks such as yours' and CPCTelera.
CPCTelera is particuarly impressive as it was unheralded and super useful for games coders. All development is good.
Quote from: madram on 11:06, 06 July 16What I called sprite is an arbritrary bitmap to fill a round number of cells. No move planned.
More like a tile/pattern so?
Quote from: TotO on 13:20, 06 July 16
More like a tile/pattern so?
You're right, tile is surely less misleading than sprite.
Note: each would come with its own arbitrary size (in grid-unit), for possibly unique usage (e.g. title/logo).
Hi Madram,
Quote from: madram on 07:48, 02 July 16I've taken a look at Symbios's way to define GUI, but I haven't found the way to bind user inputs with specific actions (i.e. the 'controller' part of MVC).
Quote from: madram on 11:06, 06 July 16No code needed to encode UI logic (except some thin wrappers to query/update the model).
The SymbOS GUI is sending messages to the owner of a form each time something happend (control with ID xyz of form abc has been clicked, control has been modified, control got/lost focus, form has been moved etc. etc.). The app then decides if and how to react on these events. As an example, if you have a settings dialogue the app wouldn't take care about anything the users does in the form until he clicks "Ok" or "Cancel". Then you may have to implement some "controller" code, if the modified data have to be transformed into another format or whatever (what you described as the "thin wrapper"), but the "model" may also directly be linked to the "viewer".
I am not sure how you want to integrate the "controller" part in Gedeihen? I couldn't find something in the draft, or maybe I missed it.
View / Controller
Yes there is not yet emphasis on this matter, it's a draft draft!
Each updatable widget (e.g. numeric or text field) must set:
* access (2 words): addresses of getter and setter routines.
The getter accounts for the 'view' part, and the setter for the 'controller' one.
It's necessary since we must query/update the model at some point.
I think it's also sufficient, together with some optional routines associated to widgets:
* on_enter (1 word)
* on_exit (1 word)
* on_enter_row (1 word) ; for TableWidget
* on_enter_col (1 word) ; for TableWidget
...
Each of these options must be followed by the address of the perticular routine to call.
gedeihen wouldn't do any data housekeeping per se. But a particular widget can. For instance TextFieldWidget will only call the setter once the text is fully entered and validated.
To reproduce your form+validation example, the setters could update a temporary data structure, and validation would copy it to a persistent one.
Reusing data-structures would amount to reuse getters/setters.
Widget reuse via additional parameter
We might customize a widget, e.g. adding keyboard shortcuts to dec/inc a numeric field. Or create a composite widget alltogether, e.g. a field surrounded by button to act on it.
Such enriched widgets can be reused in the UI. The problem is that associated setter and getter will point to the same data.
To circonvent this issue, we allow to define a parameter, which will be passed by setter/getter.
The setter/getter interface would resemble:
; In:
; HL= external parameter (0 if not set)
; C= emmitor widget ID
; In for setter, out for getter:
; A or DE (depending on widget type): value
Concrete example, self explanatory I hope:
; UI Definition, vertical list of 3 numeric fields ---------------------
mainUI WORD VerticalStack
WORD numField1
WORD numField2
WORD numField3
WORD endOfStack
numField1 WORD CustomizeWidget, myNumeric
BYTE setExtParam:WORD data1
BYTE endOfParam
numField2 WORD CustomizeWidget, myNumeric
BYTE setExtParam:WORD data2
BYTE endOfParam
numField3 WORD CustomizeWidget, myNumeric
BYTE setExtParam:WORD data3
BYTE endOfParam
myNumeric
; Warning: extParam must be set to use this Widget
WORD NumericWidget
BYTE minRange, 1
BYTE maxRange, 9
BYTE access: WORD genericGetter, genericSetter
BYTE keyMap: WORD numericKeyMap
BYTE endOfParameter
numericKeyMap BYTE keyPlus: WORD genericInc
BYTE keyMinus: WORD genericDec
BYTE endOfKeyMap
; Routine for model view update
genericGetter ld a,(hl):RET
genericSetter ld (hl),a:RET
genericInc inc (hl):SCF:RET ; carry to trigger refresh
genericDec dec (hl):SCF:RET
data1 BYTE 1
data2 BYTE 1
data3 BYTE 1
There is a flaw in this picture. NumericWidget in accountable for entering figure within the defined range. But genericInc/Dec don't make any check. Adding them manually would be ugly. A better solution is to let NumericWidget do Increment/Decrement.
The question now is how to activate these 'widget actions' beasts.
Maybe afterall we need messages for inter-widgets communication.
[Keyboard Management]
In AyAy context, there are two ways a key is bound to note playing.
In pattern editor, pressing R will lead to enter one "F" note and process to next line, whereas elsewhere we want to sustain the note as long the key is pressed.
For the latter case, we may test if the key is still pressed (e.g. &BB1E KM Test Key), but it would defeat the nice decoupling of key handling vs event management. Put in another way, if an action is triggered by an event, either it's a one shot, or it should be stopped by another event. Viva symmetry.
That's why I think a model based on "key_pressed & key_released" events would be a better match for Gedeihen.
Con: have to rewrite the whole keyboard manager (e.g. the auto-repetition part)
Pro: allow finer handling (dead-keys, multiple keys, ...).
@BSC (http://www.cpcwiki.eu/forum/index.php?action=profile;u=480): no news since your PM the 31st of July. Should I Worry?
Quote from: madram on 15:52, 19 August 16@BSC: no news since your PM the 31st of July. Should I Worry?
Here I am! What's happenin'?
Quote from: BSC on 10:32, 09 April 22Quote from: madram on 15:52, 19 August 16@BSC: no news since your PM the 31st of July. Should I Worry?
Here I am! What's happenin'?
you are ware that you are answering a 6 year old question and that Madram did not log in for almost 5 years?
Quote from: eto on 11:45, 09 April 22Quote from: BSC on 10:32, 09 April 22Quote from: madram on 15:52, 19 August 16@BSC: no news since your PM the 31st of July. Should I Worry?
Here I am! What's happenin'?
you are ware that you are answering a 6 year old question and that Madram did not log in for almost 5 years?
His reincarnation is still here... ;)
Quote from: eto on 11:45, 09 April 22Quote from: BSC on 10:32, 09 April 22Quote from: madram on 15:52, 19 August 16@BSC: no news since your PM the 31st of July. Should I Worry?
Here I am! What's happenin'?
you are ware that you are answering a 6 year old question and that Madram did not log in for almost 5 years?
No shit, Sherlock! ;-) My post was meant tongue-in-cheek, implying I was there all the time. But forums are to transporting jokes what snails are to transporting TCP packets.