pfritz

January 4, 2010

Color your diffs

Filed under: Uncategorized — pfritz @ 2:00

I’m using the command “svn diff” very often to control my already done changes for the subversion repo I’m working on. To be exactly I’m using “svn diff | colordiff” because it simplifies reading those diffs enormous. Since colordiff is a simple wrapper around the good old diff, I was wondering if it is possible to change the diff command used by subversion to something else. And yes it is! After some googling I found out the solution to define an alias to use colordiff, but an alias is not what I want. There must be a neater solution. Looking into the config file ‘.subversion/config’ I uncomment and changed the line starting with diff-cmd to ‘diff-cmd = colordiff’ and now the output of ‘svn diff’ is colored. Isn’t that nice? What I haven’t found out yet, however, is how you can change it back to normal diff if you want to prepare a normal patch without colors. I’ll report it to you if I find it out.

August 9, 2009

The new state system for the themers

Filed under: edje,ewl — pfritz @ 21:47

I’ve already written an article about the new state system of ewl for
programmers. This article will concentrate on the stuff that is interesting for
the themers. In fact the new event system gives the themers more possibilities
to design their theme. This was one of the motivations to do this changes.
To keep this article simple and general I will not comment the actual changes,
but I’ll talk about how the event system works now.

Some words about the lifetime of an edje object

Unlike to other widgets lib based on edje, ewl has not a permanent edje object
per widget. If a widget gets off-screen or is hidden it will not have an edje
object. This state is called obscured in ewl. This means that any change to a
obscured widget cannot be repeated to the edje object, because there is no
edje object. So we will differ in ewl and in this article two different types
of state changes. The first type is an active change, i.e. there already exists
a edje object and a state changes. The second type is for a widget that is
revealed (= the widget is not longer obscured), it already has some states set,
maybe long before.

A little example

This all may sound complicated for you. Let’s take a look on a real-life
example to illustrate the difference. We have a list of check buttons in a
scroll pane. Now we click on an un-checked and visible check box. The check box
will toggle to the checked state. As a themer you maybe want to have an
animation here, like the check is bouncing or fades-in. Now we scroll this
check button off-screen, hence it is no longer visible. Ewl will now destroy the
edje object, in fact it will not destroy it but reuse it for other widgets. The
important point is that the widget doesn’t have this theme object any longer
associated to itself and thus we lost all state informations for the theme
object. If we now move the check button back to the screen, ewl will create a
new theme object for it, so we need to inform it that the widget is already
checked, but this time we do not want the animation, because the state of the
widget has not been changed. It is only the state of the edje object that
changes. So we need another signal name for it.

And here comes the new state system, formerly it was not possible in ewl
to distinguish between such different edje theme state changes. Now it is!

The new signal names

Puh, that was much text, sorry I’m bad in summarizing stuff. Besides that we
differ between getting a state and having a state. We uniformed the signal
names. Here is a table of them:

adding state        removing state       has state

"mouse,in"          "mouse,out"          "hovered"
"mouse,down"        "mouse,up"           "pressed"
"focus,in"          "focus,out"          "focused"
"disable"           "enable"             "disabled"
"highlight,on"      "highlight,off"      "highlighted"
"selection,on"      "selection,off"      "selected"
"state,on"          "state,off"          "on"
"odd,on"            "odd,off"            "odd"
"dnd,in"            "dnd,out"            "dnd"

One special case is “mouse,down” and “mouse,up” you also get a “mouse,down,x”
and “mouse,up,x” where x is the button number pressed. But this states are
custom states and aren’t inherit to the internal child widgets. You’ll learn
more about internal child widgets in the next section.

Even more things are now possible

Many ewl widgets are a composition of different widgets, for instance let’s
talk about a button. A button is a container that holds a label and maybe
an icon, if present. This label is an internal widget, because it is not added
by the app writer, but an inherent part of the widget. Those internal widgets
now inherit the states of the parent widget. To differentiate between state
changes of the parent and of the widget itself the source is a different.

It used to be “EWL”, now it is “ewl/this” if the change is done to the widget
itself, if the state of the parent is changed the source is “ewl/parent”. There
is even a third source I’ll explain later.

Let’s go back to our button example, if the mouse enters the button you maybe
want to change the background (the outer shape) of the button, that isn’t nor
was it a problem. But what happen if you turn the light background into a dark
one? Now the font of the label is most probably not visible. In contrast it
needs to be changed from dark to light.

Now the label theme object will also receive a signal if the background state
changes, so that you can adjust the font color. Very often you don’t care if the
state changes happens to the widget or it close parent. It should always behave
the same. Therefor there is a third source “ewl/both”, it is send if one of the
widgets (the actual widget for theme and the (maybe indirect) parent) is getting
the state, or if none of them is having it no longer.

Custom states

Because the list of states given above is not always sufficient for every
widget, there are also custom states. Custom states are more like pure edje
signals, they are not repeated to the child widgets of a container, and they
do not necessarily differ between getting and having a state. But the usage of
custom states in ewl is rare. Custom states will always have “ewl/this” as
source.

I hoped this explained the new features of the new state system. If you still
have questions about it, do not hesitate to ask them.

August 5, 2009

Kissed by a nymph

Filed under: ewl — pfritz @ 20:31

Most apps and libs in the e-land are migrating or are already migrated to eina.
And you probably know that Nathan and me are not big fans of eina. Here a
some points we dislike:

  • the API
  • the licence (unlike almost all efl libs it is not BSD-like)
  • the scope (eina handles many things that do not belong into a data type lib)

I’m not going to go into details here. The decisions are already done. We
will not use eina for EWL. As you see it’s not only one point, but a bunch of
several issues that we dislike. At the moment EWL is using the ecore data types,
but I guess they will be removed from ecore soon. So we have basically two
choices:

  1. We can revive EWD, i.e. make a stand-alone lib out of the ecore data types
  2. We can switch to another data type library

Since there are some problems with the ecore data types, in particular the
missing iterator implementations and we also missed some other sugar, we took
the second way. After checking several adt libs, we chose to write our own one, because none has all the feature we want.

For sure this step was not ill-considered, we already discussed years ago about
the future about the ecore data types, but now we are taking the chance to
switch to a similar but not API compatible design. The lib is called
cmaid.

Cmaid

The basic design ideas of cmaid is a mixture of ecore, libast and some new bits.

From libast it has the interface design. I.e. you program against an interface
and only on creation of the data type, you choose what implementation you
actually take. This makes it easy to switch from one implementation to another.
It also brings an inheritance stair, so ecore_hash_count() and
ecore_list_count() becomes cmaid_container_count().

From ecore it has the API and also the hash implementation, most of the
function names are very similar to the one of ecore, except those for
iterating. Not directly from ecore but from an idea of Nathan for improving
ecore_hash is Cmaid_Value. It’s describing the data to be stored in the
container. This can reduce the allocation time because it can in-line the data
into the data node, of course, only if you desire it.

Really new is the iterator concept. Unlike to many other adt libs there is
no rule like: Do not touch the container while you are iterating. If you
remove some item the container will correct your (other) iterators to point to
the right and valid position. This works because the container has a list of
all attached iterators. It might sound heavy, but those few checks that are
done, are not a really slow down, compared to the luxury they bring. Of course
if you artificially add thousands of iterators it becomes heavy, but that’s not
the life as it is.

If you are now curious about cmaid you can find it
here and
here the documentation. BTW cmaid is still
not finished, and the port of ewl to it will take some time.

July 1, 2009

The new state system of EWL

Filed under: ewl — pfritz @ 23:04

Maybe you have already seen it, I started some weeks ago a branch for ewl in svn. Since the changes aren’t self explaining, I want to describe here how the new system works and also why it works that way.


The old system

Let’s start with some history about the old, but still current main trunk system. There are two different kinds of states:

  • One are for internal usage only. They are part of the Ewl_Flag enumeration and are set with macros like ewl_widget_state_add(). They are to keep track if a widget is pressed, has focus, etc.
  • The second kind is to keep the widget decoration informed about some evens. It is a tight wrapper around edje_object_signal_emit(). With “tight” I mean that it doesn’t provide any extra functionality besides that it can save one (and only one!) set state, so that the state will be applied if the widget is obscured and revealed again (this happens if the widget gets offscreen, or hidden for some time).

Losing states

This design has some flaws, because it ignores the fact that most ewl widgets are a composition of several widgets. For instance the label in a button need to know when the parent button container changes its appearance, in other words when it changes its state. On the first sight the solution seems to be obvious. Simply pass the state changes to the internal children.

But what happens if the label goes offscreen, but not the button? Or what happens if we create the label later than the button changed it theme? The label will not know about the state changes of the button. That means we need to keep track of all state changes so we can apply it to the children, when they are created or recreated. This list approach has also problems, for example if you apply “mouse,in”, you need to remove it from the list before you apply later “mouse,out”.


Having a state is different to getting a state

Another problem that exists with the current system is that we do not differ between retrieving a state and having a state. For example a themer might want to add a fancy animation when a checkbutton is checked, but on the other hand he maybe do not want an animation when the check is already applied, when the widget is new created or it is on-screen again. This issue is not inherent in the current system, and could probably also be solved in it. But it is something I had also in mind when I was going to switch to the new system.


The solution

I hope you understand now some of the issues that led me to change the current system. The first step is to remove the tight wrapping of edje_object_signal_emit(). I doubt it is possible to find a way that is not memory wasting and slow, but managed all the states in plain strings.

Like we already did it for the internal state management, states are now labeled by an enumeration. Every state in this enum reserves its own bit, so you can easily combine them with ORing. This atomatically solves the list problem. If the mouse enters the widget you simply add the EWL_STATE_MOUSE_IN bit and if the mouse later leaves you remove the state again.

Since old internal state keeping and the new state system works very similar, I simply merged them to one system, with the main difference that ewl_widget_state_add() will now inform the theme (actually the engine), that the state changed. If the widget isn’t already realized, the theme gets another information on realization, namely that the widget has this state. This solves the second problem.

The widget does not only save the directly applied states, but also the states that it inherits from the parent widget. Those are easily queried on realization and are kept up-to-date, if the state changes on the parent widget.

But the state enumeration is not enough. In some rare, but important cases, we still need custom states, that only makes sense for the given widget and are not general enough to be put into the enum. For those cases there is still a function that works as a tight wrapper around edje_object_signal_emit(). It is called ewl_widget_custom_state_set() and works like the old ewl_widget_state_set(), i.e. it does not inform the internal children about the change.

I hope I’ll write a second part of this blog discussing the changes from the view of a themer.

April 26, 2009

Setting up autofoo for gettext

Filed under: Uncategorized — pfritz @ 23:44
Tags:

Using gettext in your application or library is very easy and straight forward. The hard part is to setup autoconfig and automake to use gettext. Not because itis very difficult, but because there is not a good tutorial, at least I haven’t found one. The only resource is the gettext manual which is over 100 pages large and covers too many legacy cases to be simple. And the other resource is to look into existing project and take their setup as a base, either easy and you’ll find out that there are many ways of doing it, most of them are dated.

Since I added gettext support to EWL, I thought I can tell you the single steps, making your life easier, one you want to add i18n support to your application or library. I assume that you already have a autoconfig setup for your software.


First step: Setup the c code

Libraries need a different treatment here, because they cannot rely on global settings, else they would overwrite the catalog of the application that is using the library. Nevertheless the steps are very similar. I start here with the steps for the application.

Create a header file called intl.h or – if you prefer – mynamespace_intl.h it’s containing this code:

#ifndef INTL_H
#define INTL_H

#include <string.h>

#ifdef ENABLE_NLS
# include <libintl.h>
# include <locale.h>
#else
# define gettext(str) ((char*) (str))
#endif

#define _(str) gettext(str)
#define gettext_noop(str) str
#define N_(str) gettext_noop(str)
#define S_(str) sgettext(str)

static inline char *
sgettext(const char *msgid)
{
        char *msgval = gettext(msgid);
        if (msgval == msgid)
                msgval = strrchr(msgid, '|') + 1;
        return msgval;
}

#endif

This defines some useful macros, namely (), N() and S_(). Take a look into the gettext handbook to see how they work.

For libraries use this header:

#ifndef INTL_H
#define INTL_H

#include <string.h>

#ifdef ENABLE_NLS
# include <libintl.h>
# include <locale.h>
#else
# define dgettext(domain, str) ((char*) (str))
#endif

#define D_(str) dgettext(PACKAGE, str)
#define gettext_noop(str) str
#define N_(str) gettext_noop(str)
#define SD_(str) sdgettext(PACKAGE, str)

static inline char *
sdgettext(const char *domain, const char *msgid)
{
        char *msgval = dgettext(domain, msgid);
        if (msgval == msgid)
                msgval = strrchr(msgid, '|') + 1;
        return msgval;
}

#endif

Add this new header file to the (not installed) list of source files in your Makefile.am. You also need to add the following option to the AM_CPPFLAGS

-DPACKAGE_LOCALE_DIR=\"$(localedir)\"

We need this definition later.

To initialize the correct language and loading the language catalog we need to add some code, for apps add this code near the beginning of your main() function:

    /* Initialize NLS */
#ifdef ENABLE_NLS
    setlocale(LC_MESSAGES, "");
    bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
    bind_textdomain_codeset(PACKAGE, "UTF-8"); /* add this only if you want to
                                                  deal with UTF-8 strings
                                                  exclusivly. If you are using
                                                  evas, you most probably
                                                  want. */
    textdomain(PACKAGE);
#endif

For libraries add this:

    /* Initialize NLS */
#ifdef ENABLE_NLS
    bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
    bind_textdomain_codeset(PACKAGE, "UTF-8"); /* add this only if you want to
                                                  deal with UTF-8 strings
                                                  exclusivly. If you are using
                                                  evas, you most probably
                                                  want. */
#endif

As you can see it is up to the library user to set the locale. Don’t forget to add the intl.h header file.

The only missing thing for the c-files is to mark translatable strings, with the defined macros. I will not explain here how to use them.


Second step: Setup autoconfig and automake

First add the following line in your autogen.sh or bootstrap.sh file, if you are using autoreconf you can jump to the next topic.

echo "Running autopoint..." ; autopoint -f || :

Before the line where aclocal is called.

Now execute autopoint -f in your package base dir. It will create the po/-directory and copy some files you will need later.

Add the following lines some where in your configure.ac file:

AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.15])

And add po/Makefile.in (don’t forget the .in, this is not a typo!) into the AC_OUTPUT list. And add the po dir at the end of the subbdir list in the Makefile.am.

Now create the po/Makevars file, you will find there already a template for it. Simply copy it and adjust it for your needs. You may want to add the S_ or the D_ and SD_ macros to the xgettext options.

Create a new file called POTFILES.in. There you put every source file that contains a translatable string. The path should be relative to your base directory.

Well, if you are an English-speaker you are done know. Your project should now be translatable. If your not an English-speaker you can test your work and start a translation for your mother tongue.


Step three: The first translation

Run now ./autogen.sh, ./bootstrap.sh or autoreconf and the ./configure and make. After that you will find a pot file in the po/ directory. Use it to create a translation for your project and save the po file in the po/ dir.

Therefor that your translation will be converted into a binary form and later be installed add this file to a newly created LINGUAS file. There are all available translations listed. For example:

# Set of available languages.
de it cz

Call now make maintainer-clean and the next time you are going to build your project, your translation will be installed and used.

February 25, 2009

Mythbusting

Filed under: ecore,eina — pfritz @ 18:51

