LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Blogs > rainbowsally
User Name
Password

Notices


Rate this Entry

GLADE meets FLUID (FLTK designer) Pt 1

Posted 04-14-2015 at 04:49 AM by rainbowsally
Updated 05-26-2015 at 06:11 PM by rainbowsally (clarification)

May 25, 2015: This project is not dead (yet). We're on out third hack doing this having taken several wrong turns as far as which tags actually need to be written out as code and which can be included as comments (like custom tags).

But as an addendum, I'd like to add, that if this works (at all) it will be useful for seeing how to write a gtk application by hand by outputting working code for whichever tags it ends up handling correctly. And for those it doesn't handle correctly -- that's where this stuff gets interesting. The Computer Mad Scientist gets to fix it! And, that's probably you. ;-)

Too much of the modern stuff is so automated that you never learn how to work with the basic toolkits. What if glade output c/c++ code itself. Wouldn't that be helpful in assuring another generation of gtk programmers comes along? And while wxglade outp8uts code, it's only for wxWidgets and oddly enough it outputs the "extra code" faithfully for every language EXCEPT C++. Python? No prob. Perl? Yup. Gotcha covered. LISP!!! Not a problem. But wxWidgets which is written in C++ can't save its "extra code". But that's not the only problem with wxWidgets. But about that later. (For example, wxScintilla may work around the macro syntax required by wxWidgets but it probably is what ruins the formatting for any other code. Noticed in CODE::BLOCKS.)

And about the glade code writer... Stay tuned.

=== Here's the original blog entry ===

