UI design question

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

UI design question

Post by Candy »

I'm designing the UI portion of the preferred application format, which of course should become the easiest way to do it. I've been thinking about an XML based format for the GUI layout, but the GUI layout is tightly coupled with a code file implementing the actual code behind it. I'm searching for new ways to do this. Up to now I've tried to use the C++ code inline with the XML, while escaping the quotation marks, but this looks icky and isn't nice. Anybody have any ideas?

The current idea is like:

Code: Select all

<xml>

<window style="fullscreen" bgcolor="#0010B7" transparency="179" 
  onclick="if (!isLogin) { exit(); } else { child.hide(); }" 
  classname="SSABackground" onSysKeyPress="
if (key == SYS_KEY_HOME) {
  child.show(); 
} else {
  if (!isLogin) {
    exit();
  }
}
">
  <bool name="isLogin" value="false" />
  <module type="SYS_MOD_PASSWORD" />
  <window classname="SSAWindow" name="child" style="static">
    <label caption="Username:" x="8" y="8" width="104" height="16" />
    <textbox x="112" y="8" width="104" height="16" name="Username"/>
    <label caption="Password:" x="8" y="32" width="104" height="16" />
    <textbox x="112" y="32" width="104" height="16" name="Password" />
    <button caption="Login" x="72" y="56" width="72" height="24" onClick="
passmodule.switch(parent.Username.text, parent.Password.text);
// if it gets here, it didn't switch, so one of two is wrong
MessageBox(\"Username or password incorrect.\", \"Error logging in\");
" />
  </window>
  <label location="centered" caption="Press ctrl-alt-home to login" />
</window>

</xml>
which in itself, together with a PassChecking module would be a login screen (including the preferences I have for my login stuff). There is, of course, the obvious way:

Code: Select all

<xml>

<window classname="SSAWindow" style="static">
  <label caption="Username:" x="8" y="8" width="104" height="16" />
  <textbox x="112" y="8" width="104" height="16" name="Username"/>
  <label caption="Password:" x="8" y="32" width="104" height="16" />
  <textbox x="112" y="32" width="104" height="16" name="Password" />
  <button caption="Login" x="72" y="56" width="72" height="24" name="LoginButton" />
</window>

<window style="fullscreen" bgcolor="#0010B7" transparency="179" 
  classname="SSABackground">
  <window classname="SSAWindow" name="child" />
  <bool name="isLogin" value="false" />
  <module type="SYS_MOD_PASSWORD" />
  <label location="centered" caption="Press ctrl-alt-home to login" />
</window>

</xml>

-- snip, file something.code starts
SSABackground::onSysKeyPress () {
  if (key == SYS_KEY_HOME) {
    child.show(); 
  } else {
    if (!isLogin) {
      exit();
    }
  }
}

SSAWindow::onClick() {
  if (!isLogin) {
    exit();
  } else {
    child.hide();
  }
}

SSAWindow::LoginButton::onClick() {
  passmodule.switch(parent.Username.text,   parent.Password.text);
  // if it gets here, it didn't switch, so one of two is wrong
  MessageBox(\"Username or password incorrect.\", \"Error logging in\");
}

I've omitted the allocation of passmodule, since it's something I haven't thought about yet.

Anyone have an idea similar to this, or an improvement? I'm thinking most about the second one, but it has an obvious difficulty with children and functions.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:UI design question

Post by Pype.Clicker »

err ... i'm somewhat confuse at what you're trying to do ...
wacco

Re:UI design question

Post by wacco »

The second one is definately more readable. Especially since you can split the work in two (let someone design, let someone code). I like the idea! But i am missing something: reference to the code file in your xml. But that shouldn't be to hard :P

Is an project file an idea? Loader loads project file, project file knows where to start, what xml files to load, what code files are connected to them, etc. If you're building an editor studio or something, it eases a lot of configuration stuff.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:UI design question

Post by Candy »

wacco wrote: The second one is definately more readable. Especially since you can split the work in two (let someone design, let someone code). I like the idea! But i am missing something: reference to the code file in your xml. But that shouldn't be to hard :P

Is an project file an idea? Loader loads project file, project file knows where to start, what xml files to load, what code files are connected to them, etc. If you're building an editor studio or something, it eases a lot of configuration stuff.
well, this was more for the OS design part, where my intent is to separate the sections of GUI design, GUI linkage to the code, and the actual hard code itself. Example was a login procedure, which has a GUI (the window), some glue code (the code section above) and a bit of hard code, which is the module defined in the code. This module would connect to the system to authenticate the user, and then exec() to the shell of the user, or complain (using the predefined GUI stuff). The actual login function is done by the system, which says whether the login was or was not successful.

This way, most people can make their own GUI around the same code (customizing is very easy), and if you make your own glue code, ALL other code can be reused. That's at least the intent. Got the dynamic linking problem worked out (damn that was hard), so you can now do a sort of

Code: Select all

Convertor<file, image> conv;
image blank;
file newfile = conv(blank);
which is a lot more usable than the current state with proprietary and very incompatible library interfaces. I still have some problem with multi-module calls, especially with settings, but I'm figuring it out... should be quite a research paper (might make me finish Uni) when it's complete.



The main problem in this stuff is how to interface to the three developers, or to the two coders plus the guy making the program the GUI designer uses. I've seen GUI designers being quite proficient in XML-like languages (such as HTML), so this format seemed most logical. It's directly convertible to C++ by the way, which is my intent.
Therx

Re:UI design question

Post by Therx »

If you did keep the code and GUI thing seperate it would be quite cool as the app could be skinned by anyone! For linking the too together surely you could have the GUI read the xml and when there's an event of some sort it sends an IPC to the app concerned. and vice-versa for drawing etc.

Pete
mystran

Re:UI design question

Post by mystran »

Keep code and layout separate I think. One method used is to define events (or signals) in the XML file, and then attach to them in code (either statically or at runtime).

Basicly, the idea works like this:

Code: Select all

<window title="Hello World Window">
  <label text="Hello World."/>
  <button onClick="clicked">
    <img src="smiley.png"/> Click me!
  </button>
</window>
Then you have something like:

Code: Select all

def myHandler():
   log.notice("User clicked button.")
   exit()

win = GUI.load("hello.xml")
win.attach("clicked", myHandler)
win.show()
Now, one thing I'd advice you to do, would be to make it easy to drive your GUI from a scripting language. It's a lot easier to write that kind of stuff with a really high-level language, even when the actual application backend was C/C++.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:UI design question

Post by Candy »

Pete wrote: If you did keep the code and GUI thing seperate it would be quite cool as the app could be skinned by anyone! For linking the too together surely you could have the GUI read the xml and when there's an event of some sort it sends an IPC to the app concerned. and vice-versa for drawing etc.

Pete
The idea is not just skinning, it's full modular design. You design modules (things that perform complex actions that are limited) and interfaces (things that have a look, but don't have any function). A program is then an interface (or more than one) plus a number of modules that define the default function of the interface. If you want to add GIF support, write a module that converts from file:gif to image:8rgba and install it on your system, after which EVERY PROGRAM can use the GIF format you defined. You can also use default functions on it, say a blur filter of type image:8rgba->image:8rgba/blur to blur it. Because blurring is hard on 8-bit, you use the default convertor to 24-bit, then do the edit, and if you like dither / color crop to 8-bit again.

The concept is that you make your computer understand GIF, or have a certain interface, and that the concepts of input/output/operation is completely separate from the concept of interface. I personally don't like the Word interface, but I have to use it because it's the only one that knows the word file format. I kind of like to use acrobat to read documents, but I can't because it doesn't know PS or DOC files. That sort of logic.

I also hope to get people to choose a file format instead of being forced into one, based on file size or quality (each conversion defines how good its quality is (not sure how to do that decently, but I'll figure it out) and how big the resulting file will be) so that the users can decide how to store an image best, in terms they understand (users seem to know better about the terms "quality" than "file format", so if you present the file format as a quality term, it's understandable).

Got rants on this done at http://www.atlantisos.com/index.php?id= ... =2&pagid=4 and http://www.atlantisos.com/index.php?id= ... =2&pagid=3

for the general concept of the idea.

Anyone want to make this a cross-platform concept? Perhaps binary compatible (I'm using ELF btw)?

Especially, does anyone have an idea how to make it link with c++ class members?
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:UI design question

Post by Candy »

For commenting, the design (well... code template) for the current idea:

Code: Select all

namespace module {

template <class source, class target, class arg = struct { int pad; }>
class reader {
   typedef target &(*function_pointer)(source &, arg);
    public:
   reader(string source, string target, string conversiontype);
   ~reader();
   target &operator()(source &, arg = {0});
   target &(*read)(source &, arg = {0});
};

template <class source, class target, class arg = struct { int pad; }>
class writer {
   typedef target &(*function_pointer)(source &, arg);
    public:
   writer(string source, string target, string conversiontype);
   ~writer();
   target &operator()(source &, arg = {0});
   target &(*write)(source &, arg = {0});
};

template <class type, class arg = struct { int pad; }>
class effect {
   typedef target &(*function_pointer)(source &, arg);
    public:
   effect(string source, string target, string conversiontype);
   ~effect();
   type &operator()(type &, arg = {0});
   type &(*perform)(type &, arg = {0});
};

};
This allows:

Code: Select all

module::reader read = system::getmodule("file::gif", "image::8rgb");
file f = new file("c:\unnamed.gif");
image i = read(f);
The arg-argument allows you to pass a struct containing module settings, which are again defined using an XML based configuratoin definition, parsed by a default settings display that sets the options the user wants.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:UI design question

Post by Pype.Clicker »

@auto-modules: i'm interrested in that way, but you (candy) already knows it, don't you ;D

I'd even push it up to

Code: Select all

myFile; //!< this is the GIF file, but since you got it from user-input, you don't know it's image/gif :)
myFilter; //!< this is the BLUR filter, but the user will select it at run time so you don't know it's image/rgba8 ...
try {
converter=system::getModule(myFile.getFormatString(), myFilter.getFormatString());
} catch (System.NoSuchModuleException) {
   //! why am i catching this ? what could i do but report the error ...
}
@ the GUI and stuff, i wouldn't be placing the "onclick" etc. events as attributes like HTML usually does, but rather as *text* within a special <event> tag, for better readability

Code: Select all

<window ...>
   <button label="ok" text="OK" ...>
       <event name="clicked">
            // code when button clicked
       </event>
   </button>
</window>
The XML should only contain server-side instructions (like changing a list item color when an item in the list is clicked, or redraw a set of radiobuttons), and events that couldn't be resolved from the XML gui description would be deferred for processing by the application (using the loader to locate the function that is expected to handle <window_name>_<button_name>_<event_name>.

No need to have win.attach(function) if you already have

Code: Select all

Login_Ok_Clicked(GuiEvent, ...) {

}
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:UI design question

Post by Candy »

Pype.Clicker wrote: @auto-modules: i'm interrested in that way, but you (candy) already knows it, don't you ;D
I guessed :P
I'd even push it up to

Code: Select all

myFile; //!< this is the GIF file, but since you got it from user-input, you don't know it's image/gif :)
myFilter; //!< this is the BLUR filter, but the user will select it at run time so you don't know it's image/rgba8 ...
try {
converter=system::getModule(myFile.getFormatString(), myFilter.getFormatString());
} catch (System.NoSuchModuleException) {
   //! why am i catching this ? what could i do but report the error ...
}
This is very much possible with this module stuff. Personally, I'd rather see the file object contain information on what type it is (so if you do new file("c:\unnamed.gif"); it knows it's a GIF file and reports its type as file::gif). The blur filter would be able to report its internal format too, why wouldn't it be able to? BTW, you're implicitly talking about the input format. Could we make that explicit?

Code: Select all

file myFile = new File(args[1]);
image i;
try {
module::filter imageload = system::getModule(myFile.getType(), image::32rgba);
module::filter blur = system::getModule(image::32rgba, image::32rgba, "effects:blur");
} catch (Exception e) {exit(1);}

module::options *bluropts;

try {
bluropts = blur::getDefaultOptions();
blur::setOption(bluropts, "distance", 5);
blur::setOption(bluropts, "type", "radial");
} catch(Exception e) {exit(2);}

i = blur(imageload(myFile), bluropts);

mainWindow.setBackground(i);

although I seem to not like that options method. Is there an easier method to do that? Can't find a nice portable separately linkable method :-[
@ the GUI and stuff, i wouldn't be placing the "onclick" etc. events as attributes like HTML usually does, but rather as *text* within a special <event> tag, for better readability

Code: Select all

<window ...>
   <button label="ok" text="OK" ...>
       <event name="clicked">
            // code when button clicked
       </event>
   </button>
</window>
Agree.
The XML should only contain server-side instructions (like changing a list item color when an item in the list is clicked, or redraw a set of radiobuttons), and events that couldn't be resolved from the XML gui description would be deferred for processing by the application (using the loader to locate the function that is expected to handle <window_name>_<button_name>_<event_name>.
That's not doable. There may be infinite nestings (think child windows and frames). I agree more with Mystran's idea on this, using a runtime binding operation. I would like it to be compiletime though, any idea on that (am going to think in a few minutes myself)?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:UI design question

Post by Pype.Clicker »

Code: Select all

@ "dont like those options":
i guess you dislike the fact the option name is a string, right ? what about having the string processed into a flat number (hash at compile-time or resolved against a 'properties names database' at load time ?)

@ this is not feasible ...

well, let's say you tell in your <window> or <frame> which module it should interact with, from there by design the button 'label' (to be understood like a label in code, not like the text displayed) should be unique much like the option name is unique in a HTTP form. 

<application root="Painter">

<window "Painter">
    <frame "menubar">...</frame>
    <frame "palette" target="ColorSelector">
        <button label="browse" text="predefined ..."/>
     </frame>
</window>
</application>
it sounds more natural to me that the *script* knows when new window should be opened and when an applicative module should be used.
At application.xml parsing, the loader must find the ColorSelector component and will check if it has a "gui_browse_clicked(GuiEvent)" function. If another object uses the ColorSelector 'plug-in', the application.xml parser will create another 'session' out of it and may perform another checks.

If someone is trying to label the button something else than 'browse' then he's misinterpreting the docs. And he's trying to put several 'browse' buttons in a single frame (aimed at different components), he should have targets declared at a more precise level)

Code: Select all

<frame "FileMenuBar">
    <button target="ColorSelector" label="browse" text="$icon{FILE} palette"/>
    <button target="FileSelector" label="browse" text="$icon{FILE} picture"/>
    ...
</frame>
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:UI design question

Post by Candy »

Pype.Clicker wrote: @ "dont like those options":
i guess you dislike the fact the option name is a string, right ? what about having the string processed into a flat number (hash at compile-time or resolved against a 'properties names database' at load time ?)
Well, no. The use of a temporary object into which you then insert the extra options, that's the part I don't like. Even when I can't figure out a way to make that better.

Using compiletime constants is not an option, they must be compile independant, and those constants can change between versions.

Hashes can collide, not good.
@ this is not feasible ...

well, let's say you tell in your <window> or <frame> which module it should interact with, from there by design the button 'label' (to be understood like a label in code, not like the text displayed) should be unique much like the option name is unique in a HTTP form.
I think it's best to make the code developer supply a definition file where he maps the UI code to his code... guess it could be in the code, as a form of defines, but I think it's best to encourage that to be a header with defines. Not liking the define approach then again, so I think Mystran's method is still best. Either that or using some form of proprietary linking stuff... :(

Code: Select all

<application root="Painter">

<window "Painter">
    <frame "menubar">...</frame>
    <frame "palette" target="ColorSelector">
        <button label="browse" text="predefined ..."/>
     </frame>
</window>
</application>
it sounds more natural to me that the *script* knows when new window should be opened and when an applicative module should be used.
At application.xml parsing, the loader must find the ColorSelector component and will check if it has a "gui_browse_clicked(GuiEvent)" function. If another object uses the ColorSelector 'plug-in', the application.xml parser will create another 'session' out of it and may perform another checks.

If someone is trying to label the button something else than 'browse' then he's misinterpreting the docs. And he's trying to put several 'browse' buttons in a single frame (aimed at different components), he should have targets declared at a more precise level)

Code: Select all

<frame "FileMenuBar">
    <button target="ColorSelector" label="browse" text="$icon{FILE} palette"/>
    <button target="FileSelector" label="browse" text="$icon{FILE} picture"/>
    ...
</frame>
Yet I do consider this a bad design. You still use an explicit 3-layer hierarchy in a place where it's natural to use a dynamically-layered hierarchy, or explicit linkage. Especially since you can attach more descriptive and shorter names to the UI code, and thus delink the UI structure from the glue code between the UI and the background function, allowing as Pete put it, skinning without doing additional trouble.

You get to make your own UI, if you like, so if you don't like the default one make your own. You can replace each part of an application without modifying the original, while you can still reuse the parts of them that you like. You can also replace them or recode them to a different license. The GPL is thus obsolete, in my opinion. GPL forbids linking it like this, so it's either all GPL or none GPL, and my choice is for the second one (with BSD or PD or whatever code). LGPL can still be used (as most modules are treated as libraries).

From a users point of view, when you buy (or download) software that makes the computer learn GIF files and some effects, each program can use those effects. The computer is brought back to the black box stage, which was the idea behind this all (oh, and to make appdev a lot quicker).
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:UI design question

Post by Candy »

Just to get it back to the original exact intent, this is the current example:

GUI code:

Code: Select all

<application>

<!--
window design:
+-----------------------+
| Username: [=========] |
| Password: [=========] |
|       [ Login ]       |
+-----------------------+
-->
<window classname="SSAWindow" style="gui::window::static" name="authwindow">
  <event name="show" func="timerstart" />
  <label caption="Username:" x="8" y="8" width="104" height="16">
    <event name="keypress" func="updatetimer" />
  </label>
  <textbox x="112" y="8" width="104" height="16" name="Username" />
  <label caption="Password:" x="8" y="32" width="104" height="16">
    <event name="keypress" func="updatetimer" />
  </label>
  <textbox x="112" y="32" width="104" height="16" name="Password" />
  <button caption="Login" x="72" y="56" width="72" height="24">
    <event name="keypress" func="updatetimer" />
    <event name="click" func="passcheck" />
  </button>
</window>

<!--
this is the background "window", a fullscreen blank window with only a 
label stating that you should press ctrl-alt-home to login
-->
<window style="gui::window::fullscreen" bgcolor="#0010B7" 
   transparency="179" name="bg" classname="SSABackground">
  <event name="click" func="bgclick" />
  <event name="syskeypress" func="handlesyskey" />
  <var type="bool" name="isLogin" value="false" />
  <label location="centered" caption="Press ctrl-alt-home to login" />
</window>

</application>
"Glue" code:

Code: Select all

#include <system>
#include "gui"

void timerstart() {
   authwindow.timer.addSignal(authwindow.timer.getTime() + 30000, &timerinterrupt, system::timer::volatile);
}

void updatetimer() {
   authwindow.lastaction = authwindow.timer.getTime();
}

void timerinterrupt() {
   if (authwindow.timer.getTime() - authwindow.lastaction > 29000) {
      authwindow.hide();
   } else {
      authwindow.timer.addSignal(authwindow.lastaction + 30000, &timerinterrupt, system::timer::volatile);
   }
}

void start(vector<string> args) {
   bg.show();
   if (args[1] == "--login") {
      bg.isLogin = true;
   } else {
      authwindow.show();
   }
}

void passcheck() {
   authwindow.attemptswitch(authwindow.Username.text, authwindow.Password.text);

   MessageBox("Invalid username or password", "Login failed");
}

void handlesyskey(key_t key) {
   if (key == sys::keys::login) {
      authwindow.show();
   }
}

bgclick(struct mousebuttons buttons, int x, int y, int s1, int s2) {
   if (bg.isLogin == false) {
      exit();
   } else {
      authwindow.hide();
   }
}
Does this look reasonable to people that want to do a similar idea, or to GUI-esque developers?
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:UI design question

Post by Candy »

The 1M $ question:

How do you use something similar to this with streams?

I've been thinking about making a default <file, bytestream> filter that allows things as cd burning, plus a <bytestream, arg> filter that limits the bandwidth (speed), but I can't seem to figure out how to get it to work decently in code.

Anyone have an idea?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:UI design question

Post by Pype.Clicker »

Actually, for Clicker, i was thinking at having some such 'streams' that boxes could receive from the application in order to display progresses, for instance.

Code: Select all

MyDownloader extends ReportProvider {
    ReportName: "download";
    ReportInfo(name:"source",mode:"system/humanreadable")=
        "http://"+domain;
    ReportInfo(name:"items", mode:"system/items");
    ExportStream(name:"CurrentFile", mode:"system/filename");
    ExportStream(name:"FileSize", mode:"system/size");
    ExportStream(name:"TransferredSize", mode:"system/size");
    ExportStream(name:"TransferredItems", mode:"system/items");
}
and the user requests display of either complete or partial information, becoming listener on those streams

Code: Select all

foreach my $report (@{ReportProvider("download")}) {
    $frame=new Dialog::Frame(alpha=>0.1, color=>color::DarkBlue);
    $frame.drawBox(0,0,$report->TransferredSize/$report->FileSize,0.5,
                       alpha=>0.5, color=>color::White);
$frame.drawBox(0,0.5,$report->TransferredItems/$report->Items,1,
                       alpha=>0.5,color=>color::White);

}
Post Reply