Today I was talking with Vincent about the memory usage of the Ecore and Eina datatypes. And he stated that Eina’s datatypes are using less memory then the counter-parts of Ecore. That wasn’t the first time that I heard about that myth, and I don’t know how it ever came off, if it was because of ignorance or if it is just a lie to promote Eina as the best stuff ever. In dubio pro reo! So let me show you that it is simply not true.

For the lists the calculation is pretty simple. The container base of Ecore_List and Ecore_DList has 4 pointers and 2 integers. That are on a 32-bit architecture, 24 bytes. The nodes of Ecore_List has 2 pointers the double linked version has 3. On 32-bit that are 8 and 12 bytes. The countainer base of Eina_List takes one integer and one pointer the nodes are taking 4 pointers. That are on 32-bit systems that are 8 and 16 bytes. If you now want to calculate the memory usage you get the formulas for Ecore_List 32 + 8n, for Ecore_DList 32 + 12n, for Eina_List 8 + 16n. And there is the special case that Eina_List is using 0 bytes if the list is empty. Indeed, Eina_List is using less memory then Ecore_Dlist, but only for lists that are shorter then 4 nodes! For large lists where the container base size is negliable it is using 33% more space.

For hashes the calculations are a bit more difficult. Ecore doesn’t use a static bucket size and Eina has a nested tree structure for collisions protection. If I understood it right, it has a tree for every hash value, those nodes are called heads, and every head has a tree for futher collisions. Since the formulars are here more complexe, I don’t want to discuss them in detail. I put them into a little c app, to actually calculate them. Since the memory usage of Eina_Hash differs depending of the quality of the hash function, I’ve calculated the best case (no collisions) and the worst case (only one hash value for every key). The real world case is some where between those two values. For bit fields I used the size of an integer, which should be at least on 32-bit architectures correct. You can find the source code here: http://mowem.de/ecore/hash.c

The results can be found here: http://mowem.de/ecore/plot1000.png http://mowem.de/ecore/plot10000.png

The red line is for Ecore, the blue for the worst case of Eina and the green line is for the best case scenario. Note: with best/worst case senario I’m talking about hash collisions and not about memory usage! So what we see is that Eina_Hash eats between 100% and 275% more memory then Ecore_Hash.

I know that there is a trade-off between memory usage and performance, but please stop pretending that Eina datatypes are using less memory then the Ecore counterparts. It’s simply not true.

November 29, 2008

The Lists and their quirks

Filed under: Uncategorized — pfritz @ 22:24

When I started to write this article I planed to write about the API of the two major list implementations and their weak points. But since this article is already long enough, I only focusing on evas_list. Don’t worry, an article about ecore_list will follow.

Both API are widely used so you should assume that they are proved to be suited for daily use. And that is right in most of the cases where I have seen them to be used. But they have some weak points, which I want to show you here. Creating a list is in both cases very simple, where it gets hairy is removing items from the list. Evas_List (now Eina_List) doesn’t have a real destroy function, so you have to figure out the best way to free a complete list.

But this is an relative easy job and you’ll find thousands of examples in the efl. The real tricky point is if you do selective destruction, i.e. you remove a list item under some conditions.

Let’s say we have a list of filenames and want to remove the files that doesn’t have the extension “.jpg”. This shouldn’t be a hard job you think, shouldn’t it? Well it could be easier.

Let’s start with Eina_List. I mimic here the unaware new user, of course I know already how to do it right. We start with the normal approach. Iterate over all items and remove the items we don’t like.

#include <Eina.h>
#include <Ecore_Str.h>
#include <string.h>
#include <stdio.h>