Today's Features:
  • See how the glade files suggest the names of the gtk functions needed to "write" C/C++ directly from ui text.
  • Using anonymous child objects and parent linkage. (It's easy.)
  • Hypothetical code translation with ui definitions in comments.

I confess, I like the fltk 2.0 concept and I have reworked it into my own FTL interface creator. You'll have a heck of a time getting a copy of 2.0 anymore. And it's substantially messed up. But I like my FTL because it's got no dependencies other than X11 but I don't like it because the graphics are still quite primitive and I'm having a bit of trouble with threads in timeout loops right now.

And I LOVE the fluid designer concept. It parses simple user interface definition files and outputs C++ code. And the key to doing that is that the code output uses anonymous objects and links them into anonymous Group types, which is just the FLTK name for a container.

So today's Mad Science experiment is to convert a GTK tutorial into a glade ui file (normally used by GtkBuilder -- try to find theo source download, I dare you) just to look for patterns.

And there are some patterns. Writing a new glade to C/C++ utility doesn't look like it would be too hard, though there may be some snags down the road further.

But at this point we can see how the ui file can be divided up into scopes (curley braces in C/C++) and we can see how the "object" and "child" tags can be used to nest the objects and what they link to just like FLUID does automagically.

The main snag so far is that not all of these function names deduced from the properties tags work on all the classes. There are ways to deal with this in a parser, if it's necessary, but we'll look into that later, as time permits.

Here's the snag. Notice the somewhat unpredictable names for:
Code:
      gtk_button_set_label(o, "Hello World!");
      gtk_activatable_set_use_action_appearance(o, FALSE);
      gtk_container_add(_p, o);
There are clues that can help us figure out that the code written for set_label is a button method, but there are no clues for writing the function names for set_use_action_appearance or add.

Well, it's time. So finally, the moment we've been waiting for... Here's today's experiment based on https://developer.gnome.org/gtk-tuto...table/c39.html
[Scroll down below the callbacks in the file below to see the comparison between glade and C/C++ code.]
file: src/main.c
purpose: source file
Code:
// Compare GTK tutorial: 3.1. Hello World in GTK
// https://developer.gnome.org/gtk-tutorial/stable/c39.html

#include <gtk/gtk.h>

static void hello( GtkWidget *o,
                   gpointer   parent )
{
  g_print ("Hello World\n");
}

static gboolean delete_event( GtkWidget *widget,
                              GdkEvent  *event,
                              gpointer   data )
{
    /* If you return FALSE in the "delete-event" signal handler,
  * GTK will emit the "destroy" signal. Returning TRUE means
  * you don't want the window to be destroyed.
  * This is useful for popping up 'are you sure you want to quit?'
    * type dialogs. */

  g_print ("delete event occurred\n");

    /* Change TRUE to FALSE and the main window will be destroyed with
    * a "delete-event". */

  return TRUE;
}

/* Another callback */
static void destroy( GtkWidget *widget,
                     gpointer   data )
{
  gtk_main_quit ();
}

int main( int   argc,
          char *argv[] )
{
  GtkWidget *window;
  GtkWidget *button;
    
  gtk_init (&argc, &argv);
  /// <interface>
  {
    
    ///   <object class="GtkWindow" id="window">
    void* o = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    window = o;
    
    /// NON-GLADE FEATURE
    gtk_window_set_keep_above(o, TRUE);
    
    /// <property name="can_focus">False</property>
    gtk_widget_set_can_focus(o, FALSE);
    
    // <property name="window_position">center</property>
    // see /usr/include/gtk/gtkenums.h
    gtk_window_position(o, GTK_WIN_POS_CENTER);
    
    ///     <property name="border_width">10</property>
    gtk_container_set_border_width (GTK_CONTAINER (o), 10);

    // <signal name="destroy" handler="destroy" swapped="no"/>
    g_signal_connect (o, "destroy",
                      G_CALLBACK (destroy), NULL);
    
    /// <signal name="clicked" handler="clicked" swapped="yes"/>
    g_signal_connect(o, "delete-event",
                      G_CALLBACK (delete_event), NULL);
    
    /// <child>
    {
      void* _p = o;
      
      ///    <object class="GtkButton" id="button">
      void* o = gtk_button_new();
      button = o;
      
      /// <property name="label" translatable="yes">Hello World!</property>
      gtk_button_set_label(o, "Hello World!");
      
      /// <property name="visible">True</property>
      gtk_widget_set_visible(o, TRUE);

      /// <property name="can_focus">True</property>
      gtk_widget_set_can_focus(o, TRUE);
      
      /// <property name="receives_default">True</property>
      gtk_widget_set_receives_default(o, TRUE);
      
      /// <property name="use_action_appearance">False</property>
      gtk_activatable_set_use_action_appearance(o, FALSE);
      
      /// <signal name="clicked" handler="hello" swapped="no"/>
      g_signal_connect (button, "clicked",
                        G_CALLBACK (hello), NULL);
      
      // See ui button signals and expand the list of handlers for clicked.
      /// <signal name="clicked" handler="gtk_widget_destroy" swapped="yes"/>
      g_signal_connect_swapped (button, "clicked",
                                G_CALLBACK (gtk_widget_destroy),
                                window);
      
      /// </object>
      gtk_widget_show (o);
      gtk_container_add(_p, o);
    
    /// </child>
    }

    /// </object>
    gtk_widget_show (o);

  /// </interface>
  // root_widget = o; return root_widget;
  }   
  gtk_main ();
    
  return 0;
}

file: src/a.ui
purpose: glade ui file, may need glade-2 or glade-gtk2 to show right
Code:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy toplevel-contextual -->
  <object class="GtkWindow" id="window">
    <property name="can_focus">False</property>
    <property name="border_width">10</property>
    <property name="window_position">center</property>
    <signal name="destroy" handler="destroy" swapped="no"/>
    <signal name="delete-event" handler="delete_event" swapped="no"/>
    <child>
      <object class="GtkButton" id="button">
        <property name="label" translatable="yes">Hello World!</property>
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="receives_default">True</property>
        <property name="use_action_appearance">False</property>
        <signal name="clicked" handler="hello" swapped="no"/>
        <signal name="clicked" handler="gtk_widget_destroy" swapped="yes"/>
      </object>
    </child>
  </object>
</interface>

file: src/preview.exec
purpose: utility (executable)
Code:
#!/bin/sh
curdir=`dirname "$0"`
cd "$curdir"
printf "" >.msg
glade-previewer -f a.ui
echo 'done.' >> .msg
kdialog --msgbox "$(<.msg)"
rm -f .msg

file: Makefile
purpose: builds app
Code:
## Makefile created with makefile creator 'mc2' v 3.2.0

################################################################
## Note: The following section can be put into a 'mc2.def' and 
## modified for automatic override of defaults as needed.
################################################################

################################################################
## Variable Definitions Section

## User Defined Vars

PREFIX = $(HOME)/usr
BUILDDIR := $(PWD)
## The output file name not including path
OUTNAME = main

## The directories for sources, (temp) objects, and binary output(s)
BINDIR = .
SRCDIR = src
OBJDIR = o

## What COMPILE should do.
COMPILE = gcc -m64 -c -o
CFLAGS = -Wall -g3
INCLUDE = -I $(SRCDIR) -I$(PREFIX)/include `pkg-config gtk+-2.0 --cflags`

## What LINK should do.
LINK = gcc -m64 -o
LDFLAGS = `pkg-config gtk+-2.0 --libs` -lpng
LIB = -L$(PREFIX)/lib -L/usr/lib

## MODIFY BELOW THIS LINE WITH GREAT CARE
################################################################
## File Lists Section

## The full path to the output file
MAIN = $(BINDIR)/$(OUTNAME)

SRC = \
  src/main.c \
  #############

# If your your headers aren't all in SRCDIR, you can define
# EXT_HDR in a makeinclude to add others to the dependencies
HDR = \
  $(EXT_HDR) \
  #############

OBJ = \
  o/main.o \
  $(EXT_OBJ) \
  #############

################################################################
## Rules Section

all: $(EXT_ALL) $(MAIN) $(HDR) $(OBJ) $(SRC)

$(MAIN): $(OBJ) $(HDR) $(SRC)
	@echo
	@echo "Linking $(OUTNAME)"
	$(LINK) $(MAIN) $(OBJ) $(LDFLAGS) $(LIB)
	$(POST)

$(OBJDIR)/main.o: $(SRCDIR)/main.c $(HDR)
	@echo
	@echo "Compiling main.o"
	$(COMPILE) $(OBJDIR)/main.o $(SRCDIR)/main.c $(CFLAGS) $(INCLUDE)

################################################################
## Additional Targets

update: $(EXT_UPDATE)
	@mc2 -update

# example targets
#mc2-semiclean: $(EXT_SEMICLEAN)
#	@rm -f *~ */*~ */*/*~

#mc2-clean: $(EXT_CLEAN)
#	@rm -f $(MAIN)
#	@rm -f $(OBJ)
#	@rm -f *~ */*~ */*/*~ */*/*/*~
################################################################
## User Defined Targets


old_semiclean: $(EXT_SEMICLEAN)
	@rm -f $(OBJ)
	@rm -f *~ */*~ */*/*~ */*/*/*~

strip:
	@strip $(MAIN)
	@make semiclean

clean: $(EXT_CLEAN)
	@rm -f $(MAIN)
	@rm -f $(OBJ)
	@rm -f *.kdevelop.pcs *.kdevses
	@rm -f *~ */*~ */*/*~ */*/*/*~ tmp.mak

semiclean: $(EXT_SEMICLEAN)
	@rm -f $(OBJ)
	@rm -f *.kdevelop.pcs *.kdevses
	@rm -f *~ */*~ */*/*~ */*/*/*~

force: # used to force execution

 
################################################################
This mc2.def file doesn't specify 32 or 64 bits. I'm now working with Mint 17 KDE 64 bits which still works with my ancient kdevelop (KDE3 version) which is the best IDE in the world for this kind of stuff. The idiot developers are jumping off the end of the world with their "let us do it for you" BS. It may reduce the number of false bug reports for them to deal with, but it also cuts off an entire new generation from being able to WRITE apps instead of having to download them.

file: mc2.def
purpose: source file for the Makefile
Code:
# mc2.def template created with Makefile Creator 'mc2'

# sandbox path and other new variables
PREFIX = $(HOME)/usr
BUILDDIR := $(PWD)

OUTNAME = main

SRCDIR = src
OBJDIR = o
BINDIR = .

# what COMPILE should do
COMPILE = gcc -m64 -c -o # COMPILE <output_file> (for C, 32 bit, object)
 CFLAGS = -Wall -g3 # debug
# CFLAGS = -Wall -O2 # optimized
INCLUDE = -I $(SRCDIR) -I$(PREFIX)/include `pkg-config gtk+-2.0 --cflags`

# gtk+-2.0 cflags
# -pthread -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include 
# -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 
# -I/usr/include/pango-1.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/freetype2 
# -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include 
# -I/usr/include/pixman-1 -I/usr/include/libpng12 -I/usr/include/harfbuzz  

# what LINK should do
LINK = gcc -m64 -o
LDFLAGS = `pkg-config gtk+-2.0 --libs` 
LIB = -L$(PREFIX)/lib -L/usr/lib 
 
semiclean: $(EXT_SEMICLEAN)
  @rm -f $(OBJ)
  @rm -f *~ */*~ */*/*~ */*/*/*~

strip:
  @strip $(MAIN)
  @make semiclean

# additional targets
#mc2-update:
#  @mc2 -update

clean: $(EXT_CLEAN)
  @rm -f $(MAIN)
  @rm -f $(OBJ)
  @rm -f *.kdevelop.pcs *.kdevses
  @rm -f *~ */*~ */*/*~ */*/*/*~ tmp.mak

semiclean: $(EXT_SEMICLEAN)
  @rm -f $(OBJ)
  @rm -f *.kdevelop.pcs *.kdevses
  @rm -f *~ */*~ */*/*~ */*/*/*~

force: # used to force execution
Posted in Uncategorized
Views 1176 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 10:12 AM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration