Initial work on erigo support in pyefl.

This will be developed in a separate branch and it will be ready for the 1.14 release.

The generator implemented here is on-the-fly, it does not generate the python code,
but actually generate the real interface from the json file on runtime.

The work is really at a good point yet, just need to fix/implement some
little more.

Test included
This commit is contained in:
Davide Andreoli 2015-01-22 20:43:51 +01:00
parent d4572bf26a
commit 2d2bbb1977
5 changed files with 460 additions and 0 deletions

View File

@ -396,6 +396,22 @@ cdef class Object(evasObject):
if type(self) is Object:
raise TypeError("Must not instantiate Object, but subclasses")
property part_text:
"""Sets the text of a specific part of this object.
:type: (part_name, text_to_set)
.. versionadded:: 1.14
"""
def __set__(self, value):
part, text = value
if isinstance(part, unicode): part = PyUnicode_AsUTF8String(part)
if isinstance(text, unicode): text = PyUnicode_AsUTF8String(text)
elm_object_part_text_set(self.obj,
<const char *>part if part is not None else NULL,
<const char *>text if text is not None else NULL)
def part_text_set(self, part, text):
"""Sets the text of a given part of this object.

177
efl/utils/erigo.py Normal file
View File

@ -0,0 +1,177 @@
# Copyright (C) 2007-2015 various contributors (see AUTHORS)
#
# This file is part of Python-EFL.
#
# Python-EFL is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# Python-EFL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
"""
TODO
====
* fix 'file' property
* mainmenu ??
* implement Resources ... but when? always in the file prop?
* test more widget items (only menu tested atm)
* implement callbacks
* documentation for this module
"""
import importlib
import json
###################################################################
## NOTE/TODO: importlib is only implemented from python 2.7
## From py-efl 1.14 we will need to rise py min version
###################################################################
KLASSES = {
'Elm_Win': ('efl.elementary.window', 'Window'),
'Elm_Bg': ('efl.elementary.background', 'Background'),
'Elm_Box': ('efl.elementary.box', 'Box'),
'Elm_Button': ('efl.elementary.button', 'Button'),
'Elm_Image': ('efl.elementary.image', 'Image'),
'Elm_Label': ('efl.elementary.label', 'Label'),
'Elm_Layout': ('efl.elementary.layout', 'Layout'),
'Elm_Menu': ('efl.elementary.menu', 'Menu'),
'Elm_Table': ('efl.elementary.table', 'Table'),
}
class ErigoGui(object):
""" TODO: Class doc """
def __init__ (self, json_file=None, json_string=None, verbose=False):
self._verbose = verbose
self._widgets = {} # key: widget_name data: widget_instance
if json_file is not None:
self._print('\n### Generating gui from file: %s' % json_file)
data = json.load(open(json_file))
elif json_string is not None:
self._print('\n### Generating gui from string')
data = json.loads(json_string)
else:
raise RuntimeError('One of "file" or "json_string" is mandatory')
for w_name in data['Settings']['start_points']:
_widget_generate(self, data, w_name)
def _print(self, msg):
if self._verbose:
print(msg)
def _widget_generate(self, data, name):
self._print('\n### Generating widget: %s' % name)
# get the widget class object from the correct module
w_data = data['Widgets'][name]
eo_klass_name = w_data['Desc']['class']
module_name, klass_name = KLASSES[eo_klass_name]
mod = importlib.import_module(module_name)
klass = getattr(mod, klass_name)
# class constructor
if eo_klass_name+'.constructor' in w_data.get('Properties', []):
# Custom CONSTRUCTOR
params = w_data['Properties'][eo_klass_name+'.constructor']
params = _params_list_parse(mod, params)
w = klass(*params)
else:
# Standard CONSTRUCTOR
parent_name = w_data['Desc']['parent']
parent = self._widgets[parent_name]
w = klass(parent)
self._widgets[name] = w
# make the widget public if requested
if w_data['Desc'].get('public', False) is True:
self._print('Installing name: %s' % name)
setattr(self, name, w)
# apply widget properties
if 'Properties' in w_data:
for eo_name, p_vals in w_data['Properties'].items():
p_name = eo_name.split('.')[-1]
if p_name == 'visibility':
if p_vals[0] is True:
w.show()
elif p_name == 'constructor':
pass
else:
self._print('property %s => %s' % (p_name, p_vals))
p_vals = _params_list_parse(mod, p_vals)
if p_name == 'file': # ARGHHHHHHHHHHH TODO FIXME
p_vals = (p_vals[0])
if len(p_vals) == 1:
setattr(w, p_name, p_vals[0])
else:
setattr(w, p_name, p_vals)
# generate widget items
if 'Items' in w_data:
for item_name, item_data in w_data['Items'].items():
_item_generate(self, w, None, item_name, item_data)
# generate (and pack) children widgets
if eo_klass_name == 'Elm_Win':
for c_name in w_data.get('Contains', []):
child = _widget_generate(self, data, c_name)
w.resize_object_add(child)
elif eo_klass_name == 'Elm_Box':
for c_name in w_data.get('Contains', []):
child = _widget_generate(self, data, c_name)
w.pack_end(child)
elif eo_klass_name == 'Elm_Table':
for c_name, (x, y, cspan, rspan) in w_data.get('Contains', {}).items():
child = _widget_generate(self, data, c_name)
w.pack(child, x, y, rspan, cspan)
return w
def _item_generate(self, parent_widget, parent_item, item_name, item_data):
self._print("Generating ITEM: %s" % item_name)
it = parent_widget.item_add(parent_item,
item_data['label'], # use kargs instead ?
item_data['icon'])
# print(item_data)
# TODO make the item accessible with his name from the base class ???
if 'Items' in item_data:
for item_name, item_data in item_data['Items'].items():
_item_generate(self, parent_widget, it, item_name, item_data)
def _params_list_parse(mod, params):
return [ _param_parse(mod, p) for p in params ]
def _param_parse(mod, p_value):
if isinstance(p_value, (unicode, str)):
if p_value.startswith('ELM_'):
enum_val = getattr(mod, p_value, None)
if enum_val is not None:
return enum_val
return p_value

View File

@ -0,0 +1,231 @@
{
"JSON_Version":"2",
"Settings":
{
"project":"pyefl_erigo_test",
"images_prefix":"",
"start_points":["elm_win1"]
},
"Resources":
{
"Images":
{
"logo":"/home/yakov/egui/examples/logo.png"
}
},
"Widgets":
{
"elm_win1":
{
"Desc":
{
"parent":null,
"class":"Elm_Win"
},
"Properties":
{
"Evas.Object.visibility":[true],
"Elm_Win.constructor":[null, "ELM_WIN_BASIC"],
"Elm_Win.autodel":[true],
"Elm_Win.title":["Win1 Title"],
"Evas.Object.size":[381, 480]
},
"Contains":["elm_bg1", "elm_box1"]
},
"elm_win1_main_menu":
{
"Desc":
{
"parent":"elm_win1",
"class":"Elm_Menu",
"public":true
},
"Items":
{
"elm_win1_main_menu_it0":
{
"type":"regular",
"icon":"stop",
"label":"Button",
"callback":null,
"Items":
{
"elm_win1_main_menu_it2":
{
"type":"regular",
"icon":"fileopen",
"label":"Show",
"callback":null
},
"elm_win1_main_menu_it3":
{
"type":"regular",
"icon":"list-add",
"label":"Hide",
"callback":null
}
}
},
"elm_win1_main_menu_it1":
{
"type":"regular",
"icon":"list-add",
"label":"Table",
"callback":null,
"Items":
{
"elm_win1_main_menu_it4":
{
"type":"regular",
"icon":"search",
"label":"Show",
"callback":null
},
"elm_win1_main_menu_it5":
{
"type":"regular",
"icon":"fileopen",
"label":"Hide",
"callback":null
}
}
}
}
},
"elm_bg1":
{
"Desc":
{
"parent":"elm_win1",
"class":"Elm_Bg"
},
"Properties":
{
"Evas.Object.visibility":[true],
"Elm_Widget.part_text":[null, "elm_bg1"],
"Evas.Object.size_hint_weight":[1, 1]
}
},
"elm_box1":
{
"Desc":
{
"parent":"elm_win1",
"class":"Elm_Box"
},
"Properties":
{
"Evas.Object.visibility":[true],
"Elm_Widget.part_text":[null, "elm_box1"],
"Evas.Object.size_hint_weight":[1, 1]
},
"Contains":["elm_label1", "elm_button1", "elm_table1"]
},
"elm_button1":
{
"Desc":
{
"parent":"elm_box1",
"class":"Elm_Button"
},
"Properties":
{
"Evas.Object.visibility":[true],
"Elm_Widget.part_text":[null, "elm_button1"],
"Evas.Object.size_hint_weight":[1, 1],
"Evas.Object.size_hint_align":[-1, -1]
}
},
"elm_table1":
{
"Desc":
{
"parent":"elm_box1",
"class":"Elm_Table"
},
"Properties":
{
"Evas.Object.visibility":[true],
"Elm_Widget.part_text":[null, "elm_table1"],
"Evas.Object.size_hint_weight":[1, 1],
"Evas.Object.size_hint_align":[-1, -1]
},
"Contains":
{
"elm_button2":[0, 0, 1, 1],
"elm_button3":[1, 1, 1, 1],
"elm_image1":[1, 0, 1, 1]
}
},
"elm_button2":
{
"Desc":
{
"parent":"elm_table1",
"class":"Elm_Button"
},
"Properties":
{
"Evas.Object.visibility":[true],
"Elm_Widget.part_text":[null, "elm_button2"],
"Evas.Object.size_hint_weight":[1, 1],
"Evas.Object.color":[0, 255, 0, 255]
},
"Callbacks":
{
"clicked":["Modify", "elm_button1", "Evas.Object.visibility", [false]]
}
},
"elm_button3":
{
"Desc":
{
"parent":"elm_table1",
"class":"Elm_Button"
},
"Properties":
{
"Evas.Object.visibility":[true],
"Elm_Widget.part_text":[null, "elm_button3"],
"Evas.Object.size_hint_weight":[1, 1],
"Evas.Object.color":[255, 255, 0, 255]
},
"Callbacks":
{
"clicked":["Modify", "elm_button1", "Evas.Object.visibility", [true]]
}
},
"elm_image1":
{
"Desc":
{
"parent":"elm_table1",
"class":"Elm_Image"
},
"Properties":
{
"Elm_Widget.part_text":[null, "elm_image1"],
"Evas.Object.size_hint_weight":[1, 1],
"Evas.Object.visibility":[true],
"Efl.File.file":["logo", null],
"Evas.Object.size":[40, 40],
"Evas.Object.size_hint_align":[-1, -1]
}
},
"elm_label1":
{
"Desc":
{
"parent":"elm_box1",
"class":"Elm_Label",
"public":true
},
"Properties":
{
"Evas.Object.visibility":[true],
"Elm_Widget.part_text":[null, "Label"],
"Evas.Object.size_hint_weight":[1, 0]
}
}
}
}

View File

@ -0,0 +1,35 @@
#!/usr/bin/env python
# encoding: utf-8
import os
import time
from efl import elementary
from efl.utils.erigo import ErigoGui
prj_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "erigo_prj")
json_file = os.path.join(prj_path, "test_gui.egui")
def erigo_clicked(obj):
start_time = time.time()
# Test from file
egui = ErigoGui(json_file, verbose=True)
# Test from json string
# json = open(json_file).read()
# egui = ErigoGui(json_string=json, verbose=True)
egui.elm_label1.text = 'GUI Generated in %.5f seconds' % \
(time.time() - start_time)
if __name__ == '__main__':
elementary.init()
erigo_clicked(None)
elementary.run()
elementary.shutdown()

View File

@ -278,6 +278,7 @@ if set(("build", "build_ext", "install", "bdist", "sdist")) & set(sys.argv):
]
ext_modules.extend(utils_ext)
py_modules.append("efl.utils.setup")
py_modules.append("efl.utils.erigo")
packages.append("efl.utils")
# === Evas ===