int
main(void)
{
        Eina_List *list = NULL;
        Eina_List *l;
        const char *file;

        eina_init();

        list = eina_list_append(list, "dsc01.jpg");
        list = eina_list_append(list, "blah");
        list = eina_list_append(list, "dsc02.jpg");
        list = eina_list_append(list, "dsc03.jpg");
        list = eina_list_append(list, "dsc04.jpg");
        list = eina_list_append(list, "dsc05.jpg");
        list = eina_list_append(list, "foooo");
        list = eina_list_append(list, "dsc07.jpg");
        list = eina_list_append(list, "dsc08.jpg");
        list = eina_list_append(list, "dada");
        list = eina_list_append(list, "dsc10.jpg");

        EINA_LIST_FOREACH(list, l, file)
        {
                if (!ecore_str_has_extension(file, ".jpg"))
                        list = eina_list_remove(list, file);
        }

        /* and now print the rest */
        while (list)
        {
                file = eina_list_data_get(list);

                printf("%s\n", file);
                list = eina_list_remove(list, file);
        }

        eina_shutdown();
        return 0;
}

This doesn’t look that bad on the first look and if you test it does indeed work. But it is wrong! Let me first explain why it is wrong, I’ll explain you later why it does work nevertheless. Let’s take a look on what the EINA_LIST_FOREACH-macro does. Here is the same loop but the macro expanded:

        for (l = list, file = eina_list_data_get(l); l; l = eina_list_next(l),
                        file = eina_list_data_get(l))
        {
                if (!ecore_str_has_extension(file, ".jpg"))
                        list = eina_list_remove(list, file);
        }

eina_list_remove() will, remove the node where l is pointing to and frees the node. So with the following l = eina_list_next(l) we are accessing an already freed node. But why doesn’t it crash? Or why doesn’t valgrind show any error? Because eina uses an memory pool, to reduce the free()s and malloc()s, so the given node isn’t in fact freed. Ok, but if eina is working like that, why shouldn’t we take it as a hidden feature, since it does the job as we need it?

Imagine we want now not only remove the non-jpg-files, but want to put them in a second list:

#include <Eina.h>
#include <Ecore_Str.h>
#include <string.h>
#include <stdio.h>

int
main(void)
{
        Eina_List *list = NULL;
        Eina_List *list2 = NULL;
        Eina_List *l;
        const char *file;

        eina_init();

        list = eina_list_append(list, "dsc01.jpg");
        list = eina_list_append(list, "blah");
        list = eina_list_append(list, "dsc02.jpg");
        list = eina_list_append(list, "dsc03.jpg");
        list = eina_list_append(list, "dsc04.jpg");
        list = eina_list_append(list, "dsc05.jpg");
        list = eina_list_append(list, "foooo");
        list = eina_list_append(list, "dsc07.jpg");
        list = eina_list_append(list, "dsc08.jpg");
        list = eina_list_append(list, "dada");
        list = eina_list_append(list, "dsc10.jpg");

        for (l = list, file = eina_list_data_get(l); l; l = eina_list_next(l),
                        file = eina_list_data_get(l))
        {
                if (!ecore_str_has_extension(file, ".jpg"))
                {
                        list = eina_list_remove(list, file);
                        list2 = eina_list_append(list2, file);
                }
        }

        /* and now print the rest */
        printf("first list:\n");
        while (list)
        {
                const char *file = eina_list_data_get(list);

                printf("\t%s\n", file);
                list = eina_list_remove(list, file);
        }

        /* and now print the rest */
        printf("second list:\n");
        while (list2)
        {
                const char *file = eina_list_data_get(list2);

                printf("\t%s\n", file);
                list2 = eina_list_remove(list2, file);
        }

        eina_shutdown();
        return 0;
}

And suddenly it doesn’t work anymore. The reason is pretty simple the removed node is put into the memory pool, but then before we iterate to the next node it is appended to the second list. So in fact we are looping after the first remove over the second list.

So how can we do it right? We need to go to the next node before we are removing the node, i.e. we need to keep a reference of the node that is to be removed and do the next step:

        for (l = list; l;)
        {
                Eina_List *tmp = l;

                l = eina_list_next(l);
                file = eina_list_data_get(tmp);
                if (!ecore_str_has_extension(file, ".jpg"))
                {
                        list = eina_list_remove(list, file);
                        list2 = eina_list_append(list2, file);
                }
        }

Nice that works! So are we finally done? Not quite. We are using eina_list_remove(). Although there is nothing wrong with this function, you should avoid to use it, because it does a linear search to find the node to remove, i.e. the complexity is O(n). Better use eina_list_remove_list(). Unlike the name suggests, it doesn’t remove a list, but it removes a list node, actually exactly what we want.

        for (l = list; l;)
        {
                Eina_List *tmp = l;

                l = eina_list_next(l);
                file = eina_list_data_get(tmp);
                if (!ecore_str_has_extension(file, ".jpg"))
                {
                        list = eina_list_remove_list(list, tmp);
                        list2 = eina_list_append(list2, file);
                }
        }

Puh, that was harden then expected, but it was doable, and we even kept it to be an O(n) algorithim. The actually bad thing was that our first shot worked by accident. So keep your eyes open, if you have ever to do a selective remove with eina_list.

August 14, 2008

What are the rules?

Filed under: elitaire — pfritz @ 12:10

After I put elitaire into CVS, and hence gave it a wider publicity, one of the first question was: “What are the rules of the game XY?” Most people know the rules of klondike, but some other games like Baker’s Dozen are unbeknown. So I had the plan to write a little help viewer for it for more than year.

And last weekend I’ve started to write one. First I was unsure what syntax I should use for the file format. For the writers html would be the easiest one, because almost every one has at least a little knowledge about html. So why didn’t I choose html?

  1. The help viewer is using ewl_text, so it suffers under the same limitations like Evas_Textblock does. Things like embedding images, tables and nice enumerations are not possible. I could only support a subset of html. Hence the author lost the advantage of knowing html, because he has to learn what he can use of the html syntax and what not.
  2. Html is tough to parse. If you have to deal with missing end brackets or misconstructions like this <em><a href=”…”> bla </em></a>.
  3. I don’t like html🙂

Of course I could simply open the help page within a browser, but they are IMHO still too slow. I don’t want to wait some seconds untill I can see the help page.

How does the format look like? I have chosen a syntax that is inspired by tex, but much easier too parse. It has actually only one construction.

{\tag[parameter] text}

The parameter is optional, that means in most cases it looks like this:

{\tag text}

But also the text is optional, if you want for example a new line what is in html <br>, you have simply a new paragraph with no indentation.

{\noip}

The tags are very similar to the one of html:

{\h[x] text} is a header where x is a number between 1 and 6, default is 1. X determines the size of the header.

{\p text} is a paragraph with text.

{\a[url] } is a link

{\em text} italic text

{\st text} bold text

{\pre text} is a preformated text, it will not remove whitespace and the output is in monospace font

I still need to do some cleanups in the code and I haven’t integrated it in the elitaire code. But parsing and showing the text works already, even links🙂. And I need to write the documentation😦. Hopefully, I find a native-speaking volunteer, who helps me to eliminate my spelling and grammar mistakes.

August 2, 2008

Theme Specification

Filed under: edje,elitaire — pfritz @ 12:27
Tags: ,

Last weak I have finally written the theme specs for elitaire. I really didn’t thought that it’d take that much time to do that. But now it is ready and in cvs. I also namespaced the group parts, so new themes can now be shared on exchange. Hopefully it will lead people to write their own themes.

Here are some tips for those writing an edje based application. So you can learn from my mistakes.

  1. Use a name space for your theme groups. It used to unimportant, but now with exchange it is needed.
  2. Write a theme specification before or while your writing the c code for it. It is a hard to write it after your application is finished, because you need then to grep for all the relevant part names, groups, signals, etc. Writing the spec before you start to code serves you to get a consistent naming.
  3. Don’t write the theme specification with your own theme in mind. People can and want to arrange things different then you.

Of course I know that when you start to write an application you want something that works first, before you start worrying about things like theme specifications. But don’t forget to write it as soon as possible.

Blog at WordPress.com.